code: purgatorio

Download patch

ref: d990c25d5795b16c181e875bf2f55aa06c2f75f9
parent: 70f57939ef437a822bfacde3a6e487633b6ba706
author: henesy <devnull@localhost>
date: Sun Nov 4 06:03:02 EST 2018

init 3

diff: cannot open b/lib/acid//null: file does not exist: 'b/lib/acid//null' diff: cannot open b/lib/convcs//null: file does not exist: 'b/lib/convcs//null' diff: cannot open b/lib/ebook//null: file does not exist: 'b/lib/ebook//null' diff: cannot open b/lib/ebooks/devils//null: file does not exist: 'b/lib/ebooks/devils//null' diff: cannot open b/lib/ebooks/oebtest//null: file does not exist: 'b/lib/ebooks/oebtest//null' diff: cannot open b/lib/ebooks/understandingoeb//null: file does not exist: 'b/lib/ebooks/understandingoeb//null' diff: cannot open b/lib/ebooks//null: file does not exist: 'b/lib/ebooks//null' diff: cannot open b/lib/games//null: file does not exist: 'b/lib/games//null' diff: cannot open b/lib/legal//null: file does not exist: 'b/lib/legal//null' diff: cannot open b/lib/lego//null: file does not exist: 'b/lib/lego//null' diff: cannot open b/lib/mk//null: file does not exist: 'b/lib/mk//null' diff: cannot open b/lib/ndb//null: file does not exist: 'b/lib/ndb//null' diff: cannot open b/lib/print//null: file does not exist: 'b/lib/print//null' diff: cannot open b/lib/proto//null: file does not exist: 'b/lib/proto//null' diff: cannot open b/lib/scores//null: file does not exist: 'b/lib/scores//null' diff: cannot open b/lib/sh//null: file does not exist: 'b/lib/sh//null' diff: cannot open b/lib/strokes//null: file does not exist: 'b/lib/strokes//null' diff: cannot open b/lib/unidata//null: file does not exist: 'b/lib/unidata//null' diff: cannot open b/lib//null: file does not exist: 'b/lib//null' diff: cannot open b/lib9//null: file does not exist: 'b/lib9//null' diff: cannot open b/libbio//null: file does not exist: 'b/libbio//null' diff: cannot open b/libdraw//null: file does not exist: 'b/libdraw//null' diff: cannot open b/libdynld//null: file does not exist: 'b/libdynld//null' diff: cannot open b/libfreetype/NOTICE//null: file does not exist: 'b/libfreetype/NOTICE//null' diff: cannot open b/libfreetype//null: file does not exist: 'b/libfreetype//null' diff: cannot open b/libinterp//null: file does not exist: 'b/libinterp//null' diff: cannot open b/libkern//null: file does not exist: 'b/libkern//null' diff: cannot open b/libkeyring//null: file does not exist: 'b/libkeyring//null' diff: cannot open b/liblogfs//null: file does not exist: 'b/liblogfs//null' diff: cannot open b/libmath/bin//null: file does not exist: 'b/libmath/bin//null' diff: cannot open b/libmath/fdlibm//null: file does not exist: 'b/libmath/fdlibm//null' diff: cannot open b/libmath//null: file does not exist: 'b/libmath//null' diff: cannot open b/libmemdraw//null: file does not exist: 'b/libmemdraw//null' diff: cannot open b/libmemlayer//null: file does not exist: 'b/libmemlayer//null' diff: cannot open b/libmp/Inferno-386//null: file does not exist: 'b/libmp/Inferno-386//null' diff: cannot open b/libmp/Inferno-amd64//null: file does not exist: 'b/libmp/Inferno-amd64//null' diff: cannot open b/libmp/Inferno-mips//null: file does not exist: 'b/libmp/Inferno-mips//null' diff: cannot open b/libmp/Inferno-power//null: file does not exist: 'b/libmp/Inferno-power//null' diff: cannot open b/libmp/Plan9-386//null: file does not exist: 'b/libmp/Plan9-386//null' diff: cannot open b/libmp/Plan9-amd64//null: file does not exist: 'b/libmp/Plan9-amd64//null' diff: cannot open b/libmp/Plan9-mips//null: file does not exist: 'b/libmp/Plan9-mips//null' diff: cannot open b/libmp/Plan9-power//null: file does not exist: 'b/libmp/Plan9-power//null' diff: cannot open b/libmp/port//null: file does not exist: 'b/libmp/port//null' diff: cannot open b/libmp//null: file does not exist: 'b/libmp//null' diff: cannot open b/libnandfs//null: file does not exist: 'b/libnandfs//null' diff: cannot open b/libprefab//null: file does not exist: 'b/libprefab//null' diff: cannot open b/libsec/Inferno-386//null: file does not exist: 'b/libsec/Inferno-386//null' diff: cannot open b/libsec/Inferno-mips//null: file does not exist: 'b/libsec/Inferno-mips//null' diff: cannot open b/libsec/Plan9-386//null: file does not exist: 'b/libsec/Plan9-386//null' diff: cannot open b/libsec/Plan9-mips//null: file does not exist: 'b/libsec/Plan9-mips//null' diff: cannot open b/libsec/port//null: file does not exist: 'b/libsec/port//null' diff: cannot open b/libsec//null: file does not exist: 'b/libsec//null' diff: cannot open b/libtk//null: file does not exist: 'b/libtk//null'
--- /dev/null
+++ b/lib/acid/386
@@ -1,0 +1,205 @@
+// 386 support
+
+defn acidinit()			// Called after all the init modules are loaded
+{
+	bpl = {};
+	bpid = -1;
+	bpfmt = 'b';
+
+	srcpath = {
+		"./",
+	};
+
+	nopstop = 0;
+	srcfiles = {};			// list of loaded files
+	srctext = {};			// the text of the files
+	Labspoff = 4;		// adjustment to Label's sp
+	Labpcoff = 0;		// adjustment to Label's pc
+}
+
+defn linkreg(addr)
+{
+	return 0;
+}
+
+defn stk()				// trace
+{
+	_stk(*PC, *SP, 0, 0);
+}
+
+defn lstk()				// trace with locals
+{
+	_stk(*PC, *SP, 0, 1);
+}
+
+defn kstk()				// kernel stack, PC and SP point to kernel
+{
+	_stk(*PC, *SP, 0, 0);
+}
+
+defn lkstk()				// kernel stack and locals, PC and SP are kernel's
+{
+	_stk(*PC, *SP, 0, 1);
+}
+defn gpr()		// print general(hah hah!) purpose registers
+{
+	print("AX\t", *AX, " BX\t", *BX, " CX\t", *CX, " DX\t", *DX, "\n");
+	print("DI\t", *DI, " SI\t", *SI, " BP\t", *BP, "\n");
+}
+
+defn spr()				// print special processor registers
+{
+	local pc;
+	local cause;
+
+	pc = *PC;
+	print("PC\t", pc, " ", fmt(pc, 'a'), "  ");
+	pfl(pc);
+	print("SP\t", *SP, " ECODE ", *ECODE, " EFLAG ", *EFLAGS, "\n");
+	print("CS\t", *CS, " DS\t ", *DS, " SS\t", *SS, "\n");
+	print("GS\t", *GS, " FS\t ", *FS, " ES\t", *ES, "\n");
+	
+	cause = *TRAP;
+	print("TRAP\t", cause, " ", reason(cause), "\n");
+}
+
+defn regs()				// print all registers
+{
+	spr();
+	gpr();
+}
+
+defn step()
+{
+	local ur;
+	local addrs;
+	local id;
+	local l;
+	local b;
+	local bl;
+	local sl;
+	local pc;
+
+	complex Proc proc;
+	ur = proc.dbgreg;
+	if ur == 0 then
+		error("step: process not in breakpoint trap");
+	complex Ureg ur;
+
+	 //
+	 // stop all kprocs that could potentially hit this breakpoint
+	 // make a list of all the breakpoints at this address
+	 //
+	bl = {};
+	sl = {};
+	l = bpl;
+
+	while l do {
+		b = head l;
+		if ((b[2] & *PC) == b[2]) then {
+			if status(b[1]) != "Stopped" then {
+				stop(b[1]);
+				sl = append sl, b[1];
+			}
+			bl = append bl, b;
+		}
+		l = tail l;
+	}
+
+	 //
+	 // delete all the breakpoints at this address
+	 //
+	if bl then {
+		l = bl;
+		while l do {
+			b = head l;
+			_bpconddel(b[0]);
+			l = tail l;
+		}
+	}
+
+	 //
+	 // single step to the following address
+	 //
+	addrs = follow(*PC);
+	id = bpset(addrs[0]);
+	startstop(pid);
+	bpdel(id);
+
+	 //
+	 // restore all the breakpoints at this address
+	 //
+	if bl then {
+		l = bl;
+		while l do {
+			b = head l;
+			_bpcondset(b[0], b[1], b[2], b[3]);
+			l = tail l;
+		}
+	}
+
+	 //
+	 // restart all kprocs that could potentially hit this breakpoint
+	 //
+	if sl then {
+		l = sl;
+		while l do {
+			start(head l);
+			l = tail l;
+		}
+	}
+}
+
+aggr Ureg
+{
+	'X' 0 di;
+	'X' 4 si;
+	'X' 8 bp;
+	'X' 12 nsp;
+	'X' 16 bx;
+	'X' 20 dx;
+	'X' 24 cx;
+	'X' 28 ax;
+	'X' 32 gs;
+	'X' 36 fs;
+	'X' 40 es;
+	'X' 44 ds;
+	'X' 48 trap;
+	'X' 52 ecode;
+	'X' 56 pc;
+	'X' 60 cs;
+	'X' 64 flags;
+	{
+	'X' 68 usp;
+	'X' 68 sp;
+	};
+	'X' 72 ss;
+};
+
+
+defn
+Ureg(addr) {
+	complex Ureg addr;
+	print("	di	", addr.di, "\n");
+	print("	si	", addr.si, "\n");
+	print("	bp	", addr.bp, "\n");
+	print("	nsp	", addr.nsp, "\n");
+	print("	bx	", addr.bx, "\n");
+	print("	dx	", addr.dx, "\n");
+	print("	cx	", addr.cx, "\n");
+	print("	ax	", addr.ax, "\n");
+	print("	gs	", addr.gs, "\n");
+	print("	fs	", addr.fs, "\n");
+	print("	es	", addr.es, "\n");
+	print("	ds	", addr.ds, "\n");
+	print("	trap	", addr.trap, "\n");
+	print("	ecode	", addr.ecode, "\n");
+	print("	pc	", addr.pc, "\n");
+	print("	cs	", addr.cs, "\n");
+	print("	flags	", addr.flags, "\n");
+	print("	sp	", addr.sp, "\n");
+	print("}\n");
+	print("	ss	", addr.ss, "\n");
+};
+
+print("/sys/lib/acid/386");
--- /dev/null
+++ b/lib/acid/amd64
@@ -1,0 +1,123 @@
+// amd64
+
+defn acidinit()
+{
+	bplist = {};
+	bpfmt = 'b';
+
+	srcpath = {
+		"./",
+		"/sys/src/libc/port/",
+		"/sys/src/libc/9sys/",
+		"/sys/src/libc/amd64/"
+	};
+
+	srcfiles = {};		// list of loaded files
+	srctext = {};		// the text of the files
+}
+
+defn gpr()
+{
+	print("AX    ", *AX, "\n");
+	print("BX    ", *BX, "\n");
+	print("CX    ", *CX, "\n");
+	print("DX    ", *DX, "\n");
+	print("DI    ", *DI, "\n"); 
+	print("SI    ", *SI, "\n");
+	print("BP    ", *BP, "\n");
+	print("R8    ", *R8, "\n");
+	print("R9    ", *R9, "\n");
+	print("R10   ", *R10, "\n");
+	print("R11   ", *R11, "\n");
+	print("R12   ", *R12, "\n");
+	print("R13   ", *R13, "\n");
+	print("R14   ", *R14, "\n");
+	print("R15   ", *R15, "\n");
+}
+
+defn spr()
+{
+	print("DS  ", *DS, "  ES  ", *ES, "  FS  ", *FS, "  GS  ", *GS, "\n");
+	print("TYPE  ", *TYPE, "\n");
+	print("ERROR ", *ERROR, "\n");
+	print("PC    ", *PC, "\n");
+	print("CS    ", *CS, "\n");
+	print("FLAGS ", *FLAGS, "\n");
+	print("SP    ", *SP, "\n");
+	print("SS    ", *SS, "\n");
+}
+
+defn x87r()
+{
+	print("FCW  ", *FCW, "  FSW  ", *FSW, "  FTW  ", *FTW, "  FOP  ", *FOP, "\n");
+	print("RIP  ", *RIP, "   RDP  ", *RDP, "\n");
+	print("M0   ", *M0, "\n");
+	print("M1   ", *M1, "\n");
+	print("M2   ", *M2, "\n");
+	print("M3   ", *M3, "\n");
+	print("M4   ", *M4, "\n");
+	print("M5   ", *M5, "\n");
+	print("M6   ", *M6, "\n");
+	print("M7   ", *M7, "\n");
+}
+
+defn xmmr()
+{
+	print("MXCSR  ", *MXCSR, "   MXCSRMASK  ", *MXCSRMASK, "\n");
+	print("X0   ", *X0, "\n");
+	print("X1   ", *X1, "\n");
+	print("X2   ", *X2, "\n");
+	print("X3   ", *X3, "\n");
+	print("X4   ", *X4, "\n");
+	print("X5   ", *X5, "\n");
+	print("X6   ", *X6, "\n");
+	print("X7   ", *X7, "\n");
+	print("X8   ", *X8, "\n");
+	print("X9   ", *X9, "\n");
+	print("X10  ", *X10, "\n");
+	print("X11  ", *X11, "\n");
+	print("X12  ", *X12, "\n");
+	print("X13  ", *X13, "\n");
+	print("X14  ", *X14, "\n");
+	print("X15  ", *X15, "\n");
+}
+
+defn fpr()
+{
+	xmmr();
+}
+
+defn regs()
+{
+	gpr();
+	spr();
+}
+
+defn pstop(pid)
+{
+	local l;
+	local pc;
+
+	pc = *PC;
+
+	print(pid,": ", reason(*TRAP), "\t");
+	print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+	if notes then {
+		if notes[0] != "sys: breakpoint" then {
+			print("Notes pending:\n");
+			l = notes;
+			while l do {
+				print("\t", head l, "\n");
+				l = tail l;
+			}
+		}
+	}
+}
+
+defn stk()
+{
+	_stk(*PC, *SP, 0, 0);
+}
+
+print("/sys/lib/acid/amd64");
--- /dev/null
+++ b/lib/acid/arm
@@ -1,0 +1,84 @@
+// ARM support
+
+defn acidinit()			// Called after all the init modules are loaded
+{
+	bpl = {};
+	bpid = -1;
+	bpfmt = 'X';
+	nopstop = 0;
+
+	srcpath = {
+		"./",
+	};
+
+	srcfiles = {};			// list of loaded files
+	srctext = {};			// the text of the files
+}
+
+defn linkreg(addr)
+{
+	return 0;
+}
+
+defn stk()			// trace
+{
+	_stk(*PC, *SP, linkreg(0), 0);
+}
+
+defn lstk()			// trace with locals
+{
+	_stk(*PC, *SP, linkreg(0), 1);
+}
+
+defn kstk()
+{
+	local lab;
+	complex Proc proc;
+	lab = proc.sched;
+	complex Label lab;
+	_stk(lab.pc\X, lab.sp\X, linkreg(0), 0);
+}
+
+defn lkstk()
+{
+	local lab;
+	complex Proc proc;
+	lab = proc.sched;
+	complex Label lab;
+	_stk(lab.pc\X, lab.sp\X, linkreg(0), 1);
+}
+
+defn gpr()				// print general purpose registers
+{
+	print("R0\t", *R0, " R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n");
+	print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, " R7\t", *R7, "\n");
+	print("R8\t", *R8, " R9\t", *R9, " R10\t", *R10, " R11\t", *R11, "\n");
+	print("R12\t", *R12, "\n");
+	return 0;
+}
+
+defn spr()				// print special processor registers
+{
+	local pc;
+	local cause;
+	local lr;
+
+	pc = *PC;
+	lr = *LINK;
+	print("PC\t", pc, " ", fmt(pc, 'a'), "  ");
+	pfl(pc);
+	print("LINK\t", lr, " ", fmt(lr, 'a'), "  ");
+	pfl(lr);
+	print("TYPE: ", reason(*TYPE), "\n");
+	print("SP\t", *SP, "\n");
+	
+	return 0;
+}
+
+defn regs()				// print all registers
+{
+	spr();
+	gpr();
+}
+
+print("$ROOT/lib/acid/arm");
--- /dev/null
+++ b/lib/acid/gpa
@@ -1,0 +1,88 @@
+//
+//	generate ``General Purpose Ascii'' file for HP logic analyser
+//
+//	usage: gpa()
+//	note: output has to be postprocessed with "sed 's/0x//g' "...
+//
+
+defn functions(start, end)
+{
+	print("[FUNCTIONS]\n");
+	pc = start;
+	while pc < end do {
+		bnd = fnbound(pc);
+		print(pc\a, "\t", bnd[0], "..", bnd[1]-1, "\n");
+		pc = bnd[1];
+	}
+	print("\n");
+}
+
+defn variables(start, end)
+{
+	print("[VARIABLES]\n");
+	// TODO: how do we get this one?
+	print("\n");
+}
+
+defn sourcelines(start, end)
+{
+	local pc, curfile, curline, newfile, newline;
+
+	print("[SOURCE LINES]\n");
+	pc = txtstart;
+	curfile = "<no-file>";
+	curline = -1;
+	while pc < txtend do {
+		newfile = pcfile(pc);
+		newline = pcline(pc);
+		if newfile != curfile then {
+			if curline != -1 then
+				print("\n");
+			print("File: ", newfile, "\n");
+			curfile = newfile;
+		}
+		if newline != curline then {
+			print(newline, "\t", pc, "\n");
+			curline = newline;
+		}
+		pc++;
+	}
+	print("\n");
+}
+
+defn gpa()
+{
+	local l, ent, txtstart, txtend, datastart, dataend, pc, bnd;
+
+	print("[SECTIONS]\n");
+	l = map();
+	while l do {
+		ent = head l;
+		if ent[0] == "text" || ent[0] == "data" then {
+			if ent[0] == "text" then {
+				txtstart = ent[1];
+				txtend = ent[2];
+			}
+			else {
+				datastart = ent[1];
+				dataend = ent[2];
+			}
+			print(ent[0], "\t", ent[1], "..", ent[2]-1, "\n");
+		}
+		l = tail l;
+	}
+	print("\n");
+
+	functions(txtstart, txtend);
+//	variables(datastart, dataend);
+	sourcelines(datastart, dataend);
+
+	print("[START ADDRESS]\n");
+	print(txtstart, "\n");
+	print("\n");
+}
+
+defn acidinit()
+{
+	gpa();
+}
--- /dev/null
+++ b/lib/acid/inferno
@@ -1,0 +1,63 @@
+//
+//	experimental acid functions for Inferno (common to native and emu)
+//
+//	problems arise because of unnamed substructures having to be
+//	named in emu, for instance Ref.  We cheat by ``knowing'' that Ref
+//	is first in the structure, to keep this code portable between native
+//	and emu.
+//
+
+//
+// ps() - Process Listing
+//
+complex Ref	pidalloc;
+
+defn
+ps()
+{
+	local i;
+	local n;
+	local done;
+	local p;
+	local curpid;
+
+	i = 0;
+	done = 0;
+	n = pidalloc.ref;
+	curpid = pid;
+	p = procalloc.arena;
+
+	if n > conf.nproc then
+		n = conf.nproc;
+
+	print("PID	PC          PRI     STATE   NAME\n");
+	while n > 0 && i < conf.nproc do {
+		complex Proc p;
+		if p.state != 0 then {
+			print(p.pid, "\t", p.pc\X, "\t", p.pri, "\t", status(p.pid), "\t");
+			mem(p.text, "s");
+			n = n - 1;
+		}
+		i = i + 1;
+		p = p + sizeofProc;
+	}
+}
+
+defn labels()
+{
+	local n;
+	local l;
+	complex Proc proc;
+
+	n = proc.nerrlab;
+	l = proc.errlab;
+	while n > 0 do {
+		complex Label l;
+		print(l.pc\a, " ");
+		pfl(l.pc);
+		l = l + sizeofLabel;
+		n = n - 1;
+	}
+}
+
+print("$ROOT/lib/acid/inferno");
--- /dev/null
+++ b/lib/acid/mips
@@ -1,0 +1,217 @@
+// Mips support
+
+defn acidinit()			// Called after all the init modules are loaded
+{
+	bplist = {};
+	bpfmt = 'X';
+
+	srcpath = {
+		"./",
+		"/sys/src/libc/port/",
+		"/sys/src/libc/9sys/",
+		"/sys/src/libc/mips/"
+	};
+
+	srcfiles = {};		// list of loaded files
+	srctext = {};		// the text of the files
+}
+
+defn stk()			// trace
+{
+	_stk(*PC, *SP, linkreg(0), 0);
+}
+
+defn lstk()			// trace with locals
+{
+	_stk(*PC, *SP, linkreg(0), 1);
+}
+
+defn gpr()			// print general purpose registers
+{
+	print("R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n");
+	print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n");
+	print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n");
+	print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n");
+	print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n");
+	print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n");
+	print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n");
+	print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n");
+	print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n");
+	print("R28\t", *R28, " R29\t", *SP, " R30\t", *R30, "\n");
+	print("R31\t", *R31, "\n");
+}
+
+defn Fpr()
+{
+	print("F0\t",  *fmt(F0, 'G'),  "\tF2\t",  *fmt(F2, 'G'), "\n");
+	print("F4\t",  *fmt(F4, 'G'),  "\tF6\t",  *fmt(F6, 'G'), "\n");
+	print("F8\t",  *fmt(F8, 'G'),  "\tF10\t", *fmt(F10, 'G'), "\n");
+	print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+	print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+	print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+	print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+	print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+	print("F0\t",  *fmt(F0, 'g'),  "\tF1\t",  *fmt(F1, 'g'), "\n");
+	print("F2\t",  *fmt(F2, 'g'),  "\tF3\t",  *fmt(F3, 'g'), "\n");
+	print("F4\t",  *fmt(F4, 'g'),  "\tF5\t",  *fmt(F5, 'g'), "\n");
+	print("F6\t",  *fmt(F6, 'g'),  "\tF7\t",  *fmt(F7, 'g'), "\n");
+	print("F8\t",  *fmt(F8, 'g'),  "\tF9\t",  *fmt(F9, 'g'), "\n");
+	print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+	print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+	print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+	print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+	print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+	print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+	print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+	print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+	print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+	print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+	print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn spr()				// print special processor registers
+{
+	local pc, link, cause;
+
+	pc = *PC;
+	print("PC\t", pc, " ", fmt(pc, 'a'), "  ");
+	pfl(pc);
+
+	link = *R31;
+	print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " ");
+	pfl(link);
+
+	cause = *CAUSE;
+	print("STATUS\t", *STATUS, "\tCAUSE\t", cause, " ", reason(cause), "\n");
+	print("TLBVIR\t", *TLBVIRT, "\tBADVADR\t", *BADVADDR, "\n");
+
+	print("HI\t", *HI, "\tLO\t", *LO, "\n");
+}
+
+defn regs()				// print all registers
+{
+	spr();
+	gpr();
+}
+
+defn pstop(pid)
+{
+	local l, pc;
+
+	pc = *PC;
+
+	print(pid,": ", reason(*CAUSE), "\t");
+	print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+	if notes then {
+		if notes[0] != "sys: breakpoint" then {
+			print("Notes pending:\n");
+			l = notes;
+			while l do {
+				print("\t", head l, "\n");
+				l = tail l;
+			}
+		}
+	}
+}
+
+sizeofUreg = 152;
+aggr Ureg
+{
+	'X' 0 status;
+	'X' 4 pc;
+	{
+	'X' 8 sp;
+	'X' 8 usp;
+	};
+	'X' 12 cause;
+	'X' 16 badvaddr;
+	'X' 20 tlbvirt;
+	'X' 24 hi;
+	'X' 28 lo;
+	'X' 32 r31;
+	'X' 36 r30;
+	'X' 40 r28;
+	'X' 44 r27;
+	'X' 48 r26;
+	'X' 52 r25;
+	'X' 56 r24;
+	'X' 60 r23;
+	'X' 64 r22;
+	'X' 68 r21;
+	'X' 72 r20;
+	'X' 76 r19;
+	'X' 80 r18;
+	'X' 84 r17;
+	'X' 88 r16;
+	'X' 92 r15;
+	'X' 96 r14;
+	'X' 100 r13;
+	'X' 104 r12;
+	'X' 108 r11;
+	'X' 112 r10;
+	'X' 116 r9;
+	'X' 120 r8;
+	'X' 124 r7;
+	'X' 128 r6;
+	'X' 132 r5;
+	'X' 136 r4;
+	'X' 140 r3;
+	'X' 144 r2;
+	'X' 148 r1;
+};
+
+defn
+Ureg(addr) {
+	complex Ureg addr;
+	print("	status	", addr.status, "\n");
+	print("	pc	", addr.pc, "\n");
+	print("	sp	", addr.sp, "\n");
+	print("	cause	", addr.cause, "\n");
+	print("	badvaddr	", addr.badvaddr, "\n");
+	print("	tlbvirt	", addr.tlbvirt, "\n");
+	print("	hi	", addr.hi, "\n");
+	print("	lo	", addr.lo, "\n");
+	print("	r31	", addr.r31, "\n");
+	print("	r30	", addr.r30, "\n");
+	print("	r28	", addr.r28, "\n");
+	print("	r27	", addr.r27, "\n");
+	print("	r26	", addr.r26, "\n");
+	print("	r25	", addr.r25, "\n");
+	print("	r24	", addr.r24, "\n");
+	print("	r23	", addr.r23, "\n");
+	print("	r22	", addr.r22, "\n");
+	print("	r21	", addr.r21, "\n");
+	print("	r20	", addr.r20, "\n");
+	print("	r19	", addr.r19, "\n");
+	print("	r18	", addr.r18, "\n");
+	print("	r17	", addr.r17, "\n");
+	print("	r16	", addr.r16, "\n");
+	print("	r15	", addr.r15, "\n");
+	print("	r14	", addr.r14, "\n");
+	print("	r13	", addr.r13, "\n");
+	print("	r12	", addr.r12, "\n");
+	print("	r11	", addr.r11, "\n");
+	print("	r10	", addr.r10, "\n");
+	print("	r9	", addr.r9, "\n");
+	print("	r8	", addr.r8, "\n");
+	print("	r7	", addr.r7, "\n");
+	print("	r6	", addr.r6, "\n");
+	print("	r5	", addr.r5, "\n");
+	print("	r4	", addr.r4, "\n");
+	print("	r3	", addr.r3, "\n");
+	print("	r2	", addr.r2, "\n");
+	print("	r1	", addr.r1, "\n");
+};
+
+defn linkreg(addr)
+{
+	complex Ureg addr;
+	return addr.r31\X;
+}
+
+print("/sys/lib/acid/mips");
--- /dev/null
+++ b/lib/acid/port
@@ -1,0 +1,547 @@
+// portable acid for all architectures
+
+defn pfl(addr)
+{
+	print(pcfile(addr), ":", pcline(addr), "\n");
+}
+
+defn
+notestk(addr)
+{
+	local pc, sp;
+	complex Ureg addr;
+
+	pc = addr.pc\X;
+	sp = addr.sp\X;
+
+	print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
+	pfl(pc);
+	_stk(pc, sp, linkreg(addr), 1);
+}
+
+defn labstk(l)				// trace from a label
+{
+	_stk(*(l+4), *l, linkreg(0), 0);
+}
+
+defn params(param)
+{
+	while param do {
+		sym = head param;
+		print(sym[0], "=", sym[1]);
+		param = tail param;
+		if param then
+			print (",");
+	}	
+}
+
+defn locals(l)
+{
+	local sym;
+
+	while l do {
+		sym = head l;
+		print("\t", sym[0], "=", sym[1], "\n");
+		l = tail l;
+	}	
+}
+
+defn _stk(pc, sp, link, dolocals)
+{
+	local stk;
+
+	print("At pc:", pc, ":", fmt(pc, 'a'), " ");
+	pfl(pc);
+
+	stk = strace(pc, sp, link);
+
+	while stk do {
+		frame = head stk;
+		print(fmt(frame[0], 'a'), "(");
+		params(frame[2]);
+		print(") ", pcfile(frame[0]), ":", pcline(frame[0]));
+		print("\n\tcalled from ", fmt(frame[1], 'a'), " ");
+		pfl(frame[1]);
+		stk = tail stk;
+		if dolocals then
+			locals(frame[3]);
+	}
+}
+
+defn findsrc(file)
+{
+	local lst, src;
+
+	if file[0] == '/' then {
+		src = file(file);
+		if src != {} then {
+			srcfiles = append srcfiles, file;
+			srctext = append srctext, src;
+			return src;
+		}
+		return {};
+	}
+
+	lst = srcpath;
+	while head lst do {
+		src = file(head lst+file);
+		if src != {} then {
+			srcfiles = append srcfiles, file;
+			srctext = append srctext, src;
+			return src;
+		}
+		lst = tail lst;
+	}
+}
+
+defn line(addr)
+{
+	local src, file;
+
+	file = pcfile(addr);
+	src = match(file, srcfiles);
+
+	if src >= 0 then
+		src = srctext[src];
+	else
+		src = findsrc(file);
+
+	if src == {} then {
+		print("no source for ", file, "\n");
+		return {};
+	}
+	line = pcline(addr)-1;
+	print(file, ":", src[line], "\n");
+}
+
+defn addsrcdir(dir)
+{
+	dir = dir+"/";
+
+	if match(dir, srcpath) >= 0 then {
+		print("already in srcpath\n");
+		return {};
+	}
+
+	srcpath = {dir}+srcpath;
+}
+
+defn source()
+{
+	local l;
+
+	l = srcpath;
+	while l do {
+		print(head l, "\n");
+		l = tail l;
+	}
+	l = srcfiles;
+
+	while l do {
+		print("\t", head l, "\n");
+		l = tail l;
+	}
+}
+
+defn Bsrc(addr)
+{
+	local lst;
+
+	lst = srcpath;
+	file = pcfile(addr);
+	if file[0] == '/' && access(file) then {
+		rc("B "+itoa(-pcline(addr))+" "+file);
+		return {};
+	}
+	while head lst do {
+		name = head lst+file;
+		if access(name) then {
+			rc("B "+itoa(-pcline(addr))+" "+name);
+			return {};
+		}
+		lst = tail lst;
+	}
+	print("no source for ", file, "\n");
+}
+
+defn src(addr)
+{
+	local src, file, line, cline, text;
+
+	file = pcfile(addr);
+	src = match(file, srcfiles);
+
+	if src >= 0 then
+		src = srctext[src];
+	else
+		src = findsrc(file);
+
+	if src == {} then {
+		print("no source for ", file, "\n");
+		return {};
+	}
+
+	cline = pcline(addr)-1;
+	print(file, ":", cline, "\n");
+	line = cline-5;
+	loop 0,10 do {
+		if line >= 0 then {
+			if line == cline then
+				print(">");
+			else
+				print(" ");
+			text = src[line];
+			if text == {} then
+				return {};
+			print(line, "\t", text, "\n");
+		}
+		line = line+1;
+	}
+}
+
+defn stopped(pid)		// called from acid when a process changes state
+{
+	pstop(pid);		// stub so this is easy to replace
+}
+
+defn procs()			// print status of processes
+{
+	local c, lst, cpid;
+
+	cpid = pid;
+	lst = proclist;
+	while lst do {
+		np = head lst;
+		setproc(np);
+		if np == cpid then
+			c = '>';
+		else
+			c = ' ';
+		print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n");
+		lst = tail lst;
+	}
+	pid = cpid;
+	if pid != 0 then
+		setproc(pid);
+}
+
+defn asm(addr)
+{
+	local bound;
+
+	bound = fnbound(addr);
+
+	addr = fmt(addr, 'i');
+	loop 1,30 do {
+		print(fmt(addr, 'a'), " ", fmt(addr, 'X'));
+		print("\t", @addr++, "\n");
+		if bound != {} && addr > bound[1] then {
+			lasmaddr = addr;
+			return {};
+		}
+	}
+	lasmaddr = addr;
+}
+
+defn casm()
+{
+	asm(lasmaddr);
+}
+
+defn new()
+{
+	bplist = {};
+	newproc(progargs);
+	// Dont miss the delay slot calls
+	bpset(follow(main)[0]);
+	cont();
+	bpdel(*PC);
+}
+
+defn stmnt()			// step one statement
+{
+	local line;
+
+	line = pcline(*PC);
+	while 1 do {
+		step();
+		if line != pcline(*PC) then {
+			src(*PC);
+			return {};
+		}
+	}
+}
+
+defn func()			// step until we leave the current function
+{
+	local bound, end, start, pc;
+
+	bound = fnbound(*PC);
+	if bound == {} then {
+		print("cannot locate text symbol\n");
+		return {};
+	}
+
+	pc = *PC;
+	start = bound[0];
+	end = bound[1];
+	while pc >= start && pc < end do {
+		step();
+		pc = *PC;
+	}
+}
+
+defn next()
+{
+	local sp, bound;
+
+	sp = *SP;
+	bound = fnbound(*PC);
+	stmnt();
+	pc = *PC;
+	if pc >= bound[0] && pc < bound[1] then
+		return {};
+
+	while (pc < bound[0] || pc > bound[1]) && sp >= *SP do {
+		step();
+		pc = *PC;
+	}
+	src(*PC);
+}
+
+defn dump(addr, n, fmt)
+{
+	loop 0, n do {
+		print(fmt(addr, 'X'), ": ");
+		addr = mem(addr, fmt);
+	}
+}
+
+defn mem(addr, fmt)
+{
+
+	local i, c, n;
+
+	i = 0;
+	while fmt[i] != 0 do {
+		c = fmt[i];
+		n = 0;
+		while '0' <= fmt[i] && fmt[i] <= '9' do {
+			n = 10*n + fmt[i]-'0';
+			i = i+1;
+		}
+		if n <= 0 then n = 1;
+		addr = fmt(addr, fmt[i]);
+		while n > 0 do {
+			print(*addr++, " ");
+			n = n-1;
+		}
+		i = i+1;
+	}
+	print("\n");
+	return addr;
+}
+
+defn symbols(pattern)
+{
+	local l, s;
+
+	l = symbols;
+	while l do {
+		s = head l;
+		if regexp(pattern, s[0]) then
+			print(s[0], "\t", s[1], "\t", s[2], "\n");
+		l = tail l;
+	}
+}
+
+defn spsrch(len)
+{
+	local addr, a, s, e;
+
+	addr = *SP;
+	s = origin & 0x7fffffff;
+	e = etext & 0x7fffffff;
+	loop 1, len do {
+		a = *addr++;
+		c = a & 0x7fffffff;
+		if c > s && c < e then {
+			print("src(", a, ")\n");
+			pfl(a);
+		}			
+	}
+}
+
+defn bppush(val)
+{
+	return {"p", val};
+}
+
+defn bpderef()
+{
+	return {"*", 0};
+}
+
+defn bpmask()
+{
+	return {"&", 0};
+}
+
+defn bpeq()
+{
+	return {"=", 0};
+}
+
+defn bpneq()
+{
+	return {"!", 0};
+}
+
+defn bpand()
+{
+	return {"a", 0};
+}
+
+defn bpor()
+{
+	return {"o", 0};
+}
+
+defn bpcondset(pid, addr, conds)
+{
+	local l;
+	local id;
+	local found;
+
+ 	if status(pid) != "Stopped" then {
+ 		print("Waiting...\n");
+ 		stop(pid);
+ 	}
+
+	id = 0;
+	found = 0;
+
+	while !found && id <= 255 do {
+		l = bpl;
+		while l && head head l != id do {
+			l = tail l;
+		}
+
+		if !l then
+			found = 1;
+		else
+			id = id + 1;
+	}
+
+	if !found then {
+		print("error: no breakpoints available\n");
+		return -1;
+	}
+
+	bpl = append bpl, {id\d, pid\d, addr\X, conds};
+
+	_bpcondset(id, pid, addr, conds);
+
+	return id;
+}
+
+defn bpconddel(id)
+{
+	local i;
+	local l;
+
+	l = bpl;
+	i = 0;
+	while l do {
+		if id == head head l then {
+			bpl = delete bpl, i;
+			_bpconddel(id);
+			if id == bpid then
+				bpid = -1;
+			return {};
+		}
+		i = i + 1;
+		l = tail l;
+	}
+	print("no breakpoint with id ", id\d, ".\n");
+}
+
+defn bpprint(b)
+{
+	local l;
+
+	print(b[0], "\t", b[1], "\t", fmt(b[2], 'a'), " ", b[2]);
+	print("\t{");
+	l = b[3];
+	while l do {
+		print("\n\t\t\t\t\t", head l);
+		l = tail l;
+	}
+	print(" }\n");
+}
+
+defn bptab()
+{
+	local l;
+
+	l = bpl;
+	print("ID	PID	ADDR			CONDITIONS\n");
+	while l do {
+		bpprint(head l);
+		l = tail l;
+	}
+}
+
+defn cont()
+{
+	local b, c, l, found;
+
+	l = bpl;
+	found = 0;
+	c = *PC;
+	while !found && l do {
+		b = head l;
+		if b[2] == c then {
+			nopstop = 1;
+			step();
+			nopstop = 0;
+			found = 1;
+		} else {
+			l = tail l;
+		}
+	}
+
+	return startstop(pid);
+}
+
+defn bpset(addr)				// set a breakpoint
+{
+	return bpcondset(pid, addr, {});
+}
+
+defn bpdel(id)
+{
+	bpconddel(id);
+}
+
+defn bpaddr(id)
+{
+	local i;
+	local l;
+	local b;
+
+	l = bpl;
+	i = 0;
+	while l do {
+		b = head l;
+		if id == b[0] then
+			return b[2];
+		i = i + 1;
+		l = tail l;
+	}
+	print("bpaddr(", id\d, "): no match\n");
+	return {};
+}
+
+progargs="";
+print("$ROOT/lib/acid/port");
--- /dev/null
+++ b/lib/acid/power
@@ -1,0 +1,233 @@
+// Power PC support
+
+defn acidinit()			// Called after all the init modules are loaded
+{
+        bpl = {};
+        bpid = -1;
+        bpfmt = 'X';
+        nopstop = 0;
+	bplist = {};
+
+	srcpath = {
+		"./",
+		"/sys/src/libc/port/",
+		"/sys/src/libc/9sys/",
+		"/sys/src/libc/power/"
+	};
+
+	srcfiles = {};		// list of loaded files
+	srctext = {};		// the text of the files
+}
+
+// defn stk()			// trace
+// {
+// 	_stk(*PC, *SP, linkreg(0), 0);
+// }
+
+// defn lstk()			// trace with locals
+// {
+// 	_stk(*PC, *SP, linkreg(0), 1);
+// }
+
+defn ustk(ur)
+{
+	complex Ureg ur;
+	_stk(ur.pc, ur.sp, 0, 0);
+}
+
+defn lustk(ur)
+{
+	complex Ureg ur;
+	_stk(ur.pc, ur.sp, 0, 1);
+}
+
+defn stk()
+{
+	ustk(0);
+}
+
+defn lstk()
+{
+	lustk(0);
+}
+
+defn kstk()
+{
+	local lab;
+	complex Proc proc;
+	lab = proc.sched;
+	complex Label lab;
+	_stk(lab.pc\X, lab.sp\X, 0, 0);
+}
+
+defn lkstk()
+{
+	local lab;
+	complex Proc proc;
+	lab = proc.sched;
+	complex Label lab;
+	_stk(lab.pc\X, lab.sp\X, 0, 1);
+}
+
+defn gpr()			// print general purpose registers
+{
+	print("SP\t", *SP, " R2\t", *R2, " R3\t", *R3, "\n");
+	print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n");
+	print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n");
+	print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n");
+	print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n");
+	print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n");
+	print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n");
+	print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n");
+	print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n");
+	print("R28\t", *R28, " R29\t", *R29, " R30\t", *R30, "\n");
+	print("R31\t", *R31, "\n");
+}
+
+defn Fpr()
+{
+	fpr();
+}
+
+defn fpr()
+{
+	print("F0\t",  *fmt(F0, 'G'),  "\tF1\t",  *fmt(F1, 'G'), "\n");
+	print("F2\t",  *fmt(F2, 'G'),  "\tF3\t",  *fmt(F3, 'G'), "\n");
+	print("F4\t",  *fmt(F4, 'G'),  "\tF5\t",  *fmt(F5, 'G'), "\n");
+	print("F6\t",  *fmt(F6, 'G'),  "\tF7\t",  *fmt(F7, 'G'), "\n");
+	print("F8\t",  *fmt(F8, 'G'),  "\tF9\t",  *fmt(F9, 'G'), "\n");
+	print("F10\t", *fmt(F10, 'G'), "\tF11\t", *fmt(F11, 'G'), "\n");
+	print("F12\t", *fmt(F12, 'G'), "\tF13\t", *fmt(F13, 'G'), "\n");
+	print("F14\t", *fmt(F14, 'G'), "\tF15\t", *fmt(F15, 'G'), "\n");
+	print("F16\t", *fmt(F16, 'G'), "\tF17\t", *fmt(F17, 'G'), "\n");
+	print("F18\t", *fmt(F18, 'G'), "\tF19\t", *fmt(F19, 'G'), "\n");
+	print("F20\t", *fmt(F20, 'G'), "\tF21\t", *fmt(F21, 'G'), "\n");
+	print("F22\t", *fmt(F22, 'G'), "\tF23\t", *fmt(F23, 'G'), "\n");
+	print("F24\t", *fmt(F24, 'G'), "\tF25\t", *fmt(F25, 'G'), "\n");
+	print("F26\t", *fmt(F26, 'G'), "\tF27\t", *fmt(F27, 'G'), "\n");
+	print("F28\t", *fmt(F28, 'G'), "\tF29\t", *fmt(F29, 'G'), "\n");
+	print("F30\t", *fmt(F30, 'G'), "\tF31\t", *fmt(F31, 'G'), "\n");
+}
+
+defn spr()				// print special processor registers
+{
+	local pc, link, cause;
+
+	pc = *PC;
+	print("PC\t", pc, " ", fmt(pc, 'a'), "  ");
+	pfl(pc);
+
+	link = *R31;
+	print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " ");
+	pfl(link);
+
+	cause = *CAUSE;
+	print("SRR1\t", *SRR1, "\tCAUSE\t", cause, " ", reason(cause), "\n");
+	print("LR\t", *LR, "\tCR\t", *CR, "\n");
+
+	print("XER\t", *XER, "\tCTR\t", *CTR, "\n");
+}
+
+defn regs()				// print all registers
+{
+	spr();
+	gpr();
+}
+
+
+defn linkreg(addr)
+{
+	return *LR;
+}
+
+sizeofUreg = 160;
+aggr Ureg
+{
+	'U' 0 cause;
+	'U' 4 status;
+	'U' 8 pc;
+	'U' 12 pad;
+	'U' 16 lr;
+	'U' 20 cr;
+	'U' 24 xer;
+	'U' 28 ctr;
+	'U' 32 r0;
+	'U' 36 sp;
+	'U' 40 r2;
+	'U' 44 r3;
+	'U' 48 r4;
+	'U' 52 r5;
+	'U' 56 r6;
+	'U' 60 r7;
+	'U' 64 r8;
+	'U' 68 r9;
+	'U' 72 r10;
+	'U' 76 r11;
+	'U' 80 r12;
+	'U' 84 r13;
+	'U' 88 r14;
+	'U' 92 r15;
+	'U' 96 r16;
+	'U' 100 r17;
+	'U' 104 r18;
+	'U' 108 r19;
+	'U' 112 r20;
+	'U' 116 r21;
+	'U' 120 r22;
+	'U' 124 r23;
+	'U' 128 r24;
+	'U' 132 r25;
+	'U' 136 r26;
+	'U' 140 r27;
+	'U' 144 r28;
+	'U' 148 r29;
+	'U' 152 r30;
+	'U' 156 r31;
+};
+
+defn
+Ureg(addr) {
+	complex Ureg addr;
+	print("	cause	", addr.cause, "\n");
+	print("	status	", addr.status, "\n");
+	print("	pc	", addr.pc, "\n");
+	print("	pad	", addr.pad, "\n");
+	print("	lr	", addr.lr, "\n");
+	print("	cr	", addr.cr, "\n");
+	print("	xer	", addr.xer, "\n");
+	print("	ctr	", addr.ctr, "\n");
+	print("	r0	", addr.r0, "\n");
+	print("	sp	", addr.sp, "\n");
+	print("	r2	", addr.r2, "\n");
+	print("	r3	", addr.r3, "\n");
+	print("	r4	", addr.r4, "\n");
+	print("	r5	", addr.r5, "\n");
+	print("	r6	", addr.r6, "\n");
+	print("	r7	", addr.r7, "\n");
+	print("	r8	", addr.r8, "\n");
+	print("	r9	", addr.r9, "\n");
+	print("	r10	", addr.r10, "\n");
+	print("	r11	", addr.r11, "\n");
+	print("	r12	", addr.r12, "\n");
+	print("	r13	", addr.r13, "\n");
+	print("	r14	", addr.r14, "\n");
+	print("	r15	", addr.r15, "\n");
+	print("	r16	", addr.r16, "\n");
+	print("	r17	", addr.r17, "\n");
+	print("	r18	", addr.r18, "\n");
+	print("	r19	", addr.r19, "\n");
+	print("	r20	", addr.r20, "\n");
+	print("	r21	", addr.r21, "\n");
+	print("	r22	", addr.r22, "\n");
+	print("	r23	", addr.r23, "\n");
+	print("	r24	", addr.r24, "\n");
+	print("	r25	", addr.r25, "\n");
+	print("	r26	", addr.r26, "\n");
+	print("	r27	", addr.r27, "\n");
+	print("	r28	", addr.r28, "\n");
+	print("	r29	", addr.r29, "\n");
+	print("	r30	", addr.r30, "\n");
+	print("	r31	", addr.r31, "\n");
+};
+
+print("/sys/lib/acid/power");
--- /dev/null
+++ b/lib/acid/rdebug
@@ -1,0 +1,116 @@
+// Acid remote debug (using devdbg.c)
+
+defn step()
+{
+	local ur;
+	local addrs;
+	local id;
+	local l;
+	local b;
+	local bl;
+	local sl;
+
+	complex Proc proc;
+	ur = proc.dbgreg;
+	if ur == 0 then
+		error("step: process not in breakpoint trap");
+	complex Ureg ur;
+
+	 //
+	 // stop all kprocs that could potentially hit this breakpoint
+	 // make a list of all the breakpoints at this address
+	 //
+	bl = {};
+	sl = {};
+	l = bpl;
+	while l do {
+		b = head l;
+		if b[2] == ur.pc then {
+			if status(b[1]) != "Stopped" then {
+				stop(b[1]);
+				sl = append sl, b[1];
+			}
+			bl = append bl, b;
+		}
+		l = tail l;
+	}
+
+	 //
+	 // delete all the breakpoints at this address
+	 //
+	if bl then {
+		l = bl;
+		while l do {
+			b = head l;
+			_bpconddel(b[0]);
+			l = tail l;
+		}
+	}
+
+	 //
+	 // single step to the following address
+	 //
+	addrs = follow(ur.pc);
+	id = bpset(addrs[0]);
+	startstop(pid);
+	bpdel(id);
+
+	 //
+	 // restore all the breakpoints at this address
+	 //
+	if bl then {
+		l = bl;
+		while l do {
+			b = head l;
+			_bpcondset(b[0], b[1], b[2], b[3]);
+			l = tail l;
+		}
+	}
+
+	 //
+	 // restart all kprocs that could potentially hit this breakpoint
+	 //
+	if sl then {
+		l = sl;
+		while l do {
+			start(head l);
+			l = tail l;
+		}
+	}
+}
+
+defn pstop(pid)
+{
+	local l;
+	local pc;
+	local ur;
+
+	if nopstop then
+		return {};
+
+	complex Proc proc;
+	ur = proc.dbgreg;
+	complex Ureg ur;
+	pc = ur.pc;
+
+	if _breakid != -1 then {
+		print("break ", _breakid\d, ": pid ");
+		_breakid = -1;
+	}
+	print(pid,": ", status(pid), "\t");
+
+	print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+	if notes then {
+		if notes[0] != "sys: breakpoint" then {
+			print("Notes pending:\n");
+			l = notes;
+			while l do {
+				print("\t", head l, "\n");
+				l = tail l;
+			}
+		}
+	}
+}
+
+print("$ROOT/lib/acid/rdebug");
--- /dev/null
+++ b/lib/acid/sparc
@@ -1,0 +1,218 @@
+// Sparc support
+
+defn acidinit()			// Called after all the init modules are loaded
+{
+	bplist = {};
+	bpfmt = 'X';
+
+	srcpath = {
+		"./",
+		"/sys/src/libc/port/",
+		"/sys/src/libc/9sys/",
+		"/sys/src/libc/sparc/"
+	};
+
+	srcfiles = {};		// list of loaded files
+	srctext = {};		// the text of the files
+}
+
+defn stk()			// trace
+{
+	_stk(*PC, *R1, linkreg(0), 0);
+}
+
+defn lstk()			// trace with locals
+{
+	_stk(*PC, *R1, linkreg(0), 1);
+}
+
+defn gpr()			// print general purpose registers
+{
+	print("R1\t", *R1, "R2\t", *R2, "R3\t", *R3, "\n");
+	print("R4\t", *R4, "R5\t", *R5, "R6\t", *R6, "\n");
+	print("R7\t", *R7, "R8\t", *R8, "R9\t", *R9, "\n");
+	print("R10\t", *R10, "R11\t", *R11, "R12\t", *R12, "\n");
+	print("R13\t", *R13, "R14\t", *R14, "R15\t", *R15, "\n");
+	print("R16\t", *R16, "R17\t", *R17, "R18\t", *R18, "\n");
+	print("R19\t", *R19, "R20\t", *R20, "R21\t", *R21, "\n");
+	print("R22\t", *R22, "R23\t", *R23, "R24\t", *R24, "\n");
+	print("R25\t", *R25, "R26\t", *R26, "R27\t", *R27, "\n");
+	print("R28\t", *R28, "R29\t", *R29, "R30\t", *R30, "\n");
+	print("R31\t", *R31, "\n");
+}
+
+defn spr()				// print special processor registers
+{
+	local pc;
+	local link;
+	local cause;
+
+	pc = *PC;
+	print("PC\t", pc, " ", fmt(pc, 'a'), "  ");
+	pfl(pc);
+	print("PSR\t", *PSR, "\n");
+
+	link = *R15;
+	print("SP\t", *R1, "\tLINK\t\t", link, " ", fmt(link, 'a'));
+	pfl(link);
+
+	cause = *TBR;
+	print("Y\t", *Y, "\tCAUSE\t", *Y, cause, " ", reason(cause), "\n");
+}
+
+defn Fpr()
+{
+	print("F0\t",  *fmt(F0, 'G'),  "\tF2\t",  *fmt(F2, 'G'), "\n");
+	print("F4\t",  *fmt(F4, 'G'),  "\tF6\t",  *fmt(F6, 'G'), "\n");
+	print("F8\t",  *fmt(F8, 'G'),  "\tF10\t", *fmt(F10, 'G'), "\n");
+	print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+	print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+	print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+	print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+	print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+	print("F0\t",  *fmt(F0, 'g'),  "\tF1\t",  *fmt(F1, 'g'), "\n");
+	print("F2\t",  *fmt(F2, 'g'),  "\tF3\t",  *fmt(F3, 'g'), "\n");
+	print("F4\t",  *fmt(F4, 'g'),  "\tF5\t",  *fmt(F5, 'g'), "\n");
+	print("F6\t",  *fmt(F6, 'g'),  "\tF7\t",  *fmt(F7, 'g'), "\n");
+	print("F8\t",  *fmt(F8, 'g'),  "\tF9\t",  *fmt(F9, 'g'), "\n");
+	print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+	print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+	print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+	print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+	print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+	print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+	print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+	print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+	print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+	print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+	print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn regs()				// print all registers
+{
+	spr();
+	gpr();
+}
+
+defn pstop(pid)
+{
+	local l;
+	local pc;
+
+	pc = *PC;
+
+	print(pid,": ", reason(*TBR), "\t");
+	print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+	if notes then {
+		if notes[0] != "sys: breakpoint" then {
+			print("Notes pending:\n");
+			l = notes;
+			while l do {
+				print("\t", head l, "\n");
+				l = tail l;
+			}
+		}
+	}
+}
+
+aggr Ureg
+{
+	'U' 0 r0;
+	{
+	'U' 4 sp;
+	'U' 4 usp;
+	'U' 4 r1;
+	};
+	'U' 8 r2;
+	'U' 12 r3;
+	'U' 16 r4;
+	'U' 20 r5;
+	'U' 24 r6;
+	'U' 28 r7;
+	'U' 32 r8;
+	'U' 36 r9;
+	'U' 40 r10;
+	'U' 44 r11;
+	'U' 48 r12;
+	'U' 52 r13;
+	'U' 56 r14;
+	'U' 60 r15;
+	'U' 64 r16;
+	'U' 68 r17;
+	'U' 72 r18;
+	'U' 76 r19;
+	'U' 80 r20;
+	'U' 84 r21;
+	'U' 88 r22;
+	'U' 92 r23;
+	'U' 96 r24;
+	'U' 100 r25;
+	'U' 104 r26;
+	'U' 108 r27;
+	'U' 112 r28;
+	'U' 116 r29;
+	'U' 120 r30;
+	'U' 124 r31;
+	'U' 128 y;
+	'U' 132 tbr;
+	'U' 136 psr;
+	'U' 140 npc;
+	'U' 144 pc;
+	'U' 148 pad;
+};
+
+defn
+Ureg(addr) {
+	complex Ureg addr;
+	print("	r0	", addr.r0, "\n");
+	print("	sp	", addr.sp, "\n");
+	print("	r2	", addr.r2, "\n");
+	print("	r3	", addr.r3, "\n");
+	print("	r4	", addr.r4, "\n");
+	print("	r5	", addr.r5, "\n");
+	print("	r6	", addr.r6, "\n");
+	print("	r7	", addr.r7, "\n");
+	print("	r8	", addr.r8, "\n");
+	print("	r9	", addr.r9, "\n");
+	print("	r10	", addr.r10, "\n");
+	print("	r11	", addr.r11, "\n");
+	print("	r12	", addr.r12, "\n");
+	print("	r13	", addr.r13, "\n");
+	print("	r14	", addr.r14, "\n");
+	print("	r15	", addr.r15, "\n");
+	print("	r16	", addr.r16, "\n");
+	print("	r17	", addr.r17, "\n");
+	print("	r18	", addr.r18, "\n");
+	print("	r19	", addr.r19, "\n");
+	print("	r20	", addr.r20, "\n");
+	print("	r21	", addr.r21, "\n");
+	print("	r22	", addr.r22, "\n");
+	print("	r23	", addr.r23, "\n");
+	print("	r24	", addr.r24, "\n");
+	print("	r25	", addr.r25, "\n");
+	print("	r26	", addr.r26, "\n");
+	print("	r27	", addr.r27, "\n");
+	print("	r28	", addr.r28, "\n");
+	print("	r29	", addr.r29, "\n");
+	print("	r30	", addr.r30, "\n");
+	print("	r31	", addr.r31, "\n");
+	print("	y	", addr.y, "\n");
+	print("	tbr	", addr.tbr, "\n");
+	print("	psr	", addr.psr, "\n");
+	print("	npc	", addr.npc, "\n");
+	print("	pc	", addr.pc, "\n");
+	print("	pad	", addr.pad, "\n");
+};
+
+defn linkreg(addr)
+{
+	complex Ureg addr;
+	return addr.r15\X;
+}
+
+print("/sys/lib/acid/sparc");
--- /dev/null
+++ b/lib/convcs/big5
@@ -1,0 +1,1 @@
+ ,、。.・;:?!︰…‥﹐﹑﹒·﹔﹕﹖﹗︲–︱—︳�︴﹏()︵︶{}︷︸〔〕︹︺【】︻︼《》︽︾〈〉︿﹀「」﹁﹂『』﹃﹄﹙﹚﹛﹜﹝﹞‘’“”〝〞‵′#&*※§〃○●△▲◎☆★◇◆□■▽▼㊣℅‾�_�﹉﹊﹍﹎﹋﹌#&*+-×÷±√<>=≤≥≠∞≒≡﹢﹣﹤﹥﹦∼∩∪⊥∠∟⊿㏒㏑∫∮∵∴♀♂♁☉↑↓←→↖↗↙↘∥∣��/\$¥〒¢£%@℃℉$%@㏕㎜㎝㎞㏎㎡㎎㎏㏄°兙兛兞兝兡兣嗧瓩糎▁▂▃▄▅▆▇█▏▎▍▌▋▊▉┼┴┬┤├▔─│▕┌┐└┘╭╮╰╯═╞╪╡◢◣◥◤╱╲╳0123456789ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ〡〢〣〤〥〦〧〨〩�卄�ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ˙ˉˊˇˋ���������������������������������������������������������������一乙丁七乃九了二人儿入八几刀刁力匕十卜又三下丈上丫丸凡久么也乞于亡兀刃勺千叉口土士夕大女子孑孓寸小尢尸山川工己已巳巾干廾弋弓才丑丐不中丰丹之尹予云井互五亢仁什仃仆仇仍今介仄元允內六兮公冗凶分切刈勻勾勿化匹午升卅卞厄友及反壬天夫太夭孔少尤尺屯巴幻廿弔引心戈戶手扎支文斗斤方日曰月木欠止歹毋比毛氏水火爪父爻片牙牛犬王丙世丕且丘主乍乏乎以付仔仕他仗代令仙仞充兄冉冊冬凹出凸刊加功包匆北匝仟半卉卡占卯卮去可古右召叮叩叨叼司叵叫另只史叱台句叭叻四囚外央失奴奶孕它尼巨巧左市布平幼弁弘弗必戊打扔扒扑斥旦朮本未末札正母民氐永汁汀氾犯玄玉瓜瓦甘生用甩田由甲申疋白皮皿目矛矢石示禾穴立丞丟乒乓乩亙交亦亥仿伉伙伊伕伍伐休伏仲件任仰仳份企伋光兇兆先全共再冰列刑划刎刖劣匈匡匠印危吉吏同吊吐吁吋各向名合吃后吆吒因回囝圳地在圭圬圯圩夙多夷夸妄奸妃好她如妁字存宇守宅安寺尖屹州帆并年式弛忙忖戎戌戍成扣扛托收早旨旬旭曲曳有朽朴朱朵次此死氖汝汗汙江池汐汕污汛汍汎灰牟牝百竹米糸缶羊羽老考而耒耳聿肉肋肌臣自至臼舌舛舟艮色艾虫血行衣西阡串亨位住佇佗佞伴佛何估佐佑伽伺伸佃佔似但佣作你伯低伶余佝佈佚兌克免兵冶冷別判利刪刨劫助努劬匣即卵吝吭吞吾否呎吧呆呃吳呈呂君吩告吹吻吸吮吵吶吠吼呀吱含吟听囪困囤囫坊坑址坍均坎圾坐坏圻壯夾妝妒妨妞妣妙妖妍妤妓妊妥孝孜孚孛完宋宏尬局屁尿尾岐岑岔岌巫希序庇床廷弄弟彤形彷役忘忌志忍忱快忸忪戒我抄抗抖技扶抉扭把扼找批扳抒扯折扮投抓抑抆改攻攸旱更束李杏材村杜杖杞杉杆杠杓杗步每求汞沙沁沈沉沅沛汪決沐汰沌汨沖沒汽沃汲汾汴沆汶沍沔沘沂灶灼災灸牢牡牠狄狂玖甬甫男甸皂盯矣私秀禿究系罕肖肓肝肘肛肚育良芒芋芍見角言谷豆豕貝赤走足身車辛辰迂迆迅迄巡邑邢邪邦那酉釆里防阮阱阪阬並乖乳事些亞享京佯依侍佳使佬供例來侃佰併侈佩佻侖佾侏侑佺兔兒兕兩具其典冽函刻券刷刺到刮制剁劾劻卒協卓卑卦卷卸卹取叔受味呵咖呸咕咀呻呷咄咒咆呼咐呱呶和咚呢周咋命咎固垃坷坪坩坡坦坤坼夜奉奇奈奄奔妾妻委妹妮姑姆姐姍始姓姊妯妳姒姅孟孤季宗定官宜宙宛尚屈居屆岷岡岸岩岫岱岳帘帚帖帕帛帑幸庚店府底庖延弦弧弩往征彿彼忝忠忽念忿怏怔怯怵怖怪怕怡性怩怫怛或戕房戾所承拉拌拄抿拂抹拒招披拓拔拋拈抨抽押拐拙拇
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/charsets
@@ -1,0 +1,225 @@
+iso_8859-1:1987=iso-8859-1
+iso-ir-100=iso-8859-1
+iso_8859-1=iso-8859-1
+8859_1=iso-8859-1	# botched alias
+iso8859-1=iso-8859-1		# commonly seen non IANA alias
+iso8859_1=iso-8859-1		# lookup should probably map _ to -
+latin1=iso-8859-1
+iso-latin-1=iso-8859-1
+l1=iso-8859-1
+ibm819=iso-8859-1
+cp819=iso-8859-1
+iso-8859-1=
+	desc=Latin-1
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-1.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-1.cp
+
+iso_8859-2:1987=iso-8859-2
+iso-ir-101=iso-8859-2
+iso_8859-2=iso-8859-2
+latin2=iso-8859-2
+l2=iso-8859-2
+iso-8859-2=
+	desc=Latin-2
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-2.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-2.cp
+
+iso_8859-3:1988=iso-8859-3
+iso-ir-109=iso-8859-3
+iso_8859-3=iso-8859-3
+latin3=iso-8859-3
+l3=iso-8859-3
+iso-8859-3=
+	desc=Latin-3
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-3.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-3.cp
+
+iso_8859-4:1988=iso-8859-4
+iso-ir-110=iso-8859-4
+iso_8859-4=iso-8859-4
+latin4=iso-8859-4
+l4=iso-8859-4
+iso-8859-4=
+	desc=Latin-4
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-4.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-4.cp
+
+iso_8859-5:1988=iso-8859-5
+iso-ir-144=iso-8859-5
+iso_8859-5=iso-8859-5
+cyrillic=iso-8859-5
+iso-8859-5=
+	desc='Part 5 (Cyrillic)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-5.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-5.cp
+
+iso_8859-6:1987=iso-8859-6
+iso-ir-127=iso-8859-6
+iso_8859-6=iso-8859-6
+ecma-114=iso-8859-6
+asmo-708=iso-8859-6
+arabic=iso-8859-6
+iso-8859-6=
+	desc='Part 6 (Arabic)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-6.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-6.cp
+
+iso_8859-7:1987=iso-8859-7
+iso-ir-126=iso-8859-7
+iso_8859-7=iso-8859-7
+elot_928=iso-8859-7
+ecma-118=iso-8859-7
+greek=iso-8859-7
+greek8=iso-8859-7
+iso-8859-7=
+	desc='Part 7 (Greek)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-7.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-7.cp
+
+iso_8859-8:1988=iso-8859-8
+iso-ir-138=iso-8859-8
+iso_8859-8=iso-8859-8
+hebrew=iso-8859-8
+iso-8859-8=
+	desc='Part 8 (Hebrew)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-8.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-8.cp
+
+iso_8859-9:1989=iso-8859-9
+iso-ir-148=iso-8859-9
+iso_8859-9=iso-8859-9
+latin5=iso-8859-9
+l5=iso-8859-9
+iso-8859-9=
+	desc=Latin-5
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-9.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-9.cp
+
+iso-ir-157=iso-8859-10
+l6=iso-8859-10
+iso_8859-10:1992=iso-8859-10
+latin6=iso-8859-10
+iso-8859-10=
+	# originally from dkuug.dk:i18n/charmaps/ISO_8859-10:1993
+	desc=Latin-6
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-10.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-10.cp
+
+l9-iso-8859-15
+latin9=iso-8859-15
+iso-8859-15=
+	desc=Latin-9
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/iso-8859-15.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/iso-8859-15.cp
+
+# Traditional Chinese
+big5=
+	desc='Big 5 (HKU)'
+	stob=/dis/lib/convcs/big5_stob.dis
+	btos=/dis/lib/convcs/big5_btos.dis
+
+# UTF-8
+ascii=utf-8
+us-ascii=utf-8
+utf8=utf-8	# commonly seen non IANA alias
+utf-8=
+	desc='Unicode UTF-8'
+	stob=/dis/lib/convcs/utf8_stob.dis
+	btos=/dis/lib/convcs/utf8_btos.dis
+
+utf16=utf-16
+utf-16=
+	desc='Unicode UTF-16'
+	btos=/dis/lib/convcs/utf16_btos.dis
+	stob=/dis/lib/convcs/utf16_stob.dis
+
+utf16le=utf-16le
+utf-16le=
+	desc='Unicode UTF-16 little endian'
+	btos=/dis/lib/convcs/utf16_btos.dis arg=le
+	stob=/dis/lib/convcs/utf16_stob.dis arg=le
+
+utf16be=utf-16be
+utf-16be=
+	desc='Unicode UTF-16 big endian'
+	btos=/dis/lib/convcs/utf16_btos.dis arg=be
+	stob=/dis/lib/convcs/utf16_stob.dis arg=be
+
+# UTF-7
+#utf-7=
+#	desc='Unicode UTF-7'
+#	stob=/dis/lib/convcs/utf7_stob.dis
+#	btos=/dis/lib/convcs/utf7_btos.dis
+
+
+cp437=ibm437
+437=ibm437
+ibm437=
+	# originally from jhelling@cs.ruu.nl (Jeroen Hellingman)
+	desc='IBM PC: CP 437'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/ibm437.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/ibm437.cp
+
+cp850=ibm850
+850=ibm850
+ibm850=
+	# originally from jhelling@cs.ruu.nl (Jeroen Hellingman)
+	desc='IBM PS/2: CP 850'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/ibm850.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/ibm850.cp
+
+cp866=ibm866
+866=ibm866
+ibm866=
+	desc='Russian MS-DOS CP 866'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/ibm866.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/ibm866.cp
+
+windows-1250=
+	desc='MS Windows CP 1250 (Central Europe)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/windows-1250.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/windows-1250.cp
+
+windows-1251=
+	desc='MS Windows CP 1251 (Cyrillic)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/windows-1251.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/windows-1251.cp
+
+windows-1252=
+	desc='MS Windows CP 1252 (Latin 1)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/windows-1252.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/windows-1252.cp
+
+koi8-r=
+	desc='KOI8-R (RFC1489)'
+	stob=/dis/lib/convcs/cp_stob.dis	arg=/lib/convcs/koi8-r.cp
+	btos=/dis/lib/convcs/cp_btos.dis	arg=/lib/convcs/koi8-r.cp
+
+gb_2312-80=gb2312
+iso-ir-58=gb2312
+chinese=gb2312
+gb2312=
+	desc="Chinese mixed one byte"
+	btos=/dis/lib/convcs/gb2312_btos.dis
+
+
+x-euc-jp=euc-jp	# often seen non-IANA alias
+euc-jp=
+	desc="Japanese Extended UNIX Code"
+	btos=/dis/lib/convcs/euc-jp_btos.dis
+
+cp932=windows-31j
+windows-31j=
+	desc="MS-Windows Japanese (cp932)"
+	btos=/dis/lib/convcs/cp932_btos.dis	arg=cp932
+
+ms_kanji=shift_jis
+x-sjis=shift_jis		# often seen non-IANA alias
+shift_jis=
+	desc="Shift-JIS Japanese",
+	btos=/dis/lib/convcs/cp932_btos.dis	arg=shiftjis
+
+# special converter for raw 8bit data that has been converted to utf-8
+8bit=
+	desc="raw 8-bit data"
+	stob=/dis/lib/convcs/8bit_stob.dis
--- /dev/null
+++ b/lib/convcs/cp932
@@ -1,0 +1,1 @@
+ 、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\~∥|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】+-±×�÷=≠<>≦≧∞∴♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓�����������∈∋⊆⊇⊂⊃∪∩��������∧∨¬⇒⇔∀∃�����������∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬�������ʼn♯♭♪†‡¶����◯���������������0123456789�������ABCDEFGHIJKLMNOPQRSTUVWXYZ�������abcdefghijklmnopqrstuvwxyz����ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん�����������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミ�ムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ��������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω��������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмн�опрстуфхцчшщъыьэюя�������������─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂��������������������������������������������������������������①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ�㍉㌔㌢㍍㌘㌧㌃㌶㍑㍗㌍㌦㌣㌫㍊㌻㎜㎝㎞㎎㎏㏄㎡��������㍻�〝〟№㏍℡㊤㊥㊦㊧㊨㈱㈲㈹㍾㍽㍼≒≡∫∮∑√⊥∠∟⊿∵∩∪�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������亜唖娃阿哀愛挨姶逢葵茜穐悪握渥旭葦芦鯵梓圧斡扱宛姐虻飴絢綾鮎或粟袷安庵按暗案闇鞍杏以伊位依偉囲夷委威尉惟意慰易椅為畏異移維緯胃萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭院陰隠韻吋右宇烏羽迂雨卯鵜窺丑碓臼渦嘘唄欝蔚鰻姥厩浦瓜閏噂云運雲荏餌叡営嬰影映曳栄永泳洩瑛盈穎頴英衛詠鋭液疫益駅悦謁越閲榎厭円�園堰奄宴延怨掩援沿演炎焔煙燕猿縁艶苑薗遠鉛鴛塩於汚甥凹央奥往応押旺横欧殴王翁襖鴬鴎黄岡沖荻億屋憶臆桶牡乙俺卸恩温穏音下化仮何伽価佳加可嘉夏嫁家寡科暇果架歌河火珂禍禾稼箇花苛茄荷華菓蝦課嘩貨迦過霞蚊俄峨我牙画臥芽蛾賀雅餓駕介会解回塊壊廻快怪悔恢懐戒拐改魁晦械海灰界皆絵芥蟹開階貝凱劾外咳害崖慨概涯碍蓋街該鎧骸浬馨蛙垣柿蛎鈎劃嚇各廓拡撹格核殻獲確穫覚角赫較郭閣隔革学岳楽額顎掛笠樫�橿梶鰍潟割喝恰括活渇滑葛褐轄且鰹叶椛
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/gb2312
@@ -1,0 +1,1 @@
+����������������������������������������������������������������������������������������������������� 、。・ˉˇ¨〃々―〜∥…‘’“”〔〕〈〉《》「」『』〖〗【】±×÷∶∧∨∑∏∪∩∈∷√⊥∥∠⌒⊙∫∮≡≌≈∽∝≠≮≯≤≥∞∵∴♂♀°′″℃$¤¢£‰§№☆★○●◎◇◆□■△▲※→←↑↓〓����������������������⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇①②③④⑤⑥⑦⑧⑨⑩��㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩��ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ��������!"#¥%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ̄������ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん�����������������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ��������������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω��������������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмнопрстуфхцчшщъыьэюя�������������������āáǎàēéěèīíǐìōóǒòūúǔùǖǘǚǜüê����������ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ������������������������������─━│┃┄┅┆┇┈┉┊┋┌┍┎┏┐┑┒┓└┕┖┗┘┙┚┛├┝┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿╀╁╂╃╄╅╆╇╈╉╊╋��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
\ No newline at end of file
binary files /dev/null b/lib/convcs/ibm437.cp differ
binary files /dev/null b/lib/convcs/ibm850.cp differ
binary files /dev/null b/lib/convcs/ibm866.cp differ
binary files /dev/null b/lib/convcs/iso-8859-1.cp differ
binary files /dev/null b/lib/convcs/iso-8859-10.cp differ
binary files /dev/null b/lib/convcs/iso-8859-15.cp differ
binary files /dev/null b/lib/convcs/iso-8859-2.cp differ
binary files /dev/null b/lib/convcs/iso-8859-3.cp differ
binary files /dev/null b/lib/convcs/iso-8859-4.cp differ
binary files /dev/null b/lib/convcs/iso-8859-5.cp differ
binary files /dev/null b/lib/convcs/iso-8859-6.cp differ
binary files /dev/null b/lib/convcs/iso-8859-7.cp differ
binary files /dev/null b/lib/convcs/iso-8859-8.cp differ
binary files /dev/null b/lib/convcs/iso-8859-9.cp differ
--- /dev/null
+++ b/lib/convcs/jisx0201kana
@@ -1,0 +1,1 @@
+。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/jisx0208-1997
@@ -1,0 +1,1 @@
+ 、。,.・:;?!゛゜´`¨^ ̄_ヽヾゝゞ〃仝々〆〇ー―‐/\〜‖|…‥‘’“”()〔〕[]{}〈〉《》「」『』【】+−±×÷=≠<>≦≧∞∴♂♀°′″℃¥$¢£%#&*@§☆★○●◎◇◆□■△▲▽▼※〒→←↑↓〓�����������∈∋⊆⊇⊂⊃∪∩��������∧∨¬⇒⇔∀∃�����������∠⊥⌒∂∇≡≒≪≫√∽∝∵∫∬�������ʼn♯♭♪†‡¶����◯���������������0123456789�������ABCDEFGHIJKLMNOPQRSTUVWXYZ������abcdefghijklmnopqrstuvwxyz����ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをん�����������ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶ��������ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ��������αβγδεζηθικλμνξοπρστυφχψω��������������������������������������АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ���������������абвгдеёжзийклмнопрстуфхцчшщъыьэюя�������������─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������
\ No newline at end of file
--- /dev/null
+++ b/lib/convcs/jisx0212
@@ -1,0 +1,1 @@
+������������������������������������������������������������������������������������������������������������˘ˇ¸˙˝¯˛˚~΄΅��������¡¦¿��������������������������������������ºª©®™¤№�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������ΆΈΉΊΪ�Ό�ΎΫ�Ώ����άέήίϊΐόςύϋΰώ�����������������������������������ЂЃЄЅІЇЈЉЊЋЌЎЏ�����������������������������������ђѓєѕіїјљњћќўџ����������������������������������������������������������������������������������������������ÆĐ�Ħ�IJ�ŁĿ�ŊØŒ�ŦÞ����������������æđðħıijĸłŀʼnŋøœßŧþ����������������������������������������������ÁÀÄÂĂǍĀĄÅÃĆĈČÇĊĎÉÈËÊĚĖĒĘ�ĜĞĢĠĤÍÌÏÎǏİĪĮĨĴĶĹĽĻŃŇŅÑÓÒÖÔǑŐŌÕŔŘŖŚŜŠŞŤŢÚÙÜÛŬǓŰŪŲŮŨǗǛǙǕŴÝŸŶŹŽŻ�������áàäâăǎāąåãćĉčçċďéèëêěėēęǵĝğ�ġĥíìïîǐ�īįĩĵķĺľļńňņñóòöôǒőōõŕřŗśŝšşťţúùüûŭǔűūųůũǘǜǚǖŵýÿŷźžż�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������丂丄丅丌丒丟丣两丨丫丮丯丰丵乀乁乄乇乑乚乜乣乨乩乴乵乹乿亍亖亗亝亯亹仃仐仚仛仠仡仢仨
\ No newline at end of file
binary files /dev/null b/lib/convcs/koi8-r.cp differ
binary files /dev/null b/lib/convcs/windows-1250.cp differ
binary files /dev/null b/lib/convcs/windows-1251.cp differ
binary files /dev/null b/lib/convcs/windows-1252.cp differ
--- /dev/null
+++ b/lib/ebook/default.css
@@ -1,0 +1,116 @@
+body {
+	margin: 1em;
+	font-family: serif;
+	background: white;
+	color: black;
+}
+
+h1, h2, h3, h4, h5, h6, p, ul, ol, dir, menu, div,
+dt, dd, address, blockquote, pre, br, hr, form, dl {
+	display: block;
+}
+
+b, strong, i, em, cite, var, tt, code, kbd, samp,
+img, span {
+	display: inline;
+}
+
+li {
+	display: inline;
+}
+
+h1, h2, h3, h4 {
+	margin-top: 1em;
+	margin-bottom: 1em;
+}
+
+h5, h6 {
+	margin-top: 1em;
+}
+
+h1 {
+	text-align: center;
+}
+
+h1, h2, h4, h6 {
+	font-weight: bold;
+}
+
+h3, h5 {
+	font-style: italic;
+}
+
+h1 {
+	font-size: xx-large;
+}
+
+h2 {
+	font-size: x-large;
+}
+
+h3 {
+	font-size: large;
+}
+
+b, strong {
+	font-weight: bold
+}
+
+i, cite, em, var, address, blockquote {
+	font-style: italic
+}
+
+pre, tt, code, kbd, samp {
+	font-family: monospace
+}
+
+pre {
+	white-space: pre
+}
+
+address {
+	margin-left: 3em
+}
+
+blockquote {
+	margin-left: 2em;
+	margin-right: 2em
+}
+
+ul, dir {
+	list-style: disc
+}
+ol {
+	list-style: decimal
+}
+
+menu {
+	margin: 0
+}
+
+li {
+	margin-left: 1em
+}
+
+dt {
+	margin-bottom: 0
+}
+
+dd {
+	margin-top: 0;
+	margin-left: 1em
+}
+
+hr {
+	border-top: solid
+}
+
+a {
+	color: blue;
+	text-decoration: underline
+}
+
+p {
+	margin-top: 1em;
+	margin-bottom: 1em
+}
--- /dev/null
+++ b/lib/ebooks/devils/A.html
@@ -1,0 +1,586 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+    "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&rsquo;s Dictionary: A</title>
+</head>
+
+<body lang="en-us">
+
+<h1>A</h1>
+
+<p class="entry"><span class="def">abasement,</span> <span class="pos">n.</span> A decent and customary
+mental attitude in the presence of wealth of power. Peculiarly appropriate in an employee when addressing
+an employer.</p>
+   
+<p class="entry"><span class="def">abatis,</span> <span class="pos">n.</span> Rubbish in front of a fort,
+to prevent the rubbish outside from molesting the rubbish inside.</p>
+
+<p class="entry" id="abdication"><span class="def">abdication,</span> <span class="pos">n.</span> An act
+whereby a sovereign attests his sense of the high temperature of the throne.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="po">Poor Isabella&rsquo;s Dead, whose abdication</p>
+<p class="po">Set all tongues wagging in the Spanish nation.</p>
+<p class="po">For that performance &rsquo;twere unfair to scold her:</p>
+<p class="po">She wisely left a throne too hot to hold her.</p>
+<p class="po">To History she&rsquo;ll be no royal riddle&mdash;</p>
+<p class="po">Merely a plain parched pea that jumped the griddle.</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">abdomen,</span> <span class="pos">n.</span> The temple of the god
+Stomach, in whose worship, with sacrificial rights, all true men engage. From women this ancient faith commands but a
+stammering assent. They sometimes minister at the altar in a half-hearted and ineffective way, but true reverence
+for the one deity that men really adore they know not. If woman had a free hand in the world&rsquo;s
+marketing the race would become graminivorous.</p>
+
+<p class="entry"><span class="def">ability,</span> <span class="pos">n.</span> The natural equipment to accomplish
+some small part of the meaner ambitions distinguishing able men from dead ones. In the last analysis ability is commonly
+found to consist mainly in a high degree of solemnity. Perhaps, however, this impressive quality is
+rightly appraised; it is no easy task to be solemn.</p>
+            
+<p class="entry"><span class="def">abnormal,</span> <span class="pos">adj.</span> Not conforming to
+standard. In matters of thought and conduct, to be independent is to be abnormal, to be abnormal is to
+be detested. Wherefore the lexicographer adviseth a striving toward the straiter resemblance of the
+Average Man than he hath to himself. Whoso attaineth thereto shall have peace, the prospect of death
+and the hope of Hell.</p>
+
+<p class="entry"><span class="def">aboriginies,</span>  <span class="pos">n.</span> Persons of little worth found             
+cumbering the soil of a newly discovered country. They soon cease to cumber; they fertilize.</p>
+             
+<p class="entry" id="abracadabra"><span class="def">abracadabra.</span></p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">By <i>Abracadabra</i> we signify<br />
+<span class="ind1">An infinite number of things.</span><br />
+&rsquo;Tis the answer to What? and How? and Why?<br />
+And Whence? and Whither?&mdash;a word whereby<br />
+<span class="ind1">The Truth (with the comfort it brings)</span><br />
+Is open to all who grope in night,<br />
+Crying for Wisdom&rsquo;s holy light.</p>
+</div>
+
+<div class="stanza">
+<p class="poem">Whether the word is a verb or a noun<br />
+<span class="ind1">Is knowledge beyond my reach.</span><br />
+I only know that &rsquo;tis handed down.<br />
+<span class="ind3">From sage to sage,</span><br />
+<span class="ind3">From age to age&mdash;</span><br />
+<span class="ind1">An immortal part of speech!</span></p>
+</div>
+
+<div class="stanza">
+<p class="poem">Of an ancient man the tale is told<br />
+That he lived to be ten centuries old,<br />
+<span class="ind1">In a cave on a mountain side.</span><br />
+<span class="ind1">(True, he finally died.)</span><br />
+The fame of his wisdom filled the land,<br />
+For his head was bald, and you&rsquo;ll understand<br />
+<span class="ind1">His beard was long and white</span><br />
+<span class="ind1">And his eyes uncommonly bright.</span></p>
+</div>
+
+<div class="stanza">
+<p class="poem">Philosophers gathered from far and near<br />
+To sit at his feat and hear and hear,<br />
+<span class="ind3">Though he never was heard</span><br />
+<span class="ind3">To utter a word</span><br />
+<span class="ind1">But &ldquo;<i>Abracadabra</i>, abracadab,</span><br />
+<span class="ind3">Abracada, abracad,</span><br />
+<span class="ind1">Abraca, abrac, abra, ab!&rdquo;</span><br />
+<span class="ind3">&rsquo;Twas all he had,</span><br />
+&rsquo;Twas all they wanted to hear, and each<br />
+Made copious notes of the mystical speech,<br />
+<span class="ind3">Which they published next&mdash;</span><br />
+<span class="ind3">A trickle of text</span><br />
+In the meadow of commentary.<br />
+<span class="ind1">Mighty big books were these,</span><br />
+<span class="ind1">In a number, as leaves of trees;</span><br />
+In learning, remarkably&mdash;very!</p>
+</div>
+
+<div class="stanza">
+<p class="poem"><span class="ind3">He&rsquo;s dead,</span><br />
+<span class="ind3">As I said,</span><br />
+And the books of the sages have perished,<br />
+But his wisdom is sacredly cherished.<br />
+In <i>Abracadabra</i> it solemnly rings,<br />
+Like an ancient bell that forever swings.<br />
+<span class="poind3">O, I love to hear</span><br />
+<span class="poind3">That word make clear</span><br />
+Humanity&rsquo;s General Sense of Things.</p>
+<p class="citepoet">Jamrach Holobom.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">abridge,</span> <span class="pos">v.t.</span> To shorten.</p>
+                 
+<p class="quote">When in the course of human events it becomes necessary for people to abridge their
+king, a decent respect for the opinions of mankind requires that they should declare the 
+causes which impel them to the separation.&mdash;<i>Oliver Cromwell</i></p>
+                  
+<p class="entry"><span class="def">abrupt,</span> <span class="pos">adj.</span> Sudden, without
+ceremony, like the arrival of a cannon-shot and the departure of the soldier whose interests are most
+affected by it. Dr. Samuel Johnson beautifully said of another author&rsquo;s ideas that they were]
+&ldquo;concatenated without abruption.&rdquo;</p>
+                   
+<p class="entry" id="abscond"><span class="def">abscond,</span> <span class="pos">v.i.</span> To &ldquo;move
+in a mysterious way,&rdquo; commonly with the property of another.</p>
+ 
+<blockquote>
+<div class="stanza">
+<p class="poem">Spring beckons!&nbsp;&nbsp;&nbsp;All things to the call respond;<br />
+The trees are leaving and cashiers abscond.</p>
+<p class="citepoet">Phela Orm.</p>
+</div>
+</blockquote>
+  
+<p class="entry" id="absent"><span class="def">absent,</span> <span class="pos">adj.</span> Peculiarly
+exposed to the tooth of detraction; vilifed; hopelessly in the wrong; superseded in the consideration
+and affection of another.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">To men a man is but a mind. Who cares<br />
+What face he carries or what form he wears?<br />
+But woman&rsquo;s body is the woman. O,<br />
+Stay thou, my sweetheart, and do never go,<br />
+But heed the warning words the sage hath said:<br />
+A woman absent is a woman dead.<br />
+</p>
+<p class="citepoet">Jogo Tyree.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">absentee,</span><span class="pos">n.</span> A person
+with an <a href="I.html#income">income</a> who has had the forethought to remove himself from the sphere of exaction.</p>
+
+<p class="entry"><span class="def">absolute,</span> <span class="pos">adj.</span> Independent, irresponsible.
+An absolute monarchy is one in which the sovereign does as he pleases so long as he pleases the assassins.
+Not many absolute monarchies are left, most of them having been replaced by limited monarchies, where the
+sovereign&rsquo;s power for evil (and for good) is greatly curtailed, and by republics, which are
+governed by chance.</p>                           
+                           
+<p class="entry" id="abstainer"><span class="def">abstainer,</span> <span class="pos">n.</span> A weak
+person who yields to the temptation of denying himself a <a href="P.html#pleasure">pleasure</a>. A total abstainer is one who abstains
+from everything but abstention, and especially from inactivity in the affairs of others.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">Said a man to a crapulent youth: &ldquo;I thought<br />
+<span class="ind1">You a total abstainer, my son.&rdquo;</span><br />
+&ldquo;So I am, so I am,&rdquo; said the scrapgrace caught&mdash;<br />
+<span class="ind1">&ldquo;But not, sir, a bigoted one.&rdquo;</span></p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">absurdity,</span> <span class="pos">n.</span> A statement or belief
+manifestly inconsistent with one&rsquo;s own opinion.</p>
+
+<p class="entry"><span class="def">academe,</span> <span class="pos">n.</span> An ancient school where
+morality and philosophy were taught.</p>
+
+<p class="entry"><span class="def">academy,</span> <span class="pos">n.</span>
+(from academe). A modern school where football is taught.</p>
+                          
+<p class="entry"><span class="def">accident,</span> <span class="pos">n.</span> An inevitable
+occurrence due to the action of immutable natural laws.</p>
+                         
+<p class="entry"><span class="def">accomplice,</span> <span class="pos">n.</span> One associated
+with another in a crime, having guilty knowledge and complicity, as an <a href="L.html#lawyer">attorney</a> who defends a
+criminal, knowing him guilty. This view of the attorney&rsquo;s position in the matter has not hitherto
+commanded the assent of attorneys, no one having offered them a fee for assenting.</p>
+
+<p class="entry"><span class="def">accord,</span> <span class="pos">n.</span> Harmony.</p>
+
+<p class="entry"><span class="def">accordion,</span> <span class="pos">n.</span> An instrument
+in harmony with the sentiments of an assassin.</p>
+
+<p class="entry" id="accountability"><span class="def">accountability,</span> <span class="pos">n.</span> The
+mother of caution.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">&ldquo;My accountability, bear in mind,&rdquo;<br />
+<span class="ind1">Said the Grand Vizier: &ldquo;Yes, yes,&rdquo;</span><br />
+Said the Shah: &ldquo;I do&mdash;&rsquo;tis the only kind<br />
+<span class="ind1">Of ability you possess.&rdquo;</span></p>
+<p class="citepoet">Joram Tate.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">accuse,</span> <span class="pos">v.t.</span> To affirm another&rsquo;s guilt
+or unworth; most commonly as a justification of ourselves for having wronged him.</p>
+                         
+<p class="entry"><span class="def">acephalous,</span> <span class="pos">adj.</span> In the surprising condition of the
+Crusader who absently pulled at his forelock some hours after a Saracen scimitar had, unconsciously to him,
+passed through his neck, as related by de Joinville.</p>
+
+<p class="entry"><span class="def">achievement,</span> <span class="pos">n.</span> The death of endeavor
+and the birth of disgust.</p>
+
+<p class="entry"><span class="def">acknowledge,</span> <span class="pos">v.t.</span> To confess.
+Acknowledgement of one another&rsquo;s faults is the highest duty imposed by our love of
+<a href="T.html#truth">truth</a>.</p>
+
+<p class="entry"><span class="def">acquaintance,</span> <span class="pos">n.</span> A person whom we
+know well enough to borrow from, but not well enough to lend to. A degree of friendship called slight when
+its object is poor or obscure, and intimate when he is <a href="R.html#rich">rich</a> or
+<a href="F.html#famous">famous.</a></p>
+
+<p class="entry"><span class="def">actually,</span> <span class="pos">adv.</span> Perhaps; possibly.</p>
+
+<p class="entry"><span class="def">adage,</span> <span class="pos">n.</span> Boned wisdom for weak teeth.</p>
+
+<p class="entry"><span class="def">adamant,</span> <span class="pos">n.</span> A mineral frequently found
+beneath a corset. Soluble in solicitate of gold.</p>
+
+<p class="entry"><span class="def">adder,</span> <span class="pos">n.</span> A species of snake. So called
+from its habit of adding <a href="F.html#funeral">funeral</a> outlays to the other expenses of living.</p>
+
+<p class="entry"><span class="def">adherent,</span> <span class="pos">n.</span> A follower who has not
+yet obtained all that he expects to get.</p>
+
+<p class="entry"><span class="def">administration,</span> <span class="pos">n.</span> An ingenious
+abstraction in <a href="P.html#politics">politics</a>, designed to receive the kicks and cuffs due to
+the premier or <a href="P.html#president">president</a>. A man of straw, proof against bad-egging
+and dead-catting.</p>
+                         
+<p class="entry"><span class="def">admiral,</span> <span class="pos">n.</span> That part of a war-ship
+which does the talking while the figure-head does the thinking.</p>
+
+<p class="entry"><span class="def">admiration,</span> <span class="pos">n.</span> Our polite recognition of
+another&rsquo;s resemblance to ourselves.</p>
+
+<p class="entry" id="admonition"><span class="def">admonition,</span> <span class="pos">n.</span> Gentle
+reproof, as with a meat-axe. Friendly warning.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">Consigned by way of admonition,<br />
+His soul foever to perdition.</p>
+<p class="citepoet">Judibras.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">adore,</span> <span class="pos">v.t.</span> To venerate expectantly.</p>
+
+<p class="entry" id="advice"><span class="def">advice,</span> <span class="pos">n.</span> The smallest
+current coin.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">&ldquo;The man was in such deep distress,&rdquo;<br />
+Said Tom, &ldquo;that I could do no less<br />
+Than give him good advice.&rdquo; Said Jim:<br />
+&ldquo;If less could have been done for him<br />
+I know you well enough, my son,<br />
+To know that&rsquo;s what you would have done.&rdquo;</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">affianced,</span> <span class="pos">pp.</span> Fitted with an
+ankle-ring for the ball-and-chain.</p>
+
+<p class="entry"><span class="def">affliction,</span> <span class="pos">n.</span> An acclimatizing
+process preparing the <a href="S.html#soul">soul</a> for another and bitter world.</p>
+
+<p class="entry"><span class="def">African,</span> <span class="pos">n.</span> A nigger that votes our way.</p>
+
+<p class="entry"><span class="def">age,</span> <span class="pos">n.</span> That period of life in which
+we compound for the vices that we still cherish by reviling those that we have no longer the
+enterprise to commit.</p>
+
+<p class="entry"><span class="def">agitator,</span> <span class="pos">n.</span> A statesman who shakes
+the fruit trees of his neighbors&mdash;to dislodge the worms.</p>
+
+<p class="entry" id="aim"><span class="def">aim,</span> <span class="pos">n.</span> The task we set our wishes to.</p>                          
+
+<blockquote>
+<div class="stanza">
+<p class="poem">&ldquo;Cheer up! Have you no aim in life?&rdquo;<br />
+<span class="ind1">She tenderly inquired.</span><br />
+&ldquo;An aim? Well, no, I haven&rsquo;t, wife;<br />
+<span class="ind1">The fact is&mdash;I have fired.&rdquo;</span></p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">air,</span> <span class="pos">n.</span> A nutritious substance supplied by a                         
+bountiful Providence for the fattening of the poor.</p>
+
+<p class="entry"><span class="def">alderman,</span> <span class="pos">n.</span> An ingenious criminal
+who covers his secret thieving with a pretence of open marauding.</p>
+
+<p class="entry"><span class="def">alien,</span> <span class="pos">n.</span> An American sovereign
+in his probationary state.</p>
+
+<p class="entry" id="allah"><span class="def">Allah,</span> <span class="pos">n.</span> The Mahometan
+Supreme Being, as distinguished from the Christian, Jewish, and so forth.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">Allah&rsquo;s good laws I faithfully have kept,<br />
+And ever for the sins of man have wept;<br />
+<span class="ind1">And sometimes kneeling in the temple I</span><br />
+Have reverently crossed my hands and slept.</p>
+<p class="citepoet">Junker Barlow.</p>
+</div>
+</blockquote>
+
+<p class="entry" id="allegiance"><span class="def">allegiance,</span> <span class="pos">n.</span> </p>                          
+
+<blockquote>
+<div class="stanza">
+<p class="poem">This thing Allegiance, as I suppose,<br />
+Is a ring fitted in the subject&rsquo;s nose,<br />
+Whereby that organ is kept rightly pointed<br />
+To smell the sweetness of the Lord&rsquo;s anointed.</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">alliance,</span> <span class="pos">n.</span> In international politics,
+the union of two thieves who have their hands so deeply inserted in each other&rsquo;s pockets that
+they cannot separately plunder a third.</p>
+
+<p class="entry"><span class="def">alligator,</span> <span class="pos">n.</span> The crocodile of
+America, superior in every detail to the crocodile of the effete monarchies of the Old World.
+Herodotus says the Indus is, with one exception, the only river that produces crocodiles, but they
+appear to have gone West and grown up with the other rivers. From the notches on his back the
+alligator is called a sawrian.</p>
+
+<p class="entry" id="alone"><span class="def">alone,</span> <span class="pos">adj.</span> In bad company.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">In contact, lo! the flint and steel,<br />
+By spark and flame, the thought reveal<br />
+That he the metal, she the stone,<br />
+Had cherished secretly alone.</p>
+</div>
+</blockquote>
+
+<p class="entry" id="altar"><span class="def">altar,</span> <span class="pos">n.</span> The place whereupon
+the priest formerly raveled out the small intestine of the sacrificial victim for purposes of divination and
+cooked its flesh for the gods. The word is now seldom used, except with reference to the sacrifice of
+their liberty and peace by a male and a female tool.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">They stood before the altar and supplied<br />
+The fire themselves in which their fat was fried.<br />
+In vain the sacrifice!&mdash;no god will claim<br />
+An offering burnt with an unholy flame.</p>
+<p class="citepoet">M. P. Nopput.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">ambidextrous,</span> <span class="pos">adj.</span> Able to pick
+with equal skill a right-hand pocket or a left.</p>
+
+<p class="entry"><span class="def">ambition,</span> <span class="pos">n.</span> An overmastering
+desire to be vilified by enemies while living and made ridiculous by friends when dead.</p>
+
+<p class="entry"><span class="def">amnesty,</span> <span class="pos">n.</span> The state&rsquo;s
+magnanimity to those offenders whom it would be too expensive to punish.</p>
+
+<p class="entry" id="anoint"><span class="def">anoint,</span> <span class="pos">v.t.</span> To grease a
+<a href="K.html#king">king</a> or other great functionary already sufficiently slippery.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">As sovereigns are anointed by the priesthood,<br />
+So pigs to lead the populace are greased good.</p>
+<p class="citepoet">Judibras.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">antipathy,</span> <span class="pos">n.</span> The sentiment
+inspired by one&rsquo;s friend&rsquo;s friend.</p>
+
+<p class="entry" id="aphorism"><span class="def">aphorism,</span> <span class="pos">n.</span> Predigested wisdom.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">The flabby wine-skin of his brain<br />
+Yields to some pathologic strain,<br />
+And voids from its unstored abysm<br />
+The driblet of an aphorism.</p>
+<p class="citepoet">&nbsp;&ldquo;The Mad Philosopher,&rdquo;<span style="font-style: normal"> 1697.</span></p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">apologize,</span> <span class="pos">v.i.</span> To lay the foundation for a future
+offence.</p>
+
+<p class="entry"><span class="def">apostate,</span> <span class="pos">n.</span> A leech who, having
+penetrated the shell of a turtle only to find that the creature has long been dead, deems it expedient
+to form a new attachment to a fresh turtle.</p>
+
+<p class="entry" id="apothecary"><span class="def">apothecary,</span> <span class="pos">n.</span> The
+physician&rsquo;s accomplice, undertaker&rsquo;s benefactor and grave worm&rsquo;s provider.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">When Jove sent blessings to all men that are,<br />
+And Mercury conveyed them in a jar,<br />
+That friend of tricksters introduced by stealth<br />
+Disease for the apothecary&rsquo;s health,<br />
+Whose gratitude impelled him to proclaim:<br />
+&ldquo;My deadliest drug shall bear my patron&rsquo;s name!&rdquo;</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">appeal,</span> <span class="pos">v.t.</span> In <a href="L.html#law">law</a>,
+to put the dice into the box for another throw.</p>
+
+<p class="entry"><span class="def">appetite,</span> <span class="pos">n.</span> An instinct thoughtfully
+implanted by Providence as a solution to the labor question.</p>
+
+<p class="entry"><span class="def">applause,</span> <span class="pos">n.</span> The echo of
+a <a href="P.html#platitude">platitude</a>.</p>
+
+<p class="entry"><span class="def">April Fool,</span> <span class="pos">n.</span> The March
+<a href="F.html#fool">fool</a> with another month added to his folly.</p>
+
+<p class="entry" id="archbishop"><span class="def">archbishop,</span> <span class="pos">n.</span> An ecclesiastical
+dignitary one point holier than a bishop.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">If I were a jolly archbishop,<br />
+On Fridays I&rsquo;d eat all the fish up&mdash;<br />
+Salmon and flounders and smelts;<br />
+On other days everything else.<br />
+</p>
+<p class="citepoet">Jodo Rem.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">architect,</span> <span class="pos">n.</span> One who drafts a plan
+of your <a href="H.html#house">house</a>, and plans a draft of your money.</p>
+
+<p class="entry"><span class="def">ardor,</span> <span class="pos">n.</span> The quality that distinguishes
+love without knowledge.</p>
+
+<p class="entry"><span class="def">arena,</span> <span class="pos">n.</span> In politics, an imaginary rat-pit
+in which the statesman wrestles with his record.</p>
+
+<p class="entry"><span class="def">aristocracy,</span> <span class="pos">n.</span> Government by the
+best men. (In this sense the word is obsolete; so is that kind of government.) Fellows that wear downy hats
+and clean shirts&mdash;guilty of education and suspected of bank accounts.</p>
+
+<p class="entry"><span class="def">armor,</span> <span class="pos">n.</span> The kind of clothing worn
+by a man whose tailor is a blacksmith.</p>
+
+<p class="entry"><span class="def">arrayed,</span> <span class="pos">pp.</span> Drawn up and given an
+orderly disposition, as a rioter hanged to a lamppost.</p>
+
+<p class="entry"><span class="def">arrest,</span> <span class="pos">v.t.</span> Formally to detain one
+accused of unusualness.</p>
+
+<p class="quote">God made the world in six days and was arrested on the
+seventh.&mdash;<i>The Unauthorized Version</i></p>
+
+<p class="entry" id="arsenic"><span class="def">arsenic,</span> <span class="pos">n.</span> A kind of
+cosmetic greatly affected by the ladies, whom it greatly affects in turn.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">&ldquo;Eat arsenic? Yes, all you get,&rdquo;<br />
+<span class="ind1">Consenting, he did speak up;</span><br />
+&ldquo;&rsquo;Tis better you should eat it, pet,<br />
+<span class="ind1">Than put it in my teacup.&rdquo;</span></p>
+<p class="citepoet">Joel Huck.</p>
+</div>
+</blockquote>
+                        
+<p class="entry" id="art"><span class="def">art,</span> <span class="pos">n.</span> This word has no
+definition. Its origin is related as follows by the ingenious Father Gassalasca Jape, S. J.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">One day a wag&mdash;what would the wretch be at?&mdash;<br />
+Shifted a letter of the cipher RAT,<br />
+And said it was a god&rsquo;s name! Straight arose<br />
+Fantastic priests and postulants (with shows,<br />
+And mysteries, and mummeries, and hymns,<br />
+And disputations dire that lamed their limbs)<br />
+To serve his temple and maintain the fires,<br />
+Expound the law, manipulate the wires.<br />
+Amazed, the populace that rites attend,<br />
+Believe whate&rsquo;er they cannot comprehend,<br />
+And, inly edified to learn that two<br />
+Half-hairs joined so and so (as Art can do)<br />
+Have sweeter values and a grace more fit<br />
+Than Nature&rsquo;s hairs that never have been split,<br />
+Bring cates and wines for sacrificial feasts,<br />
+And sell their garments to support the priests.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">artlessness,</span> <span class="pos">n.</span> A certain engaging
+quality to which women attain by long study and severe practice upon the admiring <a href="M.html#male">male</a>,
+who is pleased to fancy it resembles the candid simplicity of his young.</p>
+                          
+<p class="entry"><span class="def">asperse,</span> <span class="pos">v.t.</span> Maliciously to ascribe
+to another vicious actions which one has not had the temptation and opportunity to commit.</p>
+
+<p class="entry" id="ass"><span class="def">ass,</span> <span class="pos">n.</span> A public singer with
+a good voice but no ear. In Virginia City, Nevada, he is called the Washoe Canary, in Dakota, the Senator,
+and everywhere the Donkey. The animal is widely and variously celebrated in the literature, <a href="#art">art</a>
+and <a href="R.html#religion">religion</a> of every age and country; no other so engages and fires the human
+imagination as this noble vertebrate. Indeed, it is doubted by some (Ramasilus, <span xml:lang="la"><i>lib. II.,
+De Clem.</i></span>, and C. Stantatus, <span xml:lang="la"><i>De Temperamente</i></span>)
+if it is not a god; and as such we know it was worshiped by the Etruscans, and, if we may believe Macrobious,
+by the Cupasians also. Of the only two animals admitted into the Mahometan Paradise along with the souls of
+men, the ass that carried Balaam is one, the <a href="D.html#dog">dog</a> of the Seven Sleepers the other.
+This is no small distinction. From what has been written about this beast might be compiled a library of great
+splendor and magnitude, rivalling that of the Shakespearean cult, and that which clusters about the Bible. It
+may be said, generally, that all literature is more or less Asinine.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem">&ldquo;Hail, holy Ass!&rdquo;the quiring angels sing;<br />
+&ldquo;Priest of Unreason, and of Discords King!&rdquo;<br />
+Great co-Creator, let Thy glory shine:<br />
+God made all else, the Mule, the Mule is thine!&rdquo;</p>
+<p class="citepoet">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">auctioneer,</span> <span class="pos">n.</span> The man who proclaims
+with a hammer that he has picked a pocket with his tongue.</p>
+
+<p class="entry"><span class="def">Australia,</span> <span class="pos">n.</span> A country lying in the
+South Sea, whose industrial and commercial development has been unspeakably retarded by an unfortunate
+dispute among geographers as to whether it is a continent or an island.</p>
+
+<p class="entry"><span class="def">avernus,</span> <span class="pos">n.</span> The lake by which the
+ancients entered the infernal regions. The fact that access to the infernal regions was obtained by a lake
+is believed by the learned Marcus Ansello Scrutator to have suggested the <a href="C.html#christian">Christian</a>
+rite of <a href="B.html#baptism">baptism</a> by immersion. This, however, has been shown by Lactantius to be
+an error.</p>
+
+<blockquote>
+<div class="stanza">
+<p class="poem" xml:lang="la"><i>Facilis descensus Averni,</i><br />
+<span class="ind1">The poet remarks; and the sense</span><br />
+Of it is that when down-hill I turn I<br />
+<span class="ind1">Will get more of punches than pence.</span></p>
+<p class="citepoet">Jehal Dai Lupe.</p>
+</div>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/A.html.i
@@ -1,0 +1,53 @@
+15 pages
+size 400 552
+length 28806
+400 2 11 body html
+0
+1984 2 43 body html
+73
+3135 2 59 body html
+331
+3135 2 59 body html
+874
+7242 2 149 body html
+142
+9706 2 197 body html
+0
+11725 2 234 body html
+56
+14044 2 279 body html
+43
+16224 2 326 body html
+22
+17952 2 363 body html
+43
+19588 2 399 body html
+90
+21737 2 450 body html
+0
+23824 2 495 body html
+0
+25445 2 532 body html
+56
+27720 2 565 body html
+22
+abracadabra 1
+arsenic 11
+anoint 9
+allah 7
+aphorism 10
+absent 3
+aim 7
+abstainer 4
+abscond 3
+art 12
+ass 13
+advice 6
+apothecary 10
+altar 9
+admonition 6
+alone 8
+archbishop 11
+abdication 0
+accountability 5
+allegiance 8
--- /dev/null
+++ b/lib/ebooks/devils/B.html
@@ -1,0 +1,398 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+    "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&rsquo;s Dictionary: B</title>
+</head>
+
+<body lang="en-US">
+
+<h1>B</h1>
+
+<p class="entry"><span class="def">Baal,</span> <span class="pos">n.</span> An old deity formerly
+much worshiped under various names.
+As Baal he was popular with the Phoenicians; as Belus or Bel he had the honor to
+be served by the priest Berosus, who wrote the famous account of the Deluge;
+as Babel he had a tower partly erected to his glory on the Plain of Shinar. From Babel comes our English word
+&ldquo;babble.&rdquo; Under whatever name worshiped,
+Baal is the Sun-god. As Beelzebub he is the god of flies, which are begotten
+of the sun&rsquo;s rays on the stagnant water. In Physicia Baal is still
+worshiped as Bolus, and as Belly he is adored and served with abundant
+sacrifice by the priests of Guttledom.</p>
+
+<p class="entry"><span class="def">babe</span> or <span class="def">baby,</span> <span class="pos">n.</span> A
+misshapen creature of no particular age, sex, or
+condition, chiefly remarkable for the violence of the sympathies and
+antipathies it excites in others, itself without sentiment or emotion. There
+have been famous babes; for example, little Moses, from whose adventure in the
+bulrushes the Egyptian hierophants of seven centuries before doubtless derived
+their idle tale of the child Osiris being preserved on a floating lotus leaf.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="poind3">Ere babes were invented</p>
+<p class="poind3">The girls were contended.</p>
+<p class="poind3">Now man is tormented</p>
+<p class="po">Until to buy babes he has squandered</p>
+<p class="po">His money. And so I have pondered</p>
+<p class="poind3">This thing, and thought may be</p>
+<p class="poind3">&rsquo;T were better that Baby</p>
+<p class="po">The First had been eagled or condored.</p>
+<p class="citeauth">Ro Amil.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">Bacchus,</span> <span class="pos">n.</span> A convenient
+deity invented by the ancients as an excuse for getting drunk.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">Is public worship, then, a sin,</p>
+<p class="poind2">That for devotions paid to Bacchus</p>
+<p class="po">The lictors dare to run us in,</p>
+<p class="poind2">And resolutely thump and whack us?</p>
+<p class="citeauth">Jorace.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">back,</span> <span class="pos">n.</span> That part of your
+friend which it is your privilege to contemplate in your adversity.</p>
+
+<p class="entry"><span class="def">backbite,</span> <span class="pos">v.t.</span> To speak of a man as
+you find him when he can&rsquo;t find you.</p>
+
+<p class="entry"><span class="def">bait,</span> <span class="pos">n.</span> A preparation
+that renders the hook more palatable. The best kind is beauty.</p>
+
+<p id="baptism" class="entry"><span class="def">baptism,</span> <span class="pos">n.</span> A sacred rite of
+such efficacy that he who finds himself in heaven without having undergone it will be unhappy forever.
+It is performed with water in two ways by immersion, or plunging, and by aspersion, or sprinkling.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">But whether the plan of immersion</p>
+<p class="po">Is better than simple aspersion</p>
+<p class="poind1">Let those immersed</p>
+<p class="poind1">And those aspersed</p>
+<p class="po">Decide by the Authorized Version,</p>
+<p class="po">And by matching their agues tertian.</p>
+<p class="citeauth">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">barometer,</span> <span class="pos">n.</span> An ingenious
+instrument which indicates what kind of weather we are having.</p>
+
+<p class="entry"><span class="def">barrack,</span> <span class="pos">n.</span> A house in which
+soldiers enjoy a portion of that of which it is their business to deprive others.</p>
+
+<p class="entry"><span class="def">basilisk,</span> <span class="pos">n.</span> The cockatrice.
+A sort of serpent hatched form the egg of a cock. The basilisk had a bad eye, and its glance was
+fatal. Many infidels deny this creature&rsquo;s existence, but Semprello Aurator saw and handled one
+that had been blinded by lightning as a punishment for having fatally gazed on
+a lady of rank whom Jupiter loved. Juno afterward restored the reptile&rsquo;s
+sight and hid it in a cave. Nothing is so well attested by the ancients as
+the existence of the basilisk, but the cocks have stopped laying.</p>
+
+<p class="entry"><span class="def">bastinado,</span> <span class="pos">n.</span> The act of walking
+on wood without exertion.</p>
+
+<p class="entry"><span class="def">bath,</span> <span class="pos">n.</span> A kind of mystic ceremony
+substituted for religious worship, with what spiritual efficacy has not been determined.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">The man who taketh a steam bath</p>
+<p class="po">He loseth all the skin he hath,</p>
+<p class="po">And, for he&rsquo;s boiled a brilliant red,</p>
+<p class="po">Thinketh to cleanliness he&rsquo;s wed,</p>
+<p class="po">Forgetting that his lungs he&rsquo;s soiling</p>
+<p class="po">With dirty vapors of the boiling.</p>
+<p class="citeauth">Richard Gwow.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">battle,</span> <span class="pos">n.</span> A method of untying
+with the teeth of a political knot that would not yield to the tongue.</p>
+
+<p class="entry"><span class="def">beard,</span> <span class="pos">n.</span> The hair that is commonly
+cut off by those who justly execrate the absurd Chinese custom of shaving the head.</p>
+
+<p class="entry"><span class="def">beauty,</span> <span class="pos">n.</span> The power by which a woman
+charms a lover and terrifies a husband.</p>
+
+<p class="entry"><span class="def">befriend,</span> <span class="pos">v.t.</span> To make an ingrate.</p>
+
+<p class="entry" id="beg"><span class="def">beg,</span> <span class="pos">v.</span> To ask for something with
+an earnestness proportioned to the belief that it will not be given.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">Who is that, father?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">A mendicant, child,</p>
+<p class="po">Haggard, morose, and unaffable&mdash;wild!</p>
+<p class="po">See how he glares through the bars of his cell!</p>
+<p class="po">With Citizen Mendicant all is not well.</p>
+</div>
+
+<div class="stanza">
+<p class="po">Why did they put him there, father?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Because</p>
+<p class="po">Obeying his belly he struck at the laws.</p>
+</div>
+
+<div class="stanza">
+<p class="po">His belly?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Oh, well, he was starving, my boy&mdash;</p>
+<p class="po">A state in which, doubtless, there&rsquo;s little of joy.</p>
+<p class="po">No bite had he eaten for days, and his cry</p>
+<p class="po">Was &ldquo;Bread!&rdquo; ever &ldquo;Bread!&rdquo;</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">What&rsquo;s the matter with pie?</p>
+</div>
+
+<div class="stanza">
+<p class="po">With little to wear, he had nothing to sell;</p>
+<p class="po">To beg was unlawful&mdash;improper as well.</p>
+</div>
+
+<div class="stanza">
+<p class="po">Why didn&rsquo;t he work?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">He would even have done that,</p>
+<p class="po">But men said: &ldquo;Get out!&rdquo; and the State remarked:</p>
+<p class="po">&ldquo;Scat!&rdquo;</p>
+<p class="po">I mention these incidents merely to show</p>
+<p class="po">That the vengeance he took was uncommonly low.</p>
+<p class="po">Revenge, at the best, is the act of a Siou,</p>
+<p class="po">But for trifles&mdash;</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Pray what did bad Mendicant do?</p>
+</div>
+
+<div class="stanza">
+<p class="po">Stole two loaves of bread to replenish his lack</p>
+<p class="po">And tuck out the belly that clung to his back.</p>
+</div>
+
+<div class="stanza">
+<p class="po">Is that <i>all</i> father dear?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">There&rsquo;s little to tell:</p>
+<p class="po">They sent him to jail, and they&rsquo;ll send him to&mdash;well,</p>
+<p class="po">The company&rsquo;s better than here we can boast,</p>
+<p class="po">And there&rsquo;s&mdash;</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: center">Bread for the needy, dear father?</p>
+</div>
+
+<div class="stanza">
+<p class="po" style="text-align: right">Um&mdash;toast.</p>
+<p class="citeauth">Atka Mip.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">beggar,</span> <span class="pos">n.</span> One who has relied
+on the assistance of his friends.</p>
+
+<p class="entry"><span class="def">behavior,</span> <span class="pos">n.</span> Conduct, as determined,
+not by principle, but by breeding. The word seems to be somewhat loosely used in Dr. Jamrach Holobom&rsquo;s
+translation of the following lines from the <i>Dies Ir&aelig;</i>:</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<div xml:lang="la">
+<p class="poind2">Recordare, Jesu pie,</p>
+<p class="poind2">Quod sum causa tuae vi&aelig;.</p>
+<p class="poind2">Ne me perdas illa die.</p></div>
+</div>
+
+<div class="stanza">
+<p class="po">Pray remember, sacred Savior,</p>
+<p class="po">Whose the thoughtless hand that gave your</p>
+<p class="po">Death-blow. Pardon such behavior.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">Belladonna,</span> <span class="pos">n.</span> In Italian a beautiful
+lady; in English a deadly poison. A striking example of the essential identity of the two tongues.</p>
+
+<p class="entry"><span class="def">Benedictines,</span> <span class="pos">n.</span> An order of monks
+otherwise known as black friars.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">She thought it a crow, but it turn out to be</p>
+<p class="poind1">A monk of St. Benedict croaking a text.</p>
+<p class="po">&ldquo;Here&rsquo;s one of an order of cooks,&rdquo; said she&mdash;</p>
+<p class="poind1">&ldquo;Black friars in this world, fried black in the next.&rdquo;</p>
+<p class="citeauth">&ldquo;The Devil on Earth&rdquo; <span style="font-style: normal">(<i>London</i>, 1712.)</span></p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">benefactor,</span> <span class="pos">n.</span> One who makes
+heavy purchases of ingratitude, without, however, materially affecting the price, which is still within
+the means of all.</p>
+
+<p class="entry"><span class="def">Berenice&rsquo;s Hair,</span> <span class="pos">n.</span> A constellation
+(<span xml:lang="la"><i>Coma Berenices</i></span>) named in honor of one who sacrificed her hair to
+save her husband.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">Her locks an ancient lady gave</p>
+<p class="po">Her loving husband&rsquo;s life to save;</p>
+<p class="po">And men&mdash;they honored so the dame&mdash;</p>
+<p class="po">Upon some stars bestowed her name.</p>
+</div>
+
+<div class="stanza">
+<p class="po">But to our modern married fair,</p>
+<p class="po">Who&rsquo;d give their lords to save their hair,</p>
+<p class="po">No stellar recognition&rsquo;s given.</p>
+<p class="po">There are not stars enough in heaven.</p>
+<p class="citeauth">G. J.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">bigamy,</span> <span class="pos">n.</span> A mistake in taste
+for which the wisdom of the future will adjudge a punishment called trigamy.</p>
+
+<p class="entry"><span class="def">bigot,</span> <span class="pos">n.</span> One who is obstinately
+and zealously attached to an opinion that you do not entertain.</p>
+
+<p class="entry"><span class="def">billingsgate,</span> <span class="pos">n.</span> The invective of
+an opponent.</p>
+
+<p class="entry"><span class="def">birth,</span> <span class="pos">n.</span> The first and direst of
+all disasters. As to the nature of it there appears to be no uniformity. Castor and Pollux were born
+from the egg. Pallas came out of a skull. Galatea was once a block of stone. Peresilis, who wrote in
+the tenth century, avers that he grew up out of the ground where a priest had spilled holy water. It
+is known that Arimaxus was derived from a hole in the earth, made by a stroke of lightning. Leucomedon
+was the son of a cavern in Mount &AElig;tna, and I have myself seen a man come out of a wine cellar.</p>
+
+<p class="entry"><span class="def">blackguard,</span> <span class="pos">n.</span> A man whose qualities,
+prepared for display like a box of berries in a market&mdash;the fine ones on top&mdash;have been opened on the wrong
+side. An inverted gentleman.</p>
+
+<p class="entry"><span class="def">blank-verse,</span> <span class="pos">n.</span> Unrhymed iambic
+pentameters&mdash;the most difficult kind of English verse to write acceptably; a kind, therefore, much affected
+by those who cannot acceptably write any kind.</p>
+
+<p class="entry"><span class="def">body-snatcher,</span> <span class="pos">n.</span> A robber of grave-worms.
+One who supplies the young physicians with that with which the old physicians have supplied the undertaker.
+The hyena.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">&ldquo;One night,&rdquo; a doctor said, &ldquo;last fall,</p>
+<p class="po">I and my comrades, four in all,</p>
+<p class="poind1">When visiting a graveyard stood</p>
+<p class="po">Within the shadow of a wall.</p>
+</div>
+
+<div class="stanza">
+<p class="po">&ldquo;While waiting for the moon to sink</p>
+<p class="po">We saw a wild hyena slink</p>
+<p class="poind1">About a new-made grave, and then</p>
+<p class="po">Begin to excavate its brink!</p>
+</div>
+
+<div class="stanza">
+<p class="po">&ldquo;Shocked by the horrid act, we made</p>
+<p class="po">A sally from our ambuscade,</p>
+<p class="poind1">And, falling on the unholy beast,</p>
+<p class="po">Dispatched him with a pick and spade.&rdquo;</p>
+<p class="citeauth">Bettel K. Jhones.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">bondsman,</span> <span class="pos">n.</span> A fool who, having
+property of his own, undertakes to become responsible for that entrusted to another to a third.</p>
+
+<p class="indentpara">Philippe of Orleans wishing to appoint one of his favorites, a dissolute
+nobleman, to a high office, asked him what security he would be able to give. &ldquo;I need no
+bondsmen,&rdquo; he replied, &ldquo;for I can give you my word of honor.&rdquo; &ldquo;And
+pray what may be the value of that?&rdquo; inquired the amused Regent. &ldquo;Monsieur, it
+is worth its weight in gold.&rdquo;</p>
+
+<p class="entry"><span class="def">bore,</span> <span class="pos">n.</span> A person who talks
+when you wish him to listen.</p>
+
+<p class="entry"><span class="def">botany,</span> <span class="pos">n.</span> The science of      
+vegetables&mdash;those that are not good to eat, as well as those that are. It deals largely with
+their flowers, which are commonly badly designed, inartistic in color, and ill-smelling.</p>
+
+<p class="entry"><span class="def">bottle-nosed,</span> <span class="pos">adj.</span> Having a
+nose created in the image of its maker.</p>
+
+<p class="entry"><span class="def">boundary,</span> <span class="pos">n.</span> In political
+geography, an imaginary line between two nations, separating the imaginary rights of one from
+the imaginary rights of the other.</p>
+
+<p class="entry"><span class="def">bounty,</span> <span class="pos">n.</span> The liberality
+of one who has much, in permitting one who has nothing to get all that he can.</p>
+
+<p class="quote">A single swallow, it is said, devours ten millions of insects every year. The
+supplying of these insects I take to be a signal instance of the Creator&rsquo;s bounty in providing
+for the lives of His creatures.&mdash;<i>Henry Ward Beecher</i></p>
+
+<p class="entry"><span class="def">brahma,</span> <span class="pos">n.</span> He who created
+the Hindoos, who are preserved by Vishnu and destroyed by Siva&mdash;a rather neater division of labor
+than is found among the deities of some other nations. The Abracadabranese, for example, are created
+by Sin, maintained by Theft and destroyed by Folly. The priests of Brahma, like those of Abracadabranese,
+are holy and learned men who are never naughty.</p>
+
+<blockquote class="poem">
+<div class="stanza">
+<p class="po">O Brahma, thou rare old Divinity,</p>
+<p class="po">First Person of the Hindoo Trinity,</p>
+<p class="po">You sit there so calm and securely,</p>
+<p class="po">With feet folded up so demurely&mdash;</p>
+<p class="po">You&rsquo;re the First Person Singular, surely.</p>
+<p class="citeauth">Polydore Smith.</p>
+</div>
+</blockquote>
+
+<p class="entry"><span class="def">brain,</span> <span class="pos">n.</span> An apparatus with which
+we think what we think. That which distinguishes the man who is content to <i>be</i> something from
+the man who wishes to <i>do</i> something. A man of great wealth, or one who has been pitchforked
+into high station, has commonly such a headful of brain that his neighbors cannot keep their hats on.
+In our civilization, and under our republican form of government, brain is so highly honored that it is
+rewarded by exemption from the cares of office.</p>
+
+<p class="entry"><span class="def">brandy,</span> <span class="pos">n.</span> A cordial composed of
+one part thunder-and-lightning, one part remorse, two parts bloody murder, one part death-hell-and-the-grave
+and four parts clarified Satan. Dose, a headful all the time. Brandy is said by Dr. Johnson to be the drink of
+heroes. Only a hero will venture to drink it.</p>
+
+<p class="entry"><span class="def">bride,</span> <span class="pos">n.</span> A woman with a fine prospect
+of happiness behind her.</p>
+
+<p class="entry"><span class="def">brute,</span> <span class="pos">n.</span> See
+<a href="H.html#husband"><span class="def">husband</span></a>.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/B.html.i
@@ -1,0 +1,23 @@
+9 pages
+size 400 552
+length 18309
+400 2 11 body html
+0
+1681 2 34 body html
+117
+4008 2 89 body html
+0
+6365 2 132 body html
+0
+6365 2 132 body html
+547
+10201 2 245 body html
+13
+12195 2 289 body html
+90
+14590 2 335 body html
+0
+16688 2 368 body html
+13
+baptism 1
+beg 2
--- /dev/null
+++ b/lib/ebooks/devils/C.html
@@ -1,0 +1,528 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+ "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&rsquo;s Dictionary: C</title>
+</head>
+
+<body lang="en-us">
+
+<h1>C</h1>
+
+<p class="entry"><span class="def">Caaba,</span> <span class="pos">n.</span> A large stone
+presented by the archangel Gabriel to the patriarch Abraham, and preserved at Mecca. The
+patriarch had perhaps asked the archangel for bread.</p>
+
+<p class="entry"><span class="def">cabbage,</span> <span class="pos">n.</span> A familiar
+kitchen-garden vegetable about as large and wise as a man&rsquo;s head.</p>
+
+<p class="indentpara">The cabbage is so called from Cabagius, a prince who on ascending
+the throne issued a decree appointing a High Council of Empire consisting of the members of his
+predecessor&rsquo;s Ministry and the cabbages in the royal garden. When any of his Majesty&rsquo;s measures
+of state policy miscarried conspicuously it was gravely announced that several members
+of the High Council had been beheaded, and his murmuring subjects were appeased.</p>
+
+<p class="entry"><span class="def">calamity,</span> <span class="pos">n.</span> A more than commonly
+plain and unmistakable reminder that the affairs of this life are not of our own ordering. Calamities are
+of two kinds: misfortune to ourselves, and good fortune to others.</p>
+
+<p class="entry"><span class="def">callous,</span> <span class="pos">adj.</span> Gifted with great
+fortitude to bear the evils afflicting another.</p>
+
+<p class="indentpara">When Zeno was told that one of his enemies was no more he was observed to
+be deeply moved. &ldquo;What!&rdquo; said one of his disciples, &ldquo;you weep at the death of an
+enemy?&rdquo; &ldquo;Ah, &rsquo;tis true,&rdquo;
+replied the great Stoic; &ldquo;but you should see me smile at the death of a friend.&rdquo;</p>
+
+<p class="entry"><span class="def">calumnus,</span> <span class="pos">n.</span> A graduate of the School
+for Scandal.</p>
+ 
+<p class="entry"><span class="def">camel,</span> <span class="pos">n.</span> A quadruped (the <i>Splaypes
+humpidorsus</i>) of great value to the show business. There are two kinds of camels&mdash;the camel proper and
+the camel improper. It is the latter that is always exhibited.</p>
+
+<p class="entry"><span class="def">cannibal,</span> <span class="pos">n.</span> A gastronome of the old
+school who preserves the simple tastes and adheres to the natural diet of the pre-pork period.</p>
+
+<p class="entry"><span class="def">cannon,</span> <span class="pos">n.</span> An instrument employed
+in the rectification of national boundaries.</p>
+
+<p class="entry"><span class="def">canonicals,</span> <span class="pos">n.</span> The motley worm by
+Jesters of the Court of Heaven.</p>
+ 
+<p class="entry"><span class="def">capital,</span> <span class="pos">n.</span> The seat of misgovernment.
+That which provides the fire, the pot, the dinner, the table and the knife and fork for the anarchist; the
+part of the repast that himself supplies is the disgrace before meat. <i>Capital Punishment</i>, a penalty
+regarding the justice and expediency of which many worthy persons&mdash;including all the assassins&mdash;entertain
+grave misgivings.</p>
+
+<p class="entry" id="carmelite"><span class="def">carmelite,</span> <span class="pos">n.</span> A mendicant friar of
+the order of Mount Carmel.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">As Death was a-rising out one day,</p>
+<p class="po">Across Mount Camel he took his way,</p>
+<p class="poind1">Where he met a mendicant monk,</p>
+<p class="poind1">Some three or four quarters drunk,</p>
+<p class="po">With a holy leer and a pious grin,</p>
+<p class="po">Ragged and fat and as saucy as sin,</p>
+<p class="poind1">Who held out his hands and cried:</p>
+<p class="po">&ldquo;Give, give in Charity&rsquo;s name, I pray.</p>
+<p class="po">Give in the name of the Church. O give,</p>
+<p class="po">Give that her holy sons may live!&rdquo;</p>
+<p class="poind1">And Death replied,</p>
+<p class="poind1">Smiling long and wide:</p>
+<p class="poind1">&ldquo;I&rsquo;ll give, holy father, I&rsquo;ll give thee&mdash;a ride.&rdquo;</p>
+</td></tr>
+<tr><td class="poem">
+<p class="poind1">With a rattle and bang</p>
+<p class="poind1">Of his bones, he sprang</p>
+<p class="po">From his famous Pale Horse, with his spear;</p>
+<p class="poind1">By the neck and the foot</p>
+<p class="poind1">Seized the fellow, and put</p>
+<p class="po">Him astride with his face to the rear.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">The Monarch laughed loud with a sound that fell</p>
+<p class="po">Like clods on the coffin&rsquo;s sounding shell:</p>
+<p class="po">&ldquo;Ho, ho! A beggar on horseback, they say,</p>
+<p class="poind1">Will ride to the devil!&rdquo;&mdash;and thump</p>
+<p class="poind1">Fell the flat of his dart on the rump</p>
+<p class="po">Of the charger, which galloped away.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">Faster and faster and faster it flew,</p>
+<p class="po">Till the rocks and the flocks and the trees that grew</p>
+<p class="po">By the road were dim and blended and blue</p>
+<p class="poind1">To the wild, wild eyes</p>
+<p class="poind1">Of the rider&mdash;in size</p>
+</td></tr>
+<tr><td class="poem">
+<p class="poind1">Resembling a couple of blackberry pies.</p>
+<p class="po">Death laughed again, as a tomb might laugh</p>
+<p class="poind1">At a burial service spoiled,</p>
+<p class="poind1">And the mourners&rsquo; intentions foiled</p>
+<p class="poind1">By the body erecting</p>
+<p class="poind1">Its head and objecting</p>
+<p class="po">To further proceedings in its behalf.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="poind1">Resembling a couple of blackberry pies.</p>
+<p class="po">Death laughed again, as a tomb might laugh</p>
+<p class="poind1">At a burial service spoiled,</p>
+<p class="poind1">And the mourners&rsquo; intentions foiled</p>
+<p class="poind1">By the body erecting</p>
+<p class="poind1">Its head and objecting</p>
+<p class="po">To further proceedings in its behalf.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">Many a year and many a day</p>
+<p class="po">Have passed since these events away.</p>
+<p class="po">The monk has long been a dusty corse,</p>
+<p class="po">And Death has never recovered his horse.</p>
+<p class="poind1">For the friar got hold of its tail,</p>
+<p class="poind1">And steered it within the pale</p>
+<p class="po">Of the monastery gray,</p>
+<p class="po">Where the beast was stabled and fed</p>
+<p class="po">With barley and oil and bread</p>
+<p class="po">Till fatter it grew than the fattest friar,</p>
+<p class="po">And so in due course was appointed Prior.</p>
+<p class="citeauth">G. J.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">carnivorous,</span> <span class="pos">adj.</span> Addicted to the
+cruelty of devouring the timorous vegetarian, his heirs and assigns.</p>
+
+<p class="entry"><span class="def">cartesian,</span> <span class="pos">adj.</span> Relating to Descartes,
+a famous philosopher, author of the celebrated dictum, <span xml:lang="la"><i>Cogito ergo sum</i></span>&mdash;whereby
+he was pleased to suppose he demonstrated the reality of human existence. The dictum might be improved,
+however, thus: <i>Cogito cogito ergo cogito sum</i>&mdash;&ldquo;I think that I think, therefore I think that I am;&rdquo; as
+close an approach to certainty as any philosopher has yet made.</p>
+ 
+<p class="entry"><span class="def">cat,</span> <span class="pos">n.</span> A soft, indestructible automaton
+provided by nature to be kicked when things go wrong in the domestic circle.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">This is a dog,</p>
+<p class="poind1">This is a cat.</p>
+<p class="po">This is a frog,</p>
+<p class="poind1">This is a rat.</p>
+<p class="po">Run, dog, mew, cat.</p>
+<p class="po">Jump, frog, gnaw, rat.</p>
+<p class="citeauth">Elevenson.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">caviler,</span> <span class="pos">n.</span> A critic of our own work.</p>
+
+<p class="entry"><span class="def">cemetery,</span> <span class="pos">n.</span> An isolated suburban
+spot where mourners match lies, poets write at a target and stone-cutters spell for a wager. The
+inscriptions following will serve to illustrate the success attained in these Olympian games:</p>
+
+<p class="quote">His virtues were so conspicuous that his enemies, unable to overlook them, denied
+them, and his friends, to whose loose lives they were a rebuke, represented them as vices. They are
+here commemorated by his family, who shared them.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">In the earth we here prepare a</p>
+<p class="po">Place to lay our little Clara.</p>
+<p class="citepoet">Thomas M. and Mary Frazer</p>
+<p class="po">P.S.&mdash;Gabriel will raise her.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">centaur,</span> <span class="pos">n.</span> One of a race of
+persons who lived before the division of labor had been carried to such a pitch of differentiation, and
+who followed the primitive economic maxim, &ldquo;Every man his own horse.&rdquo; The best of the lot was Chiron,
+who to the wisdom and virtues of the horse added the fleetness of man. The scripture story of the head
+of John the Baptist on a charger shows that pagan myths have somewhat sophisticated sacred history.</p>
+
+<p class="entry"><span class="def">Cerberus,</span> <span class="pos">n.</span> The watch-dog of
+Hades, whose duty it was to guard the entrance&mdash;against whom or what does not clearly appear;
+everybody, sooner or later, had to go there, and nobody wanted to carry off the entrance. Cerberus
+is known to have had three heads, and some of the poets have credited him with as many as a hundred.
+Professor Graybill, whose clerky erudition and profound knowledge of Greek give his opinion great weight,
+has averaged all the estimates, and makes the number twenty-seven&mdash;a judgment that would be entirely
+conclusive is Professor Graybill had known (<i>a</i>) something about dogs, and (<i>b</i>) something about
+arithmetic.</p>
+ 
+<p class="entry"><span class="def">childhood,</span> <span class="pos">n.</span> The period of human
+life intermediate between the idiocy of infancy and the folly of youth&mdash;two removes from the sin of
+manhood and three from the remorse of age.</p>
+
+<p id="christian" class="entry"><span class="def">Christian,</span> <span class="pos">n.</span> One who believes that
+the New Testament is a divinely inspired book admirably suited to the spiritual needs of his neighbor. One
+who follows the teachings of Christ in so far as they are not inconsistent with a life of sin.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">I dreamed I stood upon a hill, and, lo!</p>
+<p class="po">The godly multitudes walked to and fro</p>
+<p class="po">Beneath, in Sabbath garments fitly clad,</p>
+<p class="po">With pious mien, appropriately sad,</p>
+<p class="po">While all the church bells made a solemn din&mdash;</p>
+<p class="po">A fire-alarm to those who lived in sin.</p>
+<p class="po">Then saw I gazing thoughtfully below,</p>
+<p class="po">With tranquil face, upon that holy show</p>
+<p class="po">A tall, spare figure in a robe of white,</p>
+<p class="po">Whose eyes diffused a melancholy light.</p>
+<p class="po">&ldquo;God keep you, strange,&rdquo; I exclaimed. &ldquo;You are</p>
+<p class="po">No doubt (your habit shows it) from afar;</p>
+<p class="po">And yet I entertain the hope that you,</p>
+<p class="po">Like these good people, are a Christian too.&rdquo;</p>
+<p class="po">He raised his eyes and with a look so stern</p>
+<p class="po">It made me with a thousand blushes burn</p>
+<p class="po">Replied&mdash;his manner with disdain was spiced:</p>
+<p class="po">&ldquo;What! I a Christian? No, indeed! I&rsquo;m Christ.&rdquo;</p>
+<p class="citeauth">G. J.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">circus,</span> <span class="pos">n.</span> A place where horses,
+ponies and elephants are permitted to see men, women and children acting the fool.</p>
+
+<p class="entry"><span class="def">clairvoyant,</span> <span class="pos">n.</span> A person, commonly
+a woman, who has the power of seeing that which is invisible to her patron, namely, that he is a blockhead.</p>
+
+<p class="entry"><span class="def">clarionet,</span> <span class="pos">n.</span> An instrument of torture
+operated by a person with cotton in his ears. There are two instruments that are worse than a clarionet&mdash;two
+clarionets.</p>
+
+<p class="entry"><span class="def">clergyman,</span> <span class="pos">n.</span> A man who undertakes
+the management of our spiritual affairs as a method of better his temporal ones.</p>
+
+<p class="entry"><span class="def">Clio,</span> <span class="pos">n.</span> One of the nine Muses. Clio&rsquo;s
+function was to preside over history&mdash;which she did with great dignity, many of the prominent citizens of
+Athens occupying seats on the platform, the meetings being addressed by Messrs. Xenophon, Herodotus and
+other popular speakers.</p>
+
+<p class="entry"><span class="def">clock,</span> <span class="pos">n.</span> A machine of great moral
+value to man, allaying his concern for the future by reminding him what a lot of time remains to him.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">A busy man complained one day:</p>
+<p class="po">&ldquo;I get no time!&rdquo; &ldquo;What&rsquo;s that you say?&rdquo;</p>
+<p class="po">Cried out his friend, a lazy quiz;</p>
+<p class="po">&ldquo;You have, sir, all the time there is.</p>
+<p class="po">There&rsquo;s plenty, too, and don&rsquo;t you doubt it&mdash;</p>
+<p class="po">We&rsquo;re never for an hour without it.&rdquo;</p>
+<p class="citeauth">Purzil Crofe.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">close-fisted,</span> <span class="pos">adj.</span> Unduly desirous
+of keeping that which many meritorious persons wish to obtain.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">&ldquo;Close-fisted Scotchman!&rdquo; Johnson cried</p>
+<p class="poind1">To thrifty J. Macpherson;</p>
+<p class="po">&ldquo;See me&mdash;I&rsquo;m ready to divide</p>
+<p class="poind1">With any worthy person.&rdquo;</p>
+<p class="po">Sad Jamie: &ldquo;That is very true&mdash;</p>
+<p class="poind1">The boast requires no backing;</p>
+<p class="po">And all are worthy, sir, to you,</p>
+<p class="poind1">Who have what you are lacking.&rdquo;</p>
+<p class="citeauth">Anita M. Bobe.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">c&oelig;nobite,</span> <span class="pos">n.</span> A man who piously
+shuts himself up to meditate upon the sin of wickedness; and to keep it fresh in his mind joins a brotherhood
+of awful examples.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">O C&oelig;nobite, O c&oelig;nobite,</p>
+<p class="poind1">Monastical gregarian,</p>
+<p class="po">You differ from the anchorite,</p>
+<p class="poind1">That solitudinarian:</p>
+<p class="po">With vollied prayers you wound Old Nick;</p>
+<p class="po">With dropping shots he makes him sick.</p>
+<p class="citeauth">Quincy Giles.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">comfort,</span> <span class="pos">n.</span> A state of mind
+produced by contemplation of a neighbor&rsquo;s uneasiness.</p>
+
+<p class="entry"><span class="def">commendation,</span> <span class="pos">n.</span> The tribute
+that we pay to achievements that resembles, but do not equal, our own.</p>
+
+<p class="entry"><span class="def">commerce,</span> <span class="pos">n.</span> A kind of
+transaction in which A plunders from B the goods of C, and for compensation B picks the pocket of D
+of money belonging to E.</p>
+
+<p class="entry"><span class="def">commonwealth,</span> <span class="pos">n.</span> An administrative
+entity operated by an incalculable multitude of political parasites, logically active but fortuitously efficient.</p>
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">This commonwealth&rsquo;s capitol&rsquo;s corridors view,</p>
+<p class="po">So thronged with a hungry and indolent crew</p>
+<p class="po">Of clerks, pages, porters and all attaches</p>
+<p class="po">Whom rascals appoint and the populace pays</p>
+<p class="po">That a cat cannot slip through the thicket of shins</p>
+<p class="po">Nor hear its own shriek for the noise of their chins.</p>
+<p class="po">On clerks and on pages, and porters, and all,</p>
+<p class="po">Misfortune attend and disaster befall!</p>
+<p class="po">May life be to them a succession of hurts;</p>
+<p class="po">May fleas by the bushel inhabit their shirts;</p>
+<p class="po">May aches and diseases encamp in their bones,</p>
+<p class="po">Their lungs full of tubercles, bladders of stones;</p>
+<p class="po">May microbes, bacilli, their tissues infest,</p>
+<p class="po">And tapeworms securely their bowels digest;</p>
+<p class="po">May corn-cobs be snared without hope in their hair,</p>
+<p class="po">And frequent impalement their pleasure impair.</p>
+<p class="po">Disturbed be their dreams by the awful discourse</p>
+<p class="po">Of audible sofas sepulchrally hoarse,</p>
+<p class="po">By chairs acrobatic and wavering floors&mdash;</p>
+<p class="po">The mattress that kicks and the pillow that snores!</p>
+<p class="po">Sons of cupidity, cradled in sin!</p>
+<p class="po">Your criminal ranks may the death angel thin,</p>
+<p class="po">Avenging the friend whom I couldn&rsquo;t work in.</p>
+<p class="citeauth">K. Q.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">compromise,</span> <span class="pos">n.</span> Such an adjustment
+of conflicting interests as gives each adversary the satisfaction of thinking he has got what he ought not
+to have, and is deprived of nothing except what was justly his due.</p>
+
+<p class="entry"><span class="def">compulsion,</span> <span class="pos">n.</span> The eloquence of power.</p>
+
+<p class="entry"><span class="def">condole,</span> <span class="pos">v.i.</span> To show that bereavement
+is a smaller evil than sympathy.</p>
+
+<p class="entry"><span class="def">confidant,</span> <span class="def">confidante,</span> <span class="pos">n.</span> One
+entrusted by A with the secrets of B, confided by <i>him </i>to C.</p>
+ 
+<p class="entry"><span class="def">congratulation,</span> <span class="pos">n.</span> The civility of envy.</p> 
+ 
+<p class="entry"><span class="def">congress,</span> <span class="pos">n.</span> A body of men who meet to repeal laws.</p> 
+ 
+<p class="entry"><span class="def">connoisseur,</span> <span class="pos">n.</span> A specialist who knows everything 
+about something and nothing about anything else.</p> 
+ 
+<p class="indentpara">An old wine-bibber having been smashed in a railway collision, some wine was pouted on his lips to 
+revive him. &ldquo;Pauillac, 1873,&rdquo; he murmured and died.</p> 
+ 
+<p class="entry"><span class="def">conservative,</span> <span class="pos">n.</span> A statesman who is enamored of 
+existing evils, as distinguished from the Liberal, who wishes to replace them 
+with others.</p> 
+ 
+<p class="entry"><span class="def">consolation,</span> <span class="pos">n.</span> The knowledge that a better man is 
+more unfortunate than yourself.</p> 
+ 
+<p class="entry"><span class="def">consul,</span> <span class="pos">n.</span> In American politics, a person who having 
+failed to secure and office from the people is given one by the Administration 
+on condition that he leave the country.</p> 
+ 
+<p class="entry"><span class="def">consult,</span> <span class="pos">v.i.</span> To seek another&rsquo;s disapproval of a course already decided on.</p> 
+ 
+<p class="entry"><span class="def">contempt,</span> <span class="pos">n.</span> The feeling of a prudent man for an enemy who is too formidable safely to be opposed.</p> 
+ 
+<p class="entry"><span class="def">controversy,</span> <span class="pos">n.</span> A battle in which spittle or ink replaces the injurious cannon-ball and the inconsiderate bayonet.</p> 
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">In controversy with the facile tongue&mdash;</p>
+<p class="po">That bloodless warfare of the old and young&mdash;</p>
+<p class="po">So seek your adversary to engage</p>
+<p class="po">That on himself he shall exhaust his rage,</p>
+<p class="po">And, like a snake that&rsquo;s fastened to the ground,</p>
+<p class="po">With his own fangs inflict the fatal wound.</p>
+<p class="po">You ask me how this miracle is done?</p>
+<p class="po">Adopt his own opinions, one by one,</p>
+<p class="po">And taunt him to refute them; in his wrath</p>
+<p class="po">He&rsquo;ll sweep them pitilessly from his path.</p>
+<p class="po">Advance then gently all you wish to prove,</p>
+<p class="po">Each proposition prefaced with, &ldquo;As you&rsquo;ve</p>
+<p class="po">So well remarked,&rdquo; or, &ldquo;As you wisely say,</p>
+<p class="po">And I cannot dispute,&rdquo; or, &ldquo;By the way,</p>
+<p class="po">This view of it which, better far expressed,</p>
+<p class="po">Runs through your argument.&rdquo; Then leave the rest</p>
+<p class="po">To him, secure that he&rsquo;ll perform his trust</p>
+<p class="po">And prove your views intelligent and just.</p>
+<p class="citeauth">Conmore Apel Brune.</p> 
+</td></tr>
+</table>
+  
+<p class="entry"><span class="def">convent,</span> <span class="pos">n.</span> A place of retirement for woman who wish for leisure to meditate upon the vice of idleness.</p> 
+ 
+<p class="entry"><span class="def">conversation,</span> <span class="pos">n.</span> A fair to the display of the minor 
+mental commodities, each exhibitor being too intent upon the arrangement of his 
+own wares to observe those of his neighbor.</p> 
+ 
+<p class="entry"><span class="def">coronation,</span> <span class="pos">n.</span> The ceremony of investing a 
+sovereign with the outward and visible signs of his divine right to be blown 
+skyhigh with a dynamite bomb.</p> 
+ 
+<p class="entry"><span class="def">corporal,</span> <span class="pos">n.</span> A man who occupies the lowest rung of the military ladder.</p> 
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">Fiercely the battle raged and, sad to tell,</p>
+<p class="po">Our corporal heroically fell!</p>
+<p class="po">Fame from her height looked down upon the brawl</p>
+<p class="po">And said: &ldquo;He hadn&rsquo;t very far to fall.&rdquo;</p>
+<p class="citeauth">Giacomo Smith.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">corporation,</span> <span class="pos">n.</span> An ingenious device for obtaining individual profit without individual responsibility.</p> 
+ 
+<p class="entry"><span class="def">Corsair,</span> <span class="pos">n.</span> A politician of the seas.</p> 
+ 
+<p class="entry"><span class="def">court fool,</span> <span class="pos">n.</span> The plaintiff.</p> 
+
+<p class="entry"><span class="def">coward,</span> <span class="pos">n.</span> One who in a perilous emergency thinks with his legs.</p> 
+
+<p class="entry"><span class="def">crayfish,</span> n. A small crustacean very much resembling the lobster, but less indigestible.</p> 
+
+<p class="quote">In this small fish I take it that human wisdom is admirably figured and symbolized; for whereas 
+the crayfish doth move only backward, and can have only retrospection, seeing 
+naught but the perils already passed, so the wisdom of man doth not enable him 
+to avoid the follies that beset his course, but only to apprehend their nature afterward.&mdash;<i>Sir James Merivale</i></p> 
+
+<p class="entry"><span class="def">creditor,</span> <span class="pos">n.</span> One of a tribe of savages dwelling beyond the Financial Straits and dreaded for their desolating incursions.</p> 
+
+<p class="entry"><span class="def">Cremona,</span> <span class="pos">n.</span> A high-priced violin made in Connecticut.</p> 
+
+<p class="entry"><span class="def">critic,</span> <span class="pos">n.</span> A person who boasts himself hard to please 
+because nobody tries to please him.</p> 
+
+<table class="poem">
+<tr><td class="poem">
+<p class="po">There is a land of pure delight,</p>
+<p class="poind1">Beyond the Jordan&rsquo;s flood,</p>
+<p class="po">Where saints, apparelled all in white,</p>
+<p class="poind1">Fling back the critic&rsquo;s mud.</p>
+</td></tr>
+<tr><td class="poem">
+<p class="po">And as he legs it through the skies,</p>
+<p class="poind1">His pelt a sable hue,</p>
+<p class="po">He sorrows sore to recognize</p>
+<p class="poind1">The missiles that he threw.</p>
+<p class="citeauth">Orrin Goof.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def">cross,</span> <span class="pos">n.</span> An ancient religious symbol erroneously 
+supposed to owe its significance to the most solemn event in the history of 
+Christianity, but really antedating it by thousands of years. By many it has been believed to be identical 
+with the <span xml:lang="la"><i>crux ansata</i></span> of the 
+ancient phallic worship, but it has been traced even beyond all that we know of 
+that, to the rites of primitive peoples. We have to-day the White Cross as a symbol of chastity, and the Red 
+Cross as a badge of benevolent neutrality in war. Having in mind the former, the reverend Father Gassalasca Jape 
+smites the lyre to the effect following:</p> 
+ 
+  
+<table class="poem">
+<tr><td class="poem">
+<p class="po">&ldquo;Be good, be good!&rdquo; the sisterhood</p>
+<p class="poind1">Cry out in holy chorus,</p>
+<p class="po">And, to dissuade from sin, parade</p>
+<p class="poind1">Their various charms before us.</p>
+</td></tr>
+
+<tr><td class="poem">
+<p class="po">But why, O why, has ne&rsquo;er an eye</p> 
+<p class="poind1">Seen her of winsome manner</p> 
+<p class="po">And youthful grace and pretty face</p>
+<p class="poind1">Flaunting the White Cross banner?</p>
+</td></tr>
+
+<tr><td class="poem">
+<p class="po">Now where&rsquo;s the need of speech and screed</p> 
+<p class="poind1">To better our behaving?</p> 
+<p class="po">A simpler plan for saving man</p>
+<p class="poind1">(But, first, is he worth saving?)</p>
+</td></tr>
+
+<tr><td class="poem">
+<p class="po">Is, dears, when he declines to flee</p>
+<p class="poind1">From bad thoughts that beset him,</p>
+<p class="po">Ignores the Law as &rsquo;t were a straw,</p>
+<p class="poind1">And wants to sin&mdash;don&rsquo;t let him.</p>
+</td></tr>
+</table>
+
+<p class="entry"><span class="def" lang="la">Cui Bono?</span> (Latin). What good would that do <i>me</i>?</p> 
+ 
+<p class="entry"><span class="def">cunning,</span> <span class="pos">n.</span> The faculty that distinguishes
+a weak animal or person from a strong one. It brings its possessor much mental satisfaction and great material
+adversity. An Italian proverb says: &ldquo;The furrier gets the skins of more foxes than asses.&rdquo;</p> 
+ 
+<p class="entry"><span class="def">Cupid,</span> <span class="pos">n.</span> The so-called god of love. This bastard creation of a barbarous fancy 
+was no doubt inflicted upon mythology for the sins of its deities. Of all unbeautiful and inappropriate 
+conceptions this is the most reasonless and offensive. The notion of symbolizing sexual love by a 
+semisexless babe, and comparing the pains of passion to the wounds of an 
+arrow&mdash;of introducing this pudgy homunculus into art grossly to materialize the 
+subtle spirit and suggestion of the work&mdash;this is eminently worthy of the age 
+that, giving it birth, laid it on the doorstep of prosperity.</p> 
+ 
+<p class="entry"><span class="def">curiosity,</span> <span class="pos">n.</span> An objectionable quality of the female 
+mind. The desire to know whether or not 
+a woman is cursed with curiosity is one of the most active and insatiable 
+passions of the masculine soul.</p> 
+ 
+<p class="entry"><span class="def">curse,</span> <span class="pos">v.t.</span> Energetically to belabor with a verbal 
+slap-stick. This is an operation which 
+in literature, particularly in the drama, is commonly fatal to the victim. Nevertheless, the liability to a cursing is 
+a risk that cuts but a small figure in fixing the rates of life insurance.</p> 
+ 
+<p class="entry"><span class="def">cynic,</span> <span class="pos">n.</span> A blackguard whose faulty vision sees things 
+as they are, not as they ought to be. Hence the custom among the Scythians of plucking out a cynic&rsquo;s eyes to 
+improve his vision.</p> 
+ 
+</body> 
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/C.html.i
@@ -1,0 +1,33 @@
+14 pages
+size 400 552
+length 28562
+397 2 11 body html
+0
+1712 2 35 body html
+85
+3565 2 65 body html
+0
+3565 2 65 body html
+552
+8255 2 164 body html
+22
+10580 2 200 body html
+0
+12955 2 241 body html
+22
+14994 2 282 body html
+0
+16175 2 307 body html
+0
+18725 2 352 body html
+0
+20230 2 375 body html
+0
+22655 2 421 body html
+0
+24758 2 459 body html
+90
+26978 2 505 body html
+141
+carmelite 1
+christian 4
--- /dev/null
+++ b/lib/ebooks/devils/D.html
@@ -1,0 +1,536 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+    "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: D</title>
+</head>
+
+<body lang="en-us">
+
+    
+<h1>D</h1>    
+    
+<p class="entry"><span class="def">damn,</span> <span class="pos">v.</span> A word formerly much used by the    
+Paphlagonians, the meaning of which is lost. By the learned Dr. Dolabelly Gak it is believed to have been a term of    
+satisfaction, implying the highest possible degree of mental tranquillity. 
+Professor Groke, on the contrary, thinks it    
+expressed an emotion of tumultuous delight, because it so frequently occurs in    
+combination with the word <i>jod</i> or <i>god</i>, meaning “joy.” It would be with great diffidence that I    
+should advance an opinion conflicting with that of either of these formidable    
+authorities.</p>    
+    
+<p class="entry"><span class="def">dance,</span> <span class="pos">v.i.</span> To leap about to the sound of tittering    
+music, preferably with arms about your neighbor’s wife or daughter. There are many kinds of dances, but all    
+those requiring the participation of the two sexes have two characteristics in 
+common: they are conspicuously innocent, and warmly loved by the vicious.</p>    
+    
+<p class="entry"><span class="def">danger,</span> <span class="pos">n.</span></p>   
+   
+  <table align="center" border="0"> 
+    <tr> 
+      <td valign="top" align="left">  
+  
+<p class="poetry">A savage beast which, when it sleeps,<br />   
+<span class="ind1">   
+Man girds at and despises,</span><br />   
+But takes himself away by leaps<br />   
+<span class="ind1">   
+And bounds when it arises.</span></p>    
+    
+<p class="citeauth">Ambat Delaso.</p>    
+    
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">daring,</span> <span class="pos">n.</span> One of the most conspicuous qualities of a man in security.</p>    
+    
+<p class="entry"><span class="def">datary,</span> <span class="pos">n.</span> A high ecclesiastic official of the Roman    
+Catholic Church, whose important function is to brand the Pope’s bulls with the    
+words <i>Datum Romae</i>.He enjoys a princely revenue and the friendship of God.</p>    
+    
+<p class="entry"><span class="def">dawn,</span> <span class="pos">n.</span> The time when men of reason go to  
+bed. Certain old men prefer to rise at about that    
+time, taking a cold bath and a long walk with an empty stomach, and otherwise    
+mortifying the flesh. They then point    
+with pride to these practices as the cause of their sturdy health and ripe    
+years; the truth being that they are hearty and old, not because of their    
+habits, but in spite of them. The    
+reason we find only robust persons doing this thing is that it has killed all    
+the others who have tried it.</p>    
+    
+<p class="entry"><span class="def">day,</span> <span class="pos">n.</span> A period of twenty-four hours, mostly  
+misspent. This period is divided into    
+two parts, the day proper and the night, or day improper—the former devoted to    
+sins of business, the latter consecrated to the other sort. These two kinds of social activity overlap.</p>    
+    
+<p class="entry"><span class="def">dead,</span> <span class="pos">adj.</span></p>   
+   
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">   
+Done with the work of breathing;   
+done<br />   
+   
+With all the world; the mad race   
+run<br />  
+   
+Though to the end; the golden goal<br />   
+   
+Attained and found to be a hole!</p>  
+   
+<p class="citeauth">Squatol Johnes.</p>  
+    
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">debauchee,</span> <span class="pos">n.</span> One who has so earnestly pursued pleasure    
+that he has had the misfortune to overtake it.</p>    
+    
+<p class="entry"><span class="def">debt,</span> <span class="pos">n.</span> An ingenious substitute for the chain and    
+whip of the slave-driver.</p>    
+    
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">As, pent in an aquarium, the troutlet<br />    
+    
+Swims round and round his tank to find an outlet,<br /> 
+Pressing his nose against the glass that    
+holds him,<br /> 
+Nor ever sees the prison that enfolds him;<br />  
+    
+So the poor debtor, seeing naught around him,<br /> 
+Yet feels the narrow limits that impound him,<br /> 
+Grieves at his debt and studies to evade it,<br /> 
+And finds at last he might as well    
+have paid it.</p>  
+    
+<p class="citeauth">Barlow S. Vode.</p>  
+    
+      </td>  
+    </tr>  
+  </table>  
+
+
+<p class="entry"><span class="def">decalogue,</span> <span class="pos">n.</span> A series of commandments, ten in number—just     
+enough to permit an intelligent selection for observance, but not enough to     
+embarrass the choice. Following is the     
+revised edition of the Decalogue, calculated for this meridian.</p>     
+     
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Thou shalt no God but me adore:<br />     
+     
+‘Twere too expensive to have more.</p>   
+     
+<p class="poetry">No images nor idols make<br />   
+     
+For Robert Ingersoll to break.</p>   
+     
+<p class="poetry">Take not God’s name in vain; select<br />   
+A time when it will have effect.</p>   
+   
+<p class="poetry">Work not on Sabbath days at all,<br />   
+But go to see the teams play ball.</p>   
+   
+<p class="poetry">Honor thy parents. That creates<br />   
+For life insurance lower rates.</p>   
+   
+<p class="poetry">Kill not, abet not those who kill;<br />   
+Thou shalt not pay thy butcher’s bill.</p>   
+   
+<p class="poetry">Kiss not thy neighbor’s wife, unless<br />   
+Thine own thy neighbor doth caress</p>   
+   
+<p class="poetry">Don’t steal; thou’lt never thus compete<br />   
+Successfully in business. Cheat.</p>     
+   
+<p class="poetry">Bear not false witness—that is low—<br />   
+But “hear ‘tis rumored so and so.”</p>   
+   
+<p class="poetry">Covet thou naught that thou hast not<br />   
+By hook or crook, or somehow, got.</p>   
+   
+<p class="citeauth">G. J.</p>     
+   
+      </td>   
+    </tr>   
+  </table>   
+     
+
+     
+<p class="entry"><span class="def">decide,</span> <span class="pos">v.i.</span> To succumb to the preponderance of one set     
+of influences over another set.</p>     
+     
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">A leaf was riven from a tree,<br />   
+“I mean to fall to earth,” said he.</p>   
+   
+<p class="poetry">The west wind, rising, made him veer.<br />   
+“Eastward,” said he, “I now shall steer.”</p>     
+   
+<p class="poetry">The east wind rose with greater force.<br />   
+Said he: “’Twere wise to change my course.”</p>     
+   
+<p class="poetry">With equal power they contend.<br />  
+He said: “My judgment I suspend.”</p>     
+   
+<p class="poetry">Down died the winds; the leaf, elate,<br />   
+Cried: “I’ve decided to fall straight.”</p>   
+   
+<p class="poetry">“First thoughts are best?” That’s not the moral;<br />   
+Just choose your own and we’ll not quarrel.</p>   
+   
+<p class="poetry">Howe’er your choice may chance to fall,<br />   
+You’ll have no hand in it at all.</p>   
+   
+<p class="citeauth">G. J.</p>     
+   
+      </td>   
+    </tr>   
+  </table>   
+     
+<p class="entry"><span class="def">defame,</span> <span class="pos">v.t.</span> To lie about   
+another. To tell the truth about another.</p>     
+     
+<p class="entry"><span class="def">defenceless,</span> <span class="pos">adj. </span>Unable to attack.</p>     
+     
+<p class="entry"><span class="def">degenerate,</span> <span class="pos">adj. </span>Less conspicuously admirable than     
+one’s ancestors. The contemporaries of     
+Homer were striking examples of degeneracy; it required ten of them to raise a     
+rock or a riot that one of the heroes of the Trojan war could have raised with   
+ease. Homer never tires of sneering at     
+“men who live in these degenerate days,” which is perhaps why they suffered him     
+to beg his bread—a marked instance of returning good for evil, by the way, for     
+if they had forbidden him he would certainly have starved.</p>     
+     
+<p class="entry"><span class="def">degradation,</span> <span class="pos">n.</span> One of the stages of moral and     
+social progress from private station to political preferment.</p>     
+     
+<p class="entry"><span class="def">deinotherium,</span> <span class="pos">n.</span> An extinct pachyderm that flourished     
+when the Pterodactyl was in fashion. The latter was a native of Ireland, its name being pronounced Terry    
+Dactyl or Peter O’Dactyl, as the man pronouncing it may chance to have heard it spoken or seen it printed.</p>     
+     
+<p class="entry"><span class="def">dejeuner,</span> <span class="pos">n.</span> The breakfast of an American who has been in     
+Paris. Variously pronounced.</p>     
+     
+<p class="entry"><span class="def">delegation,</span> <span class="pos">n.</span> In American politics, an article of     
+merchandise that comes in sets.</p>   
+     
+<p class="entry"><span class="def">deliberation,</span> <span class="pos">n.</span> The act of examining one’s bread to     
+determine which side it is buttered on.</p>   
+     
+<p class="entry"><span class="def">deluge,</span> <span class="pos">n.</span> A notable first experiment in baptism which     
+washed away the sins (and sinners) of the world.</p>   
+     
+<p class="entry"><span class="def">delusion,</span> <span class="pos">n.</span> The father of a most respectable family,   
+comprising Enthusiasm, Affection, Self-denial, Faith, Hope, Charity and many   
+other goodly sons and daughters.</p>   
+     
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">All hail, Delusion! Were it not for thee<br />  
+The world turned topsy-turvy we should see;<br />  
+For Vice, respectable with cleanly fancies,<br />  
+Would fly abandoned Virtue’s gross advances.</p>     
+     
+<p class="citeauth">Mumfrey Mappel.</p>  
+  
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">dentist,</span> <span class="pos">n.</span> A prestidigitator who, putting metal into    
+your mouth, pulls coins out of your pocket.</p>    
+    
+<p class="entry"><span class="def">dependent,</span> <span class="pos">adj.</span> Reliant upon another’s generosity    
+for the support which you are not in a position to exact from his fears.</p>    
+    
+<p class="entry"><span class="def">deputy,</span> <span class="pos">n.</span> A male relative of an office-holder, or of  
+his bondsman. The deputy is commonly a beautiful young man, with a red necktie and an intricate system of cobwebs  
+extending from his nose to his desk. When accidentally struck by the janitor’s broom, he gives off a cloud of dust.</p>  
+    
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">“Chief Deputy,” the Master cried,<br />  
+“To-day the books are to be tried<br />  
+By experts and accountants who<br />  
+Have been commissioned to go through<br />  
+Our office here, to see if we<br />  
+Have stolen injudiciously.<br />  
+Please have the proper entries made,<br />  
+The proper balances displayed,<br />  
+Conforming to the whole amount<br />   
+Of cash on hand—which they will count.<br />  
+I’ve long admired your punctual way—<br />  
+Here at the break and close of day,<br />  
+Confronting in your chair the crowd<br />  
+Of business men, whose voices loud<br />  
+And gestures violent you quell<br />  
+By some mysterious, calm spell—<br />  
+Some magic lurking in your look<br />  
+That brings the noisiest to book<br />  
+And spreads a holy and profound<br />  
+Tranquillity o’er all around.<br />  
+So orderly all’s done that they<br />  
+Who came to draw remain to pay.<br />  
+But now the time demands, at last,<br />  
+That you employ your genius vast<br />  
+In energies more active. Rise<br /> 
+And shake the lightnings from your eyes;<br />  
+Inspire your underlings, and fling<br />  
+Your spirit into everything!”<br />  
+The Master’s hand here dealt a whack<br />  
+Upon the Deputy’s bent back,<br />  
+When straightway to the floor there fell<br />  
+A shrunken globe, a rattling shell<br />  
+A blackened, withered, eyeless head!<br />  
+The man had been a twelvemonth dead.</p>  
+<p class="citeauth">Jamrach Holobom.</p>  
+    
+      </td>  
+    </tr>  
+  </table>  
+    
+
+    
+<p class="entry"><span class="def">destiny,</span> <span class="pos">n.</span> A tyrant’s authority for crime and fool’s excuse for failure.</p>     
+     
+<p class="entry"><span class="def">diagnosis,</span> <span class="pos">n.</span> A physician’s forecast of the disease by the     
+patient’s pulse and purse.</p>     
+     
+<p class="entry"><span class="def">diaphragm,</span> <span class="pos">n.</span> A muscular partition separating disorders of     
+the chest from disorders of the bowels.</p>     
+     
+<p class="entry"><span class="def">diary,</span> <span class="pos">n.</span> A daily record of that part of one’s life,     
+which he can relate to himself without blushing.</p>     
+   
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Hearst kept a diary wherein were writ<br />   
+All that he had of wisdom and of wit.<br />   
+So the Recording Angel, when Hearst died,<br />  
+Erased all entries of his own and cried:<br />   
+“I’ll judge you by your diary.” Said Hearst:<br />   
+“Thank you; ‘twill show you I am Saint the First”—<br />   
+Straightway producing, jubilant and proud,<br />  
+That record from a pocket in his shroud.<br />   
+The Angel slowly turned the pages o’er,<br />  
+Each stupid line of which he knew before,<br />  
+Glooming and     
+gleaming as by turns he hit<br />  
+On Shallow sentiment and stolen wit;<br />   
+Then gravely closed the book and gave it back.<br />   
+“My friend, you’ve wandered from your proper track:<br />   
+You’d never be content this side the tomb—<br />   
+For big ideas Heaven has little room,<br />  
+And Hell’s no latitude for making mirth,”<br />  
+He said, and     
+kicked the fellow back to earth.</p>  
+  
+<p class="citeauth">“The Mad Philosopher.”</p>  
+  
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">dictator,</span> <span class="pos">n.</span> The chief of a nation that prefers the    
+pestilence of despotism to the plague of anarchy.</p>    
+    
+<p class="entry"><span class="def">dictionary,</span> <span class="pos">n.</span> A malevolent literary device for cramping the growth of a language    
+and making it hard and inelastic. This dictionary, however, is a most useful work.</p>    
+    
+<p class="entry"><span class="def">die,</span> <span class="pos">n.</span> The singular of “dice.”   
+We seldom hear the word, because there is a     
+prohibitory proverb, “Never say die.” At long intervals, however, some one says:     
+“The die is cast,” which is not true, for it is cut. The word is found in an immortal couplet by     
+that eminent poet and domestic economist, Senator Depew:</p>     
+     
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">A cube of cheese no larger than a die</p>  
+ May bait the trap to catch a nibbling mie.   
+   
+      </td>   
+    </tr>   
+  </table>   
+     
+<p class="entry"><span class="def">digestion,</span> <span class="pos">n.</span> The conversion of victuals into   
+virtues. When the process is imperfect,     
+vices are evolved instead—a circumstance from which that wicked writer, Dr.     
+Jeremiah Blenn, infers that the ladies are the greater sufferers from dyspepsia.</p>     
+     
+<p class="entry"><span class="def">diplomacy,</span> <span class="pos">n.</span> The patriotic art of lying for one’s country.</p>     
+     
+<p class="entry"><span class="def">disabuse,</span> <span class="pos">v.t.</span> The present your neighbor with another and better error than the one     
+which he has deemed it advantageous to embrace.</p>     
+     
+<p class="entry"><span class="def">discriminate,</span> <span class="pos">v.i.</span> To note the particulars in which     
+one person or thing is, if possible, more objectionable than another.</p>     
+     
+<p class="entry"><span class="def">discussion,</span> <span class="pos">n.</span> A method of confirming others in their errors.</p>     
+     
+<p class="entry"><span class="def">disobedience,</span> <span class="pos">n.</span> The silver lining to the cloud of servitude.</p>     
+     
+<p class="entry"><span class="def">disobey,</span> <span class="pos">v.t.</span> To celebrate with an appropriate ceremony the maturity of a command.</p>     
+     
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">His right to govern me is clear as day,<br />   
+My duty manifest to disobey;<br />   
+And if that fit observance e’er I shut<br />   
+May I and duty be alike undone.</p>   
+   
+<p class="citeauth">Israfel Brown.</p>  
+  
+      </td>  
+    </tr>  
+  </table>  
+    
+
+    
+<p class="entry"><span class="def">dissemble,</span> <span class="pos">v.i.</span> To put a clean shirt upon the character.</p>   
+   
+<p class="quote" style="text-align: center">Let us dissemble.—<i>Adam.</i></p> 
+ 
+<p class="entry"><span class="def">distance,</span> <span class="pos">n.</span> The only thing that the rich are willing for   
+the poor to call theirs, and keep.</p> 
+   
+<p class="entry"><span class="def">distress,</span> <span class="pos">n.</span> A disease incurred by exposure to the prosperity of a friend.</p>   
+   
+<p class="entry"><span class="def">divination,</span> <span class="pos">n.</span> The art of nosing out the 
+occult. Divination is of as many kinds     
+as there are fruit-bearing varieties of the flowering dunce and the early fool.</p>     
+     
+<p id="dog" class="entry"><span class="def">dog,</span> <span class="pos">n.</span> A kind of additional or subsidiary Deity     
+designed to catch the overflow and surplus of the world’s worship. This Divine Being in some of his smaller and     
+silkier incarnations takes, in the affection of Woman, the place to which there     
+is no human male aspirant. The Dog is a survival—an anachronism. He toils not,     
+neither does he spin, yet Solomon in all his glory never lay upon a door-mat     
+all day long, sun-soaked and fly-fed and fat, while his master worked for the     
+means wherewith to purchase the idle wag of the Solomonic tail, seasoned with a     
+look of tolerant recognition.</p>     
+     
+<p class="entry"><span class="def">dragoon,</span> <span class="pos">n.</span> A soldier who combines dash and steadiness in so equal measure     
+that he makes his advances on foot and his retreats on horseback.</p>     
+     
+<p class="entry"><span class="def">dramatist,</span> <span class="pos">n.</span> One who adapts plays from the French.</p>     
+     
+<p class="entry"><span class="def">druids,</span> <span class="pos">n.</span> Priests and ministers of an ancient Celtic     
+religion which did not disdain to employ the humble allurement of human     
+sacrifice. Very little is now known     
+about the Druids and their faith. Pliny     
+says their religion, originating in Britain, spread eastward as far as     
+Persia. Caesar says those who desired     
+to study its mysteries went to Britain. Caesar himself went to Britain, but does not appear to have obtained any     
+high preferment in the Druidical Church, although his talent for human sacrifice     
+was considerable.</p>     
+     
+<p class="indentpara">Druids performed their     
+religious rites in groves, and knew nothing of church mortgages and the     
+season-ticket system of pew rents. They     
+were, in short, heathens and—as they were once complacently catalogued by a     
+distinguished prelate of the Church of England—<i>Dissenters.</i></p>   
+   
+<p class="entry"><span class="def">duck-bill,</span> <span class="pos">n.</span> Your account at your restaurant during the canvas-back season.</p>   
+   
+<p class="entry"><span class="def">duel,</span> <span class="pos">n.</span> A formal ceremony preliminary to the    
+reconciliation of two enemies. Great skill is necessary to its satisfactory observance; if awkwardly performed the    
+most unexpected and deplorable consequences sometimes ensue. A long time ago a man lost his life in a duel.</p>    
+    
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">That dueling’s a gentlemanly vice<br />   
+<span class="ind1">   
+I hold; and wish that it had been my lot</span><br /> 
+<span class="ind1">   
+To live my life out in some favored spot—</span><br />   
+Some country where it is considered nice<br />   
+To split a rival like a fish, or slice<br />   
+<span class="ind1">   
+A husband like a spud, or with a shot</span><br />   
+<span class="ind1">   
+Bring down a debtor doubled in a knot</span><br />   
+And ready to be put upon the ice.<br />   
+Some miscreants there are, whom I do long<br />   
+<span class="ind1">   
+To shoot, to stab, or some such way reclaim</span><br /> 
+The scurvy rogues to better lives and manners,<br /> 
+I seem     
+to see them now—a mighty throng.<br />   
+<span class="ind1">   
+It looks as if to challenge me they came,</span><br /> 
+Jauntily marching with brass bands and banners!</p>   
+   
+<p class="citeauth">Xamba Q. Dar.</p>    
+    
+      </td>  
+    </tr>  
+  </table>  
+    
+    
+<p class="entry"><span class="def">Dullard,</span> <span class="pos">n.</span> A member of the reigning dynasty in letters     
+and life. The Dullards came in with     
+Adam, and being both numerous and sturdy have overrun the habitable world. The secret of their power is their     
+insensibility to blows; tickle them with a bludgeon and they laugh with a     
+platitude. The Dullards came originally     
+from Boeotia, whence they were driven by stress of starvation, their dullness     
+having blighted the crops. For some     
+centuries they infested Philistia, and many of them are called Philistines to     
+this day. In the turbulent times of the     
+Crusades they withdrew thence and gradually overspread all Europe, occupying     
+most of the high places in politics, art, literature, science and     
+theology. Since a detachment of     
+Dullards came over with the Pilgrims in the <i>Mayflower</i>     
+and made a favorable report of the country, their increase by birth, immigration,     
+and conversion has been rapid and steady. According to the most trustworthy statistics the number of adult     
+Dullards in the United States is but little short of thirty millions, including     
+the statisticians. The intellectual     
+centre of the race is somewhere about Peoria, Illinois, but the New England     
+Dullard is the most shockingly moral.</p>     
+     
+<p class="entry"><span class="def">duty,</span> <span class="pos">n.</span> That which sternly impels us in the direction of profit, along the line of desire.</p>     
+     
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Sir Lavender Portwine, in favor at court,</p> 
+Was wroth at his master, who’d kissed Lady Port.<br /> 
+His anger provoked him to take the king’s head,<br />   
+But duty prevailed, and he took the king’s bread,<br />   
+<span class="ind3">   
+Instead.</span>     
+<p class="citeauth">G. J.</p>     
+     
+      </td>   
+    </tr>   
+  </table>   
+     
+</body>     
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/D.html.i
@@ -1,0 +1,30 @@
+13 pages
+size 400 552
+length 24257
+399 2 11 body html
+0
+2156 2 51 body html
+39
+4271 2 99 body html
+0
+5258 2 128 body html
+0
+6732 2 175 body html
+0
+8859 2 223 body html
+39
+11359 2 268 body html
+0
+11359 2 268 body html
+552
+14896 2 356 body html
+0
+17380 2 398 body html
+0
+19636 2 442 body html
+22
+21129 2 464 body html
+0
+22215 2 497 body html
+277
+dog 9
--- /dev/null
+++ b/lib/ebooks/devils/DevilsDictionary.opf
@@ -1,0 +1,119 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN" "oebpkg1.dtd">
+<package unique-identifier="oeb10devilsdictionary">
+<metadata>
+<dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/"
+    xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0">
+<dc:Title>The Devil's Dictionary</dc:Title>
+<dc:Type>Essay</dc:Type>
+<dc:Identifier scheme="none">123456789X</dc:Identifier>
+<dc:Creator role="aut" file-as="Bierce, Ambrose">Ambrose Bierce</dc:Creator>
+<dc:Subject>acidic commentary</dc:Subject>
+<dc:Publisher>PetesGuide.com</dc:Publisher>
+<dc:Contributor>Peter K. Sheerin</dc:Contributor>
+<dc:Contributor>Peter K. Sheerin</dc:Contributor>
+<dc:Date event="creation">1911</dc:Date>
+<dc:Date event="electronic publication">2000/07/21</dc:Date>
+<dc:Rights>This work is now in the public domain. This edition is based on the Project Guttenberg plain ASCII edition.</dc:Rights>
+<dc:Language>en-us</dc:Language>
+<dc:Coverage>Commentary on the use of language in the early 1900&rsquo;s</dc:Coverage>
+</dc-metadata>
+<x-metadata>
+<meta name="price" content="US $0.00" />
+</x-metadata>
+</metadata>
+<manifest>
+<item id="toc" href="index.html" media-type="text/x-oeb1-document"/>
+<item id="preface" href="preface.html" media-type="text/x-oeb1-document"/>
+<item id="foreword" href="foreword.html" media-type="text/x-oeb1-document"/>
+<item id="titlepage" href="TitlePage.html" media-type="text/x-oeb1-document"/>
+<item id="A" href="A.html" media-type="text/x-oeb1-document"/>
+<item id="B" href="B.html" media-type="text/x-oeb1-document"/>
+<item id="C" href="C.html" media-type="text/x-oeb1-document"/>
+<item id="D" href="D.html" media-type="text/x-oeb1-document"/>
+<item id="E" href="E.html" media-type="text/x-oeb1-document"/>
+<item id="F" href="F.html" media-type="text/x-oeb1-document"/>
+<item id="G" href="G.html" media-type="text/x-oeb1-document"/>
+<item id="H" href="H.html" media-type="text/x-oeb1-document"/>
+<item id="I" href="I.html" media-type="text/x-oeb1-document"/>
+<item id="J" href="J.html" media-type="text/x-oeb1-document"/>
+<item id="K" href="K.html" media-type="text/x-oeb1-document"/>
+<item id="L" href="L.html" media-type="text/x-oeb1-document"/>
+<item id="M" href="M.html" media-type="text/x-oeb1-document"/>
+<item id="N" href="N.html" media-type="text/x-oeb1-document"/>
+<item id="O" href="O.html" media-type="text/x-oeb1-document"/>
+<item id="P" href="P.html" media-type="text/x-oeb1-document"/>
+<item id="Q" href="Q.html" media-type="text/x-oeb1-document"/>
+<item id="R" href="R.html" media-type="text/x-oeb1-document"/>
+<item id="S" href="S.html" media-type="text/x-oeb1-document"/>
+<item id="T" href="T.html" media-type="text/x-oeb1-document"/>
+<item id="U" href="U.html" media-type="text/x-oeb1-document"/>
+<item id="V" href="V.html" media-type="text/x-oeb1-document"/>
+<item id="W" href="W.html" media-type="text/x-oeb1-document"/>
+<item id="X" href="X.html" media-type="text/x-oeb1-document"/>
+<item id="Y" href="Y.html" media-type="text/x-oeb1-document"/>
+<item id="Z" href="Z.html" media-type="text/x-oeb1-document"/>
+<item id="StyleSheet" href="devil.css" media-type="text/x-oeb1-css"/>
+</manifest>
+<spine>
+<itemref idref="titlepage"/>
+<itemref idref="toc"/>
+<itemref idref="foreword"/>
+<itemref idref="preface"/>
+<itemref idref="A"/>
+<itemref idref="B"/>
+<itemref idref="C"/>
+<itemref idref="D"/>
+<itemref idref="E"/>
+<itemref idref="F"/>
+<itemref idref="G"/>
+<itemref idref="H"/>
+<itemref idref="I"/>
+<itemref idref="J"/>
+<itemref idref="K"/>
+<itemref idref="L"/>
+<itemref idref="M"/>
+<itemref idref="N"/>
+<itemref idref="O"/>
+<itemref idref="P"/>
+<itemref idref="Q"/>
+<itemref idref="R"/>
+<itemref idref="S"/>
+<itemref idref="T"/>
+<itemref idref="U"/>
+<itemref idref="V"/>
+<itemref idref="W"/>
+<itemref idref="X"/>
+<itemref idref="Y"/>
+<itemref idref="Z"/>
+</spine>
+<tours>
+<tour id="poetrytour" title="Alphabetical Tour of Poetry Citations">
+<site title="Poor Isabella&rsquo;s Dead" href="A.html#abdication"/>
+<site title="Abracadabra" href="A.html#abracadabra"/>
+<site title="Spring Beckons!" href="A.html#abscond"/>
+<site title="Poor Isabella's Dead" href="A.html#absent"/>
+<site title="Poor Isabella's Dead" href="A.html#abstainer"/>
+<site title="Poor Isabella's Dead" href="A.html#accountability"/>
+<site title="Poor Isabella's Dead" href="A.html#admonition"/>
+<site title="Poor Isabella's Dead" href="A.html#advice"/>
+<site title="Poor Isabella's Dead" href="A.html#aim"/>
+<site title="Poor Isabella's Dead" href="A.html#allah"/>
+<site title="Poor Isabella's Dead" href="A.html#allegiance"/>
+<site title="Poor Isabella's Dead" href="A.html#alone"/>
+<site title="Poor Isabella's Dead" href="A.html#altar"/>
+<site title="Poor Isabella's Dead" href="A.html#anoint"/>
+<site title="Poor Isabella's Dead" href="A.html#aphorism"/>
+<site title="Poor Isabella's Dead" href="A.html#apothecary"/>
+<site title="Poor Isabella's Dead" href="A.html#archbishop"/>
+<site title="Poor Isabella's Dead" href="A.html#arsenic"/>
+<site title="Poor Isabella's Dead" href="A.html#art"/>
+</tour>
+</tours>
+<guide>
+<reference type="toc" title="Table of Contents" href="index.html"/>
+<reference type="foreword" title="Foreword" href="foreword.html"/>
+<reference type="preface" title="Preface" href="preface.html"/>
+<reference type="other.ms-firstpage" title="" href="foreword.html"/>
+</guide>
+</package>
--- /dev/null
+++ b/lib/ebooks/devils/E.html
@@ -1,0 +1,629 @@
+<?xml version="1.0" encoding="utf-16"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+    "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil’s Dictionary: E</title>
+</head>
+
+<body lang="en-us">
+
+<h1>E</h1>
+
+<p class="entry"><span class="def">eat,</span> <span class="pos">v.i.</span> To perform  
+successively (and successfully) the functions of mastication, humectation, and deglutition.</p>   
+
+<p class="indentpara">“I was in the drawing-room, enjoying my dinner,” said Brillat-Savarin, beginning
+an anecdote. “What!” interrupted Rochebriant; “eating dinner in a drawing-room?” “I must beg you to   
+observe, monsieur,” explained the great gastronome, “that I did not say I was eating my dinner, but enjoying it. I   
+had dined an hour before.”</p>
+
+<p class="entry"><span class="def">eavesdrop,</span> <span class="pos">v.i.</span> Secretly   
+to overhear a catalogue    
+of the crimes and vices of another or yourself.</p>    
+    
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">A lady with one of her ears applied<br /> 
+To an open keyhole heard, inside,<br /> 
+Two female gossips in converse    
+free—<br /> 
+The subject engaging them was she.<br /> 
+“I think,” said    
+one, “and my husband thinks<br /> 
+That she’s a prying, inquisitive minx!”<br /> 
+As soon as no more of it she could    
+hear<br /> 
+The lady, indignant, removed her    
+ear.<br /> 
+“I will not stay,”    
+she said, with a pout,<br /> 
+“To hear my character lied about!”</p>    
+    
+<p class="citeauth">Gopete Sherany.</p>   
+   
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">eccentricity,</span> <span class="pos">n.</span> A method of distinction so cheap      
+that fools employ it to accentuate their incapacity.</p>      
+      
+<p class="entry"><span class="def">economy,</span> <span class="pos">n.</span> Purchasing     
+the barrel of whiskey that you do      
+not need for the price of the cow that you cannot afford.</p>      
+      
+<p class="entry"><span class="def">edible,</span> <span class="pos">adj.</span> Good to eat,     
+and wholesome to digest, as a      
+worm to a toad, a toad to a snake, a snake to a pig, a pig to a man, and a man      
+to a worm.</p>      
+      
+<p class="entry"><span class="def">editor,</span> <span class="pos">n.</span> A person who combines the judicial functions       
+of Minos, Rhadamanthus and Aeacus, but is placable with an obolus; a severely       
+virtuous censor, but so charitable withal that he tolerates the virtues of       
+others and the vices of himself; who flings about him the splintering lightning       
+and sturdy thunders of admonition till he resembles a bunch of firecrackers       
+petulantly uttering his mind at the tail of a dog; then straightway murmurs a       
+mild, melodious lay, soft as the cooing of a donkey intoning its prayer to the       
+evening star. Master of mysteries and       
+lord of law, high-pinnacled upon the throne of thought, his face suffused with       
+the dim splendors of the Transfiguration, his legs intertwisted and his tongue       
+a-cheek, the editor spills his will along the paper and cuts it off in lengths       
+to suit. And at intervals from behind       
+the veil of the temple is heard the voice of the foreman demanding three inches       
+of wit and six lines of religious meditation, or bidding him turn off the wisdom       
+and whack up some pathos.</p>       
+       
+  <table align="center" border="0">     
+    <tr>     
+      <td valign="top" align="left">      
+      
+<p class="poetry">O, the Lord of Law       
+on the Throne of Thought,<br />    
+<span class="ind1">A gilded impostor is he.</span><br />      
+Of shreds and       
+patches his robes are wrought,<br />      
+<span class="ind3">      
+His crown is brass,</span><br />      
+<span class="ind3">      
+Himself an ass,</span><br />      
+<span class="ind1">      
+And his power is fiddle-dee-dee.</span><br />     
+Prankily, crankily prating of       
+naught,<br />      
+Silly old quilly old Monarch of       
+Thought.<br />      
+<span class="ind1">      
+Public opinion’s       
+camp-follower he,</span><br />    
+<span class="ind1">Thundering, blundering, plundering free.</span><br />      
+<span class="ind3">      
+Affected,</span><br />      
+<span class="ind6">      
+Ungracious,</span><br />      
+<span class="ind3">      
+Suspected,</span><br />      
+<span class="ind6">      
+Mendacious,</span><br />    
+Respected contemporaree!</p>      
+      
+<p class="citeauth">J.H. Bumbleshook.</p>     
+     
+      </td>    
+    </tr>    
+  </table>    
+      
+<p class="entry"><span class="def">education,</span> <span class="pos"> n.</span> That     
+which discloses to the wise and disguises from the foolish their lack of     
+understanding.</p>     
+     
+<p class="entry"><span class="def">effect,</span> <span class="pos">n.</span> The second of two phenomena which always     
+occur together in the same order. The     
+first, called a Cause, is said to generate the other—which is no more sensible     
+than it would be for one who has never seen a dog except in the pursuit of a     
+rabbit to declare the rabbit the cause of a dog.</p>     
+     
+<p class="entry"><span class="def">egotist,</span> <span class="pos">n.</span> A  
+person of low taste, more interested in himself than in me.</p>    
+    
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Megaceph, chosen to serve the State<br />    
+In the halls of legislative debate,<br />    
+One day with all his credentials     
+came<br />    
+To the capitol’s door and announced     
+his name.<br />    
+The doorkeeper looked, with a     
+comical twist<br />    
+Of the face, at the eminent     
+egotist,<br />    
+And said: “Go away, for we settle here<br />    
+All manner of questions, knotty and     
+queer,<br />    
+And we cannot have, when the     
+speaker demands<br />    
+To be told how every member stands,<br />    
+A man who to all things under the     
+sky<br />    
+Assents by eternally voting ‘I’.”     
+ </p>
+      </td>    
+    </tr>    
+  </table>    
+      
+<p class="entry"><span class="def">ejection,</span> <span class="pos">n.</span> An approved remedy for the disease of     
+garrulity. It is also much used in     
+cases of extreme poverty.</p>     
+     
+<p class="entry"><span class="def">elector,</span> <span class="pos">n.</span> One who enjoys the sacred privilege of     
+voting for the man of another man’s choice.</p>     
+     
+<p class="entry"><span class="def">electricity,</span> <span class="pos">n.</span> The power that causes all natural       
+phenomena not known to be caused by something else. It is the same thing as lightning, and its famous attempt to       
+strike Dr. Franklin is one of the most picturesque incidents in that great and       
+good man’s career. The memory of Dr.       
+Franklin is justly held in great reverence, particularly in France, where a       
+waxen effigy of him was recently on exhibition, bearing the following touching       
+account of his life and services to science:</p>       
+       
+<p class="quote">“Monsieur       
+Franqulin, inventor of electricity.       
+This illustrious savant, after having made several voyages around the       
+world, died on the Sandwich Islands and was devoured by savages, of whom not a       
+single fragment was ever recovered.”</p>       
+       
+<p class="indentpara">Electricity seems       
+destined to play a most important part in the arts and industries. The question of its economical application       
+to some purposes is still unsettled, but experiment has already proved that it       
+will propel a street car better than a gas jet and give more light than a       
+horse.</p>       
+       
+<p class="entry"><span class="def">elegy,</span> <span class="pos">n.</span> A composition in verse, in which, without       
+employing any of the methods of humor, the writer aims to produce in the       
+reader’s mind the dampest kind of dejection.       
+The most famous English example begins somewhat like this:</p>       
+       
+  <table align="center" border="0">    
+    <tr>    
+      <td valign="top" align="left">     
+     
+<p class="poetry">The cur foretells       
+the knell of parting day;<br />      
+<span class="ind1">      
+The loafing herd        
+winds slowly o’er the lea;</span><br />      
+The wise man       
+homeward plods; I only stay<br />      
+<span class="ind1">      
+To fiddle-faddle       
+in a minor key.</span>     
+     </p>
+      </td>    
+    </tr>    
+  </table>    
+      
+<p class="entry"><span class="def">eloquence,</span> <span class="pos">n.</span>       
+The art of orally persuading fools that white       
+is the color that it appears to be. It       
+includes the gift of making any color appear white.</p>       
+       
+<p class="entry"><span class="def">elysium,</span> <span class="pos">n.</span> An imaginary delightful country which the       
+ancients foolishly believed to be inhabited by the spirits of the good. This ridiculous and mischievous fable was       
+swept off the face of the earth by the early Christians—may their souls be       
+happy in Heaven!</p>       
+       
+<p class="entry"><span class="def">emancipation,</span> <span class="pos">       
+n.</span> A bondman’s change from the tyranny       
+of another to the despotism of himself.</p>       
+       
+  <table align="center" border="0">    
+    <tr>    
+      <td valign="top" align="left">     
+     
+<p class="poetry">He was a       
+slave: at word he went and came;<br />      
+<span class="ind1">      
+His iron collar cut       
+him to the bone.</span><br />      
+Then Liberty       
+erased his owner’s name,<br />      
+<span class="ind1">      
+Tightened the       
+rivets and inscribed his own.</span></p>       
+       
+<p class="citeauth">G. J.</p>      
+      
+      </td>    
+    </tr>    
+  </table>    
+      
+<p class="entry"><span class="def">embalm,</span> <span class="pos">v.i.</span> To cheat vegetation by locking up the gases      
+upon which it feeds. By embalming their      
+dead and thereby deranging the natural balance between animal and vegetable      
+life, the Egyptians made their once fertile and populous country barren and      
+incapable of supporting more than a meagre crew. The modern metallic burial casket is a step in the same direction,      
+and many a dead man who ought now to be ornamenting his neighbor’s lawn as a      
+tree, or enriching his table as a bunch of radishes, is doomed to a long      
+inutility. We shall get him after      
+awhile if we are spared, but in the meantime the violet and rose are      
+languishing for a nibble at his <i>glutoeus      
+maximus</i>.</p>      
+      
+<p class="entry"><span class="def">emotion,</span> <span class="pos">n.</span> A prostrating disease caused by a      
+determination of the heart to the head.      
+It is sometimes accompanied by a copious discharge of hydrated chloride      
+of sodium from the eyes.</p>      
+      
+<p class="entry"><span class="def">encomiast,</span> <span class="pos">n.</span> A special (but not particular) kind of liar.</p>      
+      
+<p class="entry"><span class="def">end,</span> <span class="pos">n.</span> The position farthest removed on either hand      
+from the Interlocutor.</p>      
+      
+  <table align="center" border="0">    
+    <tr>    
+      <td valign="top" align="left">     
+     
+<p class="poetry">The man was       
+perishing apace<br />      
+<span class="ind1">      
+Who played the       
+tambourine;</span><br />      
+The seal of death       
+was on his face—<br />      
+<span class="ind1">      
+‘Twas pallid, for       
+‘twas clean.</span></p>       
+       
+<p class="poetry">“This is the end,”       
+the sick man said<br />      
+<span class="ind1">      
+In faint and       
+failing tones.</span><br />      
+A moment later he       
+was dead,<br />      
+<span class="ind1">      
+And Tambourine was       
+Bones.</span></p>       
+       
+<p class="citeauth">Tinley Roquot.</p>      
+      
+      </td>   
+    </tr>   
+  </table>   
+     
+<p></p>      
+      
+<p class="entry"><span class="def">enough,</span> <span class="pos">pro.</span> All there is in the world if you like it.</p>      
+      
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Enough is as good       
+as a feast—for that matter<br />  
+Enougher’s as good as a feast for the platter.</p>  
+<p class="citeauth">Arbely C. Strunk.   </p>
+   
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">entertainment,</span> <span class="pos">n.</span> Any kind of amusement whose inroads     
+stop short of death by injection.</p>     
+     
+<p class="entry"><span class="def">enthusiasm,</span> <span class="pos">n.</span> A distemper of youth, curable by     
+small doses of repentance in connection with outward applications of     
+experience. Byron, who recovered long     
+enough to call it “entuzy-muzy,” had a relapse, which carried him off—to     
+Missolonghi.</p>     
+     
+<p class="entry"><span class="def">envelope,</span> <span class="pos">n.</span> The coffin of a document; the scabbard of a     
+bill; the husk of a remittance; the bed-gown of a love-letter.</p>     
+     
+<p class="entry"><span class="def">envy,</span> <span class="pos">n.</span> Emulation adapted to the meanest capacity.</p>     
+     
+<p class="entry"><span class="def">epaulet,</span> <span class="pos">n.</span> An ornamented badge, serving to distinguish     
+a military officer from the enemy—that is to say, from the officer of lower     
+rank to whom his death would give promotion.</p>     
+     
+<p class="entry"><span class="def">epicure,</span> <span class="pos">n.</span> An opponent of Epicurus, an abstemious     
+philosopher who, holding that pleasure should be the chief aim of man, wasted     
+no time in gratification from the senses.</p>     
+     
+<p class="entry"><span class="def">epigram,</span> <span class="pos">n.</span> A short, sharp saying in prose or verse,      
+frequently characterize by acidity or acerbity and sometimes by wisdom. Following are some of the more notable      
+epigrams of the learned and ingenious Dr. Jamrach Holobom:</p>     
+
+   <blockquote>
+<p>We know better the      
+needs of ourselves than of others. To      
+serve oneself is economy of administration.</p> 
+<p>In each human      
+heart are a tiger, a pig, an ass and a nightingale. Diversity of character is due to their unequal activity.</p> 
+<p>There are three      
+sexes; males, females and girls.</p> 
+<p>Beauty in women      
+and distinction in men are alike in this:     
+they seem to be      
+the unthinking a kind of credibility.</p> 
+<p>Women in love are      
+less ashamed than men. They have less      
+to be ashamed of.</p> 
+<p>While your friend      
+holds you affectionately by both your hands you are safe, for you can watch      
+both his.</p>
+    </blockquote>
+
+    
+      
+<p class="entry"><span class="def">epitaph,</span> <span class="pos">n.</span> An inscription on a tomb, showing that      
+virtues acquired by death have a retroactive effect. Following is a touching example:</p>      
+      
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Here lie the bones of Parson Platt,<br />     
+Wise, pious, humble and all that,<br />     
+Who showed us life as all should      
+live it;<br />     
+Let that be said—and God forgive      
+it!    </p>
+    
+      </td>   
+    </tr>   
+  </table>   
+     
+<p class="entry"><span class="def">erudition,</span> <span class="pos">n.</span> Dust shaken out of a book into an empty      
+skull.</p>      
+      
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">So wide his erudition’s mighty      
+span,<br />     
+He knew Creation’s origin and plan<br />     
+And only came by accident to grief—<br />     
+He thought, poor man, ‘twas right      
+to be a thief.</p>      
+      
+<p></p>      
+      
+<p class="citeauth">Romach Pute.</p>     
+     
+      </td>  
+    </tr>  
+  </table>  
+    
+<p></p>     
+     
+<p class="entry"><span class="def">esoteric,</span> <span class="pos">adj.</span> Very particularly abstruse and     
+consummately occult. The ancient     
+philosophies were of two kinds,<i>&#8212;exoteric</i>,     
+those that the philosophers themselves could partly understand, and <i>esoteric</i>, those that nobody could     
+understand. It is the latter that have     
+most profoundly affected modern thought and found greatest acceptance in our     
+time.</p>     
+     
+<p class="entry"><span class="def">ethnology,</span> <span class="pos">n.</span> The science that treats of the various     
+tribes of Man, as robbers, thieves, swindlers, dunces, lunatics, idiots and     
+ethnologists.</p>     
+     
+<p class="entry"><span class="def">Eucharist,</span> <span class="pos">n.</span> A sacred feast of the religious sect of     
+Theophagi.</p>     
+     
+<p class="indentpara">A dispute once     
+unhappily arose among the members of this sect as to what it was that they     
+ate. In this controversy some five     
+hundred thousand have already been slain, and the question is still unsettled.</p>     
+     
+<p class="entry"><span class="def">eulogy,</span> <span class="pos">n.</span> Praise of a person who has either the     
+advantages of wealth and power, or the consideration to be dead.</p>     
+     
+<p class="entry"><span class="def">evangelist,</span> <span class="pos">n.</span> A bearer of good tidings,     
+particularly (in a religious sense) such as assure us of our own salvation and     
+the damnation of our neighbors.</p>     
+     
+<p class="entry"><span class="def">everlasting,</span> <span class="pos">adj.</span> Lasting forever. It is with no small diffidence that I     
+venture to offer this brief and elementary definition, for I am not unaware of     
+the existence of a bulky volume by a sometime Bishop of Worcester, entitled, <i>A     
+Partial Definition of the Word “Everlasting,” as Used in the Authorized Version     
+of the Holy Scriptures</i>. His book was     
+once esteemed of great authority in the Anglican Church, and is still, I     
+understand, studied with pleasure to the mind and profit of the soul.</p>     
+     
+<p class="entry"><span class="def">exception,</span> <span class="pos">n.</span> A thing which takes the liberty to differ     
+from other things of its class, as an honest man, a truthful woman, etc. “The exception proves the rule” is an     
+expression constantly upon the lips of the ignorant, who parrot it from one     
+another with never a thought of its absurdity.     
+In the Latin, “<i>Exceptio probat regulam</i>” means that the exception <i>tests</i> the rule, puts it to the proof, not <i>confirms</i> it.    
+The malefactor who drew the meaning from this excellent dictum     
+and substituted a contrary one of his own exerted an evil power which appears     
+to be immortal.</p>     
+     
+<p class="entry"><span class="def">excess,</span> <span class="pos">n.</span> In morals, an indulgence that enforces by     
+appropriate penalties the law of moderation.</p>     
+     
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">   
+   
+Hail, high       
+Excess—especially in wine,<br />      
+<span class="ind1">      
+To thee in worship        
+do I bend the knee</span><br />  
+<span class="ind1">      
+ Who preach abstemiousness unto me—</span><br />      
+My skull thy       
+pulpit, as my paunch thy shrine.<br />      
+Precept on       
+precept, aye, and line on line,<br />      
+<span class="ind1">      
+Could ne’er       
+persuade so sweetly to agree</span><br />      
+<span class="ind1">      
+With reason as thy       
+touch, exact and free,</span><br />      
+Upon my forehead       
+and along my spine.<br />      
+At thy command       
+eschewing pleasure’s cup,<br />      
+<span class="ind1">      
+With the hot grape       
+I warm no more my wit;</span><br />      
+<span class="ind1">      
+When on thy stool       
+of penitence I sit</span><br />      
+I’m quite converted, for I can’t       
+get up.<br />      
+Ungrateful he who afterward would       
+falter<br />      
+To make new sacrifices at thine       
+altar!</p> 
+     
+      </td>    
+    </tr>    
+  </table>    
+      
+<p class="entry"><span class="def">excommunication,</span> <span class="pos">n.</span></p>      
+      
+  <table align="center" border="0">    
+    <tr>    
+      <td valign="top" align="left">     
+     
+<p class="poetry">This “excommunication” is a word<br />      
+In speech ecclesiastical oft heard,<br />      
+And means the      
+damning, with bell, book and candle,<br />  
+Some sinner whose opinions are a scandal—<br />      
+A rite permitting      
+Satan to enslave him<br /> 
+Forever, and forbidding Christ to save him.</p>      
+      
+<p class="citeauth">Gat Huckle.</p>    
+    
+      </td>  
+    </tr>  
+  </table>  
+    
+<p></p>    
+    
+<p class="entry"><span class="def">executive,</span> <span class="pos">n.</span> An officer of the Government, whose duty it     
+is to enforce the wishes of the legislative power until such time as the     
+judicial department shall be pleased to pronounce them invalid and of no     
+effect. Following is an extract from an     
+old book entitled, <i>The Lunarian Astonished&#8212;</i>Pfeiffer &amp; Co., Boston,     
+1803:</p>     
+<blockquote>   
+<p>Lunarian: Then when your Congress has passed a law it    
+goes directly to the Supreme Court in order that it may at once be known whether it is constitutional?</p>     
+     
+<p>Terrestrain: O no; it does not require the approval of     
+the Supreme Court until having perhaps been enforced for many years somebody objects to its     
+operation against himself—I mean his client.     
+The President, if he approves it, begins to execute it at once.</p>     
+     
+<p>Lunarian: Ah, the executive power is a part of the legislative.</p>     
+     
+<p>Do your policemen also have to approve the local ordinances that they enforce?</p>     
+     
+<p>Terrestrian: Not yet—at least not in their character of constables.   
+Generally speaking, though, all laws require the approval of those whom they are intended to restrain.</p>     
+     
+<p>Lunarian: I see. The death warrant is not valid until signed by the murderer.</p>     
+     
+<p>Terrestrian: My friend, you put it too strongly; we are not so consistent.</p>     
+     
+<p>Lunarian: But this system of maintaining an expensive     
+judicial machinery to pass upon the validity of laws only after they have long been executed, and then     
+only when brought before the court by some private person—does it not cause great confusion?</p>     
+     
+<p>Terrestrian: It does.</p>     
+     
+<p>Lunarian: Why then should not your laws, previously to     
+being executed, be validated, not by the signature of your President, but by that of the Chief     
+Justice of the Supreme Court?</p>     
+     
+<p>Terrestrian: There is no precedent for any such course.</p>     
+     
+<p>Lunarian: Precedent. What is that?</p>     
+     
+<p>Terrestrian: It has been defined by five hundred lawyers     
+in three volumes each. So how can any one know?</p>     
+</blockquote>   
+     
+<p class="entry"><span class="def">exhort,</span> <span class="pos">v.t.</span> In     
+religious affairs, to put the conscience of another upon the spit and roast it     
+to a nut-brown discomfort.</p>     
+     
+<p class="entry"><span class="def">exile,</span> <span class="pos">n.</span> One who serves his country by residing     
+abroad, yet is not an ambassador.</p>     
+     
+<p class="indentpara">An English     
+sea-captain being asked if he had read “The Exile of Erin,” replied: “No, sir, but I should like to anchor on     
+it.” Years afterwards, when he had been     
+hanged as a pirate after a career of unparalleled atrocities, the following     
+memorandum was found in the ship’s log that he had kept at the time of his     
+reply:</p>     
+     
+<p class="quote">Aug. 3d,     
+1842. Made a joke on the ex-Isle of Erin. Coldly received. War with the whole world!</p>     
+     
+<p class="entry"><span class="def">existence,</span> <span class="pos">n.</span></p>    
+    
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">A transient,     
+horrible, fantastic dream,<br /> 
+Wherein is nothing yet all things do seem:<br /> 
+From which we’re      
+wakened by a friendly nudge<br /> 
+Of our bedfellow Death, and cry: “O fudge!”</p>     
+     
+      </td>   
+    </tr>   
+  </table>   
+     
+<p class="entry"><span class="def">experience,</span> <span class="pos">n.</span> The wisdom that enables us to recognize      
+as an undesirable old acquaintance the folly that we have already embraced.</p>      
+      
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">To one who,      
+journeying through night and fog,<br /> 
+Is mired neck-deep in an unwholesome bog,<br /> 
+Experience, like the rising of the dawn,<br /> 
+Reveals the path that he should not      
+have gone.</p>      
+      
+<p class="citeauth">Joel Frad Bink.</p>     
+     
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">expostulation,</span> <span class="pos">n.</span> One of the many methods by which     
+fools prefer to lose their friends.</p>     
+     
+<p class="entry"><span class="def">extinction,</span> <span class="pos">n.</span> The raw material out of which     
+theology created the future state.</p>     
+     
+     
+</body>     
+     
+</html>     
--- /dev/null
+++ b/lib/ebooks/devils/E.html.i
@@ -1,0 +1,31 @@
+14 pages
+size 400 552
+length 26246
+397 2 11 body html
+0
+2053 2 56 body html
+0
+3718 2 81 body html
+0
+5641 2 133 body html
+0
+7742 2 182 body html
+51
+10267 2 247 body html
+39
+12629 2 305 body html
+0
+14666 2 344 body html
+118
+16609 2 408 body html
+22
+18788 2 443 body html
+56
+20989 2 501 body html
+0
+21978 2 528 body html
+284
+21978 2 528 body html
+823
+25433 2 603 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/F.html
@@ -1,0 +1,578 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: F</title>
+</head>
+
+<body lang="en-US">
+
+<h1>F</h1>
+
+<p class="entry"><span class="def">fairy,</span> <span class="pos"> n.</span> A creature, variously fashioned and endowed, 
+that formerly inhabited the meadows and forests. It was nocturnal in its habits, 
+and somewhat addicted to dancing and the theft of children. The fairies 
+are now believed by naturalist to be extinct, though a clergyman of the Church 
+of England saw three near Colchester as lately as 1855, while passing through a 
+park after dining with the lord of the manor. 
+The sight greatly staggered him, and he was so affected that his account 
+of it was incoherent. In the year 1807 
+a troop of fairies visited a wood near Aix and carried off the daughter of a 
+peasant, who had been seen to enter it with a bundle of clothing. The son of a wealthy 
+<i>bourgeois</i> disappeared about the same time, 
+but afterward returned. He had seen the 
+abduction been in pursuit of the fairies. 
+Justinian Gaux, a writer of the fourteenth century, avers that so great 
+is the fairies’ power of transformation that he saw one change itself into two 
+opposing armies and fight a battle with great slaughter, and that the next day, 
+after it had resumed its original shape and gone away, there were seven hundred 
+bodies of the slain which the villagers had to bury. He does not say if any of the 
+wounded recovered. In the time of Henry III, of England, a law 
+was made which prescribed the death penalty for “Kyllynge, wowndynge, or 
+mamynge” a fairy, and it was universally respected.</p> 
+ 
+<p class="entry"><span class="def">faith,</span> <span class="pos"> n.</span> Belief without evidence in what is told by 
+one who speaks without knowledge, of things without parallel.</p> 
+ 
+<p id="famous" class="entry"><span class="def">famous,</span> <span class="pos">adj.</span> Conspicuously miserable.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Done to a turn on 
+the iron, behold<br /> 
+Him who to be 
+famous aspired.<br /> 
+Content? Well, his grill has a plating of gold,<br /> 
+And his twistings 
+are greatly admired.</p> 
+ 
+<p class="citeauth">Hassan Brubuddy.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry">&nbsp;</p>
+
+<p class="entry"><span class="def">fashion,</span> <span class="pos"> n.</span> A despot whom the wise ridicule and obey.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">A king there was 
+who lost an eye<br /> 
+In some excess of 
+passion;<br /> 
+And straight his 
+courtiers all did try<br /> 
+To follow the new 
+fashion.<br /> 
+Each dropped one 
+eyelid when before<br /> 
+The throne he 
+ventured, thinking<br /> 
+‘Twould please the 
+king. That monarch swore<br /> 
+He’d slay them all 
+for winking.<br /> 
+What should they 
+do? They were not hot<br /> 
+To hazard such 
+disaster;<br /> 
+They dared not 
+close an eye—dared not<br /> 
+See better than 
+their master.<br /> 
+Seeing them 
+lacrymose and glum,<br /> 
+A leech consoled 
+the weepers:<br /> 
+He spread small 
+rags with liquid gum<br /> 
+And covered half 
+their peepers.<br /> 
+The court all wore 
+the stuff, the flame<br /> 
+Of royal anger 
+dying.<br /> 
+That’s how 
+court-plaster got its name<br /> 
+Unless I’m greatly 
+lying.</p> 
+ 
+<p class="citeauth">Naramy Oof.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">feast,</span> <span class="pos"> n.</span> A festival. 
+A religious celebration usually signalized by gluttony and drunkenness, frequently 
+in honor of some holy person distinguished for abstemiousness. In the Roman Catholic 
+Church feasts are 
+“movable” and “immovable,” but the celebrants are uniformly immovable until 
+they are full. In their earliest 
+development these entertainments took the form of feasts for the dead; such 
+were held by the Greeks, under the name <i>Nemeseia</i>, 
+by the Aztecs and Peruvians, as in modern times they are popular with the 
+Chinese; though it is believed that the ancient dead, like the modern, were 
+light eaters. Among the many feasts of 
+the Romans was the <i>Novemdiale</i>, 
+which was held, according to Livy, whenever stones fell from heaven.</p> 
+ 
+<p class="entry"><span class="def">felon,</span> <span class="pos"> n.</span> A person of greater enterprise than 
+discretion, who in embracing an opportunity has formed an unfortunate 
+attachment.</p> 
+ 
+<p class="entry"><span class="def">female,</span> <span class="pos"> n.</span> One of the opposing, or unfair, sex.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">The Maker, at Creation’s birth,<br /> 
+With living things had stocked the 
+earth.<br /> 
+From elephants to bats and snails,<br /> 
+They all were good, for all were 
+males.<br /> 
+But when the Devil came and saw<br /> 
+He said: “By Thine eternal law<br /> 
+Of growth, maturity, decay,<br /> 
+These all must quickly pass away<br /> 
+And leave untenanted the earth<br /> 
+Unless Thou dost establish birth”—<br /> 
+Then tucked his head beneath his 
+wing<br /> 
+To laugh—he had no sleeve—the thing<br /> 
+With deviltry did so accord,<br /> 
+That he’d suggested to the Lord.<br /> 
+The Master pondered this advice,<br /> 
+Then shook and threw the fateful 
+dice<br /> 
+Wherewith all matters here below<br /> 
+Are ordered, and observed the 
+throw;<br /> 
+Then bent His head in awful state,<br /> 
+Confirming the decree of Fate.<br /> 
+From every part of earth anew<br /> 
+The conscious dust consenting flew,<br /> 
+While rivers from their courses rolled<br /> 
+To make it plastic for the mould.<br />
+Enough collected (but no more,<br /> 
+For niggard Nature hoards her store)<br /> 
+He kneaded it to flexible clay,<br /> 
+While Nick unseen threw some away.<br /> 
+And then the various forms He cast,<br /> 
+Gross organs first and finer last;<br />
+No one at once evolved, but all<br /> 
+By even touches grew and small<br /> 
+Degrees advanced, till, shade by shade,<br /> 
+To match all living things He’d made<br /> 
+Females, complete in all their parts<br /> 
+Except (His clay gave out) thec hearts.<br /> 
+“No matter,” Satan cried; “with speed<br /> 
+I’ll fetch the very hearts they need”—<br /> 
+So flew away and soon brought back<br /> 
+The number needed, in a sack.<br /> 
+That night earth range with sounds of strife—<br /> 
+Ten million males each had a wife;<br /> 
+That night sweet Peace her pinions spread<br /> 
+O’er Hell—ten million devils dead!</p> 
+ 
+<p class="citeauth">G. J.</p> 
+ 
+ 
+ 
+      </td>   
+    </tr>   
+  </table>   
+     
+ 
+ 
+<p class="entry"><span class="def">fib,</span> <span class="pos"> n.</span> A lie that has not cut its teeth. An habitual liar’s 
+nearest approach to truth: the perigee of his eccentric orbit.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">When David said: “All men are liars,” Dave,<br /> 
+Himself a liar, fibbed like any thief.<br /> 
+Perhaps he thought to weaken disbelief<br /> 
+By proof that even himself was not a slave<br /> 
+To Truth; though I suspect the aged knave<br /> 
+Had been of all her servitors the chief<br /> 
+Had he but known a fig’s reluctant leaf<br /> 
+Is more than e’er she wore on land or wave.<br /> 
+No, David served not Naked Truth when he<br /> 
+Struck that sledge-hammer blow at all his race;<br /> 
+Nor did he hit the nail upon the head:<br /> 
+For reason shows that it could never be,<br /> 
+And the facts contradict him to his face.<br /> 
+Men are not liars all, for some are dead.</p> 
+ 
+<p class="citeauth">Bartle Quinker.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">fickleness,</span> <span class="pos"> n.</span> The iterated satiety of an 
+enterprising affection.</p> 
+ 
+<p class="entry"><span class="def">fiddle,</span> <span class="pos"> n.</span> An instrument to tickle human ears by 
+friction of a horse’s tail on the entrails of a cat.</p> 
+ 
+<p class="quote">To Rome said 
+Nero: “If to smoke you turn I shall not 
+cease to fiddle while you burn.” To Nero Rome replied: “Pray do your worst, 
+‘Tis my excuse that you were fiddling first.”&#8212;<i>Orm Pludge</i></p> 
+ 
+<p class="entry"><span class="def">fidelity,</span> <span class="pos"> n.</span> A virtue peculiar to those who are about to 
+be betrayed.</p> 
+ 
+<p class="entry"><span class="def">finance,</span> <span class="pos"> n.</span> The art or science of managing revenues and resources 
+for the best advantage of the manager. 
+The pronunciation of this word with the i long and the accent on the 
+first syllable is one of America’s most precious discoveries and possessions.</p> 
+ 
+<p class="entry"><span class="def">flag,</span> <span class="pos"> n.</span> A colored rag borne above troops and hoisted 
+on forts and ships. It appears to serve 
+the same purpose as certain signs that one sees and vacant lots in 
+London—“Rubbish may be shot here.”</p> 
+ 
+<p class="entry"><span class="def">flesh,</span> <span class="pos"> n.</span> The Second Person of the secular Trinity.</p> 
+ 
+<p class="entry"><span class="def">flop,</span> <span class="pos"> v.</span> Suddenly to change one’s opinions and go 
+over to another party. The most notable 
+flop on record was that of Saul of Tarsus, who has been severely criticised as 
+a turn-coat by some of our partisan journals.</p> 
+ 
+<p class="entry"><span class="def">fly-speck,</span> <span class="pos"> n.</span> The prototype of punctuation. It is observed by 
+Garvinus that the systems 
+of punctuation in use by the various literary nations depended originally upon 
+the social habits and general diet of the flies infesting the several 
+countries. These creatures, which have 
+always been distinguished for a neighborly and companionable familiarity with 
+authors, liberally or niggardly embellish the manuscripts in process of growth 
+under the pen, according to their bodily habit, bringing out the sense of the 
+work by a species of interpretation superior to, and independent of, the 
+writer’s powers. The “old masters” of 
+literature—that is to say, the early writers whose work is so esteemed by later 
+scribes and critics in the same language—never punctuated at all, but worked 
+right along free-handed, without that abruption of the thought which comes from 
+the use of points. (We observe the same 
+thing in children to-day, whose usage in this particular is a striking and 
+beautiful instance of the law that the infancy of individuals reproduces the 
+methods and stages of development characterizing the infancy of races.) 
+In the work of these primitive scribes all 
+the punctuation is found, by the modern investigator with his optical 
+instruments and chemical tests, to have been inserted by the writers’ ingenious 
+and serviceable collaborator, the common house-fly&#8212;<i>Musca maledicta</i>. 
+In transcribing these ancient MSS, for the purpose of either 
+making the work their own or preserving what they naturally regard as divine 
+revelations, later writers reverently and accurately copy whatever marks they 
+find upon the papyrus or parchment, to the unspeakable enhancement of the 
+lucidity of the thought and value of the work. 
+Writers contemporary with the copyists naturally avail themselves of the 
+obvious advantages of these marks in their own work, and with such assistance 
+as the flies of their own household may be willing to grant, frequently rival 
+and sometimes surpass the older compositions, in respect at least of 
+punctuation, which is no small glory. 
+Fully to understand the important services that flies perform to 
+literature it is only necessary to lay a page of some popular novelist 
+alongside a saucer of cream-and-molasses in a sunny room and observe “how the 
+wit brightens and the style refines” in accurate proportion to the duration of 
+exposure.</p> 
+ 
+<p class="entry"><span class="def">folly,</span> <span class="pos"> n.</span> That “gift and faculty divine” whose 
+creative and controlling energy inspires Man’s mind, guides his actions and 
+adorns his life.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Folly! although Erasmus praised thee once<br /> 
+In a thick volume, and all authors known,<br /> 
+If not thy glory yet thy power have shown,<br /> 
+Deign to take homage from thy son who hunts<br /> 
+Through all thy maze his brothers, fool and dunce,<br /> 
+To mend their lives and to sustain his own,<br /> 
+However feebly be his arrows thrown,<br /> 
+Howe’er each hide the flying weapons blunts.<br /> 
+All-Father Folly! be it mine to raise,<br /> 
+With lusty lung, here on his western strand<br /> 
+With all thine offspring thronged from every land,<br /> 
+Thyself inspiring me, the song of praise.<br /> 
+And if too weak, I’ll hire, to help me bawl,<br /> 
+Dick Watson Gilder, gravest of us all.</p> 
+ 
+<p class="citeauth">Aramis Loto Frope.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p id="fool" class="entry"><span class="def">fool,</span> <span class="pos"> n.</span> A person who pervades the domain of 
+intellectual speculation and diffuses himself through the channels of moral 
+activity. He is omnific, omniform, 
+omnipercipient, omniscience, omnipotent. 
+He it was who invented letters, printing, the railroad, the steamboat, 
+the telegraph, the platitude and the circle of the sciences. He created 
+patriotism and taught the nations 
+war—founded theology, philosophy, law, medicine and Chicago. He established 
+monarchical and republican 
+government. He is from everlasting to 
+everlasting—such as creation’s dawn beheld he fooleth now. In the morning 
+of time he sang upon 
+primitive hills, and in the noonday of existence headed the procession of 
+being. His grandmotherly hand was 
+warmly tucked-in the set sun of civilization, and in the twilight he prepares 
+Man’s evening meal of milk-and-morality and turns down the covers of the 
+universal grave. And after the rest of 
+us shall have retired for the night of eternal oblivion he will sit up to write 
+a history of human civilization.</p> 
+ 
+<p class="entry"><span class="def">force,</span> <span class="pos"> n.</span></p>
+
+  <table align="center" border="0">  
+    <tr>  
+      <td valign="top" align="left">   
+   
+<p class="poetry">“Force is but might,” the teacher said—<br /> 
+“That definition’s just.”<br /> 
+The boy said naught but through instead,<br /> 
+Remembering his pounded head:<br /> 
+“Force is not might but must!”</p> 
+ 
+      </td>   
+    </tr>   
+  </table>   
+     
+<p class="entry"><span class="def">forefinger,</span> <span class="pos"> n.</span> The finger commonly used in pointing out two malefactors.</p> 
+ 
+<p class="entry"><span class="def">foreordination,</span> <span class="pos"> n.</span> This looks like an easy word to 
+define, but when I consider that pious and learned theologians have spent long 
+lives in explaining it, and written libraries to explain their explanations; 
+when I remember the nations have been divided and bloody battles caused by the 
+difference between foreordination and predestination, and that millions of 
+treasure have been expended in the effort to prove and disprove its 
+compatibility with freedom of the will and the efficacy of prayer, praise, and 
+a religious life,&#82128;recalling these awful facts in the history of the word, I 
+stand appalled before the mighty problem of its signification, abase my 
+spiritual eyes, fearing to contemplate its portentous magnitude, reverently 
+uncover and humbly refer it to His Eminence Cardinal Gibbons and His Grace 
+Bishop Potter.</p> 
+ 
+<p class="entry"><span class="def">forgetfulness,</span> <span class="pos"> n.</span> A gift of God bestowed upon doctors 
+in compensation for their destitution of conscience.</p> 
+ 
+<p class="entry"><span class="def">fork,</span> <span class="pos"> n.</span> An instrument used chiefly for the purpose 
+of putting dead animals into the mouth. 
+Formerly the knife was employed for this purpose, and by many worthy 
+persons is still thought to have many advantages over the other tool, which, 
+however, they do not altogether reject, but use to assist in charging the 
+knife. The immunity of these persons 
+from swift and awful death is one of the most striking proofs of God’s mercy to 
+those that hate Him.</p> 
+ 
+<p class="entry"><span class="def">forma pauperis.</span> <span class="pos"> [Latin]</span> In the character of a poor person—a method 
+by which a litigant without money for lawyers is considerately permitted to 
+lose his case.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">When Adam long ago in Cupid’s awful court<br /> 
+(For Cupid ruled ere Adam was invented)<br /> 
+Sued for Eve’s favor, says an ancient law report,<br /> 
+He stood and pleaded unhabilimented.<br />
+“You sue <i>in forma pauperis</i>, I see,” Eve cried;<br /> 
+“Actions can’t here be that way prosecuted.”<br /> 
+So all poor Adam’s motions coldly were denied:<br /> 
+He went away—as he had come—nonsuited.</p>
+
+<p class="citeauth">G. J.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">Frankalmoigne,</span> <span class="pos"> n.</span> The tenure by which a religious 
+corporation holds lands on condition of praying for the soul of the donor. 
+In mediaeval times many of the wealthiest 
+fraternities obtained their estates in this simple and cheap manner, and once 
+when Henry VIII of England sent an officer to confiscate certain vast 
+possessions which a fraternity of monks held by frankalmoigne, “What!” said the 
+Prior, “would you master stay our benefactor’s soul in Purgatory?” “Ay,” 
+said the officer, coldly, “an ye will 
+not pray him thence for naught he must e’en roast.” “But look you, my son,” 
+persisted the good man, “this act hath 
+rank as robbery of God!” “Nay, nay, 
+good father, my master the king doth but deliver him from the manifold 
+temptations of too great wealth.”</p> 
+ 
+<p class="entry"><span class="def">freebooter,</span> <span class="pos"> n.</span> A conqueror in a small way of 
+business, whose annexations lack of the sanctifying merit of magnitude.</p> 
+ 
+<p class="entry"><span class="def">freedom,</span> <span class="pos"> n.</span> Exemption from the stress of authority in a 
+beggarly half dozen of restraint’s infinite multitude of methods. A political 
+condition that every nation 
+supposes itself to enjoy in virtual monopoly. 
+Liberty. The distinction between 
+freedom and liberty is not accurately known; naturalists have never been able 
+to find a living specimen of either.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Freedom, as every schoolboy knows,<br /> 
+Once shrieked as Kosciusko fell;<br /> 
+On every wind, indeed, that blows<br /> 
+I hear her yell.<br /> 
+She screams whenever monarchs meet,<br /> 
+And parliaments as well,<br /> 
+To bind the chains about her feet<br /> 
+And toll her knell.<br /> 
+And when the sovereign people cast<br /> 
+The votes they cannot spell,<br /> 
+Upon the pestilential blast<br /> 
+Her clamors swell.<br /> 
+For all to whom the power’s given<br /> 
+To sway or to compel,<br /> 
+Among themselves apportion Heaven<br /> 
+And give her Hell.</p> 
+ 
+<p class="citeauth">Blary O’Gary.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">Freemasons,</span> <span class="pos"> n.</span> An order with secret rites, 
+grotesque ceremonies and fantastic costumes, which, originating in the reign of 
+Charles II, among working artisans of London, has been joined successively by 
+the dead of past centuries in unbroken retrogression until now it embraces all 
+the generations of man on the hither side of Adam and is drumming up 
+distinguished recruits among the pre-Creational inhabitants of Chaos and 
+Formless Void. The order was founded at 
+different times by Charlemagne, Julius Caesar, Cyrus, Solomon, Zoroaster, 
+Confucious, Thothmes, and Buddha. Its 
+emblems and symbols have been found in the Catacombs of Paris and Rome, on the 
+stones of the Parthenon and the Chinese Great Wall, among the temples of Karnak 
+and Palmyra and in the Egyptian Pyramids—always by a Freemason.</p> 
+ 
+<p class="entry"><span class="def">friendless,</span> <span class="pos"> adj.</span> Having no favors to bestow. Destitute of fortune. 
+Addicted to utterance of truth and common sense. </p> 
+ 
+<p class="entry"><span class="def">friendship,</span> <span class="pos"> n.</span> A ship big enough to carry two in fair weather, but only one in foul.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">The sea was calm and the sky was blue;<br /> 
+Merrily, merrily sailed we two.<br /> 
+(High barometer maketh glad.)<br /> 
+On the tipsy ship, with a dreadful shout,<br /> 
+The tempest descended and we fell out.<br /> 
+(O the walking is nasty bad!)</p> 
+ 
+<p class="citeauth">Armit Huff Bettle.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">frog,</span> <span class="pos"> n.</span> A reptile with edible legs. The first mention of frogs in profane 
+literature is in Homer’s narrative of the war between them and the mice. 
+Skeptical persons have doubted Homer’s 
+authorship of the work, but the learned, ingenious and industrious Dr. Schliemann 
+has set the question forever at rest by uncovering the bones of the slain 
+frogs. One of the forms of moral 
+suasion by which Pharaoh was besought to favor the Israelities was a plague of 
+frogs, but Pharaoh, who liked them <i>fricasees</i>, 
+remarked, with truly oriental stoicism, that he could stand it as long as the 
+frogs and the Jews could; so the programme was changed. The frog is a 
+diligent songster, having a 
+good voice but no ear. The libretto of 
+his favorite opera, as written by Aristophanes, is brief, simple and 
+effective—“brekekex-koax”; the music is apparently by that eminent composer, 
+Richard Wagner. Horses have a frog in 
+each hoof—a thoughtful provision of nature, enabling them to shine in a hurdle 
+race.</p> 
+ 
+<p class="entry"><span class="def">frying-pan,</span> <span class="pos"> n.</span> One part of the penal apparatus 
+employed in that punitive institution, a woman’s kitchen. The frying-pan was 
+invented by Calvin, and 
+by him used in cooking span-long infants that had died without baptism; and 
+observing one day the horrible torment of a tramp who had incautiously pulled a 
+fried babe from the waste-dump and devoured it, it occurred to the great divine 
+to rob death of its terrors by introducing the frying-pan into every household 
+in Geneva. Thence it spread to all 
+corners of the world, and has been of invaluable assistance in the propagation 
+of his sombre faith. The following 
+lines (said to be from the pen of his Grace Bishop Potter) seem to imply that 
+the usefulness of this utensil is not limited to this world; but as the 
+consequences of its employment in this life reach over into the life to come, 
+so also itself may be found on the other side, rewarding its devotees:</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">Old Nick was summoned to the skies.<br /> 
+Said Peter: “Your intentions<br /> 
+Are good, but you lack enterprise<br /> 
+Concerning new inventions.<br /> 
+“Now, broiling in an ancient plan<br /> 
+Of torment, but I hear it<br /> 
+Reported that the frying-pan<br /> 
+Sears best the wicked spirit.<br /> 
+“Go get one—fill it up with fat—<br /> 
+Fry sinners brown and good in’t.”<br />
+“I know a trick worth two o’ that,”<br /> 
+Said Nick—“I’ll cook their food in’t.”</p>
+
+<p class="citeauth">&nbsp;</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p id="funeral" class="entry"><span class="def">funeral,</span> <span class="pos"> n.</span> A pageant whereby we attest our respect for 
+the dead by enriching the undertaker, and strengthen our grief by an 
+expenditure that deepens our groans and doubles our tears.</p> 
+ 
+  <table align="center" border="0">   
+    <tr>   
+      <td valign="top" align="left">    
+    
+<p class="poetry">The savage dies—they sacrifice a horse<br /> 
+To bear to happy hunting-grounds the corse.<br />
+Our friends expire—we make the money fly<br /> 
+In 
+hope their souls will chase it to the sky.</p> 
+ 
+<p class="citeauth">Jex Wopley.</p>
+
+      </td>  
+    </tr>  
+  </table>  
+    
+<p class="entry"><span class="def">future,</span> <span class="pos"> n.</span> That period of time in which our affairs 
+prosper, our friends are true and our happiness is assured.</p>
+
+</body>
+
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/F.html.i
@@ -1,0 +1,34 @@
+14 pages
+size 400 552
+length 25380
+390 2 11 body html
+0
+2225 2 42 body html
+0
+3791 2 115 body html
+39
+4962 2 135 body html
+0
+4962 2 135 body html
+552
+8145 2 227 body html
+0
+9883 2 258 body html
+141
+12382 2 295 body html
+22
+13518 2 324 body html
+243
+16357 2 378 body html
+39
+18626 2 424 body html
+0
+20026 2 462 body html
+90
+21721 2 497 body html
+175
+23819 2 530 body html
+0
+famous 0
+funeral 12
+fool 7
--- /dev/null
+++ b/lib/ebooks/devils/G.html
@@ -1,0 +1,313 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: D</title>
+</head>
+<body lang="en-US">
+
+<h1>G</h1>
+
+
+<p class="entry"><span class="def">gallows</span>, <span class="pos">n.</span> A stage for the performance of miracle plays, in which the leading actor is
+translated to heaven. In this country the gallows is chiefly remarkable for the
+number of persons who escape it.</p>
+
+<div class="poem">
+<p class="poetry">Whether on the gallows high</p>
+<p class="poetry">Or where blood flows the reddest, The noblest place for man to die—</p>
+<p class="poetry">Is where he died the deadest.</p>
+<p class="citeauth">(Old play)</p>
+</div>
+
+<p class="entry"><span class="def">gargoyle</span>, <span class="pos">n.</span> A rain-pout projecting from the eaves of mediaeval buildings, commonly fashioned
+into a grotesque caricature of some personal enemy of the architect or owner of
+the building. This was especially the case in churches and ecclesiastical
+structures generally, in which the gargoyles presented a perfect rogues’
+gallery of local heretics and controversialists. Sometimes when a new dean and
+chapter were installed the old gargoyles were removed and others substituted
+having a closer relation to the private animosities of the new incumbents.</p>
+
+<p class="entry"><span class="def">garther</span>, <span class="pos">n.</span> An elastic band intended to keep a woman from coming out of her stockings and
+desolating the country.</p>
+
+<p class="entry"><span class="def">generous</span>, <span class="pos">adj.</span> Originally this word meant noble by birth and was rightly applied to a great multitude of
+persons. It now means noble by nature and is taking a bit of a rest.</p>
+
+<p class="entry"><span class="def">genealogy</span>, <span class="pos">n.</span> An account of one’s descent from an ancestor who did not particularly care to trace his own.</p>
+
+<p class="entry"><span class="def">genteel</span>, <span class="pos">adj.</span> Refined, after the fashion of a gent.</p>
+
+<div class="poem">
+<p class="poetry">Observe with care, my son, the distinction I reveal:</p>
+<p class="poetry">A gentleman is gentle and a gent genteel.</p>
+<p class="poetry">Heed not the definitions your “Unabridged” presents,</p>
+<p class="poetry">For dictionary makers are generally gents.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">geographer</span>, <span class="pos">n.</span> A chap who can tell you offhand the difference between the outside of the world and the inside.</p>
+
+<div class="poem">
+<p class="poetry">Habeam, geographer of wide reknown,</p>
+<p class="poetry">Native of Abu-Keber’s ancient town,</p>
+<p class="poetry">In passing thence along the river Zam</p>
+<p class="poetry">To the adjacent village of Xelam,</p>
+<p class="poetry">Bewildered by the multitude of roads,</p>
+<p class="poetry">Got lost, lived long on migratory toads,</p>
+<p class="poetry">Then from exposure miserably died,</p>
+<p class="poetry">And grateful travelers bewailed their guide.</p>
+<p class="citeauth">Henry Haukhorn</p>
+</div>
+
+<p class="entry"><span class="def">geology</span>, <span class="pos">n.</span> The science of the earth’s crust—to which, doubtless, will be added that of its
+interior whenever a man shall come up garrulous out of a well. The geological
+formations of the globe already noted are catalogued thus: The Primary, or
+lower one, consists of rocks, bones or mired mules, gas-pipes, miners’ tools,
+antique statues minus the nose, Spanish doubloons and ancestors. The Secondary
+is largely made up of red worms and moles. The Tertiary comprises railway
+tracks, patent pavements, grass, snakes, mouldy boots, beer bottles, tomato
+cans, intoxicated citizens, garbage, anarchists, snap-dogs and fools.</p>
+
+<p class="entry"><span class="def">ghost</span>, <span class="pos">n.</span> The outward and visible sign of an inward fear.</p>
+
+<div class="poem">
+<p class="poetry">He saw a ghost.</p>
+<p class="poetry">It occupied—that dismal thing!&#8212;</p>
+<p class="poetry">The path that he was following.</p>
+<p class="poetry">Before he’d time to stop and fly,</p>
+<p class="poetry">An earthquake trifled with the eye</p>
+<p class="poetry">That saw a ghost.</p>
+<p class="poetry">He fell as fall the early good;</p>
+<p class="poetry">Unmoved that awful vision stood.</p>
+<p class="poetry">The stars that danced before his ken</p>
+<p class="poetry">He wildly brushed away, and then</p>
+<p class="poetry">He saw a post.</p>
+<p class="citeauth">Jared Macphester</p>
+</div>
+
+<p class="indentpara">Accounting for the uncommon behavior of ghosts, Heine mentions somebody’s ingenious theory to the
+effect that they are as much afraid of us as we of them. Not quite, if I may
+judge from such tables of comparative speed as I am able to compile from
+memories of my own experience.</p>
+
+<p class="indentpara">There is one insuperable obstacle to a belief in ghosts. A ghost never comes naked: he
+appears either in a winding-sheet or “in his habit as he lived.” To believe in
+him, then, is to believe that not only have the dead the power to make
+themselves visible after there is nothing left of them, but that the same power
+inheres in textile fabrics. Supposing the products of the loom to have this
+ability, what object would they have in exercising it? And why does not the
+apparition of a suit of clothes sometimes walk abroad without a ghost in it? These
+be riddles of significance. They reach away down and get a convulsive grip on
+the very tap-root of this flourishing faith.</p>
+
+<p class="entry"><span class="def">ghoul</span>, <span class="pos">n.</span> A demon addicted to the reprehensible habit of devouring the dead. The existence of
+ghouls has been disputed by that class of controversialists who are more
+concerned to deprive the world of comforting beliefs than to give it anything
+good in their place. In 1640 Father Secchi saw one in a cemetery near Florence
+and frightened it away with the sign of the cross. He describes it as gifted
+with many heads an an uncommon allowance of limbs, and he saw it in more than
+one place at a time. The good man was coming away from dinner at the time and
+explains that if he had not been “heavy with eating” he would have seized the
+demon at all hazards. Atholston relates that a ghoul was caught by some sturdy
+peasants in a churchyard at Sudbury and ducked in a horsepond. (He appears to
+think that so distinguished a criminal should have been ducked in a tank of
+rosewater.) The water turned at once to blood “and so contynues unto ys daye.” The
+pond has since been bled with a ditch. As late as the beginning of the
+fourteenth century a ghoul was cornered in the crypt of the cathedral at Amiens
+and the whole population surrounded the place. Twenty armed men with a priest
+at their head, bearing a crucifix, entered and captured the ghoul, which,
+thinking to escape by the stratagem, had transformed itself to the semblance of
+a well known citizen, but was nevertheless hanged, drawn and quartered in the
+midst of hideous popular orgies. The citizen whose shape the demon had assumed
+was so affected by the sinister occurrence that he never again showed himself
+in Amiens and his fate remains a mystery.</p>
+
+<p class="entry"><span class="def">glutton</span>, <span class="pos">n.</span> A person who escapes the evils of moderation by committing dyspepsia.</p>
+
+<p class="entry"><span class="def">gnome</span>, <span class="pos">n.</span> In North-European mythology, a dwarfish imp inhabiting the interior parts of the
+earth and having special custody of mineral treasures. Bjorsen, who died in
+1765, says gnomes were common enough in the southern parts of Sweden in his
+boyhood, and he frequently saw them scampering on the hills in the evening
+twilight. Ludwig Binkerhoof saw three as recently as 1792, in the Black Forest,
+and Sneddeker avers that in 1803 they drove a party of miners out of a Silesian
+mine. Basing our computations upon data supplied by these statements, we find
+that the gnomes were probably extinct as early as 1764.</p>
+
+<p class="entry"><span class="def">gnostics</span>, <span class="pos">n.</span> A sect of philosophers who tried to engineer a fusion between the early
+Christians and the Platonists. The former would not go into the caucus and the
+combination failed, greatly to the chagrin of the fusion managers.</p>
+
+<p class="entry"><span class="def">gnu</span>, <span class="pos">n.</span> An animal of South Africa, which in its domesticated state resembles a horse, a buffalo
+and a stag. In its wild condition it is something like a thunderbolt, an
+earthquake and a cyclone.</p>
+
+<div class="poem">
+<p class="poetry">A hunter from Kew caught a distant view</p>
+<p class="poetry">Of a peacefully meditative gnu,</p>
+<p class="poetry">And he said: “I’ll pursue, and my hands imbrue</p>
+<p class="poetry">In its blood at a closer interview.”</p>
+<p class="poetry">But that beast did ensue and the hunter it threw</p>
+<p class="poetry">O’er the top of a palm that adjacent grew;</p>
+<p class="poetry">And he said as he flew: “It is well I withdrew</p>
+<p class="poetry">Ere, losing my temper, I wickedly slew That really meritorious gnu.”</p>
+<p class="citeauth">Jarn Leffer</p>
+</div>
+
+<p class="entry"><span class="def">good</span>, <span class="pos">adj.</span> Sensible, madam,
+to the worth of this present writer.</p>
+
+<p>Alive, sir, to the advantages of letting him alone.</p>
+
+<p class="entry"><span class="def">goose</span>, <span class="pos">n.</span> A bird that supplies quills for writing. These, by some occult process of nature, are
+penetrated and suffused with various degrees of the bird’s intellectual
+energies and emotional character, so that when inked and drawn mechanically
+across paper by a person called an “author,” there results a very fair and
+accurate transcript of the fowl’s thought and feeling. The difference in geese,
+as discovered by this ingenious method, is considerable: many are found to have
+only trivial and insignificant powers, but some are seen to be very great geese
+indeed.</p>
+
+<p class="entry"><span class="def">gorgon</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">The Gorgon was a maiden bold</p>
+<p class="poetry">Who turned to stone the Greeks of old</p>
+<p class="poetry">That looked upon her awful brow.</p>
+<p class="poetry">We dig them out of ruins now,</p>
+<p class="poetry">And swear that workmanship so bad</p>
+<p class="poetry">Proves all the ancient sculptors mad.</p>
+</div>
+<p class="entry"><span class="def">gout</span>, <span class="pos">n.</span> A physician’s name for the rheumatism of a rich patient.</p>
+
+<p class="entry"><span class="def">graces</span>, <span class="pos">n.</span> Three beautiful goddesses, Aglaia, Thalia and Euphrosyne, who attended upon Venus,
+serving without salary. They were at no expense for board and clothing, for
+they ate nothing to speak of and dressed according to the weather, wearing
+whatever breeze happened to be blowing.</p>
+
+<p class="entry"><span class="def">grammar</span>, <span class="pos">n.</span> A system of pitfalls thoughtfully prepared for the feet for the self-made man,
+along the path by which he advances to distinction.</p>
+
+<p class="entry"><span class="def">grape</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Hail noble fruit!&#8212;by Homer sung,</p>
+<p class="poetry">Anacreon and Khayyam;</p>
+<p class="poetry">Thy praise is ever on the tongue</p>
+<p class="poetry">Of better men than I am.</p>
+<p class="poetry">The lyre in my hand has never swept,</p>
+<p class="poetry">The song I cannot offer:</p>
+<p class="poetry">My humbler service pray accept—</p>
+<p class="poetry">I’ll help to kill the scoffer.</p>
+<p class="poetry">The water-drinkers and the cranks</p>
+<p class="poetry">Who load their skins with liquor—</p>
+<p class="poetry">I’ll gladly bear their belly-tanks</p>
+<p class="poetry">And tap them with my sticker.</p>
+<p class="poetry">Fill up, fill up, for wisdom cools</p>
+<p class="poetry">When e’er we let the wine rest.</p>
+<p class="poetry">Here’s death to Prohibition’s fools,</p>
+<p class="poetry">And every kind of vine-pest!</p>
+<p class="citeauth">Jamrach Holobom</p>
+</div>
+
+<p class="entry"><span class="def">grapeshot</span>, <span class="pos">n.</span> An argument which the future is preparing in answer to the demands of American Socialism.</p>
+
+<p class="entry"><span class="def">grave</span>, <span class="pos">n.</span> A place in which the dead are laid to await the coming of the medical student.</p>
+
+<div class="poem">
+<p class="poetry">Beside a lonely grave I stood—</p>
+<p class="poetry">With brambles ‘twas encumbered;</p>
+<p class="poetry">The winds were moaning in the wood,</p>
+<p class="poetry">Unheard by him who slumbered,</p>
+<p class="poetry">A rustic standing near, I said:</p>
+<p class="poetry">“He cannot hear it blowing!”</p>
+<p class="poetry">“’Course not,” said he: “the feller’s dead—</p>
+<p class="poetry">He can’t hear nowt [sic] that’s going.”</p>
+<p class="poetry">“Too true,” I said; “alas, too true—</p>
+<p class="poetry">No sound his sense can quicken!”</p>
+<p class="poetry">“Well, mister, wot is that to you?&#8212;</p>
+<p class="poetry">The deadster ain’t a-kickin’.”</p>
+<p class="poetry">I knelt and prayed: “O Father, smile</p>
+<p class="poetry">On him, and mercy show him!”</p>
+<p class="poetry">That countryman looked on the while,</p>
+<p class="poetry">And said: “Ye didn’t know him.”</p>
+<p class="citeauth">Pobeter Dunko</p>
+</div>
+
+<p class="entry"><span class="def">gravitation</span>, <span class="pos">n.</span> The tendency of all bodies to approach one another with a strength proportion to
+the quantity of matter they contain—the quantity of matter they contain being
+ascertained by the strength of their tendency to approach one another. This is
+a lovely and edifying illustration of how science, having made A the proof of
+B, makes B the proof of A.</p>
+
+<p class="entry"><span class="def">great</span>, <span class="pos">adj.</span></p>
+
+<div class="poem">
+<p class="poetry">“I’m great,” the Lion said—“I reign</p>
+<p class="poetry">The monarch of the wood and plain!”</p>
+<p class="poetry">The Elephant replied: “I’m great—</p>
+<p class="poetry">No quadruped can match my weight!”</p>
+<p class="poetry">“I’m great—no animal has half</p>
+<p class="poetry">So long a neck!” said the Giraffe.</p>
+<p class="poetry">“I’m great,” the Kangaroo said—“see</p>
+<p class="poetry">My femoral muscularity!”</p>
+<p class="poetry">The ‘Possum said: “I’m great—behold,</p>
+<p class="poetry">My tail is lithe and bald and cold!”</p>
+<p class="poetry">An Oyster fried was understood</p>
+<p class="poetry">To say: “I’m great because I’m good!”</p>
+<p class="poetry">Each reckons greatness to consist</p>
+<p class="poetry">In that in which he heads the list,</p>
+<p class="poetry">And Vierick thinks he tops his class</p>
+<p class="poetry">Because he is the greatest ass.</p>
+<p class="citeauth">Arion Spurl Doke</p>
+</div>
+
+<p class="entry"><span class="def">guillotine</span>, <span class="pos">n.</span> A machine which makes a Frenchman shrug his shoulders with good reason.</p>
+
+<p>In his great work on <i>Divergent Lines of Racial Evolution</i>,
+the learned Professor Brayfugle argues from the prevalence of this gesture&#8212;
+the shrug—among Frenchmen, that they are descended from turtles and it is
+simply a survival of the habit of retracing the head inside the shell. It is
+with reluctance that I differ with so eminent an authority, but in my judgment
+(as more elaborately set forth and enforced in my work entitled <i>Hereditary Emotions</i>&#8212;lib. II, c. XI) the
+shrug is a poor foundation upon which to build so important a theory, for
+previously to the Revolution the gesture was unknown. I have not a doubt that
+it is directly referable to the terror inspired by the guillotine during the
+period of that instrument’s activity.</p>
+
+<p class="entry"><span class="def">gunpowder</span>, <span class="pos">n.</span> An agency employed by civilized nations for the settlement of disputes which might
+become troublesome if left unadjusted. By most writers the invention of
+gunpowder is ascribed to the Chinese, but not upon very convincing evidence. Milton
+says it was invented by the devil to dispel angels with, and this opinion seems
+to derive some support from the scarcity of angels. Moreover, it has the hearty
+concurrence of the Hon. James Wilson, Secretary of Agriculture.</p>
+
+<p>Secretary Wilson became interested in gunpowder through an event that occurred on the Government
+experimental farm in the District of Columbia. One day, several years ago, a
+rogue imperfectly reverent of the Secretary’s profound attainments and personal
+character presented him with a sack of gunpowder, representing it as the sed of
+the <i>Flashawful flabbergastor</i>, a
+Patagonian cereal of great commercial value, admirably adapted to this climate.
+The good Secretary was instructed to spill it along in a furrow and afterward
+inhume it with soil. This he at once proceeded to do, and had made a continuous
+line of it all the way across a ten-acre field, when he was made to look
+backward by a shout from the generous donor, who at once dropped a lighted
+match into the furrow at the starting-point. Contact with the earth had
+somewhat dampened the powder, but the startled functionary saw himself pursued
+by a tall moving pillar of fire and smoke and fierce evolution. He stood for a
+moment paralyzed and speechless, then he recollected an engagement and,
+dropping all, absented himself thence with such surprising celerity that to the
+eyes of spectators along the route selected he appeared like a long, dim streak
+prolonging itself with inconceivable rapidity through seven villages, and
+audibly refusing to be comforted. “Great Scott! what is that?” cried a
+surveyor’s chainman, shading his eyes and gazing at the fading line of
+agriculturist which bisected his visible horizon. “That,” said the surveyor,
+carelessly glancing at the phenomenon and again centering his attention upon
+his instrument, “is the Meridian of Washington.”</p>
+
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/G.html.i
@@ -1,0 +1,31 @@
+14 pages
+size 400 552
+length 18661
+396 2 10 body html
+0
+1752 2 37 body html
+0
+2826 2 54 body html
+199
+4203 2 77 body html
+199
+5148 2 97 body html
+187
+7699 2 131 body html
+0
+8953 2 148 body html
+199
+10495 2 176 body html
+127
+11649 2 196 body html
+252
+12929 2 220 body html
+91
+13952 2 240 body html
+0
+14469 2 248 body html
+415
+16428 2 281 body html
+56
+16977 2 288 body html
+459
--- /dev/null
+++ b/lib/ebooks/devils/H.html
@@ -1,0 +1,432 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: H</title>
+</head>
+<body lang="en-US">
+
+
+<h1>H</h1>
+
+
+<p class="entry"><span class="def">habeas corpus.</span> A writ by which a man may be taken out of jail when confined for the wrong crime.</p>
+
+<p class="entry"><span class="def">habit</span>, <span class="pos">n.</span> A shackle for the free.</p>
+
+<p class="entry"><span class="def">hades</span>, <span class="pos">n.</span> The lower world;
+the residence of departed spirits; the place where the dead live.</p>
+
+<p>Among the ancients the idea of Hades was not synonymous with our Hell, many of the most
+respectable men of antiquity residing there in a very comfortable kind of way. Indeed,
+the Elysian Fields themselves were a part of Hades, though they have since been
+removed to Paris. When the Jacobean version of the New Testament was in process
+of evolution the pious and learned men engaged in the work insisted by a
+majority vote on translating the Greek word “Aides” as “Hell”; but a
+conscientious minority member secretly possessed himself of the record and
+struck out the objectional word wherever he could find it. At the next meeting,
+the Bishop of Salisbury, looking over the work, suddenly sprang to his feet and
+said with considerable excitement: “Gentlemen, somebody has been razing ‘Hell’
+here!” Years afterward the good prelate’s death was made sweet by the
+reflection that he had been the means (under Providence) of making an
+important, serviceable and immortal addition to the phraseology of the English
+tongue.</p>
+
+<p class="entry"><span class="def">hag</span>, <span class="pos">n.</span> An elderly lady whom you do not happen to like; sometimes called, also, a hen, or cat. Old
+witches, sorceresses, etc., were called hags from the belief that their heads
+were surrounded by a kind of baleful lumination or nimbus—hag being the popular
+name of that peculiar electrical light sometimes observed in the hair. At one
+time hag was not a word of reproach: Drayton speaks of a “beautiful hag, all
+smiles,” much as Shakespeare said, “sweet wench.” It would not now be proper to
+call your sweetheart a hag—that compliment is reserved for the use of her
+grandchildren.</p>
+
+<p class="entry"><span class="def">half</span>, <span class="pos">n.</span> One of two equal parts into which a thing may be divided, or considered as divided. In
+the fourteenth century a heated discussion arose among theologists and
+philosophers as to whether Omniscience could part an object into three halves;
+and the pious Father Aldrovinus publicly prayed in the cathedral at Rouen that
+God would demonstrate the affirmative of the proposition in some signal and
+unmistakable way, and particularly (if it should please Him) upon the body of
+that hardy blasphemer, Manutius Procinus, who maintained the negative. Procinus,
+however, was spared to die of the bite of a viper.</p>
+
+<p class="entry"><span class="def">halo</span>, <span class="pos">n.</span> Properly, a luminous ring encircling an astronomical body, but not infrequently
+confounded with “aureola,” or “nimbus,” a somewhat similar phenomenon worn as a
+head-dress by divinities and saints. The halo is a purely optical illusion,
+produced by moisture in the air, in the manner of a rainbow; but the aureola is
+conferred as a sign of superior sanctity, in the same way as a bishop’s mitre,
+or the Pope’s tiara. In the painting of the Nativity, by Szedgkin, a pious artist
+of Pesth, not only do the Virgin and the Child wear the nimbus, but an ass
+nibbling hay from the sacred manger is similarly decorated and, to his lasting
+honor be it said, appears to bear his unaccustomed dignity with a truly saintly
+grace.</p>
+
+<p class="entry"><span class="def">hand</span>, <span class="pos">n.</span> A singular instrument worn at the end of the human arm and commonly thrust into
+somebody’s pocket.</p>
+
+<p class="entry"><span class="def">handkerchief</span>, <span class="pos">n.</span> A small square of silk or linen, used in various ignoble offices about the face
+and especially serviceable at funerals to conceal the lack of tears. The
+handkerchief is of recent invention; our ancestors knew nothing of it and
+intrusted its duties to the sleeve. Shakespeare’s introducing it into the play
+of “Othello” is an anachronism: Desdemona dried her nose with her skirt, as Dr.
+Mary Walker and other reformers have done with their coattails in our own
+day—an evidence that revolutions sometimes go backward.</p>
+
+<p class="entry"><span class="def">hangman</span>, <span class="pos">n.</span> An officer of the law charged with duties of the highest dignity and utmost
+gravity, and held in hereditary disesteem by a populace having a criminal
+ancestry. In some of the American States his functions are now performed by an
+electrician, as in New Jersey, where executions by electricity have recently
+been ordered—the first instance known to this lexicographer of anybody
+questioning the expediency of hanging Jerseymen.</p>
+
+<p class="entry"><span class="def">happiness</span>, <span class="pos">n.</span> An agreeable sensation arising from contemplating the misery of another.</p>
+
+<p class="entry"><span class="def">harangue</span>, <span class="pos">n.</span> A speech by an opponent, who is known as an harrangue- outang.</p>
+
+<p class="entry"><span class="def">harbor</span>, <span class="pos">n.</span> A place where ships taking shelter from stores are exposed to the fury of the customs.</p>
+
+<p class="entry"><span class="def">harmonists</span>, <span class="pos">n.</span> A sect of Protestants, now extinct, who came from Europe in the beginning of the
+last century and were distinguished for the bitterness of their internal controversies and dissensions.</p>
+
+<p class="entry"><span class="def">hash,</span> <span class="pos">x.</span> There is no definition for this word—nobody knows what hash is.</p>
+
+<p class="entry"><span class="def">hatchet</span>, <span class="pos">n.</span> A young axe, known among Indians as a Thomashawk.</p>
+
+<div class="poem">
+<p class="poetry">“O bury the hatchet, irascible Red,</p>
+<p class="poetry">For peace is a blessing,” the White Man said.</p>
+<p class="poetry">The Savage concurred, and that weapon interred, With imposing rites, in the White Man’s head.</p>
+<p class="poetry">John Lukkus</p>
+</div>
+
+<p class="entry"><span class="def">hatred</span>, <span class="pos">n.</span> A sentiment appropriate to the occasion of another’s superiority.</p>
+
+<p class="entry"><span class="def">head-money</span>, <span class="pos">n.</span> A capitation tax, or poll-tax.</p>
+
+<div class="poem">
+<p class="poetry">In ancient times there lived a king</p>
+<p class="poetry">Whose tax-collectors could not wring</p>
+<p class="poetry">From all his subjects gold enough</p>
+<p class="poetry">To make the royal way less rough.</p>
+<p class="poetry">For pleasure’s highway, like the dames</p>
+<p class="poetry">Whose premises adjoin it, claims</p>
+<p class="poetry">Perpetual repairing. So</p>
+<p class="poetry">The tax-collectors in a row</p>
+<p class="poetry">Appeared before the throne to pray</p>
+<p class="poetry">Their master to devise some way</p>
+<p class="poetry">To swell the revenue. “So great,”</p>
+<p class="poetry">Said they, “are the demands of state</p>
+<p class="poetry">A tithe of all that we collect</p>
+<p class="poetry">Will scarcely meet them. Pray reflect:</p>
+<p class="poetry">How, if one-tenth we must resign,</p>
+<p class="poetry">Can we exist on t’other nine?”</p>
+<p class="poetry">The monarch asked them in reply:</p>
+<p class="poetry">“Has it occurred to you to try</p>
+<p class="poetry">The advantage of economy?”</p>
+<p class="poetry">“It has,” the spokesman said: “we sold</p>
+<p class="poetry">All of our gray garrotes of gold;</p>
+<p class="poetry">With plated-ware we now compress</p>
+<p class="poetry">The necks of those whom we assess.</p>
+<p class="poetry">Plain iron forceps we employ</p>
+<p class="poetry">To mitigate the miser’s joy</p>
+<p class="poetry">Who hoards, with greed that never tires,</p>
+<p class="poetry">That which your Majesty requires.”</p>
+<p class="poetry">Deep lines of thought were seen to plow</p>
+<p class="poetry">Their way across the royal brow.</p>
+<p class="poetry">“Your state is desperate, no question;</p>
+<p class="poetry">Pray favor me with a suggestion.”</p>
+<p class="poetry">“O King of Men,” the spokesman said,</p>
+<p class="poetry">“If you’ll impose upon each head</p>
+<p class="poetry">A tax, the augmented revenue</p>
+<p class="poetry">We’ll cheerfully divide with you.”</p>
+<p class="poetry">As flashes of the sun illume</p>
+<p class="poetry">The parted storm-cloud’s sullen gloom,</p>
+<p class="poetry">The king smiled grimly. “I decree</p>
+<p class="poetry">That it be so—and, not to be</p>
+<p class="poetry">In generosity outdone,</p>
+<p class="poetry">Declare you, each and every one,</p>
+<p class="poetry">Exempted from the operation</p>
+<p class="poetry">Of this new law of capitation.</p>
+<p class="poetry">But lest the people censure me</p>
+<p class="poetry">Because they’re bound and you are free,</p>
+<p class="poetry">‘Twere well some clever scheme were laid</p>
+<p class="poetry">By you this poll-tax to evade.</p>
+<p class="poetry">I’ll leave you now while you confer</p>
+<p class="poetry">With my most trusted minister.”</p>
+<p class="poetry">The monarch from the throne-room walked</p>
+<p class="poetry">And straightway in among them stalked</p>
+<p class="poetry">A silent man, with brow concealed,</p>
+<p class="poetry">Bare-armed—his gleaming axe revealed!</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">hearse</span>, <span class="pos">n.</span> Death’s baby-carriage.</p>
+
+<p class="entry"><span class="def">heart</span>, <span class="pos">n.</span> An automatic, muscular blood-pump. Figuratively, this useful organ is said to be
+the esat of emotions and sentiments—a very pretty fancy which, however, is
+nothing but a survival of a once universal belief. It is now known that the
+sentiments and emotions reside in the stomach, being evolved from food by
+chemical action of the gastric fluid. The exact process by which a beefsteak
+becomes a feeling—tender or not, according to the age of the animal from which
+it was cut; the successive stages of elaboration through which a caviar
+sandwich is transmuted to a quaint fancy and reappears as a pungent epigram;
+the marvelous functional methods of converting a hard-boiled egg into religious
+contrition, or a cream-puff into a sigh of sensibility—these things have been
+patiently ascertained by M. Pasteur, and by him expounded with convincing
+lucidity. (See, also, my monograph, <i>The Essential Identity of the Spiritual
+Affections and Certain Intestinal Gases Freed in Digestion</i>&#8212;4to, 687 pp.) In
+a scientific work entitled, I believe, <i>Delectatio
+Demonorum</i> (John Camden Hotton, London, 1873) this view of the
+sentiments receives a striking illustration; and for further light consult
+Professor Dam’s famous treatise on <i>Love as a
+Product of Alimentary Maceration</i>.</p>
+
+<p class="entry"><span class="def">heat</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Heat, says Professor Tyndall, is a mode</p>
+<p class="poetry">Of motion, but I know now how he’s proving</p>
+<p class="poetry">His point; but this I know—hot words bestowed</p>
+<p class="poetry">With skill will set the human fist a-moving, And where it stops the stars burn free and wild. <i>Crede expertum</i>&#8212;I have seen them, child.</p>
+<p class="citeauth">Gorton Swope</p>
+</div>
+
+<p class="entry"><span class="def">heathen</span>, <span class="pos">n.</span> A benighted creature who has the folly to worship something that he can see and
+feel. According to Professor Howison, of the California State University,
+Hebrews are heathens.</p>
+
+<div class="poem">
+<p class="poetry">“The Hebrews are heathens!” says Howison. He’s</p>
+<p class="poetry">A Christian philosopher. I’m</p>
+<p class="poetry">A scurril agnostical chap, if you please,</p>
+<p class="poetry">Addicted too much to the crime</p>
+<p class="poetry">Of religious discussion in my rhyme.</p>
+<p class="poetry">Though Hebrew and Howison cannot agree</p>
+<p class="poetry">On a <i>modus vivendi</i>&#8212;not they!&#8212;</p>
+<p class="poetry">Yet Heaven has had the designing of me,</p>
+<p class="poetry">And I haven’t been reared in a way</p>
+<p class="poetry">To joy in the thick of the fray.</p>
+<p class="poetry">For this of my creed is the soul and the gist,</p>
+<p class="poetry">And the truth of it I aver:</p>
+<p class="poetry">Who differs from me in his faith is an ‘ist,</p>
+<p class="poetry">And ‘ite, an ‘ie, or an ‘er—</p>
+<p class="poetry">And I’m down upon him or her!</p>
+<p class="poetry">Let Howison urge with perfunctory chin</p>
+<p class="poetry">Toleration—that’s all very well,</p>
+<p class="poetry">But a roast is “nuts” to his nostril thin,</p>
+<p class="poetry">And he’s running—I know by the smell—</p>
+<p class="poetry">A secret and personal Hell!</p>
+<p class="citeauth">Bissell Gip</p>
+</div>
+
+<p class="entry"><span class="def">heaven</span>, <span class="pos">n.</span> A place where the wicked cease from troubling you with talk of their personal affairs,
+and the good listen with attention while you expound your own.</p>
+
+<p class="entry"><span class="def">hebrew</span>, <span class="pos">n.</span> A male Jew, as distinguished from the Shebrew, an altogether superior creation.</p>
+
+<p class="entry"><span class="def">helpmate</span>, <span class="pos">n.</span> A wife, or bitter half.</p>
+
+<div class="poem">
+<p class="poetry">“Now, why is yer wife called a helpmate, Pat?”</p>
+<p class="poetry">Says the priest. “Since the time ‘o yer wooin’ She’s niver [sic] assisted in what ye were at—</p>
+<p class="poetry">For it’s naught ye are ever doin’.”</p>
+<p class="poetry">“That’s true of yer Riverence [sic],” Patrick replies,</p>
+<p class="poetry">And no sign of contrition envices;</p>
+<p class="poetry">“But, bedad, it’s a fact which the word implies,</p>
+<p class="poetry">For she helps to mate the expinses [sic]!”</p>
+<p class="citeauth">Marley Wottel</p>
+</div>
+
+<p class="entry"><span class="def">hemp</span>, <span class="pos">n.</span> A plant from whose fibrous bark is made an article of neckwear which is frequently put
+on after public speaking in the open air and prevents the wearer from taking cold.</p>
+
+<p class="entry"><span class="def">hermit</span>, <span class="pos">n.</span> A person whose vices and follies are not sociable.</p>
+
+<p class="entry"><span class="def">hers,</span> <span class="pos">pron.</span> His.</p>
+
+<p class="entry"><span class="def">hibernate</span>, <span class="pos">v.i.</span> To pass the winter season in domestic seclusion. There have been many singular
+popular notions about the hibernation of various animals. Many believe that the
+bear hibernates during the whole winter and subsists by mechanically sucking
+its paws. It is admitted that it comes out of its retirement in the spring so
+lean that it had to try twice before it can cast a shadow. Three or four centuries
+ago, in England, no fact was better attested than that swallows passed the
+winter months in the mud at the bottom of their brooks, clinging together in
+globular masses. They have apparently been compelled to give up the custom and
+account of the foulness of the brooks. Sotus Ecobius discovered in Central Asia
+a whole nation of people who hibernate. By some investigators, the fasting of
+Lent is supposed to have been originally a modified form of hibernation, to
+which the Church gave a religious significance; but this view was strenuously
+opposed by that eminent authority, Bishop Kip, who did not wish any honors
+denied to the memory of the Founder of his family.</p>
+
+<p class="entry"><span class="def">hippogriff</span>, <span class="pos">n.</span> An animal (now extinct) which was half horse and half griffin. The griffin was
+itself a compound creature, half lion and half eagle. The hippogriff was
+actually, therefore, a one-quarter eagle, which is two dollars and fifty cents
+in gold. The study of zoology is full of surprises.</p>
+
+<p class="entry"><span class="def">historian</span>, <span class="pos">n.</span> A broad-gauge gossip.</p>
+
+<p class="entry"><span class="def">history</span>, <span class="pos">n.</span> An account mostly false, of events mostly unimportant, which are brought about by
+rulers mostly knaves, and soldiers mostly fools.</p>
+
+<div class="poem">
+<p class="poetry">Of Roman history, great Niebuhr’s shown</p>
+<p class="poetry">‘Tis nine-tenths lying.<br />
+Faith, I wish ‘twere known, Ere we accept great Niebuhr as a guide,<br />
+Wherein he blundered and how much he lied.</p>
+<p class="citeauth">Salder Bupp</p>
+</div>
+
+<p class="entry"><span class="def">hog</span>, <span class="pos">n.</span> A bird remarkable for the catholicity of its appetite and serving to illustrate that
+of ours. Among the Mahometans and Jews, the hog is not in favor as an article
+of diet, but is respected for the delicacy and the melody of its voice. It is
+chiefly as a songster that the fowl is esteemed; the cage of him in full chorus
+has been known to draw tears from two persons at once. The scientific name of
+this dicky-bird is <i>Porcus Rockefelleri</i>.
+Mr. Rockefeller did not discover the hog, but it is considered his by right of
+resemblance.</p>
+
+<p class="entry"><span class="def">homoeopathist</span>, <span class="pos">n.</span> The humorist of the medical profession.</p>
+
+<p class="entry"><span class="def">homoeopathy</span>, <span class="pos">n.</span> A school of medicine midway between Allopathy and Christian Science. To the last
+both the others are distinctly inferior, for Christian Science will cure
+imaginary diseases, and they can not.</p>
+
+<p class="entry"><span class="def">homicide</span>, <span class="pos">n.</span> The slaying of one human being by another. There are four kinds of homocide: felonious,
+excusable, justifiable, and praiseworthy, but it makes no great difference to
+the person slain whether he fell by one kind or another—the classification is
+for advantage of the lawyers.</p>
+
+<p class="entry"><span class="def">homiletics</span>, <span class="pos">n.</span> The science of adapting sermons to the spiritual needs, capacities and conditions
+of the congregation.</p>
+
+<div class="poem">
+<p class="poetry">So skilled the parson was in homiletics</p>
+<p class="poetry">That all his normal purges and emetics</p>
+<p class="poetry">To medicine the spirit were compounded</p>
+<p class="poetry">With a most just discrimination founded</p>
+<p class="poetry">Upon a rigorous examination</p>
+<p class="poetry">Of tongue and pulse and heart and respiration.</p>
+<p class="poetry">Then, having diagnosed each one’s condition,</p>
+<p class="poetry">His scriptural specifics this physician</p>
+<p class="poetry">Administered—his pills so efficacious</p>
+<p class="poetry">And pukes of disposition so vivacious</p>
+<p class="poetry">That souls afflicted with ten kinds of Adam<br />
+Were convalescent ere they knew they had ‘em.<br />
+But Slander’s tongue—itself all coated—uttered<br />
+Her bilious mind and scandalously muttered<br />
+That in the case of patients having money<br />
+The pills were sugar and the pukes were honey.</p>
+<p class="citeauth"><i>Biography of Bishop Potter</i></p>
+</div>
+
+<p class="entry"><span class="def">honorable</span>, <span class="pos">adj.</span> Afflicted with an impediment in one’s reach. In legislative bodies it is customary to
+mention all members as honorable; as, “the honorable gentleman is a scurvy cur.”</p>
+
+<p class="entry"><span class="def">hope</span>, <span class="pos">n.</span> Desire and expectation rolled into one.</p>
+
+<div class="poem">
+<p class="poetry">Delicious Hope! when naught to man it left—</p>
+<p class="poetry">Of fortune destitute, of friends bereft;</p>
+<p class="poetry">When even his dog deserts him, and his goat
+With tranquil disaffection chews his coat
+While yet it hangs upon his back; then thou,
+The star far-flaming on thine angel brow,
+Descendest, radiant, from the skies to hint
+The promise of a clerkship in the Mint.</p>
+<p class="citeauth"><span class="def">Fogarty Weffing</span></p>
+</div>
+
+<p class="entry"><span class="def">hospitality</span>, <span class="pos">n.</span> The virtue which induces us to feed and lodge certain persons who are not in need
+of food and lodging.</p>
+
+<p class="entry"><span class="def">hostility</span>, <span class="pos">n.</span> A peculiarly sharp and specially applied sense of the earth’s overpopulation. Hostility
+is classified as active and passive; as (respectively) the feeling of a woman
+for her female friends, and that which she entertains for all the rest of her sex.</p>
+
+<p class="entry"><span class="def">Houri</span>, <span class="pos">n.</span> A comely female inhabiting the Mohammedan Paradise to make things cheery for the good
+Mussulman, whose belief in her existence marks a noble discontent with his
+earthly spouse, whom he denies a soul. By that good lady the Houris are said to
+be held in deficient esteem.</p>
+
+<p id="house" class="entry"><span class="def">house</span>, <span class="pos">n.</span> A hollow edifice erected for the habitation of man, rat, mouse, beelte, cockroach, fly,
+mosquito, flea, bacillus and microbe. <i>House
+of Correction</i>, a place of reward for political and personal service,
+and for the detention of offenders and appropriations. <i>House of God</i>, a building with a steeple
+and a mortgage on it. <i>House-dog</i>,
+a pestilent beast kept on domestic premises to insult persons passing by and
+appal the hardy visitor. <i>House-maid</i>,
+a youngerly person of the opposing sex employed to be variously disagreeable
+and ingeniously unclean in the station in which it has pleased God to place her.</p>
+
+<p class="entry"><span class="def">houseless</span>, <span class="pos">adj.</span> Having paid all taxes on household goods.</p>
+
+<p class="entry"><span class="def">hovel</span>, <span class="pos">n.</span> The fruit of a flower called the Palace.</p>
+
+<div class="poem">
+<p class="poetry">Twaddle had a hovel,</p>
+<p class="poetry">Twiddle had a palace;</p>
+<p class="poetry">Twaddle said: “I’ll grovel</p>
+<p class="poetry">Or he’ll think I bear him malice”—</p>
+<p class="poetry">A sentiment as novel</p>
+<p class="poetry">As a castor on a chalice.</p>
+<p class="poetry">Down upon the middle</p>
+<p class="poetry">Of his legs fell Twaddle</p>
+<p class="poetry">And astonished Mr. Twiddle,</p>
+<p class="poetry">Who began to lift his noddle.</p>
+<p class="poetry">Feed upon the fiddle&#8212;</p>
+<p class="poetry">Faddle flummery, unswaddle</p>
+<p class="poetry">A new-born self-sufficiency and think himself a [mockery.]</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">humanity</span>, <span class="pos">n.</span> The human race, collectively, exclusive of the anthropoid poets.</p>
+
+<p class="entry"><span class="def">humorist</span>, <span class="pos">n.</span> A plague that would have softened down the hoar austerity of Pharaoh’s heart and
+persuaded him to dismiss Israel with his best wishes, cat-quick.</p>
+
+<div class="poem">
+<p class="poetry">Lo! the poor humorist, whose tortured mind</p>
+<p class="poetry">See jokes in crowds, though still to gloom inclined—</p>
+<p class="poetry">Whose simple appetite, untaught to stray, His brains, renewed by night, consumes by day.</p>
+<p class="poetry">He thinks, admitted to an equal sty,</p>
+<p class="poetry">A graceful hog would bear his company.</p>
+<p class="citeauth">Alexander Poke</p>
+</div>
+
+<p class="entry"><span class="def">hurricane</span>, <span class="pos">n.</span> An atmospheric demonstration once very common but now generally abandoned for the
+tornado and cyclone. The hurricane is still in popular use in the West Indies
+and is preferred by certain old-fashioned sea-captains. It is also used in the
+construction of the upper decks of steamboats, but generally speaking, the
+hurricane’s usefulness has outlasted it.</p>
+
+<p class="entry"><span class="def">hurry</span>, <span class="pos">n.</span> The dispatch of bunglers.</p>
+
+<p id="husband" class="entry"><span class="def">husband</span>, <span class="pos">n.</span> One who, having dined, is charged with the care of the plate.</p>
+
+<p class="entry"><span class="def">hybrid</span>, <span class="pos">n.</span> A pooled issue.</p>
+
+<p class="entry"><span class="def">hydra</span>, <span class="pos">n.</span> A kind of animal that the ancients catalogued under many heads.</p>
+
+<p class="entry"><span class="def">hyena</span>, <span class="pos">n.</span> A beast held in reverence by some oriental nations from its habit of frequenting at
+night the burial-places of the dead. But the medical student does that.</p>
+
+<p class="entry"><span class="def">hypochondriasis</span>, <span class="pos">n.</span> Depression of one’s own spirits.</p>
+
+<div class="poem">
+<p class="poetry">Some heaps of trash upon a vacant lot<br />
+Where long the village rubbish had been shot<br />
+Displayed a sign among the stuff and stumps—<br />
+“Hypochondriasis.” It meant The Dumps.</p>
+<p class="citeauth">Bogul S. Purvy</p>
+</div>
+
+<p class="entry"><span class="def">hypocrite</span>, <span class="pos">n.</span> One who, profession virtues that he does not respect secures the advantage of
+seeming to be what he depises.</p>
+
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/H.html.annot
@@ -1,0 +1,1 @@
+22841 Hello
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/H.html.i
@@ -1,0 +1,41 @@
+18 pages
+size 400 552
+length 26002
+396 2 10 body html
+0
+1871 2 38 body html
+39
+4030 2 67 body html
+22
+6233 2 96 body html
+0
+6945 2 109 body html
+271
+6945 2 109 body html
+811
+6945 2 109 body html
+1351
+6945 2 109 body html
+1891
+11584 2 189 body html
+72
+12276 2 201 body html
+324
+13953 2 230 body html
+0
+15146 2 250 body html
+107
+17293 2 283 body html
+0
+18872 2 306 body html
+163
+20286 2 331 body html
+91
+22520 2 367 body html
+0
+23366 2 386 body html
+0
+24997 2 412 body html
+0
+husband 16
+house 14
--- /dev/null
+++ b/lib/ebooks/devils/I.html
@@ -1,0 +1,681 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: I</title>
+</head>
+<body lang="en-US">
+
+
+<h1>I</h1>
+
+
+<p>I is the first letter of the alphabet, the first word of the language, the first thought of
+the mind, the first object of affection. In grammar it is a pronoun of the
+first person and singular number. Its plural is said to be <i>We</i>, but how there can be more than one
+myself is doubtless clearer the grammarians than it is to the author of this
+incomparable dictionary. Conception of two myselfs is difficult, but fine. The
+frank yet graceful use of “I” distinguishes a good writer from a bad; the
+latter carries it with the manner of a thief trying to cloak his loot.</p>
+
+<p class="entry"><span class="def">Ichor</span>, <span class="pos">n.</span> A fluid that serves the gods and goddesses in place of blood.</p>
+
+<div class="poem">
+<p class="poetry">Fair Venus, speared by Diomed,</p>
+<p class="poetry">Restrained the raging chief and said:</p>
+<p class="poetry">“Behold, rash mortal, whom you’ve bled—</p>
+<p class="poetry">Your soul’s stained white with ichorshed!”</p>
+<p class="citeauth">Mary Doke</p>
+</div>
+
+<p class="entry"><span class="def">iconoclast</span>, <span class="pos">n.</span> A breaker of idols, the worshipers whereof are imperfectly gratified by the
+performance, and most strenuously protest that he unbuildeth but doth not
+reedify, that he pulleth down but pileth not up. For the poor things would have
+other idols in place of those he thwacketh upon the mazzard and dispelleth. But
+the iconoclast saith: “Ye shall have none at all, for ye need them not; and if
+the rebuilder fooleth round hereabout, behold I will depress the head of him
+and sit thereon till he squawk it.”</p>
+
+<p class="entry"><span class="def">idiot</span>, <span class="pos">n.</span> A member of a large and powerful tribe whose influence in human affairs has always been
+dominant and controlling. The Idiot’s activity is not confined to any special
+field of thought or action, but “pervades and regulates the whole.” He has the
+last word in everything; his decision is unappealable. He sets the fashions and
+opinion of taste, dictates the limitations of speech and circumscribes conduct
+with a dead-line.</p>
+
+<p class="entry"><span class="def">idleness</span>, <span class="pos">n.</span> A model farm where the
+devil experiments with seeds of new sins and promotes the growth of staple vices.</p>
+
+<p class="entry"><span class="def">ignoramus</span>, <span class="pos">n.</span> A person unacquainted with certain kinds of knowledge familiar to yourself, and
+having certain other kinds that you know nothing about.</p>
+
+<div class="poem">
+<p class="poetry">Dumble was an ignoramus,</p>
+<p class="poetry">Mumble was for learning famous.</p>
+<p class="poetry">Mumble said one day to Dumble:</p>
+<p class="poetry">“Ignorance should be more humble.</p>
+<p class="poetry">Not a spark have you of knowledge</p>
+<p class="poetry">That was got in any college.”</p>
+<p class="poetry">Dumble said to Mumble: “Truly</p>
+<p class="poetry">You’re self-satisfied unduly.</p>
+<p class="poetry">Of things in college I’m denied</p>
+<p class="poetry">A knowledge—you of all beside.”</p>
+<p class="citeauth">Borelli</p>
+</div>
+
+<p class="entry"><span class="def">illuminati</span>, <span class="pos">n.</span> A sect of Spanish heretics of the latter part of the sixteenth century; so called
+because they were light weights—<i>cunctationes illuminati</i>.</p>
+
+<p class="entry"><span class="def">illustrious</span>, <span class="pos">adj.</span> Suitably placed for the shafts of malice, envy and detraction.</p>
+
+<p class="entry"><span class="def">imagination</span>, <span class="pos">n.</span> A warehouse of facts, with poet and liar in joint ownership.</p>
+
+<p class="entry"><span class="def">imbecility</span>, <span class="pos">n.</span> A kind of divine inspiration, or sacred fire affecting censorious critics of this dictionary.</p>
+
+<p class="entry"><span class="def">immigrant</span>, <span class="pos">n.</span> An unenlightened person who thinks one country better than another.</p>
+
+<p class="entry"><span class="def">immodest</span>, <span class="pos">adj.</span> Having a strong sense of one’s own merit, coupled with a feeble conception of worth in others.</p>
+
+<div class="poem">
+<p class="poetry">There was once a man in Ispahan</p>
+<p class="poetry">Ever and ever so long ago,</p>
+<p class="poetry">And he had a head, the phrenologists said,</p>
+<p class="poetry">That fitted him for a show.</p>
+<p class="poetry">For his modesty’s bump was so large a lump</p>
+<p class="poetry">(Nature, they said, had taken a freak)</p>
+<p class="poetry">That its summit stood far above the wood</p>
+<p class="poetry">Of his hair, like a mountain peak.</p>
+<p class="poetry">So modest a man in all Ispahan,</p>
+<p class="poetry">Over and over again they swore—</p>
+<p class="poetry">So humble and meek, you would vainly seek;</p>
+<p class="poetry">None ever was found before.</p>
+<p class="poetry">Meantime the hump of that awful bump</p>
+<p class="poetry">Into the heavens contrived to get</p>
+<p class="poetry">To so great a height that they called the wight</p>
+<p class="poetry">The man with the minaret.</p>
+<p class="poetry">There wasn’t a man in all Ispahan</p>
+<p class="poetry">Prouder, or louder in praise of his chump:</p>
+<p class="poetry">With a tireless tongue and a brazen lung</p>
+<p class="poetry">He bragged of that beautiful bump</p>
+<p class="poetry">Till the Shah in a rage sent a trusty page</p>
+<p class="poetry">Bearing a sack and a bow-string too,</p>
+<p class="poetry">And that gentle child explained as he smiled:</p>
+<p class="poetry">“A little present for you.”</p>
+<p class="poetry">The saddest man in all Ispahan,</p>
+<p class="poetry">Sniffed at the gift, yet accepted the same.</p>
+<p class="poetry">“If I’d lived,” said he, “my humility</p>
+<p class="poetry">Had given me deathless fame!”</p>
+<p class="citeauth">Sukker Uffro</p>
+</div>
+
+<p class="entry"><span class="def">immoral</span>, <span class="pos">adj.</span> Inexpedient. Whatever in the long run and with regard to the greater number of instances men
+find to be generally inexpedient comes to be considered wrong, wicked, immoral.
+If man’s notions of right and wrong have any other basis than this of
+expediency; if they originated, or could have originated, in any other way; if
+actions have in themselves a moral character apart from, and nowise dependent
+on, their consequences—then all philosophy is a lie and reason a disorder of the mind.</p>
+
+<p class="entry"><span class="def">immorality</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">A toy which people cry for,</p>
+<p class="poetry">And on their knees apply for,</p>
+<p class="poetry">Dispute, contend and lie for,</p>
+<p class="poetry">And if allowed</p>
+<p class="poetry">Would be right proud</p>
+<p class="poetry">Eternally to die for.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">impale</span>, <span class="pos">v.t.</span> In popular usage to pierce with any weapon which remains fixed in the wound. This,
+however, is inaccurate; to imaple is, properly, to put to death by thrusting an
+upright sharp stake into the body, the victim being left in a sitting position.
+This was a common mode of punishment among many of the nations of antiquity,
+and is still in high favor in China and other parts of Asia. Down to the
+beginning of the fifteenth century it was widely employed in “churching”
+heretics and schismatics. Wolecraft calls it the “stoole of repentynge,” and
+among the common people it was jocularly known as “riding the one legged
+horse.” Ludwig Salzmann informs us that in Thibet impalement is considered the
+most appropriate punishment for crimes against religion; and although in China
+it is sometimes awarded for secular offences, it is most frequently adjudged in
+cases of sacrilege. To the person in actual experience of impalement it must be
+a matter of minor importance by what kind of civil or religious dissent he was
+made acquainted with its discomforts; but doubtless he would feel a certain
+satisfaction if able to contemplate himself in the character of a weather-cock
+on the spire of the True Church.</p>
+
+<p class="entry"><span class="def">impartial</span>, <span class="pos">adj.</span> Unable to perceive any promise of personal advantage from espousing either side of a
+controversy or adopting either of two conflicting opinions.</p>
+
+<p class="entry"><span class="def">impenitence</span>, <span class="pos">n.</span> A state of mind intermediate in point of time between sin and punishment.</p>
+
+<p class="entry"><span class="def">impiety</span>, <span class="pos">n.</span> Your irreverence toward my deity.</p>
+
+<p class="entry"><span class="def">imposition</span>, <span class="pos">n.</span> The act of blessing
+or consecrating by the laying on of hands—a ceremony common to many ecclesiastical systems, but performed
+with the frankest sincerity by the sect known as Thieves.</p>
+
+<div class="poem">
+<p class="poetry">“Lo! by the laying on of hands,”</p>
+<p class="poetry">Say parson, priest and dervise,</p>
+<p class="poetry">“We consecrate your cash and lands</p>
+<p class="poetry">To ecclesiastical service.</p>
+<p class="poetry">No doubt you’ll swear till all is blue</p>
+<p class="poetry">At such an imposition. Do.”</p>
+<p class="poetry">Pollo Doncas</p>
+<p class="poetry">impostor n. A rival aspirant to public honors.</p>
+<p class="poetry">improbability, <span class="pos">n.</span></p>
+<p class="poetry">His tale he told with a solemn face</p>
+<p class="poetry">And a tender, melancholy grace.</p>
+<p class="poetry">Improbable ‘twas, no doubt,</p>
+<p class="poetry">When you came to think it out,</p>
+<p class="poetry">But the fascinated crowd</p>
+<p class="poetry">Their deep surprise avowed</p>
+<p class="poetry">And all with a single voice averred ‘Twas the most amazing thing they’d heard—</p>
+<p class="poetry">All save one who spake never a word,</p>
+<p class="poetry">But sat as mum</p>
+<p class="poetry">As if deaf and dumb,</p>
+<p class="poetry">Serene, indifferent and unstirred.</p>
+<p class="poetry">Then all the others turned to him And scrutinized him limb from limb—</p>
+<p class="poetry">Scanned him alive;</p>
+<p class="poetry">But he seemed to thrive</p>
+<p class="poetry">And tranquiler grow each minute,</p>
+<p class="poetry">As if there were nothing in it.</p>
+<p class="poetry">“What! what!” cried one, “are you not amazed</p>
+<p class="poetry">At what our friend has told?” He raised</p>
+<p class="poetry">Soberly then his eyes and gazed</p>
+<p class="poetry">In a natural way</p>
+<p class="poetry">And proceeded to say,</p>
+<p class="poetry">As he crossed his feet on the mantel-shelf:</p>
+<p class="poetry">“O no—not at all; I’m a liar myself.”</p>
+</div>
+
+<p class="entry"><span class="def">improvidence</span>, <span class="pos">n.</span> Provision for the needs of to-day from the revenues of to-morrow.</p>
+
+<p class="entry"><span class="def">impunity</span>, <span class="pos">n.</span> Wealth.</p>
+
+<p class="entry"><span class="def">inadmissible</span>, <span class="pos">adj.</span> Not competent to be considered. Said of certain kinds of testimony which juries
+are supposed to be unfit to be entrusted with, and which judges, therefore,
+rule out, even of proceedings before themselves alone. Hearsay evidence is
+inadmissible because the person quoted was unsworn and is not before the court
+for examination; yet most momentous actions, military, political, commercial
+and of every other kind, are daily undertaken on hearsay evidence. There is no
+religion in the world that has any other basis than hearsay evidence. Revelation
+is hearsay evidence; that the Scriptures are the word of God we have only the
+testimony of men long dead whose identity is not clearly established and who
+are not known to have been sworn in any sense. Under the rules of evidence as
+they now exist in this country, no single assertion in the Bible has in its
+support any evidence admissible in a court of law. It cannot be proved that the
+battle of Blenheim ever was fought, that there was such as person as Julius
+Caesar, such an empire as Assyria.</p>
+
+<p>But as records of courts of justice are admissible, it can easily be proved that powerful and
+malevolent magicians once existed and were a scourge to mankind. The evidence
+(including confession) upon which certain women were convicted of witchcraft
+and executed was without a flaw; it is still unimpeachable. The judges’
+decisions based on it were sound in logic and in law. Nothing in any existing
+court was ever more thoroughly proved than the charges of witchcraft and
+sorcery for which so many suffered death. If there were no witches, human
+testimony and human reason are alike destitute of value.</p>
+
+<p class="entry"><span class="def">inauspiciously</span>, <span class="pos">adv.</span> In an unpromising manner, the auspices being unfavorable. Among the Romans
+it was customary before undertaking any important action or enterprise to
+obtain from the augurs, or state prophets, some hint of its probable outcome;
+and one of their favorite and most trustworthy modes of divination consisted in
+observing the flight of birds—the omens thence derived being called <i>auspices</i>. Newspaper reporters and certain
+miscreant lexicographers have decided that the word—always in the plural—shall
+mean “patronage” or “management”; as, “The festivities were under the auspices
+of the Ancient and Honorable Order of Body-Snatchers”; or, “The hilarities were
+auspicated by the Knights of Hunger.”</p>
+
+<div class="poem">
+<p class="poetry">A Roman slave appeared one day</p>
+<p class="poetry">Before the Augur. “Tell me, pray,</p>
+<p class="poetry">If—“ here the Augur, smiling, made</p>
+<p class="poetry">A checking gesture and displayed</p>
+<p class="poetry">His open palm, which plainly itched,</p>
+<p class="poetry">For visibly its surface twitched.</p>
+<p class="poetry">A <i>denarius</i> (the Latin nickel)</p>
+<p class="poetry">Successfully allayed the tickle,</p>
+<p class="poetry">And then the slave proceeded: “Please</p>
+<p class="poetry">Inform me whether Fate decrees</p>
+<p class="poetry">Success or failure in what I</p>
+<p class="poetry">To-night (if it be dark) shall try.</p>
+<p class="poetry">Its nature? Never mind—I think</p>
+<p class="poetry">‘Tis writ on this”—and with a wink</p>
+<p class="poetry">Which darkened half the earth, he drew</p>
+<p class="poetry">Another denarius to view,</p>
+<p class="poetry">Its shining face attentive scanned,</p>
+<p class="poetry">Then slipped it into the good man’s hand,</p>
+<p class="poetry">Who with great gravity said: “Wait</p>
+<p class="poetry">While I retire to question Fate.”</p>
+<p class="poetry">That holy person then withdrew</p>
+<p class="poetry">His scared clay and, passing through</p>
+<p class="poetry">The temple’s rearward gate, cried “Shoo!”</p>
+<p class="poetry">Waving his robe of office. Straight</p>
+<p class="poetry">Each sacred peacock and its mate</p>
+<p class="poetry">(Maintained for Juno’s favor) fled</p>
+<p class="poetry">With clamor from the trees o’erhead,</p>
+<p class="poetry">Where they were perching for the night.</p>
+<p class="poetry">The temple’s roof received their flight,</p>
+<p class="poetry">For thither they would always go,</p>
+<p class="poetry">When danger threatened them below.</p>
+<p class="poetry">Back to the slave the Augur went:</p>
+<p class="poetry">“My son, forecasting the event</p>
+<p class="poetry">By flight of birds, I must confess</p>
+<p class="poetry">The auspices deny success.”</p>
+<p class="poetry">That slave retired, a sadder man,</p>
+<p class="poetry">Abandoning his secret plan—</p>
+<p class="poetry">Which was (as well the craft seer</p>
+<p class="poetry">Had from the first divined) to clear</p>
+<p class="poetry">The wall and fraudulently seize</p>
+<p class="poetry">On Juno’s poultry in the trees.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p id="income" class="entry"><span class="def">income</span>, <span class="pos">n.</span> The natural and rational gauge and measure of respectability, the commonly accepted
+standards being artificial, arbitrary and fallacious; for, as “Sir Sycophas
+Chrysolater” in the play has justly remarked, “the true use and function of
+property (in whatsoever it consisteth—coins, or land, or houses, or merchant-stuff,
+or anything which may be named as holden of right to one’s own
+subservience) as also of honors, titles, preferments and place, and all favor
+and acquaintance of persons of quality or ableness, are but to get money. Hence
+it followeth that all things are truly to be rated as of worth in measure of
+their serviceableness to that end; and their possessors should take rank in
+agreement thereto, neither the lord of an unproducing manor, howsoever broad
+and ancient, nor he who bears an unremunerate dignity, nor yet the pauper
+favorite of a king, being esteemed of level excellency with him whose riches
+are of daily accretion; and hardly should they whose wealth is barren claim and
+rightly take more honor than the poor and unworthy.”</p>
+
+<p class="entry"><span class="def">incompatibility</span>, <span class="pos">n.</span> In matrimony a similarity of tastes, particularly the taste for domination. Incompatibility
+may, however, consist of a meek-eyed matron living just around the corner. It
+has even been known to wear a moustache.</p>
+
+<p class="entry"><span class="def">incompossible</span>, <span class="pos">adj.</span> Unable to exist if something else exists. Two things are incompossible
+when the world of being has scope enough for one of them, but not enough for
+both—as Walt Whitman’s poetry and God’s mercy to man. Incompossibility, it will
+be seen, is only incompatibility let loose. Instead of such low language as “Go
+heel yourself—I mean to kill you on sight,” the words, “Sir, we are
+incompossible,” would convey and equally significant intimation and in stately
+courtesy are altogether superior.</p>
+
+<p class="entry"><span class="def">Incubus</span>, <span class="pos">n.</span> One of a race of highly improper demons who, though probably not wholly extinct, may
+be said to have seen their best nights. For a complete account of <i>incubi</i> and <i>succubi</i>, including <i>incubae</i>
+and <i>succubae</i>, see the <i>Liber Demonorum</i> of Protassus (Paris,
+1328), which contains much curious information that would be out of place in a
+dictionary intended as a text-book for the public schools.</p>
+
+<p>Victor Hugo relates that in the Channel Islands Satan himself—tempted more than elsewhere
+by the beauty of the women, doubtless—sometimes plays at <i>incubus</i>, greatly to the inconvenience and
+alarm of the good dames who wish to be loyal to their marriage vows, generally
+speaking. A certain lady applied to the parish priest to learn how they might,
+in the dark, distinguish the hardy intruder from their husbands. The holy man
+said they must feel his brown for horns; but Hugo is ungallant enough to hint a
+doubt of the efficacy of the test.</p>
+
+<p class="entry"><span class="def">incumbent</span>, <span class="pos">n.</span> A
+person of the liveliest interest to the outcumbents.</p>
+
+<p class="entry"><span class="def">indecision</span>, <span class="pos">n.</span> The
+chief element of success; “for whereas,” saith Sir Thomas Brewbold, “there is
+but one way to do nothing and divers way to do something, whereof, to a surety,
+only one is the right way, it followeth that he who from indecision standeth
+still hath not so many chances of going astray as he who pusheth forwards”—a
+most clear and satisfactory exposition on the matter.</p>
+
+<p class="dialog">“Your prompt decision to attack,” said Genera Grant
+on a certain occasion to General Gordon Granger, “was admirable; you had but five minutes
+to make up your mind in.”</p>
+
+<p class="dialog">“Yes, sir,” answered the victorious subordinate,
+“it is a great thing to be know exactly what to do in an emergency. When in doubt
+whether to attack or retreat I never hesitate a moment—I toss us a copper.”</p>
+
+<p class="dialog">“Do you mean to say that’s what you did this time?”</p>
+<p class="dialog">“Yes, General; but for Heaven’s sake don’t reprimand me: I disobeyed the coin.”</p>
+
+<p class="entry"><span class="def">indifferent</span>, <span class="pos">adj.</span> Imperfectly
+sensible to distinctions among things.</p>
+
+<div class="poem">
+<p class="poetry">“You tiresome man!” cried Indolentio’s wife,<br />
+“You’ve grown indifferent to all in life.”<br />
+“Indifferent?” he drawled with a slow smile;<br />
+“I would be, dear, but it is not worth while.”</p>
+<p class="citeauth">Apuleius M. Gokul</p>
+</div>
+
+<p class="entry"><span class="def">indigestion</span>, <span class="pos">n.</span> A
+disease which the patient and his friends frequently mistake for deep religious
+conviction and concern for the salvation of mankind. As the simple Red Man of
+the western wild put it, with, it must be confessed, a certain force: “Plenty
+well, no pray; big bellyache, heap God.”</p>
+
+<p class="entry"><span class="def">indiscretion</span>, <span class="pos">n.</span> The guilt of woman.</p>
+
+<p class="entry"><span class="def">inexpedient</span>, <span class="pos">adj.</span> Not calculated
+to advance one’s interests.</p>
+
+<p class="entry"><span class="def">infancy</span>, <span class="pos">n.</span> The
+period of our lives when, according to Wordsworth, “Heaven lies about us.” The
+world begins lying about us pretty soon afterward.</p>
+
+<p class="entry"><span class="def">Inferiae,</span> <span class="pos">n.</span> [Latin] Among the Greeks and Romans, sacrifices
+for propitation of the <i>Dii Manes</i>, or souls of the dead heroes;
+for the pious ancients could not invent enough gods to satisfy their spiritual
+needs, and had to have a number of makeshift deities, or, as a sailor might
+say, jury-gods, which they made out of the most unpromising materials. It was
+while sacrificing a bullock to the spirit of Agamemnon that Laiaides, a priest
+of Aulis, was favored with an audience of that illustrious warrior’s shade, who
+prophetically recounted to him the birth of Christ and the triumph of
+Christianity, giving him also a rapid but tolerably complete review of events
+down to the reign of Saint Louis. The narrative ended abruptly at the point,
+owing to the inconsiderate crowing of a cock, which compelled the ghosted King
+of Men to scamper back to Hades. There is a fine mediaeval flavor to this
+story, and as it has not been traced back further than Pere Brateille, a pious
+but obscure writer at the court of Saint Louis, we shall probably not err on
+the side of presumption in considering it apocryphal, though Monsignor Capel’s
+judgment of the matter might be different; and to that I bow—wow.</p>
+
+<p class="entry"><span class="def">infidel</span>, <span class="pos">n.</span> In New
+York, one who does not believe in the Christian religion; in Constantinople,
+one who does. (See GIAOUR.) A kind of scoundrel imperfectly reverent of, and
+niggardly contributory to, divines, ecclesiastics, popes, parsons, canons,
+monks, mollahs, voodoos, presbyters, hierophants, prelates, obeah-men, abbes,
+nuns, missionaries, exhorters, deacons, friars, hadjis, high-priests, muezzins,
+brahmins, medicine-men, confessors, eminences, elders, primates, prebendaries,
+pilgrims, prophets, imaums, beneficiaries, clerks, vicars-choral, archbishops,
+bishops, abbots, priors, preachers, padres, abbotesses, caloyers, palmers,
+curates, patriarchs, bonezs, santons, beadsmen, canonesses, residentiaries,
+diocesans, deans, subdeans, rural deans, abdals, charm-sellers, archdeacons,
+hierarchs, class-leaders, incumbents, capitulars, sheiks, talapoins,
+postulants, scribes, gooroos, precentors, beadles, fakeers, sextons,
+reverences, revivalists, cenobites, perpetual curates, chaplains, mudjoes,
+readers, novices, vicars, pastors, rabbis, ulemas, lamas, sacristans, vergers,
+dervises, lectors, church wardens, cardinals, prioresses, suffragans, acolytes,
+rectors, cures, sophis, mutifs and pumpums.</p>
+
+<p class="entry"><span class="def">influence</span>, <span class="pos">n.</span> In politics,
+a visionary <i>quo</i> given in exchange for a substantial <i>quid</i>.</p>
+
+<p class="entry"><span class="def">Infalapsarian</span>, <span class="pos">n.</span> One
+who ventures to believe that Adam need not have sinned unless he had a mind
+to—in opposition to the Supralapsarians, who hold that that luckless person’s
+fall was decreed from the beginning. Infralapsarians are sometimes called
+Sublapsarians without material effect upon the importance and lucidity of their
+views about Adam.</p>
+
+<div class="poem">
+<p class="poetry">Two theologues once, as they wended their way</p>
+<p class="poetry">To chapel, engaged in colloquial fray—</p>
+<p class="poetry">An earnest logomachy, bitter as gall,</p>
+<p class="poetry">Concerning poor Adam and what made him fall.<br />
+“’Twas Predestination,” cried one—“for the Lord<br />
+Decreed he should fall of his own accord.”<br />
+“Not so—‘twas Free will,” the other maintained,<br />
+“Which led him to choose what the Lord had ordained.”<br />
+So fierce and so fiery grew the debate<br />
+That nothing but bloodshed their dudgeon could sate;</p>
+<p class="poetry">So off flew their
+cassocks and caps to the ground And, moved by the spirit, their hands went
+round. Ere either had proved his theology right By winning, or even beginning,
+the fight, A gray old professor of Latin came by, A staff in his hand and a
+scowl in his eye, And learning the cause of their quarrel (for still As they
+clumsily sparred they disputed with skill Of foreordination freedom of will)</p>
+<p class="poetry">Cried: “Sirrahs! this reasonless warfare compose:</p>
+<p class="poetry">Atwixt ye’s no
+difference worthy of blows. The sects ye belong to—I’m ready to swear Ye
+wrongly interpret the names that they bear. <i>You</i>
+&#8212;Infralapsarian son of a clown!&#8212;</p>
+<p class="poetry">Should only contend that Adam slipped down;</p>
+<p class="poetry">While <i>you</i>&#8212;you Supralapsarian pup!&#8212;</p>
+<p class="poetry">Should nothing aver but that Adam slipped up.</p>
+<p class="poetry">It’s all the same whether up or down</p>
+<p class="poetry">You slip on a peel of banana brown.</p>
+<p class="poetry">Even Adam analyzed not his blunder,</p>
+<p class="poetry">But thought he had slipped on a peal of thunder!</p>
+<p class="citeauth">G. J.</p>
+</div>
+<p class="entry"><span class="def">ingrate</span>, <span class="pos">n.</span> One
+who receives a benefit from another, or is otherwise an object of charity.</p>
+
+<div class="poem">
+<p class="poetry">“All men are ingrates,” sneered the cynic. “Nay,”</p>
+<p class="poetry">The good philanthropist replied;</p>
+<p class="poetry">“I did great service to a man one day</p>
+<p class="poetry">Who never since has cursed me to repay,</p>
+<p class="poetry">Nor vilified.”</p>
+<p class="poetry">“Ho!” cried the cynic, “lead me to him straight—</p>
+<p class="poetry">With veneration I am overcome,</p>
+<p class="poetry">And fain would have his blessing.” “Sad your fate—</p>
+<p class="poetry">He cannot bless you, for AI grieve to state</p>
+<p class="poetry">This man is dumb.”</p>
+<p class="citeauth">Ariel Selp</p>
+</div>
+
+<p class="entry"><span class="def">injury</span>, <span class="pos">n.</span> An
+offense next in degree of enormity to a slight.</p>
+
+<p class="entry"><span class="def">injustice</span>, <span class="pos">n.</span> A
+burden which of all those that we load upon others and carry ourselves is
+lightest in the hands and heaviest upon the back.</p>
+
+<p class="entry"><span class="def">ink</span>, <span class="pos">n.</span> A
+villainous compound of tannogallate of iron, gum-arabic and water, chiefly used
+to facilitate the infection of idiocy and promote intellectual crime. The
+properties of ink are peculiar and contradictory: it may be used to make
+reputations and unmake them; to blacken them and to make them white; but it is
+most generally and acceptably employed as a mortar to bind together the stones
+of an edifice of fame, and as a whitewash to conceal afterward the rascal
+quality of the material. There are men called journalists who have established
+ink baths which some persons pay money to get into, others to get out of. Not
+infrequently it occurs that a person who has paid to get in pays twice as much
+to get out.</p>
+
+<p class="entry"><span class="def">innate</span>, <span class="pos">adj.</span> Natural,
+inherent—as innate ideas, that is to say, ideas that we are born with, having
+had them previously imparted to us. The doctrine of innate ideas is one of the
+most admirable faiths of philosophy, being itself an innate idea and therefore
+inaccessible to disproof, though Locke foolishly supposed himself to have given
+it “a black eye.” Among innate ideas may be mentioned the belief in one’s
+ability to conduct a newspaper, in the greatness of one’s country, in the
+superiority of one’s civilization, in the importance of one’s personal affairs
+and in the interesting nature of one’s diseases.</p>
+
+<p class="entry"><span class="def">in’ards</span>, <span class="pos">n.</span> The
+stomach, heart, soul and other bowels. Many eminent investigators do not class
+the soul as an in’ard, but that acute observer and renowned authority, Dr.
+Gunsaulus, is persuaded that the mysterious organ known as the spleen is
+nothing less than our important part. To the contrary, Professor Garrett P.
+Servis holds that man’s soul is that prolongation of his spinal marrow which
+forms the pith of his no tail; and for demonstration of his faith points
+confidently to the fact that no tailed animals have no souls. Concerning these
+two theories, it is best to suspend judgment by believing both.</p>
+
+<p class="entry"><span class="def">inscription</span>, <span class="pos">n.</span> Something
+written on another thing. Inscriptions are of many kinds, but mostly memorial,
+intended to commemorate the fame of some illustrious person and hand down to
+distant ages the record of his services and virtues. To this class of
+inscriptions belongs the name of John Smith, penciled on the Washington
+monument. Following are examples of memorial inscriptions on tombstones: (See
+EPITAPH.)</p>
+
+<div class="poem">
+<p class="poetry">“In the sky my soul is found,</p>
+<p class="poetry">And my body in the ground.</p>
+<p class="poetry">By and by my body’ll rise</p>
+<p class="poetry">To my spirit in the skies,</p>
+<p class="poetry">Soaring up to Heaven’s gate.</p>
+<p class="poetry">1878.”</p>
+<p class="poetry">“Sacred to the memory of Jeremiah Tree. Cut down May 9<sup>th</sup>, 1862, aged 27 yrs. 4 mos.
+and 12 ds. Indigenous.”</p>
+<p class="poetry">“Affliction sore long time she boar,</p>
+<p class="poetry">Phisicians was in vain,</p>
+<p class="poetry">Till Deth released the dear deceased</p>
+<p class="poetry">And left her a remain.</p>
+<p class="poetry">Gone to join Ananias in the regions of bliss.”</p>
+<p class="poetry">“The clay that rests beneath this stone</p>
+<p class="poetry">As Silas Wood was widely known.</p>
+<p class="poetry">Now, lying here, I ask what good</p>
+<p class="poetry">It was to let me be S. Wood.</p>
+<p class="poetry">O Man, let not ambition trouble you,</p>
+<p class="poetry">Is the advice of Silas W.”</p>
+<p class="citeauth">“Richard Haymon, of Heaven. Fell to Earth Jan. 20, 1807, and had the dust brushed off him Oct.
+3, 1874.”</p>
+</div>
+
+<p class="entry"><span class="def">insectivora</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">“See,” cries the chorus of admiring preachers, “How Providence provides for all His creatures!”</p>
+<p class="poetry">“His care,” the gnat said, “even the insects follows:</p>
+<p class="poetry">For us He has provided wrens and swallows.”</p>
+<p class="citeauth">Sempen Railey</p>
+</div>
+
+<p class="entry"><span class="def">insurance</span>, <span class="pos">n.</span> An
+ingenious modern game of chance in which the player is permitted to enjoy the
+comfortable conviction that he is beating the man who keeps the table.</p>
+
+<p class="dialog">INSURANCE AGENT: My
+dear sir, that is a fine house—pray let me insure it.</p>
+
+<p class="dialog">HOUSE OWNER: With pleasure. Please make the annual premium so low that by the
+time when, according to the tables of your actuary, it will probably be
+destroyed by fire I will have paid you considerably less than the face of the policy.</p>
+
+<p class="dialog">INSURANCE AGENT: O dear, no—we could not afford to do that. </p>
+
+<p class="dialog">We must fix the premium so that you will have paid more.</p>
+
+<p class="dialog">HOUSE OWNER: How, then, can <i>I</i> afford <i>that</i>?</p>
+
+<p class="dialog">INSURANCE AGENT: Why, your house may burn down at any time. </p>
+
+<p class="dialog">There was Smith’s house, for example, which—</p>
+
+<p class="dialog">HOUSE OWNER: Spare me—there were Brown’s house, on the contrary, and
+Jones’s house, and Robinson’s house, which—</p>
+
+<p class="dialog">INSURANCE AGENT: Spare <i>me</i>!</p>
+
+<p class="dialog">HOUSE OWNER: Let us understand each other. You want me to pay you money on the
+supposition that something will occur previously to the time set by yourself
+for its occurrence. In other words, you expect me to bet that my house will not
+last so long as you say that it will probably last.</p>
+
+<p class="dialog">INSURANCE AGENT: But if your house burns without insurance it will be a total loss.</p>
+
+<p class="dialog">HOUSE OWNER: Beg your pardon—by your own actuary’s tables I shall probably
+have saved, when it burns, all the premiums I would otherwise have paid to
+you—amounting to more than the face of the policy they would have bought. But
+suppose it to burn, uninsured, before the time upon which your figures are
+based. If I could not afford that, how could you if it were insured?</p>
+
+<p class="dialog">INSURANCE AGENT: O, we should make ourselves whole from our luckier ventures
+with other clients. Virtually, they pay your loss.</p>
+
+<p class="dialog">HOUSE OWNER: And virtually, then, don’t I help to pay their losses? Are not
+their houses as likely as mine to burn before they have paid you as much as you
+must pay them? The case stands this way: you expect to take more money from
+your clients than you pay to them, do you not?</p>
+
+<p class="dialog">INSURANCE AGENT: Certainly; if we did not—</p>
+
+<p class="dialog">HOUSE OWNER: I would not trust you with my money. Very well then. If it is <i>certain</i>, with
+reference to the whole body of your clients, that they lose money on you it is <i>probable</i>, with
+reference to any one of them, that <i>he</i> will. It is these individual
+probabilities that make the aggregate certainty.</p>
+
+<p class="dialog">INSURANCE AGENT: I will not deny it—but look at the figures in this pamph—</p>
+
+<p class="dialog">HOUSE OWNER: Heaven forbid!</p>
+
+<p class="dialog">INSURANCE AGENT: You spoke of saving the premiums which you would otherwise pay to
+me. Will you not be more likely to squander them? We offer you an incentive to thrift.</p>
+
+<p class="dialog">HOUSE OWNER: The willingness of A to take care of B’s money is not peculiar to
+insurance, but as a charitable institution you command esteem. Deign to accept
+its expression from a Deserving Object.</p>
+
+<p class="entry"><span class="def">insurrection</span>, <span class="pos">n.</span> An
+unsuccessful revolution. Disaffection’s failure to substitute misrule for bad government.</p>
+
+<p class="entry"><span class="def">intention</span>, <span class="pos">n.</span> The
+mind’s sense of the prevalence of one set of influences over another set; an
+effect whose cause is the imminence, immediate or remote, of the performance of
+an involuntary act.</p>
+
+<p class="entry"><span class="def">interpreter</span>, <span class="pos">n.</span> One
+who enables two persons of different languages to understand each other by
+repeating to each what it would have been to the interpreter’s advantage for
+the other to have said.</p>
+
+<p class="entry"><span class="def">interregnum</span>, <span class="pos">n.</span> The
+period during which a monarchical country is governed by a warm spot on the
+cushion of the throne. The experiment of letting the spot grow cold has
+commonly been attended by most unhappy results from the zeal of many worthy
+persons to make it warm again.</p>
+
+<p class="entry"><span class="def">intimacy</span>, <span class="pos">n.</span> A
+relation into which fools are providentially drawn for their mutual destruction.</p>
+
+<div class="poem">
+<p class="poetry">Two Seidlitz powders, one in blue</p>
+<p class="poetry">And one in white, together drew</p>
+<p class="poetry">And having each a pleasant sense</p>
+<p class="poetry">Of t’other powder’s excellence,</p>
+<p class="poetry">Forsook their jackets for the snug</p>
+<p class="poetry">Enjoyment of a common mug.</p>
+<p class="poetry">So close their intimacy grew</p>
+<p class="poetry">One paper would have held the two.</p>
+<p class="poetry">To confidences straight they fell,</p>
+<p class="poetry">Less anxious each to hear than tell;</p>
+<p class="poetry">Then each remorsefully confessed</p>
+<p class="poetry">To all the virtues he possessed,</p>
+<p class="poetry">Acknowledging he had them in</p>
+<p class="poetry">So high degree it was a sin.</p>
+<p class="poetry">The more they said, the more they felt</p>
+<p class="poetry">Their spirits with emotion melt,</p>
+<p class="poetry">Till tears of sentiment expressed</p>
+<p class="poetry">Their feelings. Then they effervesced!</p>
+<p class="poetry">So Nature executes her feats</p>
+<p class="poetry">Of wrath on friends and sympathetes</p>
+<p class="poetry">The good old rule who don’t apply,</p>
+<p class="poetry">That you are you and I am I.</p>
+</div>
+
+<p class="entry"><span class="def">introduction</span>, <span class="pos">n.</span> A
+social ceremony invented by the devil for the gratification of his servants and
+the plaguing of his enemies. The introduction attains its most malevolent
+development in this century, being, indeed, closely related to our political
+system. Every American being the equal of every other American, it follows that
+everybody has the right to know everybody else, which implies the right to
+introduce without request or permission. The Declaration of Independence should
+have read thus:</p>
+
+<p class="quote">“We hold these truths to be self-evident: that all men are created equal; that they are
+endowed by their Creator with certain inalienable rights; that among these are
+life, and the right to make that of another miserable by thrusting upon him an
+incalculable quantity of acquaintances; liberty, particularly the liberty to
+introduce persons to one another without first ascertaining if they are not
+already acquainted as enemies; and the pursuit of another’s happiness with a
+running pack of strangers.”</p>
+
+<p class="entry"><span class="def">inventor</span>, <span class="pos">n.</span> A
+person who makes an ingenious arrangement of wheels, levers and springs, and
+believes it civilization.</p>
+
+<p class="entry"><span class="def">irreligion</span>, <span class="pos">n.</span> The
+principal one of the great faiths of the world.</p>
+
+<p class="entry"><span class="def">itch</span>, <span class="pos">n.</span> The
+patriotism of a Scotchman.</p>
+
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/I.html.i
@@ -1,0 +1,62 @@
+29 pages
+size 400 552
+length 40130
+396 2 10 body html
+0
+1452 2 34 body html
+56
+2967 2 55 body html
+216
+4626 2 82 body html
+108
+4626 2 82 body html
+648
+6344 2 114 body html
+141
+7343 2 133 body html
+243
+9427 2 161 body html
+252
+9427 2 161 body html
+790
+11521 2 200 body html
+73
+13272 2 224 body html
+124
+14087 2 234 body html
+451
+14087 2 234 body html
+991
+16500 2 279 body html
+0
+18562 2 306 body html
+0
+20433 2 334 body html
+0
+22151 2 367 body html
+0
+23431 2 384 body html
+209
+25306 2 412 body html
+246
+27137 2 443 body html
+0
+28326 2 467 body html
+22
+30507 2 499 body html
+0
+30991 2 507 body html
+413
+32627 2 540 body html
+39
+34139 2 571 body html
+0
+35615 2 596 body html
+0
+37320 2 627 body html
+36
+37320 2 627 body html
+576
+39859 2 673 body html
+0
+income 12
--- /dev/null
+++ b/lib/ebooks/devils/J.html
@@ -1,0 +1,74 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: J</title>
+</head>
+<body lang="en-US">
+
+<h1>J</h1>
+
+<p class="firstpara">J is a consonant in English, but some nations use it as a vowel—than which nothing could be more
+absurd. Its original form, which has been but slightly modified, was that of
+the tail of a subdued dog, and it was not a letter but a character, standing
+for a Latin verb, <i>jacere</i>, “to throw,” because when a stone is thrown at a dog the dog’s tail assumes that
+shape. This is the origin of the letter, as expounded by the renowned Dr.
+Jocolpus Bumer, of the University of Belgrade, who established his conclusions
+on the subject in a work of three quarto volumes and committed suicide on being
+reminded that the j in the Roman alphabet had originally no curl.</p>
+
+<p class="entry"><span class="def">jealous</span>, <span class="pos">adj.</span> Unduly
+concerned about the preservation of that which can be lost only if not worth keeping.</p>
+
+<p class="entry"><span class="def">jester</span>, <span class="pos">n.</span> An
+officer formerly attached to a king’s household, whose business it was to amuse
+the court by ludicrous actions and utterances, the absurdity being attested by
+his motley costume. The king himself being attired with dignity, it took the
+world some centuries to discover that his own conduct and decrees were
+sufficiently ridiculous for the amusement not only of his court but of all
+mankind. The jester was commonly called a fool, but the poets and romancers have
+ever delighted to represent him as a singularly wise and witty person. In the
+circus of to-day the melancholy ghost of the court fool effects the dejection
+of humbler audiences with the same jests wherewith in life he gloomed the
+marble hall, panged the patrician sense of humor and tapped the tank of royal tears.</p>
+
+<div class="poem">
+<p class="poetry">The widow-queen of Portugal</p>
+<p class="poetry">Had an audacious jester</p>
+<p class="poetry">Who entered the confessional</p>
+<p class="poetry">Disguised, and there confessed her.</p>
+<p class="poetry">“Father,” she said, “thine ear bend down—</p>
+<p class="poetry">My sins are more than scarlet:</p>
+<p class="poetry">I love my fool—blaspheming clown,</p>
+<p class="poetry">And common, base-born varlet.”</p>
+<p class="poetry">“Daughter,” the mimic priest replied,</p>
+<p class="poetry">“That sin, indeed, is awful:</p>
+<p class="poetry">The church’s pardon is denied</p>
+<p class="poetry"> To love that is unlawful.</p>
+<p class="poetry">“But since thy stubborn heart will be</p>
+<p class="poetry">For him forever pleading,</p>
+<p class="poetry">Thou’dst better make him, by decree,</p>
+<p class="poetry">A man of birth and breeding.”</p>
+<p class="poetry">She made the fool a duke, in hope</p>
+<p class="poetry">With Heaven’s taboo to palter;</p>
+<p class="poetry">Then told a priest, who told the Pope,</p>
+<p class="poetry">Who damned her from the altar!</p>
+<p class="citeauth">Barel Dort</p>
+</div>
+
+<p class="entry"><span class="def">Jews-harp</span>, <span class="pos">n.</span> An
+unmusical instrument, played by holding it fast with the teeth and trying to brush it away with the finger.</p>
+
+<p class="entry"><span class="def">Joss-sticks</span>, <span class="pos">n.</span> Small
+sticks burned by the Chinese in their pagan tomfoolery, in imitation of certain sacred rites of our holy religion.</p>
+
+<p class="entry"><span class="def">justice</span>, <span class="pos">n.</span> A
+commodity which is a more or less adulterated condition the State sells to the
+citizen as a reward for his allegiance, taxes and personal service.</p>
+
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/J.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 552
+length 3986
+396 2 10 body html
+0
+1286 2 26 body html
+209
+2152 2 38 body html
+523
--- /dev/null
+++ b/lib/ebooks/devils/K.html
@@ -1,0 +1,137 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: K</title>
+</head>
+<body lang="en-US">
+
+
+<h1>K</h1>
+
+<p class="firstpara">K is a consonant that we get from the Greeks, but it can be traced away back beyond them to the
+Cerathians, a small commercial nation inhabiting the peninsula of Smero. In
+their tongue it was called <i>Klatch</i>, which means “destroyed.” The form of the letter was originally precisely that
+of our H, but the erudite Dr. Snedeker explains that it was altered to its
+present shape to commemorate the destruction of the great temple of Jarute by
+an earthquake, <i>circa</i> 730 B.C. This building was famous for the two lofty columns of its portico, one of which was
+broken in half by the catastrophe, the other remaining intact. As the earlier
+form of the letter is supposed to have been suggested by these pillars, so, it
+is thought by the great antiquary, its later was adopted as a simple and
+natural—not to say touching—means of keeping the calamity ever in the national
+memory. It is not known if the name of the letter was altered as an additional
+mnemonic, or if the name was always <i>Klatch</i> and the destruction one of nature’s pums. As each theory seems probable enough,
+I see no objection to believing both—and Dr. Snedeker arrayed himself on that side of the question.</p>
+
+<p class="entry"><span class="def">keep</span>, <span class="pos">v.t.</span></p>
+
+<div class="poem">
+<p class="poetry">He willed away his whole estate,</p>
+<p class="poetry">And then in death he fell asleep,</p>
+<p class="poetry">Murmuring: “Well, at any rate,</p>
+<p class="poetry">My name unblemished I shall keep.”</p>
+<p class="poetry">But when upon the tomb ‘twas wrought Whose was it?&#8212;for the dead keep naught.</p>
+<p class="citeauth">Durang Gophel Arn</p>
+</div>
+
+<p class="entry"><span class="def">kill</span>, <span class="pos">v.t.</span> To
+create a vacancy without nominating a successor.</p>
+
+<p class="entry"><span class="def">kilt</span>, <span class="pos">n.</span> A costume
+sometimes worn by Scotchmen in America and Americans in Scotland.</p>
+
+<p class="entry"><span class="def">kindness</span>, <span class="pos">n.</span> A
+brief preface to ten volumes of exaction.</p>
+
+<p id="king" class="entry"><span class="def">king</span>, <span class="pos">n.</span> A male
+person commonly known in America as a “crowned head,” although he never wears a
+crown and has usually no head to speak of.</p>
+
+<div class="poem">
+<p class="poetry">A king, in times long, long gone by,</p>
+<p class="poetry">Said to his lazy jester:</p>
+<p class="poetry">“If I were you and you were I</p>
+<p class="poetry">My moments merrily would fly—</p>
+<p class="poetry">Nor care nor grief to pester.”</p>
+<p class="poetry">“The reason, Sire, that you would thrive,”</p>
+<p class="poetry">The fool said—“if you’ll hear it—</p>
+<p class="poetry">Is that of all the fools alive</p>
+<p class="poetry">Who own you for their sovereign, I’ve</p>
+<p class="poetry">The most forgiving spirit.”</p>
+<p class="citeauth">Oogum Bem</p>
+</div>
+
+<p class="entry"><span class="def">King’s Evil</span>, <span class="pos">n.</span> A
+malady that was formerly cured by the touch of the sovereign, but has now to be
+treated by the physicians. Thus ‘the most pious Edward” of England used to lay
+his royal hand upon the ailing subjects and make them whole—</p>
+
+<div class="poem">
+<p class="poetry">a crowd of wretched souls</p>
+<p class="poetry">That stay his cure: their malady convinces</p>
+<p class="poetry">The great essay of art; but at his touch,</p>
+<p class="poetry">Such sanctity hath Heaven given his hand,</p>
+<p class="poetry">They presently amend,</p>
+<p class="poetry">as the “Doctor” in <i>Macbeth</i> hath it. This useful property of the </p>
+<p class="poetry">royal hand could, it appears, be transmitted along with other crown </p>
+<p class="poetry">properties; for according to “Malcolm,”</p>
+<p class="poetry">‘tis spoken To the succeeding royalty he leaves The healing benediction.</p>
+<p class="poetry">But the gift somewhere dropped out of the line of succession: the later sovereigns of
+England have not been tactual healers, and the disease once honored with the
+name “king’s evil” now bears the humbler one of “scrofula,” from <i>scrofa</i>, a sow. The date and author of the
+following epigram are known only to the author of this dictionary, but it is
+old enough to show that the jest about Scotland’s national disorder is not a
+thing of yesterday.</p>
+<p class="poetry">Ye Kynge his evill in me laye,</p>
+<p class="poetry">Wh. he of Scottlande charmed awaye.</p>
+<p class="poetry">He layde his hand on mine and sayd:</p>
+<p class="poetry">“Be gone!” Ye ill no longer stayd.</p>
+<p class="poetry">But O ye wofull plyght in wh.</p>
+<p class="poetry">I’m now y-pight: I have ye itche!</p>
+<p class="poetry">The superstitionth at maladies can be cured by royal taction is </p>
+<p class="poetry">dead, but like many a departed conviction it has left a monument of </p>
+<p class="poetry">custom to keep its memory green. The practice of forming a line and </p>
+<p class="poetry">shaking the President’s hand had no other origin, and when that great </p>
+<p class="poetry">dignitary bestows his healing salutation on</p>
+<p class="poetry">strangely visited people,</p>
+<p class="poetry">All swoln and ulcerous, pitiful to the eye,</p>
+<p class="poetry">The mere despair of surgery,</p>
+<p class="poetry">he and his patients are handing along an extinguished torch which once was kindled at the
+altar-fire of a faith long held by all classes of men. It is a beautiful and
+edifying “survival”—one which brings the sainted past close home in our “business and bosoms.”</p>
+</div>
+
+<p class="entry"><span class="def">kiss</span>, <span class="pos">n.</span> A word
+invented by the poets as a rhyme for “bliss.” It is supposed to signify, in a
+general way, some kind of rite or ceremony appertaining to a good
+understanding; but the manner of its performance is unknown to this lexicographer.</p>
+
+<p class="entry"><span class="def">kleptomaniac</span>, <span class="pos">n.</span> A
+rich thief.</p>
+
+<p class="entry"><span class="def">knight</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Once a warrior gentle of birth,</p>
+<p class="poetry">Then a person of civic worth,</p>
+<p class="poetry">Now a fellow to move our mirth.</p>
+<p class="poetry">Warrior, person, and fellow—no more:</p>
+<p class="poetry">We must knight our dogs to get any lower.</p>
+<p class="poetry">Brave Knights Kennelers then shall be,</p>
+<p class="poetry">Noble Knights of the Golden Flea,</p>
+<p class="poetry">Knights of the Order of St. Steboy,</p>
+<p class="poetry">Knights of St. Gorge and Sir Knights Jawy.</p>
+<p class="poetry">God speed the day when this knighting fad</p>
+<p class="poetry">Shall go to the dogs and the dogs go mad.</p>
+</div>
+
+<p class="entry"><span class="def">Koran</span>, <span class="pos">n.</span> A book
+which the Mohammedans foolishly believe to have been written by divine
+inspiration, but which Christians know to be a wicked imposture, contradictory
+to the Holy Scriptures.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/K.html.i
@@ -1,0 +1,16 @@
+6 pages
+size 400 552
+length 7556
+396 2 10 body html
+0
+1716 2 31 body html
+91
+2763 2 53 body html
+252
+3711 2 72 body html
+305
+3711 2 72 body html
+854
+6594 2 117 body html
+91
+king 1
--- /dev/null
+++ b/lib/ebooks/devils/L.html
@@ -1,0 +1,525 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: L</title>
+</head>
+<body lang="en-US">
+
+<h1>L</h1>
+
+<p class="entry"><span class="def">labor</span>, <span class="pos">n.</span> One of
+the processes by which A acquires property for B.</p>
+
+<p class="entry"><span class="def">land</span>, <span class="pos">n.</span> A part of
+the earth’s surface, considered as property. The theory that land is property
+subject to private ownership and control is the foundation of modern society,
+and is eminently worthy of the superstructure. Carried to its logical
+conclusion, it means that some have the right to prevent others from living;
+for the right to own implies the right exclusively to occupy; and in fact laws
+of trespass are enacted wherever property in land is recognized. It follows
+that if the whole area of <i>terra firma</i>
+is owned by A, B and C, there will be no place for D, E, F and G to be born,
+or, born as trespassers, to exist.</p>
+
+<div class="poem">
+<p class="poetry">A life on the ocean wave,</p>
+<p class="poetry">A home on the rolling deep,</p>
+<p class="poetry">For the spark the nature gave</p>
+<p class="poetry">I have there the right to keep.</p>
+<p class="poetry">They give me the cat-o’-nine</p>
+<p class="poetry">Whenever I go ashore.</p>
+<p class="poetry">Then ho! for the flashing brine—</p>
+<p class="poetry">I’m a natural commodore!</p>
+<p class="citeauth">Dodle</p>
+</div>
+
+<p class="entry"><span class="def">language</span>, <span class="pos">n.</span> The
+music with which we charm the serpents guarding another’s treasure.</p>
+
+<p class="entry"><span class="def">Laocoon</span>, <span class="pos">n.</span> A
+famous piece of antique scripture representing a priest of that name and his
+two sons in the folds of two enormous serpents. The skill and diligence with
+which the old man and lads support the serpents and keep them up to their work
+have been justly regarded as one of the noblest artistic illustrations of the
+mastery of human intelligence over brute inertia.</p>
+
+<p class="entry"><span class="def">lap</span>, <span class="pos">n.</span> One of the
+most important organs of the female system—an admirable provision of nature for
+the repose of infancy, but chiefly useful in rural festivities to support
+plates of cold chicken and heads of adult males. The male of our species has a
+rudimentary lap, imperfectly developed and in no way contributing to the
+animal’s substantial welfare.</p>
+
+<p class="entry"><span class="def">last</span>, <span class="pos">n.</span> A
+shoemaker’s implement, named by a frowning Providence as opportunity to the
+maker of puns.</p>
+
+<div class="poem">
+<p class="poetry">Ah, punster, would my lot were cast,</p>
+<p class="poetry">Where the cobbler is unknown,</p>
+<p class="poetry">So that I might forget his last</p>
+<p class="poetry">And hear your own.</p>
+<p class="citeauth">Gargo Repsky</p>
+</div>
+
+<p class="entry"><span class="def">laughter</span>, <span class="pos">n.</span> An
+interior convulsion, producing a distortion of the features and accompanied by
+inarticulate noises. It is infectious and, though intermittent, incurable. Liability
+to attacks of laughter is one of the characteristics distinguishing man from
+the animals—these being not only inaccessible to the provocation of his
+example, but impregnable to the microbes having original jurisdiction in
+bestowal of the disease. Whether laughter could be imparted to animals by
+inoculation from the human patient is a question that has not been answered by
+experimentation. Dr. Meir Witchell holds that the infection character of
+laughter is due to the instantaneous fermentation of <i>sputa</i> diffused in a spray. From this peculiarity he names
+the disorder <i>Convulsio spargens</i>.</p>
+
+<p class="entry"><span class="def">laureate</span>, <span class="pos">adj.</span> Crowned
+with leaves of the laurel. In England the Poet Laureate is an officer of the
+sovereign’s court, acting as dancing skeleton at every royal feast and
+singing-mute at every royal funeral. Of all incumbents of that high office,
+Robert Southey had the most notable knack at drugging the Samson of public joy
+and cutting his hair to the quick; and he had an artistic color-sense which
+enabled him so to blacken a public grief as to give it the aspect of a national
+crime.</p>
+
+<p class="entry"><span class="def">laurel</span>, <span class="pos">n.</span> The <i>laurus</i>, a vegetable dedicated to Apollo,
+and formerly defoliated to wreathe the brows of victors and such poets as had
+influence at court. (<i>Vide supra.</i>)</p>
+
+<p id="law" class="entry"><span class="def">law</span>, <span class="pos">n.</span></p>
+
+<div class="poem">
+<p class="poetry">Once Law was sitting on the bench,</p>
+<p class="poetry">And Mercy knelt a-weeping.</p>
+<p class="poetry">“Clear out!” he cried, “disordered wench!</p>
+<p class="poetry">Nor come before me creeping.</p>
+<p class="poetry">Upon your knees if you appear,</p>
+<p class="poetry">‘Tis plain your have no standing here.”</p>
+<p class="poetry">Then Justice came. His Honor cried:</p>
+<p class="poetry">“<i>Your</i> status?&#8212;devil seize you!”</p>
+<p class="poetry">“<i>Amica curiae,</i>” she replied—</p>
+<p class="poetry">“Friend of the court, so please you.”</p>
+<p class="poetry">“Begone!” he shouted—“there’s the door—</p>
+<p class="poetry">I never saw your face before!”</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">lawful</span>, <span class="pos">adj.</span> Compatible
+with the will of a judge having jurisdiction.</p>
+
+<p id="lawyer" class="entry"><span class="def">lawyer</span>, <span class="pos">n.</span> One
+skilled in circumvention of the law.</p>
+
+<p class="entry"><span class="def">laziness</span>, <span class="pos">n.</span> Unwarranted
+repose of manner in a person of low degree.</p>
+
+<p class="entry"><span class="def">lead</span>, <span class="pos">n.</span> A heavy
+blue-gray metal much used in giving stability to light lovers—particularly to
+those who love not wisely but other men’s wives. Lead is also of great service
+as a counterpoise to an argument of such weight that it turns the scale of
+debate the wrong way. An interesting fact in the chemistry of international
+controversy is that at the point of contact of two patriotisms lead is
+precipitated in great quantities.</p>
+
+<div class="poem">
+<p class="poetry">Hail, holy Lead!&#8212;of human feuds the great</p>
+<p class="poetry">And universal arbiter; endowed</p>
+<p class="poetry">With penetration to pierce any cloud</p>
+<p class="poetry">Fogging the field of controversial hate,</p>
+<p class="poetry">And with a sift, inevitable, straight,</p>
+<p class="poetry">Searching precision find the unavowed</p>
+<p class="poetry">But vital point. Thy judgment, when allowed</p>
+<p class="poetry">By the chirurgeon, settles the debate.</p>
+<p class="poetry">O useful metal!&#8212;were it not for thee</p>
+<p class="poetry">We’d grapple one another’s ears alway:</p>
+<p class="poetry">But when we hear thee buzzing like a bee</p>
+<p class="poetry">We, like old Muhlenberg, “care not to stay.”</p>
+<p class="poetry">And when the quick have run away like pellets</p>
+<p class="poetry">Jack Satan smelts the dead to make new bullets.</p>
+</div>
+
+<p class="entry"><span class="def">learning</span>, <span class="pos">n.</span> The
+kind of ignorance distinguishing the studious.</p>
+
+<p class="entry"><span class="def">lecturer</span>, <span class="pos">n.</span> One
+with his hand in your pocket, his tongue in your ear and his faith in your patience.</p>
+
+<p class="entry"><span class="def">legacy</span>, <span class="pos">n.</span> A gift
+from one who is legging it out of this vale of tears.</p>
+
+<p class="entry"><span class="def">leonine</span>, <span class="pos">adj.</span> Unlike
+a menagerie lion. Leonine verses are those in which a word in the middle of a
+line rhymes with a word at the end, as in this famous passage from Bella Peeler Silcox:</p>
+
+<div class="poem">
+<p class="poetry">The electric light invades the dunnest deep of Hades.</p>
+<p class="poetry">Cries Pluto, ‘twixt his snores: “O tempora! O mores!”</p>
+<p class="poetry">It should be explained that Mrs. Silcox does not undertake to teach pronunciation of the
+Greek and Latin tongues. Leonine verses are so called in honor of a poet named
+Leo, whom prosodists appear to find a pleasure in believing to have been the
+first to discover that a rhyming couplet could be run into a single line.</p>
+</div>
+
+<p class="entry"><span class="def">lettuce</span>, <span class="pos">n.</span> An
+herb of the genus <i>Lactuca</i>, “Wherewith,” says that pious gastronome, Hengist Pelly, “God has been pleased
+to reward the good and punish the wicked. For by his inner light the righteous
+man has discerned a manner of compounding for it a dressing to the appetency
+whereof a multitude of gustible condiments conspire, being reconciled and
+ameliorated with profusion of oil, the entire comestible making glad the heart
+of the godly and causing his face to shine. But the person of spiritual unworth
+is successfully tempted to the Adversary to eat of lettuce with destitution of
+oil, mustard, egg, salt and garlic, and with a rascal bath of vinegar polluted
+with sugar. Wherefore the person of spiritual unworth suffers an intestinal
+pang of strange complexity and raises the song.”</p>
+
+<p class="entry"><span class="def">leviathan</span>, <span class="pos">n.</span> An
+enormous aquatic animal mentioned by Job. Some suppose it to have been the
+whale, but that distinguished ichthyologer, Dr. Jordan, of Stanford University,
+maintains with considerable heat that it was a species of gigantic Tadpole
+(<i>Thaddeus Polandensis</i>) or Polliwig&#8212;<i>Maria
+pseudo-hirsuta</i>. For an exhaustive description and history of the
+Tadpole consult the famous monograph of Jane Potter, <i>Thaddeus of Warsaw</i>.</p>
+
+<p class="entry"><span class="def">lexicographer</span>, <span class="pos">n.</span> A
+pestilent fellow who, under the pretense of recording some particular stage in
+the development of a language, does what he can to arrest its growth, stiffen
+its flexibility and mechanize its methods. For your lexicographer, having
+written his dictionary, comes to be considered “as one having authority,”
+whereas his function is only to make a record, not to give a law. The natural
+servility of the human understanding having invested him with judicial power,
+surrenders its right of reason and submits itself to a chronicle as if it were
+a statue. Let the dictionary (for example) mark a good word as “obsolete” or
+“obsolescent” and few men thereafter venture to use it, whatever their need of
+it and however desirable its restoration to favor—whereby the process of
+improverishment is accelerated and speech decays. On the contrary, recognizing
+the truth that language must grow by innovation if it grow at all, makes new
+words and uses the old in an unfamiliar sense, has no following and is tartly
+reminded that “it isn’t in the dictionary”&#8212;although down to the time of the
+first lexicographer (Heaven forgive him!) no author ever had used a word that <i>was</i> in the dictionary. In the golden prime
+and high noon of English speech; when from the lips of the great Elizabethans
+fell words that made their own meaning and carried it in their very sound; when
+a Shakespeare and a Bacon were possible, and the language now rapidly perishing
+at one end and slowly renewed at the other was in vigorous growth and hardy
+preservation—sweeter than honey and stronger than a lion—the lexicographer was
+a person unknown, the dictionary a creation which his Creator had not created
+him to create.</p>
+
+<div class="poem">
+<p class="poetry">God said: “Let Spirit perish into Form,”</p>
+<p class="poetry">And lexicographers arose, a swarm!</p>
+<p class="poetry">Thought fled and left her clothing, which they took,</p>
+<p class="poetry">And catalogued each garment in a book.</p>
+<p class="poetry">Now, from her leafy covert when she cries:</p>
+<p class="poetry">“Give me my clothes and I’ll return,” they rise</p>
+<p class="poetry">And scan the list, and say without compassion:</p>
+<p class="poetry">“Excuse us—they are mostly out of fashion.”</p>
+<p class="citeauth">Sigismund Smith</p>
+</div>
+
+<p class="entry"><span class="def">liar</span>, <span class="pos">n.</span> A lawyer
+with a roving commission.</p>
+
+<p class="entry"><span class="def">liberty</span>, <span class="pos">n.</span> One of
+Imagination’s most precious possessions.</p>
+
+<div class="poem">
+<p class="poetry">The rising People, hot and out of breath,</p>
+<p class="poetry">Roared around the palace: “Liberty or death!”</p>
+<p class="poetry">“If death will do,” the King said, “let me reign;</p>
+<p class="poetry">You’ll have, I’m sure, no reason to complain.”</p>
+<p class="citeauth">Martha Braymance</p>
+</div>
+
+<p class="entry"><span class="def">lickspittle</span>, <span class="pos">n.</span> A
+useful functionary, not infrequently found editing a newspaper. In his
+character of editor he is closely allied to the blackmailer by the tie of
+occasional identity; for in truth the lickspittle is only the blackmailer under
+another aspect, although the latter is frequently found as an independent
+species. Lickspittling is more detestable than blackmailing, precisely as the
+business of a confidence man is more detestable than that of a highway robber;
+and the parallel maintains itself throughout, for whereas few robbers will
+cheat, every sneak will plunder if he dare.</p>
+
+<p class="entry"><span class="def">life</span>, <span class="pos">n.</span> A
+spiritual pickle preserving the body from decay. We live in daily apprehension
+of its loss; yet when lost it is not missed. The question, “Is life worth
+living?” has been much discussed; particularly by those who think it is not,
+many of whom have written at great length in support of their view and by
+careful observance of the laws of health enjoyed for long terms of years the
+honors of successful controversy.</p>
+
+<div class="poem">
+<p class="poetry">“Life’s not worth living, and that’s the truth,”</p>
+<p class="poetry">Carelessly caroled the golden youth.</p>
+<p class="poetry">In manhood still he maintained that view</p>
+<p class="poetry">And held it more strongly the older he grew.</p>
+<p class="poetry">When kicked by a jackass at eighty-three,</p>
+<p class="poetry">“Go fetch me a surgeon at once!” cried he.</p>
+<p class="citeauth">Han Soper</p>
+</div>
+
+<p class="entry"><span class="def">lighthouse</span>, <span class="pos">n.</span> A
+tall building on the seashore in which the government maintains a lamp and the friend of a politician.</p>
+
+<p class="entry"><span class="def">limb</span>, <span class="pos">n.</span> The
+branch of a tree or the leg of an American woman.</p>
+
+<div class="poem">
+<p class="poetry">‘Twas a pair of boots that the lady bought,</p>
+<p class="poetry">And the salesman laced them tight</p>
+<p class="poetry">To a very remarkable height—</p>
+<p class="poetry">Higher, indeed, than I think he ought—</p>
+<p class="poetry">Higher than <i>can</i> be right.</p>
+<p class="poetry">For the Bible declares—but never mind:</p>
+<p class="poetry">It is hardly fit</p>
+<p class="poetry">To censure freely and fault to find</p>
+<p class="poetry">With others for sins that I’m not inclined</p>
+<p class="poetry">Myself to commit.</p>
+<p class="poetry">Each has his weakness, and though my own</p>
+<p class="poetry">Is freedom from every sin,</p>
+<p class="poetry">It still were unfair to pitch in,</p>
+<p class="poetry">Discharging the first censorious stone.</p>
+<p class="poetry">Besides, the truth compels me to say,</p>
+<p class="poetry">The boots in question were <i>made</i> that way.</p>
+<p class="poetry">As he drew the lace she made a grimace,</p>
+<p class="poetry">And blushingly said to him:</p>
+<p class="poetry">“This boot, I’m sure, is too high to endure, It hurts my—hurts my—limb.”</p>
+<p class="poetry">The salesman smiled in a manner mild,</p>
+<p class="poetry">Like an artless, undesigning child;</p>
+<p class="poetry">Then, checking himself, to his face he gave</p>
+<p class="poetry">A look as sorrowful as the grave,</p>
+<p class="poetry">Though he didn’t care two figs</p>
+<p class="poetry">For her paints and throes,</p>
+<p class="poetry">As he stroked her toes,</p>
+<p class="poetry">Remarking with speech and manner just</p>
+<p class="poetry">Befitting his calling: “Madam, I trust</p>
+<p class="poetry">That it doesn’t hurt your twigs.”</p>
+<p class="citeauth">B. Percival Dike</p>
+</div>
+
+<p class="entry"><span class="def">linen</span>, <span class="pos">n.</span> “A kind
+of cloth the making of which, when made of hemp, entails a great waste of
+hemp.”—Calcraft the Hangman.</p>
+
+<p class="entry"><span class="def">litigant</span>, <span class="pos">n.</span> A
+person about to give up his skin for the hope of retaining his bones.</p>
+
+<p class="entry"><span class="def">litigation</span>, <span class="pos">n.</span> A
+machine which you go into as a pig and come out of as a sausage.</p>
+
+<p class="entry"><span class="def">liver</span>, <span class="pos">n.</span> A large
+red organ thoughtfully provided by nature to be bilious with. The sentiments
+and emotions which every literary anatomist now knows to haunt the heart were
+anciently believed to infest the liver; and even Gascoygne, speaking of the
+emotional side of human nature, calls it “our hepaticall parte.” It was at one
+time considered the seat of life; hence its name—liver, the thing we live with.
+The liver is heaven’s best gift to the goose; without it that bird would be
+unable to supply us with the Strasbourg <i>pate</i>.</p>
+
+<p>LL.D. Letters indicating the degree <i>Legumptionorum Doctor</i>,
+one learned in laws, gifted with legal gumption. Some suspicion is cast upon
+this derivation by the fact that the title was formerly <i>LL.d.</i>, and conferred only upon gentlemen
+distinguished for their wealth. At the date of this writing Columbia University
+is considering the expediency of making another degree for clergymen, in place
+of the old D.D.&#8212;<i>Damnator Diaboli</i>.
+The new honor will be known as <i>Sanctorum Custus</i>, and written <i>$$c</i>. The name of the Rev. John Satan has
+been suggested as a suitable recipient by a lover of consistency, who points
+out that Professor Harry Thurston Peck has long enjoyed the advantage of a
+degree.</p>
+
+<p class="entry"><span class="def">lock-and-key</span>, <span class="pos">n.</span> The
+distinguishing device of civilization and enlightenment.</p>
+
+<p class="entry"><span class="def">Lodger</span>, <span class="pos">n.</span> A less
+popular name for the Second Person of that delectable newspaper Trinity, the
+Roomer, the Bedder, and the Mealer.</p>
+
+<p class="entry"><span class="def">logic</span>, <span class="pos">n.</span> The art
+of thinking and reasoning in strict accordance with the limitations and
+incapacities of the human misunderstanding. The basic of logic is the
+syllogism, consisting of a major and a minor premise and a conclusion—thus:</p>
+
+<p><i>Major Premise</i>: Sixty men can do a piece of work sixty times as quickly as one man.</p>
+
+<p><i>Minor Premise</i>: One man can dig a posthole in sixty seconds; therefore—</p>
+
+<p><i>Conclusion</i>: Sixty men can dig a posthole in one second.</p>
+
+<p>This may be called the syllogism arithmetical, in which, by combining logic and mathematics, we
+obtain a double certainty and are twice blessed.</p>
+
+<p class="entry"><span class="def">logomachy</span>, <span class="pos">n.</span> A
+war in which the weapons are words and the wounds punctures in the swim-bladder
+of self-esteem—a kind of contest in which, the vanquished being unconscious of
+defeat, the victor is denied the reward of success.</p>
+
+<div class="poem">
+<p class="poetry">‘Tis said by divers of the scholar-men That poor Salmasius died of Milton’s pen.</p>
+<p class="poetry">Alas! we cannot know if this is true,</p>
+<p class="poetry">For reading Milton’s wit we perish too.</p>
+</div>
+
+<p class="entry"><span class="def">loganimity</span>, <span class="pos">n.</span> The
+disposition to endure injury with meek forbearance while maturing a plan of revenge.</p>
+
+<p class="entry"><span class="def">longevity</span>, <span class="pos">n.</span> Uncommon
+extension of the fear of death.</p>
+
+<p class="entry"><span class="def">looking-glass</span>, <span class="pos">n.</span> A
+vitreous plane upon which to display a fleeting show for man’s disillusion given.</p>
+
+<p class="cite">The King of
+Manchuria had a magic looking-glass, whereon whoso looked saw, not his own
+image, but only that of the king. A certain courtier who had long enjoyed the
+king’s favor and was thereby enriched beyond any other subject of the realm,
+said to the king: </p>
+
+<p class="cite">“Give me, I pray,
+thy wonderful mirror, so that when absent out of thine august presence I may
+yet do homage before thy visible shadow, prostrating myself night and morning
+in the glory of thy benign countenance, as which nothing has so divine
+splendor, O Noonday Sun of the Universe!”</p>
+
+<p class="cite">Please with the
+speech, the king commanded that the mirror be conveyed to the courtier’s
+palace; but after, having gone thither without apprisal, he found it in an
+apartment where was naught but idle lumber. And the mirror was dimmed with dust
+and overlaced with cobwebs. This so angered him that he fisted it hard,
+shattering the glass, and was sorely hurt. Enraged all the more by this
+mischance, he commanded that the ungrateful courtier be thrown into prison, and
+that the glass be repaired and taken back to his own palace; and this was done.
+But when the king looked again on the mirror he saw not his image as before,
+but only the figure of a crowned ass, having a bloody bandage on one of its
+hinder hooves—as the artificers and all who had looked upon it had before
+discerned but feared to report. Taught wisdom and charity, the king restored
+his courtier to liberty, had the mirror set into the back of the throne and
+reigned many years with justice and humility; and one day when he fell asleep
+in death while on the throne, the whole court saw in the mirror the luminous
+figure of an angel, which remains to this day.</p>
+
+<p class="entry"><span class="def">loquacity</span>, <span class="pos">n.</span> A
+disorder which renders the sufferer unable to curb his tongue when you wish to
+talk.</p>
+
+<p class="entry"><span class="def">lord</span>, <span class="pos">n.</span> In
+American society, an English tourist above the state of a costermonger, as,
+lord ‘Aberdasher, Lord Hartisan and so forth. The traveling Briton of lesser
+degree is addressed as “Sir,” as, Sir ‘Arry Donkiboi, or ‘Amstead ‘Eath. The
+word “Lord” is sometimes used, also, as a title of the Supreme Being; but this
+is thought to be rather flattery than true reverence.</p>
+
+<div class="poem">
+<p class="poetry">Miss Sallie Ann Splurge, of her own accord,<br />
+Wedded a wandering English lord—</p>
+<p class="poetry">Wedded and took him to dwell with her “paw,”<br />
+A parent who throve by the practice of Draw.</p>
+<p class="poetry">Lord Cadde I don’t hesitate to declare</p>
+<p class="poetry">Unworthy the father-in-legal care</p>
+<p class="poetry">Of that elderly sport, notwithstanding the truth<br />
+That Cadde had renounced all the follies of youth;</p>
+<p class="poetry">For, sad to relate, he’d arrived at the stage<br />
+Of existence that’s marked by the vices of age.<br />
+Among them, cupidity caused him to urge<br />
+Repeated demands on the pocket of Splurge,<br />
+Till, wrecked in his fortune, that gentleman saw<br />
+Inadequate aid in the practice of Draw,<br />
+And took, as a means of augmenting his pelf,<br />
+To the business of being a lord himself.</p>
+<p class="poetry">His neat-fitting garments he wilfully shed<br />
+And sacked himself strangely in checks instead;</p>
+<p class="poetry">Denuded his chin, but retained at each ear<br />
+A whisker that looked like a blasted career.<br />
+He painted his neck an incarnadine hue<br />
+Each morning and varnished it all that he knew.</p>
+<p class="poetry">The moony monocular set in his eye</p>
+<p class="poetry">Appeared to be scanning the Sweet Bye-and-Bye.<br />
+His head was enroofed with a billycock hat, And
+his low-necked shoes were aduncous and flat.</p>
+<p class="poetry">In speech he eschewed his American ways,</p>
+<p class="poetry">Denying his nose to the use of his A’s</p>
+<p class="poetry">And dulling their edge till the delicate sense<br />
+Of a babe at their temper could take no offence.<br />
+His H’s—‘twas most inexpressibly sweet,<br />
+The patter they made as they fell at his feet!</p>
+<p class="poetry">Re-outfitted thus, Mr. Splurge without fear</p>
+<p class="poetry">Began as Lord Splurge his recouping career.</p>
+<p class="poetry">Alas, the Divinity shaping his end</p>
+<p class="poetry">Entertained other views and decided to send</p>
+<p class="poetry">His lordship in horror, despair and dismay</p>
+<p class="poetry">From the land of the nobleman’s natural prey.</p>
+<p class="poetry">For, smit with his Old World ways,</p>
+<p class="poetry">Lady Cadde Fell—suffering Caesar!&#8212;in love with her dad!</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">lore</span>, <span class="pos">n.</span> Learning—particularly
+that sort which is not derived from a regular course of instruction but comes
+of the reading of occult books, or by nature. This latter is commonly
+designated as folk-lore and embraces popularly myths and superstitions. In
+Baring-Gould’s <i>Curious Myths of the Middle
+Ages</i> the reader will find many of these traced backward, through
+various people son converging lines, toward a common origin in remote
+antiquity. Among these are the fables of “Teddy the Giant Killer,” “The
+Sleeping John Sharp Williams,” “Little Red Riding Hood and the Sugar Trust,”
+“Beauty and the Brisbane,” “The Seven Aldermen of Ephesus,” “Rip Van
+Fairbanks,” and so forth. The fable with Goethe so affectingly relates under
+the title of “The Erl- King” was known two thousand years ago in Greece as “The
+Demos and the Infant Industry.” One of the most general and ancient of these
+myths is that Arabian tale of “Ali Baba and the Forty Rockefellers.”</p>
+
+<p class="entry"><span class="def">loss</span>, <span class="pos">n.</span> Privation
+of that which we had, or had not. Thus, in the latter sense, it is said of a
+defeated candidate that he “lost his election”; and of that eminent man, the
+poet Gilder, that he has “lost his mind.” It is in the former and more
+legitimate sense, that the word is used in the famous epitaph:</p>
+
+<div class="poem">
+<p class="poetry">Here Huntington’s ashes long have lain</p>
+<p class="poetry">Whose loss is our eternal gain,</p>
+<p class="poetry">For while he exercised all his powers</p>
+<p class="poetry">Whatever he gained, the loss was ours.</p>
+</div>
+
+<p class="entry"><span class="def">love</span>, <span class="pos">n.</span> A
+temporary insanity curable by marriage or by removal of the patient from the
+influences under which he incurred the disorder. This disease, like <i>caries</i> and many other ailments, is
+prevalent only among civilized races living under artificial conditions;
+barbarous nations breathing pure air and eating simple food enjoy immunity from
+its ravages. It is sometimes fatal, but more frequently to the physician than to the patient.</p>
+
+<p class="entry"><span class="def">low-bred</span>, <span class="pos">adj.</span> “Raised”
+instead of brought up.</p>
+
+<p class="entry"><span class="def">luminary</span>, <span class="pos">n.</span> One
+who throws light upon a subject; as an editor by not writing about it.</p>
+
+<p class="entry"><span class="def">lunarian</span>, <span class="pos">n.</span> An
+inhabitant of the moon, as distinguished from Lunatic, one whom the moon
+inhabits. The Lunarians have been described by Lucian, Locke and other
+observers, but without much agreement. For example, Bragellos avers their
+anatomical identity with Man, but Professor Newcomb says they are more like the
+hill tribes of Vermont.</p>
+
+<p class="entry"><span class="def">lyre</span>, <span class="pos">n.</span> An
+ancient instrument of torture. The word is now used in a figurative sense to
+denote the poetic faculty, as in the following fiery lines of our great poet,
+Ella Wheeler Wilcox:</p>
+
+<div class="poem">
+<p class="poetry">I sit astride Parnassus with my lyre,</p>
+<p class="poetry">And pick with care the disobedient wire.</p>
+<p class="poetry">That stupid shepherd lolling on his crook With deaf attention scarcely deigns to look. I
+bide my time, and it shall come at length, When, with a Titan’s energy and
+strength, I’ll grab a fistful of the strings, and O, The word shall suffer when
+I let them go!</p>
+<p class="citeauth">Farquharson Harris</p>
+</div>
+
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/L.html.i
@@ -1,0 +1,45 @@
+20 pages
+size 400 552
+length 29470
+396 2 10 body html
+0
+1257 2 28 body html
+235
+2934 2 61 body html
+127
+4970 2 96 body html
+36
+6178 2 121 body html
+0
+6684 2 129 body html
+415
+8845 2 168 body html
+73
+10249 2 188 body html
+260
+12064 2 212 body html
+320
+13945 2 248 body html
+107
+15236 2 272 body html
+199
+15236 2 272 body html
+737
+17527 2 315 body html
+56
+19544 2 347 body html
+34
+20992 2 376 body html
+51
+22915 2 409 body html
+0
+23378 2 416 body html
+439
+23378 2 416 body html
+990
+27237 2 481 body html
+36
+28972 2 513 body html
+72
+law 2
+lawyer 3
--- /dev/null
+++ b/lib/ebooks/devils/M.html
@@ -1,0 +1,580 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: M</title>
+</head>
+<body lang="en-US">
+
+
+<h1>M</h1>
+
+<p class="entry"><span class="def">mace</span>, <span class="pos">n.</span> A staff
+of office signifying authority. Its form, that of a heavy club, indicates its
+original purpose and use in dissuading from dissent.</p>
+
+<p class="entry"><span class="def">machination</span>, <span class="pos">n.</span> The
+method employed by one’s opponents in baffling one’s open and honorable efforts
+to do the right thing.</p>
+
+<div class="poem">
+<p class="poetry">So plain the advantages of machination</p>
+<p class="poetry">It constitutes a moral obligation,</p>
+<p class="poetry">And honest wolves who think upon’t with loathing</p>
+<p class="poetry">Feel bound to don the sheep’s deceptive clothing.</p>
+<p class="poetry">So prospers still the diplomatic art,</p>
+<p class="poetry">And Satan bows, with hand upon his heart.</p>
+<p class="citeauth">R. S. K.</p>
+</div>
+
+<p class="entry"><span class="def">macrobian</span>, <span class="pos">n.</span> One
+forgotten of the gods and living to a great age. History is abundantly supplied
+with examples, from Methuselah to Old Parr, but some notable instances of
+longevity are less well known. A Calabrian peasant named Coloni, born in 1753,
+lived so long that he had what he considered a glimpse of the dawn of universal
+peace. Scanavius relates that he knew an archbishop who was so old that he
+could remember a time when he did not deserve hanging. In 1566 a linen draper
+of Bristol, England, declared that he had lived five hundred years, and that in
+all that time he had never told a lie. There are instances of longevity
+(<i>macrobiosis</i>) in our own country. Senator Chauncey Depew is old enough to
+know better. The editor of <i>The American</i>,
+a newspaper in New York City, has a memory that goes back to the time when he
+was a rascal, but not to the fact. The President of the United States was born
+so long ago that many of the friends of his youth have risen to high political
+and military preferment without the assistance of personal merit. The verses
+following were written by a macrobian:</p>
+
+<div class="poem">
+<p class="poetry">When I was young the world was fair</p>
+<p class="poetry">And amiable and sunny.</p>
+<p class="poetry">A brightness was in all the air,</p>
+<p class="poetry">In all the waters, honey.</p>
+<p class="poetry">The jokes were fine and funny,</p>
+<p class="poetry">The statesmen honest in their views,</p>
+<p class="poetry">And in their lives, as well,</p>
+<p class="poetry">And when you heard a bit of news</p>
+<p class="poetry">‘Twas true enough to tell.</p>
+<p class="poetry">Men were not ranting, shouting, reeking,</p>
+<p class="poetry">Nor women “generally speaking.”</p>
+<p class="poetry">The Summer then was long indeed:</p>
+<p class="poetry">It lasted one whole season!</p>
+<p class="poetry">The sparkling Winter gave no heed</p>
+<p class="poetry">When ordered by Unreason</p>
+<p class="poetry">To bring the early peas on.</p>
+<p class="poetry">Now, where the dickens is the sense</p>
+<p class="poetry"> In calling that a year</p>
+<p class="poetry">Which does no more than just commence</p>
+<p class="poetry">Before the end is near?</p>
+<p class="poetry">When I was young the year extended</p>
+<p class="poetry">From month to month until it ended.</p>
+<p class="poetry">I know not why the world has changed</p>
+<p class="poetry">To something dark and dreary,</p>
+<p class="poetry">And everything is now arranged</p>
+<p class="poetry">To make a fellow weary.</p>
+<p class="poetry">The Weather Man—I fear he</p>
+<p class="poetry">Has much to do with it, for, sure,</p>
+<p class="poetry">The air is not the same:</p>
+<p class="poetry">It chokes you when it is impure,</p>
+<p class="poetry">When pure it makes you lame.</p>
+<p class="poetry">With windows closed you are asthmatic;</p>
+<p class="poetry">Open, neuralgic or sciatic.</p>
+<p class="poetry">Well, I suppose this new regime</p>
+<p class="poetry">Of dun degeneration</p>
+<p class="poetry">Seems eviler than it would seem</p>
+<p class="poetry">To a better observation,</p>
+<p class="poetry">And has for compensation</p>
+<p class="poetry">Some blessings in a deep disguise</p>
+<p class="poetry">Which mortal sight has failed</p>
+<p class="poetry">To pierce, although to angels’ eyes</p>
+<p class="poetry">They’re visible unveiled.</p>
+<p class="poetry">If Age is such a boon, good land!</p>
+<p class="poetry">He’s costumed by a master hand!</p>
+<p class="citeauth">Venable Strigg</p>
+</div>
+
+<p class="entry"><span class="def">mad</span>, <span class="pos">adj.</span> Affected
+with a high degree of intellectual independence; not conforming to standards of
+thought, speech and action derived by the conformants from study of themselves;
+at odds with the majority; in short, unusual. It is noteworthy that persons are
+pronounced mad by officials destitute of evidence that themselves are sane. For
+illustration, this present (and illustrious) lexicographer is no firmer in the
+faith of his own sanity than is any inmate of any madhouse in the land; yet for
+aught he knows to the contrary, instead of the lofty occupation that seems to
+him to be engaging his powers he may really be beating his hands against the
+window bars of an asylum and declaring himself Noah Webster, to the innocent
+delight of many thoughtless spectators.</p>
+
+<p class="entry"><span class="def">Magdalene</span>, <span class="pos">n.</span> An
+inhabitant of Magdala. Popularly, a woman found out. This definition of the
+word has the authority of ignorance, Mary of Magdala being another person than
+the penitent woman mentioned by St. Luke. It has also the official sanction of
+the governments of Great Britain and the United States. In England the word is
+pronounced Maudlin, whence maudlin, adjective, unpleasantly sentimental. With
+their Maudlin for Magdalene, and their Bedlam for Bethlehem, the English may
+justly boast themselves the greatest of revisers.</p>
+
+<p class="entry"><span class="def">magic</span>, <span class="pos">n.</span> An art
+of converting superstition into coin. There are other arts serving the same
+high purpose, but the discreet lexicographer does not name them.</p>
+
+<p class="entry"><span class="def">magnet</span>, <span class="pos">n.</span> Something
+acted upon by magnetism.</p>
+
+<p class="entry"><span class="def">magnetism</span>, <span class="pos">n.</span> Something
+acting upon a magnet.</p>
+
+<p class="indentpara">The two definitions immediately foregoing are condensed from the works of one thousand
+eminent scientists, who have illuminated the subject with a great white light,
+to the inexpressible advancement of human knowledge.</p>
+
+<p class="entry"><span class="def">magnificient</span>, <span class="pos">adj.</span> Having
+a grandeur or splendor superior to that to which the spectator is accustomed,
+as the ears of an ass, to a rabbit, or the glory of a glowworm, to a maggot.</p>
+
+<p class="entry"><span class="def">magnitude</span>, <span class="pos">n.</span> Size.
+Magnitude being purely relative, nothing is large and nothing small. If
+everything in the universe were increased in bulk one thousand diameters
+nothing would be any larger than it was before, but if one thing remain
+unchanged all the others would be larger than they had been. To an
+understanding familiar with the relativity of magnitude and distance the spaces
+and masses of the astronomer would be no more impressive than those of the
+microscopist. For anything we know to the contrary, the visible universe may be
+a small part of an atom, with its component ions, floating in the life- fluid
+(luminiferous ether) of some animal. Possibly the wee creatures peopling the
+corpuscles of our own blood are overcome with the proper emotion when
+contemplating the unthinkable distance from one of these to another.</p>
+
+<p class="entry"><span class="def">magpie</span>, <span class="pos">n.</span> A bird
+whose thievish disposition suggested to someone that it might be taught to talk.</p>
+
+<p class="entry"><span class="def">maiden</span>, <span class="pos">n.</span> A young
+person of the unfair sex addicted to clewless conduct and views that madden to
+crime. The genus has a wide geographical distribution, being found wherever
+sought and deplored wherever found. The maiden is not altogether unpleasing to
+the eye, nor (without her piano and her views) insupportable to the ear, though
+in respect to comeliness distinctly inferior to the rainbow, and, with regard
+to the part of her that is audible, bleating out of the field by the
+canary—which, also, is more portable.</p>
+
+<div class="poem">
+<p class="poetry">A lovelorn maiden she sat and sang—</p>
+<p class="poetry">This quaint, sweet song sang she;</p>
+<p class="poetry">“It’s O for a youth with a football bang</p>
+<p class="poetry">And a muscle fair to see!</p>
+<p class="poetry">The Captain he</p>
+<p class="poetry">Of a team to be!</p>
+<p class="poetry">On the gridiron he shall shine,</p>
+<p class="poetry">A monarch by right divine,</p>
+<p class="poetry">And never to roast on it—me!”</p>
+<p class="citeauth">Opoline Jones</p>
+</div>
+
+<p class="entry"><span class="def">majesty</span>, <span class="pos">n.</span> The
+state and title of a king. Regarded with a just contempt by the Most Eminent
+Grand Masters, Grand Chancellors, Great Incohonees and Imperial Potentates of
+the ancient and honorable orders of republican America.</p>
+
+<p id="male" class="entry"><span class="def">male</span>, <span class="pos">n.</span> A member
+of the unconsidered, or negligible sex. The male of the human race is commonly
+known (to the female) as Mere Man. The genus has two varieties: good providers
+and bad providers.</p>
+
+<p class="entry"><span class="def">malefactor</span>, <span class="pos">n.</span> The
+chief factor in the progress of the human race.</p>
+
+<p class="entry"><span class="def">malthusian</span>, <span class="pos">adj.</span> Pertaining
+to Malthus and his doctrines. Malthus believed in artificially limiting
+population, but found that it could not be done by talking. One of the most
+practical exponents of the Malthusian idea was Herod of Judea, though all the
+famous soldiers have been of the same way of thinking.</p>
+
+<p class="entry"><span class="def">mammalia</span>, <span class="pos">n.</span>pl. A
+family of vertebrate animals whose females in a state of nature suckle their
+young, but when civilized and enlightened put them out to nurse, or use the bottle.</p>
+
+<p class="entry"><span class="def">Mammon</span>, <span class="pos">n.</span> The god
+of the world’s leading religion. The chief temple is in the holy city of New York.</p>
+
+<div class="poem">
+<p class="poetry">He swore that all other religions were</p>
+<p class="poetry">gammon, And wore out his knees in the worship of Mammon.</p>
+<p class="citeauth">Jared Oopf</p>
+</div>
+
+<p class="entry"><span class="def">man</span>, <span class="pos">n.</span> An animal
+so lost in rapturous contemplation of what he thinks he is as to overlook what
+he indubitably ought to be. His chief occupation is extermination of other
+animals and his own species, which, however, multiplies with such insistent
+rapidity as to infest the whole habitable earh and Canada.</p>
+
+<div class="poem">
+<p class="poetry">When the world was young and Man was new,</p>
+<p class="poetry">And everything was pleasant,</p>
+<p class="poetry">Distinctions Nature never drew</p>
+<p class="poetry">‘Mongst kings and priest and peasant.</p>
+<p class="poetry">We’re not that way at present,</p>
+<p class="poetry">Save here in this Republic, where</p>
+<p class="poetry">We have that old regime,</p>
+<p class="poetry">For all are kings, however bare</p>
+<p class="poetry">Their backs, howe’er extreme</p>
+<p class="poetry">Their hunger. And, indeed, each has a voice</p>
+<p class="poetry">To accept the tyrant of his party’s choice.</p>
+<p class="poetry">A citizen who would not vote,</p>
+<p class="poetry">And, therefore, was detested,</p>
+<p class="poetry">Was one day with a tarry coat</p>
+<p class="poetry">(With feathers backed and breasted)</p>
+<p class="poetry">By patriots invested.</p>
+<p class="poetry">“It is your duty,” cried the crowd,</p>
+<p class="poetry">“Your ballot true to cast</p>
+<p class="poetry">For the man o’ your choice.” He humbly bowed,</p>
+<p class="poetry">And explained his wicked past:</p>
+<p class="poetry">“That’s what I very gladly would have done, Dear patriots, but he has never run.”</p>
+<p class="citeauth">Apperton Duke</p>
+</div>
+
+<p class="entry"><span class="def">manes</span>, <span class="pos">n.</span> The
+immortal parts of dead Greeks and Romans. They were in a state of dull
+discomfort until the bodies from which they had exhaled were buried and burned;
+and they seem not to have been particularly happy afterward.</p>
+
+<p class="entry"><span class="def">Manicheism</span>, <span class="pos">n.</span> The
+ancient Persian doctrine of an incessant warfare between Good and Evil. When
+Good gave up the fight the Persians joined the victorious Opposition.</p>
+
+<p class="entry"><span class="def">Manna</span>, <span class="pos">n.</span> A food
+miraculously given to the Israelites in the wilderness. When it was no longer
+supplied to them they settled down and tilled the soil, fertilizing it, as a
+rule, with the bodies of the original occupants.</p>
+
+<p class="entry"><span class="def">marriage</span>, <span class="pos">n.</span> The
+state or condition of a community consisting of a master, a mistress and two
+slaves, making in all, two.</p>
+
+<p class="entry"><span class="def">martyr</span>, <span class="pos">n.</span> One who
+moves along the line of least reluctance to a desired death.</p>
+
+<p class="entry"><span class="def">material</span>, <span class="pos">adj.</span> Having
+an actual existence, as distinguished from an imaginary one. Important.</p>
+
+<div class="poem">
+<p class="poetry">Material things I know, or fell, or see;</p>
+<p class="poetry">All else is immaterial to me.</p>
+<p class="citeauth">Jamrach Holobom</p>
+</div>
+
+<p class="entry"><span class="def">mausoleum</span>, <span class="pos">n.</span> The
+final and funniest folly of the rich.</p>
+
+<p class="entry"><span class="def">mayonnaise</span>, <span class="pos">n.</span> One
+of the sauces which serve the French in place of a state religion.</p>
+
+<p class="entry"><span class="def">me,</span> <span class="pos">pro.</span> The
+objectionable case of I. The personal pronoun in English has three cases, the
+dominative, the objectionable and the oppressive. Each is all three.</p>
+
+<p class="entry"><span class="def">meander</span>, <span class="pos">n.</span> To
+proceed sinuously and aimlessly. The word is the ancient name of a river about
+one hundred and fifty miles south of Troy, which turned and twisted in the
+effort to get out of hearing when the Greeks and Trojans boasted of their prowess.</p>
+
+<p class="entry"><span class="def">medal</span>, <span class="pos">n.</span> A small
+metal disk given as a reward for virtues, attainments or services more or less
+authentic.</p>
+
+<p class="indentpara">It is related of Bismark, who had been awarded a medal for gallantly rescuing a drowning person,
+that, being asked the meaning of the medal, he replied: “I save lives
+sometimes.” And sometimes he didn’t.</p>
+
+<p class="entry"><span class="def">medicine</span>, <span class="pos">n.</span> A stone
+flung down the Bowery to kill a dog in Broadway.</p>
+
+<p class="entry"><span class="def">meekness</span>, <span class="pos">n.</span> Uncommon
+patience in planning a revenge that is worth while.</p>
+
+<div class="poem">
+<p class="poetry">M is for Moses,</p>
+<p class="poetry">Who slew the Egyptian.</p>
+<p class="poetry">As sweet as a rose is</p>
+<p class="poetry">The meekness of Moses.</p>
+<p class="poetry">No monument shows his</p>
+<p class="poetry">Post-mortem inscription,</p>
+<p class="poetry">But M is for Moses</p>
+<p class="poetry">Who slew the Egyptian.</p>
+<p class="citeauth"><i>The Biographical Alphabet</i></p>
+</div>
+
+<p class="entry"><span class="def">meerschaum</span>, <span class="pos">n.</span> (Literally,
+seafoam, and by many erroneously supposed to be made of it.) A fine white clay,
+which for convenience in coloring it brown is made into tobacco pipes and smoked
+by the workmen engaged in that industry. The purpose of coloring it has not
+been disclosed by the manufacturers.</p>
+
+<div class="poem">
+<p class="poetry">There was a youth (you’ve heard before,</p>
+<p class="poetry">This woeful tale, may be),</p>
+<p class="poetry">Who bought a meerschaum pipe and swore</p>
+<p class="poetry">That color it would he!</p>
+<p class="poetry">He shut himself from the world away,</p>
+<p class="poetry">Nor any soul he saw.</p>
+<p class="poetry">He smoke by night, he smoked by day,</p>
+<p class="poetry">As hard as he could draw.</p>
+<p class="poetry">His dog died moaning in the wrath</p>
+<p class="poetry">Of winds that blew aloof;</p>
+<p class="poetry">The weeds were in the gravel path,</p>
+<p class="poetry">The owl was on the roof.</p>
+<p class="poetry">“He’s gone afar, he’ll come no more,”</p>
+<p class="poetry">The neighbors sadly say.</p>
+<p class="poetry">And so they batter in the door</p>
+<p class="poetry">To take his goods away.</p>
+<p class="poetry">Dead, pipe in mouth, the youngster lay,</p>
+<p class="poetry">Nut-brown in face and limb.</p>
+<p class="poetry">“That pipe’s a lovely white,” they say,</p>
+<p class="poetry">“But it has colored him!”</p>
+<p class="poetry">The moral there’s small need to sing—</p>
+<p class="poetry">‘Tis plain as day to you:</p>
+<p class="poetry">Don’t play your game on any thing</p>
+<p class="poetry">That is a gamester too.</p>
+<p class="citeauth">Martin Bulstrode</p>
+</div>
+
+<p class="entry"><span class="def">mendacious</span>, <span class="pos">adj.</span> Addicted to rhetoric.</p>
+
+<p class="entry"><span class="def">merchant</span>, <span class="pos">n.</span> One
+engaged in a commercial pursuit. A commercial pursuit is one in which the thing
+pursued is a dollar.</p>
+
+<p class="entry"><span class="def">mercy</span>, <span class="pos">n.</span> An
+attribute beloved of detected offenders.</p>
+
+<p class="entry"><span class="def">mesmerism</span>, <span class="pos">n.</span> Hypnotism
+before it wore good clothes, kept a carriage and asked Incredulity to dinner.</p>
+
+<p class="entry"><span class="def">metropolis</span>, <span class="pos">n.</span> A
+stronghold of provincialism.</p>
+
+<p class="entry"><span class="def">millennium</span>, <span class="pos">n.</span> The
+period of a thousand years when the lid is to be screwed down, with all reformers on the under side.</p>
+
+<p class="entry"><span class="def">mind</span>, <span class="pos">n.</span> A
+mysterious form of matter secreted by the brain. Its chief activity consists in
+the endeavor to ascertain its own nature, the futility of the attempt being due
+to the fact that it has nothing but itself to know itself with. From the Latin <i>mens</i>, a fact unknown to that honest
+shoe-seller, who, observing that his learned competitor over the way had
+displayed the motto “<i>Mens conscia recti</i>,” emblazoned his own front with the
+words “Men’s, women’s and children’s conscia recti.”</p>
+
+<p class="entry"><span class="def">mine</span>, <span class="pos">adj.</span> Belonging
+to me if I can hold or seize it.</p>
+
+<p class="entry"><span class="def">minister</span>, <span class="pos">n.</span> An
+agent of a higher power with a lower responsibility. In diplomacy and officer
+sent into a foreign country as the visible embodiment of his sovereign’s
+hostility. His principal qualification is a degree of plausible inveracity next
+below that of an ambassador.</p>
+
+<p class="entry"><span class="def">minor</span>, <span class="pos">adj.</span> Less
+objectionable.</p>
+
+<p class="entry"><span class="def">minstrel</span>, <span class="pos">adj.</span> Formerly
+a poet, singer or musician; now a nigger with a color less than skin deep and a
+humor more than flesh and blood can bear.</p>
+
+<p class="entry"><span class="def">miracle</span>, <span class="pos">n.</span> An act
+or event out of the order of nature and unaccountable, as beating a normal hand
+of four kings and an ace with four aces and a king.</p>
+
+<p class="entry"><span class="def">miscreant</span>, <span class="pos">n.</span> A
+person of the highest degree of unworth. Etymologically, the word means
+unbeliever, and its present signification may be regarded as theology’s noblest
+contribution to the development of our language.</p>
+
+<p class="entry"><span class="def">misdemeanor</span>, <span class="pos">n.</span> An
+infraction of the law having less dignity than a felony and constituting no
+claim to admittance into the best criminal society.</p>
+
+<div class="poem">
+<p class="poetry">By misdemeanors he essays to climb</p>
+<p class="poetry">Into the aristocracy of crime.</p>
+<p class="poetry">O, woe was him!&#8212;with manner chill and grand “Captains of industry” refused his hand, “Kings of
+finance” denied him recognition And “railway magnates” jeered his low
+condition. He robbed a bank to make himself respected.</p>
+<p class="poetry">They still rebuffed him, for he was detected.</p>
+<p class="citeauth">S. V. Hanipur</p>
+</div>
+
+<p class="entry"><span class="def">misericorde</span>, <span class="pos">n.</span> A
+dagger which in mediaeval warfare was used by the foot soldier to remind an
+unhorsed knight that he was mortal.</p>
+
+<p class="entry"><span class="def">misfortune</span>, <span class="pos">n.</span> The
+kind of fortune that never misses.</p>
+
+<p class="entry"><span class="def">miss</span>, <span class="pos">n.</span> The title
+with which we brand unmarried women to indicate that they are in the market. Miss,
+Missis (Mrs.) and Mister (Mr.) are the three most distinctly disagreeable words
+in the language, in sound and sense. Two are corruptions of Mistress, the other
+of Master. In the general abolition of social titles in this our country they
+miraculously escaped to plague us. If we must have them let us be consistent
+and give one to the unmarried man. I venture to suggest Mush, abbreviated to
+Mh.</p>
+
+<p class="entry"><span class="def">molecule</span>, <span class="pos">n.</span> The
+ultimate, indivisible unit of matter. It is distinguished from the corpuscle,
+also the ultimate, indivisible unit of matter, by a closer resemblance to the
+atom, also the ultimate, indivisible unit of matter. Three great scientific
+theories of the structure of the universe are the molecular, the corpuscular
+and the atomic. A fourth affirms, with Haeckel, the condensation of
+precipitation of matter from ether—whose existence is proved by the
+condensation of precipitation. The present trend of scientific thought is
+toward the theory of ions. The ion differs from the molecule, the corpuscle and
+the atom in that it is an ion. A fifth theory is held by idiots, but it is
+doubtful if they know any more about the matter than the others.</p>
+
+<p class="entry"><span class="def">monad</span>, <span class="pos">n.</span> The
+ultimate, indivisible unit of matter. (See <i>Molecule</i>.)
+According to Leibnitz, as nearly as he seems willing to be understood, the
+monad has body without bulk, and mind without manifestation—Leibnitz knows him
+by the innate power of considering. He has founded upon him a theory of the
+universe, which the creature bears without resentment, for the monad is a
+gentlmean. Small as he is, the monad contains all the powers and possibilities
+needful to his evolution into a German philosopher of the first class&#8212;
+altogether a very capable little fellow. He is not to be confounded with the
+microbe, or bacillus; by its inability to discern him, a good microscope shows
+him to be of an entirely distinct species.</p>
+
+<p class="entry"><span class="def">monarch</span>, <span class="pos">n.</span> A
+person engaged in reigning. Formerly the monarch ruled, as the derivation of
+the word attests, and as many subjects have had occasion to learn. In Russia
+and the Orient the monarch has still a considerable influence in public affairs
+and in the disposition of the human head, but in western Europe political
+administration is mostly entrusted to his ministers, he being somewhat
+preoccupied with reflections relating to the status of his own head.</p>
+
+<p class="entry"><span class="def">monarchical government</span>, <span class="pos">n.</span> Government.</p>
+
+<p class="entry"><span class="def">Monday</span>, <span class="pos">n.</span> In
+Christian countries, the day after the baseball game.</p>
+
+<p class="entry"><span class="def">money</span>, <span class="pos">n.</span> A
+blessing that is of no advantage to us excepting when we part with it. An
+evidence of culture and a passport to polite society. Supportable property.</p>
+
+<p class="entry"><span class="def">monkey</span>, <span class="pos">n.</span> An
+arboreal animal which makes itself at home in genealogical trees.</p>
+
+<p class="entry"><span class="def">monosyllabic</span>, <span class="pos">adj.</span>
+Composed of words of one syllable, for literary babes who never tire of
+testifying their delight in the vapid compound by appropriate googoogling. The
+words are commonly Saxon—that is to say, words of a barbarous people destitute
+of ideas and incapable of any but the most elementary sentiments and emotions.</p>
+
+<div class="poem">
+<p class="poetry">The man who writes in Saxon</p>
+<p class="poetry">Is the man to use an ax on</p>
+<p class="citeauth">Judibras</p>
+</div>
+
+<p class="entry"><span class="def">monsignor</span>, <span class="pos">n.</span> A
+high ecclesiastical title, of which the Founder of our religion overlooked the advantages.</p>
+
+<p class="entry"><span class="def">monument</span>, <span class="pos">n.</span> A
+structure intended to commemorate something which either needs no commemoration
+or cannot be commemorated.</p>
+
+<div class="poem">
+<p class="poetry">The bones of Agammemnon are a show,</p>
+<p class="poetry">And ruined is his royal monument,</p>
+<p class="poetry">but Agammemnon’s
+fame suffers no diminution in consequence. The monument custom has its <i>reductiones ad absurdum</i> in monuments “to
+the unknown dead”—that is to say, monuments to perpetuate the memory of those
+who have left no memory.</p>
+</div>
+
+<p class="entry"><span class="def">moral</span>, <span class="pos">adj.</span> Conforming
+to a local and mutable standard of right. </p>
+
+<div class="poem">
+<p class="poetry">Having the quality of general expediency.</p>
+<p class="poetry">It is sayd there
+be a raunge of mountaynes in the Easte, on one syde of the which certayn
+conducts are immorall, yet on the other syde they are holden in good esteeme;
+wherebye the mountayneer is much conveenyenced, for it is given to him to goe
+downe eyther way and act as it shall suite his moode, withouten offence.</p>
+<p class="citeauth"><i>Gooke’s Meditations</i></p>
+</div>
+
+<p class="entry"><span class="def">more</span>, <span class="pos">adj.</span> The
+comparative degree of too much.</p>
+
+<p class="entry"><span class="def">mouse</span>, <span class="pos">n.</span> An
+animal which strews its path with fainting women. As in Rome Christians were
+thrown to the lions, so centuries earlier in Otumwee, the most ancient and
+famous city of the world, female heretics were thrown to the mice. Jakak-Zotp,
+the historian, the only Otumwump whose writings have descended to us, says that
+these martyrs met their death with little dignity and much exertion. He even
+attempts to exculpate the mice (such is the malice of bigotry) by declaring
+that the unfortunate women perished, some from exhaustion, some of broken necks
+from falling over their own feet, and some from lack of restoratives. The mice,
+he avers, enjoyed the pleasures of the chase with composure. But if “Roman
+history is nine-tenths lying,” we can hardly expect a smaller proportion of
+that rhetorical figure in the annals of a people capable of so incredible
+cruelty to a lovely women; for a hard heart has a false tongue.</p>
+
+<p class="entry"><span class="def">mousquetaire</span>, <span class="pos">n.</span> A
+long glove covering a part of the arm. Worn in New Jersey. But “mousquetaire”
+is a might poor way to spell muskeeter.</p>
+
+<p class="entry"><span class="def">mouth</span>, <span class="pos">n.</span> In man,
+the gateway to the soul; in woman, the outlet of the heart.</p>
+
+<p class="entry"><span class="def">mugwump</span>, <span class="pos">n.</span> In
+politics one afflicted with self-respect and addicted to the vice of
+independence. A term of contempt.</p>
+
+<p class="entry"><span class="def">mulatto</span>, <span class="pos">n.</span> A
+child of two races, ashamed of both.</p>
+
+<p class="entry"><span class="def">multitude</span>, <span class="pos">n.</span> A
+crowd; the source of political wisdom and virtue. In a republic, the object of
+the statesman’s adoration. “In a multitude of consellors there is wisdom,”
+saith the proverb. If many men of equal individual wisdom are wiser than any
+one of them, it must be that they acquire the excess of wisdom by the mere act
+of getting together. Whence comes it? Obviously from nowhere—as well say that a
+range of mountains is higher than the single mountains composing it. A
+multitude is as wise as its wisest member if it obey him; if not, it is no
+wiser than its most foolish.</p>
+
+<p class="entry"><span class="def">mummy</span>, <span class="pos">n.</span> An
+ancient Egyptian, formerly in universal use among modern civilized nations as
+medicine, and now engaged in supplying art with an excellent pigment. He is
+handy, too, in museums in gratifying the vulgar curiosity that serves to
+distinguish man from the lower animals.</p>
+
+<div class="poem">
+<p class="poetry">By means of the
+Mummy, mankind, it is said, Attests to the gods its respect for the dead. We
+plunder his tomb, be he sinner or saint, Distil him for physic and grind him
+for paint, Exhibit for money his poor, shrunken frame, And with levity flock to
+the scene of the shame.</p>
+<p class="poetry">O, tell me, ye gods, for the use of my rhyme:</p>
+<p class="poetry">For respecting the dead what’s the limit of time?</p>
+<p class="citeauth">Scopas Brune</p>
+</div>
+
+<p class="entry"><span class="def">mustang</span>, <span class="pos">n.</span> An
+indocile horse of the western plains. In English society, the American wife of
+an English nobleman.</p>
+
+<p class="entry"><span class="def">myrmidon</span>, <span class="pos">n.</span> A
+follower of Achilles—particularly when he didn’t lead.</p>
+
+<p class="entry"><span class="def">mythology</span>, <span class="pos">n.</span> The
+body of a primitive people’s beliefs concerning its origin, early history,
+heroes, deities and so forth, as distinguished from the true accounts which it
+invents later.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/M.html.i
@@ -1,0 +1,46 @@
+21 pages
+size 400 552
+length 31261
+396 2 10 body html
+0
+1279 2 33 body html
+90
+2468 2 50 body html
+324
+2468 2 50 body html
+864
+2468 2 50 body html
+1404
+5710 2 110 body html
+90
+7282 2 137 body html
+226
+8950 2 162 body html
+324
+11206 2 207 body html
+0
+11585 2 213 body html
+451
+13420 2 247 body html
+39
+15429 2 287 body html
+34
+16387 2 309 body html
+73
+16760 2 315 body html
+523
+18848 2 358 body html
+0
+20940 2 394 body html
+39
+22560 2 424 body html
+56
+24843 2 458 body html
+22
+26303 2 487 body html
+108
+27455 2 512 body html
+226
+30146 2 556 body html
+87
+male 7
--- /dev/null
+++ b/lib/ebooks/devils/N.html
@@ -1,0 +1,130 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: N</title>
+</head>
+<body lang="en-US">
+
+
+<h1>N</h1>
+
+<p class="entry"><span class="def">nectar</span>, <span class="pos">n.</span> A drink
+served at banquets of the Olympian deities. The secret of its preparation is
+lost, but the modern Kentuckians believe that they come pretty near to a
+knowledge of its chief ingredient.</p>
+
+<div class="poem">
+<p class="poetry">Juno drank a cup of nectar,</p>
+<p class="poetry">But the draught did not affect her.</p>
+<p class="poetry">Juno drank a cup of rye—</p>
+<p class="poetry">Then she bad herself good-bye.</p>
+<p class="citeauth">J. G.</p>
+</div>
+
+<p class="entry"><span class="def">negro</span>, <span class="pos">n.</span> The <i>piece de resistance</i> in the American
+political problem. Representing him by the letter n, the Republicans begin to
+build their equation thus: “Let n = the white man.” This, however, appears to
+give an unsatisfactory solution.</p>
+
+<p class="entry"><span class="def">neighbor</span>, <span class="pos">n.</span> One
+whom we are commanded to love as ourselves, and who does all he knows how to
+make us disobedient.</p>
+
+<p class="entry"><span class="def">nepotism</span>, <span class="pos">n.</span> Appointing
+your grandmother to office for the good of the party.</p>
+
+<p class="entry"><span class="def">Newtonian</span>, <span class="pos">adj.</span> Pertaining
+to a philosophy of the universe invented by Newton, who discovered that an
+apple will fall to the ground, but was unable to say why. His successors and
+disciples have advanced so far as to be able to say when.</p>
+
+<p class="entry"><span class="def">nihilist</span>, <span class="pos">n.</span> A
+Russian who denies the existence of anything but Tolstoi. The leader of the
+school is Tolstoi.</p>
+
+<p class="entry"><span class="def">Nirvana</span>, <span class="pos">n.</span> In the
+Buddhist religion, a state of pleasurable annihilation awarded to the wise,
+particularly to those wise enough to understand it.</p>
+
+<p class="entry"><span class="def">nobleman</span>, <span class="pos">n.</span> Nature’s
+provision for wealthy American minds ambitious to incur social distinction and
+suffer high life.</p>
+
+<p class="entry"><span class="def">noise</span>, <span class="pos">n.</span> A stench
+in the ear. Undomesticated music. The chief product and authenticating sign of
+civilization.</p>
+
+<p class="entry"><span class="def">nominate</span>, <span class="pos">v.</span> To
+designate for the heaviest political assessment. To put forward a suitable
+person to incur the mudgobbling and deadcatting of the opposition.</p>
+
+<p class="entry"><span class="def">nominee</span>, <span class="pos">n.</span> A
+modest gentleman shrinking from the distinction of private life and diligently
+seeking the honorable obscurity of public office.</p>
+
+<p class="entry"><span class="def">non-combatant</span>, <span class="pos">n.</span> A
+dead Quaker.</p>
+
+<p class="entry"><span class="def">nonsense</span>, <span class="pos">n.</span> The
+objections that are urged against this excellent dictionary.</p>
+
+<p class="entry"><span class="def">nose</span>, <span class="pos">n.</span> The
+extreme outpost of the face. From the circumstance that great conquerors have
+great noses, Getius, whose writings antedate the age of humor, calls the nose
+the organ of quell. It has been observed that one’s nose is never so happy as
+when thrust into the affairs of others, from which some physiologists have
+drawn the inference that the nose is devoid of the sense of smell.</p>
+
+<div class="poem">
+<p class="poetry">There’s a man with a Nose,</p>
+<p class="poetry">And wherever he goes</p>
+<p class="poetry">The people run from him and shout:</p>
+<p class="poetry">“No cotton have we</p>
+<p class="poetry">For our ears if so be</p>
+<p class="poetry">He blow that interminous snout!”</p>
+<p class="poetry">So the lawyers applied</p>
+<p class="poetry">For injunction. “Denied,”</p>
+<p class="poetry">Said the Judge: “the defendant prefixion,</p>
+<p class="poetry">Whate’er it portend,</p>
+<p class="poetry">Appears to transcend</p>
+<p class="poetry">The bounds of this court’s jurisdiction.”</p>
+<p class="citeauth">Arpad Singiny</p>
+</div>
+
+<p class="entry"><span class="def">notoriety</span>, <span class="pos">n.</span> The
+fame of one’s competitor for public honors. The kind of renown most accessible
+and acceptable to mediocrity. A Jacob’s-ladder leading to the vaudeville stage,
+with angels ascending and descending.</p>
+
+<p class="entry"><span class="def">noumenon</span>, <span class="pos">n.</span> That
+which exists, as distinguished from that which merely seems to exist, the
+latter being a phenomenon. The noumenon is a bit difficult to locate; it can be
+apprehended only be a process of reasoning—which is a phenomenon. Nevertheless,
+the discovery and exposition of noumena offer a rich field for what Lewes calls
+“the endless variety and excitement of philosophic thought.” Hurrah (therefore)
+for the noumenon!</p>
+
+<p class="entry"><span class="def">novel</span>, <span class="pos">n.</span> A short
+story padded. A species of composition bearing the same relation to literature
+that the panorama bears to art. As it is too long to be read at a sitting the
+impressions made by its successive parts are successively effaced, as in the
+panorama. Unity, totality of effect, is impossible; for besides the few pages
+last read all that is carried in mind is the mere plot of what has gone before.
+To the romance the novel is what photography is to painting. Its distinguishing
+principle, probability, corresponds to the literal actuality of the photograph
+and puts it distinctly into the category of reporting; whereas the free wing of
+the romancer enables him to mount to such altitudes of imagination as he may be
+fitted to attain; and the first three essentials of the literary art are
+imagination, imagination and imagination. The art of writing novels, such as it
+was, is long dead everywhere except in Russia, where it is new. Peace to its
+ashes—some of which have a large sale.</p>
+
+<p class="entry"><span class="def">November</span>, <span class="pos">n.</span> The
+eleventh twelfth of a weariness.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/N.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 552
+length 6554
+396 2 10 body html
+0
+1613 2 40 body html
+22
+3863 2 82 body html
+19
+4833 2 103 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/O.html
@@ -1,0 +1,304 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: O</title>
+</head>
+<body lang="en-US">
+
+
+<h1>O</h1>
+
+<p class="entry"><span class="def">oath</span>, <span class="pos">n.</span> In law, a
+solemn appeal to the Deity, made binding upon the conscience by a penalty for
+perjury.</p>
+
+<p class="entry"><span class="def">oblivion</span>, <span class="pos">n.</span> The
+state or condition in which the wicked cease from struggling and the dreary are
+at rest. Fame’s eternal dumping ground. Cold storage for high hopes. A place
+where ambitious authors meet their works without pride and their betters
+without envy. A dormitory without an alarm clock.</p>
+
+<p class="entry"><span class="def">observatory</span>, <span class="pos">n.</span> A
+place where astronomers conjecture away the guesses of their predecessors.</p>
+
+<p class="entry"><span class="def">obsessed,</span> <span class="pos">p.p.</span> Vexed
+by an evil spirit, like the Gadarene swine and other critics. Obsession was once
+more common than it is now. Arasthus tells of a peasant who was occupied by a
+different devil for every day in the week, and on Sundays by two. They were
+frequently seen, always walking in his shadow, when he had one, but were
+finally driven away by the village notary, a holy man; but they took the
+peasant with them, for he vanished utterly. A devil thrown out of a woman by
+the Archbishop of Rheims ran through the trees, pursued by a hundred persons,
+until the open country was reached, where by a leap higher than a church spire
+he escaped into a bird. A chaplain in Cromwell’s army exorcised a soldier’s
+obsessing devil by throwing the soldier into the water, when the devil came to
+the surface. The soldier, unfortunately, did not.</p>
+
+<p class="entry"><span class="def">obsolete</span>, <span class="pos">adj.</span> No longer
+used by the timid. Said chiefly of words. A word which some lexicographer has
+marked obsolete is ever thereafter an object of dread and loathing to the fool
+writer, but if it is a good word and has no exact modern equivalent equally
+good, it is good enough for the good writer. Indeed, a writer’s attitude toward
+“obsolete” words is as true a measure of his literary ability as anything
+except the character of his work. A dictionary of obsolete and obsolescent
+words would not only be singularly rich in strong and sweet parts of speech; it
+would add large possessions to the vocabulary of every competent writer who
+might not happen to be a competent reader.</p>
+
+<p class="entry"><span class="def">obstinate</span>, <span class="pos">adj.</span> Inaccessible
+to the truth as it is manifest in the splendor and stress of our advocacy.</p>
+
+<p>The popular type and exponent of obstinacy is the mule, a most intelligent animal.</p>
+
+<p class="entry"><span class="def">occasional</span>, <span class="pos">adj.</span> Afflicting us with
+greater or less frequency. That, however, is not the sense in which the word is used in the phrase
+“occasional verses,” which are verses written for an “occasion,” such as an anniversary, a celebration or
+other event. True, they afflict us a little worse than other sorts of verse, but their name has no reference to
+irregular recurrence.</p>
+
+<p class="entry"><span class="def">occident</span>, <span class="pos">n.</span> The
+part of the world lying west (or east) of the Orient. It is largely inhabited
+by Christians, a powerful subtribe of the Hypocrites, whose principal
+industries are murder and cheating, which they are pleased to call “war” and
+“commerce.” These, also, are the principal industries of the Orient.</p>
+
+<p class="entry"><span class="def">ocean</span>, <span class="pos">n.</span> A body
+of water occupying about two-thirds of a world made for man—who has no gills.</p>
+
+<p class="entry"><span class="def">offensive</span>, <span class="pos">adj.</span> Generating
+disagreeable emotions or sensations, as the advance of an army against its enemy.</p>
+
+<p>“Were the enemy’s tactics offensive?” the king asked. “I should say so!” replied the unsuccessful
+general. “The blackguard wouldn’t come out of his works!”</p>
+
+<p class="entry"><span class="def">old</span>, <span class="pos">adj.</span> In that
+stage of usefulness which is not inconsistent with general inefficiency, as an <i>old man</i>. Discredited by lapse of time and
+offensive to the popular taste, as an <i>old</i>
+book.</p>
+
+<div class="poem">
+<p class="poetry">“Old books? The devil take them!” Goby said.</p>
+<p class="poetry">“Fresh every day must be my books and bread.”</p>
+<p class="poetry">Nature herself approves the Goby rule</p>
+<p class="poetry">And gives us every moment a fresh fool.</p>
+<p class="citeauth">Harley Shum</p>
+</div>
+
+<p class="entry"><span class="def">oleginous</span>, <span class="pos">adj.</span> Oily,
+smooth, sleek.</p>
+
+<p>Disraeli once described the manner of Bishop Wilberforce as “unctuous, oleaginous,
+saponaceous.” And the good prelate was ever afterward known as Soapy Sam. For
+every man there is something in the vocabulary that would stick to him like a
+second skin. His enemies have only to find it.</p>
+
+<p class="entry"><span class="def">Olympian</span>, <span class="pos">adj.</span> Relating
+to a mountain in Thessaly, once inhabited by gods, now a repository of
+yellowing newspapers, beer bottles and mutilated sardine cans, attesting the
+presence of the tourist and his appetite.</p>
+
+<div class="poem">
+<p class="poetry">His name the smirking tourist scrawls</p>
+<p class="poetry">Upon Minerva’s temple walls,</p>
+<p class="poetry">Where thundered once Olympian Zeus,</p>
+<p class="poetry">And marks his appetite’s abuse.</p>
+<p class="citeauth">Averil Joop</p>
+</div>
+
+<p class="entry"><span class="def">omen</span>, <span class="pos">n.</span> A sign
+that something will happen if nothing happens.</p>
+
+<p class="entry"><span class="def">once</span>, <span class="pos">adv.</span> Enough.</p>
+
+<p class="entry"><span class="def">opera</span>, <span class="pos">n.</span> A play
+representing life in another world, whose inhabitants have no speech but song,
+no motions but gestures and no postures but attitudes. All acting is
+simulation, and the word <i>simulation</i> is from <i>simia</i>, an ape; but in
+opera the actor takes for his model <i>Simia audibilis</i> (or <i>Pithecanthropos
+stentor</i>)&#8212;the ape that howls.</p>
+
+<div class="poem">
+<p class="poetry">The actor apes a man—at least in shape;</p>
+<p class="poetry">The opera performer apes and ape.</p>
+</div>
+
+<p class="entry"><span class="def">Opiate</span>, <span class="pos">n.</span> An
+unlocked door in the prison of Identity. It leads into the jail yard.</p>
+
+<p class="entry"><span class="def">opportunity</span>, <span class="pos">n.</span> A
+favorable occasion for grasping a disappointment.</p>
+
+<p class="entry"><span class="def">oppose</span>, <span class="pos">v.</span> To
+assist with obstructions and objections.</p>
+
+<div class="poem">
+<p class="poetry">How lonely he who thinks to vex</p>
+<p class="poetry">With bandinage the Solemn Sex!</p>
+<p class="poetry">Of levity, Mere Man, beware;</p>
+<p class="poetry">None but the Grave deserve the Unfair.</p>
+<p class="citeauth">Percy P. Orminder</p>
+</div>
+
+<p class="entry"><span class="def">opposition</span>, <span class="pos">n.</span> In
+politics the party that prevents the Government from running amuck by hamstringing it.</p>
+
+<p>The King of Ghargaroo, who had been abroad to study the science of government, appointed
+one hundred of his fattest subjects as members of a parliament to make laws for
+the collection of revenue. Forty of these he named the Party of Opposition and
+had his Prime Minister carefully instruct them in their duty of opposing every
+royal measure. Nevertheless, the first one that was submitted passed unanimously.
+Greatly displeased, the King vetoed it, informing the Opposition that if they
+did that again they would pay for their obstinacy with their heads. The entire
+forty promptly disemboweled themselves.</p>
+
+<p>“What shall we do now?” the King asked. “Liberal institutions cannot be maintained without a
+party of Opposition.”</p>
+
+<p>“Splendor of the universe,” replied the Prime Minister, “it is true these dogs of darkness have
+no longer their credentials, but all is not lost. Leave the matter to this worm of the dust.”</p>
+
+<p>So the Minister had the bodies of his Majesty’s Opposition embalmed and stuffed with straw, put
+back into the seats of power and nailed there. Forty votes were recorded
+against every bill and the nation prospered. But one day a bill imposing a tax
+on warts was defeated—the members of the Government party had not been nailed
+to their seats! This so enraged the King that the Prime Minister was put to
+death, the parliament was dissolved with a battery of artillery, and government
+of the people, by the people, for the people perished from Ghargaroo.</p>
+
+<p class="entry"><span class="def">optimism</span>, <span class="pos">n.</span> The
+doctrine, or belief, that everything is beautiful, including what is ugly,
+everything good, especially the bad, and everything right that is wrong. It is
+held with greatest tenacity by those most accustomed to the mischance of
+falling into adversity, and is most acceptably expounded with the grin that
+apes a smile. Being a blind faith, it is inaccessible to the light of
+disproof—an intellectual disorder, yielding to no treatment but death. It is
+hereditary, but fortunately not contagious.</p>
+
+<p class="entry"><span class="def">optimist</span>, <span class="pos">n.</span> A proponent of the
+doctrine that black is white.</p>
+
+<p>A pessimist applied to God for relief.</p>
+<p>“Ah, you wish me to restore your hope and cheerfulness,” said God.</p>
+<p>“No,” replied the petitioner, “I wish you to create something that would justify them.”</p>
+<p>“The world is all created,” said God, “but you have overlooked something—the mortality of the optimist.”</p>
+
+<p class="entry"><span class="def">oratory</span>, <span class="pos">n.</span> A
+conspiracy between speech and action to cheat the understanding. A tyranny
+tempered by stenography.</p>
+
+<p class="entry"><span class="def">orphan</span>, <span class="pos">n.</span> A
+living person whom death has deprived of the power of filial ingratitude—a
+privation appealing with a particular eloquence to all that is sympathetic in
+human nature. When young the orphan is commonly sent to an asylum, where by
+careful cultivation of its rudimentary sense of locality it is taught to know
+its place. It is then instructed in the arts of dependence and servitude and
+eventually turned loose to prey upon the world as a bootblack or scullery maid.</p>
+
+<p class="entry"><span class="def">orthodox</span>, <span class="pos">n.</span> An ox
+wearing the popular religious joke.</p>
+
+<p class="entry"><span class="def">orthography</span>, <span class="pos">n.</span> The
+science of spelling by the eye instead of the ear. Advocated with more heat
+than light by the outmates of every asylum for the insane. They have had to
+concede a few things since the time of Chaucer, but are none the less hot in
+defence of those to be conceded hereafter.</p>
+
+<div class="poem">
+<p class="poetry">A spelling reformer indicted</p>
+<p class="poetry">For fudge was before the court cicted.</p>
+<p class="poetry">The judge said: “Enough—</p>
+<p class="poetry">His candle we’ll snough,</p>
+<p class="poetry">And his sepulchre shall not be whicted.”</p>
+</div>
+
+<p class="entry"><span class="def">ostrich</span>, <span class="pos">n.</span> A large
+bird to which (for its sins, doubtless) nature has denied that hinder toe in
+which so many pious naturalists have seen a conspicuous evidence of design. The
+absence of a good working pair of wings is no defect, for, as has been
+ingeniously pointed out, the ostrich does not fly.</p>
+
+<p class="entry"><span class="def">otherwise</span>, <span class="pos">adv.</span> No better.</p>
+
+<p class="entry"><span class="def">outcome</span>, <span class="pos">n.</span> A
+particular type of disappointment. By the kind of intelligence that sees in an
+exception a proof of the rule the wisdom of an act is judged by the outcome,
+the result. This is immortal nonsense; the wisdom of an act is to be juded by
+the light that the doer had when he performed it.</p>
+
+<p class="entry"><span class="def">outdo</span>, <span class="pos">v.t.</span> To
+make an enemy.</p>
+
+<p class="entry"><span class="def">out-of-doors</span>, <span class="pos">n.</span> That
+part of one’s environment upon which no government has been able to collect
+taxes. Chiefly useful to inspire poets.</p>
+
+<div class="poem">
+<p class="poetry">I climbed to the top of a mountain one day</p>
+<p class="poetry">To see the sun setting in glory,</p>
+<p class="poetry">And I thought, as I looked at his vanishing ray,</p>
+<p class="poetry">Of a perfectly splendid story.</p>
+<p class="poetry">‘Twas about an old man and the ass he bestrode</p>
+<p class="poetry">Till the strength of the beast was o’ertested;</p>
+<p class="poetry">Then the man would carry him miles on the road</p>
+<p class="poetry">Till Neddy was pretty well rested.</p>
+<p class="poetry">The moon rising solemnly over the crest</p>
+<p class="poetry">Of the hills to the east of my station</p>
+<p class="poetry">Displayed her broad disk to the darkening west</p>
+<p class="poetry">Like a visible new creation.</p>
+<p class="poetry">And I thought of a joke (and I laughed till I cried)</p>
+<p class="poetry">Of an idle young woman who tarried</p>
+<p class="poetry">About a church-door for a look at the bride,</p>
+<p class="poetry">Although ‘twas herself that was married.</p>
+<p class="poetry">To poets all Nature is pregnant with grand</p>
+<p class="poetry">Ideas—with thought and emotion.</p>
+<p class="poetry">I pity the dunces who don’t understand</p>
+<p class="poetry">The speech of earth, heaven and ocean.</p>
+<p class="citeauth">Stromboli Smith</p>
+</div>
+
+<p class="entry"><span class="def">ovation</span>, <span class="pos">n.</span> n
+ancient Rome, a definite, formal pageant in honor of one who had been
+disserviceable to the enemies of the nation. A lesser “triumph.” In modern
+English the word is improperly used to signify any loose and spontaneous
+expression of popular homage to the hero of the hour and place.</p>
+
+<div class="poem">
+<p class="poetry">“I had an ovation!” the actor man said,</p>
+<p class="poetry">But I thought it uncommonly queer,</p>
+<p class="poetry">That people and critics by him had been led</p>
+<p class="poetry">By the ear.</p>
+<p class="poetry">The Latin lexicon makes his absurd</p>
+<p class="poetry">Assertion as plain as a peg;</p>
+<p class="poetry">In “ovum” we find the true root of the word.</p>
+<p class="poetry">It means egg.</p>
+<p class="citeauth">Dudley Spink</p>
+</div>
+
+<p class="entry"><span class="def">overeat</span>, <span class="pos">v.</span> To
+dine.</p>
+
+<div class="poem">
+<p class="poetry">Hail, Gastronome, Apostle of Excess, Well skilled to overeat without distress!</p>
+<p class="poetry">Thy great invention, the unfatal feast,</p>
+<p class="poetry">Shows Man’s superiority to Beast.</p>
+<p class="citeauth">John Boop</p>
+</div>
+
+<p class="entry"><span class="def">overwork</span>, <span class="pos">n.</span> A
+dangerous disorder affecting high public functionaries who want to go fishing.</p>
+
+<p class="entry"><span class="def">owe</span>, <span class="pos">v.</span> To have
+(and to hold) a debt. The word formerly signified not indebtedness, but possession;
+it meant “own,” and in the minds of debtors there is still a good deal of
+confusion between assets and liabilities.</p>
+
+<p class="entry"><span class="def">oyster</span>, <span class="pos">n.</span> A
+slimy, gobby shellfish which civilization gives men the hardihood to eat
+without removing its entrails! The shells are sometimes given to the poor.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/O.html.i
@@ -1,0 +1,25 @@
+11 pages
+size 400 552
+length 16292
+396 2 10 body html
+0
+2042 2 41 body html
+39
+4269 2 75 body html
+0
+5743 2 104 body html
+0
+7267 2 138 body html
+0
+8683 2 164 body html
+0
+10316 2 189 body html
+0
+11848 2 218 body html
+56
+13002 2 239 body html
+324
+14705 2 269 body html
+0
+15582 2 291 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/P.html
@@ -1,0 +1,653 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: P</title>
+</head>
+<body lang="en-US">
+
+
+<h1>P</h1>
+
+<p class="entry"><span class="def">pain</span>, <span class="pos">n.</span> An
+uncomfortable frame of mind that may have a physical basis in something that is
+being done to the body, or may be purely mental, caused by the good fortune of
+another.</p>
+
+<p class="entry"><span class="def">painting</span>, <span class="pos">n.</span> The
+art of protecting flat surfaces from the weather and exposing them to the critic.</p>
+
+<p>Formerly, painting and sculpture were combined in the same work: </p>
+
+<p>the ancients painted their statues. The only present alliance between the two arts is that
+the modern painter chisels his patrons.</p>
+
+<p class="entry"><span class="def">palace</span>, <span class="pos">n.</span> A fine
+and costly residence, particularly that of a great official. The residence of a
+high dignitary of the Christian Church is called a palace; that of the Founder
+of his religion was known as a field, or wayside. There is progress.</p>
+
+<p class="entry"><span class="def">palm</span>, <span class="pos">n.</span> A species
+of tree having several varieties, of which the familiar “itching palm” (<i>Palma
+hominis</i>) is most widely distributed and sedulously cultivated. This noble
+vegetable exudes a kind of invisible gum, which may be detected by applying to
+the bark a piece of gold or silver. The metal will adhere with remarkable
+tenacity. The fruit of the itching palm is so bitter and unsatisfying that a
+considerable percentage of it is sometimes given away in what are known as
+“benefactions.”</p>
+
+<p class="entry"><span class="def">palmistry</span>, <span class="pos">n.</span> The
+947<sup>th</sup> method (according to Mimbleshaw’s classification) of obtaining
+money by false pretences. It consists in “reading character” in the wrinkles
+made by closing the hand. The pretence is not altogether false; character can
+really be read very accurately in this way, for the wrinkles in every hand
+submitted plainly spell the word “dupe.” The imposture consists in not reading
+it aloud.</p>
+
+<p class="entry"><span class="def">pandemonium </span>, <span class="pos">n.</span> Literally,
+the Place of All the Demons. Most of them have escaped into politics and
+finance, and the place is now used as a lecture hall by the Audible Reformer. When
+disturbed by his voice the ancient echoes clamor appropriate responses most
+gratifying to his pride of distinction.</p>
+
+<p class="entry"><span class="def">pantaloons</span>, <span class="pos">n.</span> A
+nether habiliment of the adult civilized male. The garment is tubular and
+unprovided with hinges at the points of flexion. Supposed to have been invented
+by a humorist. Called “trousers” by the enlightened and “pants” by the
+unworthy.</p>
+
+<p class="entry"><span class="def">pantheism</span>, <span class="pos">n.</span> The
+doctrine that everything is God, in contradistinction to the doctrine that God is everything.</p>
+
+<p class="entry"><span class="def">pantomime</span>, <span class="pos">n.</span> A
+play in which the story is told without violence to the language. The least
+disagreeable form of dramatic action.</p>
+
+<p class="entry"><span class="def">pardon</span>, <span class="pos">v.</span> To
+remit a penalty and restore to the life of crime. To add to the lure of crime
+the temptation of ingratitude.</p>
+
+<p class="entry"><span class="def">passport</span>, <span class="pos">n.</span> A
+document treacherously inflicted upon a citizen going abroad, exposing him as
+an alien and pointing him out for special reprobation and outrage.</p>
+
+<p class="entry"><span class="def">past</span>, <span class="pos">n.</span> That part
+of Eternity with some small fraction of which we have a slight and regrettable
+acquaintance. A moving line called the Present parts it from an imaginary
+period known as the Future. These two grand divisions of Eternity, of which the
+one is continually effacing the other, are entirely unlike. The one is dark
+with sorrow and disappointment, the other bright with prosperity and joy. The
+Past is the region of sobs, the Future is the realm of song. In the one
+crouches Memory, clad in sackcloth and ashes, mumbling penitential prayer; in
+the sunshine of the other Hope flies with a free wing, beckoning to temples of
+success and bowers of ease. Yet the Past is the Future of yesterday, the Future
+is the Past of to-morrow. They are one—the knowledge and the dream.</p>
+
+<p class="entry"><span class="def">pastime</span>, <span class="pos">n.</span> A
+device for promoting dejection. Gentle exercise for intellectual debility.</p>
+
+<p class="entry"><span class="def">patience</span>, <span class="pos">n.</span> A
+minor form of despair, disguised as a virtue.</p>
+
+<p class="entry"><span class="def">patriot</span>, <span class="pos">n.</span> One to
+whom the interests of a part seem superior to those of the whole. The dupe of
+statesmen and the tool of conquerors.</p>
+
+<p class="entry"><span class="def">patriotism</span>, <span class="pos">n.</span> Combustible
+rubbish read to the torch of any one ambitious to illuminate his name.</p>
+
+<p>In Dr. Johnson’s famous dictionary patriotism is defined as the last resort of a scoundrel. With
+all due respect to an enlightened but inferior lexicographer I beg to submit
+that it is the first.</p>
+
+<p class="entry"><span class="def">peace</span>, <span class="pos">n.</span> In
+international affairs, a period of cheating between two periods of fighting.</p>
+
+<div class="poem">
+<p class="poetry">O, what’s the loud uproar assailing</p>
+<p class="poetry">Mine ears without cease?</p>
+<p class="poetry">‘Tis the voice of the hopeful, all-hailing</p>
+<p class="poetry">The horrors of peace.</p>
+<p class="poetry">Ah, Peace Universal; they woo it—</p>
+<p class="poetry">Would marry it, too.</p>
+<p class="poetry">If only they knew how to do it</p>
+<p class="poetry">‘Twere easy to do.</p>
+<p class="poetry">They’re working by night and by day</p>
+<p class="poetry">On their problem, like moles.</p>
+<p class="poetry">Have mercy, O Heaven, I pray,</p>
+<p class="poetry">On their meddlesome souls!</p>
+<p class="citeauth">Ro Amil</p>
+</div>
+
+<p class="entry"><span class="def">pedestrian</span>, <span class="pos">n.</span> The
+variable (an audible) part of the roadway for an automobile.</p>
+
+<p class="entry"><span class="def">pedigree</span>, <span class="pos">n.</span> The
+known part of the route from an arboreal ancestor with a swim bladder to an
+urban descendant with a cigarette.</p>
+
+<p class="entry"><span class="def">penitentN</span>, <span class="pos">adj.</span> Undergoing
+or awaiting punishment.</p>
+
+<p class="entry"><span class="def">perfection</span>, <span class="pos">n.</span> An
+imaginary state of quality distinguished from the actual by an element known as
+excellence; an attribute of the critic.</p>
+
+<p class="indentpara">The editor of an English magazine having received a letter pointing out the erroneous nature of
+his views and style, and signed “Perfection,” promptly wrote at the foot of the
+letter: “I don’t agree with you,” and mailed it to Matthew Arnold.</p>
+
+<p class="entry"><span class="def">peripatetic</span>, <span class="pos">adj.</span> Walking
+about. Relating to the philosophy of Aristotle, who, while expounding it, moved
+from place to place in order to avoid his pupil’s objections. A needless
+precaution—they knew no more of the matter than he.</p>
+
+<p class="entry"><span class="def">peroration</span>, <span class="pos">n.</span> The
+explosion of an oratorical rocket. It dazzles, but to an observer having the
+wrong kind of nose its most conspicuous peculiarity is the smell of the several
+kinds of powder used in preparing it.</p>
+
+<p class="entry"><span class="def">perseverance</span>, <span class="pos">n.</span> A
+lowly virtue whereby mediocrity achieves an inglorious success.</p>
+
+<div class="poem">
+<p class="poetry">“Persevere, persevere!” cry the homilists all,<br />
+Themselves, day and night, persevering to bawl.<br />
+“Remember the fable of tortoise and hare—</p>
+<p class="poetry">The one at the goal while the other is—where?”<br />
+Why, back there in Dreamland, renewing his lease<br />
+Of life, all his muscles preserving the peace,<br />
+The goal and the rival forgotten alike,<br />
+And the long fatigue of the needless hike.</p>
+<p class="poetry">His spirit a-squat in the grass and the dew</p>
+<p class="poetry">Of the dogless Land beyond the Stew,</p>
+<p class="poetry">He sleeps, like a saint in a holy place,</p>
+<p class="poetry">A winner of all that is good in a race.</p>
+<p class="citeauth">Sukker Uffro</p>
+</div>
+
+<p class="entry"><span class="def">pessimism</span>, <span class="pos">n.</span> A
+philosophy forced upon the convictions of the observer by the disheartening
+prevalence of the optimist with his scarecrow hope and his unsightly smile.</p>
+
+<p class="entry"><span class="def">philanthropist</span>, <span class="pos">n.</span>
+A rich (and usually bald) old gentleman who has trained himself to grin while
+his conscience is picking his pocket.</p>
+
+<p class="entry"><span class="def">philistine</span>, <span class="pos">n.</span> One
+whose mind is the creature of its environment, following the fashion in
+thought, feeling and sentiment. He is sometimes learned, frequently prosperous,
+commonly clean and always solemn.</p>
+
+<p class="entry"><span class="def">philosophy</span>, <span class="pos">n.</span> A
+route of many roads leading from nowhere to nothing.</p>
+
+<p class="entry"><span class="def">Phoenix</span>, <span class="pos">n.</span> The classical
+prototype of the modern “small hot bird.”</p>
+
+<p class="entry"><span class="def">phonograph</span>, <span class="pos">n.</span> An
+irritating toy that restores life to dead noises.</p>
+
+<p class="entry"><span class="def">photograph</span>, <span class="pos">n.</span> A
+picture painted by the sun without instruction in art. It is a little better
+than the work of an Apache, but not quite so good as that of a Cheyenne.</p>
+
+<p class="entry"><span class="def">phrenology</span>, <span class="pos">n.</span> The
+science of picking the pocket through the scalp. It consists in locating and
+exploiting the organ that one is a dupe with.</p>
+
+<p class="entry"><span class="def">physician</span>, <span class="pos">n.</span> One
+upon whom we set our hopes when ill and our dogs when well.</p>
+
+<p class="entry"><span class="def">physiognomy</span>, <span class="pos">n.</span> The
+art of determining the character of another by the resemblances and differences
+between his face and our own, which is the standard of excellence.</p>
+
+<div class="poem">
+<p class="poetry">“There is no art,” says Shakespeare, foolish man,</p>
+<p class="poetry">“To read the mind’s construction in the face.”</p>
+<p class="poetry">The physiognomists his portrait scan,</p>
+<p class="poetry">And say: “How little wisdom here we trace! He knew his face disclosed his mind and heart, So,
+in his own defence, denied our art.”</p>
+<p class="poetry">Lavatar Shunk</p>
+</div>
+
+<p class="entry"><span class="def">piano</span>, <span class="pos">n.</span> A parlor
+utensil for subduing the impenitent visitor. It is operated by pressing the
+keys of the machine and the spirits of the audience.</p>
+
+<p class="entry"><span class="def">pickaninny</span>, <span class="pos">n.</span> The
+young of the <i>Procyanthropos</i>, or <i>Americanus dominans</i>. It is small, black and charged with political
+fatalities.</p>
+
+<p class="entry"><span class="def">picture</span>, <span class="pos">n.</span> A
+representation in two dimensions of something wearisome in three.</p>
+
+<div class="poem">
+<p class="poetry">“Behold great Daubert’s picture here on view—</p>
+<p class="poetry">Taken from Life.” If that description’s true, Grant, heavenly Powers, that I be taken, too.</p>
+<p class="citeauth">Jali Hane</p>
+</div>
+
+<p class="entry"><span class="def">pie</span>, <span class="pos">n.</span> An advance
+agent of the reaper whose name is Indigestion.</p>
+
+<div class="poem">
+<p class="poetry">Cold pie was highly esteemed by the remains.</p>
+<p class="poetry">Rev. Dr. Mucker</p>
+<p class="poetry">(in a funeral sermon over a British nobleman)</p>
+<p class="poetry">Cold pie is a detestable</p>
+<p class="poetry">American comestible.</p>
+<p class="poetry">That’s why I’m done—or undone—</p>
+<p class="poetry">So far from that dear London.</p>
+<p class="citeauth">(from the headstone of a British nobleman in Kalamazoo)</p>
+</div>
+
+<p class="entry"><span class="def">piety</span>, <span class="pos">n.</span> Reverence
+for the Supreme Being, based upon His supposed resemblance to man.</p>
+
+<div class="poem">
+<p class="poetry">The pig is taught by sermons and epistles<br />
+To think the God of Swine has snout and bristles.</p>
+<p class="citeauth">Judibras</p>
+</div>
+
+<p class="entry"><span class="def">pig</span>, <span class="pos">n.</span> An animal
+(<i>Porcus omnivorus</i>) closely allied to the human race by the splendor and
+vivacity of its appetite, which, however, is inferior in scope, for it sticks
+at pig.</p>
+
+<p class="entry"><span class="def">pigmy</span>, <span class="pos">n.</span> One of a
+tribe of very small men found by ancient travelers in many parts of the world,
+but by modern in Central Africa only. The Pigmies are so called to distinguish
+them from the bulkier Caucasians&#8212;who are Hogmies.</p>
+
+<p class="entry"><span class="def">Pilgrim</span>, <span class="pos">n.</span> A
+traveler that is taken seriously. A Pilgrim Father was one who, leaving Europe
+in 1620 because not permitted to sing psalms through his nose, followed it to
+Massachusetts, where he could personate God according to the dictates of his
+conscience.</p>
+
+<p class="entry"><span class="def">pillory</span>, <span class="pos">n.</span> A
+mechanical device for inflicting personal distinction&#8212;prototype of the
+modern newspaper conducted by persons of austere virtues and blameless lives.</p>
+
+<p class="entry"><span class="def">piracy</span>, <span class="pos">n.</span> Commerce
+without its folly-swaddles, just as God made it.</p>
+
+<p class="entry"><span class="def">pitiful</span>, <span class="pos">adj.</span> The
+state of an enemy of opponent after an imaginary encounter with oneself.</p>
+
+<p class="entry"><span class="def">pity</span>, <span class="pos">n.</span> A failing
+sense of exemption, inspired by contrast.</p>
+
+<p class="entry"><span class="def">plagiarism</span>, <span class="pos">n.</span> A
+literary coincidence compounded of a discreditable priority and an honorable subsequence.</p>
+
+<p class="entry"><span class="def">plagiarize</span>, <span class="pos">v.</span> To
+take the thought or style of another writer whom one has never, never read.</p>
+
+<p class="entry"><span class="def">plague</span>, <span class="pos">n.</span> In
+ancient times a general punishment of the innocent for admonition of their
+ruler, as in the familiar instance of Pharaoh the Immune. The plague as we of
+to-day have the happiness to know it is merely Nature’s fortuitous
+manifestation of her purposeless objectionableness.</p>
+
+<p class="entry"><span class="def">plan</span>, <span class="pos">v.t.</span> To
+bother about the best method of accomplishing an accidental result.</p>
+
+<p id="platitude" class="entry"><span class="def">platitude</span>, <span class="pos">n.</span> The
+fundamental element and special glory of popular literature. A thought that
+snores in words that smoke. The wisdom of a million fools in the diction of a
+dullard. A fossil sentiment in artificial rock. A moral without the fable. All
+that is mortal of a departed truth. A demi-tasse of milk-and-mortality. The
+Pope’s-nose of a featherless peacock. A jelly-fish withering on the shore of
+the sea of thought. The cackle surviving the egg. A desiccated epigram.</p>
+
+<p class="entry"><span class="def">platonic</span>, <span class="pos">adj.</span> Pertaining
+to the philosophy of Socrates. Platonic Love is a fool’s name for the affection
+between a disability and a frost.</p>
+
+<p class="entry"><span class="def">plaudits</span>, <span class="pos">n.</span> Coins
+with which the populace pays those who tickle and devour it.</p>
+
+<p class="entry"><span class="def">please</span>, <span class="pos">v.</span> To lay
+the foundation for a superstructure of imposition.</p>
+
+<p id="pleasure" class="entry"><span class="def">pleasure</span>, <span class="pos">n.</span> The
+least hateful form of dejection.</p>
+
+<p class="entry"><span class="def">plebeian</span>, <span class="pos">n.</span> An
+ancient Roman who in the blood of his country stained nothing but his hands. Distinguished
+from the Patrician, who was a saturated solution.</p>
+
+<p class="entry"><span class="def">plebiscite</span>, <span class="pos">n.</span> A
+popular vote to ascertain the will of the sovereign.</p>
+
+<p class="entry"><span class="def">plenipotentiary,</span> <span class="pos">adj.</span> Having full power.
+A Minister Plenipotentiary is a diplomatist possessing
+absolute authority on condition that he never exert it.</p>
+
+<p class="entry"><span class="def">pleonasm</span>, <span class="pos">n.</span> An
+army of words escorting a corporal of thought.</p>
+
+<p class="entry"><span class="def">plow</span>, <span class="pos">n.</span> An
+implement that cries aloud for hands accustomed to the pen.</p>
+
+<p class="entry"><span class="def">plunder</span>, <span class="pos">v.</span> To
+take the property of another without observing the decent and customary
+reticences of theft. To effect a change of ownership with the candid
+concomitance of a brass band. To wrest the wealth of A from B and leave C
+lamenting a vanishing opportunity.</p>
+
+<p class="entry"><span class="def">pocket</span>, <span class="pos">n.</span> The
+cradle of motive and the grave of conscience. In woman this organ is lacking;
+so she acts without motive, and her conscience, denied burial, remains ever
+alive, confessing the sins of others.</p>
+
+<p class="entry"><span class="def">poetry</span>, <span class="pos">n.</span> A form
+of expression peculiar to the Land beyond the Magazines.</p>
+
+<p class="entry"><span class="def">poker</span>, <span class="pos">n.</span> A game
+said to be played with cards for some purpose to this lexicographer unknown.</p>
+
+<p class="entry"><span class="def">police</span>, <span class="pos">n.</span> An
+armed force for protection and participation.</p>
+
+<p class="entry"><span class="def">politeness</span>, <span class="pos">n.</span> The
+most acceptable hypocrisy.</p>
+
+<p id="politics" class="entry"><span class="def">politics</span>, <span class="pos">n.</span> A
+strife of interests masquerading as a contest of principles. The conduct of
+public affairs for private advantage.</p>
+
+<p class="entry"><span class="def">politician</span>, <span class="pos">n.</span> An
+eel in the fundamental mud upon which the superstructure of organized society
+is reared. When we wriggles he mistakes the agitation of his tail for the
+trembling of the edifice. As compared with the statesman, he suffers the
+disadvantage of being alive.</p>
+
+<p class="entry"><span class="def">polygamy</span>, <span class="pos">n.</span> A
+house of atonement, or expiatory chapel, fitted with several stools of
+repentance, as distinguished from monogamy, which has but one.</p>
+
+<p class="entry"><span class="def">populist</span>, <span class="pos">n.</span> A
+fossil patriot of the early agricultural period, found in the old red soapstone
+underlying Kansas; characterized by an uncommon spread of ear, which some
+naturalists contend gave him the power of flight, though Professors Morse and
+Whitney, pursuing independent lines of thought, have ingeniously pointed out
+that had he possessed it he would have gone elsewhere. In the picturesque
+speech of his period, some fragments of which have come down to us, he was
+known as “The Matter with Kansas.”</p>
+
+<p class="entry"><span class="def">portable</span>, <span class="pos">adj.</span> Exposed
+to a mutable ownership through vicissitudes of possession.</p>
+
+<div class="poem">
+<p class="poetry">His light estate, if neither he did make it<br />
+Nor yet its former guardian forsake it,<br />
+Is portable improperly, I take it.</p>
+<p class="citeauth">Worgum Slupsky</p>
+</div>
+
+<p class="entry"><span class="def">Portuguese</span>, <span class="pos">n.</span>pl. A
+species of geese indigenous to Portugal. They are mostly without feathers and
+imperfectly edible, even when stuffed with garlic.</p>
+
+<p class="entry"><span class="def">positive</span>, <span class="pos">adj.</span> Mistaken
+at the top of one’s voice.</p>
+
+<p class="entry"><span class="def">positivism</span>, <span class="pos">n.</span> A
+philosophy that denies our knowledge of the Real and affirms our ignorance of
+the Apparent. Its longest exponent is Comte, its broadest Mill and its thickest
+Spencer.</p>
+
+<p class="entry"><span class="def">posterity</span>, <span class="pos">n.</span> An
+appellate court which reverses the judgment of a popular author’s
+contemporaries, the appellant being his obscure competitor.</p>
+
+<p class="entry"><span class="def">potable</span>, <span class="pos">n.</span> Suitable
+for drinking. Water is said to be potable; indeed, some declare it our natural
+beverage, although even they find it palatable only when suffering from the
+recurrent disorder known as thirst, for which it is a medicine. Upon nothing
+has so great and diligent ingenuity been brought to bear in all ages and in all
+countries, except the most uncivilized, as upon the invention of substitutes
+for water. To hold that this general aversion to that liquid has no basis in
+the preservative instinct of the race is to be unscientific—and without science
+we are as the snakes and toads.</p>
+
+<p class="entry"><span class="def">poverty</span>, <span class="pos">n.</span> A file
+provided for the teeth of the rats of reform. The number of plans for its
+abolition equals that of the reformers who suffer from it, plus that of the
+philosophers who know nothing about it. Its victims are distinguished by
+possession of all the virtues and by their faith in leaders seeking to conduct
+them into a prosperity where they believe these to be unknown.</p>
+
+<p class="entry"><span class="def">pray</span>, <span class="pos">v.</span> To ask
+that the laws of the universe be annulled in behalf of a single petitioner
+confessedly unworthy.</p>
+
+<p class="entry"><span class="def">Pre-Adamite</span>, <span class="pos">n.</span> One
+of an experimental and apparently unsatisfactory race of antedated Creation and
+lived under conditions not easily conceived. Melsius believed them to have
+inhabited “the Void” and to have been something intermediate between fishes and
+birds. Little its known of them beyond the fact that they supplied Cain with a
+wife and theologians with a controversy.</p>
+
+<p class="entry"><span class="def">precedent</span>, <span class="pos">n.</span> In
+Law, a previous decision, rule or practice which, in the absence of a definite
+statute, has whatever force and authority a Judge may choose to give it,
+thereby greatly simplifying his task of doing as he pleases. As there are
+precedents for everything, he has only to ignore those that make against his
+interest and accentuate those in the line of his desire. Invention of the
+precedent elevates the trial-at-law from the low estate of a fortuitous ordeal
+to the noble attitude of a dirigible arbitrament.</p>
+
+<p class="entry"><span class="def">precipitate</span>, <span class="pos">adj.</span> Anteprandial.</p>
+
+<div class="poem">
+<p class="poetry">Precipitate in all, this sinner</p>
+<p class="poetry">Took action first, and then his dinner.</p>
+<p class="citeauth">Judibras</p>
+</div>
+
+<p class="entry"><span class="def">predestination</span>, <span class="pos">n.</span>
+The doctrine that all things occur according to programme. This doctrine should
+not be confused with that of foreordination, which means that all things are
+programmed, but does not affirm their occurrence, that being only an
+implication from other doctrines by which this is entailed. The difference is
+great enough to have deluged Christendom with ink, to say nothing of the gore. With
+the distinction of the two doctrines kept well in mind, and a reverent belief
+in both, one may hope to escape perdition if spared.</p>
+
+<p class="entry"><span class="def">predicament</span>, <span class="pos">n.</span> The
+wage of consistency.</p>
+
+<p class="entry"><span class="def">predilection</span>, <span class="pos">n.</span> The
+preparatory stage of disillusion.</p>
+
+<p class="entry"><span class="def">pre-existence</span>, <span class="pos">n.</span> An
+unnoted factor in creation.</p>
+
+<p class="entry"><span class="def">preference</span>, <span class="pos">n.</span> A
+sentiment, or frame of mind, induced by the erroneous belief that one thing is
+better than another.</p>
+
+<p>An ancient philosopher, expounding his conviction that life is no better than death, was
+asked by a disciple why, then, he did not die. “Because,” he replied, “death is
+no better than life.” It is longer.</p>
+
+<p class="entry"><span class="def">prehistoric</span>, <span class="pos">adj.</span> Belonging
+to an early period and a museum. </p>
+
+<div class="poem">
+<p class="poetry">Antedating the art and practice of perpetuating falsehood.</p>
+<p class="poetry">He lived in a period prehistoric,</p>
+<p class="poetry">When all was absurd and phantasmagoric.</p>
+<p class="poetry">Born later, when Clio, celestial recorded,</p>
+<p class="poetry">Set down great events in succession and order,</p>
+<p class="poetry">He surely had seen nothing droll or fortuitous</p>
+<p class="poetry">In anything here but the lies that she threw at us.</p>
+<p class="citeauth">Orpheus Bowen</p>
+</div>
+
+<p class="entry"><span class="def">prejudice</span>, <span class="pos">n.</span> A
+vagrant opinion without visible means of support.</p>
+
+<p class="entry"><span class="def">prelate</span>, <span class="pos">n.</span> A
+church officer having a superior degree of holiness and a fat preferment. One
+of Heaven’s aristocracy. A gentleman of God.</p>
+
+<p class="entry"><span class="def">prerogative</span>, <span class="pos">n.</span> A
+sovereign’s right to do wrong.</p>
+
+<p class="entry"><span class="def">Presbyterian</span>, <span class="pos">n.</span> One
+who holds the conviction that the government authorities of the Church should
+be called presbyters.</p>
+
+<p class="entry"><span class="def">prescription</span>, <span class="pos">n.</span> A
+physician’s guess at what will best prolong the situation with least harm to the patient.</p>
+
+<p class="entry"><span class="def">present</span>, <span class="pos">n.</span> That
+part of eternity dividing the domain of disappointment from the realm of hope.</p>
+
+<p class="entry"><span class="def">presentable</span>, <span class="pos">adj.</span> Hideously
+appareled after the manner of the time and place.</p>
+
+<p>In Boorioboola-Gha a man is presentable on occasions of ceremony if he have his abdomen painted a
+bright blue and wear a cow’s tail; in New York he may, if it please him, omit
+the paint, but after sunset he must wear two tails made of the wool of a sheep
+and dyed black.</p>
+
+<p class="entry"><span class="def">preside</span>, <span class="pos">v.</span> To
+guide the action of a deliberative body to a desirable result. In Journalese,
+to perform upon a musical instrument; as, “He presided at the piccolo.”</p>
+
+<div class="poem">
+<p class="poetry">The Headliner, holding the copy in hand,</p>
+<p class="poetry">Read with a solemn face:</p>
+<p class="poetry">“The music was very uncommonly grand—</p>
+<p class="poetry">The best that was every provided,</p>
+<p class="poetry">For our townsman Brown presided</p>
+<p class="poetry">At the organ with skill and grace.”</p>
+<p class="poetry">The Headliner discontinued to read,</p>
+<p class="poetry">And, spread the paper down</p>
+<p class="poetry">On the desk, he dashed in at the top of the screed:</p>
+<p class="poetry">“Great playing by President Brown.”</p>
+<p class="citeauth">Orpheus Bowen</p>
+</div>
+
+<p class="entry"><span class="def">presidency</span>, <span class="pos">n.</span> The
+greased pig in the field game of American politics.</p>
+
+<p id="president" class="entry"><span class="def">president</span>, <span class="pos">n.</span> The
+leading figure in a small group of men of whom—and of whom only—it is
+positively known that immense numbers of their countrymen did not want any of
+them for President.</p>
+
+<div class="poem">
+<p class="poetry">If that’s an honor surely ‘tis a greater<br />
+To have been a simple and undamned spectator.</p>
+<p class="poetry">Behold in me a man of mark and note</p>
+<p class="poetry">Whom no elector e’er denied a vote!&#8212;</p>
+<p class="poetry">An undiscredited, unhooted gent</p>
+<p class="poetry">Who might, for all we know, be President</p>
+<p class="poetry">By acclimation. Cheer, ye varlets, cheer—</p>
+<p class="poetry">I’m passing with a wide and open ear!</p>
+<p class="citeauth">Jonathan Fomry</p>
+</div>
+
+<p class="entry"><span class="def">prevaricator</span>, <span class="pos">n.</span> A
+liar in the caterpillar estate.</p>
+
+<p class="entry"><span class="def">price</span>, <span class="pos">n.</span> Value,
+plus a reasonable sum for the wear and tear of conscience in demanding it.</p>
+
+<p class="entry"><span class="def">primate</span>, <span class="pos">n.</span> The
+head of a church, especially a State church supported by involuntary
+contributions. The Primate of England is the Archbishop of Canterbury, an
+amiable old gentleman, who occupies Lambeth Palace when living and Westminster
+Abbey when dead. He is commonly dead.</p>
+
+<p class="entry"><span class="def">prisonu</span>, <span class="pos">n.</span> A place
+of punishments and rewards. The poet assures us that—</p>
+
+<div class="poem">
+<p class="poetry">“Stone walls do not a prison make,”</p>
+<p class="poetry">but a combination of the stone wall, the political parasite and the moral instructor is no garden
+of sweets.</p>
+</div>
+
+<p class="entry"><span class="def">private</span>, <span class="pos">n.</span> A
+military gentleman with a field-marshal’s baton in his knapsack and an
+impediment in his hope.</p>
+
+<p class="entry"><span class="def">proboscis</span>, <span class="pos">n.</span> The
+rudimentary organ of an elephant which serves him in place of the
+knife-and-fork that Evolution has as yet denied him. For purposes of humor it
+is popularly called a trunk.</p>
+
+<p>Asked how he knew that an elephant was going on a journey, the illustrious Jo. Miller cast a
+reproachful look upon his tormentor, and answered, absently: “When it is ajar,”
+and threw himself from a high promontory into the sea. Thus perished in his
+pride the most famous humorist of antiquity, leaving to mankind a heritage of
+woe! No successor worthy of the title has appeared, though Mr. Edward bok, of <i>The Ladies’ Home Journal</i>, is much
+respected for the purity and sweetness of his personal character.</p>
+
+<p class="entry"><span class="def">projectile</span>, <span class="pos">n.</span> The
+final arbiter in international disputes. Formerly these disputes were settled
+by physical contact of the disputants, with such simple arguments as the
+rudimentary logic of the times could supply—the sword, the spear, and so forth.
+With the growth of prudence in military affairs the projectile came more and
+more into favor, and is now held in high esteem by the most courageous. Its
+capital defect is that it requires personal attendance at the point of
+propulsion.</p>
+
+<p class="entry"><span class="def">proof</span>, <span class="pos">n.</span> Evidence
+having a shade more of plausibility than of unlikelihood. The testimony of two
+credible witnesses as opposed to that of only one.</p>
+
+<p class="entry"><span class="def">proof-reader</span>, <span class="pos">n.</span> A
+malefactor who atones for making your writing nonsense by permitting the
+compositor to make it unintelligible.</p>
+
+<p class="entry"><span class="def">property</span>, <span class="pos">n.</span> Any
+material thing, having no particular value, that may be held by A against the
+cupidity of B. Whatever gratifies the passion for possession in one and
+disappoints it in all others. The object of man’s brief rapacity and long indifference.</p>
+
+<p class="entry"><span class="def">prophecy</span>, <span class="pos">n.</span> The
+art and practice of selling one’s credibility for future delivery.</p>
+
+<p class="entry"><span class="def">prospect</span>, <span class="pos">n.</span> An
+outlook, usually forbidding. An expectation, usually forbidden.</p>
+
+<div class="poem">
+<p class="poetry">Blow, blow, ye spicy breezes—</p>
+<p class="poetry">O’er Ceylon blow your breath,</p>
+<p class="poetry">Where every prospect pleases,</p>
+<p class="poetry">Save only that of death.</p>
+<p class="citeauth">Bishop Sheber</p>
+</div>
+
+<p class="entry"><span class="def">providential</span>, <span class="pos">adj.</span>
+Unexpectedly and conspicuously beneficial to the person so describing it.</p>
+
+<p class="entry"><span class="def">prude</span>, <span class="pos">n.</span> A bawd
+hiding behind the back of her demeanor.</p>
+
+<p class="entry"><span class="def">publish</span>, <span class="pos">n.</span> In
+literary affairs, to become the fundamental element in a cone of critics.</p>
+
+<p class="entry"><span class="def">push</span>, <span class="pos">n.</span> One of
+the two things mainly conducive to success, especially in politics. The other is Pull.</p>
+
+<p class="entry"><span class="def">pyrrhonism</span>, <span class="pos">n.</span> An
+ancient philosophy, named for its inventor. It consisted of an absolute
+disbelief in everything but Pyrrhonism. Its modern professors have added that.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/P.html.i
@@ -1,0 +1,47 @@
+20 pages
+size 400 552
+length 34265
+396 2 10 body html
+0
+1944 2 42 body html
+22
+3960 2 77 body html
+90
+5856 2 109 body html
+127
+7228 2 139 body html
+0
+8256 2 156 body html
+265
+10628 2 202 body html
+22
+12036 2 229 body html
+89
+13249 2 258 body html
+22
+15524 2 299 body html
+22
+17760 2 340 body html
+22
+19719 2 377 body html
+90
+21495 2 412 body html
+124
+23959 2 451 body html
+36
+25650 2 486 body html
+72
+27357 2 520 body html
+0
+27879 2 529 body html
+379
+29793 2 569 body html
+22
+31481 2 600 body html
+39
+33103 2 628 body html
+176
+president 16
+platitude 9
+politics 10
+pleasure 9
--- /dev/null
+++ b/lib/ebooks/devils/Q.html
@@ -1,0 +1,71 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: Q</title>
+</head>
+<body lang="en-US">
+
+
+<h1>Q</h1>
+
+<p class="entry"><span class="def">queen</span>, <span class="pos">n.</span> A woman
+by whom the realm is ruled when there is a king, and through whom it is ruled
+when there is not.</p>
+
+<p class="entry"><span class="def">quill</span>, <span class="pos">n.</span> An
+implement of torture yielded by a goose and commonly wielded by an ass. This
+use of the quill is now obsolete, but its modern equivalent, the steel pen, is
+wielded by the same everlasting Presence.</p>
+
+<p class="entry"><span class="def">quiver</span>, <span class="pos">n.</span> A
+portable sheath in which the ancient statesman and the aboriginal lawyer
+carried their lighter arguments.</p>
+
+<div class="poem">
+<p class="poetry">He extracted from his quiver,</p>
+<p class="poetry">Did the controversial Roman,</p>
+<p class="poetry">An argument well fitted</p>
+<p class="poetry">To the question as submitted,</p>
+<p class="poetry">Then addressed it to the liver,</p>
+<p class="poetry">Of the unpersuaded foeman.</p>
+<p class="citeauth">Oglum P. Boomp</p>
+</div>
+
+<p class="entry"><span class="def">quixotic</span>, <span class="pos">adj.</span> Absurdly
+chivalric, like Don Quixote. An insight into the beauty and excellence of this
+incomparable adjective is unhappily denied to him who has the misfortune to
+know that the gentleman’s name is pronounced Ke-ho-tay.</p>
+
+<div class="poem">
+<p class="poetry">When ignorance from out of our lives can banish Philology, ‘tis folly to know Spanish.</p>
+<p class="citeauth">Juan Smith</p>
+</div>
+
+<p class="entry"><span class="def">quorum</span>, <span class="pos">n.</span> A
+sufficient number of members of a deliberative body to have their own way and
+their own way of having it. In the United States Senate a quorum consists of
+the chairman of the Committee on Finance and a messenger from the White House;
+in the House of Representatives, of the Speaker and the devil.</p>
+
+<p class="entry"><span class="def">quotation</span>, <span class="pos">n.</span> The
+act of repeating erroneously the words of another. </p>
+
+<div class="poem">
+<p class="poetry">The words erroneously repeated.</p>
+<p class="poetry">Intent on making his quotation truer,</p>
+<p class="poetry">He sought the page infallible of Brewer,</p>
+<p class="poetry">Then made a solemn vow that we would be</p>
+<p class="poetry">Condemned eternally. Ah, me, ah, me!</p>
+<p class="citeauth">Stumpo Gaker</p>
+</div>
+
+<p class="entry"><span class="def">quotient</span>, <span class="pos">n.</span> A
+number showing how many times a sum of money belonging to one person is
+contained in the pocket of another—usually about as many times as it can be got there.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/Q.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 3077
+396 2 10 body html
+0
+1442 2 38 body html
+39
--- /dev/null
+++ b/lib/ebooks/devils/R.html
@@ -1,0 +1,728 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: R</title>
+</head>
+<body lang="en-US">
+
+
+
+<h1>R</h1>
+
+<p class="entry"><span class="def">rabble</span>, <span class="pos">n.</span> In a
+republic, those who exercise a supreme authority tempered by fraudulent
+elections. The rabble is like the sacred Simurgh, of Arabian fable—omnipotent
+on condition that it do nothing. (The word is Aristocratese, and has no exact
+equivalent in our tongue, but means, as nearly as may be, “soaring swine.”)</p>
+
+<p class="entry"><span class="def">rack</span>, <span class="pos">n.</span> An
+argumentative implement formerly much used in persuading devotees of a false
+faith to embrace the living truth. As a call to the unconverted the rack never
+had any particular efficacy, and is now held in light popular esteem.</p>
+
+<p class="entry"><span class="def">rank</span>, <span class="pos">n.</span> Relative
+elevation in the scale of human worth.</p>
+
+<div class="poem">
+<p class="poetry">He held at court a rank so high</p>
+<p class="poetry">That other noblemen asked why.</p>
+<p class="poetry">“Because,” ‘twas answered, “others lack</p>
+<p class="poetry">His skill to scratch the royal back.”</p>
+<p class="citeauth">Aramis Jukes</p>
+</div>
+
+<p class="entry"><span class="def">ransom</span>, <span class="pos">n.</span> The
+purchase of that which neither belongs to the seller, nor can belong to the
+buyer. The most unprofitable of investments.</p>
+
+<p class="entry"><span class="def">rapacity</span>, <span class="pos">n.</span> Providence
+without industry. The thrift of power.</p>
+
+<p class="entry"><span class="def">rarebit</span>, <span class="pos">n.</span> A
+Welsh rabbit, in the speech of the humorless, who point out that it is not a
+rabbit. To whom it may be solemnly explained that the comestible known as
+toad-in-a-hole is really not a toad, and that <i>riz-de-veau
+a la financiere</i> is not the smile of a calf prepared after the recipe
+of a she banker.</p>
+
+<p class="entry"><span class="def">rascal</span>, <span class="pos">n.</span> A fool
+considered under another aspect.</p>
+
+<p class="entry"><span class="def">rascality</span>, <span class="pos">n.</span> Stupidity
+militant. The activity of a clouded intellect.</p>
+
+<p class="entry"><span class="def">rash</span>, <span class="pos">adj.</span> Insensible
+to the value of our advice.</p>
+
+<div class="poem">
+<p class="poetry">“Now lay your bet with mine, nor let</p>
+<p class="poetry">These gamblers take your cash.”</p>
+<p class="poetry">“Nay, this child makes no bet.” “Great snakes!</p>
+<p class="poetry">How can you be so rash?”</p>
+<p class="citeauth">Bootle P. Gish</p>
+</div>
+
+<p class="entry"><span class="def">rational</span>, <span class="pos">adj.</span> Devoid
+of all delusions save those of observation, experience and reflection.</p>
+
+<p class="entry"><span class="def">rattlesnake</span>, <span class="pos">n.</span> Our
+prostrate brother, <i>Homo ventrambulans</i>.</p>
+
+<p class="entry"><span class="def">razor</span>, <span class="pos">n.</span> An
+instrument used by the Caucasian to enhance his beauty, by the Mongolian to make
+a guy of himself, and by the Afro-American to affirm his worth.</p>
+
+<p class="entry"><span class="def">reach</span>, <span class="pos">n.</span> The
+radius of action of the human hand. The area within which it is possible (and
+customary) to gratify directly the propensity to provide.</p>
+
+<div class="poem">
+<p class="poetry">This is a truth, as old as the hills,</p>
+<p class="poetry">That life and experience teach:</p>
+<p class="poetry">The poor man suffers that keenest of ills,</p>
+<p class="poetry">An impediment of his reach.</p>
+<p class="citeauth">G. J.</p>
+</div>
+
+<p class="entry"><span class="def">reading</span>, <span class="pos">n.</span> The
+general body of what one reads. In our country it consists, as a rule, of
+Indiana novels, short stories in “dialect” and humor in slang.</p>
+
+<div class="poem">
+<p class="poetry">We know by one’s reading</p>
+<p class="poetry">His learning and breeding;</p>
+<p class="poetry">By what draws his laughter</p>
+<p class="poetry">We know his Hereafter.</p>
+<p class="poetry">Read nothing, laugh never—</p>
+<p class="poetry">The Sphinx was less clever!</p>
+<p class="citeauth">Jupiter Muke</p>
+</div>
+
+<p class="entry"><span class="def">radicalsim</span>, <span class="pos">n.</span> The
+conservatism of to-morrow injected into the affairs of to-day.</p>
+
+<p class="entry"><span class="def">radium</span>, <span class="pos">n.</span> A
+mineral that gives off heat and stimulates the organ that a scientist is a fool
+with.</p>
+
+<p class="entry"><span class="def">railroad</span>, <span class="pos">n.</span> The
+chief of many mechanical devices enabling us to get away from where we are to
+wher we are no better off. For this purpose the railroad is held in highest
+favor by the optimist, for it permits him to make the transit with great expedition.</p>
+
+<p class="entry"><span class="def">ramshackle</span>, <span class="pos">adj.</span> Pertaining
+to a certain order of architecture, otherwise known as the Normal American. Most
+of the public buildings of the United States are of the Ramshackle order,
+though some of our earlier architects preferred the Ironic. Recent additions to
+the White House in Washington are Theo-Doric, the ecclesiastic order of the
+Dorians. They are exceedingly fine and cost one hundred dollars a brick.</p>
+
+<p class="entry"><span class="def">realism</span>, <span class="pos">n.</span> The
+art of depicting nature as it is seem by toads. The charm suffusing a landscape
+painted by a mole, or a story written by a measuring-worm.</p>
+
+<p class="entry"><span class="def">reality</span>, <span class="pos">n.</span> The
+dream of a mad philosopher. That which would remain in the cupel if one should
+assay a phantom. The nucleus of a vacuum.</p>
+
+<p class="entry"><span class="def">really</span>, <span class="pos">adv.</span> Apparently.</p>
+
+<p class="entry"><span class="def">rear</span>, <span class="pos">n.</span> In
+American military matters, that exposed part of the army that is nearest to Congress.</p>
+
+<p class="entry"><span class="def">reason</span>, <span class="pos">v.i.</span> To
+weight probabilities in the scales of desire.</p>
+
+<p class="entry"><span class="def">reason</span>, <span class="pos">n.</span> Propensitate of prejudice.</p>
+
+<p class="entry"><span class="def">reasonable</span>, <span class="pos">adj.</span> Accessible
+to the infection of our own opinions. </p>
+
+<p>Hospitable to persuasion, dissuasion and evasion.</p>
+
+<p class="entry"><span class="def">rebel</span>, <span class="pos">n.</span> A
+proponent of a new misrule who has failed to establish it.</p>
+
+<p class="entry"><span class="def">recollect</span>, <span class="pos">v.</span> To
+recall with additions something not previously known.</p>
+
+<p class="entry"><span class="def">reconciliation</span>, <span class="pos">n.</span>
+A suspension of hostilities. An armed truce for the purpose of digging up the dead.</p>
+
+<p class="entry"><span class="def">reconsider</span>, <span class="pos">v.</span> To
+seek a justification for a decision already made.</p>
+
+<p class="entry"><span class="def">recount</span>, <span class="pos">n.</span> In
+American politics, another throw of the dice, accorded to the player against
+whom they are loaded.</p>
+
+<p class="entry"><span class="def">recreation</span>, <span class="pos">n.</span> A
+particular kind of dejection to relieve a general fatigue.</p>
+
+<p class="entry"><span class="def">recruit</span>, <span class="pos">n.</span> A
+person distinguishable from a civilian by his uniform and from a soldier by his gait.</p>
+
+<div class="poem">
+<p class="poetry">Fresh from the farm or factory or street,</p>
+
+<p class="poetry">His marching, in pursuit or in retreat,</p>
+<p class="poetry">Were an impressive martial spectacle</p>
+<p class="poetry">Except for two impediments—his feet.</p>
+
+<p class="citeauth">Thompson Johnson</p>
+</div>
+
+<p class="entry"><span class="def">rector</span>, <span class="pos">n.</span> In the
+Church of England, the Third Person of the parochial Trinity, the Cruate and
+the Vicar being the other two.</p>
+
+<p class="entry"><span class="def">redemption</span>, <span class="pos">n.</span> Deliverance
+of sinners from the penalty of their sin, through their murder of the deity
+against whom they sinned. The doctrine of Redemption is the fundamental mystery
+of our holy religion, and whoso believeth in it shall not perish, but have
+everlasting life in which to try to understand it.</p>
+
+<div class="poem">
+<p class="poetry">We must awake Man’s spirit from his sin,</p>
+<p class="poetry">And take some special measure for redeeming it;</p>
+<p class="poetry">Though hard indeed the task to get it in</p>
+<p class="poetry">Among the angels any way but teaming it,</p>
+<p class="poetry">Or purify it otherwise than steaming it.</p>
+<p class="poetry">I’m awkward at Redemption—a beginner:</p>
+<p class="poetry">My method is to crucify the sinner.</p>
+<p class="citeauth">Golgo Brone</p>
+</div>
+
+<p class="entry"><span class="def">redress</span>, <span class="pos">n.</span> Reparation
+without satisfaction.</p>
+
+<p>Among the Anglo-Saxon a subject conceiving himself wronged by the king was permitted, on
+proving his injury, to beat a brazen image of the royal offender with a switch
+that was afterward applied to his own naked back. The latter rite was performed
+by the public hangman, and it assured moderation in the plaintiff’s choice of a switch.</p>
+
+<p class="entry"><span class="def">red-skin</span>, <span class="pos">n.</span> A
+North American Indian, whose skin is not red—at least not on the outside.</p>
+
+<p class="entry"><span class="def">redundant</span>, <span class="pos">adj.</span> Superfluous;
+needless; <i>de trop</i>.</p>
+
+<div class="poem">The Sultan said: “There’s evidence abundant<br />
+To prove this unbelieving dog redundant.”<br />
+To whom the Grand Vizier, with mien impressive,<br />
+Replied: “His head, at least, appears excessive.”<br />
+<p class="citeauth">Habeeb Suleiman</p>
+</div>
+
+<p class="quote">Mr. Debs is a redundant citizen. Theodore Roosevelt</p>
+
+<p class="entry"><span class="def">referendum</span>, <span class="pos">n.</span> A
+law for submission of proposed legislation to a popular vote to learn the
+nonsensus of public opinion.</p>
+
+<p class="entry"><span class="def">reflection</span>, <span class="pos">n.</span> An
+action of the mind whereby we obtain a clearer view of our relation to the
+things of yesterday and are able to avoid the perils that we shall not again encounter.</p>
+
+<p class="entry"><span class="def">reform</span>, <span class="pos">v.</span> A thing
+that mostly satisfies reformers opposed to reformation.</p>
+
+<p class="entry"><span class="def">refuge</span>, <span class="pos">n.</span> Anything
+assuring protection to one in peril. Moses and Joshua provided six cities of
+refuge—Bezer, Golan, Ramoth, Kadesh, Schekem and Hebron—to which one who had
+taken life inadvertently could flee when hunted by relatives of the deceased. This
+admirable expedient supplied him with wholesome exercise and enabled them to
+enjoy the pleasures of the chase; whereby the soul of the dead man was
+appropriately honored by observations akin to the funeral games of early
+Greece.</p>
+
+<p class="entry"><span class="def">refusal</span>, <span class="pos">n.</span> Denial
+of something desired; as an elderly maiden’s hand in marriage, to a rich and
+handsome suitor; a valuable franchise to a rich corporation, by an alderman;
+absolution to an impenitent king, by a priest, and so forth. Refusals are
+graded in a descending scale of finality thus: the refusal absolute, the
+refusal condition, the refusal tentative and the refusal feminine. The last is
+called by some casuists the refusal assentive.</p>
+
+<p class="entry"><span class="def">regalia</span>, <span class="pos">n.</span> Distinguishing
+insignia, jewels and costume of such ancient and honorable orders as Knights of
+Adam; Visionaries of Detectable Bosh; the Ancient Order of Modern Troglodytes;
+the League of Holy Humbug; the Golden Phalanx of Phalangers; the Genteel
+Society of Expurgated Hoodlums; the Mystic Alliances of Georgeous Regalians; Knights and Ladies
+of the Yellow Dog; the Oriental Order of Sons of the West; the Blatherhood of
+Insufferable Stuff; Warriors of the Long Bow; Guardians of the Great Horn
+Spoon; the Band of Brutes; the Impenitent Order of Wife-Beaters; the Sublime Legion
+of Flamboyant Conspicuants; Worshipers at the Electroplated Shrine; Shining
+Inaccessibles; Fee-Faw-Fummers of the inimitable Grip; Jannissaries of the
+Broad-Blown Peacock; Plumed Increscencies of the Magic Temple; the Grand Cabal
+of Able-Bodied Sedentarians; Associated Deities of the Butter Trade; the Garden
+of Galoots; the Affectionate Fraternity of Men Similarly Warted; the Flashing
+Astonishers; Ladies of Horror;  Cooperative Association for Breaking into the Spotlight; Dukes of Eden;
+Disciples Militant of the Hidden Faith; Knights-Champions of the Domestic Dog; the Holy
+Gregarians; the Resolute Optimists; the Ancient Sodality of Inhospitable Hogs;
+Associated Sovereigns of Mendacity; Dukes-Guardian of the Mystic Cess-Pool; the Society for
+Prevention of Prevalence; Kings of Drink;
+Polite Federation of Gents-Consequential; the Mysterious Order of the
+Undecipherable Scroll; Uniformed Rank of Lousy Cats; Monarchs of Worth and
+Hunger; Sons of the South Star; Prelates of the Tub-and-Sword.</p>
+
+<p id="religion" class="entry"><span class="def">religion</span>, <span class="pos">n.</span> A
+daughter of Hope and Fear, explaining to Ignorance the nature of the Unknowable.</p>
+
+<span class="dialoge">
+<p>“What is your religion my son?” inquired the Archbishop of Rheims.</p>
+<p>“Pardon, monseigneur,” replied Rochebriant; “I am ashamed of it.”</p>
+<p>“Then why do you not become an atheist?”</p>
+<p>“Impossible! I should be ashamed of atheism.”</p>
+<p>“In that case, monseiegneur, you should join the Protestants.”</p>
+</span>
+
+<p class="entry"><span class="def">reliquary</span>, <span class="pos">n.</span> A
+receptacle for such sacred objects as pieces of the true cross, short-ribs of
+the saints, the ears of Balaam’s ass, the lung of the cock that called Peter to
+repentance and so forth. Reliquaries are commonly of metal, and provided with a
+lock to prevent the contents from coming out and performing miracles at
+unseasonable times. A feather from the wing of the Angel of the Annunciation
+once escaped during a sermon in Saint Peter’s and so tickled the noses of the
+congregation that they woke and sneezed with great vehemence three times each. It
+is related in the “Gesta Sanctorum” that a sacristan in the Canterbury
+cathedral surprised the head of Saint Dennis in the library. Reprimanded by its
+stern custodian, it explained that it was seeking a body of doctrine. This
+unseemly levity so raged the diocesan that the offender was publicly
+anathematized, thrown into the Stour and replaced by another head of Saint
+Dennis, brought from Rome.</p>
+
+<p class="entry"><span class="def">renown</span>, <span class="pos">n.</span> A
+degree of distinction between notoriety and fame—a little more supportable than
+the one and a little more intolerable than the other. Sometimes it is conferred
+by an unfriendly and inconsiderate hand.</p>
+
+<div class="poem">
+<p class="poetry">I touched the harp in every key,</p>
+<p class="poetry">But found no heeding ear;</p>
+<p class="poetry">And then Ithuriel touched me</p>
+<p class="poetry">With a revealing spear.</p>
+<p class="poetry">Not all my genius, great as ‘tis,</p>
+<p class="poetry">Could urge me out of night.</p>
+<p class="poetry">I felt the faint appulse of his,</p>
+<p class="poetry">And leapt into the light!</p>
+<p class="citeauth">W. J. Candleton</p>
+</div>
+
+<p class="entry"><span class="def">reparation</span>, <span class="pos">n.</span> Satisfaction
+that is made for a wrong and deducted from the satisfaction felt in committing it.</p>
+
+<p class="entry"><span class="def">repartee</span>, <span class="pos">n.</span> Prudent
+insult in retort. Practiced by gentlemen with a constitutional aversion to
+violence, but a strong disposition to offend. In a war of words, the tactics of
+the North American Indian.</p>
+
+<p class="entry"><span class="def">repentance</span>, <span class="pos">n.</span> The
+faithful attendant and follower of Punishment. It is usually manifest in a
+degree of reformation that is not inconsistent with continuity of sin.</p>
+
+<div class="poem">
+<p class="poetry">Desirous to avoid the pains of Hell,</p>
+<p class="poetry">You will repent and join the Church, Parnell?</p>
+<p class="poetry">How needless!&#8212;Nick will keep you off the coals
+And add you to the woes of other souls.</p>
+<p class="citeauth">Jomater Abemy</p>
+</div>
+
+<p class="entry"><span class="def">replica</span>, <span class="pos">n.</span> A
+reproduction of a work of art, by the artist that made the original. It is so
+called to distinguish it from a “copy,” which is made by another artist. When
+the two are mae with equal skill the replica is the more valuable, for it is
+supposed to be more beautiful than it looks.</p>
+
+<p class="entry"><span class="def">reporter</span>, <span class="pos">n.</span> A
+writer who guesses his way to the truth and dispels it with a tempest of words.</p>
+
+<div class="poem">
+<p class="poetry">“More dear than all my bosom knows, O thou Whose ‘lips are sealed’ and will not disavow!” So
+sang the blithe reporter-man as grew Beneath his hand the leg-long “interview.”</p>
+<p class="citeauth">Barson Maith</p>
+</div>
+
+<p class="entry"><span class="def">repose</span>, <span class="pos">v.i.</span> To
+cease from troubling.</p>
+
+<p class="entry"><span class="def">representative</span>, <span class="pos">n.</span>
+In national politics, a member of the Lower House in this world, and without
+discernible hope of promotion in the next.</p>
+
+<p class="entry"><span class="def">reprobation</span>, <span class="pos">n.</span> In
+theology, the state of a luckless mortal prenatally damned. The doctrine of
+reprobation was taught by Calvin, whose joy in it was somewhat marred by the
+sad sincerity of his conviction that although some are foredoomed to perdition,
+others are predestined to salvation.</p>
+
+<p class="entry"><span class="def">republic</span>, <span class="pos">n.</span> A
+nation in which, the thing governing and the thing governed being the same,
+there is only a permitted authority to enforce an optional obedience. In a
+republic, the foundation of public order is the ever lessening habit of
+submission inherited from ancestors who, being truly governed, submitted
+because they had to. There are as many kinds of republics as there are
+graduations between the despotism whence they came and the anarchy whither they
+lead.</p>
+
+<p class="entry"><span class="def">requiem</span>, <span class="pos">n.</span> A mass
+for the dead which the minor poets assure us the winds sing o’er the graves of
+their favorites. Sometimes, by way of providing a varied entertainment, they sing a dirge.</p>
+
+<p class="entry"><span class="def">resident</span>, <span class="pos">adj.</span> Unable
+to leave.</p>
+
+<p class="entry"><span class="def">resign</span>, <span class="pos">v.t.</span> To
+renounce an honor for an advantage. To renounce an advantage for a greater advantage.</p>
+
+<div class="poem">
+<p class="poetry">‘Twas rumored Leonard Wood had signed</p>
+<p class="poetry">A true renunciation</p>
+<p class="poetry">Of title, rank and every kind</p>
+<p class="poetry">Of military station—</p>
+<p class="poetry">Each honorable station.</p>
+<p class="poetry">By his example fired—inclined</p>
+<p class="poetry">To noble emulation,</p>
+<p class="poetry">The country humbly was resigned</p>
+<p class="poetry">To Leonard’s resignation—</p>
+<p class="poetry">His Christian resignation.</p>
+<p class="citeauth">Politian Greame</p>
+</div>
+
+<p class="entry"><span class="def">resolute</span>, <span class="pos">adj.</span> Obstinate
+in a course that we approve.</p>
+
+<p class="entry"><span class="def">respectability</span>, <span class="pos">n.</span>
+The offspring of a <i>liaison</i> between a bald head and a bank account.</p>
+
+<p class="entry"><span class="def">respirator</span>, <span class="pos">n.</span> An
+apparatus fitted over the nose and mouth of an inhabitant of London, whereby to
+filter the visible universe in its passage to the lungs.</p>
+
+<p class="entry"><span class="def">respite</span>, <span class="pos">n.</span> A
+suspension of hostilities against a sentenced assassin, to enable the Executive
+to determine whether the murder may not have been done by the prosecuting
+attorney. Any break in the continuity of a disagreeable expectation.</p>
+
+<div class="poem">
+<p class="poetry">Altgeld upon his incandescend bed</p>
+<p class="poetry">Lay, an attendant demon at his head.</p>
+<p class="poetry">“O cruel cook, pray grant me some relief—</p>
+<p class="poetry">Some respite from the roast, however brief.”</p>
+<p class="poetry">“Remember how on earth I pardoned all Your friends in Illinois when held in thrall.”</p>
+<p class="poetry">“Unhappy soul! for that alone you squirm O’er fire unquenched, a never-dying worm.</p>
+<p class="poetry">“Yet, for I pity your uneasy state,</p>
+<p class="poetry">Your doom I’ll mollify and pains abate.</p>
+<p class="poetry">“Naught, for a season, shall your comfort mar,</p>
+<p class="poetry">Not even the memory of who you are.”</p>
+<p class="poetry">Throughout eternal space dread silence fell;</p>
+<p class="poetry">Heaven trembled as Compassion entered Hell.</p>
+<p class="poetry">“As long, sweet demon, let my respite be As, governing down here, I’d respite thee.”</p>
+<p class="poetry">“As long, poor soul, as any of the pack You thrust from jail consumed in getting back.”</p>
+<p class="poetry">A genial chill affected Altgeld’s hide While they were turning him on t’other side.</p>
+<p class="citeauth">Joel Spate Woop</p>
+</div>
+
+<p class="entry"><span class="def">resplendent</span>, <span class="pos">adj.</span> Like
+a simple American citizen beduking himself in his lodge, or affirming his
+consequence in the Scheme of Things as an elemental unit of a parade.</p>
+
+<p class="cite">The Knights of
+Dominion were so resplendent in their velvet- and-gold that their masters would
+hardly have known them. “Chronicles of the Classes”</p>
+
+<p class="entry"><span class="def">respond</span>, <span class="pos">v.i.</span> To
+make answer, or disclose otherwise a consciousness of having inspired an interest
+in what Herbert Spencer calls “external coexistences,” as Satan “squat like a
+toad” at the ear of Eve, responded to the touch of the angel’s spear. To
+respond in damages is to contribute to the maintenance of the plaintiff’s
+attorney and, incidentally, to the gratification of the plaintiff.</p>
+
+<p class="entry"><span class="def">responsibility</span>, <span class="pos">n.</span>
+A detachable burden easily shifted to the shoulders of God, Fate, Fortune, Luck
+or one’s neighbor. In the days of astrology it was customary to unload it upon a star.</p>
+
+<div class="poem">
+<p class="poetry">Alas, things ain’t what we should see</p>
+<p class="poetry">If Eve had let that apple be;</p>
+<p class="poetry">And many a feller which had ought</p>
+<p class="poetry">To set with monarchses of thought,</p>
+<p class="poetry">Or play some rosy little game</p>
+<p class="poetry">With battle-chaps on fields of fame,</p>
+<p class="poetry">Is downed by his unlucky star</p>
+<p class="poetry">And hollers: “Peanuts!&#8212;here you are!”</p>
+<p class="citeauth">“The Sturdy Beggar”</p>
+</div>
+
+<p class="entry"><span class="def">restitutions</span>, <span class="pos">n.</span> The
+founding or endowing of universities and public libraries by gift or bequest.</p>
+
+<p class="entry"><span class="def">restitutor</span>, <span class="pos">n.</span> Benefactor;
+philanthropist.</p>
+
+<p class="entry"><span class="def">retaliation</span>, <span class="pos">n.</span> The
+natural rock upon which is reared the Temple of Law.</p>
+
+<p class="entry"><span class="def">retribution</span>, <span class="pos">n.</span> A
+rain of fire-and-brimstone that falls alike upon the just and such of the
+unjust as have not procured shelter by evicting them.</p>
+
+<p>In the lines following, addressed to an Emperor in exile by Father Gassalasca Jape, the
+reverend poet appears to hint his sense of the improduence of turning about to
+face Retribution when it is talking exercise:</p>
+
+<p>What, what! Dom Pedro, you desire to go</p>
+
+<p>Back to Brazil to end your days in quiet?</p>
+
+<p>Why, what assurance have you ‘twould be so?</p>
+
+<p>‘Tis not so long since you were in a riot,</p>
+
+<p>And your dear subjects showed a will to fly at</p>
+
+<p>Your throat and shake you like a rat. You know That empires are ungrateful; are you certain
+Republics are less handy to get hurt in?</p>
+
+<p class="entry"><span class="def">reveille</span>, <span class="pos">n.</span> A
+signal to sleeping soldiers to dream of battlefields no more, but get up and
+have their blue noses counted. In the American army it is ingeniously called
+“rev-e-lee,” and to that pronunciation our countrymen have pledged their lives,
+their misfortunes and their sacred dishonor.</p>
+
+<p class="entry"><span class="def">revelation</span>, <span class="pos">n.</span> A
+famous book in which St. John the Divine concealed all that he knew. The
+revealing is done by the commentators, who know nothing.</p>
+
+<p class="entry"><span class="def">reverence</span>, <span class="pos">n.</span> The
+spiritual attitude of a man to a god and a dog to a man.</p>
+
+<p class="entry"><span class="def">review</span>, <span class="pos">v.t.</span></p>
+
+<div class="poem">
+<p class="poetry">To set your wisdom (holding not a doubt of it,</p>
+<p class="poetry">Although in truth there’s neither bone nor skin to it)</p>
+<p class="poetry">At work upon a book, and so read out of it</p>
+<p class="poetry">The qualities that you have first read into it.</p>
+</div>
+
+<p class="entry"><span class="def">revolution</span>, <span class="pos">n.</span> In
+politics, an abrupt change in the form of misgovernment. Specifically, in
+American history, the substitution of the rule of an Administration for that of
+a Ministry, whereby the welfare and happiness of the people were advanced a
+full half-inch. Revolutions are usually accompanied by a considerable effusion
+of blood, but are accounted worth it—this appraisement being made by
+beneficiaries whose blood had not the mischance to be shed. The French
+revolution is of incalculable value to the Socialist of to-day; when he pulls
+the string actuating its bones its gestures are inexpressibly terrifying to
+gory tyrants suspected of fomenting law and order.</p>
+
+<p class="entry"><span class="def">rhadomancer</span>, <span class="pos">n.</span> One
+who uses a divining-rod in prospecting for precious metals in the pocket of a fool.</p>
+
+<p class="entry"><span class="def">ribaldry</span>, <span class="pos">n.</span> Censorious
+language by another concerning oneself.</p>
+
+<p class="entry"><span class="def">ribroaster</span>, <span class="pos">n.</span> Censorious
+language by oneself concerning another. The word is of classical refinement,
+and is even said to have been used in a fable by Georgius Coadjutor, one of the
+most fastidious writers of the fifteenth century—commonly, indeed, regarded as
+the founder of the Fastidiotic School.</p>
+
+<p class="entry"><span class="def">rice-water</span>, <span class="pos">n.</span> A
+mystic beverage secretly used by our most popular novelists and poets to
+regulate the imagination and narcotize the conscience. It is said to be rich in
+both obtundite and lethargine, and is brewed in a midnight fog by a fat which
+of the Dismal Swamp.</p>
+
+<p id="rich" class="entry"><span class="def">rich</span>, <span class="pos">adj.</span> Holding
+in trust and subject to an accounting the property of the indolent, the
+incompetent, the unthrifty, the envious and the luckless. That is the view that
+prevails in the underworld, where the Brotherhood of Man finds its most logical
+development and candid advocacy. To denizens of the midworld the word means
+good and wise.</p>
+
+<p class="entry"><span class="def">riches</span>, <span class="pos">n.</span></p>
+
+<p class="cite">A gift from Heaven signifying, “This is my beloved son, in whom I am well pleased.” John D. Rockefeller</p>
+
+<p class="cite">The reward of toil and virtue. J.P. Morgan</p>
+
+<p class="cite">The sayings of many in the hands of one. Eugene Debs</p>
+
+<p class="indentpara">To these excellent definitions the inspired lexicographer feels that he can add nothing of value.</p>
+
+<p class="entry"><span class="def">ridicule</span>, <span class="pos">n.</span> Words
+designed to show that the person of whom they are uttered is devoid of the
+dignity of character distinguishing him who utters them. It may be graphic,
+mimetic or merely rident. Shaftesbury is quoted as having pronounced it the
+test of truth—a ridiculous assertion, for many a solemn fallacy has undergone
+centuries of ridicule with no abatement of its popular acceptance. What, for
+example, has been more valorously derided than the doctrine of Infant
+Respectability?</p>
+
+<p class="entry"><span class="def">right</span>, <span class="pos">n.</span> Legitimate
+authority to be, to do or to have; as the right to be a king, the right to do
+one’s neighbor, the right to have measles, and the like. The first of these
+rights was once universally believed to be derived directly from the will of
+God; and this is still sometimes affirmed <i>in
+partibus infidelium</i> outside the enlightened realms of Democracy; as
+the well known lines of Sir Abednego Bink, following:</p>
+
+<div class="poem">
+<p class="poetry">By what right, then, do royal rulers rule?</p>
+<p class="poetry">Whose is the sanction of their state and pow’r?</p>
+<p class="poetry">He surely were as stubborn as a mule</p>
+<p class="poetry">Who, God unwilling, could maintain an hour
+His uninvited session on the throne, or air
+His pride securely in the Presidential chair.</p>
+<p class="poetry">Whatever is is so by Right Divine;</p>
+<p class="poetry">Whate’er occurs, God wills it so. Good land!</p>
+<p class="poetry">It were a wondrous thing if His design</p>
+<p class="poetry">A fool could baffle or a rogue withstand!</p>
+<p class="poetry">If so, then God, Isay (intending no offence)</p>
+<p class="poetry">Is guilty of contributory negligence.</p>
+</div>
+
+<p class="entry"><span class="def">righteousness</span>, <span class="pos">n.</span> A
+sturdy virtue that was once found among the Pantidoodles inhabiting the lower
+part of the peninsula of Oque. Some feeble attempts were made by returned
+missionaries to introduce it into several European countries, but it appears to
+have been imperfectly expounded. An example of this faulty exposition is found
+in the only extant sermon of the pious Bishop Rowley, a characteristic passage
+from which is here given:</p>
+
+<p>“Now righteousness consisteth not merely in a holy state of mind, nor yet in performance of
+religious rites and obedience to the letter of the law. It is not enough that
+one be pious and just: one must see to it that others also are in the same
+state; and to this end compulsion is a proper means. Forasmuch as my injustice
+may work ill to another, so by his injustice may evil be wrought upon still
+another, the which it is as manifestly my duty to estop as to forestall mine
+own tort. Wherefore if I would be righteous I am bound to restrain my neighbor,
+by force if needful, in all those injurious enterprises from which, through a
+better disposition and by the help of Heaven, I do myself restrain.”</p>
+
+<p class="entry"><span class="def">rime</span>, <span class="pos">n.</span> Agreeing
+sounds in the terminals of verse, mostly bad. The verses themselves, as
+distinguished from prose, mostly dull. Usually (and wickedly) spelled “rhyme.”</p>
+
+<div class="poem">
+<p class="entry"><span class="def">rimer</span>, <span class="pos">n.</span> A poet
+regarded with indifference or disesteem.</p>
+<p class="poetry">The rimer quenches his unheeded fires,<br />
+The sound surceases and the sense expires.<br />
+Then the domestic dog, to east and west,<br />
+Expounds the passions burning in his breast.</p>
+<p class="poetry">The rising moon o’er that enchanted land</p>
+<p class="poetry">Pauses to hear and yearns to understand.</p>
+<p class="citeauth">Mowbray Myles</p>
+</div>
+
+<p class="entry"><span class="def">riot</span>, <span class="pos">n.</span> A popular
+entertainment given to the military by innocent bystanders.</p>
+
+<p class="entry"><span class="def">R.I.P.</span> A careless abbreviation of <i>requiescat in pace</i>,
+attesting to indolent goodwill to the dead. According to the learned Dr.
+Drigge, however, the letters originally meant nothing more than <i>reductus in pulvis</i>.</p>
+
+<p class="entry"><span class="def">riteE</span>, <span class="pos">n.</span> A
+religious or semi-religious ceremony fixed by law, precept or custom, with the
+essential oil of sincerity carefully squeezed out of it.</p>
+
+<p class="entry"><span class="def">ritualism</span>, <span class="pos">n.</span> A
+Dutch Garden of God where He may walk in rectilinear freedom, keeping off the
+grass.</p>
+
+<p class="entry"><span class="def">road</span>, <span class="pos">n.</span> A strip
+of land along which one may pass from where it is too tiresome to be to where
+it is futile to go.</p>
+
+<div class="poem">
+<p class="poetry">All roads, howsoe’er they diverge, lead to Rome,<br />
+Whence, thank the good Lord, at least one leads back home.</p>
+<p class="citeauth">Borey the Bald</p>
+</div>
+
+<p class="entry"><span class="def">robber</span>, <span class="pos">n.</span> A
+candid man of affairs.</p>
+
+<p class="indentpara">It is related of Voltaire that one night he and some traveling companion lodged at a wayside
+inn. The surroundings were suggestive, and after supper they agreed to tell
+robber stories in turn. “Once there was a Farmer-General of the Revenues.” Saying
+nothing more, he was encouraged to continue. “That,” he said, “is the story.”</p>
+
+<p class="entry"><span class="def">romance</span>, <span class="pos">n.</span> Fiction
+that owes no allegiance to the God of Things as They Are. In the novel the
+writer’s thought is tethered to probability, as a domestic horse to the
+hitching-post, but in romance it ranges at will over the entire region of the
+imagination—free, lawless, immune to bit and rein. Your novelist is a poor
+creature, as Carlyle might say—a mere reporter. He may invent his characters
+and plot, but he must not imagine anything taking place that might not occur,
+albeit his entire narrative is candidly a lie. Why he imposes this hard
+condition on himself, and “drags at each remove a lengthening chain” of his own
+forging he can explain in ten thick volumes without illuminating by so much as
+a candle’s ray the black profound of his own ignorance of the matter. There are
+great novels, for great writers have “laid waste their powers” to write them,
+but it remains true that far and away the most fascinating fiction that we have
+is “The Thousand and One Nights.”</p>
+
+<p class="entry"><span class="def">rope</span>, <span class="pos">n.</span> An
+obsolescent appliance for reminding assassins that they too are mortal. It is
+put about the neck and remains in place one’s whole life long. It has been
+largely superseded by a more complex electrical device worn upon another part
+of the person; and this is rapidly giving place to an apparatus known as the
+preachment.</p>
+
+<p class="entry"><span class="def">rostrum</span>, <span class="pos">n.</span> In
+Latin, the beak of a bird or the prow of a ship. In America, a place from which
+a candidate for office energetically expounds the wisdom, virtue and power of
+the rabble.</p>
+
+<p class="entry"><span class="def">roundhead</span>, <span class="pos">n.</span> A
+member of the Parliamentarian party in the English civil war—so called from his
+habit of wearing his hair short, whereas his enemy, the Cavalier, wore his
+long. There were other points of difference between them, but the fashion in
+hair was the fundamental cause of quarrel. The Cavaliers were royalists because
+the king, an indolent fellow, found it more convenient to let his hair grow
+than to wash his neck. This the Roundheads, who were mostly barbers and
+soap-boilers, deemed an injury to trade, and the royal neck was therefore the
+object of their particular indignation. Descendants of the belligerents now
+wear their hair all alike, but the fires of animosity enkindled in that ancient
+strife smoulder to this day beneath the snows of British civility.</p>
+
+<p class="entry"><span class="def">rubbish</span>, <span class="pos">n.</span> Worthless
+matter, such as the religions, philosophies, literatures, arts and sciences of
+the tribes infesting the regions lying due south from Boreaplas.</p>
+
+<p class="entry"><span class="def">ruin</span>, <span class="pos">v.</span> To
+destroy. Specifically, to destroy a maid’s belief in the virtue of maids.</p>
+
+<p class="entry"><span class="def">rum</span>, <span class="pos">n.</span> Generically,
+fiery liquors that produce madness in total abstainers.</p>
+
+<p class="entry"><span class="def">rumor</span>, <span class="pos">n.</span> A
+favorite weapon of the assassins of character.</p>
+
+<div class="poem">
+<p class="poetry">Sharp, irresistible by mail or shield,</p>
+<p class="poetry">By guard unparried as by flight unstayed,</p>
+<p class="poetry">O serviceable Rumor, let me wield</p>
+<p class="poetry">Against my enemy no other blade.</p>
+<p class="poetry">His be the terror of a foe unseen,</p>
+<p class="poetry">His the inutile hand upon the hilt,</p>
+<p class="poetry">And mine the deadly tongue, long, slender, keen,</p>
+<p class="poetry">Hinting a rumor of some ancient guilt. So shall I slay the wretch without a blow, Spare me to
+celebrate his overthrow, And nurse my valor for another foe.</p>
+<p class="citeauth">Joel Buxter</p>
+</div>
+
+<p class="entry"><span class="def">Russian</span>, <span class="pos">n.</span> A
+person with a Caucasian body and a Mongolian soul. A Tartar Emetic.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/R.html.i
@@ -1,0 +1,53 @@
+24 pages
+size 400 552
+length 38788
+396 2 10 body html
+0
+1895 2 45 body html
+0
+3733 2 83 body html
+19
+4759 2 108 body html
+0
+6886 2 147 body html
+0
+8507 2 183 body html
+39
+10023 2 211 body html
+0
+12182 2 251 body html
+0
+14402 2 284 body html
+56
+15730 2 304 body html
+252
+17578 2 342 body html
+22
+19605 2 380 body html
+22
+20862 2 407 body html
+0
+21171 2 412 body html
+466
+23582 2 450 body html
+19
+24766 2 475 body html
+68
+26209 2 507 body html
+72
+28293 2 543 body html
+0
+29753 2 569 body html
+90
+31009 2 592 body html
+90
+32478 2 614 body html
+222
+34691 2 659 body html
+22
+36424 2 686 body html
+124
+37953 2 711 body html
+288
+religion 7
+rich 16
--- /dev/null
+++ b/lib/ebooks/devils/S.html
@@ -1,0 +1,844 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: S</title>
+</head>
+<body lang="en-US">
+
+
+<h1>S</h1>
+
+<p class="entry"><span class="def">Sabbath</span>, <span class="pos">n.</span> A
+weekly festival having its origin in the fact that God made the world in six
+days and was arrested on the seventh. Among the Jews observance of the day was
+enforced by a Commandment of which this is the Christian version: “Remember the
+seventh day to make thy neighbor keep it wholly.” To the Creator it seemed fit
+and expedient that the Sabbath should be the last day of the week, but the
+Early Fathers of the Church held other views. So great is the sanctity of the
+day that even where the Lord holds a doubtful and precarious jurisdiction over
+those who go down to (and down into) the sea it is reverently recognized, as is
+manifest in the following deep-water version of the Fourth Commandment:</p>
+
+<p>Six days shalt thou labor and do all thou art able, And on the seventh holystone the deck and
+scrape the cable.</p>
+
+<p>Decks are no longer holystoned, but the cable still supplies the captain with opportunity to
+attest a pious respect for the divine ordinance.</p>
+
+<p class="entry"><span class="def">sacerdotalist</span>, <span class="pos">n.</span> One
+who holds the belief that a clergyman is a priest. Denial of this momentous
+doctrine is the hardest challenge that is now flung into the teeth of the
+Episcopalian church by the Neo-Dictionarians.</p>
+
+<p class="entry"><span class="def">sacrament</span>, <span class="pos">n.</span> A
+solemn religious ceremony to which several degrees of authority and
+significance are attached. Rome has seven sacraments, but the Protestant
+churches, being less prosperous, feel that they can afford only two, and these
+of inferior sanctity. Some of the smaller sects have no sacraments at all—for
+which mean economy they will indubitable be damned.</p>
+
+<p class="entry"><span class="def">sacred</span>, <span class="pos">adj.</span> Dedicated
+to some religious purpose; having a divine character; inspiring solemn thoughts
+or emotions; as, the Dalai Lama of Thibet; the Moogum of M’bwango; the temple
+of Apes in Ceylon; the Cow in India; the Crocodile, the Cat and the Onion of
+ancient Egypt; the Mufti of Moosh; the hair of the dog that bit Noah, etc.</p>
+
+<div class="poem">
+<p class="poetry">All things are either sacred or profane.</p>
+<p class="poetry">The former to ecclesiasts bring gain;</p>
+<p class="poetry">The latter to the devil appertain.</p>
+<p class="citeauth">Dumbo Omohundro</p>
+</div>
+
+<p class="entry"><span class="def">sandlotter</span>, <span class="pos">n.</span> A
+vertebrate mammal holding the political views of Denis Kearney, a notorious
+demagogue of San Francisco, whose audiences gathered in the open spaces
+(sandlots) of the town. True to the traditions of his species, this leader of
+the proletariat was finally bought off by his law-and-order enemies, living
+prosperously silent and dying impenitently rich. But before his treason he
+imposed upon California a constitution that was a confection of sin in a
+diction of solecisms. The similarity between the words “sandlotter” and
+“sansculotte” is problematically significant, but indubitably suggestive.</p>
+
+<p class="entry"><span class="def">safety-clutch</span>, <span class="pos">n.</span> A
+mechanical device acting automatically to prevent the fall of an elevator, or
+cage, in case of an accident to the hoisting apparatus.</p>
+
+<div class="poem">
+<p class="poetry">Once I seen a human ruin</p>
+<p class="poetry">In an elevator-well,</p>
+<p class="poetry">And his members was bestrewin’</p>
+<p class="poetry">All the place where he had fell.</p>
+<p class="poetry">And I says, apostrophisin’</p>
+<p class="poetry">That uncommon woful wreck:</p>
+<p class="poetry">“Your position’s so surprisin’</p>
+<p class="poetry">That I tremble for your neck!”</p>
+<p class="poetry">Then that ruin, smilin’ sadly</p>
+<p class="poetry">And impressive, up and spoke:</p>
+<p class="poetry">“Well, I wouldn’t tremble badly,</p>
+<p class="poetry">For it’s been a fortnight broke.”</p>
+<p class="poetry">Then, for further comprehension</p>
+<p class="poetry">Of his attitude, he begs</p>
+<p class="poetry">I will focus my attention</p>
+<p class="poetry">On his various arms and legs—</p>
+<p class="poetry">How they all are contumacious;</p>
+<p class="poetry">Where they each, respective, lie;</p>
+<p class="poetry">How one trotter proves ungracious,</p>
+<p class="poetry">T’other one an <i>alibi</i>.</p>
+<p class="poetry">These particulars is mentioned</p>
+<p class="poetry">For to show his dismal state,</p>
+<p class="poetry">Which I wasn’t first intentioned</p>
+<p class="poetry">To specifical relate.</p>
+<p class="poetry">None is worser to be dreaded</p>
+<p class="poetry">That I ever have heard tell</p>
+<p class="poetry">Than the gent’s who there was spreaded</p>
+<p class="poetry">In that elevator-well.</p>
+<p class="poetry">Now this tale is allegoric—</p>
+<p class="poetry">It is figurative all,</p>
+<p class="poetry">For the well is metaphoric</p>
+<p class="poetry">And the feller didn’t fall.</p>
+<p class="poetry">I opine it isn’t moral</p>
+<p class="poetry">For a writer-man to cheat,</p>
+<p class="poetry">And despise to wear a laurel</p>
+<p class="poetry">As was gotten by deceit.</p>
+<p class="poetry">For ‘tis Politics intended</p>
+<p class="poetry">By the elevator, mind,</p>
+<p class="poetry">It will boost a person splendid</p>
+<p class="poetry">If his talent is the kind.</p>
+<p class="poetry">Col. Bryan had the talent</p>
+<p class="poetry">(For the busted man is him)</p>
+<p class="poetry">And it shot him up right gallant</p>
+<p class="poetry">Till his head begun to swim.</p>
+<p class="poetry">Then the rope it broke above him</p>
+<p class="poetry">And he painful come to earth</p>
+<p class="poetry">Where there’s nobody to love him</p>
+<p class="poetry">For his detrimented worth.</p>
+<p class="poetry">Though he’s livin’ none would know him,</p>
+<p class="poetry">Or at leastwise not as such.</p>
+<p class="poetry">Moral of this woful poem:</p>
+<p class="poetry">Frequent oil your safety-clutch.</p>
+<p class="citeauth">Porfer Poog</p>
+</div>
+
+<p class="entry"><span class="def">saint</span>, <span class="pos">n.</span> A dead
+sinner revised and edited.</p>
+
+<p class="indentpara">The Duchess of Orleans relates that the irreverent old calumniator, Marshal Villeroi, who in
+his youth had known St. Francis de Sales, said, on hearing him called saint: “I
+am delighted to hear that Monsieur de Sales is a saint. He was fond of saying
+indelicate things, and used to cheat at cards. In other respects he was a
+perfect gentleman, though a fool.”</p>
+
+<p class="entry"><span class="def">salacity</span>, <span class="pos">n.</span> A
+certain literary quality frequently observed in popular novels, especially in
+those written by women and young girls, who give it another name and think that
+in introducing it they are occupying a neglected field of letters and reaping
+an overlooked harvest. If they have the misfortune to live long enough they are
+tormented with a desire to burn their sheaves.</p>
+
+<p class="entry"><span class="def">salamander</span>, <span class="pos">n.</span> Originally
+a reptile inhabiting fire; later, an anthropomorphous immortal, but still a pyrophile.
+Salamanders are now believed to be extinct, the last one of which we have an
+account having been seen in Carcassonne by the Abbe Belloc, who exorcised it
+with a bucket of holy water.</p>
+
+<p class="entry"><span class="def">sarcophagus</span>, <span class="pos">n.</span> Among
+the Greeks a coffin which being made of a certain kind of carnivorous stone,
+had the peculiar property of devouring the body placed in it. The sarcophagus
+known to modern obsequiographers is commonly a product of the carpenter’s art.</p>
+
+<p class="entry"><span class="def">Satan</span>, <span class="pos">n.</span> One of
+the Creator’s lamentable mistakes, repented in sashcloth and axes. Being
+instated as an archangel, Satan made himself multifariously objectionable and
+was finally expelled from Heaven. Halfway in his descent he paused, bent his
+head in thought a moment and at last went back. “There is one favor that I
+should like to ask,” said he.</p>
+<p>“Name it.”</p>
+<p>“Man, I understand, is about to be created. He will need laws.”</p>
+<p>“What, wretch! you his appointed adversary, charged from the dawn </p>
+<p>of eternity with hatred of his soul—you ask for the right to make his laws?”</p>
+<p>“Pardon; what I have to ask is that he be permitted to make them himself.”</p>
+<p>It was so ordered.</p>
+
+<p class="entry"><span class="def">satiety</span>, <span class="pos">n.</span> The
+feeling that one has for the plate after he has eaten its contents, madam.</p>
+
+<p class="entry"><span class="def">satire</span>, <span class="pos">n.</span> An
+obsolete kind of literary composition in which the vices and follies of the
+author’s enemies were expounded with imperfect tenderness. In this country
+satire never had more than a sickly and uncertain existence, for the soul of it
+is wit, wherein we are dolefully deficient, the humor that we mistake for it,
+like all humor, being tolerant and sympathetic. Moreover, although Americans
+are “endowed by their Creator” with abundant vice and folly, it is not
+generally known that these are reprehensible qualities, wherefore the satirist
+is popularly regarded as a soul-spirited knave, and his ever victim’s outcry
+for codefendants evokes a national assent.</p>
+
+<div class="poem">
+<p class="poetry">Hail Satire! be thy praises ever sung</p>
+In the dead language of a mummy’s tongue,<br />
+For thou thyself art dead, and damned as well—<br />
+Thy spirit (usefully employed) in Hell.<br />
+Had it been such as consecrates the Bible<br />
+Thou hadst not perished by the law of libel.<br />
+<p class="citeauth">Barney Stims</p>
+</div>
+
+<p class="entry"><span class="def">satyr</span>, <span class="pos">n.</span> One of
+the few characters of the Grecian mythology accorded recognition in the Hebrew.
+(Leviticus, xvii, 7.) The satyr was at first a member of the dissolute
+community acknowledging a loose allegiance with Dionysius, but underwent many
+transformations and improvements. Not infrequently he is confounded with the
+faun, a later and decenter creation of the Romans, who was less like a man and more
+like a goat.</p>
+
+<p class="entry"><span class="def">sauce</span>, <span class="pos">n.</span> The one
+infallible sign of civilization and enlightenment. A people with no sauces has
+one thousand vices; a people with one sauce has only nine hundred and
+ninety-nine. For every sauce invented and accepted a vice is renounced and
+forgiven.</p>
+
+<p class="entry"><span class="def">saw</span>, <span class="pos">n.</span> A trite
+popular saying, or proverb. (Figurative and colloquial.) So called because it
+makes its way into a wooden head. Following are examples of old saws fitted
+with new teeth.</p>
+
+<div class="poem">
+<p class="poetry">A penny saved is a penny to squander.</p>
+<p class="poetry">A man is known by the company that he organizes.</p>
+<p class="poetry">A bad workman quarrels with the man who calls him that.</p>
+<p class="poetry">A bird in the hand is worth what it will bring.</p>
+<p class="poetry">Better late than before anybody has invited you.</p>
+<p class="poetry">Example is better than following it.</p>
+<p class="poetry">Half a loaf is better than a whole one if there is much else.</p>
+<p class="poetry">Think twice before you speak to a friend in need.</p>
+<p class="poetry">What is worth doing is worth the trouble of asking somebody to do it.</p>
+<p class="poetry">Least said is soonest disavowed.</p>
+<p class="poetry">He laughs best who laughs least.</p>
+<p class="poetry">Speak of the Devil and he will hear about it.</p>
+<p class="poetry">Of two evils choose to be the least.</p>
+<p class="poetry">Strike while your employer has a big contract.</p>
+<p class="poetry">Where there’s a will there’s a won’t.</p>
+</div>
+
+<p class="entry"><span class="def">Sacrabaeus</span>, <span class="pos">n.</span> The
+sacred beetle of the ancient Egyptians, allied to our familiar “tumble-bug.” It
+was supposed to symbolize immortality, the fact that God knew why giving it its
+peculiar sanctity. Its habit of incubating its eggs in a ball of ordure may
+also have commended it to the favor of the priesthood, and may some day assure
+it an equal reverence among ourselves. True, the American beetle is an inferior
+beetle, but the American priest is an inferior priest.</p>
+
+<p class="entry"><span class="def">Scarabee</span>, <span class="pos">n.</span> The
+same as scarabaeus.</p>
+
+<div class="poem">
+<p class="poetry">He fell by his own hand<br />
+Beneath the great oak tree.<br />
+He’d traveled in a foreign land.<br />
+He tried to make her understand<br />
+The dance that’s called the Saraband,<br />
+But he called it Scarabee.<br />
+He had called it so through an afternoon,<br />
+And she, the light of his harem if so might be,<br />
+Had smiled and said naught. O the body was fair to see,<br />
+All frosted there in the shine o’ the moon—<br />
+Dead for a Scarabee And a recollection that came too late.<br />
+O Fate!<br />
+They buried him where he lay,<br />
+He sleeps awaiting the Day,<br />
+In state, And two Possible Puns, moon-eyed and wan,<br />
+Gloom over the grave and then move on.<br />
+Dead for a Scarabee!</p>
+<p class="citeauth">Fernando Tapple</p>
+</div>
+
+<p class="entry"><span class="def">scarification</span>, <span class="pos">n.</span> A
+form of penance practised by the mediaeval pious. The rite was performed,
+sometimes with a knife, sometimes with a hot iron, but always, says Arsenius
+Asceticus, acceptably if the penitent spared himself no pain nor harmless
+disfigurement. Scarification, with other crude penances, has now been
+superseded by benefaction. The founding of a library or endowment of a
+university is said to yield to the penitent a sharper and more lasting pain
+than is conferred by the knife or iron, and is therefore a surer means of
+grace. There are, however, two grave objections to it as a penitential method: the
+good that it does and the taint of justice.</p>
+
+<p class="entry"><span class="def">scepter</span>, <span class="pos">n.</span> A
+king’s staff of office, the sign and symbol of his authority. It was originally
+a mace with which the sovereign admonished his jester and vetoed ministerial
+measures by breaking the bones of their proponents.</p>
+
+<p class="entry"><span class="def">scimetar</span>, <span class="pos">n.</span> A
+curved sword of exceeding keenness, in the conduct of which certain Orientals
+attain a surprising proficiency, as the incident here related will serve to
+show. The account is translated from the Japanese by Shusi Itama, a famous
+writer of the thirteenth century.</p>
+
+<p class="indentpara">When the great Gichi-Kuktai was Mikado he condemned to decapitation Jijiji Ri, a high officer
+of the Court. Soon after the hour appointed for performance of the rite what
+was his Majesty’s surprise to see calmly approaching the throne the man who
+should have been at that time ten minutes dead!</p>
+
+<p class="indentpara">“Seventeen hundred impossible dragons!” shouted the enraged monarch. “Did I not sentence you to
+stand in the market-place and have your head struck off by the public
+executioner at three o’clock? And is it not now 3:10?”</p>
+
+<p class="indentpara">“Son of a thousand illustrious deities,” answered the condemned minister, “all that you say is so
+true that the truth is a lie in comparison. But your heavenly Majesty’s sunny
+and vitalizing wishes have been pestilently disregarded. With joy I ran and
+placed my unworthy body in the market-place. The executioner appeared with his
+bare scimetar, ostentatiously whirled it in air, and then, tapping me lightly
+upon the neck, strode away, pelted by the populace, with whom I was ever a
+favorite. I am come to pray for justice upon his own dishonorable and
+treasonous head.”</p>
+
+<p class="indentpara">“To what regiment
+of executioners does the black-boweled caitiff belong?” asked the Mikado.</p>
+
+<p class="indentpara">“To the gallant Ninety-eight Hundred and Thirty-seventh—I know the man. His name is
+Sakko-Samshi.”</p>
+
+<p class="indentpara">“Let him be
+brought before me,” said the Mikado to an attendant, and a half-hour later the
+culprit stood in the Presence.</p>
+
+<p class="indentpara">“Thou bastard son
+of a three-legged hunchback without thumbs!” roared the sovereign—“why didst
+thou but lightly tap the neck that it should have been thy pleasure to sever?”</p>
+
+<p class="indentpara">“Lord of Cranes of
+Cherry Blooms,” replied the executioner, unmoved, “command him to blow his nose
+with his fingers.”</p>
+
+<p class="indentpara">Being commanded,
+Jijiji Ri laid hold of his nose and trumpeted like an elephant, all expecting
+to see the severed head flung violently from him. Nothing occurred: the
+performance prospered peacefully to the close, without incident.</p>
+
+<p class="indentpara">All eyes were now
+turned on the executioner, who had grown as white as the snows on the summit of
+Fujiama. His legs trembled and his breath came in gasps of terror.</p>
+
+<p class="indentpara">“Several kinds of
+spike-tailed brass lions!” he cried; “I am a ruined and disgraced swordsman! I
+struck the villain feebly because in flourishing the scimetar I had
+accidentally passed it through my own neck! Father of the Moon, I resign my office.”</p>
+
+<p class="indentpara">So saying, he
+gasped his top-knot, lifted off his head, and advancing to the throne laid it
+humbly at the Mikado’s feet.</p>
+
+<p class="entry"><span class="def">scrap-book</span>, <span class="pos">n.</span> A
+book that is commonly edited by a fool. Many persons of some small distinction
+compile scrap-books containing whatever they happen to read about themselves or
+employ others to collect. One of these egotists was addressed in the lines
+following, by Agamemnon Melancthon Peters:</p>
+
+<div class="poem">
+<p class="poetry">Dear Frank, that scrap-book where you boast<br />
+You keep a record true<br />
+Of every kind of peppered roast<br />
+That’s made of you;<br />
+Wherein you paste the printed gibes<br />
+That revel round your name,<br />
+Thinking the laughter of the scribes<br />
+Attests your fame;<br />
+Where all the pictures you arrange<br />
+That comic pencils trace—<br />
+Your funny figure and your strange<br />
+Semitic face—<br />
+Pray lend it me. Wit I have not,<br />
+Nor art, but there I’ll list<br />
+The daily drubbings you’d have got<br />
+Had God a fist.</p>
+</div>
+
+<p class="entry"><span class="def">scribbler</span>, <span class="pos">n.</span> A
+professional writer whose views are antagonistic to one’s own.</p>
+
+<p class="entry"><span class="def">scriptures</span>, <span class="pos">n.</span> The
+sacred books of our holy religion, as distinguished from the false and profane
+writings on which all other faiths are based.</p>
+
+<p class="entry"><span class="def">seal</span>, <span class="pos">n.</span> A mark
+impressed upon certain kinds of documents to attest their authenticity and
+authority. Sometimes it is stamped upon wax, and attached to the paper,
+sometimes into the paper itself. Sealing, in this sense, is a survival of an
+ancient custom of inscribing important papers with cabalistic words or signs to
+give them a magical efficacy independent of the authority that they represent. In
+the British museum are preserved many ancient papers, mostly of a sacerdotal
+character, validated by necromantic pentagrams and other devices, frequently
+initial letters of words to conjure with; and in many instances these are
+attached in the same way that seals are appended now. As nearly every
+reasonless and apparently meaningless custom, rite or observance of modern
+times had origin in some remote utility, it is pleasing to note an example of
+ancient nonsense evolving in the process of ages into something really useful. Our
+word “sincere” is derived from <i>sine cero</i>,
+without wax, but the learned are not in agreement as to whether this refers to
+the absence of the cabalistic signs, or to that of the wax with which letters
+were formerly closed from public scrutiny. Either view of the matter will serve
+one in immediate need of an hypothesis. The initials L.S., commonly appended to
+signatures of legal documents, mean <i>locum sigillis</i>, the place of the seal,
+although the seal is no longer used&#8212;an admirable example of conservatism
+distinguishing Man from the beasts that perish. The words <i>locum sigillis</i> are humbly suggested as a
+suitable motto for the Pribyloff Islands whenever they shall take their place
+as a sovereign State of the American Union.</p>
+
+<p class="entry"><span class="def">seine</span>, <span class="pos">n.</span> A kind
+of net for effecting an involuntary change of environment. For fish it is made
+strong and coarse, but women are more easily taken with a singularly delicate
+fabric weighted with small, cut stones.</p>
+
+<div class="poem">
+<p class="poetry">The devil casting a seine of lace,<br />
+(With precious stones ‘twas weighted)<br />
+Drew it into the landing place<br />
+And its contents calculated.<br />
+All souls of women were in that sack—<br />
+A draft miraculous, precious!<br />
+But ere he could throw it across his back<br />
+They’d all escaped through the meshes.</p>
+<p class="citeauth">Baruch de Loppis</p>
+</div>
+
+<p class="entry"><span class="def">self-esteem</span>, <span class="pos">n.</span> An
+erroneous appraisement.</p>
+
+<p class="entry"><span class="def">self-evident</span>, <span class="pos">adj.</span>
+Evident to one’s self and to nobody else.</p>
+
+<p class="entry"><span class="def">selfish</span>, <span class="pos">adj.</span> Devoid
+of consideration for the selfishness of others.</p>
+
+<p class="entry"><span class="def">senate</span>, <span class="pos">n.</span> A body
+of elderly gentlemen charged with high duties and misdemeanors.</p>
+
+<p class="entry"><span class="def">serial</span>, <span class="pos">n.</span> A
+literary work, usually a story that is not true, creeping through several issues
+of a newspaper or magazine. Frequently appended to each installment is a
+“synposis of preceding chapters” for those who have not read them, but a direr
+need is a synposis of succeeding chapters for those who do not intend to read <i>them</i>. A synposis of the entire work would
+be still better.</p>
+
+<p class="indentpara">The late James F. Bowman was writing a serial tale for a weekly paper in collaboration with a
+genius whose name has not come down to us. They wrote, not jointly but
+alternately, Bowman supplying the installment for one week, his friend for the
+next, and so on, world without end, they hoped. Unfortunately they quarreled,
+and one Monday morning when Bowman read the paper to prepare himself for his
+task, he found his work cut out for him in a way to surprise and pain him. His
+collaborator had embarked every character of the narrative on a ship and sunk
+them all in the deepest part of the Atlantic.</p>
+
+<p class="entry"><span class="def">severalty</span>, <span class="pos">n.</span> Separateness,
+as, lands in severalty, i.e., lands held individually, not in joint ownership. Certain
+tribes of Indians are believed now to be sufficiently civilized to have in
+severalty the lands that they have hitherto held as tribal organizations, and
+could not sell to the Whites for waxen beads and potato whiskey.</p>
+
+<div class="poem">
+<p class="poetry">Lo! the poor Indian whose unsuited mind<br />
+Saw death before, hell and the grave behind;<br />
+Whom thrifty settler ne’er besought to stay—<br />
+His small belongings their appointed prey;<br />
+Whom Dispossession, with alluring wile,<br />
+Persuaded elsewhere every little while!<br />
+His fire unquenched and his undying worm<br />
+By “land in severalty” (charming term!)<br />
+Are cooled and killed, respectively, at last,<br />
+And he to his new holding anchored fast!</p>
+</div>
+
+<p class="entry"><span class="def">sheriff</span>, <span class="pos">n.</span> In
+America the chief executive office of a country, whose most characteristic
+duties, in some of the Western and Southern States, are the catching and
+hanging of rogues.</p>
+
+<div class="poem">
+<p class="poetry">John Elmer Pettibone Cajee<br />
+(I write of him with little glee)<br />
+Was just as bad as he could be.</p>
+
+<p class="poetry">‘Twas frequently remarked: “I swon!<br />
+The sun has never looked upon<br />
+So bad a man as Neighbor John.”</p>
+
+<p class="poetry">A sinner through and through, he had<br />
+This added fault: it made him mad<br />
+To know another man was bad.</p>
+
+<p class="poetry">In such a case he thought it right<br />
+To rise at any hour of night<br />
+And quench that wicked person’s light.</p>
+
+<p class="poetry">Despite the town’s entreaties, he<br />
+Would hale him to the nearest tree<br />
+And leave him swinging wide and free.</p>
+
+<p class="poetry">Or sometimes, if the humor came,<br />
+A luckless wight’s reluctant frame<br />
+Was given to the cheerful flame.</p>
+
+<p class="poetry">While it was turning nice and brown,<br />
+All unconcerned John met the frown<br />
+Of that austere and righteous town.</p>
+
+<p class="poetry">“How sad,” his neighbors said, “that he<br />
+So scornful of the law should be—<br />
+An anar c, h, i, s, t.”</p>
+
+<p class="poetry">(That is the way that they preferred<br />
+To utter the abhorrent word,<br />
+So strong the aversion that it stirred.)</p>
+
+<p class="poetry">“Resolved,” they said, continuing,<br />
+“That Badman John must cease this thing<br />
+Of having his unlawful fling.</p>
+
+<p class="poetry">“Now, by these sacred relics”—here<br />
+Each man had out a souvenir<br />
+Got at a lynching yesteryear—</p>
+
+<p class="poetry">“By these we swear he shall forsake<br />
+His ways, nor cause our hearts to ache<br />
+By sins of rope and torch and stake.</p>
+
+<p class="poetry">“We’ll tie his red right hand until<br />
+He’ll have small freedom to fulfil<br />
+The mandates of his lawless will.”</p>
+
+<p class="poetry">So, in convention then and there,<br />
+They named him Sheriff. The affair<br />
+Was opened, it is said, with prayer.</p>
+<p class="citeauth">J. Milton Sloluck</p>
+</div>
+
+<p class="entry"><span class="def">siren</span>, <span class="pos">n.</span> One of several
+musical prodigies famous for a vain attempt to dissuade Odysseus from a life on
+the ocean wave. Figuratively, any lady of splendid promise, dissembled purpose
+and disappointing performance.</p>
+
+<p class="entry"><span class="def">slang</span>, <span class="pos">n.</span> The
+grunt of the human hog (<i>Pignoramus intolerabilis</i>) with an audible memory. The
+speech of one who utters with his tongue what he thinks with his ear, and feels
+the pride of a creator in accomplishing the feat of a parrot. A means (under
+Providence) of setting up as a wit without a capital of sense.</p>
+
+<p class="entry"><span class="def">smithareen</span>, <span class="pos">n.</span> A
+fragment, a decomponent part, a remain. The word is used variously, but in the
+following verse on a noted female reformer who opposed bicycle-riding by women
+because it “led them to the devil” it is seen at its best:</p>
+
+<div class="poem">
+<p class="poetry">The wheels go round without a sound—<br />
+The maidens hold high revel;<br />
+In sinful mood, insanely gay,<br />
+True spinsters spin adown the way<br />
+From duty to the devil!<br />
+They laugh, they sing, and—ting-a-ling!<br />
+Their bells go all the morning;<br />
+Their lanterns bright bestar the night<br />
+Pedestrians a-warning.<br />
+With lifted hands Miss Charlotte stands,<br />
+Good-Lording and O-mying,<br />
+Her rheumatism forgotten quite,<br />
+Her fat with anger frying.<br />
+She blocks the path that leads to wrath,<br />
+Jack Satan’s power defying.<br />
+The wheels go round without a sound<br />
+The lights burn red and blue and green.<br />
+What’s this that’s found upon the ground?<br />
+Poor Charlotte Smith’s a smithareen!</p>
+<p class="citeauth">John William Yope</p>
+</div>
+
+<p class="entry"><span class="def">sophistry</span>, <span class="pos">n.</span> The
+controversial method of an opponent, distinguished from one’s own by superior
+insincerity and fooling. This method is that of the later Sophists, a Grecian
+sect of philosophers who began by teaching wisdom, prudence, science, art and,
+in brief, whatever men ought to know, but lost themselves in a maze of quibbles
+and a fog of words.</p>
+
+<div class="poem">
+<p class="poetry">His bad opponent’s “facts” he sweeps away, And drags his sophistry to light of day;<br />
+Then swears they’re pushed to madness who resort To falsehood of so desperate a sort.<br />
+Not so; like sods upon a dead man’s breast, He lies most lightly who the least is pressed.</p>
+<p class="citeauth">Polydore Smith</p>
+</div>
+<p class="entry"><span class="def">sorcery</span>, <span class="pos">n.</span> The
+ancient prototype and forerunner of political influence. It was, however,
+deemed less respectable and sometimes was punished by torture and death. Augustine
+Nicholas relates that a poor peasant who had been accused of sorcery was put to
+the torture to compel a confession. After enduring a few gentle agonies the
+suffering simpleton admitted his guilt, but naively asked his tormentors if it
+were not possible to be a sorcerer without knowing it.</p>
+
+<p id="soul" class="entry"><span class="def">soul</span>, <span class="pos">n.</span> A
+spiritual entity concerning which there hath been brave disputation. Plato held
+that those souls which in a previous state of existence (antedating Athens) had
+obtained the clearest glimpses of eternal truth entered into the bodies of
+persons who became philosophers. Plato himself was a philosopher. The souls
+that had least contemplated divine truth animated the bodies of usurpers and
+despots. Dionysius I, who had threatened to decapitate the broad- browed
+philosopher, was a usurper and a despot. Plato, doubtless, was not the first to
+construct a system of philosophy that could be quoted against his enemies;
+certainly he was not the last.</p>
+
+<p class="indentpara">“Concerning the nature of the soul,” saith the renowned author
+of <i>Diversiones Sanctorum</i>, “there hath been hardly more argument
+than that of its place in the body. Mine own belief is that the soul hath her
+seat in the abdomen—in which faith we may discern and interpret a truth
+hitherto unintelligible, namely that the glutton is of all men most devout. He
+is said in the Scripture to ‘make a god of his belly’&#8212;why, then, should he
+not be pious, having ever his Deity with him to freshen his faith? Who so well
+as he can know the might and majesty that he shrines? Truly and soberly, the
+soul and the stomach are one Divine Entity; and such was the belief of Promasius,
+who nevertheless erred in denying it immortality. He had observed that its
+visible and material substance failed and decayed with the rest of the body
+after death, but of its immaterial essence he knew nothing. This is what we
+call the Appetite, and it survives the wreck and reek of mortality, to be
+rewarded or punished in another world, according to what it hath demanded in
+the flesh. The Appetite whose coarse clamoring was for the unwholesome viands
+of the general market and the public refectory shall be cast into eternal
+famine, whilst that which firmly through civilly insisted on ortolans, caviare,
+terrapin, anchovies, <i>pates de foie gras</i>
+and all such Christian comestibles shall flesh its spiritual tooth in the souls
+of them forever and ever, and wreak its divine thirst upon the immortal parts
+of the rarest and richest wines ever quaffed here below. Such is my religious
+faith, though I grieve to confess that neither His Holiness the Pope nor His
+Grace the Archbishop of Canterbury (whom I equally and profoundly revere) will
+assent to its dissemination.”</p>
+
+<p class="entry"><span class="def">spooker</span>, <span class="pos">n.</span> A
+writer whose imagination concerns itself with supernatural phenomena,
+especially in the doings of spooks. One of the most illustrious spookers of our
+time is Mr. William D. Howells, who introduces a well-credentialed reader to as
+respectable and mannerly a company of spooks as one could wish to meet. To the
+terror that invests the chairman of a district school board, the Howells ghost
+adds something of the mystery enveloping a farmer from another township.</p>
+
+<p class="entry"><span class="def">story</span>, <span class="pos">n.</span> A
+narrative, commonly untrue. The truth of the stories here following has,
+however, not been successfully impeached.</p>
+
+<p>One evening Mr. Rudolph Block, of New York, found himself seated at dinner alongside Mr.
+Percival Pollard, the distinguished critic.</p>
+
+<p>“Mr. Pollard,” said he, “my book, <i>The Biography of a Dead
+Cow</i>, is published anonymously, but you can hardly be ignorant of its
+authorship. Yet in reviewing it you speak of it as the work of the Idiot of the
+Century. Do you think that fair criticism?”</p>
+
+<p>“I am very sorry, sir,” replied the critic, amiably, “but it did not occur to me that you really
+might not wish the public to know who wrote it.”</p>
+
+<p>Mr. W.C. Morrow, who used to live in San Jose, California, was addicted to writing ghost stories
+which made the reader feel as if a stream of lizards, fresh from the ice, were
+streaking it up his back and hiding in his hair. San Jose was at that time
+believed to be haunted by the visible spirit of a noted bandit named Vasquez,
+who had been hanged there. The town was not very well lighted, and it is
+putting it mildly to say that San Jose was reluctant to be out o’ nights. One
+particularly dark night two gentlemen were abroad in the loneliest spot within
+the city limits, talking loudly to keep up their courage, when they came upon
+Mr. J.J. Owen, a well-known journalist.</p>
+
+<p>“Why, Owen,” said one, “what brings you here on such a night as this? You told me that this is
+one of Vasquez’ favorite haunts! And you are a believer. Aren’t you afraid to be out?”</p>
+
+<p>“My dear fellow,” the journalist replied with a drear autumnal cadence in his speech, like the
+moan of a leaf-laden wind, “I am afraid to be in. I have one of Will Morrow’s
+stories in my pocket and I don’t dare to go where there is light enough to read it.”</p>
+
+<p>Rear-Admiral Schley and Representative Charles F. Joy were standing near the Peace Monument,
+in Washington, discussing the question, Is success a failure? Mr. Joy suddenly
+broke off in the middle of an eloquent sentence, exclaiming: “Hello! I’ve heard
+that band before. Santlemann’s, I think.”</p>
+
+<p>“I don’t hear any band,” said Schley.</p>
+
+<p>“Come to think, I don’t either,” said Joy; “but I see General </p>
+
+<p>Miles coming down the avenue, and that pageant always affects me in the same way as a brass band. One has to
+scrutinize one’s impressions pretty closely, or one will mistake their origin.”</p>
+
+<p>While the Admiral was digesting this hasty meal of philosophy General Miles passed in review, a
+spectacle of impressive dignity. When the tail of the seeming procession had
+passed and the two observers had recovered from the transient blindness caused
+by its effulgence—</p>
+
+<p>“He seems to be enjoying himself,” said the Admiral.</p>
+
+<p>“There is nothing,” assented Joy, thoughtfully, “that he enjoys one-half so well.”</p>
+
+<p>The illustrious statesman, Champ Clark, once lived about a mile from the village of Jebigue, in
+Missouri. One day he rode into town on a favorite mule, and, hitching the beast
+on the sunny side of a street, in front of a saloon, he went inside in his
+character of teetotaler, to apprise the barkeeper that wine is a mocker. It was
+a dreadfully hot day. Pretty soon a neighbor came in and seeing Clark, said:</p>
+
+<p>“Champ, it is not right to leave that mule out there in the sun. </p>
+
+<p>He’ll roast, sure!&#8212;he was smoking as I passed him.”</p>
+
+<p>“O, he’s all right,” said Clark, lightly; “he’s an inveterate smoker.”</p>
+
+<p>The neighbor took a lemonade, but shook his head and repeated that it was not right.</p>
+
+<p>He was a conspirator. There had been a fire the night before: a stable just around the
+corner had burned and a number of horses had put on their immortality, among
+them a young colt, which was roasted to a rich nut-brown. Some of the boys had
+turned Mr. Clark’s mule loose and substituted the mortal part of the colt. Presently
+another man entered the saloon.</p>
+
+<p>“For mercy’s sake!” he said, taking it with sugar, “do remove that mule, barkeeper: it smells.”</p>
+
+<p>“Yes,” interposed Clark, “that animal has the best nose in Missouri. But if he doesn’t mind, you
+shouldn’t.”</p>
+
+<p>In the course of human events Mr. Clark went out, and there, apparently, lay the incinerated and
+shrunken remains of his charger. The boys idd not have any fun out of Mr.
+Clarke, who looked at the body and, with the non-committal expression to which
+he owes so much of his political preferment, went away. But walking home late
+that night he saw his mule standing silent and solemn by the wayside in the
+misty moonlight. Mentioning the name of Helen Blazes with uncommon emphasis,
+Mr. Clark took the back track as hard as ever he could hook it, and passed the
+night in town.</p>
+
+<p>General H.H. Wotherspoon, president of the Army War College, has a pet rib-nosed baboon, an
+animal of uncommon intelligence but imperfectly beautiful. Returning to his
+apartment one evening, the General was surprised and pained to find Adam (for
+so the creature is named, the general being a Darwinian) sitting up for him and
+wearing his master’s best uniform coat, epaulettes and all.</p>
+
+<p>“You confounded remote ancestor!” thundered the great strategist, “what do you mean by being
+out of bed after naps?&#8212;and with my coat on!”</p>
+
+<p>Adam rose and with a reproachful look got down on all fours in the manner of his kind and,
+scuffling across the room to a table, returned with a visiting-card: General
+Barry had called and, judging by an empty champagne bottle and several
+cigar-stumps, had been hospitably entertained while waiting. The general
+apologized to his faithful progenitor and retired. The next day he met General
+Barry, who said:</p>
+
+<p>“Spoon, old man, when leaving you last evening I forgot to ask you about those excellent cigars.
+Where did you get them?”</p>
+
+<p>General Wotherspoon did not deign to reply, but walked away.</p>
+
+<p>“Pardon me, please,” said Barry, moving after him; “I was joking of course. Why, I knew it was not
+you before I had been in the room fifteen minutes.”</p>
+
+<p class="entry"><span class="def">success</span>, <span class="pos">n.</span> The
+one unpardonable sin against one’s fellows. In literature, and particularly in
+poetry, the elements of success are exceedingly simple, and are admirably set
+forth in the following lines by the reverend Father Gassalasca Jape, entitled,
+for some mysterious reason, “John A. Joyce.”</p>
+
+<div class="poem">
+<p class="poetry">The bard who would prosper must carry a book,<br />
+Do his thinking in prose and wear<br />
+A crimson cravat, a far-away look<br />
+And a head of hexameter hair.<br />
+Be thin in your thought and your body’ll be fat;<br />
+If you wear your hair long you needn’t your hat.</p>
+</div>
+
+<p class="entry"><span class="def">suffrage</span>, <span class="pos">n.</span> Expression
+of opinion by means of a ballot. The right of suffrage (which is held to be
+both a privilege and a duty) means, as commonly interpreted, the right to vote
+for the man of another man’s choice, and is highly prized. Refusal to do so has
+the bad name of “incivism.” The incivilian, however, cannot be properly
+arraigned for his crime, for there is no legitimate accuser. If the accuser is
+himself guilty he has no standing in the court of opinion; if not, he profits
+by the crime, for A’s abstention from voting gives greater weight to the vote
+of B. By female suffrage is meant the right of a woman to vote as some man
+tells her to. It is based on female responsibility, which is somewhat limited. The
+woman most eager to jump out of her petticoat to assert her rights is first to
+jump back into it when threatened with a switching for misusing them.</p>
+
+<p class="entry"><span class="def">sycophant</span>, <span class="pos">n.</span> One
+who approaches Greatness on his belly so that he may not be commanded to turn
+and be kicked. He is sometimes an editor.</p>
+
+<div class="poem">
+<p class="poetry">As the lean leech, its victim found, is pleased<br />
+To fix itself upon a part diseased<br />
+Till, its black hide distended with bad blood,<br />
+It drops to die of surfeit in the mud,<br />
+So the base sycophant with joy descries<br />
+His neighbor’s weak spot and his mouth applies,<br />
+Gorges and prospers like the leech, although,
+Unlike that reptile, he will not let go.<br />
+Gelasma, if it paid you to devote<br />
+Your talent to the service of a goat,<br />
+Showing by forceful logic that its beard<br />
+Is more than Aaron’s fit to be revered;<br />
+If to the task of honoring its smell<br />
+Profit had prompted you, and love as well,<br />
+The world would benefit at last by you<br />
+And wealthy malefactors weep anew—<br />
+Your favor for a moment’s space denied<br />
+And to the nobler object turned aside.<br />
+Is’t not enough that thrifty millionaires<br />
+Who loot in freight and spoliate in fares,<br />
+Or, cursed with consciences that bid them fly<br />
+To safer villainies of darker dye,<br />
+Forswearing robbery and fain, instead,<br />
+To steal (they call it “cornering”) our bread<br />
+May see you groveling their boots to lick<br />
+And begging for the favor of a kick?<br />
+Still must you follow to the bitter end<br />
+Your sycophantic disposition’s trend,<br />
+And in your eagerness to please the rich<br />
+Hunt hungry sinners to their final ditch?<br />
+In Morgan’s praise you smite the sounding wire,
+And sing hosannas to great Havemeyher!<br />
+What’s Satan done that him you should eschew?<br />
+He too is reeking rich—deducting <i>you</i>.</p>
+</div>
+
+<p class="entry"><span class="def">syllogism</span>, <span class="pos">n.</span> A
+logical formula consisting of a major and a minor assumption and an
+inconsequent. (See logic.)</p>
+
+<p class="entry"><span class="def">sylph</span>, <span class="pos">n.</span> An
+immaterial but visible being that inhabited the air when the air was an element
+and before it was fatally polluted with factory smoke, sewer gas and similar
+products of civilization. Sylphs were allied to gnomes, nymphs and salamanders,
+which dwelt, respectively, in earth, water and fire, all now insalubrious. Sylphs,
+like fowls of the air, were male and female, to no purpose, apparently, for if
+they had progeny they must have nested in accessible places, none of the chicks
+having ever been seen.</p>
+
+<p class="entry"><span class="def">symbol</span>, <span class="pos">n.</span> Something
+that is supposed to typify or stand for something else. Many symbols are mere
+“survivals”—things which having no longer any utility continue to exist because
+we have inherited the tendency to make them; as funereal urns carved on
+memorial monuments. They were once real urns holding the ashes of the dead. We
+cannot stop making them, but we can give them a name that conceals our helplessness.</p>
+
+<p class="entry"><span class="def">symbolic</span>, <span class="pos">adj.</span> Pertaining
+to symbols and the use and interpretation of symbols.</p>
+
+<div class="poem">
+<p class="poetry">They say ‘tis conscience feels compunction;<br />
+I hold that that’s the stomach’s function,<br />
+For of the sinner I have noted<br />
+<br />That when he’s sinned he’s somewhat bloated,<br />
+Or ill some other ghastly fashion<br />
+Within that bowel of compassion.<br />
+True, I believe the only sinner<br />
+Is he that eats a shabby dinner.<br />
+You know how Adam with good reason,<br />
+For eating apples out of season,<br />
+Was “cursed.” But that is all symbolic:<br />
+The truth is, Adam had the colic.</p>
+<p class="poetry">G. J.</p>
+</div>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/S.html.i
@@ -1,0 +1,64 @@
+30 pages
+size 400 552
+length 44914
+396 2 10 body html
+0
+1760 2 37 body html
+39
+3547 2 67 body html
+39
+3773 2 71 body html
+523
+3773 2 71 body html
+1063
+3773 2 71 body html
+1603
+7045 2 136 body html
+73
+8967 2 165 body html
+0
+10281 2 191 body html
+90
+11355 2 210 body html
+360
+13065 2 239 body html
+172
+15249 2 282 body html
+0
+16848 2 310 body html
+0
+18464 2 342 body html
+36
+19444 2 368 body html
+175
+21497 2 397 body html
+187
+23557 2 437 body html
+90
+24748 2 461 body html
+263
+24748 2 461 body html
+806
+27777 2 536 body html
+70
+29053 2 566 body html
+121
+30698 2 591 body html
+170
+33246 2 628 body html
+34
+34990 2 656 body html
+0
+36077 2 677 body html
+119
+37436 2 702 body html
+153
+39361 2 735 body html
+0
+41224 2 767 body html
+19
+41224 2 767 body html
+563
+44294 2 827 body html
+138
+soul 20
--- /dev/null
+++ b/lib/ebooks/devils/T.html
@@ -1,0 +1,397 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: T</title>
+</head>
+<body lang="en-US">
+
+
+
+<h1>T</h1>
+
+<p class="entry">T, the twentieth letter of the English alphabet, was by the Greeks absurdly
+called <i>tau</i>. In the alphabet whence ours comes it
+had the form of the rude corkscrew of the period, and when it stood alone
+(which was more than the Phoenicians could always do) signified <i>Tallegal</i>, translated by the learned Dr.
+Brownrigg, “tanglefoot.”</p>
+
+<p class="entry"><span class="def">Table D’Hote</span>, <span class="pos">n.</span> A
+caterer’s thrifty concession to the universal passion for irresponsibility.</p>
+
+<div class="poem">
+<p class="poetry">Old Paunchinello, freshly wed,<br />
+Took Madam P. to table,<br />
+And there deliriously fed<br />
+As fast as he was able.<br />
+“I dote upon good grub,” he cried,<br />
+Intent upon its throatage.<br />
+“Ah, yes,” said the neglected bride,<br />
+“You’re in your <i>table d’hotage</i>.”</p>
+
+<p class="citeauth">Associated Poets</p>
+</div>
+
+<p class="entry"><span class="def">tail</span>, <span class="pos">n.</span> The part
+of an animal’s spine that has transcended its natural limitations to set up an
+independent existence in a world of its own. Excepting in its foetal state, Man
+is without a tail, a privation of which he attests an hereditary and uneasy
+consciousness by the coat-skirt of the male and the train of the female, and by
+a marked tendency to ornament that part of his attire where the tail should be,
+and indubitably once was. This tendency is most observable in the female of the
+species, in whom the ancestral sense is strong and persistent. The tailed men
+described by Lord Monboddo are now generally regarded as a product of an
+imagination unusually susceptible to influences generated in the golden age of
+our pithecan past.</p>
+
+<p class="entry"><span class="def">take</span>, <span class="pos">v.t.</span> To
+acquire, frequently by force but preferably by stealth.</p>
+
+<p class="entry"><span class="def">talk</span>, <span class="pos">v.t.</span> To
+commit an indiscretion without temptation, from an impulse without purpose.</p>
+
+<p class="entry"><span class="def">tariff</span>, <span class="pos">n.</span> A scale
+of taxes on imports, designed to protect the domestic producer against the
+greed of his consumer.</p>
+
+<div class="poem">
+<p class="poetry">The Enemy of Human Souls<br />
+Sat grieving at the cost of coals;<br />
+For Hell had been annexed of late,<br />
+And was a sovereign Southern State.</p>
+
+<p class="poetry">“It were no more than right,” said he,<br />
+“That I should get my fuel free.<br />
+The duty, neither just nor wise,<br />
+Compels me to economize—<br />
+Whereby my broilers, every one,<br />
+Are execrably underdone.<br />
+What would they have?&#8212;although I yearn<br />
+To do them nicely to a turn,<br />
+I can’t afford an honest heat.<br />
+This tariff makes even devils cheat!<br />
+I’m ruined, and my humble trade<br />
+All rascals may at will invade:<br />
+Beneath my nose the public press<br />
+Outdoes me in sulphureousness;<br />
+The bar ingeniously applies<br />
+To my undoing my own lies;<br />
+My medicines the doctors use<br />
+(Albeit vainly) to refuse<br />
+To me my fair and rightful prey<br />
+And keep their own in shape to pay;<br />
+The preachers by example teach<br />
+What, scorning to perform, I teach;<br />
+And statesmen, aping me, all make<br />
+More promises than they can break.<br />
+Against such competition I<br />
+Lift up a disregarded cry.<br />
+Since all ignore my just complaint,<br />
+By Hokey-Pokey! I’ll turn saint!”<br />
+Now, the Republicans, who all<br />
+Are saints, began at once to bawl<br />
+Against <i>his</i> competition; so<br />
+There was a devil of a go!<br />
+They locked horns with him, tete-a-tete<br />
+In acrimonious debate,<br />
+Till Democrats, forlorn and lone,<br />
+Had hopes of coming by their own.<br />
+That evil to avert, in haste<br />
+The two belligerents embraced;<br />
+But since ‘twere wicked to relax<br />
+A tittle of the Sacred Tax,<br />
+‘Twas finally agreed to grant<br />
+The bold Insurgent-protestant<br />
+A bounty on each soul that fell<br />
+Into his ineffectual Hell.</p>
+<p class="citeauth">Edam Smith</p>
+</div>
+
+<p class="entry"><span class="def">technicality</span>, <span class="pos">n.</span> In
+an English court a man named Home was tried for slander in having accused his
+neighbor of murder. His exact words were: “Sir Thomas Holt hath taken a cleaver
+and stricken his cook upon the head, so that one side of the head fell upon one
+shoulder and the other side upon the other shoulder.” The defendant was
+acquitted by instruction of the court, the learned judges holding that the
+words did not charge murder, for they did not affirm the death of the cook,
+that being only an inference.</p>
+
+<p class="entry"><span class="def">tedium</span>, <span class="pos">n.</span> Ennui,
+the state or condition of one that is bored. Many fanciful derivations of the
+word have been affirmed, but so high an authority as Father Jape says that it
+comes from a very obvious source—the first words of the ancient Latin hymn <i>Te
+Deum Laudamus</i>. In this apparently natural derivation there is something that
+saddens.</p>
+
+<p class="entry"><span class="def">teetotaler</span>, <span class="pos">n.</span> One
+who abstains from strong drink, sometimes totally, sometimes tolerably totally.</p>
+
+<p class="entry"><span class="def">telephone</span>, <span class="pos">n.</span> An
+invention of the devil which abrogates some of the advantages of making a
+disagreeable person keep his distance.</p>
+
+<p class="entry"><span class="def">telescope</span>, <span class="pos">n.</span> A
+device having a relation to the eye similar to that of the telephone to the
+ear, enabling distant objects to plague us with a multitude of needless
+details. Luckily it is unprovided with a bell summoning us to the sacrifice.</p>
+
+<p class="entry"><span class="def">tenacity</span>, <span class="pos">n.</span> A
+certain quality of the human hand in its relation to the coin of the realm. It
+attains its highest development in the hand of authority and is considered a
+serviceable equipment for a career in politics. The following illustrative
+lines were written of a Californian gentleman in high political preferment, who
+has passed to his accounting:</p>
+
+<div class="poem">
+<p class="poetry">Of such tenacity his grip<br />
+That nothing from his hand can slip.<br />
+Well-buttered eels you may o’erwhelm<br />
+In tubs of liquid slippery-elm<br />
+In vain—from his detaining pinch<br />
+They cannot struggle half an inch!<br />
+‘Tis lucky that he so is planned<br />
+That breath he draws not with his hand,<br />
+For if he did, so great his greed<br />
+He’d draw his last with eager speed.<br />
+Nay, that were well, you say. Not so<br />
+He’d draw but never let it go!</p>
+</div>
+
+<p class="entry"><span class="def">theosophy</span>, <span class="pos">n.</span> An
+ancient faith having all the certitude of religion and all the mystery of
+science. The modern Theosophist holds, with the Buddhists, that we live an
+incalculable number of times on this earth, in as many several bodies, because
+one life is not long enough for our complete spiritual development; that is, a
+single lifetime does not suffice for us to become as wise and good as we choose
+to wish to become. To be absolutely wise and good—that is perfection; and the
+Theosophist is so keen-sighted as to have observed that everything desirous of
+improvement eventually attains perfection. Less competent observers are
+disposed to except cats, which seem neither wiser nor better than they were
+last year. The greatest and fattest of recent Theosophists was the late Madame
+Blavatsky, who had no cat.</p>
+
+<p class="entry"><span class="def">tights</span>, <span class="pos">n.</span> An
+habiliment of the stage designed to reinforce the general acclamation of the
+press agent with a particular publicity. Public attention was once somewhat
+diverted from this garment to Miss Lillian Russell’s refusal to wear it, and
+many were the conjectures as to her motive, the guess of Miss Pauline Hall
+showing a high order of ingenuity and sustained reflection. It was Miss Hall’s
+belief that nature had not endowed Miss Russell with beautiful legs. This
+theory was impossible of acceptance by the male understanding, but the
+conception of a faulty female leg was of so prodigious originality as to rank
+among the most brilliant feats of philosophical speculation! It is strange that
+in all the controversy regarding Miss Russell’s aversion to tights no one seems
+to have thought to ascribe it to what was known among the ancients as
+“modesty.” The nature of that sentiment is now imperfectly understood, and
+possibly incapable of exposition with the vocabulary that remains to us. The
+study of lost arts has, however, been recently revived and some of the arts
+themselves recovered. This is an epoch of <i>renaissances</i>,
+and there is ground for hope that the primitive “blush” may be dragged from its
+hiding-place amongst the tombs of antiquity and hissed on to the stage.</p>
+
+<p class="entry"><span class="def">tomb</span>, <span class="pos">n.</span> The House
+of Indifference. Tombs are now by common consent invested with a certain
+sanctity, but when they have been long tenanted it is considered no sin to
+break them open and rifle them, the famous Egyptologist, Dr. Huggyns,
+explaining that a tomb may be innocently “glened” as soon as its occupant is
+done “smellynge,” the soul being then all exhaled. This reasonable view is now
+generally accepted by archaeologists, whereby the noble science of Curiosity
+has been greatly dignified.</p>
+
+<p class="entry"><span class="def">tope</span>, <span class="pos">v.</span> To tipple,
+booze, swill, soak, guzzle, lush, bib, or swig. In the individual, toping is
+regarded with disesteem, but toping nations are in the forefront of
+civilization and power. When pitted against the hard-drinking Christians the
+absemious Mahometans go down like grass before the scythe. In India one hundred
+thousand beef-eating and brandy-and-soda guzzling Britons hold in subjection
+two hundred and fifty million vegetarian abstainers of the same Aryan race. With
+what an easy grace the whisky-loving American pushed the temperate Spaniard out
+of his possessions! From the time when the Berserkers ravaged all the coasts of
+western Europe and lay drunk in every conquered port it has been the same way: everywhere
+the nations that drink too much are observed to fight rather well and not too
+righteously. Wherefore the estimable old ladies who abolished the canteen from
+the American army may justly boast of having materially augmented the nation’s
+military power.</p>
+
+<p class="entry"><span class="def">tortoise</span>, <span class="pos">n.</span> A
+creature thoughtfully created to supply occasion for the following lines by the
+illustrious Ambat Delaso:</p>
+
+<div class="poem">
+<p class="poetry">TO MY PET TORTOISE</p>
+
+<p class="poetry">My friend, you are not graceful—not at all;<br />
+Your gait’s between a stagger and a sprawl.<br />
+Nor are you beautiful: your head’s a snake’s<br />
+To look at, and I do not doubt it aches.<br />
+As to your feet, they’d make an angel weep.<br />
+‘Tis true you take them in whene’er you sleep.<br />
+No, you’re not pretty, but you have, I own,<br />
+A certain firmness—mostly you’re [sic] backbone.<br />
+Firmness and strength (you have a giant’s thews)<br />
+Are virtues that the great know how to use—<br />
+I wish that they did not; yet, on the whole,<br />
+You lack—excuse my mentioning it—Soul.<br />
+So, to be candid, unreserved and true,<br />
+I’d rather you were I than I were you.</p>
+
+<p class="poetry">Perhaps, however, in a time to be,<br />
+When Man’s extinct, a better world may see<br />
+Your progeny in power and control,<br />
+Due to the genesis and growth of Soul.</p>
+
+<p class="poetry">So I salute you as a reptile grand<br />
+Predestined to regenerate the land.</p>
+
+<p class="poetry">Father of Possibilities, O deign<br />
+To accept the homage of a dying reign!<br />
+In the far region of the unforeknown<br />
+I dream a tortoise upon every throne.</p>
+
+<p class="poetry">I see an Emperor his head withdraw<br />
+Into his carapace for fear of Law;</p>
+
+<p class="poetry">A King who carries something else than fat,<br />
+Howe’er acceptably he carries that;<br />
+A President not strenuously bent<br />
+On punishment of audible dissent—</p>
+
+<p class="poetry">Who never shot (it were a vain attack)<br />
+An armed or unarmed tortoise in the back;<br />
+Subject and citizens that feel no need<br />
+To make the March of Mind a wild stampede;<br />
+All progress slow, contemplative, sedate,<br />
+And “Take your time” the word, in Church and State.<br />
+O Tortoise, ‘tis a happy, happy dream,<br />
+My glorious testudinous regime!</p>
+
+<p class="poetry">I wish in Eden you’d brought this about<br />
+By slouching in and chasing Adam out.</p>
+</div>
+
+<p class="entry"><span class="def">tree</span>, <span class="pos">n.</span> A tall
+vegetable intended by nature to serve as a penal apparatus, though through a
+miscarriage of justice most trees bear only a negligible fruit, or none at all.
+When naturally fruited, the tree is a beneficient agency of civilization and an
+important factor in public morals. In the stern West and the sensitive South
+its fruit (white and black respectively) though not eaten, is agreeable to the
+public taste and, though not exported, profitable to the general welfare. That
+the legitimate relation of the tree to justice was no discovery of Judge Lynch
+(who, indeed, conceded it no primacy over the lamp-post and the bridge-girder)
+is made plain by the following passage from Morryster, who antedated him by two
+centuries:</p>
+
+<p>While in yt londe
+I was carried to see ye Ghogo tree, whereof I had hearde moch talk; but sayynge
+yt I saw naught remarkabyll in it, ye hed manne of ye villayge where it grewe
+made answer as followeth:</p>
+
+<p>“Ye tree is not nowe in fruite, but in his seasonne you shall see dependynge fr. his braunches
+all soch as have affroynted ye King his Majesty.”</p>
+
+<p>And I was furder tolde yt ye worde “Ghogo” sygnifyeth in yr tong ye same as “rapscal” in our
+owne.</p>
+
+<p><i>Trauvells in ye Easte</i></p>
+
+<p class="entry"><span class="def">trial</span>, <span class="pos">n.</span> A formal
+inquiry designed to prove and put upon record the blameless characters of
+judges, advocates and jurors. In order to effect this purpose it is necessary
+to supply a contrast in the person of one who is called the defendant, the
+prisoner, or the accused. If the contrast is made sufficiently clear this
+person is made to undergo such an affliction as will give the virtuous
+gentlemen a comfortable sense of their immunity, added to that of their worth. In
+our day the accused is usually a human being, or a socialist, but in mediaeval
+times, animals, fishes, reptiles and insects were brought to trial. A beast
+that had taken human life, or practiced sorcery, was duly arrested, tried and,
+if condemned, put to death by the public executioner. Insects ravaging grain
+fields, orchards or vineyards were cited to appeal by counsel before a civil
+tribunal, and after testimony, argument and condemnation, if they continued <i>in
+contumaciam</i> the matter was taken to a high ecclesiastical court, where they
+were solemnly excommunicated and anathematized. In a street of Toledo, some
+pigs that had wickedly run between the viceroy’s legs, upsetting him, were arrested
+on a warrant, tried and punished. In Naples and ass was condemned to be burned
+at the stake, but the sentence appears not to have been executed. D’Addosio
+relates from the court records many trials of pigs, bulls, horses, cocks, dogs,
+goats, etc., greatly, it is believed, to the betterment of their conduct and
+morals. In 1451 a suit was brought against the leeches infesting some ponds
+about Berne, and the Bishop of Lausanne, instructed by the faculty of
+Heidelberg University, directed that some of “the aquatic worms” be brought
+before the local magistracy. This was done and the leeches, both present and
+absent, were ordered to leave the places that they had infested within three
+days on pain of incurring “the malediction of God.” In the voluminous records
+of this <i>cause celebre</i> nothing is
+found to show whether the offenders braved the punishment, or departed
+forthwith out of that inhospitable jurisdiction.</p>
+
+<p class="entry"><span class="def">trichinosis</span>, <span class="pos">n.</span> The
+pig’s reply to proponents of porcophagy.</p>
+
+<p class="indentpara">Moses Mendlessohn
+having fallen ill sent for a Christian physician, who at once diagnosed the
+philosopher’s disorder as trichinosis, but tactfully gave it another name. “You
+need and immediate change of diet,” he said; “you must eat six ounces of pork
+every other day.”</p>
+
+<p class="dialog">“Pork?” shrieked the patient—“pork? Nothing shall induce me to touch it!”</p>
+
+<p class="dialog">“Do you mean that?” the doctor gravely asked.</p>
+
+<p class="dialog">“I swear it!”</p>
+
+<p class="dialog">“Good!&#8212;then I will undertake to cure you.”</p>
+
+<p class="entry"><span class="def">Trinity</span>, <span class="pos">n.</span> In the
+multiplex theism of certain Christian churches, three entirely distinct deities
+consistent with only one. Subordinate deities of the polytheistic faith, such
+as devils and angels, are not dowered with the power of combination, and must
+urge individually their clames to adoration and propitiation. The Trinity is
+one of the most sublime mysteries of our holy religion. In rejecting it because
+it is incomprehensible, Unitarians betray their inadequate sense of theological
+fundamentals. In religion we believe only what we do not understand, except in
+the instance of an intelligible doctrine that contradicts an incomprehensible
+one. In that case we believe the former as a part of the latter.</p>
+
+<p class="entry"><span class="def">Troglodyte</span>, <span class="pos">n.</span> Specifically,
+a cave-dweller of the paleolithic period, after the Tree and before the Flat. A
+famous community of troglodytes dwelt with David in the Cave of Adullam. The
+colony consisted of “every one that was in distress, and every one that was in
+debt, and every one that was discontented”—in brief, all the Socialists of
+Judah.</p>
+
+<p class="entry"><span class="def">truce</span>, <span class="pos">n.</span> Friendship.</p>
+
+<p id="truth" class="entry"><span class="def">truth</span>, <span class="pos">n.</span> An
+ingenious compound of desirability and appearance. Discovery of truth is the
+sole purpose of philosophy, which is the most ancient occupation of the human
+mind and has a fair prospect of existing with increasing activity to the end of time.</p>
+
+<p class="entry"><span class="def">truthful</span>, <span class="pos">adj.</span> Dumb
+and illiterate.</p>
+
+<p class="entry"><span class="def">trust</span>, <span class="pos">n.</span> In
+American politics, a large corporation composed in greater part of thrifty
+working men, widows of small means, orphans in the care of guardians and the
+courts, with many similar malefactors and public enemies.</p>
+
+<p class="entry"><span class="def">turkey</span>, <span class="pos">n.</span> A large
+bird whose flesh when eaten on certain religious anniversaries has the peculiar
+property of attesting piety and gratitude. Incidentally, it is pretty good eating.</p>
+
+<p class="entry"><span class="def">twice</span>, <span class="pos">adv.</span> Once
+too often.</p>
+
+<p class="entry"><span class="def">type</span>, <span class="pos">n.</span> Pestilent
+bits of metal suspected of destroying civilization and enlightenment, despite
+their obvious agency in this incomparable dictionary.</p>
+
+<p class="entry"><span class="def">Tzetze (or Tsetse) Fly</span>, <span class="pos">n.</span> An African
+insect (<i>Glossina morsitans</i>) whose bite is commonly
+regarded as nature’s most efficacious remedy for insomnia, though some patients
+prefer that of the American novelist (<i>Mendax interminabilis</i>).</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/T.html.i
@@ -1,0 +1,30 @@
+13 pages
+size 400 552
+length 20645
+396 2 10 body html
+0
+1344 2 38 body html
+107
+2653 2 60 body html
+327
+2653 2 60 body html
+873
+6271 2 141 body html
+73
+8124 2 176 body html
+22
+10082 2 204 body html
+39
+11331 2 223 body html
+242
+11331 2 223 body html
+781
+14716 2 298 body html
+0
+14753 2 300 body html
+498
+17685 2 347 body html
+175
+20307 2 391 body html
+56
+truth 11
--- /dev/null
+++ b/lib/ebooks/devils/TitlePage.html
@@ -1,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+    "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary</title>
+</head>
+<body lang="en-us">
+
+<h1 class="title">The Devil&#8217;s Dictionary</h1>
+
+<h2 class="title">AMBROSE BIERCE</h2>
+
+<p class="title">Originally published by Neale Publishing Company in 1911.</p>
+
+<p class="title">This version began as a plain ASCII text from Project
+Gutenberg, and was entered by Aloysius of &amp;tSftDotIotE (aloysius@west.darkside.com)</p>
+
+<p class="title">Open eBook formatting and editing was performed July&#x2013;September, 2000 by
+Peter K. Sheerin (psheerin@petesguide.com), with formatting based on that found in the 1993
+Dover Publications edition.</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/TitlePage.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 552
+length 969
+396 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/U.html
@@ -1,0 +1,118 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: U</title>
+</head>
+<body lang="en-US">
+
+
+<h1>U</h1>
+
+<p class="entry"><span class="def">ubiquity</span>, <span class="pos">n.</span> The
+gift or power of being in all places at one time, but not in all places at all
+times, which is omnipresence, an attribute of God and the luminiferous ether
+only. This important distinction between ubiquity and omnipresence was not
+clear to the mediaeval Church and there was much bloodshed about it. Certain
+Lutherans, who affirmed the presence everywhere of Christ’s body were known as
+Ubiquitarians. For this error they were doubtless damned, for Christ’s body is
+present only in the eucharist, though that sacrament may be performed in more
+than one place simultaneously. In recent times ubiquity has not always been
+understood—not even by Sir Boyle Roche, for example, who held that a man cannot
+be in two places at once unless he is a bird.</p>
+
+<p class="entry"><span class="def">ugliness</span>, <span class="pos">n.</span> A
+gift of the gods to certain women, entailing virtue without humility.</p>
+
+<p class="entry"><span class="def">ultimatum</span>, <span class="pos">n.</span> In
+diplomacy, a last demand before resorting to concessions.</p>
+
+<p>Having received an ultimatum from Austria, the Turkish Ministry met to consider it.</p>
+
+<p>“O servant of the Prophet,” said the Sheik of the Imperial Chibouk to the Mamoosh of the
+Invincible Army, “how many unconquerable soldiers have we in arms?”</p>
+
+<p>“Upholder of the Faith,” that dignitary replied after examining his memoranda, “they are in
+numbers as the leaves of the forest!”</p>
+
+<p>“And how many impenetrable battleships strike terror to the hearts of all Christian swine?”
+he asked the Imaum of the Ever Victorious Navy.</p>
+
+<p>“Uncle of the Full Moon,” was the reply, “deign to know that they are as the waves of the ocean,
+the sands of the desert and the stars of Heaven!”</p>
+
+<p>For eight hours the broad brow of the Sheik of the Imperial Chibouk was corrugated with
+evidences of deep thought: he was calculating the chances of war. Then, “Sons
+of angels,” he said, “the die is cast! I shall suggest to the Ulema of the
+Imperial Ear that he advise inaction. In the name of Allah, the council is adjourned.”</p>
+
+<p class="entry"><span class="def">un-American</span>, <span class="pos">adj.</span> Wicked,
+intolerable, heathenish.</p>
+
+<p class="entry"><span class="def">unction</span>, <span class="pos">n.</span> An
+oiling, or greasing. The rite of extreme unction consists in touching with oil
+consecrated by a bishop several parts of the body of one engaged in dying. Marbury
+relates that after the rite had been administered to a certain wicked English
+nobleman it was discovered that the oil had not been properly consecrated and
+no other could be obtained. When informed of this the sick man said in anger: </p>
+
+<p>“Then I’ll be damned if I die!”</p>
+
+<p>“My son,” said the priest, “this is what we fear.”</p>
+
+<p class="entry"><span class="def">understanding</span>, <span class="pos">n.</span> A
+cerebral secretion that enables one having it to know a house from a horse by
+the roof on the house. Its nature and laws have been exhaustively expounded by
+Locke, who rode a house, and Kant, who lived in a horse.</p>
+
+<div class="poem">
+<p class="poetry">His understanding was so keen<br />
+That all things which he’d felt, heard, seen,<br />
+He could interpret without fail<br />
+If he was in or out of jail.<br />
+He wrote at Inspiration’s call<br />
+Deep disquisitions on them all,<br />
+Then, pent at last in an asylum,<br />
+Performed the service to compile ‘em.<br />
+So great a writer, all men swore,<br />
+They never had not read before.</p>
+<p class="citeauth">Jorrock Wormley</p>
+</div>
+
+<p class="entry"><span class="def">Unitarian</span>, <span class="pos">n.</span> One
+who denies the divinity of a Trinitarian.</p>
+
+<p class="entry"><span class="def">universalist</span>, <span class="pos">n.</span> One
+who forgoes the advantage of a Hell for persons of another faith.</p>
+
+<p class="entry"><span class="def">urbanity</span>, <span class="pos">n.</span> The
+kind of civility that urban observers ascribe to dwellers in all cities but New
+York. Its commonest expression is heard in the words, “I beg your pardon,” and
+it is not consistent with disregard of the rights of others.</p>
+
+<div class="poem">
+<p class="poetry">The owner of a powder mill<br />
+Was musing on a distant hill—<br />
+Something his mind foreboded—<br />
+When from the cloudless sky there fell<br />
+A deviled human kidney! Well,<br />
+The man’s mill had exploded.<br />
+His hat he lifted from his head;<br />
+“I beg your pardon, sir,” he said;<br />
+“I didn’t know ‘twas loaded.”</p>
+<p class="citeauth">Swatkin</p>
+</div>
+
+<p class="entry"><span class="def">usage</span>, <span class="pos">n.</span> The First
+Person of the literary Trinity, the Second and Third being Custom and
+Conventionality. Imbued with a decent reverence for this Holy Triad an
+industrious writer may hope to produce books that will live as long as the fashion.</p>
+
+<p class="entry"><span class="def">uxoriousness</span>, <span class="pos">n.</span> A
+perverted affection that has strayed to one’s own wife.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/U.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 552
+length 5657
+396 2 10 body html
+0
+1821 2 38 body html
+34
+3346 2 66 body html
+39
+4742 2 96 body html
+138
--- /dev/null
+++ b/lib/ebooks/devils/V.html
@@ -1,0 +1,57 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: V</title>
+</head>
+<body lang="en-US">
+
+
+<h1>V</h1>
+
+<p class="entry"><span class="def">valor</span>, <span class="pos">n.</span> A
+soldierly compound of vanity, duty and the gambler’s hope.</p>
+
+<p>“Why have you halted?” roared the commander of a division and Chickamauga, who had ordered a
+charge; “move forward, sir, at once.”</p>
+
+<p>“General,” said the commander of the delinquent brigade, “I am persuaded that any further
+display of valor by my troops will bring them into collision with the enemy.”</p>
+
+<p class="entry"><span class="def">vanity</span>, <span class="pos">n.</span> The
+tribute of a fool to the worth of the nearest ass.</p>
+
+<div class="poem">
+<p class="poetry">They say that hens do cackle loudest when<br />
+There’s nothing vital in the eggs they’ve laid;<br />
+And there are hens, professing to have made<br />
+A study of mankind, who say that men<br />
+Whose business ‘tis to drive the tongue or pen<br />
+Make the most clamorous fanfaronade<br />
+O’er their most worthless work; and I’m afraid<br />
+They’re not entirely different from the hen.<br />
+Lo! the drum-major in his coat of gold,<br />
+His blazing breeches and high-towering cap—<br />
+Imperiously pompous, grandly bold,<br />
+Grim, resolute, an awe-inspiring chap!<br />
+Who’d think this gorgeous creature’s only virtue Is that in
+battle he will never hurt you?</p>
+
+<p class="citeauth">Hannibal Hunsiker</p>
+</div>
+
+<p class="entry"><span class="def">virtues</span>, <span class="pos">n.</span>pl. Certain
+abstentions.</p>
+
+<p class="entry"><span class="def">vituperation</span>, <span class="pos">n.</span> Saite,
+as understood by dunces and all such as suffer from an impediment in their wit.</p>
+
+<p class="entry"><span class="def">vote</span>, <span class="pos">n.</span> The
+instrument and symbol of a freeman’s power to make a fool of himself and a
+wreck of his country.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/V.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 2289
+396 2 10 body html
+0
+1025 2 27 body html
+240
--- /dev/null
+++ b/lib/ebooks/devils/W.html
@@ -1,0 +1,275 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: W</title>
+</head>
+<body lang="en-US">
+
+
+<h1>W</h1>
+
+<p class="firstpara">W (double U) has,
+of all the letters in our alphabet, the only cumbrous name, the names of the
+others being monosyllabic. This advantage of the Roman alphabet over the Grecian
+is the more valued after audibly spelling out some simple Greek word, like <i>epixoriambikos</i>. Still, it is now thought
+by the learned that other agencies than the difference of the two alphabets may
+have been concerned in the decline of “the glory that was Greece” and the rise
+of “the grandeur that was Rome.” There can be no doubt, however, that by
+simplifying the name of W (calling it “wow,” for example) our civilization
+could be, if not promoted, at least better endured.</p>
+
+<p class="entry"><span class="def">Wall Street</span>, <span class="pos">n.</span> A
+symbol for sin for every devil to rebuke. That Wall Street is a den of thieves
+is a belief that serves every unsuccessful thief in place of a hope in Heaven. Even
+the great and good Andrew Carnegie has made his profession of faith in the
+matter.</p>
+
+<div class="poem">
+<p class="poetry">Carnegie the dauntless
+has uttered his call To battle: “The brokers are parasites all!” Carnegie,
+Carnegie, you’ll never prevail;</p>
+
+<p class="poetry">Keep the wind of your slogan to belly your sail, Go back to your isle of perpetual brume,
+Silence your pibroch, doff tartan and plume:</p>
+
+<p class="poetry">Ben Lomond is calling his son from the fray—</p>
+
+<p class="poetry">Fly, fly from the region of Wall Street away! While still you’re possessed of a single baubee (I
+wish it were pledged to endowment of me) ‘Twere wise to retreat from the wars
+of finance Lest its value decline ere your credit advance. For a man ‘twixt a
+king of finance and the sea, Carnegie, Carnegie, your tongue is too free!</p>
+
+<p class="citeauth">Anonymus Bink</p>
+</div>
+
+<p class="entry"><span class="def">war</span>, <span class="pos">n.</span> A by-product of the arts of
+peace. The most menacing political condition is a period of
+international amity. The student of history who has not been taught
+to expect the unexpected may justly boast himself inaccessible to the
+light. “In time of peace prepare for war” has a deeper meaning than
+is commonly discerned; it means, not merely that all things earthly
+have an end—that change is the one immutable and eternal law—but
+that the soil of peace is thickly sown with the seeds of war and
+singularly suited to their germination and growth. It was when Kubla Khan
+had decreed his “stately pleasure dome”—when, that is to say, there
+were peace and fat feasting in Xanadu—that he heard from afar
+Ancestral voices prophesying war.</p>
+
+<p class="indentpara">One of the
+greatest of poets, Coleridge was one of the wisest of men, and it was not for
+nothing that he read us this parable. Let us have a little less of “hands
+across the sea,” and a little more of that elemental distrust that is the
+security of nations. War loves to come like a thief in the night; professions
+of eternal amity provide the night.</p>
+
+<p class="entry"><span class="def">Washingtonian</span>, <span class="pos">n.</span> A
+Potomac tribesman who exchanged the privilege of governing himself for the
+advantage of good government. In justice to him it should be said that he did
+not want to.</p>
+
+<div class="poem">
+<p class="poetry">They took away his vote and gave instead<br />
+The right, when he had earned, to <i>eat</i> his bread.<br />
+In vain—he clamors for his “boss,” pour soul,<br />
+To come again and part him from his roll.</p>
+
+<p class="citeauth">Offenbach Stutz</p>
+</div>
+
+<p class="entry"><span class="def">weaknesses</span>, <span class="pos">n.</span>pl. Certain
+primal powers of Tyrant Woman wherewith she holds dominion over the male of her
+species, binding him to the service of her will and paralyzing his rebellious
+energies.</p>
+
+<p class="entry"><span class="def">weather</span>, <span class="pos">n.</span> The
+climate of the hour. A permanent topic of conversation among persons whom it
+does not interest, but who have inherited the tendency to chatter about it from
+naked arboreal ancestors whom it keenly concerned. The setting up official
+weather bureaus and their maintenance in mendacity prove that even governments
+are accessible to suasion by the rude forefathers of the jungle.</p>
+
+<div class="poem">
+<p class="poetry">Once I dipt into
+the future far as human eye could see, And I saw the Chief Forecaster, dead as
+any one can be—</p>
+
+<p class="poetry">Dead and damned
+and shut in Hades as a liar from his birth, With a record of unreason seldom
+paralleled on earth. While I looked he reared him solemnly, that incadescent
+youth, From the coals that he’d preferred to the advantages of truth. He cast
+his eyes about him and above him; then he wrote On a slab of thin asbestos what
+I venture here to quote—</p>
+
+<p class="poetry">For I read it in
+the rose-light of the everlasting glow:</p>
+
+<p class="poetry">“Cloudy; variable
+winds, with local showers; cooler; snow.”</p>
+
+<p class="citeauth">Halcyon Jones</p>
+</div>
+
+<p class="entry"><span class="def">wedding</span>, <span class="pos">n.</span> A
+ceremony at which two persons undertake to become one, one undertakes to become
+nothing, and nothing undertakes to become supportable.</p>
+
+<p class="entry"><span class="def">werewolf</span>, <span class="pos">n.</span> A
+wolf that was once, or is sometimes, a man. All werewolves are of evil
+disposition, having assumed a bestial form to gratify a beastial appetite, but
+some, transformed by sorcery, are as humane and is consistent with an acquired
+taste for human flesh.</p>
+
+<p>Some Bavarian peasants having caught a wolf one evening, tied it to a post by the tail and
+went to bed. The next morning nothing was there! Greatly perplexed, they
+consulted the local priest, who told them that their captive was undoubtedly a
+werewolf and had resumed its human for during the night. “The next time that
+you take a wolf,” the good man said, “see that you chain it by the leg, and in
+the morning you will find a Lutheran.”</p>
+
+<p class="entry"><span class="def">Whangdepootenawah,</span> <span class="pos">n.</span> In the
+Ojibwa tongue, disaster; an unexpected affliction that strikes hard.</p>
+
+<div class="poem">
+<p class="poetry">Should you ask me whence this laughter,</p>
+<p class="poetry">Whence this audible big-smiling,</p>
+<p class="poetry">With its labial extension,</p>
+<p class="poetry">With its maxillar distortion</p>
+<p class="poetry">And its diaphragmic rhythmus</p>
+<p class="poetry">Like the billowing of an ocean,</p>
+<p class="poetry">Like the shaking of a carpet,</p>
+<p class="poetry">I should answer, I should tell you:</p>
+<p class="poetry">From the great deeps of the spirit,</p>
+<p class="poetry">From the unplummeted abysmus</p>
+<p class="poetry">Of the soul this laughter welleth</p>
+<p class="poetry">As the fountain, the gug-guggle,</p>
+<p class="poetry">Like the river from the canon [sic],</p>
+<p class="poetry">To entoken and give warning</p>
+<p class="poetry">That my present mood is sunny.</p>
+<p class="poetry">Should you ask me further question—</p>
+<p class="poetry">Why the great deeps of the spirit,</p>
+<p class="poetry">Why the unplummeted abysmus</p>
+<p class="poetry">Of the soule extrudes this laughter,</p>
+<p class="poetry">This all audible big-smiling,</p>
+<p class="poetry">I should answer, I should tell you</p>
+<p class="poetry">With a white heart, tumpitumpy,</p>
+<p class="poetry">With a true tongue, honest Injun:</p>
+<p class="poetry">William Bryan, he has Caught It,</p>
+<p class="poetry">Caught the Whangdepootenawah!</p>
+<p class="poetry">Is’t the sandhill crane, the shankank,</p>
+<p class="poetry">Standing in the marsh, the kneedeep,</p>
+<p class="poetry">Standing silent in the kneedeep</p>
+<p class="poetry">With his wing-tips crossed behind him</p>
+<p class="poetry">And his neck close-reefed before him,</p>
+<p class="poetry">With his bill, his william, buried</p>
+<p class="poetry">In the down upon his bosom,</p>
+<p class="poetry">With his head retracted inly,</p>
+<p class="poetry">While his shoulders overlook it?</p>
+<p class="poetry">Does the sandhill crane, the shankank,</p>
+<p class="poetry">Shiver grayly in the north wind,</p>
+<p class="poetry">Wishing he had died when little,</p>
+<p class="poetry">As the sparrow, the chipchip, does?</p>
+<p class="poetry">No ‘tis not the Shankank standing,</p>
+<p class="poetry">Standing in the gray and dismal</p>
+<p class="poetry">Marsh, the gray and dismal kneedeep.</p>
+<p class="poetry">No, ‘tis peerless William Bryan</p>
+<p class="poetry">Realizing that he’s Caught It,</p>
+<p class="poetry">Caught the Whangdepootenawah!</p>
+</div>
+
+<p class="entry"><span class="def">wheat</span>, <span class="pos">n.</span> A cereal
+from which a tolerably good whisky can with some difficulty be made, and which
+is used also for bread. The French are said to eat more bread <i>per capita</i> of population than any other
+people, which is natural, for only they know how to make the stuff palatable.</p>
+
+<p class="entry"><span class="def">white</span>, <span class="pos">adj.</span> and n.
+Black.</p>
+
+<p class="entry"><span class="def">widow</span>, <span class="pos">n.</span> A
+pathetic figure that the Christian world has agreed to take humorously,
+although Christ’s tenderness towards widows was one of the most marked features
+of his character.</p>
+
+<p class="entry"><span class="def">wine</span>, <span class="pos">n.</span> Fermented
+grape-juice known to the Women’s Christian Union as “liquor,” sometimes as
+“rum.” Wine, madam, is God’s next best gift to man.</p>
+
+<p class="entry"><span class="def">wit</span>, <span class="pos">n.</span> The salt
+with which the American humorist spoils his intellectual cookery by leaving it
+out.</p>
+
+<p class="entry"><span class="def">witch</span>, <span class="pos">n.</span> (1) Any
+ugly and repulsive old woman, in a wicked league with the devil. (2) A
+beautiful and attractive young woman, in wickedness a league beyond the devil.</p>
+
+<p class="entry"><span class="def">witticism</span>, <span class="pos">n.</span> A
+sharp and clever remark, usually quoted, and seldom noted; what the Philistine
+is pleased to call a “joke.”</p>
+
+<p class="entry"><span class="def">woman</span>, <span class="pos">n.</span></p>
+
+<p>An animal usually
+living in the vicinity of Man, and having a rudimentary susceptibility to
+domestication. It is credited by many of the elder zoologists with a certain
+vestigial docility acquired in a former state of seclusion, but naturalists of
+the postsusananthony period, having no knowledge of the seclusion, deny the
+virtue and declare that such as creation’s dawn beheld, it roareth now. The
+species is the most widely distributed of all beasts of prey, infesting all
+habitable parts of the globe, from Greeland’s spicy mountains to India’s moral
+strand. The popular name (wolfman) is incorrect, for the creature is of the cat
+kind. The woman is lithe and graceful in its movement, especially the American
+variety (<i>felis pugnans</i>), is omnivorous and can be taught not to talk.</p>
+
+<p class="citeauth">Balthasar Pober</p>
+
+<p class="entry"><span class="def">worms’-meat</span>, <span class="pos">n.</span> The
+finished product of which we are the raw material. The contents of the Taj
+Mahal, the Tombeau Napoleon and the Granitarium. Worms’-meat is usually
+outlasted by the structure that houses it, but “this too must pass away.” Probably
+the silliest work in which a human being can engage is construction of a tomb
+for himself. The solemn purpose cannot dignify, but only accentuates by
+contrast the foreknown futility.</p>
+
+<div class="poem">
+<p class="poetry">Ambitious fool! so mad to be a show!<br />
+How profitless the labor you bestow<br />
+Upon a dwelling whose magnificence<br />
+The tenant neither can admire nor know.<br />
+Build deep, build high, build massive as you can,<br />
+The wanton grass-roots will defeat the plan<br />
+By shouldering asunder all the stones<br />
+In what to you would be a moment’s span.<br />
+Time to the dead so all unreckoned flies<br />
+That when your marble is all dust, arise,<br />
+If wakened, stretch your limbs and yawn—<br />
+You’ll think you scarcely can have closed your eyes.<br />
+What though of all man’s works your tomb alone
+Should stand till Time himself be overthrown?<br />
+Would it advantage you to dwell therein<br />
+Forever as a stain upon a stone?</p>
+
+<p class="citeauth">Joel Huck</p>
+</div>
+
+<p class="entry"><span class="def">worship</span>, <span class="pos">n.</span> Homo
+Creator’s testimony to the sound construction and fine finish of Deus Creatus. A
+popular form of abjection, having an element of pride.</p>
+
+<p class="entry"><span class="def">wrath</span>, <span class="pos">n.</span> Anger of
+a superior quality and degree, appropriate to exalted characters and momentous
+occasions; as, “the wrath of God,” “the day of wrath,” etc. Amongst the
+ancients the wrath of kings was deemed sacred, for it could usually command the
+agency of some god for its fit manifestation, as could also that of a priest. The
+Greeks before Troy were so harried by Apollo that they jumped out of the
+frying-pan of the wrath of Cryses into the fire of the wrath of Achilles,
+though Agamemnon, the sole offender, was neither fried nor roasted. A similar
+noted immunity was that of David when he incurred the wrath of Yahveh by
+numbering his people, seventy thousand of whom paid the penalty with their
+lives. God is now Love, and a director of the census performs his work without
+apprehension of disaster.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/W.html.i
@@ -1,0 +1,23 @@
+10 pages
+size 400 552
+length 14117
+396 2 10 body html
+0
+1443 2 31 body html
+159
+3459 2 69 body html
+22
+4746 2 95 body html
+157
+6679 2 136 body html
+72
+6679 2 136 body html
+612
+6679 2 136 body html
+1152
+9503 2 188 body html
+0
+11587 2 226 body html
+0
+13208 2 261 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/X.html
@@ -1,0 +1,25 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: X</title>
+</head>
+<body lang="en-US">
+
+
+<h1>X</h1>
+
+<p class="firstpara">X in our alphabet being a needless letter has an added invincibility to the attacks of the
+spelling reformers, and like them, will doubtless last as long as the language.
+X is the sacred symbol of ten dollars, and in such words as Xmas, Xn, etc.,
+stands for Christ, not, as is popular supposed, because it represents a cross,
+but because the corresponding letter in the Greek alphabet is the initial of
+his name&#8212;<i>Xristos</i>. If it represented a cross it would stand for St. Andrew, who “testified” upon one of
+that shape. In the algebra of psychology x stands for Woman’s mind. Words
+beginning with X are Grecian and will not be defined in this standard English dictionary.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/X.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 552
+length 1145
+396 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/Y.html
@@ -1,0 +1,72 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: Y</title>
+</head>
+<body lang="en-US">
+
+
+<h1>Y</h1>
+
+<p class="entry"><span class="def">Yankee</span>, <span class="pos">n.</span> In
+Europe, an American. In the Northern States of our Union, a New Englander. In
+the Southern States the word is unknown. (See DAMNYANK.)</p>
+
+<p class="entry"><span class="def">year</span>, <span class="pos">n.</span> A period
+of three hundred and sixty-five disappointments.</p>
+
+<p class="entry"><span class="def">yesterday</span>, <span class="pos">n.</span> The
+infancy of youth, the youth of manhood, the entire past of age.</p>
+
+<div class="poem">
+<p class="poetry">But yesterday I should have thought me blest<br />
+To stand high-pinnacled upon the peak<br />
+Of middle life and look adown the bleak<br />
+And unfamiliar foreslope to the West,<br />
+Where solemn shadows all the land invest<br />
+And stilly voices, half-remembered, speak<br />
+Unfinished prophecy, and witch-fires freak<br />
+The haunted twilight of the Dark of Rest.<br />
+Yea, yesterday my soul was all aflame<br />
+To stay the shadow on the dial’s face<br />
+At manhood’s noonmark! Now, in God His name<br />
+I chide aloud the little interspace<br />
+Disparting me from Certitude, and fain<br />
+Would know the dream and vision ne’er again.</p>
+
+<p class="citeauth">Baruch Arnegriff</p>
+</div>
+
+<p class="indentpara">It is said that in his last illness the poet Arnegriff was attended at different times by seven
+doctors.</p>
+
+<p class="entry"><span class="def">yoke</span>, <span class="pos">n.</span> An
+implement, madam, to whose Latin name, <i>jugum</i>,
+we owe one of the most illuminating words in our language—a word that defines
+the matrimonial situation with precision, point and poignancy. A thousand
+apologies for withholding it.</p>
+
+<p class="entry"><span class="def">youth</span>, <span class="pos">n.</span> The
+Period of Possibility, when Archimedes finds a fulcrum, Cassandra has a
+following and seven cities compete for the honor of endowing a living Homer.</p>
+
+<p class="poetry">Youth is the true Saturnian Reign,<br />
+the Golden Age on earth again,<br />
+when figs are grown on thistles,<br />
+and pigs betailed with whistles and,<br />
+wearing silken bristles,<br />
+live ever in clover,<br />
+and clows fly over,<br />
+delivering milk at every door,<br />
+and Justice never is heard to snore,<br />
+and every assassin is made a ghost<br />
+and, howling, is cast into Baltimost!</p>
+
+<p class="citeauth">Polydore Smith</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/Y.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 2842
+396 2 10 body html
+0
+1669 2 44 body html
+0
--- /dev/null
+++ b/lib/ebooks/devils/Z.html
@@ -1,0 +1,96 @@
+<?xml version="1.0"?>       
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"       
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: Z</title>
+</head>
+<body lang="en-US">
+
+
+<h1>Z</h1>
+
+<p class="entry"><span class="def">zany</span>, <span class="pos">n.</span> A popular
+character in old Italian plays, who imitated with ludicrous incompetence the <i>buffone</i>, or clown, and was therefore the
+ape of an ape; for the clown himself imitated the serious characters of the
+play. The zany was progenitor to the specialist in humor, as we to-day have the
+unhappiness to know him. In the zany we see an example of creation; in the
+humorist, of transmission. Another excellent specimen of the modern zany is the
+curate, who apes the rector, who apes the bishop, who apes the archbishop, who
+apes the devil.</p>
+
+<p class="entry"><span class="def">Zanzibari</span>, <span class="pos">n.</span> An
+inhabitant of the Sultanate of Zanzibar, off the eastern coast of Africa. The
+Zanzibaris, a warlike people, are best known in this country through a
+threatening diplomatic incident that occurred a few years ago. The American
+consul at the capital occupied a dwelling that faced the sea, with a sandy
+beach between. Greatly to the scandal of this official’s family, and against
+repeated remonstrances of the official himself, the people of the city
+persisted in using the beach for bathing. One day a woman came down to the edge
+of the water and was stooping to remove her attire (a pair of sandals) when the
+consul, incensed beyond restraint, fired a charge of bird-shot into the most
+conspicuous part of her person. Unfortunately for the existing <i>entente cordiale</i> between two great
+nations, she was the Sultana.</p>
+
+<p class="entry"><span class="def">zeal</span>, <span class="pos">n.</span> A certain
+nervous disorder afflicting the young and inexperienced. A passion that goeth
+before a sprawl.</p>
+
+<div class="poem">
+<p class="poetry">When Zeal sought Gratitude for his reward<br />
+He went away exclaiming: “O my Lord!”<br />
+“What do you want?” the Lord asked, bending down.<br />
+“An ointment for my cracked and bleeding crown.”</p>
+
+<p class="citeauth">Jum Coople</p>
+</div>
+
+<p class="entry"><span class="def">zenith</span>, <span class="pos">n.</span> The
+point in the heavens directly overhead to a man standing or a growing cabbage. A
+man in bed or a cabbage in the pot is not considered as having a zenith, though
+from this view of the matter there was once a considerably dissent among the
+learned, some holding that the posture of the body was immaterial. These were
+called Horizontalists, their opponents, Verticalists. The Horizontalist heresy
+was finally extinguished by Xanobus, the philosopher-king of Abara, a zealous
+Verticalist. Entering an assembly of philosophers who were debating the matter,
+he cast a severed human head at the feet of his opponents and asked them to
+determine its zenith, explaining that its body was hanging by the heels
+outside. Observing that it was the head of their leader, the Horizontalists
+hastened to profess themselves converted to whatever opinion the Crown might be
+pleased to hold, and Horizontalism took its place among <i>fides defuncti</i>.</p>
+
+<p class="entry"><span class="def">Zeus</span>, <span class="pos">n.</span> The chief
+of Grecian gods, adored by the Romans as Jupiter and by the modern Americans as
+God, Gold, Mob and Dog. Some explorers who have touched upon the shores of
+America, and one who professes to have penetrated a considerable distance to
+the interior, have thought that these four names stand for as many distinct
+deities, but in his monumental work on Surviving Faiths, Frumpp insists that
+the natives are monotheists, each having no other god than himself, whom he
+worships under many sacred names.</p>
+
+<p class="entry"><span class="def">zigzag</span>, <span class="pos">v.t.</span> To
+move forward uncertainly, from side to side, as one carrying the white man’s
+burden. (From <i>zed</i>, <i>z</i>, and <i>jag</i>,
+an Icelandic word of unknown meaning.)</p>
+
+<div class="poem">
+<p class="poetry">He zedjagged so uncomen wyde<br />
+Thet non coude pas on eyder syde;<br />
+So, to com saufly thruh, I been<br />
+Constreynet for to doodge betwene.</p>
+
+<p class="citeauth">Munwele</p>
+</div>
+
+<p class="entry"><span class="def">zoology</span>, <span class="pos">n.</span> The science
+and history of the animal kingdom, including its king, the House Fly (<i>Musca
+maledicta</i>). The father of Zoology was Aristotle, as is universally conceded,
+but the name of its mother has not come down to us. Two of the science’s most
+illustrious expounders were Buffon and Oliver Goldsmith, from both of whom we
+learn (<i>L’Histoire generale des animaux</i> and <i>A History of Animated Nature</i>)
+that the domestic cow sheds its horn every two years.</p>
+
+</body>    
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/Z.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 552
+length 5097
+396 2 10 body html
+0
+2130 2 41 body html
+19
+3447 2 64 body html
+141
--- /dev/null
+++ b/lib/ebooks/devils/devil.css
@@ -1,0 +1,203 @@
+p {
+    text-align: justify
+   }
+
+p.title {
+    margin-bottom: 1em
+    }
+
+p.entry {
+    margin-top: .33em;
+    text-indent: 0em;
+    margin-bottom: 0em
+    }
+
+p.firstpara {
+    text-indent: 0pt;
+    }
+
+p.indentpara {
+    text-indent: 1em;
+    }
+
+p.poem {
+    font-size: smaller;
+    text-align: left;
+    text-indent: 0em
+    }
+
+p.po {
+    font-size: smaller;
+    text-align: left;
+    margin-bottom: 0;
+    margin-top: 0em;
+    text-indent: 0em
+    }
+
+p.poind1 {
+    font-size: smaller;
+    text-align: left;
+    margin-bottom: 0;
+    margin-top: 0em;
+    text-indent: 1em
+    }
+p.poind2 {
+    font-size: smaller;
+    text-align: left;
+    margin-bottom: 0;
+    margin-top: 0em;
+    text-indent: 2em
+    }
+p.poind3 {
+    font-size: smaller;
+    text-align: left;
+    margin-bottom: 0;
+    margin-top: 0em;
+    text-indent: 3em
+    }
+
+div.poem {
+text-align: center
+}
+
+span.stanza {
+    page-break-inside: avoid;
+    margin-bottom: 1em
+}
+div.stanza {
+    page-break-inside: avoid;
+    margin-bottom: 1em
+}
+
+blockquote.poem {
+    page-break-inside: avoid
+}
+
+table.poem {
+    float: center;
+    text-align: center
+}
+
+td.poem {
+    margin-bottom: 1em
+}
+
+p.citepoet {
+    font-style: italic;
+    font-size: smaller;
+    text-align: right;
+    margin-top: 0;
+    }
+
+p.citeauth {
+    font-style: italic;
+    font-size: smaller;
+    text-align: right;
+    margin-top: 0;
+    }
+
+p.quote {
+    text-indent: 1em;
+    margin-top: 0em;
+    margin-bottom: .5em;
+    font-size: smaller
+    }
+
+cite {
+    text-indent: 12pt;
+    margin-top: 1em;
+    margin-bottom: 1em;
+    font-size: smaller
+    }
+
+.title {
+    text-align: center
+    }
+
+span.def {
+    font-weight: bold
+    }
+
+span.pos {
+    font-style: italic;
+    } /* part of speech formatting */
+
+/*SPAN.smallcap {
+    text-transform: small-caps;
+    }
+*/
+
+span.rj {
+    text-align: right
+    }
+
+span.ind1 {
+    margin-left: 30px
+    }
+span.ind2 {
+    margin-left: 2em
+    }
+span.ind3 {
+    margin-left: 3em
+    }
+span.ind4 {
+    margin-left: 4em
+    }
+span.ind5 {
+    margin-left: 5em
+    }
+span.ind6 {
+    margin-left: 6em
+    }
+
+a:link {
+    color: rgb(204,0,0);
+    text-decoration: none
+}
+
+a:visited {color: rgb(51,0,153)}
+
+a:active {color: rgb(255,204,51)}
+
+body {
+    color: rgb(0,0,0);
+    background-color: rgb(255,255,255);
+    font-family: 'Times New Roman', Times, Serif}
+
+h1 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 24pt;
+    text-align: center
+    }
+
+/*H1.title {
+    text-transform: capitalize
+    }
+*/
+
+h2 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 18pt}
+
+h3 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 14pt}
+
+h4 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 12pt}
+
+h5 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 10pt}
+
+h6 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 8pt
+    }
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/foreword.html
@@ -1,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+    "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: Editor&rsquo;s Foreword</title>
+</head>
+<body lang="en-us">
+
+<h1>Editor&rsquo;s Foreword</h1>
+
+<p class="firstpara">This Open eBook edition of <i>The Devil&#x2019;s Dictionary</i> was begun as a way for
+me to learn the Open eBook (OEB) structure and how to write clean XHTML that duplicates the original formatting of the 
+typeset edition.</p>
+
+<p class="indentpara">Having hit the limitations of the OEB format and current OEB readers in this attempt, I am
+posting this early version of my conversion effort as a test document that illustrates the shortcomings of the
+format and is meant to encourage the developers to address these issues in forthcoming versions of their software
+and the OEB specification itself.</p>
+
+<p class="indentpara">The most difficult problem I have faced in formatting <i>The Devil&#x2019;s Dictionary</i>
+has been poetry. The print copy I own has the poems formatted so that the attribution line is right justified
+with the end of the longest line of the poem, no stanza is broken across pages, and the whole thing is centered
+within the margins of the body text. This is a very natural way to format the poetry, yet it is impossible to
+duplicate this structure with the current eBook readers&mdash;most notably, with Microsoft Reader.</p>
+
+<p>First, the only
+way to create the desired justification and centering with HTML is to place the whole poem inside one table. This
+works for small poems, but not for larger ones because MS Reader cuts off all text in a table cell when the end
+of the page is reached, preventing long poems from being displayed in their entirity. Additionally, if each stanza
+is placed inside a pair of paragraph tags (as would seem natural) many of the indents must be accomplished by
+adjusting the left margin of that individual line with a <code>&lt;span&gt;</code> tag. This should work, since
+both this tag and the left margin property are applied to all elements (block and inline) according to the HTML and
+CSS specifications. MS Reader, however, ignores this instruction. An example of this formatting
+is found in the &ldquo;A&rdquo; section of the <i>Dictionary</i>.</p>
+
+<p>An alternate way to format the poems is to enclose each poem in a <code>&lt;blockquote&gt;</code> tag,
+each line in its own paragraph tag (with different CSS classes to handle the needed indents and close up
+the line spacing) and, each stanza in a <code>&lt;span&gt;</code> tag (with the CSS page-break-after property set
+to avoid breaking across pages). However, the blockquote&rsquo;s margins causes many poems towrap, does not
+center the poem, places the attribution line (and any right-justified lines of the poem) almost at the right margin
+of the book (sometimes far away from the poem itself), and MS Reader ignores the instructions to not
+wrap the stanzas. This method is demonstrated in the &ldquo;B&rdquo; section of the <i>Dictionary</i>.</p>
+
+<p>As I was writing this, I thought of what should have been an obvious construct for these poems: putting
+each stanza in a separate table cell. This solves many, but not all, of the problems described above. For poems
+with short- or medium-length stanzas viewed with the PC version of MS Reader on a large-screen laptop
+it should work fine. But for a PocketPC, or even for poems with long single stanzas on a PC, the bottom of each long
+stanza will still be lost. You can see the results of this experiment in the &ldquo;C&rdquo; section of the
+<i>Dictionary</i>.</p>
+
+<p>These issues can best be demonstrated by one representative poem in each of the first three sections, when
+reading the book in the desktop version of MS Reader. <a href="A.html#abracadabra">Abracadabra</a> should
+be separated into stanzas with 1em of space between each, but since Reader ignores the <code>&lt;span&gt;</code>
+tag, it is just one long block. The poem cited under the definition of <a href="B.html#beg">beg</a> exemplifies
+the problems with the wide right margin described above. Although not perfect, the poem cited under
+<a href="C.html#carmelite">carmelite</a> is presented almost exactly as it should be. The poem is properly
+centered, the indents and right justification appear as intended, and the poem is broken across pages only
+between stanzas. But when viewed on a smaller screen (almost certainly with a Pocket PC) the first stanza
+alone will likely be cut off.</p>
+
+<p>A major additional problem, not specific to this book, is the inability of any current OEB reader to handle
+Unicode text, as mandated in the OEB specification. An example of how such a Unicode document appears is
+demonstrated in sections &ldquo;D&rdquo; (UTF-8) and &ldquo;E&rdquo; (UTF-16) of the <i>Dictionary</i>. Notice that
+the Unicode signature/byte-order mark which appears at the beginning of each of these files causes problems with
+both the readers and with the authoring tools. The MobiPocket Publisher can not complete the conversion
+process at all, and while ReaderWorks handles both relatively OK, MS Reader can not display UTF-8 files
+correctly (the Unicode signature causes it to ignore all CSS formatting and UTF-8 characters are displayed
+as their literal byte sequence, something specifically forbidden by the OEB specification) and the whole
+section &ldquo;E&rdquo; disappears because of the byte-order mark.</p>
+
+<p>Most sections beyond E have not yet been fully formatted, so please do not expect them to look pretty.</p>
+
+<h2>Project Gutenberg</h2>
+
+<p class="indentpara">Another goal is much broader. I have long known of Project Gutenberg, but have
+always found its insistence on plain ASCII to be a handicap that limited its appeal and usability. Don&#x2019;t
+get me wrong&#x2014;the effort has provided a  tremendous resource, and at the time the project was begun
+(and until very recently) plain ASCII was clearly the best  choice. But you can&#x2019;t properly format a book
+with just ASCII characters. Not only must basic things such as *bold* and _italics_ be indicated in a funky
+manner, it is simply impossible to preserve the accented characters, ligatures, and many other important
+features. And trying to display such a work legibly on a PDA or eBbook reader with a small screen is
+impossible, given the hard line breaks that are present (keeping the text from flowing properly).</p>
+
+<p class="indentpara">With is footing solidly in HTML and XML and its completely open nature, the Open eBook
+format is the ideal structure in which to continue the goals of Project Gutenberg on into the 21<sup>st</sup>
+century. So this edition of <i>The Devil&#x2019;s Dictionary</i> is not meant just as a personal learning
+project, but as an example of the benefits to offering current and future editions as Open eBooks. I don&#x2019;t
+dispute the benefits of the current plain ASCII versions, but with the right automation tools, future editions
+could begin as Open eBooks and then be converted to plain ASCII, making both versions available without
+duplicated effort. This would be far preferable to starting with plain ASCII versions and converting them to
+Open eBook. This is the method I obviously used for this edition, and I assure you that it is quite tedious 
+and not well-suited as a standard practice.</p>
+
+<p style="text-align: right">Peter K. Sheerin</p>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/foreword.html.i
@@ -1,0 +1,13 @@
+5 pages
+size 400 552
+length 7632
+421 2 10 body html
+0
+1633 2 29 body html
+119
+3826 2 54 body html
+34
+5770 2 76 body html
+0
+6646 2 87 body html
+238
--- /dev/null
+++ b/lib/ebooks/devils/index.html
@@ -1,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Package//EN"   
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<link rel="stylesheet" type="text/css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: Table of Contents</title>
+</head>
+<body lang="en-US">
+<h1 align="center">Table of Contents</h1>   
+<p><a href="TitlePage.html">Title Page</a></p>   
+<p><a href="foreword.html">Foreword</a></p>   
+<p><a href="preface.html">Author&#8217;s Preface</a></p>   
+<ul>   
+  <li><a href="A.html">A</a></li>   
+  <li><a href="B.html">B</a></li>   
+  <li><a href="C.html">C</a></li>   
+  <li><a href="D.html">D</a></li>  
+  <li><a href="E.html">E</a></li> 
+  <li><a href="F.html">F</a></li>
+  <li><a href="G.html">G</a></li>
+  <li><a href="H.html">H</a></li>
+  <li><a href="I.html">I</a></li>
+  <li><a href="J.html">J</a></li>
+  <li><a href="K.html">K</a></li>
+  <li><a href="L.html">L</a></li>
+  <li><a href="M.html">M</a></li>
+  <li><a href="N.html">N</a></li>
+  <li><a href="O.html">O</a></li>
+  <li><a href="P.html">P</a></li>
+  <li><a href="Q.html">Q</a></li>
+  <li><a href="R.html">R</a></li>
+  <li><a href="S.html">S</a></li>
+  <li><a href="T.html">T</a></li>
+  <li><a href="U.html">U</a></li>
+  <li><a href="V.html">V</a></li>
+  <li><a href="W.html">W</a></li>
+  <li><a href="X.html">X</a></li>
+  <li><a href="Y.html">Y</a></li>
+  <li><a href="Z.html">Z</a></li>
+</ul>
+</body>
+</html> 
--- /dev/null
+++ b/lib/ebooks/devils/index.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 1530
+400 2 10 body html
+0
+603 2 15 body html
+357
--- /dev/null
+++ b/lib/ebooks/devils/preface.html
@@ -1,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+    "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="devil.css" />
+<title>The Devil&#8217;s Dictionary: Preface</title>
+</head>
+<body lang="en-us">
+
+<h1>Preface</h1>
+
+<p class="firstpara"><i>The Devil&#x2019;s Dictionary</i>
+was begun in a weekly paper in 1881, and was continued in a desultory way at 
+long intervals until 1906. In that year a large part of it was published in 
+covers with the title <i>The Cynic&#x2019;s Word Book</i>, 
+a name which the author had not the power to reject or happiness to approve. To 
+quote the publishers of the present work:</p> 
+ 
+<p class="indentpara">&#x201c;This more reverent title had previously been forced upon him by the religious scruples of 
+the last newspaper in which a part of the work had appeared, with the natural 
+consequence that when it came out in covers the country already had been 
+flooded by its imitators with a score of &#x2018;cynic&#x2019; books&#x2014;<i>The Cynic&#x2019;s This</i>, <i>The Cynic&#x2019;s That</i>,
+and <i>The Cynic&#x2019;s t&#x2019;Other</i>. Most of these books 
+were merely stupid, though some of them added the distinction of silliness. 
+Among them, they brought the word &#x2018;cynic&#x2019; into disfavor so deep that any book 
+bearing it was discredited in advance of publication.&#x201d;</p>
+
+<p class="indentpara">Meantime, too, some of the enterprising humorists of the country had helped themselves to such 
+parts of the work as served their needs, and many of its definitions, 
+anecdotes, phrases and so forth, had become more or less current in popular 
+speech. This explanation is made, not with any pride of priority in trifles, 
+but in simple denial of possible charges of plagiarism, which is no trifle. In 
+merely resuming his own the author hopes to be held guiltless by those to whom 
+the work is addressed&#x2014;enlightened souls who prefer dry wines to sweet, sense to 
+sentiment, wit to humor and clean English to slang.</p>
+
+<p class="indentpara">A conspicuous, and it is hope not unpleasant, feature of the book is its abundant illustrative 
+quotations from eminent poets, chief of whom is that learned and ingenius 
+cleric, Father Gassalasca Jape, S.J., whose lines bear his initials. To Father 
+Jape&#x2019;s kindly encouragement and assistance the author of the prose text is 
+greatly indebted.</p>
+
+<p style="text-align: right">A. B.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/devils/preface.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 552
+length 2629
+405 2 10 body html
+0
+1546 2 30 body html
+170
--- /dev/null
+++ b/lib/ebooks/oebtest/BART.html
@@ -1,0 +1,323 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Fixing BART Safety</title>
+</head>
+
+<body>
+
+<h1>Fixing BART Safety (Bay Area Rapid Transit System)</h1>
+
+<h2>(1972–1974)</h2>
+
+<p>Wattenburg’s two-year running battle with the BART agency appears to be the first time
+he publicly confronted a government agency as a scientist. We found over fifty-five
+press reports with his name involved with this subject during the period 1972 to 1974. Some of
+the history we summarize below comes from a U.S. Department of Transportation (DOT) internal
+report we obtained from a congressional staff member. DOT was evidently funding BART and
+concerned about Wattenburg’s highly publicized criticisms of BART management.</p>
+
+<p>The State of California asked Wattenburg to fix the electronic train control problems that
+plagued the new Bay Area Rapid Transit System (BART). BART and Westinghouse Corp.
+engineers who designed the system insisted that there were no problems and essentially told the
+State of California safety officials to go to hell. BART claimed that the state safety officials were
+needlessly preventing Bay Area commuters from getting full benefit of the BART system.</p>
+
+<p>With the encouragement of exasperated state officials, Wattenburg, acting only as a taxpayer,
+confronted the local BART managers at their bi-weekly public meetings for two years running
+while many of his public predictions of safety problems came true. BART management was
+eventually fired, and the State demanded that Wattenburg’s clever design modifications be
+installed before the BART system could run full service. The press confirmed that Wattenburg
+refused all payment from BART and the State for his efforts.</p>
+
+<p>During this nationally publicized battle, Wattenburg first described many of his design
+improvements for BART to the press and over KGO Radio in terms that the lay public could
+understand. It became a popular game for his listeners to know more—and sooner—about BART
+design problems than the BART engineers. He generated press headlines the next day for months
+on end. His radio shows and the subsequent press stories each week carried his predictions of the
+next problem or accident that would occur on BART—and they invariably happened on schedule.
+He literally intimidated the incompetent BART management out of office with the power of talk radio.</p>
+
+<br />
+<p><b>Here is a summary of the sequence of events:</b></p>
+<br />
+
+<p>BART as an independent agency experienced some early safety problems with a new
+electronic train control system built by Westinghouse Corp. One train ran away during trial runs
+of the new BART system. BART and Westinghouse engineers insisted that this was a “one in a
+hundred-million failure that could never happen again.” BART would not cooperate with state
+agencies that wanted to investigate these problems before giving BART approval to operate the
+trains.</p>
+
+<p>The noted California legislative analyst, A. Alan Post, enlisted U. C. Berkeley Professor
+Bill Wattenburg to evaluate the design of the BART automated train control system designed by
+Westinghouse. Wattenburg subsequently testified at a state senate committee hearing that he had
+found some serious design flaws in the Westinghouse design and warned that the system was
+unsafe to operate. Westinghouse and BART both protested vehemently that Wattenburg was
+unqualified in the field and that he was “just a headline grabbing radio talk-show host and only a
+junior faculty member at Berkeley looking to impress his students.”</p>
+
+<p>Wattenburg was the sole expert witness for the state. Seven senior Westinghouse and
+BART executives told the confused state senators that Wattenburg was wrong.</p>
+
+<p>A flurry of front-page stories report that Wattenburg then responded by offering a list of
+the most probable dangerous failures that would occur in the BART system that could lead to
+collisions between high-speed trains. He even estimated the time periods for when these failures
+would likely occur. BART and Westinghouse engineers were furious. They denied that any of
+these failures could ever happen. Both BART and Westinghouse threatened to “take legal action
+against Wattenburg if he persisted in making inflammatory statements that destroyed the public’s
+confidence in the BART system.”</p>
+
+<p>Wattenburg’s answer to the BART threats was to give a quote to Herb Caen, the most
+widely read columnist on the west coast. The item appeared the next day in the San Francisco
+Chronicle. Wattenburg said that if the BART train control system was not fixed, it would be “the
+world’s most expensive, computer-controlled, track-mounted pinball machine.” The battle lines
+were drawn. Bay Area readers who were riding BART were shocked by the front-page stories
+that appeared the next day.</p>
+
+<p>The first of Wattenburg’s predictions actually occurred the following week as the
+California Public Utilities Commission (PUC) inspectors were monitoring the BART operation.
+They discovered that trains disappeared at certain times from the master control panel. Central
+controllers didn’t know where some trains were on the tracks for several minutes at a time. This
+meant that the automated train control system could be telling one train to speed right into
+another train parked ahead—a train that it didn’t know about. This is the most dangerous
+situation that can happen on any railroad.</p>
+
+<p>Naturally, the PUC and the press swarmed all over Wattenburg to explain why he was able
+to predict that this would happen. He told them he could only show them with “a little
+experiment”, and that BART would have to cooperate to let him demonstrate the cause of the
+problem. BART objected. The PUC threatened to shut BART down completely unless BART
+could identify the problem or prove it was corrected immediately. BART allowed Wattenburg to do
+his experiment.</p>
+
+<p>Wattenburg led everyone to a section of unused BART track early on a foggy morning.
+He pointed to the rusty surface on the normally shiny track. He motioned for a waiting train to
+move forward. He told a PUC inspector to call his colleagues waiting at BART central.
+Wattenburg said: “I’ll bet they can’t see that train right now.” The reporters watched the PUC
+inspector get the word from BART central and then nod that Wattenburg was right.</p>
+
+<p>Next, Wattenburg ordered the train to run back and forth over this stretch of track several
+times. He announced: “Now they can see the train.” The PUC inspector on the portable phone
+confirmed that he was right again. Then Wattenburg gave them the answer and how he was able
+to predict the problem.</p>
+
+<p>He explained that he had first noticed that the Westinghouse designers had used very low-voltage (less than a volt) to shunt a current across the rails through the steel wheels and axle of a
+train. This shunt signal is what tells central control that a train is at a given location. Standard
+train control systems use a much higher voltage, like 15 volts. He explained how this low-voltage
+scheme probably worked very well in the nice, clean Westinghouse factory where they tested their
+new design. But it doesn’t rain inside the factory. When it rains, or there is heavy fog, the shiny
+steel rails take on a thin layer of rust very quickly. The rusty surface has a much higher electrical
+resistance that clean rails. The low voltage cannot drive a current through the rusty surface on
+the rails. Hence, there is no signal of where the train is on the tracks.</p>
+
+<p>Then, according to the press reports, he made another seemingly arrogant prediction. He
+told them that a train would only disappear when:</p>
+
+<ol>
+ <li>The track had not been used for several hours during rain or heavy fog, and</li>
+ <li>The missing train would be the first or second train to use the track after the
+ unused period during which the track had been exposed to rain or fog.</li>
+</ol>
+
+<p>“Other than that,” he said, “the BART system was marginally safe and
+riders shouldn’t worry.”</p>
+
+<p>The PUC inspectors rushed to check their records of past missing trains. BART public
+relations issued a press release saying that Wattenburg was trying to “dazzle the press with
+scientific hocus-pocus.” The Bay Area papers all included the BART accusation in their stories.</p>
+
+<p>The PUC confirmed that Wattenburg was right two days later. Trains had only disappeared on the BART tracks in the early mornings after it had rained or been very foggy the
+night before, and it was almost always the first or second train over the tracks. But, there was one
+case in which a third train had been missing for short intervals as well.</p>
+
+<p>BART public relations next tried to suggest that everything that Wattenburg said shouldn’t
+be believed because he had not been accurate about how many trains were required to clean the
+tracks so that BART could run safely. When the press asked Wattenburg for his comments on this,
+he said: “Well, I guess I screwed up on that third train. I’ll have to take back what I said. The
+system is not as safe as I thought it was.”</p>
+
+<p>BART soon announced that it had solved the missing train problem by installing special
+“scrubbers” on its trains. (The scrubbers were nothing more than pieces of metal dragged along
+the track to scrape off the rust.) BART would run special “pilot” trains every morning to make sure
+the tracks were clean before passenger trains moved onto the tracks. Their press release stated
+that no one could have predicted this problem because “the special rails that they had ordered for
+this futuristic system had never before been tested.”</p>
+
+<p>Wattenburg countered with his usual stinging sarcasm: “This is really a futuristic system,
+alright. I wonder if anyone ever reminded them that in the eighteen hundreds the cities used to
+hire boys to walk along behind horse-drawn carriages to scoop up the horse manure so it wouldn’t
+blow in the citizens’ faces?”</p>
+
+<p>He then announced his next challenge. He said that he had had his electrical engineering
+students at CAL design a simple battery-powered electronic package that any BART rider could
+carry along with him on the train to make sure that the train control system knew where the train
+was at all times. “I mean these are my undergraduate students. They don’t know enough yet to
+design anything fancy. So, it’s cheap and it works great. Just ask the PUC inspectors. I’ll bet they
+were wondering why train number 102 never disappeared this morning even though it rained last
+night.”</p>
+
+<p>A reporter hinted that one of Wattenburg’s students had been on that train. The story
+reported that the device his students had built was nothing more than a radio frequency noise
+generator that messed up the normal train control signals in the track immediately below the train
+wherever it went. This caused the train control error detection circuits to report a problem at
+that location. This created a moving problem indicator with the train number on it to appear on
+the central control screen. Hence, the error indicator told central control where the train was at
+all times.</p>
+
+<p>Westinghouse engineers immediately complained that this scheme would disable their
+error detection circuits and endanger the whole BART system. Wattenburg countered with:
+“Why in the hell do you need error detection electronics when you know the whole damn system
+is broken down all the time anyway without even asking? Why not put these unemployed circuits
+to work so that we can get some people to work for a change?”</p>
+
+<p>The PUC wanted to test the device immediately. BART threatened to have Wattenburg
+arrested if he took any electronic device on a train that interfered with the train control system.
+Wattenburg offered the press an estimate of how long it would be before the BART track
+scrubbers would cut so much metal off the rails that they would have to be replaced. A later story
+suggested that the PUC did test Wattenburg’s device and BART agreed to use it so long as the
+PUC ordered BART to do so and Wattenburg agreed to say no more about it. However,
+Westinghouse notified BART that all its warranties would be voided if any foreign device was
+installed or used without their permission. It’s not clear what happened thereafter, but the missing
+train problem did suddenly disappear—at least from the press coverage.</p>
+
+<p>After this episode, the press evidently began to believe that Wattenburg was for real. The
+stories that followed looked into both his background and the qualifications of the Westinghouse
+designers.</p>
+
+<p>A reporter discovered that NASA had hired Wattenburg in 1963 to 1967 to do extensive
+design work on the electronic control and computer systems for the Apollo man-to-the moon
+project. Westinghouse and BART had earlier claimed that their engineers had worked on the
+Apollo project to support their claims to the state senate committee that they were “the world’s
+experts on advanced automated control systems of this nature and that no one else was qualified
+to evaluate the BART train control design.” Press stories verified that the Westinghouse
+engineers who were later assigned to the BART project had actually worked several levels below
+Wattenburg’s design responsibility in NASA. (Evidently, Legislative Analyst A. Alan Post had
+known this when he first contacted Wattenburg for help.)</p>
+
+<p>When one irritated reporter asked Wattenburg why he had not told the press for months
+about his NASA experience, he answered: “You should have asked me. I noticed that you print
+every handout that the BART bullshitters give you, so why should I bother to tell you the truth.”
+This newspaper later ran an editorial which indirectly apologized to Wattenburg for some of the
+snide stories about him that their reporter had filed after he first challenged BART before the
+state senate committee.</p>
+
+<p>After the dramatic sequence of events described above, the PUC refused permission for
+BART to operate their trains at designed speeds until all of Wattenburg’s technical objections
+were investigated. More state senate hearings were called. Wattenburg appeared at the next
+hearing with alarming data from some more experiments that he had done on his own. BART and
+Westinghouse again protested that he had interfered without their permission. Wattenburg
+described how he had given his engineering students who ride BART some simple instruments
+that measured BART train control signals without interfering with the operation in any way.
+Then he described several more design changes that should be made to the train control
+electronics to make the system safer.</p>
+
+<p>At this dramatic hearing, he gave his new design documents to the state senate committee
+and the Legislative Analyst and asked them to hand these documents to the irate BART General
+Manager, Billy Stokes, who was sitting in the hearing room with a group of Westinghouse
+executives. One story reported that Wattenburg turned to Billy Stokes and announced: “Here’s a
+present for you. Be my guest. That’ll fix the hundred million dollar screw job you guys have
+given the taxpayers.”</p>
+
+<p>The public standoff escalated when the BART District Directors were told by their
+General Manager that Wattenburg was part of a political conspiracy to discredit the District and
+this was the only reason he was trying to embarrass the BART and Westinghouse engineers. This
+made headlines. Wattenburg appeared at the next public BART board meeting and requested to
+speak as a taxpayer. One group of concerned BART directors demanded that he be allowed to
+speak at all meetings as a public representative and rebut anything he felt was not accurate in what
+the general manager and the BART engineers were telling the directors.</p>
+
+<p>The state officials could not direct BART to take any specific action to correct the
+alleged problems, but through the California PUC they could and did withhold permission for
+BART to operate their trains at full speed until the safety problems were resolved. A majority of
+the BART directors refused to allow Wattenburg to test his ideas or order Westinghouse to make
+the simple changes that Wattenburg had specified. The argument was that this would violate the
+warranties in the Westinghouse contract and open up BART to lawsuits from both Westinghouse
+and the taxpayers. Almost weekly front-page stories in the San Francisco Chronicle and other Bay
+Area papers detail how BART was forced to operate their new trains under severe restrictions
+that guaranteed that trains could not collide if the train control system malfunctioned.</p>
+
+<p>More serious problems and near accidents did occur over the next six months. These were
+witnessed by PUC inspectors stationed in BART central control. Some of these were on the list
+that Wattenburg had originally given to the state senate committee and A. Alan Post. Wattenburg
+appeared at every BART board meeting and battled with the BART and Westinghouse engineers.
+Wattenburg challenged the credentials of three successive chief engineers at BART. All of them
+left or were fired. These confrontations became the media event of the week for the press as the
+controversy raged.</p>
+
+<p>The matter finally came to a head when BART ran out of money and had to appeal to the
+state for financial assistance to operate the system. The State Senate Transportation
+Committee
+headed by Senator Alfred Alquist demanded that Billy Stokes be fired as a condition for approval
+of any state funds. Wattenburg was in attendance. A story reports that he stood up and
+announced to Mr. Stokes: “I told you that the truth would catch up with you, you lying bastard.”
+(Wattenburg had earlier called Stokes a liar at several public BART meetings when Stokes and his
+chief engineers gave engineering reports to the board members that Wattenburg proved were false
+or incomplete. Stokes had been forced to apologize for these
+“oversights”. The chief engineers were replaced shortly thereafter.)</p>
+
+<p>The state legislature finally passed a law that required elected board members for BART
+as a condition for state financial assistance. All the Billy Stokes supporters on the BART board
+were replaced in the election. Wattenburg refused requests that he run for the board or agree to be
+the new general manager (two papers editorialized that he should serve). The new board
+immediately ordered BART engineers to incorporate Wattenburg’s design changes into the train
+control system. Wattenburg recommended that BART hire the University of California Lawrence
+Berkeley Laboratory to supervise the design modifications. BART hired Hewlett-Packard
+Corporation to build and install the equipment.</p>
+
+<p>Wattenburg issued a press release in which he stated that he had done all he could and that
+he wanted nothing more to do with BART other than ride the trains when they could “safely
+move faster than he could walk.”</p>
+
+<p>Hewlett-Packard and Lawrence Berkeley Laboratory were paid over two million dollars
+for their work over the next two years which consisted mostly of installing improved versions of
+the train control design changes that Wattenburg had originally specified. There were press
+reports that Hewlett Packard engineers later insisted that all the new design changes were their
+own ideas and that this created some friction between them and Lawrence Berkeley scientists who
+claimed otherwise. Wattenburg refused to get into the argument or comment to the press. His
+only comment was that he “never wanted to hear about BART again.”</p>
+
+<p>The new BART board filed suit against Westinghouse after the design changes proved to
+solve the missing train problem and other safety problems. The PUC allowed them to run trains at
+design speeds for the first time in five years. Wattenburg agreed to testify for BART if requested.
+Westinghouse settled the suit for a reported sixteen million dollars.</p>
+
+<p>When the press inquired whether Wattenburg had received any payment for his services
+over two years, he gave them the following statement: “Hell, if I had even asked for a free ride on
+their silly trains somebody would have claimed that I did it just to get a handout. The taxpayers of
+the State of California gave me a great education. All I want is for them to know that I paid them
+back in full.”</p>
+
+<p>Some BART directors suggested offering Wattenburg $50,000 for his services after his
+solution to the BART train control problem was adopted. He declined, saying that he might have
+to criticize them again in the future if they didn’t do their job.</p>
+
+<p>The Department of Transportation internal report points out that another real beneficiary of
+Wattenburg’s efforts is the Washington D.C. Metro system. All of Wattenburg’s design
+improvements were incorporated into the Metro system before it was opened. As a consequence,
+the Metro did not suffer the long delays and safety problems that BART suffered. The author of
+this report notes the curious fact that Westinghouse had to have been making some of these
+changes in the Metro equipment they delivered to Washington even while they were still insisting
+that Wattenburg’s changes were not necessary in the BART system. Otherwise, there would have
+been long delays in starting operation in Washington. The writer suggests that DOT might
+consider some sort of recognition to Wattenburg for his contribution to the mass transit industry
+in the U.S.</p>
+
+<p>It is not surprising that such recognition never came. We talked to a long-time BART
+employee who was on the scene at the time all this happened. He said that the new general
+manager selected for BART was none other than the former Secretary of Transportation who had
+given some support to Billy Stokes during his battles with Wattenburg, and that Billy Stokes
+himself moved upstairs as the new Director of the Urban Mass Transit Association
+(UMTA) representing such companies as Westinghouse. The UMTA and DOT officials work very closely
+together.</p>
+
+<p>During our visits to this KGO radio show in October 1990, several callers to his show
+wanted to talk about the most recent problems with the BART system. He absolutely refused to
+discuss the subject on his show. He said to one caller, “I’ll tell you what though, why don’t you
+ask me about my first wife?”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/BART.html.i
@@ -1,0 +1,33 @@
+15 pages
+size 400 562
+length 22832
+408 2 11 body html
+0
+1503 2 30 body html
+34
+2772 2 49 body html
+136
+4665 2 75 body html
+34
+6253 2 97 body html
+34
+7896 2 117 body html
+34
+9056 2 137 body html
+136
+10974 2 163 body html
+34
+11997 2 177 body html
+238
+13838 2 201 body html
+170
+15608 2 225 body html
+85
+17088 2 243 body html
+136
+18478 2 262 body html
+221
+20407 2 288 body html
+102
+21936 2 309 body html
+119
--- /dev/null
+++ b/lib/ebooks/oebtest/BentSub.html
@@ -1,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Downhole Drillbit</title>
+</head>
+
+<body>
+
+<h1>Downhole Drillbit</h1>
+
+<h2>(1990’s)</h2>
+
+<p>We were told by some Livermore engineers in November 1992 that Bill Wattenburg has
+been working on a device for drilling oil wells that could save enormous amounts of money and
+improve the safety of drilling if he is successful. Neither he nor they would tell us what it was.
+They would only tell us that everyone else has failed for fifty years to achieve this “driller’s
+dream”. They said that some company with a lot of money bet Wattenburg that it couldn’t be
+done. They said that his first experiment failed. Because of that alone, they figured he would
+have it solved before long. <q>That’s how he gets warmed up.</q></p>
+
+<hr />
+
+<p><i>[Note: Bill did succeed in this task, and has since received two patents
+on the resulting invention—PKS]</i></p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/BentSub.html.index
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 1245
+407 2 11 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/BlueWater.html
@@ -1,0 +1,293 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Blue Water Contamination</title>
+</head>
+
+<body>
+
+<h1>Blue Water (Copper) Contamination in Homes</h1>
+
+<h2>(1991)</h2>
+
+<p>This is the latest of Wattenburg’s bizarre escapades reported in press stories all over the
+country. We contacted many of the people who were on the scene to get interesting parts of
+this story that were not covered by the press.</p>
+
+<p>Hundreds of expensive new homes in the affluent area of Danville, California, had suffered
+serious copper contamination (blue water) for several years. Lawsuits were filed in all directions
+because homeowners had to use bottled water, children in schools had become sick, and home
+values were dropping. Neither the water company (EBMUD) nor the home builders would take
+responsibility. Both had spent over $5,000,000 on water corrosion experts and lawyers who were
+investigating the problem.</p>
+
+<p>A professor of civil engineering who was on the project at times has told us that he could
+show us hundreds of technical reports on blue water from around the world in the last fifty years
+where corrosion experts have been unable to completely explain the cause of “blue water”. He
+told us: “In many cases the problem just mysteriously goes away for reasons that ‘corrosion
+experts’ cannot adequately explain, although most take credit for doing something the solved their
+local problem. However, each one claims he found a different solution that does not seem to
+work everywhere else.”</p>
+
+<p>We called Wattenburg to tell us why and how he solved the problem in Danville. He
+cautioned us immediately that he did not completely solve the problem, in spite of what the
+newspaper and technical journals reported. He said: “It is one thing to isolate a problem and then
+make it go away. I do that with obnoxious people all the time. But it is another thing to explain
+why they came around in the first place.” (This may have been a message to us, but he softened
+up after that.)</p>
+
+<br />
+<p><b>Here is his story:</b></p>
+<br />
+
+<p>He said he got involved when some Danville home owners called him on his KGO radio
+show in May 1991. They pleaded with him to help them because they were losing their life
+savings in the value of their homes. They described the blue water problem to him on the air.
+They told him that there was conclusive proof that the contamination was copper hydroxide.
+They told him that the only copper pipes were the water pipes in their homes. He says he “shot
+his mouth off and told them that good scientists should have no problem finding the problem very
+quickly if they did the proper experiments.”</p>
+
+<blockquote>
+<p>“They asked me how much I thought it should cost. I stupidly said that it shouldn’t cost
+more than a few thousand dollars for a good scientist to make the right measurements. I told
+them to call the Lawrence Livermore National Laboratory which is right near them. The next day,
+I got a call from the Livermore Lab saying they were getting calls from people pleading with them
+to help, and the newspapers were asking them why the laboratory didn’t help solve this serious
+problem. Livermore said they couldn’t get involved because there was litigation going on and the
+water company was a public agency that had not requested their services. I got the picture, but I
+was stuck. I went out there the next day to take a look.”</p>
+</blockquote>
+
+<p>A civil engineering professor who was working on the problem as a consultant to the
+homebuilders told us the story we summarize below:</p>
+
+<p>He says that Wattenburg quickly made a startling discovery right in the faces of the water
+corrosion experts who had been working on the problem for a year. They had been studying
+only the corrosion characteristics of the water in the house pipes. They had expensive water
+chemistry testing laboratories set up in the garages of two blue water homes supplied by the
+builders. Wattenburg walked out of one of these laboratories while they were still telling him
+about all their experiments. He got some things out of his car. Then he stuck some small copper
+rods into the ground at various points around the house and measured the voltages between these
+points with a little voltmeter that he carried in his pocket. They thought he was a little strange.</p>
+
+<p>He found electrical voltages of about half a volt in the ground all around the homes and
+between the ground and the water pipes in the homes. “He did this within about twenty minutes
+after he arrived. The gadgets he had in the trunk of his car looked like an electronics laboratory.
+He then told us to go to the hardware store and buy all the small copper wire we could find, I
+remember the driver asking him how much? He calmly said: ‘Oh, about a mile of it, if you can.’ It
+was rather amazing what we did all the rest of that day.”</p>
+
+<blockquote>
+<p>“Wattenburg made some more measurements around and inside several more blue water
+houses. Then he told all the corrosion consultants who were gathered around that the problem
+probably wasn’t in the houses or in their copper water pipes. The real cause was most
+likely coming from the power lines or EBMUD water mains somehow. At that point, most of them
+walked away shaking their heads. Wattenburg told me that he was surprised that these guys were
+corrosion experts. He said that the corrosion was most likely happening because there was
+electrochemistry going on in the copper pipes. He said that they obviously hadn’t worried about
+what was producing the ‘electro’ part of the electrochemistry they thought they were studying.
+It made sense to me after I thought about it a while. …</p>
+
+<p>“I remember one of them asking him what degrees or credentials he had as a corrosion
+engineer. I’ll never forget what Wattenburg said to the guy. He asked the guy how long he had
+been working on this problem. This very huffy guy said he had been working on the project for a
+year. Wattenburg told him: ‘Where I went to school. we don’t give degrees to engineers who
+can’t solve a problem in a year.’</p>
+
+<p>“Fortunately, I knew who Wattenburg was. I remembered what he had done to a lot of
+big-time engineers on the BART project many years earlier. I found it best to just help him and
+see what would happen. …</p>
+
+<p>“The water company, EBMUD, claimed that Wattenburg’s theory was nonsense. The
+water mains leading into the houses were plastic lines. They said these lines couldn’t possibly
+feed electrical current into the house water pipes. Wattenburg asked them to explain the electrical
+voltages he found in the ground and between the houses. They pointed the finger at the power
+company, PG&amp;E. I remember Wattenburg smiling as he told us: ‘Well, that will get PG&amp;E out
+here to help us in a hurry, won’t it?’</p>
+
+<p>“The next thing he did was cut all the electrical power off from the test houses and measure
+the voltages again. The voltages in the ground and on the house water pipes were still there. I
+saw him go down the street opening manholes to the water mains all over the place while
+suspicious EBMUD employees got on their mobile phones and called their office.</p>
+
+<p>“Over the next few weeks, Wattenburg used his long copper wires to measure voltages
+along the large steel water mains which were buried deep underground. The water company had
+told him that there was no way they would dig up the lines at various points so he could measure
+them. So, he figured out a very clever way that no one had thought about before. The water
+mains were protected by devices called sacrificial anodes which are connected to the lines below
+ground. But electrical wires attached to these devices are brought up to the ground at various
+places along the lines, about every half mile. This is why he wanted the mile of copper wire. We
+stretched the copper wire between the anode stations and he measured the voltage from one to
+the next. In this way, he mapped the voltages on the steel water mains all the way to the water
+storage tanks where the lines began up on the hills.”</p>
+</blockquote>
+
+<p>The home builders assigned one of their construction superintendents to help Wattenburg.
+Here is what he observed: </p>
+
+<blockquote>
+ <p>“The Power company, PG&amp;E, was real happy to help him. He was getting them off the
+ hook for ten million dollars of liability. I remember one day he calmly told them to cut the power
+ off of a whole area in Danville because he had to be sure that these water main voltages were not
+ coming from the PG&amp;E power lines. I couldn’t believe it when a whole goddamn shopping center
+ went dead right before my eyes about fifteen minutes later. … He only wanted it off for a few
+ minutes. … Hell, they’d have put me in jail if I had even cut their power accidentally.</p>
+
+ <p>“It really became a circus after that. The water company, EBMUD, realized what he was
+ doing. They refused to give him permission to measure the voltages on their water mains at
+ places where their lines were behind fences and near their pumping plants. Wattenburg just told
+ us to get more copper wire. PG&amp;E sent out two more line crews that very day and they helped
+ stretch the copper wires around these areas for a mile or more while EBMUD employees stood
+ guard at their gates to make sure he didn’t trespass on their property. It was like two armies
+ facing off each other on the battle line. It was ludicrous. These are two companies that are
+ supposed to be public utilities. …</p>
+
+ <p>“Wattenburg’s answer was to call the newspapers and tell them to come out and watch
+ what was happening. The reporters showed up in droves. It was on the TV news for several
+ days. Finally, the general manager of EBMUD threw in the towel and asked to see Wattenburg.
+ Wattenburg told him to come out where he was working. They had a private conversation while
+ Wattenburg continued to make measurements along the water mains. EBMUD announced that
+ they were going to join the investigation the next day. The EBMUD gates and all the pumping
+ plants were opened for Wattenburg.</p>
+
+ <p>“A PG&amp;E engineer told me that an hour after Wattenburg walked into the first EBMUD
+ pumping plant, I think it was called the New Scenic East Plant, he found a major problem that
+ EBMUD engineers had told the newspapers just couldn’t possibly happen. I remember this
+ big-shot from EBMUD saying on television that all the EBMUD water mains and their pumping plants
+ were completely isolated from the power lines. He said that they had double-checked that there
+ was no electricity getting into their water mains or plants.</p>
+
+ <p>“Wattenburg got PG&amp;E to cut off the power to the plant for a few minutes and he did
+ some measurements that even the PG&amp;E engineers didn’t understand. They objected as well as
+ the EBMUD engineers. However, the PG&amp;E manager ordered them to do what Wattenburg
+ wanted. I think the PG&amp;E manager’s name was Walt Musso from Walnut Creek. Wattenburg
+ then showed EBMUD that they had a major electrical short across the water mains leading into
+ and out of the plant.</p>
+
+ <p>“This hit the newspapers the next day. The EBMUD public relations people were eating
+ crow. EBMUD construction crews were working for the next month digging enormous holes
+ around the plant to find and fix the short in the water mains that were supposed to be isolated
+ from the PG&amp;E lines.”</p>
+</blockquote>
+
+<p>He told us a funny story that happened next:</p>
+
+<blockquote>
+ <p>“Wattenburg casually told the EBMUD construction foreman one day that they should not do something he had observed them doing
+ with a big backhoe near this enormous water main that led into the pumping plant. The foreman
+ said that he had been operating backhoes for twenty years and he had never broken a water line
+ yet. He said that he was going to dig out all the dirt around the large main line for about a
+ hundred feet. He bragged that they wouldn’t even have to turn off the water pressure in the line
+ and interrupt service to their customers while they were doing it. Wattenburg told them that that
+ was what he was afraid of. Wattenburg did a quick calculation of the pressure forces in the
+ curved pipe they were exposing. The foreman laughed and said that EBMUD engineers had done
+ their own calculations, or something to that effect.</p>
+
+ <p>“Wattenburg told the PG&amp;E crews working with us that they should get the hell out there
+ for a while. About an hour later, while we were having coffee at the Blackhawk Cafe, the water
+ main burst and it looked like Niagara Falls had appeared on the hillside above Danville.
+ Wattenburg didn’t even look surprised when we hollered at him to come see what had happened.
+ He didn’t even look up from the newspaper he was reading…”</p>
+</blockquote>
+
+<p>A PG&amp;E lineman remembered:</p>
+
+<blockquote>
+ <p>“Wattenburg did most of his work at night for the next two months. He would show up
+ sometimes at two in the morning and work until dawn. PG&amp;E would send my crew out to help
+ him whenever he wanted us.”</p>
+</blockquote>
+
+<p>Finally, Wattenburg put the word out that he had located the source of the blue water
+problem. There was a big news conference. Wattenburg showed the press some maps of how he
+had traced the electrical voltages all over the maze of water mains in the
+Danville–Blackhawk area. The voltages all followed one new water main that EBMUD had installed a few years
+earlier, the New Scenic Line, I believe. This was one of the new super-insulated water mains that
+was wrapped with a thick plastic coating so that no electrical current from the ground could get
+into the line and corrode it. Wattenburg explained that this also turned this new water main into
+a very good insulated electrical power line that could carry small electrical currents for long
+distances without the current being dissipated into the ground. Older water mains that are not so
+well insulated quickly lose any current that gets onto them.</p>
+
+<p>Walt Musso, the PG&amp;E manager who was assigned to work with Wattenburg tells about
+the dramatic meeting that he attended with Wattenburg the day before the press conference:</p>
+<p>They met the engineering and operations managers from EBMUD at a PG&amp;E office in
+Dublin. Wattenburg had asked them to bring their maps of the entire EBMUD water system in
+the Danville area with them. The EBMUD engineering manager had been very defiant toward
+Wattenburg all along. He had been insisting to the press that Wattenburg was just on a wild
+goose chase and a publicity stunt.</p>
+
+<p>Musso remembered that Wattenburg began the meeting with a short discussion of what
+happened to all the top BART engineers years earlier when they had refused to tell the truth about
+technical problems in the BART system that endangered many people. Then he pushed a map
+across the table to the EBMUD managers. This map showed that the voltages he had measured
+all centered around one new water main that Wattenburg had tracked for so many days and
+nights. Wattenburg let them study the map for a while. The EBMUD engineering manager said
+this was “all a lot of bullshit.”</p>
+
+<p>“Wattenburg turned to the EBMUD operations manager and told him very sternly:
+‘You know damn well that all the blue water houses are served by just this one new water main, don’t
+you?’ The engineering manager got up and walked out. The others wouldn’t answer for several
+minutes. Wattenburg confronted the operations manager: ‘You’ve known this all along, haven’t
+you? God-damn-it, I’m giving you a chance to keep your asses out of a lot of trouble. Now make
+it quick, or I’m going to turn all of my maps and yours over to the district attorney. I notice on
+your new water service maps that you carefully didn’t show which water mains all the blue water
+houses are connected to, but you show the connections for all the other houses in the
+area.’</p>
+
+<p>“The operations manager nodded sheepishly and admitted that Wattenburg was right. That
+is all he would say for a few minutes. We just sat there looking at each other in disbelief. Finally,
+Wattenburg demanded: ‘Is it true that you have known all along that the blue water houses are all
+fed from this one new line?’ One EBMUD guy tried to say that the new and old water mains are
+crisscrossed all over the area such that one house may be connected to an old line and the house
+next door is connected to the new line. Wattenburg snapped: ‘Yes, and that is why some of the
+poor bastards put their life savings into a house they thought was safe because the neighbor didn’t
+have blue water. They had no way of knowing that their dream house was connected to your
+new water main. How long have you known this?’</p>
+
+<p>“The operations manager pulled out a map that they had not shown us at the beginning of
+the meeting. He said they had just made this map ‘a few weeks ago.’ Wattenburg looked at it. It
+confirmed what he had discovered in all his work. This crude EBMUD map showed that all the
+blue water houses were connected to the New Scenic East Line. Wattenburg told them he hoped
+that they could convince a judge that they had just discovered this and hadn’t known it for all the
+time that EBMUD had been blaming the home builders and letting homeowners suffer and spend
+million of dollars… .</p>
+
+<p>“Wattenburg asked them why they hadn’t told anybody about this. The operations manager
+said that EBMUD engineers and attorneys didn’t consider it significant because it didn’t prove
+what was really causing the blue water. It just localized where it was occurring. They still insisted
+that the only copper was in the copper water pipes in the homes and that the EBMUD water lines
+couldn’t be the problem no matter how the homes were hooked up. Wattenburg told them that
+they weren’t sending the copper into the houses. EBMUD’s new water main was clearly sending
+something worse that was making the copper come off the water pipes in the blue water houses.
+‘And you guys had better find out what it is. I’m sure as hell not going to do it for
+you.’</p>
+
+<p>“The EBMUD engineering manager came back to the meeting and didn’t say a word. He
+picked up their maps and they left. Wattenburg commented as we left: ‘You want to bet that
+even the FBI won’t be able to find that one map anywhere tomorrow?’ We went over to a
+nearby bar for lunch. He curled up in his car afterwards and went to sleep.”</p>
+
+<p>Wattenburg quit the investigation after the newspapers announced his discovery of the
+“Blue Water Pipeline” (San Francisco Chronicle, September 19, 1991, page A17). He said that he
+had done his part and he didn’t want to get involved in litigation. EBMUD’s New Scenic East
+Line became known as the ’Blue Water Line’ after that. EBMUD didn’t deny it any longer. They
+organized a multi-million dollar task force to solve the problem. Later press reports say that they
+and the homebuilders are working together to try to cure the problem with the water line.</p>
+
+<p>Our professor contact says that he is surprised that Wattenburg didn’t continue with his
+research and publish the results of his investigation in the technical journals somewhere. He
+points out that blue water is still a serious problem around the world. He feels that maybe
+Wattenburg didn’t want to be associated with “corrosion engineers” whom he often described as
+“guess-work artists”. He says that Wattenburg was the only one who wasn’t paid by one side or
+the other in the controversy. He said he once asked Wattenburg whom he was working for and
+Wattenburg answered: “Me. That way I don’t have to go to court. This is what happens to you
+when you shoot your mouth off at the wrong time.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/BlueWater.html.i
@@ -1,0 +1,31 @@
+14 pages
+size 400 562
+length 20263
+414 2 11 body html
+0
+1226 2 28 body html
+119
+2982 2 55 body html
+51
+3894 2 69 body html
+221
+5205 2 85 body html
+307
+5205 2 85 body html
+863
+8598 2 133 body html
+19
+8598 2 133 body html
+569
+8598 2 133 body html
+1119
+11904 2 180 body html
+323
+13529 2 206 body html
+187
+15610 2 233 body html
+0
+17216 2 253 body html
+34
+18946 2 276 body html
+0
binary files /dev/null b/lib/ebooks/oebtest/DrBill.jpg differ
binary files /dev/null b/lib/ebooks/oebtest/DrBill.png differ
binary files /dev/null b/lib/ebooks/oebtest/DrBill.tif differ
--- /dev/null
+++ b/lib/ebooks/oebtest/DrBillBio.css
@@ -1,0 +1,92 @@
+P {
+    text-align: justify
+    }
+
+P.right {
+    text-align: right
+    }
+
+P.title {
+    margin-bottom: 1em
+    }
+
+P.firstpara {
+    text-indent: 0pt;
+    }
+
+P.indentpara {
+    text-indent: 1em;
+    }
+
+.pagebreak {
+    page-break-before: right
+    }
+
+CITE {
+    text-indent: 12pt;
+    margin-top: 1em;
+    margin-bottom: 1em;
+    font-size: smaller
+    }
+
+.title {
+    text-align: center
+    }
+
+SPAN.rj {
+    text-align: right
+    }
+
+A {
+    color: blue;
+    text-decoration: none
+}
+
+DIV.image {
+    page-break-before: right;
+    page-break-after: left;
+    height: 100%
+    }
+
+BODY {
+    color: rgb(0,0,0);
+    background-color: rgb(255,255,255);
+    font-family: 'Times New Roman', Times, Serif}
+
+H1 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 24pt;
+    text-align: center;
+    }
+
+H1.title {
+    font-weight: bold
+    }
+
+H2 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 18pt}
+
+H3 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 14pt}
+
+H4 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 12pt}
+
+H5 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 10pt
+    }
+
+H6 {
+    font-weight: normal;
+    font-style:                  normal;
+    font-size: 8pt
+    }
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/DrBillBio.opf
@@ -1,0 +1,100 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd">
+<package unique-identifier="DrBillBio">
+<metadata>
+<dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/"
+    xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0">
+<dc:Title>Bill Wattenburg’s Background</dc:Title>
+<dc:Type>Biography</dc:Type>
+<dc:Identifier scheme="none">DrBillBackground</dc:Identifier>
+<dc:Subject>background report</dc:Subject>
+<dc:Publisher>PetesGuide.com</dc:Publisher>
+<dc:Contributor role="edt">Peter K. Sheerin</dc:Contributor>
+<dc:Date event="creation">1992</dc:Date>
+<dc:Date event="electronic publication">2000/09</dc:Date>
+<dc:Rights>This work was provided to me by a government agency.</dc:Rights>
+<dc:Language>en-us</dc:Language>
+<dc:Coverage>Biographical background on Dr. Bill Wattenburg</dc:Coverage>
+</dc-metadata>
+<x-metadata>
+<meta name="price" content="US $0.00" />
+</x-metadata>
+</metadata>
+<manifest>
+<item id="about" href="about.html" media-type="text/x-oeb1-document" />
+<item id="copyright" href="copyright.html" media-type="text/x-oeb1-document" />
+<item id="TofC" href="toc.html" media-type="text/x-oeb1-document" />
+<item id="titlepage" href="TitlePage.html" media-type="text/x-oeb1-document" />
+<item id="foreword" href="foreword.html" media-type="text/x-oeb1-document" />
+<item id="summary" href="ExecutiveSummary.html" media-type="text/x-oeb1-document" />
+<item id="TalkRadio" href="TalkRadio.html" media-type="text/x-oeb1-document" />
+<item id="movies" href="movies.html" media-type="text/x-oeb1-document" />
+<item id="TV" href="television.html" media-type="text/x-oeb1-document" />
+<item id="publishing" href="publishing.html" media-type="text/x-oeb1-document" />
+<item id="education" href="background-education.html" media-type="text/x-oeb1-document" />
+<item id="business" href="business.html" media-type="text/x-oeb1-document" />
+<item id="patents" href="patents.html" media-type="text/x-oeb1-document" />
+<item id="awards" href="awards.html" media-type="text/x-oeb1-document" />
+<item id="hobbies" href="hobbies.html" media-type="text/x-oeb1-document" />
+<item id="covert" href="covert.html" media-type="text/x-oeb1-document" />
+<item id="colleague" href="colleague.html" media-type="text/x-oeb1-document" />
+<item id="bloodbanks" href="bloodbanks.html" media-type="text/x-oeb1-document" />
+<item id="chainmatrix" href="HelicopterMinesweeper.html" media-type="text/x-oeb1-document" />
+<item id="confrontations" href="confrontations.html" media-type="text/x-oeb1-document" />
+<item id="BART" href="BART.html" media-type="text/x-oeb1-document"  />
+<item id="creditcards" href="creditcards.html" media-type="text/x-oeb1-document" />
+<item id="carpooling" href="dial-a-ride.html" media-type="text/x-oeb1-document" />
+<item id="hiddenoil" href="MeasuringOilTanks.html" media-type="text/x-oeb1-document" />
+<item id="barrier" href="GoldenGate.html" media-type="text/x-oeb1-document" />
+<item id="bluewater" href="BlueWater.html" media-type="text/x-oeb1-document" />
+<item id="GoldMine" href="GoldMine.html" media-type="text/x-oeb1-document" />
+<item id="drillbit" href="BentSub.html" media-type="text/x-oeb1-document" />
+<item id="DrBill" href="DrBill.tif" media-type="image/tiff" fallback="DrBilljpeg" />
+<item id="DrBilljpeg" href="DrBill.jpg" media-type="image/jpeg" fallback="DrBillpng" />
+<item id="DrBillpng" href="DrBill.png" media-type="image/png" />
+<item id="raportIMG" href="raport.png" media-type="image/png" />
+<item id="QuotesFromBill" href="QuotesFromBill.html" media-type="text/x-oeb1-document" />
+<item id="QuotesAboutBill" href="QuotesAboutBill.html" media-type="text/x-oeb1-document" />
+<item id="resume" href="resume.html" media-type="text/x-oeb1-document" />
+<item id="StyleSheet" href="DrBillBio.css" media-type="text/x-oeb1-css" />
+</manifest>
+<spine>
+<itemref idref="titlepage" />
+<itemref idref="TofC" />
+<itemref idref="foreword" />
+<itemref idref="summary" />
+<itemref idref="TalkRadio" />
+<itemref idref="movies" />
+<itemref idref="TV" />
+<itemref idref="publishing" />
+<itemref idref="education" />
+<itemref idref="business" />
+<itemref idref="patents" />
+<itemref idref="awards" />
+<itemref idref="hobbies" />
+<itemref idref="covert" />
+<itemref idref="colleague" />
+<itemref idref="bloodbanks" />
+<itemref idref="chainmatrix" />
+<itemref idref="confrontations" />
+<itemref idref="BART" />
+<itemref idref="creditcards" />
+<itemref idref="carpooling" />
+<itemref idref="hiddenoil" />
+<itemref idref="barrier" />
+<itemref idref="bluewater" />
+<itemref idref="GoldMine" />
+<itemref idref="drillbit" />
+</spine>
+<tours>
+<tour id="chapterTourName" title="These are the chapters">
+<site title="TOC" href="toc.html" />
+</tour>
+</tours>
+<guide>
+<reference type="title-page" title="About This Book" href="about.html" />
+<reference type="other.ms-firstpage" title="First Page" href="TitlePage.html" />
+<reference type="foreword" title="Foreword" href="foreword.html" />
+<reference type="toc" title="Table of Contents" href="toc.html" />
+</guide>
+</package>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/ExecutiveSummary.html
@@ -1,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Executive Summary</title>
+</head>
+
+<body>
+
+<h1>Executive Summary</h1>
+
+<p>Bill Wattenburg is one of the most interesting, if not bizarre, media
+personalities we have ever researched. Most professional broadcasters would be
+jealous of the high celebrity Bill Wattenburg has gained on the West Coast. He
+is a ruggedly handsome and athletic man with a brilliant mind. He has both a
+voice and a presence on the air that is the envy of many in radio and
+television. He switches easily between serious intellectual and humorous
+entertainer as the occasion demands. <i>But he seems to deal with his media role
+as if it is just a pleasant hobby.</i> An ABC executive in San Francisco told us
+that he will only do radio and television shows on weekends. This position may
+be explained by his other activities and accomplishments. He is a well-known
+scientist of some notoriety in the public eye. He presently holds the title of
+research scientist at California State University, Chico, where he works during
+the week.</p>
+
+<p>A news organization may have some difficulty in forcing him to confine
+himself to reporting the news instead of trying to make the news. He has
+displayed considerable news-making desires in his very public dealings with
+government agencies. This should be of concern to a network news organization
+that must protect confidential relationships with high-level contacts in the
+government. This observation is supported by his confrontational tactics
+reported in the section <a href="confrontations.html">Public Confrontations</a>.</p>
+
+<p>We do believe, however, that he would be a very effective and popular
+network news commentator or show host. Both his credibility and integrity appear
+to be very high.</p>
+
+<p>Our contacts in the media have told us that since 1988 he has turned down
+numerous offers to host major radio and television shows in Los Angeles and New
+York as well as San Francisco. One LA radio station executive said that he
+offered Wattenburg three times his KGO Radio salary and he turned it down.
+Contacts at a major movie studio say he also passed up another movie role that was
+offered after his <a href="movies.html">appearance in two Clint Eastwood movies in 1988 and
+1989</a>, saying that he did not have the time.</p>
+
+<p>Our general impression is that it may be difficult to convince him to expand
+his media role because of his interests in his scientific work and other
+activities. From what we were able to observe of his considerable financial
+resources, it would appear that money will not be a big factor in what he
+chooses to do in the near future.</p>
+
+<h2>Our Recommendation for Executive Negotiations with Bill Wattenburg</h2>
+
+<p>For those who do not have time to read this lengthy report in full, we
+suggest three sections in particular that we believe provide the best analysis
+of his talents, his personality, and his style in dealing with professional and
+business associates. These sections are: <a href="TalkRadio.html">Talk Radio</a>,
+<a href="colleague.html">A Colleague’s Observations</a>,
+and the <a href="BlueWater.html">Blue Water project</a>. We suggest careful review of his other
+projects on the <a href="creditcards.html">Magnetic Credit Cards</a> and
+<a href="GoldMine.html">the Gold Mine</a> before any contract negotiations of
+a legal nature with him.</p>
+
+<p>An astute reviewer of this report who specializes in resolving executive
+conflicts in major corporations has offered this observation:</p>
+
+<blockquote>“His behavior appears to be iconoclastic in his dealings with other
+professionals in their own fields if they challenge him in some arrogant or pompous
+manner. This behavior pattern and an obsessive desire to maintain independence
+seem to be common elements in all his public exploits. He seems to enjoy his
+accomplishments in very private ways and is not driven by a desire for career
+advancement or immediate monetary rewards. However, this may be deceiving. He
+has obviously achieved great notoriety and professional respect in his own ways.
+This may have been financially rewarding beyond what most professionals might
+achieve in a conventional manner. In dealing with him an any business or
+professional situation, one should be on guard to not unnecessarily challenge
+his competitive instincts unless there is a major mutual objective to be
+accomplished.”</blockquote>
+
+<p><b>We strongly recommend that you see him in action <i>when he is live on the
+air in the studio</i> before making any appraisal of his media talents. In
+private interviews, he is very laid back. He responds with vigor only when you
+aggressively challenge him on some subject. Otherwise, he displays very little
+of the brilliance and wit that he delivers when he is on the air. We doubt that
+he will sell himself in an executive interview. In our interviews with him, he
+didn’t mention any of his many exploits detailed herein until we brought up the
+subjects and asked him to comment on the press reports and interviews with
+others. His attitude seems to be that if you don’t already know something about
+him, why should he tell you. He will try to deflect a conversation toward the
+interviewer (Who are you? Where are you coming from? What do you like to do?)
+This is complimentary, but often evasive.</b></p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/ExecutiveSummary.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 562
+length 5673
+407 2 11 body html
+0
+1382 2 29 body html
+170
+3053 2 57 body html
+0
+3847 2 70 body html
+304
--- /dev/null
+++ b/lib/ebooks/oebtest/ExecutiveSummary.html.index
@@ -1,0 +1,11 @@
+4 pages
+size 400 562
+length 5673
+407 2 11 body html
+0
+1382 2 29 body html
+170
+3053 2 57 body html
+0
+3847 2 70 body html
+304
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldMine.html
@@ -1,0 +1,389 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: The Gold Mine</title>
+</head>
+
+<body>
+<h1>The Gold Mine</h1>
+
+<h2>(1985–1986)</h2>
+
+<p>In our 1990 report, we had no information on Bill Wattenburg’s activities for 1985 and
+1986. He declined to volunteer anything about this period during our two interviews with him in
+1990. However, we picked up some information on this period during our 1992 interview with
+him at his ranch in Plumas County, California. People in the town told us that he was working on,
+of all things, a gold mine in 1985. They told us that this venture became the largest industry in
+the area for the unemployed loggers and construction workers in Plumas County. We left one of
+our staff in the area for a week to learn about this activity. The story we got suggests that
+Wattenburg had an almost complete change of lifestyle for these two years, as well as a purpose
+in what he was doing. He returned to the profession that he learned from his father when he was
+young, that is, operating heavy construction equipment. He took on another strange challenge at
+the same time.</p>
+
+<p>The following individuals can confirm the events that we summarize below: Clifford Gibbs was the
+general manager on the job for Sunbelt. Earl Arlin, was the Sunbelt chief engineer. James Moak and
+Bill Pinkston were the job supervisors that Wattenburg hired. Attorney John Burghardt, of the law
+firm of Marshall, Burghardt &amp; Kelleher, Chico, California, was Wattenburg’s attorney who set
+up Wattenburg’s mining company called Wattexco and handled his later negotiations with Sunbelt
+Mining Company.</p>
+
+<br />
+<p><b>Here is the story, with references to the individuals who confirmed it for us:</b></p>
+<br />
+
+<p>The logging and lumbering industry in Plumas County began to fade away in the early
+eighties. Many skilled equipment operators and mechanics in the area were unemployed. Bill
+Wattenburg’s classmates from high school and his father’s old friends were among them. They
+had asked Bill Wattenburg to help them find some new industry for the town.</p>
+
+<p>The Sunbelt Mining Company from New Mexico was planning to open a large gold mine
+near Bill’s ranch. It was called the Calgom Mine. Sunbelt had discovered an
+enormous body of low-grade gold ore under a mountain top at five thousand feet elevation. Sunbelt was going to
+put the work of extracting and transporting the gold ore out to bid to several large mining
+construction companies from Nevada and Utah. These companies typically brought in their own
+employees and their own equipment for such jobs. The idle construction equipment owned by the
+local people would not have been used by an outside mining contractor. The locals had no way
+of bidding for the job because this required posting a $2,000,000 performance bond and
+substantial operating capital that they did not have available.</p>
+
+<p>They appealed to Bill Wattenburg to get the job for them somehow when he was vacationing
+at his ranch in December 1984. Wattenburg studied the specifications for the job and
+the manner in which the standard mining companies normally did such work. He concluded that
+there was a much less expensive way to do the job using a lot of the surplus logging equipment in
+the area. But, Sunbelt did not believe that this could be done.</p>
+
+<p>Wattenburg made them an offer they couldn’t refuse. He agreed to a penalty clause in the
+contract whereby he would pay Sunbelt for any loss of projected productivity based on the
+estimates that Sunbelt had made for the progress that standard mining companies should achieve.
+Furthermore, he would start the work immediately that winter (December 1984), whereas the
+other mining companies would not start until the snow melted in the spring. Sunbelt agreed to let
+him try it.</p>
+
+<p>The rest appears to be typical Bill Wattenburg. Local workmen and supervisors at the
+Calgom mine told us numerous stories of the unorthodox and “absolutely crazy” things that
+Wattenburg organized with the local workmen and their equipment that winter.</p>
+
+<p>Wattenburg used his own bulldozer and personally built a road to the top of the mountain
+during the Christmas week of 1984. He then put out the call for all the locals who wanted to go to
+work with their equipment, Several workmen told us that they all got a lecture when they first
+arrived. Wattenburg told them that they had no damn business even trying to beat the big mining
+companies at their own game. But if they wanted to try, he had a plan. He told
+them, “Of course, if you don’t think it will work, you can always go back home where it is nice and warm
+and slowly go bankrupt.” The workmen told us that everybody stayed.</p>
+
+<p>The first task was to cut 2,000,000 tons of “overburden” dirt and rock off the top of the
+mountain and move it a half mile away where it was dumped into a deep canyon. Overburden is
+the dirt and rock on top of the ore body beneath it. The gold ore body was at a depth of a two-hundred
+feet below the surface. Mining companies use very large off-highway trucks for this kind of
+job where the dirt has to be moved some distance. They dig the dirt with enormous excavators
+and load it into the trucks that haul it away. These machines typically cost $200,000 to $400,000 apiece.
+The loggers had no such equipment. All they had were medium-sized bulldozers and small loaders.</p>
+
+<p>They said that Wattenburg told them: “Well, if we can’t haul the damn dirt, I guess we’ll
+just have to push it where we want it to go.” The problem was that a bulldozer is only good for
+pushing dirt very short distances. The dirt falls away from the bulldozer blade if you try to push a
+blade-full of dirt more than a few hundred feet. But Wattenburg showed them how to do it
+anyway.</p>
+
+<p>Here is how one seasoned operator described it: </p>
+
+<blockquote>
+<p>“He dug a big trench starting from the top and all the way down the side of the mountain to the canyon. This trench was about six feet
+deep and just the width of a bulldozer blade. We stood around wondering what the hell he was
+doing. We thought maybe he was going to run water down this trench to carry the dirt away.
+But then he put maybe five or six of us on bulldozers to start pushing dirt on the mountain top
+into this trench, up at the top of the trench. Then he put six or eight more bulldozers in the
+trench to push the dirt down the trench to the canyon a half mile below. He lined them up one
+right after the other in the trench. He had to teach a lot of us how to keep a load of dirt in front
+of the bulldozer blade without loosing it all on the way down. You know, his daddy taught him
+how to give you a shave with a bulldozer blade if you sit still. … When the dozers reached the
+bottom, they just climbed out of the trench and went back up another road to get another load of
+dirt at the top. We thought it would be tough trying to push dirt with a dozer down that trench
+that far, but it was easy once you got the hang of it. Hell, in a couple of days we were moving
+20,000 tons a day. That’s more than you can haul in trucks that cost three times as much to own
+and operate. … Some of the guys had dozers that were so old and worn out that they could hardly
+climb back up the mountain. It was pathetic. But Bill just told the others guys with new
+equipment to give the old boys a push back up the mountain. The old dozers did just as good as
+the new ones when they were pushing dirt down the hill. … Bill fired one guy with a new Cat
+who was complaining about helping the others. He told this asshole that he could go back home
+and wait by the fire for the bank to come and repossess his new bulldozer. … The guy should have
+realized that Bill’s father always had to work with beat up old equipment. He never could afford
+a new piece of equipment in his life.”</p>
+</blockquote>
+
+<p>The former Sunbelt chief engineer, Earl Arlin, told us that his bosses from Sunbelt
+headquarters came out and saw what Wattenburg was doing and got unhappy as hell. He was
+moving the dirt with loggers and cheap equipment for less than half the cost that Sunbelt had
+estimated it would cost a mining company using regular loaders and big trucks. And they had
+agreed to pay Wattenburg what they were going to pay the other contractors. Wattenburg and
+the loggers were obviously making a killing.</p>
+
+<p>Mr. Arlin remembers that the Sunbelt executives called Wattenburg into a meeting where
+they tried to get him to modify their contract. Wattenburg asked them what they would be saying
+if they had discovered that he was behind on schedule instead of ahead of schedule. Arlin says
+that they just looked at him and smiled. They admitted that they would be fining him for lost
+productivity. At that, Wattenburg told them that he appreciated honest men and he
+would consider reducing the amount they were paying him because he was moving the dirt for much less than
+even he thought was possible. He offered to reduce his payments by ten percent. They wanted
+him to reduce it by twenty percent. They settled on a fifteen percent reduction. The Sunbelt
+executives went home to New Mexico very happy. They told Wattenburg that he could have all
+the work he wanted in the future. Mr. Arlin suggests that he knew something was wrong.
+Contractors just don’t give up money. They usually sue you for more.</p>
+
+<p>Mr. Arlin laughed as he told us: “By the next week, Wattenburg’s crazy crew was moving
+30,000 tons a day down the mountain, not 20,000! Hell, they were now making more money than
+they were before he gave Sunbelt back the fifteen percent reduction. Some of the
+poor loggers were making more money in a week than they made all year when they were starving to death
+working in the logging woods with their equipment.”</p>
+
+<p>Wattenburg paid each of the loggers a percentage of the total income he received so that
+the more dirt they moved the more money they made. One workman told us that most of them
+were fighting over who could work two shifts a day. He said that he made as much as $1000
+dollars a day. He was able to pay off the loan on his bulldozer in two months. He said they were
+working in four feet of snow most of the time that winter, and yet they were as happy as a bunch
+of kids playing at a ski resort.</p>
+
+<p>Wattenburg’s job supervisors James Moak and Bill Pinkston told us that the one who was
+having the most fun was Bill Wattenburg. “He couldn’t be on the job during the day because he
+had to be at the university in Chico during the weekdays, but he came up and worked the
+graveyard shift most nights. He loved to get on a big Cat and push dirt. Everybody else got their
+asses in gear when he was there. The two daytime shifts had to go like hell to keep up with the
+graveyard shift. Chico was only an hour away. Some of the equipment operators lived down
+there. They would pick him up at 11pm and get him back to Chico in the morning by 9am. We
+had our management meetings with him on weekends.”</p>
+
+<p>Wattenburg’s crew finished the first phase of the job in April 1985. This was a month
+earlier than the other companies could even have started. Apparently, his company, Wattexco,
+made so much money that he was able to buy a new fleet of bulldozers and earth movers (called
+scrappers) for the second phase of the job.</p>
+
+<p>The second phase was to start digging the gold ore out of the enormous open pit they had
+made at the top of mountain and then transport the ore to the processing plant two miles down
+the mountain. His contract with Sunbelt included this work at a predetermined price which,
+again, was based on what other mining contractors normally charged. Sunbelt was soon very
+unhappy about this, according to those on the scene we talked to.</p>
+
+<p>Supervisors Moak and Pinkston told us that Wattenburg again figured out a way to do
+this next job for about half the estimated costs. Instead of using big trucks to haul the ore down
+the mountain, he told them that they were going to use the rubber-tired Cat earthmovers
+(scrappers) they already had. Wattenburg told them that this way they wouldn’t have to use
+extra loaders to dig the ore and load big haul trucks—and they didn’t have to buy ten of the
+$200,000 trucks either. He argued that the scrapers could load themselves with bulldozers
+pushing them. Once they were loaded, they could go straight down the road to the plant. The
+equipment operators protested that no one in his right mind would do this because these big
+earthmovers are not designed to go long distances downhill with a load of fifty tons of dirt. They
+don’t have enough brakes to keep from running away. Everyone told him it was suicide.</p>
+
+<p>They said that Bill Wattenburg got on the first scrapper and showed them how to do it.
+They recall that he made all the nervous scrapper operators walk alongside the loaded scrapper
+and watch what he was doing as he slowly took it down the hill. An hour later, they were all
+going down the mountain in their scrappers with fifty-ton loads.</p>
+
+<p>Wattenburg’s scheme was something that no decent equipment operator would ever do.
+He told them to drag their scrapper blades on the dirt road surface as they went down the
+mountain. This would give them the braking power they needed. (The scrapper blade is what
+digs the dirt up as a scrapper is being loaded.) Any operator would be fired on a normal
+construction job if he ever let his scrapper blade dig into the road he was running over after he
+was loaded. This would tear up the road as well as wear out the expensive steel cutting edge on
+the scrapper blade.</p>
+
+<p>But this wasn’t a normal job, Wattenburg told them. Supervisor Moak remembers that
+Wattenburg told them: “I am the one who pays for the scrapper blades, and who cares about the
+goddamn road! So you cut the surface level of the road down ten feet over the next year? So
+what? I could have built that damn dirt road ten feet lower to begin with. When we’re through,
+I’ll put it back where it was when we began. You guys just get your asses down that road with
+all the ore you can haul, and I’ll worry about the rest.”</p>
+
+<p>One of Wattenburg’s equipment mechanics told us that he hired two more unemployed
+mechanics to work every night to replace the worn-out blades on the scrappers. He said that a
+truck load of new scrapper blades worth about ten thousand dollars was delivered to the job each
+week. “Normally, you wouldn’t use this many scrapper blades on a job in a year.”</p>
+
+<p>The Sunbelt manager on the job, Mr.Gibbs, said that he soon figured out what
+Wattenburg was doing. The ten thousand dollars worth of scrapper blades each week was only
+about one-tenth of the cost of the only other alternative, that is, using conventional haul trucks to
+do the job the way that mining contractors would do it. He realized that Wattenburg was making
+a killing again. He was probably digging and hauling the ore for about 60 percent of the normal
+cost of $1.40 per ton. There was at least 4,000,000 tons of ore to be hauled. Wattenburg was
+being paid $1.50 per ton under his contract. That meant that he was going to make about sixty
+cents a ton profit instead of the usual ten cents a ton. It wasn’t long before the Sunbelt executives
+from headquarters in New Mexico wanted another meeting with Wattenburg.</p>
+
+<p>Wattenburg agreed to a ten percent reduction in what they were paying him to deliver the
+ore. But Wattenburg made them agree to give him the third phase of the job which was to build
+the biggest part of the gold processing plant, the buildings and the laboratory. They gave him the
+job on a time and materials basis plus ten percent profit because they had learned their lesson with
+this guy and they figured that he already knew some way to do this job at a lot less cost. The
+local Sunbelt building supervisor objected like hell because he had his own favorite contractor
+from New Mexico already lined up to do the job, but the headquarters guys insisted that they had
+just cut “a hell of a deal with Wattenburg that would save the company six hundred thousand
+dollars.” Arlin told us:</p>
+
+<blockquote>
+<p>“I knew this guy Wattenburg had something up his sleeve again.”</p>
+
+<p>“Sure enough, the next week the place looked like a flea market with all the characters
+who showed up in beat-up old pickups with a hammer or a saw in their hands. Wattenburg hired
+just about every unemployed carpenter and small building contractor in the county. He gave
+them all a piece of the action and turned them loose. They had the damn buildings up in about
+half of the time we expected. You know, this meant that he got paid for what the contractors
+charged to do the job, plus he got a ten percent profit on top of that. But nobody in headquarters
+complained. He got the job done for about ten percent less than we expected.</p>
+
+<p>…</p>
+
+<p>“Later one of our engineers sat down and figured out how much lumber we paid for on
+that building job. It turned that we paid for about twice as much lumber as they used in the
+finished buildings! Right then we realized that these hick contractors who built the buildings for
+us probably were building something for themselves somewhere else at the same time. Where
+else could that much lumber have gone?</p>
+
+<p>“When we asked Wattenburg about this, he said: ‘I sure as hell don’t need to steal lumber.
+But you corporate guys have got to realize that life is pretty rough for these people who have to
+make a living up here nowadays. Most of their families never dreamed of having a home. What
+are you bitching about? They saved you a lot of money, didn’t they?.’ We dropped the subject.”</p>
+</blockquote>
+
+<p>The Calgom Mine was in full operation by August 1985. They began producing
+3,000 to 4,000 ounces of gold a month. Wattenburg was building one of the biggest fleets of dirt moving
+equipment anywhere to deliver the ore from the mountain top to the processing plant. He bought
+every used D9 Cat bulldozer and Cat 631C scrapper he could find on the west coast, according to
+Mr. Al Pissetti, Dillingham Construction Co., Benicia, Ca., and Mr. Roger Ash
+of Wershow, Ash and Lewis, Equipment Auctioneers of Los Angeles and Portland, Oregon.</p>
+
+<p>Mr. Pissetti told us that Wattenburg once called him up in the summer of 1985 and
+bought two of Dillingham’s used D9 bulldozers, sight unseen, for $50,000 apiece. But
+Wattenburg wanted them delivered to the mine site the next day. Pissetti said he had never heard
+of anything like that before. He said that Wattenburg told him on the phone: “I believe you
+when you tell me that the bulldozers are in good shape. If you’re lying to me, you’ll find out who
+I am quick enough.” Pissetti said that he called the bank and found out that Wattenburg had
+already wired the money to the Dillingham account—and the banker told him who Wattenburg
+was. He said he found some truckers to haul the bulldozers to Plumas County that afternoon.
+(Our staff saw pictures in the bars and restaurants in the area in 1992 which showed
+Wattenburg’s enormous fleet of equipment working at the open pit mine in 1985).</p>
+
+<p>Wattenburg was employing 100 equipment operators by that time to run the equipment
+around the clock, seven days a week. He even rented a restaurant to feed them. We were told
+that the reason he did that was too encourage the operators to show up on time. Loggers and
+construction workers are evidently notorious for having hangovers on Monday mornings. He
+gave them free meals if they showed up on time before the shift started. If they were late, they
+didn’t get any free meals for a week after that.</p>
+
+<p>After the mine had been in full operation for only six months, Sunbelt Mining Company
+executives decided that it would be to their advantage to buy out Wattenburg. He was making
+more money than they were, and they owned the mine.</p>
+
+<p>Wattenburg gave us permission to talk to his attorney, John Burghardt at the law firm of
+Marshall, Burghardt, and Kelleher, Chico, California. Burghardt handled the final negotiations with Sunbelt for him. Burghardt told us that Sunbelt first said that they were
+going to get another contractor who could deliver the ore at a lower price. Bill Wattenburg’s
+answer was, “be my guest”. Evidently, Sunbelt couldn’t find another contractor at a lower price
+than they were paying Wattenburg. Burghardt said that he then realized why Wattenburg had
+earlier given them the reduction in price that he, Burghardt, had opposed. He said that
+Wattenburg must have known that this would eventually happen and that no one else would be
+able to do the job any cheaper. But Wattenburg was still making a good profit. By not being
+too greedy, Wattenburg had put Sunbelt in a real bind.</p>
+
+<p>They negotiated for several months. Wattenburg said that he just wanted to keep on
+working because the job was providing employment to so many local workmen. Sunbelt
+finally offered to keep most of Wattenburg’s employees if he would sell. Wattenburg agreed to a
+deal whereby Sunbelt would buy his company, Wattexco, and as much of his equipment as they
+needed to operate the mine, but it would have to be all cash.</p>
+
+<p>Burghardt told us about the scene when he appeared with Wattenburg at the Sunbelt
+office to sign the papers and collect the cashier’s check that Wattenburg had demanded:</p>
+
+<blockquote>
+<p>“The Sunbelt representative came with several lawyers and accountants in three piece
+suits. Wattenburg was in his boots and greasy Levis. At the last minute, the Sunbelt boss
+announced that they had thought it over and determined that Wattenburg’s equipment was not
+worth what they had earlier agreed upon. He pushed a cashier’s check across the table to
+Wattenburg. It was for $200,000 less than what it was supposed to be. But it was still more
+money than I had ever seen. My heart started pounding. I nudged Wattenburg to take it, and let’s
+get out of there before they change their minds completely. But, Wattenburg just
+slid the cashier’s check back across the table and told them that if they were a little short of money, he
+might be interested in buying out their interest in the mine. They had a meeting in the next
+room for a while and finally came back with another check for the missing $200,000.
+Wattenburg handed me the check, we shook hands with them, and he motioned for us to go.
+There was no more conversation. That was it—It was all over.”</p>
+</blockquote>
+
+<p>Burghardt told us he was sweating when he left. Wattenburg said to him later:</p>
+
+<blockquote>
+<p>“Don’t feel bad about leaving without sticking around for small talk. Those Wall Street lawyers always
+pull that bullshit of bringing two or more checks to a closing to see if they can get an anxious
+seller to chicken out at the last minute and take less money. They figure most suckers are so
+anxious to get a few million dollars cash in their hands that they will always take a few hundred
+thousand less. That way they can go back to headquarters and brag about how much money they
+saved the company. But when you call their bluff, they feel sort of stupid on the spot. It’s best
+not to rub it in by sticking around too long. You might have to deal with them again someday.”</p>
+</blockquote>
+
+<p>Attorney Burghardt said that this was his trial-by-fire in corporate mergers. Burghardt
+admitted that he didn’t realize what Wattenburg really knew about big business until after this was
+all over. Much later he learned that “this guy in greasy Levis” had built and sold two high-tech
+companies to the Wall Street crowd before he got in the dirt moving business. He said that he
+later realized that Wattenburg had been playing a chess game with them all along, but that
+Wattenburg was always about three moves ahead of them. “I was his attorney, but he never
+really told me what he had up his sleeve.”</p>
+
+<p>In terms of how much money Wattenburg made, Attorney Burghardt would only volunteer: “He did all right, but he didn’t walk away with what he could have by any means. He
+got his capital back with a decent profit and he created thirty million dollars of business in the area
+and a lot of jobs. I’m sure he could have made a lot more money doing other things for the time
+he put in.”</p>
+
+<p>Calgom Mine chief engineer Earl Arlin, now retired, was on the job every
+day supervising the mining operation. He probably saw more of this story first-hand than anyone.
+He was an engineer on major mining jobs for thirty years. His analysis of the scene may be the
+best overall:</p>
+
+<blockquote>
+<p>“I knew who this fellow Wattenburg was. I listened to him on the radio for years. It
+was always hard to believe that he was up there running a bulldozer or fixing a piece of broken-down equipment in the middle of the night. It was not
+surprising what he did. I knew he wouldn’t do things in ordinary ways. I sort of felt sorry for my own company
+every time they negotiated a contract with him.</p>
+
+<p>…</p>
+
+ <p>“He gave those old loggers their moment of glory and the chance to do one big job. I
+ think he wanted them to know that they could be somebody … that they could do better than the
+ big-city contractors with all their new equipment. … He was reliving his childhood. I don’t think it
+ was just the money. I think he had been dreaming about going back and doing something like
+ this in the construction business that would have made his father proud.</p>
+
+<p>…</p>
+
+<p>“When a man drives his new Mercedes up a dirt road with greasy tools in the back seat, he
+is not there because he has to be. … We had calls coming into the office for him all the time from
+important people in San Francisco and Hollywood and Washington. He wouldn’t come down off
+the mountain to call them back, and he wouldn’t use the portable telephones we gave him
+either. … He left a lot of his money on the table to take care of the people who worked with him. In the
+deal he made with Sunbelt, they didn’t buy all of his equipment by any means. But he agreed to
+leave some of his extra equipment on the job for us to use, I mean big bulldozers and scrappers.
+He let us use that equipment for free so long as we employed some of his old-timers from
+the area to operate the equipment. They had jobs for the next two years … some of those old
+boys were running new bulldozers that they never before in their lives even dreamed of touching
+All the next year, he would stop by the job whenever he was in town and just watch his old
+crew working on the mountain. He’d climb on a Cat and do a little work while the crew was
+having lunch or he’d give some suggestions to the mechanics working on a piece of equipment
+that broke down. He never came in the office to tell us how we ought to be running the
+operation.</p>
+
+<p>…</p>
+
+<p>“We had one real emergency in the winter of 1986. Heavy rains for two weeks almost
+washed out our cyanide ponds. The mine would have been out of business if the cyanide had
+washed into the river below. Wattenburg showed up with a truckload of big water pumps that
+we hadn’t been able to rent from anybody because everybody in northern California was being
+flooded. He stayed up there to help us day and night for almost a week. We asked him later
+where he found the pumps we needed. He told us that Dillingham Construction Company, the
+big contractor in Benicia, owed him a favor. He never sent us a bill.”</p>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldMine.html.i
@@ -1,0 +1,41 @@
+19 pages
+size 400 562
+length 27915
+403 2 11 body html
+0
+1423 2 28 body html
+102
+3201 2 54 body html
+0
+4386 2 71 body html
+136
+6172 2 95 body html
+35
+6172 2 95 body html
+595
+8711 2 126 body html
+221
+10645 2 151 body html
+102
+12119 2 171 body html
+136
+13973 2 195 body html
+51
+15711 2 217 body html
+0
+16511 2 227 body html
+262
+18082 2 252 body html
+119
+19539 2 270 body html
+170
+21599 2 297 body html
+0
+22887 2 315 body html
+0
+23693 2 327 body html
+187
+24997 2 345 body html
+249
+24997 2 345 body html
+799
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldMine.html.index
@@ -1,0 +1,41 @@
+19 pages
+size 400 562
+length 27949
+403 2 11 body html
+0
+1423 2 28 body html
+102
+3203 2 54 body html
+0
+4388 2 71 body html
+136
+6182 2 95 body html
+35
+6182 2 95 body html
+595
+8721 2 126 body html
+221
+10655 2 151 body html
+102
+12129 2 171 body html
+136
+13987 2 195 body html
+51
+15729 2 217 body html
+0
+16529 2 227 body html
+262
+18102 2 252 body html
+119
+19559 2 270 body html
+170
+21619 2 297 body html
+0
+22907 2 315 body html
+0
+23713 2 327 body html
+187
+25025 2 345 body html
+249
+25025 2 345 body html
+799
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldenGate.html
@@ -1,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Golden Gate Bridge Traffic Barrier</title>
+</head>
+
+<body>
+
+<h1>Golden Gate Bridge Traffic Barrier</h1>
+
+<h2>(1982–1984)</h2>
+
+<p>Another series of newspaper articles in 1982–1984 describe how Wattenburg did the
+“<a href="BART.html">BART story</a>” again on the over-confident Golden Gate Bridge
+engineers who insisted that a moveable
+anti-collision barrier could not be designed that would fit between the traffic lanes on the bridge
+and meet the requirement that it be moved twice each day to allow reallocation of the lanes for
+rush hour flow. The Bridge’s private engineering firm was being paid over a million dollars a
+year to advise the bridge district. Numerous fatal head-on collisions had made this a very
+controversial subject. A frustrated bridge director called on Wattenburg to find a solution. A few
+weeks later he came up with a design that stunned the confident engineers—and evidently
+fascinated the press and the public because it was so simple.</p>
+
+<p>His solution was to use sections of large-diameter (24″) round steel pipe which are strung together
+on a strong steel cable like a spaghetti necklace. He later proved that the steel pipe is as strong as
+conventional concrete lane dividers. The steel pipe can be rolled from lane to lane quite easily to
+change traffic flow patterns. Once Wattenburg had proved that the problem could be solved by at
+least one inexpensive scheme, two other companies quickly came forth with alternate designs of
+their own. Internal politics over where and how money should be spent on bridge improvements
+has delayed installation of any of these anti-collision barriers to date. However, other bridges
+around the world have installed movable traffic barriers which are renditions of Wattenburg’s
+patented design that he offered to give the Golden Gate Bridge District free-of-charge.</p>
+
+<p>The head of one embarrassed engineering firm working for the bridge district attacked
+Wattenburg’s credentials to be doing work for the district without having a license as a
+professional engineer (he evidently assumed that Wattenburg must be getting paid). Wattenburg’s
+terse response to the press was: “I don’t take public money for exposing high-priced fools who
+pretend to be competent engineers.”</p>
+
+<p>Bill Wattenburg and his son, Eric, who was an engineering student at California State
+University, Chico, were issued a patent on their movable pipe barrier design in 1987. His son
+had designed the mechanism that automatically rolls the pipe barrier from lane to lane while
+keeping it tied down securely to the bridge deck or roadway at all times. Wattenburg said that he
+was about to give up on the pipe barrier idea because he hadn’t solved this problem. Eric picked
+up the problem one weekend and found a clever solution that made the whole scheme practical.
+Eric built a fully operational scale model that he demonstrated to the Golden Gate Bridge
+Directors.</p>
+
+<p>Wattenburg told us that movable pipe barriers are still the cheapest and best traffic barriers
+that can be quickly installed around many places that could be attacked by vehicles carrying
+bombs or terrorists, such as government buildings, embassies oversees, and troop encampments
+in hostile places. “The military will get around to it someday, after we lose another few hundred
+of our people.”</p>
+
+<hr />
+
+<p><i>Note: It took until late 1998 before anyone paid serious attention to
+Wattenburg’s idea of using the barrier to protect against truck bombs. The San
+Francisco Chronicle reported
+on the successful testing performed by Lawrence Livermore National Labs (October 8, 1988).
+Unfortunately, the device still has not been used to this date.—PKS</i></p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/GoldenGate.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 562
+length 4104
+424 2 11 body html
+0
+1348 2 28 body html
+136
+3318 2 53 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/HelicopterMinesweeper.html
@@ -1,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Helicopter Minesweeper</title>
+</head>
+
+<body>
+
+<h1>Helicopters to Clear Minefields</h1>
+
+<h2>(1990)</h2>
+
+<p>His most recent invention is a new device for clearing minefields out of war zones during
+the Gulf War. He designed a thing called a “chain matrix” which is pulled by a helicopter over the
+ground to dig up the mines and explode them without endangering people. The story (San
+Francisco Chronicle, March 8, 1991, front page) picked up the human interest side because he
+had used a small blacksmith’s shop in a farming town to build the first prototypes and local
+farmers to test the devices when major defense contractors would not move fast enough to please
+him.</p>
+
+<p>Wattenburg really didn’t want to talk about it beyond what was disclosed in the many
+press stories about his helicopter minesweeper. He told us to contact the Livermore National
+Laboratory for anything more we wanted to know. He mentioned that some parts of his design
+were now classified and that the full details of the design were not disclosed to the press for
+obvious reasons. He did say that the version that was tested at the Yuma Proving Grounds was
+“not quite as clumsy and contained things a little more sophisticated than what the newspaper
+stories showed.”</p>
+
+<p>The Livermore Lab spokesperson would not comment beyond the press stories. He did
+say that Wattenburg would soon be issued a patent on the unclassified portions of the
+minesweeper design. He said that this device also appears to have great application in farming
+operations in areas where the ground is very rocky. He said that Livermore engineers were
+already in contact with manufacturers of agriculture equipment. He laughed when he told us that
+“Wattenburg says that the last thing he ever wants to see again is a farm.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/MeasuringOilTanks.html
@@ -1,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Don’t Call the FBI!</title>
+</head>
+
+<body>
+
+<h1>Don’t Call the FBI!</h1>
+
+<h2>(1974)</h2>
+
+<p>This next story amused our staff to no end when they found the first of the newspaper
+stories. Wattenburg seemed excited himself when we showed him how widely the story had been
+publicized around the world. He said that he hadn’t realized it at the time.</p>
+
+<p>In 1974, Wattenburg again embarrassed government scientists and bureaucrats alike. He saved
+the country millions of dollars during the first oil crisis when he showed that he could measure
+how much oil was in oil refinery storage tanks by simply pointing a special infra-red camera at the
+tanks from a distance. This story was first reported in the San Francisco Chronicle, February 6,
+1974, with the headline: “How to See Inside Their Oil Tanks”.</p>
+
+<p>During the oil crisis, Energy Department officials announced that they were going to use
+a thousand FBI agents to crawl into all the oil tanks in all the refineries of the country to see how
+much gas and oil the oil companies were hoarding. Embarrassed officials in Washington quickly
+cancelled their plans to use FBI agents after the story of Wattenburg’s feat was carried by the
+wire services all over the country.</p>
+
+<p>Wattenburg treated the viewers of the ABC network to a dramatic film that showed how he
+stood back at a distance and measured the oil levels in all the storage tanks at the Richmond,
+California, Chevron Oil Co. refinery—without really trying! As his special TV-like camera
+scanned the tank farm, the screen showed the surface of each oil tank glowing brightly up to the
+liquid level in the tank. The empty upper portion of each tank showed black. The liquid levels of
+a hundred oil tanks in the distance could be measured to an accuracy of 5% just by looking at
+their images on the camera screen.</p>
+
+<p>Wattenburg had made the film in a few minutes using a commercially available infra-red TV
+camera—from a distance of a mile away! He showed that the government could easily measure
+the oil in all the refinery tank farms of the country. He proved that they could do this in a day by
+simply flying over the tank farms with military reconnaissance aircraft that carried the same infra-red camera. </p>
+
+<p>This is the story he gave one reporter at the time:</p>
+
+<blockquote>
+ <p>The idea came to him when he remembered that water tanks on the farms near where he
+ grew up often had a very visible dew line on them early in the morning because the portion of the
+ tank filled with water stayed at a warmer temperature overnight than the empty upper portion that
+ was cooled down by the nighttime air temperature. Conversely, the sun warmed the upper
+ surface more quickly than the lower surface in the afternoon. This meant that the portions of oil
+ tanks filled with oil would be warmer in the morning and cooler in the evening than the empty
+ portions which followed the local air temperature. This temperature difference is easily measured
+ and displayed by infra-red TV cameras of the kind Wattenburg borrowed for his dramatic
+ experiment (Thermovision by AGA Corporation). This technology was first developed for satellite
+ reconnaissance of rocket launchings (Wattenburg worked on this as a consultant to Lockheed
+ Missiles and Space Co. in 1965–1968.)</p>
+
+ <p>The congressional subcommittee that had initially insisted that the Energy Department use
+ FBI agents later asked Wattenburg to testify at a hearing in Washington. They wanted to
+ investigate why the  Energy Dept. had not thought of his idea. He wrote the committee staff a
+ widely publicized letter in which he gave them complete instructions on how to do it themselves
+ and where they could find a suitable infra-red camera in the Pentagon! He suggested that this
+ would save the taxpayers his airfare—and that “they would really find it a lot more fun to do it
+ themselves.”</p>
+
+<p>The subcommittee staff insisted that he appear. Then he wrote back that he would be
+ delighted to appear because he had “just discovered something else that your subcommittee has
+ told a government agency to do that is even more foolish than using FBI agents to crawl into oil
+ tanks.” They evidently cancelled the hearing.</p>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/MeasuringOilTanks.html.i
@@ -1,0 +1,11 @@
+4 pages
+size 400 562
+length 4646
+411 2 11 body html
+0
+1614 2 33 body html
+0
+2685 2 48 body html
+147
+2685 2 48 body html
+697
--- /dev/null
+++ b/lib/ebooks/oebtest/QuotesAboutBill.html
@@ -1,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Quotes About Bill Wattenburg</title>
+</head>
+
+<body>
+
+<html>
+
+<h1>Quotes about Bill Wattenburg</h1>
+
+<p>From a well-known scientist who once worked with Wattenburg:</p>
+
+<blockquote><q>If anyone has spent $10 or $20 million on a difficult technical problem and not
+found a solution, they probably should have asked Bill Wattenburg First.</q></blockquote>
+
+
+<p class=pagebreak>Said to Bill by a woman who pulled up next to his Mercedes 280SL in traffic (his licence
+plate read “PILL”):</p>
+
+<blockquote><q>Hey, thanks for reminding me!</q>—<i>SF Chronicle, Aug. 16,
+1974, p. 25, in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">From a colleague at the Nevada nuclear weapons test site:</p>
+
+<blockquote><p><q>He was always looking for the simple solution that everyone else had
+      overlooked. His favorite saying was: <q>A smart cowboy just wouldn’t work
+      this hard to make things so goddamn difficult.</q> Then he would throw up his
+      hands and go off to tease the ladies in some local bar down the highway
+      while the rest of us were working our butts off.</q></p>
+      <p><q>You are always wondering when he is going to make a fool out of
+      you, and do it in some simple way or with some crazy experiment that
+      forces you to stand and applaud your own ignorance.</q></p>
+      <p><q>But if you want to know what I really think of him, I’ll tell
+      you. If I am ever trapped in a spaceship and everyone says it is hopeless,
+      I hope he is still around, and near a telephone…</q></p></blockquote>
+
+<p class="pagebreak">From a U.S. Forest Service Supervisor in Plumas County, Calif.:</p>
+
+<blockquote><q>There are not many old pros like him left anymore who can chase a forest fire on
+a bulldozer in the night over mountains so rugged that you can’t walk on them. I mean fire crews
+won’t go where he takes a bulldozer. This guy attacks a fire just like it was trying to kill his
+kids. We called him once when he was on the radio in San Francisco—we just needed his equipment
+on the fire. He was on the fire <i>himself</i> four hours later.</q></blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/QuotesFromBill.html
@@ -1,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Quotes From Bill Wattenburg</title>
+</head>
+
+<body>
+
+<html>
+
+<h1>Quotes From Bill Wattenburg</h1>
+
+<p>In response to a California state Senator asking his opinion of BART management:</p>
+
+<blockquote><q>I’m still looking for the front end of the horse.</q>—<i>SF Chronicle,
+Nov. 19, 1973, p. 29 in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">To the Maitre d’Hotel (while slipping him $20) after his date made him take back a bottle of
+wine—but one of many complaints:</p>
+
+<blockquote><q>Take <i>her</i> away!</q>—<i>San Francisco Chronicle, Apr. 19, 1974,
+p. 27, in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">Describing BART General Manager Billy Stokes at a Commonwealth Club meeting:</p>
+
+<blockquote><q>The extraction by some farmers of methane gas from manure piles is interesting,
+but how can you top a genius who is trying to run a subway system on pure bullshit?</q>—<i>San
+Francisco Chronicle, Mar. 29, 1974, p. 29, in Herb Caen’s column.</i></blockquote>
+
+<p class="pagebreak">On why he hasn’t written more books:</strong></p>
+
+<blockquote><q>You can sometimes beat the pros at their own game once. But they don’t often let
+you get away with it a second time. It’s much easier to find another field.</q></blockquote>
+
+<p class="pagebreak">A favorite saying at the Nevada test site:</p>
+
+<blockquote><q>A smart cowboy just wouldn’t work this hard to make things so goddamn
+difficult.</q></blockquote>
+
+<p class="pagebreak">In response to a fellow scientist asking if he had been in an accident:</p>
+
+<blockquote><q>No, some women just like to make their cowboys jealous. I guess it makes him better
+in bed after she takes him home and patches him up.</q></blockquote>
+
+<p class="pagebreak">Describing the BART train control system in the 1970s:</p>
+
+<blockquote><q>…the world’s most expensive, computer-controlled, track-mounted
+pinball machine.</q></blockquote>
+
+<p class="pagebreak">On why it was so easy for him to find a easy, reliable way to duplicate the
+early BART magstripe tickets (and thus credit cards, until he helped the banks find a more reliable
+encryption design):</p>
+
+<blockquote><q>It’s not my fault. When engineers have too much money, they usually
+think only of the most sophisticated ways they can spend it. No one asks them to play devil’s
+advocate and think of the obvious until it’s too late.</q></blockquote>
+
+<p class="pagebreak">In response to an allegation that he was working for the Golden Gate Bridge district
+(designing a traffic barrier to prevent head-on collisions that the bridge engineers said could not be designed)
+without a professional engineer’s license:</p>
+
+<blockquote><q>I don’t take public money for exposing high-priced fools who pretend
+to be competent engineers.</q></blockquote>
+
+<p class="pagebreak">In response to a corrosion engineer who had been working on the EBMUD blue water problem
+for a year:</p>
+
+<blockquote><q>Where I went to school, we don’t give degrees to engineers who can’t
+solve a problem in a year.</q></blockquote>
+
+<p class="pagebreak">Upon being asked why other talk show hosts don’t follow his format of welcoming callers
+on any subject:</p>
+
+<blockquote><q>If you do, you’d better be ready to spend three hours on the air
+admitting your ignorance. You’d better be prepared for what smart people will ask
+you.</q></blockquote>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/TalkRadio.html
@@ -1,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Talk Radio on the West Coast</title>
+</head>
+
+<body>
+
+<h1>Talk Radio on the West Coast</h1>
+
+<p>The ratings for Bill Wattenburg’s night-time talk show “The Open Line To
+The West Coast” on KGO Radio (ABC),
+San Francisco, have been three to four times above the average of the next best-rated
+shows (AM and FM) in the market for at least the last eleven years running (since 1982).
+His show gains 11 to 20 shares in his time slot compared to 3 to 4 shares for his closest competitors.
+He has been a regular on KGO talk radio since 1972. His nighttime radio shows
+reach the entire west coast from Alaska to Mexico, as he announces when he comes
+on the air. Based on his Bay Area audience ratings, we estimate that at least
+1,200,000 in the eleven western states and Alaska hear some part of each of his
+three-hour, 10pm to 1am KGO shows on weekends. We estimate that at least
+13,000,000 on the west coast have listened to him at some time in the last three
+years on radio and recognize his name or his voice. Out-of-market numbers say
+that his total listening audience in southern California is substantially larger
+than in the Bay Area in the 10pm to 12pm time slot.</p>
+
+<p>Our staff evaluated tapes of sixteen of his KGO Radio shows and three of his
+TV shows picked at random for the period January 1988 to December 1992. He
+allowed us to observe him in-studio during four of his live KGO radio talk shows
+in October 1992. A recent feature story on his KGO radio performances appeared
+in the Capitol Cities/ABC employee magazine. We believe this to be a fair
+analysis of his radio performances.</p>
+
+<p><i>[The story from the employee magazine, <i>ABC Ink</i>, is not included here because
+ABC does not grant permission for this content to be reproduced electronicly, but it is quite
+interesting.—PKS]</i></p>
+
+<hr />
+
+<p>We picked up some sour notes however, from one KGO Radio producer who has
+been with the station for many years. This producer said that Wattenburg almost
+never takes guests on his show and that he ignores advice from producers who
+offer him important material and topics for his shows. We asked this producer to
+give us an example. The producer mentioned that Wattenburg ignored some news
+stories during the Gulf War that reported the danger of nuclear material being
+scattered all over the desert, or that the Iraqis could have retrieved a nuclear
+warhead and used it against us. We asked the producer if he/she knew that
+Wattenburg was probably very familiar with the safeguards on our nuclear weapons
+because he worked on the design of nuclear weapons at one time and was an
+advisor to the Air Force. The producer said that he/she did not know that
+Wattenburg had ever done that.</p>
+
+<p>As to the second complaint—no guests on his shows—we politely asked if
+anyone could explain why Wattenburg’s ratings were more than twice as high as
+the top-rated daytime KGO shows that specialized in interviewing guests booked
+on the shows by producers. The answer we got was that it was easier for him to
+hold high ratings in the nighttime slot at 10pm to 1am than during the daytime.
+We pointed out that all the other major radio shows on the west coast in the
+same time slot had much lower ratings that Wattenburg. And, we asked why
+Wattenburg still had higher ratings when he did the KGO daytime shows in the
+seventies.</p>
+
+<p>The last response we were offered by this senior producer was: “Well,
+he’s been around for twenty years, you know. All the rednecks listen to
+him.”</p>
+
+<p>Another KGO producer who works Wattenburg’s shows commented that some of the
+older KGO producers don’t like Wattenburg just because he won’t take guests that
+they try to book on his shows. “They get a lot of flak from their public
+relations friends in New York who want to book authors on Wattenburg’s shows.
+Wattenburg won’t take even his own best friends on his shows. Why should he take
+theirs? … The younger producers here fight to work Wattenburg’s shows. It’s a
+lot of fun, and it’s sort of satisfying. And it’s a snap. … He tells us to take
+every caller who calls on his show. We get a lot of really bright young kids who
+call his show late at night. He gets a little mad if you even refuse to let a
+drunk on his show. He says a lot of drunks make more sense than the sober ones,
+and people love to hear them on the air because if you work them right they will
+tell the whole world the truth that they will be sorry about tomorrow. … It’s
+sort of nice to start a show when the switchboard is already full of calls
+before he goes on the air … our biggest problem is when people start to call
+before the end of the previous show and only want to know if Wattenburg is going
+to be there later. The host on that show gets mad at you if he is pleading for
+callers and he sees calls coming in, but none of them are for him…”</p>
+
+<p><b>We verified that Wattenburg started and promoted two major environmental
+campaigns on his radio shows. These were: stopping the giveaway of the Tongass
+National Forest in Alaska to foreign-owned (Japanese) interests, and saving the
+old-growth redwoods in the Headwaters Forest owned by Pacific Lumber Company.</b></p>
+
+<p>He began alerting his west coast audience to these dangers in 1989, well before
+national environmental organizations were on the bandwagon. He first warned that
+the takeover of Pacific Lumber by a Houston investor in a junk bond deal would
+lead to the cutting of the last of the privately-owned virgin redwoods. State
+and federal officials didn’t believe him until Pacific Lumber’s new owners filed
+for a logging permit the next year. Major public campaigns and legislation have
+since stopped the cutting for the near future.</p>
+
+<p>For two years, Wattenburg’s audience bombarded congress with protests over
+the fifty-year contracts given to foreign-owned lumber companies to cut the
+virgin forests in the Tongass Forest for as little as a few dollars a tree. Most
+members of congress admitted that they didn’t even know that this country’s
+largest national forest existed, let alone where it was. Wattenburg’s favorite
+ploy was to remind politicians that they were hypocrites for complaining about
+the cutting of rain forests in other countries while they allowed the
+clear-cutting of this country’s only temperate rain forest.</p>
+
+<p>The U.S. Forest Service finally modified the contracts extensively in 1992
+and set aside large areas in the Tongass that can not be cut. Wattenburg still
+delights in reminding the environmental lobbies that they only later got
+interested in this problem to get contributions to save a forest that was
+actually rescued by his audience on KGO Radio.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/TitlePage.html
@@ -1,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background</title>
+</head>
+<body lang="en-us">
+
+<h1 class="title">Bill Wattenburg’s Background</h1>
+
+<p style="text-align: center">Originally compiled in 1992</p>
+
+<br />
+
+<center><img src="DrBill.tif" /></center>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/TitlePage.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 586
+400 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/TitlePage.html.index
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 586
+400 2 10 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/about.html
@@ -1,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: About This Report</title>
+</head>
+<body lang="en-us">
+
+<h1 class="title">About This Book</h1>
+
+<h2 class="title">Peter K. Sheerin</h2>
+
+<p class="title">I received the report from a government agency that wanted more people to know more of Bill
+Wattenburg’s interesting and varied background.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/awards.html
@@ -1,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Awards</title>
+</head>
+
+<body>
+
+<h1>Awards</h1>
+
+<p>Wattenburg received a Certificate of Merit from the Secretary of Defense in 1970 for his
+service on the U.S. Air Force Scientific Advisory Board from 1966 to 1970. Members of this
+Board were authorized by Congress to oversee and advise the Secretary of Defense and the
+President on the strategic defense programs of the Air Force. Members are given the equivalent
+military rank of General and the authority to request briefings from the staffs of any Air Force
+command concerning the defense programs and forces at their command.</p>
+
+<p>Wattenburg served on a sub-committee headed by Dr. Edward Teller which reviewed and
+evaluated this nation’s nuclear defense and missile capability. Wattenburg proposed
+significant defense strategy changes which are recorded in still classified documents from this period.</p>
+
+<hr />
+
+<p><i>I also found out that Bill was named a Distinguished Alumni of Chico State
+for 1999, in the College of Engineering, Computer Science, and Technology.</i>—PKS</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/awards.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 1429
+396 2 11 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/background-education.html
@@ -1,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Education</title>
+</head>
+
+<body>
+
+<h1>Background and Education</h1>
+
+<p>Bill Wattenburg’s academic training explains some of the technical tricks he has pulled off
+in the public domain. He has a Ph.D. in electrical engineering and physics from
+U.C. Berkeley, and he has kept up very successful careers in science and business throughout the entire time he
+has been doing radio, television and publishing.</p>
+
+<h2 id="Hometown">Hometown</h2>
+
+<p><i>(The following comes from KGO Radio promotional material.)</i></p>
+
+<blockquote><p>Bill Wattenburg was born in Chico, California, on February 9, 1936. He grew up in the
+mountains of northeastern California in the lumber industry and ranching areas of Plumas County. His
+mother died when he was nine.  He and his younger sister were raised by
+their father. They often lived with family friends when their father was away seeking work as a
+logger, road builder and mechanic. When he was nine to thirteen years old, Bill lived and worked
+with an old gold miner friend of his father’s most of the time. The family friend had a mining claim
+and cabin twenty miles from the nearest town and located at 7,000 feet in the Sierra. They were
+snowed in several months each winter and Bill got his education from books, a short-wave radio,
+and correspondence courses supplied by the school district.</p>
+
+<p>When asked how he got where he is today, Wattenburg says it began shortly after he
+graduated from high school when he was 15. His father walked up to him one afternoon on their
+logging job and told him to get off the bulldozer he was operating. He said that he had told his
+father that he wanted to work as a logger instead of going to college. His father then threatened
+to “knock him on his butt” if he didn’t get on the Greyhound bus that very night and go to
+U.C. Berkeley where he had been offered a scholarship. He had never been out of the mountains of
+northern California except for a few trips to nearby Reno to buy school clothes. His high school
+science teacher had insisted that he take a National Science Foundation examination before he
+graduated. This teacher helped him apply to several universities. He had never opened the
+letters that came back from the universities. But his father, who had not finished high school, had
+opened the letters and seen the scholarship offer from U.C. Berkeley.</blockquote>
+
+<h2 id="Education">Education</h2>
+
+<p>Bill Wattenburg enrolled at Berkeley as an engineering major and finished his freshmen year
+with honors. The following year he moved to California State University at Chico because it was
+closer to home and his father needed help to support the family in Plumas County. He worked
+in the logging woods and as a ranch hand. He commuted to college at Chico during the week.
+His records at Chico State show that he played football and boxed on the Chico State teams for
+three years.</p>
+
+<p>Young Bill Wattenburg evidently had some trouble with the law in his home town
+in Plumas County. Some of the local people we interviewed remembered that Bill was
+involved in some fights in local bars around the county when he was eighteen or nineteen. The
+other men involved had reputedly threatened or attacked Bill’s father while Bill was away in
+college. These were disgruntled former employees whom his father had given jobs when no
+one else would hire them.</p>
+
+<p>However, the Plumas County Sheriff’s Department and the local newspaper have records of
+only one incident in 1955 involving a man who was formerly convicted of assault with a deadly
+weapon. Bill’s father had given him a job while he was on probation, but later fired him over
+some disagreement. This man later got in a fight with Bill and then filed assault and battery
+charges against Bill. The charges were dismissed after witnesses said that the man threatened Bill
+with a hunting knife. The news story quoted witnesses as saying that Bill approached the man in
+a local bar and asked him: “Would you like to point that knife at me the same way you did
+my father?” The man was returned to county jail after he was released from the county hospital
+with a cast on his broken right arm.</p>
+
+<h2 id="GraduateSchool">Graduate School</h2>
+
+<p>Bill Wattenburg graduated summa cum laude from California State University, Chico,
+with a double major in electrical engineering and physics. He returned to Berkeley as a graduate
+student on a National Science Foundation scholarship in 1958. There he studied electrical
+engineering under Professor Harry D. Huskey, who was intimately involved in some
+of the world’s first digital
+computers <i>[and was the president of the Association for Computing Machinery
+in the early 1960s—PKS]</i>. Professor Edward Teller (known to many as the “father of the
+hydrogen bomb”) was one of his physics teachers. He was awarded a Ph.D. in electrical
+engineering and physics at Berkeley (summa cum laude) in 1961, after only three years in
+graduate school. He was immediately offered a position as Assistant Professor of Electrical
+Engineering on the prestigious Berkeley faculty.</p>
+
+<p>The following year he was captivated, he says, by President John F. Kennedy’s call for an end
+to atmospheric nuclear testing and the development of cleaner underground testing procedures.
+He took a leave of absence from Berkeley and moved to the Livermore National Laboratory
+where he worked in the physics division on the design of nuclear devices and the first
+underground nuclear tests. He then spent six months at the Nevada nuclear test site.</p>
+
+<p>A Lawrence Livermore National Laboratory official confirmed that he was the
+inventor of still-classified nuclear test measurement and diagnostic procedures that are essential to
+our nuclear test ban treaty verification technology today.</p>
+
+<h2 id="AcademicWork">Academic Work</h2>
+
+<p>He returned to teaching and research at the University of California, Berkeley campus in 1964
+where he continued his research in the design of digital computers systems and supervised a large
+group of graduate students. He taught the main graduate courses in digital computer design and
+programming at Berkeley for the next five years. Many of his graduate students are today high
+level executives in major American computer and communication companies. He also continued
+his work in nuclear weapons testing at Livermore as a part-time consultant and became a
+consultant to IBM, General Electric, and Lockheed Missiles and Space Company in various
+defense and space projects at those companies from 1964–1970. He was a member of the U.S. Air
+Force Scientific Advisory Board from 1966 to 1970.</p>
+
+<p>From 1961 to date, he has published over twenty scientific research papers and technical
+articles and has been awarded six U.S. and foreign patents. <i>[The total is now
+eight U.S. patents—PKS]</i></p>
+
+</body>
+</html>
+
--- /dev/null
+++ b/lib/ebooks/oebtest/background-education.html.i
@@ -1,0 +1,19 @@
+6 pages
+size 400 562
+length 7245
+399 2 11 body html
+0
+886 2 24 body html
+227
+2747 2 46 body html
+0
+3742 2 62 body html
+153
+5472 2 86 body html
+68
+7020 2 108 body html
+0
+AcademicWork 4
+Education 1
+GraduateSchool 3
+Hometown 0
--- /dev/null
+++ b/lib/ebooks/oebtest/bloodbanks.html
@@ -1,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Blood Banks</title>
+</head>
+
+<body>
+
+<h1>Blood Banks</h1>
+
+<p>Bill Wattenburg’s first reported entry in the public domain happened when he was a young
+assistant professor at Berkeley. The Director of the Alameda County Blood Bank, Dr. David
+Singman, a pathologist at Alta Bates Hospital in Berkeley, came to him in 1965 with a problem at
+the Alameda–Contra Costa Blood Bank that was costing a great deal of money and loss of life
+around the country. In the traditional way that blood banks distributed blood to local hospitals,
+up to twenty percent of the blood was being lost because of “outdating”. This spoilage
+occurred because the blood sat in refrigerators in the hospitals past the thirty-day limit during which it
+could be safely used somewhere else. Once a unit of blood was sent to a hospital, it was usually
+cross-matched and set aside for a particular patient. Even if the patient didn’t need it later, this
+particular unit of blood was seldom ever sent to another hospital before it became outdated and
+had to be thrown away.</p>
+
+<p>Dr. Singman knew that Wattenburg was designing computers at U.C Berkeley at the time.
+He told Wattenburg about this problem and asked him if he could solve it.</p>
+
+<p>On his own time, Wattenburg first designed a method to positively identify each pint of
+blood by a special code before it left the blood bank. He then designed a computer system to
+track each pint of blood as it went into hospital inventories. Frustrated with writing proposals and
+waiting for government money to buy the computer equipment he needed, Wattenburg convinced
+Lockheed Missiles &amp; Space Co. in Sunnyvale to contribute time on one of their large defense
+computers during nighttime. Wattenburg had earlier helped design this computer for an Air Force
+project. He made a deal with Lockheed—He promised to show them how to save at least an hour
+of computer time a day on the Air Force project in return for the fifteen minutes at night he
+needed for the blood bank.</p>
+
+<p>Next, he devised a scheme to hook up all hospitals and the Alameda Blood Bank to the
+Lockheed Sunnyvale central computer over telephone lines. This was ten years before remote
+data terminals for computers were commonly available.</p>
+
+<p>Finally, he designed the computer programs that allowed the Alameda blood bank to keep
+track of every pint of blood in its inventory and sitting at the hospitals it served, His system
+allowed the blood bank to order all blood units approaching outdating at the hospitals to be
+located everyday and sent to other hospitals where they were needed instead of sending new units
+from the blood bank while the old units went to waste in hospital refrigerators.</p>
+
+<p><b>His clever solution stopped the needless waste of ten percent of the blood supply in the Bay
+Area in the first year it was used. The average age of transfused blood was reduced by ten percent,
+and the need for outside donors was reduced by thirty-three percent. His system was quickly
+adopted by the Red Cross nationwide. The results were published in The Journal of the American
+Medical Association (JAMA), November 8, 1965, pp 583–586, “Computerized Blood Bank
+Control”. Wattenburg’s design was soon adopted by most blood banks throughout the country.</b></p>
+
+<p>Dr. Singman has died, but we talked to a retired Red Cross medical advisor who knew Dr.
+Singman at Alta Bates Hospital in Berkeley when he was working with Wattenburg on this
+project. He remembers when all this happened twenty-five years ago. He says that some top
+Red Cross administrators were defensive and annoyed over the attention that Wattenburg’s
+innovation received in the press. “They were forced to admit that it was a great improvement and
+that they would use it as soon as possible, but they were uncomfortable because his idea and the
+JAMA article also brought public attention to the fact that large amounts of blood had been lost in
+the past because they had not recognized something that seemed so simple.” He said he
+remembers how he kicked himself when he saw it. He says that, for certain, hundreds of lives
+have been saved in the twenty-five years since then because desperately needed blood has been
+available were and when it is needed, and the cost of blood has been reduced significantly. He
+remembers that Wattenburg was invited to a blood bank association meeting in San Francisco
+shortly after the JAMA article appeared. Wattenburg announced that he was giving the rights to
+his idea to any blood bank that wanted to use it, free of charge. However, Lockheed built a
+substantial business supplying the computer programs and equipment to hundreds of blood banks
+around the country.</p>
+
+<p>In one of our interviews with him, we showed Wattenburg the nice comments above and
+said that he must be very proud of what he had done at such an early age (29). He displayed
+some annoyance. He then told us that a U.C. Berkeley faculty promotions committee in 1966
+concluded that this work for the nation’s blood banks was “more in the line of public service than
+university level scientific research worthy of promotion consideration.” He said that this
+disappointment was the second time that, “This sort of thing happened to me, but I grew up after
+that.” He wouldn’t elaborate on what the first time was.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/business.html
@@ -1,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Business</title>
+</head>
+
+<body>
+
+<h1>Business</h1>
+
+<p>In 1966, Bill Wattenburg and physicist Donald Glaser
+(winner of the Nobel Prize in Physics, 1960, for the invention of the bubble chamber)
+formed a company called Berkeley Scientific Laboratories (BSL) which grew to a thirty-million
+dollar a year enterprise within three years. Wattenburg served as president of the company until
+1970. The scientific staff at BSL directed by Wattenburg received major NASA contracts for
+work on the spacecraft guidance computer for the Apollo man-to-the-moon project and
+Department of Defense contracts for the computer systems for the Navy’s Poseidon missile. BSL later developed
+a number of very successful commercial products, including the first small medical data computer
+systems used in hospitals around the world to automate and improve medical testing procedures
+in clinical and radiology laboratories.</p>
+
+<p>Berkeley Scientific Laboratories was purchased by Tracor, Inc., a high-technology
+conglomerate in Austin, Texas, in 1969. Wattenburg became a major stockholder in
+Tracor. He resigned as president of BSL and sold his substantial interests in Tracor in 1970. Tracor stock
+dropped considerably over the next few years. He later reinvested heavily in Tracor in 1975
+shortly before it entered a long and profitable growth period over the following ten years under
+the leadership of president Frank McBee, a friend of Wattenburg’s. Wattenburg sold all his
+interests in Tracor again when the company was taken over by Admiral Bobby Inman in the eighties.</p>
+
+<p><i>(The following comes from investment banker Faris Chesley, The Chicago Corporation,
+Chicago, who has known Bill Wattenburg since 1967.)</i></p>
+
+<p>In 1969 Wattenburg and a group of physicians and medical specialists started a company
+in San Francisco called Comprehensive Health Services (CHS), later renamed Comprehensive
+Computer Systems, which developed health screening programs for professional groups such as
+the California Teachers Association and operated a large clinical laboratory in San Francisco. He
+joined the company as director of research in 1972 and developed another very successful product
+line of medical computer systems for radiology which was marketed worldwide by General
+Electric Co. CHS also acquired Bakte-Bennet Laboratories, a major supplier of growth media to
+hospitals and clinical laboratories on the west coast.</p>
+
+<p>Wattenburg and his technical staff at CHS developed a unique system of “marked-sense”
+Medical documents that allow a radiologist to report his full diagnostic findings by simply
+marking a few spots on one of a series of special diagnostic reporting forms. We have attached
+one of these “Raport” forms to this report. General Electric Medical
+Systems division invested over eight million dollars in this development from 1972 to 1976.</p>
+
+<p>The reader will find the following explanation much easier to understand by first
+examining the radiology report form and computer-generated radiology report attached.</p>
+
+<div class="image">
+<img src="raport.png" height="100%" />
+</div>
+
+<p>The computer-readable forms they developed cover the full human anatomy with pictorial diagrams
+showing the areas of interest to a radiologist. Each color-code form also contains a set of
+symbols that describe almost all qualifying statements that a radiologist would normally dictate in
+a report of his examination of an X-ray film.</p>
+
+<p>Wattenburg cautioned us that the original idea for all this came from Dr. Richard
+Mani, a young radiologist at the University of California San Francisco Medical Center who later worked
+with CHS. Several major computer companies and the U.C. computer center staff had told Dr.
+Mani that his idea was not workable.</p>
+
+<p>Wattenburg and his staff worked for two years to build the computer hardware and special
+programs that could read the marked-sense documents and produce medical prose in the
+computer-generated diagnostic reports that would be both accurate and pleasing to radiologists.</p>
+
+<p>General Electric sold hundreds of these small computer systems to major hospitals and
+radiology groups around the world from 1975 to 1980. The product line was sold to National
+Computer Systems, Minneapolis, in 1980.</p>
+
+<p>National Computer Systems bought Comprehensive Computer Systems CHS) from Wattenburg and his group in 1979.
+National Computer Systems was the world’s biggest supplier
+of marked-sense computer equipment and technology. (They still were in 1990. NCS supplies most
+of the multiple choice forms and data processing for schools and educational testing services
+world wide.) Wattenburg became a major stockholder in National Computer Systems.</p>
+
+<p>Wattenburg was doing <a href="TalkRadio.html">talk radio on KGO</a> and <a href="television.html">television
+shows</a> on nights and weekends throughout this period from 1972 on.</p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/oebtest/business.html.i
@@ -1,0 +1,15 @@
+6 pages
+size 400 562
+length 5301
+398 2 11 body html
+0
+1275 2 26 body html
+187
+3241 2 52 body html
+34
+3417 2 55 body html
+0
+3417 2 55 body html
+562
+4148 2 69 body html
+85
--- /dev/null
+++ b/lib/ebooks/oebtest/colleague.html
@@ -1,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: A Colleague’s Observations</title>
+</head>
+
+<body>
+
+<h1>A Colleague’s Observations</h1>
+
+<p>We interviewed a professor of engineering at a major California university who worked with
+Bill Wattenburg at the Nevada Nuclear Test Site in 1962–1963 and at the Livermore
+National Laboratory for some time after that. Like many of his former scientific colleagues we interviewed,
+this man has followed Wattenburg’s public career ever since.</p>
+
+<p>His candid recollections give a good picture of Bill Wattenburg’s personality and style as a young
+scientist. We believe these observations explain a lot about Wattenburg’s public activities and
+personality in later years, as we have summarized it in the following sections of this report.</p>
+
+<p>These are the professor’s comments taped and included here with his permission:</p>
+
+<hr />
+
+<blockquote>
+<p>“Bill Wattenburg’s mind just doesn’t work the same way that everyone else’s does. He is
+bored to death with complicated solutions to difficult scientific problems. He obviously
+understands scientific fundamentals as well as any of the rest of us, but he is basically lazy. … He
+was always looking for the simple solution that everyone else had overlooked. His favorite saying
+was: ‘A smart cowboy just wouldn’t work this hard to make things so goddamn difficult.’ Then
+he would throw up his hands and go off to tease the ladies in some local bar down the
+highway while the rest of us were working our butts off.</p>
+
+<p>…</p>
+
+<p>“But, all too often, he would come back to wake us all up in our trailers in the middle of
+the night and march us into the laboratory to see some Rube Goldberg solution he had discovered,
+or a clever gadget he had built to do the same thing we had worked months to do.</p>
+
+<p>…</p>
+
+<p>“I admired the guy’s genius, but I have to admit that I came to simply dread working with
+him for the first few months that I knew him. You are always wondering when he is going to
+make a fool out of you, and do it in some simple way or with some crazy experiment that forces
+you to stand and applaud your own ignorance. … He was always watching everything what
+everybody else was doing. He seldom ever criticized, but you always had the feeling that he was
+seeing something about your work that you didn’t realize yourself. It was very unnerving in the
+beginning. … But I have to admit that now I try to teach my own graduate students some of the
+things I learned from him.</p>
+
+<p>…</p>
+
+<p>“He was only twenty-five when I began working for him at the Test Site. It was hard to
+believe that he was a nuclear weapons designer from ‘A’ division. Most of us were ten years
+older and we were working for him. … The guy never slept. … A tennis game was the only thing
+that seemed to hold his attention in one place for more than an hour … or maybe a cute cowgirl on
+a barstool somewhere.</p>
+
+<p>“There was a problem with him on this score. Once in a while they would have to send
+out the Test Site security guards to scout every country bar within 50 miles of the test site to find
+him if a problem came up on a weekend. I remember once when they brought him back to the
+trailers and he had blood all over his shirt. Someone asked him if he had been in an accident. He
+said, ‘No, some women just like to make their cowboys jealous. I guess it makes him better in bed
+after she takes him home and patches him up.’</p>
+
+<p>“Once when an underground nuclear test at Mercury was delayed and there was absolutely
+nothing we could do for two days but catch up on our sleep, he kept busy tuning up every
+secretary’s car in the parking lot, free of charge of course. We all knew what he was doing … he
+always found a lady friend out in that god-forsaken desert somewhere who took real good care of
+him. We would get hamburgers for dinner in the cafeteria and he would get a steak with all the
+trimmings.</p>
+
+<p>…</p>
+
+<p>“He would try any damn thing that popped into his mind—even at
+the very last minute before a nuclear shot. He was always pushing everybody to try add-on
+experiments that he cooked up. He was always fooling around with your equipment in the test
+shack in the middle of the night. You’d come back the next morning and something would be
+changed. It was hard enough to carry out the main experiments that we were supposed to do.
+And, he was supposed to be the group leader. But his attitude was that once he showed you how
+to do something, and he was very good at that, it was all over as far as he was concerned. It was
+of no interest to him whatsoever after that. I didn’t feel that he was a good manager in that sense,
+but he made up for it in other ways that I’ll tell you about later.<p>
+
+<p>…</p>
+
+<p>We actually got to the point that we would hide any extra test equipment, like
+oscilloscopes and cameras, and even dumb things like extra pieces of wire and signal cable. If you
+didn’t, he would try to use them for some other quirky experiment that could be wired
+up at the last minute before the shot. He always liked to find things he could add on to other
+people’s equipments that we had been working on for months to get checked out. Most of the
+other physicists made jokes about his ideas. But, on one underground nuclear shot in 1962, they
+all got a real jolt of a different sort.</p>
+
+<p>“One of his ‘midnight’ experiments hit the jackpot. The results shocked all the experts.
+And it was one that the bosses in ‘L’ division at Livermore had said could not possibly work. I
+remember that he was really pissed off because they wouldn’t even let him use some spare test
+equipment from the Livermore shops to do it. How he got permission and the equipment I don’t
+know. Another physicist from ‘A’ division named Russ Duff worked with him, I recall. Yes, I
+think it was Russ Duff who was showing everybody the surprising results of Wattenburg’s
+experiment right after the shot. … I mean the pictures from the Polaroid cameras we used in those
+days to record test results from a shot. They were all gathered around Russ Duff talking about it.
+Someone asked Wattenburg at dinner that night in the cafeteria what he thought about his
+experiment and he said something like ‘Yeah, I thought it would be interesting. Now maybe those
+assholes will wake up next time.’ I think he was talking about the bosses at
+‘L’ division who wouldn’t help him do it.</p>
+
+<p>“What Wattenburg discovered in this experiment really changed the way we instrumented
+bomb tests after that. The report on his Nevada Test Site experiment was still classified for many
+years after that for reasons that I never understood. I was going to talk about it in a classified
+seminar I was going to give to new test engineers in 1975, and I discovered that his report was
+still classified beyond my need to know, which I thought was fairly high at the time. I told the
+head of the division that I thought it was a valuable example for new test engineers … which means
+that I’m a hell of a hypocrite for what I said a while ago about Wattenburg’s crazy ideas. The
+division head, I’ll leave his name out of this, told me that I shouldn’t discuss his report. He said it
+was a “sensitive matter” that he didn’t want to have to get into right then. I dropped
+the subject.</p>
+
+<p>…</p>
+
+<p>“A year or so later, I saw Wattenburg and asked him what was the big deal with his report
+on the 1962 experiment. We all knew that the scheme he discovered—invented would be a better
+description—was being used by everybody in the nuclear testing business since 1963. He just
+shrugged his shoulders and muttered something like ‘It looks like everybody but me has made a
+career out of being the real expert on that subject.’ I sensed that there was some annoyance on
+his part over it, so I dropped the subject.</p>
+
+<p>“This wasn’t the only startling thing he did when he was at the lab by any means. After I
+was no longer working with him in Nevada, I heard through the grapevine at the lab that he shook
+them up a few more times in ‘A’ division, that’s the H-bomb design division. I heard a few of the
+bomb designers say later that they were happy when he finally went back to teaching at
+Berkeley. … But if he went back to Berkeley you’d never have known it. I saw him at
+the lab at night for years after that. I would go in late at night or on weekends to check on one of my
+experiments or a computer run, and I’d see him in the computer room or in the cafeteria, sometimes
+at two in the morning.</p>
+
+<p>…</p>
+
+<p>“A guy in ‘A’ division told me a story about how Wattenburg learned to deal with the
+bureaucracy at the Laboratory after his first successful experiment. He said that Wattenburg had
+another idea and he desperately wanted money to do the experiment. He bragged that this idea
+was so good that he was going to convince them to give him two hundred thousand dollars to do
+this experiment. Everyone laughed at him. When he went to see the the bosses, they would only
+agree to give him twenty thousand. He was happy as a lark when he came back to the physics
+department. Some thought that he had gotten what he wanted. One of the physicists asked him:
+‘Did you get the two-hundred thousand you wanted?’</p>
+
+<p>“He answered: ‘No. I got twice as much as I needed.’ ”</p>
+</blockquote>
+
+<p><i>(The professor now talks at length about other scientists at the Livermore lab that
+Wattenburg used to pal around with, how he taught them to ride a horse in a local rodeo, shoot a
+pistol, water-ski, go deer hunting in the Sierra, and some of his amusing escapades with women
+at the lab. None of this is relevant here, but it is consistent with Wattenburg’s general playfulness
+and hobbies that are reported elsewhere in this report.)</i></p>
+
+<br />
+
+<p>He continues:</p>
+
+<blockquote>
+<p>“Bill Wattenburg’s latest hobby on radio and television is just the right place for him to show off what a clever
+smart-ass he can be. … On the other hand, there are probably few good scientists who can explain complex technical things to the lay public as well as
+he can. … He can cook up the most clever little experiments for people to do at home so that they
+can explain science to themselves. He’s really good with bright kids. I’ve heard ten-year olds call
+him on the radio at midnight. They love him … but that’s because he’s still just a kid at heart
+himself.</p>
+
+<p>“I’m sure a lot of people are happy he is spending his time as a radio celebrity nowadays
+instead of on their backs in the laboratory. … It’s probably a good thing that the crazy guy got
+rich from his early inventions because the ordinary engineers of the world simply wouldn’t be safe
+with him wondering around looking for consulting contracts to beat them at their own
+game. …Anyone who has ever worked with him would never bet money that he couldn’t open a bank
+vault with the manager’s own pocketknife.</p>
+
+<p>…</p>
+
+<p>“I think he has been away from the scientific laboratory too long now to still be up on the
+cutting edge of scientific research. … That means he’ll probably walk into my lab any day now and
+tell me how much he enjoyed reading my latest scientific papers. Then he’ll probably show me all
+the simple things I overlooked.</p>
+
+<p>…</p>
+
+<p>“But if you want to know what I really think of him, I’ll tell you. If I am ever trapped in a
+spaceship and everyone says it is hopeless, I hope he is still around, and near a telephone. …”</p>
+</blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/confrontations.html
@@ -1,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Public Confrontations</title>
+</head>
+
+<body>
+
+<h1>Public Confrontations</h1>
+
+<p>The episodes that follow show that Wattenburg seemed to delight in exposing the failures
+of over-confident engineers who managed public projects. His style, however, was not just to
+criticize them. He typically offered them a better idea or a clever design of his own which he
+then contributed free of charge to the public agencies in question. The trouble seems to have
+started when they said that his ideas wouldn’t work or that he didn’t know what
+he was talking about. (See <a href="BART.html">BART</a>, <a href="GoldenGate.html">Golden
+Gate Bridge Barrier</a>, and <a href="BlueWater.html">Blue Water</a> projects described below.)</p>
+
+<p>We were rather astounded at what we found from database searches of newspaper and wire
+service stories on Bill Wattenburg. At first, we were ignoring those on “Willard”
+Wattenburg, “William” Wattenburg, “Professor W. H.” Wattenburg,
+and “Ben Wattenberg” because we thought they were all different people. Then we
+realized that all but “Ben Wattenberg”, the columnist, are Bill Wattenburg. He has used
+“Willard” and “Professor W. H.” at various times and places for reasons
+of his own. His most recent mention in the New York Times uses “Willard”. We asked him
+why. He said that his driver’s license says “Willard”, so when he was out of the Bay
+Area he told press people who might have wanted to check up on him that his name is Willard Wattenburg.
+Sometimes the press was confused and used “William”. He said he never bothered to correct
+a reporter. Apparently, the importance of building national name recognition as media personality Bill
+Wattenburg did not occur to him.</p>
+
+<ul>
+ <li><a href="BART.html">Fixing BART Safety</a>(Bay Area Rapid Transit System)</li>
+ <li><a href="creditcards.html">Magnetic Credit Cards</a></li>
+ <li><a href="dial-a-ride.html">Dial-A-Ride Carpooling</a></li>
+ <li><a href="MeasuringOilTanks.html">Don’t Call the FBI!</a></li>
+ <li><a href="GoldenGate.html">Golden Gate Bridge Traffic Barrier</a></li>
+ <li><a href="BlueWater.html">Blue Water (Copper) Contamination in Homes</a></li>
+</ul>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/confrontations.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 562
+length 2593
+411 2 11 body html
+0
+1096 2 23 body html
+272
--- /dev/null
+++ b/lib/ebooks/oebtest/copyright.html
@@ -1,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: About This Report</title>
+</head>
+<body lang="en-us">
+
+<p>Text goes here.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/covert.html
@@ -1,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Covert Activities?</title>
+</head>
+
+<body>
+
+<h1>Covert Activities?</h1>
+
+<p>We could find no evidence that Wattenburg has ever been involved in government
+intelligence or covert activities. We enlisted the services of an investigative firm in Washington,
+D.C., whose staff is knowledgeable about the intelligence services. They have reported to us that
+their inquiries indicated no knowledge of Wattenburg having any involvement with the services in
+the past. However, they pointed out that knowledge of any covert activates would never be
+disclosed by their contacts for obvious reasons.</p>
+
+<p>They reported that Wattenburg had been asked by one service to help correct a problem
+with Soviet spying on our new embassy building in Moscow, but that Wattenburg had insisted
+that anything he did would have to be made public because he was working for ABC. He
+evidently made this activity public in the San Francisco Chronicle, April 22, 1987, page 18. The
+U.S. State Dept. did not seem too happy with his comments.</p>
+
+<p>We verified that he was in the country during the period 1985 to 1986 for which we had
+no information in our 1990 report (see his work on <a href="GoldMine.html">The Gold Mine project</a>).</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/covert.html.i
@@ -1,0 +1,5 @@
+1 pages
+size 400 562
+length 1599
+408 2 11 body html
+0
--- /dev/null
+++ b/lib/ebooks/oebtest/creditcards.html
@@ -1,0 +1,241 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Magnetic Credit Cards</title>
+</head>
+
+<body>
+
+<h1>Magnetic Credit Cards</h1>
+
+<h2>(1973)</h2>
+
+<p>We believe that this event lends some insight into Wattenburg’s integrity in honoring
+contractual commitments and confidentiality agreements.</p>
+
+<p>The San Francisco Chronicle reported another of Wattenburg’s startling
+technical tricks during the BART controversy in 1973. A subsequent story in
+Business Week (August 11, 1973, page 120) stunned and sobered the nation’s
+banking and credit card industry which was planning to convert all credit cards
+to the same magnetic stripe system used in the new BART cards. Chronicle
+reporter Michael Harris approached Wattenburg in his Berkeley laboratory and
+asked Wattenburg whether it was possible to counterfeit the new multi-million
+dollar, “fool-proof” BART ticket magnetic stripe designed by IBM.
+This system was the first to use a magnetic stripe to record the value of a
+transit rider’s ticket. BART officials, IBM, and the nation’s banks had all said
+that “anyone would need at least $500,000 worth of specialized electronic
+equipment to copy the magnetic stripe and fool their reading machines.”
+(Anyone but Bill Wattenburg, as it turned out.)</p>
+
+<p>We located one of the technical people, now retired, who was on the scene in 1973 in
+order to verify a couple of minor items about Wattenburg’s financial involvement in this
+event. We got a lot more than we expected. We were able to get some of “the rest of the story” at this
+late date that was not available to the press in 1973.</p>
+
+<br />
+<p><b>Here is the story from press reports:</b></p>
+<br />
+
+<p>On June 4, 1973, in the San Francisco Chronicle (page 22), reporter Harris described how
+he was able to “boost” a 5-cent BART ticket to any value he wanted using an inexpensive scheme
+that Wattenburg had invented in a few hours. Worse yet, Wattenburg devised a simple scheme
+that any housewife could do in her kitchen! Harris described how the idea came to Wattenburg,
+and how he, reporter Harris, was later able to give startled officials a private demonstration at the
+Chronicle offices. The banking industry was about to issue the first of millions of credit cards
+that could have been counterfeited “by any high school kid”, according to Wattenburg. IBM and
+the banks went back to the drawing board for another year before they came up with a better
+scheme (that Wattenburg said he couldn’t easily beat—see story below).</p>
+
+<p>When Wattenburg was later asked by the press and angry government officials how he
+could so easily defeat the efforts of this country’s best engineers, he sent them the following
+apology:</p>
+
+<blockquote>“It’s not my fault. When engineers have too much money, they usually think only of the
+most sophisticated ways they can spend it. No one asks them to play devil’s advocate and think of
+the obvious until it’s too late. I never would have bothered to think about the subject. It was none
+of my business. Hell, I didn’t know that BART and banks all over the country were really planning
+to use this silly scheme.”</blockquote>
+
+<p>He continued:</p>
+
+<blockquote>
+<p>“All that happened is that this reporter Michael Harris, who is a very
+clever guy by the way, came along and bet me that I couldn’t find an easy way to copy this
+funny-looking BART ticket with a magnetic stripe. I thought it was just someone’s prototype idea. But
+he said that IBM had bragged that no one could do it for less than a half-million dollars. Now,
+that kind of gets a scientist’s juices flowing. I mean I didn’t interrupt my serious scientific work at
+Berkeley, but his challenge was on my mind for a few hours.</p>
+
+<p>“Suddenly, I remembered an obscure little thing about the physics of magnetic materials
+that most scientists don’t bother with very often. This phenomenon had given me fits in an
+experiment that I had done as a graduate student. Even my professor at the time didn’t believe it
+until I showed it to him. I thought, ‘Oh my God, the IBM guys couldn’t possibly have
+overlooked that! They’re the world’s experts on magnetic recording.’</p>
+
+<p>“I did a quick experiment with some magnetic tape that I bought at lunchtime in a music
+store on Shattuck Avenue, and damned if I wasn’t able to make a good copy of the BART ticket
+magnetic stripe that Harris had left with me to play with. I didn’t even have time to go to a BART
+station and see if my counterfeit ticket worked. When Harris came back the next day, I gave him
+the materials he would need and showed him how to do it in his kitchen at home. Well, you know
+the rest of the story. …”</p>
+</blockquote>
+
+<p>Wattenburg recently told us that he believed that the 1973 Business Week story contained
+some half-truths to steer thieves in the wrong direction. The press reports show him copying a
+credit card with another piece of magnetic tape. But the stories don’t explain that this was no
+ordinary piece of magnetic tape. He said that the 22 other ways discovered by Cal Tech students
+were all too clumsy or unreliable to be any threat. He believed that IBM and the banks didn’t
+really care if thieves concentrated on these. He said that the banks wanted the Business Week
+story written that way. He agreed to go along with the story for the sake of all the innocent
+people who could have lost their money, but it wasn’t pleasing to him to know all the things that
+were not disclosed to the press.</p>
+
+<p>He told us ruefully:</p>
+
+<blockquote><p>“At least I didn’t say anything dishonest to Business Week. They came around to
+see how I did it and I showed them the mechanics of how it could be done, They
+didn’t ask the right questions and I didn’t volunteer anything more. I hoped they would go out and
+try to copy a card with a piece of ordinary iron oxide magnetic tape, the way Michael Harris did.
+They would have discovered in a hurry that the scheme required something else special. But they
+didn’t. I was really surprised that they wrote the story without checking that. … That was the last
+time I ever took money to keep my mouth shut. I needed money at the time to do a lot of
+important scientific experiments that were on my mind, and I had a lot of good graduate students
+who needed support. The bankers were the big boys. Who was I to tell them what was ethical?
+But you know, when I asked them to provide a few scholarships, they turned me down. That is
+why it eventually cost them a hell of a lot more than a few scholarships.”</p>
+</blockquote>
+
+<p>One of Wattenburg’s scientist colleagues whom we interviewed in August 1990 told us
+what he thinks happened with the magnetic stripe. He said that obviously the whole thing was
+hushed up very quickly because of the potential losses due to thieves learning how to copy the
+magnetic stripe on the new bank credit cards. He said the rumor was that IBM or the
+banks, or both, paid Wattenburg a very handsome sum to help them devise a better scheme. He said that
+one of Wattenburg’s former Berkeley students who worked at IBM was asked to approach
+Wattenburg and that Wattenburg agreed to help them under the condition that he work only
+through his former student.</p>
+
+<p>This IBM engineer, Wattenburg’s former student, later went to work at Livermore. We
+were told that he took great joy in telling the funny stories that happened when the banking
+association attorneys tried to negotiate a deal with Wattenburg. He said they offered Wattenburg
+a very large amount of money if he would help them design a new scheme that couldn’t be
+counterfeited by anyone who did not have at least a hundred thousand dollars of specialized
+equipment which they itemized in the agreement. And Wattenburg had to agree to never again
+talk about or disclose to anyone how he had copied the BART card or anything about new
+schemes that would be developed. He said that Wattenburg agreed that the payment they offered
+seemed quite fair, provided there were a few minor changes. One change Wattenburg made to
+the agreement he sent back was “by anyone other than Wattenburg” in the clause “couldn’t be
+counterfeited by anyone”. The attorneys saw no problem with this because if he helped develop a
+new scheme, obviously he would be one of the few who would know how to beat it as well.
+They accepted the agreement.</p>
+
+<p>But then the bankers realized that Wattenburg could collect his money by only proving
+that “other people” could not copy some new magnetic stripe that he helped them develop. They
+protested that they already had a scheme that “other people” could not easily copy. They had paid
+large sums to universities and major consulting firms to have it tested and no one could copy it
+easily and reliably until Wattenburg came along.</p>
+
+<p>They demanded that Wattenburg change the language of the agreement. Wattenburg
+responded: “Well, tell me how much it is worth to you if I take it out.” Before it was over with,
+they had tripled the amount they first agreed to pay him. The former student said that Wattenburg
+succeeded in beating the next two magnetic stripe recording schemes that they proposed until
+they finally came up with one that he said he couldn’t beat without expensive equipment.</p>
+
+<p>Our contact laughed when he recalled what the former student often told his Livermore
+friends about Wattenburg’s assurance that he couldn’t beat the latest magnetic stripe scheme that
+is now used worldwide. He said: “I’ll bet that Wattenburg just got tired of fooling around with this
+business and told them it was OK. But, do you want to bet what will happen if Wattenburg is ever
+broke and he gets a hold of your credit card for a few hours?”</p>
+
+<hr />
+
+<p>We later learned that some of the 1973 press stories were probably encouraged for public
+consumption, and that maybe even Wattenburg left out a little of the story he told us—for a
+proper reason.</p>
+
+<p>Since this was the only episode in Wattenburg’s public exploits for which he admitted
+taking payment for his services, we decided to investigate it more deeply. In particular, we thought
+this would be a good situation in which to explore how he handled the confidentiality of his
+dealings with those who paid him in return for the same. We were able to locate the “former
+student” mentioned above. Now retired, he was willing to tell us almost all of “the rest of the
+story” since he felt that there was no danger at this late date.</p>
+
+<p>All of the above story is mostly true, as far as it goes. But there was more that the public
+was not told, and for good reason. He said that in the contract that they wanted Wattenburg to
+sign, he refused to disclose, even to IBM and the banks, the nature of the magnetic material he
+used to copy the BART and bank cards. Wattenburg had made some magnetic strips that looked
+like the ordinary Mylar-backed audio magnetic tape with the usual iron oxide magnetic surface,
+but it really had been coated with another special material. Wattenburg gave the reporter Michael
+Harris enough of this special magnetic tape to do his experiment at the BART ticket machines
+and for Harris to later give another demonstration to various officials at the Chronicle offices.
+They never knew for sure what the material was.</p>
+
+<p>He further explained that, unknown to Wattenburg, IBM and others had deliberately
+arranged the competition with Cal Tech students to see who could counterfeit the BART cards.
+But, the BART cards didn’t include all the coding safeguards that were used in the scheme that
+was designed for bank credit cards. He says he believes that IBM knew that most anyone could
+use simple magnetic tape reading equipment to read a BART card magnetic stripe and make a
+copy, as the Cal Tech students and others quickly proved.  But, they were confident that no one
+could counterfeit the more valuable bank cards the same way because ordinary magnetic reading
+equipment could not read the special magnetic coding that they intended to use on the bank
+cards.</p>
+
+<p>In other words, he felt that the well-publicized student competition for copying the BART
+cards and the 22 schemes they came up with was a ruse to cause potential thieves to go in the
+wrong direction and frustrate themselves when the bank cards were issued. He said he learned
+that the first thing that IBM had tested was to make sure that their magnetic coding scheme on
+the bank cards could be not read by ordinary magnetic tape reading equipment. They were no
+fools.</p>
+
+<p>But they did not count on Wattenburg coming along. He found a way to physically copy
+the magnetic coding on the IBM stripe directly onto another magnetic stripe without using any
+intermediate electronic read-write cycle. His scheme copied everything, including the magnetic
+special coding on the bank cards that couldn’t be copied by inexpensive magnetic tape reading
+equipment. In fact, they found out that Wattenburg’s copies had as much resolution (were as
+good) as the original magnetic stripe that he had copied. This scared the hell out of them. This
+meant that he could copy the new bank cards as well.</p>
+
+<p>He said that Wattenburg refused to tell IBM or the bankers what the material was that he
+had used to make his special magnetic tape that could capture an image of their magnetic
+stripes—and could be accomplished in the kitchen. This was the real sticking point in the agreement that
+they wanted with him. Wattenburg insisted that if IBM scientists used their heads they would
+soon figure it our on their own. He felt that he didn’t want to be the one who gave license to
+thieves by being the first one to disclose it. He felt that the university would get a bad name. They
+finally settled on an agreement with him to help them anyway. And, they had to pay him
+handsomely to take out the “anyone other than Wattenburg” clause.</p>
+
+<p>He said that it became an obsession at IBM San Jose for the next year to figure out what
+Wattenburg had done. He remembers engineers and scientists meeting at lunch time to compare
+notes on their latest ideas and experiments. They even hired a guy from Livermore who had
+worked with Wattenburg to help them as a consultant. They found all sorts of new ways, but none
+of them could be accomplished with something so simple as a clothes iron the kitchen. He said
+that the attorneys got very angry with Wattenburg. They essentially accused Wattenburg of
+being a fraud and demanded that he disclose the answer or they would recommend that his future
+payments due under their contract be stopped. Our contact says that he had to take these
+communications to Wattenburg at the university. Wattenburg’s answer to the attorneys was that
+IBM ought to be very happy that their engineers were discovering so many new ways on their
+own that they never would have considered if they had not been trying to discover his way. He
+offered to demonstrate his scheme again anytime they would like.</p>
+
+<p>He says that he never heard whether they figured it out on their own or whether
+Wattenburg eventually told them. All he knows is that they eventually came up with a new scheme
+that could not be easily counterfeited by Wattenburg, so he said.</p>
+
+<p>He told us that he was impressed that, for ten years, Wattenburg would never tell even
+his best friends at Livermore who insisted that he could tell them his method under the strict
+security rules that prevailed at this nuclear weapons laboratory. He heard one senior laboratory
+official jokingly promise Wattenburg that he would personally stamp the document “classified” if
+Wattenburg would write it down for them. He said that Wattenburg would not even confirm
+what the answer was long after it had became generally known to scientists and engineers what
+the special material was that he had used.</p>
+
+<p>Our contact said that he always respected Wattenburg for never violating the agreement
+that he knew Wattenburg had signed with the bankers. But then he added: “if you knew how
+much they paid him in real dollars today, you would not have taken a chance on losing it either by
+opening your mouth just to show off.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/dial-a-ride.html
@@ -1,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Better Carpooling</title>
+</head>
+
+<body>
+
+<h1>Dial-A-Ride Carpooling</h1>
+
+<h2>(1973)</h2>
+
+<p>Bill Wattenburg upstaged the government bureaucracies during the 1973 energy
+crisis when the U.S. Energy Department proposed spending millions to organize
+all the state departments of motor vehicles across the country to use their
+files on motorists to match up citizens for carpools. They told Congress that
+they needed at least fifty million to subsidize the state agencies so that they
+could write the special computer programs required to do this within eighteen
+months. Wattenburg announced that the telephone companies could do the same
+thing immediately—at no extra cost to the taxpayers. And he proved it with a
+simple experiment.</p>
+
+<p>The San Francisco Chronicle reported Wattenburg’s idea on December 22, 1973.
+He pointed out that a person’s telephone numbers at home and at work were all
+that was needed to match him up with the nearest other person who drove
+approximately the same route. The telephone companies had all the address data
+for every telephone number. Their computer programs were ready to do the job
+with very little modification. All the government had to do was ask them. And,
+it wouldn’t cost the taxpayers a dime.</p>
+
+<p>He suggested that a person who wanted a carpool partner could simply dial a
+special “carpool” request code into his telephone and provide his work
+number. The telephone company, for a small charge, could then send him a list of
+all others who drove a similar route. Officials from Pacific Telephone Company
+in San Francisco agreed that Wattenburg was right. They said they would do it.</p>
+
+<p>The czar of the energy department appeared to like the idea and promised to
+implement it, but nothing official was announced. We asked Bill Wattenburg
+whatever happened to this neat idea. He told us:</p>
+
+<blockquote>
+<p>“All the state departments of motor vehicles were already counting the
+millions they had been promised from Washington. Some powerful congressmen
+complained that my idea was illegal according to the consent decree that
+prohibited telephone companies from using their computers to process data. It
+was stupid, but the Justice Department was never formally asked to waive the
+prohibition. The federal pork barrel money was sent out as promised.</p>
+
+<p>“However, most of the state motor vehicle people realized that my scheme was a
+lot easier and more comprehensive because the telephone company data is always
+far more complete than address data in the motor vehicle files. So, they just
+got the files from the telephone company that they needed and did the same
+thing. Obviously, they used the millions they got from Washington to pay for
+other things. The sad part is that most people still can’t simply use their
+telephones to arrange carpooling with the ease that should be available to them
+everywhere. But, California does this with a special 800 number.</p>
+
+<p>“As always, the state bureaucracies invented forms that people have to fill
+out to make a carpool request. This discourages most. But it keeps a lot of
+idiot bureaucrats busy. The people who could benefit the most from carpooling
+are not going to allow themselves to be matched up with other people by the
+government. And they avoid giving personal information to the government.
+However, most trust the telephone company.”</p>
+</blockquote>
+
+<p>We asked Wattenburg what he thought about not getting any official
+recognition for this. His answer was: “Ah, what the hell. That’s the usual
+case when you deal with bureaucrats. They know I made them do what I wanted. I
+made them jump. That’s good enough.”</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/dial-a-ride.html.i
@@ -1,0 +1,9 @@
+3 pages
+size 400 562
+length 4055
+407 2 11 body html
+0
+1623 2 35 body html
+0
+2229 2 45 body html
+294
--- /dev/null
+++ b/lib/ebooks/oebtest/foreword.html
@@ -1,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Editor’s Foreword</title>
+</head>
+
+<body>
+<a name="begin"></a>
+<h1>Editor’s Foreword</h1>
+
+<p>I received this report on Bill Wattenburg from a government agency as a
+public document, and am making it publicly available so that the public may learn of his many
+accomplishments and some insight into his character.</p>
+
+<p>If this little report isn’t enough, you can follow Bill’s continuing exploits at
+www.DrBill.org, which is a shortcut to a section of my main Web site, PushBack.com, that closely
+follows his radio show and other exploits.</p>
+
+<p>As a means of introduction to this report, you can start with Bill’s <a href="resume.html">résumé</a>,
+and some of the more interesting quotations that I are taken from this report
+<a href="QuotesFromBill.html">from Bill</a> and <a href="QuotesAboutBill.html">about Bill</a>. They
+are all interesting and provide a great introduction to Bill’s iconoclastic personality.</p>
+
+<p class="right">—Peter K. Sheerin<br />
+Webmaster and Editor-in-Chief, PushBack.com</p>
+
+<br />
+
+<p>P.S. If some of what you read seems hard to believe, then this quote from a very well known scientist who
+has worked with Bill should serve as a good introduction:</p>
+
+<blockquote><q>If anyone has spent $10 or $20 million on a difficult technical problem and not found a
+solution, they probably should have asked Bill Wattenburg First.”</q></blockquote>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/foreword.html.i
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 1785
+409 2 11 body html
+0
+1581 2 36 body html
+32
+begin 0
--- /dev/null
+++ b/lib/ebooks/oebtest/foreword.html.index
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 1785
+409 2 11 body html
+0
+1581 2 36 body html
+32
+begin 0
--- /dev/null
+++ b/lib/ebooks/oebtest/hobbies.html
@@ -1,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Hobbies</title>
+</head>
+
+<body>
+
+<h1>Hobbies</h1>
+
+<p>Wattenburg is an avid tennis player. He has played in many celebrity tennis tournaments
+around the country with his friends from Hollywood. He says that the decision as to where he
+travels nowadays depends a lot on where the sun is shining and where there is a tennis court. (We
+had to wait two hours at the Berkeley Tennis Club for the first interview we got with him.)</p>
+
+<p>Access to tennis courts will certainly be an important consideration to him before working in
+another city. We recommend that guaranteed membership in a first-class tennis club be part of
+any offer made to him.</p>
+
+<p>In the summertime, he still runs the bulldozers he learned to operate when he worked with his
+father in the logging woods years ago. He spends two to three weeks average each year fighting
+forest fires as a bulldozer operator (Catskinner) on the west coast with U.S. Forest Service
+firefighting crews. A U.S. Forest Service Supervisor in Plumas County, Calif., told us that,
+“There are not many old pros like him left anymore who can chase a forest fire on a bulldozer in the night
+over mountains so rugged that you can’t walk on them.” He said, “I mean fire crews won’t go
+where he takes a bulldozer. This guy attacks a fire just like it was trying to kill his kids. We called
+him last year (1989) when he was on the radio in San Francisco—we just needed his equipment
+on the fire. He was on the fire himself four hours later.”</p>
+
+<p>Wattenburg keeps two large bulldozers specially equipped for fire fighting at his ranch in
+northern California. He mentioned to us that nothing makes him so sad as to see the last of our
+virgin forests go up in smoke. There was anger in his voice when he told us that a lot of the
+heavy equipment operators nowadays (he called them hard-hat executives) just sit back and let a
+fire go until it changes course on its own and burns itself out. “Then they brag about how they
+bravely stopped this ten-thousand acre fire.” (We found him running a bulldozer when we
+interviewed him the second time at his ranch in Northern California. He gave one of us, who
+never learned to drive a car, a lesson on the bulldozer.)</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/hobbies.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 562
+length 2604
+397 2 11 body html
+0
+1015 2 24 body html
+255
--- /dev/null
+++ b/lib/ebooks/oebtest/index.html
@@ -1,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Table of Contents</title>
+</head>
+
+<body lang="en-us">
+<a name="toc"></a>
+<h1>Table of contents</h1>
+<ol>
+  <li><a href="foreword.html">Editor’s Foreword</a></li>
+  <li><a href="ExecutiveSummary.html">Executive Summary</a></li>
+  <li>On The Air and Publishing
+    <ol>
+      <li><a href="TalkRadio.html">Talk Radio on the West Coast</a></li>
+      <li><a href="movies.html">Movies</a></li>
+      <li><a href="television.html">Television Shows</a></li>
+      <li><a href="publishing.html">Publishing</a></li>
+    </ol>
+  </li>
+  <li><a href="background-education.html">Background and Education</a>
+    <ol>
+      <li><a href="background-education.html#Hometown">Hometown</a></li>
+      <li><a href="background-education.html#Education">Education</a></li>
+      <li><a href="background-education.html#GraduateSchool">Graduate School</a></li>
+      <li><a href="background-education.html#AcademicWork">Academic Work</a></li>
+    </ol>
+  </li>
+  <li><a href="business.html">Business</a></li>
+  <li><a href="patents.html">Patents and Inventions</a></li>
+  <li><a href="awards.html">Awards</a></li>
+  <li><a href="hobbies.html">Hobbies</a></li>
+  <li><a href="covert.html">Covert Activities?</a></li>
+  <li><a href="colleague.html">A Colleague’s Observations</a></li>
+  <li>Public Service
+    <ol>
+      <li><a href="bloodbanks.html">Blood Banks</a></li>
+      <li><a href="HelicopterMinesweeper.html">Helicopters to Clear Minefields</a></li>
+    </ol>
+  </li>
+  <li><a href="confrontations.html">Public Confrontations</a>
+    <ol>
+      <li><a href="BART.html">Fixing BART Safety (Bay Area Rapid Transit System)</a></li>
+      <li><a href="creditcards.html">Magnetic Credit Cards</a></li>
+      <li><a href="dial-a-ride.html">Dial-A-Ride Carpooling</a></li>
+      <li><a href="MeasuringOilTanks.html">Seeing Inside Oil Tanks!</a></li>
+      <li><a href="GoldenGate.html">Golden Gate Bridge Traffic Barrier</a></li>
+      <li><a href="BlueWater.html">Blue Water (Copper) Contamination in Homes</a></li>
+    </ol>
+  </li>
+  <li><a href="GoldMine.html">The Gold Mine</a></li>
+  <li><a href="BentSub.html">Downhole Drillbit</a></li>
+</ol>
+</ol>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/movies.html
@@ -1,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Movie Projects</title>
+</head>
+
+<body>
+
+<h1>Movies</h1>
+
+<p>Bill Wattenburg played the tough guy talk show host and tennis player (Nolan
+Kennard) in Clint Eastwood’s 1988 Dirty Harry movie, “The
+Dead Pool”. He next worked with Eastwood and played the role of the pit boss in the
+filming of “Pink Cadillac”.</p>
+
+<p>Clint Eastwood made one of his rare public appearances on Wattenburg’s talk
+show to express his views on the political issues on the California ballot in
+November 1990. The two of them teamed up for two hours, live on KGO, before the
+California audience to support the Legislative Term Limit initiative,
+Proposition 140. This “voter’s revolt” was strongly opposed by the
+political powerhouses who were unleashing a multi-million dollar, last-minute TV
+blitz using other Hollywood personalities to defeat the initiative. The polls
+were predicting that Proposition 140 would be defeated. It passed two days
+later.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/patents.html
@@ -1,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Patents</title>
+</head>
+
+<body>
+
+<h1>Patents and Inventions</h1>
+
+<p>Wattenburg holds patents on ideas as diverse as computer design, medical diagnostic
+instruments, power line communication systems, tennis training devices for handicapped people,
+movable traffic barriers for multi-lane highways, and home alarm systems. Asked which one he was
+most proud of, he singled out the home alarm systems he invented in 1964 when he was a young
+professor at U.C. Berkeley. This invention (patent 3,460,121, Signaling and Communication
+System, 1965) has saved thousands of lives over the last twenty years. Hundreds of thousands of
+home fire and smoke alarm systems based on his patent were installed in homes in the U.S.,
+Canada, and Europe.</p>
+
+<p>He holds the original patent on the use of existing electrical house wiring as a means for
+communicating alarm signals from sensors, such as smoke detectors, to receivers placed
+elsewhere in the building. His inexpensive design was the first that eliminated the need for
+separate wiring to connect multiple alarm devices to remote receivers far away in the same
+building or even outside the building on the same power line.</p>
+
+<p>His home and building alarm systems were originally marketed by the Heath Company
+(Heathkit) in Benton Harbor, Michigan. They were able to sell smoke and fire alarm systems to
+protect all areas of a home for less than $100. The technology in his original patent is now used
+by many companies all over the world for a wide variety or electronic and alarm devices that plug
+into power receptacles and use the power lines to communicate electrical signals. He also
+invented one of the first inexpensive smoke alarms for homes which was installed in hundreds of
+thousands of homes throughout the U.S. beginning in 1967. His two inventions allowed several
+hundred thousand homeowners to have reliable fire and smoke alarm systems that would
+otherwise have been too expensive by the old procedure of installing special wiring for an alarm
+system.</p>
+
+<p>Since this was his first patent, we asked him what it was like and how did he come up with
+the idea. He said that a friend of his was going to have to pay over twenty thousand dollars to
+have a standard fire alarm system put in a warehouse that he owned. Wattenburg said that he
+asked his friend if he could have half that much if he could find a cheaper way than having to put
+special wiring in the whole building. He shrugged his shoulders and told us: “Well anyway, I
+needed some money for more important experiments that I wanted to do about that time. I had
+no choice.”</p>
+
+<p>We asked him if it made a lot of money. He answered: “Oh yes, about twenty times what
+I needed in those days. It carried me over until I got some really expensive ideas.”</p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/oebtest/patents.html.i
@@ -1,0 +1,7 @@
+2 pages
+size 400 562
+length 3173
+397 2 11 body html
+0
+1538 2 30 body html
+85
--- /dev/null
+++ b/lib/ebooks/oebtest/publishing.html
@@ -1,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+   "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Publishing</title>
+</head>
+
+<body>
+
+<h1>Publishing</h1>
+
+<p>Bill Wattenburg is also the comical author Will Harvey who once entertained
+nationwide audiences on major TV shows such as “The Phil Donahue Show” and
+“The Tonight Show”. Wattenburg’s media career began when he wrote a surprising
+best-seller while he was the president of a scientific laboratory in Berkeley.
+He had written short stories during his college days. He told us that in 1971 a
+group of women at a University cocktail party, who had read some of his short
+stories, bet him that he couldn’t write a book that was funnier than the New
+York Times’ then best-seller on sexual fantasies,
+<i>The Sensuous Woman</i>. So, he whipped
+out a book for them in three weeks with the title <i>How To Be Good To A Woman</i>,
+which they liked enough to make hundreds of Xerox copies of the manuscript to
+send to friends all over the country. But New York publishers said it wouldn’t
+sell when he tried to give it to them to publish, free—so his friends could buy
+cheaper copies. Unconvinced, he changed the title of the book to <i>How To Find
+And Fascinate A Mistress</i>, changed “woman” to “mistress”
+in the text, and had a Berkeley printer produce the first five thousand
+hardcover with a catchy jacket designed by his engineering draftsmen. He then
+gave away 200 copies to airline flight attendants (for whom he had written a complimentary
+chapter in the book). Orders began coming in from all over the country.</p>
+
+<p>Three months later, his kitchen publishing company, Montgomery Street Press,
+had shipped over sixty-thousand hardcover copies to every major bookstore chain
+in the country. The New York publishing houses that could have had the book for
+nothing were soon bidding for the paperback rights. Pocketbooks (Simon and
+Schuster) finally bought the paperback rights for a reported $650,000.
+Pocketbooks sent him out on a national promotion tour to a few major TV shows.
+Requests then poured in from other shows all over the country who wanted him.
+Over the next year, he appeared as funnyman Will Harvey on over 130 local and
+national TV and radio shows. He was invited back to some major shows several
+times in 1972. Paperback sales of his book climbed to over 2,000,000 as he
+tickled audiences all over the country with his cowboy humor and the image of
+the hapless male struggling to keep up with the sexually aggressive women of the
+burgeoning feminist movement.</p>
+
+<p>A former Pocketbooks executive has told us that Wattenburg received an
+advance for the paperback rights of “over $500,000”. She remembered
+that he caused quite a problem at Simon and Schuster during the bidding for the
+paperback rights to his book. She recalled: “He didn’t have an agent. He
+thought that our standard royalty contracts with authors were crazy. He demanded
+a guaranteed cash payment up front—not conditioned on future book sales, as was
+the usual case. He cleaned up after that. I think he still owns the
+hardcover. … He wouldn’t stay at some of the best hotels we booked him into
+during the promotion tours. He found out that travel expenses were being
+deducted from his royalties after sales went above, I think, 2,000,000. … He
+drove us nuts. We had to plead with some famous newspaper columnists and book
+reviewers to meet him for interviews at Holiday Inns. …”</p>
+
+<p>Before it was over, the book that he had tried to give away had earned him
+over $1,300,000! It was published in six countries. Bantam books bought the
+rights to his next book for an undisclosed sum. He says he still has to explain
+on the radio to women who like to tease him that “in no way could I ever
+live up to the exploits of Will Harvey.”</p>
+
+<p>We asked him in 1990 why he didn’t write more books. He said: “You can
+sometimes beat the pros at their own game once. But they don’t often let you get
+away with it a second time. It’s much easier to find another field.”</p>
+
+</body>
+</html>
\ No newline at end of file
binary files /dev/null b/lib/ebooks/oebtest/raport-small.png differ
binary files /dev/null b/lib/ebooks/oebtest/raport.png differ
--- /dev/null
+++ b/lib/ebooks/oebtest/resume.html
@@ -1,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Résumé</title>
+</head>
+
+<body>
+
+<h1>Dr. Bill Wattenburg’s Résumé</h1>
+
+<h2>1980–Present</h2>
+<ul>
+  <li>Research Scientist and Adjunct Professor of Science, University Foundation, California
+State University, Chico.</li>
+  <li>Consultant, Lawrence Livermore National Laboratory.</li>
+  <li>Talk show host, “The Open Line to the West Coast” (Sat. and Sun. 10pm to 1am), KGO Radio AM-810,
+       American Broadcasting Company, San Francisco  (since 1972).</li>
+</ul>
+<h2>1965–1980</h2>
+<ul>
+  <li>Co-founder of Berkeley Scientific Laboratories, Berkeley, California, 1966, with Dr. Donald Glaser,
+       (Nobel Prize, Physics, 1960).</li>
+  <li>President, Berkeley Scientific Laboratories, 1966–1970.</li>
+  <li>Co-founder and Chairman of the Board, Comprehensive Health Services (later reorganized as
+       Comprehensive Computer Services and Bakte-Bennent Medical Laboratories), 1970–1980.</li>
+  <li>Member of:<br />
+    U.S. Air Force Scientific Advisory Board, 1967–1970.<br />
+    Subcommittee on Nuclear Defense Systems (headed by Dr. Edward Teller).</li>
+</ul>
+<h2>1961–1967</h2>
+<ul>
+  <li>Assistant Professor, Electrical Engineering, U.C. Berkeley</li>
+  <li>Staff member, Lawrence Livermore National Laboratory, Physics Division.</li>
+  <li>Consultant:
+    <ul>
+      <li>Lockheed Missiles and Space Company</li>
+      <li>IBM Corporation</li>
+      <li>General Electric Co.</li>
+      <li>Bellcom (NASA Apollo Project)</li>
+    </ul>
+  </li>
+</ul>
+<h2>Education</h2>
+<ul>
+  <li>1961: Ph.D., Electrical Engineering and Physics, U.C. Berkeley</li>
+  <li>1959: Master’s Degree, Electrical Engineering, U.C. Berkeley</li>
+  <li>1958: B.S., Electrical Engineering, California State University, Chico.</li>
+</ul>
+<h2>References</h2>
+<ul>
+  <li>Dr. John Nuckolls, former Director, Lawrence Livermore National
+    Laboratory, Livermore, California (currently Director Emeritus)</li>
+  <li>Mr. Michael Luckoff, President, KGO Radio, San Francisco, California.</li>
+  <li>Dr. Edward Teller, Hoover Institute, Stanford University.</li>
+  <li>Mr. James Roberts, Chief Engineer, California Department of Transportation,
+       Sacramento, California.</li>
+</ul>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/television.html
@@ -1,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Television Shows</title>
+</head>
+
+<body>
+
+<h1>Television Shows</h1>
+
+<p id="dolphins">Bill Wattenburg’s first television show was an expose on the slaughter of
+dolphins by tuna fishing fleets called “The Last Days of the Dolphins”,
+which Westinghouse Broadcasting aired nationally in 1975. Strong complaints from
+major food company advertisers who market tuna almost cancelled the show. The
+original celebrity host had backed out after major advertisers complained.
+Wattenburg agreed to replace him. This shocking documentary showed the needless
+slaughter of 500,000 dolphins a year because tuna fisherman refused to change
+the crude nets they had been using for decades. Congress outlawed the old nets a
+week after this dramatic show was aired nationwide.</p>
+
+<p id="KPIX">Westinghouse Broadcasting Co. (KPIX Channel 5 TV, San Francisco) then asked Bill
+Wattenburg to host a new half-hour newsmagazine show which aired on Friday
+nights primetime (The People’s Five Show) from September 1975 to 1977. They used one of
+the first TV mini-cams to shoot the show “on the street” with only one
+cameraman-director, host Wattenburg, and no scriptwriters.</p>
+
+<p>This show and its format were later expanded to become Westinghouse’s
+“Evening Magazine”, which has been syndicated nationwide since 1977 <i>[usually
+under the name “P.M. Magazine” outside of the SF broadcasting area</i>—<i>PKS]</i>.
+Wattenburg returned to weekend talk radio and his scientific work at the
+university when the TV show went to five nights a week.</p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/toc.html
@@ -1,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0 Document//EN"
+  "http://openebook.org/dtds/oeb-1.0/oebdoc1.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/x-oeb1-document; charset=utf-8" />
+<link rel="stylesheet" type="text/x-oeb1-css" href="DrBillBio.css" />
+<title>Bill Wattenburg’s Background: Table of Contents</title>
+</head>
+
+<body lang="en-us">
+<a name="toc"></a>
+<h1>Table of contents</h1>
+<ol>
+  <li><a href="foreword.html">Editor’s Foreword</a></li>
+  <li><a href="ExecutiveSummary.html">Executive Summary</a></li>
+  <li>On The Air and Publishing
+    <ol>
+      <li><a href="TalkRadio.html">Talk Radio on the West Coast</a></li>
+      <li><a href="movies.html">Movies</a></li>
+      <li><a href="television.html">Television Shows</a></li>
+      <li><a href="publishing.html">Publishing</a></li>
+    </ol>
+  </li>
+  <li><a href="background-education.html">Background and Education</a>
+    <ol>
+      <li><a href="background-education.html#Hometown">Hometown</a></li>
+      <li><a href="background-education.html#Education">Education</a></li>
+      <li><a href="background-education.html#GraduateSchool">Graduate School</a></li>
+      <li><a href="background-education.html#AcademicWork">Academic Work</a></li>
+    </ol>
+  </li>
+  <li><a href="business.html">Business</a></li>
+  <li><a href="patents.html">Patents and Inventions</a></li>
+  <li><a href="awards.html">Awards</a></li>
+  <li><a href="hobbies.html">Hobbies</a></li>
+  <li><a href="covert.html">Covert Activities?</a></li>
+  <li><a href="colleague.html">A Colleague’s Observations</a></li>
+  <li>Public Service
+    <ol>
+      <li><a href="bloodbanks.html">Blood Banks</a></li>
+      <li><a href="HelicopterMinesweeper.html">Helicopters to Clear Minefields</a></li>
+    </ol>
+  </li>
+  <li><a href="confrontations.html">Public Confrontations</a>
+    <ol>
+      <li><a href="BART.html">Fixing BART Safety (Bay Area Rapid Transit System)</a></li>
+      <li><a href="creditcards.html">Magnetic Credit Cards</a></li>
+      <li><a href="dial-a-ride.html">Dial-A-Ride Carpooling</a></li>
+      <li><a href="MeasuringOilTanks.html">Seeing Inside Oil Tanks!</a></li>
+      <li><a href="GoldenGate.html">Golden Gate Bridge Traffic Barrier</a></li>
+      <li><a href="BlueWater.html">Blue Water (Copper) Contamination in Homes</a></li>
+    </ol>
+  </li>
+  <li><a href="GoldMine.html">The Gold Mine</a></li>
+  <li><a href="BentSub.html">Downhole Drillbit</a></li>
+</ol>
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+++ b/lib/ebooks/oebtest/toc.html.i
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 2515
+420 2 11 body html
+0
+467 2 14 body html
+459
+toc 0
--- /dev/null
+++ b/lib/ebooks/oebtest/toc.html.index
@@ -1,0 +1,8 @@
+2 pages
+size 400 562
+length 2533
+420 2 11 body html
+0
+467 2 14 body html
+459
+toc 0
binary files /dev/null b/lib/ebooks/understandingoeb/OEBActivityDiagram.png differ
binary files /dev/null b/lib/ebooks/understandingoeb/OEBClassDiagram.png differ
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter1.html
@@ -1,0 +1,114 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 1</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter1">1. Defining a Beginning</h2>
+
+<p>eBooks are by no means new. For years educators have been creating multimedia learning systems, businesses have been showing interactive kiosks, entrepreneurs have been showing electronic presentations, and corporations have been distributing PDF documents. Michael Hart's Project Gutenberg has been giving away electronic texts for, well, practically since computers were invented. A student creates an eBook when she writes a report for college. Your brother writes an eBook when he enters recipes into his computer. I listen to an eBook when I download an MP3 from...</p>
+
+<p>"Wait," you might say. "Those aren't really eBooks." You might say that because you've noticed some fundamental difference between eBooks and other electronic things, but more likely you would say that because you have an intuitive notion of what an eBook is.</p>
+
+<p>Unfortunately, many people have conflicting ideas about which electronic "things" are eBooks. Are eBooks hardware devices, or software? Are eBooks merely textual electronic content? Normal books can be shown on overhead projectors &mdash; is an electronic presentation an eBook? What's the difference between a file of recipes and a book full of recipies? An MP3 file isn't an eBook because you can't hear books &mdash; yet don't many companies sucessfully sell "audio books" on cassette?</p>
+
+<p>It should be painfully obvious at this point that to adequately discuss the Open eBook specification, it might be wise to find out exactly what an <dfn>eBook</dfn> is. Somewhat less obvious but no less painful is that I don't really know what an eBook is, either. Sorry. Even if I did, well, it probably wouldn't be the same thing that <em>you</em> think an eBook is. And whatever we thought, we'd likely change our minds once we thought about it a little longer. But don't worry, you're in good company &mdash; no one else in the "eBook industry" knows what an eBook is, either, although they all have ideas about what they want you to think an eBook is.</p>
+
+<h3 id="definingEBook">Defining "eBook"</h3>
+
+<p>In this book we'll try to skirt the issue of creating an authoritative definition of an eBook, considering an eBook to broadly mean whatever electronic content you want to present. We'll specifically discuss the <em>Open eBook Publication Structure</em> and the types of content it allows one to publish, allowing you to determine whether this format is right for your content. While we discuss the <em>Open eBook Publication Structure</em> and related publications, though, we'll need to come to some definitions that we agree upon, at least in the context of our discussion, which will allow us to know what the other is talking about.</p>
+
+<div class="sidebar" id="oebDefinitions">
+<h4 class="sidebarTitle">More Information: OEB and Definitions</h4>
+<p>Most specifications, the OEB Publication Structure included, recognize the definition problem soon enough, as industry leaders sit around a table arguing for hours before realizing that they agree &mdash; they just used different words to express their viewpoints. For this reason, most specifications include a <dfn>glossary</dfn> of terms and their definitions as used within the specification.</p>
+
+<p>Glossaries are fine for one specification, but in the eBook world there are many separate relevant documents that use different terminologies to mean the same thing, or use the same terminology to mean different things. The OEB Forum has recently therefore committed to creating a terminology that can be used as a common language for the eBook industry as a whole. The Forum has even gone so far as to create a framework for explaining how different players in the eBook industry might give different meanings, based upon their backgrounds, for the words they use.</p>
+
+<p>Such a defining of terms is a necessity for the eBook industry to be able to efficiently move forward with other open, interdependent specifications related to the OEB Publication Structure. Currently the effort refers to this framework as an <dfn>ontology</dfn>, referring to the eBook industry as a whole as an <dfn>ePublishing ecology</dfn>. This framework is not yet finalized, but there have been reports that the terms "ontology" and "ecology" will be defined Real Soon Now.</p>
+</div>
+
+<h4 id="eText">Electronic Book as an "Etext"</h4>
+
+<p>One of the first and most famous popularizations of books in electronic format was Project Gutenberg (<a href="http://www.gutenberg.org">http://www.gutenberg.org</a>). According to his own rendition (<a href="http://promo.net/pg/history.html">http://promo.net/pg/history.html</a>), Michael Hart in 1971 was granted access to a mainframe at the University of Illinois. Wanting to make productive use of the precious time he had been allotted on such a scarce resource, he entered the United States "Declaration of Independence" electronically and attempted to send it to everyone on the networks.</p>
+
+<p>Luckily, such an act occurred before the concept of spam and before the notoriety of computer viruses, so whatever negative repercussions of such unrequested correspondence did not spread far. Michael soon changed from actively sending these <dfn>electronic texts</dfn> (Etexts), as he calls them, to instead archiving them so that they can be downloaded from anyone at any time from anywhere. According to their published figures, Project Gutenberg went from archiving only 100 Etexts in January 1994 to 3333 Etexts in April 2001.</p>
+
+<p>Michael Hart's Etexts were certainly related to books &mdash; they did contain the same text word for word (more or less, in many cases page numbers and all) as the book from which they were taken. There was nothing "book-like" about these works, though. A user can read an Etext with whatever tool he/she has available, such as a text editor or word processor. As electronic versions of textual content of a book, though, Etexts could certainly fit one definition of an "eBook."</p>
+
+<h4 id="eBookHype">"eBook" as a Marketing Tool</h4>
+
+<p>By the late 1990s, several companies were attempting to make electronic versions of books that not only replicated the book's content but also duplicated the look of a book. Nuvomedia made a device the size of a small paperback named the Rocket eBook, and Softbook created a somewhat larger device called the Softbook Reader. Both were <dfn>dedicated</dfn> eBook reading devices; their only purpose in their electronic life was to show electronic texts. It seemed that so much attention was paid to the small packages of plastic and silicon that the devices themselves were referred to as "eBooks". It never really seemed clear what the textual content was called.</p>
+
+<p>One thing was clear, though: there needed to be some way for this textual content to somehow interoperate with both devices. Either company assumed it could win any war of device creation and marketing, but there were more immediate concerns: if the market for these new devices was to explode as these two companies hoped, they needed the help of the publishers from whom the textual content originated. They knew that publishers would not want to create electronic versions of their text in two separate formats, one for the Rocket eBook and another for the Softbook Reader.</p>
+
+<p>In late 1998 these two companies were joined by a third: Microsoft. Together these corporations formed an informal group of companies that vowed to prevent a "VHS vs. Betamax" war of formats in the eBook industry by inventing a common format in which electronic information could be stored. The Open eBook (OEB) Authoring Group they formed set out to create a specification that would allow publishers to release content in one format and know that any of the devices could access the stored information.</p>
+
+<p>Further divorcing the term "eBook" from the concept of a particular device was Microsoft's announcement in 1999 that it would be releasing the Microsoft Reader software. This software would run on any Windows-based computer and would allow eBooks to be downloaded and read without the need for a dedicated reading device. With the support of these two device manufacturers, a software giant, and other members of the OEB Authoring Group such as Versaware, Nokia, and GlobalMentor, the idea of an electronic book became a marketable idea around which each proponent could advance its own desires of profitability. The term "eBook" began to represent not just electronic text, but electronic text in the context of a new industry that would, it was claimed, change reading forever.</p>
+
+<h4 id="eBookInevitibility">The eBook as Inevitable</h4>
+
+<p>At this point we haven't really come any closer to knowing what an eBook is, but we've picked up a few other terms such as "reader" and "publisher" which themselves cry out for definitions. Before inevitably drawing artificial lines in the sand, it would be profitable to examine just what is significant about the eBook as an industry.</p>
+
+<p>It could be that the "universal format" argument of OEB is somewhat of a hollow one. As you'll learn, some parts of OEB by themselves are inadequate for complex textual content. Furthermore, although some software programs allow you to read OEB-based eBooks directly, on other devices and software products what you'll read is not OEB, but OEB text that has been manipulated and transformed into something specific to that device or software. eBooks in general and OEB in particular do in fact represent something very significant, though: the inevitability of electronic information storage and interaction.</p>
+
+<ol>
+	<li><strong>Convenience</strong>. Electronic song storage and listening is already too popular to fade. The convenience and space-saving efficiency of electronic music are no less significant in the world of electronic texts.</li>
+	<li><strong>Versatility</strong>. Once a book is in electronic format, it can be manipulated and presented in a variety of formats on a number of different devices.</li>
+	<li><strong>Storage</strong> Books that are stored electronically take up no physical space and can be transported with ease.</li>
+</ol>
+
+<p>eBooks give the promise of true foreverness and universality to information. OEB is significant because its authors were wise enough to base it on several elegant standards that were already popular, robust, and that provide no roadblocks to international access. Will the OEB texts you create five years from now look like the OEB works you create today? Maybe. But because of OEB's foundations, the OEB eBooks you write will either work just as well as they do now or will be easily manipulated so that they can. In short, OEB is important because of the standards-compliant ways it requires you to encode your works. Whatever "OEB" means five years from now, the OEB works of today will still be useful.</p>
+
+<h3 id="oebMeaning">The Meaning of OEB</h3>
+
+<p>A year of hard work by the Open eBook Authoring Group led to the release on 16 September 1999 of the <em class="title">Open eBook Publication Structure 1.0</em>. This specification, which has recently been clarified and refined by version 1.0.1, defines a <dfn>publication structure</dfn> or format in which one can store a particular work. A work created in OEB format is called, appropriately, an <dfn>OEB publication</dfn>.</p>
+
+<p>In early 2000 the OEB Authoring Group became a formal body named the Open eBook Forum (OEBF) (<a href="http://www.openebook.org">http://www.openebook.org</a>). The term "OEB" itself is used in a multitude of contexts. Sometimes the OEB Forum is referred to as "OEB"; at other times, "OEB" refers to the <em class="title">OEB Publication Structure</em> which defines OEB Publications. Here we'll try to be specific about how we use OEB unless the meaning is clear from the context. In general, "OEB" will be used to designate that something has been produced by the OEB Forum, such as the <em>Open eBook Publication Structure</em> itself.</p>
+
+<p><object data="OEBClassDiagram.png" type="image/png">OEB Class Diagram</object></p>
+
+<p>The <em>Open eBook Publication Structure</em> is a specification for a document format, but to understand this format in context the specification divides the world into several abstract parts. In particular, a <dfn>publication</dfn> is meant for storing eBook content, and this content is processed and displayed to the user by a <dfn>reading system</dfn>. OEB calls the person reading the content the <dfn>reader</dfn>, which may be confusing to those who use software packages that contain "Reader" in their names.</p>
+
+<p><object data="OEBActivityDiagram.png" type="image/png">OEB Activity Diagram</object></p>
+
+<p><em class="rhetoricalQuestion">Is a reading system a piece of software?</em> Perhaps, but it could also be a hardware device. In fact, the reading system could be a piece of software that processes the OEB publication and stores it in a different form to be read by the reader on a hardware device.</p>
+
+<p><object data="ReadingSystemClassDiagram.png" type="image/png">Reading System Class Diagram</object></p>
+
+<p>The reading system is a convenient abstraction that allows the OEB publication structure specification to define how an OEB publication must be constructed, as well as how it must be interpreted and presented to a reader. As long as the rules in the <em>OEB Publication Structure</em> are followed, any number of things could work together and be classified as one "reading system". This allows a strict definition of how pieces of a system interact, without restricting innovation in implementing the various system components.</p>
+
+<p><em class="rhetoricalQuestion">Is the OEB publication actually delivered to the reader?</em> This depends on the particular reading system being used. Some reading systems may combine both the processing and the display of the OEB publication into one piece of software or into one hardware device. In other instances, a reading system may be composed of several components: one piece of software may read the OEB publication and interpret it and store it in a proprietary format that only the second display portion of the reading system can understand. It is then this proprietary version of the text that is used to display the data to the reader. In this scenario, the two pieces together would comprise the reading system.</p>
+
+<p>OEB does not care what type (if any) of intermediate files are produced before the content is shown to the user. The usefulness of the OEB publication, therefore, is not directly related to the user, but to the publisher. The author and/or publisher must convert content to only <em>one</em> format: the OEB publication structure format. Any OEB-compliant reading system will have the means to either display the OEB publication directly, or to convert it into a format that it can display or allow another component to display.</p>
+
+<p>The most important task as far as an author or publisher is concerned is therefore ensuring a work is in the OEB publication structure format. Any OEB-compliant reading system will be able to do whatever it needs to do to allow your content to be accessed by a reader.</p>
+
+<h3 id="usingOEB">Using OEB</h3>
+
+<p>All examples in this book (and this book itself) should be fully compliant with the <em>Open eBook Publication Structure</em> version 1.0.1. It should be possible to read each example using a OEB reading system that fully complies with the specification. As explained above, various OEB reading systems are available &mdash; some that use software combined with hardware, some that use separate software components, and some that can natively read an OEB-encoded work and display the eBook to the reader immediately.</p>
+
+<p>The Mentoract&trade; Reader from GlobalMentor, Inc. is one example of a native software-based OEB reading system. To read the example eBooks presented here, simply load an OEB package file or an individual OEB document (both of which will be explained in upcoming chapters) in the Mentoract Reader by selecting <code>File|Open...</code> from the pull-down menu. The Mentoract Reader is written in the Java programming language and can therefore run on a variety of desktop and notebook operating systems. The Mentoract&trade; Reader is available from <a href="http://www.globalmentor.com/software/reader/">http://www.globalmentor.com/software/reader/</a> as a free download.</p>
+
+<p>Other software-based reading systems, such as the Microsoft Reader from Microsoft Corporation, require two components for processing an eBook. The first component, such as the ReaderWorks software from OverDrive, Inc., manipulates the OEB files into a proprietary Microsoft file format named LIT. This LIT file can then be read using the Microsoft Reader. ReaderWorks is available from <a href="http://www.overdrive.com/readerworks/">http://www.overdrive.com/readerworks/</a> and the Microsoft Reader is available from the <a href="http://www.microsoft.com/reader/">http://www.microsoft.com/reader/</a> site.</p>
+
+<p>Various hardware eBook devices exist as well. Each usually comes with the appropriate software to process your OEB files so that they can be used with the device. Check with your specific eBook hardware vendor for more information on regarding the level of OEB support.</p>
+
+<h3 id="review">Review</h3>
+
+<h4 id="summary">Summary</h4>
+<ul>
+	<li>In the OEB world, an OEB Publication is processed by a reading system and presented to a reader.</li>
+	<li>A reading system is an abstract concept; a reading system implementation may be composed of hardware, software, or both.</li>
+	<li>A reading system may present information to the reader directly from the OEB publication, or it may create one or more intermediate files. The OEB publication structure specification only defines that an OEB publication must be input to the reading system, and that the reading system correctly present the information to the reader.</li>
+</ul>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter2.html
@@ -1,0 +1,442 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 2</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter2">2. Understanding an OEB Publication</h2>
+
+<p>When you write a letter or create a report, you usually think of your end product as one entity: "my essay" or "Ralph's grocery list." Depending on how fancy you get, your document might have several pages with graphs, pictures, links, or even a sound clip. Depending on which application you use to create the document, the pictures might be separate clip art files or they might be embedded directly in the document. You may not know where the pictures are stored, and you may not care.</p>
+
+<p>Here you'll learn how to create a book in the OEB format by hand. Doing so is straightforward and easy, but there are several things you <em>will</em> have to know about and keep track of, such as the location of whatever graphics (if any) you have in your book. To keep things straight in the discussion, OEB uses the term <dfn>OEB Publication</dfn> to refer to all of the items &mdash; the pictures, charts, text, and everything else in your book &mdash; that are included in your work. We'll sometimes use just <dfn>publication</dfn> to mean the same thing.</p>
+
+<p><object data="OEBPublicationClassDiagram.png" type="image/png">OEB Publication Class Diagram</object></p>
+
+<p>You'll therefore be creating a publication, which consists of several items: an <dfn>OEB Package</dfn>, one or more <dfn>OEB Documents</dfn>, and other related files. The simplest publication would simply have two files: a package and a document. In fact, the first publication we'll create here will be that simple, including the book itself (the document) and a separate file (the package) that simply gives information about the book.</p>
+
+<h3 id="oebdocument">An OEB Document</h3>
+
+<p>Let's assume you already have a book. Your book is quite short &mdash; only one paragraph long. You've spent hours on every word, and now you're ready to introduce it to the world. Your book reads:</p>
+
+<blockquote>
+Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being extremely smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.
+</blockquote>
+
+<p>You have yet to decide whether this work is science fiction, poetry, or a science textbook, but you decide to put off that decision until the sequel &mdash; right now, the important thing is to get it into OEB format!</p>
+
+<h4 id="needmarkup">The Need for Markup</h4>
+
+<p>To publish this work, you would have to decide the format in which it should be stored. The first option would be to simply store the text of the book in a file with no formatting whatsoever. The file might be named <code>karl.txt</code>, and you could use a simple text editor such as the <code>Notepad</code> program that comes with Microsoft Windows. This method, sometimes referred to as <dfn>plain text</dfn> or <dfn>ASCII</dfn>, has several advantages, one of the most important being that your file can be read on basically any computer that has a text editor (most do).</p>
+
+<p>On the downside, your text doesn't look so great: you can't specify the font, you can't change styles, and you certainly can't embed pictures. Supporting multiple languages quickly becomes a problem, and when you realize that some text editors don't wrap lines, you'll have to go back and manually specify where each line ends.</p>
+
+<p>You may then decide to use a word processor to publish your work. This certainly works if you plan to print hard copies on a printer, but if you want to distribute your work electronically there are several issues to deal with. Instead of storing your book in plain text in a file, the word processor will add many codes to the file to specify the font, the style, the pictures, the default printer, among other things. If you were to examine your word processor file using a text editor, it might look something like this (although this particular example is completely fabricated):</p>
+
+<blockquote>@#$5098aa23150J:being @#$@$extremely@!$@...</blockquote>
+
+<p>You might see some familiar words somewhere in the file, but the rest of the "garbage" comprise codes recognizable to your word processor. The problem that arises is that each word processor uses a different format to store data. In fact, most word processors change storage formats whenever a new version is released, and sometimes have different formats for different operating systems. Furthermore, the format is <em>not</em> something that you could edit manually, without the help of the word processor itself.</p>
+
+<p>To solve problems such as these, <dfn>markup languages</dfn> were invented. Markup languages allow documents to be created in plain text format, just as we used earlier, with the addition of special symbols called <dfn>markup</dfn>. This allows files to be easily read, transported to several systems, and even edited by hand if needed, as we'll soon do here.</p>
+
+<p>An early markup language, SGML, stands for "Standard Generalized Markup Language" and was created before the World Wide Web even existed. If you've ever surfed the Web, you've definitely used (though maybe not created) HTML, a particular implementation of SGML which stands for "HyperText Markup Language." Most important to OEB is a markup language named XML, which stands for "eXtensible Markup Language." OEB uses XML to define what markup can be used in a particular document.</p>
+
+<p>As you've noticed already, OEB, like everything else in the computer industry, is rife with acronyms &mdash; don't let that confuse you. To see just how easy it is to create and OEB document, assume you want to emphasize that Karl was <em>extremely</em> small. You might then modify your story as follows:</p>
+
+<blockquote>
+Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.
+</blockquote>
+
+<p>The word "extremely" doesn't look any different &mdash; it just has <code>&lt;em&gt;</code> on one side and <code>&lt;/em&gt;</code> on the other. However, when this gets displayed using an actual OEB reading system, it will look like this: <em>extremely</em>. We refer to the <code>&lt;em&gt;</code> and the <code>&lt;/em&gt;</code> as the beginning and ending <dfn>tags</dfn>. In this case, "em" stands for "emphasized," and the "em" has to be in lowercase.</p>
+
+<div class="sidebar" id="markupalphabetsoup">
+<h4 class="sidebarTitle">More Information: Markup Alphabet Soup</h4>
+<p>Standard Generalized Markup Language (SGML) can be considered the parent of all the markup languages we'll be discussing here. In reality, SGML is more like a markup language construction set &mdash; it allows one to create other markup languages by defining which tags can be used, for example. The Hypertext Markup Language (HTML), used on the World Wide Web,  is a specific <dfn>application</dfn> of SGML. That is, SGML was used to create a certain set of tags and other markup to be used in the web; this set of tags is what is known as HTML.</p>
+
+<p>SGML is a very broad, generic language, allowing other markup languages to be constructed with a wide range of possibilities in the way actual tags are used. While this allows a lot of flexibility in designing markup languages using SGML, it's somewhat more difficult to actually process the documents based upon markup languages created with SGML. HTML in particular is notorious for allowing so many possible tag representations that in many cases it is ambiguous as to what was intended.</p>
+
+<p>In order to make SGML easier to use, easier to process, and to increase its popularity, the eXstensible Markup Language (XML) was created. XML simply takes the rules of SGML and makes them stricter. XML is therefore a subset of SGML, and all correct XML documents will be correct SGML documents. This doesn't necessarily work the other way around, though: even though HTML is an application of SGML, many (perhaps most) HTML documents are not correct XML documents because they don't meet XML's stricter rules.</p>
+
+<p>The OEB publication structure is an application of XML in the same way HTML is an application of SGML. The OEBPS uses XML to define a set of tags to be used for storing electronic book information. OEB documents are by definition correct XML documents. Since XML is a subset of SGML, this means that all correct OEB documents are by definition correct SGML documents.</p>
+
+<p>To say that XML has become popular is certainly an understatement; indeed, it's likely that in the future you can ignore the fact that SGML even exists. What about HTML, though? It's still used on the web and, HTML being an SGML application only, most HTML documents don't meet the strict requirements of XML. To address this situation, the World Wide Web Consortium has now released the XHTML specification at <a href="http://www.w3.org/TR/xhtml1/">http://www.w3.org/TR/xhtml1/</a>. XHTML is a modified version of HTML that correctly follows the rules of XML. Since XML is the way of the future, it is recommended you use XHTML for creating new web pages.</p>
+</div>
+
+<h4 id="usingxml">Using XML</h4>
+
+<p>XML is powerful, but it's quite a simple markup language to use. Its basic rule is that markup consists of a beginning <dfn>tag</dfn> and a matching ending <dfn>tag</dfn>, and this pair of tags says something about the text which appears between them. In our example above, the beginning OEB tag <code>&lt;em&gt;</code> and the ending OEB tag <code>&lt;/em&gt;</code> mean that the text between them should be emphasized, which usually means that they should be displayed in italics. In XML, an ending tag always has the same name as its beginning tag, with an extra slash (/) at the beginning. We usually refer to the <code>&lt;em&gt;</code> <code>&lt;/em&gt;</code> tag pair in general as simply the "<code>&lt;em&gt;</code> tag" or more correctly, the "<code>&lt;em&gt;</code> element" which refers to both the beginning and ending tags and all text between them.</p>
+
+<ul>
+	<li><strong>XML Rule 1:</strong> Every beginning tag must be matched by an ending tag which has the same name, except that the ending tag begins with a forward slash (/).</li>
+</ul>
+
+<p>Another important OEB tag to know about is the <code>&lt;p&gt;</code> tag, which indicates a paragraph. (You know by now that the <code>&lt;p&gt;</code> tag has a beginning tag part, <code>&lt;p&gt;</code>, and ending tag part, <code>&lt;/p&gt;</code>.) Your soon-to-be bestseller, to correctly use OEB, should use the <code>&lt;p&gt;</code> tag for each paragraph. Since you have only one paragraph in your story, adding the <code>&lt;p&gt;</code> tag would look like this:</p>
+
+<blockquote>
+<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>You'll notice that the <code>&lt;em&gt;</code> tag is inside the <code>&lt;p&gt;</code> tag. That's fine. In fact, there's even a name for it: a <dfn>nested tag</dfn>. OEB has certain rules about which tags can go inside which other tags, but one thing that applies to <em>all</em> nested XML tags (OEB tags included), is that they must fit neatly inside one another and not be crossed. In other words, <code>&lt;p&gt;</code><code>&lt;em&gt;</code><code>&lt;/em&gt;</code><code>&lt;/p&gt;</code> is fine, but <code>&lt;p&gt;</code><code>&lt;em&gt;</code><code>&lt;/p&gt;</code><code>&lt;/em&gt;</code> is not.</p>
+
+<ul>
+	<li><strong>XML Rule 2:</strong> A nested tag must have both its beginning and ending tags inside the tag in which it is found; that is, two tags cannot be crossed.</li>
+</ul>
+
+<p>At this point you may be wondering, <em class="rhetoricalQuestion">If the less than (&lt;) and greater than (&gt;) symbols are markup characters, used to indicate tags, how do I present them in the text simply as characters, not as markup?</em> If you use one of these characters in your OEB document, it's likely to be confused as a tag, even if you're writing a mathematical expression such as <code>1 + 2 &lt; 4</code>. For this reason, it is illegal in XML to use the less than (&lt;) or greater than (&gt;) character literally except as part of markup.</p>
+
+<p>To represent one of these characters, you'll need to use a <dfn>general entity</dfn>, which takes the form <code>&amp;<em>entityName</em>;</code>, replacing <code><em>entityName</em></code> with the name of the character. To represent the less than (&lt;) character, for example, you would use <code>&amp;lt;</code>, and to represent the greater than (&gt;) character you would use <code>&amp;gt;</code>. This implies another question: <em class="rhetoricalQuestion">If the ampersand (&amp;) character is used in general entities, how can I place an ampersand itself in the text?</em> There is a general entity for ampersand (&amp;) as well: &amp;amp;.</p>
+
+<p>XML defines five general entities that may be used in any XML document, including OEB documents. These are &amp;amp; (&amp;), &amp;lt; (&lt;), &amp;gt; (&gt;), &amp;apos; ('), and &amp;quot; (&quot;).</p>
+
+<ul>
+	<li><strong>XML Rule 3:</strong> A general entity takes the form <code>&amp;<em>entityName</em>;</code> and represents one or more characters by name. XML defines five general entities that may always be used: &amp;amp; (&amp;), &amp;lt; (&lt;), &amp;gt; (&gt;), &amp;apos; ('), and &amp;quot; (&quot;).</li>
+</ul>
+
+<h4 id="creatingoebdocument">Creating an OEB Document</h4>
+
+<p>There are only two more tags you should know about before you create your first OEB document: <code>&lt;html&gt;</code> and <code>&lt;body&gt;</code>. There's nothing difficult here, it's just a requirement set forth by OEB for a standard OEB document: each document must be inside an <code>&lt;html&gt;</code> tag, and the actual text of your work must be inside a <code>&lt;body&gt;</code> tag. You'll learn why later. For now, they are easy enough to add:</p>
+
+<blockquote>
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<p>That's it! You've created your first OEB document. Although it's not a complete <em>OEB publication</em>, it is a an <em>OEB document</em>. The way the OEB Publication Structure 1.0 was written, each OEB document is also more or less an HTML file, which means that you can use an Internet World Wide Web browser to look at the document, even though your entire OEB publication isn't yet finished. Just name the file <code>karl.html</code>, for example, and load it into your favorite Web browser application.</p>
+
+<p>OK, actually, it's an HTML document but not <em>quite</em> an OEB document. Why? Because it doesn't <em>say</em> it is. The document needs to declare that it is an OEB document, and doing so requires two more lines that are always the same in OEB documents. Again, you'll learn more about these lines later, but in short, the first one says, "I'm an XML file:"</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code>
+</blockquote>
+
+<p>(Note that this line uses an single quotes (') rather than double quotes ("). As in most cases in XML, either can be used.)</p>
+
+<p>The second one says, "Specifically, I'm an OEB document file &mdash; even more specifically, a 1.0.1 OEB document file:"</p>
+
+<blockquote>
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code>
+</blockquote>
+
+<p>These two lines go at the top of the file, making the final OEB document look like this:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<h4 id="formattingoebtext">Formatting OEB Text</h4>
+
+<p>In this example, we've entered a <dfn>line break</dfn> at the end of each line by pressing the <code>Enter</code> or <code>Return</code> key on the computer keyboard. We've placed line breaks, for example after the <code>&lt;html&gt;</code> and <code>&lt;body&gt;</code> beginning tags. We've done this purely out of convenience: it's easier to edit the file with the beginning <code>&lt;body&gt;</code> tag directly above and in line with the ending <code>&lt;body&gt;</code> tag, for example.</p>
+
+<p>Our formatting of the document text (what programmers call the <dfn>source file</dfn>, or the text originally entered before it is displayed) does not always affect the appearance of the OEB document when it is displayed. We could have instead not entered any line breaks, making that section of the file look like this:</p>
+
+<blockquote>
+...<br />
+<code>&lt;html&gt;</code><code>&lt;body&gt;</code><code>&lt;p&gt;</code>Years ago...<code>&lt;/p&gt;</code><code>&lt;/body&gt;</code><code>&lt;/html&gt;</code>
+</blockquote>
+
+<p>Any <dfn>whitespace</dfn> between elements, such as space, tab, and line breaks, are ignored when the document is displayed.</p>
+
+<ul>
+	<li><strong>XML Rule 4:</strong> Whitespace characters between elements are ignored; spaces, tabs, and line breaks can therefore be used arbitrarily to aid in text entry.</li>
+</ul>
+
+<p>What about whitespace that appears in displayed sections, such as inside the beginning and ending <code>&lt;p&gt;</code> tags? They obviously aren't ignored; when your document is displayed, spaces appear between words. However, multiple whitespace characters are replaced by a single space before being displayed.</p>
+
+<ul>
+	<li><strong>OEB Rule 1:</strong> (<em>Display of Whitespace</em>) If two or more whitespace characters (such as spaces, tabs, and line breaks) appear in a row, they will be <dfn>collapsed</dfn> into (that is, replaced by) a single space character before being displayed.</li>
+</ul>
+
+<p>This means that the following examples will all be displayed identically:</p>
+
+<blockquote>
+<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth...<code>&lt;/p&gt;</code>
+</blockquote>
+
+<blockquote>
+<pre><code>&lt;p&gt;</code>Years      ago,<br />     when strange creatures<br />ruled the earth...<code>&lt;/p&gt;</code></pre>
+</blockquote>
+
+<p>Both of these examples will collapse all spaces, tabs, and line breaks into single spaces, displaying the following:</p>
+
+<blockquote>Years ago, when strange creatures ruled the earth...</blockquote>
+
+<h3 id="oebpackage">An OEB Package</h3>
+
+<p>Half of the job is now done and you have an OEB document. The other half of an OEB publication, as you learned earlier, is an OEB package. The package is where an <dfn>OEB Reading System</dfn> (such as a software reader or a separate eBook device) will look to find out information about your book. What sort of things would a reading system need to know before displaying your book? At minimum, there are three things that a reading system <em>must</em> know:</p>
+
+<ol>
+	<li>Which book is this?</li>
+	<li>What files are in the book?</li>
+	<li>In what order should the files be displayed?</li>
+</ol>
+
+<p>Although the first item sounds reasonable, for your short masterpiece the last two items may seem ridiculous; there is, after all, only one document &mdash; and it's obvious in what order it should be displayed! As we discussed at the beginning of this chapter, though, many people will have several documents and even pictures in their masterpieces. While OEB certainly could have created an exception for one-document publications (and may even decide to do this in a future version of the specification), currently you still need to specifically supply information you may think is obvious. Besides, you may want more than one document in your sequel, so you would have had to learn this information anyway!</p>
+
+<p>The OEB package is an XML file just like the OEB document, and accordingly follows XML rules, including the ones you've learned already. Instead of using HTML tags (as the OEB document does), it will use a special set of tags made especially for an OEB package.</p>
+
+<p>The first two lines look very similar to the first two lines of an OEB document. The first one says, "I'm an XML file, too:"</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code>
+</blockquote>
+
+<p>The second one says, "I'm not an OEB document, though; I'm an OEB <em>package</em>:"</p>
+
+<blockquote>
+<code>&lt;!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"&gt;</code>
+</blockquote>
+
+<p>Like all XML files, there is a beginning and ending tag which together contain the main part of the file. In the OEB document, it was the <code>&lt;html&gt;</code> tag. In contrast, the OEB package uses the <code>&lt;package&gt;</code> tag (for obvious reasons), making the "outside" portion of the package look like this:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"&gt;</code><br />
+<code>&lt;package&gt;</code><br />
+	<em>Actual package goes here...</em><br />
+<code>&lt;/package&gt;</code>
+</blockquote>
+
+<p>Inside the package are several required sections; each one answers one of the questions raised above. Each section has its corresponding tag which reflects the function of that section: <code>&lt;metadata&gt;</code>, <code>&lt;manifest&gt;</code>, and <code>&lt;spine&gt;</code>:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"&gt;</code><br />
+<code>&lt;package&gt;</code>
+	<blockquote>
+	<code>&lt;metadata&gt;</code><br />
+		<em>Which book is this?</em><br />
+	<code>&lt;/metadata&gt;</code>
+	</blockquote>
+	<blockquote>
+	<code>&lt;manifest&gt;</code><br />
+		<em>What files are in the book?</em><br />
+	<code>&lt;/manifest&gt;</code>
+	</blockquote>
+	<blockquote>
+	<code>&lt;spine&gt;</code><br />
+		<em>In what order should the files be displayed?</em><br />
+	<code>&lt;/spine&gt;</code>
+	</blockquote>
+<code>&lt;/package&gt;</code>
+</blockquote>
+
+<p>As we examine the structure of the OEB package, we'll display the text using spaces and tabs so as to make the sections easier to read. When you create your document, you can enter the package in any way you like, using spaces, tabs, or new lines. In fact, XML (and OEB) doesn't even care if everything is entered on one line &mdash; it's just harder for you to read that way, so we've decided not to do that here.</p>
+
+<h4 id="packageelement">The <code>&lt;package&gt;</code> Element</h4>
+
+<p>The surrounding <code>&lt;package&gt;</code> element, made up of the <code>&lt;package&gt;</code> and <code>&lt;/package&gt;</code> tags, is pretty straightforward except that it specifies a unique identifier which will be used later for identifying the document. The exact unique identifier you used is up to you. In this case, it might be appropriate to use the identifier, "karlpackage", like this:</p>
+
+<blockquote>
+<code>&lt;package unique-identifier="karlpackage"&gt;</code>
+</blockquote>
+
+<p>You'll notice that we specify the identifier inside the tag itself! In XML terms, <code>unique-identifier</code> is referred to an <dfn>attribute</dfn> of the tag.</p>
+
+<ul>
+	<li><strong>XML Rule 5:</strong> An element's beginning tag may have one or more attributes in the form <code>attributeName="value"</code> or <code>attributeName='value'</code>.</li>
+</ul>
+
+<p>The value can be surrounded by single or double quotes, as long as you are consistent on both sides of the value.</p>
+
+<h4 id="packagemetadata">The Package Metadata</h4>
+
+<p>The first section inside the <code>&lt;package&gt;</code> element contains metadata. In answering the question, "Which document is this?" the <code>&lt;metadata&gt;</code> element contains several elements, each of which specify something about the book, such as its title and author(s). These items are called <dfn>metadata</dfn> items, hence the name of the element.</p>
+
+<p>In an added twist, the elements in the metadata section are inside another element named <code>&lt;dc-metadata&gt;</code>. The OEB Authoring Group did not create these metadata identifiers from scratch; instead, they used a set of metadata identifiers already defined by a group named the <a href="http://purl.org/dc/">Dublin Core</a>. Since the OEB publication structure allows you to create your own metadata items, the Authoring Group decided to group together the special metadata items from the Dublin core inside its own <code>&lt;dc-metadata&gt;</code> element. Moreover, the <code>&lt;dc-metadata&gt;</code> element takes certain attributes that specify that these metadata are Dublin Code metadata. Your book's metadata section, therefore, might turn out to look something like this:</p>
+
+<blockquote>
+<code>&lt;metadata&gt;</code>
+	<blockquote>
+	<code>&lt;dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"&gt;</code>
+		<blockquote>
+      <code>&lt;dc:Title&gt;</code>Karl the Kreature<code>&lt;/dc:Title&gt;</code><br />
+			<code>&lt;dc:Identifier id="karlpackage" scheme="ISBN"&gt;</code>123456789X<code>&lt;/dc:Identifier&gt;</code><br />
+			<code>&lt;dc:Creator role="aut"&gt;</code>Jane Doe<code>&lt;/dc:Creator&gt;</code>
+		</blockquote>
+	<code>&lt;/dc-metadata&gt;</code>
+	</blockquote>
+<code>&lt;/metadata&gt;</code>
+</blockquote>
+
+<p>The parts from the above example that will change for each book are the metadata elements: the required elements <code>&lt;dc:Title&gt;</code> and <code>&lt;dc:Identifier&gt;</code>, and the optional (but important to you!) element <code>&lt;dc:Creator&gt;</code>. The metadata elements in this section all begin with "dc:", another requirement that simply specifies that these are Dublin Core metadata.</p>
+
+<p>The <code>&lt;dc:Title&gt;</code> element is simple enough: it holds the title of the book. Similarly, the <code>&lt;dc:Identifier&gt;</code> element holds an identifier that hopefully uniquely identifies the book in the world, even if two books by two separate authors have identical titles. Since there are several methods of identifying books uniquely, the <code>scheme</code> attribute is necessary to specify the identifier used. In this case, we're using an ISBN for the identifier, so we set <code>scheme="ISBN"</code>.</p>
+
+<p>As there are several methods of uniquely identifying a single book, the OEB Authoring Group allowed for several methods to be used together in the same package. However, one identifier must be chosen as the main identifer; this identifier's element must have an <code>id</code> attribute set to the unique ID we specified earlier in the beginning <code>&lt;package&gt;</code> tag. Here we only have one identifier, and we've appropriately set the <code>id</code> attribute to <code>id="karlpackage"</code>.</p>
+
+<p>You can identify yourself as the creator of the work using the <code>&lt;dc:Creator&gt;</code> element. The <code>role</code> attribute, is optional, specifying what role you played during the creation of the book. Common values are <code>"aut"</code> (representing "author"), <code>"edt"</code> ("editor"), and <code>"trl"</code> ("translator"). Probably the role used the most, and the one recommended here that should always be included, is <code>"aut"</code>. As with <code>&lt;dc:Identifier&gt;</code>, you can include several <code>&lt;dc:Creator&gt;</code> elements to identify several creators of your work.</p>
+
+<h4 id="packagemanifest">The Package Manifest</h4>
+
+<p>The next section of the package is referred to as the <dfn>manifest</dfn>, holding information about which files should be included with the book. The Open eBook specification was designed to be distributed and read on a variety of systems and platforms; the manifest guarantees that each system can have a complete list of the minimum files that will be needed to display the contents of the book.</p>
+
+<p>Each item in the manifest specifies three things:</p>
+
+<ul>
+	<li>A unique identifier for the item, so that other parts of the book can unambiguously refer to it.</li>
+	<li>The name of the file in which the actual item is stored.</li>
+	<li>The type of the item (such as a document or a picture).</li>
+</ul>
+
+<p>The manifest of our example, then, will be quite simple:</p>
+
+<blockquote>
+<code>&lt;manifest&gt;</code>
+	<blockquote>
+		<code>&lt;item id="karl" href="karl.html" media-type="text/x-oeb1-document"&gt;</code>
+	</blockquote>
+<code>&lt;/manifest&gt;</code>
+</blockquote>
+
+<p>Each item in the book will be represented by an <code>&lt;item&gt;</code> element. Here, there is only one item in the book, the OEB document we created earlier. You can choose any unique ID you like; here we'll use <code>id="karl"</code>. For the <code>href</code> attribute (so-named from the hypertext references used in HTML), specify the filename you gave the OEB document. There are a standard set of <code>media-type</code> attribute values you can use, such as <code>"image/jpeg"</code> and <code>"image/png"</code> for certain types of images. In this case, the item is an OEB document, so we must state as much by setting <code>media-type="text/x-oeb1-document"</code>.</p>
+
+<h4 id="packagespine">The Package Spine</h4>
+
+<p>Now that we've given information about the book and specified which items are in the book, the last required step is to specify the order in which the book should be read, and this is done inside the <code>&lt;spine&gt;</code> element. Although electronic books bring all sorts of possibilities as far as interaction and reader-influenced reading orders, there must still be one default reading order specified, or what the OEB specification refers to as the <dfn>primary linear reading order</dfn>. (Writers of adventure stories that have no predetermined reading order are in luck; how to format such interactive stories will be explained in a later version of this work.)</p>
+
+<p>The <dfn>spine</dfn> is even simpler than the manifest, because the information about each item has already been specified in the manifest. Therefore, the spine only needs to identify which items from the manifest appear in what order. This implies that only items defined in the manifest can appear in the spine. Furthermore, only OEB documents (that is, items included in the manifest that are of type "text/x-oeb1-document") can appear in the spine. Specifically, only those OEB documents that should be displayed as part of the normal linear reading order of the book should be included in the spine.</p>
+
+<p>The spine of our book is certainly straightforward. Its one item reference (the <code>&lt;itemref&gt;</code> element) identifies the one item in the manifest by referencing the unique ID we assigned it: <code>idref="karl"</code>.</p>
+
+<blockquote>
+<code>&lt;spine&gt;</code>
+	<blockquote>
+		<code>&lt;itemref idref="karl"&gt;</code>
+	</blockquote>
+<code>&lt;/spine&gt;</code>
+</blockquote>
+
+<p>With that, we've answered all three questions a reading system requires, and are thus finished with the OEB package. The complete listings of both the finished document and package appear at the end of this chapter.</p>
+
+<h3 id="xmlrepresentdata">Using XML to Represent Data</h3>
+
+<p>You've probably noticed at least two different ways in which we've used XML tag pairs, or elements. The first was to specify formatting: the <code>&lt;em&gt;</code> element made a section of text appear in italics. The second was to represent data, or information about the work: we used the <code>&lt;dc:Creator&gt;</code> element to specify the author of the book, without specifying how (or if) the author's name would actually be displayed. The latter is simply for storing information about the book.</p>
+
+<p>A closer examination reveals that the uses of both of these elements, <code>&lt;em&gt;</code> and <code>&lt;dc:Creator&gt;</code>, are actually virtually identical. As it turns out, the <code>&lt;em&gt;</code> element does not specify that italics should be used; it rather specifies that the text should be emphasized without specifying exactly <em>how</em> the text should be emphasized. Although the default display method for text inside an <code>&lt;em&gt;</code> element is to use italics, it's certainly conceivable that you could decide later to display emphasis using the color red, so that your book displays, "Being <span style="color: red;">extremely</span> smaller..." instead of "Being <span style="font-style: italic;">extremely</span> smaller..."</p>
+
+<p>If you consistently use <code>&lt;em&gt;</code> to represent emphasis, it's relatively simple using XML (and, by definition, OEB) to change how emphasized text appears &mdash; without changing the actual text of your book! This is an important concept in creating documents, and it's often referred to as a <dfn>separation of content and presentation</dfn>. As you'll learn soon, the way a document appears should be kept distinct (in a completely separate file, in fact) from the actual content of your book.</p>
+
+<ul>
+	<li><strong>OEB Tip 1:</strong> (<em>Separation of Content and Presentation</em>) Do not use an element to specify how text should appear, but rather use elements to specify the content or meaning of sections of your work.</li>
+</ul>
+
+<p>To provide an example of how useful it is to encode <em>meaning</em> into a document rather than trying to specify how a document should be displayed, consider the following extract:</p>
+
+<blockquote>
+<p>In the Urdu language, there is a class of descriptive words called <span style="font-style: italic;">postpositions</span>. These are similar to English prepositions except that they come <span style="font-style: italic;">after</span> the words they modify; hence the name "post"+"position".</p>
+</blockquote>
+
+<p>Since we want "postposition" to be displayed (or <dfn>rendered</dfn>) in italics, it would be tempting at first to use the <code>&lt;em&gt;</code> tag like this: <code>&lt;em&gt;</code>postposition<code>&lt;/em&gt;</code>. However, if you take a moment to think about why we want the word "postposition" displayed differently, you'll realize that we really don't want to emphasize the word but want rather to indicate that we are defining the word for the first time.</p>
+
+<p>There so happens to be an OEB tag that does just that &mdash; the <code>&lt;dfn&gt;</code> tag specifies that a new word is being defined or used for the first time. Text which uses the <code>&lt;dfn&gt;</code> tag is also usually displayed in italics as well, so you might wonder why it matters which tag is used. The concept of separation of content and presentation answers this question. What if we make a reading system that automatically generates a glossary in the back of the book, listing all the new terms introduced and where they were first defined? If we have used the <code>&lt;dfn&gt;</code> tag in the correct places, these terms could be found easily and placed in the glossary automatically.</p>
+
+<p>It's important to note that, in the section above, we would not want to use the <code>&lt;dfn&gt;</code> tag for the second italicized word, "after." Instead, we would want to use the <code>&lt;em&gt;</code> tag; we are not wanting to define the word "after," but merely emphasize the position of a "postposition". Keeping in mind our concept of separation of content and presentation, we'd probably enter the above section like this:</p>
+
+<blockquote>
+<p>&lt;p&gt;In the Urdu language, there is a class of descriptive words called &lt;dfn&gt;postpositions&lt;/dfn&gt;. These are similar to English prepositions except that they come &lt;em&gt;after&lt;/em&gt; the words they modify; hence the name "post"+"position".&lt;/p&gt;</p>
+</blockquote>
+
+<p>As you will see later, there are several methods of displaying italics in OEB. A popular method in the past was the <code>&lt;i&gt;</code> tag, which actually means "italics". This is now considered bad practice, considering the need to separate content from presentation. Unfortunately, since OEB uses many tags from HTML, the <code>&lt;i&gt;</code> tag is available to use in OEB documents. For reasons we've just explained, we strongly recommend against using the <code>&lt;i&gt;</code> tag in your documents, and using the <code>&lt;em&gt;</code> instead in most cases.</p>
+
+<p>The concept of separation of content and presentation is a very important one, and we'll revisit this topic.</p>
+
+<p>You now know the basic structure of an OEB publication. There are several tags which we haven't covered yet which you'll want to use when you create real-world documents. After discussing <a href="chapter3.html">styles and style sheets</a>, we'll cover the <a href="chapter4.html">tags you'll normally need</a> when working in the real world.</p>
+
+<h3 id="review">Review</h3>
+
+<h4 id="summary">Summary</h4>
+<ul>
+	<li>An OEB Publication consists of an OEB Package, one or more OEB Documents, and other related files such as images.</li>
+	<li>The OEB Publication Structure is a markup language which follows the rules of XML; therefore, all OEB files are XML files.</li>
+	<li>OEB in its basic form specifies a set of tags which should be used, always following the rules of XML. OEB also contains the flexibility to use custom tags.</li>
+	<li>The set of basic tags specified by OEB is very similar to, for better or for worse, the set of tags specified by HTML.</li>
+</ul>
+
+<h4 id="xmlrules">XML Rules</h4>
+<ul>
+	<li><strong>XML Rule 1:</strong> Every beginning tag must be matched by an ending tag which has the same name, except that it begins with a forward slash (/). (Special <a href="chapter4.html#emptyElement">empty tags</a> will be discussed later.)</li>
+	<li><strong>XML Rule 2:</strong> A nested tag must have both its beginning and ending tags inside the tag in which it is found; that is, two tags cannot be crossed.</li>
+	<li><strong>XML Rule 3:</strong> A general entity takes the form <code>&amp;<em>entityName</em>;</code> and represents one or more characters by name. XML defines five general entities that may always be used: &amp;amp; (&amp;), &amp;lt; (&lt;), &amp;gt; (&gt;), &amp;apos; ('), and &amp;quot; (&quot;).</li>
+	<li><strong>XML Rule 4:</strong> Whitespace characters between elements are ignored; spaces, tabs, and line breaks can therefore be used arbitrarily to aid in text entry.</li>
+	<li><strong>XML Rule 5:</strong> An element's beginning tag may have one or more attributes in the form <code>attributeName="value"</code> or <code>attributeName='value'</code>.</li>
+</ul>
+
+<h4 id="oebrules">OEB Rules</h4>
+<ul>
+	<li><strong>OEB Rule 1:</strong> (<em>Display of Whitespace</em>) If two or more whitespace characters (such as spaces, tabs, and line breaks) appear in a row, they will be <dfn>collapsed</dfn> into (that is, replaced by) a single space character before being displayed.</li>
+	<li><strong>OEB Tip 1:</strong> (<em>Separation of Content and Presentation</em>) Do not use an element to specify how text should appear, but rather use elements to specify the content or meaning of sections of your work.</li>
+</ul>
+
+<h4 id="oebtags">OEB Tags</h4>
+<ul>
+	<li><code>&lt;dfn&gt;</code> Specifies that a term is being used for the first time; usually rendered in italics.</li>
+	<li><code>&lt;em&gt;</code> Emphasizes text; usually rendered in italics.</li>
+</ul>
+
+<h3 id="exampleoebdocument">Completed Example OEB Document (<code>karl.html</code>)</h3>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<h3 id="exampleoebpackage">Completed Example OEB Package (<code>karl.opf</code>)</h3>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"&gt;</code><br />
+<code>&lt;package unique-identifier="karlpackage"&gt;</code>
+
+	<blockquote>
+	<code>&lt;metadata&gt;</code>
+		<blockquote>
+		<code>&lt;dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"&gt;</code>
+			<blockquote>
+	      <code>&lt;dc:Title&gt;</code>Karl the Kreature<code>&lt;/dc:Title&gt;</code><br />
+				<code>&lt;dc:Identifier id="karlpackage" scheme="ISBN"&gt;</code>123456789X<code>&lt;/dc:Identifier&gt;</code><br />
+				<code>&lt;dc:Creator role="aut"&gt;</code>Jane Doe<code>&lt;/dc:Creator&gt;</code>
+			</blockquote>
+		<code>&lt;/dc-metadata&gt;</code>
+		</blockquote>
+	<code>&lt;/metadata&gt;</code>
+	</blockquote>
+	<blockquote>
+	<code>&lt;manifest&gt;</code>
+		<blockquote>
+			<code>&lt;item id="karl" href="karl.html" media-type="text/x-oeb1-document"&gt;</code>
+		</blockquote>
+	<code>&lt;/manifest&gt;</code>
+	</blockquote>
+	<blockquote>
+	<code>&lt;spine&gt;</code>
+		<blockquote>
+			<code>&lt;itemref idref="karl"&gt;</code>
+		</blockquote>
+	<code>&lt;/spine&gt;</code>
+	</blockquote>
+<code>&lt;/package&gt;</code>
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter3.html
@@ -1,0 +1,230 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 3</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter3">3. Styles and Style Sheets</h2>
+
+<p>One of the most integral parts of OEB is the concept of <dfn>style sheets</dfn>. A style sheet is a tool that helps to separate content from presentation and is used not only with OEB but with XML and (increasingly) with HTML web pages as well. You've been told that the separation of content and presentation is a "Good Thing" &mdash; after you understand style sheets, you'll begin to see why this concept is so important.</p>
+
+<p>Style sheets have a few unusual properties: you could write OEB-compliant eBooks all your life and never use a stylesheet. Stranger still, someone might create a style sheet that could be used with your work long after you've written it. That's what makes stylesheets so useful: they represent the <dfn>encapsulation</dfn> (or bundling) of the presentation part of the <em>publication=content+presentation</em> equation, and therefore help keep the two completely separate. Your OEB document, with its text and tags, is the content and holds the meaning of what you're written; the style sheet(s) hold how your work is presented to the user.</p>
+
+<p>How is this supposed to work? Imagine that you're writing a book to be published by the Happy Publishing Company. Happy has its own ideas about how your book should look &mdash; that is, which fonts it should have, how it should be spaced, etc. (Happy Publishing Company might have ideas about what your book should <em>say</em> as well, but that's another story; it should be clear to you by now that these are two separate concepts.) If you write a book and concentrate on the content, Happy Publishing Company can simply use its style sheet with your work after you're finished, and the book will look just like Happy wants it to. What happens when you change publishers? Your new publisher can simply substitute their standard style sheet and your book will suddenly take on its new look, without your having to make one single change to the actual content of the book &mdash; <em>if</em> you've correctly separated the content from the presentation.</p>
+
+<p>That's a big "if", and one that takes a little thinking on your part, at least to begin with. Since OEB comes from a legacy of HTML which didn't stress as strongly such a separation of content and presentation, OEB in some cases makes it easier for you to put style information where it doesn't belong: mixed in with the content of your work. It is hoped that you'll be able not only to overcome these temptations, but to understand why the current emphasis of information storage and retrieval formats is going in a direction that stresses that these elements be separated.</p>
+
+<p>Before going any further into the theory of style sheets, we'll examine a few examples of using styles, from the least desired to the most appropriate.</p>
+
+<h3 id="emphasisrevisited">Emphasis Revisited</h3>
+
+<p>The previous chapter hinted that OEB has a tag named <code>&lt;i&gt;</code> which causes the specified text to be rendered (or displayed) in italics. We've told you that this is not recommended.</p>
+
+<ul>
+	<li><strong>Not Recommended:</strong> <code>&lt;p&gt;</code>Being <code>&lt;i&gt;</code>extremely<code>&lt;/i&gt;</code> smaller than other blovji his age...<code>&lt;/p&gt;</code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic;">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>What's the alternative? We've stressed that in many places, the <code>&lt;em&gt;</code> tag, specifying "emphasis", can be used in place of the <code>&lt;i&gt;</code> tag for the same effect. We've answered the question, "If they both have the same effect, what's the difference?" by saying that <code>&lt;em&gt;</code> specifies simply that a section of text should be emphasized, not <em>how</em> the text should be emphasized.</p>
+
+<ul>
+	<li><strong>Recommended:</strong> <code>&lt;p&gt;</code>Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age...<code>&lt;/p&gt;</code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic;">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>The point is that, although <code>&lt;em&gt;</code> is usually rendered in italics by default, there's nothing that prevents you from changing how <code>&lt;em&gt;</code> gets displayed &mdash; nothing except a lack of knowledge, of course. We'll now address how that's done.</p>
+
+<p>OEB has specified that every element has an optional <code>style</code> attribute. As you might guess, you can use this attribute to override the style of that element. We'll explain later the specifics of the style information, but here's a quick example of how you could guarantee that <code>&lt;em&gt;</code> is displayed in italics:</p>
+
+<ul>
+	<li><strong>Not Recommended:</strong> <code>&lt;p&gt;</code>Being <code>&lt;em style="font-style: italic"&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age...<code>&lt;/p&gt;</code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic;">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>If you wanted the emphasized text to not only be displayed in italics but also in red, you'd use the following:</p>
+
+<ul>
+	<li><strong>Not Recommended:</strong> <code>&lt;p&gt;</code>Being <code>&lt;em style="color: red"&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age...<code>&lt;/p&gt;</code></li>
+</ul>
+
+<blockquote>Being <span style="font-style: italic; color: red">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>Notice that the text is still displayed in italics, because we didn't specify that the italics should be removed (there's a way to do this, which you'll see later). Instead, we specified that the color red should be added to whatever style was there already.</p>
+
+<p>As you can see, we don't recommend this method, and it's not hard to figure out why. If you specify the style of the tag directly, you've gained nothing over just using the <code>&lt;i&gt;</code> tag and manually making changes. After all, this method still mixes our presentation information inside the content of our book.</p>
+
+<p>Let's continue with the assumption that we'd like all emphasized text to be displayed using not only italics, but also the color red. We'll also assume you've followed the recommendations here and used the <code>&lt;em&gt;</code> tag for emphasized text. The secret to style sheets is that they use the same format you just saw used inside the <code>style</code> attribute, only that they've been removed from the content and placed in a separate location. This is the first way we could do it:</p>
+
+<ul>
+	<li><strong>Recommended:</strong></li>
+</ul>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;head&gt;</code><br />
+  <code>&lt;title&gt;</code>Karl the Creature<code>&lt;/title&gt;</code><br />
+  <code>&lt;style&gt;</code>em {color: red}<code>&lt;/style&gt;</code><br />
+<code>&lt;/head&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;p&gt;</code>...Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age...<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<blockquote>Being <span style="font-style: italic; color: red">extremely</span> smaller than other blovji his age...</blockquote>
+
+<p>This example correctly specifies that <em>all</em> occurrences of the <code>&lt;em&gt;</code> element should be displayed in red. Furthermore, the actual body of the document does not need to be changed; all text marked as emphasized will be shown with the new style.</p>
+
+<p>In the previous chapter we touched on the essential components of an OEB document. In the above example you'll notice several elements we didn't discuss. OEB specifies that the <code>&lt;head&gt;</code> element is optional in a document, but if included it should contain a <code>&lt;title&gt;</code> element. The element we're interested in, <code>&lt;style&gt;</code> must be inside the <code>&lt;head&gt;</code> element. This means that whenever we include a <code>&lt;style&gt;</code> element, we'll have to include both a <code>&lt;head&gt;</code> and a <code>&lt;title&gt;</code> element as well. Both of these elements will be discussed in depth later. For now, note simply that we are specifying style information outside the actual body of the document, in a separate element named <code>&lt;style&gt;</code>.</p>
+
+<p>You might wonder at this point, if we were to take our concept of separation of content and presentation to the extreme, why we place any style information at all in the same file as the document. Wouldn't it be better to store presentation information in a completely separate location? Yes, in many circumstances it would. We'll explain how a little later; for now, to make things simple, we'll keep the style information in the same file as the document.</p>
+
+<h3 id="cascadingstylesheets">Cascading Style Sheets (CSS)</h3>
+
+<p>You've seen how OEB has used XML to create a set of tags and rules to use those tags, in many instances borrowing tags from HTML. Similarly, there is a set of rules for specifying style information in an OEB document. Here, OEB borrowed the format of a specification for <dfn>Cascading Style Sheets</dfn> (CSS). Although there are a few differences between OEB's version of CSS and standard CSS, these differences are very minor; in most instances, OEB simply specifies which CSS constructs cannot be used. There's only one instance where OEB actually creates new identifiers. For the most part, then, if you're familiar with CSS at all you can apply your knowledge to OEB.</p>
+
+<p>XML, on which OEB is based, uses a set of elements, each of which have a beginning and ending tag. CSS, on the other hand, uses different constructs. In general, CSS styles consist of <dfn>selectors</dfn> and <dfn>declarations</dfn>, the latter of which contains one or more sets of a <dfn>property</dfn> and a <dfn>value</dfn>. Although this sounds complicated, it's quite simple in practice; once you understand these basic parts, there isn't much more to learn for most things you'll want to do.</p>
+
+<div class="sidebar" id="cssvsxsl">
+<h4 class="sidebarTitle">More Information: CSS vs. XSL</h4>
+
+<p>OEB uses XML to store content, but uses a separate language named CSS to store style (presentation) information. Why must one use two separate formats? Why doesn't OEB simply use XML for storing both content and presentation information, even if these things are stored separately?</p>
+
+<p>That's a legitimate and important question. It so happens that there is a method for specifying style and formatting information using XML &mdash; it's called <dfn>XML Style Language</dfn> (XSL). Since it uses XML, XSL doesn't force one to learn another format just to create style information, and XSL is even more powerful than CSS</p>
+
+<p>Why doesn't OEB use XSL instead of CSS, then? There are several reasons. When the OEB Publication Structure 1.0 specification was being written, there were not any tools available specifically for viewing OEB documents. Since an OEB document is very similar to a normal HTML document, it was possible however to view OEB documents using a web browser. The OEB Authoring Group chose to use CSS, which most browsers at the time supported, rather than to use XSL, which most browsers couldn't handle.</p>
+
+<p>More importantly, the XSL specification was not yet finalized at the time the OEB specification was being written, so any use of XSL would have had to predict the final form in which XSL would appear. OEB therefore relies primarily on CSS, although future version of OEB may well rely on XSL. It's even possible to use XSL stylesheets with OEBPS 1.0, as long as an appropriate CSS stylesheet is included for those reading systems that do not understand XSL.</p>
+
+</div>
+
+<p>The particular style we specified for <code>&lt;em&gt;</code> looks like this:</p>
+
+<blockquote><code>em {color: red}</code></blockquote>
+
+<p>This style represents how most styles you specify will appear. Each will have the same parts introduced earlier:</p>
+
+<ul>
+	<li><strong>selector</strong> - <code>em</code> - Specifies which elements will be "selected" to receive this style. In this case, we indicate that this style applies to every <code>&lt;em&gt;</code> element.</li>
+	<li><strong>declaration</strong> - <code>{color: red}</code> - Specifies the style of the selected element(s). In this case, we've specified that the color of the text should be red. As noted earlier, the declaration is divided up into one or more properties and corresponding values.</li>
+	<li><strong>property</strong> - <code>color</code> - Specifies a particular property to be modified. Here the color of the text is being modified. Each declaration could modify several properties &mdash; both the color and the size of the text could be changed, for example.</li>
+	<li><strong>value</strong> - <code>red</code> - The new value of the property. Each property will have at least one value, although more than one value can be specified in some instances in which the first value might not be available.</li>
+</ul>
+
+<p>There are, of course, a few more intricacies which we'll go into later, especially concerning the selector part of the equation. There are probably a couple of questions about exactly what's happening here that should probably be cleared up first.</p>
+
+<p><em class="rhetoricalQuestion">Why does my emphasized text show up both in red <em>and</em> italics, even though I specified just the color red?</em> If you specify no styles at all, there is a default style which will be applied to text between OEB tags. In OEB, the <code>&lt;em&gt;</code> tag is usually rendered in italics by default. In fact, the effect is exactly as if you had specified the following style in your document:</p>
+
+<blockquote><code>em {font-style: italic}</code></blockquote>
+
+<p>In other words, there's effectively a default style sheet used which specifies the standard style of OEB elements. In our example, specifying that the color red should be used did not state that the default style of italics should not be used. The color red was therefore added to the existing default style of italics, giving all text between <code>&lt;em&gt;</code> tags both the italic style and the color red.</p>
+
+<p><em class="rhetoricalQuestion">If styles can be specified in multiple places, such as on the actual tag and elsewhere in the document, what happens when I declare the same style in multiple places?</em> This question relates to the previous one. If you specify in the document's <code>&lt;style&gt;</code> tag, for example, the style <code>em {color: red}</code>, then every occurrence of the <code>&lt;em&gt;</code> tag will be rendered in red. If you specify, using the <code>style</code> attribute, that a particular <code>&lt;em&gt;</code> tag should have be underlined using <code>&lt;em style="text-decoration: underline"&gt;</code>, then that particular portion of text will be underlined. But it will also be shown in red, because you've already specified that <em>all</em> occurrences of the <code>&lt;em&gt;</code> tag should be in red.</p>
+
+<p>Each particular instance of the <code>&lt;em&gt;</code> tag, therefore, <dfn>inherits</dfn> the properties already defined for it. Since you specified a property for <em>all</em> <code>&lt;em&gt;</code> tags, this property <dfn>cascades</dfn> down to each of the individual <code>&lt;em&gt;</code> tags similar to the way water from a waterfall cascades down to each level of rocks before it reaches the pool below. In fact, that's why CSS uses the name "Cascading Style Sheets."</p>
+
+<p><em class="rhetoricalQuestion">What happens if the properties I specify in several places conflict with each other?</em> As a rule of thumb, the most specific declaration is used. If you've specified, for example, that all <code>&lt;em&gt;</code> elements should be red, but then in a particular instance specified that a particular <code>&lt;em&gt;</code> element should instead be blue, the blue wins.</p>
+
+<h4 id="cssselectors">CSS Selectors</h4>
+
+<p>A selector determines (or selects) the element(s) to which a particular style declaration applies. In our example above, <code>em {color: red}</code>, the selector is simple: this style will be applied to every <code>&lt;em&gt;</code> element. There are several other additions to the selector syntax that make it easy to select exactly which element(s) you prefer.</p>
+
+<p><strong>Select Multiple Elements:</strong> You could always duplicate a style declaration for several elements with different names, but CSS has an easier way to select several elements for the same style. Just place several element names in a row, separated by commas (,). For example, <code>em, dfn {color: red}</code> would make all emphasized text (<code>&lt;em&gt;</code>) <em>and</em> all defined words (<code>&lt;dfn&gt;</code>) appear in red.</p>
+
+<p><strong>Select Elements Only in Certain Contexts:</strong> So far, we've only seen the <code>&lt;em&gt;</code> element appear inside a paragraph (<code>&lt;p&gt;</code>). As we'll see later, emphasized text could appear in several places, such as inside a list or a heading. To specify that <em>only</em> emphasized text inside a paragraph should be red, you would list the nested elements in the correct order, separated by whitespace.: <code>p em {color: red}</code>. This would mean that emphasized text inside a paragraph (e.g. <code>&lt;p&gt;&lt;em&gt;&lt;/em&gt;&lt;/p&gt;</code>) would appear in red, but not emphasized text inside a list (e.g. <code>&lt;li&gt;&lt;em&gt;&lt;/em&gt;&lt;/li&gt;</code>). Again, we'll discuss lists later; for now, simply realize that an element can appear in different contexts, and CSS provides a way to specify these situations.</p>
+
+<p><strong>Select Elements by Class</strong> CSS allows a style to be created and given a name, and then later used with any element you decide. After specifying a name (or <dfn>class</dfn>) for a style, you can use the style with a particular element simply by specifying the style name in the <code>class</code> attribute of an element. The <code>class</code> attribute, like the <code>style</code> attribute, is an optional attribute that can be used with many elements.</p>
+
+<p>For example, instead of explicitly specifying that every <code>&lt;em&gt;</code> element should appear in red, we could create a class that would allow you to specify to which <code>&lt;em&gt;</code> element the style applied. A style class is always preceded by a period or full stop character (.), like this: <code>em.colorful {color: red}</code>. We could then specify that a particular emphasized portion of text would use this style:"this is <code>&lt;em class="colorful"&gt;</code>emphasized<code>&lt;/em&gt;</code> text".</p>
+
+<p>A style class can be made even more generic by omitting an element designation altogether. A modification of the previous example yields <code>.colorful {color: red}</code> (don't forget the '.' character), a style class which can apply to <em>any</em> element. This change still allows the <code>&lt;em&gt;</code> tag be made colorful as in the previous example: <code>&lt;em class="colorful"&gt;</code>emphasized<code>&lt;/em&gt;</code>. Furthermore, the class can be applied to other elements, such as the <code>&lt;p&gt;</code> tag: <code>&lt;p class="colorful"&gt;</code>emphasized<code>&lt;/em&gt;</code> would assure that all the text in the specified paragraph appeared in the color red. Note, however, that the text would not appear in italics, since the <code>&lt;p&gt;</code> tag does not have an italic style by default, as does the <code>&lt;em&gt;</code> tag.</p>
+
+<h3 id="linkingstylesheets">Linking to Style Sheets</h3>
+
+<p>As we've seen, there are several places where we can store style information, from the most specific to the most general:</p>
+
+<ol>
+	<li>By putting style information in an element's <code>style</code> attribute.</li>
+	<li>By specifying a style class in an element's <code>class</code> attribute.</li>
+	<li>By defining styles in a <code>&lt;style&gt;</code> element inside the document <code>&lt;head&gt;</code>.</li>
+	<li>By defining styles in separate style sheet file linked to the document.</li>
+</ol>
+
+<p>The last method, linking to an external style sheet, has only been touched upon briefly. Using this method is straightforward: simply take the style information from inside the <code>&lt;style&gt;</code> element and place it inside a separate file (preferably with a ".css" extension). The entire <code>&lt;style&gt;</code> element can then be removed, and the document can simply specify that it uses the external stylesheet.</p>
+
+<p>By placing style information in a separate file, we've arrived at our ultimate goal of separating content from presentation. If there are multiple documents in a given book, the style information does not have be be duplicated inside each document; each document can rather <dfn>link</dfn> to one style sheet, which contains all relevant presentation information. Furthermore, a book's style can be changed simply by making the document link to another style sheet. To carry on the example at the beginning of this chapter, if Happy Publishing Company decides it wants to redesign the appearance of its entire selection of books, none of the books' contents need to be changed. Instead, Happy can simply supply an updated style sheet.</p>
+
+<h4 id="linkelement">Linking Style Sheets with the <code>&lt;link&gt;</code> Element</h4>
+
+<p>There are several ways to actually link a style sheet to a document, reflecting the evolution of HTML and markup languages in general. When HTML first allowed style sheets, it specified a <code>&lt;link&gt;</code> element that appears inside the <code>&lt;head&gt;</code> element in place of <code>&lt;style&gt;</code>. After moving our style information out of our sample document, our style link information might look like this:</p>
+
+<blockquote><code>&lt;link href="karl.css" type="text/x-oeb1-css"&gt;</code></blockquote>
+
+<p>As before, the <code>href</code> attribute specifies the style sheet to which the document is linking. The <code>type</code> attribute specifies the type of the style sheet. Although normal CSS style sheets have the type <code>text/css</code>, OEB requires that your standard style sheet have the type <code>text/x-oeb1-css</code> to indicate it meets the modified requirements of OEB style information.</p>
+
+<p>Using <code>&lt;link&gt;</code> will make your document compatible with HTML and allow your style information to show up in a typical HTML browser. The <code>&lt;link&gt;</code> tag is not, however, a standard way of linking XML documents in general, which is why OEB allows (and the authors of this work recommend) another linking mechanism which is standardized for XML.</p>
+
+<h4 id="linkxml">Linking Style Sheets with XML</h4>
+
+<p>XML now defines a standard method of linking style sheets to any XML document, which includes OEB documents. This method was still being standardized while the OEB Publication Structure specification was first being written, and that's why OEBPS 1.0 does not give examples of XML style linking. However, on 29 June 1999, version 1.0 of "Associating Style Sheets with XML documents" became an official W3C recommendation, and can be found at <a href="http://www.w3.org/TR/xml-stylesheet/">http://www.w3.org/TR/xml-stylesheet/</a>. This new development was unfortunately missed as OEB was released, so the OEB specification still states that the final form of XML style association has yet to be finalized.</p>
+
+<p>With the final recommendation of XML style association by the W3C, we can recommend that all OEB books use this method for linking to style sheets. Doing so will ensure that OEB works are standard XML documents that can endure as older versions of HTML fade. Using the XML style association mechanism is very similar to the HTML method:</p>
+
+<blockquote><code>&lt;?xml-stylesheet href="karl.css" type="text/x-oeb1-css"?&gt;</code></blockquote>
+
+<p>The attributes here are identical to those in the <code>&lt;link&gt;</code> element, and have the same usage. The location in the document, however, is different: the <code>&lt;?xml-stylesheet&gt;</code> instruction appears before the <code>&lt;html&gt;</code> element.</p>
+
+<h3 id="review">Review</h3>
+
+<h4 id="summary">Summary</h4>
+<ul>
+	<li>OEB allows style sheets to be defined which specify how parts of an OEB document should be displayed or rendered.</li>
+	<li>Style sheets, when correctly used, help separate the content of a document from its presentation information.</li>
+	<li>OEB by default uses a modified form of CSS to specify style information.</li>
+	<li>A particular CSS style consists of a selector (such as <code>em</code>) and a style declaration which consists of one or more properties (e.g. <code>color:</code>) and associated values (e.g. <code>red</code>), such as <code>em {color: red}</code>.</li>
+	<li>A style can specify a style class that can be used for particular elements inside the <code>class</code> attribute. The style <code>em.colorful {color: red}</code>, for example, can be used with a particular <code>&lt;em&gt;</code> element: <code>&lt;em class="colorful"&gt;</code>...<code>&lt;/em&gt;</code>.</li>
+	<li>Although not normally recommended, style information can be specified for a particular element inside its <code>style</code> attribute, such as <code>&lt;em style="color: red"&gt;</code>...<code>&lt;/em&gt;</code>.</li>
+	<li>External style sheets can be associated with the document using the <code>&lt;link&gt;</code> element, a carryover from HTML, inside the <code>&lt;head&gt;</code> element.</li>
+	<li>The recommended standard way for associating a style sheet with a document is to instead use the <code>&lt;?xml-stylesheet&gt;</code> instruction before the <code>&lt;head&gt;</code> element.</li>
+</ul>
+
+<h4 id="cssproperties">CSS Properties</h4>
+<ul>
+	<li><code>font-style:</code> Specifies the style of the font; although several values are available, we only addressed <code>italic</code>.</li>
+	<li><code>color:</code> Specifies the color of the font; although several values are available, we only addressed <code>red</code>.</li>
+</ul>
+
+<h3 id="exampleoebdocument">Completed Example OEB Document with Styles (<code>karl.html</code>)</h3>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;?xml-stylesheet href="karl.css" type="text/x-oeb1-css"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl. Karl had three siblings: Kris, Krista, and Karla. Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age, Karl constantly ran into trouble at the dinner table.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<h3 id="examplestylesheet">Completed Example Style Sheet (<code>karl.css</code>)</h3>
+
+<blockquote>
+  em {color: red}
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter4.html
@@ -1,0 +1,442 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 4</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter4">4. Essential OEB Elements</h2>
+
+<p>You now know the minimum structural requirements of creating a publication in OEB format. You're beginning to understand some of the reasoning behind latest directions of information storage formats such as XML, which OEB is based on. Right now, you could place almost any work in a few OEB documents and an OEB package, and it would at least be legal OEB and work with a compliant OEB reading system. You also know how to create style sheets and associate them with your documents.</p>
+
+<p>What you've learned so far will work fine for your one-paragraph masterpiece. But once you try to use OEB to create a slightly longer sequel, you'll probably very soon run into some very real needs: "How do I display lists?" "How do I change the font?" "How so I create links from one section of my book to another?" The OEB Publication Structure has some very real answers to these questions. Even better yet, since OEB is built upon XML, the following chapters will show you how to create your own answers in areas that OEB does not yet address.</p>
+
+<p>You've had a glance at a few elements defined by OEB, such as <code>&lt;p&gt;</code>, <code>&lt;em&gt;</code> and <code>&lt;dfn&gt;</code>. OEB has a substantial number of other tags already defined for you to use; obviously, you'll need to know at least some of the others to do anything useful with OEB. We'll now look at essential elements and styles that you'll need in day-to-day use of OEB. If you've already started putting together an OEB publication, hopefully we'll answer some of the issues you've already encountered. Otherwise, we'll get a lot of common questions out of the way and prepare you for the real-world OEB creation project found in the next chapter.</p>
+
+<p>It's important to note that the OEB elements discussed here are a basic set of elements defined by OEB. OEB is flexible enough to allow extended documents that include user-defined elements, and this process is likely to be enhanced even more in future OEB versions. Creating user-defined elements is beyond the scope of this current edition, but will likely be addressed in an upcoming version of this book.</p>
+
+<h3 id="inlineelements">Inline Elements</h3>
+
+<p>Although XML allows any number of elements to be defined, OEB has defined a certain set of elements to be used in documents. You've seen and used a few of those, such as <code>&lt;p&gt;</code>, <code>&lt;em&gt;</code> and <code>&lt;dfn&gt;</code>. Besides defining which tags can be used, OEB also specifies the location and contexts in which these elements can appear. You've probably understood intuitively, for example, that emphasized text goes inside a paragraph, like this:</p>
+
+<blockquote><code>&lt;p&gt;</code>This is <code>&lt;em&gt;</code>emphasized<code>&lt;/em&gt;</code> text.<code>&lt;/p&gt;</code></blockquote>
+
+<p>You probably didn't even consider putting a paragraph inside of emphasized text:</p>
+
+<blockquote><strong>Illegal!</strong> <code>&lt;p&gt;</code>This is <code>&lt;em&gt;</code>emphasized text with a <code>&lt;p&gt;</code>paragraph<code>&lt;/p&gt;</code> inside<code>&lt;/em&gt;</code> the emphasized text.<code>&lt;/p&gt;</code></blockquote>
+
+<p>As you might have guessed, this sort of construction is not allowed. The elements <code>&lt;em&gt;</code> and <code>&lt;dfn&gt;</code> can only appear inside paragraphs (and lists and other similar elements), and are therefore considered <em>inline</em> elements. Those are the elements we'll examine here.</p>
+
+<div class="sidebar" id="xmlcontentmodels">
+<h4 class="sidebarTitle">More Information: XML Content Models</h4>
+
+<p>XML could be considered a general markup language that acts as a toolkit for creating other markup languages. OEB uses XML to create its own markup language called the OEB Publication Structure. OEB uses XML not only to create a set of elements to be used (the <dfn>tag set</dfn>), but also to specify where the elements may appear. The specification of the correct locations of elements is called a <dfn>content model</dfn>.</p>
+
+<p>HTML uses a very lenient content model; a web browser will read HTML files that have elements that appear just about anywhere. This is not only notoriously hard to process, it also results in many ambiguities in what was actually meant by the author of the document. Since we'd like to follow the trend in encoding data and meaning into documents, this ambiguity is not acceptable.</p>
+
+<p>The content model used by OEB is therefore more strict than traditional HTML, and closely follows <a href="http://www.w3.org/TR/xhtml1/">XHTML</a>, a new version of HTML created specifically to be used with XML. This means that some constructs which could be used in HTML are not allowed in OEB. For example, the inline element <code>&lt;em&gt;</code> could be used in HTML to make several paragraphs emphasized:</p>
+
+<blockquote><strong>Legal HTML, Illegal OEB:</strong><br />
+	<code>&lt;em&gt;</code><br />
+	<code>&lt;p&gt;</code>Paragraph 1<code>&lt;/p&gt;</code><br />
+	<code>&lt;p&gt;</code>Paragraph 2<code>&lt;/p&gt;</code><br />
+	<code>&lt;/em&gt;</code>
+</blockquote>
+
+<p>Since <code>&lt;em&gt;</code> is an inline element, this will not work in an OEB document. Fixing this problem is simple, however: just bring the <code>&lt;em&gt;</code> back inside each <code>&lt;p&gt;</code> element:</p>
+
+<blockquote><strong>Legal HTML, Legal OEB:</strong><br />
+	<code>&lt;p&gt;&lt;em&gt;</code>Paragraph 1<code>&lt;/em&gt;&lt;/p&gt;</code><br />
+	<code>&lt;p&gt;&lt;em&gt;</code>Paragraph 2<code>&lt;/em&gt;&lt;/p&gt;</code><br />
+</blockquote>
+
+<p>The actual OEB content model is not discussed explitely in the OEB specification, but it is defined in the OEB XML Document Type Declaration (DTD), which will be discussed later. Many times, such as in the case of the <code>&lt;em&gt;</code> element, the you can probably tell intuitively where an element can appear. In all cases, OEB validation software will be able to check your document against the OEB DTD and tell you whether or not your document has all its elements in the correct places.</p>
+
+</div>
+
+<h4 id="emelement">The <code>&lt;em&gt;</code> Element</h4>
+
+<p>You've already seen the <code>&lt;em&gt;</code> element &mdash; perhaps more than you've wanted. It bears repeating that the <code>&lt;em&gt;</code> element should be used instead of the <code>&lt;i&gt;</code> (italics) element in most cases, designating that the text should be emphasized but not specifying how the emphasized text should appear. An example of how specific text could be emphasized might be this:</p>
+
+<blockquote><code>&lt;p&gt;</code>Although the venture capital company seemed <code>&lt;em&gt;</code>really<code>&lt;/em&gt;</code> interested in our project, perhaps the representative only <code>&lt;em&gt;</code>seemed<code>&lt;/em&gt;</code> really interested.<code>&lt;/p&gt;</code></blockquote>
+
+<blockquote>Although the venture capital company seemed <span style="font-style: italic">really</span> interested in our project, perhaps the representative only <span style="font-style: italic">seemed</span> really interested.</blockquote>
+
+<h4 id="strongelement">The <code>&lt;strong&gt;</code> Element</h4>
+
+<p>The <code>&lt;strong&gt;</code> element is similarly to the <code>&lt;em&gt;</code> in that it specifies that a section of text should be emphasized, but is used in most cases where bold text would be used. In fact, the default rendering of the <code>&lt;strong&gt;</code> element is using a bold font, although we've seen that any default rendering can be changed using styles.</p>
+
+<p>Also similar to the <code>&lt;em&gt;</code> tag, OEB has a carryover tag from HTML that functions similar to the <code>&lt;strong&gt;</code> tag but that specifies actual formatting: the <code>&lt;b&gt;</code> tag, representing bold text. For reasons we've explained earlier, we don't recommend using tags that specify presentation information within a document itself. Therefore, you should in most cases use <code>&lt;strong&gt;</code> rather than <code>&lt;b&gt;</code> whenever marking up text usually rendered in bold.</p>
+
+<blockquote><code>&lt;p&gt;</code>The Hindi letter "ka" is pronounced similarly to the first part of the English word, "<code>&lt;strong&gt;</code>cu<code>&lt;/strong&gt;</code>p".<code>&lt;/p&gt;</code></blockquote>
+
+<blockquote>The Hindi letter "ka" is pronounced similarly to the first part of the English word, "<span style="font-weight: bolder">cu</span>p".<code>&lt;/p&gt;</code></blockquote>
+
+<h4 id="dfnelement">The <code>&lt;dfn&gt;</code> Element</h4>
+
+<p>We've already discussed using the <code>&lt;dfn&gt;</code> element to represent a word or words that are being defined for the first time.</p>
+
+<blockquote><code>&lt;p&gt;</code>The Hindi alphabet is usually specified as being a <code>&lt;dfn&gt;</code>syllabary<code>&lt;/dfn&gt;</code>, since each letter of a word represents a syllable.<code>&lt;/p&gt;</code></blockquote>
+
+<blockquote>The Hindi alphabet is usually specified as being a <dfn>syllabary</dfn>, since each letter of a word represents a syllable.</blockquote>
+
+<h4 id="codeelement">The <code>&lt;code&gt;</code> Element</h4>
+
+<p>OEB has several inline elements, some of which you'll use and some of which you'll never need unless creating certain esoteric documents. We mention that <code>&lt;code&gt;</code> element here because, since OEB was created by the computer-using community, it's likely that the first applications of OEB (this work included) will refer to computer programs or software.</p>
+
+<p>The <code>&lt;code&gt;</code> element was created to represent a section of computer program code, or data that should be entered by the user. This element is usually rendered in a monospaced font such as Courier, but as we've repeatedly stressed, you can change this behavior using styles.</p>
+
+<blockquote><code>&lt;p&gt;</code>In many programming languages, the statement <code>&lt;code&gt;</code>variable=16<code>&lt;/code&gt;</code> represents an assignment operation, assigning the value on the right to the variable on the left of the equals sign.<code>&lt;/p&gt;</code></blockquote>
+
+<blockquote>In many programming languages, the statement <code>variable=16</code> represents an assignment operation, assigning the value on the right to the variable on the left of the equals sign.</blockquote>
+
+<h4 id="citeelement">The <code>&lt;cite&gt;</code> Element</h4>
+
+<p>Many nonfiction works include information from other sources, and when they do so it is proper to cite the source from which the material was derived. The <code>&lt;cite&gt;</code> provides a standard way to indicate a cited source.</p>
+
+<blockquote>
+	<code>&lt;p&gt;</code>"The UN, like the League of Nations before it, was designed around the concept of state sovereignty" (<code>&lt;cite&gt;</code>Calvocoressi 1996<code>&lt;/cite&gt;</code>).
+</blockquote>
+
+<blockquote>
+	"The UN, like the League of Nations before it, was designed around the concept of state sovereignty" (<cite>Calvocoressi 1996</cite>).
+</blockquote>
+
+<h4 id="spanelement">The <code>&lt;span&gt;</code> Element</h4>
+
+<p>Our discussion of inline elements has thus far assumed that, if you looked hard enough, you could find an OEB element that represented more or less the meaning of the section of text to which you're referring. We've stressed that you can always later change the style of the particular element you chose.</p>
+
+<p>What if you can't find an element that's appropriate, but still want to specify a style for a section of text? OEB provides (again borrowed from HTML) a generic element, <code>&lt;span&gt;</code>, that has no meaning other than to specify a section of text. The <code>&lt;span&gt;</code> element has the normal <code>style</code> and <code>class</code> attributes, allowing you to specify style for an arbitrary section of text. For example, imagine you want to somehow highlight the vowels in an alphabet, but don't want to use <code>&lt;em&gt;</code> because you'd like to use some separate style. You could always create a specific style class for <code>&lt;em&gt;</code>, but you might rather specify style information from scratch using <code>&lt;span&gt;</code>, like this:</p>
+
+<blockquote><code>&lt;p&gt;</code>English Alphabet: <code>&lt;span style="color: red"&gt;</code>A<code>&lt;/span&gt;</code> B C D <code>&lt;span style="color: red"&gt;</code>E<code>&lt;/span&gt;</code> F G...<code>&lt;/p&gt;</code></blockquote>
+
+<blockquote>English Alphabet: <span style="color: red">A</span> B C D  <span style="color: red">E</span> F G...</blockquote>
+
+<p>You should immediately protest that actual style information should not be included in the document itself. A slight modification resolves this problem and makes the use of <code>&lt;span&gt;</code> acceptable. First specify a style class, such as <code>.vowel {color:red}</code>, and then use this class in the <code>&lt;span&gt;</code> element:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>.vowel {color:red}</code></blockquote>
+
+<blockquote><strong>Document:</strong> <code>&lt;p&gt;</code>English Alphabet: <code>&lt;span class="vowel"&gt;</code>A<code>&lt;/span&gt;</code> B C D <code>&lt;span class="vowel"&gt;</code>E<code>&lt;/span&gt;</code> F G...<code>&lt;/p&gt;</code></blockquote>
+
+<blockquote>English Alphabet: <span style="color: red">A</span> B C D  <span style="color: red">E</span> F G...</blockquote>
+
+<div class="sidebar" id="customelements">
+<h4 class="sidebarTitle">More Information: Creating Custom Elements</h4>
+
+<p>Using the <code>&lt;span&gt;</code> element in the way we've just outlined is remarkably close to creating a new element named <code>&lt;vowel&gt;</code>; instead, we've used the <code>&lt;span&gt;</code> element with a style class named "vowel", which ends of serving the same function.</p>
+
+<p>The <code>&lt;span&gt;</code> element was introduced in HTML before XML was available, and is therefore the only way standard HTML can add what may be called pseudo-elements into an HTML document. XML, on the other hand, includes a method (which will be discussed later) for creating real custom elements from scratch. Since OEB is based on XML, it does allow one to create something called an <dfn>extended</dfn> OEB document which includes custom-built tags, meaning that the <code>&lt;span&gt;</code> element is little more than an a clumsy, inefficient way to do something that is much more elegantly done using standard XML techniques.</p>
+
+<p>Why then does OEB include the <code>&lt;span&gt;</code> element? One of the reasons should be quite familiar by now: since this tag is included in HTML, it was brought over into OEB so that standard HTML pages could be converted to OEB with minimal modification. The creation of custom elements using XML is furthermore more difficult than using the <code>&lt;span&gt;</code> element. Another reason should also be familiar: custom XML elements do not display correctly on HTML browsers.</p>
+
+<p>The majority of the OEB Authoring Group therefore felt it a higher priority to quickly release a specification that would bring about consensus in a quickly growing eBook industry than to force the adoption of barely released technologies such as custom XML elements. Happily, the OEBPS 1.0.1 still allows those who wish to follow useful standardization trends can still use XML to create custom elements. A discussion of how this is done is outside the scope of the current release of this book.</p>
+
+</div>
+
+<h4 id="brelement">The <code>&lt;br&gt;</code> Element</h4>
+
+<p>You learned in an earlier chapter that multiple adjacent whitespace characters, such as spaces and line breaks, are always replaced with a single space character before the text is displayed. This seems reasonable until you encounters a situation in which you'd like to display text on a separate line, perhaps like this:</p>
+
+<blockquote>
+<code>&lt;p&gt;</code>...Karl had three siblings:<br />
+Kris<br />
+Krista<br />
+Karla<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>As you'll soon realize, if you've forgotten our earlier discussion about whitespace, what is displayed is not exactly what was entered:</p>
+
+<blockquote>...Karl had three siblings: Kris Krista Karla</blockquote>
+
+<p>You could always put the name of each of Karl's siblings in a separate paragraph, but they aren't really separate paragraphs. Besides, you don't want to risk their being formatted like paragraphs when displayed (either indented or separated by blank lines, depending on the reading system).</p>
+
+<p>The real solution here is to use a separate list element, which you'll learn about later in this chapter. But you might insist that these items should go <em>inside</em> the paragraph, and you want to choose where the line breaks appear. A better example might be a poem, in which you'd like to guarantee that a line break appears after each line:</p>
+
+<blockquote>
+<code>&lt;p&gt;</code>There was a young creature named Karl<br />
+Whose siblings would say with a snarl<br />
+We'll share what we eat:<br />
+Just some bones from the meat<br />
+And a little of "ic" from the "garl".<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>Here again, it would be more preferable if there were a <code>&lt;poem&gt;</code> element in OEB. There isn't. Short of creating your own tag for this situation, OEB provides an element that specifies that a line break should appear: the <code>&lt;br&gt;</code> element.</p>
+
+<p>The <code>&lt;br&gt;</code> element is different than the elements examined so far in that it cannot have content; since it signifies a line break at a particular location in the text, it doesn't display text and has no need to hold text. The <code>&lt;br&gt;</code> element is therefore referred to as an <dfn>empty element</dfn>. You might expect the <code>&lt;br&gt;</code> element to simply have a beginning and ending tag with nothing in between (<code>&lt;br&gt;</code><code>&lt;/br&gt;</code>). However, XML specifies a special format for empty elements by combining the beginning and ending tags into one tag: <code>&lt;br /&gt;</code></p>
+
+<ul>
+	<li id="emptyElement"><strong>XML Rule 6:</strong> (<em>Empty Elements</em>) An element that cannot have text between its beginning and ending tags is classified as a <dfn>empty element</dfn>, and has a special form of a single tag with the element name followed by a slash (/): <code>&lt;name /&gt;</code></li>
+</ul>
+
+<p><strong>Important:</strong> While not required by XML, OEB specifies that all empty tags must have a space between the tag name and the slash character. This is to ensure that OEB documents can be displayed more or less correctly in HTML browsers.</p>
+
+<p>The <code>&lt;br&gt;</code> element might therefore be used in a re-write of Lewis Carroll's <i>Alice's Adventures in Wonderland</i>:</p>
+
+<blockquote>
+<code>&lt;p&gt;</code>Alice fell down the rabbit hole...<code>&lt;br /&gt;</code><br />
+Down...<code>&lt;br /&gt;</code><br />
+Down...<code>&lt;br /&gt;</code><br />
+Down...<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>This would be correctly displayed as expected:</p>
+
+<blockquote>
+Alice fell down the rabbit hole...<br />
+Down...<br />
+Down...<br />
+Down...
+</blockquote>
+
+<p>The <code>&lt;br&gt;</code> element, however, has the potential of being abused and overused. In most places, items might more appropriately be placed in separate paragraphs, or perhaps in a list. In keeping with our goal of using markup to encode meaning into a document, it would probably be better to place a poem inside a <code>&lt;poem&gt;</code> element or something similar, although in this case we would have to define such an element before it could be used. The use of <code>&lt;br&gt;</code> to show the plight of Alice, above, is certainly the easiest and perhaps even an appropriate way to create the desired visual effect. We'd just like to encourage you to make sure that the <code>&lt;br&gt;</code> element is appropriate for the situation before using it.</p>
+
+<h4 id="aelement">The <code>&lt;a&gt;</code> Element</h4>
+
+<p>The anchor element, <code>&lt;a&gt;</code>, was first made popular by HTML. Since the <code>&lt;a&gt;</code> element is responsible for linking documents and sections of documents, this element is responsible for the "hypertext" part of HTML. Without <code>&lt;a&gt;</code>, HTML might otherwise have only been "TML", a text markup language with no linking capabilities. The OEB Publication Structure incorporated <code>&lt;a&gt;</code> into its tag set with hardly any modifications to its fundamental form.</p>
+
+<p>With its linking capabilites, <code>&lt;a&gt;</code> is the first tag we've discussed that starts to allow static pages in a book to come to life, to allow interaction with the user. The Open eBook specification begins with the assumption that a user will be provided with a paging function that will allow traversal through the contents of a book. The most fundamental purpose for hypertext anchors might be to link to reference sections or a glossary; however, the <code>&lt;a&gt;</code> element allows the author to provide many more complex navigation capabilites, allowing readers to even choose an arbitrary path through the book as they read.</p>
+
+<p>The most important attribute of the <code>&lt;a&gt;</code> element is <code>href</code>. As you've seen in elements both in the OEB package and in OEB style sheets, the <code>href</code> attribute specifies a "hypertext reference" location. Usually, the value of this attribute refers to a file; in other instances is can refer to a specific location within a file.</p>
+
+<p>Let's revisit a section from the first work we created.</p>
+
+<blockquote>
+	<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young blovjus named Karl.<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>Now, some uninformed readers may not know what a "blovjus" is. You may wish to provide a definition a reader can read. Having a definition in the text is unacceptable; you don't want to bother your many readers who know exactly what a blovjus is and do not want to be told again. Instead, you elect to place the definition in a separate OEB document file named <code>blovjus.html</code>:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;p&gt;&lt;strong&gt;</code>blovjus<code>&lt;/strong&gt;</code> A strange, mythical creature which lived many years ago; sometimes it stole supper from its siblings.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<p>Using the <code>&lt;a&gt;</code> tag, it's a simple job to link "blovjus" in the text to its definition:</p>
+
+<blockquote>
+	<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the earth, the seas were beginning to form, and humans had yet to appear, there lived a young <code>&lt;a href="blovjus.html"&gt;</code>blovjus<code>&lt;/a&gt;</code> named Karl.<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>Anchor elements can also be used to mark, or <dfn>anchor</dfn>, a section of text in a document (although this function is less important since each element in OEB contains an <code>id</code> attribute). This way, two <code>&lt;a&gt;</code> elements can be used together, one to mark a location and another to link to that location. This allows links not only to files, but to a specific location in a file. The tag serving as an anchor will use the <code>id</code> tag to provide a name for the anchor. The tag serving as a link will use the <code>href</code> as before to refer to a file, except that a pound sign (#) will be appended followed by the id of the anchor which serves as the link <dfn>target</dfn>.</p>
+
+<p>This is actually quite simple in practice. Assume that you have so many uninformed readers that you've created an entire glossary with many definitions. This glossary replaces the <code>blovjus.html</code> document file you created earlier, containing "blovjus" and other terms:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;p&gt;&lt;a id="blovjus"&gt;&lt;strong&gt;</code>blovjus<code>&lt;/strong&gt;&lt;/a&gt;</code> A strange, mythical creature which lived many years ago; sometimes it stole supper from its siblings.<code>&lt;/p&gt;</code><br />
+	<code>&lt;p&gt;&lt;a id="earth"&gt;&lt;strong&gt;</code>earth<code>&lt;/strong&gt;&lt;/a&gt;</code> The third planet from the sun.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<p>Note that we've placed an <code>&lt;a&gt;</code> element around each term to serve as an anchor to mark the link targer. We've specified a name for each target using the <code>id</code> attribute. Here, we've used names that match the terms we're defining, but we could have used any names as long as they are unique and we use the same names in the links. Here's what the links look like in our original file:</p>
+
+<blockquote>
+	<code>&lt;p&gt;</code>Years ago, when strange creatures ruled the <code>&lt;a href="glossary.html#earth"&gt;</code>earth<code>&lt;/a&gt;</code>, the seas were beginning to form, and humans had yet to appear, there lived a young <code>&lt;a href="glossary.html#blovjus"&gt;</code>blovjus<code>&lt;/a&gt;</code> named Karl.<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>In each link, we specify the document in which the definitions reside (<code>glossary.html</code> in this example), followed by a pound sign (#) and then the ID of the appropriate definition (here, <code>earth</code> and <code>blovjus</code>). It is here that we must always make sure the name in the <code>href</code> attribute always matches the name in the target anchor tag's <code>id</code> attribute.</p>
+
+<p>This application of the anchor tag as a true anchor is less useful since OEB provides an <code>id</code> attribute for most elements. Instead of adding an <code>&lt;a&gt;</code> element and <code>id</code> attribute to serve as an anchor, you can instead add an <code>id</code> to the element to which you want to link. The above example, then, would appear like this:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;p id="blovjus"&gt;&lt;strong&gt;</code>blovjus<code>&lt;/strong&gt;</code> A strange, mythical creature which lived many years ago; sometimes it stole supper from its siblings.<code>&lt;/p&gt;</code><br />
+	<code>&lt;p id="earth"&gt;&lt;strong&gt;</code>earth<code>&lt;/strong&gt;</code> The third planet from the sun.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<p>This version of specifying a link target is the recommended one &mdash; there is no need to specify an anchor for the target because almost any OEB element can contain an ID attribute. The <code>&lt;a&gt;</code> element will still be needed, of course, to link <em>to</em> the referenced location.</p>
+
+<p>Anchor tags are the first step in leveraging the capabilities of electronic books which static books do not have. Hypertext linking has many uses, from creating tables of contents to providing user-initiated changes in a plot. We'll address some of these uses in the following chapters.</p>
+
+<h3 id="blockelements">Block Elements</h3>
+
+<p>Block elements could be considered the opposite of inline elements. They are the enclosing elements within which inline elements are placed. That is, inline elements have to have some element to be inside; this element is ultimately a block element (although inline elements can appear inside other inline elements). You've already seen one example of a block element, the <code>&lt;p&gt;</code> element representing a paragraph. Block elements could also be classified as elements that automatically have a line break before and after them; they might therefore also be appropriately called "out-of-line" elements.</p>
+
+<p>Traditionally, block elements in HTML also had a blank line immediately before and immediately after them, but OEB reading systems may prefer to display block elements differently, indenting the first line of text in a <code>&lt;p&gt;</code> element, for example.</p>
+
+<h4 id="pelement">The <code>&lt;p&gt;</code> Element</h4>
+
+<p>The <code>&lt;p&gt;</code> element is probably the most straightforward block-level element, and probably the most common. Every paragraph in OEB should be surrounded by <code>&lt;p&gt;</code>...<code>&lt;/p&gt;</code>. As we've certainly used plenty of paragraphs up to this point, we won't give any examples here. Instead, we'll just give one precaution: be careful not to <em>	overuse</em> the <code>&lt;p&gt;</code> tag. Make sure the block of text you're marking up is really a paragraph and not, say, a list or a heading, both of which are covered in the sections below.</p>
+
+<h4 id="headingelements">The <code>&lt;h1&gt;</code>...<code>&lt;h6&gt;</code> Heading Elements</h4>
+
+<p>Perhaps the second most common block element is actually a group of similar elements: <code>&lt;h1&gt;</code>, <code>&lt;h2&gt;</code>, <code>&lt;h3&gt;</code>, <code>&lt;h4&gt;</code>, <code>&lt;h5&gt;</code>, and <code>&lt;h6&gt;</code>. These elements represent different levels of headings in your document.</p>
+
+<p>What does "heading" mean? It represents whatever you want it to represent. You could use <code>&lt;h1&gt;</code> to represent the title of your book on the title page, and use <code>&lt;h2&gt;</code> to represent the title of each chapter. Alternatively, you could use <code>&lt;h1&gt;</code> to represent each chapter title, <code>&lt;h2&gt;</code> to represent each chapter subtitle, and use a completely separate style class (or custom XML element) to represent the book title on the title page.</p>
+
+<p>All this is at your discretion because the heading elements do not directly correspond to any particular division of a book; they do not have a particular meaning, such as "chapter title" or "subtitle". The only thing that you can be sure of is that the default rendering method for each higher-numbered heading (such as <code>&lt;h1&gt;</code>) will be larger than a lower-numbered heading (such as <code>&lt;h2&gt;</code>).</p>
+
+<p>The lack of a particular meaning for the <code>&lt;hX&gt;</code> elements makes them slightly less useful than one might expect. Some early eBook reading systems assigned meanings to the <code>&lt;hX&gt;</code> elements, allowing the reading system to automatically find and understand when chapters begin, for example. Other markup languages have specific tags that represent chapters and other divisions. OEBPS 1.0, however, has no elements that specifically indicate book structure, so you'll have to make do with the heading elements. While OEB may introduce such elements in the future, for now using the heading elements is highly preferable to specifying the styles of headings manually, of course. Just remember that the meanings assigned to the heading elements are completely up to you. You might choose, for example, to use them like this:</p>
+
+<blockquote>
+	<code>&lt;h1&gt;</code>Karl the Creature<code>&lt;/h1&gt;</code><br />
+	<code>&lt;h2&gt;</code>Chapter 1: Karl as a Kid<code>&lt;/h2&gt;</code><br />
+	<code>&lt;p&gt;</code>Years ago...<code>&lt;/p&gt;</code><br />
+</blockquote>
+
+<blockquote>
+	<h1>Karl the Creature</h1>
+	<h2>Episode 1: Karl as a Kid</h2>
+	<p>Years ago...</p>
+</blockquote>
+
+<h4 id="lists">Lists, Ordered (<code>&lt;ol&gt;</code>) and Unordered (<code>&lt;ul&gt;</code>)</h4>
+
+<p>Almost every work, especially non-fiction educational works (like this one), have instances in which a list of items must be displayed. Many times the items in these lists are shown in a particular order, each item with a particular number. These lists are called <dfn>ordered lists</dfn>:</p>
+
+<blockquote>
+The names of the first three planets from the sun, in order, are:<br />
+1. Mercury<br />
+2. Venus<br />
+3. Earth
+</blockquote>
+
+<p>Not only must the numbers of each item in the list be carefully considered, care must be taken to ensure that the list is formatted correctly. Whenever the list is modified or reordered, care must be taken in modifying the numbering involved. Furthermore, there's no indication encoded in the file that this is a list; no meaning has been added to text that a computer or data-retrieval program could extract.</p>
+
+<p>OEB provides elements that solves all of these problems. In this case, we can use markup to specify that we have an ordered list (using the <code>&lt;ul&gt;</code> element), and that each item in the list is (as you would expect) a list item (using the <code>&lt;li&gt;</code> element). Ordered lists in OEB therefore consist of two separate elements, <code>&lt;ol&gt;</code> and <code>&lt;li&gt;</code>, used in conjunction like this:</p>
+
+<blockquote>
+<code>&lt;p&gt;</code>The names of the first three planets from the sun, in order, are:<code>&lt;/p&gt;</code><br />
+<code>&lt;ol&gt;</code><br />
+<code>&lt;li&gt;</code>Mercury<code>&lt;/li&gt;</code><br />
+<code>&lt;li&gt;</code>Venus<code>&lt;/li&gt;</code><br />
+<code>&lt;li&gt;</code>Earth<code>&lt;/li&gt;</code><br />
+<code>&lt;/ol&gt;</code>
+</blockquote>
+
+<blockquote>
+<p>The names of the first three planets from the sun, in order, are:</p>
+<ol>
+<li>Mercury</li>
+<li>Venus</li>
+<li>Earth</li>
+</ol>
+</blockquote>
+
+<p>Notice two things: first, the number of each list item does not need to be specified; it is supplied automatically when the list is displayed. Second, the introductory statement, "The names of the first three planets...", is not technically part of the list, so it is not placed within the <code>&lt;ol&gt;</code>...<code>&lt;/ol&gt;</code> tags. The OEB publication structure allows you to specify the formatting, the type, and even a language-specific representation of the numbers used in a list.</p>
+
+<p>Some types of lists do not have numbers associated with them; they are <dfn>unordered lists</dfn>. If you're listing items in a grocery list, for example, you may not care about the order in which they are purchased. You would therefore use the <code>&lt;ul&gt;</code> for the unordered list, which functions exactly like the <code>&lt;ol&gt;</code> element used for ordered lists:</p>
+
+<blockquote>
+<code>&lt;p&gt;</code>Please purchase the following items:<code>&lt;/p&gt;</code><br />
+<code>&lt;ul&gt;</code><br />
+<code>&lt;li&gt;</code>Bread<code>&lt;/li&gt;</code><br />
+<code>&lt;li&gt;</code>Eggs<code>&lt;/li&gt;</code><br />
+<code>&lt;li&gt;</code>Milk<code>&lt;/li&gt;</code><br />
+<code>&lt;/ul&gt;</code>
+</blockquote>
+
+<blockquote>
+<p>Please purchase the following items:</p>
+<ul>
+<li>Bread</li>
+<li>Eggs</li>
+<li>Milk</li>
+</ul>
+</blockquote>
+
+<p>The default rendering method for unordered lists is to display a small round circle next to each item. You'll learn later how to use styles to modify this behavior. Most importantly, we've specified that the information is actually a list of items, and we can later, if we wish, arbitrarily change the way this list is displayed using styles, without changing the actual text of the document.</p>
+
+<h4 id="divelement">The <code>&lt;div&gt;</code> Element</h4>
+
+<p>The <code>&lt;span&gt;</code> element, as you saw earlier, provided a convenient way to specify style information about an arbitrary set of characters inside a block element. That last aspect somewhat limits its applicability, though: since <code>&lt;span&gt;</code> is an inline element, it can't be used to specify style information for more than one block element. That's why <code>&lt;div&gt;</code> in included in OEB.</p>
+
+<p>The <code>&lt;div&gt;</code> element is the block-level equivalent to the inline <code>&lt;span&gt;</code> span. It has no meaning in itself; its sole purpose is to group several block-level elements for the purpose of applying styles, for example. To see an example of where the <code>&lt;div&gt;</code> element could be applied, let's revisit an example of an inappropriate use of the <code>&lt;em&gt;</code> element:</p>
+
+<blockquote><strong>Illegal:</strong><br />
+	<code>&lt;em&gt;</code><br />
+	<code>&lt;p&gt;</code>Paragraph 1<code>&lt;/p&gt;</code><br />
+	<code>&lt;p&gt;</code>Paragraph 2<code>&lt;/p&gt;</code><br />
+	<code>&lt;/em&gt;</code>
+</blockquote>
+
+<p>As we noted when discussing the OEB content model, the <code>&lt;em&gt;</code> element, being an inline element, cannot enclose the <code>&lt;p&gt;</code> element, a block element. We explained that the <code>&lt;em&gt;</code> element could simply be moved inside the <code>&lt;p&gt;</code>, like this:</p>
+
+<blockquote><strong>Legal OEB:</strong><br />
+	<code>&lt;p&gt;&lt;em&gt;</code>Paragraph 1<code>&lt;/em&gt;&lt;/p&gt;</code><br />
+	<code>&lt;p&gt;&lt;em&gt;</code>Paragraph 2<code>&lt;/em&gt;&lt;/p&gt;</code><br />
+</blockquote>
+
+<p>The same effect could be achieved using the <code>&lt;div&gt;</code> element in a similar manner to that used in the first example. An emphasis style class could be created and applied to a surrounding <code>&lt;div&gt;</code> element:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>.emphasis {font-style: italic}</code></blockquote>
+
+<blockquote><strong>Document:</strong><br />
+	<code>&lt;div class="emphasis"&gt;</code><br />
+	<code>&lt;p&gt;</code>Paragraph 1<code>&lt;/p&gt;</code><br />
+	<code>&lt;p&gt;</code>Paragraph 2<code>&lt;/p&gt;</code><br />
+	<code>&lt;/div&gt;</code>
+</blockquote>
+
+<p>As with the <code>&lt;span&gt;</code> element, the <code>&lt;div&gt;</code> element is another carryover from HTML that allows one to simulate the creation of a custom tag. Also similarly to how the <code>&lt;span&gt;</code> element is used, XML allows true custom elements to be created, making <code>&lt;div&gt;</code>, although convenient, somewhat redundant. It's this convenience that makes <code>&lt;div&gt;</code> quite attractive and perhaps acceptable in some situations. Before using it, however, make sure that a custom XML element wouldn't be more appropriate.</p>
+
+<h4 id="centerelement">The <code>&lt;center&gt;</code> Element (deprecated)</h4>
+
+<p>OEB includes <code>&lt;center&gt;</code> but marks it as <dfn>deprecated</dfn>: its use is allowed so that HTML documents will not require much modification, but its use is discouraged. In fact, the <code>&lt;center&gt;</code> element is mentioned here only because its use has become <em>very</em> popular over the years in HTML documents. We echo the exhortation of the OEBPS specification (and the latest version of HTML) that the <code>&lt;center&gt;</code> element should not be used in new OEB document; explicitly specifying that a section of text should be centered goes against the concept of separation of content and presentation.</p>
+
+<blockquote>
+	<strong>Deprecated:</strong> <code>&lt;center&gt;</code>Chapter 1: Karl as a Kid<code>&lt;/center&gt;</code>
+</blockquote>
+
+<blockquote>
+	<div style="text-align: center">Chapter 1: Karl as a Kid</div>
+</blockquote>
+
+<p>As an alternative, OEB (and HTML) allow text to be centered using styles. Specifically, the <code>text-align</code> property, which we'll discuss later in this chapter, allows a <code>"center"</code> value that gives the desired effect. Using style classes with the <code>&lt;div&gt;</code> element we just discussed might yield something like this:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>.chapterhead {text-align: center}</code></blockquote>
+
+<blockquote><strong>Document:</strong>
+	<code>&lt;div class="chapterhead"&gt;</code>Chapter 1: Karl as a Kid<code>&lt;/div&gt;</code>
+</blockquote>
+
+<p>As is usually the case with <code>&lt;div&gt;</code>, there are better ways to specify which text should be centered. If you're already using <code>&lt;h1&gt;</code> for chapter headings, for example, specifying that the chapter headings should be centered is quite easy using styles, and illustrates how convenient and appropriate style sheets can be:</p>
+
+<blockquote><strong>Style Sheet:</strong> <code>h1 {text-align: center}</code></blockquote>
+
+<blockquote><strong>Document:</strong>
+	<code>&lt;h1&gt;</code>Chapter 1: Karl as a Kid<code>&lt;/h1&gt;</code>
+</blockquote>
+
+<p>Whatever method you choose to use to center text, we encourage you that it not be the <code>&lt;center&gt;</code> element.</p>
+
+<h4 id="blockquoteelement">The <code>&lt;blockquote&gt;</code> Element</h4>
+
+<p>In contrast to the <code>&lt;center&gt;</code> element, <code>&lt;blockquote&gt;</code> is a good example of how elements should encode meaning into a document and assist in separating content from presentation. Many nonfiction works have sentences quoted from other works. If a quote is several sentences or even several paragraphs long, it is usually placed in a separate, indented paragraph or group of paragraphs. The <code>&lt;blockquote&gt;</code> element allows text to be specified as a block of quoted text without worrying how it will be formatted. Usually, the default indented style is acceptable, but this can easily be changed using styles.</p>
+
+<p>The <code>&lt;blockquote&gt;</code> element has one optional attribute, <code>cite</code>, which allows the web address location of the quote to be specified. Note that the inline element with the same name as the attribute, <code>&lt;cite&gt;</code>, is often used in conjunction with the <code>&lt;blockquote&gt;</code> element:</p>
+
+<blockquote>
+	<code>&lt;blockquote cite="http://www.un.org/Overview/rights.html"&gt;</code><br />
+	Everyone is entitled to all the rights and freedoms set forth in this Declaration, without distinction of any kind, such as race, colour, sex, language, religion, political or other opinion, national or social origin, property, birth or other status. Furthermore, no distinction shall be made on the basis of the political, jurisdictional or international status of the country or territory to which a person belongs, whether it be independent, trust, non-self-governing or under any other limitation of sovereignty.
+	(<code>&lt;cite&gt;</code>UN Declaration of Universal Human Rights, Article 2, December 10, 1948<code>&lt;/cite&gt;</code>)<br />
+	<code>&lt;/blockquote&gt;</code>
+</blockquote>
+
+<blockquote cite="http://www.un.org/Overview/rights.html">
+Everyone is entitled to all the rights and freedoms set forth in this Declaration, without distinction of any kind, such as race, colour, sex, language, religion, political or other opinion, national or social origin, property, birth or other status. Furthermore, no distinction shall be made on the basis of the political, jurisdictional or international status of the country or territory to which a person belongs, whether it be independent, trust, non-self-governing or under any other limitation of sovereignty. (<cite>UN Declaration of Universal Human Rights, Article 2, December 10, 1948</cite>)
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter5.html
@@ -1,0 +1,156 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 5</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter5">5. Essential OEB Styles</h2>
+
+<p>You've learned the essentials of styles in OEB, but you would be hard-pressed at this point to put this knowledge to use without knowing which styles are actually allowed. You probably have visions of how you'd like to change the appearance of your document: its fonts, its indentation, even its color. Here we'll address some of the most important style properties available for your use. Keep in mind that OEB style sheets are little more (and a little more less) than a subset of Cascading Style Sheets (CSS); what you'll learn here will in large part be transferable (although somewhat restricted) to CSS as it is used in general.</p>
+
+<h3 id="styleunits">Style Units</h3>
+
+<p>The styles you have seen so far in the examples have been qualitative, specifying whether a particular property applies to a particular section of text. We've seen how to specify italics: the <code>font-style</code> of text is either <code>italic</code> or it isn't. Similarly with color, the CSS <code>color</code> property can take color names such as <code>black</code> and <code>red</code>.</p>
+
+<p>Other style values can be quantitative, specifying numerical values for style properties. There are many cases in which you would want to specify the length, the height, or the width of something such as a font size or an indentation amount. Implicit in each of these cases is a <dfn>unit</dfn> of measurement: if you want a font of size <code>12</code>, does that "12" represent a height of 12 pixels, 12 centimeters, or 12 kilometers?</p>
+
+<p>When a <dfn>length</dfn> (the CSS term for instances of numeric value) is used, CSS requests that you specify a <dfn>unit</dfn>, unless in specific cases which we'll discuss later. A percentage, for example, does not need a unit specified, nor does a property which takes a count of something rather than a measurement. In all other cases, a unit will be used from the following list of those supported by CSS (and by OEB):</p>
+
+<ul>
+	<li><strong><code>px</code></strong> (pixels) The length represents a number of pixels.</li>
+	<li><strong><code>ex</code></strong> (x-height) The length represents multiples of the height of the lowercase letter "x" in the current font.</li>
+	<li><strong><code>em</code></strong> (m-width) The length represents the size of the font. (The name comes from its originally representing multiples of the width of the letter "M" in the current font.)</li>
+	<li><strong><code>pt</code></strong> (points) The length represents a number of points, with one point being equal to 1/72 of an inch.</li>
+	<li><strong><code>cn</code></strong> (centimeters) The length represents a number of centimeters.</li>
+	<li><strong><code>mm</code></strong> (millimeters) The length represents a number of millimeters.</li>
+	<li><strong><code>pc</code></strong> (picas) The length represents a number of picas, with one pica being equal to 12 points.</li>
+</ul>
+
+<p>This list can be used as a short reference; the units themselves will become more straightforward in their actual use.</p>
+
+<h3 id="fontproperties">Font Properties</h3>
+
+<p>CSS font-related properties specify how a portion of text looks: the size, the type family, and the style, for instance. Specifically, we'll consider <code>font-family</code>, <code>font-size</code>, <code>font-style</code>, and <code>font-weight</code>, throwing <code>text-decoration</code>, <code>color</code> and <code>background-color</code> in for good measure.</p>
+
+<h4 id="fontfamilyproperty">The <code>font-family</code> Property</h4>
+
+<p>When you think of changing a font in a word processor, you usually think of specifying its name: "Times New Roman" and "Arial" are common examples. These names do not really specify the entire font itself (remember, the font includes the size, style and everything else about the font), but instead indicates the <dfn>font family</dfn>, the group of fonts of varying styles and sizes that look similar.</p>
+
+<p>The <code>font-family</code> property allows you to specify the name of a font family in the normal CSS way, specifying the property and value in a declaration:</p>
+
+<blockquote><code>{font-family: "Times New Roman"}</code></blockquote>
+
+<p>Since this particular font family, "Times New Roman", has spaces in its name, we've placed it inside quotes. Family names without spaces do not need quotes.</p>
+
+<p>In a real style sheet, you would also need to specify one or more elements to which to apply the style, using a selector. For example, you might wish to specify the default font for the entire OEB document. Since all text in an OEB document appears inside an enclosing <code>&lt;body&gt;</code> element, you can specify a default font by using <code>body</code> as the selector:</p>
+
+<blockquote><code>body {font-family: "Times New Roman"}</code></blockquote>
+
+<p>The font family "Times New Roman" is quite popular and comes installed on many computer operating platforms. There's no way to guarantee that it will be installed on the device or software the person reading your book is using, however. You might even decide to use a font family that no one else is using (after all, style sheets are about specifying custom styles). Perhaps you've created a custom font family, and it only exists on your machine! Your book will look quite nice on your own computer or reading device, but what about on other systems?</p>
+
+<p>CSS defines several generic font families (or more accurately, generic divisions of font families), three of which OEB uses. These font familes are guaranteed to be present on any OEB compliant reading system. They are:</p>
+
+<ul>
+	<li><strong>serif</strong> A font family with serifs present (such as "Times New Roman").</li>
+	<li><strong>sans-serif</strong> A font family without serifs present (such as "Arial").</li>
+	<li><strong>monospace</strong> A font family in which each character takes up the same amount of horizontal space (such as "Courier").</li>
+</ul>
+
+<p>Using one of these three fonts will guarantee that your text will be assigned a font with the same properties you intended on every OEB compliant reading system. But what about customization? OEB does not yet specify a way to deliver custom fonts to a reading system, but there is a middle ground: CSS allows one to specify the preferred font family, yet also specify the font family to use if the preferred font is not present.</p>
+
+<p>Specify a list of preferred <code>font-family</code> values by separating them with commas (,) with the most preferred font first. If you use "Book Antiqua", a serif font family, you might specify the following as the default font:</p>
+
+<blockquote><code>body {font-family: "Book Antiqua", "Times New Roman", serif}</code></blockquote>
+
+<p>Notice that we've specified <code>serif</code>, the generic font family guaranteed to be present, as our last choice. We always want the text displayed, and even if the reading system offers no frills whatsoever, this font family is guaranteed to be present. In fact, it is recommended that you <em>always</em> provide one of the generic font families as your last choice in your fallback list.</p>
+
+<ul>
+	<li><strong>CSS Tip 1:</strong> (<em>Supplying Default Generic Font Family Names</em>) Always provide one of the generic font family names in your <code>font-family</code> fallback list.</li>
+</ul>
+
+<h4 id="fontsizeproperty">The <code>font-size</code> Property</h4>
+
+<p>CSS allows a font size to be specified absolutely, using the <code>font-size</code> property and one of the units specified earlier. (Note that there is no whitespace between the value and the unit name.) A 12 point font could be selected as the default using the following:</p>
+
+<blockquote><code>body {font-size: 12pt}</code></blockquote>
+
+<p>While it might be appropriate to specify the absolute size of the default font, which applies to everything inside the <code>&lt;body&gt;</code> tag (and thereby everything in the document), it's not wise to specify an absolute value for elements within the document. For example, to make all emphasized text a little larger than the surrounding text, an absolute value might be used like this:</p>
+
+<blockquote><strong>Not Recommended:</strong> <code>em {font-size: 14pt}</code></blockquote>
+
+<p>There are several reasons this isn't a good idea. What if you were to later change the default font for <code>&lt;body&gt;</code> to 16 points? You'd then have to make sure that every other absolute value, such as that for <code>&lt;em&gt;</code>, was changed as well, or the emphasized text would be <em>smaller</em> than the surrounding text &mdash; the 14-point emphasized text didn't change, but the surrounding text changed to 16 points. Furthermore, remember that the <code>&lt;em&gt;</code> element can appear several places, such as within an <code>&lt;h1&gt;</code> element, which traditionally is larger than the default text. You'd want the emphasized text even larger than the 14 points you specified. In short, it would be ideal to be able to specify that a particular element's size in relation to its surrounding text (or rather, relative to the size of the enclosing element's font).</p>
+
+<p>One way CSS allows this to be done is using percentages. If you want emphasized text to be slightly larger than the text that surrounds it, it would be better to use something like this:</p>
+
+<blockquote><code>em {font-size: 120%}</code></blockquote>
+
+<p>In this case, if the <code>&lt;em&gt;</code> tag appeared inside an element of 12-point text, it would be rendered in a 14.4-point font (12 multiplied by 120% is 14.4). If the <code>&lt;em&gt;</code> element were to appear inside 16-point text, it would be rendered in a 19.2-point font. The following example shows how using a percentage can make relative sizes appear correctly in several locations:</p>
+
+<p>Style Sheet:</p>
+
+<blockquote>
+	<code>body {font-size: 12pt}</code><br />
+	<code>em {font-size: 120%}</code>
+</blockquote>
+
+<p>Document Extract:</p>
+
+<blockquote>
+	<code>&lt;h2&gt;</code>The <code>&lt;em&gt;</code>Extremely<code>&lt;/em&gt;</code> Small Blovjus<code>&lt;/h2&gt;</code><br />
+	<code>&lt;p&gt;</code>...Being <code>&lt;em&gt;</code>extremely<code>&lt;/em&gt;</code> smaller than other blovji his age...<code>&lt;/p&gt;</code><br />
+</blockquote>
+
+<blockquote>
+	<h2>The <em style="font-size: 120%">Extremely</em> Small Blovjus</h2>
+	<p>...Being <em style="font-size: 120%">extremely</em> smaller than other blovji his age...</p>
+</blockquote>
+
+<p>There are several other ways to represent relative sizes. You can use the units "em" or "ex", which specifies that the font should be so many multiples of the width of the "m" character or the height of the "ex" character, respectively, in the current font. We won't discuss these methods here.</p>
+
+<p>Just like <code>font-family</code>, which allows certain pre-defined font family names to be used, the <code>font-size</code> property has several pre-defined sizes. Some of these are relative sizes, functioning exactly as if percentages were used, and others are absolute, functioning exactly as if absolute sizes were used.</p>
+
+<p>Predefined relative <code>font-size</code> values:</p>
+
+<ul>
+	<li><strong>smaller</strong> Specifies the font size should be smaller than that of the enclosing element.</li>
+	<li><strong>larger</strong> Specifies the font size should be larger than that of the enclosing element.</li>
+</ul>
+
+<p>CSS recommends that a difference of 120% be used, which would make using <code>font-size: larger</code> equivalent to using <code>font-size: 120%</code>, for example, but this difference is not guaranteed.</p>
+
+<p>The other pre-defined <code>font-size</code> values are the following:</p>
+
+<ul>
+	<li><strong>xx-small</strong></li>
+	<li><strong>x-small</strong></li>
+	<li><strong>small</strong></li>
+	<li><strong>medium</strong></li>
+	<li><strong>large</strong></li>
+	<li><strong>x-large</strong></li>
+	<li><strong>xx-large</strong></li>
+</ul>
+
+<p>Although these are equivalent to using absolute font sizes, the actual font sizes these values stand for may very from platform to platform. CSS does say that you can expect values of <code>larger</code> and <code>smaller</code> to change between these absolute values. That is, for a current font size of <code>small</code>, an element with <code>font-size: larger</code> would give the equivalent of a font of size <code>medium</code>.</p>
+
+<h4 id="fontstyleproperty">The <code>font-style</code> Property</h4>
+
+<p>The <code>font-style</code>, as implemented by OEB, allows a font to be specified as <code>italic</code> or <code>normal</code> (that is, not italic). Although CSS allows another value, <code>oblique</code>, OEB reading systems are not required to support it, and may represent it as synonymous with <code>italic</code>.</p>
+
+<h4 id="fontweightproperty">The <code>font-weight</code> Property</h4>
+
+<p>Although CSS allows several values to be used with the <code>font-weight</code> property, OEB eliminates all but two of them, making <code>font-weight</code> simply a way to designate that text should be rendered as bold, in much the same way that <code>font-style</code> represented italics. The two values OEB allows for <code>font-weight</code> are <code>bold</code> and <code>normal</code>.</p>
+
+<h4 id="textdecorationproperty">The <code>text-decoration</code> Property</h4>
+
+<p>The <code>text-decoration</code> property allows underlining to be specified, in much the same way that previous properties allowed italics and bold to be specified. The two values allowed are <code>none</code> (the default), and <code>underline</code>.</p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/chapter6.html
@@ -1,0 +1,626 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Chapter 6</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="chapter6">6. Real-World OEB: Charter of the United Nations</h2>
+
+<p>At this point you should be able to create a fairly complex real-world OEB publication. We could demonstrate creating an OEB publication from the ground up by writing a book-length work from scratch, but it will probably be more illustrative to take a publication that already exists and convert it to OEB.</p>
+
+<p>Here, we'll take the Charter of the United Nations &mdash; available on the Internet at <a href="http://www.un.org/aboutun/charter/">http://www.un.org/aboutun/charter/</a> &mdash; and convert it into an OEB publication in the same step-by-step manner you would use with your own publication, or one you are converting. You can find the finished product at <a href="http://www.globalmentor.com/bookstore/search?text=un+charter">http://www.globalmentor.com/bookstore/search?text=un+charter</a>.</p>
+
+<p>It's best to first take a broad look of how the work is organized, so that we can correctly model its structure using OEB elements. In general, the UN Charter is organized in the following hierarchy:</p>
+
+<ul>
+	<li>Charter of the United Nations<br />
+	<ul>
+		<li>Chapters<br />
+		<ul>
+			<li>Articles</li>
+		</ul>
+		</li>
+	</ul>
+	</li>
+</ul>
+
+<p>Since OEB, being modeled so closely after HTML, has no concept of hierarchical divisions, we'll divide the UN Charter using whatever method we feel appropriate. While we could certainly put the entire Charter into one OEB document, it will probably be easier for us to keep track of things if we use several OEB document files. We'll place each chapter and all its article into a separate OEB document file, and do the same with the Introductory Note and the Preamble.</p>
+
+<p>Without specific elements to represent hierarchical divisions, we'll use own arbitrary method of representing headings within each division. There are a number of ways the division headings could be represented, none really being any better than the others, so we'll choose the following representation:</p>
+
+<ul>
+	<li><strong><code>&lt;h1&gt;</code></strong> Title of entire UN Charter.</li>
+	<li><strong><code>&lt;h2&gt;</code></strong> Title of each chapter.</li>
+	<li><strong><code>&lt;h3&gt;</code></strong> Title of each article.</li>
+</ul>
+
+<h3 id="uncharterchapter2">UN Charter Chapter 2: <code>chapter2.html</code></h3>
+
+<p>Since we're using separate document files for each chapter, this makes it easy to analyze different parts of the Charter separately. Although it might seem strange that we're not starting from the beginning, it's probably best to first jump into the midst of the document and see how the "mundane" structures will be implemented; we can look at the "Introductory Note", "Preamble", and trimmings such as a table of contents later, after you're comfortable with producing more common OEB elements.</p>
+
+<p>The second chapter of the UN charter begins with the chapter name and title, then proceeds with each separate article title and the article's contents:</p>
+
+<blockquote>
+<p>CHAPTER II</p>
+<p>MEMBERSHIP</p>
+<p>Article 3</p>
+<p>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.</p>
+<p>Article 4</p>
+<p>1. Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.</p>
+<p>2. The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.</p>
+<p><em>. . .</em></p>
+</blockquote>
+
+<p>We've already decided to represent the chapter title using the <code>&lt;h2&gt;</code> element, and the title for each article using the <code>&lt;h3&gt;</code> element. After this is done, the first part of our converted text looks like this:</p>
+
+<blockquote>
+	<code>&lt;h2&gt;</code>Chapter II: Membership<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 3<code>&lt;/h3&gt;</code>
+</blockquote>
+
+<p>The text of "Article 3", being a simple paragraph, will simply go inside a <code>&lt;p&gt;</code> element:</p>
+
+<blockquote>
+	<code>&lt;h2&gt;</code>Chapter II: Membership<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 3<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.<code>&lt;/p&gt;</code>
+</blockquote>
+
+<p>The title of "Article 4" can obviously be placed inside a <code>&lt;h3&gt;</code> element, as was "Article 3", but what about the article's contents? While we could simply use two <code>&lt;p&gt;</code> elements, these two paragraphs are numbered; it would be more appropriate to use an ordered list, with each paragraph appearing inside one of the items in the list:</p>
+
+<blockquote>
+<p><em>. . .</em></p>
+	<code>&lt;h3&gt;</code>Article 4<code>&lt;/h3&gt;</code><br />
+	<code>&lt;ol&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.<code>&lt;/p&gt;&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.<code>&lt;/p&gt;&lt;/li&gt;</code><br />
+	<code>&lt;/ol&gt;</code>
+</blockquote>
+
+<p>Note that we remove the literal numbers in each paragraph; the <code>&lt;ol&gt;</code> element combined with the <code>&lt;li&gt;</code> elements will add the correct numbers automatically when the book is displayed.</p>
+
+<p>Markup added to articles five and six will be identical to that added to the first article. The last step is even more important than the others: add the <code>&lt;body&gt;</code> element and the other required OEB document markup. The resulting document file <code>chapter2.html</code> appears below:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;h2&gt;</code>Chapter II: Membership<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 3<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.<code>&lt;/p&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 4<code>&lt;/h3&gt;</code><br />
+	<code>&lt;ol&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.<code>&lt;/p&gt;&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.<code>&lt;/p&gt;&lt;/li&gt;</code><br />
+	<code>&lt;/ol&gt;</code>
+	<code>&lt;h3&gt;</code>Article 5<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>A Member of the United Nations against which preventive or enforcement action has been taken by the Security Council may be suspended from the exercise of the rights and privileges of membership by the General Assembly upon the recommendation of the Security Council. The exercise of these rights and privileges may be restored by the Security Council.<code>&lt;/p&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 6<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>A Member of the United Nations which has persistently violated the Principles contained in the present Charter may be expelled from the Organization by the General Assembly upon the recommendation of the Security Council.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<p>When this chapter is displayed, here's how it will appear:</p>
+
+<blockquote>
+	<h2>Chapter II: Membership</h2>
+	<h3>Article 3</h3>
+	<p>The original Members of the United Nations shall be the states which, having participated in the United Nations Conference on International Organization at San Francisco, or having previously signed the Declaration by United Nations of 1 January 1942, sign the present Charter and ratify it in accordance with Article 110.</p>
+	<h3>Article 4</h3>
+	<ol>
+	<li><p>Membership in the United Nations is open to all other peace-loving states which accept the obligations contained in the present Charter and, in the judgment of the Organization, are able and willing to carry out these obligations.</p></li>
+	<li><p>The admission of any such state to membership in the United Nations will be effected by a decision of the General Assembly upon the recommendation of the Security Council.</p></li>
+	</ol>
+	<h3>Article 5</h3>
+	<p>A Member of the United Nations against which preventive or enforcement action has been taken by the Security Council may be suspended from the exercise of the rights and privileges of membership by the General Assembly upon the recommendation of the Security Council. The exercise of these rights and privileges may be restored by the Security Council.</p>
+	<h3>Article 6</h3>
+	<p>A Member of the United Nations which has persistently violated the Principles contained in the present Charter may be expelled from the Organization by the General Assembly upon the recommendation of the Security Council.</p>
+</blockquote>
+
+<h3 id="uncharterchapter3">UN Charter Chapter 3: <code>chapter3.html</code></h3>
+
+<p>After applying markup to the second chapter of the UN Charter, doing the same for the first chapter is straightforward; we'll therefore examine the following chapter, chapter three:</p>
+
+
+<blockquote>
+<p>CHAPTER III</p>
+<p>ORGANS</p>
+<p>Article 7</p>
+<p>1. There are established as the principal organs of the United Nations:<br />
+a General Assembly<br />
+a Security Council<br />
+an Economic and Social Council<br />
+a Trusteeship Council<br />
+an International Court of Justice<br />
+and a Secretariat.
+</p>
+<p>2. Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.</p>
+<p>Article 8</p>
+<p>The United Nations shall place no restrictions on the eligibility of men and women to participate in any capacity and under conditions of equality in its principal and subsidiary organs.</p>
+</blockquote>
+
+<p>Since we've already established a consistent way to use heading elements, the chapter and article titles can be converted as before:</p>
+
+<blockquote>
+	<code>&lt;h2&gt;</code>Chapter III: Organs<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 7<code>&lt;/h3&gt;</code><br />
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p>Similar to Chapter II, Article 4, the individual items in Chapter II, Article 7 are numbered (ordered) items in a list. We'll therefore begin the text as follows:</p>
+
+<blockquote>
+	<p><em>. . .</em></p>
+	<code>&lt;ol&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>There are established as the principal organs of the United Nations:<code>&lt;/p&gt;&lt;/li&gt;</code><br />
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p>At this point there seems to be a problem: The first listed item, beginning with "There are established...," itself contains a list of items, including "a General Assembly," "a Security Council," etc. These items are unordered (that is, they have no number beside them), but they represent a list nonetheless. It seems as if the first list item itself contains a list.</p>
+
+<p>These <dfn>nested lists</dfn> present no problem any more than common nested elements. They do require that you take special care in making sure which list elements appear in which other elements. We should first decide which type of list element to use for the list of "principal organs." As before, we'll present each of these items using the <code>&lt;li&gt;</code> tag. Together, these tags go inside an enclosing list element, but these particular items shouldn't be listed in any particular order; more precisely, we don't want these items to be represented with numbers beside them. We'll therefore use an unordered list <code>&lt;ul&gt;</code> instead of an ordered list <code>&lt;ul&gt;</code>.</p>
+
+<p>We'll therefore put the <code>&lt;li&gt;</code> list items of the unordered list <code>&lt;ui&gt;</code> inside the first <code>&lt;li&gt;</code> list item of the ordered list <code>&lt;ol&gt;</code>. Looking at the finished product should help to understand how this works:</p>
+
+<blockquote>
+	<code>&lt;h2&gt;</code>Chapter III: Organs<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 7<code>&lt;/h3&gt;</code><br />
+	<code>&lt;ol&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>There are established as the principal organs of the United Nations:<code>&lt;/p&gt;</code><br />
+	<blockquote>
+	<code>&lt;ul&gt;</code><br />
+	<code>&lt;li&gt;</code>a General Assembly<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>a Security Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>an Economic and Social Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>a Trusteeship Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>an International Court of Justice<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>and a Secretariat.<code>&lt;/li&gt;</code><br />
+	<code>&lt;/ul&gt;</code>
+	</blockquote>	
+	<code>&lt;/li&gt;</code>
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p>Notice that the ending tag <code>&lt;/li&gt;</code> of the first item in the ordered list comes <em>after</em> the end of the entire unordered list <code>&lt;ul&gt;</code>. This means that the entire unordered list <code>&lt;ul&gt;</code> is actually part of one list item element: the first list item in the ordered list <code>&lt;ol&gt;</code></p>
+
+<p>We're still not finished with Article 7; we still must add the second item, beginning with, "Such subsidiary organs...:"</p>
+
+<blockquote>
+	<code>&lt;h2&gt;</code>Chapter III: Organs<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 7<code>&lt;/h3&gt;</code><br />
+	<code>&lt;ol&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>There are established as the principal organs of the United Nations:<code>&lt;/p&gt;</code><br />
+	<blockquote>
+	<code>&lt;ul&gt;</code>
+	<code>&lt;li&gt;</code>a General Assembly<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>a Security Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>an Economic and Social Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>a Trusteeship Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>an International Court of Justice<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>and a Secretariat.<code>&lt;/li&gt;</code><br />
+	<code>&lt;/ul&gt;</code>
+	</blockquote>	
+	<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.<code>&lt;/p&gt;&lt;/li&gt;</code><br />
+	<code>&lt;/ol&gt;</code>
+</blockquote>
+
+<p>The following article, Article 8, which ends this chapter of the UN Charter, is quite simple structurally. As with any OEB document file, we'll also need to add the enclosing <code>&lt;html&gt;</code> and <code>&lt;body&gt; elements:</code></p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd"&gt;</code><br />
+<code>&lt;html&gt;</code><br />
+<code>&lt;body&gt;</code><br />
+	<code>&lt;h2&gt;</code>Chapter III: Organs<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 7<code>&lt;/h3&gt;</code><br />
+	<code>&lt;ol&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>There are established as the principal organs of the United Nations:<code>&lt;/p&gt;</code><br />
+	<blockquote>
+	<code>&lt;ul&gt;</code>
+	<code>&lt;li&gt;</code>a General Assembly<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>a Security Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>an Economic and Social Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>a Trusteeship Council<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>an International Court of Justice<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>and a Secretariat.<code>&lt;/li&gt;</code><br />
+	<code>&lt;/ul&gt;</code>
+	</blockquote>	
+	<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;&lt;p&gt;</code>Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.<code>&lt;/p&gt;&lt;/li&gt;</code><br />
+	<code>&lt;/ol&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 8<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>The United Nations shall place no restrictions on the eligibility of men and women to participate in any capacity and under conditions of equality in its principal and subsidiary organs.<code>&lt;/p&gt;</code><br />
+<code>&lt;/body&gt;</code><br />
+<code>&lt;/html&gt;</code>
+</blockquote>
+
+<p>The chapter will then appear like this when it's displayed:</p>
+
+<blockquote>
+	<h2>Chapter III: Organs</h2>
+	<h3>Article 7</h3>
+	<ol>
+	<li><p>There are established as the principal organs of the United Nations:</p>
+		<ul>
+		<li>a General Assembly</li>
+		<li>a Security Council</li>
+		<li>an Economic and Social Council</li>
+		<li>a Trusteeship Council</li>
+		<li>an International Court of Justice</li>
+		<li>and a Secretariat.</li>
+		</ul>
+	</li>
+	<li><p>Such subsidiary organs as may be found necessary may be established in accordance with the present Charter.</p></li>
+	</ol>
+	<h3>Article 8</h3>
+	<p>The United Nations shall place no restrictions on the eligibility of men and women to participate in any capacity and under conditions of equality in its principal and subsidiary organs.</p>
+</blockquote>
+
+<h3 id="uncharterchapter1">UN Charter Chapter 1: <code>chapter1.html</code></h3>
+
+<p>Now that we've examined chapters two and three, we can return to Chapter One. At first the structure of the content looks relatively straightforward compared to the chapters we've already examined.</p>
+
+<blockquote>
+<p>CHAPTER I</p>
+<p>PURPOSES AND PRINCIPLES</p>
+<p>Article 1</p>
+<p>The Purposes of the United Nations are:</p>
+<p><em>. . .</em></p>
+<p>Article 2</p>
+<p>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following Principles.</p>
+<p><em>. . .</em></p>
+</blockquote>
+
+<p>You should be able to easily mark up the information using the OEB publication structure, resulting in something similar to the following:</p>
+
+<blockquote>
+	<code>&lt;h2&gt;</code>Chapter I: Purposes and Principles<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3&gt;</code>Article 1<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>The Purposes of the United Nations are:<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p><br />
+	<code>&lt;h3&gt;</code>Article 2<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following Principles.<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p>It is at this point that the power of OEB can be put to use to store information within the document. Since these are the first places that the UN <dfn>Purposes</dfn> and <dfn>Principles</dfn> are being defined, we can make good use of the <code>&lt;dfn&gt;</code> element to indicate this:</p>
+
+<blockquote>
+	<code>&lt;p&gt;</code>The <code>&lt;dfn&gt;</code>Purposes<code>&lt;/dfn&gt;</code> of the United Nations are:<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p><br />
+	<code>&lt;p&gt;</code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following <code>&lt;dfn&gt;</code>Principles<code>&lt;/dfn&gt;</code>.<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p>Adding the <code>&lt;dfn&gt;</code> tag encodes meaning into the document, explicitly stating that these two concepts are being defined for the first time. We can go one step further and mark these definitions with anchors, in case we want to refer to these specific definitions later in the document (remember that, instead of using actual <code>&lt;a&gt;</code> elements for anchors, we can simply add <code>id</code> attributes to the target elements):</p>
+
+<blockquote>
+	<code>&lt;p&gt;</code>The <code>&lt;dfn id="purposesDefinition"&gt;</code>Purposes<code>&lt;/dfn&gt;</code> of the United Nations are:<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p><br />
+	<code>&lt;p&gt;</code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following <code>&lt;dfn id="principlesDefinition"&gt;</code>Principles<code>&lt;/dfn&gt;</code>.<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p>In fact, it's a good idea if we place anchors on every heading in the document so that the respective sections can be linked to later. For example, adding anchors to the sections of this chapter results in the markup below. (If we were to use actual anchor elements for anchors, we would place the anchor element, <code>&lt;a&gt;</code>, inside the heading element, <code>&lt;h2&gt;</code>. This order cannot be reversed, for the same reason that the <code>&lt;p&gt;</code> element cannot go inside an <code>&lt;em&gt;</code> element: inline elements must go inside block elements, and not vice-versa. Here we don't even use anchor elements at all, but simply add <code>id</code> attributes to the <code>&lt;h2&gt;</code> and <code>&lt;h3&gt;</code> elements.)</p>
+
+<blockquote>
+	<code>&lt;h2 id="chapter1"&gt;</code>Chapter I: Purposes and Principles<code>&lt;/h2&gt;</code><br />
+	<code>&lt;h3 id="article1"&gt;</code>Article 1<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>The Purposes of the United Nations are:<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p><br />
+	<code>&lt;h3 id="article2"&gt;</code>Article 2<code>&lt;/h3&gt;</code><br />
+	<code>&lt;p&gt;</code>The Organization and its Members, in pursuit of the Purposes stated in Article 1, shall act in accordance with the following Principles.<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p></p>
+
+<p>Assuming we add anchor elements to every division in the entire UN Charter, and assuming Chapter VII is placed in a file named <code>chapter7.html</code>, we can provide links from this chapter. The last principle in Article 2 states that "this principle shall not prejudice the application of enforcement measures under Chapter Vll."; with anchor tags appropriately placed throughout our documents, we can provide a direct hypertext link to the chapter by using the anchor element <code>&lt;a&gt;</code> like this:</p>
+
+<blockquote>
+	<code>&lt;p&gt;</code>...this principle shall not prejudice the application of enforcement measures under <code>&lt;a href="chapter7.html#chapter7"&gt;</code>Chapter Vll<code>&lt;/a&gt;</code>.<code>&lt;p&gt;</code>
+</blockquote>
+
+<p>Notice that we've not only linked to the file, <code>chapter7.html</code>, we've also provided the ID of the anchor, <code>#chapter7</code>, which marks the beginning of the actual chapter in the file. Since Chapter 7 is at the beginning of <code>chapter7.html</code>, we could have simply linked to the document file itself: <code>&lt;a href="chapter7.html"&gt;</code>. However, in many cases the target anchor within the file will be important as well when the anchor is not at the beginning of the document &mdash; in the case of articles, for instance.</p>
+
+<h3 id="uncharterintro">UN Charter Introductory Note: <code>intro.html</code></h3>
+
+<p>Moving back another step to the UN Charter's Introductory Note provides more examples of linking, provided the appropriate anchor elements have been placed at the start of every chapter and article:</p>
+
+<blockquote>
+	<code>&lt;h2 id="chapter1"&gt;</code>Introductory Note<code>&lt;/h2&gt;</code><br />
+	<code>&lt;p&gt;</code>The Charter of the United Nations was signed on 26 June 1945, in San Francisco, at the conclusion of the United Nations Conference on International Organization, and came into force on 24 October 1945. The Statute of the International Court of Justice is an integral part of the Charter.<code>&lt;/p&gt;</code><br />
+	<code>&lt;p&gt;</code>Amendments to <code>&lt;a href="chapter5.html#article23"&gt;</code>Articles 23<code>&lt;/a&gt;</code>, <code>&lt;a href="chapter5.html#article27"&gt;</code>27<code>&lt;/a&gt;</code> and <code>&lt;a href="chapter10.html#article61"&gt;</code>61<code>&lt;/a&gt;</code> of the Charter were adopted by the General Assembly on 17 December 1963 and came into force on 31 August 1965. A further amendment to <code>&lt;a href="chapter10.html#article61"&gt;</code>Article 61<code>&lt;/a&gt;</code> was adopted by the General Assembly on 20 December 1971, and came into force on 24 September 1973. An amendment to <code>&lt;a href="chapter18.html#article109"&gt;</code>Article 109<code>&lt;/a&gt;</code>, adopted by the General Assembly on 20 December 1965, came into force on 12 June 1968.<code>&lt;/p&gt;</code><br />
+	<p><em>. . .</em></p>
+</blockquote>
+
+<p>Note that we had to first check and see in which document files the articles appear before we could link to them.</p>
+
+<h3 id="unchartertoc">Table of Contents: <code>toc.html</code></h3>
+
+<p>The first version of the Open eBook Publication Structure has no specific elements for creating a table of contents; this means that, outside of creating a new set of elements specifically for a table of contents, we'll be forced to use generic elements to do the job. Here we'll use the standard elements to create a table of contents inside a normal OEB document.</p>
+
+<p>A table of contents is usually one of the last things you'll add to your OEB publication, for good reason: not only does it provide a hierarchical view of the structure of the publication, it provides links to each one of publication sections. You may, however, elect to create a table of contents early and use it as a working design of your entire publication, if you are writing the work from scratch; you'd still have to wait until the document was finished to test all of the hyperlinks, though.</p>
+
+<p>The table of contents therefore has two elements: its reflection of the publication's structure, as well as hyperlinks to parts of the publication. Reflecting the work's structure can be accomplished in several ways; here we'll use unordered list <code>&lt;ol&gt;</code> elements. An OEB document displaying the top-level UN Charter structure (that is, the level containing the Introductory Note, Preamble, and chapters), might be marked up like this:</p>
+
+<blockquote>
+<code>&lt;ul&gt;</code><br />
+	<code>&lt;li&gt;</code>Introductory Note<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>Preamble<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>Chapter I: Purposes and Principles<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>Chapter II: Membership<code>&lt;/li&gt;</code><br />
+	<em>. . .</em><br />
+<code>&lt;/ul&gt;</code>
+</blockquote>
+
+<p>This would appear something like this:</p>
+
+<blockquote>
+<ul>
+	<li>Introductory Note</li>
+	<li>Preamble</li>
+	<li>Chapter I: Purposes and Principles</li>
+	<li>Chapter II: Membership</li>
+	<li><em>. . .</em></li>
+</ul>
+</blockquote>
+
+<p>Displaying the second level of organization, the level containing the articles, requires a bit more concentration on details. It's evident that each list of articles that appear within a chapter will be marked up using a separate list element, but it's important to remember that all of these lists are actually sub-lists of the chapter item in which they appear. Each chapter item is enclosed within a list item <code>&lt;li&gt;</code><em>...</em><code>&lt;/li&gt;</code> beginning and ending tag pair. Each sub-list of articles must appear <em>inside</em> that list item's beginning and ending tags. OEB's content model does not allow lists to appear between list items; sub-lists must appear inside the list item to which they belong.</p>
+
+<blockquote>
+<code>&lt;ul&gt;</code><br />
+	<code>&lt;li&gt;</code>Introductory Note<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>Preamble<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>Chapter I: Purposes and Principles<br />
+	<blockquote>
+	<code>&lt;ul&gt;</code><br />
+		<code>&lt;li&gt;</code>Article 1<code>&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;</code>Article 2<code>&lt;/li&gt;</code><br />
+	<code>&lt;/ul&gt;</code>
+	</blockquote>
+	<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;</code>Chapter II: Membership<br />
+	<blockquote>
+	<code>&lt;ul&gt;</code><br />
+		<code>&lt;li&gt;</code>Article 3<code>&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;</code>Article 4<code>&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;</code>Article 5<code>&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;</code>Article 6<code>&lt;/li&gt;</code><br />
+	<code>&lt;/ul&gt;</code>
+	</blockquote>
+	<code>&lt;/li&gt;</code><br />
+	<em>. . .</em><br />
+<code>&lt;/ul&gt;</code>
+</blockquote>
+
+<p>When displayed, the table of contents would now appear like this:</p>
+
+<blockquote>
+<ul>
+	<li>Introductory Note</li>
+	<li>Preamble</li>
+	<li>Chapter I: Purposes and Principles
+	<ul>
+		<li>Article 1</li>
+		<li>Article 2</li>
+	</ul>
+	</li>
+	<li>Chapter II: Membership
+	<ul>
+		<li>Article 3</li>
+		<li>Article 4</li>
+		<li>Article 5</li>
+		<li>Article 6</li>
+	</ul>	
+	</li>
+	<li><em>. . .</em></li>
+</ul>
+</blockquote>
+
+<p>That's all we need to do regarding structure, since the UN Charter has only these levels of hierarchy. The other issue to address is hyperlinking: each item in the table of contents must link to the respective section of the publication. If that section lies somewhere in the middle of the physical document file in which it appears, we must have first provided anchors with unique IDs for the table of contents to link to.</p>
+
+<p>After adding hyperlinks, our table of contents is basically finished:</p>
+
+<blockquote>
+<code>&lt;ul&gt;</code><br />
+	<code>&lt;li&gt;&lt;a href="intro.html"&gt;</code>Introductory Note<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;&lt;a href="preamble.html"&gt;</code>Preamble<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;&lt;a href="chapter1.html"&gt;</code>Chapter I: Purposes and Principles&lt;/a&gt;<br />
+	<blockquote>
+	<code>&lt;ul&gt;</code><br />
+		<code>&lt;li&gt;&lt;a href="chapter1.html#article1"&gt;</code>Article 1<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;&lt;a href="chapter1.html#article2"&gt;</code>Article 2<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+	<code>&lt;/ul&gt;</code>
+	</blockquote>
+	<code>&lt;/li&gt;</code><br />
+	<code>&lt;li&gt;&lt;a href="chapter2.html"&gt;</code>Chapter II: Membership&lt;/a&gt;<br />
+	<blockquote>
+	<code>&lt;ul&gt;</code><br />
+		<code>&lt;li&gt;&lt;a href="chapter2.html#article3"&gt;</code>Article 3<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;&lt;a href="chapter2.html#article4"&gt;</code>Article 4<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;&lt;a href="chapter2.html#article5"&gt;</code>Article 5<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+		<code>&lt;li&gt;&lt;a href="chapter2.html#article6"&gt;</code>Article 6<code>&lt;/a&gt;&lt;/li&gt;</code><br />
+	<code>&lt;/ul&gt;</code>
+	</blockquote>
+	<code>&lt;/li&gt;</code><br />
+	<em>. . .</em><br />
+<code>&lt;/ul&gt;</code>
+</blockquote>
+
+<h3 id="uncharterpackage">UN Charter Package File: <code>uncharter.opf</code></h3>
+
+<p>From the examples covered so far, marking up the rest of the UN Charter should be a simple task. There's still one more file we need to create, however, to tie all the pieces together and make our series of OEB documents into a complete OEB publication: the OEB package file.</p>
+
+<p>Creating the package file, as you know by now, requires less thinking and planning than cutting, pasting, and altering to match the particular publication you're working with. In this example, we'll simply start from the top of the file and work our way downwards &mdash; although we'll include ending tags when appropriate, which may occur at the end of the file. The first part should be familiar &mdash; it appears at the top of every package file:</p>
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"&gt;</code><br />
+<code>&lt;package unique-identifier="uncharterpackage"&gt;</code>
+
+	<blockquote>
+		<em>. . .</em>
+	</blockquote>
+
+<code>&lt;/package&gt;</code>
+</blockquote>
+
+<p>Inside the <code>&lt;package&gt;</code> element, we'll place the metadata. In particular, we'll include the title of the publication (<em>Charter of the United Nations</em>) and we'll create our own type of "charter", although this particular type of document has not been standardized.</p>
+
+<p>The <code>&lt;dc:Identifier&gt;</code> element requires particular attention. Notice that we've given the <code>id</code> attribute the value <code>"uncharterpackage"</code> to match the <code>unique-identifier</code> attribute in the earlier <code>&lt;package&gt;</code> element. Furthermore, we've used a <code>scheme</code> of <code>"url"</code>, although this value is not standard. It would be better to include a <code>scheme</code> of <code>ISBN</code> or some other similar identifier more useful to third parties such as bookstores and libraries.</p>
+
+<p>There are two <code>&lt;dc:Creator&gt;</code> elements; one specifies an author (<code>"aut"</code>) of <code>United Nations</code> and a book publisher (<code>"bkp"</code>) of <code>Mentor Publishing</code>. The <code>&lt;dc:Date</code> element contains the date this package file was created, July 11, 2001.</p>
+
+<p>Three arbitrary subjects have been added using the <code>&lt;ds:Subject&gt;</code> element: <code>United Nations</code>, <code>Historical Documents</code>, and <code>International Politics</code>. Lastly, a <code>&lt;dc:Source&gt;</code> element shows that we originally found the content at <code><a href="http://www.un.org/aboutun/charter/">http://www.un.org/aboutun/charter/</a></code>.</p>
+
+<blockquote>
+    <code>&lt;dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"&gt;</code><br />
+      <code>&lt;dc:Title&gt;</code>Charter of the United Nations<code>&lt;/dc:Title&gt;</code><br />
+			<code>&lt;dc:Type&gt;</code>charter<code>&lt;/dc:Type&gt;</code><br />
+			<code>&lt;dc:Identifier id="uncharterpackage" scheme="url"&gt;</code>http://www.un.org/aboutun/charter/<code>&lt;/dc:Identifier&gt;</code><br />
+			<code>&lt;dc:Creator role="aut"&gt;</code>United Nations<code>&lt;/dc:Creator&gt;</code><br />
+			<code>&lt;dc:Creator role="bkp"&gt;</code>Mentor Publishing<code>&lt;/dc:Creator&gt;</code><br />
+			<code>&lt;dc:Date&gt;</code>2001-07-11<code>&lt;/dc:Date&gt;</code><br />
+      <code>&lt;dc:Subject&gt;</code>United Nations<code>&lt;/dc:Subject&gt;</code><br />
+      <code>&lt;dc:Subject&gt;</code>Historical Documents<code>&lt;/dc:Subject&gt;</code><br />
+      <code>&lt;dc:Subject&gt;</code>International Politics<code>&lt;/dc:Subject&gt;</code><br />
+			<code>&lt;dc:Source&gt;</code>http://www.un.org/aboutun/charter/<code>&lt;/dc:Source&gt;</code><br />
+    <code>&lt;/dc-metadata&gt;</code>
+</blockquote>
+
+<p>We next need to specify the files which will be included in the publication; this information will appear inside the <code>&lt;manifest&gt;</code> element. Since our version of the the UN Charter has no images associated with it, each <code>&lt;item&gt;</code> element in the manifest will represent an OEB document file, with <code>media-type="text/x-oeb1-document"</code>. It doesn't matter what order we present the files, just so we include all the files used in the publication. This includes the table of contents, the introduction, the preamble, and all the chapters, including chapters we haven't listed here.</p>
+
+<blockquote>
+  <code>&lt;manifest&gt;</code><br />
+    <code>&lt;item id="toc" href="toc.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="intro" href="intro.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="preamble" href="preamble.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter1" href="chapter1.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter2" href="chapter2.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+	<em>. . .</em><br />
+  <code>&lt;/manifest&gt;</code>
+</blockquote>		
+
+<p>It is inside the <code>&lt;spine&gt;</code> element that we specify the reading order of the documents we listed in the <code>&lt;manifest&gt;</code> section. The order here is all that's important; having already listed the essential information about each document, we simply reference the unique ID we've assigned each item earlier:</p>
+
+<blockquote>
+  <code>&lt;spine&gt;</code><br />
+    <code>&lt;itemref idref="toc" /&gt;</code><br />
+    <code>&lt;itemref idref="intro" /&gt;</code><br />
+    <code>&lt;itemref idref="preamble" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter1" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter2" /&gt;</code><br />
+		<em>. . .</em><br />
+	<code>&lt;/spine&gt;</code>
+</blockquote>
+
+<p>That's all that OEB requires for a complete OEB publication, and we could at this point read the UN Charter on any OEB-compliant reading system. As an example of optional OEB functionality that we can add to allow future OEB reading systems to manipulate our work in various ways, we'll add a <code>&lt;guide&gt;</code> element and specify that our table of contents is one of the  <dfn>guide</dfn> types recognized by OEB; specifically, it is a <code>"toc"</code>, a table of contents. In short, we're simply identifying a particular document as a table of contents; other types of guides may be found in the <em>Open eBook Publication Structure 1.0.1 Specification</em>.</p>
+
+<p>There is currently no guarantee that a particular OEB reading system will recognize guides, but it's still a good idea to include at least the table of contents. More information on guides and a related concept, <dfn>tours</dfn>, can be found in the <em>Open eBook Publication Structure 1.0 Specification</em>, and will likely be covered in depth in a later edition of this book.</p>
+
+<blockquote>
+  <code>&lt;guide&gt;</code><br />
+    <code>&lt;reference type="toc" title="Table of Contents" href="toc.html" /&gt;</code><br />
+  <code>&lt;/guide&gt;</code>
+</blockquote>
+
+<p>At this point, we've finished the package file, completing our publication. Assuming the rest of the chapters have been marked up and included, the group of files can be presented to an OEB-compliant reading system and, based upon the function of the reading system, either be presented to a user or passed along the chain to another piece of software and/or hardware for further manipulation. The complete package file, <code>uncharter.opf</code>, is presented below:</p>
+
+
+<blockquote>
+<code>&lt;?xml version='1.0'?&gt;</code><br />
+<code>&lt;!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd"&gt;</code><br />
+<code>&lt;package unique-identifier="uncharterpackage"&gt;</code><br />
+
+	<blockquote>
+    <code>&lt;dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/"&gt;</code><br />
+      <code>&lt;dc:Title&gt;</code>Charter of the United Nations<code>&lt;/dc:Title&gt;</code><br />
+			<code>&lt;dc:Type&gt;</code>charter<code>&lt;/dc:Type&gt;</code><br />
+			<code>&lt;dc:Identifier id="uncharterpackage" scheme="url"&gt;</code>http://www.un.org/aboutun/charter/<code>&lt;/dc:Identifier&gt;</code><br />
+			<code>&lt;dc:Creator role="aut"&gt;</code>United Nations<code>&lt;/dc:Creator&gt;</code><br />
+			<code>&lt;dc:Creator role="bkp"&gt;</code>Mentor Publishing<code>&lt;/dc:Creator&gt;</code><br />
+			<code>&lt;dc:Date&gt;</code>2001-07-11<code>&lt;/dc:Date&gt;</code><br />
+      <code>&lt;dc:Subject&gt;</code>United Nations<code>&lt;/dc:Subject&gt;</code><br />
+      <code>&lt;dc:Subject&gt;</code>Historical Documents<code>&lt;/dc:Subject&gt;</code><br />
+      <code>&lt;dc:Subject&gt;</code>International Politics<code>&lt;/dc:Subject&gt;</code><br />
+			<code>&lt;dc:Source&gt;</code>http://www.un.org/aboutun/charter/<code>&lt;/dc:Source&gt;</code><br />
+    <code>&lt;/dc-metadata&gt;</code>
+	</blockquote>
+
+	<blockquote>
+  <code>&lt;manifest&gt;</code><br />
+    <code>&lt;item id="toc" href="toc.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="intro" href="intro.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="preamble" href="preamble.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter1" href="chapter1.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter2" href="chapter2.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter3" href="chapter3.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter4" href="chapter4.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter5" href="chapter5.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter6" href="chapter6.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter7" href="chapter7.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter8" href="chapter8.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter9" href="chapter9.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter10" href="chapter10.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter11" href="chapter11.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter12" href="chapter12.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter13" href="chapter13.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter14" href="chapter14.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter15" href="chapter15.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter16" href="chapter16.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter17" href="chapter17.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter18" href="chapter18.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+    <code>&lt;item id="chapter19" href="chapter19.html" media-type="text/x-oeb1-document" /&gt;</code><br />
+  <code>&lt;/manifest&gt;</code>
+	</blockquote>
+
+	<blockquote>
+  <code>&lt;spine&gt;</code><br />
+    <code>&lt;itemref idref="toc" /&gt;</code><br />
+    <code>&lt;itemref idref="intro" /&gt;</code><br />
+    <code>&lt;itemref idref="preamble" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter1" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter2" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter3" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter4" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter5" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter6" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter7" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter8" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter9" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter10" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter11" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter12" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter13" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter14" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter15" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter16" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter17" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter18" /&gt;</code><br />
+    <code>&lt;itemref idref="chapter19" /&gt;</code><br />
+	<code>&lt;/spine&gt;</code>
+	</blockquote>
+
+	<blockquote>
+  <code>&lt;guide&gt;</code><br />
+    <code>&lt;reference type="toc" title="Table of Contents" href="toc.html" /&gt;</code><br />
+  <code>&lt;/guide&gt;</code>
+	</blockquote>
+		
+<code>&lt;/package&gt;</code>
+</blockquote>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/foreword.html
@@ -1,0 +1,27 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Foreword</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="foreword">Foreword</h2>
+
+<p>When Garret told me he was writing this book, I thought "Thank, God!" The world really needs a good book about the Open eBook Publication Structure. And when I read a draft, I was even happier. It's clear and concise, direct and thorough and addresses a crucial audience. The authors of the publication structure did a great job designing and writing the technical specification, but the specification is, well, let's just say it's not gentle prose you'd read at night to relax! It's unforgivingly hard-nosed, technical and (usually!) unambiguous. And that's what a technical specification needs to be.  The primary audience for the specification is software developers who are building tools and reading systems, and the
+hyper-concise form is needed for those folks.</p>
+
+<p>But that doesn't help the rest of the world understand what the specification is, what it allows, how it works and how it nails the needs of the eBook world on its head. <em>Understanding OEB</em> tackles this task.</p>
+
+<p><em>David Ornstein</em></p>
+<p><em>President, Open eBook Forum</em></p>
+<p><em>Manager of Planning and Architecture for eReading, Microsoft</em></p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/preface.html
@@ -1,0 +1,33 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Preface</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h2 id="preface">Preface</h2>
+
+<p>Last night the finishing touches were placed on the <em>Open eBook Publication Structure 1.0.1</em>, a revision of the original specification which had as its purpose the task of clearing up ambiguities, fixing errors, and ensuring that the specification could continue to be useful as the Open eBook Forum produces new specifications for the eBook industry. As the original <em>Open eBook Publication Structure 1.0</em> was produced by the Open eBook Authoring Group (most of whom now make up the new Open eBook Forum), this updated document is the first official specification to be released by the OEBF.</p>
+
+<p>As chair of the maintenance subgroup of the publication structure working group (yes, the OEBF has a more complicated hierarchy than our original group of authors), I was responsible for overseeing the relatively easy task of updating and correcting the existing specification. As it turned out, even such minor changes are never straightforward, with such last-minute issues as corrupted logo image files. I cannot help but feel admiration (and some pity) for Gene Golovchinsky and Jerry Dunietz, who are supervising the development subgroup which is working towards the next major version of the OEB PS: <em>Open eBook Publication Structure 2.0</em></p>
+
+<p>Version 2.0 will certainly require a new "Understanding" book to be written, but the OEBF believes version 1.0.1 to be an unambiguous foundation on which to build today, a foundation that won't render content useless when new versions add new features. From the experience that version 1.0 has brought, it appears the OEB Authoring Group was correct in choosing <em>its</em> foundations: open, standards-based international specifications that can be used by all. It's my wish that this book will allow you to understand the steps you need to take to be one of those who use the specification for your next eBook.</p>
+
+<p>Thanks to Horace Dediu, Dorothea Salo, Merv Matson and Roger Sperberg for all their help in reviewing and proofreading the early drafts. Thanks to Gunter Hille and David Ornstein for their support and encouragment. Scott Oaks and Henry Wong in their <em>Java Threads</em> (O'Reilly, 1999) provided excellent examples of using rhetorical questions in a tutorial. I'm grateful to Garth Conboy for introducing me to the very useful technical term, "Real Soon Now."</p>
+
+<p>All diagrams in this book use the <a href="http://www.uml.org">Unified Modeling Language (UML)</a> and were created using the <a href="http://www.magicdraw.com">MagicDraw UML</a> modeling software.</p>
+
+<p><em>Garret Wilson</em></p>
+<p><em>President, GlobalMentor, Inc.</em></p>
+<p><em><a href="http://www.globalmentor.com">http://www.globalmentor.com</a></em></p>
+<p><em>14 June 2001</em></p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/title.html
@@ -1,0 +1,26 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+  <link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Title Page</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h1>Understanding OEB</h1>
+
+<h2>Revised and Updated for OEB PS 1.0.1</h2>
+
+<p>by <a href="mailto:garret@globalmentor.com">Garret Wilson</a></p>
+
+<p>Copyright &copy; 2000-2001 Garret Wilson. All rights reserved.</p>
+
+<p>Published by <a href="http://www.globalmentor.com/publishing/">Mentor Publishing</a>, a division of <a href="http://www.globalmentor.com">GlobalMentor, Inc.</a></p>
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/toc.html
@@ -1,0 +1,150 @@
+<?xml version='1.0'?>
+<!DOCTYPE html PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Document//EN" "http://openebook.org/dtds/oeb-1.0.1/oebdoc101.dtd">
+<?xml-stylesheet href="understandingoeb.css" type="text/x-oeb1-css"?>
+
+<html>
+<head>
+	<link rel="stylesheet" type="text/x-oeb1-css" href="understandingoeb.css" />
+<title>Understanding OEB Table of Contents</title>
+  <meta name="author" content="Garret Wilson" />
+  <meta name="copyright" content="Copyright (c) 2000-2001 Garret Wilson. All rights reserved." />
+</head>
+
+<body>
+
+<h1>Table of Contents</h1>
+
+<ul>
+	<li><a href="foreword.html">Foreword</a></li>
+	<li><a href="preface.html">Preface</a></li>
+	<li><a href="chapter1.html">1. Defining a Beginning</a>
+	<ul>	
+		<li><a href="chapter1.html#definingEBook">Defining "eBook"</a>
+		<ul>
+			<li><a href="chapter1.html#eText">Electronic Book as an "Etext"</a></li>
+			<li><a href="chapter1.html#eBookHype">"eBook" as a Marketing Tool</a></li>
+			<li><a href="chapter1.html#eBookInevitibility">The eBook as Inevitable</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter1.html#oebMeaning">The Meaning of OEB</a></li>
+		<li><a href="chapter1.html#usingOEB">Using OEB</a></li>
+		<li><a href="chapter1.html#review">Review</a>
+			<ul>
+				<li><a href="chapter1.html#summary">Summary</a></li>
+			</ul>
+		</li>
+	</ul>	
+	</li>
+	<li><a href="chapter2.html#chapter2">2. Understanding an OEB Publication</a>
+	<ul>
+		<li><a href="chapter2.html#oebdocument">An OEB Document</a>
+		<ul>
+			<li><a href="chapter2.html#needmarkup">The Need for Markup</a></li>
+			<li><a href="chapter2.html#markupalphabetsoup">More Information: Markup Alphabet Soup</a></li>
+			<li><a href="chapter2.html#usingxml">Using XML</a></li>
+			<li><a href="chapter2.html#creatingoebdocument">Creating an OEB Document</a></li>
+			<li><a href="chapter2.html#formattingoebtext">Formatting OEB Text</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter2.html#oebpackage">An OEB Package</a>
+		<ul>
+			<li><a href="chapter2.html#packageelement">The <code>&lt;package&gt;</code> Element</a></li>
+			<li><a href="chapter2.html#packagemetadata">The Package Metadata</a></li>
+			<li><a href="chapter2.html#packagemanifest">The Package Manifest</a></li>
+			<li><a href="chapter2.html#packagespine">The Package Spine</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter2.html#xmlrepresentdata">Using XML to Represent Data</a></li>
+		<li><a href="chapter2.html#review">Review</a>
+		<ul>
+			<li><a href="chapter2.html#summary">Summary</a></li>
+			<li><a href="chapter2.html#xmlrules">XML Rules</a></li>
+			<li><a href="chapter2.html#oebrules">OEB Rules</a></li>
+			<li><a href="chapter2.html#oebtags">OEB Tags</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter2.html#exampleoebdocument">Completed Example OEB Document (<code>karl.html</code>)</a></li>
+		<li><a href="chapter2.html#exampleoebpackage">Completed Example OEB Package (<code>karl.opf</code>)</a></li>
+	</ul>
+	</li>
+	<li><a href="chapter3.html#chapter3">3. Styles and Style Sheets</a>
+	<ul>
+		<li><a href="chapter3.html#emphasisrevisited">Emphasis Revisited</a></li>
+		<li><a href="chapter3.html#cascadingstylesheets">Cascading Style Sheets (CSS)</a>
+		<ul>
+			<li><a href="chapter3.html#cssvsxsl">More Information: CSS vs. XSL</a></li>
+			<li><a href="chapter3.html#cssselectors">CSS Selectors</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter3.html#linkingstylesheets">Linking to Style Sheets</a>
+		<ul>
+			<li><a href="chapter3.html#linkelement">Linking Style Sheets with the <code>&lt;link&gt;</code> Element</a></li>
+			<li><a href="chapter3.html#linkxml">Linking Style Sheets with XML</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter3.html#review">Review</a>
+		<ul>
+			<li><a href="chapter3.html#summary">Summary</a></li>
+			<li><a href="chapter3.html#cssproperties">CSS Properties</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter3.html#exampleoebdocument">Completed Example OEB Document with Styles (<code>karl.html</code>)</a></li>
+		<li><a href="chapter3.html#examplestylesheet">Completed Example Style Sheet (<code>karl.css</code>)</a></li>
+	</ul>
+	</li>
+	<li><a href="chapter4.html#chapter4">4. Essential OEB Elements</a>
+	<ul>
+		<li><a href="chapter4.html#inlineelements">Inline Elements</a>
+		<ul>
+			<li><a href="chapter4.html#xmlcontentmodels">More Information: XML Content Models</a></li>
+			<li><a href="chapter4.html#emelement">The <code>&lt;em&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#strongelement">The <code>&lt;strong&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#dfnelement">The <code>&lt;dfn&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#codeelement">The <code>&lt;code&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#citeelement">The <code>&lt;cite&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#spanelement">The <code>&lt;span&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#customelements">More Information: Creating Custom Elements</a></li>
+			<li><a href="chapter4.html#brelement">The <code>&lt;br&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#aelement">The <code>&lt;a&gt;</code> Element</a></li>
+		</ul>
+		</li>
+		<li><a href="chapter4.html#blockelements">Block Elements</a>
+		<ul>
+			<li><a href="chapter4.html#pelement">The <code>&lt;p&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#headingelements">The <code>&lt;h1&gt;</code>...<code>&lt;h6&gt;</code> Heading Elements</a></li>
+			<li><a href="chapter4.html#lists">Lists, Ordered (<code>&lt;ol&gt;</code>) and Unordered (<code>&lt;ul&gt;</code>)</a></li>
+			<li><a href="chapter4.html#divelement">The <code>&lt;div&gt;</code> Element</a></li>
+			<li><a href="chapter4.html#centerelement">The <code>&lt;center&gt;</code> Element (deprecated)</a></li>
+			<li><a href="chapter4.html#blockquoteelement">The <code>&lt;blockquote&gt;</code> Element</a></li>
+		</ul>
+		</li>
+	</ul>
+	</li>
+	<li><a href="chapter5.html#chapter5">5. Essential OEB Styles</a>
+	<ul>
+		<li><a href="chapter5.html#styleunits">Style Units</a></li>
+		<li><a href="chapter5.html#fontproperties">Font Properties</a>
+		<ul>
+			<li><a href="chapter5.html#fontfamilyproperty">The <code>font-family</code> Property</a></li>
+			<li><a href="chapter5.html#fontsizeproperty">The <code>font-size</code> Property</a></li>
+			<li><a href="chapter5.html#fontstyleproperty">The <code>font-style</code> Property</a></li>
+			<li><a href="chapter5.html#fontweightproperty">The <code>font-weight</code> Property</a></li>
+			<li><a href="chapter5.html#textdecorationproperty">The <code>text-decoration</code> Property</a></li>
+		</ul>
+		</li>
+	</ul>
+	</li>
+	<li><a href="chapter6.html#chapter6">6. Real-World OEB: Charter of the United Nations</a>
+	<ul>
+		<li><a href="chapter6.html#uncharterchapter2">UN Charter Chapter 2: <code>chapter2.html</code></a></li>
+		<li><a href="chapter6.html#uncharterchapter3">UN Charter Chapter 3: <code>chapter3.html</code></a></li>
+		<li><a href="chapter6.html#uncharterchapter1">UN Charter Chapter 1: <code>chapter1.html</code></a></li>
+		<li><a href="chapter6.html#uncharterintro">UN Charter Introductory Note: <code>intro.html</code></a></li>
+		<li><a href="chapter6.html#unchartertoc">Table of Contents: <code>toc.html</code></a></li>
+		<li><a href="chapter6.html#uncharterpackage">UN Charter Package File: <code>uncharter.opf</code></a></li>
+	</ul>
+	</li>
+</ul>	
+
+</body>
+</html>
--- /dev/null
+++ b/lib/ebooks/understandingoeb/understandingoeb.css
@@ -1,0 +1,28 @@
+.sidebar, sidebarTitle
+{
+	display: block;
+	background-color: silver;
+}
+
+h1
+{
+	font-family: sans-serif;
+	font-size: 130%;
+}
+
+h2
+{
+	font-family: sans-serif;
+	font-size: 120%;
+}
+
+h3
+{
+	font-family: sans-serif;
+	font-size: 110%;
+}
+
+blockquote
+{
+	font-size: 90%;
+}
--- /dev/null
+++ b/lib/ebooks/understandingoeb/understandingoeb.opf
@@ -1,0 +1,65 @@
+<?xml version="1.0"?>
+<!DOCTYPE package PUBLIC "+//ISBN 0-9673008-1-9//DTD OEB 1.0.1 Package//EN" "http://openebook.org/dtds/oeb-1.0.1/oebpkg101.dtd">
+<package unique-identifier="understandingoebpackage">
+  <metadata>
+    <dc-metadata xmlns:dc="http://purl.org/dc/elements/1.0/" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/">
+      <dc:Title>Understanding OEB</dc:Title>
+			<dc:Type>Tutorial</dc:Type>
+			<dc:Identifier id="understandingoebpackage" scheme="url">http://www.globalmentor.com/publishing/understandingoeb/</dc:Identifier>
+			<dc:Creator role="aut">Garret Wilson</dc:Creator>
+			<dc:Creator role="bkp">Mentor Publishing</dc:Creator>
+			<dc:Creator role="spn">GlobalMentor, Inc.</dc:Creator>
+			<dc:Contributor role="aui">David Ornstein</dc:Contributor>
+			<dc:Rights>Copyright &copy; 2000-2001 Garret Wilson. All Rights Reserved.</dc:Rights>
+			<dc:Date>2001-07-11</dc:Date>
+      <dc:Subject>OEB</dc:Subject>
+      <dc:Subject>eBooks</dc:Subject>
+      <dc:Subject>ePublishing</dc:Subject>
+    </dc-metadata>
+	</metadata>
+  
+  <manifest>
+    <!--OEB Documents-->
+    <item id="title" href="title.html" media-type="text/x-oeb1-document" />
+    <item id="toc" href="toc.html" media-type="text/x-oeb1-document" />
+    <item id="foreword" href="foreword.html" media-type="text/x-oeb1-document" />
+    <item id="preface" href="preface.html" media-type="text/x-oeb1-document" />
+    <item id="chapter1" href="chapter1.html" media-type="text/x-oeb1-document" />
+    <item id="chapter2" href="chapter2.html" media-type="text/x-oeb1-document" />
+    <item id="chapter3" href="chapter3.html" media-type="text/x-oeb1-document" />
+    <item id="chapter4" href="chapter4.html" media-type="text/x-oeb1-document" />
+    <item id="chapter5" href="chapter5.html" media-type="text/x-oeb1-document" />
+    <item id="chapter6" href="chapter6.html" media-type="text/x-oeb1-document" />
+    <!--Images-->
+    <item id="OEBActivityDiagram" href="OEBActivityDiagram.png" media-type="image/png" />
+    <item id="OEBClassDiagram" href="OEBClassDiagram.png" media-type="image/png" />
+    <item id="OEBPublicationClassDiagram" href="OEBPublicationClassDiagram.png" media-type="image/png" />
+    <item id="ReadingSystemClassDiagram" href="ReadingSystemClassDiagram.png" media-type="image/png" />
+  </manifest>
+
+  <spine>
+  	<itemref idref="title" />
+  	<itemref idref="toc" />
+  	<itemref idref="foreword" />
+  	<itemref idref="preface" />
+  	<itemref idref="chapter1" />
+  	<itemref idref="chapter2" />
+  	<itemref idref="chapter3" />
+  	<itemref idref="chapter4" />
+  	<itemref idref="chapter5" />
+  	<itemref idref="chapter6" />
+  </spine>
+
+  <guide>
+    <reference type="toc" title="Table of Contents" href="toc.html" />
+    <reference type="foreword" title="Foreword" href="foreword.html" />
+    <reference type="preface" title="Preface" href="preface.html" />
+    <reference type="other.chapter1" title="Chapter 1" href="chapter1.html" />
+    <reference type="other.chapter2" title="Chapter 2" href="chapter2.html" />
+    <reference type="other.chapter3" title="Chapter 3" href="chapter3.html" />
+    <reference type="other.chapter4" title="Chapter 4" href="chapter4.html" />
+		<reference type="other.chapter5" title="Chapter 5" href="chapter5.html" />
+		<reference type="other.chapter6" title="Chapter 6" href="chapter6.html" />
+  </guide>
+  
+</package>
--- /dev/null
+++ b/lib/emptydirs
@@ -1,0 +1,85 @@
+FreeBSD/386/lib
+Inferno/386/bin
+Inferno/386/lib
+Inferno/arm/bin
+Inferno/arm/lib
+Inferno/mips/bin
+Inferno/mips/lib
+Inferno/power/bin
+Inferno/power/lib
+Inferno/sparc/bin
+Inferno/sparc/lib
+Irix/mips/lib
+Linux/386/lib
+Linux/arm/bin
+Linux/arm/lib
+MacOSX/386/lib
+MacOSX/power/lib
+NetBSD/386/lib
+Nt/386/lib
+OpenBSD/386/bin
+OpenBSD/386/lib
+OpenBSD/arm/bin
+OpenBSD/arm/lib
+Plan9/386/bin
+Plan9/386/lib
+Plan9/arm/bin
+Plan9/arm/lib
+Plan9/mips/bin
+Plan9/mips/lib
+Plan9/power/bin
+Plan9/power/lib
+Plan9/sparc/bin
+Plan9/sparc/lib
+Solaris/sparc/lib
+keydb/countersigned
+keydb/countersigned
+keydb/signed
+keydb/signed
+mail
+man/lib/man
+man/lib/permind
+mnt
+mnt/9win
+mnt/acme
+mnt/arch
+mnt/diary
+mnt/factotum
+mnt/gossip
+mnt/icontact
+mnt/ilog
+mnt/incall
+mnt/isubs
+mnt/itrack
+mnt/keys
+mnt/keysrv
+mnt/quiz
+mnt/registry
+mnt/rstyxreg
+mnt/schedule
+mnt/vmail
+mnt/wm
+mnt/wrap
+mnt/wsys
+n
+n/cd
+n/client
+n/client/chan
+n/client/dev
+n/disk
+n/dist
+n/dump
+n/ftp
+n/gridfs
+n/kfs
+n/local
+n/rdbg
+n/registry
+n/remote
+services/logs
+services/ppp
+src
+tmp
+usr/inferno/charon
+usr/inferno/keyring
+usr/inferno/tmp
--- /dev/null
+++ b/lib/games/fortunes
@@ -1,0 +1,8 @@
+We are all interested in the future, for that is where you and I are going to spend the rest of our lives.  --Criswell, Plan 9 from Outer Space
+And remember my friend, future events such as these will affect you in the future.  --Criswell, Plan 9 from Outer Space
+We should all be concerned about the future because we will have to spend the rest of our lives there. --Charles F Kettering
+For I dipped into the future far as human eye could see. Saw the vision of the world and all the wonder that would be. --Locksley Hall, Alfred, Lord Tennyson
+Excess on occasion is exhilarating. It prevents moderation from acquiring the deadening effect of a habit. -- W Somerset Maugham
+The instruction at "0x77fcae88" referenced memory at "0x63610073".  The memory could not be "read".
+A company formed ``for carrying on an undertaking of great advantage, but nobody to know what it is.'' --Charles Mackay, ``Memoirs of Extraordinary Popular Delusions and the Madness of Crowds''
+You should be glad that bridge fell down — I was planning to build 13 more to the same design. -- Remark attributed to I K Brunel, addressing the Directors of the Great Western Railway.
binary files /dev/null b/lib/games/fortunes.index differ
--- /dev/null
+++ b/lib/ircnames
@@ -1,0 +1,1 @@
+#inferno	'Inferno general chat'	'freenode group reg'
--- /dev/null
+++ b/lib/keyboard
@@ -1,0 +1,559 @@
+00A1  !!          ¡	inverted exclamation mark
+00A2  c$          ¢	cent sign
+00A3  l$          £	pound sign
+00A4  g$          ¤	currency sign
+00A5  y$          ¥	yen sign
+00A6  ||          ¦	broken vertical bar
+00A7  SS          §	section sign
+00A8  ""          ¨	spacing diaeresis
+00A9  Oc cO       ©	copyright sign
+00AA  sa          ª	feminine ordinal indicator
+00AB  <<          «	left pointing guillemet
+00AC  no          ¬	not sign
+00AD  --          ­	soft hyphen
+00AE  Or rO       ®	registered trade mark sign
+00AF  __          ¯	spacing macron
+00B0  de          °	degree sign
+00B1  +-          ±	plus-or-minus sign
+00B2  S2          ²	superscript digit two
+00B3  S3          ³	superscript digit three
+00B4  ''          ´	spacing acute
+00B5  mi          µ	micro sign
+00B6  pg          ¶	paragraph sign
+00B7  ..          ·	middle dot
+00B8  ,,          ¸	spacing cedilla
+00B9  S1          ¹	superscript digit one
+00BA  so          º	masculine ordinal indicator
+00BB  >>          »	right pointing guillemet
+00BC  14          ¼	fraction one quarter
+00BD  12          ½	fraction one half
+00BE  34          ¾	fraction three quarters
+00BF  ??          ¿	inverted question mark
+00C0  `A          À	latin capital letter a grave
+00C1  'A          Á	latin capital letter a acute
+00C2  ^A          Â	latin capital letter a circumflex
+00C3  ~A          Ã	latin capital letter a tilde
+00C4  "A          Ä	latin capital letter a diaeresis
+00C5  oA          Å	latin capital letter a ring
+00C6  AE          Æ	latin capital letter a e
+00C7  ,C          Ç	latin capital letter c cedilla
+00C8  `E          È	latin capital letter e grave
+00C9  'E          É	latin capital letter e acute
+00CA  ^E          Ê	latin capital letter e circumflex
+00CB  "E          Ë	latin capital letter e diaeresis
+00CC  `I          Ì	latin capital letter i grave
+00CD  'I          Í	latin capital letter i acute
+00CE  ^I          Î	latin capital letter i circumflex
+00CF  "I          Ï	latin capital letter i diaeresis
+00D0  -D D-       Ð	latin capital letter eth
+00D1  ~N          Ñ	latin capital letter n tilde
+00D2  `O          Ò	latin capital letter o grave
+00D3  'O          Ó	latin capital letter o acute
+00D4  ^O          Ô	latin capital letter o circumflex
+00D5  ~O          Õ	latin capital letter o tilde
+00D6  "O          Ö	latin capital letter o diaeresis
+00D7  mu          ×	multiplication sign
+00D8  /O          Ø	latin capital letter o slash
+00D9  `U          Ù	latin capital letter u grave
+00DA  'U          Ú	latin capital letter u acute
+00DB  ^U          Û	latin capital letter u circumflex
+00DC  "U          Ü	latin capital letter u diaeresis
+00DD  'Y          Ý	latin capital letter y acute
+00DE  |P          Þ	latin capital letter thorn
+00DF  ss          ß	latin small letter sharp s
+00E0  `a          à	latin small letter a grave
+00E1  'a          á	latin small letter a acute
+00E2  ^a          â	latin small letter a circumflex
+00E3  ~a          ã	latin small letter a tilde
+00E4  "a          ä	latin small letter a diaeresis
+00E5  oa          å	latin small letter a ring
+00E6  ae          æ	latin small letter a e
+00E7  ,c          ç	latin small letter c cedilla
+00E8  `e          è	latin small letter e grave
+00E9  'e          é	latin small letter e acute
+00EA  ^e          ê	latin small letter e circumflex
+00EB  "e          ë	latin small letter e diaeresis
+00EC  `i          ì	latin small letter i grave
+00ED  'i          í	latin small letter i acute
+00EE  ^i          î	latin small letter i circumflex
+00EF  "i          ï	latin small letter i diaeresis
+00F0  -d d-       ð	latin small letter eth
+00F1  ~n          ñ	latin small letter n tilde
+00F2  `o          ò	latin small letter o grave
+00F3  'o          ó	latin small letter o acute
+00F4  ^o          ô	latin small letter o circumflex
+00F5  ~o          õ	latin small letter o tilde
+00F6  "o          ö	latin small letter o diaeresis
+00F7  -: :-       ÷	division sign
+00F8  /o          ø	latin small letter o slash
+00F9  `u          ù	latin small letter u grave
+00FA  'u          ú	latin small letter u acute
+00FB  ^u          û	latin small letter u circumflex
+00FC  "u          ü	latin small letter u diaeresis
+00FD  'y          ý	latin small letter y acute
+00FE  |p          þ	latin small letter thorn
+00FF  "y          ÿ	latin small letter y diaeresis
+0100  _A          Ā	latin capital letter a macron
+0101  _a          ā	latin small letter a macron
+0102  uA          Ă	latin capital letter a breve
+0104  ,A          Ą	latin capital letter a ogonek
+0105  ,a          ą	latin small letter a ogonek
+0106  'C          Ć	latin capital letter c acute
+0107  'c          ć	latin small letter c acute
+0108  ^C          Ĉ	latin capital letter c circumflex
+0109  ^c          ĉ	latin small letter c circumflex
+010A  .C          Ċ	latin capital letter c dot
+010B  .c          ċ	latin small letter c dot
+010C  vC          Č	latin capital letter c hacek
+010D  vc          č	latin small letter c hacek
+010E  vD          Ď	latin capital letter d hacek
+010F  vd          ď	latin small letter d hacek
+0112  _E          Ē	latin capital letter e macron
+0113  _e          ē	latin small letter e macron
+0114  uE          Ĕ	latin capital letter e breve
+0115  ue          ĕ	latin small letter e breve
+0116  .E          Ė	latin capital letter e dot
+0117  .e          ė	latin small letter e dot
+0118  ,E          Ę	latin capital letter e ogonek
+0119  ,e          ę	latin small letter e ogonek
+011A  vE          Ě	latin capital letter e hacek
+011B  ve          ě	latin small letter e hacek
+011C  ^G          Ĝ	latin capital letter g circumflex
+011D  ^g          ĝ	latin small letter g circumflex
+011E  uG          Ğ	latin capital letter g breve
+011F  ug          ğ	latin small letter g breve
+0120  .G          Ġ	latin capital letter g dot
+0121  .g          ġ	latin small letter g dot
+0122  ,G          Ģ	latin capital letter g cedilla
+0123  'g ,g       ģ	latin small letter g cedilla
+0124  ^H          Ĥ	latin capital letter h circumflex
+0125  ^h          ĥ	latin small letter h circumflex
+0126  -H H-       Ħ	latin capital letter h bar
+0128  ~I          Ĩ	latin capital letter i tilde
+0129  ~i          ĩ	latin small letter i tilde
+012A  _I          Ī	latin capital letter i macron
+012B  _i          ī	latin small letter i macron
+012C  uI          Ĭ	latin capital letter i breve
+012D  ui          ĭ	latin small letter i breve
+012E  ,I          Į	latin capital letter i ogonek
+012F  ,i          į	latin small letter i ogonek
+0130  .I          İ	latin capital letter i dot
+0131   i          ı	latin small letter dotless i
+0132  IJ          IJ	latin capital letter i j
+0133  ij          ij	latin small letter i j
+0134  ^J          Ĵ	latin capital letter j circumflex
+0135  ^j          ĵ	latin small letter j circumflex
+0136  ,K          Ķ	latin capital letter k cedilla
+0137  ,k          ķ	latin small letter k cedilla
+0139  'L          Ĺ	latin capital letter l acute
+013A  'l          ĺ	latin small letter l acute
+013B  ,L          Ļ	latin capital letter l cedilla
+013C  ,l          ļ	latin small letter l cedilla
+013D  vL          Ľ	latin capital letter l hacek
+013E  vl          ľ	latin small letter l hacek
+013F  .L          Ŀ	latin capital letter l with middle dot
+0140  .l          ŀ	latin small letter l with middle dot
+0141  -L L-       Ł	latin capital letter l slash
+0142  -l l-       ł	latin small letter l slash
+0143  'N          Ń	latin capital letter n acute
+0144  'n          ń	latin small letter n acute
+0145  ,N          Ņ	latin capital letter n cedilla
+0146  ,n          ņ	latin small letter n cedilla
+0147  vN          Ň	latin capital letter n hacek
+0148  vn          ň	latin small letter n hacek
+014C  _O          Ō	latin capital letter o macron
+014D  _o          ō	latin small letter o macron
+014E  uO          Ŏ	latin capital letter o breve
+014F  uo          ŏ	latin small letter o breve
+0152  OE          Œ	latin capital letter o e
+0153  oe          œ	latin small letter o e
+0154  'R          Ŕ	latin capital letter r acute
+0155  'r          ŕ	latin small letter r acute
+0156  ,R          Ŗ	latin capital letter r cedilla
+0157  ,r          ŗ	latin small letter r cedilla
+0158  vR          Ř	latin capital letter r hacek
+0159  vr          ř	latin small letter r hacek
+015A  'S          Ś	latin capital letter s acute
+015B  's          ś	latin small letter s acute
+015C  ^S          Ŝ	latin capital letter s circumflex
+015D  ^s          ŝ	latin small letter s circumflex
+015E  ,S          Ş	latin capital letter s cedilla
+015F  ,s          ş	latin small letter s cedilla
+0160  vS          Š	latin capital letter s hacek
+0161  vs          š	latin small letter s hacek
+0162  ,T          Ţ	latin capital letter t cedilla
+0163  ,t          ţ	latin small letter t cedilla
+0164  vT          Ť	latin capital letter t hacek
+0165  vt          ť	latin small letter t hacek
+0166  -T T-       Ŧ	latin capital letter t bar
+0167  -t t-       ŧ	latin small letter t bar
+0168  ~U          Ũ	latin capital letter u tilde
+0169  ~u          ũ	latin small letter u tilde
+016A  _U          Ū	latin capital letter u macron
+016B  _u          ū	latin small letter u macron
+016C  uU          Ŭ	latin capital letter u breve
+016D  uu          ŭ	latin small letter u breve
+016E  oU          Ů	latin capital letter u ring
+016F  ou          ů	latin small letter u ring
+0172  ,U          Ų	latin capital letter u ogonek
+0173  ,u          ų	latin small letter u ogonek
+0174  ^W          Ŵ	latin capital letter w circumflex
+0175  ^w          ŵ	latin small letter w circumflex
+0176  ^Y          Ŷ	latin capital letter y circumflex
+0177  ^y          ŷ	latin small letter y circumflex
+0178  "Y          Ÿ	latin capital letter y diaeresis
+0179  'Z          Ź	latin capital letter z acute
+017A  'z          ź	latin small letter z acute
+017B  .Z          Ż	latin capital letter z dot
+017C  .z          ż	latin small letter z dot
+017D  vZ          Ž	latin capital letter z hacek
+017E  vz          ž	latin small letter z hacek
+0180  -b          ƀ	latin small letter b bar
+0192  $f          ƒ	latin small letter script f
+0195  hv          ƕ	latin small letter h v
+0197  -I I-       Ɨ	latin capital letter barred i
+019B  -*l         ƛ	latin small letter barred lambda
+01A2  OI          Ƣ	latin capital letter o i
+01A3  oi          ƣ	latin small letter o i
+01A6  YR          Ʀ	latin letter y r
+01B2  $V          Ʋ	latin capital letter script v
+01B5  -Z Z-       Ƶ	latin capital letter z bar
+01B6  -z z-       ƶ	latin small letter z bar
+01BB  -2 2-       ƻ	latin letter two bar
+01C4  DvZ         DŽ	latin capital letter d z hacek
+01C5  Dvz         Dž	latin letter capital d small z hacek
+01C6  dvz         dž	latin small letter d z hacek
+01C7  LJ          LJ	latin capital letter l j
+01C8  Lj          Lj	latin letter capital l small j
+01C9  lj          lj	latin small letter l j
+01CA  NJ          NJ	latin capital letter n j
+01CB  Nj          Nj	latin letter capital n small j
+01CC  nj          nj	latin small letter n j
+01CD  vA          Ǎ	latin capital letter a hacek
+01CE  va          ǎ	latin small letter a hacek
+01CF  vI          Ǐ	latin capital letter i hacek
+01D0  vi          ǐ	latin small letter i hacek
+01D1  vO          Ǒ	latin capital letter o hacek
+01D2  vo          ǒ	latin small letter o hacek
+01D3  vU          Ǔ	latin capital letter u hacek
+01D4  vu          ǔ	latin small letter u hacek
+01D5  _"U         Ǖ	latin capital letter u diaeresis macron
+01D6  _"u         ǖ	latin small letter u diaeresis macron
+01D7  '"U         Ǘ	latin capital letter u diaeresis acute
+01D8  '"u         ǘ	latin small letter u diaeresis acute
+01D9  v"U         Ǚ	latin capital letter u diaeresis hacek
+01DA  v"u         ǚ	latin small letter u diaeresis hacek
+01DB  `"U         Ǜ	latin capital letter u diaeresis grave
+01DC  `"u         ǜ	latin small letter u diaeresis grave
+01DE  _"A         Ǟ	latin capital letter a diaeresis macron
+01DF  _"a         ǟ	latin small letter a diaeresis macron
+01E0  _.A         Ǡ	latin capital letter a dot macron
+01E1  _.a         ǡ	latin small letter a dot macron
+01E4  -G G-       Ǥ	latin capital letter g bar
+01E5  -g g-       ǥ	latin small letter g bar
+01E6  vG          Ǧ	latin capital letter g hacek
+01E7  vg          ǧ	latin small letter g hacek
+01E8  vK          Ǩ	latin capital letter k hacek
+01E9  vk          ǩ	latin small letter k hacek
+01EA  ,O          Ǫ	latin capital letter o ogonek
+01EB  ,o          ǫ	latin small letter o ogonek
+01EC  _,O         Ǭ	latin capital letter o ogonek macron
+01ED  _,o         ǭ	latin small letter o ogonek macron
+01F0  vj          ǰ	latin small letter j hacek
+0251  $a          ɑ	latin small letter script a
+0268  -i i-       ɨ	latin small letter barred i
+0289  -u u-       ʉ	latin small letter u bar
+028B  $v          ʋ	latin small letter script v
+02A3  dz          ʣ	latin small letter d z
+0391  *A          Α	greek capital letter alpha
+0392  *B          Β	greek capital letter beta
+0393  *G          Γ	greek capital letter gamma
+0394  *D          Δ	greek capital letter delta
+0395  *E          Ε	greek capital letter epsilon
+0396  *Z          Ζ	greek capital letter zeta
+0397  *Y          Η	greek capital letter eta
+0398  *H          Θ	greek capital letter theta
+0399  *I          Ι	greek capital letter iota
+039A  *K          Κ	greek capital letter kappa
+039B  *L          Λ	greek capital letter lambda
+039C  *M          Μ	greek capital letter mu
+039D  *N          Ν	greek capital letter nu
+039E  *C          Ξ	greek capital letter xi
+039F  *O          Ο	greek capital letter omicron
+03A0  *P          Π	greek capital letter pi
+03A1  *R          Ρ	greek capital letter rho
+03A3  *S          Σ	greek capital letter sigma
+03A4  *T          Τ	greek capital letter tau
+03A5  *U          Υ	greek capital letter upsilon
+03A6  *F          Φ	greek capital letter phi
+03A7  *X          Χ	greek capital letter chi
+03A8  *Q          Ψ	greek capital letter psi
+03A9  *W          Ω	greek capital letter omega
+03AA  "*I         Ϊ	greek capital letter iota diaeresis
+03AB  "*U         Ϋ	greek capital letter upsilon diaeresis
+03B1  *a          α	greek small letter alpha
+03B2  *b          β	greek small letter beta
+03B3  *g          γ	greek small letter gamma
+03B4  *d          δ	greek small letter delta
+03B5  *e          ε	greek small letter epsilon
+03B6  *z          ζ	greek small letter zeta
+03B7  *y          η	greek small letter eta
+03B8  *h          θ	greek small letter theta
+03B9  *i          ι	greek small letter iota
+03BA  *k          κ	greek small letter kappa
+03BB  *l          λ	greek small letter lambda
+03BC  *m          μ	greek small letter mu
+03BD  *n          ν	greek small letter nu
+03BE  *c          ξ	greek small letter xi
+03BF  *o          ο	greek small letter omicron
+03C0  *p          π	greek small letter pi
+03C1  *r          ρ	greek small letter rho
+03C2  ts          ς	greek small letter final sigma
+03C3  *s          σ	greek small letter sigma
+03C4  *t          τ	greek small letter tau
+03C5  *u          υ	greek small letter upsilon
+03C6  *f          φ	greek small letter phi
+03C7  *x          χ	greek small letter chi
+03C8  *q          ψ	greek small letter psi
+03C9  *w          ω	greek small letter omega
+03CA  "*i         ϊ	greek small letter iota diaeresis
+03CB  "*u         ϋ	greek small letter upsilon diaeresis
+03D1  $*h         ϑ	greek small letter script theta
+03D5  $*f         ϕ	greek small letter script phi
+03F0  $*k         ϰ	greek small letter script kappa
+0401  @YO @Yo     Ё	cyrillic capital letter io
+0410  @A          А	cyrillic capital letter a
+0411  @B          Б	cyrillic capital letter be
+0412  @V          В	cyrillic capital letter ve
+0413  @G          Г	cyrillic capital letter ge
+0414  @D          Д	cyrillic capital letter de
+0415  @@E @YE @Ye Е	cyrillic capital letter ie
+0416  @ZH @Zh     Ж	cyrillic capital letter zhe
+0417  @@Z         З	cyrillic capital letter ze
+0418  @I          И	cyrillic capital letter ii
+0419  @J          Й	cyrillic capital letter short ii
+041A  @@K         К	cyrillic capital letter ka
+041B  @L          Л	cyrillic capital letter el
+041C  @M          М	cyrillic capital letter em
+041D  @N          Н	cyrillic capital letter en
+041E  @O          О	cyrillic capital letter o
+041F  @P          П	cyrillic capital letter pe
+0420  @R          Р	cyrillic capital letter er
+0421  @@S         С	cyrillic capital letter es
+0422  @@T         Т	cyrillic capital letter te
+0423  @U          У	cyrillic capital letter u
+0424  @F          Ф	cyrillic capital letter ef
+0425  @KH @Kh @X  Х	cyrillic capital letter kha
+0426  @TS @Ts     Ц	cyrillic capital letter tse
+0427  @CH @Ch     Ч	cyrillic capital letter che
+0428  @SH @Sh     Ш	cyrillic capital letter sha
+0429  @SC @Sc     Щ	cyrillic capital letter shcha
+042B  @@Y         Ы	cyrillic capital letter yeri
+042D  @EH @Eh     Э	cyrillic capital letter reversed e
+042E  @YU @Yu     Ю	cyrillic capital letter iu
+042F  @YA @Ya     Я	cyrillic capital letter ia
+0430  @a          а	cyrillic small letter a
+0431  @b          б	cyrillic small letter be
+0432  @v          в	cyrillic small letter ve
+0433  @g          г	cyrillic small letter ge
+0434  @d          д	cyrillic small letter de
+0435  @@e @ye     е	cyrillic small letter ie
+0436  @zh         ж	cyrillic small letter zhe
+0437  @@z         з	cyrillic small letter ze
+0438  @i          и	cyrillic small letter ii
+0439  @j          й	cyrillic small letter short ii
+043A  @@k         к	cyrillic small letter ka
+043B  @l          л	cyrillic small letter el
+043C  @m          м	cyrillic small letter em
+043D  @n          н	cyrillic small letter en
+043E  @o          о	cyrillic small letter o
+043F  @p          п	cyrillic small letter pe
+0440  @r          р	cyrillic small letter er
+0441  @@s         с	cyrillic small letter es
+0442  @@t         т	cyrillic small letter te
+0443  @u          у	cyrillic small letter u
+0444  @f          ф	cyrillic small letter ef
+0445  @kh @x      х	cyrillic small letter kha
+0446  @ts         ц	cyrillic small letter tse
+0447  @ch         ч	cyrillic small letter che
+0448  @sh         ш	cyrillic small letter sha
+0449  @sc         щ	cyrillic small letter shcha
+044A  @''         ъ	cyrillic small letter hard sign
+044B  @@y         ы	cyrillic small letter yeri
+044C  @@'         ь	cyrillic small letter soft sign
+044D  @eh         э	cyrillic small letter reversed e
+044E  @yu         ю	cyrillic small letter iu
+044F  @ya         я	cyrillic small letter ia
+0451  @yo         ё	cyrillic small letter io
+2018  l'          ‘	single turned comma quotation mark
+2019  r'          ’	single comma quotation mark
+201C  l"          “	double turned comma quotation mark
+201D  r"          ”	double comma quotation mark
+2020  dg          †	dagger
+2021  dd          ‡	double dagger
+2022  bu          •	bullet
+203D  !? ?!       ‽	interrobang
+2070  s0          ⁰	superscript digit zero
+2071  s1          ⁱ	superscript digit one
+2072  s2          ⁲	superscript digit two
+2073  s3          ⁳	superscript digit three
+2074  s4          ⁴	superscript digit four
+2075  s5          ⁵	superscript digit five
+2076  s6          ⁶	superscript digit six
+2077  s7          ⁷	superscript digit seven
+2078  s8          ⁸	superscript digit eight
+2079  s9          ⁹	superscript digit nine
+207A  s+          ⁺	superscript plus sign
+207B  s-          ⁻	superscript hyphen-minus
+207C  s=          ⁼	superscript equals sign
+207D  s(          ⁽	superscript opening parenthesis
+207E  s)          ⁾	superscript closing parenthesis
+207F  sn          ⁿ	superscript latin small letter n
+2013  en          –	en dash
+2014  em          –	em dash
+2080  b0          ₀	subscript digit zero
+2081  b1          ₁	subscript digit one
+2082  b2          ₂	subscript digit two
+2083  b3          ₃	subscript digit three
+2084  b4          ₄	subscript digit four
+2085  b5          ₅	subscript digit five
+2086  b6          ₆	subscript digit six
+2087  b7          ₇	subscript digit seven
+2088  b8          ₈	subscript digit eight
+2089  b9          ₉	subscript digit nine
+208A  b+          ₊	subscript plus sign
+208B  b-          ₋	subscript hyphen-minus
+208C  b=          ₌	subscript equals sign
+208D  b(          ₍	subscript opening parenthesis
+208E  b)          ₎	subscript closing parenthesis
+20AC  e$          €	euro symbol
+2102  CC          ℂ	double-struck capital c
+210A  $g          ℊ	script small g
+210B  $H          ℋ	script capital h
+210D  HH          ℍ	double-struck capital h
+210F  -h h-       ℏ	planck constant over 2 pi
+2110  $I          ℐ	script capital i
+2112  $L          ℒ	script capital l
+2113  $l          ℓ	script small l
+2115  NN          ℕ	double-struck capital n
+2117  Op pO       ℗	sound recording copyright
+2118  $p          ℘	script p
+2119  PP          ℙ	double-struck capital p
+211A  QQ          ℚ	double-struck capital q
+211B  $R          ℛ	script capital r
+211D  RR          ℝ	double-struck capital r
+2122  tm          ™	trademark
+2124  ZZ          ℤ	double-struck capital z
+212C  $B          ℬ	script capital b
+212F  $e          ℯ	script small e
+2130  $E          ℰ	script capital e
+2131  $F          ℱ	script capital f
+2133  $M          ℳ	script capital m
+2134  $o          ℴ	script small o
+2153  13          ⅓	fraction one third
+2154  23          ⅔	fraction two thirds
+2155  15          ⅕	fraction one fifth
+2156  25          ⅖	fraction two fifths
+2157  35          ⅗	fraction three fifths
+2158  45          ⅘	fraction four fifths
+2159  16          ⅙	fraction one sixth
+215A  56          ⅚	fraction five sixths
+215B  18          ⅛	fraction one eighth
+215C  38          ⅜	fraction three eighths
+215D  58          ⅝	fraction five eighths
+215E  78          ⅞	fraction seven eighths
+2190  <-          ←	left arrow
+2191  ua          ↑	up arrow
+2192  ->          →	right arrow
+2193  da          ↓	down arrow
+2194  ab          ↔	left right arrow
+21D0  V=          ⇐	left double arrow
+21D2  =V          ⇒	right double arrow
+2200  fa          ∀	for all
+2202  pd          ∂	partial differential
+2203  te          ∃	there exists
+2205  es          ∅	empty set
+2206  De          ∆	increment
+2207  gr          ∇	nabla
+2208  mo          ∈	element of
+2209  !m          ∉	not an element of
+220D  st          ∍	small contains as member
+220F  pr          ∏	n-ary product
+2211  su          ∑	n-ary summation
+2213  -+          ∓	minus-or-plus sign
+2217  **          ∗	asterisk operator
+221A  sr          √	square root
+221D  pt          ∝	proportional to
+221E  if          ∞	infinity
+2220  an          ∠	angle
+2227  l&          ∧	logical and
+2228  l|          ∨	logical or
+2229  ca          ∩	intersection
+222A  cu          ∪	union
+222B  is          ∫	integral
+2234  tf          ∴	therefore
+2242  -~          ≂	minus tilde
+2243  ~-          ≃	asymptotically equal to
+2244  !~-         ≄	not asymptotically equal to
+2245  cg ~=       ≅	approximately equal to
+2246  ~!=         ≆	approximately but not actually equal to
+2247  !~=         ≇	neither approximately nor actually equal to
+2248  ~~          ≈	almost equal to
+2249  !~~         ≉	not almost equal to
+2254  :=          ≔	colon equal
+2255  =:          ≕	equal colon
+2260  !=          ≠	not equal to
+2261  ==          ≡	identical to
+2264  <=          ≤	less than or equal to
+2265  >=          ≥	greater than or equal to
+2268  <!=         ≨	less than but not equal to
+2269  >!=         ≩	greater than but not equal to
+226E  !<          ≮	not less than
+226F  !>          ≯	not greater than
+2272  <~          ≲	less than or equivalent to
+2273  >~          ≳	greater than or equivalent to
+2276  <>          ≶	less than or greater than
+2277  ><          ≷	greater than or less than
+2282  sb          ⊂	subset of
+2283  sp          ⊃	superset of
+2284  !b          ⊄	not a subset of
+2285  !p          ⊅	not a superset of
+2286  ib          ⊆	subset of or equal to
+2287  ip          ⊇	superset of or equal to
+2295  +O O+       ⊕	circled plus
+2296  -O O-       ⊖	circled minus
+2297  Ox xO       ⊗	circled times
+2298  O/          ⊘	circled division slash
+2299  .O O.       ⊙	circled dot operator
+229A  Oo oO       ⊚	circled ring operator
+229B  O*          ⊛	circled asterisk operator
+229C  =O O=       ⊜	circled equals
+22A2  tu          ⊢	right tack
+22A8  Tu          ⊨	true
+22C0  L&          ⋀	n-ary logical and
+22C1  L|          ⋁	n-ary logical or
+22C2  CA          ⋂	n-ary intersection
+22C3  CU          ⋃	n-ary union
+22C4  lz          ⋄	diamond operator
+22DC  =<          ⋜	equal to or less than
+22DD  =>          ⋝	equal to or greater than
+22E6  <!~         ⋦	less than but not equivalent to
+22E7  >!~         ⋧	greater than but not equivalent to
+22EF  el          ⋯	midline horizontal ellipsis
+2423              ␣	open box, visible space
+263A  :)          ☺ smiley face
+2654  wk          ♔	white chess king
+2655  wq          ♕	white chess queen
+2656  wr          ♖	white chess rook
+2657  wb          ♗	white chess bishop
+2658  wn          ♘	white chess knight
+2659  wp          ♙	white chess pawn
+265A  bk          ♚	black chess king
+265B  bq          ♛	black chess queen
+265C  br          ♜	black chess rook
+265D  bb          ♝	black chess bishop
+265E  bn          ♞	black chess knight
+265F  bp          ♟	black chess pawn
+F015  ZA          	raw alt (plan 9 specific)
+F016  ZS          	raw shift (plan 9 specific)
+F017  ZC          	raw ctl (plan 9 specific)
--- /dev/null
+++ b/lib/legal/GPL
@@ -1,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+++ b/lib/legal/LGPL
@@ -1,0 +1,450 @@
+GNU LESSER GENERAL PUBLIC LICENSE
+
+Version 2.1, February 1999
+
+Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+[This is the first released version of the Lesser GPL. It also counts
+as the successor of the GNU Library Public License, version 2, hence
+the version number 2.1.]
+
+Preamble
+
+The licenses for most software are designed to take away your freedom
+to share and change it. By contrast, the GNU General Public Licenses
+are intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.
+
+This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+To protect each distributor, we want to make it very clear that there
+is no warranty for the free library. Also, if the library is modified
+by someone else and passed on, the recipients should know that what
+they have is not the original version, so that the original author's
+reputation will not be affected by problems that might be introduced
+by others.
+
+Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+When a program is linked with a library, whether statically or using a
+shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+We call this license the"Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a"work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called"this License"). Each
+licensee is addressed as"you".
+
+A"library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+The"Library", below, refers to any such software library or work which
+has been distributed under these terms. A"work based on the Library"
+means either the Library or any derivative work under copyright law:
+that is to say, a work containing the Library or a portion of it,
+either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term"modification".)
+
+"Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does and
+what the program that uses the Library does.
+
+1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a
+fee.
+
+2. You may modify your copy or copies of the Library or any portion of
+it, thus forming a work based on the Library, and copy and distribute
+such modifications or work under the terms of Section 1 above,
+provided that you also meet all of these conditions:
+
+• a) The modified work must itself be a software library.
+• b) You must cause the files modified to carry prominent notices
+stating that you changed the files and the date of any change.
+• c) You must cause the whole of the work to be licensed at no charge
+to all third parties under the terms of this License.
+• d) If a facility in the modified Library refers to a function or a
+table of data to be supplied by an application program that uses the
+facility, other than as an argument passed when the facility is
+invoked, then you must make a good faith effort to ensure that, in the
+event an application does not supply such function or table, the
+facility still operates, and performs whatever part of its purpose
+remains meaningful.
+
+(For example, a function in a library to compute square roots has a
+purpose that is entirely well-defined independent of the application.
+Therefore, Subsection 2d requires that any application-supplied
+function or table used by this function must be optional: if the
+application does not supply it, the square root function must still
+compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+Once this change is made in a given copy, it is irreversible for that
+copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+This option is useful when you wish to copy part of the code of the
+Library into a program that is not a library.
+
+4. You may copy and distribute the Library (or a portion or derivative
+of it, under Section 2) in object code or executable form under the
+terms of Sections 1 and 2 above provided that you accompany it with
+the complete corresponding machine-readable source code, which must be
+distributed under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange.
+
+If distribution of object code is made by offering access to copy from
+a designated place, then offering equivalent access to copy the source
+code from the same place satisfies the requirement to distribute the
+source code, even though third parties are not compelled to copy the
+source along with the object code.
+
+5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a"work that uses the Library". Such a work,
+in isolation, is not a derivative work of the Library, and therefore
+falls outside the scope of this License.
+
+However, linking a"work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a"work that uses the
+library". The executable is therefore covered by this License. Section
+6 states terms for distribution of such executables.
+
+When a"work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+If such an object file uses only numerical parameters, data structure
+layouts and accessors, and small macros and small inline functions
+(ten lines or less in length), then the use of the object file is
+unrestricted, regardless of whether it is legally a derivative work.
+(Executables containing this object code plus portions of the Library
+will still fall under Section 6.)
+
+Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+6. As an exception to the Sections above, you may also combine or link
+a"work that uses the Library" with the Library to produce a work
+containing portions of the Library, and distribute that work under
+terms of your choice, provided that the terms permit modification of
+the work for the customer's own use and reverse engineering for
+debugging such modifications.
+
+You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+• a) Accompany the work with the complete corresponding
+machine-readable source code for the Library including whatever
+changes were used in the work (which must be distributed under
+Sections 1 and 2 above); and, if the work is an executable linked with
+the Library, with the complete machine-readable"work that uses the
+Library", as object code and/or source code, so that the user can
+modify the Library and then relink to produce a modified executable
+containing the modified Library. (It is understood that the user who
+changes the contents of definitions files in the Library will not
+necessarily be able to recompile the application to use the modified
+definitions.)
+• b) Use a suitable shared library mechanism for linking with the
+Library. A suitable mechanism is one that (1) uses at run time a copy
+of the library already present on the user's computer system, rather
+than copying library functions into the executable, and (2) will
+operate properly with a modified version of the library, if the user
+installs one, as long as the modified version is interface-compatible
+with the version that the work was made with.
+• c) Accompany the work with a written offer, valid for at least three
+years, to give the same user the materials specified in Subsection 6a,
+above, for a charge no more than the cost of performing this
+distribution.
+• d) If distribution of the work is made by offering access to copy
+from a designated place, offer equivalent access to copy the above
+specified materials from the same place.
+• e) Verify that the user has already received a copy of these
+materials or that you have already sent this user a copy.
+
+For an executable, the required form of the"work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+• a) Accompany the combined library with a copy of the same work based
+on the Library, uncombined with any other library facilities. This
+must be distributed under the terms of the Sections above.
+• b) Give prominent notice with the combined library of the fact that
+part of it is a work based on the Library, and explaining where to
+find the accompanying uncombined form of the same work.
+
+8. You may not copy, modify, sublicense, link with, or distribute the
+Library except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, link with, or distribute the
+Library is void, and will automatically terminate your rights under
+this License. However, parties who have received copies, or rights,
+from you under this License will not have their licenses terminated so
+long as such parties remain in full compliance.
+
+9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time. Such
+new versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and"any
+later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+NO WARRANTY
+
+15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY"AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+END OF TERMS AND CONDITIONS
--- /dev/null
+++ b/lib/legal/NOTICE.app
@@ -1,0 +1,4 @@
+This Inferno® software distribution is subject to your Inferno system and application commercial licence(s).
+It must not be used except as allowed by that licence.
+It must not be redistributed outside your organisation unless otherwise agreed,
+or deployed in greater numbers than allowed by your licence.
--- /dev/null
+++ b/lib/legal/NOTICE.ffal
@@ -1,0 +1,34 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+	Portions Copyright © 1997-1999 Vita Nuova Limited
+	Portions Copyright © 2000-2005 Vita Nuova Holdings Limited (www.vitanuova.com)
+	Portions Copyright © 2004,2005 Bruce Ellis
+	Portions Copyright © 2005 C H Forsyth (forsyth@terzarima.net)
+	Revisions Copyright © 2000-2005 Lucent Technologies Inc. and others
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/lib/legal/NOTICE.gpl
@@ -1,0 +1,25 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2005 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/lib/legal/NOTICE.lgpl
@@ -1,0 +1,25 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2005 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/lib/legal/NOTICE.liberal
@@ -1,0 +1,38 @@
+This Inferno® distribution includes software from various sources and
+different portions are therefore subject to different licence terms.
+
+You may copy and redistribute the package as a whole,
+with or without modification, subject to the terms of the Vita Nuova
+Liberal Source Licence (see the file LICENCE), which applies to the
+package as a whole, and to individual components unless otherwise
+specified either in an individual source file or in a NOTICE file
+in a directory or directory tree.  If the terms of that licence are not acceptable,
+you must negotiate other terms with Vita Nuova (www.vitanuova.com).
+
+Individual components (eg, some of the libraries, Freetype, and the
+B&H fonts) might have their own NOTICE and licence files (LICENCE or
+COPYING) that cover their content.  Be sure to read them before
+considering redistribution of them on their own.
+With the exception of the B&H font licence, each is typically
+some variety of Free Software licence.
+
+Where a given section of source code is distributed elsewhere (as a separable component) under
+another licence or licences, and we include it here as well under ours, you can obviously
+regard it as subject to whichever licence you like.
+
+When making non-trivial extracts, or your own modifications, you must
+retain the copyright of the original source file or files (either that
+present in the file or in a NOTICE file covering the directory or
+directories in which the file resides).
+
+The following copyright notice covers the contents of this
+distribution unless otherwise specified by a given file, directory, or
+directory tree:
+
+Inferno® Copyright © 1996-1999 Lucent Technologies Inc.  All rights reserved.
+Inferno revisions Copyright © 1997-1999 Vita Nuova Limited.  All rights reserved.
+Inferno revisions Copyright © 2000-2003 Vita Nuova Holdings Limited.  All rights reserved.
+Inferno new material Copyright © 2000-2003 Vita Nuova Holdings Limited.  All rights reserved.
+
+Inferno, Styx, Dis and Limbo are registered trademarks of Vita Nuova Holdings Limited in the USA and other countries.
+Plan 9 is a registered trademark of Lucent Technologies Inc.
--- /dev/null
+++ b/lib/legal/calderalic.pdf
@@ -1,0 +1,80 @@
+%PDF-1.2
%����
+3 0 obj
<< 
/Linearized 1 
/O 5 
/H [ 1100 188 ] 
/L 12298 
/E 12048 
/N 1 
/T 12121 
>> 
endobj
                                                            xref
3 32 
0000000016 00000 n
+0000000984 00000 n
+0000001288 00000 n
+0000001492 00000 n
+0000001692 00000 n
+0000001799 00000 n
+0000002084 00000 n
+0000002158 00000 n
+0000002343 00000 n
+0000002392 00000 n
+0000002572 00000 n
+0000003072 00000 n
+0000003093 00000 n
+0000003928 00000 n
+0000003949 00000 n
+0000004804 00000 n
+0000004825 00000 n
+0000005513 00000 n
+0000005534 00000 n
+0000006207 00000 n
+0000006228 00000 n
+0000007010 00000 n
+0000007031 00000 n
+0000007787 00000 n
+0000007808 00000 n
+0000008568 00000 n
+0000008589 00000 n
+0000008999 00000 n
+0000009279 00000 n
+0000011745 00000 n
+0000001100 00000 n
+0000001268 00000 n
+trailer
<<
/Size 35
/Info 1 0 R 
/Root 4 0 R 
/Prev 12112 
/ID[<8db5c844284c4d38daa1aaf376efa260><8db5c844284c4d38daa1aaf376efa260>]
>>
startxref
0
%%EOF
     
4 0 obj
<< 
/Type /Catalog 
/Pages 2 0 R 
/OpenAction [ 5 0 R /XYZ null null null ] 
/PageMode /UseNone 
>> 
endobj
33 0 obj
<< /S 36 /Filter /FlateDecode /Length 34 0 R >> 
stream
+H�b``�c``+�40�O`����g� �<��%H@�+H�T����0��>�G��މ�����4q�Hĉ�t�ۓ�b�%���9��ֻ�L+YR�P�E�,H�[{m�l?_��f���H���M��jd���u�D)�!|_�;�,��+endstream
endobj
9 0 obj
<< 
/Type /Encoding 
/Differences [ 1 /registersans ] 
>> 
endobj
10 0 obj
<< 
/Type /FontDescriptor 
/Ascent 891 
/CapHeight 0 
/Descent -216 
/Flags 34 
/FontBBox [ -77 -216 1009 877 ] 
/FontName /TimesNewRoman 
/ItalicAngle 0 
/StemV 0 
>> 
endobj
11 0 obj
[ 
/Indexed 12 0 R 255 30 0 R 
]
endobj
12 0 obj
[ 
/CalRGB << /WhitePoint [ 0.9505 1 1.089 ] /Gamma [ 2.22221 2.22221 2.22221 ] 
/Matrix [ 0.4124 0.2126 0.0193 0.3576 0.71519 0.1192 0.1805 0.0722 0.9505 ] >> 

]
endobj
13 0 obj
<< 
/Type /Font 
/Subtype /TrueType 
/FirstChar 32 
/LastChar 121 
/Widths [ 250 0 0 0 0 0 0 180 333 333 500 0 250 333 250 278 500 500 500 500 
500 500 500 500 500 500 278 278 0 0 0 0 0 722 667 667 722 611 556 
722 722 333 389 0 611 889 722 722 556 722 667 556 611 722 722 944 
722 722 0 0 0 0 0 0 333 444 500 444 500 444 333 500 500 278 0 500 
278 778 500 500 500 0 333 389 278 500 500 722 500 500 ] 
/Encoding /WinAnsiEncoding 
/BaseFont /TimesNewRoman 
/FontDescriptor 10 0 R 
>> 
endobj
14 0 obj
757 
endobj
15 0 obj
<< /Filter /FlateDecode /Length 14 0 R >> 
stream
+H��TMo�@U���9�Jf�,�^�(UrhU�����ʱ[ M��;3�8�*��%3��f����M�)���\�����
+�‚�+h���c��c��N�um ��!�������QFk5�l�ډ��6I�Ҙ�&�����ad�9U+S�U�$+|�2�L+�Ō�B9,
+�;k%�Q���ndZ���}?˻�:��2��6����hgDY}�G�rb�E0\�-��Qjؒ���d��f0^�g�O�*ԯ8��Q5"ˢ���V��X��(z���օ��'��D񪄍R	�W>�:�͔պ����3x_7�/�译����`�/iH�����,��ܻ���eL܁;}3����ϲ���/#����$�i���o8��9��/L�b��-�NA�^i�'m�54�>�<�.�����pκ? [jnd��mp���w�؀̌�: M���1�<�y^DCHX�G���+=��}LÍ���餸��F�^�A��$��
�KaA�9h�mѡ
̻�P+"�퉵N�9��>�k���
���yȍ�V��Q�L�ၷnp<��8P�2f>�8�?���rx5��O"^�u�����^��|a]ub]���7��H��[1���m��C�Á��>��;��B;�xb� "DF2b��"a�8�},հ>����1��x�B�v�B��ãf�G`�M9����{Z�?'RP�%���������q1?KS*bo�L���X�n���$�̯��+H�dT�n�0��+�H� �Z��\�C�NP��A�G�b�����'�Egy3on�/�_E^��;+��e�+�j@�
++�	�@��[>������+�6�BC�7XU�}0"��� ��%�P�g�%ԟ�
g�� �WR�Az��ju���L�D�ǽ�
�N���~�y�tWB2^&KzY�3X��Q��8YV��@��8��ئP2Q�a�݀�L#MDC(�d��$V�Fʖ�lÏG�y�m�#i���~F����)Z�*h]����}��h!�>A(gA���+H�tTMo�0��W�(
�`��w+��v|[{p51஁�5��)��
l�D��G>�Oݏ]�2g]Uת���m�{��!��Vu��/���i��1�t���n2Wk�4��z�+��y��P7/�ׄ�He}6�-uP�)�+[�i�{�W���>s�BR�>�_5���}?�kl�gq>�5e��b9&�CP�����aQ�T�+	y�7����h�P��q�L�Qm	����l��B�ګH�‡��{��TL�-J��w�'~
��%���"�w��*LL�}�z�j�+0+H�tT�n�0��,E`͈:�~�-w��,�dˠh��g�R�mD���x���&U[k�r��7�I�ԪC�JK����{w�����^�f�L��GQ<uel���Z��<��ΦI�hw�Y�dRӸ�sz[PX۩z�t�I��	�V��"ݴ�!2��}��U9���7����+�����_ٷS�q��:��ξp��C���U\�\D���~��2�I
1�j�&ծ����v�չ�瞚U�qf0ƞ���eUŕV^�����),u[S$�.I���0e���P"(�mSSъD�t�I�3�O���v+:hY�t�3J�k�[0�hχ���ܢ�x��w�Q����x�aQY�����r�YN�?��`}�� JD��O��,��ȁ9�+�����^�ˎ�E-�6�-���x+�Ģ!�Ԥ �7C+H�lT=��0��+�D��A�mH�I��"]&J„�< ߍ�}�Kܤ1�~�ݷ^����Cj������!��<����T��};�H���4A7�Ԟ��jNY�8�e�d�2�1Ϛ�b�cvJ~��Xd6y1�Ɋ����汛4~Yc����N��rr_k�m_◩)�sc�l�/n/}�Ľ�]+\
����~���A[^��������PU���^±A@��
�g�|�D���wS��+O�+%�b��b��<�L��^!pE����m�^jF>[�+�0'g��;�a�+�~Ga�v�o[cl@!��J)-{�`xvp�\�]*8�2xE�q��]ŃJ���e`J��k��+n�R+H�lT�n�0��+���	Q�me��Yhq(9�QЏ��wRv�^,s�f{o����������)3Y�������KX~?�T���t�Eome*u��?���l?�vo����)8��mmjt����w��ӄ���T��ع���g��a^oKcU�F,�H*u�rl�(�.�'�~LyP�R�1���Oc#7������D�lY�V����a/la��䊂[d�<�v��%r<���?W�!.�'>��៟1��Ll������Je�������"�AW���9a+Tg��&s��]�4&�LDZ�����V't�fH#w_��N��IΥW+����c
+��b.�g�U5�U������)��j�W��B�P�GA����-V��[i�}�����W�Ţ/����,(�MӌKZ"7��t^L�d45=�+H��uPq�ܛ�f���M���:���s��}�Bw�\iY�g*a	C)��獱&>G1�gx���z�gy�6&��:�L_8���YU��}�E#t�!/���L(*��He�'O����4�3���z~`�x��[�b�˽�!�{��^�m���h�qJ5͚0�zM�}#��S�0Aj`�d�����+H�|TMo�0��W�(
�k���)��DEc
��"Xz��!X�튡�~�D9M�d����������a��2M6�Y|�G���N4|�L��w"?X7K�ID�'o!��/덐2n.|�E���iQ���R`������|K2Q|9�4m ��j��Ǭ����)<
+�k�隟#�6�t���Y5��sռ� �#CT�B����< ���v��H�2�K6vPƤHJ_�ɪ%�V3n���D�k�k�2x�mu���u�e&�7�7�Q���W{5�֧#|����b�C��llI�>�\b��)3�.Ci��(�8}q���E��B���`����!��=�+IpK��"�b0���e֬GBX0�0C=���e�t{����$�q-`�����L��$�^'̬L`\܆��Z(h���לnwn��2Ҟ��h��s�?�)��n���a.�8/���Q+�@��=�=A�o~��`$�������H�Bs��3��px
��_�,��|����e/���ƛ„����黈
+��S
���m7�IwU*��|�'��",�Q4�}:=�+H�\QMK1�ﯘcRLH�;W��E�����lc
mwe[��;+��L^޼7o֮
+�(�TJ�`�X�5��b�����f�t�\�\T�c���>�k����#��B��R7-�-�^IʪO�K?��:�w��[�y)
��{Y�-	��Cw]c�?�K�륪A���
+���BWc����俀
A�%
{�#�%<�
N�s��g��{�9$.Cb�9��]����;\�K~�у;�N���8R����`?�^È�}0�1,�O��3ND��:�hdl+�d7�MR^��11��a�qb��<����0+���}�&��0߃-+H�b``�ͬu��}=�(''g����8�r����mM###����gQ�2�K�����?m.ikkM�9>{挖��-��nݺ�[o~߳����[�=|{v���O^}��ַ[�n��u����O�>�������~~z����}��}���ߏ��������?�?����������������߯��}���������$��g��z+endstream
endobj
31 0 obj
<< /Type /XObject /Subtype /Image /Width 156 /Height 81 /BitsPerComponent 8 
/ColorSpace 11 0 R /Length 2298 /Filter /FlateDecode >> 
stream
+H�̗�r���f�,��`0q";7��*_��lw�$��äV����T�ҧ����ڦ��aհ5�'6��털l��ކ4��ǭ9��p�rR��j�o���c����;�|�
+>O������8���-C�<%{��P��I�Q\��	����j&��4���w�X����;�$6$�P�c&�-#K�\�4�����i���
=;�Y`9��*l�`�I�j�N���UU�б/����V�.Q������ƀ-�o���]|05,��Z��J�
�
Us@���3�;�Ee�'�bZK�sv���~���K��sV���N����\�W>�q��c�[9G����C9.��_�ņ٥)	%��i%��0�lʼne�p���~�d����n241�-5p����ܹ
�~띕F��qp5����0��7��!�TR�E�9�'3tC�I�dgN����5�U����������Bf+-3�BL�^h�?��͂��Kl�ү�M��* ]e����"Ƌ�M٢n連��A�cDy4FD�%�����5���;R=Q+��ھ��
T\��Khp
+�%�l�W�\+��,+΢h�$�3�l��A���ѳɡ�R�K4��O�m�d+H��B���hř'/V��;68v�u
�E��c;�Oo+��D���SR�>�[F04�ۺ(�,��V��l��	P51"��|�TnBq��F��`�+b�0#��UF�s�B�f�/���̓l8[Vp�;��R�!��!�ؓ
+8ϳ��$7*^�G�8R�>����wFZڨ��EP��ྡྷ���4�y�m��KM����P���z~�CT
+��<��d�,E���2��#�!����(��R$�Dn�:��޵'�(*�8�����j���<�9�EpD����}R��!,����_�ֶ���-�Ri�#�.�p؄"���r;6�+�G:�+_a��B��>0#��<ow%����m���Gt3��m��츷�a���O�v��hӡ�<�gG��V��'�t<�d����k��+endstream
endobj
32 0 obj
<< 
/Type /ExtGState 
/SA false 
/SM 0.02 
/TR /Identity 
>> 
endobj
1 0 obj
<< 
/Producer (Acrobat Distiller 4.05 for Windows)
/Creator (Microsoft Word 8.0)
/ModDate (D:20020123204028-08'00')
/Author (Bill Broderick)
/Title (Dear Unix enthusiasts,)
/CreationDate (D:20020123203956)
>> 
endobj
2 0 obj
<< 
/Type /Pages 
/Kids [ 5 0 R ] 
/Count 1 
>> 
endobj
xref
0 3 
0000000000 65535 f
+0000011823 00000 n
+0000012048 00000 n
+trailer
<<
/Size 3
/ID[<8db5c844284c4d38daa1aaf376efa260><8db5c844284c4d38daa1aaf376efa260>]
>>
startxref
173
%%EOF
\ No newline at end of file
--- /dev/null
+++ b/lib/legal/lucent
@@ -1,0 +1,237 @@
+Lucent Public License Version 1.02
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
+     Program, and
+  b. in the case of each Contributor,
+
+     i. changes to the Program, and
+    ii. additions to the Program;
+
+    where such changes and/or additions to the Program were added to the
+    Program by such Contributor itself or anyone acting on such
+    Contributor's behalf, and the Contributor explicitly consents, in
+    accordance with Section 3C, to characterization of the changes and/or
+    additions as Contributions.
+
+"Contributor" means LUCENT and any other entity that has Contributed a
+Contribution to the Program.
+
+"Distributor" means a Recipient that distributes the Program,
+modifications to the Program, or any part thereof.
+
+"Licensed Patents" mean patent claims licensable by a Contributor
+which are necessarily infringed by the use or sale of its Contribution
+alone or when combined with the Program.
+
+"Original Program" means the original version of the software
+accompanying this Agreement as released by LUCENT, including source
+code, object code and documentation, if any.
+
+"Program" means the Original Program and Contributions or any part
+thereof
+
+"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free copyright
+    license to reproduce, prepare derivative works of, publicly display,
+    publicly perform, distribute and sublicense the Contribution of such
+    Contributor, if any, and such derivative works, in source code and
+    object code form.
+    
+ b. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free patent
+    license under Licensed Patents to make, use, sell, offer to sell,
+    import and otherwise transfer the Contribution of such Contributor, if
+    any, in source code and object code form. The patent license granted
+    by a Contributor shall also apply to the combination of the
+    Contribution of that Contributor and the Program if, at the time the
+    Contribution is added by the Contributor, such addition of the
+    Contribution causes such combination to be covered by the Licensed
+    Patents. The patent license granted by a Contributor shall not apply
+    to (i) any other combinations which include the Contribution, nor to
+    (ii) Contributions of other Contributors. No hardware per se is
+    licensed hereunder.
+    
+ c. Recipient understands that although each Contributor grants the
+    licenses to its Contributions set forth herein, no assurances are
+    provided by any Contributor that the Program does not infringe the
+    patent or other intellectual property rights of any other entity. Each
+    Contributor disclaims any liability to Recipient for claims brought by
+    any other entity based on infringement of intellectual property rights
+    or otherwise. As a condition to exercising the rights and licenses
+    granted hereunder, each Recipient hereby assumes sole responsibility
+    to secure any other intellectual property rights needed, if any. For
+    example, if a third party patent license is required to allow
+    Recipient to distribute the Program, it is Recipient's responsibility
+    to acquire that license before distributing the Program.
+
+ d. Each Contributor represents that to its knowledge it has sufficient
+    copyright rights in its Contribution, if any, to grant the copyright
+    license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A. Distributor may choose to distribute the Program in any form under
+this Agreement or under its own license agreement, provided that:
+
+ a. it complies with the terms and conditions of this Agreement;
+
+ b. if the Program is distributed in source code or other tangible
+    form, a copy of this Agreement or Distributor's own license agreement
+    is included with each copy of the Program; and
+
+ c. if distributed under Distributor's own license agreement, such
+    license agreement:
+
+      i. effectively disclaims on behalf of all Contributors all warranties
+         and conditions, express and implied, including warranties or
+         conditions of title and non-infringement, and implied warranties or
+         conditions of merchantability and fitness for a particular purpose;
+     ii. effectively excludes on behalf of all Contributors all liability
+         for damages, including direct, indirect, special, incidental and
+         consequential damages, such as lost profits; and
+    iii. states that any provisions which differ from this Agreement are
+         offered by that Contributor alone and not by any other party.
+
+B. Each Distributor must include the following in a conspicuous
+   location in the Program:
+
+   Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
+   Reserved.
+
+C. In addition, each Contributor must identify itself as the
+originator of its Contribution in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+Also, each Contributor must agree that the additions and/or changes
+are intended to be a Contribution. Once a Contribution is contributed,
+it may not thereafter be revoked.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use
+of the Program, the Distributor who includes the Program in a
+commercial product offering should do so in a manner which does not
+create potential liability for Contributors. Therefore, if a
+Distributor includes the Program in a commercial product offering,
+such Distributor ("Commercial Distributor") hereby agrees to defend
+and indemnify every Contributor ("Indemnified Contributor") against
+any losses, damages and costs (collectively"Losses") arising from
+claims, lawsuits and other legal actions brought by a third party
+against the Indemnified Contributor to the extent caused by the acts
+or omissions of such Commercial Distributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement.
+In order to qualify, an Indemnified Contributor must: a) promptly
+notify the Commercial Distributor in writing of such claim, and b)
+allow the Commercial Distributor to control, and cooperate with the
+Commercial Distributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such
+claim at its own expense.
+
+For example, a Distributor might include the Program in a commercial
+product offering, Product X. That Distributor is then a Commercial
+Distributor. If that Commercial Distributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Distributor's responsibility
+alone. Under this section, the Commercial Distributor would have to
+defend claims against the Contributors related to those performance
+claims and warranties, and if a court requires any Contributor to pay
+any damages as a result, the Commercial Distributor must pay those
+damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement, including but not limited to
+the risks and costs of program errors, compliance with applicable
+laws, damage to or loss of data, programs or equipment, and
+unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
+ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. EXPORT CONTROL
+
+Recipient agrees that Recipient alone is responsible for compliance
+with the United States export administration regulations (and the
+export control laws and regulation of any other countries).
+
+8. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with
+respect to a patent applicable to software (including a cross-claim or
+counterclaim in a lawsuit), then any patent licenses granted by that
+Contributor to such Recipient under this Agreement shall terminate as
+of the date such litigation is filed. In addition, if Recipient
+institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program
+itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and
+survive.
+
+LUCENT may publish new versions (including revisions) of this
+Agreement from time to time. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new
+version of the Agreement is published, Contributor may elect to
+distribute the Program (including its Contributions) under the new
+version. No one other than LUCENT has the right to modify this
+Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
+Recipient receives no rights or licenses to the intellectual property
+of any Contributor under this Agreement, whether expressly, by
+implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No
+party to this Agreement will bring a legal action under this Agreement
+more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.
+
--- /dev/null
+++ b/lib/lego/llp.h
@@ -1,0 +1,4 @@
+#define LLP_ALTERNATING		0x01
+#define LLP_POLL_IMMEDIATE	0x02
+#define LLP_POLL_PERIODIC	0x04
+#define LLP_COMPRESSION		0x08
--- /dev/null
+++ b/lib/lego/styx.c
@@ -1,0 +1,1113 @@
+/*
+ *  styx.c
+ *
+ *  A Styx fileserver for a Lego RCX
+ *
+ *  Nigel Roles
+ *  Vita Nuova
+ *
+ *  This is a heavily modified version of test5.c
+ *
+ *  I couldn't have done this without Kekoa...
+ *
+ *
+ *  The contents of this file are subject to the Mozilla Public License
+ *  Version 1.0 (the "License"); you may not use this file except in
+ *  compliance with the License. You may obtain a copy of the License at
+ *  http://www.mozilla.org/MPL/
+ *
+ *  Software distributed under the License is distributed on an "AS IS"
+ *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ *  License for the specific language governing rights and limitations
+ *  under the License.
+ *
+ *  The Original Code is Librcx sample program code, released February 9,
+ *  1999.
+ *
+ *  The Initial Developer of the Original Code is Kekoa Proudfoot.
+ *  Portions created by Kekoa Proudfoot are Copyright (C) 1999
+ *  Kekoa Proudfoot. All Rights Reserved.
+ *
+ *  Contributor(s): Kekoa Proudfoot <kekoa@graphics.stanford.edu>
+ */
+
+//#include "stdlib.h"
+#include "rom.h"
+
+#include "lib9.h"
+#include "styx.h"
+
+#include "llp.h"
+
+#define ASSERT(cond) if (!(cond)) fatal(__LINE__)
+#define FATAL fatal(__LINE__)
+#define PROGRESS progress(__LINE__)
+
+#if 0
+#define ABP
+#endif
+
+uchar *send_fid_reply_payload(void);
+void send_fid_reply(uchar type, ushort tag, ushort fid, uchar *msg, short len);
+void send_error_reply(unsigned short tag, char *msg);
+
+static unsigned short msgcount;
+static unsigned char compressed_incoming[150];
+static unsigned char incoming[1024];
+static unsigned char compressed_reply[150];
+short compressed_reply_len;
+static unsigned char reply[1024];
+unsigned short reply_len;
+unsigned short transmitted_reply_len;
+unsigned char alternating_bit;
+static uchar dir[116];
+uchar prepared;
+uchar reader_count;
+uchar dispatch[6];
+
+/* ROM pseudofunctions */
+
+static inline void
+set_data_pointer (void *ptr)
+{
+    play_sound_or_set_data_pointer(0x1771, (short)ptr, 0);
+}
+
+static inline char
+check_valid (void)
+{
+	char valid;
+	check_for_data(&valid, NULL);
+	return valid;
+}
+
+static inline int
+receive_message (void *ptr, int len)
+{
+	char bytes = 0;
+	receive_data(ptr, len, &bytes);
+	/* Bytes includes checksum, since we don't want that, return bytes-1 */
+	return bytes - 1;
+}
+
+static inline void
+send_message (void *ptr, int len)
+{
+	if (len)
+		while (send_data(0x1776, 0, ptr, len));
+}
+
+int
+poll_power(void)
+{
+	static short debounce = 0;
+	static short state = -1;
+	short status;
+	get_power_status(0x4000, &status);
+	if (state != status)
+		debounce = 0;
+	else if (debounce < 10)
+		debounce++;
+	state = status;
+	return debounce >= 10 ? state : -1;
+}
+
+static void
+progress(short line)
+{
+	set_lcd_number(LCD_UNSIGNED, line, LCD_DECIMAL_0);
+	refresh_display();
+}
+
+static void
+fatal(short line)
+{
+	set_lcd_segment(LCD_STANDING);
+	progress(line);
+	while (poll_power() != 0)
+		;
+}
+
+typedef struct Reader {
+	ushort tag;
+	ushort fid;
+	ushort offset;
+	ushort count;
+	struct Reader *next;
+} Reader;
+
+typedef struct DirectoryEntry {
+	char *name;
+	uchar qid;
+	const struct DirectoryEntry *sub;
+	short (*read)(const struct DirectoryEntry *dp, ushort tag, ushort fid, ushort offset, ushort count);
+	short (*write)(const struct DirectoryEntry *dp, ushort offset, ushort count, uchar *buf);
+} DirectoryEntry;
+
+#define QID_ROOT 0
+#define QID_MOTOR 1
+#define QID_MOTOR_0 2
+#define QID_MOTOR_1 3
+#define QID_MOTOR_2 4
+#define QID_MOTOR_012 5
+#define QID_SENSOR 6
+#define QID_SENSOR_0 7
+#define QID_SENSOR_1 8
+#define QID_SENSOR_2 9
+
+typedef struct Sensor {
+	sensor_t sensor;
+	uchar active;
+	uchar greater;
+	ushort thresh;
+	Reader *reader;
+} Sensor;
+
+Sensor sensor[3];
+
+short
+atoin(char *s, short lim)
+{
+	short total = 0;
+	while (*s && lim) {
+		char c = *s++;
+		if (c >= '0' && c <= '9')
+			total = total * 10 + c - '0';
+		else
+			break;
+		lim--;
+	}
+	return total;
+}
+
+short
+itoa(char *buf, short value)
+{
+	char *bp = buf;
+	short divisor;
+	if (value < 0) {
+		*bp++ = '-';
+		value = -value;
+	}
+	if (value == 0)
+		*bp++ = '0';
+	else {
+		divisor = 10000;
+		while (divisor > value)
+			divisor /= 10;
+		while (divisor) {
+			*bp++ = '0' + value / divisor;
+			value %= divisor;
+			divisor /= 10;
+		}
+	}
+	return bp - buf;
+}
+
+Reader *
+readercreate(ushort tag, ushort fid, ushort offset, ushort count)
+{
+	Reader *rp = malloc(sizeof(Reader));
+	rp->tag = tag;
+	rp->fid = fid;
+	rp->offset = offset;
+	rp->count = count;
+	rp->next = 0;
+	reader_count++;
+	return rp;
+}
+
+void
+readerfree(Reader *rp)
+{
+	free(rp);
+	reader_count--;
+}
+
+int
+senderrorreset(Reader *rp, void *magic)
+{
+	send_error_reply(rp->tag, "reset");
+	return 1;
+}
+
+void
+readerlistfindanddestroy(Reader **rpp, int (*action)(Reader *rp, void *magic), void *magic)
+{
+	while (*rpp) {
+		Reader *rp = *rpp;
+		if ((*action)(rp, magic)) {
+			*rpp = rp->next;
+			readerfree(rp);
+		}
+		else
+			rpp = &(rp->next);
+	}
+}
+
+void
+allreaderlistfindanddestroy(int (*action)(Reader *rp, void *magic), void *magic)
+{
+	short i;
+	for (i = 0; i < 3; i++)
+		readerlistfindanddestroy(&sensor[i].reader, action, magic);
+}
+
+short
+sensorwrite(const DirectoryEntry *dp, ushort offset, ushort count, uchar *data)
+{
+	short i;
+	Sensor *sp;
+	uchar greater;
+	short type, mode;
+	ushort k;
+
+	if (offset != 0)
+		return -1;
+	i = dp->qid - QID_SENSOR_0;
+	sp = &sensor[i];
+	k = count;
+	if (k == 0)
+		return -1;
+	switch (data[0]) {
+	case 'b':
+		type = SENSOR_TYPE_TOUCH;
+		mode = SENSOR_MODE_PULSE;
+		break;
+	case 'l':
+		type = SENSOR_TYPE_TOUCH;
+		mode = SENSOR_MODE_RAW;
+		break;
+	default:
+		return -1;
+	}
+	data++; k--;
+	if (k == 0)
+		return -1;
+	if (*data == '>') {
+		greater = 1;
+		data++;
+		k--;
+	}
+	else if (*data == '<') {
+		greater = 0;
+		data++;
+		k--;
+	}
+	else
+		greater = 1;
+	if (k == 0)
+		return -1;
+	readerlistfindanddestroy(&sp->reader, senderrorreset, 0);
+	set_sensor_passive(SENSOR_0 + i);
+	sp->sensor.type = type;
+	sp->sensor.mode = mode;
+	sp->thresh = atoin(data, k);
+	sp->sensor.raw = 0;
+	sp->sensor.value = 0;
+	sp->sensor.boolean = 0;
+	sp->active = 1;
+	sp->greater = greater;
+	set_sensor_active(SENSOR_0 + i);
+	return count;
+}
+
+void
+send_read_reply(ushort tag, ushort fid, ushort offset, ushort len, uchar *answer, short answerlen)
+{
+	uchar *out = send_fid_reply_payload();
+	ushort actual;
+	if (offset < answerlen) {
+		actual = answerlen - offset;
+		if (actual > len)
+			actual = len;
+		memcpy(out + 3, answer + offset, actual);
+	}
+	else
+		actual = 0;
+	out[0] = actual;
+	out[1] = actual >> 8;
+	out[2] = 0;
+	send_fid_reply(Rread, tag, fid, 0, actual + 3);
+}
+
+void
+send_sensor_read_reply(ushort tag, ushort fid, ushort offset, ushort count, short value)
+{
+	short answerlen;
+	char answer[8];
+	/* reply is countlow counthigh pad data[count] */
+	answerlen = itoa(answer, value);
+	send_read_reply(tag, fid, offset, count, answer, answerlen);
+}
+
+int
+sensortriggered(Sensor *sp)
+{
+	if (sp->greater)
+		return sp->sensor.value >= sp->thresh;
+	else
+		return sp->sensor.value < sp->thresh;
+}
+
+short
+sensorread(const struct DirectoryEntry *dp, ushort tag, ushort fid, ushort offset, ushort count)
+{
+	short i;
+	Sensor *sp;
+	i = dp->qid - QID_SENSOR_0;
+	sp = sensor + i;
+	if (!sp->active)
+		return -1;
+	if (sensortriggered(sp))
+		send_sensor_read_reply(tag, fid, offset, count, sp->sensor.value);
+	else {
+		/* add to queue */
+		Reader *rp = readercreate(tag, fid, offset, count);
+		rp->next = sp->reader;
+		sp->reader = rp;
+	}
+	return 0;
+}
+
+void
+sensorpoll(void)
+{
+	short i;
+	Sensor *sp;
+
+	if ((dispatch[0] & 0x80) == 0) {
+		return;
+	}
+	dispatch[0] &= 0x7f;
+	/* do the following every 3 ms with a following wind */
+	for (i = 0; i < 3; i++) {
+		sp = sensor + i;
+		if (sp->active) {
+			/*
+			 * read sensor 4 times to reduce debounce on each
+			 * edge to effectively 25 counts, or 75ms
+			 * allowing about 8 pulses a second
+			 */
+			read_sensor(SENSOR_0 + i, &sp->sensor);
+			read_sensor(SENSOR_0 + i, &sp->sensor);
+			read_sensor(SENSOR_0 + i, &sp->sensor);
+			read_sensor(SENSOR_0 + i, &sp->sensor);
+			if (sensortriggered(sp)) {
+				/* complete any outstanding reads */
+				while (sp->reader) {
+					Reader *rp = sp->reader;
+					sp->reader = rp->next;
+					send_sensor_read_reply(rp->tag, rp->fid, rp->offset, rp->count, sp->sensor.value);
+					readerfree(rp);
+				}
+			}
+		}
+	}
+}
+
+short
+motorparse(uchar *flag, short *mode, short *power, uchar *data)
+{
+	switch (data[0]) {
+	case 'f': *mode = MOTOR_FWD; break;
+	case 'r': *mode = MOTOR_REV; break;
+	case 's': *mode = MOTOR_STOP; break;
+	case 'F': *mode = MOTOR_FLOAT; break;
+	case '-': return 1;
+	default:
+		return 0;
+	}
+	if (data[1] >= '0' && data[1] <= '7')
+		*power = data[1] - '0';
+	else
+		return 0;
+	*flag = 1;
+	return 1;
+}
+
+short
+motorwrite(const DirectoryEntry *dp, ushort offset, ushort count, uchar *data)
+{
+	short mode[3], power[3];
+	uchar flag[3];
+	short i;
+
+	if (offset != 0)
+		return -1;
+	flag[0] = flag[1] = flag[2] = 0;
+	if (dp->qid == QID_MOTOR_012) {
+		if (count != 6)
+			return -1;
+		if (!motorparse(flag, mode, power, data)
+		 || !motorparse(flag + 1, mode + 1, power + 1, data + 2)
+		 || !motorparse(flag + 2, mode + 2, power + 2, data + 4))
+			return -1;
+	}
+	else {
+		if (count != 2)
+			return -1;
+		i = dp->qid - QID_MOTOR_0;
+		if (!motorparse(flag + i, mode + i, power + i, data))
+			return -1;
+	}
+	for (i = 0; i < 3; i++)
+		if (flag[i])
+			control_motor(MOTOR_0 + i, mode[i], power[i]);
+	return count;
+}
+
+const uchar qid_root[8] = { QID_ROOT, 0, 0, 0x80 };
+
+const DirectoryEntry dir_root[], dir_slash[];
+
+const DirectoryEntry dir_motor[] = {
+	{ "..", QID_ROOT, dir_root },
+	{ "0", QID_MOTOR_0,	0, 0, motorwrite },
+	{ "1", QID_MOTOR_1,	0, 0, motorwrite },
+	{ "2", QID_MOTOR_2,	0, 0, motorwrite },
+	{ "012", QID_MOTOR_012, 0, 0, motorwrite },
+	{ 0 }
+};
+
+const DirectoryEntry dir_sensor[] = {
+	{ "..", QID_ROOT, dir_root },
+	{ "0", QID_SENSOR_0,	0, sensorread, sensorwrite },
+	{ "1", QID_SENSOR_1,	0, sensorread, sensorwrite },
+	{ "2", QID_SENSOR_2,	0, sensorread, sensorwrite },
+	{ 0 }
+};
+
+const DirectoryEntry dir_root[] = {
+	{ "..", QID_ROOT, dir_slash },
+	{ "motor", QID_MOTOR, dir_motor },
+	{ "sensor", QID_SENSOR, dir_sensor },
+	{ 0 }
+};
+
+const DirectoryEntry dir_slash[] = {
+	{ "/", QID_ROOT, dir_root },
+	{ 0 }
+};
+
+const DirectoryEntry *qid_map[] = {
+	/* QID_ROOT */		&dir_slash[0],
+	/* QID_MOTOR */		&dir_root[1],
+	/* QID_MOTOR_0 */	&dir_motor[1],
+	/* QID_MOTOR_1 */	&dir_motor[2],
+	/* QID_MOTOR_2 */	&dir_motor[3],
+	/* QID_MOTOR_012 */	&dir_motor[4],
+	/* QID_SENSOR */	&dir_root[2],
+	/* QID_SENSOR_0 */	&dir_sensor[1],
+	/* QID_SENSOR_1 */	&dir_sensor[2],
+	/* QID_SENSOR_2 */	&dir_sensor[3],
+};
+
+#define QID_MAP_MAX (sizeof(qid_map) / sizeof(qid_map[0]))
+
+typedef struct Fid {
+	struct Fid *next;
+	ushort fid;
+	uchar open;
+	uchar qid[8];
+} Fid;
+
+Fid *fids;
+
+Fid *
+fidfind(ushort fid)
+{
+	Fid *fp;
+	for (fp = fids; fp && fp->fid != fid; fp = fp->next)
+		;
+	return fp;
+}
+
+Fid *
+fidcreate(ushort fid, const uchar qid[8])
+{
+	Fid *fp;
+	fp = malloc(sizeof(Fid));
+	ASSERT(fp);
+	fp->open = 0;
+	fp->fid = fid;
+	fp->next = fids;
+	memcpy(fp->qid, qid, 8);
+	fids = fp;
+	return fp;
+}
+
+int
+matchfp(Reader *rp, void *magic)
+{
+	if (rp->fid == ((Fid *)magic)->fid) {
+		return 1;
+	}
+	return 0;
+}
+
+void
+fiddelete(Fid *fp)
+{
+	Fid **fpp;
+	/* clobber any outstanding reads on this fid */
+	allreaderlistfindanddestroy(matchfp, fp);
+	/* now clobber the fid */
+	for (fpp = &fids; *fpp; fpp = &(*fpp)->next)
+		if (*fpp == fp) {
+			*fpp = fp->next;
+			free(fp);
+			return;
+		}
+	FATAL;
+}
+
+const DirectoryEntry *
+nthentry(const DirectoryEntry *dp, ushort n)
+{
+	const DirectoryEntry *sdp;
+	ASSERT(dp->sub);
+	for (sdp = dp->sub; sdp->name; sdp++)
+		if (strcmp(sdp->name, "..") != 0) {
+			if (n == 0)
+				return sdp;
+			n--;
+		}
+	return 0;
+}
+
+int
+fidwalk(Fid *fp, char name[28])
+{
+	const DirectoryEntry *sdp;
+	const DirectoryEntry *dp;
+
+	if (fp->open)
+		return -1;
+	ASSERT(fp->qid[0] < QID_MAP_MAX);
+	dp = qid_map[fp->qid[0]];
+	if (dp->sub == 0)
+		return -1;
+	for (sdp = dp->sub; sdp->name; sdp++)
+		if (strcmp(sdp->name, name) == 0) {
+			fp->qid[0] = sdp->qid;
+			fp->qid[3] = sdp->sub ? 0x80 : 0;
+			return 1;
+		}
+	return 0;
+}
+
+void
+mkdirent(const DirectoryEntry *dp, uchar *dir)
+{
+	memset(dir, 0, DIRLEN);
+	strcpy(dir, dp->name);
+	strcpy(dir + 28, "lego");
+	strcpy(dir + 56, "lego");
+	dir[84] = dp->qid;
+	dir[92] = dp->sub ? 0555 : 0666;
+	dir[93] = dp->sub ? (0555 >> 8) : (0666 >> 8);
+	dir[95] = dp->sub ? 0x80 : 0;
+}
+
+int
+fidstat(Fid *fp, uchar *dir)
+{
+	const DirectoryEntry *dp;
+	if (fp->open)
+		return -1;
+	ASSERT(fp->qid[0] < QID_MAP_MAX);
+	dp = qid_map[fp->qid[0]];
+	mkdirent(dp, dir);
+	return 1;
+}
+
+int
+fidopen(Fid *fp, uchar mode)
+{
+	if (fp->open
+	    || (mode & ORCLOSE)
+	    /*|| (mode & OTRUNC) */)
+		return 0;
+	if (fp->qid[3] && (mode == OWRITE || mode == ORDWR))
+		/* can't write directories */
+		return 0;
+	fp->open = 1;
+	return 1;
+}
+
+short
+fidread(Fid *fp, ushort tag, ushort offset, ushort count)
+{
+	short k;
+	uchar *p;
+	const DirectoryEntry *dp;
+	uchar *buf;
+
+	ASSERT(fp->qid[0] < QID_MAP_MAX);
+	dp = qid_map[fp->qid[0]];
+
+	if (fp->qid[3] & 0x80) {
+		if (!fp->open)
+			return -1;
+		if (count % DIRLEN != 0 || offset % DIRLEN != 0)
+			return -1;
+		count /= DIRLEN;
+		offset /= DIRLEN;
+		buf = send_fid_reply_payload();
+		p = buf + 3;
+		for (k = 0; k < count; k++) {
+			const DirectoryEntry *sdp = nthentry(dp, offset + k);
+			if (sdp == 0)
+				break;
+			mkdirent(sdp, p);
+			p += DIRLEN;
+		}
+/* a read beyond just returns 0 
+		if (k == 0 && count)
+			return -1;
+*/
+		k *= DIRLEN;
+		buf[0] = k;
+		buf[1] = k >> 8;
+		buf[2] = 0;
+		send_fid_reply(Rread, tag, fp->fid, 0, k + 3);
+		return 0;
+	}
+	/* right, that's that out of the way */
+	if (!dp->read)
+		return -1;
+	return (*dp->read)(dp, tag, fp->fid, offset, count);
+}
+
+short
+fidwrite(Fid *fp, ushort offset, ushort count, uchar *buf)
+{
+	const DirectoryEntry *dp;
+	if (fp->qid[3] & 0x80)
+		return -1;		/* can't write directories */
+	if (!fp->open)
+		return -1;
+	ASSERT(fp->qid[0] < QID_MAP_MAX);
+	dp = qid_map[fp->qid[0]];
+	if (!dp->write)
+		return -1;		/* no write method */
+	return (*dp->write)(dp, offset, count, buf);
+}
+
+int
+rlencode(unsigned char *out, int limit, unsigned char *in, int len)
+{
+	unsigned char *ip, *op;
+	int oc, zc;
+
+	if (len == 0)
+		return -1;
+	ip = in;
+	op = out;
+	zc = 0;
+
+	oc = 0;
+
+	for (;;) {
+		int last = ip >= in + len;
+		if (*ip != 0 || last)
+		{
+			switch (zc) {
+			case 1:
+				if (oc >= len - 1)
+					return -1;
+				*op++ = 0;
+				oc++;
+				break;
+			case 2:
+				if (oc >= len - 2)
+					return -1;
+				*op++ = 0;
+				*op++ = 0;
+				oc += 2;
+				break;
+			case 0:
+				break;
+			default:
+				if (oc >= len - 2)
+					return -1;
+				*op++ = 0x88;
+				*op++ = zc - 2;
+				oc += 2;
+				break;
+			}
+			zc = 0;
+		}
+		if (last)
+			break;
+		if (*ip == 0x88) {
+			if (oc >= len - 2)
+				return -1;
+			*op++ = 0x88;
+			*op++ = 0x00;
+			oc += 2;
+		}
+		else if (*ip == 0x00)
+		{
+			zc++;
+		}
+		else {
+			if (oc >= len - 1)
+				return -1;
+			*op++ = *ip;
+			oc++;
+		}
+		ip++;
+	}
+	return oc;
+}
+
+int
+rldecode(unsigned char *out, unsigned char *in, int len)
+{
+	int oc, k;
+
+	oc = 0;
+
+	while (len) {
+		if (*in != 0x88) {
+			*out++ = *in++;
+			oc++;
+			len--;
+			continue;
+		}
+		in++;
+		switch (*in) {
+		case 0:
+			*out++ = 0x88;
+			oc++;
+			break;
+		default:
+			k = *in + 2;
+			oc += k;
+			while (k-- > 0)
+				*out++ = 0;
+		}
+		in++;
+		len -= 2;
+	}
+	return oc;
+}
+
+void
+prepare_transmission(void)
+{
+	if (prepared)
+		return;
+	compressed_reply_len = rlencode(compressed_reply + 3, sizeof(compressed_reply) - 3, reply, reply_len);
+	if (compressed_reply_len < 0) {
+		memcpy(compressed_reply + 3, reply, reply_len);
+		compressed_reply_len = reply_len;
+		compressed_reply[2] = 0x0;
+	}
+	else
+		compressed_reply[2] = LLP_COMPRESSION;
+	if (reader_count)
+		compressed_reply[2] |= LLP_POLL_PERIODIC;
+	compressed_reply[2] |= !alternating_bit;
+	compressed_reply_len++;
+	compressed_reply[0] = compressed_reply_len;
+	compressed_reply[1] = compressed_reply_len >> 8;
+	compressed_reply_len += 2;
+	prepared = 1;
+}
+
+void
+transmit(void)
+{
+	prepare_transmission();
+	transmitted_reply_len = reply_len;
+	send_message(compressed_reply, compressed_reply_len);
+}
+
+void
+flush_reply_buffer(void)
+{
+	if (reply_len > transmitted_reply_len)
+		memcpy(reply, reply + transmitted_reply_len, reply_len - transmitted_reply_len);
+	reply_len -= transmitted_reply_len;
+	prepared = 0;
+}
+
+void
+send_reply(unsigned char type, unsigned short tag, unsigned char *msg, short len)
+{
+	uchar *p = reply + reply_len;
+	p[0] = type;
+	p[1] = tag & 0xff;
+	p[2] = tag >> 8;
+	if (msg)
+		memcpy(p + 3, msg, len);
+	reply_len += len + 3;
+	prepared = 0;
+}
+
+void
+send_error_reply(unsigned short tag, char *msg)
+{
+	short len;
+	uchar *p = reply + reply_len;
+	p[0] = Rerror;
+	p[1] = tag & 0xff;
+	p[2] = tag >> 8;
+	len = (short)strlen(msg);
+	if (len > 64)
+		len = 64;
+	memcpy(p + 3, msg, len);
+	reply_len += 67;
+	prepared = 0;
+}
+
+uchar *
+send_fid_reply_payload(void)
+{
+	return reply + reply_len + 5;
+}
+
+void
+send_fid_reply(uchar type, ushort tag, ushort fid, uchar *msg, short len)
+{
+	uchar *p = reply + reply_len;
+	p[0] = type;
+	p[1] = tag & 0xff;
+	p[2] = tag >> 8;
+	p[3] = fid & 0xff;
+	p[4] = fid >> 8;
+	if (msg)
+		memcpy(p + 5, msg, len);
+	reply_len += len + 5;
+	prepared = 0;
+}
+
+int
+matchtag(Reader *rp, void *oldtag)
+{
+	if (rp->tag == (ushort)oldtag) {
+		return 1;
+	}
+	return 0;
+}
+
+void
+flushtag(ushort oldtag)
+{
+	/* a little inefficient this - there can be at most one match! */
+	allreaderlistfindanddestroy(matchtag, (void *)oldtag);
+}
+
+void
+process_styx_message(unsigned char *msg, short len)
+{
+	unsigned char type;
+	ushort tag, oldtag, fid, newfid;
+	ushort offset, count;
+	short extra;
+	Fid *fp, *nfp;
+	short written;
+	uchar buf[2];
+
+	ASSERT(len >= 3);
+	
+	type = *msg++; len--;
+	tag = (msg[1] << 8) | msg[0]; len -= 2; msg += 2;
+
+	switch (type) {
+	case Tnop:
+		send_reply(Rnop, tag, 0, 0);
+		goto done;
+	case Tflush:
+		ASSERT(len == 2);
+		oldtag = (msg[1] << 8) | msg[0];
+		flushtag(oldtag);
+		send_reply(Rflush, tag, 0, 0);
+		goto done;
+	}
+	/* all other messages take a fid as well */
+	ASSERT(len >= 2);
+	fid = (msg[1] << 8) | msg[0]; len -= 2; msg += 2;
+	fp = fidfind(fid);
+	
+	switch (type) {
+	case Tattach:
+		ASSERT(len == 56);
+		if (fp) {
+		fid_in_use:
+			send_error_reply(tag, "fid in use");
+		}
+		else {
+			fp = fidcreate(fid, qid_root);
+			send_fid_reply(Rattach, tag, fid, fp->qid, 8);
+		}
+		break;
+	case Tclunk:
+	case Tremove:
+		ASSERT(len == 0);
+		if (!fp) {
+		no_such_fid:
+			send_error_reply(tag, "no such fid");
+		}
+		else {
+			fiddelete(fp);
+			if (type == Tremove)
+				send_error_reply(tag, "can't remove");
+			else
+				send_fid_reply(Rclunk, tag, fid, 0, 0);
+		}
+		break;
+	case Tclone:
+		ASSERT(len == 2);
+		newfid = (msg[1] << 8) | msg[0];
+		nfp = fidfind(newfid);
+		if (!fp)
+			goto no_such_fid;
+		if (fp->open) {
+			send_error_reply(tag, "can't clone");
+			break;
+		}
+		if (nfp)
+			goto fid_in_use;
+		nfp = fidcreate(newfid, fp->qid);
+		send_fid_reply(Rclone, tag, fid, 0, 0);
+		break;
+	case Twalk:
+		ASSERT(len == 28);
+		if (!fidwalk(fp, msg))
+			send_error_reply(tag, "no such name");
+		else
+			send_fid_reply(Rwalk, tag, fid, fp->qid, 8);
+		break;
+	case Tstat:
+		ASSERT(len == 0);
+		if (!fidstat(fp, dir))
+			send_error_reply(tag, "can't stat");
+		else
+			send_fid_reply(Rstat, tag, fid, dir, 116);
+		break;
+		ASSERT(len == 0);
+	case Tcreate:
+		ASSERT(len == 33);
+		send_error_reply(tag, "can't create");
+		break;
+	case Topen:
+		ASSERT(len == 1);
+		if (!fidopen(fp, msg[0]))
+			send_error_reply(tag, "can't open");
+		else
+			send_fid_reply(Ropen, tag, fid, fp->qid, 8);
+		break;
+	case Tread:
+		ASSERT(len == 10);
+		offset = (msg[1] << 8) | msg[0];
+		count = (msg[9] << 8) | msg[8];
+		if (fidread(fp, tag, offset, count) < 0)
+			send_error_reply(tag, "can't read");
+		break;
+	case Twrite:
+		ASSERT(len >= 11);
+		offset = (msg[1] << 8) | msg[0];
+		count = (msg[9] << 8) | msg[8];
+		msg += 11;
+		len -= 11;
+		ASSERT(count == len);
+		written = fidwrite(fp, offset, count, msg);
+		if (written < 0)
+			send_error_reply(tag, "can't write");
+		else {
+			buf[0] = written;
+			buf[1] = written >> 8;
+			send_fid_reply(Rwrite, tag, fid, buf, 2);
+		}
+		break;
+	default:
+		FATAL;
+	}
+done:
+	;
+}
+
+void
+process_llp_message(unsigned char *msg, short len)
+{
+	short styxlen;
+	switch (msg[0]) {
+	case 0x45:
+	case 0x4d:
+		if (len != 5)
+			FATAL;
+		styxlen = compressed_incoming[0] | (compressed_incoming[1] << 8);
+		/* transfer the transmitted checksum to the end */
+		compressed_incoming[styxlen + 2 - 1] = msg[3];
+		/* check alternating bit */
+#ifdef ABP
+		if ((compressed_incoming[2] & 1) != alternating_bit ||
+		    ((msg[0] & 8) != 0) != alternating_bit) {
+			transmit();
+			break;
+		}
+#endif
+		alternating_bit = !alternating_bit;
+		flush_reply_buffer();
+		if (styxlen > 1) {
+			if (compressed_incoming[2] & LLP_COMPRESSION) {
+				/* decompress everything but length and link header */
+				styxlen = rldecode(incoming, compressed_incoming + 3, styxlen - 1);
+				process_styx_message(incoming, styxlen);
+			}
+			else
+				process_styx_message(compressed_incoming + 3, styxlen - 1);
+		}
+		transmit();
+		break;
+	default:
+		FATAL;
+	}
+}
+
+int
+main (void)
+{
+	int count = 0;
+	char buf[16];
+	char temp[64];
+
+	mem_init();
+	memset(temp,0, sizeof(temp));
+
+	/* Initialize */
+
+	init_timer(&temp[6], &dispatch[0]);
+	init_power();
+	init_sensors();
+	init_serial(&temp[4], &temp[6], 1, 1);
+
+	set_lcd_number(LCD_UNSIGNED, 0, LCD_DECIMAL_0);
+	set_lcd_segment(LCD_WALKING);
+	refresh_display();
+
+	set_data_pointer(compressed_incoming);
+
+	alternating_bit = 0;
+	compressed_reply_len = 0;
+	reply_len = 0;
+	prepared = 0;
+
+	while (poll_power() != 0) {
+
+		/* If a message has arrived, send a response with opcode inverted */
+
+		if (check_valid()) {
+			int len = receive_message(buf, sizeof(buf));
+			msgcount++;
+			process_llp_message(buf, len);
+		}
+		sensorpoll();
+	}
+
+	return 0;
+}
--- /dev/null
+++ b/lib/lego/styx.srec
@@ -1,0 +1,329 @@
+S00C0000737479782E7372656340
+S11880006DF06DF16DF26DF35E00967E6D736D726D716D7054AD
+S118801570446F20796F7520627974652C207768656E20492057
+S10B802A6B6E6F636B3F0000F5
+S11880326DF60D761B870D621B8279014000790029F25E00965F
+S1188047AC6B039A0A6F62FFFE1D23470819226B829A084012E9
+S118805C6B039A08790200091D234E060B036B839A086F61FF76
+S1188071FE6B819A0A6B039A08790200097900FFFF1D234F02CC
+S11880860D100B876D7654706DF60D760D02790330026DF3790F
+S118809B01301F79001FF25E0096BC0B87790027C85E0096D480
+S11880B06D7654706DF60D766DF40D047901300679001B625EB4
+S11880C50096DE0D405E00808E5E0080320D0046F86D746D7656
+S11880DA54706DF60D766DF40D041900684B473C0D1147380B7A
+S11880EF040CBA8AD0AA09422E0CB8F00088D090FF1B01684BC7
+S118810447200D11471C0B040CBA8AD0AA0942120D0209220901
+S118811922092009000CBAF200092040D66D746D7654706DF617
+S118812E0D761B871B876DF46DF56FE0FFFE0D146FE0FFFC0DEA
+S1188143444C16FA2D688A6F62FFFE0D230B036FE3FFFC170CE8
+S118815817040B040D444610FA306F63FFFC68BA0B036FE3FFC5
+S118816DFC404C790527101D454F407901000A0D505E0096EA0C
+S11881820D051D454EF0402E0D510D405E0096EA0C8A8A306F7C
+S118819763FFFC68BA0B036FE3FFFC0D510D405E0096FC0D0448
+S11881AC7901000A0D505E0096EA0D050D5546CE6F62FFFC6F38
+S11881C163FFFE19326FE2FFFC6F60FFFC6D756D740B870B87FD
+S11881D66D7654706DF60D761B876DF46DF50D040D156FE2FF1B
+S11881EBFE7900000A5E00972269846F8500026F62FFFE6F8241
+S118820000046F6200046F82000619226F8200086A0AA40A8AB5
+S1188215016A8AA40A6D756D740B876D7654706DF60D765E006D
+S118822A979C6A0AA40A8AFF6A8AA40A6D7654706DF60D7669C5
+S118823F00790198885E008FD6790000016D7654706DF60D76C2
+S11882541B871B876DF46DF50D056FE1FFFE6FE2FFFC40266990
+S1188269546F61FFFC0D406F62FFFE5D200D00470E6F4200082A
+S118827E69D20D405E0082244006790500080945695246D66DFD
+S1188293756D740B870B876D7654706DF60D761B871B876DF426
+S11882A86DF56FE0FFFE6FE1FFFC19557904A3DC6F62FFFC6F1F
+S11882BD61FFFE0D405E0082508C0E94000B05790200021D25D0
+S11882D24FE46D756D740B870B876D7654706DF60D7679030070
+S11882E70C19376DF46DF56FE2FFFE6F6400040D1147045A0077
+S11882FC83FE6E080002F00088F990FF6FE0FFFC6F65FFFC094E
+S11883115509550955190509557902A3D009520D256F62FFFE7D
+S118832646045A0083FE684BF300790200621D23470C79020088
+S118833B6C1D23470A5A0083FE79020060400219226FE2FFF8B1
+S11883500B046F63FFFE1B030D3346045A0083FE684AAA3E46D3
+S118836504FA014006AA3C460C18AA6EEAFFFB0B041B034006FB
+S118837AFA016EEAFFFB0D3346045A0083FE7901823A0D50881D
+S118838F0C900019226FE3FFF45E0082506F62FFFC8A00921091
+S11883A46FE2FFF66F61FFF6790019C45E0096DEFA0168DA6EE2
+S11883B96AFFF96EDA00016F63FFF40D310D405E0080DC6FD0B7
+S11883CE000A19226FD200026FD200046EDA0006FA016EDA0038
+S11883E3086E6AFFFB6EDA00096F61FFF6790019465E0096DEE7
+S11883F86F60FFFE40047900FFFF6D756D747903000C09376DED
+S118840D7654706DF60D767903000619376DF46DF56FE0FFFE55
+S11884226FE1FFFC0D256F6400085E0090340D031D45443219C6
+S1188437546F6000041D0443046F6400046F62000609526FE243
+S118844C00060D300B800B000D426F6100066FE3FFFA5E0097D9
+S1188461AE6F63FFFA4002194468BC0D420C2A18226EBA0001DE
+S118847618AA6EBA00020B840B046DF419226DF26F62FFFC6F2D
+S118848B61FFFEF80F5E0090480B870B876D756D7479030006D4
+S11884A009376D7654706DF60D767903000C19376DF46DF56FEC
+S11884B5E0FFF66FE1FFF40D257904FFF809646F6100060D4060
+S11884CA5E00812C6DF06DF46F6200046DF20D526F61FFF46F0B
+S11884DF60FFF65E0084108F0697006D756D747903000C093786
+S11884F46D7654706DF60D766E0A0009471019116F0300046FFB
+S118850902000A1D234514400E19116F0300046F02000A1D230B
+S118851E4404790100010D106D7654706DF60D761B876DF46D67
+S1188533F56FE1FFFE0D256E0A0002F2008AF992FF0D240944BD
+S118854809440944192409447902A3D009420D246E4A00084686
+S118855D067900FFFF404E0D405E0084F80D0047206F420004AA
+S11885726DF26F6200066DF26F6200040D516F60FFFE5E00847A
+S1188587A60B870B8740226F6200066DF26F6200040D516F6077
+S118859CFFFE5E0081DA6F42000C6F8200086FC0000C0B871974
+S11885B1006D756D740B876D7654706DF60D761B876DF46DF56A
+S11885C67903A400683A4D045A008686EA7F68BA19440D4509E0
+S11885DB5509550955194509557902A3D009520D256E5A00086F
+S11885F00D430B036FE3FFFE0CAA46045A0086768C0094100D32
+S1188605520D41790014C05E0096AC0D520D41790014C05E0077
+S118861A96AC0D520D41790014C05E0096AC0D520D4179001431
+S118862FC05E0096AC0D505E0084F80D00473840306F54000CD0
+S11886446F4200086FD2000C6F41000269406F5200046DF26F29
+S11886594200066DF26F4200045E0084A60D405E0082240B8741
+S118866E0B876F52000C46CA6F64FFFE790200021D244E045A4A
+S11886830085D86D756D740B876D7654706DF60D766DF46DF5DC
+S11886980D050D246F600004680BF300790200661D2347244E73
+S11886AD127902002D1D234750790200461D23472440327902CA
+S11886C200721D23470E0B021D23470E4022790200014010794F
+S11886D7020002400A7902000340047902000469926E0A000187
+S11886EC8AD0AA074304190040146E0A0001F2008AD092FF69F7
+S1188701C2FA0168DA790000016D756D746D7654706DF60D7696
+S11887167903001A19376DF46DF56FE2FFEE0D1147045A008818
+S118872B1A6EE9FFF26EE9FFF16EE9FFF06E0A0002AA054704D2
+S11887405A0087CC790200066F60FFEE1D2047045A00881A7939
+S118875504FFF409647905FFFA09657902FFF009626FE2FFECB1
+S118876A6F6300046DF30D420D516F60FFEC5E0086900B870D46
+S118877F0046045A00881A0D611B811B817900FFF109606F6252
+S118879400040B826DF21B826FE200047902FFF609625E00862B
+S11887A9900B870D00476A0D611B817900FFF209606F63000424
+S11887BE0B830B836DF37902FFF809624044790200026F63FF77
+S11887D3EE1D2346426E0B0002F3001B837900FFF409606FE0A7
+S11887E8FFEA0D3209227905FFFA09650D5109217904FFF00943
+S11887FD640D4009306F6300046DF36F63FFEA09230D325E00BF
+S118881286900B870D0046067900FFFF405019337904FFF40980
+S1188827647900FFF009606FE0FFE86F60FFE86C0A6FE0FFE86B
+S118883C0CAA471E0D318900912069426DF2695279001A4E6F7B
+S1188851E3FFE65E0096BC0B876F63FFE60B840B850B037902A5
+S118886600021D234FC66F60FFEE6D756D747903001A09376DE0
+S118887B7654706DF60D760D036B00A408400269000D00470896
+S11888906F0200021D3246F26D7654706DF60D761B876DF46DD8
+S11888A5F50D056FE1FFFE7900000E5E0097220D0446087900F0
+S11888BA02135E0080B418AA6ECA00046FC500026B02A4086948
+S11888CFC20D4088059000790200086F61FFFE5E0097AE6B8482
+S11888E4A4080D406D756D740B876D7654706DF60D766F03002E
+S11888F9026F1200021D23470419004004790000016D765470D8
+S118890E6DF60D766DF40D04790088F20D415E00829E7903A419
+S118892308401269301D40460A690269B25E00979C400E0D0326
+S1188938693246EA790002325E0080B46D746D7654706DF60D24
+S118894D766DF46DF50D040D156F4200044608790002395E0090
+S118896280B46F440004401C6940790198DC5E0097D20D004703
+S11889770A0D5546040D40400C1B058C0A9400694246E0190064
+S118898C6D756D746D7654706DF60D761B876DF46DF50D056F9C
+S11889A1E1FFFE6E5A000446226E5A0005AA0943087900024B1A
+S11889B65E0080B46E5A0005F20009226F229A0C6F220004461A
+S11889CB067900FFFF403E0D20690247360D0469406F61FFFEFC
+S11889E05E0097D20D00461E6E4A00026EDA00056F4200041872
+S11889F5BB0D224702FB806EDB000879000001400A8C0A94007C
+S1188A0A694246CC19006D756D740B876D7654706DF60D761B80
+S1188A1F876DF46DF56FE0FFFE0D157902007419110D505E00B2
+S1188A3498086F62FFFE69210D505E00981E0D50881C900079B6
+S1188A490400050D427901995E5E0097AE0D50883890000D42AC
+S1188A5E7901995E5E0097AE6F63FFFE6E3A00026EDA00546F67
+S1188A73320004FBB60D224702FB6D6EDB005CFA016EDA005DDE
+S1188A886F63FFFE6F32000418BB0D224702FB806EDB005F6D86
+S1188A9D756D740B876D7654706DF60D766DF46DF50D040D1555
+S1188AB26E4A000447067900FFFF40266E4A0005AA0943087991
+S1188AC700026B5E0080B46E4A0005F20009226F209A0C0D512A
+S1188ADC5E008A1A790000016D756D746D7654706DF60D766E47
+S1188AF10A000446107369460C6E0A0008470A89FFA901420491
+S1188B061900400AFA016E8A0004790000016D7654706DF60D6B
+S1188B1B767903000A19376DF46DF56FE0FFFE6FE1FFFC6FE24A
+S1188B30FFFA6E0A0005AA094308790002875E0080B46F60FF56
+S1188B45FE6E0A0005F20009226F229A0C6FE2FFF86E0A000880
+S1188B5AEA8046045A008C3A6E0A00044720790100746F60008E
+S1188B6F045E0098320D004610790100746F60FFFA5E00983280
+S1188B840D0047087900FFFF5A008C6C790100746F6000045E94
+S1188B990098446FE00004790100746F60FFFA5E0098446FE055
+S1188BAEFFFA5E0090346FE0FFF66F64FFF60B840B041955403B
+S1188BC30C0D415E008A1A8C7494000B056F6200041D2544122C
+S1188BD86F61FFFA09516F60FFF85E00894A0D0046DA0D5209D5
+S1188BED22092209221952092209220925095509556F63FFF685
+S1188C0268BD0D520C2A10021E226EBA000118AA6EBA00020B2D
+S1188C17850B056DF519226DF26F63FFFE6F3200026F61FFFC76
+S1188C2CF80F5E00904819000B870B8740326F60FFF86F03000B
+S1188C410647246F6200046DF26F60FFFA6DF06F60FFFE6F0213
+S1188C5600026F61FFFC6F60FFF85D300B870B8740047900FF05
+S1188C6BFF6D756D747903000A09376D7654706DF60D761B8739
+S1188C806DF46DF50D046FE1FFFE0D256E4A0008EA8046066EA4
+S1188C954A000446067900FFFF403C6E4A0005AA094308790005
+S1188CAA02B35E0080B46E4A0005F20009226F209A0C6F0200EA
+S1188CBF0847166F6200046DF26F0300080D526F61FFFE5D30D0
+S1188CD40B8740047900FFFF6D756D740B876D7654706DF60DCE
+S1188CE9761B876DF46DF56F63000446087900FFFF5A008DD243
+S1188CFE0D25194419116F6300040D5209326FE2FFFE40386806
+S1188D135BAB8846186F6200041B821D214CD4688B0B0018AACB
+S1188D28688A0B000B8140180CBB46040B0440106F6200041BF1
+S1188D3D021D214CB4688B0B000B010B0519336F62FFFE1D2567
+S1188D52450479030001685A46040D3347B2790200011D2447F9
+S1188D67124E060D4447584038790200021D24471A402E6F62C7
+S1188D7C00041B021D214D045A008CF618AA688A0B000B014047
+S1188D91346F6200041B821D214D045A008CF618AA688A0B00F9
+S1188DA640186F6200041B821D214D045A008CF6FA88688A0B00
+S1188DBB000CCA8AFE688A0B000B8119440D3346045A008D12D8
+S1188DD00D106D756D740B876D7654706DF60D761B876DF46D1B
+S1188DE5F50D040D2519226FE2FFFE0D55475E681AAA8847149E
+S1188DFA68CA0B010B046F62FFFE0B026FE2FFFE1B0540E20B9D
+S1188E0F016818F0000D00461468CA0B046F62FFFE0B026FE205
+S1188E24FFFE0B011B8540C40D030B836F62FFFE09326FE2FF91
+S1188E39FE0D321B030B011B854FAC188868C80B040D321B03E2
+S1188E4E4EF6409E6F60FFFE6D756D740B876D7654706DF60DB1
+S1188E63766DF46DF56A0CA40E47045A008F0079059F586B027F
+S1188E78A4106DF20D527901009379009EC35E008CE66B80A429
+S1188E8D060B870D004C206B02A4100D5179009EC35E0097AEBF
+S1188EA26B02A4106B82A40679029EC268AC0D23400879039E7E
+S1188EB7C2FA0868BA6A0AA40A47047D3070206838F0006A0A0E
+S1188ECCA40F4602C80168B86B00A4060D020B026B82A4066A77
+S1188EE10BA4076A8B9EC00C2A10021E226A8A9EC10B800B00FE
+S1188EF66B80A406FA016A8AA40E6D756D746D7654706DF60D53
+S1188F0B766DF46DF55E008E606B02A4106B82A40C79059EC02E
+S1188F206B04A406471A6DF46DF51922790117767900343E5E70
+S1188F350098560B870B870C8846E66D756D746D7654706DF684
+S1188F4A0D766B02A4106B03A40C1D32430E79009F580D3109F5
+S1188F5F0119325E0097AE6B02A40C6B03A41019230D326B8263
+S1188F74A41018AA6A8AA40E6D7654706DF60D766DF46DF50D6B
+S1188F89246F6500046B03A41079029F5809320D2368B86EB98D
+S1188F9E00010C1918116EB900020D44470E0B830B030D520D94
+S1188FB3410D305E0097AE6B02A4100B820B0209526B82A410CD
+S1188FC818AA6A8AA40E6D756D746D7654706DF60D766DF46D0A
+S1188FDDF50D156B04A41079029F5809420D24FA0368CA6EC8EE
+S1188FF200010C0818006EC800020D505E009874790200401D62
+S1189007204F020D200B840B040D020D510D405E0097AE6B024A
+S118901CA4108A4392006B82A41018AA6A8AA40E6D756D746DEF
+S11890317654706DF60D766B00A41079029F5D09020D206D7655
+S118904654706DF60D766DF46DF56F6400046B03A41079059F8E
+S118905B5809350D5368B86EB900010C1918116EB900026EBA1F
+S118907000030C2A18226EBA00040D4447108B0593006F6200AC
+S1189085060D410D305E0097AE6B02A4108A0592006F60000687
+S118909A09026B82A41018AA6A8AA40E6D756D746D7654706DD2
+S11890AFF60D7669021D12470419004004790000016D765470CC
+S11890C46DF60D760D01790090AE5E00829E6D7654706DF60D53
+S11890D9767903000E19376DF46DF50D050D14790000021D049C
+S11890EE4E08790003935E0080B46C5A6EEAFFFD6E5B00010C82
+S1189103B318BB685AF20014AB14236FE3FFFA1B841B040B858A
+S11891186E6BFFFDF3000D33470A790200041D23470E40446DE0
+S118912DF319226F61FFFAF801402E790200021D244708790045
+S1189142039D5E0080B46E5800010C801888685AF20014A8146B
+S1189157205E0090C419226DF26F61FFFAF8055E008F800B87CE
+S118916C5A009496790200011D244E08790003A45E0080B46E33
+S11891815800010C801888685AF20014A814206FE0FFF81B84C7
+S11891960B855E00887E6FE0FFF46E6BFFFDF3008BFA93FF7932
+S11891AB0200161D2343045A00948E09336F3299DA592079024C
+S11891C000381D244708790003AA5E0080B46F63FFF447087989
+S11891D50199635A0094567901988E6F60FFF85E00889C6FE009
+S11891EAFFF4790200086DF2880590006DF06F62FFF86F61FF86
+S11891FFFAF81D5A0094840D444708790003B65E0080B46F62A1
+S1189214FFF446087901996E5A0094566F60FFF45E00890E6E16
+S11892296BFFFDAB1446087901997A5A00945619226DF26DF2EE
+S118923E6F62FFF86F61FFFAF8135A009484790200021D244704
+S118925308790003C45E0080B46E5C00010CC418CC685AF200F5
+S118926814AC14240D405E00887E6F62FFF446045A0092186EC4
+S118927D2A00044708790199875A0094560D0047045A0091D466
+S11892926F61FFF4890591000D405E00889C19226DF26DF26FAA
+S11892A762FFF86F61FFFAF8075A0094847902001C1D244708F4
+S11892BC790003D35E0080B40D516F60FFF45E0089940D0046CA
+S11892D108790199935A009456790200086DF26F63FFF48B055B
+S11892E693006DF36F62FFF86F61FFFAF8095A0094840D4447E0
+S11892FB08790003DA5E0080B47904A3580D416F60FFF45E0084
+S11893108AA60D004608790199A05A009456790200746DF26D07
+S1189325F46F62FFF86F61FFFAF8175A009484790200211D244C
+S118933A4708790003E25E0080B4790199AB5A0094567902005E
+S118934F011D244708790003E65E0080B468596F60FFF45E009F
+S11893648AEC0D004608790199B85A009456790200086DF26FBF
+S118937960FFF4880590006DF06F62FFF86F61FFFAF80B5A0020
+S118938E94847902000A1D244708790003ED5E0080B46E5A00D6
+S11893A3010CA218AA6859F1006E5B00090CB318BB6E5800085C
+S11893B8F000148B14036DF3149A14126F61FFFA6F60FFF45ED9
+S11893CD008B180B870D004D045A009496790199C35A00945656
+S11893E27902000A1D244E08790003F45E0080B46E5A00010C7F
+S11893F7A218AA6FE2FFF6685AF2006F60FFF614A814206FE0FC
+S118940CFFF66E5B00090CB318BB6E5A0008F20014AB14238DA9
+S11894210B95008CF594FF1D434710790003F96FE3FFF25E00B1
+S118943680B46F63FFF26DF50D326F61FFF66F60FFF45E008C14
+S118944B7A0B870D004C0E790199CE6F60FFFA5E008FD64036B3
+S11894606EE8FFFE0C0810001E006EE8FFFF790200026DF20D21
+S1189475621B826DF26F62FFF86F61FFFAF8115E0090480B871E
+S118948A0B874008790004045E0080B46D756D747903000E0986
+S118949F376D7654706DF60D766DF46DF50D04684BF3007902FB
+S11894B400451D23470C7902004D1D2347045A009548790200C2
+S11894C9051D214708790004125E0080B479039A28683DF500FF
+S11894DE6A0A9A290CA218AA14AD14250D5209326E4B00036E10
+S11894F3AB000118BB6A0AA40F4602FB016A8BA40F5E008F4899
+S1189508790200011D254F326A0A9A2AEA08471E79019A2B79C4
+S118951D049AC00D521B020D405E008DDC0D050D510D405E002C
+S118953290D6400C79009A2B0D511B015E0090D65E008F0840BD
+S1189547087900042C5E0080B46D756D746D7654706DF60D7678
+S118955C7903005219376DF45E00970E7900FFB0096079020068
+S11895714019115E0098087902A4007901FFB6096179003B9A73
+S11895865E0096AC790029645E0096D4790014985E0096D479F8
+S118959B0200016DF26DF27902FFB609627901FFB4096179004B
+S11895B030D05E0098560B870B87790230026DF2192279013041
+S11895C51F79001FF25E0096BC0B877901300779001B625E009D
+S11895DA96DE790027C85E0096D419446DF479029A2879011748
+S11895EF717900327C5E0096BC0B876A8CA40F6B84A4066B8458
+S1189604A4106A8CA40E405C19227901FFAF0961790034265E57
+S11896190096AC6E6AFFAFF2000CAA473E18AA6EEAFFAE790201
+S118962EFFAE09626DF2790200107901FFF00961790033B05E94
+S11896430096BC0B876E69FFAEF1006B029A200B026B829A20DA
+S11896581B017900FFF009605E0094A45E0085BC5E0080320DBA
+S114966D00469C19006D747903005209376D76547057
+S118967E6DF60D7679029A207903A4121D32470A188868A80B2B
+S1189693021D3246F85E009558FA016A8AFFCC6B0200005D2040
+S10796A86D76547013
+S11396AC6DF66DF20D165D000D600B876D765470C2
+S11896BC6DF66F7300046DF36DF20D165D000D600B870B876D0F
+S10696D176547058
+S10D96D46DF65D000D606D765470B4
+S10F96DE6DF60D165D000D606D76547085
+S11596EA6DF56DF60D060D155F520D606D766D755470C9
+S11596FC6DF56DF60D060D155F500D606D766D755470B9
+S118970E6DF60D767903A4127902EF00193269B26D7654706D46
+S1189723F60D766DF46DF50D040B04ECFE0B841D04455C79001D
+S1189738A4120D01404C69024D4209217902EEFF1D2142144068
+S118974D0E690209326982691209211D51420469134CEE6903E9
+S11897621D4345220D428A0692001D23450A0D02094219436908
+S1189777A369846902C28069820B804010E27F09210D107905B0
+S118978CEEFF1D5043AC19006D756D746D7654706DF60D766FA3
+S11097A102FFFEE27F6F82FFFE6D765470C2
+S11897AE6DF60D766DF40D140D010D0309231D31470A6C4A6833
+S11297C38A0B001D3046F60D106D746D765470D0
+S11897D26DF60D76401C680B681A1CAB430679000001401E1C43
+S11897E7AB44067900FFFF40140B000B01680A46E0681A19005F
+S10F97FC0CAA47047900FFFF6D7654703E
+S11898086DF60D760D0309231D3047066CB91D3046FA6D7654A2
+S104981D70D6
+S117981E6DF60D760D036C1A68BA0B030CAA46F66D765470ED
+S11598326DF56DF60D060D155F4C0D606D766D75547085
+S11598446DF56DF60D060D155F4E0D606D766D75547071
+S11898566DF66F7300066DF36F7300066DF36DF20D165D000D1A
+S10C986B608F0697006D765470BD
+S11798746DF60D76193340020B036C0A46FA0D306D765470C0
+S1189888726573657400000000800000000098DC000099120005
+S118989D00000098DA020000000000871298D803000000000032
+S11898B2871298D6040000000000871298D20500000000008703
+S11898C712000000000000000000003031320032003100300050
+S11898DC2E2E000098DC000099120000000098DA0700000085FA
+S11898F12A82E098D808000000852A82E098D609000000852A23
+S118990682E00000000000000000000098DC0000994800000091
+S118991B0099410100989600000000993A060098E000000000D9
+S11899300000000000000000000073656E736F72006D6F746FC5
+S1189945720000995C00009912000000000000000000000000F7
+S118995A00002F006C65676F0066696420696E20757365006E19
+S118996F6F2073756368206669640063616E27742072656D6FAA
+S118998476650063616E277420636C6F6E65006E6F20737563A9
+S118999968206E616D650063616E277420737461740063616EB1
+S11899AE2774206372656174650063616E2774206F70656E00D2
+S11899C363616E277420726561640063616E277420777269744F
+S11899D86500924C948E92B4948E934C948E9334948E93909408
+S11899ED8E93E2948E9206948E9206948E92F8948E948E948ED8
+S1099A02948E948E91BEC7
+S1189A080000FFFF9948991C98A098AA98B498BE992698EA98BC
+S1069A1DF498FEB8
+S90380007C
--- /dev/null
+++ b/lib/lego/styx_abp.srec
@@ -1,0 +1,331 @@
+S0100000737479785F6162702E73726563AA
+S11880006DF06DF16DF26DF35E0096A66D736D726D716D705485
+S118801570446F20796F7520627974652C207768656E20492057
+S10B802A6B6E6F636B3F0000F5
+S11880326DF60D761B870D621B8279014000790029F25E00965F
+S1188047D46B039A326F62FFFE1D23470819226B829A30401271
+S118805C6B039A30790200091D234E060B036B839A306F61FF26
+S1188071FE6B819A326B039A30790200097900FFFF1D234F027C
+S11880860D100B876D7654706DF60D760D02790330026DF3790F
+S118809B01301F79001FF25E0096E40B87790027C85E0096FC30
+S11880B06D7654706DF60D766DF40D047901300679001B625EB4
+S11880C50097060D405E00808E5E0080320D0046F86D746D762D
+S11880DA54706DF60D766DF40D041900684B473C0D1147380B7A
+S11880EF040CBA8AD0AA09422E0CB8F00088D090FF1B01684BC7
+S118810447200D11471C0B040CBA8AD0AA0942120D0209220901
+S118811922092009000CBAF200092040D66D746D7654706DF617
+S118812E0D761B871B876DF46DF56FE0FFFE0D146FE0FFFC0DEA
+S1188143444C16FA2D688A6F62FFFE0D230B036FE3FFFC170CE8
+S118815817040B040D444610FA306F63FFFC68BA0B036FE3FFC5
+S118816DFC404C790527101D454F407901000A0D505E009712E3
+S11881820D051D454EF0402E0D510D405E0097120C8A8A306F53
+S118819763FFFC68BA0B036FE3FFFC0D510D405E0097240D041F
+S11881AC7901000A0D505E0097120D050D5546CE6F62FFFC6F0F
+S11881C163FFFE19326FE2FFFC6F60FFFC6D756D740B870B87FD
+S11881D66D7654706DF60D761B876DF46DF50D040D156FE2FF1B
+S11881EBFE7900000A5E00974A69846F8500026F62FFFE6F8219
+S118820000046F6200046F82000619226F8200086A0AA43A8A85
+S1188215016A8AA43A6D756D740B876D7654706DF60D765E003D
+S118822A97C46A0AA43A8AFF6A8AA43A6D7654706DF60D76693D
+S118823F00790198B05E008FD6790000016D7654706DF60D769A
+S11882541B871B876DF46DF50D056FE1FFFE6FE2FFFC40266990
+S1188269546F61FFFC0D406F62FFFE5D200D00470E6F4200082A
+S118827E69D20D405E0082244006790500080945695246D66DFD
+S1188293756D740B870B876D7654706DF60D761B871B876DF426
+S11882A86DF56FE0FFFE6FE1FFFC19557904A40C6F62FFFC6FEE
+S11882BD61FFFE0D405E0082508C0E94000B05790200021D25D0
+S11882D24FE46D756D740B870B876D7654706DF60D7679030070
+S11882E70C19376DF46DF56FE2FFFE6F6400040D1147045A0077
+S11882FC83FE6E080002F00088F990FF6FE0FFFC6F65FFFC094E
+S11883115509550955190509557902A40009520D256F62FFFE4C
+S118832646045A0083FE684BF300790200621D23470C79020088
+S118833B6C1D23470A5A0083FE79020060400219226FE2FFF8B1
+S11883500B046F63FFFE1B030D3346045A0083FE684AAA3E46D3
+S118836504FA014006AA3C460C18AA6EEAFFFB0B041B034006FB
+S118837AFA016EEAFFFB0D3346045A0083FE7901823A0D50881D
+S118838F0C900019226FE3FFF45E0082506F62FFFC8A00921091
+S11883A46FE2FFF66F61FFF6790019C45E009706FA0168DA6EB9
+S11883B96AFFF96EDA00016F63FFF40D310D405E0080DC6FD0B7
+S11883CE000A19226FD200026FD200046EDA0006FA016EDA0038
+S11883E3086E6AFFFB6EDA00096F61FFF6790019465E009706BE
+S11883F86F60FFFE40047900FFFF6D756D747903000C09376DED
+S118840D7654706DF60D767903000619376DF46DF56FE0FFFE55
+S11884226FE1FFFC0D256F6400085E0090340D031D45443219C6
+S1188437546F6000041D0443046F6400046F62000609526FE243
+S118844C00060D300B800B000D426F6100066FE3FFFA5E0097D9
+S1188461D66F63FFFA4002194468BC0D420C2A18226EBA0001B6
+S118847618AA6EBA00020B840B046DF419226DF26F62FFFC6F2D
+S118848B61FFFEF80F5E0090480B870B876D756D7479030006D4
+S11884A009376D7654706DF60D767903000C19376DF46DF56FEC
+S11884B5E0FFF66FE1FFF40D257904FFF809646F6100060D4060
+S11884CA5E00812C6DF06DF46F6200046DF20D526F61FFF46F0B
+S11884DF60FFF65E0084108F0697006D756D747903000C093786
+S11884F46D7654706DF60D766E0A0009471019116F0300046FFB
+S118850902000A1D234514400E19116F0300046F02000A1D230B
+S118851E4404790100010D106D7654706DF60D761B876DF46D67
+S1188533F56FE1FFFE0D256E0A0002F2008AF992FF0D240944BD
+S118854809440944192409447902A40009420D246E4A00084655
+S118855D067900FFFF404E0D405E0084F80D0047206F420004AA
+S11885726DF26F6200066DF26F6200040D516F60FFFE5E00847A
+S1188587A60B870B8740226F6200066DF26F6200040D516F6077
+S118859CFFFE5E0081DA6F42000C6F8200086FC0000C0B871974
+S11885B1006D756D740B876D7654706DF60D761B876DF46DF56A
+S11885C67903A430683A4D045A008686EA7F68BA19440D4509B0
+S11885DB5509550955194509557902A40009520D256E5A00083E
+S11885F00D430B036FE3FFFE0CAA46045A0086768C0094100D32
+S1188605520D41790014C05E0096D40D520D41790014C05E004F
+S118861A96D40D520D41790014C05E0096D40D520D41790014E1
+S118862FC05E0096D40D505E0084F80D00473840306F54000CA8
+S11886446F4200086FD2000C6F41000269406F5200046DF26F29
+S11886594200066DF26F4200045E0084A60D405E0082240B8741
+S118866E0B876F52000C46CA6F64FFFE790200021D244E045A4A
+S11886830085D86D756D740B876D7654706DF60D766DF46DF5DC
+S11886980D050D246F600004680BF300790200661D2347244E73
+S11886AD127902002D1D234750790200461D23472440327902CA
+S11886C200721D23470E0B021D23470E4022790200014010794F
+S11886D7020002400A7902000340047902000469926E0A000187
+S11886EC8AD0AA074304190040146E0A0001F2008AD092FF69F7
+S1188701C2FA0168DA790000016D756D746D7654706DF60D7696
+S11887167903001A19376DF46DF56FE2FFEE0D1147045A008818
+S118872B1A6EE9FFF26EE9FFF16EE9FFF06E0A0002AA054704D2
+S11887405A0087CC790200066F60FFEE1D2047045A00881A7939
+S118875504FFF409647905FFFA09657902FFF009626FE2FFECB1
+S118876A6F6300046DF30D420D516F60FFEC5E0086900B870D46
+S118877F0046045A00881A0D611B811B817900FFF109606F6252
+S118879400040B826DF21B826FE200047902FFF609625E00862B
+S11887A9900B870D00476A0D611B817900FFF209606F63000424
+S11887BE0B830B836DF37902FFF809624044790200026F63FF77
+S11887D3EE1D2346426E0B0002F3001B837900FFF409606FE0A7
+S11887E8FFEA0D3209227905FFFA09650D5109217904FFF00943
+S11887FD640D4009306F6300046DF36F63FFEA09230D325E00BF
+S118881286900B870D0046067900FFFF405019337904FFF40980
+S1188827647900FFF009606FE0FFE86F60FFE86C0A6FE0FFE86B
+S118883C0CAA471E0D318900912069426DF2695279001A4E6F7B
+S1188851E3FFE65E0096E40B876F63FFE60B840B850B0379027D
+S118886600021D234FC66F60FFEE6D756D747903001A09376DE0
+S118887B7654706DF60D760D036B00A438400269000D00470866
+S11888906F0200021D3246F26D7654706DF60D761B876DF46DD8
+S11888A5F50D056FE1FFFE7900000E5E00974A0D0446087900C8
+S11888BA02135E0080B418AA6ECA00046FC500026B02A4386918
+S11888CFC20D4088059000790200086F61FFFE5E0097D66B845A
+S11888E4A4380D406D756D740B876D7654706DF60D766F0300FE
+S11888F9026F1200021D23470419004004790000016D765470D8
+S118890E6DF60D766DF40D04790088F20D415E00829E7903A419
+S118892338401269301D40460A690269B25E0097C4400E0D03CE
+S1188938693246EA790002325E0080B46D746D7654706DF60D24
+S118894D766DF46DF50D040D156F4200044608790002395E0090
+S118896280B46F440004401C6940790199045E0097FA0D0047B2
+S11889770A0D5546040D40400C1B058C0A9400694246E0190064
+S118898C6D756D746D7654706DF60D761B876DF46DF50D056F9C
+S11889A1E1FFFE6E5A000446226E5A0005AA0943087900024B1A
+S11889B65E0080B46E5A0005F20009226F229A346F22000446F2
+S11889CB067900FFFF403E0D20690247360D0469406F61FFFEFC
+S11889E05E0097FA0D00461E6E4A00026EDA00056F420004184A
+S11889F5BB0D224702FB806EDB000879000001400A8C0A94007C
+S1188A0A694246CC19006D756D740B876D7654706DF60D761B80
+S1188A1F876DF46DF56FE0FFFE0D157902007419110D505E00B2
+S1188A3498306F62FFFE69210D505E0098460D50881C90007966
+S1188A490400050D42790199865E0097D60D50883890000D425C
+S1188A5E790199865E0097D66F63FFFE6E3A00026EDA00546F17
+S1188A73320004FBB60D224702FB6D6EDB005CFA016EDA005DDE
+S1188A886F63FFFE6F32000418BB0D224702FB806EDB005F6D86
+S1188A9D756D740B876D7654706DF60D766DF46DF50D040D1555
+S1188AB26E4A000447067900FFFF40266E4A0005AA0943087991
+S1188AC700026B5E0080B46E4A0005F20009226F209A340D5102
+S1188ADC5E008A1A790000016D756D746D7654706DF60D766E47
+S1188AF10A000446107369460C6E0A0008470A89FFA901420491
+S1188B061900400AFA016E8A0004790000016D7654706DF60D6B
+S1188B1B767903000A19376DF46DF56FE0FFFE6FE1FFFC6FE24A
+S1188B30FFFA6E0A0005AA094308790002875E0080B46F60FF56
+S1188B45FE6E0A0005F20009226F229A346FE2FFF86E0A000858
+S1188B5AEA8046045A008C3A6E0A00044720790100746F60008E
+S1188B6F045E00985A0D004610790100746F60FFFA5E00985A30
+S1188B840D0047087900FFFF5A008C6C790100746F6000045E94
+S1188B9900986C6FE00004790100746F60FFFA5E00986C6FE005
+S1188BAEFFFA5E0090346FE0FFF66F64FFF60B840B041955403B
+S1188BC30C0D415E008A1A8C7494000B056F6200041D2544122C
+S1188BD86F61FFFA09516F60FFF85E00894A0D0046DA0D5209D5
+S1188BED22092209221952092209220925095509556F63FFF685
+S1188C0268BD0D520C2A10021E226EBA000118AA6EBA00020B2D
+S1188C17850B056DF519226DF26F63FFFE6F3200026F61FFFC76
+S1188C2CF80F5E00904819000B870B8740326F60FFF86F03000B
+S1188C410647246F6200046DF26F60FFFA6DF06F60FFFE6F0213
+S1188C5600026F61FFFC6F60FFF85D300B870B8740047900FF05
+S1188C6BFF6D756D747903000A09376D7654706DF60D761B8739
+S1188C806DF46DF50D046FE1FFFE0D256E4A0008EA8046066EA4
+S1188C954A000446067900FFFF403C6E4A0005AA094308790005
+S1188CAA02B35E0080B46E4A0005F20009226F209A346F0200C2
+S1188CBF0847166F6200046DF26F0300080D526F61FFFE5D30D0
+S1188CD40B8740047900FFFF6D756D740B876D7654706DF60DCE
+S1188CE9761B876DF46DF56F63000446087900FFFF5A008DD243
+S1188CFE0D25194419116F6300040D5209326FE2FFFE40386806
+S1188D135BAB8846186F6200041B821D214CD4688B0B0018AACB
+S1188D28688A0B000B8140180CBB46040B0440106F6200041BF1
+S1188D3D021D214CB4688B0B000B010B0519336F62FFFE1D2567
+S1188D52450479030001685A46040D3347B2790200011D2447F9
+S1188D67124E060D4447584038790200021D24471A402E6F62C7
+S1188D7C00041B021D214D045A008CF618AA688A0B000B014047
+S1188D91346F6200041B821D214D045A008CF618AA688A0B00F9
+S1188DA640186F6200041B821D214D045A008CF6FA88688A0B00
+S1188DBB000CCA8AFE688A0B000B8119440D3346045A008D12D8
+S1188DD00D106D756D740B876D7654706DF60D761B876DF46D1B
+S1188DE5F50D040D2519226FE2FFFE0D55475E681AAA8847149E
+S1188DFA68CA0B010B046F62FFFE0B026FE2FFFE1B0540E20B9D
+S1188E0F016818F0000D00461468CA0B046F62FFFE0B026FE205
+S1188E24FFFE0B011B8540C40D030B836F62FFFE09326FE2FF91
+S1188E39FE0D321B030B011B854FAC188868C80B040D321B03E2
+S1188E4E4EF6409E6F60FFFE6D756D740B876D7654706DF60DB1
+S1188E63766DF46DF56A0CA43E47045A008F0079059F886B021F
+S1188E78A4406DF20D527901009379009EF35E008CE66B80A4C9
+S1188E8D360B870D004C206B02A4400D5179009EF35E0097D607
+S1188EA26B02A4406B82A43679029EF268AC0D23400879039EEE
+S1188EB7F2FA0868BA6A0AA43A47047D3070206838F0006A0AAE
+S1188ECCA43F4602C80168B86B00A4360D020B026B82A4366AE7
+S1188EE10BA4376A8B9EF00C2A10021E226A8A9EF10B800B006E
+S1188EF66B80A436FA016A8AA43E6D756D746D7654706DF60DF3
+S1188F0B766DF46DF55E008E606B02A4406B82A43C79059EF09E
+S1188F206B04A436471A6DF46DF51922790117767900343E5E40
+S1188F3500987E0B870B870C8846E66D756D746D7654706DF65C
+S1188F4A0D766B02A4406B03A43C1D32430E79009F880D310965
+S1188F5F0119325E0097D66B02A43C6B03A44019230D326B82DB
+S1188F74A44018AA6A8AA43E6D7654706DF60D766DF46DF50D0B
+S1188F89246F6500046B03A44079029F8809320D2368B86EB92D
+S1188F9E00010C1918116EB900020D44470E0B830B030D520D94
+S1188FB3410D305E0097D66B02A4400B820B0209526B82A44045
+S1188FC818AA6A8AA43E6D756D746D7654706DF60D766DF46DDA
+S1188FDDF50D156B04A44079029F8809420D24FA0368CA6EC88E
+S1188FF200010C0818006EC800020D505E00989C790200401D3A
+S1189007204F020D200B840B040D020D510D405E0097D66B0222
+S118901CA4408A4392006B82A44018AA6A8AA43E6D756D746D5F
+S11890317654706DF60D766B00A44079029F8D09020D206D76F5
+S118904654706DF60D766DF46DF56F6400046B03A44079059F5E
+S118905B8809350D5368B86EB900010C1918116EB900026EBAEF
+S118907000030C2A18226EBA00040D4447108B0593006F6200AC
+S1189085060D410D305E0097D66B02A4408A0592006F6000062F
+S118909A09026B82A44018AA6A8AA43E6D756D746D7654706D72
+S11890AFF60D7669021D12470419004004790000016D765470CC
+S11890C46DF60D760D01790090AE5E00829E6D7654706DF60D53
+S11890D9767903000E19376DF46DF50D050D14790000021D049C
+S11890EE4E08790003935E0080B46C5A6EEAFFFD6E5B00010C82
+S1189103B318BB685AF20014AB14236FE3FFFA1B841B040B858A
+S11891186E6BFFFDF3000D33470A790200041D23470E40446DE0
+S118912DF319226F61FFFAF801402E790200021D244708790045
+S1189142039D5E0080B46E5800010C801888685AF20014A8146B
+S1189157205E0090C419226DF26F61FFFAF8055E008F800B87CE
+S118916C5A009496790200011D244E08790003A45E0080B46E33
+S11891815800010C801888685AF20014A814206FE0FFF81B84C7
+S11891960B855E00887E6FE0FFF46E6BFFFDF3008BFA93FF7932
+S11891AB0200161D2343045A00948E09336F329A025920790223
+S11891C000381D244708790003AA5E0080B46F63FFF447087989
+S11891D501998B5A009456790198B66F60FFF85E00889C6FE0B9
+S11891EAFFF4790200086DF2880590006DF06F62FFF86F61FF86
+S11891FFFAF81D5A0094840D444708790003B65E0080B46F62A1
+S1189214FFF44608790199965A0094566F60FFF45E00890E6EEE
+S11892296BFFFDAB144608790199A25A00945619226DF26DF2C6
+S118923E6F62FFF86F61FFFAF8135A009484790200021D244704
+S118925308790003C45E0080B46E5C00010CC418CC685AF200F5
+S118926814AC14240D405E00887E6F62FFF446045A0092186EC4
+S118927D2A00044708790199AF5A0094560D0047045A0091D43E
+S11892926F61FFF4890591000D405E00889C19226DF26DF26FAA
+S11892A762FFF86F61FFFAF8075A0094847902001C1D244708F4
+S11892BC790003D35E0080B40D516F60FFF45E0089940D0046CA
+S11892D108790199BB5A009456790200086DF26F63FFF48B0533
+S11892E693006DF36F62FFF86F61FFFAF8095A0094840D4447E0
+S11892FB08790003DA5E0080B47904A3880D416F60FFF45E0054
+S11893108AA60D004608790199C85A009456790200746DF26DDF
+S1189325F46F62FFF86F61FFFAF8175A009484790200211D244C
+S118933A4708790003E25E0080B4790199D35A00945679020036
+S118934F011D244708790003E65E0080B468596F60FFF45E009F
+S11893648AEC0D004608790199E05A009456790200086DF26F97
+S118937960FFF4880590006DF06F62FFF86F61FFFAF80B5A0020
+S118938E94847902000A1D244708790003ED5E0080B46E5A00D6
+S11893A3010CA218AA6859F1006E5B00090CB318BB6E5800085C
+S11893B8F000148B14036DF3149A14126F61FFFA6F60FFF45ED9
+S11893CD008B180B870D004D045A009496790199EB5A0094562E
+S11893E27902000A1D244E08790003F45E0080B46E5A00010C7F
+S11893F7A218AA6FE2FFF6685AF2006F60FFF614A814206FE0FC
+S118940CFFF66E5B00090CB318BB6E5A0008F20014AB14238DA9
+S11894210B95008CF594FF1D434710790003F96FE3FFF25E00B1
+S118943680B46F63FFF26DF50D326F61FFF66F60FFF45E008C14
+S118944B7A0B870D004C0E790199F66F60FFFA5E008FD640368B
+S11894606EE8FFFE0C0810001E006EE8FFFF790200026DF20D21
+S1189475621B826DF26F62FFF86F61FFFAF8115E0090480B871E
+S118948A0B874008790004045E0080B46D756D747903000E0986
+S118949F376D7654706DF60D766DF46DF50D04684BF3007902FB
+S11894B400451D23470C7902004D1D2347045A0095707902009A
+S11894C9051D214708790004125E0080B479039A58683DF500CF
+S11894DE6A0A9A590CA218AA14AD14250D5209326E4B00036EE0
+S11894F3AB00016A089A5AE8016A0AA43F1CA84666684A1102D9
+S1189508130A1102130A1102130AEA01E2006A0BA43FF3001D98
+S118951D32464A18AA0C884602FA016A8AA43F5E008F48790253
+S118953200011D254F326A0A9A5A733A471E79019A5B79049A5C
+S1189547F00D521B020D405E008DDC0D050D510D405E0090D60A
+S118955C400C79009A5B0D511B015E0090D65E008F0840087948
+S118957100042C5E0080B46D756D746D7654706DF60D76790353
+S1189586005219376DF45E0097367900FFB00960790200401939
+S118959B115E0098307902A4307901FFB6096179003B9A5E00EC
+S11895B096D4790029645E0096FC790014985E0096FC790200B2
+S11895C5016DF26DF27902FFB609627901FFB40961790030D023
+S11895DA5E00987E0B870B87790230026DF219227901301F7957
+S11895EF001FF25E0096E40B877901300779001B625E00970646
+S1189604790027C85E0096FC19446DF479029A5879011771794F
+S118961900327C5E0096E40B876A8CA43F6B84A4366B84A440AB
+S118962E6A8CA43E405C19227901FFAF0961790034265E00961B
+S1189643D46E6AFFAFF2000CAA473E18AA6EEAFFAE7902FFAE98
+S118965809626DF2790200107901FFF00961790033B05E009681
+S118966DE40B876E69FFAEF1006B029A500B026B829A501B01A2
+S11896827900FFF009605E0094A45E0085BC5E0080320D004666
+S11296979C19006D747903005209376D76547075
+S11896A66DF60D7679029A507903A4421D32470A188868A80BA3
+S11896BB021D3246F85E009580FA016A8AFFCC6B0200005D20F0
+S10796D06D765470EB
+S11396D46DF66DF20D165D000D600B876D7654709A
+S11896E46DF66F7300046DF36DF20D165D000D600B870B876DE7
+S10696F976547030
+S10D96FC6DF65D000D606D7654708C
+S10F97066DF60D165D000D606D7654705C
+S11597126DF56DF60D060D155F520D606D766D755470A0
+S11597246DF56DF60D060D155F500D606D766D75547090
+S11897366DF60D767903A4427902EF00193269B26D7654706DEE
+S118974BF60D766DF46DF50D040B04ECFE0B841D04455C7900F5
+S1189760A4420D01404C69024D4209217902EEFF1D2142144010
+S11897750E690209326982691209211D51420469134CEE6903C1
+S118978A1D4345220D428A0692001D23450A0D020942194369E0
+S118979FA369846902C28069820B804010E27F09210D10790588
+S11897B4EEFF1D5043AC19006D756D746D7654706DF60D766F7B
+S11097C902FFFEE27F6F82FFFE6D7654709A
+S11897D66DF60D766DF40D140D010D0309231D31470A6C4A680B
+S11297EB8A0B001D3046F60D106D746D765470A8
+S11897FA6DF60D76401C680B681A1CAB430679000001401E1C1B
+S118980FAB44067900FFFF40140B000B01680A46E0681A190036
+S10F98240CAA47047900FFFF6D76547015
+S11898306DF60D760D0309231D3047066CB91D3046FA6D76547A
+S104984570AE
+S11798466DF60D760D036C1A68BA0B030CAA46F66D765470C5
+S115985A6DF56DF60D060D155F4C0D606D766D7554705D
+S115986C6DF56DF60D060D155F4E0D606D766D75547049
+S118987E6DF66F7300066DF36F7300066DF36DF20D165D000DF2
+S10C9893608F0697006D76547095
+S117989C6DF60D76193340020B036C0A46FA0D306D76547098
+S11898B0726573657400000000800000000099040000993A008C
+S11898C5000000990202000000000087129900030000000000B8
+S11898DA871298FE040000000000871298FA050000000000878B
+S11898EF12000000000000000000003031320032003100300028
+S11899042E2E000099040000993A000000009902070000008557
+S11899192A82E0990008000000852A82E098FE09000000852AA9
+S118992E82E00000000000000000000099040000997000000018
+S1189943009969010098BE000000009962060099080000000010
+S11899580000000000000000000073656E736F72006D6F746F9D
+S118996D72000099840000993A0000000000000000000000007F
+S118998200002F006C65676F0066696420696E20757365006EF1
+S11899976F2073756368206669640063616E27742072656D6F82
+S11899AC76650063616E277420636C6F6E65006E6F2073756381
+S11899C168206E616D650063616E277420737461740063616E89
+S11899D62774206372656174650063616E2774206F70656E00AA
+S11899EB63616E277420726561640063616E2774207772697427
+S1189A006500924C948E92B4948E934C948E9334948E939094DF
+S1189A158E93E2948E9206948E9206948E92F8948E948E948EAF
+S1099A2A948E948E91BE9F
+S1189A300000FFFF9970994498C898D298DC98E6994E99129952
+S1069A451C99263F
+S90380007C
--- /dev/null
+++ b/lib/limbo.vim
@@ -1,0 +1,92 @@
+" Vim syntax file
+" Language:     Limbo
+" Maintainer:   Alex Efros <powerman-asdf@ya.ru>
+" Version:	0.5
+" Updated:      2008-10-17
+
+" Remove any old syntax stuff that was loaded (5.x) or quit when a syntax file
+" was already loaded (6.x).
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+
+syn keyword	lTodo		TODO TBD FIXME XXX BUG contained
+syn match	lComment	"#.*" contains=@Spell,lTodo
+
+syn keyword	lInclude	include
+
+syn match	lSpecialChar	display contained "\\\(u\x\{4}\|['\"\\tnrbavf0]\)"
+syn match	lSpecialError	display contained "\(\\[^'\"\\tnrbavf0u]\+\|\\u.\{0,3}\X\)"
+syn match	lCharError	display contained "\([^\\'][^']\+\|\\[^'][^']\+\)"
+syn region	lString		start=+"+ end=+"+ skip=+\\"+ contains=@Spell,lSpecialChar,lSpecialError
+syn region	lCharacter	start=+'+ end=+'+ skip=+\\'+ contains=lSpecialChar,lSpecialError,lCharError
+
+syn keyword	lSpecial	nil iota
+
+syn keyword	lFunction	tl hd len tagof
+syn match	lFunction	"<-=\?"
+
+syn keyword	lStatement	alt break continue exit return spawn implement import load raise
+syn keyword 	lRepeat		for while do
+syn keyword	lConditional	if else case 
+
+syn keyword	lType		array big byte chan con int list real string fn fixed
+syn keyword	lStructure	adt pick module
+syn keyword	lStorageClass	ref self cyclic type of
+
+syn keyword	lDelimiter	or to
+syn match	lDelimiter	"=>\|->\|\.\|::"
+
+
+if version >= 508 || !exists("did_icgiperl_syn_inits")
+  if version < 508
+    let did_icgiperl_syn_inits = 1
+    command -nargs=+ HiLink hi link <args>
+  else
+    command -nargs=+ HiLink hi def link <args>
+  endif
+
+    " Comment
+    HiLink lComment         Comment
+
+    " PreProc (Include, PreCondit)
+    HiLink lInclude         Include
+
+    " Constant (String, Character, Number, Boolean, Float)
+    HiLink lString          String
+    HiLink lCharacter       Character
+
+    " Special (Tag, SpecialChar, SpecialComment, Debug)
+    HiLink lSpecial	    Special
+    HiLink lSpecialChar     SpecialChar
+
+    " Identifier (Function)
+    HiLink lFunction        Function
+
+    " Statement (Conditional, Repeat, Label, Operator, Keyword, Exception)
+    HiLink lStatement       Statement
+    HiLink lRepeat          Repeat
+    HiLink lConditional     Conditional
+
+    " Type (StorageClass, Structure, Typedef)
+    HiLink lType            Type
+    HiLink lStructure       Structure
+    HiLink lStorageClass    StorageClass
+
+    " Error
+    HiLink lSpecialError    Error
+    HiLink lCharError	    Error
+
+    " Todo
+    HiLink lTodo	    Todo
+
+    " Delimiter
+    HiLink lDelimiter	    Delimiter
+
+  delcommand HiLink
+endif
+
+
+let b:current_syntax = "limbo"
--- /dev/null
+++ b/lib/mashinit
@@ -1,0 +1,4 @@
+sysname = `{ cat /dev/sysname };
+user = `{ cat  /dev/user };
+home = /usr/$user;
+run - $home/lib/mashinit;
--- /dev/null
+++ b/lib/mimetype
@@ -1,0 +1,171 @@
+#suffix		generic type	specific type	encoding	safe? y=yes, m=maybe, n=no, p=previous.suffix, r=mailreject
+.3gp		video		3gpp		-		y
+.3gpp		video		3gpp		-		y
+.C		text		plain		-		y # C++ program
+.Z		-		-		compress	m
+.a		application	octet-stream	-		y
+.ada		text		plain		-		y # ada program
+.ai		application	postscript	-		y
+.aif		audio		x-aiff		-		y
+.aifc		audio		x-aiff		-		y
+.aiff		audio		x-aiff		-		y
+.asf		video		x-ms-asf	-		m # MS streaming
+.asc		application	text		-		y # sometimes application/pgp-signature
+.asx		video		x-ms-asf	-		m # MS streaming
+.au		audio		basic		-		y # sun audio
+.avi		video		x-msvideo	-		m
+.awk		text		plain		-		y # awk program
+.bas		text		plain		-		y # basic program
+.bat		application	octet-stream	-		r # DOS executable
+.bbl		text		plain		-		y # BibTex output
+.bcpio		application	x-bcpio		-		m
+.bib		text		plain		-		y # BibTex input
+.bmp		image		bmp		-		y # bitmapped image
+.bz2		-		-		bzip2		m # bzipped file
+.c		text		plain		-		y # C program
+.c++		text		plain		-		y # C++ program
+.cacert		application	x-x509-ca-cert	-		y # DER X.509 CA certificate
+.cc		text		plain		-		y
+.cdf		application	x-netcdf	-		y
+.class		application	java		-		y # Java bytecodes
+.com		application	octet-stream	-		r # DOS executable
+.cpio		application	x-cpio		-		y
+.cpl		application	octet-stream	-		r # Windows Control Panel Applet
+.cpp		text		plain		-		y # DOS C++ program
+.crt		application	x-x509-ca-cert	-		y # DER X.509 CA certificate
+.css		text		css		-		m
+.csv		application	vnd.ms-excel	-		y # Microsoft Excel comma-separated-values
+.dat		text		plain		-		y # AMPL et al.
+.diff		text		plain		-		y
+.doc		application	msword		-		n # Microsoft Word
+.dvi		application	x-dvi		-		y # TeX output
+.enc		application	octet-stream	-		y # encrypted file
+.eps		application	postscript	-		y
+.etx		text		x-setext	-		m
+.exe		application	octet-stream	-		r # DOS executable
+.executable	application	octet-stream	-		r # DOS executable
+.exz		application	octet-stream	gzip		n # gzipped DOS executable
+.f		text		plain		-		y # fortran-77 program
+.fm		application	framemaker	-		y
+.f90		text		plain		-		y # fortran-90 program
+.flc		video		x-flc		-		m
+.fli		video		x-fli		-		m
+.gcd		text		x-pcs-gcd	-		y	# helper file for .qcp
+.gif		image		gif		-		y
+.gtar		application	x-gtar		-		m
+.gz		-		-		gzip		m # gzipped file
+.h		text		plain		-		y # C header file
+.hdf		application	x-hdf		-		y
+.hdml		text		x-hdml		-		y
+.hqx		application	octet-stream	-		m # Mac BinHex
+.htm		text		html		-		m
+.html		text		html		-		m
+.ico		image		x-icon		-		y
+.ief		image		ief		-		y
+.iso		application	octet-stream	-	y	# ISO9660 image
+.jad		text		vnd.sun.j2me.app-descriptor	-	y
+.jar		application	java-archive	-		y
+.jfif		image		jpeg		-		y
+.jfif-tbnl	image		jpeg		-		y
+.jpe		image		jpeg		-		y
+.jpeg		image		jpeg		-		y
+.jpg		image		jpeg		-		y
+#.jpg		image		pjpeg		-		y
+.js		application	x-javascript	-		y
+.latex		application	x-latex		-		y
+.ltx		application	x-latex		-		y
+.man		application	x-troff-man	-		y
+.me		application	x-troff-me	-		y
+.mid		audio		midi		-		y # MIDI music
+.mime		message		rfc822		-		y
+.mod		text		plain		-		y # AMPL et al.
+.mov		video		quicktime	-		y
+.movie		video		x-sgi-movie	-		y
+.mpe		video		mpeg		-		y
+.mpeg		video		mpeg		-		y
+.mpg		video		mpeg		-		y
+.ms		application	x-troff-ms	-		y
+.mv		video		x-sgi-movie	-		y
+.nc		application	x-netcdf	-		y
+.o		application	octet-stream	-		y
+.oda		application	oda		-		m
+.p		text		plain			-	y # Pascal program
+.p7m		application	x-pkcs7-mime		-	y # SMIME
+.p7s		application	x-pkcs7-signature	-	y # SMIME
+.pbm		image		x-portable-bitmap	-	y
+.pdf		application	pdf		-		y # Adobe Portable Document Format
+.pif		application	octet-stream	-		r # DOS executable
+.pgm		image		x-portable-graymap	-	y
+.pl		text		plain		-		y
+.png		image		png		-		y
+.pnm		image		x-portable-anymap	-	y
+.ppm		image		x-portable-pixmap	-	y
+.ppt		application	vnd.ms-powerpoint	-	n # Microsoft PowerPoint
+.ps		application	postscript	-		m
+.qcp		audio		vnd.qcelp	-		y # Qualcomm CELP
+.qcp2		audio		qcp		-		y # Qualcomm CELP
+.qt		video		quicktime	-		y
+.r		text		plain		-		y # ratfor program
+.ra		audio		x-pn-realaudio	-		y # G2 RealAudio
+.ram		audio		x-pn-realaudio	-		y # G2 RealAudio
+.ras		image		x-cmu-rast	-		y
+.rc		text		plain		-		y # rc
+.rfr		text		plain		-		y # refer
+.rgb		image		x-rgb		-		y
+.rm		application	x-pn-realmedia	-		y # G2 RealAudio
+.roff		application	x-troff		-		y
+.rpm		audio		x-pn-realaudio-plugin	-	y # G2 RealAudio
+.rtf		application	rtf		-		y
+.rtx		text		richtext 	-		y
+.scr		application	octet-stream	-		r # DOS executable (screen saver)
+.sh		application	x-shar		-		m
+.shar		application	x-shar		-		m
+.smi		application	smil		-		m # sync multimedia
+.smil		application	smil		-		m # sync multimedia
+.snd		audio		basic		-		y
+.suspect	application	octet-stream	-		y # upas/vf
+.sv4cpio	application	x-sv4cpio	-		m
+.sv4crc		application	x-sv4crc	-		y
+.swf		application	x-shockwave-flash		-		y
+.t		application	x-troff		-		y
+.tar		application	x-tar		-		m
+.tardist	application	x-tardist	-		n # SGI SoftwareManager
+.taz		application	x-tar		compress	m
+.tcl		application	x-tcl		-		y
+.tex		application	x-tex		-		y # Tex input
+.texi		application	x-texinfo	-		y
+.texinfo	application	x-texinfo	-		y
+.text		text		plain		-		y
+.tgz		application	x-tar		gzip		m
+.tif		image		tiff		-		y
+.tiff		image		tiff		-		y
+.toc		text		plain		-		y # table of contents
+.tr		application	x-troff		-		y
+.trz		application	x-tar		compress	m
+.tsv		text		tab-separated-values	-	y
+.txt		text		-		-		y
+.txt		text		plain		-		y
+.ucert		application	x-x509-user-cert	-	y # DER X.509 user certificate
+.ustar		application	x-ustar		-		m
+.vcf		text		x-vcard		-		y # vCard
+.wav		audio		x-wav		-		y
+.wbmp		image		vnd.wap.wbmp	-		y # wireless bitmap
+.wml		text		vnd.wap.wml	-		m # WML doc
+.wmlc		application	vnd.wap.wmlc	-		m # compiled WML doc
+.wmls		text		vnd.wap.wmlscript	-	m # WMLScript
+.wmlsc		application	vnd.wap.wmlscriptc	-	m # compiled WMLScript
+.wsrc		application	x-wais-source	-		y
+.xbm		image		x-xbitmap	-		y # X bitmap
+.xgz		-		-		x-gzip		m # gzipped file
+.xls		application	vnd.ms-excel	-		n # Microsoft Excel
+.xml		text		xml		-		m
+.xpm		image		x-xpixmap	-		y
+.xwd		image		x-xwindowdump	-		y
+.z		-		-		compress	m
+.Z		-		-		compress	m
+.zip		application	zip		-		n
+.zzz		application	sleep		-		n # testing
+-		application	x-gunzip	-		p # type for .tar.gz
+-		message		delivery-status	-		y # mail bounces
+-		application	pgp-signature	-		y
+-		application	pgp-encrypted	-		y
--- /dev/null
+++ b/lib/mk/binds
@@ -1,0 +1,2 @@
+/lib/mk/mkconfig	/mkconfig
+/lib/mk/mksubdirs	/mkfiles/mksubdirs
--- /dev/null
+++ b/lib/mk/mkconfig
@@ -1,0 +1,28 @@
+#
+#	Set the following 4 variables.  The host system is the system where
+#	the software will be built; the target system is where it will run.
+#	They are almost always the same.
+
+#	On Nt systems, the ROOT path MUST be of the form `drive:/path'
+ROOT=
+
+#
+#	Except for building kernels, SYSTARG must always be the same as SYSHOST
+#
+SYSHOST=Plan9		# build system OS type (Hp, Inferno, Irix, Linux, Nt, Plan9, Solaris)
+SYSTARG=$SYSHOST		# target system OS type (Hp, Inferno, Irix, Linux, Nt, Plan9, Solaris)
+
+#
+#	specify the architecture of the target system - Inferno imports it from the
+#	environment; for other systems it is usually just hard-coded
+#
+#OBJTYPE=386			# target system object type (s800, mips, 386, arm, sparc)
+OBJTYPE=386
+
+#
+#	no changes required beyond this point
+#
+OBJDIR=$SYSTARG/$OBJTYPE
+
+<$ROOT/mkfiles/mkhost-$SYSHOST			# variables appropriate for host system
+<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE	# variables used to build target object type
--- /dev/null
+++ b/lib/mk/mksubdirs
@@ -1,0 +1,13 @@
+all:V:	all-$SHELLTYPE
+install:V: install-$SHELLTYPE
+uninstall:V: uninstall-$SHELLTYPE
+nuke:V: nuke-$SHELLTYPE
+clean:V: clean-$SHELLTYPE
+
+%-rc %-nt %-sh:QV:
+	for j in $DIRS {
+		if { ftest -d $j } {
+			echo 'cd' $j '; mk' $MKFLAGS $stem
+			cd $j; mk $MKFLAGS $stem; cd ..
+		}
+	}
--- /dev/null
+++ b/lib/ndb/common
@@ -1,0 +1,242 @@
+#
+#  ip protocol numbers
+#
+protocol=reserved	ipv4proto=0
+protocol=icmp		ipv4proto=1
+protocol=igmp		ipv4proto=2
+protocol=ggp		ipv4proto=3
+protocol=ip		ipv4proto=4
+protocol=st		ipv4proto=5
+protocol=tcp		ipv4proto=6
+protocol=ucl		ipv4proto=7
+protocol=egp		ipv4proto=8
+protocol=igp		ipv4proto=9
+protocol=bbn-rcc-mon	ipv4proto=10
+protocol=nvp-ii		ipv4proto=11
+protocol=pup		ipv4proto=12
+protocol=argus		ipv4proto=13
+protocol=emcon		ipv4proto=14
+protocol=xnet		ipv4proto=15
+protocol=chaos		ipv4proto=16
+protocol=udp		ipv4proto=17
+protocol=mux		ipv4proto=18
+protocol=dcn-meas	ipv4proto=19
+protocol=hmp		ipv4proto=20
+protocol=prm		ipv4proto=21
+protocol=xns-idp	ipv4proto=22
+protocol=trunk-1	ipv4proto=23
+protocol=trunk-2	ipv4proto=24
+protocol=leaf-1		ipv4proto=25
+protocol=leaf-2		ipv4proto=26
+protocol=rdp		ipv4proto=27
+protocol=irtp		ipv4proto=28
+protocol=iso-tp4	ipv4proto=29
+protocol=netblt		ipv4proto=30
+protocol=mfe-nsp	ipv4proto=31
+protocol=merit-inp	ipv4proto=32
+protocol=sep		ipv4proto=33
+protocol=3pc		ipv4proto=34
+protocol=idpr		ipv4proto=35
+protocol=xtp		ipv4proto=36
+protocol=ddp		ipv4proto=37
+protocol=idpr-cmtp	ipv4proto=38
+protocol=tp++		ipv4proto=39
+protocol=il		ipv4proto=40
+protocol=sip		ipv4proto=41
+protocol=sdrp		ipv4proto=42
+protocol=sip-sr		ipv4proto=43
+protocol=sip-frag	ipv4proto=44
+protocol=idrp		ipv4proto=45
+protocol=rsvp		ipv4proto=46
+protocol=gre		ipv4proto=47
+protocol=mhrp		ipv4proto=48
+protocol=bna		ipv4proto=49
+protocol=sipp-esp	ipv4proto=50
+protocol=sipp-ah	ipv4proto=51
+protocol=i-nlsp		ipv4proto=52
+protocol=swipe		ipv4proto=53
+protocol=nhrp		ipv4proto=54
+protocol=any		ipv4proto=61
+protocol=cftp		ipv4proto=62
+protocol=any		ipv4proto=63
+protocol=sat-expak	ipv4proto=64
+protocol=kryptolan	ipv4proto=65
+protocol=rvd		ipv4proto=66
+protocol=ippc		ipv4proto=67
+protocol=any		ipv4proto=68
+protocol=sat-mon	ipv4proto=69
+protocol=visa		ipv4proto=70
+protocol=ipcv		ipv4proto=71
+protocol=cpnx		ipv4proto=72
+protocol=cphb		ipv4proto=73
+protocol=wsn		ipv4proto=74
+protocol=pvp		ipv4proto=75
+protocol=br-sat-mon	ipv4proto=76
+protocol=sun-nd		ipv4proto=77
+protocol=wb-mon		ipv4proto=78
+protocol=wb-expak	ipv4proto=79
+protocol=iso-ip		ipv4proto=80
+protocol=vmtp		ipv4proto=81
+protocol=secure-vmtp	ipv4proto=82
+protocol=vines		ipv4proto=83
+protocol=ttp		ipv4proto=84
+protocol=nsfnet-igp	ipv4proto=85
+protocol=dgp		ipv4proto=86
+protocol=tcf		ipv4proto=87
+protocol=igrp		ipv4proto=88
+protocol=ospfigp	ipv4proto=89	protocol=ospf
+protocol=sprite-rpc	ipv4proto=90
+protocol=larp		ipv4proto=91
+protocol=mtp		ipv4proto=92
+protocol=ax.25		ipv4proto=93
+protocol=ipip		ipv4proto=94
+protocol=micp		ipv4proto=95
+protocol=scc-sp		ipv4proto=96
+protocol=etherip	ipv4proto=97
+protocol=encap		ipv4proto=98
+protocol=any		ipv4proto=99
+protocol=gmtp		ipv4proto=100
+protocol=rudp		ipv4proto=254	# unofficial
+
+#
+#  services
+#
+tcp=cs port=1
+tcp=echo port=7
+tcp=discard port=9
+tcp=systat port=11
+tcp=daytime port=13
+tcp=netstat port=15
+tcp=chargen port=19
+tcp=ftp-data port=20
+tcp=ftp port=21
+tcp=ssh port=22
+tcp=telnet port=23
+tcp=smtp port=25
+tcp=time port=37
+tcp=whois port=43
+tcp=dns port=53
+tcp=domain port=53
+tcp=uucp port=64
+tcp=gopher port=70
+tcp=rje port=77
+tcp=finger port=79
+tcp=http port=80
+tcp=link port=87
+tcp=supdup port=95
+tcp=hostnames port=101
+tcp=iso-tsap port=102
+tcp=x400 port=103
+tcp=x400-snd port=104
+tcp=csnet-ns port=105
+tcp=pop-2 port=109
+tcp=pop3 port=110
+tcp=sunrpc port=111
+tcp=uucp-path port=117
+tcp=nntp port=119
+tcp=profile port=136
+tcp=netbios port=139
+tcp=imap4 port=143
+tcp=NeWS port=144
+tcp=print-srv port=170
+tcp=z39.50 port=210
+tcp=fsb port=400
+tcp=sysmon port=401
+tcp=proxy port=402
+tcp=proxyd port=404
+tcp=https port=443
+tcp=ssmtp port=465
+tcp=rexec port=512 restricted=
+tcp=login port=513 restricted=
+tcp=shell port=514 restricted=
+tcp=printer port=515
+tcp=courier port=530
+tcp=cscan port=531
+tcp=uucp port=540
+tcp=snntp port=563
+tcp=9fs port=564
+tcp=whoami port=565
+tcp=guard port=566
+tcp=ticket port=567
+tcp=dlsftp port=666
+tcp=fmclient port=729
+tcp=imaps port=993
+tcp=pop3s port=995
+tcp=ingreslock port=1524
+tcp=pptp port=1723
+tcp=webster port=2627
+tcp=weather port=3000
+tcp=secstore port=5356
+tcp=Xdisplay port=6000
+tcp=styx port=6666
+tcp=mpeg port=6667
+tcp=rstyx port=6668
+tcp=infdb port=6669
+tcp=infsigner port=6671
+tcp=infcsigner port=6672
+tcp=inflogin port=6673
+tcp=registry port=6675
+tcp=internalreg port=6676
+tcp=bandt port=7330
+tcp=face port=32000
+tcp=exportfs port=17007
+tcp=rexexec port=17009
+tcp=ncpu port=17010
+tcp=cpu port=17013
+tcp=glenglenda1 port=17020
+tcp=glenglenda2 port=17021
+tcp=glenglenda3 port=17022
+tcp=glenglenda4 port=17023
+tcp=glenglenda5 port=17024
+tcp=glenglenda6 port=17025
+tcp=glenglenda7 port=17026
+tcp=glenglenda8 port=17027
+tcp=glenglenda9 port=17028
+tcp=glenglenda10 port=17029
+tcp=flyboy port=17032
+tcp=dlsftp port=17033
+tcp=venti port=17034
+tcp=wiki port=17035
+tcp=vica port=17036
+
+il=echo port=7
+il=discard port=9
+il=chargen port=19
+il=whoami port=565
+il=ticket port=566
+il=challbox port=567
+il=ocpu port=17005
+il=ocpunote port=17006
+il=exportfs port=17007
+il=9fs port=17008
+il=rexexec port=17009
+il=ncpu port=17010
+il=ncpunote port=17011
+il=tcpu port=17012
+il=cpu port=17013
+il=fsauth port=17020
+il=rexauth port=17021
+il=changekey port=17022
+il=chal port=17023
+il=check port=17024
+il=juke port=17026
+il=ramfs port=17031
+
+udp=echo port=7
+udp=tacacs port=49
+udp=tftp port=69
+udp=bootpc port=68
+udp=bootp port=67
+udp=domain port=53
+udp=dns port=53
+udp=ntp port=123
+udp=profile port=136
+udp=snmp port=161
+udp=rip port=520
+udp=bfs port=2201
+udp=virgil port=2202
+udp=bandt2 port=7331
+udp=oradius port=1645
+udp=chord-dhash port=11865
+
+gre=ppp port=34827
--- /dev/null
+++ b/lib/ndb/dns
@@ -1,0 +1,31 @@
+#
+# optional bootstrap data for ndb/dns
+# (it has got a.root-servers.net built-in if necessary)
+#
+dom=
+	ns=m.root-servers.net
+	ns=c.root-servers.net
+	ns=d.root-servers.net
+	ns=e.root-servers.net
+	ns=l.root-servers.net
+	ns=f.root-servers.net
+	ns=a.root-servers.net
+	ns=b.root-servers.net
+	ns=g.root-servers.net
+	ns=h.root-servers.net
+	ns=i.root-servers.net
+	ns=j.root-servers.net
+	ns=k.root-servers.net
+dom=a.root-servers.net ip=198.41.0.4
+dom=b.root-servers.net ip=128.9.0.107
+dom=c.root-servers.net ip=192.33.4.12
+dom=d.root-servers.net ip=128.8.10.90
+dom=e.root-servers.net ip=192.203.230.10
+dom=f.root-servers.net ip=192.5.5.241
+dom=g.root-servers.net ip=192.112.36.4
+dom=h.root-servers.net ip=128.63.2.53
+dom=i.root-servers.net ip=192.36.148.17
+dom=j.root-servers.net ip=198.41.0.10
+dom=k.root-servers.net ip=193.0.14.129
+dom=l.root-servers.net ip=198.32.64.12
+dom=m.root-servers.net ip=202.12.27.33
--- /dev/null
+++ b/lib/ndb/inferno
@@ -1,0 +1,21 @@
+#
+# inferno port assignment
+#
+
+tcp=infgamelogin port=6660	# inferno games login service
+tcp=styx port=6666	# main file service
+tcp=mpeg port=6667	# mpeg stream
+tcp=rstyx port=6668	# remote invocation
+tcp=infdb port=6669	# database server
+tcp=infweb port=6670	# inferno web server
+tcp=infsigner port=6671	# inferno signing services
+tcp=infcsigner port=6672	# inferno countersigner
+tcp=inflogin port=6673	# inferno credential service
+tcp=infsds port=6674	# software download
+tcp=registry port=6675	# default registry
+tcp=internalreg port=6676	# cpupool registry
+tcp=infkey	port=6677	# key-changing service
+tcp=infsched port=6678	# grid scheduler
+
+udp=virgil port=2202	# naming service
+udp=gossip port=2666	# gossip protocol
--- /dev/null
+++ b/lib/ndb/local
@@ -1,0 +1,20 @@
+database=
+	file=/lib/ndb/local
+	file=/lib/ndb/dns
+	file=/lib/ndb/inferno
+	file=/lib/ndb/common
+
+#
+# default site-wide resources
+#
+infernosite=
+	#dnsdomain=your.domain.com
+	#dns=1.2.3.4	# resolver
+	SIGNER=your_signer_here
+	FILESERVER=your_fileserver_here
+	smtp=your_smtpserver_here
+	pop3=your_pop3server_here
+	PROXY=your_httpproxy_here
+	GAMES=your_games_server
+	registry=your_registry_server
+	gridsched=your_inferno_grid_scheduler
--- /dev/null
+++ b/lib/ndb/registry
@@ -1,0 +1,2 @@
+# this file is given to the local registry(4) by svc/registry (see svc(8))
+# as its initial data.  you could put static local service descriptions here.
--- /dev/null
+++ b/lib/ndb/services
@@ -1,0 +1,21 @@
+# this is not an ndb file, but a file in Unix /etc/services format
+# that might be added to the Unix file (or the similar one on Windows)
+# if needed for host applications to access Inferno.
+# Inferno uses the ndb files when ndb/cs and ndb/dns are running
+#
+# Assignment of inferno port numbers
+#
+
+styx		6666/tcp	# Main file service
+mpeg		6667/tcp	# Mpeg stream
+rstyx		6668/tcp	# Remote invocation
+infdb		6669/tcp	# Database connection
+infweb		6670/tcp	# inferno web server
+infsigner	6671/tcp	# inferno signing services
+infcsigner	6672/tcp	# inferno signing services
+inflogin	6673/tcp	# inferno login service
+virgil		2202/udp	virgild		# inferno info
+infsds	6674/tcp	# SDS
+infgamelogin	6660/tcp	# inferno games login service
+registry		6675/tcp	# default registry
+cpupoolreg	6676/tcp	# cpupool registry
--- /dev/null
+++ b/lib/polyhedra
@@ -1,0 +1,2459 @@
+# data generated by kaleido written by Dr. Zvi Har'El (rl@math.technion.ac.il)
+pentagonal prism
+pentagonal dipyramid
+2 5|2
+(4.4.5)
+dihedral group
+D
+2{5}+5{4}
+0 10 15 7 10 1 0 0 2 2 3 20 2 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8737108351  0.0000000000  0.4864456563
+-0.3018596695  0.8199093629  0.4864456563
+-0.6651309335 -0.5665434359  0.4864456563
+ 0.5718511657  0.8199093629 -0.0271086873
+ 0.7485628941 -0.5665434359 -0.3445027268
+-0.9669906029  0.2533659270 -0.0271086873
+-0.2024936222 -0.9166865354 -0.3445027268
+ 0.4467032247  0.2533659270 -0.8580570704
+-0.5043532916 -0.0967771725 -0.8580570704
+ 0.2978495106  0.4270509831  0.5067318540
+-0.5036584607  0.1319660113  0.5067318540
+ 0.2978495106 -0.8090169944  0.5067318540
+ 0.6877395818  0.1319660113 -0.1935543450
+-0.2978495106  0.8090169944 -0.5067318540
+-0.6091275581 -0.3454915028 -0.1935543450
+ 0.1271969263 -0.3454915028 -0.6263550179
+4 0 2 4 1 
+4 0 3 6 2 
+5 0 1 5 7 3 
+4 1 4 8 5 
+5 2 6 9 8 4 
+4 3 7 9 6 
+4 5 8 9 7 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 2 6 3 
+3 4 5 1 
+3 5 6 2 
+3 6 4 3 
+3 4 5 6 
+pentagonal antiprism
+pentagonal deltohedron
+|2 2 5
+(3.3.3.5)
+dihedral group
+D
+2{5}+10{3}
+1 10 20 12 10 1 0 0 2 2 4 20 2 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000  0.4472135955
+ 0.2763932023  0.8506508084  0.4472135955
+-0.7236067977  0.5257311121  0.4472135955
+-0.7236067977 -0.5257311121  0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+ 0.7236067977  0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2763932023  0.2008114159  0.4472135955
+-0.1055728090  0.3249196962  0.4472135955
+-0.3416407865 -0.0000000000  0.4472135955
+ 0.2763932023 -0.8506508084  0.4472135955
+ 0.5527864045  0.0000000000 -0.1055728090
+ 0.4472135955  0.3249196962  0.1055728090
+-0.2763932023  0.8506508084 -0.4472135955
+-0.5527864045 -0.0000000000  0.1055728090
+-0.4472135955 -0.3249196962 -0.1055728090
+ 0.1055728090 -0.3249196962 -0.4472135955
+ 0.3416407865  0.0000000000 -0.4472135955
+-0.2763932023 -0.2008114159 -0.4472135955
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+5 0 1 5 8 4 
+3 1 6 5 
+3 1 2 6 
+5 2 3 7 9 6 
+3 3 4 7 
+3 4 8 7 
+3 5 9 8 
+3 5 6 9 
+3 7 8 9 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 6 7 2 1 
+4 7 8 3 2 
+4 3 9 10 4 
+4 10 6 5 4 
+4 6 11 8 7 
+4 11 9 3 8 
+4 9 10 6 11 
+tetrahedron
+tetrahedron
+3|2 3
+(3.3.3)
+tetrahedral group
+A4
+4{3}
+5 4 6 4 4 1 0 0 2 1 3 24 3 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9428090416  0.0000000000 -0.3333333333
+-0.4714045208  0.8164965809 -0.3333333333
+-0.4714045208 -0.8164965809 -0.3333333333
+ 0.4714045208  0.8164965809  0.3333333333
+-0.9428090416 -0.0000000000  0.3333333333
+ 0.4714045208 -0.8164965809  0.3333333333
+-0.0000000000  0.0000000000 -1.0000000000
+3 0 2 1 
+3 0 3 2 
+3 0 1 3 
+3 1 2 3 
+3 2 0 1 
+3 2 3 0 
+3 3 1 0 
+3 1 2 3 
+truncated tetrahedron
+triakistetrahedron
+2 3|3
+(6.6.3)
+tetrahedral group
+A4
+4{6}+4{3}
+6 12 18 8 12 1 0 0 2 2 3 24 3 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7713892158  0.0000000000  0.6363636364
+-0.6428243465  0.4264014327  0.6363636364
+ 0.2999846950 -0.7106690545  0.6363636364
+ 0.8999540851  0.4264014327 -0.0909090909
+-0.9856639980  0.1421338109 -0.0909090909
+-0.5142594772  0.8528028654 -0.0909090909
+-0.0428549564 -0.9949366763 -0.0909090909
+ 0.5571144337  0.1421338109 -0.8181818182
+ 0.2571297386  0.8528028654 -0.4545454545
+-0.6856793030 -0.5685352436 -0.4545454545
+ 0.0857099129 -0.5685352436 -0.8181818182
+ 0.2461829820  0.8164965809  0.5222329679
+-0.6564879519 -0.5443310540  0.5222329679
+ 0.2461829820 -0.1632993162  0.5222329679
+ 0.8206099399 -0.5443310540 -0.1740776560
+-0.4923659639  0.3265986324  0.1044465936
+ 0.3938927711  0.3265986324 -0.3133397807
+-0.4103049699  0.2721655270 -0.8703882798
+-0.1477097892 -0.4898979486 -0.3133397807
+6 0 2 6 9 4 1 
+6 0 3 7 10 5 2 
+3 0 1 3 
+6 1 4 8 11 7 3 
+3 2 5 6 
+3 4 9 8 
+6 5 10 11 8 9 6 
+3 7 11 10 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 6 5 
+3 5 0 6 
+3 6 7 1 
+3 7 3 6 
+octahedron
+hexahedron
+4|2 3
+(3.3.3.3)
+octahedral group
+S4
+8{3}
+9 6 12 8 6 1 0 0 2 1 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 1.0000000000  0.0000000000 -0.0000000000
+-0.0000000000  1.0000000000 -0.0000000000
+-1.0000000000 -0.0000000000 -0.0000000000
+ 0.0000000000 -1.0000000000 -0.0000000000
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.5773502692  0.5773502692  0.5773502692
+-0.5773502692  0.5773502692  0.5773502692
+-0.5773502692 -0.5773502692  0.5773502692
+ 0.5773502692 -0.5773502692  0.5773502692
+ 0.5773502692 -0.5773502692 -0.5773502692
+ 0.5773502692  0.5773502692 -0.5773502692
+-0.5773502692  0.5773502692 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 1 4 
+3 1 5 4 
+3 1 2 5 
+3 2 3 5 
+3 3 4 5 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 6 7 2 1 
+4 7 4 3 2 
+4 4 5 6 7 
+hexahedron
+octahedron
+3|2 4
+(4.4.4)
+octahedral group
+S4
+6{4}
+10 8 12 6 8 1 0 0 2 1 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9428090416  0.0000000000  0.3333333333
+-0.4714045208  0.8164965809  0.3333333333
+-0.4714045208 -0.8164965809  0.3333333333
+ 0.4714045208  0.8164965809 -0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+-0.9428090416 -0.0000000000 -0.3333333333
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.4082482905  0.7071067812  0.5773502692
+-0.8164965809 -0.0000000000  0.5773502692
+ 0.4082482905 -0.7071067812  0.5773502692
+ 0.8164965809 -0.0000000000 -0.5773502692
+-0.4082482905  0.7071067812 -0.5773502692
+-0.4082482905 -0.7071067812 -0.5773502692
+4 0 2 4 1 
+4 0 3 6 2 
+4 0 1 5 3 
+4 1 4 7 5 
+4 2 6 7 4 
+4 3 5 7 6 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 5 3 2 
+3 4 5 1 
+3 3 4 5 
+cuboctahedron
+rhombic dodecahedron
+2|3 4
+(3.4.3.4)
+octahedral group
+S4
+6{4}+8{3}
+11 12 24 14 12 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8660254038  0.0000000000  0.5000000000
+ 0.2886751346  0.8164965809  0.5000000000
+-0.8660254038 -0.0000000000  0.5000000000
+-0.2886751346 -0.8164965809  0.5000000000
+ 0.8660254038 -0.0000000000 -0.5000000000
+ 0.5773502692 -0.8164965809 -0.0000000000
+-0.5773502692  0.8164965809 -0.0000000000
+ 0.2886751346  0.8164965809 -0.5000000000
+-0.8660254038  0.0000000000 -0.5000000000
+-0.2886751346 -0.8164965809 -0.5000000000
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.4082482905  0.2886751346  0.7071067812
+-0.4082482905  0.5773502692  0.7071067812
+-0.4082482905 -0.2886751346  0.7071067812
+ 0.4082482905 -0.5773502692  0.7071067812
+ 0.8164965809 -0.2886751346 -0.0000000000
+ 0.8164965809  0.5773502692 -0.0000000000
+ 0.0000000000  0.8660254038 -0.0000000000
+-0.8164965809  0.2886751346 -0.0000000000
+-0.8164965809 -0.5773502692 -0.0000000000
+-0.0000000000 -0.8660254038 -0.0000000000
+ 0.4082482905 -0.5773502692 -0.7071067812
+ 0.4082482905  0.2886751346 -0.7071067812
+-0.4082482905  0.5773502692 -0.7071067812
+-0.4082482905 -0.2886751346 -0.7071067812
+3 0 2 1 
+4 0 3 7 2 
+3 0 4 3 
+4 0 1 6 4 
+3 1 5 6 
+4 1 2 8 5 
+3 2 7 8 
+3 3 9 7 
+4 3 4 10 9 
+3 4 6 10 
+4 5 11 10 6 
+3 5 8 11 
+4 7 9 11 8 
+3 9 10 11 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 1 7 8 2 
+4 8 9 3 2 
+4 4 10 11 5 
+4 9 10 4 3 
+4 6 12 7 1 
+4 11 12 6 5 
+4 12 13 8 7 
+4 13 10 9 8 
+4 10 11 12 13 
+truncated octahedron
+tetrakishexahedron
+2 4|3
+(6.6.4)
+octahedral group
+S4
+8{6}+6{4}
+12 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6000000000  0.0000000000  0.8000000000
+-0.4000000000  0.4472135955  0.8000000000
+-0.0666666667 -0.5962847940  0.8000000000
+ 0.8000000000  0.4472135955  0.4000000000
+ 0.5333333333 -0.5962847940  0.6000000000
+-0.8666666667  0.2981423970  0.4000000000
+-0.2000000000  0.8944271910  0.4000000000
+-0.5333333333 -0.7453559925  0.4000000000
+ 0.9333333333  0.2981423970 -0.2000000000
+ 0.4000000000  0.8944271910  0.2000000000
+ 0.6666666667 -0.7453559925 -0.0000000000
+-0.6666666667  0.7453559925 -0.0000000000
+-0.9333333333 -0.2981423970  0.2000000000
+-0.4000000000 -0.8944271910 -0.2000000000
+ 0.5333333333  0.7453559925 -0.4000000000
+ 0.8666666667 -0.2981423970 -0.4000000000
+ 0.2000000000 -0.8944271910 -0.4000000000
+-0.5333333333  0.5962847940 -0.6000000000
+-0.8000000000 -0.4472135955 -0.4000000000
+ 0.0666666667  0.5962847940 -0.8000000000
+ 0.4000000000 -0.4472135955 -0.8000000000
+-0.6000000000  0.0000000000 -0.8000000000
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.2581988897  0.5773502692  0.7745966692
+-0.6024640761 -0.1924500897  0.7745966692
+ 0.2581988897 -0.2886751346  0.7745966692
+ 0.9467292624 -0.1924500897  0.2581988897
+-0.5163977795  0.5773502692  0.3872983346
+ 0.0860662966 -0.9622504486  0.2581988897
+ 0.6454972244  0.5773502692 -0.0000000000
+-0.9467292624  0.1924500897 -0.2581988897
+-0.0860662966  0.9622504486 -0.2581988897
+-0.6454972244 -0.5773502692 -0.0000000000
+ 0.6024640761  0.1924500897 -0.7745966692
+ 0.5163977795 -0.5773502692 -0.3872983346
+-0.2581988897 -0.5773502692 -0.7745966692
+-0.2581988897  0.2886751346 -0.7745966692
+6 0 2 7 10 4 1 
+6 0 3 8 13 6 2 
+4 0 1 5 3 
+6 1 4 9 16 11 5 
+4 2 6 12 7 
+6 3 5 11 17 14 8 
+4 4 10 15 9 
+6 6 13 19 22 18 12 
+6 7 12 18 20 15 10 
+4 8 14 19 13 
+6 9 15 20 23 21 16 
+4 11 16 21 17 
+6 14 17 21 23 22 19 
+4 18 22 23 20 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 5 3 2 
+3 4 7 1 
+3 0 8 4 
+3 1 9 5 
+3 3 10 6 
+3 6 8 0 
+3 5 11 3 
+3 8 7 4 
+3 7 9 1 
+3 9 12 5 
+3 10 8 6 
+3 11 10 3 
+3 12 11 5 
+3 8 13 7 
+3 7 12 9 
+3 10 13 8 
+3 12 10 11 
+3 13 12 7 
+3 10 13 12 
+truncated hexahedron
+triakisoctahedron
+2 3|4
+(8.8.3)
+octahedral group
+S4
+6{8}+8{3}
+13 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5395042868  0.0000000000  0.8419828529
+-0.4604957132  0.2810846377  0.8419828529
+ 0.2466110680 -0.4798414911  0.8419828529
+ 0.8419828529  0.2810846377  0.4604957132
+-0.8651239283  0.1987568534  0.4604957132
+-0.5722307095  0.6785983445  0.4604957132
+ 0.1348760717 -0.8773551980  0.4604957132
+ 0.9768589246  0.1987568534 -0.0790085736
+ 0.7302478566  0.6785983445  0.0790085736
+-0.9768589246 -0.1987568534  0.0790085736
+-0.2697521434  0.9596829823  0.0790085736
+-0.2697521434 -0.9596829823  0.0790085736
+ 0.2697521434 -0.9596829823 -0.0790085736
+ 0.8651239283 -0.1987568534 -0.4604957132
+ 0.2697521434  0.9596829823 -0.0790085736
+-0.7302478566 -0.6785983445 -0.0790085736
+-0.8419828529 -0.2810846377 -0.4604957132
+-0.1348760717  0.8773551980 -0.4604957132
+ 0.5722307095 -0.6785983445 -0.4604957132
+ 0.4604957132 -0.2810846377 -0.8419828529
+-0.5395042868  0.0000000000 -0.8419828529
+-0.2466110680  0.4798414911 -0.8419828529
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1987568534  0.7071067812  0.6785983445
+-0.5380560257 -0.5000000000  0.6785983445
+ 0.1987568534 -0.1213203436  0.6785983445
+ 0.8191406634 -0.5000000000  0.2810846377
+-0.4798414911  0.2928932188  0.4457402063
+ 0.6444970597  0.2928932188  0.1164290691
+-0.8191406634  0.5000000000 -0.2810846377
+ 0.0341012848 -0.7071067812  0.1164290691
+ 0.5380560257  0.5000000000 -0.6785983445
+-0.6444970597 -0.2928932188 -0.1164290691
+-0.0341012848  0.7071067812 -0.1164290691
+-0.1987568534 -0.7071067812 -0.6785983445
+ 0.4798414911 -0.2928932188 -0.4457402063
+-0.1987568534  0.1213203436 -0.6785983445
+8 0 2 6 11 15 9 4 1 
+8 0 3 7 12 16 10 5 2 
+3 0 1 3 
+8 1 4 8 14 19 13 7 3 
+3 2 5 6 
+3 4 9 8 
+8 5 10 17 21 22 18 11 6 
+3 7 13 12 
+8 8 9 15 18 22 23 20 14 
+3 10 16 17 
+3 11 18 15 
+8 12 13 19 20 23 21 17 16 
+3 14 20 19 
+3 21 23 22 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 8 5 
+3 8 0 5 
+3 6 9 1 
+3 0 10 6 
+3 1 11 7 
+3 11 3 7 
+3 3 12 8 
+3 8 10 0 
+3 9 11 1 
+3 6 11 9 
+3 8 6 10 
+3 11 12 3 
+3 11 8 12 
+3 6 13 11 
+3 8 13 6 
+3 11 8 13 
+small rhombicuboctahedron
+deltoidal icositetrahedron
+3 4|2
+(4.3.4.4)
+octahedral group
+S4
+18{4}+8{3}
+14 24 48 26 24 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6675992222  0.0000000000  0.7445208382
+-0.0977676425  0.6604015517  0.7445208382
+-0.6389637427  0.1934271362  0.7445208382
+-0.0977676425 -0.6604015517  0.7445208382
+ 0.5698315797  0.6604015517  0.4890416764
+ 0.9727633538  0.1934271362  0.1277395809
+ 0.5698315797 -0.6604015517  0.4890416764
+-0.3337996111  0.9339488311  0.1277395809
+-0.7367313852 -0.4669744155  0.4890416764
+-0.8749957112  0.4669744155  0.1277395809
+-0.3337996111 -0.9339488311  0.1277395809
+ 0.3337996111  0.9339488311 -0.1277395809
+ 0.8749957112 -0.4669744155 -0.1277395809
+ 0.7367313852  0.4669744155 -0.4890416764
+ 0.3337996111 -0.9339488311 -0.1277395809
+-0.5698315797  0.6604015517 -0.4890416764
+-0.9727633538 -0.1934271362 -0.1277395809
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.0977676425  0.6604015517 -0.7445208382
+ 0.6389637427 -0.1934271362 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222  0.0000000000 -0.7445208382
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.3302007759  0.3826834324  0.8628562095
+-0.2553967884  0.2959899757  0.8628562095
+-0.4269143440 -0.2705980501  0.8628562095
+ 0.3302007759 -0.3826834324  0.8628562095
+ 0.8938887595 -0.2705980501  0.3574067443
+ 0.7661903653  0.2959899757  0.4719117310
+ 0.1367736397  0.9238795325  0.3574067443
+-0.5636879836  0.6532814824  0.5054494651
+-0.9339488311 -0.0000000000  0.3574067443
+-0.4050047633 -0.7145830136  0.4719117310
+ 0.1367736397 -0.9238795325  0.3574067443
+ 0.7571151198  0.6532814824 -0.0000000000
+ 0.9339488311 -0.0000000000 -0.3574067443
+ 0.6165823904 -0.7145830136  0.0809672526
+-0.1367736397  0.9238795325 -0.3574067443
+-0.6165823904  0.7145830136 -0.0809672526
+-0.7571151198 -0.6532814824 -0.0000000000
+-0.8938887595  0.2705980501 -0.3574067443
+-0.1367736397 -0.9238795325 -0.3574067443
+ 0.4050047633  0.7145830136 -0.4719117310
+ 0.5636879836 -0.6532814824 -0.5054494651
+ 0.4269143440  0.2705980501 -0.8628562095
+-0.3302007759  0.3826834324 -0.8628562095
+-0.7661903653 -0.2959899757 -0.4719117310
+-0.3302007759 -0.3826834324 -0.8628562095
+ 0.2553967884 -0.2959899757 -0.8628562095
+4 0 2 5 1 
+3 0 3 2 
+4 0 4 9 3 
+4 0 1 7 4 
+4 1 6 13 7 
+3 1 5 6 
+4 2 8 12 5 
+4 2 3 10 8 
+4 3 9 17 10 
+3 4 11 9 
+4 4 7 15 11 
+4 5 12 14 6 
+4 6 14 20 13 
+3 7 13 15 
+4 8 16 19 12 
+3 8 10 16 
+4 9 11 18 17 
+4 10 17 22 16 
+4 11 15 21 18 
+3 12 19 14 
+4 13 20 21 15 
+4 14 19 23 20 
+4 16 22 23 19 
+3 17 18 22 
+4 18 21 23 22 
+3 20 23 21 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 11 6 0 
+4 4 12 11 5 
+4 10 13 4 3 
+4 6 14 15 7 
+4 8 16 9 2 
+4 15 17 8 7 
+4 16 18 10 9 
+4 11 19 14 6 
+4 13 20 12 4 
+4 12 21 19 11 
+4 18 20 13 10 
+4 14 22 17 15 
+4 17 23 16 8 
+4 23 24 18 16 
+4 21 22 14 19 
+4 20 25 21 12 
+4 24 25 20 18 
+4 22 24 23 17 
+4 21 22 24 25 
+truncated cuboctahedron
+disdyakisdodecahedron
+2 3 4|
+(4.6.8)
+octahedral group
+S4
+6{8}+8{6}+12{4}
+15 48 72 26 48 1 0 0 2 3 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4213179058  0.0000000000  0.9069130180
+-0.0205668596  0.4208156152  0.9069130180
+-0.3330265737 -0.2580737859  0.9069130180
+ 0.4007510462  0.4208156152  0.8138260361
+ 0.6841248285 -0.2580737859  0.6821811637
+-0.3741602929  0.5835574446  0.7207390541
+-0.3826793651 -0.6230452339  0.6821811637
+-0.6866200070 -0.0953319565  0.7207390541
+ 0.6429911093  0.5835574446  0.4960071997
+ 0.6344720372 -0.6230452339  0.4574493093
+ 0.9263648917 -0.0953319565  0.3643623273
+-0.4528990160  0.8137091469  0.3643623273
+-0.7071868666  0.3254836587  0.6276520721
+-0.7362727984 -0.4603034045  0.4960071997
+-0.1198724423 -0.8811190198  0.4574493093
+ 0.5642523862  0.8137091469  0.1396304730
+ 0.9057980321  0.3254836587  0.2712753454
+ 0.8767121003 -0.4603034045  0.1396304730
+ 0.3014454635 -0.8811190198  0.3643623273
+-0.7859255897  0.5556353610  0.2712753454
+-0.2106589529  0.9764509762  0.0465434910
+-0.8270593089 -0.5556353610  0.0851013814
+-0.2106589529 -0.9764509762  0.0465434910
+ 0.8270593089  0.5556353610 -0.0851013814
+ 0.2106589529  0.9764509762 -0.0465434910
+ 0.7859255897 -0.5556353610 -0.2712753454
+ 0.2106589529 -0.9764509762 -0.0465434910
+-0.8767121003  0.4603034045 -0.1396304730
+-0.3014454635  0.8811190198 -0.3643623273
+-0.9057980321 -0.3254836587 -0.2712753454
+-0.5642523862 -0.8137091469 -0.1396304730
+ 0.7362727984  0.4603034045 -0.4960071997
+ 0.1198724423  0.8811190198 -0.4574493093
+ 0.7071868666 -0.3254836587 -0.6276520721
+ 0.4528990160 -0.8137091469 -0.3643623273
+-0.9263648917  0.0953319565 -0.3643623273
+-0.6344720372  0.6230452339 -0.4574493093
+-0.6429911093 -0.5835574446 -0.4960071997
+ 0.6866200070  0.0953319565 -0.7207390541
+ 0.3826793651  0.6230452339 -0.6821811637
+ 0.3741602929 -0.5835574446 -0.7207390541
+-0.6841248285  0.2580737859 -0.6821811637
+-0.4007510462 -0.4208156152 -0.8138260361
+ 0.3330265737  0.2580737859 -0.9069130180
+ 0.0205668596 -0.4208156152 -0.9069130180
+-0.4213179058 -0.0000000000 -0.9069130180
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1824857240  0.1916223125  0.8259425910
+-0.3588578683  0.1651647923  0.8259425910
+ 0.1824857240 -0.5334020968  0.8259425910
+ 0.6734372751  0.1651647923  0.5978648424
+ 0.1150758511  0.8458618109  0.5208409981
+-0.4869154353 -0.3271197492  0.6388327969
+ 0.7107416431 -0.3271197492  0.3742195883
+-0.5282559191  0.5187420617  0.4517230027
+-0.4805150176 -0.7290726662  0.2753141970
+-0.9764509762  0.0000000000  0.2157394053
+ 0.6694011593  0.5187420617  0.1871097942
+ 0.5517801258 -0.7290726662  0.0472364484
+ 0.9764509762  0.0000000000 -0.2157394053
+-0.5517801258  0.7290726662 -0.0472364484
+ 0.0413404837 -0.8458618109  0.1871097942
+ 0.4805150176  0.7290726662 -0.2753141970
+-0.0413404837  0.8458618109 -0.1871097942
+-0.6694011593 -0.5187420617 -0.1871097942
+-0.1150758511 -0.8458618109 -0.5208409981
+ 0.5282559191 -0.5187420617 -0.4517230027
+-0.7107416431  0.3271197492 -0.3742195883
+-0.1824857240  0.5334020968 -0.8259425910
+-0.6734372751 -0.1651647923 -0.5978648424
+ 0.4869154353  0.3271197492 -0.6388327969
+ 0.3588578683 -0.1651647923 -0.8259425910
+-0.1824857240 -0.1916223125 -0.8259425910
+4 0 2 4 1 
+6 0 3 8 13 6 2 
+8 0 1 5 10 19 15 7 3 
+6 1 4 9 17 11 5 
+8 2 6 12 21 25 16 9 4 
+4 3 7 14 8 
+4 5 11 18 10 
+4 6 13 20 12 
+6 7 15 23 31 22 14 
+8 8 14 22 30 36 28 20 13 
+4 9 16 24 17 
+6 10 18 26 35 27 19 
+8 11 17 24 32 39 34 26 18 
+6 12 20 28 37 29 21 
+4 15 19 27 23 
+6 16 25 33 40 32 24 
+4 21 29 33 25 
+4 22 31 38 30 
+8 23 27 35 41 45 43 38 31 
+4 26 34 41 35 
+4 28 36 42 37 
+8 29 37 42 46 47 44 40 33 
+6 30 38 43 46 42 36 
+4 32 40 44 39 
+6 34 39 44 47 45 41 
+4 43 45 47 46 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 2 6 3 
+3 4 7 1 
+3 5 8 2 
+3 1 9 5 
+3 3 10 4 
+3 2 11 6 
+3 6 12 3 
+3 4 13 7 
+3 7 9 1 
+3 9 8 5 
+3 8 14 2 
+3 10 15 4 
+3 12 10 3 
+3 11 12 6 
+3 14 11 2 
+3 13 9 7 
+3 4 16 13 
+3 9 17 8 
+3 8 18 14 
+3 12 15 10 
+3 15 16 4 
+3 11 19 12 
+3 18 11 14 
+3 13 20 9 
+3 16 21 13 
+3 9 22 17 
+3 17 18 8 
+3 12 23 15 
+3 15 21 16 
+3 19 24 12 
+3 18 19 11 
+3 20 22 9 
+3 21 20 13 
+3 22 18 17 
+3 24 23 12 
+3 23 21 15 
+3 18 24 19 
+3 21 22 20 
+3 22 25 18 
+3 24 21 23 
+3 25 24 18 
+3 21 25 22 
+3 24 21 25 
+snub hexahedron
+pentagonal icositetrahedron
+|2 3 4
+(3.3.3.3.4)
+octahedral group
+S4
+6{4}+32{3}
+16 24 60 38 24 1 0 0 2 2 5 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6907659000  0.0000000000  0.7230784683
+ 0.2898753354  0.6270006527  0.7230784683
+-0.4474773703  0.5262333434  0.7230784683
+-0.6654371656 -0.1853399775  0.7230784683
+-0.1110152292 -0.6817867317  0.7230784683
+ 0.5797506708 -0.6817867317  0.4461569367
+ 0.9806412354 -0.1853399775  0.0631811688
+ 0.8230392005  0.5262333434  0.2137403629
+ 0.2432885297  0.9678940186  0.0631811688
+-0.4940641761  0.8671267092  0.0631811688
+-0.9340544297  0.2861072869  0.2137403629
+-0.6516662110 -0.7277679621  0.2137403629
+ 0.0253287344 -0.9976806078  0.0631811688
+ 0.6188503599 -0.7277679621 -0.2955977425
+ 0.7626814402 -0.0845726681 -0.6412210887
+ 0.6050794053  0.6270006527 -0.4906618946
+-0.1110152292  0.8123406303 -0.5725192742
+-0.7511236604  0.4416606752 -0.4906618946
+-0.9202834751 -0.2563206977 -0.2955977425
+-0.4146615192 -0.7663593998 -0.4906618946
+ 0.1788601062 -0.4964467542 -0.8494408059
+ 0.1713729895  0.2401260565 -0.9554950421
+-0.4687354417 -0.1305538986 -0.8736376625
+ 0.3408933659  0.2179597953  0.8503402074
+-0.0547860790  0.4008905646  0.8503402074
+-0.3868745963  0.1185023459  0.8503402074
+-0.2699126456 -0.3014331152  0.8503402074
+ 0.3408933659 -0.4008905646  0.8503402074
+ 0.7825540411 -0.3014331152  0.4284162431
+ 0.8671267092  0.1185023459  0.3476229160
+ 0.6270006527  0.4008905646  0.5770183396
+ 0.4714472644  0.7373527058  0.3476229160
+-0.1200630282  0.8785468151  0.4623206278
+-0.6520001425  0.5838213339  0.3476229160
+-0.7115733209  0.2179597953  0.5770183396
+-0.9324036585 -0.2596964552  0.2513586457
+-0.4964467542 -0.5544219364  0.5770183396
+-0.2563206977 -0.8368101551  0.3476229160
+ 0.1717480296 -0.8208260257  0.4284162431
+ 0.4254660340 -0.8368101551  0.0743010482
+ 0.7575545513 -0.5544219364  0.0743010482
+ 0.8211454788 -0.3468166421 -0.3036964718
+ 0.9324036585  0.2596964552 -0.2513586457
+ 0.5810194223  0.7373527058 -0.0743010482
+ 0.2563206977  0.8368101551 -0.3476229160
+-0.1257667992  0.9202834751 -0.1550943753
+-0.4714472644  0.7373527058 -0.3476229160
+-0.7575545513  0.5544219364 -0.0743010482
+-0.9057181469  0.1638858728 -0.1990208196
+-0.6905915802 -0.6084958589 -0.1990208196
+-0.3618751065 -0.8662095526 -0.0743010482
+ 0.1200630282 -0.8785468151 -0.4623206278
+ 0.5424279846 -0.4549644871 -0.6209447838
+ 0.3868745963 -0.1185023459 -0.8503402074
+ 0.5350381919  0.2720337177 -0.7256204361
+ 0.2313212079  0.5838213339 -0.7017381110
+-0.3408933659  0.4008905646 -0.8503402074
+-0.7439626034  0.0190448965 -0.5770183396
+-0.6270006527 -0.4008905646 -0.5770183396
+-0.2449131559 -0.4843638846 -0.7695468803
+-0.0411941310 -0.1344864753 -0.9311335345
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 5 4 
+4 0 1 6 5 
+3 1 7 6 
+3 1 8 7 
+3 1 2 8 
+3 2 9 8 
+4 2 3 10 9 
+3 3 11 10 
+3 3 4 11 
+4 4 12 19 11 
+3 4 5 12 
+3 5 13 12 
+3 5 6 13 
+3 6 14 13 
+3 6 7 14 
+3 7 15 14 
+4 7 8 16 15 
+3 8 9 16 
+3 9 17 16 
+3 9 10 17 
+3 10 18 17 
+3 10 11 18 
+3 11 19 18 
+3 12 20 19 
+3 12 13 20 
+4 13 14 21 20 
+3 14 15 21 
+3 15 22 21 
+3 15 16 22 
+3 16 17 22 
+4 17 18 23 22 
+3 18 19 23 
+3 19 20 23 
+3 20 21 23 
+3 21 22 23 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 13 14 15 4 3 
+5 15 16 17 5 4 
+5 17 18 19 6 5 
+5 19 20 8 7 6 
+5 20 21 22 9 8 
+5 22 23 24 10 9 
+5 24 25 12 11 10 
+5 12 26 27 14 13 
+5 27 28 16 15 14 
+5 28 29 18 17 16 
+5 29 30 31 19 18 
+5 31 32 21 20 19 
+5 32 33 23 22 21 
+5 33 34 25 24 23 
+5 34 35 26 12 25 
+5 35 36 28 27 26 
+5 36 37 30 29 28 
+5 37 33 32 31 30 
+5 33 34 35 36 37 
+icosahedron
+dodecahedron
+5|2 3
+(3.3.3.3.3)
+icosahedral group
+A5
+20{3}
+26 12 30 20 12 1 0 0 2 1 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000  0.4472135955
+ 0.2763932023  0.8506508084  0.4472135955
+-0.7236067977  0.5257311121  0.4472135955
+-0.7236067977 -0.5257311121  0.4472135955
+ 0.2763932023 -0.8506508084  0.4472135955
+ 0.7236067977  0.5257311121 -0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.2763932023  0.8506508084 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.4911234732  0.3568220898  0.7946544723
+-0.1875924741  0.5773502692  0.7946544723
+-0.6070619982 -0.0000000000  0.7946544723
+-0.1875924741 -0.5773502692  0.7946544723
+ 0.4911234732 -0.3568220898  0.7946544723
+ 0.7946544723 -0.5773502692  0.1875924741
+ 0.9822469464 -0.0000000000 -0.1875924741
+ 0.7946544723  0.5773502692  0.1875924741
+ 0.3035309991  0.9341723590 -0.1875924741
+-0.3035309991  0.9341723590  0.1875924741
+-0.7946544723  0.5773502692 -0.1875924741
+-0.9822469464 -0.0000000000  0.1875924741
+-0.7946544723 -0.5773502692 -0.1875924741
+-0.3035309991 -0.9341723590  0.1875924741
+ 0.3035309991 -0.9341723590 -0.1875924741
+ 0.6070619982 -0.0000000000 -0.7946544723
+ 0.1875924741  0.5773502692 -0.7946544723
+ 0.1875924741 -0.5773502692 -0.7946544723
+-0.4911234732  0.3568220898 -0.7946544723
+-0.4911234732 -0.3568220898 -0.7946544723
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 5 4 
+3 0 1 5 
+3 1 7 5 
+3 1 6 7 
+3 1 2 6 
+3 2 8 6 
+3 2 3 8 
+3 3 9 8 
+3 3 4 9 
+3 4 10 9 
+3 4 5 10 
+3 5 7 10 
+3 6 11 7 
+3 6 8 11 
+3 7 11 10 
+3 8 9 11 
+3 9 10 11 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 13 14 5 4 3 
+5 6 15 16 8 7 
+5 14 17 15 6 5 
+5 16 18 10 9 8 
+5 18 19 12 11 10 
+5 19 17 14 13 12 
+5 15 16 18 19 17 
+dodecahedron
+icosahedron
+3|2 5
+(5.5.5)
+icosahedral group
+A5
+12{5}
+27 20 30 12 20 1 0 0 2 1 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6666666667  0.0000000000  0.7453559925
+-0.3333333333  0.5773502692  0.7453559925
+-0.3333333333 -0.5773502692  0.7453559925
+ 0.7453559925  0.5773502692  0.3333333333
+ 0.7453559925 -0.5773502692  0.3333333333
+-0.8726779962  0.3568220898  0.3333333333
+ 0.1273220038  0.9341723590  0.3333333333
+ 0.1273220038 -0.9341723590  0.3333333333
+-0.8726779962 -0.3568220898  0.3333333333
+ 0.8726779962  0.3568220898 -0.3333333333
+ 0.8726779962 -0.3568220898 -0.3333333333
+-0.7453559925  0.5773502692 -0.3333333333
+-0.1273220038  0.9341723590 -0.3333333333
+-0.1273220038 -0.9341723590 -0.3333333333
+-0.7453559925 -0.5773502692 -0.3333333333
+ 0.3333333333  0.5773502692 -0.7453559925
+ 0.3333333333 -0.5773502692 -0.7453559925
+-0.6666666667 -0.0000000000 -0.7453559925
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.3035309991  0.5257311121  0.7946544723
+-0.6070619982 -0.0000000000  0.7946544723
+ 0.3035309991 -0.5257311121  0.7946544723
+ 0.9822469464 -0.0000000000  0.1875924741
+-0.4911234732  0.8506508084  0.1875924741
+-0.4911234732 -0.8506508084  0.1875924741
+ 0.4911234732  0.8506508084 -0.1875924741
+ 0.4911234732 -0.8506508084 -0.1875924741
+-0.9822469464 -0.0000000000 -0.1875924741
+ 0.6070619982 -0.0000000000 -0.7946544723
+-0.3035309991  0.5257311121 -0.7946544723
+-0.3035309991 -0.5257311121 -0.7946544723
+5 0 2 7 4 1 
+5 0 3 9 6 2 
+5 0 1 5 8 3 
+5 1 4 10 11 5 
+5 2 6 12 13 7 
+5 3 8 14 15 9 
+5 4 7 13 16 10 
+5 5 11 17 14 8 
+5 6 9 15 18 12 
+5 10 16 19 17 11 
+5 12 18 19 16 13 
+5 14 17 19 18 15 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 6 4 0 
+3 5 7 2 
+3 8 5 1 
+3 3 9 6 
+3 7 9 3 
+3 4 10 8 
+3 6 10 4 
+3 5 11 7 
+3 8 11 5 
+3 9 10 6 
+3 11 9 7 
+3 10 11 8 
+3 9 10 11 
+icosidodecahedron
+rhombic triacontahedron
+2|3 5
+(3.5.3.5)
+icosahedral group
+A5
+12{5}+20{3}
+28 30 60 32 30 1 0 0 2 2 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5877852523  0.0000000000  0.8090169944
+ 0.2628655561  0.5257311121  0.8090169944
+-0.5877852523 -0.0000000000  0.8090169944
+-0.2628655561 -0.5257311121  0.8090169944
+ 0.9510565163 -0.0000000000  0.3090169944
+ 0.6881909602 -0.5257311121  0.5000000000
+-0.1624598481  0.8506508084  0.5000000000
+ 0.4253254042  0.8506508084  0.3090169944
+-0.9510565163  0.0000000000  0.3090169944
+-0.6881909602  0.5257311121  0.5000000000
+ 0.1624598481 -0.8506508084  0.5000000000
+-0.4253254042 -0.8506508084  0.3090169944
+ 0.9510565163 -0.0000000000 -0.3090169944
+ 0.8506508084  0.5257311121 -0.0000000000
+ 0.5257311121 -0.8506508084 -0.0000000000
+-0.5257311121  0.8506508084 -0.0000000000
+ 0.4253254042  0.8506508084 -0.3090169944
+-0.9510565163  0.0000000000 -0.3090169944
+-0.8506508084 -0.5257311121 -0.0000000000
+-0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602  0.5257311121 -0.5000000000
+-0.1624598481  0.8506508084 -0.5000000000
+ 0.2628655561  0.5257311121 -0.8090169944
+-0.5877852523  0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.2763932023  0.1708203932  0.8506508084
+-0.2763932023  0.4472135955  0.8506508084
+-0.2763932023 -0.1708203932  0.8506508084
+ 0.2763932023 -0.4472135955  0.8506508084
+ 0.7236067977 -0.1708203932  0.5257311121
+ 0.7236067977  0.4472135955  0.5257311121
+ 0.1708203932  0.7236067977  0.5257311121
+-0.7236067977  0.1708203932  0.5257311121
+-0.7236067977 -0.4472135955  0.5257311121
+-0.1708203932 -0.7236067977  0.5257311121
+ 0.8944271910 -0.4472135955 -0.0000000000
+ 0.8944271910  0.1708203932 -0.0000000000
+ 0.4472135955 -0.7236067977  0.3249196962
+-0.0000000000  1.0000000000 -0.0000000000
+-0.4472135955  0.7236067977  0.3249196962
+ 0.5527864045  0.7236067977 -0.0000000000
+-0.8944271910  0.4472135955 -0.0000000000
+-0.8944271910 -0.1708203932 -0.0000000000
+-0.0000000000 -1.0000000000 -0.0000000000
+-0.5527864045 -0.7236067977 -0.0000000000
+ 0.7236067977 -0.1708203932 -0.5257311121
+ 0.7236067977  0.4472135955 -0.5257311121
+ 0.4472135955 -0.7236067977 -0.3249196962
+-0.4472135955  0.7236067977 -0.3249196962
+ 0.1708203932  0.7236067977 -0.5257311121
+-0.7236067977  0.1708203932 -0.5257311121
+-0.7236067977 -0.4472135955 -0.5257311121
+-0.1708203932 -0.7236067977 -0.5257311121
+ 0.2763932023 -0.4472135955 -0.8506508084
+ 0.2763932023  0.1708203932 -0.8506508084
+-0.2763932023  0.4472135955 -0.8506508084
+-0.2763932023 -0.1708203932 -0.8506508084
+3 0 2 1 
+5 0 3 10 7 2 
+3 0 4 3 
+5 0 1 6 11 4 
+3 1 5 6 
+5 1 2 8 14 5 
+3 2 7 8 
+3 3 9 10 
+5 3 4 12 19 9 
+3 4 11 12 
+5 5 13 22 15 6 
+3 5 14 13 
+3 6 15 11 
+5 7 16 25 17 8 
+3 7 10 16 
+3 8 17 14 
+5 9 18 24 16 10 
+3 9 19 18 
+5 11 15 23 20 12 
+3 12 20 19 
+3 13 21 22 
+5 13 14 17 26 21 
+3 15 22 23 
+3 16 24 25 
+3 17 25 26 
+3 18 27 24 
+5 18 19 20 28 27 
+3 20 23 28 
+5 21 29 28 23 22 
+3 21 26 29 
+5 24 27 29 26 25 
+3 27 28 29 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 1 7 8 2 
+4 8 9 3 2 
+4 4 10 11 5 
+4 3 12 10 4 
+4 6 13 14 1 
+4 5 15 13 6 
+4 7 16 17 8 
+4 14 16 7 1 
+4 9 18 12 3 
+4 8 19 18 9 
+4 10 20 21 11 
+4 21 15 5 11 
+4 18 22 10 12 
+4 13 23 16 14 
+4 21 24 13 15 
+4 16 25 26 17 
+4 26 19 8 17 
+4 26 27 18 19 
+4 20 28 29 21 
+4 22 28 20 10 
+4 27 28 22 18 
+4 23 30 25 16 
+4 24 30 23 13 
+4 29 30 24 21 
+4 30 31 26 25 
+4 31 28 27 26 
+4 28 29 30 31 
+truncated icosahedron
+pentakisdodecahedron
+2 5|3
+(6.6.5)
+icosahedral group
+A5
+20{6}+12{5}
+29 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.3952480672  0.0000000000  0.9185744202
+-0.2227859215  0.3264773618  0.9185744202
+-0.1440965957 -0.3680451137  0.9185744202
+ 0.5677102129  0.3264773618  0.7557232605
+ 0.4954282110 -0.3680451137  0.7868250644
+-0.5896684388  0.2849096099  0.7557232605
+-0.0503237759  0.6529547237  0.7557232605
+ 0.1620948777 -0.5955095034  0.7868250644
+-0.5109791130 -0.4096128656  0.7557232605
+ 0.8403525023  0.2849096099  0.4611227451
+ 0.3449242913  0.6529547237  0.6742976806
+ 0.7680705005 -0.4096128656  0.4922245490
+-0.6439521587  0.5856966883  0.4922245490
+-0.7337650345 -0.0831355038  0.6742976806
+-0.3106188254  0.8131610779  0.4922245490
+ 0.1014038338 -0.8645416449  0.4922245490
+-0.5716701569 -0.6786450072  0.4611227451
+ 0.7860687824  0.5856966883  0.1976240336
+ 0.9405326461 -0.0831355038  0.3293733893
+ 0.4798773090  0.8131610779  0.3293733893
+ 0.7073794566 -0.6786450072  0.1976240336
+-0.8423324743  0.5184386529  0.1473002577
+-0.9321453501 -0.1503935392  0.3293733893
+-0.1756658076  0.9733674322  0.1473002577
+ 0.3740461233 -0.9061093968  0.1976240336
+-0.2654786835 -0.9061093968  0.3293733893
+-0.8319652063 -0.5184386529  0.1976240336
+ 0.8319652063  0.5184386529 -0.1976240336
+ 0.9864290700 -0.1503935392 -0.0658746779
+ 0.2195822596  0.9733674322  0.0658746779
+ 0.8423324743 -0.5184386529 -0.1473002577
+-0.7073794566  0.6786450072 -0.1976240336
+-0.9864290700  0.1503935392  0.0658746779
+-0.3740461233  0.9061093968 -0.1976240336
+ 0.1756658076 -0.9733674322 -0.1473002577
+-0.2195822596 -0.9733674322 -0.0658746779
+-0.7860687824 -0.5856966883 -0.1976240336
+ 0.5716701569  0.6786450072 -0.4611227451
+ 0.9321453501  0.1503935392 -0.3293733893
+ 0.2654786835  0.9061093968 -0.3293733893
+ 0.6439521587 -0.5856966883 -0.4922245490
+-0.7680705005  0.4096128656 -0.4922245490
+-0.9405326461  0.0831355038 -0.3293733893
+-0.1014038338  0.8645416449 -0.4922245490
+ 0.3106188254 -0.8131610779 -0.4922245490
+-0.4798773090 -0.8131610779 -0.3293733893
+-0.8403525023 -0.2849096099 -0.4611227451
+ 0.5109791130  0.4096128656 -0.7557232605
+ 0.7337650345  0.0831355038 -0.6742976806
+ 0.5896684388 -0.2849096099 -0.7557232605
+-0.4954282110  0.3680451137 -0.7868250644
+-0.1620948777  0.5955095034 -0.7868250644
+ 0.0503237759 -0.6529547237 -0.7557232605
+-0.3449242913 -0.6529547237 -0.6742976806
+-0.5677102129 -0.3264773618 -0.7557232605
+ 0.1440965957  0.3680451137 -0.9185744202
+ 0.2227859215 -0.3264773618 -0.9185744202
+-0.3952480672 -0.0000000000 -0.9185744202
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1884917927  0.3568220898  0.9149583817
+-0.4009827382 -0.0454313035  0.9149583817
+ 0.1884917927 -0.2762216876  0.9149583817
+ 0.7299680182 -0.0454313035  0.6819697127
+-0.3769835855  0.5524433752  0.7082839194
+-0.2238218084 -0.6962909658  0.6819697127
+ 0.6262353286  0.5524433752  0.5016094570
+ 0.4751441987 -0.6962909658  0.5379747963
+-0.8612946448  0.2378813932  0.4489810437
+ 0.0924951818  0.8887410555  0.4489810437
+-0.7427296631 -0.3817289838  0.5016094570
+ 0.9686221187  0.2378813932  0.0719974582
+ 0.8805126380 -0.3817289838  0.1672031523
+-0.5563085176  0.8152316624  0.1609912108
+ 0.0344457437 -0.9590792530  0.1672031523
+-0.5746422389 -0.8152316624  0.0719974582
+ 0.5746422389  0.8152316624 -0.0719974582
+ 0.5563085176 -0.8152316624 -0.1609912108
+-0.8805126380  0.3817289838 -0.1672031523
+-0.9686221187 -0.2378813932 -0.0719974582
+-0.0344457437  0.9590792530 -0.1672031523
+ 0.7427296631  0.3817289838 -0.5016094570
+ 0.8612946448 -0.2378813932 -0.4489810437
+-0.4751441987  0.6962909658 -0.5379747963
+-0.0924951818 -0.8887410555 -0.4489810437
+-0.6262353286 -0.5524433752 -0.5016094570
+ 0.2238218084  0.6962909658 -0.6819697127
+ 0.3769835855 -0.5524433752 -0.7082839194
+-0.7299680182  0.0454313035 -0.6819697127
+ 0.4009827382  0.0454313035 -0.9149583817
+-0.1884917927  0.2762216876 -0.9149583817
+-0.1884917927 -0.3568220898 -0.9149583817
+6 0 2 7 11 4 1 
+6 0 3 9 14 6 2 
+5 0 1 5 8 3 
+6 1 4 10 19 12 5 
+5 2 6 13 15 7 
+6 3 8 16 26 17 9 
+5 4 11 20 18 10 
+6 5 12 21 25 16 8 
+6 6 14 23 33 22 13 
+6 7 15 24 30 20 11 
+5 9 17 27 23 14 
+6 10 18 28 39 29 19 
+5 12 19 29 31 21 
+6 13 22 32 34 24 15 
+5 16 25 35 36 26 
+6 17 26 36 46 37 27 
+6 18 20 30 40 38 28 
+6 21 31 41 45 35 25 
+5 22 33 43 42 32 
+6 23 27 37 47 43 33 
+5 24 34 44 40 30 
+5 28 38 48 49 39 
+6 29 39 49 50 41 31 
+6 32 42 51 52 44 34 
+6 35 45 53 54 46 36 
+5 37 46 54 55 47 
+6 38 40 44 52 56 48 
+5 41 50 57 53 45 
+6 42 43 47 55 58 51 
+6 48 56 59 57 50 49 
+5 51 58 59 56 52 
+6 53 57 59 58 55 54 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 0 9 4 
+3 5 7 2 
+3 1 10 5 
+3 3 11 6 
+3 6 9 0 
+3 7 12 3 
+3 4 13 8 
+3 8 10 1 
+3 9 13 4 
+3 5 14 7 
+3 10 15 5 
+3 11 16 6 
+3 12 11 3 
+3 16 9 6 
+3 7 17 12 
+3 13 18 8 
+3 8 19 10 
+3 9 20 13 
+3 14 17 7 
+3 15 14 5 
+3 19 15 10 
+3 11 21 16 
+3 12 22 11 
+3 16 20 9 
+3 17 22 12 
+3 13 23 18 
+3 18 19 8 
+3 20 23 13 
+3 14 24 17 
+3 15 24 14 
+3 19 25 15 
+3 21 26 16 
+3 22 21 11 
+3 26 20 16 
+3 17 27 22 
+3 23 28 18 
+3 28 19 18 
+3 26 23 20 
+3 24 27 17 
+3 25 24 15 
+3 28 25 19 
+3 21 29 26 
+3 22 29 21 
+3 27 29 22 
+3 23 30 28 
+3 26 30 23 
+3 24 31 27 
+3 25 31 24 
+3 28 31 25 
+3 29 30 26 
+3 31 29 27 
+3 30 31 28 
+3 29 30 31 
+truncated dodecahedron
+triakisicosahedron
+2 3|5
+(10.10.3)
+icosahedral group
+A5
+12{10}+20{3}
+30 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.3319544852  0.0000000000  0.9432954043
+-0.2860795036  0.1683814059  0.9432954043
+ 0.1611340919 -0.2902233358  0.9432954043
+ 0.5829886213  0.1683814059  0.7948408455
+-0.5878317720  0.1506049079  0.7948408455
+-0.4170113787  0.4408282437  0.7948408455
+ 0.1357750258 -0.5914331516  0.7948408455
+ 0.8183499926  0.1506049079  0.5546363234
+ 0.6572159007  0.4408282437  0.6113409191
+-0.7899976948 -0.0465394760  0.6113409191
+-0.3427840993  0.7132750815  0.6113409191
+-0.0663908970 -0.7885775354  0.6113409191
+ 0.2655635881 -0.7885775354  0.5546363234
+ 0.9481385550 -0.0465394760  0.3144318014
+ 0.5262840256  0.7132750815  0.4628863603
+-0.8153567609 -0.3477492917  0.4628863603
+-0.9462886360 -0.0753024539  0.3144318014
+-0.3935022315  0.8638799894  0.3144318014
+-0.0917499632  0.8816564874  0.4628863603
+-0.3681431654 -0.8063540334  0.4628863603
+ 0.5009249595 -0.8063540334  0.3144318014
+ 0.9227794888 -0.3477492917  0.1659772426
+ 0.9970067683 -0.0753024539 -0.0175226837
+ 0.4755658933  0.8638799894  0.1659772426
+ 0.2402045220  0.8816564874  0.4061817646
+-0.6542226690 -0.6379726275  0.4061817646
+-0.9970067683  0.0753024539  0.0175226837
+-0.5497931728  0.8351170114  0.0175226837
+-0.5244341067 -0.8351170114  0.1659772426
+ 0.5497931728 -0.8351170114 -0.0175226837
+ 0.7519590956 -0.6379726275  0.1659772426
+ 0.9462886360  0.0753024539 -0.3144318014
+ 0.5244341067  0.8351170114 -0.1659772426
+-0.9481385550  0.0465394760 -0.3144318014
+-0.9227794888  0.3477492917 -0.1659772426
+-0.7519590956  0.6379726275 -0.1659772426
+-0.5009249595  0.8063540334 -0.3144318014
+-0.4755658933 -0.8638799894 -0.1659772426
+ 0.3935022315 -0.8638799894 -0.3144318014
+ 0.7899976948  0.0465394760 -0.6113409191
+ 0.8153567609  0.3477492917 -0.4628863603
+ 0.6542226690  0.6379726275 -0.4061817646
+ 0.3681431654  0.8063540334 -0.4628863603
+-0.8183499926 -0.1506049079 -0.5546363234
+-0.2655635881  0.7885775354 -0.5546363234
+-0.5262840256 -0.7132750815 -0.4628863603
+-0.2402045220 -0.8816564874 -0.4061817646
+ 0.0917499632 -0.8816564874 -0.4628863603
+ 0.3427840993 -0.7132750815 -0.6113409191
+ 0.5878317720 -0.1506049079 -0.7948408455
+ 0.0663908970  0.7885775354 -0.6113409191
+-0.6572159007 -0.4408282437 -0.6113409191
+-0.5829886213 -0.1683814059 -0.7948408455
+-0.1357750258  0.5914331516 -0.7948408455
+ 0.4170113787 -0.4408282437 -0.7948408455
+ 0.2860795036 -0.1683814059 -0.9432954043
+-0.3319544852  0.0000000000 -0.9432954043
+-0.1611340919  0.2902233358 -0.9432954043
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1432337790  0.5257311121  0.8385051474
+-0.3901124942 -0.3804226065  0.8385051474
+ 0.1432337790 -0.0843049040  0.8385051474
+ 0.6463368675 -0.3804226065  0.6614584599
+-0.3749909018  0.2207131041  0.7357864254
+ 0.5979747984  0.2207131041  0.5695840419
+-0.7989163046  0.4702282018  0.3749909018
+ 0.0972965700 -0.6299377043  0.5695840419
+ 0.8780939903  0.4702282018  0.0885233438
+-0.7412085774 -0.1364082001  0.4033816583
+-0.2405303491  0.7142426083  0.4033816583
+ 0.0151215924 -0.9959593140  0.0885233438
+ 0.8330829954 -0.1364082001  0.1344605528
+ 0.3607955236  0.7142426083  0.3006629363
+-0.8780939903 -0.4702282018 -0.0885233438
+-0.0151215924  0.9959593140 -0.0885233438
+-0.4493188674 -0.6621393122  0.3006629363
+ 0.5236468329 -0.6621393122  0.1344605528
+ 0.7989163046 -0.4702282018 -0.3749909018
+-0.8330829954  0.1364082001 -0.1344605528
+-0.5236468329  0.6621393122 -0.1344605528
+ 0.7412085774  0.1364082001 -0.4033816583
+ 0.4493188674  0.6621393122 -0.3006629363
+-0.6463368675  0.3804226065 -0.6614584599
+-0.3607955236 -0.7142426083 -0.3006629363
+ 0.2405303491 -0.7142426083 -0.4033816583
+ 0.3901124942  0.3804226065 -0.8385051474
+-0.5979747984 -0.2207131041 -0.5695840419
+-0.0972965700  0.6299377043 -0.5695840419
+-0.1432337790 -0.5257311121 -0.8385051474
+ 0.3749909018 -0.2207131041 -0.7357864254
+-0.1432337790  0.0843049040 -0.8385051474
+10 0 2 6 11 19 25 15 9 4 1 
+10 0 3 7 12 20 26 16 10 5 2 
+3 0 1 3 
+10 1 4 8 14 22 31 21 13 7 3 
+3 2 5 6 
+3 4 9 8 
+10 5 10 17 27 35 36 28 18 11 6 
+3 7 13 12 
+10 8 9 15 24 33 42 41 32 23 14 
+3 10 16 17 
+3 11 18 19 
+10 12 13 21 30 39 48 47 38 29 20 
+3 14 23 22 
+3 15 25 24 
+10 16 26 29 38 46 52 44 34 27 17 
+10 18 28 37 45 51 43 33 24 25 19 
+3 20 29 26 
+3 21 31 30 
+10 22 23 32 40 50 55 49 39 30 31 
+3 27 34 35 
+3 28 36 37 
+3 32 41 40 
+3 33 43 42 
+10 34 44 53 57 58 54 45 37 36 35 
+3 38 47 46 
+3 39 49 48 
+10 40 41 42 43 51 54 58 59 56 50 
+3 44 52 53 
+3 45 54 51 
+10 46 47 48 49 55 56 59 57 53 52 
+3 50 56 55 
+3 57 59 58 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 8 5 
+3 8 0 5 
+3 6 9 1 
+3 0 10 6 
+3 1 11 7 
+3 11 3 7 
+3 3 12 8 
+3 8 13 0 
+3 9 14 1 
+3 6 14 9 
+3 10 15 6 
+3 0 15 10 
+3 1 16 11 
+3 11 17 3 
+3 3 18 12 
+3 18 8 12 
+3 8 15 13 
+3 13 0 15 
+3 14 16 1 
+3 6 19 14 
+3 15 20 6 
+3 14 11 16 
+3 11 18 17 
+3 17 3 18 
+3 18 21 8 
+3 8 22 15 
+3 19 23 14 
+3 6 23 19 
+3 20 23 6 
+3 15 23 20 
+3 14 24 11 
+3 11 25 18 
+3 18 26 21 
+3 26 8 21 
+3 26 22 8 
+3 26 15 22 
+3 23 27 14 
+3 15 28 23 
+3 14 29 24 
+3 29 11 24 
+3 29 25 11 
+3 29 18 25 
+3 18 30 26 
+3 26 28 15 
+3 27 29 14 
+3 23 29 27 
+3 26 23 28 
+3 29 30 18 
+3 29 26 30 
+3 23 31 29 
+3 26 31 23 
+3 29 26 31 
+rhombicosidodecahedron
+deltoidal hexecontahedron
+3 5|2
+(4.3.4.5)
+icosahedral group
+A5
+12{5}+30{4}+20{3}
+31 60 120 62 60 1 0 0 2 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4364663517  0.0000000000  0.8997205810
+-0.0230394894  0.4358578416  0.8997205810
+-0.3947875239  0.1861335198  0.8997205810
+-0.1650346033 -0.4040624406  0.8997205810
+ 0.4134268623  0.4358578416  0.7994411620
+ 0.7478962199  0.1861335198  0.6371856536
+ 0.5411827887 -0.4040624406  0.7374650726
+-0.2253527696  0.7370282030  0.6371856536
+-0.5598221272 -0.2179289208  0.7994411620
+-0.5971008041  0.4873038812  0.6371856536
+ 0.1694347542 -0.6537867624  0.7374650726
+-0.4551056902 -0.6219913614  0.6371856536
+ 0.4808646224  0.7370282030  0.4749301452
+ 0.8526126568 -0.2179289208  0.4749301452
+ 0.8153339799  0.4873038812  0.3126746369
+ 0.6875780535 -0.6219913614  0.3746507262
+ 0.0860770985  0.9231617228  0.3746507262
+-0.5296630440  0.7884742426  0.3126746369
+-0.8641324015 -0.1664828812  0.4749301452
+-0.8871718909  0.2693749604  0.3746507262
+-0.1206363326 -0.8717156832  0.4749301452
+ 0.3158300191 -0.8717156832  0.3746507262
+-0.7594159645 -0.5705453218  0.3126746369
+ 0.6130206997  0.7884742426  0.0501397095
+ 0.9847687342 -0.1664828812  0.0501397095
+ 0.9617292448  0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.2182331759  0.9746077624  0.0501397095
+ 0.2182331759  0.9746077624 -0.0501397095
+-0.8197341309  0.5705453218  0.0501397095
+-0.9617292448 -0.2693749604  0.0501397095
+-0.9847687342  0.1664828812 -0.0501397095
+-0.2182331759 -0.9746077624  0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.7594159645  0.5705453218 -0.3126746369
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.8641324015  0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.3158300191  0.8717156832 -0.3746507262
+ 0.1206363326  0.8717156832 -0.4749301452
+-0.6875780535  0.6219913614 -0.3746507262
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.8526126568  0.2179289208 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.4551056902  0.6219913614 -0.6371856536
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.5598221272  0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.1694347542  0.6537867624 -0.7374650726
+-0.5411827887  0.4040624406 -0.7374650726
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.1650346033  0.4040624406 -0.8997205810
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517 -0.0000000000 -0.8997205810
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.2124281962  0.2239537475  0.9245941063
+-0.1379991118  0.2054301247  0.9245941063
+-0.2876494382 -0.1119768737  0.9245941063
+ 0.2124281962 -0.3162277660  0.9245941063
+ 0.6623583361 -0.1119768737  0.7063270456
+ 0.5277148574  0.2054301247  0.7716443776
+ 0.1583346290  0.7071067812  0.6891517578
+-0.3186422944  0.4743416490  0.7896976442
+-0.7144788670  0.1207882584  0.6891517578
+-0.3897157456 -0.4108602493  0.7716443776
+-0.1467842735 -0.6555240367  0.7063270456
+ 0.6313654799  0.4743416490  0.5714305835
+ 0.9436228948  0.1207882584  0.3081980354
+ 0.4403528206 -0.6555240367  0.5714305835
+ 0.6874320834 -0.4108602493  0.5241665181
+-0.2279246243  0.8794777841  0.3531635228
+-0.4465745066  0.6647858481  0.5241665181
+-0.6778547641 -0.4051361351  0.5714305835
+-0.7280022588  0.5435471629  0.3531635228
+ 0.1204287884 -0.7917486474  0.5241665181
+-0.4686190076 -0.8278950396  0.3081980354
+ 0.6305733224  0.6647858481  0.2766886585
+ 0.3592124698  0.8794777841  0.2182670607
+ 0.8592901042 -0.4051361351  0.2182670607
+ 0.8091426096  0.5435471629 -0.0000000000
+ 0.5561442379 -0.8278950396  0.0727556869
+ 0.0284293805  0.9486832981  0.1237389298
+-0.5561442379  0.8278950396 -0.0727556869
+-0.9500077743  0.0000000000  0.2182670607
+-0.8538605757 -0.3323929240  0.2766886585
+-0.8890012226  0.3323929240  0.1237389298
+ 0.0501474947 -0.9486832981  0.2182670607
+-0.8091426096 -0.5435471629 -0.0000000000
+ 0.4686190076  0.8278950396 -0.3081980354
+ 0.8890012226 -0.3323929240 -0.1237389298
+ 0.9500077743  0.0000000000 -0.2182670607
+ 0.8538605757  0.3323929240 -0.2766886585
+ 0.7280022588 -0.5435471629 -0.3531635228
+-0.0501474947  0.9486832981 -0.2182670607
+-0.8592901042  0.4051361351 -0.2182670607
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.3592124698 -0.8794777841 -0.2182670607
+-0.0284293805 -0.9486832981 -0.1237389298
+ 0.2279246243 -0.8794777841 -0.3531635228
+-0.6305733224 -0.6647858481 -0.2766886585
+ 0.6778547641  0.4051361351 -0.5714305835
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.4465745066 -0.6647858481 -0.5241665181
+-0.1204287884  0.7917486474 -0.5241665181
+-0.4403528206  0.6555240367 -0.5714305835
+ 0.1467842735  0.6555240367 -0.7063270456
+-0.6874320834  0.4108602493 -0.5241665181
+-0.6313654799 -0.4743416490 -0.5714305835
+-0.6623583361  0.1119768737 -0.7063270456
+-0.1583346290 -0.7071067812 -0.6891517578
+ 0.3897157456  0.4108602493 -0.7716443776
+ 0.3186422944 -0.4743416490 -0.7896976442
+ 0.2876494382  0.1119768737 -0.9245941063
+-0.2124281962  0.3162277660 -0.9245941063
+-0.5277148574 -0.2054301247 -0.7716443776
+-0.2124281962 -0.2239537475 -0.9245941063
+ 0.1379991118 -0.2054301247 -0.9245941063
+4 0 2 5 1 
+3 0 3 2 
+4 0 4 9 3 
+5 0 1 7 11 4 
+4 1 6 14 7 
+3 1 5 6 
+5 2 8 17 13 5 
+4 2 3 10 8 
+5 3 9 19 20 10 
+3 4 12 9 
+4 4 11 21 12 
+4 5 13 15 6 
+5 6 15 26 25 14 
+4 7 16 22 11 
+3 7 14 16 
+4 8 18 28 17 
+3 8 10 18 
+4 9 12 23 19 
+4 10 20 30 18 
+3 11 22 21 
+5 12 21 33 35 23 
+3 13 24 15 
+4 13 17 29 24 
+4 14 25 27 16 
+4 15 24 36 26 
+5 16 27 39 34 22 
+3 17 28 29 
+5 18 30 42 40 28 
+4 19 31 32 20 
+3 19 23 31 
+3 20 32 30 
+4 21 22 34 33 
+4 23 35 43 31 
+5 24 29 41 47 36 
+3 25 37 27 
+4 25 26 38 37 
+3 26 36 38 
+4 27 37 48 39 
+4 28 40 41 29 
+4 30 32 44 42 
+5 31 43 53 44 32 
+4 33 45 46 35 
+3 33 34 45 
+4 34 39 50 45 
+3 35 46 43 
+4 36 47 49 38 
+5 37 38 49 56 48 
+3 39 48 50 
+3 40 51 41 
+4 40 42 52 51 
+4 41 51 55 47 
+3 42 44 52 
+4 43 46 54 53 
+4 44 53 58 52 
+5 45 50 57 54 46 
+3 47 55 49 
+4 48 56 57 50 
+4 49 55 59 56 
+5 51 52 58 59 55 
+3 53 54 58 
+4 54 57 59 58 
+3 56 59 57 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 11 6 0 
+4 4 12 11 5 
+4 3 13 14 4 
+4 6 15 16 7 
+4 8 17 9 2 
+4 16 18 8 7 
+4 10 19 13 3 
+4 17 20 10 9 
+4 11 21 22 6 
+4 14 23 12 4 
+4 12 24 21 11 
+4 13 25 23 14 
+4 22 26 15 6 
+4 15 27 18 16 
+4 8 28 29 17 
+4 18 30 28 8 
+4 20 31 19 10 
+4 31 25 13 19 
+4 29 32 20 17 
+4 24 33 22 21 
+4 23 34 35 12 
+4 35 36 24 12 
+4 25 37 34 23 
+4 26 38 27 15 
+4 33 38 26 22 
+4 27 39 30 18 
+4 28 40 32 29 
+4 39 40 28 30 
+4 20 41 42 31 
+4 42 43 25 31 
+4 32 44 41 20 
+4 36 45 33 24 
+4 37 46 35 34 
+4 46 45 36 35 
+4 43 47 37 25 
+4 38 48 49 27 
+4 33 50 48 38 
+4 49 51 39 27 
+4 40 52 44 32 
+4 51 53 40 39 
+4 41 54 43 42 
+4 52 54 41 44 
+4 45 55 50 33 
+4 47 56 46 37 
+4 46 57 55 45 
+4 54 56 47 43 
+4 50 58 49 48 
+4 58 53 51 49 
+4 53 59 52 40 
+4 59 60 54 52 
+4 57 58 50 55 
+4 56 61 57 46 
+4 60 61 56 54 
+4 58 60 59 53 
+4 57 58 60 61 
+truncated icosidodecahedron
+disdyakistriacontahedron
+2 3 5|
+(4.6.10)
+icosahedral group
+A5
+12{10}+20{6}+30{4}
+32 120 180 62 120 1 0 0 2 3 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.2607080006  0.0000000000  0.9654177015
+-0.0045873783  0.2606676380  0.9654177015
+-0.2192156342 -0.1411140222  0.9654177015
+ 0.2561208549  0.2606676380  0.9308353722
+ 0.4633267724 -0.1411140222  0.8748800687
+-0.2283903908  0.3802212538  0.8962531046
+-0.3132059807 -0.3694413065  0.8748800687
+-0.4430186467 -0.0215604065  0.8962531046
+ 0.4541524811  0.3802212538  0.8057154101
+ 0.5304628314 -0.3694413065  0.7629694001
+ 0.6613583986 -0.0215604065  0.7497601066
+-0.3298032754  0.5736633003  0.7497601066
+-0.4476060250  0.2391072316  0.8616708061
+-0.5370090771 -0.2498878945  0.8057153910
+-0.2460699217 -0.5977685908  0.7629694001
+ 0.5138663784  0.5736633003  0.6378493263
+ 0.6567712529  0.2391072316  0.7151777773
+ 0.7284945175 -0.2498878945  0.6378493381
+ 0.4364724850 -0.5977685908  0.6724317673
+-0.5490190001  0.4325494506  0.7151776775
+-0.2700897570  0.7671054904  0.5818940537
+-0.6936761144 -0.3586617667  0.6246400447
+-0.0434511498 -0.7388826131  0.6724317673
+-0.4027369590 -0.7065424630  0.5818940537
+ 0.7164852035  0.4325494506  0.5473115438
+ 0.4124538677  0.7671054904  0.4913562594
+ 0.8325358571 -0.3586617667  0.4221916434
+ 0.2172568508 -0.7388826131  0.6378494688
+ 0.5405138246 -0.7065424630  0.4567740725
+-0.7085212064  0.4848777911  0.5127291954
+-0.0720583700  0.8866594825  0.4567740725
+-0.4295919633  0.8194338309  0.3794455716
+-0.8531785590 -0.3063341981  0.4221915508
+-0.6265400554 -0.5869890510  0.5127293760
+-0.2001180064 -0.8476566112  0.4913563402
+ 0.8176915179  0.4848777911  0.3102806942
+ 0.1886510811  0.8866594825  0.4221915817
+ 0.5136601821  0.8194338309  0.2543254098
+ 0.9337423985 -0.3063341981  0.1851607203
+ 0.7385455107 -0.5869890510  0.3316540106
+ 0.3212979948 -0.8476566112  0.4221917432
+-0.8651885085  0.3761046523  0.3316536375
+-0.6488076880  0.6783199813  0.3448631425
+-0.2315603996  0.9389879297  0.2543254788
+-0.7860426423 -0.5346614357  0.3102807015
+-0.9545918983 -0.1128925413  0.2756983531
+-0.0960768624 -0.9564306093  0.2756986145
+ 0.9217330580  0.3761046523  0.0946227263
+ 0.7162790072  0.6783199813  0.1637876273
+ 0.2898571959  0.9389879297  0.1851606704
+ 0.8397521423 -0.5346614357  0.0946228761
+ 0.9934566827 -0.1128925413  0.0172943252
+ 0.1646311382 -0.9564306093  0.2411163161
+-0.8054751299  0.5695467454  0.1637874231
+-0.9591793219  0.1477776761  0.2411157125
+-0.1303544328  0.9913166095  0.0172945558
+-0.8203200648 -0.5695470165  0.0518766546
+-0.9888693637 -0.1477781439  0.0172916663
+-0.1303536668 -0.9913167102  0.0172945558
+ 0.8203206401  0.5695467454 -0.0518705331
+ 0.9888694917  0.1477776761 -0.0172883463
+ 0.1303553059  0.9913166095 -0.0172879732
+ 0.8054761704 -0.5695470165 -0.1637813633
+ 0.9591800640 -0.1477781439 -0.2411124739
+ 0.1303545664 -0.9913167102 -0.0172877735
+-0.8397525647  0.5346618623 -0.0946167165
+-0.9934567883  0.1128921245 -0.0172909812
+-0.1646312678  0.9564322465 -0.2411097335
+-0.7162795951 -0.6783208443 -0.1637814823
+-0.9217334041 -0.3761053597 -0.0946165431
+-0.2898558028 -0.9389895580 -0.1851545936
+ 0.7860446559  0.5346618623 -0.3102748651
+ 0.9545928720  0.1128921245 -0.2756951522
+ 0.0960787036  0.9564322465 -0.2756922934
+ 0.6488098576 -0.6783208443 -0.3448573632
+ 0.8651904546 -0.3761053597 -0.3316477584
+ 0.2315606390 -0.9389895580 -0.2543192490
+-0.7385472639  0.5869902473 -0.3316479890
+-0.9337433781  0.3063348862 -0.1851546415
+-0.3212992842  0.8476584134 -0.4221871436
+-0.8176928415 -0.4848792845 -0.3102748723
+-0.5136611563 -0.8194350139 -0.2543196306
+-0.1886494644 -0.8866613987 -0.4221882798
+ 0.6265433179  0.5869902473 -0.5127240198
+ 0.8531810896  0.3063348862 -0.4221859376
+ 0.2001204504  0.8476584134 -0.4913522358
+ 0.7085240020 -0.4848792845 -0.5127239199
+ 0.4295944104 -0.8194350139 -0.3794402462
+ 0.0720576700 -0.8866613987 -0.4567704634
+-0.8325379870  0.3586633178 -0.4221861255
+-0.5405162125  0.7065442357 -0.4567685048
+-0.2172590958  0.7388844270 -0.6378466030
+-0.7164876491 -0.4325518944 -0.5473064108
+-0.4124548660 -0.7671068289 -0.4913533317
+ 0.6936796092  0.3586633178 -0.6246352729
+ 0.4027407159  0.7065442357 -0.5818893011
+ 0.0434540643  0.7388844270 -0.6724295858
+ 0.5490226993 -0.4325518944 -0.7151733596
+ 0.2700914841 -0.7671068289 -0.5818914876
+-0.7284976588  0.2498903768 -0.6378447779
+-0.4364761587  0.5977701626 -0.6724279854
+-0.6567747682 -0.2391103983 -0.7151734903
+-0.5138692103 -0.5736660641 -0.6378445591
+ 0.5370132986  0.2498903768 -0.8057118075
+ 0.2460744543  0.5977701626 -0.7629667067
+ 0.4476105365 -0.2391103983 -0.8616675838
+ 0.3298072522 -0.5736660641 -0.7497562426
+-0.6613622562  0.0215634725 -0.7497566156
+-0.5304666075  0.3694443652 -0.7629652937
+-0.4541562762 -0.3802243954 -0.8057117884
+ 0.4430232811  0.0215634725 -0.8962507401
+ 0.3132106967  0.3694443652 -0.8748770888
+ 0.2283949989 -0.3802243954 -0.8962505976
+-0.4633311450  0.1411172572 -0.8748772313
+-0.2561255056 -0.2606708670 -0.9308331883
+ 0.2192205953  0.1411172572 -0.9654161022
+ 0.0045924376 -0.2606708670 -0.9654168056
+-0.2607129987  0.0000032913 -0.9654163518
+ 0.0000051771  0.0000032912 -0.9999999999
+ 0.1200387571  0.1221698550  0.9049446030
+-0.2175780247  0.1162282816  0.9049446030
+ 0.1200387571 -0.4082474279  0.9049446030
+ 0.4459799746  0.1162282816  0.8169252068
+ 0.1016985225  0.6339220449  0.7666817889
+-0.3544276914 -0.1832548434  0.8300952867
+ 0.5585832497 -0.1832548434  0.7089865490
+-0.3643565320  0.3809295903  0.7552459704
+-0.4568036952 -0.4649138222  0.6745068322
+-0.7747432361  0.0697368203  0.6284189748
+ 0.5486549126  0.3809295903  0.6341371659
+ 0.6168557011 -0.4649138222  0.5320884576
+ 0.9117846887  0.0697368203  0.4047050422
+-0.4756956529  0.6085799433  0.5320883790
+-0.2091195905 -0.6774423865  0.5878778112
+ 0.5979647013  0.6085799433  0.3896698773
+ 0.3551522032 -0.6774423865  0.5130284950
+-0.2351136470  0.7996124516  0.3919196492
+-0.6935150612 -0.4186830921  0.4381790039
+ 0.0589047087 -0.8240793946  0.4440690614
+-0.5063278658 -0.8431340489  0.1809911096
+ 0.3291594648  0.7996124516  0.3170701581
+ 0.7837684883 -0.4186830921  0.2422208418
+ 0.5360037147 -0.8431340489  0.0427282955
+-0.7095802914  0.4941881267  0.3170700500
+ 0.0283375922  0.9128709077  0.2136305953
+-0.5360037809  0.8431342740 -0.0427230226
+-0.8627717620 -0.3317288924  0.1592318224
+ 0.7677040727  0.4941881267  0.1211117799
+ 0.5063293044  0.8431342740 -0.1809860363
+ 0.8744481415 -0.3317288924 -0.0712062810
+-0.8744476717  0.3317288831  0.0712120936
+-0.9130127824 -0.0000002089  0.1211105323
+ 0.0160652247 -0.9128709077  0.1211120373
+ 0.8627728239  0.3317288831 -0.1592260883
+ 0.9130131866 -0.0000002089 -0.1211074853
+-0.0160644264  0.9128718312 -0.1211060185
+-0.7677045094 -0.4941888273 -0.1211061534
+-0.9117856757 -0.0697383469 -0.4047106460
+-0.0283368549 -0.9128720729 -0.2136250368
+ 0.7095821798 -0.4941888273 -0.3170647319
+ 0.7747427279 -0.0697383469 -0.6284246421
+-0.7837697662  0.4186839017 -0.2422153076
+-0.0589041897  0.8240821079 -0.4440651491
+-0.5979663637 -0.6085817063 -0.3896645730
+-0.3291594183 -0.7996144008 -0.3170661961
+ 0.6935177376  0.4186839017 -0.4381739942
+ 0.4756986407 -0.6085817063 -0.5320836915
+ 0.2351146351 -0.7996144008 -0.3919158121
+-0.6168583888  0.4649158905 -0.5320835344
+-0.3551545140  0.6774441676 -0.5130247732
+-0.1016986410 -0.6339226751 -0.7666826828
+ 0.4568075735  0.4649158905 -0.6745027800
+ 0.2091227917  0.6774441676 -0.5878748207
+-0.1200394924  0.4082445693 -0.9049501465
+-0.5486577777 -0.3809323480 -0.6341330304
+ 0.3643603762 -0.3809323480 -0.7552427249
+-0.5585867166  0.1832576685 -0.7089830873
+-0.4459830958 -0.1162285368 -0.8169244453
+ 0.3544319409  0.1832576685 -0.8300928486
+ 0.2175812365 -0.1162285368 -0.9049446815
+-0.1200388929 -0.1221699932 -0.9049456265
+4 0 2 4 1 
+6 0 3 8 13 6 2 
+10 0 1 5 10 19 28 23 15 7 3 
+6 1 4 9 17 11 5 
+10 2 6 12 21 31 37 26 16 9 4 
+4 3 7 14 8 
+4 5 11 18 10 
+4 6 13 20 12 
+6 7 15 24 34 22 14 
+10 8 14 22 33 46 55 42 30 20 13 
+4 9 16 25 17 
+6 10 18 27 40 29 19 
+10 11 17 25 36 48 61 52 39 27 18 
+6 12 20 30 43 32 21 
+4 15 23 35 24 
+6 16 26 38 49 36 25 
+4 19 29 41 28 
+4 21 32 44 31 
+4 22 34 45 33 
+6 23 28 41 53 47 35 
+10 24 35 47 59 71 82 69 57 45 34 
+4 26 37 50 38 
+4 27 39 51 40 
+10 29 40 51 63 75 88 77 65 53 41 
+4 30 42 54 43 
+6 31 44 56 62 50 37 
+10 32 43 54 66 78 91 80 68 56 44 
+6 33 45 57 70 58 46 
+4 36 49 60 48 
+10 38 50 62 74 86 96 84 72 60 49 
+6 39 52 64 76 63 51 
+6 42 55 67 79 66 54 
+4 46 58 67 55 
+4 47 53 65 59 
+6 48 60 72 85 73 61 
+4 52 61 73 64 
+4 56 68 74 62 
+4 57 69 81 70 
+10 58 70 81 93 102 108 100 90 79 67 
+6 59 65 77 89 83 71 
+4 63 76 87 75 
+10 64 73 85 95 104 111 106 98 87 76 
+4 66 79 90 78 
+6 68 80 92 97 86 74 
+6 69 82 94 103 93 81 
+4 71 83 94 82 
+4 72 84 95 85 
+6 75 87 98 107 99 88 
+4 77 88 99 89 
+6 78 90 100 109 101 91 
+4 80 91 101 92 
+10 83 89 99 107 113 117 115 110 103 94 
+6 84 96 105 112 104 95 
+4 86 97 105 96 
+10 92 101 109 114 118 119 116 112 105 97 
+4 93 103 110 102 
+4 98 106 113 107 
+4 100 108 114 109 
+6 102 110 115 118 114 108 
+4 104 112 116 111 
+6 106 111 116 119 117 113 
+4 115 117 119 118 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 2 6 3 
+3 4 7 1 
+3 5 8 2 
+3 1 9 5 
+3 3 10 4 
+3 2 11 6 
+3 6 12 3 
+3 4 13 7 
+3 7 9 1 
+3 9 8 5 
+3 8 14 2 
+3 10 15 4 
+3 12 10 3 
+3 11 12 6 
+3 2 16 11 
+3 13 9 7 
+3 4 17 13 
+3 9 18 8 
+3 14 19 2 
+3 8 20 14 
+3 12 15 10 
+3 15 21 4 
+3 11 22 12 
+3 19 16 2 
+3 16 23 11 
+3 13 24 9 
+3 4 25 17 
+3 17 26 13 
+3 9 27 18 
+3 18 20 8 
+3 20 19 14 
+3 12 28 15 
+3 21 25 4 
+3 15 29 21 
+3 22 30 12 
+3 23 22 11 
+3 19 23 16 
+3 24 31 9 
+3 26 24 13 
+3 25 26 17 
+3 27 20 18 
+3 9 32 27 
+3 20 33 19 
+3 12 34 28 
+3 28 29 15 
+3 29 25 21 
+3 23 30 22 
+3 30 35 12 
+3 33 23 19 
+3 26 31 24 
+3 31 32 9 
+3 25 36 26 
+3 27 37 20 
+3 32 38 27 
+3 20 39 33 
+3 34 29 28 
+3 35 34 12 
+3 29 36 25 
+3 23 40 30 
+3 30 41 35 
+3 39 23 33 
+3 26 42 31 
+3 31 38 32 
+3 36 43 26 
+3 37 44 20 
+3 38 37 27 
+3 20 45 39 
+3 34 46 29 
+3 41 34 35 
+3 29 43 36 
+3 23 47 40 
+3 40 41 30 
+3 39 48 23 
+3 26 49 42 
+3 42 38 31 
+3 43 50 26 
+3 38 44 37 
+3 44 45 20 
+3 45 51 39 
+3 46 52 29 
+3 41 46 34 
+3 29 53 43 
+3 47 41 40 
+3 48 47 23 
+3 51 48 39 
+3 49 38 42 
+3 50 49 26 
+3 43 54 50 
+3 38 55 44 
+3 44 51 45 
+3 41 52 46 
+3 52 53 29 
+3 53 54 43 
+3 47 56 41 
+3 51 47 48 
+3 49 57 38 
+3 54 49 50 
+3 38 58 55 
+3 55 51 44 
+3 41 59 52 
+3 52 54 53 
+3 56 60 41 
+3 51 56 47 
+3 57 58 38 
+3 54 57 49 
+3 58 51 55 
+3 60 59 41 
+3 59 54 52 
+3 51 60 56 
+3 54 58 57 
+3 58 61 51 
+3 60 54 59 
+3 61 60 51 
+3 54 61 58 
+3 60 54 61 
+snub dodecahedron
+pentagonal hexecontahedron
+|2 3 5
+(3.3.3.3.5)
+icosahedral group
+A5
+12{5}+80{3}
+33 60 150 92 60 1 0 0 2 2 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4512088258  0.0000000000  0.8924183971
+ 0.2127790861  0.3978875029  0.8924183971
+-0.2505259628  0.3752680994  0.8924183971
+-0.4490629634 -0.0439529224  0.8924183971
+-0.1730083366 -0.4167223535  0.8924183971
+ 0.5570628795 -0.4167223535  0.7183477071
+ 0.8034191070 -0.0439529224  0.5937894232
+ 0.6262410352  0.3752680994  0.6833710701
+ 0.3401140582  0.7292026799  0.5937894232
+-0.4095292581  0.6926037162  0.5937894232
+-0.6598181766  0.3124803264  0.6833710701
+-0.5867073299 -0.4344864666  0.6833710701
+-0.2674638242 -0.7588657481  0.5937894232
+ 0.1712754568 -0.6742709318  0.7183477071
+ 0.5066126656 -0.7588657481  0.4092265672
+ 0.8319314730 -0.4344864666  0.3451253896
+ 0.9853200794 -0.0345183587  0.1671909808
+ 0.6986399371  0.6437955034  0.3121371303
+ 0.3534611035  0.9196768661  0.1710546996
+-0.0444936500  0.9113473168  0.4092265672
+-0.4413672010  0.8808718883  0.1710546996
+-0.7580304168  0.5726781810  0.3121371303
+-0.9277164283  0.1422346447  0.3451253896
+-0.8825314401 -0.3194162218  0.3451253896
+-0.6326042630 -0.7087892905  0.3121371303
+ 0.0822881568 -0.9349423109  0.3451253896
+ 0.3841470954 -0.9232462719 -0.0068797092
+ 0.9105239830 -0.3983895691 -0.1105975932
+ 0.9561362417  0.0261888093 -0.2917492648
+ 0.9205629910  0.3905335442 -0.0068797092
+ 0.6521763631  0.7453882542 -0.1380664403
+-0.0487110154  0.9977300839 -0.0464964156
+-0.4177242369  0.8604584989 -0.2917492648
+-0.9300960831  0.3617906055 -0.0634730968
+-0.9941677927 -0.0973061317 -0.0464964156
+-0.8422948163 -0.5352668572 -0.0634730968
+-0.5085214838 -0.8539169004 -0.1105975932
+-0.0666936701 -0.9936871537 -0.0902097278
+ 0.2171184410 -0.8730158634 -0.4366954143
+ 0.6337780180 -0.7004597412 -0.3281487085
+ 0.7752228621 -0.3165232566 -0.5466649267
+ 0.7846911652  0.4275505711 -0.4488432737
+ 0.4346204276  0.7157251860 -0.5466649267
+ 0.0014482055  0.8716810135 -0.4900715391
+-0.3439002478  0.6359394784 -0.6908788601
+-0.7197752973  0.5396486232 -0.4366954143
+-0.8871554693  0.1072142198 -0.4488432737
+-0.6414198315 -0.6014211198 -0.4763121208
+-0.2422737833 -0.8373370292 -0.4900715391
+ 0.4183769714 -0.5607792259 -0.7144839884
+ 0.4919671680 -0.1269691999 -0.8613054788
+ 0.4978189011  0.3328937158 -0.8008483725
+ 0.0947401619  0.5614556665 -0.8220655912
+-0.5854826930  0.2482988995 -0.7717238319
+-0.6691452398 -0.2043459771 -0.7144839884
+-0.3249352618 -0.5030496595 -0.8008483725
+ 0.0833693593 -0.3321275372 -0.9395428936
+ 0.1242523988  0.1277815601 -0.9839884218
+-0.2961484454 -0.0657599657 -0.9528755035
+ 0.2190839064  0.1312836377  0.9188614921
+-0.0124546442  0.2551039658  0.9188614921
+-0.2308305197  0.1093179889  0.9188614921
+-0.2052534511 -0.1520005669  0.9188614921
+ 0.2190839064 -0.3281703830  0.9188614921
+ 0.5977703708 -0.1520005669  0.7273967313
+ 0.6205958173  0.1093179889  0.7158561322
+ 0.4257131685  0.2551039658  0.8143892546
+ 0.3890572668  0.4957055924  0.7158561322
+-0.0330094857  0.6761213397  0.7360504792
+-0.4354944038  0.4554494653  0.7158561322
+-0.4485386151  0.2124213879  0.8143892546
+-0.7630826557 -0.0746882186  0.6419708175
+-0.3988385021 -0.2953600929  0.8143892546
+-0.3389195666 -0.5312467586  0.7158561322
+-0.0888218963 -0.6103640383  0.7273967313
+ 0.4074741194 -0.6103640383  0.6090650015
+ 0.6254586613 -0.5312467586  0.4859196824
+ 0.7233904360 -0.2953600929  0.5468165011
+ 0.8646946053 -0.1692512546  0.3649614304
+ 0.8780829721  0.2897337362  0.3808210291
+ 0.5493678557  0.5768433427  0.5243913714
+ 0.4593636674  0.7564719129  0.3553517403
+ 0.2141655150  0.8447510749  0.3873865601
+-0.2954354429  0.8198714201  0.3873865601
+-0.5308680756  0.7081269803  0.3553517403
+-0.6029463352  0.5205852472  0.5243913714
+-0.7739230465  0.3389900646  0.4423442636
+-0.6935065744 -0.4826176302  0.4423442636
+-0.4905640004 -0.6276147261  0.5243913714
+-0.3032002312 -0.9251016481  0.2285969389
+-0.0045863974 -0.7813515677  0.5468165011
+ 0.2508214168 -0.7813515677  0.4859196824
+ 0.3210587649 -0.8635013917  0.2466297006
+ 0.7110959079 -0.6998764938  0.0671974935
+ 0.9000340357 -0.2861982107  0.1325477729
+ 0.9410156039 -0.1341976438 -0.0775900694
+ 0.9443279912  0.1261088383 -0.0433681826
+ 0.7494453424  0.5872206583  0.0551649398
+ 0.5623291395  0.7618123698  0.1138746914
+ 0.3032002312  0.9251016481 -0.2285969389
+ 0.0858720409  0.9333521346  0.1761231918
+-0.1763828687  0.9205483682  0.1761231918
+-0.2995309163  0.9037575188 -0.0551649398
+-0.7110959079  0.6998764938 -0.0671974935
+-0.8631016874  0.3552600725  0.1959217993
+-0.9410156039  0.1341976438  0.0775900694
+-0.9253215715 -0.0905676721  0.2124078137
+-0.8971365698 -0.3141104098  0.0775900694
+-0.7778380870 -0.5158702863  0.1959217993
+-0.6544328852 -0.6922296665  0.0455552496
+ 0.1318953941 -0.9409811017  0.0818398716
+ 0.1763828687 -0.9205483682 -0.1761231918
+ 0.4075046572 -0.8237974999 -0.2546315508
+ 0.7653310532 -0.4670045122 -0.3251380596
+ 0.8716936806 -0.2272456248 -0.3131280032
+ 0.7630826557  0.0746882186 -0.6419708175
+ 0.8781301501  0.2785692436 -0.2466297006
+ 0.7778380870  0.5158702863 -0.1959217993
+ 0.6175005369  0.6231678047 -0.3740248218
+-0.1534232428  0.9007249745 -0.2733046324
+-0.2508214168  0.7813515677 -0.4859196824
+-0.4887903007  0.6717969331 -0.4683081420
+-0.8370961923  0.3328068685 -0.3131280032
+-0.9276324486  0.1226425968 -0.1843812002
+-0.8780829721 -0.2897337362 -0.3808210291
+-0.6573415966 -0.6568033615 -0.2145948808
+-0.4593636674 -0.7564719129 -0.3553517403
+-0.2697318228 -0.8859007376 -0.2279566191
+-0.0303057331 -0.8922024719 -0.3355531328
+ 0.0330094857 -0.6761213397 -0.7360504792
+ 0.4187988612 -0.7042009004 -0.4881067495
+ 0.6029463352 -0.5205852472 -0.5243913714
+ 0.5561556114 -0.3313610975 -0.7003073269
+ 0.5665700378  0.4870645516 -0.5927108132
+ 0.3389195666  0.5312467586 -0.7158561322
+ 0.1751412372  0.7090205159 -0.6133148036
+-0.0817329434  0.6826950901 -0.6608984288
+-0.2190839064  0.3281703830 -0.9188614921
+-0.5441424799  0.4698138638 -0.6266765419
+-0.7233904360  0.2953600929 -0.5468165011
+-0.7066849651  0.0498778478 -0.6384732991
+-0.5396360317 -0.4318462468 -0.6571463807
+-0.3987890908 -0.6407026882 -0.5831011230
+ 0.3278774074 -0.3365097556 -0.8299380599
+ 0.2308305197 -0.1093179889 -0.9188614921
+ 0.3675788294  0.1101068700 -0.8730990062
+ 0.2365131238  0.3372537898 -0.8601517406
+-0.5116812230 -0.0071952699 -0.8047795644
+-0.4257131685 -0.2551039658 -0.8143892546
+-0.1774197357 -0.2972657023 -0.8886478115
+-0.0292095264 -0.0891219012 -0.9490751728
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 5 4 
+5 0 1 6 14 5 
+3 1 7 6 
+3 1 8 7 
+3 1 2 8 
+3 2 9 8 
+5 2 3 10 20 9 
+3 3 11 10 
+3 3 4 11 
+5 4 12 24 23 11 
+3 4 5 12 
+3 5 13 12 
+3 5 14 13 
+3 6 15 14 
+3 6 16 15 
+3 6 7 16 
+3 7 17 16 
+5 7 8 18 30 17 
+3 8 9 18 
+3 9 19 18 
+3 9 20 19 
+3 10 21 20 
+3 10 22 21 
+3 10 11 22 
+3 11 23 22 
+3 12 25 24 
+3 12 13 25 
+5 13 26 38 37 25 
+3 13 14 26 
+3 14 15 26 
+3 15 27 26 
+5 15 16 28 40 27 
+3 16 17 28 
+3 17 29 28 
+3 17 30 29 
+3 18 31 30 
+3 18 19 31 
+5 19 32 44 43 31 
+3 19 20 32 
+3 20 21 32 
+3 21 33 32 
+5 21 22 34 46 33 
+3 22 23 34 
+3 23 35 34 
+3 23 24 35 
+3 24 36 35 
+3 24 25 36 
+3 25 37 36 
+3 26 27 38 
+3 27 39 38 
+3 27 40 39 
+3 28 41 40 
+3 28 29 41 
+5 29 42 52 51 41 
+3 29 30 42 
+3 30 31 42 
+3 31 43 42 
+3 32 33 44 
+3 33 45 44 
+3 33 46 45 
+3 34 47 46 
+3 34 35 47 
+5 35 36 48 55 47 
+3 36 37 48 
+3 37 49 48 
+3 37 38 49 
+3 38 39 49 
+5 39 50 57 56 49 
+3 39 40 50 
+3 40 41 50 
+3 41 51 50 
+3 42 43 52 
+3 43 53 52 
+3 43 44 53 
+3 44 45 53 
+5 45 54 59 58 53 
+3 45 46 54 
+3 46 47 54 
+3 47 55 54 
+3 48 56 55 
+3 48 49 56 
+3 50 51 57 
+3 51 58 57 
+3 51 52 58 
+3 52 53 58 
+3 54 55 59 
+3 55 56 59 
+3 56 57 59 
+3 57 58 59 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 13 14 15 4 3 
+5 4 16 17 18 5 
+5 18 19 20 6 5 
+5 20 21 8 7 6 
+5 21 22 23 9 8 
+5 9 24 25 26 10 
+5 26 27 12 11 10 
+5 12 28 29 14 13 
+5 29 30 31 15 14 
+5 31 32 16 4 15 
+5 32 33 34 17 16 
+5 34 35 19 18 17 
+5 35 36 37 20 19 
+5 20 38 39 22 21 
+5 39 40 41 23 22 
+5 41 42 24 9 23 
+5 42 43 44 25 24 
+5 44 45 27 26 25 
+5 45 46 47 12 27 
+5 47 48 49 28 12 
+5 49 50 30 29 28 
+5 30 51 33 32 31 
+5 51 52 53 34 33 
+5 34 54 55 36 35 
+5 55 56 57 37 36 
+5 57 58 38 20 37 
+5 58 59 40 39 38 
+5 40 60 43 42 41 
+5 60 61 62 44 43 
+5 44 63 64 46 45 
+5 64 65 48 47 46 
+5 65 66 50 49 48 
+5 66 67 68 30 50 
+5 68 69 52 51 30 
+5 69 70 71 53 52 
+5 71 72 54 34 53 
+5 72 73 56 55 54 
+5 56 74 59 58 57 
+5 74 75 76 40 59 
+5 76 77 61 60 40 
+5 77 78 79 62 61 
+5 79 80 63 44 62 
+5 80 81 65 64 63 
+5 65 82 83 67 66 
+5 83 70 69 68 67 
+5 70 84 73 72 71 
+5 84 85 86 56 73 
+5 86 87 75 74 56 
+5 87 78 77 76 75 
+5 78 88 81 80 79 
+5 88 89 82 65 81 
+5 89 90 70 83 82 
+5 90 91 85 84 70 
+5 91 78 87 86 85 
+5 78 88 89 90 91 
--- /dev/null
+++ b/lib/polyhedra.all
@@ -1,0 +1,13258 @@
+pentagonal prism
+pentagonal dipyramid
+2 5|2
+(4.4.5)
+dihedral group
+D
+2{5}+5{4}
+0 10 15 7 10 1 0 0 2 2 3 20 2 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8737108351  0.0000000000  0.4864456563
+-0.3018596695  0.8199093629  0.4864456563
+-0.6651309335 -0.5665434359  0.4864456563
+ 0.5718511657  0.8199093629 -0.0271086873
+ 0.7485628941 -0.5665434359 -0.3445027268
+-0.9669906029  0.2533659270 -0.0271086873
+-0.2024936222 -0.9166865354 -0.3445027268
+ 0.4467032247  0.2533659270 -0.8580570704
+-0.5043532916 -0.0967771725 -0.8580570704
+ 0.2978495106  0.4270509831  0.5067318540
+-0.5036584607  0.1319660113  0.5067318540
+ 0.2978495106 -0.8090169944  0.5067318540
+ 0.6877395818  0.1319660113 -0.1935543450
+-0.2978495106  0.8090169944 -0.5067318540
+-0.6091275581 -0.3454915028 -0.1935543450
+ 0.1271969263 -0.3454915028 -0.6263550179
+4 0 2 4 1 
+4 0 3 6 2 
+5 0 1 5 7 3 
+4 1 4 8 5 
+5 2 6 9 8 4 
+4 3 7 9 6 
+4 5 8 9 7 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 2 6 3 
+3 4 5 1 
+3 5 6 2 
+3 6 4 3 
+3 4 5 6 
+pentagonal antiprism
+pentagonal deltohedron
+|2 2 5
+(3.3.3.5)
+dihedral group
+D
+2{5}+10{3}
+1 10 20 12 10 1 0 0 2 2 4 20 2 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000  0.4472135955
+ 0.2763932023  0.8506508084  0.4472135955
+-0.7236067977  0.5257311121  0.4472135955
+-0.7236067977 -0.5257311121  0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+ 0.7236067977  0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2763932023  0.2008114159  0.4472135955
+-0.1055728090  0.3249196962  0.4472135955
+-0.3416407865 -0.0000000000  0.4472135955
+ 0.2763932023 -0.8506508084  0.4472135955
+ 0.5527864045  0.0000000000 -0.1055728090
+ 0.4472135955  0.3249196962  0.1055728090
+-0.2763932023  0.8506508084 -0.4472135955
+-0.5527864045 -0.0000000000  0.1055728090
+-0.4472135955 -0.3249196962 -0.1055728090
+ 0.1055728090 -0.3249196962 -0.4472135955
+ 0.3416407865  0.0000000000 -0.4472135955
+-0.2763932023 -0.2008114159 -0.4472135955
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+5 0 1 5 8 4 
+3 1 6 5 
+3 1 2 6 
+5 2 3 7 9 6 
+3 3 4 7 
+3 4 8 7 
+3 5 9 8 
+3 5 6 9 
+3 7 8 9 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 6 7 2 1 
+4 7 8 3 2 
+4 3 9 10 4 
+4 10 6 5 4 
+4 6 11 8 7 
+4 11 9 3 8 
+4 9 10 6 11 
+pentagrammic prism
+pentagrammic dipyramid
+2 5/2|2
+(4.4.5/2)
+dihedral group
+D
+5{4}+2{5/2}
+2 10 15 7 10 2 0 0 2 2 3 20 2 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9987422138  0.0000000000  0.0501397095
+-0.9033708188  0.4259192097  0.0501397095
+ 0.6354709497 -0.7704950886  0.0501397095
+ 0.0953713949  0.4259192097 -0.8997205810
+ 0.0182143157 -0.7704950886  0.6371856536
+-0.2678998691 -0.3445758789 -0.8997205810
+ 0.6059995679  0.4761921529  0.6371856536
+-0.8851565032 -0.3445758789 -0.3126746369
+-0.2973712509  0.9021113626 -0.3126746369
+ 0.2129596049  0.9510565163  0.2239189798
+-0.5982071492 -0.7694208843  0.2239189798
+ 0.2129596049 -0.1004057079  0.2239189798
+ 0.2536312703 -0.7694208843 -0.5862274998
+-0.2129596049  0.1004057079 -0.2239189798
+ 0.7549598948  0.2938926261 -0.5862274998
+-0.6233436208  0.2938926261  0.7246170401
+4 0 2 4 1 
+4 0 3 6 2 
+5 0 1 5 7 3 2
+4 1 4 8 5 
+5 2 6 9 8 4 2
+4 3 7 9 6 
+4 5 8 9 7 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 2 6 3 
+3 4 5 1 
+3 5 6 2 
+3 6 4 3 
+3 4 5 6 
+pentagrammic antiprism
+pentagrammic deltohedron
+|2 2 5/2
+(3.3.3.5/2)
+dihedral group
+D
+10{3}+2{5/2}
+3 10 20 12 10 2 0 0 2 2 4 20 2 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9870590084  0.0000000000 -0.1603574566
+-0.1885114962  0.9688905521 -0.1603574566
+-0.9150540242 -0.3700832595 -0.1603574566
+ 0.5380310318 -0.8275313256 -0.1603574566
+-0.0720049843 -0.8275313256  0.5567828907
+-0.3050180081 -0.3700832595 -0.8774978039
+ 0.1440099685  0.4574480661 -0.8774978039
+ 0.6545375437  0.5114424860  0.5567828907
+-0.8430490399  0.4574480661  0.2828596527
+ 0.5593892211  0.6787159473  0.4758448931
+-0.7730568906  0.4194695241  0.4758448931
+-0.2641077641 -0.8389390482  0.4758448931
+ 0.5593892211 -0.3035309991  0.4758448931
+ 0.4273353390 -0.8389390482 -0.3369952245
+ 0.3457215516  0.4194695241 -0.8393580447
+-0.5593892211  0.3035309991 -0.4758448931
+-0.1632275749 -0.5184928463 -0.8393580447
+ 0.9362844655  0.0990233222 -0.3369952245
+-0.1824939766  0.0990233222  0.9782077132
+-0.8546706780 -0.5184928463 -0.0265179270
+-0.0311736929  0.9991621492 -0.0265179270
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+5 0 1 5 8 4 2
+3 1 6 5 
+3 1 2 6 
+5 2 3 7 9 6 2
+3 3 4 7 
+3 4 8 7 
+3 5 9 8 
+3 5 6 9 
+3 7 8 9 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 6 7 2 1 
+4 7 8 3 2 
+4 3 9 10 4 
+4 10 6 5 4 
+4 6 11 8 7 
+4 11 9 3 8 
+4 9 10 6 11 
+pentagrammic crossed antiprism
+pentagrammic concave deltohedron
+|2 2 5/3
+(3.3.3.5/3)
+dihedral group
+D
+10{3}+2{5/3}
+4 10 20 12 10 3 0 0 2 2 4 20 2 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000 -0.4472135955
+-0.7236067977  0.5257311121 -0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+ 0.2763932023  0.8506508084 -0.4472135955
+-0.2763932023  0.8506508084  0.4472135955
+-0.2763932023 -0.8506508084  0.4472135955
+-0.8944271910  0.0000000000  0.4472135955
+ 0.7236067977 -0.5257311121  0.4472135955
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.3035309991  0.9341723590  0.1875924741
+-0.7946544723 -0.5773502692  0.1875924741
+ 0.9822469464  0.0000000000  0.1875924741
+ 0.3035309991  0.2205281794  0.1875924741
+ 0.6070619982 -0.0000000000  0.7946544723
+-0.1875924741 -0.5773502692 -0.7946544723
+-0.3035309991 -0.2205281794 -0.1875924741
+-0.6070619982 -0.0000000000 -0.7946544723
+ 0.1875924741  0.5773502692  0.7946544723
+ 0.7946544723  0.5773502692 -0.1875924741
+-0.9822469464  0.0000000000 -0.1875924741
+-0.3035309991 -0.9341723590 -0.1875924741
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+5 0 1 5 8 4 3
+3 1 6 5 
+3 1 2 6 
+5 2 3 7 9 6 3
+3 3 4 7 
+3 4 8 7 
+3 5 9 8 
+3 5 6 9 
+3 7 8 9 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 6 7 2 1 
+4 7 8 3 2 
+4 3 9 10 4 
+4 10 6 5 4 
+4 6 11 8 7 
+4 11 9 3 8 
+4 9 10 6 11 
+tetrahedron
+tetrahedron
+3|2 3
+(3.3.3)
+tetrahedral group
+A4
+4{3}
+5 4 6 4 4 1 0 0 2 1 3 24 3 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9428090416  0.0000000000 -0.3333333333
+-0.4714045208  0.8164965809 -0.3333333333
+-0.4714045208 -0.8164965809 -0.3333333333
+ 0.4714045208  0.8164965809  0.3333333333
+-0.9428090416  0.0000000000  0.3333333333
+ 0.4714045208 -0.8164965809  0.3333333333
+-0.0000000000  0.0000000000 -1.0000000000
+3 0 2 1 
+3 0 3 2 
+3 0 1 3 
+3 1 2 3 
+3 2 0 1 
+3 2 3 0 
+3 3 1 0 
+3 1 2 3 
+truncated tetrahedron
+triakistetrahedron
+2 3|3
+(6.6.3)
+tetrahedral group
+A4
+4{6}+4{3}
+6 12 18 8 12 1 0 0 2 2 3 24 3 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7713892158  0.0000000000  0.6363636364
+-0.6428243465  0.4264014327  0.6363636364
+ 0.2999846950 -0.7106690545  0.6363636364
+ 0.8999540851  0.4264014327 -0.0909090909
+-0.9856639980  0.1421338109 -0.0909090909
+-0.5142594772  0.8528028654 -0.0909090909
+-0.0428549564 -0.9949366763 -0.0909090909
+ 0.5571144337  0.1421338109 -0.8181818182
+ 0.2571297386  0.8528028654 -0.4545454545
+-0.6856793030 -0.5685352436 -0.4545454545
+ 0.0857099129 -0.5685352436 -0.8181818182
+ 0.2461829820  0.8164965809  0.5222329679
+-0.6564879519 -0.5443310540  0.5222329679
+ 0.2461829820 -0.1632993162  0.5222329679
+ 0.8206099399 -0.5443310540 -0.1740776560
+-0.4923659639  0.3265986324  0.1044465936
+ 0.3938927711  0.3265986324 -0.3133397807
+-0.4103049699  0.2721655270 -0.8703882798
+-0.1477097892 -0.4898979486 -0.3133397807
+6 0 2 6 9 4 1 
+6 0 3 7 10 5 2 
+3 0 1 3 
+6 1 4 8 11 7 3 
+3 2 5 6 
+3 4 9 8 
+6 5 10 11 8 9 6 
+3 7 11 10 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 6 5 
+3 5 0 6 
+3 6 7 1 
+3 7 3 6 
+octahemioctahedron
+octahemioctacron
+3/2 3|3
+(6.3/2.6.3)
+tetrahedral group
+A4
+4{6}+4{3}+4{3/2}
+7 12 24 12 12 0 1 0 0 3 4 24 3 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8660254038  0.0000000000  0.5000000000
+-0.8660254038  0.0000000000  0.5000000000
+-0.2886751346  0.8164965809  0.5000000000
+ 0.2886751346 -0.8164965809  0.5000000000
+ 0.8660254038  0.0000000000 -0.5000000000
+ 0.5773502692  0.8164965809  0.0000000000
+-0.5773502692 -0.8164965809  0.0000000000
+-0.8660254038 -0.0000000000 -0.5000000000
+-0.2886751346  0.8164965809 -0.5000000000
+ 0.2886751346 -0.8164965809 -0.5000000000
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-0.4714045208  0.3333333333  0.8164965809
+-0.9428090416 -0.3333333333  0.0000000000
+ 0.4714045208 -0.3333333333  0.8164965809
+ 0.4714045208 -0.3333333333 -0.8164965809
+ 0.9428090416  0.3333333333  0.0000000000
+-0.9428090416 -0.3333333333  0.0000000000
+ 0.4714045208 -0.3333333333  0.8164965809
+ 0.0000000000  1.0000000000  0.0000000000
+-0.0000000000 -1.0000000000  0.0000000000
+ 0.4714045208 -0.3333333333 -0.8164965809
+-0.4714045208  0.3333333333 -0.8164965809
+6 0 1 5 11 8 2 
+3 0 2 3 2
+6 0 3 9 11 10 4 
+3 0 1 4 
+6 1 4 7 8 9 6 
+3 1 6 5 2
+3 2 8 7 
+6 2 7 10 5 6 3 
+3 3 6 9 
+3 4 10 7 2
+3 5 10 11 
+3 8 11 9 2
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 8 7 1 2 
+4 9 2 3 4 
+4 5 7 10 0 
+4 8 4 5 7 
+4 6 4 9 7 
+4 11 0 6 4 
+4 11 2 8 4 
+4 10 2 9 7 
+4 10 0 11 2 
+tetrahemihexahedron
+tetrahemihexacron
+3/2 3|2
+(4.3/2.4.3)
+tetrahedral group
+A4
+3{4}+2{3}+2{3/2}
+8 6 12 7 6 0 1 1 1 3 4 24 3 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 1.0000000000  0.0000000000  0.0000000000
+-1.0000000000  0.0000000000  0.0000000000
+-0.0000000000  1.0000000000  0.0000000000
+-0.0000000000 -1.0000000000  0.0000000000
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-0.5773502692  0.5773502692  0.5773502692
+-1.0000000000  0.0000000000  0.0000000000
+ 0.5773502692 -0.5773502692  0.5773502692
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.5773502692  0.5773502692 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+4 0 1 5 2 
+3 0 2 3 2
+4 0 3 5 4 
+3 0 1 4 
+4 1 4 2 3 
+3 1 3 5 2
+3 2 5 4 
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 4 
+4 5 2 1 4 
+4 6 2 3 4 
+4 5 0 6 2 
+octahedron
+hexahedron
+4|2 3
+(3.3.3.3)
+octahedral group
+S4
+8{3}
+9 6 12 8 6 1 0 0 2 1 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 1.0000000000  0.0000000000  0.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-1.0000000000  0.0000000000  0.0000000000
+ 0.0000000000 -1.0000000000  0.0000000000
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.5773502692  0.5773502692  0.5773502692
+-0.5773502692  0.5773502692  0.5773502692
+-0.5773502692 -0.5773502692  0.5773502692
+ 0.5773502692 -0.5773502692  0.5773502692
+ 0.5773502692 -0.5773502692 -0.5773502692
+ 0.5773502692  0.5773502692 -0.5773502692
+-0.5773502692  0.5773502692 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 1 4 
+3 1 5 4 
+3 1 2 5 
+3 2 3 5 
+3 3 4 5 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 6 7 2 1 
+4 7 4 3 2 
+4 4 5 6 7 
+hexahedron
+octahedron
+3|2 4
+(4.4.4)
+octahedral group
+S4
+6{4}
+10 8 12 6 8 1 0 0 2 1 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9428090416  0.0000000000  0.3333333333
+-0.4714045208  0.8164965809  0.3333333333
+-0.4714045208 -0.8164965809  0.3333333333
+ 0.4714045208  0.8164965809 -0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+-0.9428090416  0.0000000000 -0.3333333333
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.4082482905  0.7071067812  0.5773502692
+-0.8164965809  0.0000000000  0.5773502692
+ 0.4082482905 -0.7071067812  0.5773502692
+ 0.8164965809  0.0000000000 -0.5773502692
+-0.4082482905  0.7071067812 -0.5773502692
+-0.4082482905 -0.7071067812 -0.5773502692
+4 0 2 4 1 
+4 0 3 6 2 
+4 0 1 5 3 
+4 1 4 7 5 
+4 2 6 7 4 
+4 3 5 7 6 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 5 3 2 
+3 4 5 1 
+3 3 4 5 
+cuboctahedron
+rhombic dodecahedron
+2|3 4
+(3.4.3.4)
+octahedral group
+S4
+6{4}+8{3}
+11 12 24 14 12 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8660254038  0.0000000000  0.5000000000
+ 0.2886751346  0.8164965809  0.5000000000
+-0.8660254038  0.0000000000  0.5000000000
+-0.2886751346 -0.8164965809  0.5000000000
+ 0.8660254038  0.0000000000 -0.5000000000
+ 0.5773502692 -0.8164965809  0.0000000000
+-0.5773502692  0.8164965809  0.0000000000
+ 0.2886751346  0.8164965809 -0.5000000000
+-0.8660254038  0.0000000000 -0.5000000000
+-0.2886751346 -0.8164965809 -0.5000000000
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.4082482905  0.2886751346  0.7071067812
+-0.4082482905  0.5773502692  0.7071067812
+-0.4082482905 -0.2886751346  0.7071067812
+ 0.4082482905 -0.5773502692  0.7071067812
+ 0.8164965809 -0.2886751346  0.0000000000
+ 0.8164965809  0.5773502692  0.0000000000
+ 0.0000000000  0.8660254038  0.0000000000
+-0.8164965809  0.2886751346 -0.0000000000
+-0.8164965809 -0.5773502692  0.0000000000
+-0.0000000000 -0.8660254038 -0.0000000000
+ 0.4082482905 -0.5773502692 -0.7071067812
+ 0.4082482905  0.2886751346 -0.7071067812
+-0.4082482905  0.5773502692 -0.7071067812
+-0.4082482905 -0.2886751346 -0.7071067812
+3 0 2 1 
+4 0 3 7 2 
+3 0 4 3 
+4 0 1 6 4 
+3 1 5 6 
+4 1 2 8 5 
+3 2 7 8 
+3 3 9 7 
+4 3 4 10 9 
+3 4 6 10 
+4 5 11 10 6 
+3 5 8 11 
+4 7 9 11 8 
+3 9 10 11 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 1 7 8 2 
+4 8 9 3 2 
+4 4 10 11 5 
+4 9 10 4 3 
+4 6 12 7 1 
+4 11 12 6 5 
+4 12 13 8 7 
+4 13 10 9 8 
+4 10 11 12 13 
+truncated octahedron
+tetrakishexahedron
+2 4|3
+(6.6.4)
+octahedral group
+S4
+8{6}+6{4}
+12 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6000000000  0.0000000000  0.8000000000
+-0.4000000000  0.4472135955  0.8000000000
+-0.0666666667 -0.5962847940  0.8000000000
+ 0.8000000000  0.4472135955  0.4000000000
+ 0.5333333333 -0.5962847940  0.6000000000
+-0.8666666667  0.2981423970  0.4000000000
+-0.2000000000  0.8944271910  0.4000000000
+-0.5333333333 -0.7453559925  0.4000000000
+ 0.9333333333  0.2981423970 -0.2000000000
+ 0.4000000000  0.8944271910  0.2000000000
+ 0.6666666667 -0.7453559925  0.0000000000
+-0.6666666667  0.7453559925  0.0000000000
+-0.9333333333 -0.2981423970  0.2000000000
+-0.4000000000 -0.8944271910 -0.2000000000
+ 0.5333333333  0.7453559925 -0.4000000000
+ 0.8666666667 -0.2981423970 -0.4000000000
+ 0.2000000000 -0.8944271910 -0.4000000000
+-0.5333333333  0.5962847940 -0.6000000000
+-0.8000000000 -0.4472135955 -0.4000000000
+ 0.0666666667  0.5962847940 -0.8000000000
+ 0.4000000000 -0.4472135955 -0.8000000000
+-0.6000000000 -0.0000000000 -0.8000000000
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.2581988897  0.5773502692  0.7745966692
+-0.6024640761 -0.1924500897  0.7745966692
+ 0.2581988897 -0.2886751346  0.7745966692
+ 0.9467292624 -0.1924500897  0.2581988897
+-0.5163977795  0.5773502692  0.3872983346
+ 0.0860662966 -0.9622504486  0.2581988897
+ 0.6454972244  0.5773502692  0.0000000000
+-0.9467292624  0.1924500897 -0.2581988897
+-0.0860662966  0.9622504486 -0.2581988897
+-0.6454972244 -0.5773502692 -0.0000000000
+ 0.6024640761  0.1924500897 -0.7745966692
+ 0.5163977795 -0.5773502692 -0.3872983346
+-0.2581988897 -0.5773502692 -0.7745966692
+-0.2581988897  0.2886751346 -0.7745966692
+6 0 2 7 10 4 1 
+6 0 3 8 13 6 2 
+4 0 1 5 3 
+6 1 4 9 16 11 5 
+4 2 6 12 7 
+6 3 5 11 17 14 8 
+4 4 10 15 9 
+6 6 13 19 22 18 12 
+6 7 12 18 20 15 10 
+4 8 14 19 13 
+6 9 15 20 23 21 16 
+4 11 16 21 17 
+6 14 17 21 23 22 19 
+4 18 22 23 20 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 5 3 2 
+3 4 7 1 
+3 0 8 4 
+3 1 9 5 
+3 3 10 6 
+3 6 8 0 
+3 5 11 3 
+3 8 7 4 
+3 7 9 1 
+3 9 12 5 
+3 10 8 6 
+3 11 10 3 
+3 12 11 5 
+3 8 13 7 
+3 7 12 9 
+3 10 13 8 
+3 12 10 11 
+3 13 12 7 
+3 10 13 12 
+truncated hexahedron
+triakisoctahedron
+2 3|4
+(8.8.3)
+octahedral group
+S4
+6{8}+8{3}
+13 24 36 14 24 1 0 0 2 2 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5395042868  0.0000000000  0.8419828529
+-0.4604957132  0.2810846377  0.8419828529
+ 0.2466110680 -0.4798414911  0.8419828529
+ 0.8419828529  0.2810846377  0.4604957132
+-0.8651239283  0.1987568534  0.4604957132
+-0.5722307095  0.6785983445  0.4604957132
+ 0.1348760717 -0.8773551980  0.4604957132
+ 0.9768589246  0.1987568534 -0.0790085736
+ 0.7302478566  0.6785983445  0.0790085736
+-0.9768589246 -0.1987568534  0.0790085736
+-0.2697521434  0.9596829823  0.0790085736
+-0.2697521434 -0.9596829823  0.0790085736
+ 0.2697521434 -0.9596829823 -0.0790085736
+ 0.8651239283 -0.1987568534 -0.4604957132
+ 0.2697521434  0.9596829823 -0.0790085736
+-0.7302478566 -0.6785983445 -0.0790085736
+-0.8419828529 -0.2810846377 -0.4604957132
+-0.1348760717  0.8773551980 -0.4604957132
+ 0.5722307095 -0.6785983445 -0.4604957132
+ 0.4604957132 -0.2810846377 -0.8419828529
+-0.5395042868  0.0000000000 -0.8419828529
+-0.2466110680  0.4798414911 -0.8419828529
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1987568534  0.7071067812  0.6785983445
+-0.5380560257 -0.5000000000  0.6785983445
+ 0.1987568534 -0.1213203436  0.6785983445
+ 0.8191406634 -0.5000000000  0.2810846377
+-0.4798414911  0.2928932188  0.4457402063
+ 0.6444970597  0.2928932188  0.1164290691
+-0.8191406634  0.5000000000 -0.2810846377
+ 0.0341012848 -0.7071067812  0.1164290691
+ 0.5380560257  0.5000000000 -0.6785983445
+-0.6444970597 -0.2928932188 -0.1164290691
+-0.0341012848  0.7071067812 -0.1164290691
+-0.1987568534 -0.7071067812 -0.6785983445
+ 0.4798414911 -0.2928932188 -0.4457402063
+-0.1987568534  0.1213203436 -0.6785983445
+8 0 2 6 11 15 9 4 1 
+8 0 3 7 12 16 10 5 2 
+3 0 1 3 
+8 1 4 8 14 19 13 7 3 
+3 2 5 6 
+3 4 9 8 
+8 5 10 17 21 22 18 11 6 
+3 7 13 12 
+8 8 9 15 18 22 23 20 14 
+3 10 16 17 
+3 11 18 15 
+8 12 13 19 20 23 21 17 16 
+3 14 20 19 
+3 21 23 22 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 8 5 
+3 8 0 5 
+3 6 9 1 
+3 0 10 6 
+3 1 11 7 
+3 11 3 7 
+3 3 12 8 
+3 8 10 0 
+3 9 11 1 
+3 6 11 9 
+3 8 6 10 
+3 11 12 3 
+3 11 8 12 
+3 6 13 11 
+3 8 13 6 
+3 11 8 13 
+small rhombicuboctahedron
+deltoidal icositetrahedron
+3 4|2
+(4.3.4.4)
+octahedral group
+S4
+18{4}+8{3}
+14 24 48 26 24 1 0 0 2 2 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6675992222  0.0000000000  0.7445208382
+-0.0977676425  0.6604015517  0.7445208382
+-0.6389637427  0.1934271362  0.7445208382
+-0.0977676425 -0.6604015517  0.7445208382
+ 0.5698315797  0.6604015517  0.4890416764
+ 0.9727633538  0.1934271362  0.1277395809
+ 0.5698315797 -0.6604015517  0.4890416764
+-0.3337996111  0.9339488311  0.1277395809
+-0.7367313852 -0.4669744155  0.4890416764
+-0.8749957112  0.4669744155  0.1277395809
+-0.3337996111 -0.9339488311  0.1277395809
+ 0.3337996111  0.9339488311 -0.1277395809
+ 0.8749957112 -0.4669744155 -0.1277395809
+ 0.7367313852  0.4669744155 -0.4890416764
+ 0.3337996111 -0.9339488311 -0.1277395809
+-0.5698315797  0.6604015517 -0.4890416764
+-0.9727633538 -0.1934271362 -0.1277395809
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.0977676425  0.6604015517 -0.7445208382
+ 0.6389637427 -0.1934271362 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222 -0.0000000000 -0.7445208382
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.3302007759  0.3826834324  0.8628562095
+-0.2553967884  0.2959899757  0.8628562095
+-0.4269143440 -0.2705980501  0.8628562095
+ 0.3302007759 -0.3826834324  0.8628562095
+ 0.8938887595 -0.2705980501  0.3574067443
+ 0.7661903653  0.2959899757  0.4719117310
+ 0.1367736397  0.9238795325  0.3574067443
+-0.5636879836  0.6532814824  0.5054494651
+-0.9339488311  0.0000000000  0.3574067443
+-0.4050047633 -0.7145830136  0.4719117310
+ 0.1367736397 -0.9238795325  0.3574067443
+ 0.7571151198  0.6532814824  0.0000000000
+ 0.9339488311  0.0000000000 -0.3574067443
+ 0.6165823904 -0.7145830136  0.0809672526
+-0.1367736397  0.9238795325 -0.3574067443
+-0.6165823904  0.7145830136 -0.0809672526
+-0.7571151198 -0.6532814824  0.0000000000
+-0.8938887595  0.2705980501 -0.3574067443
+-0.1367736397 -0.9238795325 -0.3574067443
+ 0.4050047633  0.7145830136 -0.4719117310
+ 0.5636879836 -0.6532814824 -0.5054494651
+ 0.4269143440  0.2705980501 -0.8628562095
+-0.3302007759  0.3826834324 -0.8628562095
+-0.7661903653 -0.2959899757 -0.4719117310
+-0.3302007759 -0.3826834324 -0.8628562095
+ 0.2553967884 -0.2959899757 -0.8628562095
+4 0 2 5 1 
+3 0 3 2 
+4 0 4 9 3 
+4 0 1 7 4 
+4 1 6 13 7 
+3 1 5 6 
+4 2 8 12 5 
+4 2 3 10 8 
+4 3 9 17 10 
+3 4 11 9 
+4 4 7 15 11 
+4 5 12 14 6 
+4 6 14 20 13 
+3 7 13 15 
+4 8 16 19 12 
+3 8 10 16 
+4 9 11 18 17 
+4 10 17 22 16 
+4 11 15 21 18 
+3 12 19 14 
+4 13 20 21 15 
+4 14 19 23 20 
+4 16 22 23 19 
+3 17 18 22 
+4 18 21 23 22 
+3 20 23 21 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 11 6 0 
+4 4 12 11 5 
+4 10 13 4 3 
+4 6 14 15 7 
+4 8 16 9 2 
+4 15 17 8 7 
+4 16 18 10 9 
+4 11 19 14 6 
+4 13 20 12 4 
+4 12 21 19 11 
+4 18 20 13 10 
+4 14 22 17 15 
+4 17 23 16 8 
+4 23 24 18 16 
+4 21 22 14 19 
+4 20 25 21 12 
+4 24 25 20 18 
+4 22 24 23 17 
+4 21 22 24 25 
+truncated cuboctahedron
+disdyakisdodecahedron
+2 3 4|
+(4.6.8)
+octahedral group
+S4
+6{8}+8{6}+12{4}
+15 48 72 26 48 1 0 0 2 3 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4213179058  0.0000000000  0.9069130180
+-0.0205668596  0.4208156152  0.9069130180
+-0.3330265737 -0.2580737859  0.9069130180
+ 0.4007510462  0.4208156152  0.8138260361
+ 0.6841248285 -0.2580737859  0.6821811637
+-0.3741602929  0.5835574446  0.7207390541
+-0.3826793651 -0.6230452339  0.6821811637
+-0.6866200070 -0.0953319565  0.7207390541
+ 0.6429911093  0.5835574446  0.4960071997
+ 0.6344720372 -0.6230452339  0.4574493093
+ 0.9263648917 -0.0953319565  0.3643623273
+-0.4528990160  0.8137091469  0.3643623273
+-0.7071868666  0.3254836587  0.6276520721
+-0.7362727984 -0.4603034045  0.4960071997
+-0.1198724423 -0.8811190198  0.4574493093
+ 0.5642523862  0.8137091469  0.1396304730
+ 0.9057980321  0.3254836587  0.2712753454
+ 0.8767121003 -0.4603034045  0.1396304730
+ 0.3014454635 -0.8811190198  0.3643623273
+-0.7859255897  0.5556353610  0.2712753454
+-0.2106589529  0.9764509762  0.0465434910
+-0.8270593089 -0.5556353610  0.0851013814
+-0.2106589529 -0.9764509762  0.0465434910
+ 0.8270593089  0.5556353610 -0.0851013814
+ 0.2106589529  0.9764509762 -0.0465434910
+ 0.7859255897 -0.5556353610 -0.2712753454
+ 0.2106589529 -0.9764509762 -0.0465434910
+-0.8767121003  0.4603034045 -0.1396304730
+-0.3014454635  0.8811190198 -0.3643623273
+-0.9057980321 -0.3254836587 -0.2712753454
+-0.5642523862 -0.8137091469 -0.1396304730
+ 0.7362727984  0.4603034045 -0.4960071997
+ 0.1198724423  0.8811190198 -0.4574493093
+ 0.7071868666 -0.3254836587 -0.6276520721
+ 0.4528990160 -0.8137091469 -0.3643623273
+-0.9263648917  0.0953319565 -0.3643623273
+-0.6344720372  0.6230452339 -0.4574493093
+-0.6429911093 -0.5835574446 -0.4960071997
+ 0.6866200070  0.0953319565 -0.7207390541
+ 0.3826793651  0.6230452339 -0.6821811637
+ 0.3741602929 -0.5835574446 -0.7207390541
+-0.6841248285  0.2580737859 -0.6821811637
+-0.4007510462 -0.4208156152 -0.8138260361
+ 0.3330265737  0.2580737859 -0.9069130180
+ 0.0205668596 -0.4208156152 -0.9069130180
+-0.4213179058 -0.0000000000 -0.9069130180
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1824857240  0.1916223125  0.8259425910
+-0.3588578683  0.1651647923  0.8259425910
+ 0.1824857240 -0.5334020968  0.8259425910
+ 0.6734372751  0.1651647923  0.5978648424
+ 0.1150758511  0.8458618109  0.5208409981
+-0.4869154353 -0.3271197492  0.6388327969
+ 0.7107416431 -0.3271197492  0.3742195883
+-0.5282559191  0.5187420617  0.4517230027
+-0.4805150176 -0.7290726662  0.2753141970
+-0.9764509762  0.0000000000  0.2157394053
+ 0.6694011593  0.5187420617  0.1871097942
+ 0.5517801258 -0.7290726662  0.0472364484
+ 0.9764509762  0.0000000000 -0.2157394053
+-0.5517801258  0.7290726662 -0.0472364484
+ 0.0413404837 -0.8458618109  0.1871097942
+ 0.4805150176  0.7290726662 -0.2753141970
+-0.0413404837  0.8458618109 -0.1871097942
+-0.6694011593 -0.5187420617 -0.1871097942
+-0.1150758511 -0.8458618109 -0.5208409981
+ 0.5282559191 -0.5187420617 -0.4517230027
+-0.7107416431  0.3271197492 -0.3742195883
+-0.1824857240  0.5334020968 -0.8259425910
+-0.6734372751 -0.1651647923 -0.5978648424
+ 0.4869154353  0.3271197492 -0.6388327969
+ 0.3588578683 -0.1651647923 -0.8259425910
+-0.1824857240 -0.1916223125 -0.8259425910
+4 0 2 4 1 
+6 0 3 8 13 6 2 
+8 0 1 5 10 19 15 7 3 
+6 1 4 9 17 11 5 
+8 2 6 12 21 25 16 9 4 
+4 3 7 14 8 
+4 5 11 18 10 
+4 6 13 20 12 
+6 7 15 23 31 22 14 
+8 8 14 22 30 36 28 20 13 
+4 9 16 24 17 
+6 10 18 26 35 27 19 
+8 11 17 24 32 39 34 26 18 
+6 12 20 28 37 29 21 
+4 15 19 27 23 
+6 16 25 33 40 32 24 
+4 21 29 33 25 
+4 22 31 38 30 
+8 23 27 35 41 45 43 38 31 
+4 26 34 41 35 
+4 28 36 42 37 
+8 29 37 42 46 47 44 40 33 
+6 30 38 43 46 42 36 
+4 32 40 44 39 
+6 34 39 44 47 45 41 
+4 43 45 47 46 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 2 6 3 
+3 4 7 1 
+3 5 8 2 
+3 1 9 5 
+3 3 10 4 
+3 2 11 6 
+3 6 12 3 
+3 4 13 7 
+3 7 9 1 
+3 9 8 5 
+3 8 14 2 
+3 10 15 4 
+3 12 10 3 
+3 11 12 6 
+3 14 11 2 
+3 13 9 7 
+3 4 16 13 
+3 9 17 8 
+3 8 18 14 
+3 12 15 10 
+3 15 16 4 
+3 11 19 12 
+3 18 11 14 
+3 13 20 9 
+3 16 21 13 
+3 9 22 17 
+3 17 18 8 
+3 12 23 15 
+3 15 21 16 
+3 19 24 12 
+3 18 19 11 
+3 20 22 9 
+3 21 20 13 
+3 22 18 17 
+3 24 23 12 
+3 23 21 15 
+3 18 24 19 
+3 21 22 20 
+3 22 25 18 
+3 24 21 23 
+3 25 24 18 
+3 21 25 22 
+3 24 21 25 
+snub hexahedron
+pentagonal icositetrahedron
+|2 3 4
+(3.3.3.3.4)
+octahedral group
+S4
+6{4}+32{3}
+16 24 60 38 24 1 0 0 2 2 5 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6907659000  0.0000000000  0.7230784683
+ 0.2898753354  0.6270006527  0.7230784683
+-0.4474773703  0.5262333434  0.7230784683
+-0.6654371656 -0.1853399775  0.7230784683
+-0.1110152292 -0.6817867317  0.7230784683
+ 0.5797506708 -0.6817867317  0.4461569367
+ 0.9806412354 -0.1853399775  0.0631811688
+ 0.8230392005  0.5262333434  0.2137403629
+ 0.2432885297  0.9678940186  0.0631811688
+-0.4940641761  0.8671267092  0.0631811688
+-0.9340544297  0.2861072869  0.2137403629
+-0.6516662110 -0.7277679621  0.2137403629
+ 0.0253287344 -0.9976806078  0.0631811688
+ 0.6188503599 -0.7277679621 -0.2955977425
+ 0.7626814402 -0.0845726681 -0.6412210887
+ 0.6050794053  0.6270006527 -0.4906618946
+-0.1110152292  0.8123406303 -0.5725192742
+-0.7511236604  0.4416606752 -0.4906618946
+-0.9202834751 -0.2563206977 -0.2955977425
+-0.4146615192 -0.7663593998 -0.4906618946
+ 0.1788601062 -0.4964467542 -0.8494408059
+ 0.1713729895  0.2401260565 -0.9554950421
+-0.4687354417 -0.1305538986 -0.8736376625
+ 0.3408933659  0.2179597953  0.8503402074
+-0.0547860790  0.4008905646  0.8503402074
+-0.3868745963  0.1185023459  0.8503402074
+-0.2699126456 -0.3014331152  0.8503402074
+ 0.3408933659 -0.4008905646  0.8503402074
+ 0.7825540411 -0.3014331152  0.4284162431
+ 0.8671267092  0.1185023459  0.3476229160
+ 0.6270006527  0.4008905646  0.5770183396
+ 0.4714472644  0.7373527058  0.3476229160
+-0.1200630282  0.8785468151  0.4623206278
+-0.6520001425  0.5838213339  0.3476229160
+-0.7115733209  0.2179597953  0.5770183396
+-0.9324036585 -0.2596964552  0.2513586457
+-0.4964467542 -0.5544219364  0.5770183396
+-0.2563206977 -0.8368101551  0.3476229160
+ 0.1717480296 -0.8208260257  0.4284162431
+ 0.4254660340 -0.8368101551  0.0743010482
+ 0.7575545513 -0.5544219364  0.0743010482
+ 0.8211454788 -0.3468166421 -0.3036964718
+ 0.9324036585  0.2596964552 -0.2513586457
+ 0.5810194223  0.7373527058 -0.0743010482
+ 0.2563206977  0.8368101551 -0.3476229160
+-0.1257667992  0.9202834751 -0.1550943753
+-0.4714472644  0.7373527058 -0.3476229160
+-0.7575545513  0.5544219364 -0.0743010482
+-0.9057181469  0.1638858728 -0.1990208196
+-0.6905915802 -0.6084958589 -0.1990208196
+-0.3618751065 -0.8662095526 -0.0743010482
+ 0.1200630282 -0.8785468151 -0.4623206278
+ 0.5424279846 -0.4549644871 -0.6209447838
+ 0.3868745963 -0.1185023459 -0.8503402074
+ 0.5350381919  0.2720337177 -0.7256204361
+ 0.2313212079  0.5838213339 -0.7017381110
+-0.3408933659  0.4008905646 -0.8503402074
+-0.7439626034  0.0190448965 -0.5770183396
+-0.6270006527 -0.4008905646 -0.5770183396
+-0.2449131559 -0.4843638846 -0.7695468803
+-0.0411941310 -0.1344864753 -0.9311335345
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 5 4 
+4 0 1 6 5 
+3 1 7 6 
+3 1 8 7 
+3 1 2 8 
+3 2 9 8 
+4 2 3 10 9 
+3 3 11 10 
+3 3 4 11 
+4 4 12 19 11 
+3 4 5 12 
+3 5 13 12 
+3 5 6 13 
+3 6 14 13 
+3 6 7 14 
+3 7 15 14 
+4 7 8 16 15 
+3 8 9 16 
+3 9 17 16 
+3 9 10 17 
+3 10 18 17 
+3 10 11 18 
+3 11 19 18 
+3 12 20 19 
+3 12 13 20 
+4 13 14 21 20 
+3 14 15 21 
+3 15 22 21 
+3 15 16 22 
+3 16 17 22 
+4 17 18 23 22 
+3 18 19 23 
+3 19 20 23 
+3 20 21 23 
+3 21 22 23 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 13 14 15 4 3 
+5 15 16 17 5 4 
+5 17 18 19 6 5 
+5 19 20 8 7 6 
+5 20 21 22 9 8 
+5 22 23 24 10 9 
+5 24 25 12 11 10 
+5 12 26 27 14 13 
+5 27 28 16 15 14 
+5 28 29 18 17 16 
+5 29 30 31 19 18 
+5 31 32 21 20 19 
+5 32 33 23 22 21 
+5 33 34 25 24 23 
+5 34 35 26 12 25 
+5 35 36 28 27 26 
+5 36 37 30 29 28 
+5 37 33 32 31 30 
+5 33 34 35 36 37 
+small cubicuboctahedron
+small hexacronic icositetrahedron
+3/2 4|4
+(8.3/2.8.4)
+octahedral group
+S4
+6{8}+6{4}+8{3/2}
+17 24 48 20 24 2 0 0 -4 3 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6675992222  0.0000000000  0.7445208382
+-0.6389637427  0.1934271362  0.7445208382
+-0.0977676425  0.6604015517  0.7445208382
+-0.0977676425 -0.6604015517  0.7445208382
+ 0.9727633538  0.1934271362  0.1277395809
+ 0.5698315797  0.6604015517  0.4890416764
+ 0.5698315797 -0.6604015517  0.4890416764
+-0.7367313852 -0.4669744155  0.4890416764
+-0.8749957112  0.4669744155  0.1277395809
+-0.3337996111  0.9339488311  0.1277395809
+-0.3337996111 -0.9339488311  0.1277395809
+ 0.8749957112 -0.4669744155 -0.1277395809
+ 0.7367313852  0.4669744155 -0.4890416764
+ 0.3337996111  0.9339488311 -0.1277395809
+ 0.3337996111 -0.9339488311 -0.1277395809
+-0.9727633538 -0.1934271362 -0.1277395809
+-0.5698315797  0.6604015517 -0.4890416764
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.6389637427 -0.1934271362 -0.7445208382
+ 0.0977676425  0.6604015517 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222  0.0000000000 -0.7445208382
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.1367736397  0.9238795325  0.3574067443
+-0.1057888136  0.1226030622  0.3574067443
+-0.9339488311 -0.0000000000  0.3574067443
+ 0.1367736397 -0.1585126678  0.3574067443
+ 0.9339488311 -0.0000000000 -0.3574067443
+ 0.3173664407  0.1226030622  0.1954722392
+-0.3868542724 -0.0000000000  0.1480427208
+ 0.3302007759 -0.3826834324  0.8628562095
+ 0.0566534965  0.3826834324  0.1480427208
+-0.1677584658 -0.2959899757  0.1954722392
+-0.1367736397 -0.9238795325 -0.3574067443
+ 0.3868542724 -0.0000000000 -0.1480427208
+ 0.2553967884 -0.2959899757  0.0335377341
+-0.2553967884  0.2959899757 -0.0335377341
+-0.3302007759  0.3826834324 -0.8628562095
+-0.0566534965 -0.3826834324 -0.1480427208
+ 0.1677584658  0.2959899757 -0.1954722392
+-0.3173664407 -0.1226030622 -0.1954722392
+-0.1367736397  0.1585126678 -0.3574067443
+ 0.1057888136 -0.1226030622 -0.3574067443
+8 0 2 9 17 20 13 5 1 
+3 0 3 2 2
+8 0 4 11 18 22 17 10 3 
+4 0 1 7 4 
+8 1 6 14 20 23 21 15 7 
+3 1 5 6 2
+4 2 8 16 9 
+8 2 3 6 5 12 15 11 8 
+4 3 10 14 6 
+3 4 8 11 2
+8 4 7 12 19 23 22 16 8 
+4 5 13 19 12 
+3 7 15 12 2
+3 9 10 17 2
+8 9 16 18 21 19 13 14 10 
+4 11 15 21 18 
+3 13 20 14 2
+3 16 22 18 2
+4 17 22 23 20 
+3 19 21 23 2
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 7 11 0 
+4 4 8 7 5 
+4 10 12 4 3 
+4 6 10 9 7 
+4 0 13 14 6 
+4 8 14 13 2 
+4 2 15 7 9 
+4 7 12 10 11 
+4 11 14 16 0 
+4 4 16 14 8 
+4 15 4 12 7 
+4 14 17 10 6 
+4 0 18 2 13 
+4 2 17 14 15 
+4 10 19 14 11 
+4 4 18 0 16 
+4 19 4 15 14 
+4 18 10 17 2 
+4 10 19 4 18 
+great cubicuboctahedron
+great hexacronic icositetrahedron
+3 4|4/3
+(8/3.3.8/3.4)
+octahedral group
+S4
+6{4}+8{3}+6{8/3}
+18 24 48 20 24 4 0 0 -4 3 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9968739365  0.0000000000  0.0790085736
+ 0.4556778364  0.8866314650  0.0790085736
+-0.8508851285  0.5193766874  0.0790085736
+-0.8508851285 -0.5193766874  0.0790085736
+ 0.0427591319  0.8866314650  0.4604957132
+ 0.1459888080  0.5193766874 -0.8419828529
+ 0.1459888080 -0.5193766874 -0.8419828529
+-0.3952072921  0.3672547776 -0.8419828529
+ 0.8081259966 -0.3672547776  0.4604957132
+-0.4984369683 -0.7345095553  0.4604957132
+-0.4984369683  0.7345095553  0.4604957132
+-0.8081259966  0.3672547776 -0.4604957132
+ 0.3952072921 -0.3672547776  0.8419828529
+ 0.4984369683 -0.7345095553 -0.4604957132
+ 0.4984369683  0.7345095553 -0.4604957132
+-0.0427591319 -0.8866314650 -0.4604957132
+-0.1459888080  0.5193766874  0.8419828529
+-0.1459888080 -0.5193766874  0.8419828529
+-0.4556778364 -0.8866314650 -0.0790085736
+ 0.8508851285  0.5193766874 -0.0790085736
+ 0.8508851285 -0.5193766874 -0.0790085736
+-0.9968739365  0.0000000000 -0.0790085736
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.2596883437  0.1585126678  0.2810846377
+-0.0959283710  0.3412793093  0.2810846377
+-0.3042438195  0.0000000000  0.2810846377
+ 0.2596883437 -0.9238795325  0.2810846377
+ 0.3042438195  0.0000000000 -0.2810846377
+ 0.2877851131  0.3412793093 -0.0734203966
+ 0.7345095553 -0.0000000000 -0.6785983445
+-0.1075664339  0.3826834324 -0.1164290691
+-0.6269431213 -0.3826834324 -0.6785983445
+-0.4234483164  0.1413625185 -0.0734203966
+-0.2596883437 -0.1585126678 -0.2810846377
+-0.7345095553 -0.0000000000  0.6785983445
+-0.0397348323  0.1413625185 -0.4279254308
+ 0.0397348323 -0.1413625185  0.4279254308
+ 0.1075664339 -0.3826834324  0.1164290691
+ 0.6269431213  0.3826834324  0.6785983445
+ 0.4234483164 -0.1413625185  0.0734203966
+-0.2877851131 -0.3412793093  0.0734203966
+-0.2596883437  0.9238795325 -0.2810846377
+ 0.0959283710 -0.3412793093 -0.2810846377
+8 0 2 9 17 20 13 5 1 3
+3 0 3 2 
+8 0 4 11 18 22 17 10 3 3
+4 0 1 7 4 
+8 1 6 14 20 23 21 15 7 3
+3 1 5 6 
+4 2 8 16 9 
+8 2 3 6 5 12 15 11 8 3
+4 3 10 14 6 
+3 4 8 11 
+8 4 7 12 19 23 22 16 8 3
+4 5 13 19 12 
+3 7 15 12 
+3 9 10 17 
+8 9 16 18 21 19 13 14 10 3
+4 11 15 21 18 
+3 13 20 14 
+3 16 22 18 
+4 17 22 23 20 
+3 19 21 23 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 7 11 0 
+4 4 8 7 5 
+4 10 12 4 3 
+4 6 10 9 7 
+4 0 13 14 6 
+4 8 14 13 2 
+4 2 15 7 9 
+4 7 12 10 11 
+4 11 14 16 0 
+4 4 16 14 8 
+4 15 4 12 7 
+4 14 17 10 6 
+4 0 18 2 13 
+4 2 17 14 15 
+4 10 19 14 11 
+4 4 18 0 16 
+4 19 4 15 14 
+4 18 10 17 2 
+4 10 19 4 18 
+cubohemioctahedron
+hexahemioctacron
+4/3 4|3
+(6.4/3.6.4)
+octahedral group
+S4
+4{6}+3{4}+3{4/3}
+19 12 24 10 12 0 1 1 -2 3 4 48 4 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8660254038  0.0000000000  0.5000000000
+-0.8660254038  0.0000000000  0.5000000000
+ 0.2886751346  0.8164965809  0.5000000000
+-0.2886751346 -0.8164965809  0.5000000000
+ 0.8660254038  0.0000000000 -0.5000000000
+ 0.5773502692 -0.8164965809 -0.0000000000
+-0.5773502692  0.8164965809  0.0000000000
+-0.8660254038 -0.0000000000 -0.5000000000
+ 0.2886751346  0.8164965809 -0.5000000000
+-0.2886751346 -0.8164965809 -0.5000000000
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-0.4082482905  0.5773502692  0.7071067812
+-0.9428090416  0.3333333333  0.0000000000
+ 0.4082482905 -0.5773502692  0.7071067812
+ 0.4714045208  0.3333333333 -0.8164965809
+ 0.8164965809  0.5773502692  0.0000000000
+-0.8164965809 -0.5773502692  0.0000000000
+ 0.4714045208  0.3333333333  0.8164965809
+ 0.4082482905 -0.5773502692 -0.7071067812
+-0.4082482905  0.5773502692 -0.7071067812
+6 0 1 5 11 8 2 
+4 0 2 7 3 3
+6 0 3 9 11 10 4 
+4 0 1 6 4 
+6 1 6 10 8 7 3 
+4 1 3 9 5 3
+4 2 8 10 4 
+6 2 4 6 5 9 7 
+4 5 6 10 11 
+4 7 9 11 8 
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 1 4 5 2 
+4 6 2 3 7 
+4 5 7 8 0 
+4 8 4 3 7 
+4 9 7 1 4 
+4 9 0 6 4 
+4 9 2 5 7 
+4 8 2 6 4 
+4 8 0 9 2 
+cubitruncated cuboctahedron
+tetradyakishexahedron
+4/3 3 4|
+(8/3.6.8)
+octahedral group
+S4
+6{8}+8{6}+6{8/3}
+20 48 72 20 48 4 0 0 -4 3 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6998542122  0.0000000000  0.7142857143
+ 0.4607079005  0.5268245902  0.7142857143
+-0.6939926379 -0.0903888097  0.7142857143
+ 0.1708187941  0.5268245902  0.8326324464
+ 0.9956048929 -0.0903888097  0.0245104108
+ 0.2274231631  0.9632603706  0.1428571429
+ 0.5090227516 -0.2182178902  0.8326324464
+-0.9755922264 -0.2182178902  0.0245104108
+-0.9272773753  0.3460469708  0.1428571429
+-0.0624659433  0.9632603706  0.2612038750
+ 0.2191336452 -0.2182178902  0.9509791785
+ 0.7140053045 -0.2182178902 -0.6652648928
+ 0.7623201555  0.3460469708 -0.5469181607
+-0.0541764254  0.8354312901 -0.5469181607
+-0.4665694748  0.8728715609 -0.1428571429
+-0.0200126666  0.3086066999  0.9509791785
+ 0.3440655318 -0.8354312901  0.4285714286
+-0.8106350066  0.3989955096  0.4285714286
+-0.6798415456 -0.3086066999 -0.6652648928
+-0.8789625242 -0.3989955096  0.2612038750
+-0.3440655318  0.8354312901 -0.4285714286
+ 0.2332847374  0.8728715609 -0.4285714286
+ 0.6798415456  0.3086066999  0.6652648928
+ 0.0541764254 -0.8354312901  0.5469181607
+ 0.8789625242  0.3989955096 -0.2612038750
+ 0.0200126666 -0.3086066999 -0.9509791785
+ 0.8106350066 -0.3989955096 -0.4285714286
+-0.3499271061  0.9258200998  0.1428571429
+-0.2191336452  0.2182178902 -0.9509791785
+-0.7140053045  0.2182178902  0.6652648928
+ 0.0624659433 -0.9632603706 -0.2612038750
+-0.3499271061 -0.9258200998  0.1428571429
+-0.7623201555 -0.3460469708  0.5469181607
+ 0.3499271061  0.9258200998 -0.1428571429
+-0.5090227516  0.2182178902 -0.8326324464
+ 0.9755922264  0.2182178902 -0.0245104108
+-0.2274231631 -0.9632603706 -0.1428571429
+ 0.3499271061 -0.9258200998 -0.1428571429
+ 0.9272773753 -0.3460469708 -0.1428571429
+-0.1708187941 -0.5268245902 -0.8326324464
+-0.9956048929  0.0903888097 -0.0245104108
+-0.2332847374 -0.8728715609  0.4285714286
+-0.4607079005 -0.5268245902 -0.7142857143
+ 0.6939926379  0.0903888097 -0.7142857143
+ 0.4665694748 -0.8728715609  0.1428571429
+-0.6998542122  0.0000000000 -0.7142857143
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.0639145403  0.0290133127  0.1565580108
+-0.0852193870  0.1594308745  0.1565580108
+ 0.0639145403 -0.9855985597  0.1565580108
+ 0.1704387741  0.1594308745  0.0521860036
+ 0.9258200998 -0.0000000000 -0.3779644730
+-0.1588456165  0.0000000000  0.0648484514
+-0.9258200998 -0.0000000000  0.3779644730
+ 0.1588456165  0.0000000000 -0.0648484514
+-0.0109660014  0.1691019787 -0.0268611081
+-0.0675698741 -0.1127346525  0.1997903117
+-0.1880882870  0.1127346525 -0.0954183045
+-0.3725212402 -0.1691019787 -0.9124869568
+ 0.1880882870 -0.1127346525  0.0954183045
+ 0.0675698741  0.1127346525 -0.1997903117
+-0.0639145403  0.9855985597 -0.1565580108
+ 0.0109660014 -0.1691019787  0.0268611081
+ 0.3725212402  0.1691019787  0.9124869568
+-0.0639145403 -0.0290133127 -0.1565580108
+-0.1704387741 -0.1594308745 -0.0521860036
+ 0.0852193870 -0.1594308745 -0.1565580108
+8 0 2 7 16 23 11 4 1 3
+6 0 3 9 15 6 2 
+8 0 1 5 12 26 19 8 3 
+6 1 4 10 22 13 5 
+8 2 6 14 29 40 31 17 7 
+8 3 8 18 33 41 30 20 9 3
+8 4 11 24 37 43 35 21 10 
+8 5 13 27 36 44 39 25 12 3
+8 6 15 22 10 21 34 28 14 3
+6 7 17 32 20 30 16 
+6 8 19 29 14 28 18 
+8 9 20 32 38 27 13 22 15 
+6 11 23 36 27 38 24 
+6 12 25 34 21 35 26 
+8 16 30 41 46 47 44 36 23 
+8 17 31 42 45 37 24 38 32 3
+8 18 28 34 25 39 45 42 33 
+8 19 26 35 43 47 46 40 29 3
+6 31 40 46 41 33 42 
+6 37 45 39 44 47 43 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 0 9 4 
+3 5 10 2 
+3 1 11 5 
+3 3 8 6 
+3 6 12 0 
+3 2 13 7 
+3 7 11 3 
+3 4 10 8 
+3 8 11 1 
+3 0 14 9 
+3 9 15 4 
+3 5 16 10 
+3 10 17 2 
+3 11 9 5 
+3 8 13 6 
+3 3 8 11 
+3 12 14 0 
+3 6 15 12 
+3 13 16 7 
+3 17 13 2 
+3 7 12 11 
+3 16 8 10 
+3 4 17 10 
+3 14 5 9 
+3 15 18 4 
+3 11 15 9 
+3 5 18 16 
+3 8 13 16 
+3 17 6 13 
+3 7 14 12 
+3 6 19 15 
+3 15 12 11 
+3 16 19 7 
+3 18 17 4 
+3 14 18 5 
+3 15 16 18 
+3 17 19 6 
+3 19 14 7 
+3 19 15 16 
+3 14 17 18 
+3 17 19 14 
+great rhombicuboctahedron
+great deltoidal icositetrahedron
+3/2 4|2
+(4.3/2.4.4)
+octahedral group
+S4
+18{4}+8{3/2}
+21 24 48 26 24 5 0 0 2 2 4 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9968739365  0.0000000000  0.0790085736
+-0.8508851285  0.5193766874  0.0790085736
+ 0.4556778364  0.8866314650  0.0790085736
+-0.8508851285 -0.5193766874  0.0790085736
+ 0.1459888080  0.5193766874 -0.8419828529
+ 0.0427591319  0.8866314650  0.4604957132
+ 0.1459888080 -0.5193766874 -0.8419828529
+-0.4984369683 -0.7345095553  0.4604957132
+-0.3952072921  0.3672547776 -0.8419828529
+ 0.8081259966 -0.3672547776  0.4604957132
+-0.4984369683  0.7345095553  0.4604957132
+ 0.4984369683 -0.7345095553 -0.4604957132
+-0.8081259966  0.3672547776 -0.4604957132
+ 0.3952072921 -0.3672547776  0.8419828529
+ 0.4984369683  0.7345095553 -0.4604957132
+-0.1459888080  0.5193766874  0.8419828529
+-0.0427591319 -0.8866314650 -0.4604957132
+-0.1459888080 -0.5193766874  0.8419828529
+ 0.8508851285  0.5193766874 -0.0790085736
+-0.4556778364 -0.8866314650 -0.0790085736
+ 0.8508851285 -0.5193766874 -0.0790085736
+-0.9968739365  0.0000000000 -0.0790085736
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.2596883437  0.9238795325  0.2810846377
+-0.0959283710  0.3412793093  0.2810846377
+-0.7030040762  0.6532814824  0.2810846377
+ 0.2596883437 -0.9238795325  0.2810846377
+ 0.3357492986  0.6532814824 -0.6785983445
+ 0.2877851131  0.3412793093 -0.0734203966
+-0.6269431213 -0.3826834324 -0.6785983445
+-0.0760609549  0.2705980501  0.9596829823
+ 0.7345095553  0.0000000000 -0.6785983445
+-0.4234483164  0.1413625185 -0.0734203966
+-0.6269431213  0.3826834324 -0.6785983445
+ 0.9626924199  0.2705980501  0.0000000000
+-0.7345095553  0.0000000000  0.6785983445
+-0.0397348323  0.1413625185 -0.4279254308
+ 0.6269431213 -0.3826834324  0.6785983445
+ 0.0397348323 -0.1413625185  0.4279254308
+-0.9626924199 -0.2705980501  0.0000000000
+-0.3357492986 -0.6532814824  0.6785983445
+ 0.6269431213  0.3826834324  0.6785983445
+ 0.4234483164 -0.1413625185  0.0734203966
+ 0.0760609549 -0.2705980501 -0.9596829823
+ 0.7030040762 -0.6532814824 -0.2810846377
+-0.2596883437  0.9238795325 -0.2810846377
+-0.2877851131 -0.3412793093  0.0734203966
+-0.2596883437 -0.9238795325 -0.2810846377
+ 0.0959283710 -0.3412793093 -0.2810846377
+4 0 2 5 1 
+3 0 3 2 2
+4 0 4 9 3 
+4 0 1 7 4 
+4 1 6 13 7 
+3 1 5 6 2
+4 2 8 12 5 
+4 2 3 10 8 
+4 3 9 17 10 
+3 4 11 9 2
+4 4 7 15 11 
+4 5 12 14 6 
+4 6 14 20 13 
+3 7 13 15 2
+4 8 16 19 12 
+3 8 10 16 2
+4 9 11 18 17 
+4 10 17 22 16 
+4 11 15 21 18 
+3 12 19 14 2
+4 13 20 21 15 
+4 14 19 23 20 
+4 16 22 23 19 
+3 17 18 22 2
+4 18 21 23 22 
+3 20 23 21 2
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 11 6 0 
+4 4 12 11 5 
+4 10 13 4 3 
+4 6 14 15 7 
+4 8 16 9 2 
+4 15 17 8 7 
+4 16 18 10 9 
+4 11 19 14 6 
+4 13 20 12 4 
+4 12 21 19 11 
+4 18 20 13 10 
+4 14 22 17 15 
+4 17 23 16 8 
+4 23 24 18 16 
+4 21 22 14 19 
+4 20 25 21 12 
+4 24 25 20 18 
+4 22 24 23 17 
+4 21 22 24 25 
+small rhombihexahedron
+small rhombihexacron
+3/2 2 4|
+(8.4.8/7.4/3)
+octahedral group
+S4
+3{8}+6{4}+6{4/3}+3{8/7}
+22 24 48 18 24 0 0 1 -6 4 4 48 4 0 2
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6675992222  0.0000000000  0.7445208382
+-0.6389637427 -0.1934271362  0.7445208382
+ 0.2849157898 -0.6037480552  0.7445208382
+-0.0977676425  0.6604015517  0.7445208382
+ 0.9727633538 -0.1934271362  0.1277395809
+ 0.5698315797  0.6604015517  0.4890416764
+-0.3540479528 -0.7971751914  0.4890416764
+-0.7367313852  0.4669744155  0.4890416764
+-0.8749957112 -0.4669744155  0.1277395809
+ 0.5900799214 -0.7971751914  0.1277395809
+ 0.0488838213  0.9906023276  0.1277395809
+ 0.8749957112  0.4669744155 -0.1277395809
+ 0.7367313852 -0.4669744155 -0.4890416764
+-0.0488838213 -0.9906023276 -0.1277395809
+-0.9727633538  0.1934271362 -0.1277395809
+-0.5900799214  0.7971751914 -0.1277395809
+-0.5698315797 -0.6604015517 -0.4890416764
+ 0.3540479528  0.7971751914 -0.4890416764
+ 0.6389637427  0.1934271362 -0.7445208382
+ 0.0977676425 -0.6604015517 -0.7445208382
+-0.6675992222 -0.0000000000 -0.7445208382
+-0.2849157898  0.6037480552 -0.7445208382
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1367736397 -0.9238795325  0.3574067443
+-0.0849802448 -0.1913417162  0.3574067443
+ 0.8938887595  0.2705980501  0.3574067443
+ 0.1367736397  0.1585126678  0.3574067443
+-0.4269143440  0.2705980501  0.8628562095
+ 0.3018740276 -0.1913417162  0.2093640235
+-0.3868542724 -0.0000000000  0.1480427208
+-0.8938887595 -0.2705980501 -0.3574067443
+-0.1651003879  0.3498543840  0.1480427208
+-0.1367736397  0.9238795325 -0.3574067443
+ 0.4269143440 -0.2705980501 -0.8628562095
+ 0.3868542724 -0.0000000000 -0.1480427208
+ 0.2217538845  0.3498543840 -0.0000000000
+-0.2217538845 -0.3498543840 -0.0000000000
+ 0.1651003879 -0.3498543840 -0.1480427208
+-0.3018740276  0.1913417162 -0.2093640235
+-0.1367736397 -0.1585126678 -0.3574067443
+ 0.0849802448  0.1913417162 -0.3574067443
+8 0 2 9 17 20 13 5 1 
+4 0 3 7 2 
+8 0 4 11 18 19 13 10 3 7
+4 0 1 6 4 3
+8 1 3 7 9 15 16 11 6 7
+4 1 5 10 3 
+4 2 8 15 9 3
+8 2 7 14 20 23 22 16 8 7
+4 4 8 16 11 
+8 4 6 12 19 23 21 15 8 
+8 5 12 18 22 21 17 14 10 7
+4 5 13 19 12 3
+4 6 11 18 12 
+4 7 9 17 14 3
+4 10 13 20 14 
+4 15 21 22 16 
+4 17 21 23 20 3
+4 18 22 23 19 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 4 5 2 
+4 2 8 9 3 
+4 5 10 11 0 
+4 9 12 4 3 
+4 7 13 4 1 
+4 6 9 8 7 
+4 0 13 4 6 
+4 10 14 2 5 
+4 2 12 4 8 
+4 10 12 9 11 
+4 11 2 14 0 
+4 7 14 10 13 
+4 4 15 9 6 
+4 15 7 8 4 
+4 0 16 10 13 
+4 2 17 10 12 
+4 9 17 2 11 
+4 7 16 0 14 
+4 15 10 16 9 
+4 17 7 15 10 
+4 9 17 7 16 
+stellated truncated hexahedron
+great triakisoctahedron
+2 3|4/3
+(8/3.8/3.3)
+octahedral group
+S4
+8{3}+6{8/3}
+23 24 36 14 24 7 0 0 2 2 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8722604191  0.0000000000 -0.4890416764
+-0.1277395809  0.8628562095 -0.4890416764
+-0.8348463621 -0.2527247326 -0.4890416764
+-0.4890416764  0.8628562095  0.1277395809
+-0.7819348952 -0.6101314769  0.1277395809
+ 0.9251718860 -0.3574067443  0.1277395809
+ 0.2180651048  0.9675382212  0.1277395809
+-0.2709765716 -0.6101314769 -0.7445208382
+ 0.5638697904 -0.3574067443  0.7445208382
+ 0.2709765716  0.6101314769  0.7445208382
+-0.4361302096  0.5054494651  0.7445208382
+-0.4361302096 -0.5054494651  0.7445208382
+ 0.4361302096 -0.5054494651 -0.7445208382
+ 0.7819348952  0.6101314769 -0.1277395809
+ 0.4361302096  0.5054494651 -0.7445208382
+-0.5638697904  0.3574067443 -0.7445208382
+ 0.4890416764 -0.8628562095 -0.1277395809
+-0.2180651048 -0.9675382212 -0.1277395809
+-0.9251718860  0.3574067443 -0.1277395809
+ 0.1277395809 -0.8628562095  0.4890416764
+-0.8722604191 -0.0000000000  0.4890416764
+ 0.8348463621  0.2527247326  0.4890416764
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1459106924  0.1691019787  0.0854725047
+-0.1886469447  0.1195731559  0.0854725047
+ 0.1459106924 -0.9855985597  0.0854725047
+-0.0177019353  0.1195731559 -0.2063488801
+ 0.0604381877 -0.4082482905 -0.9108680249
+-0.7649573325 -0.4082482905  0.4981702648
+ 0.0177019353 -0.1195731559  0.2063488801
+ 0.8504298372 -0.1691019787  0.4981702648
+ 0.1886469447 -0.1195731559 -0.0854725047
+ 0.7649573325  0.4082482905 -0.4981702648
+-0.8504298372  0.1691019787 -0.4981702648
+-0.1459106924 -0.1691019787 -0.0854725047
+-0.0604381877  0.4082482905  0.9108680249
+-0.1459106924  0.9855985597 -0.0854725047
+8 0 2 6 11 15 9 4 1 3
+8 0 3 7 12 16 10 5 2 3
+3 0 1 3 
+8 1 4 8 14 19 13 7 3 3
+3 2 5 6 
+3 4 9 8 
+8 5 10 17 21 22 18 11 6 3
+3 7 13 12 
+8 8 9 15 18 22 23 20 14 3
+3 10 16 17 
+3 11 18 15 
+8 12 13 19 20 23 21 17 16 3
+3 14 20 19 
+3 21 23 22 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 8 5 
+3 8 0 5 
+3 6 9 1 
+3 0 10 6 
+3 1 11 7 
+3 11 3 7 
+3 3 12 8 
+3 8 10 0 
+3 9 11 1 
+3 6 11 9 
+3 8 6 10 
+3 11 12 3 
+3 11 8 12 
+3 6 13 11 
+3 8 13 6 
+3 11 8 13 
+great truncated cuboctahedron
+great disdyakisdodecahedron
+4/3 2 3|
+(8/3.4.6)
+octahedral group
+S4
+8{6}+12{4}+6{8/3}
+24 48 72 26 48 1 0 0 2 3 3 48 4 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8305094692  0.0000000000  0.5570045077
+ 0.5180497550  0.6491305182  0.5570045077
+-0.7696968212  0.3119499667  0.5570045077
+ 0.1740414692  0.6491305182  0.7404992487
+ 0.8913221171  0.3119499667 -0.3289864768
+-0.2516470662  0.9610804849  0.1140090155
+ 0.6159262346 -0.2688786644  0.7404992487
+-0.7088841733  0.6238999334 -0.3289864768
+ 0.2348541172  0.9610804849 -0.1454917358
+ 0.2719179488 -0.2688786644  0.9239939897
+ 0.1216252958  0.6238999334 -0.7719819690
+-0.9234674078  0.3550212690 -0.1454917358
+-0.0405417653  0.3802518538  0.9239939897
+-0.0558941070 -0.8749378802  0.4809984974
+-0.2768364897  0.8318665779  0.4809984974
+ 0.3935432447  0.3550212690 -0.8479879793
+ 0.7899677039  0.3802518538  0.4809984974
+ 0.4306070763 -0.8749378802  0.2214977461
+ 0.5536729794  0.8318665779  0.0380030052
+-0.4914197242  0.5629879135  0.6644932384
+-0.8255909283 -0.5629879135  0.0380030052
+-0.7123621069 -0.2258073621  0.6644932384
+-0.9486568314  0.2258073621  0.2214977461
+ 0.8255909283  0.5629879135 -0.0380030052
+ 0.4914197242 -0.5629879135 -0.6644932384
+ 0.9486568314 -0.2258073621 -0.2214977461
+ 0.7123621069  0.2258073621 -0.6644932384
+-0.3935432447 -0.3550212690  0.8479879793
+-0.4306070763  0.8749378802 -0.2214977461
+-0.5536729794 -0.8318665779 -0.0380030052
+-0.7899677039 -0.3802518538 -0.4809984974
+ 0.9234674078 -0.3550212690  0.1454917358
+ 0.0558941070  0.8749378802 -0.4809984974
+ 0.2768364897 -0.8318665779 -0.4809984974
+ 0.0405417653 -0.3802518538 -0.9239939897
+-0.2348541172 -0.9610804849  0.1454917358
+-0.2719179488  0.2688786644 -0.9239939897
+-0.1216252958 -0.6238999334  0.7719819690
+ 0.2516470662 -0.9610804849 -0.1140090155
+-0.6159262346  0.2688786644 -0.7404992487
+ 0.7088841733 -0.6238999334  0.3289864768
+-0.8913221171 -0.3119499667  0.3289864768
+-0.1740414692 -0.6491305182 -0.7404992487
+ 0.7696968212 -0.3119499667 -0.5570045077
+-0.5180497550 -0.6491305182 -0.5570045077
+-0.8305094692  0.0000000000 -0.5570045077
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.1801043973  0.0866934567  0.3376522109
+-0.0762733399  0.2913001116  0.3376522109
+ 0.1801043973  0.9238795325  0.3376522109
+ 0.3229079525  0.2913001116  0.1247280725
+-0.4554111647  0.1275611441  0.8810952421
+-0.2736567697  0.2705980501  0.0764920424
+ 0.9854240134  0.1275611441  0.1125507370
+ 0.2159554198  0.2705980501 -0.1846681261
+-0.0292293734 -0.1499375931  0.4258482767
+-0.0470439665  0.4412377047 -0.0881960659
+ 0.3699519190 -0.1499375931  0.2129241384
+-0.3991812924  0.0000000000  0.2129241384
+ 0.3499084514 -0.6687572443  0.6559937682
+-0.2159554198 -0.2705980501  0.1846681261
+-0.3499084514  0.6687572443 -0.6559937682
+ 0.3991812924  0.0000000000 -0.2129241384
+ 0.2736567697 -0.2705980501 -0.0764920424
+-0.9854240134 -0.1275611441 -0.1125507370
+-0.3699519190  0.1499375931 -0.2129241384
+ 0.4554111647 -0.1275611441 -0.8810952421
+ 0.0292293734  0.1499375931 -0.4258482767
+ 0.0470439665 -0.4412377047  0.0881960659
+-0.1801043973 -0.0866934567 -0.3376522109
+-0.3229079525 -0.2913001116 -0.1247280725
+-0.1801043973 -0.9238795325 -0.3376522109
+ 0.0762733399 -0.2913001116 -0.3376522109
+8 0 2 7 13 17 10 4 1 3
+4 0 3 6 2 
+6 0 1 5 11 8 3 
+4 1 4 9 5 
+6 2 6 12 21 14 7 
+8 3 8 15 23 29 20 12 6 3
+6 4 10 18 25 16 9 
+8 5 9 16 24 33 27 19 11 3
+4 7 14 22 13 
+4 8 11 19 15 
+4 10 17 26 18 
+4 12 20 28 21 
+6 13 22 30 34 26 17 
+8 14 21 28 36 42 38 30 22 3
+6 15 19 27 35 31 23 
+4 16 25 32 24 
+8 18 26 34 41 44 39 32 25 3
+6 20 29 37 43 36 28 
+4 23 31 37 29 
+6 24 32 39 45 40 33 
+4 27 33 40 35 
+4 30 38 41 34 
+8 31 35 40 45 47 46 43 37 3
+4 36 43 46 42 
+6 38 42 46 47 44 41 
+4 39 44 47 45 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 5 1 
+3 0 8 4 
+3 5 9 2 
+3 7 6 3 
+3 6 10 0 
+3 9 7 2 
+3 4 11 5 
+3 0 12 8 
+3 8 13 4 
+3 5 14 9 
+3 7 15 6 
+3 10 12 0 
+3 6 16 10 
+3 14 7 9 
+3 11 17 5 
+3 13 11 4 
+3 12 13 8 
+3 5 18 14 
+3 7 19 15 
+3 15 16 6 
+3 16 12 10 
+3 14 20 7 
+3 13 17 11 
+3 17 18 5 
+3 12 21 13 
+3 18 22 14 
+3 19 16 15 
+3 20 19 7 
+3 16 21 12 
+3 22 20 14 
+3 13 23 17 
+3 17 22 18 
+3 21 24 13 
+3 19 25 16 
+3 22 19 20 
+3 16 24 21 
+3 24 23 13 
+3 23 22 17 
+3 25 24 16 
+3 22 25 19 
+3 24 22 23 
+3 25 24 22 
+great rhombihexahedron
+great rhombihexacron
+4/3 3/2 2|
+(4.8/3.4/3.8/5)
+octahedral group
+S4
+6{4}+3{8/3}+3{8/5}+6{4/3}
+25 24 48 18 24 0 0 1 -6 4 4 48 4 0 1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9968739365  0.0000000000  0.0790085736
+-0.8508851285 -0.5193766874  0.0790085736
+ 0.0729944040 -0.9941978990  0.0790085736
+ 0.4556778364  0.8866314650  0.0790085736
+ 0.1459888080 -0.5193766874 -0.8419828529
+ 0.0427591319  0.8866314650  0.4604957132
+ 0.4254425643 -0.7790650311  0.4604957132
+-0.3952072921  0.3672547776 -0.8419828529
+ 0.5286722404 -0.1075664339 -0.8419828529
+-0.8811204006 -0.1075664339  0.4604957132
+ 0.8081259966 -0.3672547776  0.4604957132
+-0.8081259966  0.3672547776 -0.4604957132
+ 0.3952072921 -0.3672547776  0.8419828529
+ 0.8811204006  0.1075664339 -0.4604957132
+-0.5286722404  0.1075664339  0.8419828529
+-0.0427591319 -0.8866314650 -0.4604957132
+-0.4254425643  0.7790650311 -0.4604957132
+-0.1459888080  0.5193766874  0.8419828529
+-0.4556778364 -0.8866314650 -0.0790085736
+ 0.8508851285  0.5193766874 -0.0790085736
+-0.0729944040  0.9941978990 -0.0790085736
+-0.9968739365  0.0000000000 -0.0790085736
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.2596883437 -0.9238795325  0.2810846377
+-0.1390719130 -0.2705980501  0.2810846377
+ 0.9404146820 -0.1913417162  0.2810846377
+ 0.2596883437  0.1585126678  0.2810846377
+ 0.2059051267 -0.1913417162  0.9596829823
+ 0.2911938228 -0.2705980501 -0.1164290691
+-0.2596883437 -0.1585126678 -0.2810846377
+ 0.0537832170 -0.7325378163 -0.6785983445
+ 0.1390719130  0.2705980501 -0.2810846377
+ 0.7345095553 -0.0000000000 -0.6785983445
+-0.6807263383 -0.7325378163 -0.0000000000
+-0.7345095553 -0.0000000000  0.6785983445
+-0.2911938228  0.2705980501  0.1164290691
+ 0.6807263383  0.7325378163 -0.0000000000
+-0.0537832170  0.7325378163  0.6785983445
+-0.2059051267  0.1913417162 -0.9596829823
+-0.9404146820  0.1913417162 -0.2810846377
+-0.2596883437  0.9238795325 -0.2810846377
+4 0 2 5 1 
+8 0 3 10 13 19 15 7 2 3
+4 0 4 9 3 3
+8 0 1 6 13 20 18 11 4 5
+4 1 3 10 6 3
+8 1 5 7 14 16 11 9 3 3
+8 2 8 16 22 23 19 12 5 5
+4 2 7 14 8 3
+8 4 8 14 21 23 20 17 9 3
+4 4 11 16 8 
+4 5 12 15 7 3
+4 6 12 19 13 
+8 6 10 17 18 22 21 15 12 3
+4 9 17 18 11 
+4 10 17 20 13 3
+4 14 16 22 21 
+4 15 19 23 21 3
+4 18 20 23 22 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 4 5 2 
+4 2 8 9 3 
+4 5 10 6 0 
+4 3 11 12 4 
+4 7 5 10 1 
+4 6 9 8 7 
+4 5 13 8 2 
+4 1 14 12 4 
+4 9 5 13 3 
+4 10 12 11 6 
+4 3 14 1 11 
+4 8 15 5 7 
+4 12 16 1 10 
+4 6 15 5 9 
+4 13 12 14 8 
+4 12 17 3 13 
+4 16 6 11 1 
+4 17 8 14 3 
+4 8 16 12 15 
+4 6 17 12 15 
+4 16 6 17 8 
+icosahedron
+dodecahedron
+5|2 3
+(3.3.3.3.3)
+icosahedral group
+A5
+20{3}
+26 12 30 20 12 1 0 0 2 1 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000  0.4472135955
+ 0.2763932023  0.8506508084  0.4472135955
+-0.7236067977  0.5257311121  0.4472135955
+-0.7236067977 -0.5257311121  0.4472135955
+ 0.2763932023 -0.8506508084  0.4472135955
+ 0.7236067977  0.5257311121 -0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.2763932023  0.8506508084 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.4911234732  0.3568220898  0.7946544723
+-0.1875924741  0.5773502692  0.7946544723
+-0.6070619982 -0.0000000000  0.7946544723
+-0.1875924741 -0.5773502692  0.7946544723
+ 0.4911234732 -0.3568220898  0.7946544723
+ 0.7946544723 -0.5773502692  0.1875924741
+ 0.9822469464  0.0000000000 -0.1875924741
+ 0.7946544723  0.5773502692  0.1875924741
+ 0.3035309991  0.9341723590 -0.1875924741
+-0.3035309991  0.9341723590  0.1875924741
+-0.7946544723  0.5773502692 -0.1875924741
+-0.9822469464 -0.0000000000  0.1875924741
+-0.7946544723 -0.5773502692 -0.1875924741
+-0.3035309991 -0.9341723590  0.1875924741
+ 0.3035309991 -0.9341723590 -0.1875924741
+ 0.6070619982  0.0000000000 -0.7946544723
+ 0.1875924741  0.5773502692 -0.7946544723
+ 0.1875924741 -0.5773502692 -0.7946544723
+-0.4911234732  0.3568220898 -0.7946544723
+-0.4911234732 -0.3568220898 -0.7946544723
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 5 4 
+3 0 1 5 
+3 1 7 5 
+3 1 6 7 
+3 1 2 6 
+3 2 8 6 
+3 2 3 8 
+3 3 9 8 
+3 3 4 9 
+3 4 10 9 
+3 4 5 10 
+3 5 7 10 
+3 6 11 7 
+3 6 8 11 
+3 7 11 10 
+3 8 9 11 
+3 9 10 11 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 13 14 5 4 3 
+5 6 15 16 8 7 
+5 14 17 15 6 5 
+5 16 18 10 9 8 
+5 18 19 12 11 10 
+5 19 17 14 13 12 
+5 15 16 18 19 17 
+dodecahedron
+icosahedron
+3|2 5
+(5.5.5)
+icosahedral group
+A5
+12{5}
+27 20 30 12 20 1 0 0 2 1 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6666666667  0.0000000000  0.7453559925
+-0.3333333333  0.5773502692  0.7453559925
+-0.3333333333 -0.5773502692  0.7453559925
+ 0.7453559925  0.5773502692  0.3333333333
+ 0.7453559925 -0.5773502692  0.3333333333
+-0.8726779962  0.3568220898  0.3333333333
+ 0.1273220038  0.9341723590  0.3333333333
+ 0.1273220038 -0.9341723590  0.3333333333
+-0.8726779962 -0.3568220898  0.3333333333
+ 0.8726779962  0.3568220898 -0.3333333333
+ 0.8726779962 -0.3568220898 -0.3333333333
+-0.7453559925  0.5773502692 -0.3333333333
+-0.1273220038  0.9341723590 -0.3333333333
+-0.1273220038 -0.9341723590 -0.3333333333
+-0.7453559925 -0.5773502692 -0.3333333333
+ 0.3333333333  0.5773502692 -0.7453559925
+ 0.3333333333 -0.5773502692 -0.7453559925
+-0.6666666667  0.0000000000 -0.7453559925
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.3035309991  0.5257311121  0.7946544723
+-0.6070619982  0.0000000000  0.7946544723
+ 0.3035309991 -0.5257311121  0.7946544723
+ 0.9822469464  0.0000000000  0.1875924741
+-0.4911234732  0.8506508084  0.1875924741
+-0.4911234732 -0.8506508084  0.1875924741
+ 0.4911234732  0.8506508084 -0.1875924741
+ 0.4911234732 -0.8506508084 -0.1875924741
+-0.9822469464 -0.0000000000 -0.1875924741
+ 0.6070619982  0.0000000000 -0.7946544723
+-0.3035309991  0.5257311121 -0.7946544723
+-0.3035309991 -0.5257311121 -0.7946544723
+5 0 2 7 4 1 
+5 0 3 9 6 2 
+5 0 1 5 8 3 
+5 1 4 10 11 5 
+5 2 6 12 13 7 
+5 3 8 14 15 9 
+5 4 7 13 16 10 
+5 5 11 17 14 8 
+5 6 9 15 18 12 
+5 10 16 19 17 11 
+5 12 18 19 16 13 
+5 14 17 19 18 15 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 6 4 0 
+3 5 7 2 
+3 8 5 1 
+3 3 9 6 
+3 7 9 3 
+3 4 10 8 
+3 6 10 4 
+3 5 11 7 
+3 8 11 5 
+3 9 10 6 
+3 11 9 7 
+3 10 11 8 
+3 9 10 11 
+icosidodecahedron
+rhombic triacontahedron
+2|3 5
+(3.5.3.5)
+icosahedral group
+A5
+12{5}+20{3}
+28 30 60 32 30 1 0 0 2 2 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5877852523  0.0000000000  0.8090169944
+ 0.2628655561  0.5257311121  0.8090169944
+-0.5877852523 -0.0000000000  0.8090169944
+-0.2628655561 -0.5257311121  0.8090169944
+ 0.9510565163  0.0000000000  0.3090169944
+ 0.6881909602 -0.5257311121  0.5000000000
+-0.1624598481  0.8506508084  0.5000000000
+ 0.4253254042  0.8506508084  0.3090169944
+-0.9510565163 -0.0000000000  0.3090169944
+-0.6881909602  0.5257311121  0.5000000000
+ 0.1624598481 -0.8506508084  0.5000000000
+-0.4253254042 -0.8506508084  0.3090169944
+ 0.9510565163 -0.0000000000 -0.3090169944
+ 0.8506508084  0.5257311121  0.0000000000
+ 0.5257311121 -0.8506508084  0.0000000000
+-0.5257311121  0.8506508084  0.0000000000
+ 0.4253254042  0.8506508084 -0.3090169944
+-0.9510565163 -0.0000000000 -0.3090169944
+-0.8506508084 -0.5257311121  0.0000000000
+-0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602  0.5257311121 -0.5000000000
+-0.1624598481  0.8506508084 -0.5000000000
+ 0.2628655561  0.5257311121 -0.8090169944
+-0.5877852523 -0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.2763932023  0.1708203932  0.8506508084
+-0.2763932023  0.4472135955  0.8506508084
+-0.2763932023 -0.1708203932  0.8506508084
+ 0.2763932023 -0.4472135955  0.8506508084
+ 0.7236067977 -0.1708203932  0.5257311121
+ 0.7236067977  0.4472135955  0.5257311121
+ 0.1708203932  0.7236067977  0.5257311121
+-0.7236067977  0.1708203932  0.5257311121
+-0.7236067977 -0.4472135955  0.5257311121
+-0.1708203932 -0.7236067977  0.5257311121
+ 0.8944271910 -0.4472135955  0.0000000000
+ 0.8944271910  0.1708203932  0.0000000000
+ 0.4472135955 -0.7236067977  0.3249196962
+ 0.0000000000  1.0000000000  0.0000000000
+-0.4472135955  0.7236067977  0.3249196962
+ 0.5527864045  0.7236067977 -0.0000000000
+-0.8944271910  0.4472135955 -0.0000000000
+-0.8944271910 -0.1708203932  0.0000000000
+-0.0000000000 -1.0000000000  0.0000000000
+-0.5527864045 -0.7236067977 -0.0000000000
+ 0.7236067977 -0.1708203932 -0.5257311121
+ 0.7236067977  0.4472135955 -0.5257311121
+ 0.4472135955 -0.7236067977 -0.3249196962
+-0.4472135955  0.7236067977 -0.3249196962
+ 0.1708203932  0.7236067977 -0.5257311121
+-0.7236067977  0.1708203932 -0.5257311121
+-0.7236067977 -0.4472135955 -0.5257311121
+-0.1708203932 -0.7236067977 -0.5257311121
+ 0.2763932023 -0.4472135955 -0.8506508084
+ 0.2763932023  0.1708203932 -0.8506508084
+-0.2763932023  0.4472135955 -0.8506508084
+-0.2763932023 -0.1708203932 -0.8506508084
+3 0 2 1 
+5 0 3 10 7 2 
+3 0 4 3 
+5 0 1 6 11 4 
+3 1 5 6 
+5 1 2 8 14 5 
+3 2 7 8 
+3 3 9 10 
+5 3 4 12 19 9 
+3 4 11 12 
+5 5 13 22 15 6 
+3 5 14 13 
+3 6 15 11 
+5 7 16 25 17 8 
+3 7 10 16 
+3 8 17 14 
+5 9 18 24 16 10 
+3 9 19 18 
+5 11 15 23 20 12 
+3 12 20 19 
+3 13 21 22 
+5 13 14 17 26 21 
+3 15 22 23 
+3 16 24 25 
+3 17 25 26 
+3 18 27 24 
+5 18 19 20 28 27 
+3 20 23 28 
+5 21 29 28 23 22 
+3 21 26 29 
+5 24 27 29 26 25 
+3 27 28 29 
+4 3 0 1 2 
+4 3 4 5 0 
+4 5 6 1 0 
+4 1 7 8 2 
+4 8 9 3 2 
+4 4 10 11 5 
+4 3 12 10 4 
+4 6 13 14 1 
+4 5 15 13 6 
+4 7 16 17 8 
+4 14 16 7 1 
+4 9 18 12 3 
+4 8 19 18 9 
+4 10 20 21 11 
+4 21 15 5 11 
+4 18 22 10 12 
+4 13 23 16 14 
+4 21 24 13 15 
+4 16 25 26 17 
+4 26 19 8 17 
+4 26 27 18 19 
+4 20 28 29 21 
+4 22 28 20 10 
+4 27 28 22 18 
+4 23 30 25 16 
+4 24 30 23 13 
+4 29 30 24 21 
+4 30 31 26 25 
+4 31 28 27 26 
+4 28 29 30 31 
+truncated icosahedron
+pentakisdodecahedron
+2 5|3
+(6.6.5)
+icosahedral group
+A5
+20{6}+12{5}
+29 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.3952480672  0.0000000000  0.9185744202
+-0.2227859215  0.3264773618  0.9185744202
+-0.1440965957 -0.3680451137  0.9185744202
+ 0.5677102129  0.3264773618  0.7557232605
+ 0.4954282110 -0.3680451137  0.7868250644
+-0.5896684388  0.2849096099  0.7557232605
+-0.0503237759  0.6529547237  0.7557232605
+ 0.1620948777 -0.5955095034  0.7868250644
+-0.5109791130 -0.4096128656  0.7557232605
+ 0.8403525023  0.2849096099  0.4611227451
+ 0.3449242913  0.6529547237  0.6742976806
+ 0.7680705005 -0.4096128656  0.4922245490
+-0.6439521587  0.5856966883  0.4922245490
+-0.7337650345 -0.0831355038  0.6742976806
+-0.3106188254  0.8131610779  0.4922245490
+ 0.1014038338 -0.8645416449  0.4922245490
+-0.5716701569 -0.6786450072  0.4611227451
+ 0.7860687824  0.5856966883  0.1976240336
+ 0.9405326461 -0.0831355038  0.3293733893
+ 0.4798773090  0.8131610779  0.3293733893
+ 0.7073794566 -0.6786450072  0.1976240336
+-0.8423324743  0.5184386529  0.1473002577
+-0.9321453501 -0.1503935392  0.3293733893
+-0.1756658076  0.9733674322  0.1473002577
+ 0.3740461233 -0.9061093968  0.1976240336
+-0.2654786835 -0.9061093968  0.3293733893
+-0.8319652063 -0.5184386529  0.1976240336
+ 0.8319652063  0.5184386529 -0.1976240336
+ 0.9864290700 -0.1503935392 -0.0658746779
+ 0.2195822596  0.9733674322  0.0658746779
+ 0.8423324743 -0.5184386529 -0.1473002577
+-0.7073794566  0.6786450072 -0.1976240336
+-0.9864290700  0.1503935392  0.0658746779
+-0.3740461233  0.9061093968 -0.1976240336
+ 0.1756658076 -0.9733674322 -0.1473002577
+-0.2195822596 -0.9733674322 -0.0658746779
+-0.7860687824 -0.5856966883 -0.1976240336
+ 0.5716701569  0.6786450072 -0.4611227451
+ 0.9321453501  0.1503935392 -0.3293733893
+ 0.2654786835  0.9061093968 -0.3293733893
+ 0.6439521587 -0.5856966883 -0.4922245490
+-0.7680705005  0.4096128656 -0.4922245490
+-0.9405326461  0.0831355038 -0.3293733893
+-0.1014038338  0.8645416449 -0.4922245490
+ 0.3106188254 -0.8131610779 -0.4922245490
+-0.4798773090 -0.8131610779 -0.3293733893
+-0.8403525023 -0.2849096099 -0.4611227451
+ 0.5109791130  0.4096128656 -0.7557232605
+ 0.7337650345  0.0831355038 -0.6742976806
+ 0.5896684388 -0.2849096099 -0.7557232605
+-0.4954282110  0.3680451137 -0.7868250644
+-0.1620948777  0.5955095034 -0.7868250644
+ 0.0503237759 -0.6529547237 -0.7557232605
+-0.3449242913 -0.6529547237 -0.6742976806
+-0.5677102129 -0.3264773618 -0.7557232605
+ 0.1440965957  0.3680451137 -0.9185744202
+ 0.2227859215 -0.3264773618 -0.9185744202
+-0.3952480672 -0.0000000000 -0.9185744202
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1884917927  0.3568220898  0.9149583817
+-0.4009827382 -0.0454313035  0.9149583817
+ 0.1884917927 -0.2762216876  0.9149583817
+ 0.7299680182 -0.0454313035  0.6819697127
+-0.3769835855  0.5524433752  0.7082839194
+-0.2238218084 -0.6962909658  0.6819697127
+ 0.6262353286  0.5524433752  0.5016094570
+ 0.4751441987 -0.6962909658  0.5379747963
+-0.8612946448  0.2378813932  0.4489810437
+ 0.0924951818  0.8887410555  0.4489810437
+-0.7427296631 -0.3817289838  0.5016094570
+ 0.9686221187  0.2378813932  0.0719974582
+ 0.8805126380 -0.3817289838  0.1672031523
+-0.5563085176  0.8152316624  0.1609912108
+ 0.0344457437 -0.9590792530  0.1672031523
+-0.5746422389 -0.8152316624  0.0719974582
+ 0.5746422389  0.8152316624 -0.0719974582
+ 0.5563085176 -0.8152316624 -0.1609912108
+-0.8805126380  0.3817289838 -0.1672031523
+-0.9686221187 -0.2378813932 -0.0719974582
+-0.0344457437  0.9590792530 -0.1672031523
+ 0.7427296631  0.3817289838 -0.5016094570
+ 0.8612946448 -0.2378813932 -0.4489810437
+-0.4751441987  0.6962909658 -0.5379747963
+-0.0924951818 -0.8887410555 -0.4489810437
+-0.6262353286 -0.5524433752 -0.5016094570
+ 0.2238218084  0.6962909658 -0.6819697127
+ 0.3769835855 -0.5524433752 -0.7082839194
+-0.7299680182  0.0454313035 -0.6819697127
+ 0.4009827382  0.0454313035 -0.9149583817
+-0.1884917927  0.2762216876 -0.9149583817
+-0.1884917927 -0.3568220898 -0.9149583817
+6 0 2 7 11 4 1 
+6 0 3 9 14 6 2 
+5 0 1 5 8 3 
+6 1 4 10 19 12 5 
+5 2 6 13 15 7 
+6 3 8 16 26 17 9 
+5 4 11 20 18 10 
+6 5 12 21 25 16 8 
+6 6 14 23 33 22 13 
+6 7 15 24 30 20 11 
+5 9 17 27 23 14 
+6 10 18 28 39 29 19 
+5 12 19 29 31 21 
+6 13 22 32 34 24 15 
+5 16 25 35 36 26 
+6 17 26 36 46 37 27 
+6 18 20 30 40 38 28 
+6 21 31 41 45 35 25 
+5 22 33 43 42 32 
+6 23 27 37 47 43 33 
+5 24 34 44 40 30 
+5 28 38 48 49 39 
+6 29 39 49 50 41 31 
+6 32 42 51 52 44 34 
+6 35 45 53 54 46 36 
+5 37 46 54 55 47 
+6 38 40 44 52 56 48 
+5 41 50 57 53 45 
+6 42 43 47 55 58 51 
+6 48 56 59 57 50 49 
+5 51 58 59 56 52 
+6 53 57 59 58 55 54 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 0 9 4 
+3 5 7 2 
+3 1 10 5 
+3 3 11 6 
+3 6 9 0 
+3 7 12 3 
+3 4 13 8 
+3 8 10 1 
+3 9 13 4 
+3 5 14 7 
+3 10 15 5 
+3 11 16 6 
+3 12 11 3 
+3 16 9 6 
+3 7 17 12 
+3 13 18 8 
+3 8 19 10 
+3 9 20 13 
+3 14 17 7 
+3 15 14 5 
+3 19 15 10 
+3 11 21 16 
+3 12 22 11 
+3 16 20 9 
+3 17 22 12 
+3 13 23 18 
+3 18 19 8 
+3 20 23 13 
+3 14 24 17 
+3 15 24 14 
+3 19 25 15 
+3 21 26 16 
+3 22 21 11 
+3 26 20 16 
+3 17 27 22 
+3 23 28 18 
+3 28 19 18 
+3 26 23 20 
+3 24 27 17 
+3 25 24 15 
+3 28 25 19 
+3 21 29 26 
+3 22 29 21 
+3 27 29 22 
+3 23 30 28 
+3 26 30 23 
+3 24 31 27 
+3 25 31 24 
+3 28 31 25 
+3 29 30 26 
+3 31 29 27 
+3 30 31 28 
+3 29 30 31 
+truncated dodecahedron
+triakisicosahedron
+2 3|5
+(10.10.3)
+icosahedral group
+A5
+12{10}+20{3}
+30 60 90 32 60 1 0 0 2 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.3319544852  0.0000000000  0.9432954043
+-0.2860795036  0.1683814059  0.9432954043
+ 0.1611340919 -0.2902233358  0.9432954043
+ 0.5829886213  0.1683814059  0.7948408455
+-0.5878317720  0.1506049079  0.7948408455
+-0.4170113787  0.4408282437  0.7948408455
+ 0.1357750258 -0.5914331516  0.7948408455
+ 0.8183499926  0.1506049079  0.5546363234
+ 0.6572159007  0.4408282437  0.6113409191
+-0.7899976948 -0.0465394760  0.6113409191
+-0.3427840993  0.7132750815  0.6113409191
+-0.0663908970 -0.7885775354  0.6113409191
+ 0.2655635881 -0.7885775354  0.5546363234
+ 0.9481385550 -0.0465394760  0.3144318014
+ 0.5262840256  0.7132750815  0.4628863603
+-0.8153567609 -0.3477492917  0.4628863603
+-0.9462886360 -0.0753024539  0.3144318014
+-0.3935022315  0.8638799894  0.3144318014
+-0.0917499632  0.8816564874  0.4628863603
+-0.3681431654 -0.8063540334  0.4628863603
+ 0.5009249595 -0.8063540334  0.3144318014
+ 0.9227794888 -0.3477492917  0.1659772426
+ 0.9970067683 -0.0753024539 -0.0175226837
+ 0.4755658933  0.8638799894  0.1659772426
+ 0.2402045220  0.8816564874  0.4061817646
+-0.6542226690 -0.6379726275  0.4061817646
+-0.9970067683  0.0753024539  0.0175226837
+-0.5497931728  0.8351170114  0.0175226837
+-0.5244341067 -0.8351170114  0.1659772426
+ 0.5497931728 -0.8351170114 -0.0175226837
+ 0.7519590956 -0.6379726275  0.1659772426
+ 0.9462886360  0.0753024539 -0.3144318014
+ 0.5244341067  0.8351170114 -0.1659772426
+-0.9481385550  0.0465394760 -0.3144318014
+-0.9227794888  0.3477492917 -0.1659772426
+-0.7519590956  0.6379726275 -0.1659772426
+-0.5009249595  0.8063540334 -0.3144318014
+-0.4755658933 -0.8638799894 -0.1659772426
+ 0.3935022315 -0.8638799894 -0.3144318014
+ 0.7899976948  0.0465394760 -0.6113409191
+ 0.8153567609  0.3477492917 -0.4628863603
+ 0.6542226690  0.6379726275 -0.4061817646
+ 0.3681431654  0.8063540334 -0.4628863603
+-0.8183499926 -0.1506049079 -0.5546363234
+-0.2655635881  0.7885775354 -0.5546363234
+-0.5262840256 -0.7132750815 -0.4628863603
+-0.2402045220 -0.8816564874 -0.4061817646
+ 0.0917499632 -0.8816564874 -0.4628863603
+ 0.3427840993 -0.7132750815 -0.6113409191
+ 0.5878317720 -0.1506049079 -0.7948408455
+ 0.0663908970  0.7885775354 -0.6113409191
+-0.6572159007 -0.4408282437 -0.6113409191
+-0.5829886213 -0.1683814059 -0.7948408455
+-0.1357750258  0.5914331516 -0.7948408455
+ 0.4170113787 -0.4408282437 -0.7948408455
+ 0.2860795036 -0.1683814059 -0.9432954043
+-0.3319544852  0.0000000000 -0.9432954043
+-0.1611340919  0.2902233358 -0.9432954043
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1432337790  0.5257311121  0.8385051474
+-0.3901124942 -0.3804226065  0.8385051474
+ 0.1432337790 -0.0843049040  0.8385051474
+ 0.6463368675 -0.3804226065  0.6614584599
+-0.3749909018  0.2207131041  0.7357864254
+ 0.5979747984  0.2207131041  0.5695840419
+-0.7989163046  0.4702282018  0.3749909018
+ 0.0972965700 -0.6299377043  0.5695840419
+ 0.8780939903  0.4702282018  0.0885233438
+-0.7412085774 -0.1364082001  0.4033816583
+-0.2405303491  0.7142426083  0.4033816583
+ 0.0151215924 -0.9959593140  0.0885233438
+ 0.8330829954 -0.1364082001  0.1344605528
+ 0.3607955236  0.7142426083  0.3006629363
+-0.8780939903 -0.4702282018 -0.0885233438
+-0.0151215924  0.9959593140 -0.0885233438
+-0.4493188674 -0.6621393122  0.3006629363
+ 0.5236468329 -0.6621393122  0.1344605528
+ 0.7989163046 -0.4702282018 -0.3749909018
+-0.8330829954  0.1364082001 -0.1344605528
+-0.5236468329  0.6621393122 -0.1344605528
+ 0.7412085774  0.1364082001 -0.4033816583
+ 0.4493188674  0.6621393122 -0.3006629363
+-0.6463368675  0.3804226065 -0.6614584599
+-0.3607955236 -0.7142426083 -0.3006629363
+ 0.2405303491 -0.7142426083 -0.4033816583
+ 0.3901124942  0.3804226065 -0.8385051474
+-0.5979747984 -0.2207131041 -0.5695840419
+-0.0972965700  0.6299377043 -0.5695840419
+-0.1432337790 -0.5257311121 -0.8385051474
+ 0.3749909018 -0.2207131041 -0.7357864254
+-0.1432337790  0.0843049040 -0.8385051475
+10 0 2 6 11 19 25 15 9 4 1 
+10 0 3 7 12 20 26 16 10 5 2 
+3 0 1 3 
+10 1 4 8 14 22 31 21 13 7 3 
+3 2 5 6 
+3 4 9 8 
+10 5 10 17 27 35 36 28 18 11 6 
+3 7 13 12 
+10 8 9 15 24 33 42 41 32 23 14 
+3 10 16 17 
+3 11 18 19 
+10 12 13 21 30 39 48 47 38 29 20 
+3 14 23 22 
+3 15 25 24 
+10 16 26 29 38 46 52 44 34 27 17 
+10 18 28 37 45 51 43 33 24 25 19 
+3 20 29 26 
+3 21 31 30 
+10 22 23 32 40 50 55 49 39 30 31 
+3 27 34 35 
+3 28 36 37 
+3 32 41 40 
+3 33 43 42 
+10 34 44 53 57 58 54 45 37 36 35 
+3 38 47 46 
+3 39 49 48 
+10 40 41 42 43 51 54 58 59 56 50 
+3 44 52 53 
+3 45 54 51 
+10 46 47 48 49 55 56 59 57 53 52 
+3 50 56 55 
+3 57 59 58 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 8 5 
+3 8 0 5 
+3 6 9 1 
+3 0 10 6 
+3 1 11 7 
+3 11 3 7 
+3 3 12 8 
+3 8 13 0 
+3 9 14 1 
+3 6 14 9 
+3 10 15 6 
+3 0 15 10 
+3 1 16 11 
+3 11 17 3 
+3 3 18 12 
+3 18 8 12 
+3 8 15 13 
+3 13 0 15 
+3 14 16 1 
+3 6 19 14 
+3 15 20 6 
+3 14 11 16 
+3 11 18 17 
+3 17 3 18 
+3 18 21 8 
+3 8 22 15 
+3 19 23 14 
+3 6 23 19 
+3 20 23 6 
+3 15 23 20 
+3 14 24 11 
+3 11 25 18 
+3 18 26 21 
+3 26 8 21 
+3 26 22 8 
+3 26 15 22 
+3 23 27 14 
+3 15 28 23 
+3 14 29 24 
+3 29 11 24 
+3 29 25 11 
+3 29 18 25 
+3 18 30 26 
+3 26 28 15 
+3 27 29 14 
+3 23 29 27 
+3 26 23 28 
+3 29 30 18 
+3 29 26 30 
+3 23 31 29 
+3 26 31 23 
+3 29 26 31 
+rhombicosidodecahedron
+deltoidal hexecontahedron
+3 5|2
+(4.3.4.5)
+icosahedral group
+A5
+12{5}+30{4}+20{3}
+31 60 120 62 60 1 0 0 2 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4364663517  0.0000000000  0.8997205810
+-0.0230394894  0.4358578416  0.8997205810
+-0.3947875239  0.1861335198  0.8997205810
+-0.1650346033 -0.4040624406  0.8997205810
+ 0.4134268623  0.4358578416  0.7994411620
+ 0.7478962199  0.1861335198  0.6371856536
+ 0.5411827887 -0.4040624406  0.7374650726
+-0.2253527696  0.7370282030  0.6371856536
+-0.5598221272 -0.2179289208  0.7994411620
+-0.5971008041  0.4873038812  0.6371856536
+ 0.1694347542 -0.6537867624  0.7374650726
+-0.4551056902 -0.6219913614  0.6371856536
+ 0.4808646224  0.7370282030  0.4749301452
+ 0.8526126568 -0.2179289208  0.4749301452
+ 0.8153339799  0.4873038812  0.3126746369
+ 0.6875780535 -0.6219913614  0.3746507262
+ 0.0860770985  0.9231617228  0.3746507262
+-0.5296630440  0.7884742426  0.3126746369
+-0.8641324015 -0.1664828812  0.4749301452
+-0.8871718909  0.2693749604  0.3746507262
+-0.1206363326 -0.8717156832  0.4749301452
+ 0.3158300191 -0.8717156832  0.3746507262
+-0.7594159645 -0.5705453218  0.3126746369
+ 0.6130206997  0.7884742426  0.0501397095
+ 0.9847687342 -0.1664828812  0.0501397095
+ 0.9617292448  0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.2182331759  0.9746077624  0.0501397095
+ 0.2182331759  0.9746077624 -0.0501397095
+-0.8197341309  0.5705453218  0.0501397095
+-0.9617292448 -0.2693749604  0.0501397095
+-0.9847687342  0.1664828812 -0.0501397095
+-0.2182331759 -0.9746077624  0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.7594159645  0.5705453218 -0.3126746369
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.8641324015  0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.3158300191  0.8717156832 -0.3746507262
+ 0.1206363326  0.8717156832 -0.4749301452
+-0.6875780535  0.6219913614 -0.3746507262
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.8526126568  0.2179289208 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.4551056902  0.6219913614 -0.6371856536
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.5598221272  0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.1694347542  0.6537867624 -0.7374650726
+-0.5411827887  0.4040624406 -0.7374650726
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.1650346033  0.4040624406 -0.8997205810
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517 -0.0000000000 -0.8997205810
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2124281962  0.2239537475  0.9245941063
+-0.1379991118  0.2054301247  0.9245941063
+-0.2876494382 -0.1119768737  0.9245941063
+ 0.2124281962 -0.3162277660  0.9245941063
+ 0.6623583361 -0.1119768737  0.7063270456
+ 0.5277148574  0.2054301247  0.7716443776
+ 0.1583346290  0.7071067812  0.6891517578
+-0.3186422944  0.4743416490  0.7896976442
+-0.7144788670  0.1207882584  0.6891517578
+-0.3897157456 -0.4108602493  0.7716443776
+-0.1467842735 -0.6555240367  0.7063270456
+ 0.6313654799  0.4743416490  0.5714305835
+ 0.9436228948  0.1207882584  0.3081980354
+ 0.4403528206 -0.6555240367  0.5714305835
+ 0.6874320834 -0.4108602493  0.5241665181
+-0.2279246243  0.8794777841  0.3531635228
+-0.4465745066  0.6647858481  0.5241665181
+-0.6778547641 -0.4051361351  0.5714305835
+-0.7280022588  0.5435471629  0.3531635228
+ 0.1204287884 -0.7917486474  0.5241665181
+-0.4686190076 -0.8278950396  0.3081980354
+ 0.6305733224  0.6647858481  0.2766886585
+ 0.3592124698  0.8794777841  0.2182670607
+ 0.8592901042 -0.4051361351  0.2182670607
+ 0.8091426096  0.5435471629 -0.0000000000
+ 0.5561442379 -0.8278950396  0.0727556869
+ 0.0284293805  0.9486832981  0.1237389298
+-0.5561442379  0.8278950396 -0.0727556869
+-0.9500077743  0.0000000000  0.2182670607
+-0.8538605757 -0.3323929240  0.2766886585
+-0.8890012226  0.3323929240  0.1237389298
+ 0.0501474947 -0.9486832981  0.2182670607
+-0.8091426096 -0.5435471629 -0.0000000000
+ 0.4686190076  0.8278950396 -0.3081980354
+ 0.8890012226 -0.3323929240 -0.1237389298
+ 0.9500077743  0.0000000000 -0.2182670607
+ 0.8538605757  0.3323929240 -0.2766886585
+ 0.7280022588 -0.5435471629 -0.3531635228
+-0.0501474947  0.9486832981 -0.2182670607
+-0.8592901042  0.4051361351 -0.2182670607
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.3592124698 -0.8794777841 -0.2182670607
+-0.0284293805 -0.9486832981 -0.1237389298
+ 0.2279246243 -0.8794777841 -0.3531635228
+-0.6305733224 -0.6647858481 -0.2766886585
+ 0.6778547641  0.4051361351 -0.5714305835
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.4465745066 -0.6647858481 -0.5241665181
+-0.1204287884  0.7917486474 -0.5241665181
+-0.4403528206  0.6555240367 -0.5714305835
+ 0.1467842735  0.6555240367 -0.7063270456
+-0.6874320834  0.4108602493 -0.5241665181
+-0.6313654799 -0.4743416490 -0.5714305835
+-0.6623583361  0.1119768737 -0.7063270456
+-0.1583346290 -0.7071067812 -0.6891517578
+ 0.3897157456  0.4108602493 -0.7716443776
+ 0.3186422944 -0.4743416490 -0.7896976442
+ 0.2876494382  0.1119768737 -0.9245941063
+-0.2124281962  0.3162277660 -0.9245941063
+-0.5277148574 -0.2054301247 -0.7716443776
+-0.2124281962 -0.2239537475 -0.9245941063
+ 0.1379991118 -0.2054301247 -0.9245941063
+4 0 2 5 1 
+3 0 3 2 
+4 0 4 9 3 
+5 0 1 7 11 4 
+4 1 6 14 7 
+3 1 5 6 
+5 2 8 17 13 5 
+4 2 3 10 8 
+5 3 9 19 20 10 
+3 4 12 9 
+4 4 11 21 12 
+4 5 13 15 6 
+5 6 15 26 25 14 
+4 7 16 22 11 
+3 7 14 16 
+4 8 18 28 17 
+3 8 10 18 
+4 9 12 23 19 
+4 10 20 30 18 
+3 11 22 21 
+5 12 21 33 35 23 
+3 13 24 15 
+4 13 17 29 24 
+4 14 25 27 16 
+4 15 24 36 26 
+5 16 27 39 34 22 
+3 17 28 29 
+5 18 30 42 40 28 
+4 19 31 32 20 
+3 19 23 31 
+3 20 32 30 
+4 21 22 34 33 
+4 23 35 43 31 
+5 24 29 41 47 36 
+3 25 37 27 
+4 25 26 38 37 
+3 26 36 38 
+4 27 37 48 39 
+4 28 40 41 29 
+4 30 32 44 42 
+5 31 43 53 44 32 
+4 33 45 46 35 
+3 33 34 45 
+4 34 39 50 45 
+3 35 46 43 
+4 36 47 49 38 
+5 37 38 49 56 48 
+3 39 48 50 
+3 40 51 41 
+4 40 42 52 51 
+4 41 51 55 47 
+3 42 44 52 
+4 43 46 54 53 
+4 44 53 58 52 
+5 45 50 57 54 46 
+3 47 55 49 
+4 48 56 57 50 
+4 49 55 59 56 
+5 51 52 58 59 55 
+3 53 54 58 
+4 54 57 59 58 
+3 56 59 57 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 11 6 0 
+4 4 12 11 5 
+4 3 13 14 4 
+4 6 15 16 7 
+4 8 17 9 2 
+4 16 18 8 7 
+4 10 19 13 3 
+4 17 20 10 9 
+4 11 21 22 6 
+4 14 23 12 4 
+4 12 24 21 11 
+4 13 25 23 14 
+4 22 26 15 6 
+4 15 27 18 16 
+4 8 28 29 17 
+4 18 30 28 8 
+4 20 31 19 10 
+4 31 25 13 19 
+4 29 32 20 17 
+4 24 33 22 21 
+4 23 34 35 12 
+4 35 36 24 12 
+4 25 37 34 23 
+4 26 38 27 15 
+4 33 38 26 22 
+4 27 39 30 18 
+4 28 40 32 29 
+4 39 40 28 30 
+4 20 41 42 31 
+4 42 43 25 31 
+4 32 44 41 20 
+4 36 45 33 24 
+4 37 46 35 34 
+4 46 45 36 35 
+4 43 47 37 25 
+4 38 48 49 27 
+4 33 50 48 38 
+4 49 51 39 27 
+4 40 52 44 32 
+4 51 53 40 39 
+4 41 54 43 42 
+4 52 54 41 44 
+4 45 55 50 33 
+4 47 56 46 37 
+4 46 57 55 45 
+4 54 56 47 43 
+4 50 58 49 48 
+4 58 53 51 49 
+4 53 59 52 40 
+4 59 60 54 52 
+4 57 58 50 55 
+4 56 61 57 46 
+4 60 61 56 54 
+4 58 60 59 53 
+4 57 58 60 61 
+truncated icosidodecahedron
+disdyakistriacontahedron
+2 3 5|
+(4.6.10)
+icosahedral group
+A5
+12{10}+20{6}+30{4}
+32 120 180 62 120 1 0 0 2 3 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.2607080006  0.0000000000  0.9654177015
+-0.0045873783  0.2606676380  0.9654177015
+-0.2192156342 -0.1411140222  0.9654177015
+ 0.2561208549  0.2606676380  0.9308353722
+ 0.4633267724 -0.1411140222  0.8748800687
+-0.2283903908  0.3802212538  0.8962531046
+-0.3132059807 -0.3694413065  0.8748800687
+-0.4430186467 -0.0215604065  0.8962531046
+ 0.4541524811  0.3802212538  0.8057154101
+ 0.5304628314 -0.3694413065  0.7629694001
+ 0.6613583986 -0.0215604065  0.7497601066
+-0.3298032754  0.5736633003  0.7497601066
+-0.4476060250  0.2391072316  0.8616708061
+-0.5370090771 -0.2498878945  0.8057153910
+-0.2460699217 -0.5977685908  0.7629694001
+ 0.5138663784  0.5736633003  0.6378493263
+ 0.6567712529  0.2391072316  0.7151777773
+ 0.7284945175 -0.2498878945  0.6378493381
+ 0.4364724850 -0.5977685908  0.6724317673
+-0.5490190001  0.4325494506  0.7151776775
+-0.2700897570  0.7671054904  0.5818940537
+-0.6936761144 -0.3586617667  0.6246400447
+-0.0434511498 -0.7388826131  0.6724317673
+-0.4027369590 -0.7065424630  0.5818940537
+ 0.7164852035  0.4325494506  0.5473115438
+ 0.4124538677  0.7671054904  0.4913562594
+ 0.8325358571 -0.3586617667  0.4221916434
+ 0.2172568508 -0.7388826131  0.6378494688
+ 0.5405138246 -0.7065424630  0.4567740725
+-0.7085212064  0.4848777911  0.5127291954
+-0.0720583700  0.8866594825  0.4567740725
+-0.4295919633  0.8194338309  0.3794455716
+-0.8531785590 -0.3063341981  0.4221915508
+-0.6265400554 -0.5869890510  0.5127293760
+-0.2001180064 -0.8476566112  0.4913563402
+ 0.8176915179  0.4848777911  0.3102806942
+ 0.1886510811  0.8866594825  0.4221915817
+ 0.5136601821  0.8194338309  0.2543254098
+ 0.9337423985 -0.3063341981  0.1851607203
+ 0.7385455107 -0.5869890510  0.3316540106
+ 0.3212979948 -0.8476566112  0.4221917432
+-0.8651885085  0.3761046523  0.3316536375
+-0.6488076880  0.6783199813  0.3448631425
+-0.2315603996  0.9389879297  0.2543254788
+-0.7860426423 -0.5346614357  0.3102807015
+-0.9545918983 -0.1128925413  0.2756983531
+-0.0960768624 -0.9564306093  0.2756986145
+ 0.9217330580  0.3761046523  0.0946227263
+ 0.7162790072  0.6783199813  0.1637876273
+ 0.2898571959  0.9389879297  0.1851606704
+ 0.8397521423 -0.5346614357  0.0946228761
+ 0.9934566827 -0.1128925413  0.0172943252
+ 0.1646311382 -0.9564306093  0.2411163161
+-0.8054751299  0.5695467454  0.1637874231
+-0.9591793219  0.1477776761  0.2411157125
+-0.1303544328  0.9913166095  0.0172945558
+-0.8203200648 -0.5695470165  0.0518766546
+-0.9888693637 -0.1477781439  0.0172916663
+-0.1303536668 -0.9913167102  0.0172945558
+ 0.8203206401  0.5695467454 -0.0518705331
+ 0.9888694917  0.1477776761 -0.0172883463
+ 0.1303553059  0.9913166095 -0.0172879732
+ 0.8054761704 -0.5695470165 -0.1637813633
+ 0.9591800640 -0.1477781439 -0.2411124739
+ 0.1303545664 -0.9913167102 -0.0172877735
+-0.8397525647  0.5346618623 -0.0946167165
+-0.9934567883  0.1128921245 -0.0172909812
+-0.1646312678  0.9564322465 -0.2411097335
+-0.7162795951 -0.6783208443 -0.1637814823
+-0.9217334041 -0.3761053597 -0.0946165431
+-0.2898558028 -0.9389895580 -0.1851545936
+ 0.7860446559  0.5346618623 -0.3102748651
+ 0.9545928720  0.1128921245 -0.2756951522
+ 0.0960787036  0.9564322465 -0.2756922934
+ 0.6488098576 -0.6783208443 -0.3448573632
+ 0.8651904546 -0.3761053597 -0.3316477584
+ 0.2315606390 -0.9389895580 -0.2543192490
+-0.7385472639  0.5869902473 -0.3316479890
+-0.9337433781  0.3063348862 -0.1851546415
+-0.3212992842  0.8476584134 -0.4221871436
+-0.8176928415 -0.4848792845 -0.3102748723
+-0.5136611563 -0.8194350139 -0.2543196306
+-0.1886494644 -0.8866613987 -0.4221882798
+ 0.6265433179  0.5869902473 -0.5127240198
+ 0.8531810896  0.3063348862 -0.4221859376
+ 0.2001204504  0.8476584134 -0.4913522358
+ 0.7085240020 -0.4848792845 -0.5127239199
+ 0.4295944105 -0.8194350139 -0.3794402462
+ 0.0720576700 -0.8866613987 -0.4567704634
+-0.8325379870  0.3586633178 -0.4221861255
+-0.5405162125  0.7065442357 -0.4567685048
+-0.2172590958  0.7388844270 -0.6378466030
+-0.7164876491 -0.4325518944 -0.5473064108
+-0.4124548660 -0.7671068289 -0.4913533317
+ 0.6936796092  0.3586633178 -0.6246352729
+ 0.4027407159  0.7065442357 -0.5818893011
+ 0.0434540643  0.7388844270 -0.6724295858
+ 0.5490226993 -0.4325518944 -0.7151733596
+ 0.2700914841 -0.7671068289 -0.5818914876
+-0.7284976588  0.2498903768 -0.6378447779
+-0.4364761587  0.5977701626 -0.6724279854
+-0.6567747682 -0.2391103983 -0.7151734903
+-0.5138692103 -0.5736660641 -0.6378445591
+ 0.5370132986  0.2498903768 -0.8057118075
+ 0.2460744543  0.5977701626 -0.7629667067
+ 0.4476105365 -0.2391103983 -0.8616675839
+ 0.3298072522 -0.5736660641 -0.7497562426
+-0.6613622562  0.0215634725 -0.7497566156
+-0.5304666075  0.3694443652 -0.7629652937
+-0.4541562762 -0.3802243954 -0.8057117884
+ 0.4430232811  0.0215634725 -0.8962507401
+ 0.3132106967  0.3694443652 -0.8748770888
+ 0.2283949989 -0.3802243954 -0.8962505976
+-0.4633311450  0.1411172572 -0.8748772313
+-0.2561255056 -0.2606708670 -0.9308331883
+ 0.2192205953  0.1411172572 -0.9654161022
+ 0.0045924376 -0.2606708671 -0.9654168058
+-0.2607129987  0.0000032913 -0.9654163518
+ 0.0000051772  0.0000032913 -1.0000000002
+ 0.1200387571  0.1221698550  0.9049446030
+-0.2175780247  0.1162282816  0.9049446030
+ 0.1200387571 -0.4082474279  0.9049446030
+ 0.4459799746  0.1162282816  0.8169252068
+ 0.1016985225  0.6339220449  0.7666817889
+-0.3544276914 -0.1832548434  0.8300952867
+ 0.5585832497 -0.1832548434  0.7089865490
+-0.3643565320  0.3809295903  0.7552459704
+-0.4568036952 -0.4649138222  0.6745068322
+-0.7747432361  0.0697368203  0.6284189748
+ 0.5486549126  0.3809295903  0.6341371659
+ 0.6168557011 -0.4649138222  0.5320884576
+ 0.9117846887  0.0697368203  0.4047050422
+-0.4756956529  0.6085799433  0.5320883790
+-0.2091195905 -0.6774423865  0.5878778112
+ 0.5979647013  0.6085799433  0.3896698773
+ 0.3551522032 -0.6774423865  0.5130284950
+-0.2351136470  0.7996124516  0.3919196492
+-0.6935150612 -0.4186830921  0.4381790039
+ 0.0589047087 -0.8240793946  0.4440690614
+-0.5063278658 -0.8431340489  0.1809911096
+ 0.3291594648  0.7996124516  0.3170701581
+ 0.7837684883 -0.4186830921  0.2422208418
+ 0.5360037147 -0.8431340489  0.0427282955
+-0.7095802914  0.4941881267  0.3170700500
+ 0.0283375922  0.9128709077  0.2136305953
+-0.5360037809  0.8431342740 -0.0427230226
+-0.8627717620 -0.3317288924  0.1592318224
+ 0.7677040727  0.4941881267  0.1211117799
+ 0.5063293044  0.8431342740 -0.1809860363
+ 0.8744481415 -0.3317288924 -0.0712062810
+-0.8744476717  0.3317288831  0.0712120936
+-0.9130127824 -0.0000002089  0.1211105323
+ 0.0160652247 -0.9128709077  0.1211120373
+ 0.8627728239  0.3317288831 -0.1592260883
+ 0.9130131866 -0.0000002089 -0.1211074853
+-0.0160644264  0.9128718312 -0.1211060185
+-0.7677045094 -0.4941888273 -0.1211061534
+-0.9117856757 -0.0697383469 -0.4047106460
+-0.0283368549 -0.9128720729 -0.2136250368
+ 0.7095821798 -0.4941888273 -0.3170647319
+ 0.7747427279 -0.0697383469 -0.6284246421
+-0.7837697662  0.4186839017 -0.2422153076
+-0.0589041897  0.8240821079 -0.4440651491
+-0.5979663637 -0.6085817063 -0.3896645730
+-0.3291594183 -0.7996144008 -0.3170661961
+ 0.6935177376  0.4186839017 -0.4381739941
+ 0.4756986407 -0.6085817062 -0.5320836915
+ 0.2351146351 -0.7996144008 -0.3919158120
+-0.6168583888  0.4649158905 -0.5320835344
+-0.3551545140  0.6774441676 -0.5130247732
+-0.1016986410 -0.6339226751 -0.7666826828
+ 0.4568075735  0.4649158905 -0.6745027800
+ 0.2091227917  0.6774441676 -0.5878748206
+-0.1200394925  0.4082445693 -0.9049501464
+-0.5486577777 -0.3809323480 -0.6341330304
+ 0.3643603763 -0.3809323480 -0.7552427249
+-0.5585867166  0.1832576685 -0.7089830873
+-0.4459830958 -0.1162285368 -0.8169244453
+ 0.3544319410  0.1832576685 -0.8300928485
+ 0.2175812366 -0.1162285368 -0.9049446814
+-0.1200388933 -0.1221699931 -0.9049456264
+4 0 2 4 1 
+6 0 3 8 13 6 2 
+10 0 1 5 10 19 28 23 15 7 3 
+6 1 4 9 17 11 5 
+10 2 6 12 21 31 37 26 16 9 4 
+4 3 7 14 8 
+4 5 11 18 10 
+4 6 13 20 12 
+6 7 15 24 34 22 14 
+10 8 14 22 33 46 55 42 30 20 13 
+4 9 16 25 17 
+6 10 18 27 40 29 19 
+10 11 17 25 36 48 61 52 39 27 18 
+6 12 20 30 43 32 21 
+4 15 23 35 24 
+6 16 26 38 49 36 25 
+4 19 29 41 28 
+4 21 32 44 31 
+4 22 34 45 33 
+6 23 28 41 53 47 35 
+10 24 35 47 59 71 82 69 57 45 34 
+4 26 37 50 38 
+4 27 39 51 40 
+10 29 40 51 63 75 88 77 65 53 41 
+4 30 42 54 43 
+6 31 44 56 62 50 37 
+10 32 43 54 66 78 91 80 68 56 44 
+6 33 45 57 70 58 46 
+4 36 49 60 48 
+10 38 50 62 74 86 96 84 72 60 49 
+6 39 52 64 76 63 51 
+6 42 55 67 79 66 54 
+4 46 58 67 55 
+4 47 53 65 59 
+6 48 60 72 85 73 61 
+4 52 61 73 64 
+4 56 68 74 62 
+4 57 69 81 70 
+10 58 70 81 93 102 108 100 90 79 67 
+6 59 65 77 89 83 71 
+4 63 76 87 75 
+10 64 73 85 95 104 111 106 98 87 76 
+4 66 79 90 78 
+6 68 80 92 97 86 74 
+6 69 82 94 103 93 81 
+4 71 83 94 82 
+4 72 84 95 85 
+6 75 87 98 107 99 88 
+4 77 88 99 89 
+6 78 90 100 109 101 91 
+4 80 91 101 92 
+10 83 89 99 107 113 117 115 110 103 94 
+6 84 96 105 112 104 95 
+4 86 97 105 96 
+10 92 101 109 114 118 119 116 112 105 97 
+4 93 103 110 102 
+4 98 106 113 107 
+4 100 108 114 109 
+6 102 110 115 118 114 108 
+4 104 112 116 111 
+6 106 111 116 119 117 113 
+4 115 117 119 118 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 4 0 
+3 2 6 3 
+3 4 7 1 
+3 5 8 2 
+3 1 9 5 
+3 3 10 4 
+3 2 11 6 
+3 6 12 3 
+3 4 13 7 
+3 7 9 1 
+3 9 8 5 
+3 8 14 2 
+3 10 15 4 
+3 12 10 3 
+3 11 12 6 
+3 2 16 11 
+3 13 9 7 
+3 4 17 13 
+3 9 18 8 
+3 14 19 2 
+3 8 20 14 
+3 12 15 10 
+3 15 21 4 
+3 11 22 12 
+3 19 16 2 
+3 16 23 11 
+3 13 24 9 
+3 4 25 17 
+3 17 26 13 
+3 9 27 18 
+3 18 20 8 
+3 20 19 14 
+3 12 28 15 
+3 21 25 4 
+3 15 29 21 
+3 22 30 12 
+3 23 22 11 
+3 19 23 16 
+3 24 31 9 
+3 26 24 13 
+3 25 26 17 
+3 27 20 18 
+3 9 32 27 
+3 20 33 19 
+3 12 34 28 
+3 28 29 15 
+3 29 25 21 
+3 23 30 22 
+3 30 35 12 
+3 33 23 19 
+3 26 31 24 
+3 31 32 9 
+3 25 36 26 
+3 27 37 20 
+3 32 38 27 
+3 20 39 33 
+3 34 29 28 
+3 35 34 12 
+3 29 36 25 
+3 23 40 30 
+3 30 41 35 
+3 39 23 33 
+3 26 42 31 
+3 31 38 32 
+3 36 43 26 
+3 37 44 20 
+3 38 37 27 
+3 20 45 39 
+3 34 46 29 
+3 41 34 35 
+3 29 43 36 
+3 23 47 40 
+3 40 41 30 
+3 39 48 23 
+3 26 49 42 
+3 42 38 31 
+3 43 50 26 
+3 38 44 37 
+3 44 45 20 
+3 45 51 39 
+3 46 52 29 
+3 41 46 34 
+3 29 53 43 
+3 47 41 40 
+3 48 47 23 
+3 51 48 39 
+3 49 38 42 
+3 50 49 26 
+3 43 54 50 
+3 38 55 44 
+3 44 51 45 
+3 41 52 46 
+3 52 53 29 
+3 53 54 43 
+3 47 56 41 
+3 51 47 48 
+3 49 57 38 
+3 54 49 50 
+3 38 58 55 
+3 55 51 44 
+3 41 59 52 
+3 52 54 53 
+3 56 60 41 
+3 51 56 47 
+3 57 58 38 
+3 54 57 49 
+3 58 51 55 
+3 60 59 41 
+3 59 54 52 
+3 51 60 56 
+3 54 58 57 
+3 58 61 51 
+3 60 54 59 
+3 61 60 51 
+3 54 61 58 
+3 60 54 61 
+snub dodecahedron
+pentagonal hexecontahedron
+|2 3 5
+(3.3.3.3.5)
+icosahedral group
+A5
+12{5}+80{3}
+33 60 150 92 60 1 0 0 2 2 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4512088258  0.0000000000  0.8924183971
+ 0.2127790861  0.3978875029  0.8924183971
+-0.2505259628  0.3752680994  0.8924183971
+-0.4490629634 -0.0439529224  0.8924183971
+-0.1730083366 -0.4167223535  0.8924183971
+ 0.5570628795 -0.4167223535  0.7183477071
+ 0.8034191070 -0.0439529224  0.5937894232
+ 0.6262410352  0.3752680994  0.6833710701
+ 0.3401140582  0.7292026799  0.5937894232
+-0.4095292581  0.6926037162  0.5937894232
+-0.6598181766  0.3124803264  0.6833710701
+-0.5867073299 -0.4344864666  0.6833710701
+-0.2674638242 -0.7588657481  0.5937894232
+ 0.1712754568 -0.6742709318  0.7183477071
+ 0.5066126656 -0.7588657481  0.4092265672
+ 0.8319314730 -0.4344864666  0.3451253896
+ 0.9853200794 -0.0345183587  0.1671909808
+ 0.6986399371  0.6437955034  0.3121371303
+ 0.3534611035  0.9196768661  0.1710546996
+-0.0444936500  0.9113473168  0.4092265672
+-0.4413672010  0.8808718883  0.1710546996
+-0.7580304168  0.5726781810  0.3121371303
+-0.9277164283  0.1422346447  0.3451253896
+-0.8825314401 -0.3194162218  0.3451253896
+-0.6326042630 -0.7087892905  0.3121371303
+ 0.0822881568 -0.9349423109  0.3451253896
+ 0.3841470954 -0.9232462719 -0.0068797092
+ 0.9105239830 -0.3983895691 -0.1105975932
+ 0.9561362417  0.0261888093 -0.2917492648
+ 0.9205629910  0.3905335442 -0.0068797092
+ 0.6521763631  0.7453882542 -0.1380664403
+-0.0487110154  0.9977300839 -0.0464964156
+-0.4177242369  0.8604584989 -0.2917492648
+-0.9300960831  0.3617906055 -0.0634730968
+-0.9941677927 -0.0973061317 -0.0464964156
+-0.8422948163 -0.5352668572 -0.0634730968
+-0.5085214838 -0.8539169004 -0.1105975932
+-0.0666936701 -0.9936871537 -0.0902097278
+ 0.2171184410 -0.8730158634 -0.4366954143
+ 0.6337780180 -0.7004597412 -0.3281487085
+ 0.7752228621 -0.3165232566 -0.5466649267
+ 0.7846911652  0.4275505711 -0.4488432737
+ 0.4346204276  0.7157251860 -0.5466649267
+ 0.0014482055  0.8716810135 -0.4900715391
+-0.3439002478  0.6359394784 -0.6908788601
+-0.7197752973  0.5396486232 -0.4366954143
+-0.8871554693  0.1072142198 -0.4488432737
+-0.6414198315 -0.6014211198 -0.4763121208
+-0.2422737833 -0.8373370292 -0.4900715391
+ 0.4183769714 -0.5607792259 -0.7144839884
+ 0.4919671680 -0.1269691999 -0.8613054788
+ 0.4978189011  0.3328937158 -0.8008483725
+ 0.0947401619  0.5614556665 -0.8220655912
+-0.5854826930  0.2482988995 -0.7717238319
+-0.6691452398 -0.2043459771 -0.7144839884
+-0.3249352618 -0.5030496595 -0.8008483725
+ 0.0833693593 -0.3321275372 -0.9395428936
+ 0.1242523988  0.1277815601 -0.9839884218
+-0.2961484454 -0.0657599657 -0.9528755035
+ 0.2190839064  0.1312836377  0.9188614921
+-0.0124546442  0.2551039658  0.9188614921
+-0.2308305197  0.1093179889  0.9188614921
+-0.2052534511 -0.1520005669  0.9188614921
+ 0.2190839064 -0.3281703830  0.9188614921
+ 0.5977703708 -0.1520005669  0.7273967313
+ 0.6205958173  0.1093179889  0.7158561322
+ 0.4257131685  0.2551039658  0.8143892546
+ 0.3890572668  0.4957055924  0.7158561322
+-0.0330094857  0.6761213397  0.7360504792
+-0.4354944038  0.4554494653  0.7158561322
+-0.4485386151  0.2124213879  0.8143892546
+-0.7630826557 -0.0746882186  0.6419708175
+-0.3988385021 -0.2953600929  0.8143892546
+-0.3389195666 -0.5312467586  0.7158561322
+-0.0888218963 -0.6103640383  0.7273967313
+ 0.4074741194 -0.6103640383  0.6090650015
+ 0.6254586613 -0.5312467586  0.4859196824
+ 0.7233904360 -0.2953600929  0.5468165011
+ 0.8646946053 -0.1692512546  0.3649614304
+ 0.8780829721  0.2897337362  0.3808210291
+ 0.5493678557  0.5768433427  0.5243913714
+ 0.4593636674  0.7564719129  0.3553517403
+ 0.2141655150  0.8447510749  0.3873865601
+-0.2954354429  0.8198714201  0.3873865601
+-0.5308680756  0.7081269803  0.3553517403
+-0.6029463352  0.5205852472  0.5243913714
+-0.7739230465  0.3389900646  0.4423442636
+-0.6935065744 -0.4826176302  0.4423442636
+-0.4905640004 -0.6276147261  0.5243913714
+-0.3032002312 -0.9251016481  0.2285969389
+-0.0045863974 -0.7813515677  0.5468165011
+ 0.2508214168 -0.7813515677  0.4859196824
+ 0.3210587649 -0.8635013917  0.2466297006
+ 0.7110959079 -0.6998764938  0.0671974935
+ 0.9000340357 -0.2861982107  0.1325477729
+ 0.9410156039 -0.1341976438 -0.0775900694
+ 0.9443279912  0.1261088383 -0.0433681826
+ 0.7494453424  0.5872206583  0.0551649398
+ 0.5623291395  0.7618123698  0.1138746914
+ 0.3032002312  0.9251016481 -0.2285969389
+ 0.0858720409  0.9333521346  0.1761231918
+-0.1763828687  0.9205483682  0.1761231918
+-0.2995309163  0.9037575188 -0.0551649398
+-0.7110959079  0.6998764938 -0.0671974935
+-0.8631016874  0.3552600725  0.1959217993
+-0.9410156039  0.1341976438  0.0775900694
+-0.9253215715 -0.0905676721  0.2124078137
+-0.8971365698 -0.3141104098  0.0775900694
+-0.7778380870 -0.5158702863  0.1959217993
+-0.6544328852 -0.6922296665  0.0455552496
+ 0.1318953941 -0.9409811017  0.0818398716
+ 0.1763828687 -0.9205483682 -0.1761231918
+ 0.4075046572 -0.8237974999 -0.2546315508
+ 0.7653310532 -0.4670045122 -0.3251380596
+ 0.8716936806 -0.2272456248 -0.3131280032
+ 0.7630826557  0.0746882186 -0.6419708175
+ 0.8781301501  0.2785692436 -0.2466297006
+ 0.7778380870  0.5158702863 -0.1959217993
+ 0.6175005369  0.6231678047 -0.3740248218
+-0.1534232428  0.9007249745 -0.2733046324
+-0.2508214168  0.7813515677 -0.4859196824
+-0.4887903007  0.6717969331 -0.4683081420
+-0.8370961923  0.3328068685 -0.3131280032
+-0.9276324486  0.1226425968 -0.1843812002
+-0.8780829721 -0.2897337362 -0.3808210291
+-0.6573415966 -0.6568033615 -0.2145948808
+-0.4593636674 -0.7564719129 -0.3553517403
+-0.2697318228 -0.8859007376 -0.2279566191
+-0.0303057331 -0.8922024719 -0.3355531328
+ 0.0330094857 -0.6761213397 -0.7360504792
+ 0.4187988612 -0.7042009004 -0.4881067495
+ 0.6029463352 -0.5205852472 -0.5243913714
+ 0.5561556114 -0.3313610975 -0.7003073269
+ 0.5665700378  0.4870645516 -0.5927108132
+ 0.3389195666  0.5312467586 -0.7158561322
+ 0.1751412372  0.7090205159 -0.6133148036
+-0.0817329434  0.6826950901 -0.6608984288
+-0.2190839064  0.3281703830 -0.9188614921
+-0.5441424799  0.4698138638 -0.6266765419
+-0.7233904360  0.2953600929 -0.5468165011
+-0.7066849651  0.0498778478 -0.6384732991
+-0.5396360317 -0.4318462468 -0.6571463807
+-0.3987890908 -0.6407026882 -0.5831011230
+ 0.3278774074 -0.3365097556 -0.8299380599
+ 0.2308305197 -0.1093179889 -0.9188614921
+ 0.3675788294  0.1101068700 -0.8730990062
+ 0.2365131238  0.3372537898 -0.8601517406
+-0.5116812230 -0.0071952699 -0.8047795644
+-0.4257131685 -0.2551039658 -0.8143892546
+-0.1774197357 -0.2972657023 -0.8886478115
+-0.0292095264 -0.0891219012 -0.9490751728
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 5 4 
+5 0 1 6 14 5 
+3 1 7 6 
+3 1 8 7 
+3 1 2 8 
+3 2 9 8 
+5 2 3 10 20 9 
+3 3 11 10 
+3 3 4 11 
+5 4 12 24 23 11 
+3 4 5 12 
+3 5 13 12 
+3 5 14 13 
+3 6 15 14 
+3 6 16 15 
+3 6 7 16 
+3 7 17 16 
+5 7 8 18 30 17 
+3 8 9 18 
+3 9 19 18 
+3 9 20 19 
+3 10 21 20 
+3 10 22 21 
+3 10 11 22 
+3 11 23 22 
+3 12 25 24 
+3 12 13 25 
+5 13 26 38 37 25 
+3 13 14 26 
+3 14 15 26 
+3 15 27 26 
+5 15 16 28 40 27 
+3 16 17 28 
+3 17 29 28 
+3 17 30 29 
+3 18 31 30 
+3 18 19 31 
+5 19 32 44 43 31 
+3 19 20 32 
+3 20 21 32 
+3 21 33 32 
+5 21 22 34 46 33 
+3 22 23 34 
+3 23 35 34 
+3 23 24 35 
+3 24 36 35 
+3 24 25 36 
+3 25 37 36 
+3 26 27 38 
+3 27 39 38 
+3 27 40 39 
+3 28 41 40 
+3 28 29 41 
+5 29 42 52 51 41 
+3 29 30 42 
+3 30 31 42 
+3 31 43 42 
+3 32 33 44 
+3 33 45 44 
+3 33 46 45 
+3 34 47 46 
+3 34 35 47 
+5 35 36 48 55 47 
+3 36 37 48 
+3 37 49 48 
+3 37 38 49 
+3 38 39 49 
+5 39 50 57 56 49 
+3 39 40 50 
+3 40 41 50 
+3 41 51 50 
+3 42 43 52 
+3 43 53 52 
+3 43 44 53 
+3 44 45 53 
+5 45 54 59 58 53 
+3 45 46 54 
+3 46 47 54 
+3 47 55 54 
+3 48 56 55 
+3 48 49 56 
+3 50 51 57 
+3 51 58 57 
+3 51 52 58 
+3 52 53 58 
+3 54 55 59 
+3 55 56 59 
+3 56 57 59 
+3 57 58 59 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 13 14 15 4 3 
+5 4 16 17 18 5 
+5 18 19 20 6 5 
+5 20 21 8 7 6 
+5 21 22 23 9 8 
+5 9 24 25 26 10 
+5 26 27 12 11 10 
+5 12 28 29 14 13 
+5 29 30 31 15 14 
+5 31 32 16 4 15 
+5 32 33 34 17 16 
+5 34 35 19 18 17 
+5 35 36 37 20 19 
+5 20 38 39 22 21 
+5 39 40 41 23 22 
+5 41 42 24 9 23 
+5 42 43 44 25 24 
+5 44 45 27 26 25 
+5 45 46 47 12 27 
+5 47 48 49 28 12 
+5 49 50 30 29 28 
+5 30 51 33 32 31 
+5 51 52 53 34 33 
+5 34 54 55 36 35 
+5 55 56 57 37 36 
+5 57 58 38 20 37 
+5 58 59 40 39 38 
+5 40 60 43 42 41 
+5 60 61 62 44 43 
+5 44 63 64 46 45 
+5 64 65 48 47 46 
+5 65 66 50 49 48 
+5 66 67 68 30 50 
+5 68 69 52 51 30 
+5 69 70 71 53 52 
+5 71 72 54 34 53 
+5 72 73 56 55 54 
+5 56 74 59 58 57 
+5 74 75 76 40 59 
+5 76 77 61 60 40 
+5 77 78 79 62 61 
+5 79 80 63 44 62 
+5 80 81 65 64 63 
+5 65 82 83 67 66 
+5 83 70 69 68 67 
+5 70 84 73 72 71 
+5 84 85 86 56 73 
+5 86 87 75 74 56 
+5 87 78 77 76 75 
+5 78 88 81 80 79 
+5 88 89 82 65 81 
+5 89 90 70 83 82 
+5 90 91 85 84 70 
+5 91 78 87 86 85 
+5 78 88 89 90 91 
+small ditrigonal icosidodecahedron
+small triambic icosahedron
+3|5/2 3
+(5/2.3.5/2.3.5/2.3)
+icosahedral group
+A5
+20{3}+12{5/2}
+34 20 60 32 20 2 0 0 -8 2 6 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9428090416  0.0000000000  0.3333333333
+ 0.6727182848  0.6605596098  0.3333333333
+-0.4714045208  0.8164965809  0.3333333333
+-0.9084205452  0.2523113194  0.3333333333
+-0.4714045208 -0.8164965809  0.3333333333
+ 0.2357022604 -0.9128709292  0.3333333333
+ 0.0900302522  0.6605596098  0.7453559925
+ 0.4714045208  0.8164965809 -0.3333333333
+ 0.6170765289  0.2523113194 -0.7453559925
+ 0.4714045208 -0.8164965809 -0.3333333333
+-0.2357022604  0.9128709292 -0.3333333333
+ 0.9084205452 -0.2523113194 -0.3333333333
+ 0.5270462767 -0.4082482905  0.7453559925
+-0.6170765289 -0.2523113194  0.7453559925
+-0.9428090416  0.0000000000 -0.3333333333
+-0.5270462767  0.4082482905 -0.7453559925
+-0.6727182848 -0.6605596098 -0.3333333333
+-0.0900302522 -0.6605596098 -0.7453559925
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.5270462767  0.2154995940  0.7453559925
+ 0.0900302522  0.6605596098  0.7453559925
+-0.4501512612  0.3486856676  0.7453559925
+-0.6170765289 -0.2523113194  0.7453559925
+-0.0768950155 -0.5641852616  0.7453559925
+ 0.5270462767 -0.4082482905  0.7453559925
+ 0.7283600407 -0.5641852616  0.1759546817
+ 0.9084205452 -0.2523113194 -0.3333333333
+ 0.8527787893  0.3486856676 -0.1759546817
+ 0.6727182848  0.6605596098  0.3333333333
+ 0.9428090416 -0.0000000000  0.3333333333
+ 0.4714045208  0.8164965809 -0.3333333333
+ 0.1244187486  0.9128709292  0.1759546817
+-0.2357022604  0.9128709292 -0.3333333333
+-0.7283600407  0.5641852616 -0.1759546817
+-0.9084205452  0.2523113194  0.3333333333
+-0.4714045208  0.8164965809  0.3333333333
+-0.9428090416 -0.0000000000 -0.3333333333
+-0.8527787893 -0.3486856676  0.1759546817
+-0.6727182848 -0.6605596098 -0.3333333333
+-0.1244187486 -0.9128709292 -0.1759546817
+ 0.2357022604 -0.9128709292  0.3333333333
+-0.4714045208 -0.8164965809  0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+ 0.0000000000 -0.0000000000  1.0000000000
+ 0.6170765289  0.2523113194 -0.7453559925
+ 0.0768950155  0.5641852616 -0.7453559925
+ 0.4501512612 -0.3486856676 -0.7453559925
+-0.0000000000  0.0000000000 -1.0000000000
+-0.0900302522 -0.6605596098 -0.7453559925
+-0.5270462767  0.4082482905 -0.7453559925
+-0.5270462767 -0.2154995940 -0.7453559925
+5 0 2 13 7 1 2
+3 0 3 2 
+5 0 4 7 14 3 2
+3 0 5 4 
+5 0 6 14 13 5 2
+3 0 1 6 
+5 1 10 13 12 6 2
+3 1 9 10 
+5 1 8 12 2 9 2
+3 1 7 8 
+3 2 12 13 
+3 2 11 9 
+5 2 3 8 7 11 2
+3 3 16 8 
+5 3 15 11 4 16 2
+3 3 14 15 
+3 4 11 7 
+3 4 17 16 
+5 4 5 15 14 17 2
+3 5 18 15 
+5 5 10 17 6 18 2
+3 5 13 10 
+3 6 17 14 
+3 6 12 18 
+3 7 13 14 
+3 8 19 12 
+5 8 16 9 11 19 2
+5 9 18 12 19 10 2
+3 9 16 18 
+3 10 19 17 
+3 11 15 19 
+5 15 18 16 17 19 2
+6 5 0 1 2 3 4 
+6 5 6 7 8 9 0 
+6 0 10 8 11 12 1 
+6 12 13 14 15 2 1 
+6 2 16 14 17 18 3 
+6 18 19 20 21 4 3 
+6 4 22 20 23 6 5 
+6 9 12 16 2 24 0 
+6 8 25 26 13 12 9 
+6 7 27 28 26 11 8 
+6 6 21 20 29 27 7 
+6 26 30 14 16 12 11 
+6 10 6 23 27 25 8 
+6 24 4 21 6 10 0 
+6 15 18 22 4 24 2 
+6 30 31 19 18 15 14 
+6 28 31 17 14 13 26 
+6 31 29 20 22 18 17 
+6 19 20 23 27 28 31 
+6 25 26 30 31 29 27 
+small icosicosidodecahedron
+small icosacronic hexecontahedron
+5/2 3|3
+(6.5/2.6.3)
+icosahedral group
+A5
+20{6}+20{3}+12{5/2}
+35 60 120 52 60 2 0 0 -8 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5558508647  0.0000000000  0.8312820317
+-0.3547421326  0.4279348118  0.8312820317
+-0.5423346067  0.1218333214  0.8312820317
+ 0.2523198656 -0.4952826155  0.8312820317
+ 0.7569595968  0.4279348118  0.4938460950
+ 0.9129018498  0.1218333214  0.3895726561
+-0.3230919115 -0.1426449373  0.9355554706
+-0.6764070948  0.6250652668  0.3895726561
+-0.1536334005  0.8558696236  0.4938460950
+-0.8323493477 -0.2516159727  0.4938460950
+-0.8639995688  0.3189637764  0.3895726561
+-0.0195609124  0.3526376782  0.9355554706
+ 0.3058398516 -0.8687319096  0.3895726561
+-0.0376948755 -0.8687319096  0.4938460950
+ 0.7886098179 -0.1426449373  0.5981195340
+ 0.7788293617  0.6250652668 -0.0521367195
+ 0.4022174642  0.8558696236  0.3251281267
+ 0.9664218358 -0.2516159727 -0.0521367195
+ 0.9347716147  0.3189637764 -0.1564101584
+ 0.5362899523  0.3526376782  0.7668375023
+-0.6131066526 -0.5160942314  0.5981195340
+-0.0707720459 -0.6379275528  0.7668375023
+-0.8421298039  0.5160942314 -0.1564101584
+-0.9664218358  0.2516159727  0.0521367195
+ 0.2034175846  0.9777029450  0.0521367195
+-0.7788293617 -0.6250652668  0.0521367195
+-0.5800294821 -0.7468985882  0.3251281267
+-0.6628908367  0.7468985882  0.0521367195
+ 0.1815478197  0.7805724901  0.5981195340
+ 0.1401171424 -0.9777029450 -0.1564101584
+ 0.6628908367 -0.7468985882 -0.0521367195
+-0.2034175846 -0.9777029450 -0.0521367195
+ 0.4850788188 -0.6379275528  0.5981195340
+ 0.8421298039 -0.5160942314  0.1564101584
+ 0.6131066526  0.5160942314 -0.5981195340
+ 0.8323493477  0.2516159727 -0.4938460950
+-0.1401171424  0.9777029450  0.1564101584
+ 0.6764070948 -0.6250652668 -0.3895726561
+ 0.5800294821  0.7468985882 -0.3251281267
+-0.9347716147 -0.3189637764  0.1564101584
+-0.7886098179  0.1426449373 -0.5981195340
+-0.4850788188  0.6379275528 -0.5981195340
+-0.9129018498 -0.1218333214 -0.3895726561
+ 0.0376948755  0.8687319096 -0.4938460950
+-0.4022174642 -0.8558696236 -0.3251281267
+-0.7569595968 -0.4279348118 -0.4938460950
+-0.3058398516  0.8687319096 -0.3895726561
+-0.1815478197 -0.7805724901 -0.5981195340
+ 0.8639995688 -0.3189637764 -0.3895726561
+ 0.1536334005 -0.8558696236 -0.4938460950
+ 0.3230919115  0.1426449373 -0.9355554706
+ 0.0707720459  0.6379275528 -0.7668375023
+ 0.5423346067 -0.1218333214 -0.8312820317
+ 0.3547421326 -0.4279348118 -0.8312820317
+-0.5362899523 -0.3526376782 -0.7668375023
+-0.5558508647 -0.0000000000 -0.8312820317
+-0.2523198656  0.4952826155 -0.8312820317
+ 0.0195609124 -0.3526376782 -0.9355554706
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2470682788  0.5257311121  0.8139803827
+-0.2225822414  0.1364082001  0.8139803827
+-0.3562920523 -0.4587939735  0.8139803827
+ 0.2470682788 -0.1514143222  0.8139803827
+ 0.7486308807 -0.4587939735  0.4786020209
+ 0.6374803174  0.1364082001  0.5529247349
+-0.3622034226  0.5835662368  0.5242062787
+-0.7921037010  0.0669371386  0.6067051560
+-0.4192065089  0.6754071043  0.6067051560
+-0.6843946014  0.0578351247  0.5242062787
+ 0.1678297972 -0.6299377043  0.5529247349
+ 0.9956991595  0.0669371386  0.0640515676
+ 0.5924737103  0.5835662368  0.2344321747
+ 0.8603054480  0.0578351247  0.0553419293
+ 0.6857164240  0.6754071043  0.2713267942
+-0.3078439816 -0.3964078418  0.7032965240
+ 0.2859515514 -0.1752437040  0.9420835178
+-0.3923388284  0.9175879470 -0.0640515676
+-0.7202912637  0.4414262081  0.1305278239
+ 0.0885913156  0.7985475123  0.2918690871
+-0.9956991595 -0.0669371386 -0.0640515676
+-0.6713191889 -0.4414262081  0.2918690871
+ 0.2134722966  0.4542429665  0.7032965240
+-0.2905410991 -0.9175879470  0.2713267942
+ 0.3389891699 -0.7928156837  0.0553419293
+-0.2510337466 -0.7928156837  0.2344321747
+ 0.3923388284 -0.9175879470  0.0640515676
+ 0.6468331514 -0.3964078418  0.4135224200
+ 0.6713191889  0.4414262081 -0.2918690871
+ 0.2905410991  0.9175879470 -0.2713267942
+ 0.7202912637 -0.4414262081 -0.1305278239
+ 0.7921037010 -0.0669371386 -0.6067051560
+-0.6468331514  0.3964078418 -0.4135224200
+-0.7486308807  0.4587939735 -0.4786020209
+-0.8603054480 -0.0578351247 -0.0553419293
+ 0.2510337466  0.7928156837 -0.2344321747
+-0.5924737103 -0.5835662368 -0.2344321747
+-0.6857164240 -0.6754071043 -0.2713267942
+-0.3389891699  0.7928156837 -0.0553419293
+-0.0885913156 -0.7985475123 -0.2918690871
+ 0.4192065089 -0.6754071043 -0.6067051560
+ 0.3078439816  0.3964078418 -0.7032965240
+ 0.6843946014 -0.0578351247 -0.5242062787
+ 0.3562920523  0.4587939735 -0.8139803827
+ 0.3622034226 -0.5835662368 -0.5242062787
+-0.2859515514  0.1752437040 -0.9420835178
+-0.6374803174 -0.1364082001 -0.5529247349
+-0.1678297972  0.6299377043 -0.5529247349
+-0.2470682788 -0.5257311121 -0.8139803827
+-0.2134722966 -0.4542429665 -0.7032965240
+ 0.2225822414 -0.1364082001 -0.8139803827
+-0.2470682788  0.1514143222 -0.8139803827
+6 0 2 9 17 5 1 
+5 0 3 12 7 2 2
+6 0 4 14 27 10 3 
+3 0 1 4 
+6 1 6 18 31 13 4 
+5 1 5 15 20 6 2
+3 2 8 9 
+6 2 7 21 40 24 8 
+6 3 11 28 37 29 12 
+3 3 10 11 
+5 4 13 22 33 14 2
+6 5 16 36 49 34 15 
+3 5 17 16 
+3 6 19 18 
+6 6 20 29 25 39 19 
+3 7 22 21 
+6 7 12 20 15 33 22 
+6 8 23 42 44 25 9 
+5 8 24 28 11 23 2
+5 9 25 29 37 17 2
+6 10 26 46 41 23 11 
+5 10 27 40 21 26 2
+3 12 29 20 
+6 13 30 45 26 21 22 
+3 13 31 30 
+3 14 32 27 
+6 14 33 34 38 50 32 
+3 15 34 33 
+5 16 35 19 39 36 2
+6 16 17 37 47 52 35 
+5 18 38 34 49 31 2
+6 18 19 35 51 54 38 
+3 23 41 42 
+6 24 43 56 57 47 28 
+3 24 40 43 
+3 25 44 39 
+3 26 45 46 
+6 27 32 48 55 43 40 
+3 28 47 37 
+5 30 48 32 50 45 2
+6 30 31 49 53 58 48 
+3 35 52 51 
+3 36 53 49 
+6 36 39 44 57 59 53 
+3 38 54 50 
+6 41 55 58 51 52 42 
+5 41 46 56 43 55 2
+5 42 52 47 57 44 2
+6 45 50 54 59 56 46 
+3 48 58 55 
+5 51 58 53 59 54 2
+3 56 59 57 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 4 3 
+4 5 11 12 0 
+4 4 13 14 5 
+4 7 15 16 1 
+4 6 17 18 7 
+4 0 19 17 6 
+4 9 20 21 2 
+4 8 18 20 9 
+4 16 22 8 1 
+4 10 23 24 4 
+4 2 25 26 10 
+4 5 16 27 11 
+4 11 28 29 12 
+4 29 19 0 12 
+4 4 30 31 13 
+4 31 28 14 13 
+4 14 22 16 5 
+4 7 21 23 15 
+4 10 16 15 23 
+4 17 32 20 18 
+4 18 33 34 7 
+4 19 14 35 17 
+4 20 36 23 21 
+4 21 37 25 2 
+4 8 38 33 18 
+4 19 8 22 14 
+4 23 39 40 24 
+4 40 30 4 24 
+4 37 39 26 25 
+4 26 27 16 10 
+4 26 30 11 27 
+4 31 41 29 28 
+4 11 42 43 28 
+4 29 38 8 19 
+4 26 44 31 30 
+4 43 35 14 28 
+4 34 37 21 7 
+4 32 45 46 20 
+4 17 47 45 32 
+4 33 46 37 34 
+4 43 47 17 35 
+4 36 48 39 23 
+4 46 48 36 20 
+4 29 47 33 38 
+4 37 49 40 39 
+4 40 42 11 30 
+4 48 44 26 39 
+4 31 50 45 41 
+4 41 29 47 45 
+4 40 50 43 42 
+4 48 50 31 44 
+4 45 49 37 46 
+4 33 51 48 46 
+4 43 51 33 47 
+4 49 40 50 45 
+4 50 43 51 48 
+small snub icosicosidodecahedron
+small hexagonal hexecontahedron
+|5/2 3 3
+(3.5/2.3.3.3.3)
+icosahedral group
+A5
+100{3}+12{5/2}
+36 60 180 112 60 2 0 0 -8 2 6 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6442062214  0.0000000000  0.7648518447
+ 0.2791862208  0.5805658531  0.7648518447
+-0.1419451564  0.6283734783  0.7648518447
+-0.6278134281  0.1444020607  0.7648518447
+-0.4022186612 -0.5032114906  0.7648518447
+ 0.2791862208 -0.5805658531  0.7648518447
+ 0.8003600018 -0.5032114906  0.3258865804
+ 0.9729065754 -0.1444020607  0.1805570281
+ 0.8003600018  0.5032114906  0.3258865804
+ 0.2915016934  0.9393752830  0.1805570281
+-0.3057103174  0.8142132953  0.4935563915
+-0.3144917300  0.2695640484  0.9101813971
+ 0.3669131520  0.1922096859  0.9101813971
+ 0.4804410603  0.7249679138  0.4935563915
+-0.0735183072  0.9808130393  0.1805570281
+-0.6671962580  0.6698112346  0.3258865804
+-0.9805179561  0.0773543625  0.1805570281
+-0.8927910249 -0.3110018047  0.3258865804
+-0.4946496843 -0.8501299015  0.1805570281
+ 0.1154210597 -0.8620209205  0.4935563915
+-0.3057103174 -0.8142132953  0.4935563915
+ 0.2915016934 -0.9393752830  0.1805570281
+ 0.6671962580 -0.6698112346 -0.3258865804
+ 0.9805179561 -0.0773543625 -0.1805570281
+ 0.8763982317  0.1665997441  0.4518524813
+ 0.5972120109 -0.4139661090  0.6870006366
+ 0.6584148454 -0.7471655971  0.0907384251
+ 0.8167527950 -0.3588094299 -0.4518524813
+ 0.8927910249  0.3110018047 -0.3258865804
+ 0.4946496843  0.8501299015 -0.1805570281
+ 0.8091414144  0.5805658531 -0.0907384251
+ 0.3057103174  0.8142132953 -0.4935563915
+-0.2915016934  0.9393752830 -0.1805570281
+-0.6584148454  0.7471655971 -0.0907384251
+-0.8167527950  0.3588094299  0.4518524813
+-0.6748076386 -0.2695640484  0.6870006366
+-0.0407327207 -0.3588094299  0.9325216558
+-0.1154210597  0.8620209205 -0.4935563915
+-0.8003600018  0.5032114906 -0.3258865804
+-0.8763982317 -0.1665997441 -0.4518524813
+-0.8091414144 -0.5805658531  0.0907384251
+-0.9729065754  0.1444020607 -0.1805570281
+-0.8003600018 -0.5032114906 -0.3258865804
+-0.4804410603 -0.7249679138 -0.4935563915
+ 0.0735183072 -0.9808130393 -0.1805570281
+-0.2915016934 -0.9393752830 -0.1805570281
+ 0.3057103174 -0.8142132953 -0.4935563915
+ 0.1419451564 -0.6283734783 -0.7648518447
+ 0.6278134281 -0.1444020607 -0.7648518447
+ 0.6748076386  0.2695640484 -0.6870006366
+ 0.3144917300 -0.2695640484 -0.9101813971
+ 0.4022186612  0.5032114906 -0.7648518447
+ 0.0407327207  0.3588094299 -0.9325216558
+-0.2791862208  0.5805658531 -0.7648518447
+-0.5972120109  0.4139661090 -0.6870006366
+-0.6442062214 -0.0000000000 -0.7648518447
+-0.3669131520 -0.1922096859 -0.9101813971
+-0.2791862208 -0.5805658531 -0.7648518447
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.3351898516  0.2107443956  0.9182780424
+ 0.0400368356  0.3526794657  0.9182780424
+-0.2794210283  0.2805161775  0.9182780424
+-0.3738998581 -0.1302471994  0.9182780424
+-0.0446605620 -0.3934092920  0.9182780424
+ 0.3351898516 -0.2107443956  0.9182780424
+ 0.6257191411 -0.3934092920  0.6735760428
+ 0.8213888526 -0.1889259414  0.5087707326
+ 0.8775384241  0.1302471994  0.4614780399
+ 0.6257191411  0.3934092920  0.6735760428
+ 0.4976880105  0.7344008871  0.4614780399
+ 0.0961864071  0.8472940016  0.5223418899
+-0.1237881524  0.6041536876  0.7871942677
+ 0.2560622612  0.5610323550  0.7871942677
+ 0.0961864071  0.8472940016  0.5223418899
+-0.3204039448  0.8272722230  0.4614780399
+-0.5216121103  0.5236564915  0.6735760428
+-0.8260125790  0.3236375102  0.4614780399
+-0.8428360805  0.0000000000  0.5087707326
+-0.6979814484 -0.2431403140  0.6735760428
+-0.6496432409 -0.6041536876  0.4614780399
+-0.2836640065 -0.8041726690  0.5223418899
+-0.0747391792 -0.6583680602  0.7281386332
+ 0.0961864071 -0.8472940016  0.5223418899
+ 0.4976880105 -0.7344008871  0.4614780399
+ 0.6385349796 -0.7667968054  0.0655418874
+ 0.8886466854 -0.4538847096 -0.0655418874
+ 0.9645866382 -0.1502689781  0.2167760402
+ 0.8089537623 -0.4739064882  0.3478598150
+ 0.8886466854 -0.4538847096 -0.0655418874
+ 0.9737248312 -0.0697717819 -0.2167760402
+ 0.9677742757  0.2431403140  0.0655418874
+ 0.7941678555  0.6041536876 -0.0655418874
+ 0.6071295333  0.7595733041  0.1538260133
+ 0.5105038490  0.8472940016 -0.1465561155
+ 0.1109723139  0.9775412010 -0.1791601123
+-0.1109723139  0.9775412010  0.1791601123
+-0.4214180402  0.8763359572  0.1538260133
+-0.6464556034  0.6970250235  0.3102438870
+-0.5216121103  0.5236564915  0.6735760428
+-0.6555937963  0.1302471994  0.7437959675
+-0.3738998581 -0.1302471994  0.9182780424
+ 0.0042429783  0.0373758635  0.9992922705
+ 0.3351898516 -0.2107443956  0.9182780424
+ 0.6681067932 -0.0200217787  0.7437959675
+ 0.6257191411  0.3934092920  0.6735760428
+ 0.7862472317  0.5343819058  0.3102438870
+ 0.3272692278  0.9277911978  0.1791601123
+ 0.1109723139  0.9775412010 -0.1791601123
+-0.3075881063  0.9401653375 -0.1465561155
+-0.6385349796  0.7667968054 -0.0655418874
+-0.8886466854  0.4538847096  0.0655418874
+-0.9645866382  0.1502689781 -0.2167760402
+-0.9677742757 -0.2431403140 -0.0655418874
+-0.8945972408 -0.2805161775  0.3478598150
+-0.9737248312  0.0697717819  0.2167760402
+-0.9677742757 -0.2431403140 -0.0655418874
+-0.7941678555 -0.6041536876  0.0655418874
+-0.6071295333 -0.7595733041 -0.1538260133
+-0.3272692278 -0.9277911978 -0.1791601123
+-0.1109723139 -0.9775412010  0.1791601123
+ 0.3075881063 -0.9401653375  0.1465561155
+ 0.4976880105 -0.7344008871  0.4614780399
+ 0.2438986592 -0.5934282734  0.7670438895
+-0.3707122206 -0.5236564915  0.7670438895
+-0.6496432409 -0.6041536876  0.4614780399
+-0.5105038490 -0.8472940016  0.1465561155
+-0.1109723139 -0.9775412010  0.1791601123
+ 0.1109723139 -0.9775412010 -0.1791601123
+ 0.4214180402 -0.8763359572 -0.1538260133
+ 0.3204039448 -0.8272722230 -0.4614780399
+ 0.5216121103 -0.5236564915 -0.6735760428
+ 0.8260125790 -0.3236375102 -0.4614780399
+ 0.8428360805  0.0000000000 -0.5087707326
+ 0.8945972408  0.2805161775 -0.3478598150
+ 0.9677742757  0.2431403140  0.0655418874
+ 0.6464556034 -0.6970250235 -0.3102438870
+ 0.5216121103 -0.5236564915 -0.6735760428
+ 0.6555937963 -0.1302471994 -0.7437959675
+ 0.6979814484  0.2431403140 -0.6735760428
+ 0.6496432409  0.6041536876 -0.4614780399
+ 0.2836640065  0.8041726690 -0.5223418899
+ 0.6496432409  0.6041536876 -0.4614780399
+ 0.3707122206  0.5236564915 -0.7670438895
+ 0.0747391792  0.6583680602 -0.7281386332
+-0.0961864071  0.8472940016 -0.5223418899
+-0.4976880105  0.7344008871 -0.4614780399
+-0.4976880105  0.7344008871 -0.4614780399
+-0.8089537623  0.4739064882 -0.3478598150
+-0.8886466854  0.4538847096  0.0655418874
+-0.2438986592  0.5934282734 -0.7670438895
+-0.6257191411  0.3934092920 -0.6735760428
+-0.8213888526  0.1889259414 -0.5087707326
+-0.6681067932  0.0200217787 -0.7437959675
+-0.6257191411 -0.3934092920 -0.6735760428
+-0.7862472317 -0.5343819058 -0.3102438870
+-0.8775384241 -0.1302471994 -0.4614780399
+-0.6257191411 -0.3934092920 -0.6735760428
+-0.4976880105 -0.7344008871 -0.4614780399
+-0.2560622612 -0.5610323550 -0.7871942677
+-0.0961864071 -0.8472940016 -0.5223418899
+-0.0961864071 -0.8472940016 -0.5223418899
+ 0.1237881524 -0.6041536876 -0.7871942677
+-0.0400368356 -0.3526794657 -0.9182780424
+ 0.2794210283 -0.2805161775 -0.9182780424
+ 0.3738998581  0.1302471994 -0.9182780424
+ 0.3738998581  0.1302471994 -0.9182780424
+-0.0042429783 -0.0373758635 -0.9992922705
+ 0.0446605620  0.3934092920 -0.9182780424
+-0.3351898516  0.2107443956 -0.9182780424
+-0.3351898516  0.2107443956 -0.9182780424
+-0.3351898516 -0.2107443956 -0.9182780424
+3 0 2 1 
+5 0 3 13 12 2 2
+3 0 4 3 
+3 0 5 4 
+3 0 6 5 
+3 0 1 6 
+3 1 7 6 
+5 1 8 26 25 7 2
+3 1 9 8 
+3 1 2 9 
+3 2 10 9 
+3 2 11 10 
+3 2 12 11 
+3 3 14 13 
+3 3 15 14 
+3 3 16 15 
+3 3 4 16 
+3 4 17 16 
+5 4 18 35 36 17 2
+3 4 5 18 
+3 5 19 18 
+3 5 20 19 
+5 5 6 21 37 20 2
+3 6 22 21 
+3 6 7 22 
+3 7 23 22 
+3 7 24 23 
+3 7 25 24 
+3 8 27 26 
+3 8 28 27 
+3 8 29 28 
+3 8 9 29 
+3 9 30 29 
+5 9 10 31 14 30 2
+3 10 32 31 
+3 10 33 32 
+3 10 11 33 
+5 11 34 15 16 33 2
+3 11 35 34 
+3 11 12 35 
+3 12 36 35 
+3 12 37 36 
+3 12 13 37 
+3 13 26 37 
+3 13 25 26 
+3 13 14 25 
+3 14 31 25 
+3 14 15 30 
+3 15 38 30 
+3 15 34 38 
+3 16 39 33 
+3 16 17 39 
+3 17 40 39 
+3 17 41 40 
+3 17 36 41 
+3 18 42 35 
+3 18 43 42 
+3 18 19 43 
+5 19 44 41 46 43 2
+3 19 45 44 
+3 19 20 45 
+3 20 27 45 
+3 20 26 27 
+3 20 37 26 
+3 21 36 37 
+3 21 41 36 
+3 21 46 41 
+3 21 22 46 
+3 22 47 46 
+5 22 23 45 27 47 2
+3 23 48 45 
+3 23 49 48 
+3 23 24 49 
+5 24 50 28 29 49 2
+3 24 31 50 
+3 24 25 31 
+3 27 28 47 
+3 28 51 47 
+3 28 50 51 
+3 29 52 49 
+3 29 30 52 
+3 30 38 52 
+3 31 32 50 
+3 32 53 50 
+5 32 54 52 38 53 2
+3 32 33 54 
+3 33 39 54 
+3 34 55 38 
+3 34 42 55 
+3 34 35 42 
+3 38 55 53 
+3 39 56 54 
+5 39 40 55 42 56 2
+3 40 57 55 
+3 40 44 57 
+3 40 41 44 
+3 42 43 56 
+3 43 58 56 
+3 43 46 58 
+3 44 48 57 
+3 44 45 48 
+3 46 47 58 
+3 47 51 58 
+5 48 59 58 51 57 2
+3 48 49 59 
+3 49 52 59 
+3 50 53 51 
+3 51 53 57 
+3 52 54 59 
+3 53 55 57 
+3 54 56 59 
+3 56 58 59 
+6 5 0 1 2 3 4 
+6 5 6 7 8 9 0 
+6 9 10 11 12 1 0 
+6 1 13 14 15 16 2 
+6 16 17 18 19 3 2 
+6 19 20 21 22 4 3 
+6 22 23 24 6 5 4 
+6 24 25 26 27 7 6 
+6 7 28 29 30 31 8 
+6 31 32 33 10 9 8 
+6 33 34 35 36 11 10 
+6 36 37 38 39 12 11 
+6 39 40 41 42 1 12 
+6 42 43 44 45 13 1 
+6 45 46 33 47 14 13 
+6 47 48 49 37 15 14 
+6 37 50 51 17 16 15 
+6 51 52 53 54 18 17 
+6 18 55 56 57 20 19 
+6 57 58 59 60 21 20 
+6 60 61 62 63 22 21 
+6 22 64 65 66 67 23 
+6 67 68 69 25 24 23 
+6 69 70 71 72 26 25 
+6 72 73 74 75 27 26 
+6 75 46 45 44 7 27 
+6 43 63 62 28 7 44 
+6 61 69 76 29 28 62 
+6 76 77 78 73 30 29 
+6 73 79 80 32 31 30 
+6 80 81 48 47 33 32 
+6 74 82 34 33 46 75 
+6 82 83 84 85 35 34 
+6 85 86 50 37 36 35 
+6 49 87 88 89 38 37 
+6 89 55 18 40 39 38 
+6 54 65 64 41 40 18 
+6 41 42 43 63 22 64 
+6 81 84 90 87 49 48 
+6 86 91 92 52 51 50 
+6 92 93 94 95 53 52 
+6 95 58 66 65 54 53 
+6 88 92 96 56 55 89 
+6 96 97 98 58 57 56 
+6 94 99 100 59 58 95 
+6 100 70 69 61 60 59 
+6 98 101 68 67 66 58 
+6 101 102 77 76 69 68 
+6 99 103 104 71 70 100 
+6 104 105 79 73 72 71 
+6 78 106 83 82 74 73 
+6 102 103 107 106 78 77 
+6 105 108 84 81 80 79 
+6 107 109 90 84 83 106 
+6 108 110 91 86 85 84 
+6 109 93 92 88 87 90 
+6 110 111 97 96 92 91 
+6 93 94 99 103 107 109 
+6 111 103 102 101 98 97 
+6 103 104 105 108 110 111 
+small dodecicosidodecahedron
+small dodecacronic hexecontahedron
+3/2 5|5
+(10.3/2.10.5)
+icosahedral group
+A5
+12{10}+12{5}+20{3/2}
+37 60 120 44 60 2 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4364663517  0.0000000000  0.8997205810
+-0.3947875239  0.1861335198  0.8997205810
+-0.0230394894  0.4358578416  0.8997205810
+-0.1650346033 -0.4040624406  0.8997205810
+ 0.7478962199  0.1861335198  0.6371856536
+ 0.4134268623  0.4358578416  0.7994411620
+ 0.5411827887 -0.4040624406  0.7374650726
+-0.5598221272 -0.2179289208  0.7994411620
+-0.5971008041  0.4873038812  0.6371856536
+-0.2253527696  0.7370282030  0.6371856536
+ 0.1694347542 -0.6537867624  0.7374650726
+-0.4551056902 -0.6219913614  0.6371856536
+ 0.8526126568 -0.2179289208  0.4749301452
+ 0.8153339799  0.4873038812  0.3126746369
+ 0.4808646224  0.7370282030  0.4749301452
+ 0.6875780535 -0.6219913614  0.3746507262
+-0.8641324015 -0.1664828812  0.4749301452
+-0.5296630440  0.7884742426  0.3126746369
+-0.8871718909  0.2693749604  0.3746507262
+ 0.0860770985  0.9231617228  0.3746507262
+ 0.3158300191 -0.8717156832  0.3746507262
+-0.1206363326 -0.8717156832  0.4749301452
+-0.7594159645 -0.5705453218  0.3126746369
+ 0.9847687342 -0.1664828812  0.0501397095
+ 0.6130206997  0.7884742426  0.0501397095
+ 0.9617292448  0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.9617292448 -0.2693749604  0.0501397095
+-0.8197341309  0.5705453218  0.0501397095
+-0.2182331759  0.9746077624  0.0501397095
+-0.9847687342  0.1664828812 -0.0501397095
+ 0.2182331759  0.9746077624 -0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+-0.2182331759 -0.9746077624  0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.7594159645  0.5705453218 -0.3126746369
+ 0.8641324015  0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.6875780535  0.6219913614 -0.3746507262
+-0.3158300191  0.8717156832 -0.3746507262
+-0.8526126568  0.2179289208 -0.4749301452
+ 0.1206363326  0.8717156832 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.4551056902  0.6219913614 -0.6371856536
+ 0.5598221272  0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.5411827887  0.4040624406 -0.7374650726
+-0.1694347542  0.6537867624 -0.7374650726
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.1650346033  0.4040624406 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517  0.0000000000 -0.8997205810
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1583346290  0.7071067812  0.6891517578
+-0.1028584649  0.1531185745  0.6891517578
+-0.7144788670  0.1207882584  0.6891517578
+ 0.1583346290 -0.2357022604  0.6891517578
+ 0.9436228948  0.1207882584  0.3081980354
+ 0.3933354313  0.1531185745  0.5751497609
+-0.5325411050  0.0900302522  0.5136633924
+ 0.2124281962 -0.3162277660  0.9245941063
+ 0.1180156646  0.5270462767  0.5136633924
+-0.2904769664 -0.3062371489  0.5751497609
+-0.4686190076 -0.8278950396  0.3081980354
+ 0.7033349793  0.0900302522  0.2297172526
+ 0.5561442379 -0.8278950396  0.0727556869
+ 0.5123816228 -0.3062371489  0.3906906553
+-0.3328569846  0.4955021156  0.3906906553
+-0.5561442379  0.8278950396 -0.0727556869
+ 0.0897623191 -0.5901345989  0.3906906553
+-0.3492879855 -0.6170765289  0.2297172526
+ 0.4686190076  0.8278950396 -0.3081980354
+ 0.4700016046  0.4955021156  0.2062315497
+ 0.4145254404 -0.6170765289  0.0542288872
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.6364300969 -0.2477510578  0.2062315497
+-0.4145254404  0.6170765289 -0.0542288872
+-0.6626223886  0.2477510578  0.0922295528
+ 0.0211900091  0.7071067812  0.0922295528
+ 0.6626223886 -0.2477510578 -0.0922295528
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.3492879855  0.6170765289 -0.2297172526
+ 0.6364300969  0.2477510578 -0.2062315497
+-0.7033349793 -0.0900302522 -0.2297172526
+-0.0211900091 -0.7071067812 -0.0922295528
+-0.1583346290 -0.7071067812 -0.6891517578
+-0.4700016046 -0.4955021156 -0.2062315497
+ 0.5325411050 -0.0900302522 -0.5136633924
+ 0.3328569846 -0.4955021156 -0.3906906553
+-0.2124281962  0.3162277660 -0.9245941063
+-0.5123816228  0.3062371489 -0.3906906553
+-0.0897623191  0.5901345989 -0.3906906553
+-0.1180156646 -0.5270462767 -0.5136633924
+ 0.2904769664  0.3062371489 -0.5751497609
+-0.3933354313 -0.1531185745 -0.5751497609
+-0.1583346290  0.2357022604 -0.6891517578
+ 0.1028584649 -0.1531185745 -0.6891517578
+10 0 2 9 18 30 32 25 14 5 1 
+3 0 3 2 2
+10 0 4 12 23 28 31 29 18 10 3 
+5 0 1 7 11 4 
+10 1 6 15 25 37 38 36 27 16 7 
+3 1 5 6 2
+5 2 8 17 19 9 
+10 2 3 6 5 13 16 21 22 12 8 
+5 3 10 20 15 6 
+3 4 8 12 2
+10 4 11 21 33 45 46 40 28 17 8 
+5 5 14 26 24 13 
+10 7 13 24 36 47 50 45 34 22 11 
+3 7 16 13 2
+3 9 10 18 2
+10 9 19 31 43 52 53 44 32 20 10 
+3 11 22 21 2
+5 12 22 34 35 23 
+10 14 15 20 30 42 53 56 49 38 26 
+3 14 25 15 2
+5 16 27 39 33 21 
+10 17 23 35 46 54 58 52 41 29 19 
+3 17 28 23 2
+5 18 29 41 42 30 
+3 19 29 31 2
+3 20 32 30 2
+3 24 27 36 2
+10 24 26 37 48 56 59 57 50 39 27 
+5 25 32 44 48 37 
+3 26 38 37 2
+5 28 40 51 43 31 
+3 33 34 45 2
+10 33 39 47 55 59 58 51 40 35 34 
+3 35 40 46 2
+5 36 38 49 55 47 
+3 39 50 47 2
+10 41 43 51 54 57 55 49 48 44 42 
+3 41 52 43 2
+3 42 44 53 2
+5 45 50 57 54 46 
+3 48 49 56 2
+3 51 58 54 2
+5 52 58 59 56 53 
+3 55 57 59 2
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 7 11 0 
+4 4 8 7 5 
+4 3 12 13 4 
+4 6 10 9 7 
+4 0 14 15 6 
+4 8 15 14 2 
+4 10 16 12 3 
+4 2 17 7 9 
+4 7 13 12 11 
+4 11 18 19 0 
+4 4 19 18 8 
+4 7 20 4 13 
+4 6 21 22 10 
+4 0 23 2 14 
+4 15 24 21 6 
+4 18 25 15 8 
+4 10 20 7 16 
+4 17 12 16 7 
+4 2 22 21 17 
+4 12 26 27 11 
+4 4 28 0 19 
+4 27 29 18 11 
+4 20 27 26 4 
+4 2 30 10 22 
+4 23 21 24 2 
+4 0 25 18 23 
+4 15 30 2 24 
+4 28 15 25 0 
+4 10 31 32 20 
+4 17 32 31 12 
+4 21 33 32 17 
+4 12 34 4 26 
+4 4 29 27 28 
+4 34 18 29 4 
+4 32 35 27 20 
+4 30 32 33 10 
+4 23 36 37 21 
+4 18 38 36 23 
+4 15 37 36 30 
+4 28 36 38 15 
+4 10 39 12 31 
+4 21 39 10 33 
+4 12 35 32 34 
+4 27 40 36 28 
+4 34 36 40 18 
+4 39 27 35 12 
+4 36 41 32 30 
+4 15 42 21 37 
+4 18 42 15 38 
+4 21 41 36 39 
+4 32 43 36 34 
+4 27 42 18 40 
+4 43 27 39 36 
+4 42 32 41 21 
+4 32 43 27 42 
+small stellated dodecahedron
+great dodecahedron
+5|2 5/2
+(5/2.5/2.5/2.5/2.5/2)
+icosahedral group
+A5
+12{5/2}
+38 12 30 12 12 3 0 0 -6 1 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000 -0.4472135955
+ 0.2763932023  0.8506508084 -0.4472135955
+-0.7236067977  0.5257311121 -0.4472135955
+-0.7236067977 -0.5257311121 -0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+-0.2763932023  0.8506508084  0.4472135955
+-0.2763932023 -0.8506508084  0.4472135955
+-0.8944271910 -0.0000000000  0.4472135955
+ 0.7236067977 -0.5257311121  0.4472135955
+ 0.7236067977  0.5257311121  0.4472135955
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.7236067977  0.5257311121  0.4472135955
+-0.2763932023  0.8506508084  0.4472135955
+-0.8944271910 -0.0000000000  0.4472135955
+-0.2763932023 -0.8506508084  0.4472135955
+ 0.7236067977 -0.5257311121  0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.2763932023  0.8506508084 -0.4472135955
+ 0.8944271910  0.0000000000 -0.4472135955
+-0.7236067977  0.5257311121 -0.4472135955
+-0.7236067977 -0.5257311121 -0.4472135955
+ 0.0000000000 -0.0000000000  1.0000000000
+5 0 2 9 6 1 2
+5 0 3 10 8 2 2
+5 0 4 6 7 3 2
+5 0 5 8 9 4 2
+5 0 1 7 10 5 2
+5 1 4 9 11 7 2
+5 1 3 5 2 4 2
+5 1 6 11 10 3 2
+5 2 5 10 11 9 2
+5 2 8 11 6 4 2
+5 3 7 11 8 5 2
+5 6 9 8 10 7 2
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 0 8 6 9 1 
+5 1 7 6 10 2 
+5 2 9 6 5 3 
+5 3 10 6 8 4 
+5 7 9 2 11 0 
+5 4 11 2 10 5 
+5 9 10 3 11 1 
+5 5 8 0 11 3 
+5 8 7 1 11 4 
+5 7 9 10 5 8 
+great dodecahedron
+small stellated dodecahedron
+5/2|2 5
+(5.5.5.5.5)/2
+icosahedral group
+A5
+12{5}
+39 12 30 12 12 3 0 0 -6 1 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000  0.4472135955
+-0.7236067977  0.5257311121  0.4472135955
+ 0.2763932023 -0.8506508084  0.4472135955
+ 0.2763932023  0.8506508084  0.4472135955
+-0.7236067977 -0.5257311121  0.4472135955
+ 0.7236067977  0.5257311121 -0.4472135955
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023  0.8506508084 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.2763932023  0.8506508084  0.4472135955
+-0.7236067977 -0.5257311121  0.4472135955
+ 0.8944271910  0.0000000000  0.4472135955
+-0.7236067977  0.5257311121  0.4472135955
+ 0.2763932023 -0.8506508084  0.4472135955
+ 0.7236067977  0.5257311121 -0.4472135955
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7236067977 -0.5257311121 -0.4472135955
+-0.8944271910 -0.0000000000 -0.4472135955
+-0.2763932023  0.8506508084 -0.4472135955
+-0.2763932023 -0.8506508084 -0.4472135955
+-0.0000000000 -0.0000000000 -1.0000000000
+5 0 2 9 6 1 
+5 0 3 10 8 2 
+5 0 4 6 7 3 
+5 0 5 8 9 4 
+5 0 1 7 10 5 
+5 1 4 9 11 7 
+5 1 3 5 2 4 
+5 1 6 11 10 3 
+5 2 5 10 11 9 
+5 2 8 11 6 4 
+5 3 7 11 8 5 
+5 6 9 8 10 7 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 0 8 6 9 1 
+5 1 7 6 10 2 
+5 2 9 6 5 3 
+5 3 10 6 8 4 
+5 7 9 2 11 0 
+5 4 11 2 10 5 
+5 9 10 3 11 1 
+5 5 8 0 11 3 
+5 8 7 1 11 4 
+5 7 9 10 5 8 
+great dodecadodecahedron
+medial rhombic triacontahedron
+2|5/2 5
+(5/2.5.5/2.5)
+icosahedral group
+A5
+12{5}+12{5/2}
+40 30 60 24 30 3 0 0 -6 2 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8660254038  0.0000000000  0.5000000000
+ 0.6454972244  0.5773502692  0.5000000000
+-0.8660254038 -0.0000000000  0.5000000000
+-0.6454972244 -0.5773502692  0.5000000000
+ 0.1102640897  0.5773502692  0.8090169944
+ 0.8660254038 -0.0000000000 -0.5000000000
+ 0.7557613141 -0.5773502692 -0.3090169944
+ 0.1784110449  0.9341723590 -0.3090169944
+ 0.6454972244  0.5773502692 -0.5000000000
+ 0.4670861795 -0.3568220898  0.8090169944
+-0.1102640897 -0.5773502692  0.8090169944
+-0.8660254038  0.0000000000 -0.5000000000
+-0.7557613141  0.5773502692 -0.3090169944
+-0.1784110449 -0.9341723590 -0.3090169944
+-0.6454972244 -0.5773502692 -0.5000000000
+-0.4670861795  0.3568220898  0.8090169944
+-0.3568220898  0.9341723590 -0.0000000000
+-0.7557613141  0.5773502692  0.3090169944
+ 0.7557613141 -0.5773502692  0.3090169944
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1102640897  0.5773502692 -0.8090169944
+-0.1102640897 -0.5773502692 -0.8090169944
+ 0.9341723590  0.3568220898  0.0000000000
+-0.4670861795  0.3568220898 -0.8090169944
+ 0.4670861795 -0.3568220898 -0.8090169944
+ 0.1784110449  0.9341723590  0.3090169944
+-0.1784110449 -0.9341723590  0.3090169944
+ 0.3568220898 -0.9341723590 -0.0000000000
+-0.9341723590 -0.3568220898  0.0000000000
+ 0.3035309991  0.1159385250  0.5257311121
+-0.3035309991  0.7946544723  0.5257311121
+-0.3035309991 -0.1159385250  0.5257311121
+ 0.3035309991 -0.7946544723  0.5257311121
+ 0.6070619982 -0.1159385250 -0.0000000000
+ 0.6070619982  0.7946544723 -0.0000000000
+ 0.9822469464 -0.1875924741 -0.0000000000
+ 0.3751849482  0.4911234732 -0.0000000000
+-0.6070619982  0.1159385250 -0.0000000000
+-0.6070619982 -0.7946544723 -0.0000000000
+-0.9822469464  0.1875924741 -0.0000000000
+-0.3751849482 -0.4911234732 -0.0000000000
+-0.1875924741  0.4911234732  0.3249196962
+-0.4911234732 -0.1875924741  0.8506508084
+ 0.3035309991 -0.7946544723 -0.5257311121
+ 0.3035309991  0.1159385250 -0.5257311121
+ 0.1875924741 -0.4911234732 -0.3249196962
+ 0.4911234732  0.1875924741 -0.8506508084
+-0.1875924741  0.4911234732 -0.3249196962
+-0.3035309991  0.7946544723 -0.5257311121
+ 0.1875924741 -0.4911234732  0.3249196962
+ 0.4911234732  0.1875924741  0.8506508084
+-0.3035309991 -0.1159385250 -0.5257311121
+-0.4911234732 -0.1875924741 -0.8506508084
+5 0 2 10 5 1 2
+5 0 3 13 8 2 
+5 0 4 16 11 3 2
+5 0 1 7 14 4 
+5 1 6 19 23 7 2
+5 1 5 17 21 6 
+5 2 9 25 28 10 
+5 2 8 23 26 9 2
+5 3 12 18 29 13 2
+5 3 11 28 22 12 
+5 4 15 24 17 16 
+5 4 14 29 27 15 2
+5 5 18 26 16 17 2
+5 5 10 27 29 18 
+5 6 20 15 27 19 
+5 6 21 25 9 20 2
+5 7 22 28 25 14 2
+5 7 23 8 24 22 
+5 8 13 21 17 24 2
+5 9 26 18 12 20 
+5 10 28 11 19 27 2
+5 11 16 26 23 19 
+5 12 22 24 15 20 2
+5 13 29 14 25 21 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 11 3 
+4 5 12 13 0 
+4 4 14 15 5 
+4 3 16 17 4 
+4 7 17 18 1 
+4 6 15 19 7 
+4 13 20 6 0 
+4 9 20 21 2 
+4 8 19 22 9 
+4 18 23 8 1 
+4 11 23 16 3 
+4 10 22 14 11 
+4 21 12 10 2 
+4 5 18 10 12 
+4 12 19 8 13 
+4 4 21 20 14 
+4 14 15 19 22 
+4 15 23 18 5 
+4 16 9 22 17 
+4 7 21 4 17 
+4 17 18 10 22 
+4 6 16 23 15 
+4 19 7 21 12 
+4 13 11 14 20 
+4 20 6 16 9 
+4 23 8 13 11 
+truncated great dodecahedron
+small stellapentakisdodecahedron
+2 5/2|5
+(10.10.5/2)
+icosahedral group
+A5
+12{10}+12{5/2}
+41 60 90 24 60 3 0 0 -6 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5135543437  0.0000000000  0.8580570704
+-0.4864456563  0.1646471601  0.8580570704
+ 0.4079815347 -0.3119120569  0.8580570704
+ 0.8580570704  0.1646471601  0.4864456563
+ 0.0905874952 -0.3119120569  0.9457826254
+-0.8655497273  0.1191398043  0.4864456563
+-0.7599769183  0.4310518612  0.4864456563
+ 0.2614078885  0.1927722527  0.9457826254
+ 0.5816638682 -0.6519492065  0.4864456563
+ 0.9925073431  0.1191398043 -0.0271086873
+ 0.9019198479  0.4310518612  0.0271086873
+-0.2492845149 -0.6519492065  0.7161141409
+-0.5256777172  0.4591769538  0.7161141409
+-0.9925073431 -0.1191398043  0.0271086873
+-0.7161141409  0.6974565623  0.0271086873
+-0.6964981104 -0.0455073558  0.7161141409
+ 0.1979290806  0.6693314697  0.7161141409
+ 0.4547062524 -0.8902288150  0.0271086873
+ 0.7161141409 -0.6974565623 -0.0271086873
+ 0.8188250096  0.4591769538  0.3445027268
+ 0.8655497273 -0.1191398043 -0.4864456563
+ 0.6283885859  0.6974565623 -0.3445027268
+ 0.9653986558 -0.0455073558  0.2567771718
+-0.3762421307 -0.8902288150  0.2567771718
+-0.6283885859 -0.6974565623  0.3445027268
+-0.1027108687  0.7710890108  0.6283885859
+-0.8188250096 -0.4591769538 -0.3445027268
+-0.8580570704 -0.1646471601 -0.4864456563
+-0.5816638682  0.6519492065 -0.4864456563
+-0.3716114141  0.8621037224 -0.3445027268
+-0.5499244642 -0.5501916655  0.6283885859
+-0.0756021814  0.9357361708  0.3445027268
+ 0.2417918580  0.9357361708  0.2567771718
+ 0.7945782625 -0.5501916655  0.2567771718
+ 0.0756021814 -0.9357361708 -0.3445027268
+ 0.7599769183 -0.4310518612 -0.4864456563
+ 0.3716114141 -0.8621037224  0.3445027268
+ 0.4108434749  0.7710890108  0.4864456563
+ 0.5256777172 -0.4591769538 -0.7161141409
+ 0.4864456563 -0.1646471601 -0.8580570704
+ 0.2492845149  0.6519492065 -0.7161141409
+ 0.1419429296  0.8621037224 -0.4864456563
+-0.2417918580 -0.9357361708 -0.2567771718
+-0.9019198479 -0.4310518612 -0.0271086873
+-0.1419429296 -0.8621037224  0.4864456563
+-0.9653986558  0.0455073558 -0.2567771718
+-0.4108434749 -0.7710890108 -0.4864456563
+-0.5135543437  0.0000000000 -0.8580570704
+-0.4547062524  0.8902288150 -0.0271086873
+-0.4079815347  0.3119120569 -0.8580570704
+-0.7945782625  0.5501916655 -0.2567771718
+ 0.3762421307  0.8902288150 -0.2567771718
+-0.1979290806 -0.6693314697 -0.7161141409
+ 0.6964981104  0.0455073558 -0.7161141409
+ 0.1027108687 -0.7710890108 -0.6283885859
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.0905874952  0.3119120569 -0.9457826254
+ 0.5499244642  0.5501916655 -0.6283885859
+-0.2614078885 -0.1927722527 -0.9457826254
+ 0.1400572398  0.8506508084  0.5067318540
+-0.4053854832 -0.7608452130  0.5067318540
+ 0.1400572398 -0.0474051448  0.5067318540
+ 0.6080782248 -0.7608452130  0.2266173744
+-0.3666746142  0.1241082803  0.3588694917
+ 0.9451803665  0.2351141009  0.2266173744
+ 0.4989267315  0.1241082803  0.1196231639
+-0.6946383593  0.2351141009  0.6798521231
+-0.6080782248  0.7608452130 -0.2266173744
+-0.9451803665 -0.2351141009 -0.2266173744
+ 0.3209826314 -0.4016228318  0.1196231639
+ 0.4053854832  0.7608452130 -0.5067318540
+ 0.6946383593 -0.2351141009 -0.6798521231
+-0.2139884209 -0.4016228318  0.2674855262
+ 0.2653282434 -0.0898055953  0.9599666027
+-0.4989267315 -0.1241082803 -0.1196231639
+-0.3209826314  0.4016228318 -0.1196231639
+ 0.0739311811  0.4490279766  0.2674855262
+-0.1400572398 -0.8506508084 -0.5067318540
+ 0.3666746142 -0.1241082803 -0.3588694917
+ 0.2139884209  0.4016228318 -0.2674855262
+-0.2653282434  0.0898055953 -0.9599666027
+-0.0739311811 -0.4490279766 -0.2674855262
+-0.1400572398  0.0474051448 -0.5067318540
+10 0 2 7 15 30 42 22 11 4 1 
+10 0 3 9 18 35 47 27 14 6 2 
+5 0 1 5 8 3 2
+10 1 4 10 21 39 55 43 24 12 5 
+5 2 6 13 16 7 2
+10 3 8 17 33 52 58 54 36 19 9 
+5 4 11 23 20 10 2
+10 5 12 25 44 46 51 49 32 17 8 
+10 6 14 28 48 57 41 52 33 26 13 
+10 7 16 31 24 43 53 59 50 29 15 
+5 9 19 37 34 18 2
+10 10 20 38 32 49 29 50 56 40 21 
+10 11 22 41 57 59 53 35 18 34 23 
+5 12 24 31 45 25 2
+10 13 26 38 20 23 34 37 45 31 16 
+5 14 27 46 44 28 2
+5 15 29 49 51 30 2
+5 17 32 38 26 33 2
+10 19 36 40 56 48 28 44 25 45 37 
+5 21 40 36 54 39 2
+5 22 42 58 52 41 2
+10 27 47 55 39 54 58 42 30 51 46 
+5 35 53 43 55 47 2
+5 48 56 50 59 57 2
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 0 9 4 
+3 5 7 2 
+3 1 10 5 
+3 3 11 6 
+3 6 12 0 
+3 7 13 3 
+3 4 14 8 
+3 8 15 1 
+3 0 16 9 
+3 9 14 4 
+3 5 17 7 
+3 1 12 10 
+3 10 18 5 
+3 11 14 6 
+3 3 19 11 
+3 12 20 0 
+3 14 12 6 
+3 13 9 3 
+3 7 18 13 
+3 14 17 8 
+3 15 21 1 
+3 8 18 15 
+3 16 11 9 
+3 0 21 16 
+3 13 14 9 
+3 17 11 7 
+3 5 8 17 
+3 14 10 12 
+3 1 22 12 
+3 18 19 5 
+3 14 18 10 
+3 11 14 17 
+3 3 21 19 
+3 18 11 19 
+3 12 8 20 
+3 20 21 0 
+3 9 22 3 
+3 7 15 18 
+3 18 13 14 
+3 7 21 15 
+3 21 22 1 
+3 8 23 18 
+3 16 7 11 
+3 11 23 9 
+3 21 16 7 
+3 5 20 8 
+3 9 12 22 
+3 21 5 19 
+3 3 21 22 
+3 18 11 23 
+3 12 23 8 
+3 20 21 5 
+3 23 9 12 
+rhombidodecadodecahedron
+medial deltoidal hexecontahedron
+5/2 5|2
+(4.5/2.4.5)
+icosahedral group
+A5
+12{5}+30{4}+12{5/2}
+42 60 120 54 60 3 0 0 -6 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6998542122  0.0000000000  0.7142857143
+-0.1166423687  0.6900655593  0.7142857143
+-0.5248906592  0.4629100499  0.7142857143
+-0.3689536881 -0.5947008445  0.7142857143
+ 0.5832118435  0.6900655593  0.4285714286
+ 0.8748177653  0.4629100499  0.1428571429
+ 0.7634342145 -0.5947008445  0.2519902889
+-0.4528017108  0.0364260797  0.8908668539
+-0.6022384255  0.7854302742  0.1428571429
+-0.8938443472 -0.1317907946  0.4285714286
+-0.3499271061  0.9258200998  0.1428571429
+ 0.2077578990  0.4039714148  0.8908668539
+ 0.1028746047 -0.9622461795  0.2519902889
+-0.8545497448 -0.4993361296  0.1428571429
+ 0.9469067137  0.0364260797  0.3194382825
+ 0.5301494771  0.7854302742 -0.3194382825
+ 0.9383977675 -0.1317907946 -0.3194382825
+ 0.3499271061  0.9258200998 -0.1428571429
+ 0.4750784209  0.4039714148  0.7817337079
+ 0.7103718480 -0.4993361296 -0.4960194221
+-0.9383977675  0.1317907946  0.3194382825
+-0.0891068406 -0.6172133998  0.7817337079
+-0.2024990811  0.8443689093 -0.4960194221
+-0.9711921135  0.1907294297 -0.1428571429
+-0.9469067137 -0.0364260797 -0.3194382825
+-0.5301494771 -0.7854302742  0.3194382825
+ 0.3827214521  0.8668814647  0.3194382825
+-0.6107473716  0.6172133998 -0.4960194221
+ 0.5714527692 -0.2496680648  0.7817337079
+-0.3827214521 -0.8668814647 -0.3194382825
+ 0.0498122382 -0.8668814647 -0.4960194221
+-0.5937294793 -0.1907294297  0.7817337079
+ 0.8938443472  0.1317907946 -0.4285714286
+ 0.6107473716 -0.6172133998  0.4960194221
+ 0.5937294793  0.1907294297 -0.7817337079
+ 0.4528017108 -0.0364260797 -0.8908668539
+ 0.6022384255 -0.7854302742 -0.1428571429
+-0.0498122382  0.8668814647  0.4960194221
+ 0.0891068406  0.6172133998 -0.7817337079
+ 0.1389190789 -0.2496680648  0.9583148475
+ 0.9711921135 -0.1907294297  0.1428571429
+-0.8748177653 -0.4629100499 -0.1428571429
+-0.7634342145  0.5947008445 -0.2519902889
+-0.3499271061 -0.9258200998  0.1428571429
+-0.5714527692  0.2496680648 -0.7817337079
+-0.1389190789  0.2496680648 -0.9583148475
+-0.7103718480  0.4993361296  0.4960194221
+-0.5832118435 -0.6900655593 -0.4285714286
+-0.4750784209 -0.4039714148 -0.7817337079
+ 0.2024990811 -0.8443689093  0.4960194221
+-0.1028746047  0.9622461795 -0.2519902889
+ 0.8545497448  0.4993361296 -0.1428571429
+ 0.3499271061 -0.9258200998 -0.1428571429
+-0.2077578990 -0.4039714148 -0.8908668539
+ 0.5248906592 -0.4629100499 -0.7142857143
+ 0.3689536881  0.5947008445 -0.7142857143
+ 0.1166423687 -0.6900655593 -0.7142857143
+-0.6998542122  0.0000000000 -0.7142857143
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.3126527364  0.3699357065  0.7658396707
+-0.1612652036  0.2898289539  0.7658396707
+-0.4791790224 -0.0706514331  0.7658396707
+ 0.3126527364 -0.5619055661  0.7658396707
+ 0.8782468497 -0.0706514331  0.2116728790
+ 0.6511655506  0.2898289539  0.4341662042
+ 0.0501361976  0.9911632216  0.1228081018
+-0.5655941134  0.4405871397  0.5541667917
+-0.0762151731  0.7128849670  0.5541667917
+-0.8686716880  0.4799246488  0.1228081018
+-0.5895677240 -0.4005337633  0.4341662042
+-0.4029638493 -0.7835364001  0.2116728790
+ 0.7918317588  0.4405871397 -0.0000000000
+ 0.7064275445  0.4799246488 -0.5202234672
+ 0.4422753728  0.7128849670  0.3424939127
+ 0.4359714769 -0.7835364001 -0.1308210337
+ 0.7249728497 -0.4005337633 -0.1024927377
+-0.7064275445 -0.4799246488  0.5202234672
+ 0.0636073813 -0.1143164201  0.8966607045
+-0.6292014946  0.5549035598 -0.3424939127
+-0.7249728497  0.4005337633  0.1024927377
+-0.7918317588 -0.4405871397 -0.0000000000
+ 0.0418424850  0.8272013871  0.1024927377
+-0.1398225544  0.8272013871 -0.3424939127
+ 0.7802348436  0.3472767383  0.5202234672
+-0.0418424850 -0.8272013871 -0.1024927377
+-0.8389353262  0.0000000000  0.3424939127
+-0.7802348436 -0.3472767383 -0.5202234672
+ 0.5820979272 -0.1143164201  0.6849878255
+ 0.8686716880 -0.4799246488 -0.1228081018
+ 0.5895677240  0.4005337633 -0.4341662042
+ 0.2097338315  0.5549035598 -0.6849878255
+ 0.5655941134 -0.4405871397 -0.5541667917
+-0.1932300177  0.3472767383  0.9176388327
+ 0.1932300177 -0.3472767383 -0.9176388327
+ 0.8389353262 -0.0000000000 -0.3424939127
+-0.8782468497  0.0706514331 -0.2116728790
+ 0.1398225544 -0.8272013871  0.3424939127
+ 0.2609325806 -0.4689530983  0.6391516797
+-0.2609325806  0.4689530983 -0.6391516797
+-0.5820979272  0.1143164201 -0.6849878255
+-0.6511655506 -0.2898289539 -0.4341662042
+-0.0501361976 -0.9911632216 -0.1228081018
+-0.2097338315 -0.5549035598  0.6849878255
+ 0.4029638493  0.7835364001 -0.2116728790
+ 0.6292014946 -0.5549035598  0.3424939127
+ 0.0762151731 -0.7128849670 -0.5541667917
+-0.4422753728 -0.7128849670 -0.3424939127
+ 0.4791790224  0.0706514331 -0.7658396707
+ 0.1612652036 -0.2898289539 -0.7658396707
+-0.0636073813  0.1143164201 -0.8966607045
+-0.4359714769  0.7835364001  0.1308210337
+-0.3126527364  0.5619055661 -0.7658396707
+-0.3126527364 -0.3699357065 -0.7658396707
+4 0 2 5 1 
+5 0 3 12 8 2 2
+4 0 4 10 3 
+5 0 1 7 13 4 
+4 1 6 17 7 
+5 1 5 15 19 6 2
+5 2 9 23 16 5 
+4 2 8 21 9 
+4 3 11 27 12 
+5 3 10 25 28 11 
+5 4 14 32 26 10 2
+4 4 13 30 14 
+4 5 16 33 15 
+5 6 18 39 36 17 
+4 6 19 38 18 
+4 7 20 31 13 
+5 7 17 37 41 20 2
+5 8 22 44 42 21 
+4 8 12 29 22 
+4 9 24 45 23 
+5 9 21 43 47 24 2
+4 10 26 48 25 
+5 11 18 38 51 27 2
+4 11 28 39 18 
+5 12 27 52 41 29 
+5 13 31 44 53 30 2
+4 14 24 47 32 
+5 14 30 54 45 24 
+4 15 34 40 19 
+5 15 33 55 53 34 
+5 16 35 52 56 33 2
+4 16 23 46 35 
+4 17 36 57 37 
+5 19 40 32 47 38 
+5 20 35 46 49 31 
+4 20 41 52 35 
+4 21 42 58 43 
+4 22 34 53 44 
+5 22 29 50 40 34 2
+5 23 45 39 28 46 2
+4 25 49 46 28 
+5 25 48 58 42 49 2
+5 26 50 37 57 48 
+4 26 32 40 50 
+4 27 51 56 52 
+4 29 41 37 50 
+4 30 53 55 54 
+4 31 49 42 44 
+4 33 56 59 55 
+5 36 54 55 59 57 2
+4 36 39 45 54 
+4 38 47 43 51 
+5 43 58 59 56 51 
+4 48 57 59 58 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 11 3 
+4 5 12 6 0 
+4 4 13 14 5 
+4 3 15 16 4 
+4 7 17 18 1 
+4 6 19 20 7 
+4 9 21 10 2 
+4 8 22 23 9 
+4 18 24 8 1 
+4 11 25 15 3 
+4 10 26 27 11 
+4 5 28 29 12 
+4 12 30 31 6 
+4 16 32 13 4 
+4 13 23 22 14 
+4 14 33 28 5 
+4 15 34 35 16 
+4 20 36 17 7 
+4 17 37 38 18 
+4 31 39 19 6 
+4 19 27 26 20 
+4 9 40 41 21 
+4 21 42 43 10 
+4 24 44 22 8 
+4 23 39 40 9 
+4 38 45 24 18 
+4 27 46 25 11 
+4 25 47 34 15 
+4 43 33 26 10 
+4 29 48 30 12 
+4 28 38 37 29 
+4 30 35 34 31 
+4 32 49 50 13 
+4 16 45 42 32 
+4 22 51 33 14 
+4 50 39 23 13 
+4 43 38 28 33 
+4 35 24 45 16 
+4 36 41 47 17 
+4 20 51 52 36 
+4 25 37 17 47 
+4 50 27 19 39 
+4 34 40 39 31 
+4 26 20 51 33 
+4 41 53 42 21 
+4 40 41 47 34 
+4 42 43 38 45 
+4 44 52 51 22 
+4 30 44 24 35 
+4 46 29 37 25 
+4 49 46 27 50 
+4 49 48 29 46 
+4 48 52 44 30 
+4 53 49 32 42 
+4 52 53 41 36 
+4 49 48 52 53 
+small rhombidodecahedron
+small rhombidodecacron
+2 5/2 5|
+(10.4.10/9.4/3)
+icosahedral group
+A5
+6{10}+15{4}+15{4/3}+6{10/9}
+43 60 120 42 60 0 0 1 -18 4 4 120 5 0 1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4364663517  0.0000000000  0.8997205810
+-0.3947875239  0.1861335198  0.8997205810
+-0.1650346033 -0.4040624406  0.8997205810
+-0.0230394894  0.4358578416  0.8997205810
+ 0.7478962199  0.1861335198  0.6371856536
+ 0.5411827887 -0.4040624406  0.7374650726
+ 0.4134268623  0.4358578416  0.7994411620
+-0.5598221272 -0.2179289208  0.7994411620
+-0.5971008041  0.4873038812  0.6371856536
+-0.4551056902 -0.6219913614  0.6371856536
+ 0.1694347542 -0.6537867624  0.7374650726
+-0.2253527696  0.7370282030  0.6371856536
+ 0.8526126568 -0.2179289208  0.4749301452
+ 0.8153339799  0.4873038812  0.3126746369
+ 0.6875780535 -0.6219913614  0.3746507262
+ 0.4808646224  0.7370282030  0.4749301452
+-0.8641324015 -0.1664828812  0.4749301452
+-0.5296630440  0.7884742426  0.3126746369
+-0.8871718909  0.2693749604  0.3746507262
+-0.1206363326 -0.8717156832  0.4749301452
+-0.7594159645 -0.5705453218  0.3126746369
+ 0.3158300191 -0.8717156832  0.3746507262
+ 0.0860770985  0.9231617228  0.3746507262
+ 0.9847687342 -0.1664828812  0.0501397095
+ 0.6130206997  0.7884742426  0.0501397095
+ 0.9617292448  0.2693749604 -0.0501397095
+ 0.8197341309 -0.5705453218 -0.0501397095
+-0.9617292448 -0.2693749604  0.0501397095
+-0.8197341309  0.5705453218  0.0501397095
+-0.2182331759  0.9746077624  0.0501397095
+-0.9847687342  0.1664828812 -0.0501397095
+-0.2182331759 -0.9746077624  0.0501397095
+-0.6130206997 -0.7884742426 -0.0501397095
+ 0.2182331759 -0.9746077624 -0.0501397095
+ 0.2182331759  0.9746077624 -0.0501397095
+ 0.8871718909 -0.2693749604 -0.3746507262
+ 0.7594159645  0.5705453218 -0.3126746369
+ 0.8641324015  0.1664828812 -0.4749301452
+ 0.5296630440 -0.7884742426 -0.3126746369
+-0.8153339799 -0.4873038812 -0.3126746369
+-0.6875780535  0.6219913614 -0.3746507262
+-0.3158300191  0.8717156832 -0.3746507262
+-0.8526126568  0.2179289208 -0.4749301452
+-0.0860770985 -0.9231617228 -0.3746507262
+-0.4808646224 -0.7370282030 -0.4749301452
+ 0.1206363326  0.8717156832 -0.4749301452
+ 0.5971008041 -0.4873038812 -0.6371856536
+ 0.4551056902  0.6219913614 -0.6371856536
+ 0.5598221272  0.2179289208 -0.7994411620
+ 0.2253527696 -0.7370282030 -0.6371856536
+-0.7478962199 -0.1861335198 -0.6371856536
+-0.5411827887  0.4040624406 -0.7374650726
+-0.1694347542  0.6537867624 -0.7374650726
+-0.4134268623 -0.4358578416 -0.7994411620
+ 0.3947875239 -0.1861335198 -0.8997205810
+ 0.1650346033  0.4040624406 -0.8997205810
+ 0.0230394894 -0.4358578416 -0.8997205810
+-0.4364663517  0.0000000000 -0.8997205810
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1583346290  0.7071067812  0.6891517578
+-0.2144012325 -0.0834626339  0.6891517578
+-0.7144788670  0.1207882584  0.6891517578
+ 0.1583346290  0.1669252677  0.6891517578
+ 0.9436228948  0.1207882584  0.3081980354
+ 0.4936927550 -0.0834626339  0.5264650961
+-0.2375019436  0.3535533906  0.5886058714
+ 0.2124281962 -0.3162277660  0.9245941063
+-0.4686190076 -0.8278950396  0.3081980354
+-0.1094065379 -0.4885987690  0.5264650961
+ 0.4705920439  0.3535533906  0.4259192097
+ 0.3282196136 -0.4885987690  0.4259192097
+ 0.5561442379 -0.8278950396  0.0727556869
+-0.5052431105 -0.3019706461  0.4259192097
+-0.5426208461  0.4051361351  0.2632325481
+-0.5561442379  0.8278950396 -0.0727556869
+-0.1698849846  0.6555240367  0.2632325481
+ 0.6404770285 -0.3019706461  0.1626866616
+ 0.4686190076  0.8278950396 -0.3081980354
+ 0.6030992928  0.4051361351  0.0000000000
+ 0.2677411669  0.6555240367  0.1626866616
+-0.9436228948 -0.1207882584 -0.3081980354
+-0.7080939875  0.0000000000  0.1626866616
+ 0.0373777356 -0.7071067812  0.1626866616
+-0.6030992928 -0.4051361351 -0.0000000000
+ 0.7080939875 -0.0000000000 -0.1626866616
+ 0.7144788670 -0.1207882584 -0.6891517578
+ 0.5426208461 -0.4051361351 -0.2632325481
+-0.6404770285  0.3019706461 -0.1626866616
+-0.0373777356  0.7071067812 -0.1626866616
+-0.2677411669 -0.6555240367 -0.1626866616
+-0.1583346290 -0.7071067812 -0.6891517578
+ 0.1698849846 -0.6555240367 -0.2632325481
+ 0.5052431105  0.3019706461 -0.4259192097
+-0.4705920439 -0.3535533906 -0.4259192097
+-0.2124281962  0.3162277660 -0.9245941063
+-0.3282196136  0.4885987690 -0.4259192097
+-0.4936927550  0.0834626339 -0.5264650961
+ 0.1094065379  0.4885987690 -0.5264650961
+ 0.2375019436 -0.3535533906 -0.5886058714
+ 0.2144012325  0.0834626339 -0.6891517578
+-0.1583346290 -0.1669252677 -0.6891517578
+10 0 2 9 18 30 35 25 14 5 1 
+4 0 3 8 2 
+10 0 4 12 18 29 31 28 21 10 3 9
+4 0 1 7 4 3
+10 1 6 15 27 36 38 37 25 16 7 9
+4 1 5 13 6 
+4 2 4 12 9 3
+10 2 8 10 20 22 15 13 5 7 4 9
+10 3 11 22 34 44 45 40 28 17 8 
+4 3 10 20 11 3
+4 5 14 16 7 3
+4 6 11 22 15 3
+10 6 13 24 36 47 50 44 32 20 11 
+4 8 17 21 10 3
+4 9 19 29 18 
+10 9 12 23 35 46 53 52 43 31 19 9
+4 12 23 30 18 3
+4 13 15 27 24 3
+10 14 26 38 49 56 53 42 30 23 16 9
+4 14 25 37 26 
+4 16 25 35 23 3
+10 17 19 29 41 52 58 54 45 33 21 9
+4 17 28 31 19 
+4 20 22 34 32 
+4 21 28 40 33 3
+4 24 26 38 36 
+10 24 27 39 50 57 59 56 48 37 26 9
+4 27 39 47 36 3
+4 29 41 43 31 3
+4 30 42 46 35 
+4 32 33 45 44 3
+10 32 34 39 47 55 59 58 51 40 33 
+4 34 39 50 44 
+4 37 38 49 48 3
+4 40 45 54 51 
+10 41 42 46 48 49 55 57 54 51 43 9
+4 41 52 53 42 
+4 43 52 58 51 3
+4 46 53 56 48 
+4 47 55 57 50 
+4 49 55 59 56 3
+4 54 57 59 58 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 6 7 3 
+4 5 7 10 0 
+4 4 11 12 5 
+4 10 4 3 7 
+4 7 13 8 1 
+4 0 14 15 6 
+4 9 7 13 2 
+4 8 11 12 9 
+4 2 16 15 6 
+4 12 17 7 5 
+4 10 18 19 0 
+4 4 17 7 11 
+4 18 20 4 10 
+4 13 21 22 8 
+4 0 16 2 14 
+4 14 21 22 15 
+4 12 23 7 9 
+4 21 24 2 13 
+4 8 23 7 11 
+4 16 18 20 15 
+4 12 25 26 17 
+4 19 4 20 0 
+4 18 25 26 19 
+4 4 27 26 17 
+4 22 2 24 8 
+4 2 28 21 14 
+4 0 29 18 16 
+4 28 15 22 2 
+4 12 30 31 23 
+4 21 30 31 24 
+4 8 32 31 23 
+4 29 15 20 0 
+4 12 27 4 25 
+4 26 33 4 19 
+4 18 33 4 25 
+4 27 31 32 26 
+4 31 34 8 24 
+4 28 35 36 21 
+4 29 35 36 18 
+4 35 37 15 28 
+4 12 32 8 30 
+4 21 34 8 30 
+4 35 38 15 29 
+4 12 39 31 27 
+4 26 38 35 33 
+4 18 40 35 33 
+4 39 26 32 12 
+4 31 37 35 34 
+4 36 15 37 21 
+4 38 18 36 15 
+4 21 41 35 34 
+4 39 35 40 31 
+4 26 40 18 38 
+4 41 26 39 35 
+4 31 41 21 37 
+4 40 31 41 26 
+snub dodecadodecahedron
+medial pentagonal hexecontahedron
+|2 5/2 5
+(3.3.5/2.3.5)
+icosahedral group
+A5
+12{5}+60{3}+12{5/2}
+44 60 150 84 60 3 0 0 -6 3 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7217483383  0.0000000000  0.6921555722
+ 0.2952223438  0.6586079498  0.6921555722
+-0.4802341493  0.5387910779  0.6921555722
+-0.7128072909  0.1132538291  0.6921555722
+-0.3949112124 -0.6041239924  0.6921555722
+ 0.7729021303 -0.6041239924  0.1940528249
+ 0.9929356725  0.1132538291 -0.0353881415
+ 0.6298389795  0.6967741838  0.3432325693
+ 0.8934465412  0.2897320856  0.3432325693
+ 0.5094943059  0.8597460274 -0.0353881415
+-0.7452206567  0.6658782563 -0.0353881415
+-0.9392275176  0.0065630428  0.3432325693
+-0.4160062641 -0.2197373699  0.8824138918
+-0.0396950161  0.4687963622  0.8824138918
+-0.5127015231  0.7869743017  0.3432325693
+-0.9061974527 -0.4015688916  0.1324711369
+-0.6380905382 -0.7691476741 -0.0353881415
+ 0.0827685741 -0.9774931531  0.1940528249
+ 0.4161165893 -0.7691476741 -0.4850348850
+ 0.8899385998 -0.1459468565 -0.4320981413
+ 0.7539503920 -0.5893107329 -0.2902958256
+ 0.6655112749  0.0439566123 -0.7450923159
+ 0.0780084845  0.9881123794 -0.1324711369
+-0.1041736883  0.7897513117  0.6045169215
+ 0.3520254514  0.2279778217  0.9078018475
+ 0.6780508743 -0.4180984375  0.6045169215
+ 0.8524892978  0.2817520197 -0.4403155647
+ 0.5063993531  0.4753594049 -0.7194394563
+-0.1335348318  0.8642393240 -0.4850348850
+-0.6262555055  0.3003513119 -0.7194394563
+-0.9884363197 -0.0737905134 -0.1324711369
+-0.8685334856  0.3336886979 -0.3664716051
+-0.8461505251 -0.4469425270 -0.2902958256
+ 0.0004392467 -0.8131042863  0.5821178804
+ 0.3680207594 -0.2011380776  0.9078018475
+ 0.2609051739  0.9140614801  0.3105158625
+-0.5824195190  0.6885337320 -0.4320981413
+-0.8256133779 -0.0460263585 -0.5623558700
+-0.4967433944 -0.7479092215 -0.4403155647
+-0.3220982637 -0.8943336110  0.3105158625
+-0.7559043639 -0.2995786473  0.5821178804
+-0.0593841233 -0.8247602084 -0.5623558700
+-0.2654045267 -0.9535247958 -0.1426565840
+-0.2602607645 -0.5330006997 -0.8050929068
+ 0.8544020838  0.5193160172 -0.0175486021
+ 0.9206031564 -0.1699152137  0.3515944377
+ 0.4508730059 -0.7963143545  0.4032331602
+ 0.1682912484 -0.5593947155 -0.8116376088
+-0.0520696708 -0.1637734841 -0.9851228326
+ 0.1000551755  0.5846489317 -0.8050929068
+-0.4001067482  0.9095681836 -0.1122511001
+-0.7889119713  0.4637034829  0.4032331602
+-0.0507662577 -0.4452651179  0.8939584788
+ 0.5039717878 -0.8635418251 -0.0175486021
+ 0.6117806625 -0.4310104555 -0.6632905911
+ 0.2552292055  0.2091181436 -0.9439955798
+ 0.2944167902  0.8325793470 -0.4691805458
+-0.2044629478  0.2361469744 -0.9499628990
+-0.4635135922 -0.0992132343 -0.8805179635
+ 0.3176067784  0.2056876888  0.7446363937
+-0.0577804302  0.3739557632  0.7446363937
+-0.2958960533  0.1617190385  0.7446363937
+-0.3459479328 -0.1533020508  0.7446363937
+ 0.3176067784 -0.5870626674  0.7446363937
+ 0.7768898692 -0.1533020508  0.2657168836
+ 0.7322102858  0.2529771921  0.3123067203
+ 0.5190711176  0.3361595084  0.5345585472
+ 0.5303477767  0.5646774283  0.3123067203
+-0.1488707758  0.9634937711  0.2225247069
+-0.6760448370  0.3782760112  0.3123067203
+-0.5732289698  0.1016922995  0.5989424632
+-0.3951316587  0.4275555494  0.5989424632
+-0.9507295624  0.3065030456  0.0465744808
+-0.6289594872 -0.2787147143  0.4737012997
+-0.5414902536 -0.5327952207  0.3018417444
+-0.2967642069 -0.7341596510  0.2657168836
+ 0.3971877186 -0.7341596510 -0.0302716515
+ 0.6492723420 -0.4744621543 -0.2258228062
+ 0.7771543287 -0.2505446113 -0.0380713515
+ 0.7534079011 -0.1349478249 -0.3344106292
+ 0.6624305789  0.6517935348 -0.3692572492
+ 0.1885313770  0.7728460386  0.2546169088
+ 0.2741087173  0.5354509080  0.5795011528
+ 0.6007291180  0.0311093314  0.5795011528
+ 0.9507295624 -0.3065030456 -0.0465744808
+ 0.7043859914  0.4469827888 -0.0413716263
+ 0.5414902536  0.5327952207 -0.3018417444
+ 0.2755665915  0.6868701477 -0.3872173856
+-0.4700250476  0.5716677363 -0.3872173856
+-0.7370165274  0.2787147143 -0.2771093578
+-0.7771543287  0.2505446113  0.0380713515
+-0.8288344054 -0.0333202496 -0.0979190443
+-0.6624305789 -0.6517935348  0.3692572492
+-0.0148490159 -0.3853801636  0.7408957323
+-0.0273832159  0.0149660237  0.8346801947
+ 0.6350041919  0.4112397892  0.6539506954
+-0.0910347123  0.6776531605  0.4797538171
+-0.1216913541  0.7875881686  0.1818982454
+-0.3176510871  0.7694052113 -0.0691249417
+-0.6959924610 -0.3733640806 -0.2717694010
+-0.5387413071 -0.6382961364  0.0008343070
+-0.7440492812 -0.3568156856  0.1293757453
+-0.6350041919 -0.4112397892 -0.6539506954
+-0.1919768421 -0.8030658240 -0.1260754705
+ 0.1216913541 -0.7875881686 -0.1818982454
+-0.0342127958 -0.7044618897 -0.4474681893
+ 0.3619836047 -0.1978385309 -0.9109488381
+ 0.7029212391  0.2650636348 -0.3651134768
+ 0.8322798705  0.0635400349 -0.0306223940
+ 0.6637849964 -0.4858056897  0.1450763943
+ 0.1488707758 -0.9634937711 -0.2225247069
+ 0.4958659056 -0.3450204858 -0.5768385544
+ 0.2958960533 -0.1617190385 -0.7446363937
+ 0.2228298392  0.1451701761 -0.7917937437
+-0.1262830522  0.7062176385 -0.4277547049
+-0.4038726796  0.6755266122  0.2796703500
+-0.3619836047  0.1978385309  0.9109488381
+ 0.3058451155 -0.1984352346  0.7514965554
+ 0.2596211293 -0.4798823043  0.6086877063
+ 0.3692908006 -0.6542027999  0.3651134768
+ 0.5370111450  0.0186945890 -0.6394797825
+ 0.4378962749  0.4133221760 -0.5788579109
+ 0.0525929431  0.4921159726 -0.6728452286
+-0.2596211293  0.4798823043 -0.6086877063
+-0.1805976074  0.2252439638 -0.7837821833
+-0.7911518284  0.0282120159  0.2663601255
+-0.6425873810  0.5330951931 -0.0235758922
+-0.3176067784  0.5870626674 -0.7446363937
+-0.6802657495 -0.0663548917 -0.4801045596
+-0.5190711176 -0.3361595084 -0.5345585472
+-0.4284272985 -0.6038350569 -0.3866498724
+ 0.0746433386 -0.8214200499  0.1317661698
+ 0.5432565786 -0.3645767609  0.5192503492
+ 0.4402662939  0.7076735504 -0.0550325933
+ 0.0484747550  0.8295519246 -0.0846088198
+-0.5035932888  0.2744096577 -0.6072544682
+-0.4029809447 -0.1070837544 -0.7237432401
+-0.2473362223 -0.4392647648 -0.6659850669
+ 0.0243625739 -0.6670600099  0.5020978570
+-0.3525221086 -0.5119261104  0.5579647573
+ 0.1562554434 -0.4433331772 -0.6904381075
+ 0.3299109277 -0.6618755327 -0.3882581729
+-0.0124901259 -0.1403786872 -0.8232877205
+3 0 2 1 
+3 0 3 2 
+5 0 4 14 13 3 2
+3 0 5 4 
+5 0 1 6 18 5 
+3 1 7 6 
+3 1 8 7 
+5 1 2 9 25 8 2
+3 2 10 9 
+5 2 3 11 29 10 
+3 3 12 11 
+3 3 13 12 
+3 4 15 14 
+5 4 16 38 37 15 
+3 4 5 16 
+5 5 17 41 40 16 2
+3 5 18 17 
+3 6 19 18 
+3 6 20 19 
+5 6 7 21 46 20 2
+3 7 22 21 
+5 7 8 23 50 22 
+3 8 24 23 
+3 8 25 24 
+3 9 26 25 
+5 9 27 55 54 26 
+3 9 10 27 
+5 10 28 45 57 27 2
+3 10 29 28 
+3 11 30 29 
+3 11 31 30 
+5 11 12 32 52 31 2
+3 12 33 32 
+5 12 13 34 43 33 
+3 13 35 34 
+3 13 14 35 
+5 14 36 45 46 35 
+3 14 15 36 
+5 15 23 24 51 36 2
+3 15 37 23 
+3 16 39 38 
+3 16 40 39 
+3 17 31 41 
+5 17 42 49 30 31 
+3 17 18 42 
+5 18 19 43 54 42 2
+3 19 44 43 
+5 19 20 28 58 44 
+3 20 45 28 
+3 20 46 45 
+3 21 47 46 
+5 21 48 39 40 47 
+3 21 22 48 
+5 22 49 55 56 48 2
+3 22 50 49 
+3 23 37 50 
+3 24 52 51 
+5 24 25 53 41 52 
+3 25 26 53 
+5 26 34 35 47 53 2
+3 26 54 34 
+3 27 56 55 
+3 27 57 56 
+3 28 29 58 
+5 29 30 50 37 58 2
+3 30 49 50 
+3 31 52 41 
+3 32 51 52 
+5 32 59 56 57 51 
+3 32 33 59 
+5 33 44 38 39 59 2
+3 33 43 44 
+3 34 54 43 
+3 35 46 47 
+3 36 57 45 
+3 36 51 57 
+3 37 38 58 
+3 38 44 58 
+3 39 48 59 
+3 40 53 47 
+3 40 41 53 
+3 42 55 49 
+3 42 54 55 
+3 48 56 59 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 2 12 13 14 3 
+5 14 15 16 4 3 
+5 4 17 18 19 5 
+5 19 20 21 6 5 
+5 21 22 23 7 6 
+5 7 24 25 26 8 
+5 26 27 28 9 8 
+5 9 29 30 31 10 
+5 31 32 33 11 10 
+5 33 34 35 2 11 
+5 35 36 37 12 2 
+5 37 38 39 13 12 
+5 13 40 41 15 14 
+5 15 42 43 44 16 
+5 44 45 17 4 16 
+5 45 46 47 18 17 
+5 47 48 49 19 18 
+5 19 50 51 52 20 
+5 52 53 54 21 20 
+5 21 55 39 38 22 
+5 38 56 57 23 22 
+5 57 58 24 7 23 
+5 58 59 60 25 24 
+5 25 61 62 27 26 
+5 27 48 47 63 28 
+5 63 64 29 9 28 
+5 64 65 43 30 29 
+5 42 66 31 30 43 
+5 31 67 68 69 32 
+5 69 70 71 33 32 
+5 33 72 60 59 34 
+5 59 73 36 35 34 
+5 36 74 75 38 37 
+5 55 64 76 13 39 
+5 76 77 70 40 13 
+5 70 78 51 41 40 
+5 51 79 80 15 41 
+5 80 57 66 42 15 
+5 43 81 82 45 44 
+5 45 72 33 71 46 
+5 77 47 46 71 70 
+5 27 74 36 49 48 
+5 73 50 19 49 36 
+5 59 79 51 50 73 
+5 78 83 53 52 51 
+5 53 81 43 65 54 
+5 54 21 55 64 65 
+5 75 68 67 56 38 
+5 56 57 66 31 67 
+5 57 58 59 79 80 
+5 82 25 60 72 45 
+5 53 61 25 82 81 
+5 83 68 62 61 53 
+5 62 27 74 75 68 
+5 47 63 64 76 77 
+5 68 69 70 78 83 
+ditrigonal dodecadodecahedron
+medial triambic icosahedron
+3|5/3 5
+(5/3.5.5/3.5.5/3.5)
+icosahedral group
+A5
+12{5}+12{5/3}
+45 20 60 24 20 4 0 0 -16 2 6 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9428090416  0.0000000000  0.3333333333
+ 0.6727182848 -0.6605596098  0.3333333333
+-0.4714045208  0.8164965809  0.3333333333
+ 0.2357022604  0.9128709292  0.3333333333
+-0.4714045208 -0.8164965809  0.3333333333
+-0.9084205452 -0.2523113194  0.3333333333
+ 0.0900302522 -0.6605596098  0.7453559925
+ 0.4714045208  0.8164965809 -0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+ 0.6170765289 -0.2523113194 -0.7453559925
+ 0.9084205452  0.2523113194 -0.3333333333
+-0.2357022604 -0.9128709292 -0.3333333333
+ 0.5270462767  0.4082482905  0.7453559925
+-0.9428090416 -0.0000000000 -0.3333333333
+-0.0900302522  0.6605596098 -0.7453559925
+-0.6727182848  0.6605596098 -0.3333333333
+-0.6170765289  0.2523113194  0.7453559925
+-0.5270462767 -0.4082482905 -0.7453559925
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.1326479105 -0.0542373073  0.1875924741
+ 0.7765343938  0.6015009550  0.1875924741
+-0.0193530693  0.1419951139  0.1875924741
+-0.9091823043  0.3717480345  0.1875924741
+-0.1132948412 -0.0877578066  0.1875924741
+ 0.1326479105 -0.9732489895  0.1875924741
+ 0.2146288278 -0.0877578066 -0.0442845760
+ 0.4799246488  0.3717480345 -0.7946544723
+ 0.1833149038  0.1419951139  0.0442845760
+-0.0819809172  0.6015009550  0.7946544723
+-0.4799246488 -0.3717480345  0.7946544723
+ 0.0313139240 -0.2297529205  0.0442845760
+ 0.0819809172 -0.6015009550 -0.7946544723
+-0.0313139240  0.2297529205 -0.0442845760
+-0.5619055661  0.2297529205 -0.7946544723
+-0.2146288278  0.0877578066  0.0442845760
+ 0.5619055661 -0.2297529205  0.7946544723
+-0.1833149038 -0.1419951139 -0.0442845760
+-0.7765343938 -0.6015009550 -0.1875924741
+ 0.9091823043 -0.3717480345 -0.1875924741
+ 0.1132948412  0.0877578066 -0.1875924741
+ 0.0193530693 -0.1419951139 -0.1875924741
+-0.1326479105  0.9732489895 -0.1875924741
+-0.1326479105  0.0542373073 -0.1875924741
+5 0 2 13 7 1 3
+5 0 3 15 10 2 
+5 0 4 17 13 3 3
+5 0 5 18 15 4 
+5 0 6 7 17 5 3
+5 0 1 10 18 6 
+5 1 9 11 2 10 3
+5 1 4 16 18 9 
+5 1 8 13 11 4 3
+5 1 7 6 16 8 
+5 2 12 14 3 13 
+5 2 5 9 7 12 3
+5 2 11 15 14 5 
+5 3 8 16 4 15 3
+5 3 6 12 10 8 
+5 3 14 17 16 6 3
+5 4 11 9 5 17 
+5 5 14 12 6 18 3
+5 7 9 19 16 17 
+5 7 13 8 19 12 
+5 8 10 15 11 19 3
+5 9 18 10 12 19 3
+5 11 13 17 14 19 
+5 14 15 18 16 19 3
+6 5 0 1 2 3 4 
+6 5 6 7 8 9 0 
+6 0 10 11 12 6 1 
+6 1 13 14 15 10 2 
+6 2 16 8 7 13 3 
+6 3 17 12 11 16 4 
+6 4 9 15 14 17 5 
+6 4 18 11 19 0 9 
+6 8 19 20 14 13 9 
+6 6 16 11 18 21 7 
+6 5 21 14 20 1 6 
+6 12 20 22 8 16 6 
+6 10 17 14 21 19 11 
+6 22 2 10 0 19 8 
+6 15 22 23 12 17 10 
+6 23 3 13 1 20 12 
+6 7 23 18 15 9 13 
+6 2 16 4 18 15 22 
+6 3 17 5 21 7 23 
+6 19 20 22 23 18 21 
+great ditrigonal dodecicosidodecahedron
+great ditrigonal dodecacronic hexecontahedron
+3 5|5/3
+(10/3.3.10/3.5)
+icosahedral group
+A5
+12{5}+12{10/3}+20{3}
+46 60 120 44 60 4 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7913673487  0.0000000000  0.6113409191
+ 0.1126514014  0.7833083316  0.6113409191
+-0.6820030709  0.4014151117  0.6113409191
+-0.4944105968 -0.6179162098  0.6113409191
+ 0.4149268310  0.7833083316  0.4628863603
+ 0.9007316265  0.4014151117 -0.1659772426
+ 0.7860486710 -0.6179162098 -0.0175226837
+-0.2691077939  0.9487004534 -0.1659772426
+ 0.8343963552  0.2991971590  0.4628863603
+-0.7549125894 -0.4645892808  0.4628863603
+-0.5726387930  0.8028302234 -0.1659772426
+-0.0086058013 -0.9998094297 -0.0175226837
+-0.8761697921 -0.4525240881 -0.1659772426
+-0.8708511144  0.1653921218  0.4628863603
+ 0.0331676357  0.9487004534 -0.3144318014
+-0.1437874830  0.2991971590  0.9432954043
+ 0.8278221080 -0.4645892808 -0.3144318014
+ 0.2187285557  0.8028302234 -0.5546363234
+ 0.4042894756 -0.4525240881 -0.7948408455
+ 0.8987000724  0.1653921218 -0.4061817646
+ 0.2166970016  0.5668072335 -0.7948408455
+-0.7635183907  0.3307842435 -0.5546363234
+-0.8278221080  0.4645892808  0.3144318014
+ 0.2756820411 -0.1849140136  0.9432954043
+ 0.7614868366 -0.5668072335  0.3144318014
+-0.6906088722 -0.5983943180 -0.4061817646
+-0.0331676357 -0.9487004534  0.3144318014
+-0.0278489580 -0.3307842435  0.9432954043
+ 0.1544248384  0.9366352607  0.3144318014
+-0.5779574707  0.1849140136 -0.7948408455
+ 0.1007584765 -0.5983943180 -0.7948408455
+-0.1544248384 -0.9366352607 -0.3144318014
+-0.7614868366  0.5668072335 -0.3144318014
+ 0.0278489580  0.3307842435 -0.9432954043
+ 0.7549125894  0.4645892808 -0.4628863603
+ 0.5779574707 -0.1849140136  0.7948408455
+-0.2166970016 -0.5668072335  0.7948408455
+ 0.2691077939 -0.9487004534  0.1659772426
+ 0.7635183907 -0.3307842435  0.5546363234
+-0.2756820411  0.1849140136 -0.9432954043
+ 0.1437874830 -0.2991971590 -0.9432954043
+-0.1007584765  0.5983943180  0.7948408455
+-0.9007316265 -0.4014151117  0.1659772426
+-0.2187285557 -0.8028302234  0.5546363234
+ 0.8708511144 -0.1653921218 -0.4628863603
+-0.4149268310 -0.7833083316 -0.4628863603
+-0.4042894756  0.4525240881  0.7948408455
+ 0.8761697921  0.4525240881  0.1659772426
+ 0.5726387930 -0.8028302234  0.1659772426
+-0.8343963552 -0.2991971590 -0.4628863603
+ 0.6906088722  0.5983943180  0.4061817646
+ 0.6820030709 -0.4014151117 -0.6113409191
+-0.8987000724 -0.1653921218  0.4061817646
+-0.1126514014 -0.7833083316 -0.6113409191
+ 0.0086058013  0.9998094297  0.0175226837
+-0.7913673487  0.0000000000 -0.6113409191
+ 0.4944105968  0.6179162098 -0.6113409191
+-0.7860486710  0.6179162098  0.0175226837
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.3248577762  0.2814806691  0.6614584599
+-0.1694360713  0.3525674843  0.6614584599
+-0.4227424795 -0.0777993435  0.6614584599
+ 0.3248577762 -0.6759734692  0.6614584599
+ 0.7818964037 -0.0777993435  0.0698320276
+ 0.6270398312  0.3525674843  0.2702904483
+ 0.5422372365  0.8355491589 -0.0885233438
+-0.3167615539  0.6591266154  0.2958132161
+-0.9911796417  0.0986232000 -0.0885233438
+-0.6670382619 -0.2693375914  0.2702904483
+-0.4277462201 -0.6591266154  0.0698320276
+ 0.4277462201  0.6591266154 -0.0698320276
+-0.4015462944  0.8355491589  0.3749909018
+ 0.5358941893  0.0986232000 -0.8385051474
+ 0.3167615539 -0.6591266154 -0.2958132161
+ 0.6216868196 -0.2693375914 -0.3626326897
+-0.2562654803  0.5332446333 -0.5217944046
+-0.5536596562  0.5190272703 -0.1208775632
+ 0.5569679993 -0.1346687957  0.5120455748
+-0.2428162464 -0.5190272703  0.5120455748
+-0.0593658087  0.7565738714 -0.1208775632
+-0.1780974260 -0.6536960660 -0.3626326897
+-0.7818964037  0.0777993435 -0.0698320276
+-0.4118095603 -0.3568220898 -0.8385051474
+ 0.2428162464  0.5190272703 -0.5120455748
+ 0.0647188203 -0.1346687957  0.7538007012
+ 0.5536596562 -0.5190272703  0.1208775632
+ 0.4227424795  0.0777993435 -0.6614584599
+-0.0647188203  0.1346687957 -0.7538007012
+-0.5358941893 -0.0986232000  0.8385051474
+ 0.2562654803 -0.5332446333  0.5217944046
+ 0.4015462944 -0.8355491589 -0.3749909018
+-0.3248577762 -0.2814806691 -0.6614584599
+ 0.4118095603  0.3568220898  0.8385051474
+ 0.0593658087 -0.7565738714  0.1208775632
+-0.5569679993  0.1346687957 -0.5120455748
+ 0.9911796417 -0.0986232000  0.0885233438
+-0.5422372365 -0.8355491589  0.0885233438
+ 0.1780974260  0.6536960660  0.3626326897
+-0.6270398312 -0.3525674843 -0.2702904483
+ 0.6670382619  0.2693375914 -0.2702904483
+-0.6216868196  0.2693375914  0.3626326897
+ 0.1694360713 -0.3525674843 -0.6614584599
+-0.3248577762  0.6759734692 -0.6614584599
+10 0 2 9 24 42 51 36 16 5 1 3
+3 0 3 2 
+10 0 4 14 16 37 53 47 28 10 3 3
+5 0 1 7 12 4 
+10 1 6 17 39 48 45 25 9 20 7 3
+3 1 5 6 
+5 2 8 21 20 9 
+10 2 3 11 29 47 58 55 42 23 8 3
+5 3 10 26 30 11 
+3 4 13 14 
+10 4 12 26 10 27 46 43 44 32 13 3
+10 5 15 35 51 55 57 48 29 18 6 3
+5 5 16 14 33 15 
+5 6 18 40 31 17 
+10 7 19 32 49 52 54 38 17 31 12 3
+3 7 20 19 
+10 8 22 34 15 33 40 18 11 30 21 3
+3 8 23 22 
+3 9 25 24 
+3 10 28 27 
+3 11 18 29 
+3 12 31 26 
+10 13 22 23 43 56 58 53 50 33 14 3
+5 13 32 19 34 22 
+3 15 34 35 
+3 16 36 37 
+3 17 38 39 
+10 19 20 21 41 45 57 59 52 35 34 3
+3 21 30 41 
+5 23 42 24 44 43 
+10 24 25 27 28 39 38 37 36 49 44 3
+5 25 45 41 46 27 
+10 26 31 40 50 54 59 56 46 41 30 3
+5 28 47 29 48 39 
+3 32 44 49 
+3 33 50 40 
+5 35 52 49 36 51 
+5 37 38 54 50 53 
+3 42 55 51 
+3 43 46 56 
+3 45 48 57 
+3 47 53 58 
+3 52 59 54 
+5 55 58 56 59 57 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 11 12 0 
+4 4 13 11 5 
+4 3 14 15 4 
+4 6 16 17 7 
+4 0 18 4 6 
+4 8 10 19 2 
+4 7 20 16 8 
+4 10 21 14 3 
+4 9 22 23 10 
+4 2 12 22 9 
+4 11 24 16 12 
+4 2 25 0 12 
+4 4 26 14 13 
+4 13 16 20 11 
+4 14 23 27 15 
+4 27 6 4 15 
+4 27 28 16 6 
+4 16 23 22 17 
+4 22 29 7 17 
+4 0 29 30 18 
+4 30 31 4 18 
+4 8 32 21 10 
+4 10 31 30 19 
+4 30 33 2 19 
+4 7 33 11 20 
+4 28 32 8 16 
+4 32 13 14 21 
+4 14 34 10 23 
+4 16 35 22 12 
+4 24 27 23 16 
+4 11 36 27 24 
+4 25 30 36 0 
+4 2 37 30 25 
+4 26 30 37 14 
+4 4 33 30 26 
+4 32 35 16 13 
+4 27 31 32 28 
+4 0 38 7 29 
+4 22 39 10 29 
+4 34 30 29 10 
+4 27 40 4 31 
+4 39 32 31 10 
+4 7 41 2 33 
+4 40 11 33 4 
+4 14 36 30 34 
+4 32 37 22 35 
+4 11 38 0 36 
+4 14 42 27 36 
+4 41 22 37 2 
+4 32 42 14 37 
+4 11 43 7 38 
+4 22 43 32 39 
+4 27 43 11 40 
+4 7 41 22 43 
+4 42 27 43 32 
+small ditrigonal dodecicosidodecahedron
+small ditrigonal dodecacronic hexecontahedron
+5/3 3|5
+(10.5/3.10.3)
+icosahedral group
+A5
+12{10}+20{3}+12{5/3}
+47 60 120 44 60 4 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5558508647  0.0000000000  0.8312820317
+-0.5423346067  0.1218333214  0.8312820317
+-0.3547421326  0.4279348118  0.8312820317
+ 0.2523198656 -0.4952826155  0.8312820317
+ 0.9129018498  0.1218333214  0.3895726561
+ 0.7569595968  0.4279348118  0.4938460950
+-0.0195609124  0.3526376782  0.9355554706
+-0.8323493477 -0.2516159727  0.4938460950
+-0.8639995688  0.3189637764  0.3895726561
+-0.6764070948  0.6250652668  0.3895726561
+-0.1536334005  0.8558696236  0.4938460950
+-0.3230919115 -0.1426449373  0.9355554706
+-0.0376948755 -0.8687319096  0.4938460950
+ 0.3058398516 -0.8687319096  0.3895726561
+ 0.5362899523  0.3526376782  0.7668375023
+ 0.9664218358 -0.2516159727 -0.0521367195
+ 0.9347716147  0.3189637764 -0.1564101584
+ 0.7788293617  0.6250652668 -0.0521367195
+ 0.4022174642  0.8558696236  0.3251281267
+ 0.7886098179 -0.1426449373  0.5981195340
+ 0.1815478197  0.7805724901  0.5981195340
+-0.5800294821 -0.7468985882  0.3251281267
+-0.7788293617 -0.6250652668  0.0521367195
+-0.8421298039  0.5160942314 -0.1564101584
+-0.6628908367  0.7468985882  0.0521367195
+-0.9664218358  0.2516159727  0.0521367195
+ 0.2034175846  0.9777029450  0.0521367195
+-0.6131066526 -0.5160942314  0.5981195340
+-0.0707720459 -0.6379275528  0.7668375023
+ 0.4850788188 -0.6379275528  0.5981195340
+-0.2034175846 -0.9777029450 -0.0521367195
+ 0.1401171424 -0.9777029450 -0.1564101584
+ 0.6628908367 -0.7468985882 -0.0521367195
+ 0.6764070948 -0.6250652668 -0.3895726561
+ 0.6131066526  0.5160942314 -0.5981195340
+ 0.5800294821  0.7468985882 -0.3251281267
+ 0.8323493477  0.2516159727 -0.4938460950
+-0.1401171424  0.9777029450  0.1564101584
+ 0.8421298039 -0.5160942314  0.1564101584
+-0.9347716147 -0.3189637764  0.1564101584
+-0.4022174642 -0.8558696236 -0.3251281267
+-0.7569595968 -0.4279348118 -0.4938460950
+-0.7886098179  0.1426449373 -0.5981195340
+-0.4850788188  0.6379275528 -0.5981195340
+-0.3058398516  0.8687319096 -0.3895726561
+-0.9129018498 -0.1218333214 -0.3895726561
+ 0.0376948755  0.8687319096 -0.4938460950
+-0.1815478197 -0.7805724901 -0.5981195340
+ 0.1536334005 -0.8558696236 -0.4938460950
+ 0.8639995688 -0.3189637764 -0.3895726561
+ 0.3547421326 -0.4279348118 -0.8312820317
+ 0.3230919115  0.1426449373 -0.9355554706
+ 0.0707720459  0.6379275528 -0.7668375023
+ 0.5423346067 -0.1218333214 -0.8312820317
+-0.5558508647  0.0000000000 -0.8312820317
+-0.5362899523 -0.3526376782 -0.7668375023
+-0.2523198656  0.4952826155 -0.8312820317
+ 0.0195609124 -0.3526376782 -0.9355554706
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1036376133  0.9341723590  0.3414399638
+-0.0933664669  0.0572190828  0.3414399638
+-0.7853356508 -0.5163977795  0.3414399638
+ 0.1036376133 -0.0635136937  0.3414399638
+ 0.8426251145 -0.5163977795 -0.1526965938
+ 0.2674035654  0.0572190828  0.2319350754
+-0.2870826778  0.0242600722  0.2198885583
+ 0.1963339127 -0.7369259589  0.6468331514
+ 0.7457496051  0.1595756897  0.6468331514
+-0.1519332973  0.2447882516  0.2198885583
+ 0.0703994852 -0.2642396690  0.2319350754
+ 0.3608719169  0.0242600722  0.0232142528
+ 0.2485246653  0.2447882516  0.0983371527
+-0.2603854803  0.1595756897  0.9522263391
+ 0.0895451227  0.1905410810  0.2950114582
+-0.8426251145  0.5163977795  0.1526965938
+-0.7457496051 -0.1595756897 -0.6468331514
+-0.2815979407 -0.1851648415  0.1224301871
+-0.3021402336  0.1851648415  0.0547524442
+-0.1963339127  0.7369259589 -0.6468331514
+ 0.0371613570  0.3349663450  0.1224301871
+-0.1291311684 -0.1662810088  0.2950114582
+-0.1053010062 -0.3325620175  0.0983371527
+ 0.1421956258 -0.3325620175  0.0232142528
+ 0.7853356508  0.5163977795 -0.3414399638
+ 0.3021402336 -0.1851648415 -0.0547524442
+ 0.2603854803 -0.1595756897 -0.9522263391
+ 0.2815979407  0.1851648415 -0.1224301871
+ 0.2713267942 -0.1662810088  0.1734600527
+-0.2485246653 -0.2447882516 -0.0983371527
+-0.2713267942  0.1662810088 -0.1734600527
+-0.1421956258  0.3325620175 -0.0232142528
+-0.3608719169 -0.0242600722 -0.0232142528
+ 0.1053010062  0.3325620175 -0.0983371527
+-0.1036376133 -0.9341723590 -0.3414399638
+-0.0371613570 -0.3349663450 -0.1224301871
+ 0.1519332973 -0.2447882516 -0.2198885583
+ 0.1291311684  0.1662810088 -0.2950114582
+ 0.2870826778 -0.0242600722 -0.2198885583
+-0.2674035654 -0.0572190828 -0.2319350754
+-0.0703994852  0.2642396690 -0.2319350754
+-0.0895451227 -0.1905410810 -0.2950114582
+ 0.0933664669 -0.0572190828 -0.3414399638
+-0.1036376133  0.0635136937 -0.3414399638
+10 0 2 9 24 44 53 35 17 5 1 
+5 0 3 12 7 2 3
+10 0 4 14 32 48 56 43 24 10 3 
+3 0 1 4 
+10 1 6 18 35 52 58 48 31 13 4 
+5 1 5 15 20 6 3
+3 2 8 9 
+10 2 7 15 5 16 34 49 41 23 8 
+10 3 11 27 36 37 50 33 14 29 12 
+3 3 10 11 
+5 4 13 30 29 14 3
+3 5 17 16 
+3 6 19 18 
+10 6 20 30 13 22 40 26 25 38 19 
+3 7 21 15 
+10 7 12 28 23 42 55 57 47 27 21 
+10 8 22 31 49 51 52 53 45 25 9 
+5 8 23 28 40 22 3
+5 9 25 26 10 24 3
+10 10 26 46 56 58 54 37 18 19 11 
+5 11 19 38 21 27 3
+3 12 29 28 
+3 13 31 22 
+3 14 33 32 
+10 15 21 38 45 57 59 51 34 39 20 
+5 16 33 50 39 34 3
+10 16 17 36 47 44 43 42 41 32 33 
+5 17 35 18 37 36 3
+3 20 39 30 
+3 23 41 42 
+3 24 43 44 
+3 25 45 38 
+3 26 40 46 
+3 27 47 36 
+10 28 29 30 39 50 54 59 55 46 40 
+5 31 48 32 41 49 3
+3 34 51 49 
+3 35 53 52 
+3 37 54 50 
+5 42 43 56 46 55 3
+5 44 47 57 45 53 3
+3 48 58 56 
+5 51 59 54 58 52 3
+3 55 59 57 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 4 3 
+4 5 7 11 0 
+4 4 12 13 5 
+4 7 14 15 1 
+4 6 16 17 7 
+4 0 18 16 6 
+4 9 19 18 2 
+4 8 20 19 9 
+4 15 21 8 1 
+4 10 13 22 4 
+4 2 23 8 10 
+4 5 24 14 7 
+4 7 25 26 11 
+4 26 27 0 11 
+4 4 27 19 12 
+4 20 13 12 19 
+4 13 28 24 5 
+4 24 20 15 14 
+4 16 22 13 17 
+4 17 15 29 7 
+4 0 30 2 18 
+4 18 13 31 16 
+4 19 32 13 18 
+4 8 33 15 20 
+4 17 34 21 15 
+4 34 10 8 21 
+4 34 28 13 10 
+4 16 35 4 22 
+4 2 35 26 23 
+4 25 8 23 26 
+4 7 36 24 25 
+4 4 37 0 27 
+4 26 33 8 27 
+4 8 38 19 27 
+4 24 31 13 20 
+4 34 25 24 28 
+4 32 34 17 13 
+4 29 26 35 7 
+4 15 39 26 29 
+4 30 26 39 2 
+4 0 40 26 30 
+4 24 40 16 31 
+4 19 39 34 32 
+4 40 15 33 26 
+4 2 41 4 35 
+4 16 36 7 35 
+4 34 38 8 25 
+4 16 42 24 36 
+4 4 42 16 37 
+4 37 0 40 16 
+4 34 42 19 38 
+4 15 43 34 39 
+4 19 41 2 39 
+4 24 43 15 40 
+4 41 4 42 19 
+4 42 24 43 34 
+icosidodecadodecahedron
+medial icosacronic hexecontahedron
+5/3 5|3
+(6.5/3.6.5)
+icosahedral group
+A5
+20{6}+12{5}+12{5/3}
+48 60 120 44 60 4 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6998542122  0.0000000000  0.7142857143
+-0.5248906592  0.4629100499  0.7142857143
+-0.1166423687  0.6900655593  0.7142857143
+-0.3689536881 -0.5947008445  0.7142857143
+ 0.8748177653  0.4629100499  0.1428571429
+ 0.5832118435  0.6900655593  0.4285714286
+ 0.7634342145 -0.5947008445  0.2519902889
+ 0.2077578990  0.4039714148  0.8908668539
+-0.8938443472 -0.1317907946  0.4285714286
+-0.3499271061  0.9258200998  0.1428571429
+-0.6022384255  0.7854302742  0.1428571429
+-0.4528017108  0.0364260797  0.8908668539
+ 0.1028746047 -0.9622461795  0.2519902889
+-0.8545497448 -0.4993361296  0.1428571429
+ 0.4750784209  0.4039714148  0.7817337079
+ 0.9383977675 -0.1317907946 -0.3194382825
+ 0.3499271061  0.9258200998 -0.1428571429
+ 0.5301494771  0.7854302742 -0.3194382825
+ 0.9469067137  0.0364260797  0.3194382825
+ 0.7103718480 -0.4993361296 -0.4960194221
+ 0.5714527692 -0.2496680648  0.7817337079
+ 0.3827214521  0.8668814647  0.3194382825
+-0.9469067137 -0.0364260797 -0.3194382825
+-0.5301494771 -0.7854302742  0.3194382825
+-0.6107473716  0.6172133998 -0.4960194221
+-0.2024990811  0.8443689093 -0.4960194221
+-0.9383977675  0.1317907946  0.3194382825
+-0.9711921135  0.1907294297 -0.1428571429
+-0.0891068406 -0.6172133998  0.7817337079
+ 0.0498122382 -0.8668814647 -0.4960194221
+-0.3827214521 -0.8668814647 -0.3194382825
+-0.5937294793 -0.1907294297  0.7817337079
+ 0.1389190789 -0.2496680648  0.9583148475
+-0.0498122382  0.8668814647  0.4960194221
+ 0.4528017108 -0.0364260797 -0.8908668539
+ 0.6022384255 -0.7854302742 -0.1428571429
+ 0.0891068406  0.6172133998 -0.7817337079
+ 0.8938443472  0.1317907946 -0.4285714286
+ 0.5937294793  0.1907294297 -0.7817337079
+ 0.6107473716 -0.6172133998  0.4960194221
+ 0.9711921135 -0.1907294297  0.1428571429
+ 0.2024990811 -0.8443689093  0.4960194221
+-0.1028746047  0.9622461795 -0.2519902889
+ 0.8545497448  0.4993361296 -0.1428571429
+-0.4750784209 -0.4039714148 -0.7817337079
+-0.5832118435 -0.6900655593 -0.4285714286
+-0.1389190789  0.2496680648 -0.9583148475
+-0.5714527692  0.2496680648 -0.7817337079
+-0.7634342145  0.5947008445 -0.2519902889
+-0.8748177653 -0.4629100499 -0.1428571429
+-0.7103718480  0.4993361296  0.4960194221
+-0.3499271061 -0.9258200998  0.1428571429
+-0.2077578990 -0.4039714148 -0.8908668539
+ 0.3499271061 -0.9258200998 -0.1428571429
+ 0.1166423687 -0.6900655593 -0.7142857143
+ 0.3689536881  0.5947008445 -0.7142857143
+ 0.5248906592 -0.4629100499 -0.7142857143
+-0.6998542122  0.0000000000 -0.7142857143
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.2672612419  0.7071067812  0.6546536707
+-0.1378524272  0.2477510578  0.6546536707
+-0.7417602291  0.1456720081  0.6546536707
+ 0.2672612419 -0.4803270912  0.6546536707
+ 0.9879908641  0.1456720081 -0.0515142560
+ 0.5566281484  0.2477510578  0.3711331629
+-0.7425563482  0.4102483131  0.1049785976
+-0.2462306350 -0.2913440163  0.9243858169
+ 0.3773789295  0.0556417559  0.9243858169
+ 0.0428573330  0.8472643375  0.1049785976
+-0.5039732067 -0.3423835411  0.3711331629
+-0.6446401714 -0.7627485371 -0.0515142560
+ 0.8228143327 -0.2913440163  0.4879500365
+ 0.6038671053  0.4102483131 -0.4446964755
+ 0.4244047962 -0.7627485371 -0.4879500365
+ 0.6197199693 -0.3423835411 -0.0876126552
+ 0.6669589261  0.2968584681  0.4446964755
+-0.4244047962  0.7627485371  0.4879500365
+ 0.0357677167  0.7071067812  0.0876126552
+ 0.1862071383  0.8527787893 -0.4879500365
+-0.8228143327  0.2913440163 -0.4879500365
+-0.6197199693  0.3423835411  0.0876126552
+-0.6038671053 -0.4102483131  0.4446964755
+-0.0357677167 -0.7071067812 -0.0876126552
+-0.6669589261 -0.2968584681 -0.4446964755
+-0.1862071383 -0.8527787893  0.4879500365
+ 0.6446401714  0.7627485371  0.0515142560
+-0.1651765314  0.2968584681  0.7844143535
+-0.4744989872  0.8527787893 -0.2182178902
+ 0.5039732067  0.3423835411 -0.3711331629
+ 0.2462306350  0.2913440163 -0.9243858169
+ 0.7425563482 -0.4102483131 -0.1049785976
+ 0.4744989872 -0.8527787893  0.2182178902
+ 0.1651765314 -0.2968584681 -0.7844143535
+ 0.2230499127 -0.4008696323  0.5463584732
+-0.3773789295 -0.0556417559 -0.9243858169
+-0.5566281484 -0.2477510578 -0.3711331629
+-0.9879908641 -0.1456720081  0.0515142560
+-0.0428573330 -0.8472643375 -0.1049785976
+-0.2230499127  0.4008696323 -0.5463584732
+ 0.1378524272 -0.2477510578 -0.6546536707
+ 0.7417602291 -0.1456720081 -0.6546536707
+-0.2672612419  0.4803270912 -0.6546536707
+-0.2672612419 -0.7071067812 -0.6546536707
+6 0 2 10 17 5 1 
+5 0 3 12 8 2 3
+6 0 4 14 28 11 3 
+5 0 1 7 13 4 
+6 1 6 18 39 20 7 
+5 1 5 15 19 6 3
+5 2 9 23 25 10 
+6 2 8 21 42 24 9 
+6 3 6 19 40 29 12 
+5 3 11 26 18 6 
+5 4 9 24 32 14 3
+6 4 13 30 45 23 9 
+6 5 16 36 42 33 15 
+5 5 17 37 35 16 
+6 7 16 35 53 31 13 
+5 7 20 41 36 16 3
+5 8 22 44 41 21 
+6 8 12 27 49 43 22 
+5 10 22 43 34 17 3
+6 10 25 47 39 44 22 
+6 11 27 50 45 47 26 
+5 11 28 51 49 27 3
+5 12 29 52 50 27 
+5 13 31 54 52 30 3
+5 14 31 53 48 28 
+6 14 32 33 40 54 31 
+6 15 34 43 56 38 19 
+5 15 33 32 51 34 
+6 17 34 51 28 48 37 
+5 18 38 56 44 39 3
+6 18 26 48 53 57 38 
+5 19 38 57 54 40 
+6 20 30 52 29 21 41 
+5 20 39 47 45 30 
+5 21 29 40 33 42 3
+6 23 46 55 35 37 25 
+5 23 45 50 58 46 3
+6 24 46 58 49 51 32 
+5 24 42 36 55 46 
+5 25 37 48 26 47 3
+5 35 55 59 57 53 3
+6 36 41 44 56 59 55 
+5 43 49 58 59 56 
+6 50 52 54 57 59 58 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 11 3 
+4 5 12 13 0 
+4 4 9 8 5 
+4 3 14 15 4 
+4 7 16 17 1 
+4 6 11 10 7 
+4 0 18 19 6 
+4 9 20 21 2 
+4 17 22 8 1 
+4 11 23 14 3 
+4 2 24 25 10 
+4 5 26 27 12 
+4 12 15 14 13 
+4 13 28 18 0 
+4 4 29 30 9 
+4 8 31 26 5 
+4 15 32 33 4 
+4 7 34 32 16 
+4 16 19 18 17 
+4 6 35 36 11 
+4 10 37 38 7 
+4 19 39 35 6 
+4 30 39 20 9 
+4 20 22 17 21 
+4 21 28 24 2 
+4 22 32 34 8 
+4 11 33 32 23 
+4 23 25 24 14 
+4 25 27 37 10 
+4 25 34 12 27 
+4 26 18 28 27 
+4 14 40 35 13 
+4 12 38 41 15 
+4 39 28 13 35 
+4 29 26 31 30 
+4 33 19 29 4 
+4 25 31 8 34 
+4 41 16 32 15 
+4 7 34 12 38 
+4 26 42 17 18 
+4 41 29 19 16 
+4 36 20 33 11 
+4 35 38 37 36 
+4 19 39 20 33 
+4 30 24 28 39 
+4 42 37 21 17 
+4 36 43 22 20 
+4 21 28 27 37 
+4 43 23 32 22 
+4 30 40 14 24 
+4 43 31 25 23 
+4 40 41 38 35 
+4 41 42 26 29 
+4 43 40 30 31 
+4 42 43 36 37 
+4 40 41 42 43 
+icositruncated dodecadodecahedron
+tridyakisicosahedron
+5/3 3 5|
+(10/3.6.10)
+icosahedral group
+A5
+12{10}+20{6}+12{10/3}
+49 120 180 44 120 4 0 0 -16 3 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.4841229183  0.0000000000  0.8750000000
+ 0.1273008285  0.4670861795  0.8750000000
+-0.4500494407 -0.1784110449  0.8750000000
+ 0.3122193286  0.4670861795  0.8272542486
+ 0.8174008141 -0.1784110449  0.5477457514
+-0.1954477837  0.7557613141  0.6250000000
+ 0.5327475080  0.1784110449  0.8272542486
+-0.6941218141 -0.4670861795  0.5477457514
+-0.7727980529  0.1102640897  0.6250000000
+ 0.4735936346  0.7557613141  0.4522542486
+-0.0656613285  0.1784110449  0.9817627458
+ 0.8725328589 -0.4670861795  0.1432372542
+ 0.9787751202  0.1102640897  0.1727457514
+-0.3122193286  0.9341723590  0.1727457514
+-0.6454972244  0.5773502692  0.5000000000
+ 0.1548668509 -0.1102640897  0.9817627458
+ 0.8660254038 -0.0000000000  0.5000000000
+-0.8660254038  0.0000000000  0.5000000000
+-0.6389897692 -0.7557613141  0.1432372542
+-0.8174008141 -0.3568220898  0.4522542486
+ 0.3568220898  0.9341723590  0.0000000000
+ 0.8068715305  0.5773502692  0.1250000000
+ 0.3397853510 -0.1102640897  0.9340169944
+-0.5157107692 -0.0000000000  0.8567627458
+ 0.9998336874  0.0000000000  0.0182372542
+ 0.6284604856 -0.7557613141 -0.1840169944
+ 0.9341723590 -0.3568220898  0.0000000000
+-0.6900999856  0.6454972244  0.3272542486
+-0.1784110449  0.9341723590 -0.3090169944
+-0.4841229183  0.8660254038  0.1250000000
+ 0.1102640897 -0.5773502692  0.8090169944
+-0.0170367388  0.3568220898  0.9340169944
+ 0.8214226426 -0.4670861795  0.3272542486
+-0.9827969487  0.1784110449  0.0477457514
+-0.3057118734 -0.9341723590 -0.1840169944
+-0.7557613141 -0.5773502692 -0.3090169944
+-0.4670861795 -0.3568220898  0.8090169944
+-0.7622687692 -0.6454972244  0.0477457514
+ 0.7622687692  0.6454972244 -0.0477457514
+ 0.0065074552  0.9341723590 -0.3567627458
+ 0.4841229183  0.8660254038 -0.1250000000
+ 0.2951825898 -0.5773502692  0.7612712430
+ 0.4670861795  0.3568220898  0.8090169944
+-0.5603135304 -0.4670861795  0.6840169944
+ 0.8830621426  0.1784110449 -0.4340169944
+ 0.1784110449 -0.9341723590 -0.3090169944
+ 0.5116889407 -0.5773502692 -0.6362712430
+ 0.8003640753 -0.3568220898  0.4817627458
+ 0.6900999856 -0.6454972244 -0.3272542486
+-0.9341723590  0.3568220898  0.0000000000
+-0.3397853510  0.6454972244  0.6840169944
+ 0.1548668509  0.7557613141 -0.6362712430
+-0.4224834183  0.6454972244 -0.6362712430
+-0.1338082837  0.8660254038  0.4817627458
+-0.3503146346  0.8660254038 -0.3567627458
+-0.1338082837 -0.8660254038  0.4817627458
+ 0.4435419855 -0.7557613141  0.4817627458
+ 0.9827969487 -0.1784110449 -0.0477457514
+-0.8214226426  0.4670861795 -0.3272542486
+-0.9276649038 -0.1102640897 -0.3567627458
+-0.6284604856 -0.6454972244 -0.4340169944
+-0.3503146346 -0.8660254038 -0.3567627458
+-0.0616395000 -0.6454972244  0.7612712430
+-0.6389897692  0.1102640897  0.7612712430
+-0.3568220898 -0.9341723590 -0.0000000000
+ 0.8174008141  0.3568220898 -0.4522542486
+ 0.6284604856  0.6454972244  0.4340169944
+-0.4435419855  0.7557613141 -0.4817627458
+ 0.0616395000  0.6454972244 -0.7612712430
+ 0.3503146346  0.8660254038  0.3567627458
+ 0.1338082837  0.8660254038 -0.4817627458
+ 0.3503146346 -0.8660254038  0.3567627458
+-0.1548668509 -0.7557613141  0.6362712430
+-0.8830621426 -0.1784110449  0.4340169944
+ 0.5603135304  0.4670861795 -0.6840169944
+ 0.6389897692 -0.1102640897 -0.7612712430
+ 0.3397853510 -0.6454972244 -0.6840169944
+ 0.1338082837 -0.8660254038 -0.4817627458
+ 0.4224834183 -0.6454972244  0.6362712430
+ 0.9276649038  0.1102640897  0.3567627458
+ 0.3122193286 -0.9341723590 -0.1727457514
+-0.9787751202 -0.1102640897 -0.1727457514
+-0.8003640753  0.3568220898 -0.4817627458
+-0.1784110449  0.9341723590  0.3090169944
+-0.2951825898  0.5773502692 -0.7612712430
+-0.5116889407  0.5773502692  0.6362712430
+-0.4841229183 -0.8660254038  0.1250000000
+-0.0065074552 -0.9341723590  0.3567627458
+ 0.8660254038  0.0000000000 -0.5000000000
+-0.8660254038 -0.0000000000 -0.5000000000
+-0.4670861795 -0.3568220898 -0.8090169944
+-0.4735936346 -0.7557613141 -0.4522542486
+ 0.7727980529 -0.1102640897 -0.6250000000
+ 0.4670861795  0.3568220898 -0.8090169944
+ 0.3057118734  0.9341723590  0.1840169944
+-0.1102640897  0.5773502692 -0.8090169944
+ 0.7557613141  0.5773502692  0.3090169944
+ 0.4841229183 -0.8660254038 -0.1250000000
+ 0.1784110449 -0.9341723590  0.3090169944
+-0.9998336874  0.0000000000 -0.0182372542
+ 0.5157107692 -0.0000000000 -0.8567627458
+ 0.0170367388 -0.3568220898 -0.9340169944
+ 0.1954477837 -0.7557613141 -0.6250000000
+-0.8174008141  0.1784110449 -0.5477457514
+-0.8068715305 -0.5773502692 -0.1250000000
+-0.6284604856  0.7557613141  0.1840169944
+-0.3397853510  0.1102640897 -0.9340169944
+ 0.6941218141  0.4670861795 -0.5477457514
+-0.5327475080 -0.1784110449 -0.8272542486
+-0.3122193286 -0.4670861795 -0.8272542486
+ 0.4500494407  0.1784110449 -0.8750000000
+ 0.6454972244 -0.5773502692 -0.5000000000
+ 0.6389897692  0.7557613141 -0.1432372542
+-0.1548668509  0.1102640897 -0.9817627458
+-0.8725328589  0.4670861795 -0.1432372542
+ 0.0656613285 -0.1784110449 -0.9817627458
+-0.1273008285 -0.4670861795 -0.8750000000
+-0.4841229183 -0.0000000000 -0.8750000000
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1517654996  0.1159385250  0.5877852523
+-0.2529424993  0.2262386491  0.5877852523
+ 0.1517654996 -0.7946544723  0.5877852523
+ 0.5058849985  0.2262386491  0.3918568349
+ 0.5849197102  0.7946544723  0.1624598481
+-0.4331542107 -0.1159385250  0.4253254042
+-0.4331542107  0.7946544723  0.4253254042
+ 0.5849197102 -0.1159385250  0.1624598481
+-0.2677040246  0.4911234732  0.2628655561
+ 0.3825657108 -0.2262386491  0.5129472562
+-0.6355082101 -0.2262386491  0.0748379961
+-0.9464199718  0.1875924741 -0.2628655561
+ 0.3615002616  0.4911234732  0.1004057079
+-0.0864154744 -0.2262386491  0.6340376775
+ 0.5923004729 -0.2262386491 -0.2421808427
+ 0.7008582352  0.1875924741 -0.6881909602
+-0.4359734112  0.5058849985 -0.1210904213
+-0.7008582352 -0.1875924741  0.6881909602
+-0.3615002616 -0.4911234732 -0.1004057079
+-0.3228540866 -0.5058849985  0.3170188388
+ 0.3228540866  0.5058849985 -0.3170188388
+ 0.9464199718 -0.1875924741  0.2628655561
+ 0.2677040246 -0.4911234732 -0.2628655561
+ 0.4359734112 -0.5058849985  0.1210904213
+-0.0937962370  0.4911234732 -0.3632712640
+ 0.0000000000  0.6787159473 -0.0000000000
+ 0.0937962370 -0.4911234732  0.3632712640
+ 0.1131193245  0.5058849985  0.4381092601
+ 0.4331542107 -0.7946544723 -0.4253254042
+-0.5849197102  0.1159385250 -0.1624598481
+-0.1131193245 -0.5058849985 -0.4381092601
+-0.2455617366 -0.1875924741 -0.9510565163
+ 0.2455617366  0.1875924741  0.9510565163
+-0.5849197102 -0.7946544723 -0.1624598481
+ 0.4331542107  0.1159385250 -0.4253254042
+ 0.0864154744  0.2262386491 -0.6340376775
+-0.0000000000 -0.6787159473 -0.0000000000
+ 0.6355082101  0.2262386491 -0.0748379961
+-0.3825657108  0.2262386491 -0.5129472562
+-0.5923004729  0.2262386491  0.2421808427
+-0.5058849985 -0.2262386491 -0.3918568349
+-0.1517654996  0.7946544723 -0.5877852523
+-0.1517654996 -0.1159385250 -0.5877852523
+ 0.2529424993 -0.2262386491 -0.5877852523
+10 0 2 7 16 32 43 23 11 4 1 3
+6 0 3 9 15 6 2 
+10 0 1 5 12 26 46 35 19 8 3 
+6 1 4 10 22 13 5 
+10 2 6 14 29 52 75 45 25 17 7 
+10 3 8 18 24 44 74 64 37 20 9 3
+10 4 11 24 18 34 59 68 40 21 10 
+10 5 13 27 48 80 58 33 17 25 12 3
+10 6 15 30 54 86 106 84 51 28 14 3
+6 7 17 33 57 31 16 
+6 8 19 36 60 34 18 
+10 9 20 38 61 91 107 85 55 30 15 
+10 10 21 39 67 95 113 97 70 41 22 3
+6 11 23 42 73 44 24 
+6 12 25 45 76 47 26 
+10 13 22 41 71 96 114 102 77 49 27 
+6 14 28 50 83 53 29 
+10 16 31 56 87 105 82 50 28 51 32 
+10 19 35 61 38 65 92 105 87 62 36 3
+6 20 37 63 88 65 38 
+6 21 40 69 94 66 39 
+10 23 43 67 39 66 93 112 98 72 42 
+10 26 47 78 98 112 103 81 49 77 46 3
+6 27 49 81 99 79 48 
+10 29 53 69 40 68 96 71 55 85 52 3
+6 30 55 71 41 70 54 
+10 31 57 88 63 79 99 73 42 72 56 3
+6 32 51 84 95 67 43 
+10 33 58 89 101 116 110 92 65 88 57 
+10 34 60 83 50 82 104 115 100 90 59 3
+6 35 46 77 102 91 61 
+10 36 62 78 47 76 94 69 53 83 60 
+10 37 64 86 54 70 97 80 48 79 63 
+10 44 73 99 81 103 117 109 90 100 74 
+10 45 75 101 89 108 111 93 66 94 76 3
+6 52 85 107 116 101 75 
+6 56 72 98 78 62 87 
+6 58 80 97 113 108 89 
+6 59 90 109 114 96 68 
+6 64 74 100 115 106 86 
+6 82 105 92 110 118 104 
+10 84 106 115 104 118 119 111 108 113 95 
+10 91 102 114 109 117 119 118 110 116 107 3
+6 93 111 119 117 103 112 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 0 9 4 
+3 5 10 2 
+3 1 11 5 
+3 3 12 6 
+3 6 13 0 
+3 2 14 7 
+3 7 15 3 
+3 4 16 8 
+3 8 11 1 
+3 0 17 9 
+3 9 7 4 
+3 5 6 10 
+3 10 18 2 
+3 11 19 5 
+3 12 20 6 
+3 15 12 3 
+3 13 21 0 
+3 5 13 6 
+3 14 4 7 
+3 2 22 14 
+3 7 23 15 
+3 16 17 8 
+3 4 24 16 
+3 8 25 11 
+3 17 26 9 
+3 0 27 17 
+3 9 28 7 
+3 6 29 10 
+3 18 30 2 
+3 10 31 18 
+3 19 32 5 
+3 11 18 19 
+3 12 21 20 
+3 20 24 6 
+3 15 25 12 
+3 13 26 21 
+3 21 27 0 
+3 5 33 13 
+3 14 34 4 
+3 30 22 2 
+3 22 31 14 
+3 7 32 23 
+3 23 22 15 
+3 16 29 17 
+3 27 8 17 
+3 4 35 24 
+3 24 31 16 
+3 8 32 25 
+3 25 24 11 
+3 17 36 26 
+3 26 28 9 
+3 28 37 7 
+3 6 38 29 
+3 29 31 10 
+3 11 30 18 
+3 31 36 18 
+3 19 26 32 
+3 32 39 5 
+3 18 28 19 
+3 21 34 20 
+3 12 27 21 
+3 24 38 6 
+3 20 31 24 
+3 32 12 25 
+3 15 24 25 
+3 36 21 26 
+3 33 26 13 
+3 39 33 5 
+3 34 35 4 
+3 31 34 14 
+3 30 15 22 
+3 22 36 31 
+3 26 23 32 
+3 37 32 7 
+3 23 33 22 
+3 29 40 17 
+3 16 29 31 
+3 27 41 8 
+3 35 11 24 
+3 8 39 32 
+3 17 18 36 
+3 26 28 19 
+3 28 34 37 
+3 38 33 29 
+3 11 42 30 
+3 18 40 28 
+3 21 43 34 
+3 34 20 31 
+3 12 41 27 
+3 15 38 24 
+3 37 12 32 
+3 22 21 36 
+3 33 26 23 
+3 39 29 33 
+3 28 35 34 
+3 42 15 30 
+3 33 43 22 
+3 29 41 40 
+3 40 17 18 
+3 41 39 8 
+3 35 42 11 
+3 34 41 37 
+3 38 42 33 
+3 40 42 28 
+3 43 41 34 
+3 21 43 22 
+3 12 41 37 
+3 15 38 42 
+3 39 29 41 
+3 28 35 42 
+3 42 43 33 
+3 41 42 40 
+3 43 41 42 
+snub icosidodecadodecahedron
+medial hexagonal hexecontahedron
+|5/3 3 5
+(3.5/3.3.3.3.5)
+icosahedral group
+A5
+12{5}+80{3}+12{5/3}
+50 60 180 104 60 4 0 0 -16 3 6 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7952605037  0.0000000000  0.6062678709
+ 0.3001621965  0.7364386767  0.6062678709
+ 0.7055094406  0.3670091252  0.6062678709
+-0.0735764581  0.7918495902  0.6062678709
+-0.7610506656  0.2307404455  0.6062678709
+-0.5009236922 -0.6176687813  0.6062678709
+ 0.7858348327 -0.6176687813 -0.0308040965
+ 0.9435414590  0.2307404455 -0.2376728044
+ 0.9243781868 -0.3167862469 -0.2125357417
+ 0.8269101315  0.5559211096 -0.0846838490
+ 0.0555412250  0.9755735394 -0.2125357417
+-0.3193254687  0.1889119844  0.9286245243
+ 0.5199990010 -0.0881350076  0.8496077091
+-0.1358666171  0.5096145631  0.8496077091
+ 0.2176453044 -0.3004779764  0.9286245243
+ 0.8327355166 -0.4593916847  0.3090482801
+-0.3170460053  0.9181467577 -0.2376728044
+-0.8371873340  0.4512278009  0.3090482801
+-0.6300413753  0.7719303797 -0.0846838490
+-0.7338395293 -0.6049534741  0.3090482801
+-0.1585581578 -0.3354337541  0.9286245243
+-0.9468108730  0.0896567415  0.3090482801
+-0.7735370212 -0.5874964807 -0.2376728044
+-0.0152510561 -0.9994090819 -0.0308040965
+ 0.2799588487 -0.5874964807 -0.7592568262
+ 0.0348116018 -0.9174921690 -0.3962275509
+ 0.5102070354 -0.2920835591 -0.8089350873
+ 0.3115674381  0.5713622348 -0.7592568262
+ 0.8637423423  0.4265251132  0.2683756583
+ 0.6801235098 -0.3583093162  0.6395673892
+ 0.3474601540 -0.9361396763  0.0539809952
+ 0.1222522224  0.8245736843 -0.5523881184
+ 0.1385433541  0.9344550281  0.3280236873
+ 0.6152755562  0.6750955630  0.4070405025
+ 0.7537879313  0.4809955435 -0.4477131243
+-0.0043310515  0.4244359070 -0.9054476257
+-0.7151305151  0.5758403202 -0.3962275509
+-0.8732845400 -0.2677538824  0.4070405025
+-0.1486782288 -0.6603643877  0.7360799276
+ 0.5996272266 -0.7539374610  0.2683756583
+-0.1581038998  0.9824462228  0.0990079602
+-0.2651930296 -0.8595294620  0.4369001728
+ 0.0873995822 -0.9406177617  0.3280236873
+ 0.8765539540 -0.0526433046 -0.4784159782
+-0.5218620448  0.2707102338 -0.8089350873
+-0.7977285113  0.2418606808 -0.5523881184
+-0.9171154526 -0.3949497421  0.0539809952
+-0.4932731016  0.4635385501  0.7360799276
+-0.5860128319 -0.5802507864 -0.5655952490
+-0.3294249208 -0.8312834534 -0.4477131243
+-0.8249774859 -0.3008825344 -0.4784159782
+-0.2157822605  0.1179027501 -0.9692971462
+ 0.7441167318 -0.4021954364 -0.5334127111
+ 0.1582993033 -0.2824850577 -0.9461202475
+ 0.4809752902  0.7416267119 -0.4676030266
+-0.0705157735 -0.7139676727 -0.6966187538
+ 0.1610261654  0.0935730734 -0.9825042768
+-0.8730256855  0.4832272272 -0.0657084418
+-0.6757924584 -0.0661265908 -0.7341197635
+ 0.3247276953  0.2183102780  0.6558852870
+ 0.2330291401  0.2556853380  0.6558852870
+ 0.1873305537  0.3435327018  0.6558852870
+-0.2474173141  0.3031371410  0.6558852870
+-0.3741003584 -0.1147012443  0.6558852870
+ 0.3247276953 -0.6814443588  0.6558852870
+ 0.7484046915 -0.1147012443  0.1001349371
+ 0.7309860539 -0.0199380975  0.1229835081
+ 0.7549003045  0.0708892675  0.0916144386
+ 0.5698573801  0.3831078312  0.3343410226
+ 0.3505745987  0.6723073767  0.0916144386
+-0.4956852875  0.7825823548  0.3766443331
+ 0.1484680132  0.2481846593  0.7068624953
+ 0.2333841167  0.1707929452  0.7068624953
+ 0.5205170549 -0.1164597889  0.5466187670
+ 0.7357021020  0.0410148862  0.2008809586
+ 0.4787409949  0.8779303974 -0.0067288271
+-0.3639725977  0.6406744508  0.2008809586
+-0.3675642883  0.5803063628  0.2792921431
+-0.4341871188  0.5319685985  0.3343410226
+-0.9857841031  0.0268878721 -0.1658515735
+-0.4901491203 -0.2103680745  0.5466187670
+-0.4381469231 -0.1343382762  0.5829610478
+-0.5238282283 -0.1005230031  0.5466187670
+-0.6584749455 -0.3306819467  0.2008809586
+-0.3823228516 -0.6535252059  0.1001349371
+ 0.3114234217 -0.6535252059 -0.2433376685
+ 0.3675642883 -0.5803063628 -0.2792921431
+ 0.3945189195 -0.5416693466 -0.3663906446
+ 0.6639032878 -0.2012866519 -0.3193885901
+ 0.5233112059  0.1511903430 -0.5353315097
+ 0.7316875924 -0.0736863580  0.2061469163
+ 0.5786406224 -0.4776354422  0.1425916469
+ 0.4600155947 -0.5455758087 -0.2720765570
+ 0.5908707414  0.1811642457 -0.7861623770
+ 0.3224400660  0.6862449721 -0.0916144386
+ 0.3549996288  0.6510095616 -0.0049896105
+ 0.4223105883  0.6319118158 -0.0750612237
+ 0.2386340718  0.5576061324 -0.4641359113
+-0.1968129036  0.5857219691 -0.4488735002
+-0.3976122076 -0.2191307095  0.6141491902
+ 0.0154135158 -0.1658843935  0.7453440513
+ 0.2878283477 -0.4453831909  0.5496195218
+ 0.9857841031 -0.0268878721  0.1658515735
+ 0.2962650281  0.3250693188  0.6243796397
+ 0.0952478389  0.6424329954  0.4018714458
+-0.3353210426  0.5760695154  0.3728225786
+-0.5908707414 -0.1811642457  0.7861623770
+ 0.1636587448 -0.5673708569  0.4843543014
+ 0.2407945267 -0.5053097542  0.4863569987
+ 0.3372842356 -0.5040934076  0.4641359113
+ 0.4956852875 -0.7825823548 -0.3766443331
+ 0.7627509365 -0.0253485937  0.0293499730
+-0.1563251351  0.5218003355 -0.5353315097
+-0.2407945267  0.5053097542 -0.4863569987
+-0.3317482574  0.4696932387 -0.5026174674
+-0.5786406224  0.4776354422 -0.1425916469
+-0.7565255326  0.0883804086 -0.0561336374
+-0.2919260821  0.6432534269  0.2903397229
+-0.1094594235  0.7502788765 -0.0916144386
+-0.3052303557  0.5535180122 -0.4286551102
+-0.3957787761 -0.6476079559 -0.0851825046
+-0.3549996288 -0.6510095616  0.0049896105
+-0.2892859071 -0.7045960843  0.0561336374
+-0.2386340718 -0.5576061324  0.4641359113
+ 0.1805218931 -0.4844908053  0.5621151741
+ 0.3142555466  0.3448089608  0.8845056427
+-0.4521061491 -0.0413976504  0.6141491902
+-0.7372235705  0.1080865268 -0.1676653603
+-0.7309860539  0.0199380975 -0.1229835081
+-0.7464599260 -0.0758825700 -0.1425916469
+-0.3142555466 -0.3448089608 -0.8845056427
+-0.2976021258 -0.7009390227 -0.0583988402
+-0.0952478389 -0.6424329954 -0.4018714458
+-0.1546934172 -0.3112164741 -0.6800788309
+ 0.4086597528 -0.6147065316 -0.1960256353
+ 0.1094594235 -0.7502788765  0.0916144386
+ 0.3734154496  0.1818211793 -0.6409328546
+ 0.4381469231  0.1343382762 -0.5829610478
+ 0.3991336762  0.0700292964 -0.6473647886
+-0.0154135158  0.1658843935 -0.7453440513
+ 0.6584749455  0.3306819467 -0.2008809586
+ 0.4396986858  0.6232979081  0.0381804502
+ 0.2605432005 -0.5794859313  0.4237997869
+-0.4787409949 -0.8779303974  0.0067288271
+ 0.3026839061 -0.6083857431 -0.3486290347
+-0.2397197699  0.4500906365 -0.5685471081
+ 0.2781047861  0.7112108017  0.0113967858
+ 0.4917743484  0.0510983985 -0.5820995682
+-0.5205170549  0.1164597889 -0.5466187670
+-0.6639032878  0.2012866519  0.3193885901
+-0.7622339142 -0.0253187462 -0.0406372303
+-0.3247276953  0.6814443588 -0.6558852870
+-0.4518947536  0.5718966444  0.2280752574
+-0.4481390643 -0.6183046056  0.0127967581
+ 0.4501613836  0.2319814646 -0.5716924804
+-0.2814926945 -0.1755003908 -0.6879349090
+-0.7310026836  0.0065664230 -0.2210993487
+-0.5698573801 -0.3831078312 -0.3343410226
+-0.2330291401 -0.2556853380 -0.6558852870
+-0.2510608506 -0.3497687395 -0.6308115736
+-0.3294271137 -0.2658915873 -0.6356668969
+ 0.2474173141 -0.3031371410 -0.6558852870
+-0.1735013310 -0.2035127114 -0.7153829937
+3 0 2 1 
+5 0 3 14 13 2 3
+3 0 4 3 
+3 0 5 4 
+3 0 6 5 
+5 0 1 7 24 6 
+3 1 8 7 
+5 1 9 29 16 8 3
+3 1 10 9 
+3 1 2 10 
+3 2 11 10 
+5 2 12 22 37 11 
+3 2 13 12 
+3 3 15 14 
+3 3 16 15 
+3 3 8 16 
+5 3 4 17 28 8 
+3 4 18 17 
+5 4 19 48 41 18 3
+3 4 5 19 
+5 5 20 49 45 19 
+3 5 21 20 
+5 5 6 12 38 21 3
+3 6 22 12 
+3 6 23 22 
+3 6 24 23 
+3 7 25 24 
+5 7 26 53 31 25 3
+3 7 27 26 
+3 7 8 27 
+3 8 28 27 
+3 9 30 29 
+3 9 31 30 
+3 9 25 31 
+5 9 10 32 52 25 
+3 10 33 32 
+5 10 11 34 55 33 3
+3 11 35 34 
+3 11 36 35 
+3 11 37 36 
+3 12 39 38 
+3 12 13 39 
+3 13 40 39 
+5 13 34 35 53 40 
+3 13 14 34 
+3 14 41 34 
+3 14 18 41 
+5 14 15 42 47 18 
+3 15 40 42 
+5 15 43 30 39 40 3
+3 15 16 43 
+5 16 44 54 50 43 
+3 16 29 44 
+3 17 45 28 
+5 17 36 37 32 45 3
+3 17 46 36 
+3 17 18 46 
+3 18 47 46 
+3 19 33 48 
+3 19 32 33 
+3 19 45 32 
+3 20 24 49 
+5 20 50 42 23 24 3
+3 20 43 50 
+3 20 21 43 
+3 21 30 43 
+5 21 48 33 29 30 
+3 21 38 48 
+3 22 51 37 
+5 22 46 47 58 51 3
+3 22 23 46 
+5 23 26 27 36 46 
+3 23 42 26 
+3 24 25 49 
+3 25 52 49 
+3 26 40 53 
+3 26 42 40 
+3 27 35 36 
+5 27 28 44 57 35 3
+3 28 54 44 
+3 28 45 54 
+3 29 55 44 
+3 29 33 55 
+3 30 31 39 
+5 31 56 51 38 39 
+3 31 53 56 
+3 32 37 52 
+3 34 41 55 
+3 35 57 53 
+3 37 51 52 
+3 38 58 48 
+3 38 51 58 
+5 41 58 59 57 55 
+3 41 48 58 
+3 42 50 47 
+3 44 55 57 
+3 45 49 54 
+3 47 59 58 
+3 47 50 59 
+5 49 52 56 59 54 3
+3 50 54 59 
+3 51 56 52 
+3 53 57 56 
+3 56 57 59 
+6 5 0 1 2 3 4 
+6 5 6 7 8 9 0 
+6 9 10 11 12 1 0 
+6 1 13 14 15 16 2 
+6 16 17 18 19 3 2 
+6 19 20 21 22 4 3 
+6 22 23 24 25 5 4 
+6 5 26 27 28 29 6 
+6 29 30 16 15 7 6 
+6 7 31 32 33 34 8 
+6 34 35 36 10 9 8 
+6 36 37 38 39 11 10 
+6 11 23 22 40 41 12 
+6 41 42 43 44 1 12 
+6 44 45 46 47 13 1 
+6 47 48 49 50 14 13 
+6 50 51 52 7 15 14 
+6 16 53 54 55 56 17 
+6 56 57 47 46 18 17 
+6 18 58 59 60 20 19 
+6 20 61 62 63 64 21 
+6 64 65 66 67 22 21 
+6 11 68 69 70 24 23 
+6 70 71 72 62 25 24 
+6 61 73 26 5 25 62 
+6 73 74 34 33 27 26 
+6 27 75 76 72 71 28 
+6 71 77 78 30 29 28 
+6 78 79 80 53 16 30 
+6 52 81 82 66 31 7 
+6 65 49 83 32 31 66 
+6 83 84 85 27 33 32 
+6 34 86 54 60 59 35 
+6 58 66 82 36 35 59 
+6 36 87 45 44 43 37 
+6 43 88 78 77 38 37 
+6 71 55 54 39 38 77 
+6 86 89 68 11 39 54 
+6 67 90 91 84 40 22 
+6 49 42 41 40 84 83 
+6 48 76 75 43 42 49 
+6 87 92 93 18 46 45 
+6 47 94 62 72 76 48 
+6 63 51 50 49 65 64 
+6 51 79 78 95 81 52 
+6 80 96 20 60 54 53 
+6 69 57 56 55 71 70 
+6 69 97 98 94 47 57 
+6 93 90 67 66 58 18 
+6 96 99 74 73 61 20 
+6 98 100 51 63 62 94 
+6 89 101 84 91 69 68 
+6 99 101 89 86 34 74 
+6 85 102 88 43 75 27 
+6 100 99 96 80 79 51 
+6 95 92 87 36 82 81 
+6 99 103 102 85 84 101 
+6 103 92 95 78 88 102 
+6 92 97 69 91 90 93 
+6 97 98 100 99 103 92 
+great ditrigonal icosidodecahedron
+great triambic icosahedron
+3/2|3 5
+(3.5.3.5.3.5)/2
+icosahedral group
+A5
+12{5}+20{3}
+51 20 60 32 20 6 0 0 -8 2 6 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9428090416  0.0000000000  0.3333333333
+ 0.2357022604  0.9128709292  0.3333333333
+-0.4714045208 -0.8164965809  0.3333333333
+ 0.6727182848 -0.6605596098  0.3333333333
+-0.4714045208  0.8164965809  0.3333333333
+-0.9084205452 -0.2523113194  0.3333333333
+ 0.4714045208 -0.8164965809 -0.3333333333
+ 0.0900302522 -0.6605596098  0.7453559925
+ 0.4714045208  0.8164965809 -0.3333333333
+ 0.6170765289 -0.2523113194 -0.7453559925
+-0.0900302522  0.6605596098 -0.7453559925
+ 0.9084205452  0.2523113194 -0.3333333333
+-0.6170765289  0.2523113194  0.7453559925
+-0.6727182848  0.6605596098 -0.3333333333
+-0.9428090416  0.0000000000 -0.3333333333
+-0.5270462767 -0.4082482905 -0.7453559925
+-0.2357022604 -0.9128709292 -0.3333333333
+ 0.5270462767  0.4082482905  0.7453559925
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1326479105  0.1027486297  0.1875924741
+-0.9091823043  0.3717480345  0.1875924741
+ 0.0226589682 -0.1662507751  0.1875924741
+ 0.7765343938  0.6015009550  0.1875924741
+-0.1553068788  0.0635021454  0.1875924741
+ 0.1326479105 -0.9732489895  0.1875924741
+ 0.2286328403  0.0635021454 -0.0838939048
+-0.0819809172  0.6015009550  0.7946544723
+ 0.1693108913 -0.1662507751  0.0838939048
+ 0.4799246488  0.3717480345 -0.7946544723
+-0.1186438980  0.2054972593  0.0838939048
+ 0.5619055661 -0.2297529205  0.7946544723
+ 0.1186438980  0.2054972593 -0.0838939048
+-0.0593219490 -0.2297529205 -0.0838939048
+-0.2286328403 -0.0635021454  0.0838939048
+ 0.0819809172 -0.6015009550 -0.7946544723
+ 0.2372877960  0.0000000000  0.0838939048
+-0.4799246488 -0.3717480345  0.7946544723
+ 0.1186438980 -0.2054972593 -0.0838939048
+-0.1693108913  0.1662507751 -0.0838939048
+ 0.0593219490  0.2297529205  0.0838939048
+-0.5619055661  0.2297529205 -0.7946544723
+-0.1186438980 -0.2054972593  0.0838939048
+-0.2372877960 -0.0000000000 -0.0838939048
+-0.7765343938 -0.6015009550 -0.1875924741
+ 0.1553068788 -0.0635021454 -0.1875924741
+ 0.9091823043 -0.3717480345 -0.1875924741
+ 0.0000000000  0.0000000000  0.2516817145
+-0.0226589682  0.1662507751 -0.1875924741
+ 0.0000000000 -0.0000000000 -0.2516817145
+-0.1326479105  0.9732489895 -0.1875924741
+-0.1326479105 -0.1027486297 -0.1875924741
+3 0 2 1 
+5 0 3 16 11 2 
+3 0 4 3 
+5 0 5 11 10 4 
+3 0 6 5 
+5 0 1 10 16 6 
+3 1 9 10 
+5 1 8 6 14 9 
+3 1 7 8 
+5 1 2 14 16 7 
+3 2 13 14 
+5 2 12 7 3 13 
+3 2 11 12 
+3 3 7 16 
+3 3 15 13 
+5 3 4 12 11 15 
+3 4 18 12 
+5 4 17 15 5 18 
+3 4 10 17 
+3 5 15 11 
+3 5 9 18 
+5 5 6 17 10 9 
+3 6 8 17 
+3 6 16 14 
+5 7 19 14 13 8 
+3 7 12 19 
+5 8 18 9 19 17 
+3 8 13 18 
+3 9 14 19 
+3 10 11 16 
+5 12 18 13 15 19 
+3 15 17 19 
+6 5 0 1 2 3 4 
+6 5 6 7 8 9 0 
+6 9 10 11 12 1 0 
+6 1 13 11 14 15 2 
+6 15 16 17 18 3 2 
+6 3 19 17 20 21 4 
+6 21 22 7 23 5 4 
+6 8 24 25 11 13 9 
+6 22 26 27 24 8 7 
+6 6 21 20 26 28 7 
+6 5 29 3 18 21 6 
+6 12 15 19 3 29 1 
+6 25 30 16 15 12 11 
+6 10 24 27 30 14 11 
+6 9 23 7 28 24 10 
+6 30 31 17 19 15 14 
+6 1 13 9 23 5 29 
+6 31 26 22 21 18 17 
+6 16 17 20 26 27 30 
+6 24 25 30 31 26 28 
+great icosicosidodecahedron
+great icosacronic hexecontahedron
+3/2 5|3
+(6.3/2.6.5)
+icosahedral group
+A5
+20{6}+12{5}+20{3/2}
+52 60 120 52 60 6 0 0 -8 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7913673487  0.0000000000  0.6113409191
+-0.6820030709  0.4014151117  0.6113409191
+ 0.1126514014  0.7833083316  0.6113409191
+-0.4944105968 -0.6179162098  0.6113409191
+ 0.9007316265  0.4014151117 -0.1659772426
+ 0.4149268310  0.7833083316  0.4628863603
+ 0.7860486710 -0.6179162098 -0.0175226837
+-0.7549125894 -0.4645892808  0.4628863603
+-0.5726387930  0.8028302234 -0.1659772426
+-0.2691077939  0.9487004534 -0.1659772426
+ 0.8343963552  0.2991971590  0.4628863603
+-0.0086058013 -0.9998094297 -0.0175226837
+-0.8708511144  0.1653921218  0.4628863603
+-0.8761697921 -0.4525240881 -0.1659772426
+ 0.8278221080 -0.4645892808 -0.3144318014
+ 0.2187285557  0.8028302234 -0.5546363234
+ 0.0331676357  0.9487004534 -0.3144318014
+-0.1437874830  0.2991971590  0.9432954043
+ 0.8987000724  0.1653921218 -0.4061817646
+ 0.4042894756 -0.4525240881 -0.7948408455
+-0.6906088722 -0.5983943180 -0.4061817646
+-0.0278489580 -0.3307842435  0.9432954043
+-0.0331676357 -0.9487004534  0.3144318014
+ 0.1544248384  0.9366352607  0.3144318014
+-0.5779574707  0.1849140136 -0.7948408455
+ 0.2166970016  0.5668072335 -0.7948408455
+-0.8278221080  0.4645892808  0.3144318014
+-0.7635183907  0.3307842435 -0.5546363234
+ 0.7614868366 -0.5668072335  0.3144318014
+ 0.2756820411 -0.1849140136  0.9432954043
+ 0.1007584765 -0.5983943180 -0.7948408455
+-0.7614868366  0.5668072335 -0.3144318014
+-0.1544248384 -0.9366352607 -0.3144318014
+ 0.7635183907 -0.3307842435  0.5546363234
+ 0.2691077939 -0.9487004534  0.1659772426
+-0.2756820411  0.1849140136 -0.9432954043
+ 0.7549125894  0.4645892808 -0.4628863603
+ 0.0278489580  0.3307842435 -0.9432954043
+-0.2166970016 -0.5668072335  0.7948408455
+ 0.5779574707 -0.1849140136  0.7948408455
+-0.4042894756  0.4525240881  0.7948408455
+-0.4149268310 -0.7833083316 -0.4628863603
+ 0.8761697921  0.4525240881  0.1659772426
+ 0.1437874830 -0.2991971590 -0.9432954043
+-0.1007584765  0.5983943180  0.7948408455
+-0.9007316265 -0.4014151117  0.1659772426
+ 0.8708511144 -0.1653921218 -0.4628863603
+-0.2187285557 -0.8028302234  0.5546363234
+-0.8343963552 -0.2991971590 -0.4628863603
+ 0.5726387930 -0.8028302234  0.1659772426
+-0.1126514014 -0.7833083316 -0.6113409191
+ 0.6906088722  0.5983943180  0.4061817646
+ 0.6820030709 -0.4014151117 -0.6113409191
+-0.8987000724 -0.1653921218  0.4061817646
+-0.7860486710  0.6179162098  0.0175226837
+-0.7913673487  0.0000000000 -0.6113409191
+ 0.4944105968  0.6179162098 -0.6113409191
+ 0.0086058013  0.9998094297  0.0175226837
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.2317571228  0.8506508084  0.4718917654
+-0.1208775632  0.2515255344  0.4718917654
+-0.8089973662  0.3504874081  0.4718917654
+ 0.2317571228 -0.4822469333  0.4718917654
+ 0.8680129287  0.3504874081 -0.3517273552
+ 0.4473371359  0.2515255344  0.1928281889
+-0.7071184954  0.0703588793 -0.0631535304
+ 0.0842182165 -0.1752437040  0.9809163757
+ 0.3868380289  0.5960899915 -0.0631535304
+-0.4758724578 -0.1921484102  0.1928281889
+-0.8159632084 -0.4587939735 -0.3517273552
+ 0.7247791497 -0.1752437040  0.6663218655
+ 0.3823128290  0.0703588793 -0.5981988263
+-0.2864675581  0.5960899915  0.2675226479
+ 0.2204861533 -0.4587939735 -0.8607519655
+ 0.4435182383 -0.1921484102 -0.2587061630
+ 0.0772523743 -0.9845250856  0.1572972551
+-0.1732277900 -0.3702797828  0.3652989642
+-0.0423522231  0.5397481497 -0.0862353877
+ 0.3159753393  0.6754071043 -0.6663218655
+-0.7247791497  0.1752437040 -0.6663218655
+-0.3949869091  0.3702797828 -0.0862353877
+ 0.3973471176 -0.0960742051  0.3652989642
+ 0.7204740224 -0.6754071043  0.1572972551
+-0.1270566693 -0.4663539879 -0.2587061630
+-0.3159753393 -0.6754071043  0.6663218655
+-0.2937894852 -0.2545608169 -0.5981988263
+ 0.3949869091 -0.3702797828  0.0862353877
+-0.7204740224  0.6754071043 -0.1572972551
+ 0.1732277900  0.3702797828 -0.3652989642
+-0.0842182165  0.1752437040 -0.9809163757
+ 0.0461711207 -0.0960742051  0.5377697395
+ 0.2937894852  0.2545608169  0.5981988263
+-0.8680129287 -0.3504874081  0.3517273552
+ 0.2864675581 -0.5960899915 -0.2675226479
+-0.0461711207  0.0960742051 -0.5377697395
+-0.3823128290 -0.0703588793  0.5981988263
+-0.0772523743  0.9845250856 -0.1572972551
+ 0.8159632084  0.4587939735  0.3517273552
+-0.3973471176  0.0960742051 -0.3652989642
+ 0.0423522231 -0.5397481497  0.0862353877
+ 0.8089973662 -0.3504874081 -0.4718917654
+-0.3868380289 -0.5960899915  0.0631535304
+ 0.7071184954 -0.0703588793  0.0631535304
+-0.2204861533  0.4587939735  0.8607519655
+-0.4435182383  0.1921484102  0.2587061630
+-0.4473371359 -0.2515255344 -0.1928281889
+ 0.4758724578  0.1921484102 -0.1928281889
+ 0.1270566693  0.4663539879  0.2587061630
+-0.2317571228 -0.8506508084 -0.4718917654
+ 0.1208775632 -0.2515255344 -0.4718917654
+-0.2317571228  0.4822469333 -0.4718917654
+6 0 2 9 16 5 1 
+3 0 3 2 2
+6 0 4 14 28 10 3 
+5 0 1 7 12 4 
+6 1 6 17 38 20 7 
+3 1 5 6 2
+5 2 8 21 25 9 
+6 2 3 11 29 23 8 
+5 3 10 26 19 11 
+3 4 13 14 2
+6 4 12 31 36 32 13 
+6 5 15 35 39 18 6 
+5 5 16 36 31 15 
+5 6 18 13 32 17 
+6 7 19 26 25 21 12 
+3 7 20 19 2
+6 8 22 34 15 31 21 
+3 8 23 22 2
+3 9 24 16 2
+6 9 25 44 47 43 24 
+6 10 27 46 42 44 26 
+3 10 28 27 2
+3 11 30 29 2
+6 11 19 20 33 48 30 
+3 12 21 31 2
+6 13 18 40 50 33 14 
+5 14 33 20 38 28 
+3 15 34 35 2
+6 16 24 41 54 49 36 
+3 17 37 38 2
+6 17 32 49 51 53 37 
+3 18 39 40 2
+5 22 41 24 43 34 
+6 22 23 42 56 55 41 
+5 23 29 47 44 42 
+3 25 26 44 2
+5 27 45 30 48 46 
+6 27 28 38 37 52 45 
+6 29 30 45 58 57 47 
+3 32 36 49 2
+3 33 50 48 2
+6 34 43 57 59 51 35 
+5 35 51 49 54 39 
+5 37 53 50 40 52 
+6 39 54 55 58 52 40 
+3 41 55 54 2
+3 42 46 56 2
+3 43 47 57 2
+3 45 52 58 2
+6 46 48 50 53 59 56 
+3 51 59 53 2
+5 55 56 59 57 58 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 10 3 
+4 5 11 12 0 
+4 4 13 11 5 
+4 3 14 15 4 
+4 6 16 17 7 
+4 0 18 19 6 
+4 8 20 21 2 
+4 7 22 23 8 
+4 10 24 14 3 
+4 9 25 13 10 
+4 2 26 25 9 
+4 11 27 16 12 
+4 12 28 18 0 
+4 4 29 30 13 
+4 25 31 11 13 
+4 14 8 23 15 
+4 23 26 4 15 
+4 6 14 24 16 
+4 16 32 33 17 
+4 33 34 7 17 
+4 28 32 19 18 
+4 19 35 14 6 
+4 35 20 8 14 
+4 20 36 37 21 
+4 37 26 2 21 
+4 34 38 22 7 
+4 38 36 23 22 
+4 10 12 16 24 
+4 30 39 10 13 
+4 23 40 25 26 
+4 27 41 32 16 
+4 11 42 41 27 
+4 39 28 12 10 
+4 29 37 43 30 
+4 4 29 37 26 
+4 31 44 42 11 
+4 25 43 44 31 
+4 28 45 33 32 
+4 33 46 20 34 
+4 41 47 19 32 
+4 19 34 20 35 
+4 38 48 37 36 
+4 46 49 36 20 
+4 47 38 34 19 
+4 49 40 23 36 
+4 30 42 28 39 
+4 49 43 25 40 
+4 30 50 41 42 
+4 48 44 43 37 
+4 49 50 30 43 
+4 44 45 28 42 
+4 44 51 33 45 
+4 51 49 46 33 
+4 41 51 38 47 
+4 38 48 44 51 
+4 50 41 51 49 
+small icosihemidodecahedron
+small icosihemidodecacron
+3/2 3|5
+(10.3/2.10.3)
+icosahedral group
+A5
+6{10}+10{3}+10{3/2}
+53 30 60 26 30 0 1 1 -4 3 4 120 5 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5877852523  0.0000000000  0.8090169944
+-0.5877852523  0.0000000000  0.8090169944
+-0.2628655561  0.5257311121  0.8090169944
+ 0.2628655561 -0.5257311121  0.8090169944
+ 0.9510565163  0.0000000000  0.3090169944
+ 0.6881909602  0.5257311121  0.5000000000
+-0.6881909602 -0.5257311121  0.5000000000
+-0.9510565163  0.0000000000  0.3090169944
+-0.4253254042  0.8506508084  0.3090169944
+ 0.1624598481  0.8506508084  0.5000000000
+-0.1624598481 -0.8506508084  0.5000000000
+ 0.4253254042 -0.8506508084  0.3090169944
+ 0.8506508084 -0.5257311121  0.0000000000
+ 0.9510565163  0.0000000000 -0.3090169944
+ 0.5257311121  0.8506508084  0.0000000000
+-0.5257311121 -0.8506508084  0.0000000000
+-0.9510565163  0.0000000000 -0.3090169944
+-0.8506508084  0.5257311121  0.0000000000
+-0.4253254042  0.8506508084 -0.3090169944
+ 0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523  0.0000000000 -0.8090169944
+ 0.6881909602  0.5257311121 -0.5000000000
+ 0.1624598481  0.8506508084 -0.5000000000
+-0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602 -0.5257311121 -0.5000000000
+-0.5877852523  0.0000000000 -0.8090169944
+-0.2628655561  0.5257311121 -0.8090169944
+ 0.2628655561 -0.5257311121 -0.8090169944
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-0.3035309991  0.1875924741  0.9341723590
+-0.8944271910 -0.4472135955  0.0000000000
+ 0.3035309991 -0.1875924741  0.9341723590
+ 0.7236067977 -0.4472135955 -0.5257311121
+ 0.7946544723  0.1875924741  0.5773502692
+-0.7946544723 -0.1875924741  0.5773502692
+ 0.7236067977 -0.4472135955  0.5257311121
+-0.1875924741  0.7946544723  0.5773502692
+ 0.1875924741 -0.7946544723  0.5773502692
+-0.2763932023 -0.4472135955  0.8506508084
+ 0.9822469464 -0.1875924741  0.0000000000
+ 0.4911234732  0.7946544723  0.3568220898
+-0.2763932023 -0.4472135955 -0.8506508084
+-0.4911234732 -0.7946544723  0.3568220898
+-0.9822469464  0.1875924741  0.0000000000
+-0.6070619982  0.7946544723  0.0000000000
+ 0.6070619982 -0.7946544723  0.0000000000
+ 0.7946544723  0.1875924741 -0.5773502692
+ 0.4911234732  0.7946544723 -0.3568220898
+-0.4911234732 -0.7946544723 -0.3568220898
+-0.7946544723 -0.1875924741 -0.5773502692
+-0.1875924741  0.7946544723 -0.5773502692
+ 0.1875924741 -0.7946544723 -0.5773502692
+ 0.3035309991 -0.1875924741 -0.9341723590
+-0.3035309991  0.1875924741 -0.9341723590
+10 0 1 5 14 21 29 26 17 8 2 
+3 0 2 3 2
+10 0 3 9 19 27 29 28 20 12 4 
+3 0 1 4 
+10 1 4 11 16 25 26 27 23 15 6 
+3 1 6 5 2
+3 2 8 7 
+10 2 7 16 24 28 21 22 15 10 3 
+3 3 10 9 
+3 4 12 11 2
+10 5 6 10 9 18 17 25 24 20 13 
+3 5 13 14 
+3 6 15 10 
+10 7 8 18 19 23 22 14 13 12 11 
+3 7 11 16 2
+3 8 17 18 2
+3 9 18 19 2
+3 12 20 13 
+3 14 22 21 2
+3 15 23 22 2
+3 16 25 24 
+3 17 26 25 
+3 19 23 27 
+3 20 28 24 2
+3 21 28 29 
+3 26 29 27 2
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 8 7 1 2 
+4 9 2 3 4 
+4 5 10 11 0 
+4 12 4 5 10 
+4 6 13 14 7 
+4 15 0 6 13 
+4 8 10 16 2 
+4 12 7 8 10 
+4 9 13 14 4 
+4 17 2 9 13 
+4 17 10 11 13 
+4 18 13 11 0 
+4 19 4 12 7 
+4 20 4 14 7 
+4 21 0 15 10 
+4 16 13 15 10 
+4 22 13 16 2 
+4 23 2 17 10 
+4 18 7 24 0 
+4 19 13 18 7 
+4 22 4 19 13 
+4 20 10 23 7 
+4 21 4 20 10 
+4 25 0 21 4 
+4 25 2 22 4 
+4 24 2 23 7 
+4 24 0 25 2 
+small dodecicosahedron
+small dodecicosacron
+3/2 3 5|
+(10.6.10/9.6/5)
+icosahedral group
+A5
+6{10}+10{6}+10{6/5}+6{10/9}
+54 60 120 32 60 0 0 1 -28 4 4 120 5 0 2
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5558508647  0.0000000000  0.8312820317
+-0.5423346067  0.1218333214  0.8312820317
+ 0.2523198656 -0.4952826155  0.8312820317
+-0.3547421326  0.4279348118  0.8312820317
+ 0.9129018498  0.1218333214  0.3895726561
+ 0.7569595968  0.4279348118  0.4938460950
+-0.8323493477 -0.2516159727  0.4938460950
+-0.0195609124  0.3526376782  0.9355554706
+-0.8639995688  0.3189637764  0.3895726561
+ 0.3058398516 -0.8687319096  0.3895726561
+-0.0376948755 -0.8687319096  0.4938460950
+-0.1536334005  0.8558696236  0.4938460950
+-0.3230919115 -0.1426449373  0.9355554706
+-0.6764070948  0.6250652668  0.3895726561
+ 0.9664218358 -0.2516159727 -0.0521367195
+ 0.5362899523  0.3526376782  0.7668375023
+ 0.9347716147  0.3189637764 -0.1564101584
+ 0.4022174642  0.8558696236  0.3251281267
+ 0.7886098179 -0.1426449373  0.5981195340
+ 0.7788293617  0.6250652668 -0.0521367195
+-0.7788293617 -0.6250652668  0.0521367195
+-0.5800294821 -0.7468985882  0.3251281267
+ 0.1815478197  0.7805724901  0.5981195340
+-0.8421298039  0.5160942314 -0.1564101584
+-0.6628908367  0.7468985882  0.0521367195
+ 0.6628908367 -0.7468985882 -0.0521367195
+-0.0707720459 -0.6379275528  0.7668375023
+ 0.1401171424 -0.9777029450 -0.1564101584
+ 0.4850788188 -0.6379275528  0.5981195340
+-0.2034175846 -0.9777029450 -0.0521367195
+ 0.2034175846  0.9777029450  0.0521367195
+-0.6131066526 -0.5160942314  0.5981195340
+-0.9664218358  0.2516159727  0.0521367195
+ 0.6764070948 -0.6250652668 -0.3895726561
+ 0.6131066526  0.5160942314 -0.5981195340
+ 0.5800294821  0.7468985882 -0.3251281267
+-0.1401171424  0.9777029450  0.1564101584
+ 0.8421298039 -0.5160942314  0.1564101584
+ 0.8323493477  0.2516159727 -0.4938460950
+-0.7569595968 -0.4279348118 -0.4938460950
+-0.4022174642 -0.8558696236 -0.3251281267
+-0.9347716147 -0.3189637764  0.1564101584
+-0.7886098179  0.1426449373 -0.5981195340
+-0.4850788188  0.6379275528 -0.5981195340
+-0.3058398516  0.8687319096 -0.3895726561
+ 0.8639995688 -0.3189637764 -0.3895726561
+-0.1815478197 -0.7805724901 -0.5981195340
+ 0.1536334005 -0.8558696236 -0.4938460950
+ 0.0376948755  0.8687319096 -0.4938460950
+-0.9129018498 -0.1218333214 -0.3895726561
+ 0.3547421326 -0.4279348118 -0.8312820317
+ 0.3230919115  0.1426449373 -0.9355554706
+ 0.0707720459  0.6379275528 -0.7668375023
+ 0.5423346067 -0.1218333214 -0.8312820317
+-0.5558508647 -0.0000000000 -0.8312820317
+-0.5362899523 -0.3526376782 -0.7668375023
+-0.2523198656  0.4952826155 -0.8312820317
+ 0.0195609124 -0.3526376782 -0.9355554706
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1036376133  0.9341723590  0.3414399638
+-0.1494536576 -0.1924500897  0.3414399638
+-0.7853356508 -0.5163977795  0.3414399638
+ 0.1036376133  0.2205281794  0.3414399638
+ 0.8426251145 -0.5163977795 -0.1526965938
+ 0.3140278393 -0.1924500897  0.2007589619
+-0.1758443548  0.2833126966  0.2544943231
+ 0.1963339127 -0.7369259589  0.6468331514
+-0.3322633625  0.0280780897  0.2544943231
+ 0.7457496051  0.1595756897  0.6468331514
+ 0.2876371421  0.2833126966  0.1138133213
+-0.2603854803  0.1595756897  0.9522263391
+ 0.4176654526  0.0280780897  0.0268676806
+-0.4176654526 -0.0280780897 -0.0268676806
+-0.7457496051 -0.1595756897 -0.6468331514
+-0.8426251145  0.5163977795  0.1526965938
+ 0.1199479612 -0.0735093931  0.3951753249
+-0.1218731366 -0.3849001795  0.1138133213
+ 0.1645741816 -0.3849001795  0.0268676806
+-0.1645741816  0.3849001795 -0.0268676806
+-0.1963339127  0.7369259589 -0.6468331514
+ 0.2603854803 -0.1595756897 -0.9522263391
+ 0.3322633625 -0.0280780897 -0.2544943231
+ 0.7853356508  0.5163977795 -0.3414399638
+ 0.1218731366  0.3849001795 -0.1138133213
+-0.2876371421 -0.2833126966 -0.1138133213
+-0.3140278393  0.1924500897 -0.2007589619
+ 0.1758443548 -0.2833126966 -0.2544943231
+-0.1036376133 -0.9341723590 -0.3414399638
+ 0.1494536576  0.1924500897 -0.3414399638
+-0.1036376133 -0.2205281794 -0.3414399638
+-0.1199479612  0.0735093931 -0.3951753249
+10 0 2 9 24 44 53 35 17 5 1 
+6 0 3 11 22 7 2 
+10 0 4 14 24 43 56 47 28 10 3 9
+6 0 1 6 18 12 4 5
+10 1 3 11 30 47 58 52 35 20 6 9
+6 1 5 15 26 10 3 
+6 2 8 23 37 25 9 5
+10 2 7 21 41 48 34 15 5 16 8 9
+6 4 13 32 42 33 14 
+10 4 12 31 36 39 46 26 10 27 13 
+6 5 17 36 31 23 16 5
+10 6 19 29 11 22 42 33 25 37 18 
+6 6 20 39 46 38 19 
+6 7 9 24 43 40 21 5
+10 7 22 30 48 51 52 53 45 25 9 
+10 8 13 32 21 40 55 57 49 31 23 
+6 8 16 19 29 27 13 
+6 10 28 41 21 32 27 
+6 11 30 48 34 38 29 5
+6 12 14 24 44 49 31 
+10 12 18 20 39 54 58 56 50 33 14 9
+10 15 17 36 49 44 43 40 41 28 26 
+6 15 34 51 52 35 17 5
+10 16 23 37 45 57 59 51 34 38 19 
+6 18 37 45 53 35 20 
+6 22 42 50 56 47 30 5
+6 25 33 50 55 57 45 
+6 26 46 54 58 47 28 
+10 27 32 42 50 55 59 54 46 38 29 9
+6 36 49 57 59 54 39 
+6 40 41 48 51 59 55 
+6 43 44 53 52 58 56 5
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 4 5 2 
+4 2 8 9 3 
+4 5 7 10 0 
+4 3 11 12 4 
+4 7 13 14 1 
+4 6 15 16 7 
+4 0 13 14 6 
+4 5 9 17 2 
+4 1 11 18 4 
+4 9 19 20 3 
+4 8 15 16 9 
+4 2 19 20 8 
+4 5 21 22 7 
+4 16 23 10 7 
+4 10 21 22 0 
+4 20 24 11 3 
+4 11 16 23 12 
+4 12 20 24 4 
+4 7 17 15 13 
+4 14 25 11 1 
+4 6 23 10 15 
+4 0 19 2 13 
+4 14 26 11 6 
+4 21 27 9 5 
+4 16 28 17 9 
+4 17 21 27 2 
+4 28 18 11 16 
+4 18 14 25 4 
+4 9 10 15 19 
+4 8 28 17 15 
+4 20 26 11 8 
+4 22 23 18 7 
+4 22 4 24 0 
+4 9 29 21 10 
+4 24 23 6 11 
+4 28 12 23 18 
+4 12 9 29 20 
+4 15 30 21 13 
+4 7 30 21 17 
+4 25 28 8 11 
+4 2 31 21 13 
+4 0 31 21 19 
+4 14 24 23 26 
+4 27 28 12 9 
+4 27 4 25 2 
+4 30 14 18 7 
+4 15 29 21 19 
+4 20 25 28 26 
+4 22 14 30 23 
+4 14 31 4 22 
+4 24 0 31 14 
+4 29 28 27 20 
+4 15 26 28 30 
+4 20 31 2 25 
+4 23 29 15 26 
+4 27 4 31 20 
+4 30 23 29 28 
+small dodecahemidodecahedron
+small dodecahemidodecacron
+5/4 5|5
+(10.5/4.10.5)
+icosahedral group
+A5
+6{10}+6{5}+6{5/4}
+55 30 60 18 30 0 1 1 -12 3 4 120 5 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5877852523  0.0000000000  0.8090169944
+-0.5877852523  0.0000000000  0.8090169944
+ 0.2628655561  0.5257311121  0.8090169944
+-0.2628655561 -0.5257311121  0.8090169944
+ 0.9510565163  0.0000000000  0.3090169944
+ 0.6881909602 -0.5257311121  0.5000000000
+-0.6881909602  0.5257311121  0.5000000000
+-0.9510565163 -0.0000000000  0.3090169944
+ 0.4253254042  0.8506508084  0.3090169944
+-0.1624598481  0.8506508084  0.5000000000
+ 0.1624598481 -0.8506508084  0.5000000000
+-0.4253254042 -0.8506508084  0.3090169944
+ 0.8506508084  0.5257311121  0.0000000000
+ 0.9510565163  0.0000000000 -0.3090169944
+ 0.5257311121 -0.8506508084  0.0000000000
+-0.5257311121  0.8506508084  0.0000000000
+-0.9510565163 -0.0000000000 -0.3090169944
+-0.8506508084 -0.5257311121  0.0000000000
+ 0.4253254042  0.8506508084 -0.3090169944
+-0.4253254042 -0.8506508084 -0.3090169944
+ 0.5877852523  0.0000000000 -0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.6881909602  0.5257311121 -0.5000000000
+-0.1624598481  0.8506508084 -0.5000000000
+-0.5877852523 -0.0000000000 -0.8090169944
+ 0.2628655561  0.5257311121 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-0.2763932023  0.4472135955  0.8506508084
+-0.8944271910  0.4472135955  0.0000000000
+ 0.2763932023 -0.4472135955  0.8506508084
+ 0.7236067977  0.4472135955 -0.5257311121
+ 0.7236067977  0.4472135955  0.5257311121
+-0.7236067977 -0.4472135955  0.5257311121
+ 0.7236067977  0.4472135955  0.5257311121
+-0.2763932023  0.4472135955  0.8506508084
+ 0.8944271910 -0.4472135955  0.0000000000
+-0.8944271910  0.4472135955  0.0000000000
+ 0.2763932023 -0.4472135955  0.8506508084
+-0.0000000000  1.0000000000  0.0000000000
+ 0.0000000000 -1.0000000000  0.0000000000
+ 0.7236067977  0.4472135955 -0.5257311121
+-0.7236067977 -0.4472135955 -0.5257311121
+ 0.2763932023 -0.4472135955 -0.8506508084
+-0.2763932023  0.4472135955 -0.8506508084
+10 0 1 5 14 21 29 26 17 8 2 
+5 0 2 7 10 3 4
+10 0 3 9 19 27 29 28 20 12 4 
+5 0 1 6 11 4 
+10 1 6 15 23 28 26 24 16 10 3 
+5 1 3 9 13 5 4
+5 2 8 18 12 4 
+10 2 4 11 15 22 21 27 25 16 7 
+10 5 13 19 25 24 17 18 12 11 6 
+5 5 6 15 22 14 
+5 7 16 24 17 8 
+10 7 8 18 20 23 22 14 13 9 10 
+5 9 10 16 25 19 4
+5 11 15 23 20 12 4
+5 13 14 21 27 19 
+5 17 26 28 20 18 
+5 21 22 23 28 29 
+5 24 26 29 27 25 4
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 1 4 5 2 
+4 6 2 3 7 
+4 5 8 9 0 
+4 3 8 9 4 
+4 10 7 1 11 
+4 10 0 6 11 
+4 5 11 12 2 
+4 12 4 1 11 
+4 13 7 3 8 
+4 13 2 6 8 
+4 14 11 5 8 
+4 9 11 14 0 
+4 9 7 13 4 
+4 12 7 10 4 
+4 15 0 10 8 
+4 15 11 6 8 
+4 12 8 14 2 
+4 15 2 13 11 
+4 14 7 16 0 
+4 16 11 9 7 
+4 16 4 13 11 
+4 17 4 10 8 
+4 17 7 12 8 
+4 17 0 15 4 
+4 17 2 14 7 
+4 16 2 15 4 
+4 16 0 17 2 
+great stellated dodecahedron
+great icosahedron
+3|2 5/2
+(5/2.5/2.5/2)
+icosahedral group
+A5
+12{5/2}
+56 20 30 12 20 7 0 0 2 1 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6666666667  0.0000000000 -0.7453559925
+-0.3333333333  0.5773502692 -0.7453559925
+-0.3333333333 -0.5773502692 -0.7453559925
+-0.7453559925  0.5773502692  0.3333333333
+-0.7453559925 -0.5773502692  0.3333333333
+-0.1273220038 -0.9341723590  0.3333333333
+ 0.8726779962 -0.3568220898  0.3333333333
+ 0.8726779962  0.3568220898  0.3333333333
+-0.1273220038  0.9341723590  0.3333333333
+ 0.1273220038 -0.9341723590 -0.3333333333
+ 0.1273220038  0.9341723590 -0.3333333333
+ 0.7453559925  0.5773502692 -0.3333333333
+-0.8726779962 -0.3568220898 -0.3333333333
+-0.8726779962  0.3568220898 -0.3333333333
+ 0.7453559925 -0.5773502692 -0.3333333333
+ 0.3333333333  0.5773502692  0.7453559925
+ 0.3333333333 -0.5773502692  0.7453559925
+-0.6666666667  0.0000000000  0.7453559925
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.4911234732  0.8506508084  0.1875924741
+-0.9822469464  0.0000000000  0.1875924741
+ 0.4911234732 -0.8506508084  0.1875924741
+-0.6070619982  0.0000000000 -0.7946544723
+ 0.3035309991 -0.5257311121 -0.7946544723
+ 0.3035309991  0.5257311121 -0.7946544723
+-0.3035309991 -0.5257311121  0.7946544723
+-0.3035309991  0.5257311121  0.7946544723
+ 0.6070619982 -0.0000000000  0.7946544723
+ 0.9822469464  0.0000000000 -0.1875924741
+-0.4911234732  0.8506508084 -0.1875924741
+-0.4911234732 -0.8506508084 -0.1875924741
+5 0 2 7 4 1 2
+5 0 3 9 6 2 2
+5 0 1 5 8 3 2
+5 1 4 10 11 5 2
+5 2 6 12 13 7 2
+5 3 8 14 15 9 2
+5 4 7 13 16 10 2
+5 5 11 17 14 8 2
+5 6 9 15 18 12 2
+5 10 16 19 17 11 2
+5 12 18 19 16 13 2
+5 14 17 19 18 15 2
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 6 4 0 
+3 5 7 2 
+3 8 5 1 
+3 3 9 6 
+3 7 9 3 
+3 4 10 8 
+3 6 10 4 
+3 5 11 7 
+3 8 11 5 
+3 9 10 6 
+3 11 9 7 
+3 10 11 8 
+3 9 10 11 
+great icosahedron
+great stellated dodecahedron
+5/2|2 3
+(3.3.3.3.3)/2
+icosahedral group
+A5
+20{3}
+57 12 30 20 12 7 0 0 2 1 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8944271910  0.0000000000 -0.4472135955
+-0.7236067977  0.5257311121 -0.4472135955
+ 0.2763932023 -0.8506508084 -0.4472135955
+ 0.2763932023  0.8506508084 -0.4472135955
+-0.7236067977 -0.5257311121 -0.4472135955
+-0.2763932023 -0.8506508084  0.4472135955
+-0.2763932023  0.8506508084  0.4472135955
+ 0.7236067977  0.5257311121  0.4472135955
+-0.8944271910 -0.0000000000  0.4472135955
+ 0.7236067977 -0.5257311121  0.4472135955
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.3035309991  0.9341723590  0.1875924741
+-0.7946544723 -0.5773502692  0.1875924741
+ 0.9822469464  0.0000000000  0.1875924741
+-0.7946544723  0.5773502692  0.1875924741
+ 0.3035309991 -0.9341723590  0.1875924741
+-0.1875924741  0.5773502692 -0.7946544723
+ 0.6070619982  0.0000000000  0.7946544723
+-0.1875924741 -0.5773502692 -0.7946544723
+-0.4911234732  0.3568220898  0.7946544723
+ 0.4911234732  0.3568220898 -0.7946544723
+ 0.1875924741 -0.5773502692  0.7946544723
+-0.6070619982 -0.0000000000 -0.7946544723
+ 0.1875924741  0.5773502692  0.7946544723
+ 0.4911234732 -0.3568220898 -0.7946544723
+-0.4911234732 -0.3568220898  0.7946544723
+-0.9822469464 -0.0000000000 -0.1875924741
+ 0.7946544723 -0.5773502692 -0.1875924741
+ 0.7946544723  0.5773502692 -0.1875924741
+-0.3035309991  0.9341723590 -0.1875924741
+-0.3035309991 -0.9341723590 -0.1875924741
+3 0 2 1 
+3 0 3 2 
+3 0 4 3 
+3 0 5 4 
+3 0 1 5 
+3 1 7 5 
+3 1 6 7 
+3 1 2 6 
+3 2 8 6 
+3 2 3 8 
+3 3 9 8 
+3 3 4 9 
+3 4 10 9 
+3 4 5 10 
+3 5 7 10 
+3 6 11 7 
+3 6 8 11 
+3 7 11 10 
+3 8 9 11 
+3 9 10 11 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 13 14 5 4 3 
+5 6 15 16 8 7 
+5 14 17 15 6 5 
+5 16 18 10 9 8 
+5 18 19 12 11 10 
+5 19 17 14 13 12 
+5 15 16 18 19 17 
+great icosidodecahedron
+great rhombic triacontahedron
+2|5/2 3
+(5/2.3.5/2.3)
+icosahedral group
+A5
+20{3}+12{5/2}
+58 30 60 32 30 7 0 0 2 2 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9510565163  0.0000000000 -0.3090169944
+ 0.4253254042  0.8506508084 -0.3090169944
+-0.9510565163  0.0000000000 -0.3090169944
+-0.4253254042 -0.8506508084 -0.3090169944
+-0.1624598481  0.8506508084  0.5000000000
+-0.5877852523  0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.6881909602 -0.5257311121  0.5000000000
+ 0.1624598481 -0.8506508084  0.5000000000
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.2628655561  0.5257311121 -0.8090169944
+-0.6881909602  0.5257311121  0.5000000000
+-0.8506508084 -0.5257311121 -0.0000000000
+ 0.5257311121 -0.8506508084 -0.0000000000
+-0.5877852523 -0.0000000000  0.8090169944
+-0.2628655561 -0.5257311121  0.8090169944
+-0.5257311121  0.8506508084  0.0000000000
+ 0.8506508084  0.5257311121 -0.0000000000
+ 0.5877852523 -0.0000000000  0.8090169944
+ 0.2628655561  0.5257311121  0.8090169944
+ 0.6881909602 -0.5257311121 -0.5000000000
+-0.1624598481  0.8506508084 -0.5000000000
+ 0.9510565163 -0.0000000000  0.3090169944
+ 0.4253254042  0.8506508084  0.3090169944
+-0.6881909602  0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.9510565163  0.0000000000  0.3090169944
+-0.4253254042 -0.8506508084  0.3090169944
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.4911234732  0.3035309991  0.3568220898
+-0.4911234732  0.7946544723  0.3568220898
+-0.4911234732 -0.3035309991  0.3568220898
+ 0.4911234732 -0.7946544723  0.3568220898
+ 0.1875924741 -0.3035309991 -0.5773502692
+ 0.1875924741  0.7946544723 -0.5773502692
+ 0.7946544723 -0.1875924741 -0.5773502692
+-0.1875924741  0.3035309991 -0.5773502692
+-0.1875924741 -0.7946544723 -0.5773502692
+-0.7946544723  0.1875924741 -0.5773502692
+-0.6070619982  0.3035309991 -0.0000000000
+-0.3035309991 -0.1875924741  0.9341723590
+-0.6070619982 -0.7946544723 -0.0000000000
+-0.0000000000 -0.6787159473 -0.0000000000
+-0.9822469464 -0.1875924741  0.0000000000
+ 0.6070619982 -0.3035309991 -0.0000000000
+ 0.3035309991  0.1875924741  0.9341723590
+ 0.6070619982  0.7946544723 -0.0000000000
+ 0.0000000000  0.6787159473  0.0000000000
+ 0.9822469464  0.1875924741  0.0000000000
+-0.3035309991 -0.1875924741 -0.9341723590
+ 0.1875924741 -0.3035309991  0.5773502692
+ 0.1875924741  0.7946544723  0.5773502692
+ 0.7946544723 -0.1875924741  0.5773502692
+-0.1875924741  0.3035309991  0.5773502692
+ 0.3035309991  0.1875924741 -0.9341723590
+-0.1875924741 -0.7946544723  0.5773502692
+-0.7946544723  0.1875924741  0.5773502692
+ 0.4911234732  0.3035309991 -0.3568220898
+ 0.4911234732 -0.7946544723 -0.3568220898
+-0.4911234732  0.7946544723 -0.3568220898
+-0.4911234732 -0.3035309991 -0.3568220898
+5 0 2 8 5 1 2
+3 0 3 2 
+5 0 4 12 9 3 2
+3 0 1 4 
+5 1 6 14 11 4 2
+3 1 5 6 
+3 2 7 8 
+5 2 3 10 17 7 2
+3 3 9 10 
+3 4 11 12 
+5 5 13 22 15 6 2
+3 5 8 13 
+3 6 15 14 
+5 7 16 21 13 8 2
+3 7 17 16 
+5 9 18 26 19 10 2
+3 9 12 18 
+3 10 19 17 
+5 11 20 25 18 12 2
+3 11 14 20 
+3 13 21 22 
+5 14 15 23 28 20 2
+3 15 22 23 
+3 16 24 21 
+5 16 17 19 27 24 2
+3 18 25 26 
+3 19 26 27 
+3 20 28 25 
+5 21 24 29 23 22 2
+3 23 29 28 
+3 24 27 29 
+5 25 28 29 27 26 2
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 7 8 2 1 
+4 2 9 4 3 
+4 5 10 11 0 
+4 4 12 10 5 
+4 6 13 14 7 
+4 11 13 6 0 
+4 8 15 16 2 
+4 7 17 15 8 
+4 9 18 19 4 
+4 16 18 9 2 
+4 10 20 13 11 
+4 19 21 12 4 
+4 21 22 10 12 
+4 13 23 24 14 
+4 24 17 7 14 
+4 15 25 18 16 
+4 24 26 15 17 
+4 18 27 21 19 
+4 20 28 23 13 
+4 22 28 20 10 
+4 21 29 28 22 
+4 28 30 24 23 
+4 25 31 27 18 
+4 26 31 25 15 
+4 30 31 26 24 
+4 31 29 21 27 
+4 29 28 30 31 
+great truncated icosahedron
+great stellapentakisdodecahedron
+2 5/2|3
+(6.6.5/2)
+icosahedral group
+A5
+20{6}+12{5/2}
+59 60 90 32 60 7 0 0 2 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8356150397  0.0000000000  0.5493154881
+-0.7824189491  0.2933821444  0.5493154881
+ 0.6296037101 -0.5494102864  0.5493154881
+ 0.8888111303  0.2933821444 -0.3520535357
+ 0.1131652141 -0.5494102864  0.8278538347
+-0.9352341880  0.0373540025 -0.3520535357
+-0.7292228585  0.5867642889 -0.3520535357
+ 0.4464985474  0.3395542307  0.8278538347
+ 0.4767884711 -0.8054384283 -0.3520535357
+ 0.2195573953  0.0373540025 -0.9748842130
+ 0.1063921812  0.5867642889 -0.8027380476
+-0.5560885209 -0.8054384283  0.2050231574
+-0.6347778468  0.7449983827  0.2050231574
+-0.3056304780 -0.5120562839 -0.8027380476
+-0.9681111801 -0.1439661345  0.2050231574
+ 0.1105781457  0.9724906059  0.2050231574
+ 0.1408680694 -0.1725020531 -0.9748842130
+ 0.5200137365  0.7449983827 -0.4178075198
+-0.5028924303 -0.5120562839 -0.6963458664
+ 0.7031188992 -0.1439661345 -0.6963458664
+-0.8920089226 -0.1725020531 -0.4178075198
+ 0.2952822046  0.9032324765  0.3114153386
+ 0.6244295734 -0.3538221901 -0.6963458664
+-0.3713844621 -0.8746965578  0.3114153386
+-0.5586755893  0.7164624640 -0.4178075198
+-0.0422370933  0.7164624640 -0.6963458664
+-0.0980202522 -0.9032324765 -0.4178075198
+ 0.0980202522  0.9032324765  0.4178075198
+-0.9248859147 -0.3538221901  0.1392691733
+ 0.4642305776 -0.8746965578 -0.1392691733
+-0.2952822046 -0.9032324765 -0.3114153386
+ 0.8920089226  0.1725020531  0.4178075198
+ 0.9248859147  0.3538221901 -0.1392691733
+ 0.5586755893 -0.7164624640  0.4178075198
+ 0.3713844621  0.8746965578 -0.3114153386
+-0.4642305776  0.8746965578  0.1392691733
+-0.5200137365 -0.7449983827  0.4178075198
+-0.1408680694  0.1725020531  0.9748842130
+-0.6244295734  0.3538221901  0.6963458664
+ 0.0422370933 -0.7164624640  0.6963458664
+ 0.6347778468 -0.7449983827 -0.2050231574
+ 0.5560885209  0.8054384283 -0.2050231574
+ 0.5028924303  0.5120562839  0.6963458664
+-0.1105781457 -0.9724906059 -0.2050231574
+ 0.9681111801  0.1439661345 -0.2050231574
+-0.7031188992  0.1439661345  0.6963458664
+-0.2195573953 -0.0373540025  0.9748842130
+-0.4767884711  0.8054384283  0.3520535357
+ 0.3056304780  0.5120562839  0.8027380476
+ 0.9352341880 -0.0373540025  0.3520535357
+-0.1131652141  0.5494102864 -0.8278538347
+-0.4464985474 -0.3395542307 -0.8278538347
+ 0.7292228585 -0.5867642889  0.3520535357
+-0.1063921812 -0.5867642889  0.8027380476
+-0.8888111303 -0.2933821444  0.3520535357
+-0.6296037101  0.5494102864 -0.5493154881
+ 0.7824189491 -0.2933821444 -0.5493154881
+-0.8356150397 -0.0000000000 -0.5493154881
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1693842601  0.9341723590  0.3140556896
+-0.4865864368 -0.8152316624  0.3140556896
+ 0.1693842601 -0.0635136937  0.3140556896
+ 0.5297191236 -0.8152316624 -0.2340832902
+-0.3387685201  0.1270273873  0.0213524160
+ 0.9351313099  0.2659594829 -0.2340832902
+ 0.2039331950  0.1270273873 -0.2713508575
+-0.7092856298  0.2659594829  0.6528242098
+-0.0164752203  0.6227815726 -0.7822222701
+-0.4218874066 -0.4584095726 -0.7822222701
+ 0.0701362950 -0.2297947024 -0.2713508575
+-0.6445865996  0.6227815726 -0.4434537500
+-0.2652718107 -0.2297947024 -0.0904502858
+-0.1211604502  0.0454313035  0.9915927299
+-0.0487838789  0.3475555668 -0.0904502858
+-0.8951451102 -0.0454313035 -0.4434537500
+ 0.8951451102  0.0454313035  0.4434537500
+ 0.1211604502 -0.0454313035 -0.9915927299
+ 0.2652718107  0.2297947024  0.0904502858
+ 0.6445865996 -0.6227815726  0.4434537500
+ 0.0487838789 -0.3475555668  0.0904502858
+-0.0701362950  0.2297947024  0.2713508575
+ 0.0164752203 -0.6227815726  0.7822222701
+ 0.7092856298 -0.2659594829 -0.6528242098
+ 0.4218874066  0.4584095726  0.7822222701
+-0.2039331950 -0.1270273873  0.2713508575
+-0.9351313099 -0.2659594829  0.2340832902
+ 0.3387685201 -0.1270273873 -0.0213524160
+-0.5297191236  0.8152316624  0.2340832902
+ 0.4865864368  0.8152316624 -0.3140556896
+-0.1693842601  0.0635136937 -0.3140556896
+-0.1693842601 -0.9341723590 -0.3140556896
+6 0 2 7 11 4 1 
+6 0 3 9 14 6 2 
+5 0 1 5 8 3 2
+6 1 4 10 19 12 5 
+5 2 6 13 15 7 2
+6 3 8 16 26 17 9 
+5 4 11 20 18 10 2
+6 5 12 21 25 16 8 
+6 6 14 23 33 22 13 
+6 7 15 24 30 20 11 
+5 9 17 27 23 14 2
+6 10 18 28 39 29 19 
+5 12 19 29 31 21 2
+6 13 22 32 34 24 15 
+5 16 25 35 36 26 2
+6 17 26 36 46 37 27 
+6 18 20 30 40 38 28 
+6 21 31 41 45 35 25 
+5 22 33 43 42 32 2
+6 23 27 37 47 43 33 
+5 24 34 44 40 30 2
+5 28 38 48 49 39 2
+6 29 39 49 50 41 31 
+6 32 42 51 52 44 34 
+6 35 45 53 54 46 36 
+5 37 46 54 55 47 2
+6 38 40 44 52 56 48 
+5 41 50 57 53 45 2
+6 42 43 47 55 58 51 
+6 48 56 59 57 50 49 
+5 51 58 59 56 52 2
+6 53 57 59 58 55 54 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 0 9 4 
+3 5 7 2 
+3 1 10 5 
+3 3 11 6 
+3 6 9 0 
+3 7 12 3 
+3 4 13 8 
+3 8 10 1 
+3 9 13 4 
+3 5 14 7 
+3 10 15 5 
+3 11 16 6 
+3 12 11 3 
+3 16 9 6 
+3 7 17 12 
+3 13 18 8 
+3 8 19 10 
+3 9 20 13 
+3 14 17 7 
+3 15 14 5 
+3 19 15 10 
+3 11 21 16 
+3 12 22 11 
+3 16 20 9 
+3 17 22 12 
+3 13 23 18 
+3 18 19 8 
+3 20 23 13 
+3 14 24 17 
+3 15 24 14 
+3 19 25 15 
+3 21 26 16 
+3 22 21 11 
+3 26 20 16 
+3 17 27 22 
+3 23 28 18 
+3 28 19 18 
+3 26 23 20 
+3 24 27 17 
+3 25 24 15 
+3 28 25 19 
+3 21 29 26 
+3 22 29 21 
+3 27 29 22 
+3 23 30 28 
+3 26 30 23 
+3 24 31 27 
+3 25 31 24 
+3 28 31 25 
+3 29 30 26 
+3 31 29 27 
+3 30 31 28 
+3 29 30 31 
+rhombicosahedron
+rhombicosacron
+2 5/2 3|
+(6.4.6/5.4/3)
+icosahedral group
+A5
+10{6}+15{4}+15{4/3}+10{6/5}
+60 60 120 50 60 0 0 1 -10 4 4 120 5 0 1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.6998542122  0.0000000000  0.7142857143
+-0.5248906592  0.4629100499  0.7142857143
+-0.3689536881 -0.5947008445  0.7142857143
+-0.1166423687  0.6900655593  0.7142857143
+ 0.8748177653  0.4629100499  0.1428571429
+ 0.7634342145 -0.5947008445  0.2519902889
+ 0.5832118435  0.6900655593  0.4285714286
+-0.8938443472 -0.1317907946  0.4285714286
+ 0.2077578990  0.4039714148  0.8908668539
+-0.3499271061  0.9258200998  0.1428571429
+-0.8545497448 -0.4993361296  0.1428571429
+ 0.1028746047 -0.9622461795  0.2519902889
+-0.4528017108  0.0364260797  0.8908668539
+-0.6022384255  0.7854302742  0.1428571429
+ 0.9383977675 -0.1317907946 -0.3194382825
+ 0.4750784209  0.4039714148  0.7817337079
+ 0.3499271061  0.9258200998 -0.1428571429
+ 0.7103718480 -0.4993361296 -0.4960194221
+ 0.9469067137  0.0364260797  0.3194382825
+ 0.5301494771  0.7854302742 -0.3194382825
+-0.5301494771 -0.7854302742  0.3194382825
+-0.9469067137 -0.0364260797 -0.3194382825
+ 0.3827214521  0.8668814647  0.3194382825
+ 0.5714527692 -0.2496680648  0.7817337079
+-0.6107473716  0.6172133998 -0.4960194221
+-0.3827214521 -0.8668814647 -0.3194382825
+-0.5937294793 -0.1907294297  0.7817337079
+-0.9711921135  0.1907294297 -0.1428571429
+ 0.0498122382 -0.8668814647 -0.4960194221
+-0.9383977675  0.1317907946  0.3194382825
+-0.0891068406 -0.6172133998  0.7817337079
+-0.2024990811  0.8443689093 -0.4960194221
+ 0.6022384255 -0.7854302742 -0.1428571429
+ 0.4528017108 -0.0364260797 -0.8908668539
+-0.0498122382  0.8668814647  0.4960194221
+ 0.1389190789 -0.2496680648  0.9583148475
+ 0.0891068406  0.6172133998 -0.7817337079
+ 0.9711921135 -0.1907294297  0.1428571429
+ 0.5937294793  0.1907294297 -0.7817337079
+ 0.8938443472  0.1317907946 -0.4285714286
+ 0.6107473716 -0.6172133998  0.4960194221
+-0.5832118435 -0.6900655593 -0.4285714286
+ 0.2024990811 -0.8443689093  0.4960194221
+-0.4750784209 -0.4039714148 -0.7817337079
+-0.1028746047  0.9622461795 -0.2519902889
+ 0.8545497448  0.4993361296 -0.1428571429
+-0.1389190789  0.2496680648 -0.9583148475
+ 0.3499271061 -0.9258200998 -0.1428571429
+-0.2077578990 -0.4039714148 -0.8908668539
+-0.7103718480  0.4993361296  0.4960194221
+-0.5714527692  0.2496680648 -0.7817337079
+-0.3499271061 -0.9258200998  0.1428571429
+-0.7634342145  0.5947008445 -0.2519902889
+-0.8748177653 -0.4629100499 -0.1428571429
+ 0.1166423687 -0.6900655593 -0.7142857143
+ 0.3689536881  0.5947008445 -0.7142857143
+ 0.5248906592 -0.4629100499 -0.7142857143
+-0.6998542122  0.0000000000 -0.7142857143
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.2672612419  0.7071067812  0.6546536707
+-0.4096109381 -0.0603941292  0.6546536707
+-0.7417602291  0.1456720081  0.6546536707
+ 0.2672612419  0.3162277660  0.6546536707
+ 0.9879908641  0.1456720081 -0.0515142560
+ 0.7507413705 -0.0603941292  0.1809418244
+-0.0651501153  0.6093870274  0.4737118463
+-0.2462306350 -0.2913440163  0.9243858169
+-0.6446401714 -0.7627485371 -0.0515142560
+-0.3444608228 -0.6697811566  0.1809418244
+-0.4834801286  0.3766218952  0.4737118463
+ 0.3773789295  0.0556417559  0.9243858169
+ 0.8228143327 -0.2913440163  0.4879500365
+ 0.3780650276  0.6093870274  0.2927700219
+ 0.3726763428 -0.6697811566 -0.1118281975
+ 0.4244047962 -0.7627485371 -0.4879500365
+ 0.6768721800  0.3766218952 -0.0000000000
+-0.6768721800 -0.3766218952 -0.0000000000
+-0.4244047962  0.7627485371  0.4879500365
+ 0.0543727456 -0.0977197538  0.7664818682
+-0.1195228609  0.7071067812 -0.2927700219
+ 0.1862071383  0.8527787893 -0.4879500365
+-0.1862071383 -0.8527787893  0.4879500365
+-0.7171371656  0.0000000000  0.2927700219
+-0.5378528742  0.4743416490 -0.2927700219
+-0.8228143327  0.2913440163 -0.4879500365
+ 0.4834801286 -0.3766218952 -0.4737118463
+ 0.4975878886 -0.0977197538  0.5855400438
+ 0.6446401714  0.7627485371  0.0515142560
+-0.4744989872  0.8527787893 -0.2182178902
+ 0.7171371656  0.0000000000 -0.2927700219
+ 0.4744989872 -0.8527787893  0.2182178902
+ 0.2462306350  0.2913440163 -0.9243858169
+ 0.1792842914  0.4743416490 -0.5855400438
+-0.1792842914 -0.4743416490  0.5855400438
+-0.9879908641 -0.1456720081  0.0515142560
+-0.3773789295 -0.0556417559 -0.9243858169
+-0.4975878886  0.0977197538 -0.5855400438
+ 0.3444608228  0.6697811566 -0.1809418244
+ 0.5378528742 -0.4743416490  0.2927700219
+ 0.0651501153 -0.6093870274 -0.4737118463
+-0.3780650276 -0.6093870274 -0.2927700219
+-0.7507413705  0.0603941292 -0.1809418244
+ 0.1195228609 -0.7071067812  0.2927700219
+ 0.7417602291 -0.1456720081 -0.6546536707
+-0.0543727456  0.0977197538 -0.7664818682
+-0.3726763428  0.6697811566  0.1118281975
+ 0.4096109381  0.0603941292 -0.6546536707
+-0.2672612419 -0.3162277660 -0.6546536707
+-0.2672612419 -0.7071067812 -0.6546536707
+6 0 2 10 17 5 1 
+4 0 3 8 2 
+6 0 4 14 28 11 3 5
+4 0 1 7 4 3
+6 1 6 18 39 20 7 5
+4 1 5 15 6 
+4 2 9 23 10 3
+6 2 8 21 43 24 9 5
+6 3 12 29 44 22 8 
+4 3 11 26 12 3
+4 4 13 30 14 
+6 4 7 19 41 31 13 
+6 5 16 36 43 33 15 5
+4 5 17 35 16 3
+4 6 12 29 18 3
+6 6 15 34 49 26 12 
+4 7 20 40 19 
+4 8 22 42 21 3
+6 9 13 30 53 45 23 
+4 9 24 31 13 
+4 10 25 37 17 
+6 10 23 46 39 47 25 5
+6 11 27 36 41 48 26 
+4 11 28 50 27 
+4 14 32 51 28 3
+6 14 30 54 44 47 32 
+4 15 33 55 34 3
+4 16 19 41 36 
+6 16 35 45 56 40 19 
+6 17 37 51 28 50 35 5
+4 18 38 46 39 
+6 18 29 52 31 24 38 
+6 20 32 51 49 57 40 
+4 20 39 47 32 3
+4 21 27 36 43 
+6 21 42 58 53 50 27 
+6 22 25 37 34 55 42 5
+4 22 44 47 25 
+4 23 45 56 46 
+4 24 43 33 38 3
+4 26 48 57 49 
+4 29 52 54 44 3
+4 30 53 58 54 3
+4 31 41 48 52 
+6 33 38 46 56 59 55 
+4 34 37 51 49 
+4 35 50 53 45 
+4 40 57 59 56 3
+4 42 55 59 58 
+6 48 52 54 58 59 57 5
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 11 3 
+4 5 12 13 0 
+4 4 14 15 5 
+4 11 16 4 3 
+4 7 17 8 1 
+4 6 18 19 7 
+4 0 20 21 6 
+4 9 22 23 2 
+4 8 14 15 9 
+4 10 18 19 11 
+4 2 24 25 10 
+4 15 26 12 5 
+4 12 27 28 13 
+4 13 29 20 0 
+4 4 30 31 14 
+4 11 27 28 16 
+4 16 32 33 4 
+4 7 34 35 17 
+4 17 36 37 8 
+4 21 38 18 6 
+4 19 31 39 7 
+4 20 36 37 21 
+4 15 40 22 9 
+4 22 34 35 23 
+4 23 29 24 2 
+4 8 41 31 14 
+4 25 42 18 10 
+4 31 43 11 19 
+4 24 32 33 25 
+4 26 44 39 12 
+4 15 45 36 26 
+4 28 46 29 13 
+4 12 34 22 27 
+4 29 45 36 20 
+4 30 44 39 31 
+4 33 21 30 4 
+4 28 47 32 16 
+4 43 22 27 11 
+4 35 48 36 17 
+4 7 34 12 39 
+4 37 25 41 8 
+4 38 28 46 18 
+4 44 38 21 30 
+4 37 21 33 25 
+4 40 49 43 22 
+4 45 32 40 15 
+4 35 46 29 23 
+4 29 24 32 45 
+4 41 49 43 31 
+4 42 35 46 18 
+4 49 42 25 41 
+4 48 44 26 36 
+4 44 47 28 38 
+4 47 49 40 32 
+4 49 48 35 42 
+4 48 44 47 49 
+great snub icosidodecahedron
+great pentagonal hexecontahedron
+|2 5/2 3
+(3.3.5/2.3.3)
+icosahedral group
+A5
+80{3}+12{5/2}
+61 60 150 92 60 7 0 0 2 2 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9684429470  0.0000000000  0.2492353475
+ 0.1932143650  0.9489731033  0.2492353475
+-0.8913464263  0.3786598604  0.2492353475
+-0.8913464263 -0.3786598604  0.2492353475
+ 0.1932143650 -0.9489731033  0.2492353475
+ 0.4635252507 -0.3786598604 -0.8010999015
+ 0.3781705098  0.7978800013 -0.4694406981
+ 0.8572881225  0.2113823691 -0.4694406981
+-0.2785691059  0.5297529623 -0.8010999015
+-0.6600348160 -0.5864976322 -0.4694406981
+-0.3404640391 -0.6126845243  0.7132334203
+-0.3404640391  0.6126845243  0.7132334203
+-0.6600348160  0.5864976322 -0.4694406981
+-0.2785691059 -0.5297529623 -0.8010999015
+-0.4456304207 -0.8822259307 -0.1519570181
+-0.6325889612  0.1672774913 -0.7562072778
+-0.5650434654  0.7637776262  0.3120410548
+ 0.5580227938  0.4558561435  0.6934015705
+ 0.6356904263 -0.7060651967  0.3120410548
+ 0.0377064707 -0.6532448048 -0.7562072778
+ 0.2734652451  0.0366360026 -0.9611839382
+ 0.4921267272 -0.8571582987 -0.1519570181
+ 0.7205513597  0.0000000000  0.6934015705
+ 0.4921267272  0.8571582987 -0.1519570181
+ 0.5168240834  0.4013021552 -0.7562072778
+ 0.7551034710 -0.6377521562 -0.1519570181
+ 0.0981457100 -0.4820430356  0.8706330636
+-0.8937570446  0.0933806725  0.4387235978
+-0.9355024568 -0.2752766852 -0.2214901802
+-0.3809719027 -0.3112209470  0.8706330636
+-0.5885888579 -0.7537751235  0.2922092050
+-0.8555038721  0.1446351965 -0.4971858654
+ 0.0022546911  0.9751599953 -0.2214901802
+ 0.9655218191  0.2590922959  0.0252744751
+ 0.8243476323 -0.2706606665 -0.4971858654
+-0.1952509108  0.2340246639 -0.9524229830
+-0.2352120726  0.9716153981  0.0252744751
+ 0.7860944598  0.4354045303  0.4387235978
+ 0.1281650723  0.7271416236  0.6744173585
+-0.4036327131  0.8094483719 -0.4264668406
+ 0.0235453925 -0.1967638477 -0.9801681502
+ 0.0397430165 -0.9978022901 -0.0530196423
+ 0.3756743067 -0.2817345907  0.8828898208
+-0.6139292842  0.4101853978  0.6744173585
+ 0.1126975629  0.4558561435  0.8828898208
+ 0.4279771028 -0.6898808074  0.5838664839
+-0.2411041472 -0.8717768201 -0.4264668406
+-0.9984623093  0.0161843893 -0.0530196423
+-0.2970106376  0.1601278451  0.9413520884
+ 0.7675414736 -0.3119126878  0.5599915727
+ 0.7838397687  0.5197504596 -0.3397862220
+ 0.9607558386 -0.2013798664 -0.1907730799
+ 0.4935202029  0.8050296475  0.3291885112
+-0.6821867327  0.7311328287 -0.0081270187
+-0.7497814649 -0.3524729683  0.5599915727
+-0.2817083791 -0.9012631765  0.3291885112
+ 0.4908680726 -0.6442100617 -0.5865508773
+ 0.2046118584  0.5226033161 -0.8276592061
+-0.6840824376 -0.3047630416 -0.6626844702
+ 0.5478898766  0.4475784305  0.7067462286
+-0.3292705043  0.6261714648  0.7067462286
+-0.5952793113 -0.0000000000  0.7067462286
+-0.3292705043 -0.6261714648  0.7067462286
+ 0.5478898766 -0.4475784305  0.7067462286
+ 0.7665092489 -0.6261714648 -0.1427335557
+ 0.8537428920  0.1977230883 -0.4816935277
+ 0.7140436788  0.5833116520  0.0611296277
+ 0.3640785289  0.7971312126 -0.4816935277
+-0.4606562335  0.8760268070 -0.1427335557
+-0.8630869536  0.1518296938 -0.4816935277
+-0.8922793901 -0.3869952480  0.2325342297
+-0.8922793901  0.3869952480  0.2325342297
+-0.8630869536 -0.1518296938 -0.4816935277
+-0.4606562335 -0.8760268070 -0.1427335557
+ 0.1661538022 -0.8160650441 -0.4003479086
+-0.2899174208 -0.5157948995 -0.8061659326
+ 0.0986241788  0.2766186827 -0.9559055266
+-0.3864951254  0.8154436245 -0.4308981471
+ 0.1750509698  0.9515503064  0.2528026353
+ 0.9673445525 -0.0183124119  0.2528026353
+ 0.7219399541 -0.5414143418 -0.4308981471
+ 0.2907340063  0.0414531285 -0.9559055266
+-0.3583185855 -0.1277530350 -0.8421013261
+ 0.0497855062 -0.6636139307 -0.7464167431
+-0.2397711783 -0.9698627183  0.0433138518
+ 0.4113754049 -0.6932440356  0.5917626073
+ 0.0186881231 -0.0000000000  0.9998253618
+ 0.4113754049  0.6932440356  0.5917626073
+-0.2397711783  0.9698627183  0.0433138518
+-0.0197040197  0.7371093263 -0.5568925235
+-0.1989303569  0.2160355002 -0.9559055266
+ 0.4685125572 -0.3613758057 -0.8061659326
+ 0.1922513550 -0.9442432760  0.2672902024
+-0.5854254823 -0.5994081243  0.5458817685
+-0.9300728450 -0.2931593368 -0.2214093636
+-0.8289101298  0.3766028993 -0.1578795205
+-0.8874084967  0.0836132249  0.4533376099
+-0.1829947623  0.4284483765  0.8848417405
+ 0.3833253882 -0.2647956591  0.8848417405
+ 0.0197040197 -0.7371093263  0.5568925235
+ 0.0399992886 -0.9966260588 -0.0716697696
+-0.6633150639 -0.5953974618 -0.4533376099
+-0.2734522013  0.5454250043 -0.7922975819
+ 0.5854254823  0.5994081243 -0.5458817685
+ 0.8164711846 -0.2647956591 -0.5130867994
+ 0.8289101298 -0.3766028993  0.1578795205
+ 0.9607530194  0.2766186827  0.0208743890
+ 0.5288194467  0.3869952480 -0.7553705520
+ 0.5035784309  0.8528860904 -0.1378190139
+ 0.9706558172  0.0938359113 -0.2214093636
+ 0.7731882508 -0.3227894416  0.5458817685
+ 0.3583185855  0.1277530350  0.8421013261
+-0.3147977002  0.1596420548  0.9356371210
+-0.5514589905  0.7687675350  0.3238664214
+-0.6204913561  0.1591367242 -0.7678971155
+-0.4113754049 -0.6932440356 -0.5917626073
+-0.6021639693 -0.7472271556  0.2811585531
+-0.3899767705 -0.2949310946  0.8723151769
+-0.9706558172 -0.0938359113  0.2214093636
+-0.6919874045  0.7216077133 -0.0208743890
+-0.1661538022  0.8160650441  0.4003479086
+ 0.5096002070  0.7971312126  0.3238664214
+ 0.7103900588  0.0118230236  0.7037088748
+ 0.4769371461 -0.8642037834 -0.1602584767
+ 0.1829947623 -0.4284483765 -0.8848417405
+-0.6767244541 -0.2931593368 -0.6753529569
+-0.6739454866  0.5762674078 -0.4622914188
+-0.7219399541  0.5414143418  0.4308981471
+ 0.1197373444  0.7391374301  0.6628263934
+ 0.7921496414  0.4409783680  0.4219443382
+ 0.2397711783  0.9698627183 -0.0433138518
+ 0.1904278281  0.5341073114 -0.8236908535
+ 0.5952793113 -0.0000000000 -0.7067462286
+ 0.4829853613 -0.6583909696 -0.5772750401
+ 0.6490652071 -0.6984669967  0.3014269586
+ 0.8630869536  0.1518296938  0.4816935277
+ 0.1203945702  0.4402714001  0.8897562822
+-0.6222274141  0.3935953105  0.6766947441
+-0.0986241788 -0.2766186827  0.9559055266
+-0.2654929905 -0.9027901475  0.3383539886
+-0.7140436788 -0.5833116520 -0.0611296277
+-0.7438697051 -0.3419194956  0.5742376863
+ 0.0890571699 -0.4966648455  0.8633613680
+ 0.4606562335 -0.8760268070  0.1427335557
+ 0.9632167023 -0.2058128138 -0.1727850402
+ 0.7824062032  0.5311916554 -0.3250783883
+ 0.0075205347  0.9710066165 -0.2389342846
+-0.5478898766  0.4475784305 -0.7067462286
+-0.9980247269  0.0348530660 -0.0522676607
+-0.2239949432 -0.8726547120 -0.4339355010
+ 0.0053755709 -0.2010951833 -0.9795569562
+3 0 2 1 
+3 0 3 2 
+5 0 4 12 11 3 2
+3 0 5 4 
+3 0 1 5 
+3 1 6 5 
+3 1 7 6 
+5 1 2 8 18 7 2
+3 2 9 8 
+3 2 3 9 
+3 3 10 9 
+3 3 11 10 
+3 4 13 12 
+3 4 14 13 
+3 4 5 14 
+5 5 6 15 26 14 2
+3 6 16 15 
+3 6 7 16 
+3 7 17 16 
+3 7 18 17 
+3 8 19 18 
+3 8 20 19 
+3 8 9 20 
+5 9 10 21 32 20 2
+3 10 22 21 
+3 10 11 22 
+3 11 23 22 
+3 11 12 23 
+3 12 24 23 
+3 12 13 24 
+5 13 25 37 36 24 2
+3 13 14 25 
+3 14 26 25 
+3 15 27 26 
+3 15 28 27 
+3 15 16 28 
+5 16 17 29 40 28 2
+3 17 30 29 
+3 17 18 30 
+3 18 19 30 
+5 19 31 43 42 30 2
+3 19 20 31 
+3 20 32 31 
+3 21 33 32 
+3 21 34 33 
+3 21 22 34 
+5 22 23 35 46 34 2
+3 23 24 35 
+3 24 36 35 
+3 25 38 37 
+3 25 26 38 
+3 26 27 38 
+5 27 39 50 49 38 2
+3 27 28 39 
+3 28 40 39 
+3 29 41 40 
+3 29 42 41 
+3 29 30 42 
+3 31 44 43 
+3 31 32 44 
+3 32 33 44 
+5 33 45 54 53 44 2
+3 33 34 45 
+3 34 46 45 
+3 35 47 46 
+3 35 36 47 
+3 36 48 47 
+3 36 37 48 
+3 37 49 48 
+3 37 38 49 
+3 39 51 50 
+3 39 40 51 
+3 40 41 51 
+5 41 52 58 57 51 2
+3 41 42 52 
+3 42 43 52 
+3 43 53 52 
+3 43 44 53 
+3 45 55 54 
+3 45 46 55 
+3 46 47 55 
+5 47 48 56 59 55 2
+3 48 49 56 
+3 49 50 56 
+3 50 57 56 
+3 50 51 57 
+3 52 53 58 
+3 53 54 58 
+3 54 59 58 
+3 54 55 59 
+3 56 57 59 
+3 57 58 59 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 2 12 13 14 3 
+5 14 15 5 4 3 
+5 15 16 17 6 5 
+5 17 18 19 7 6 
+5 7 20 21 22 8 
+5 22 23 10 9 8 
+5 23 24 25 11 10 
+5 25 26 27 2 11 
+5 27 28 29 12 2 
+5 29 30 31 13 12 
+5 31 32 15 14 13 
+5 15 33 34 35 16 
+5 35 36 18 17 16 
+5 36 37 38 19 18 
+5 38 39 20 7 19 
+5 39 40 41 21 20 
+5 41 42 23 22 21 
+5 23 43 44 45 24 
+5 45 46 26 25 24 
+5 46 47 28 27 26 
+5 47 48 30 29 28 
+5 30 49 50 32 31 
+5 50 51 33 15 32 
+5 51 52 53 34 33 
+5 53 54 36 35 34 
+5 36 55 56 57 37 
+5 57 40 39 38 37 
+5 40 58 59 42 41 
+5 59 60 43 23 42 
+5 60 61 62 44 43 
+5 62 63 46 45 44 
+5 46 64 65 48 47 
+5 65 66 67 30 48 
+5 67 68 69 49 30 
+5 69 52 51 50 49 
+5 52 70 71 54 53 
+5 71 72 55 36 54 
+5 72 73 74 56 55 
+5 74 75 40 57 56 
+5 75 76 77 58 40 
+5 77 61 60 59 58 
+5 61 78 79 63 62 
+5 79 80 64 46 63 
+5 80 81 66 65 64 
+5 81 82 68 67 66 
+5 82 83 52 69 68 
+5 83 84 85 70 52 
+5 85 73 72 71 70 
+5 73 86 76 75 74 
+5 86 87 61 77 76 
+5 87 88 89 78 61 
+5 89 81 80 79 78 
+5 81 90 84 83 82 
+5 90 91 73 85 84 
+5 91 88 87 86 73 
+5 88 89 81 90 91 
+small stellated truncated dodecahedron
+great pentakisdodekahedron
+2 5|5/3
+(10/3.10/3.5)
+icosahedral group
+A5
+12{5}+12{10/3}
+62 60 90 24 60 9 0 0 -6 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9498602905  0.0000000000  0.3126746369
+-0.0501397095  0.9485360199  0.3126746369
+-0.9445669005 -0.1001396121  0.3126746369
+ 0.3126746369  0.9485360199  0.0501397095
+ 0.5923393341 -0.1001396121 -0.7994411620
+-0.9637185654  0.2621689080  0.0501397095
+ 0.9307086256  0.3623085200  0.0501397095
+-0.5784810592 -0.1620292959 -0.7994411620
+-0.4109321609  0.9102860917  0.0501397095
+ 0.3489560715  0.2621689080 -0.8997205810
+-0.2433832625  0.3623085200  0.8997205810
+ 0.1761137832  0.9102860917 -0.3746507262
+-0.5474930145 -0.7482567958 -0.3746507262
+-0.3489560715 -0.2621689080  0.8997205810
+ 0.3746507262 -0.2239189798  0.8997205810
+ 0.6233273787 -0.6863671119 -0.3746507262
+-0.2710998123  0.8866463360 -0.3746507262
+ 0.2038303330  0.3859482757  0.8997205810
+-0.3746507262  0.2239189798 -0.8997205810
+-0.1846786681 -0.7482567958 -0.6371856536
+ 0.9637185654 -0.2621689080 -0.0501397095
+ 0.7374650726 -0.2239189798  0.6371856536
+-0.5507645094 -0.6863671119  0.4749301452
+ 0.7908762771  0.3859482757  0.4749301452
+-0.7374650726  0.2239189798 -0.6371856536
+-0.1899720581 -0.6481171837  0.7374650726
+ 0.1846786681  0.7482567958  0.6371856536
+-0.3126746369 -0.9485360199 -0.0501397095
+ 0.4109321609 -0.9102860917 -0.0501397095
+-0.2625349274  0.7246170401  0.6371856536
+ 0.2572415374 -0.6244774280  0.7374650726
+ 0.7097485229  0.3004188362 -0.6371856536
+-0.8271577117  0.3004188362  0.4749301452
+ 0.6200558838 -0.6244774280  0.4749301452
+-0.7097485229 -0.3004188362  0.6371856536
+-0.9307086256 -0.3623085200 -0.0501397095
+ 0.2625349274 -0.7246170401 -0.6371856536
+ 0.7598882324 -0.6481171837  0.0501397095
+ 0.5474930145  0.7482567958  0.3746507262
+ 0.0501397095 -0.9485360199 -0.3126746369
+-0.1761137832 -0.9102860917  0.3746507262
+ 0.6873253631  0.7246170401 -0.0501397095
+ 0.8271577117 -0.3004188362 -0.4749301452
+ 0.2433832625 -0.3623085200 -0.8997205810
+-0.6873253631 -0.7246170401  0.0501397095
+ 0.5507645094  0.6863671119 -0.4749301452
+-0.7598882324  0.6481171837 -0.0501397095
+-0.9498602905  0.0000000000 -0.3126746369
+-0.2038303330 -0.3859482757 -0.8997205810
+ 0.9445669005  0.1001396121 -0.3126746369
+-0.6200558838  0.6244774280 -0.4749301452
+-0.7908762771 -0.3859482757 -0.4749301452
+ 0.2710998123 -0.8866463360  0.3746507262
+-0.6233273787  0.6863671119  0.3746507262
+ 0.1899720581  0.6481171837 -0.7374650726
+ 0.0000000000  0.0000000000 -1.0000000000
+-0.5923393341  0.1001396121  0.7994411620
+-0.2572415374  0.6244774280 -0.7374650726
+ 0.5784810592  0.1620292959  0.7994411620
+ 0.0526465096  0.0555029103  0.0727556869
+-0.0582045495  0.0496433121  0.0727556869
+ 0.0526465096 -0.9959593140  0.0727556869
+ 0.0873068243  0.0496433121 -0.0325373323
+-0.0201091773  0.3804226065 -0.9245941063
+-0.0920539571  0.0401622832 -0.0325373323
+-0.8719475967  0.3804226065 -0.3081980354
+-0.0021229823  0.0401622832 -0.0976119970
+-0.0873068243 -0.0496433121  0.0325373323
+ 0.0920539571 -0.0401622832  0.0325373323
+ 0.8269821093  0.4702282018 -0.3081980354
+ 0.0582045495 -0.0496433121 -0.0727556869
+ 0.0021229823 -0.0401622832  0.0976119970
+-0.5513214062  0.4702282018  0.6891517578
+ 0.0055580399 -0.1051462224  0.0076810222
+ 0.8719475967 -0.3804226065  0.3081980354
+-0.8269821093 -0.4702282018  0.3081980354
+ 0.4986748966  0.5257311121  0.6891517578
+-0.0526465096 -0.0555029103 -0.0727556869
+ 0.0201091773 -0.3804226065  0.9245941063
+ 0.5513214062 -0.4702282018 -0.6891517578
+-0.0055580399  0.1051462224 -0.0076810222
+-0.4986748966 -0.5257311121 -0.6891517578
+-0.0526465096  0.9959593140 -0.0727556869
+10 0 2 7 15 30 42 22 11 4 1 3
+10 0 3 9 18 35 47 27 14 6 2 3
+5 0 1 5 8 3 
+10 1 4 10 21 39 55 43 24 12 5 3
+5 2 6 13 16 7 
+10 3 8 17 33 52 58 54 36 19 9 3
+5 4 11 23 20 10 
+10 5 12 25 44 46 51 49 32 17 8 3
+10 6 14 28 48 57 41 52 33 26 13 3
+10 7 16 31 24 43 53 59 50 29 15 3
+5 9 19 37 34 18 
+10 10 20 38 32 49 29 50 56 40 21 3
+10 11 22 41 57 59 53 35 18 34 23 3
+5 12 24 31 45 25 
+10 13 26 38 20 23 34 37 45 31 16 3
+5 14 27 46 44 28 
+5 15 29 49 51 30 
+5 17 32 38 26 33 
+10 19 36 40 56 48 28 44 25 45 37 3
+5 21 40 36 54 39 
+5 22 42 58 52 41 
+10 27 47 55 39 54 58 42 30 51 46 3
+5 35 53 43 55 47 
+5 48 56 50 59 57 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 8 1 
+3 0 9 4 
+3 5 7 2 
+3 1 10 5 
+3 3 11 6 
+3 6 12 0 
+3 7 13 3 
+3 4 14 8 
+3 8 15 1 
+3 0 16 9 
+3 9 14 4 
+3 5 17 7 
+3 1 12 10 
+3 10 18 5 
+3 11 14 6 
+3 3 19 11 
+3 12 20 0 
+3 14 12 6 
+3 13 9 3 
+3 7 18 13 
+3 14 17 8 
+3 15 21 1 
+3 8 18 15 
+3 16 11 9 
+3 0 21 16 
+3 13 14 9 
+3 17 11 7 
+3 5 8 17 
+3 14 10 12 
+3 1 22 12 
+3 18 19 5 
+3 14 18 10 
+3 11 14 17 
+3 3 21 19 
+3 18 11 19 
+3 12 8 20 
+3 20 21 0 
+3 9 22 3 
+3 7 15 18 
+3 18 13 14 
+3 7 21 15 
+3 21 22 1 
+3 8 23 18 
+3 16 7 11 
+3 11 23 9 
+3 21 16 7 
+3 5 20 8 
+3 9 12 22 
+3 21 5 19 
+3 3 21 22 
+3 18 11 23 
+3 12 23 8 
+3 20 21 5 
+3 23 9 12 
+truncated dodecadodecahedron
+medial disdyakistriacontahedron
+5/3 2 5|
+(10/3.4.10)
+icosahedral group
+A5
+12{10}+30{4}+12{10/3}
+63 120 180 54 120 3 0 0 -6 3 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5749595746  0.0000000000  0.8181818182
+ 0.1379435501  0.5581667218  0.8181818182
+-0.5691632311  0.0814354272  0.8181818182
+ 0.3575585655  0.5581667218  0.7487334525
+ 0.9361004773  0.0814354272  0.3421756384
+-0.4312196809  0.6396021491  0.6363636364
+ 0.6276493222  0.2132007164  0.7487334525
+-0.9151291095  0.2132007164  0.3421756384
+ 0.7186994682  0.6396021491  0.2727272727
+-0.0830397963  0.2132007164  0.9734730848
+ 0.9454791582  0.2132007164 -0.2462003575
+-0.8624393619  0.4264014327  0.2727272727
+ 0.1870509604 -0.1317652891  0.9734730848
+ 0.8508466748 -0.2635305783  0.4545454545
+-0.5633668875  0.6899320110  0.4545454545
+-0.9057504287  0.3449660055 -0.2462003575
+ 0.8624393619  0.4264014327 -0.2727272727
+ 0.4066659758 -0.1317652891  0.9040247191
+-0.4348020182 -0.2635305783  0.8611032686
+ 0.7222818055  0.6899320110  0.0479876405
+ 0.5995132797  0.3449660055 -0.7222065373
+-0.7338744926  0.0000000000  0.6792850868
+-0.9910042312  0.0000000000 -0.1338305414
+ 0.4102483131 -0.6084965838  0.6792850868
+-0.0303500487  0.4264014327  0.9040247191
+ 0.7222818055 -0.6899320110  0.0479876405
+-0.5539882067  0.8216973001 -0.1338305414
+-0.4348020182  0.2635305783  0.8611032686
+-0.5446095259  0.4264014327 -0.7222065373
+ 0.9910042312  0.0000000000  0.1338305414
+ 0.7338744926  0.0000000000 -0.6792850868
+ 0.0549037538 -0.6084965838  0.7916549030
+ 0.5446095259  0.4264014327  0.7222065373
+-0.5633668875 -0.6899320110  0.4545454545
+ 0.3763159271  0.8216973001 -0.4280185393
+ 0.8508466748  0.2635305783  0.4545454545
+ 0.0303500487  0.4264014327 -0.9040247191
+-0.8624393619 -0.4264014327  0.2727272727
+-0.3821122706  0.4767312946  0.7916549030
+-0.7678068785 -0.4767312946 -0.4280185393
+ 0.5539882067 -0.8216973001  0.1338305414
+-0.1589149180  0.8528028654  0.4974669050
+ 0.3611409028 -0.7713674382  0.5239938202
+ 0.2910621246 -0.9031327273 -0.3156487232
+-0.4102483131  0.6084965838 -0.6792850868
+-0.8660216992  0.0503298619  0.4974669050
+-0.2174010091 -0.2946361436  0.9305516343
+-0.4160446566  0.8528028654 -0.3156487232
+ 0.8624393619 -0.4264014327 -0.2727272727
+ 0.7678068785  0.4767312946  0.4280185393
+ 0.3821122706 -0.4767312946 -0.7916549030
+-0.3763159271 -0.8216973001  0.4280185393
+ 0.4160446566  0.8528028654  0.3156487232
+ 0.0057963435 -0.7713674382  0.6363636364
+-0.4196269939 -0.9031327273 -0.0909090909
+-0.0549037538  0.6084965838 -0.7916549030
+ 0.9945865685  0.0503298619 -0.0909090909
+ 0.7129031247 -0.2946361436  0.6363636364
+ 0.1589149180  0.8528028654 -0.4974669050
+-0.7186994682 -0.6396021491 -0.2727272727
+-0.7280781490  0.6084965838  0.3156487232
+ 0.0584860911  0.8216973001  0.5669152707
+-0.7771855594 -0.6084965838  0.1603574566
+-0.2781011065 -0.8216973001 -0.4974669050
+ 0.9057504287 -0.3449660055  0.2462003575
+ 0.5633668875 -0.6899320110 -0.4545454545
+-0.1495362372  0.9845681546 -0.0909090909
+-0.0700787782 -0.9845681546  0.1603574566
+-0.8508466748  0.2635305783 -0.4545454545
+-0.1870509604  0.1317652891 -0.9734730848
+-0.6486206900 -0.5078368599  0.5669152707
+-0.8566430183  0.5078368599 -0.0909090909
+ 0.4312196809 -0.6396021491 -0.6363636364
+ 0.7771855594  0.6084965838 -0.1603574566
+ 0.2781011065  0.8216973001  0.4974669050
+ 0.7280781490 -0.6084965838 -0.3156487232
+-0.0584860911 -0.8216973001 -0.5669152707
+-0.5995132797 -0.3449660055  0.7222065373
+-0.7222818055 -0.6899320110 -0.0479876405
+ 0.0700787782  0.9845681546 -0.1603574566
+ 0.1495362372 -0.9845681546  0.0909090909
+ 0.4348020182  0.2635305783 -0.8611032686
+-0.4066659758  0.1317652891 -0.9040247191
+ 0.8566430183 -0.5078368599  0.0909090909
+ 0.6486206900  0.5078368599 -0.5669152707
+-0.9361004773 -0.0814354272 -0.3421756384
+-0.3575585655 -0.5581667218 -0.7487334525
+-0.2874797873  0.9534625892  0.0909090909
+ 0.4196269939  0.9031327273  0.0909090909
+-0.2874797873 -0.9534625892  0.0909090909
+-0.9945865685 -0.0503298619  0.0909090909
+ 0.9151291095 -0.2132007164 -0.3421756384
+ 0.5446095259 -0.4264014327  0.7222065373
+ 0.4348020182 -0.2635305783 -0.8611032686
+-0.0057963435  0.7713674382 -0.6363636364
+-0.4160446566 -0.8528028654 -0.3156487232
+-0.6276493222 -0.2132007164 -0.7487334525
+-0.7222818055  0.6899320110 -0.0479876405
+ 0.0303500487 -0.4264014327 -0.9040247191
+-0.1589149180 -0.8528028654  0.4974669050
+-0.7129031247  0.2946361436 -0.6363636364
+ 0.5691632311 -0.0814354272 -0.8181818182
+-0.1379435501 -0.5581667218 -0.8181818182
+ 0.2874797873  0.9534625892 -0.0909090909
+-0.2910621246  0.9031327273  0.3156487232
+ 0.2874797873 -0.9534625892 -0.0909090909
+ 0.8660216992 -0.0503298619 -0.4974669050
+-0.9454791582 -0.2132007164  0.2462003575
+-0.0303500487 -0.4264014327  0.9040247191
+-0.8508466748 -0.2635305783 -0.4545454545
+-0.3611409028  0.7713674382 -0.5239938202
+ 0.1589149180 -0.8528028654 -0.4974669050
+ 0.0830397963 -0.2132007164 -0.9734730848
+ 0.5633668875  0.6899320110 -0.4545454545
+-0.5446095259 -0.4264014327 -0.7222065373
+ 0.4160446566 -0.8528028654  0.3156487232
+ 0.2174010091  0.2946361436 -0.9305516343
+-0.5749595746  0.0000000000 -0.8181818182
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.0692731120  0.0542373073  0.2190608145
+-0.0577275933  0.0856238581  0.2190608145
+ 0.0692731120  0.9732489895  0.2190608145
+ 0.1731827800  0.0856238581  0.1460405430
+-0.3199055857 -0.6015009550  0.7320225525
+-0.1650061983  0.0877578066  0.1442207056
+ 0.6826243091 -0.6015009550  0.4149947635
+ 0.2179261468  0.0877578066  0.0231268655
+ 0.1389438731 -0.0529184545  0.1911695527
+-0.1966714664  0.1385423126  0.0278912618
+-0.0037665860 -0.0529184545  0.2362985623
+ 0.1769493660  0.1385423126 -0.0902580193
+-0.2309103733 -0.0000000000  0.0730202715
+ 0.9231499720  0.3717480345  0.0979669745
+ 0.1611457400 -0.1419951139  0.0979669745
+-0.9231499720 -0.3717480345 -0.0979669745
+-0.1611457400  0.1419951139 -0.0979669745
+ 0.2309103733 -0.0000000000 -0.0730202715
+-0.6989774726  0.3717480345  0.6109287125
+-0.0755194646 -0.1419951139  0.1728070835
+ 0.6989774726 -0.3717480345 -0.6109287125
+ 0.0755194646  0.1419951139 -0.1728070835
+-0.6826243091  0.6015009550 -0.4149947635
+-0.2179261468 -0.0877578066 -0.0231268655
+ 0.0516331291  0.1712477161  0.1632782908
+ 0.0873107439 -0.2241661707  0.0278912618
+-0.1450383372 -0.0327054035  0.1911695527
+-0.0516331291  0.1712477161 -0.1632782908
+ 0.3199055857  0.6015009550 -0.7320225525
+ 0.1650061983 -0.0877578066 -0.1442207056
+-0.0553997152 -0.2241661707  0.0730202715
+ 0.2285824951 -0.0327054035  0.0730202715
+-0.0896386221  0.1914607671  0.1181492812
+-0.1412717512 -0.1914607671 -0.0451290097
+ 0.1966714664 -0.1385423126 -0.0278912618
+ 0.0163531634  0.2297529205  0.0517132434
+-0.0163531634 -0.2297529205 -0.0517132434
+-0.1389438731  0.0529184545 -0.1911695527
+ 0.2934456114  0.2297529205  0.9279565015
+-0.2934456114 -0.2297529205 -0.9279565015
+ 0.1412717512  0.1914607671  0.0451290097
+ 0.0896386221 -0.1914607671 -0.1181492812
+-0.1769493660 -0.1385423126  0.0902580193
+ 0.0037665860  0.0529184545 -0.2362985623
+-0.1731827800 -0.0856238581 -0.1460405430
+-0.0692731120 -0.9732489895 -0.2190608145
+ 0.0553997152  0.2241661707 -0.0730202715
+-0.0692731120 -0.0542373073 -0.2190608145
+-0.2285824951  0.0327054035 -0.0730202715
+ 0.0577275933 -0.0856238581 -0.2190608145
+-0.0873107439  0.2241661707 -0.0278912618
+ 0.1450383372  0.0327054035 -0.1911695527
+ 0.0516331291 -0.1712477161  0.1632782908
+-0.0516331291 -0.1712477161 -0.1632782908
+10 0 2 7 13 25 33 18 10 4 1 3
+4 0 3 6 2 
+10 0 1 5 11 21 37 29 16 8 3 
+4 1 4 9 5 
+10 2 6 12 23 40 64 44 26 14 7 
+10 3 8 15 28 46 61 39 22 12 6 3
+10 4 10 19 34 55 77 51 31 17 9 
+10 5 9 17 30 50 74 57 36 20 11 3
+4 7 14 24 13 
+4 8 16 27 15 
+4 10 18 32 19 
+4 11 20 35 21 
+4 12 22 38 23 
+10 13 24 41 66 94 117 95 67 42 25 
+10 14 26 43 58 84 116 93 65 41 24 3
+10 15 27 45 70 99 112 81 54 47 28 
+10 16 29 48 72 101 111 98 69 45 27 3
+4 17 31 49 30 
+10 18 33 53 80 111 101 110 79 52 32 
+10 19 32 52 78 109 100 71 47 54 34 3
+10 20 36 58 43 68 96 115 83 56 35 
+10 21 35 56 82 114 95 117 85 59 37 3
+10 22 39 62 89 114 82 113 87 60 38 
+10 23 38 60 86 108 79 110 91 63 40 3
+4 25 42 53 33 
+4 26 44 68 43 
+4 28 47 71 46 
+4 29 37 59 48 
+10 30 49 73 103 97 69 98 105 75 50 
+10 31 51 76 107 94 66 92 102 73 49 3
+4 34 54 81 55 
+4 36 57 84 58 
+4 39 61 88 62 
+4 40 63 90 64 
+4 41 65 92 66 
+10 42 67 89 62 88 104 75 105 80 53 3
+10 44 64 90 106 77 55 81 112 96 68 3
+4 45 69 97 70 
+10 46 71 100 116 84 57 74 104 88 61 
+10 48 59 85 107 76 106 90 63 91 72 
+4 50 75 104 74 
+4 51 77 106 76 
+4 52 79 108 78 
+4 56 83 113 82 
+4 60 87 118 86 
+10 65 93 109 78 108 86 118 119 102 92 
+4 67 95 114 89 
+10 70 97 103 119 118 87 113 83 115 99 3
+4 72 91 110 101 
+4 73 102 119 103 
+4 80 105 98 111 
+4 85 117 94 107 
+4 93 116 100 109 
+4 96 112 99 115 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 5 1 
+3 0 8 4 
+3 5 9 2 
+3 7 6 3 
+3 6 10 0 
+3 2 11 7 
+3 4 12 5 
+3 0 13 8 
+3 8 14 4 
+3 5 15 9 
+3 9 16 2 
+3 7 17 6 
+3 10 18 0 
+3 6 19 10 
+3 11 20 7 
+3 2 21 11 
+3 12 22 5 
+3 4 23 12 
+3 13 14 8 
+3 0 24 13 
+3 14 25 4 
+3 15 16 9 
+3 5 26 15 
+3 16 27 2 
+3 7 28 17 
+3 17 29 6 
+3 19 18 10 
+3 18 24 0 
+3 6 30 19 
+3 21 20 11 
+3 20 31 7 
+3 27 21 2 
+3 23 22 12 
+3 22 32 5 
+3 4 33 23 
+3 13 34 14 
+3 24 35 13 
+3 14 20 25 
+3 25 36 4 
+3 15 37 16 
+3 5 38 26 
+3 26 19 15 
+3 16 39 27 
+3 28 29 17 
+3 7 40 28 
+3 29 41 6 
+3 19 42 18 
+3 18 35 24 
+3 30 15 19 
+3 6 36 30 
+3 21 43 20 
+3 31 38 7 
+3 14 31 20 
+3 39 21 27 
+3 23 44 22 
+3 32 38 5 
+3 22 35 32 
+3 33 39 23 
+3 36 33 4 
+3 34 45 14 
+3 13 29 34 
+3 35 46 13 
+3 20 36 25 
+3 37 28 16 
+3 15 47 37 
+3 38 19 26 
+3 16 48 39 
+3 28 49 29 
+3 38 40 7 
+3 40 35 28 
+3 29 39 41 
+3 41 36 6 
+3 19 45 42 
+3 42 23 18 
+3 18 50 35 
+3 36 15 30 
+3 21 22 43 
+3 43 47 20 
+3 14 38 31 
+3 39 51 21 
+3 23 45 44 
+3 44 47 22 
+3 35 38 32 
+3 22 46 35 
+3 36 39 33 
+3 48 23 39 
+3 29 45 34 
+3 45 52 14 
+3 13 51 29 
+3 46 21 13 
+3 20 53 36 
+3 47 28 37 
+3 28 50 16 
+3 15 53 47 
+3 38 52 19 
+3 16 18 48 
+3 49 45 29 
+3 47 49 28 
+3 38 40 35 
+3 35 28 50 
+3 39 41 36 
+3 29 39 51 
+3 45 42 23 
+3 19 45 52 
+3 23 18 48 
+3 18 50 16 
+3 36 15 53 
+3 22 43 47 
+3 21 22 46 
+3 47 20 53 
+3 14 38 52 
+3 51 21 13 
+3 45 47 44 
+3 49 45 47 
+inverted snub dodecadodecahedron
+medial inverted pentagonal hexecontahedron
+|5/3 2 5
+(3.5/3.3.3.5)
+icosahedral group
+A5
+12{5}+60{3}+12{5/3}
+64 60 150 84 60 9 0 0 -6 3 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9505389400  0.0000000000  0.3106054144
+ 0.2252718768  0.9234591805  0.3106054144
+ 0.8112598353  0.4953602287  0.3106054144
+-0.2889844000  0.9055453015  0.3106054144
+-0.9482348826 -0.0661429059  0.3106054144
+ 0.5897694300 -0.0661429059 -0.8048584567
+ 0.3850026607  0.9055453015 -0.1782152018
+ 0.5573198493  0.4377082809 -0.7055537162
+-0.4709954327  0.1594257169  0.8676097874
+ 0.6720341587 -0.0753689321  0.7366747000
+-0.2761142752  0.6173097225  0.7366747000
+ 0.2950721213 -0.4002320578  0.8676097874
+ 0.8005020002 -0.5722201408 -0.1782152018
+-0.9797305684  0.0914732487 -0.1782152018
+-0.4850646484 -0.1093871277  0.8676097874
+-0.0776254431  0.4911492110  0.8676097874
+-0.4470814740  0.8765600364 -0.1782152018
+-0.5837373293 -0.1070214698 -0.8048584567
+-0.0305345625  0.8765600364 -0.4803229570
+-0.4885089715  0.3978663999 -0.7765702239
+ 0.6822034907  0.1918133228  0.7055537162
+ 0.9068404918 -0.1219494938 -0.4034459610
+ 0.6280254238  0.6350267068  0.4498056789
+ 0.9074753675 -0.4197944019  0.0161591306
+ 0.0662694728 -0.6265357487 -0.7765702239
+-0.5692643226 -0.7985238317  0.1956982912
+ 0.4568451653 -0.5417438957  0.7055537162
+-0.1299819960 -0.8836172995  0.4498056789
+ 0.5895721585  0.8070147898 -0.0336422200
+-0.5234589817  0.7504812130 -0.4034459610
+ 0.4007400217 -0.8959359724 -0.1915885392
+ 0.9945763348  0.0855188418  0.0591983266
+-0.0076279270 -0.7569762005  0.6533979236
+-0.3063909428 -0.8218360221 -0.4803229570
+-0.4897789665 -0.5772241483  0.6533979236
+-0.4053104966 -0.9140362596  0.0161591306
+ 0.1584253171  0.8200264597  0.5499618390
+-0.8270506245  0.5611198317 -0.0336422200
+-0.7034190217 -0.4502706470  0.5499618390
+-0.1409472501  0.0818639196 -0.9866266626
+-0.9653847065 -0.1769920905 -0.1915885392
+-0.8809267432  0.4308947110  0.1956982912
+ 0.8861844855  0.1438774958 -0.4404274331
+-0.1051400207 -0.1847560597 -0.9771441933
+ 0.6358781390  0.5897865144 -0.4978060464
+ 0.2874702454 -0.4819231848 -0.8277142635
+-0.7311680197 -0.6296283954 -0.2626050469
+ 0.3681846210 -0.8724307068  0.3214105579
+ 0.1681444855  0.7640334636 -0.6228806455
+-0.5294657581  0.7850867877  0.3214105579
+-0.0773062511 -0.9216496181 -0.3802442964
+ 0.3662906510  0.0161043166 -0.9303611180
+ 0.6023558347 -0.7546105427  0.2602506049
+ 0.4177101363 -0.7946961169 -0.4404274331
+ 0.2460872708  0.1028921402  0.9637708559
+-0.8447900947  0.0442149038  0.5332679797
+-0.7081172394 -0.5007585401 -0.4978060464
+-0.2634083151  0.5441095536 -0.7965932797
+-0.7705003202 -0.0094229209 -0.6373699594
+ 0.0347733835  0.0273103460  0.0479456261
+ 0.0221937153  0.0303790744  0.0479456261
+ 0.0154457535  0.0414303258  0.0479456261
+-0.0365894750  0.0248244539  0.0479456261
+ 0.0347733835 -0.9982444734  0.0479456261
+ 0.0569390737  0.0248244539 -0.0198875498
+ 0.0531075573  0.0287610955 -0.0081620442
+ 0.0512555391  0.0402551137 -0.0024943533
+-0.7983984023  0.3985080838 -0.4513881903
+ 0.0126076932  0.0297962381  0.0566308796
+ 0.0245528255  0.0210696106  0.0566308796
+ 0.0563926334 -0.0141094994  0.0295739612
+ 0.1529062285  0.4101421715 -0.8991123870
+-0.0518662103  0.0262507772  0.0295739612
+-0.0407008533  0.0276138549  0.0359881617
+-0.0435607236  0.0384924725  0.0295739612
+-0.0585284569  0.0208021960 -0.0198875498
+-0.0007246349  0.0208021960 -0.0618107580
+ 0.0093187938  0.0249959101 -0.0547959559
+ 0.0143807266  0.0365909393 -0.0520396399
+-0.6678347106  0.4530983827  0.5905071167
+ 0.0583803788  0.0288467118  0.0036639936
+ 0.0618929964  0.0193100395 -0.0070855930
+ 0.0452796477 -0.0179993596 -0.0433543864
+-0.0172538804 -0.0349221758  0.0523122501
+-0.0093187938 -0.0249959101  0.0547959559
+ 0.0021014290 -0.0236461716  0.0607475829
+ 0.6678347106 -0.4530983827 -0.5905071167
+ 0.0291449034  0.0398939600  0.0425778443
+-0.0062105643  0.0643176201  0.0088599601
+-0.8714085158 -0.4719227321  0.1339258511
+ 0.0499914832 -0.0358036921  0.0217433552
+ 0.0486579924 -0.0242868764  0.0275096281
+ 0.0436238866 -0.0336369212  0.0349190536
+ 0.0143872332 -0.0636145476 -0.0001520171
+-0.0525204118 -0.0386705249 -0.0001520171
+-0.0531075573 -0.0287610955  0.0081620442
+-0.0553064338 -0.0275614572  0.0208660182
+ 0.7983984023 -0.3985080838  0.4513881903
+-0.0341191820  0.0376109561  0.0409282746
+-0.0475577418  0.0178034772  0.0409282746
+-0.0095878575 -0.0148125719  0.0627892265
+ 0.8714085158  0.4719227321 -0.1339258511
+-0.0459405885  0.0231100357 -0.0401150201
+-0.0486579924  0.0242868764 -0.0275096281
+-0.0442189464  0.0355015672 -0.0322203316
+ 0.3641627194  0.4984711306  0.7867096324
+ 0.0221955507  0.0247144114 -0.0561282608
+ 0.0128599239  0.0149564314 -0.0621671439
+-0.0275690461 -0.0211064978 -0.0552113186
+ 0.0578830028 -0.0237350817  0.0184399064
+-0.3641627194 -0.4984711306 -0.7867096324
+ 0.0503647635  0.0377692216 -0.0170500075
+ 0.0078874982  0.0645938774  0.0043868710
+-0.1529062285 -0.4101421715  0.8991123870
+ 0.0353840547 -0.0391955450 -0.0382819042
+ 0.0407008533 -0.0276138549 -0.0359881617
+ 0.0459818845 -0.0365909393 -0.0282948002
+ 0.0029384979 -0.0644614796 -0.0094820427
+ 0.0021192465 -0.0608375115  0.0029220223
+ 0.0090286636 -0.0631393379  0.0136284081
+-0.0215500966 -0.0217815257  0.0575759041
+-0.0497697037 -0.0396338675  0.0143512855
+-0.0060124429  0.0631762251 -0.0150479691
+-0.0021192465  0.0608375115 -0.0029220223
+ 0.0080099440  0.0638884564 -0.0103890418
+ 0.0002152729  0.0341730572 -0.0555516163
+ 0.0349500485 -0.0277053167 -0.0475892403
+ 0.0520976973 -0.0234909763 -0.0314297666
+-0.0347733835  0.9982444734 -0.0479456261
+ 0.0475800150 -0.0202291728  0.0397586343
+-0.0094957793 -0.0645097026 -0.0014678904
+-0.0057318499 -0.0636925741  0.0128151536
+-0.0614790292 -0.0191369547  0.0103890418
+-0.0597571729 -0.0260027361 -0.0026008184
+-0.0262717496 -0.0415627235 -0.0428504544
+-0.0148012004  0.0634414628 -0.0031514317
+-0.0026364338 -0.0360745903  0.0542724553
+-0.0134385598 -0.0397018775 -0.0499699139
+-0.0221937153 -0.0303790744 -0.0479456261
+-0.0350048704 -0.0300701469 -0.0460898207
+-0.0519986769  0.0340752438 -0.0197190674
+-0.0547843524  0.0140253247 -0.0324929418
+-0.0142403331 -0.0270592347 -0.0576093481
+3 0 2 1 
+5 0 3 11 10 2 3
+3 0 4 3 
+3 0 5 4 
+5 0 1 6 18 5 
+3 1 7 6 
+5 1 8 23 22 7 3
+3 1 2 8 
+5 2 9 26 25 8 
+3 2 10 9 
+3 3 12 11 
+3 3 13 12 
+5 3 4 14 34 13 
+3 4 15 14 
+5 4 5 16 38 15 3
+3 5 17 16 
+3 5 18 17 
+3 6 19 18 
+5 6 20 45 44 19 3
+3 6 7 20 
+5 7 21 33 47 20 
+3 7 22 21 
+3 8 24 23 
+3 8 25 24 
+3 9 27 26 
+5 9 28 55 39 27 3
+3 9 10 28 
+5 10 29 58 57 28 
+3 10 11 29 
+3 11 30 29 
+5 11 12 31 44 30 
+3 12 32 31 
+5 12 13 21 48 32 3
+3 13 33 21 
+3 13 34 33 
+3 14 35 34 
+5 14 36 56 57 35 3
+3 14 15 36 
+5 15 37 45 46 36 
+3 15 38 37 
+3 16 39 38 
+3 16 27 39 
+5 16 17 40 54 27 
+3 17 41 40 
+5 17 18 42 58 41 3
+3 18 19 42 
+5 19 43 53 35 42 
+3 19 44 43 
+3 20 46 45 
+3 20 47 46 
+3 21 22 48 
+5 22 49 38 39 48 
+3 22 23 49 
+3 23 50 49 
+5 23 24 51 41 50 
+3 24 52 51 
+5 24 25 43 31 52 3
+3 25 53 43 
+3 25 26 53 
+5 26 54 33 34 53 3
+3 26 27 54 
+3 28 56 55 
+3 28 57 56 
+3 29 50 58 
+5 29 30 37 49 50 3
+3 30 45 37 
+3 30 44 45 
+3 31 43 44 
+3 31 32 52 
+5 32 55 56 59 52 
+3 32 48 55 
+3 33 54 47 
+3 34 35 53 
+3 35 57 42 
+3 36 59 56 
+3 36 46 59 
+3 37 38 49 
+3 39 55 48 
+3 40 47 54 
+5 40 51 59 46 47 3
+3 40 41 51 
+3 41 58 50 
+3 42 57 58 
+3 51 52 59 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 1 10 11 12 2 
+5 12 13 14 3 2 
+5 14 15 16 4 3 
+5 4 17 18 19 5 
+5 19 20 21 6 5 
+5 6 22 23 8 7 
+5 8 24 25 26 9 
+5 26 27 28 1 9 
+5 28 29 30 10 1 
+5 30 31 32 11 10 
+5 32 33 34 12 11 
+5 12 35 36 37 13 
+5 37 38 39 14 13 
+5 14 40 41 42 15 
+5 42 43 44 16 15 
+5 44 45 17 4 16 
+5 45 46 47 18 17 
+5 18 48 49 20 19 
+5 20 33 32 50 21 
+5 50 51 52 6 21 
+5 52 53 54 22 6 
+5 54 55 56 23 22 
+5 56 57 58 8 23 
+5 58 59 60 24 8 
+5 60 42 41 25 24 
+5 25 61 62 27 26 
+5 27 63 64 29 28 
+5 64 65 66 30 29 
+5 30 67 56 68 31 
+5 68 69 70 32 31 
+5 20 71 59 34 33 
+5 59 72 35 12 34 
+5 72 46 73 36 35 
+5 36 74 75 38 37 
+5 38 65 64 76 39 
+5 76 51 40 14 39 
+5 51 77 25 41 40 
+5 42 78 79 80 43 
+5 80 54 81 44 43 
+5 44 82 73 46 45 
+5 46 57 56 67 47 
+5 66 18 47 67 30 
+5 38 48 18 66 65 
+5 75 79 49 48 38 
+5 78 71 20 49 79 
+5 70 77 51 50 32 
+5 64 53 52 51 76 
+5 63 81 54 53 64 
+5 79 83 55 54 80 
+5 83 69 68 56 55 
+5 57 58 59 72 46 
+5 59 60 42 78 71 
+5 69 61 25 77 70 
+5 69 74 36 62 61 
+5 82 27 62 36 73 
+5 27 63 81 44 82 
+5 74 75 79 83 69 
+great dodecicosidodecahedron
+great dodecacronic hexecontahedron
+5/2 3|5/3
+(10/3.5/2.10/3.3)
+icosahedral group
+A5
+12{10/3}+20{3}+12{5/2}
+65 60 120 44 60 10 0 0 -16 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9996324920  0.0000000000  0.0271086873
+-0.3453645319  0.9380770007  0.0271086873
+-0.9468654869  0.3204853643  0.0271086873
+ 0.0263835025 -0.9992842588  0.0271086873
+ 0.0364611038  0.9380770007 -0.3445027268
+ 0.0527670051  0.3204853643 -0.9457826254
+-0.7334184677 -0.2592781062  0.6283885859
+-0.3189810294 -0.0612072581 -0.9457826254
+ 0.8677149793  0.3583135302 -0.3445027268
+-0.3352869307 -0.8768697425 -0.3445027268
+ 0.2398305218  0.7400061526  0.6283885859
+-0.9367878857 -0.0612072581 -0.3445027268
+ 0.6480396600 -0.2592781062 -0.7161141409
+-0.3678987333  0.3583135302  0.8580570704
+ 0.6216561575  0.7400061526  0.2567771718
+-0.4672044434 -0.5185562123 -0.7161141409
+ 0.4796610435 -0.8390415766  0.2567771718
+-0.7233408665 -0.6409707286  0.2567771718
+ 0.4633551422 -0.2214499403  0.8580570704
+ 0.8514090780 -0.4573489542  0.2567771718
+ 0.2336022217 -0.4573489542  0.8580570704
+ 0.5060445461  0.4807280465 -0.7161141409
+ 0.2762916255 -0.6409707286 -0.7161141409
+-0.7031856640 -0.5185562123 -0.4864456563
+ 0.2436798229 -0.8390415766  0.4864456563
+ 0.8451807779 -0.2214499403  0.4864456563
+-0.7295691665  0.4807280465  0.4864456563
+-0.2436798229  0.8390415766 -0.4864456563
+ 0.7031856640  0.5185562123  0.4864456563
+-0.4998162460  0.7166270604  0.4864456563
+ 0.7295691665 -0.4807280465 -0.4864456563
+-0.4998162460 -0.7166270604  0.4864456563
+ 0.4998162460 -0.7166270604 -0.4864456563
+-0.8451807779  0.2214499403 -0.4864456563
+ 0.4998162460  0.7166270604 -0.4864456563
+-0.4796610435  0.8390415766 -0.2567771718
+ 0.4672044434  0.5185562123  0.7161141409
+-0.5060445461 -0.4807280465  0.7161141409
+-0.4633551422  0.2214499403 -0.8580570704
+-0.6480396600  0.2592781062  0.7161141409
+ 0.3678987333 -0.3583135302 -0.8580570704
+-0.2336022217  0.4573489542 -0.8580570704
+-0.6216561575 -0.7400061526 -0.2567771718
+-0.2762916255  0.6409707286  0.7161141409
+ 0.7233408665  0.6409707286 -0.2567771718
+-0.8514090780  0.4573489542 -0.2567771718
+ 0.7334184677  0.2592781062 -0.6283885859
+-0.8677149793 -0.3583135302  0.3445027268
+-0.2398305218 -0.7400061526 -0.6283885859
+-0.0364611038 -0.9380770007  0.3445027268
+ 0.9367878857  0.0612072581  0.3445027268
+ 0.3352869307  0.8768697425  0.3445027268
+-0.0527670051 -0.3204853643  0.9457826254
+ 0.3189810294  0.0612072581  0.9457826254
+ 0.3453645319 -0.9380770007 -0.0271086873
+ 0.9468654869 -0.3204853643 -0.0271086873
+-0.9996324920  0.0000000000 -0.0271086873
+-0.0263835025  0.9992842588 -0.0271086873
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.4931762648  0.7071067812  0.5067318540
+-0.3915763668  0.3813742685  0.5067318540
+-0.6938439517 -0.5116672736  0.5067318540
+ 0.4931762648 -0.4803270912  0.5067318540
+ 0.5253548247 -0.5116672736 -0.6798521231
+ 0.5171607473  0.3813742685 -0.3776956239
+ 0.0977538074  0.5937169362 -0.6071725516
+-0.9541739697  0.1954395076 -0.2266173744
+-0.2205551306  0.9486832981 -0.2266173744
+-0.5909300722 -0.1133898450 -0.6071725516
+-0.3675918843 -0.5270462767 -0.3776956239
+-0.2006676869  0.1954395076 -0.9599666027
+-0.6095993882  0.5937169362  0.0812582313
+-0.3465455537 -0.7771855594  0.0812582313
+ 0.2006676869 -0.1954395076  0.9599666027
+ 0.7111992862 -0.1456720081  0.1689106180
+ 0.1643920883 -0.7071067812  0.1689106180
+ 0.7677683711  0.3669372463  0.0812582313
+ 0.9541739697 -0.1954395076  0.2266173744
+ 0.0906227633 -0.7771855594 -0.3442153914
+ 0.1495688629 -0.1456720081  0.7155168599
+ 0.0604151755  0.3669372463  0.7696890141
+-0.1495688629  0.1456720081 -0.7155168599
+ 0.2205551306 -0.9486832981  0.2266173744
+-0.3652148696 -0.0700787782  0.7696890141
+ 0.7793066430 -0.0700787782 -0.3442153914
+-0.7111992862  0.1456720081 -0.1689106180
+-0.0906227633  0.7771855594  0.3442153914
+ 0.6938439517  0.5116672736 -0.5067318540
+-0.1643920883  0.7071067812 -0.1689106180
+-0.0604151755 -0.3669372463 -0.7696890141
+-0.7793066430  0.0700787782  0.3442153914
+-0.4931762648 -0.7071067812 -0.5067318540
+ 0.3652148696  0.0700787782 -0.7696890141
+-0.5253548247  0.5116672736  0.6798521231
+ 0.3465455537  0.7771855594 -0.0812582313
+-0.7677683711 -0.3669372463 -0.0812582313
+-0.5171607473 -0.3813742685  0.3776956239
+ 0.6095993882 -0.5937169362 -0.0812582313
+ 0.3675918843  0.5270462767  0.3776956239
+ 0.3915763668 -0.3813742685 -0.5067318540
+-0.0977538074 -0.5937169362  0.6071725516
+ 0.5909300722  0.1133898450  0.6071725516
+-0.4931762648  0.4803270912 -0.5067318540
+10 0 2 9 19 30 35 26 14 5 1 3
+5 0 3 11 7 2 2
+10 0 4 12 14 25 24 27 21 10 3 3
+3 0 1 4 
+10 1 6 10 20 22 16 17 9 8 4 3
+5 1 5 13 15 6 2
+3 2 8 9 
+10 2 7 16 28 40 43 42 30 18 8 3
+10 3 6 15 27 39 45 44 34 22 11 3
+3 3 10 6 
+5 4 8 18 23 12 2
+10 5 12 23 35 46 49 47 36 24 13 3
+3 5 14 12 
+3 7 17 16 
+10 7 11 20 32 44 51 50 40 29 17 3
+5 9 17 29 31 19 2
+5 10 21 33 32 20 2
+3 11 22 20 
+10 13 25 37 47 55 54 45 33 21 15 3
+3 13 24 25 
+5 14 26 38 37 25 2
+3 15 21 27 
+5 16 22 34 41 28 2
+10 18 19 31 43 53 56 49 38 26 23 3
+3 18 30 19 
+3 23 26 35 
+5 24 36 48 39 27 2
+3 28 29 40 
+10 28 41 51 58 59 56 52 42 31 29 3
+5 30 42 52 46 35 2
+3 31 42 43 
+3 32 34 44 
+10 32 33 39 48 55 59 57 50 41 34 3
+3 33 45 39 
+10 36 37 38 46 52 53 57 58 54 48 3
+3 36 47 37 
+3 38 49 46 
+5 40 50 57 53 43 2
+3 41 50 51 
+5 44 45 54 58 51 2
+5 47 49 56 59 55 2
+3 48 54 55 
+3 52 56 53 
+3 57 59 58 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 4 3 
+4 5 11 12 0 
+4 4 9 8 5 
+4 7 13 14 1 
+4 6 4 10 7 
+4 0 15 4 6 
+4 4 16 2 9 
+4 14 17 8 1 
+4 2 12 11 10 
+4 5 18 19 11 
+4 2 20 0 12 
+4 8 21 18 5 
+4 7 22 4 13 
+4 15 14 13 4 
+4 10 23 24 7 
+4 0 24 23 15 
+4 4 17 14 16 
+4 16 18 21 2 
+4 22 8 17 4 
+4 11 25 23 10 
+4 19 2 26 11 
+4 18 20 2 19 
+4 20 23 25 0 
+4 8 26 2 21 
+4 7 27 28 22 
+4 15 28 27 14 
+4 0 29 7 24 
+4 23 30 28 15 
+4 14 31 32 16 
+4 32 33 18 16 
+4 22 32 31 8 
+4 11 29 0 25 
+4 26 34 35 11 
+4 18 35 34 20 
+4 34 36 23 20 
+4 8 33 32 26 
+4 7 37 14 27 
+4 28 38 32 22 
+4 29 28 30 7 
+4 23 37 7 30 
+4 14 39 8 31 
+4 39 18 33 8 
+4 11 36 34 29 
+4 18 40 11 35 
+4 32 41 34 26 
+4 40 23 36 11 
+4 37 32 38 14 
+4 28 39 14 38 
+4 34 42 28 29 
+4 23 42 34 37 
+4 39 34 41 18 
+4 32 40 18 41 
+4 40 28 42 23 
+4 34 43 32 37 
+4 28 43 34 39 
+4 32 40 28 43 
+small dodecahemicosahedron
+small dodecahemicosacron
+5/3 5/2|3
+(6.5/3.6.5/2)
+icosahedral group
+A5
+10{6}+6{5/2}+6{5/3}
+66 30 60 22 30 0 1 1 -8 3 4 120 5 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8660254038  0.0000000000  0.5000000000
+-0.8660254038  0.0000000000  0.5000000000
+-0.6454972244  0.5773502692  0.5000000000
+ 0.6454972244 -0.5773502692  0.5000000000
+ 0.8660254038  0.0000000000 -0.5000000000
+ 0.7557613141  0.5773502692 -0.3090169944
+ 0.1102640897 -0.5773502692  0.8090169944
+-0.1102640897  0.5773502692  0.8090169944
+-0.7557613141 -0.5773502692 -0.3090169944
+-0.8660254038  0.0000000000 -0.5000000000
+-0.6454972244  0.5773502692 -0.5000000000
+-0.1784110449  0.9341723590 -0.3090169944
+-0.4670861795 -0.3568220898  0.8090169944
+ 0.4670861795  0.3568220898  0.8090169944
+ 0.1784110449 -0.9341723590 -0.3090169944
+ 0.6454972244 -0.5773502692 -0.5000000000
+ 0.7557613141  0.5773502692  0.3090169944
+ 0.1102640897 -0.5773502692 -0.8090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.1102640897  0.5773502692 -0.8090169944
+ 0.9341723590 -0.3568220898  0.0000000000
+-0.3568220898 -0.9341723590  0.0000000000
+-0.7557613141 -0.5773502692  0.3090169944
+ 0.3568220898  0.9341723590  0.0000000000
+-0.9341723590  0.3568220898  0.0000000000
+-0.1784110449  0.9341723590  0.3090169944
+-0.4670861795 -0.3568220898 -0.8090169944
+ 0.4670861795  0.3568220898 -0.8090169944
+ 0.1784110449 -0.9341723590  0.3090169944
+ 0.0000000000  1.0000000000  0.0000000000
+-0.4911234732  0.1875924741  0.8506508084
+-0.6666666667 -0.7453559925  0.0000000000
+ 0.4911234732 -0.1875924741  0.8506508084
+ 0.3333333333 -0.7453559925 -0.5773502692
+ 0.9822469464  0.1875924741  0.0000000000
+-0.9822469464 -0.1875924741  0.0000000000
+ 0.3333333333 -0.7453559925  0.5773502692
+ 0.7453559925  0.3333333333  0.5773502692
+-0.6070619982  0.7946544723  0.0000000000
+ 0.6070619982 -0.7946544723  0.0000000000
+ 0.7453559925  0.3333333333 -0.5773502692
+ 0.4911234732 -0.1875924741 -0.8506508084
+ 0.3035309991  0.7946544723 -0.5257311121
+ 0.1273220038  0.3333333333  0.9341723590
+-0.8726779962  0.3333333333  0.3568220898
+-0.3035309991 -0.7946544723  0.5257311121
+ 0.3035309991  0.7946544723  0.5257311121
+-0.8726779962  0.3333333333 -0.3568220898
+ 0.1273220038  0.3333333333 -0.9341723590
+-0.3035309991 -0.7946544723 -0.5257311121
+-0.4911234732  0.1875924741 -0.8506508084
+6 0 1 5 19 10 2 
+5 0 2 8 13 3 3
+6 0 3 11 19 16 4 
+5 0 1 7 14 4 2
+6 1 7 23 10 20 6 
+5 1 6 21 17 5 3
+5 2 10 23 25 9 2
+6 2 9 18 5 17 8 
+6 3 13 29 16 28 12 
+5 3 12 25 26 11 2
+5 4 16 29 21 15 3
+6 4 15 27 11 26 14 
+5 5 18 28 16 19 2
+5 6 20 24 28 12 2
+6 6 12 25 23 29 21 
+6 7 14 24 20 27 22 
+5 7 22 13 29 23 3
+5 8 17 26 14 24 2
+6 8 24 28 18 22 13 
+6 9 25 26 17 21 15 
+5 9 15 27 22 18 3
+5 10 19 11 27 20 3
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 1 8 9 2 
+4 10 2 3 11 
+4 5 7 12 0 
+4 13 4 5 14 
+4 3 15 16 4 
+4 17 7 1 18 
+4 6 19 20 7 
+4 21 0 6 4 
+4 9 11 21 2 
+4 13 8 9 14 
+4 16 18 1 8 
+4 17 11 3 15 
+4 10 19 20 11 
+4 12 2 10 8 
+4 5 19 17 7 
+4 20 18 12 7 
+4 12 0 21 2 
+4 21 15 13 4 
+4 10 14 5 19 
+4 20 15 16 18 
+4 16 14 6 4 
+4 13 18 17 15 
+4 9 19 6 14 
+4 9 11 17 19 
+4 21 11 20 15 
+4 13 8 12 18 
+4 16 8 10 14 
+great dodecicosahedron
+great dodecicosacron
+5/3 5/2 3|
+(6.10/3.6/5.10/7)
+icosahedral group
+A5
+10{6}+6{10/3}+6{10/7}+10{6/5}
+67 60 120 32 60 0 0 1 -28 4 4 120 5 0 1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.7913673487  0.0000000000  0.6113409191
+-0.6820030709  0.4014151117  0.6113409191
+-0.4944105968 -0.6179162098  0.6113409191
+ 0.1126514014  0.7833083316  0.6113409191
+ 0.9007316265  0.4014151117 -0.1659772426
+ 0.7860486710 -0.6179162098 -0.0175226837
+ 0.4149268310  0.7833083316  0.4628863603
+-0.7549125894 -0.4645892808  0.4628863603
+-0.5726387930  0.8028302234 -0.1659772426
+-0.8761697921 -0.4525240881 -0.1659772426
+-0.0086058013 -0.9998094297 -0.0175226837
+-0.8708511144  0.1653921218  0.4628863603
+ 0.8343963552  0.2991971590  0.4628863603
+-0.2691077939  0.9487004534 -0.1659772426
+ 0.8278221080 -0.4645892808 -0.3144318014
+ 0.2187285557  0.8028302234 -0.5546363234
+ 0.4042894756 -0.4525240881 -0.7948408455
+ 0.8987000724  0.1653921218 -0.4061817646
+-0.1437874830  0.2991971590  0.9432954043
+ 0.0331676357  0.9487004534 -0.3144318014
+-0.0331676357 -0.9487004534  0.3144318014
+-0.6906088722 -0.5983943180 -0.4061817646
+-0.0278489580 -0.3307842435  0.9432954043
+-0.5779574707  0.1849140136 -0.7948408455
+ 0.1544248384  0.9366352607  0.3144318014
+-0.1544248384 -0.9366352607 -0.3144318014
+-0.7635183907  0.3307842435 -0.5546363234
+ 0.1007584765 -0.5983943180 -0.7948408455
+-0.7614868366  0.5668072335 -0.3144318014
+ 0.7614868366 -0.5668072335  0.3144318014
+ 0.2756820411 -0.1849140136  0.9432954043
+ 0.2166970016  0.5668072335 -0.7948408455
+-0.8278221080  0.4645892808  0.3144318014
+ 0.2691077939 -0.9487004534  0.1659772426
+ 0.7635183907 -0.3307842435  0.5546363234
+-0.2756820411  0.1849140136 -0.9432954043
+ 0.0278489580  0.3307842435 -0.9432954043
+-0.2166970016 -0.5668072335  0.7948408455
+ 0.5779574707 -0.1849140136  0.7948408455
+ 0.7549125894  0.4645892808 -0.4628863603
+-0.4149268310 -0.7833083316 -0.4628863603
+-0.4042894756  0.4525240881  0.7948408455
+ 0.1437874830 -0.2991971590 -0.9432954043
+ 0.8761697921  0.4525240881  0.1659772426
+ 0.5726387930 -0.8028302234  0.1659772426
+-0.2187285557 -0.8028302234  0.5546363234
+-0.8343963552 -0.2991971590 -0.4628863603
+ 0.8708511144 -0.1653921218 -0.4628863603
+-0.1007584765  0.5983943180  0.7948408455
+-0.9007316265 -0.4014151117  0.1659772426
+-0.1126514014 -0.7833083316 -0.6113409191
+-0.8987000724 -0.1653921218  0.4061817646
+ 0.6906088722  0.5983943180  0.4061817646
+ 0.6820030709 -0.4014151117 -0.6113409191
+-0.7913673487  0.0000000000 -0.6113409191
+-0.7860486710  0.6179162098  0.0175226837
+ 0.4944105968  0.6179162098 -0.6113409191
+ 0.0086058013  0.9998094297  0.0175226837
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.2317571228  0.8506508084  0.4718917654
+-0.3015891505 -0.0555029103  0.4718917654
+-0.8089973662  0.3504874081  0.4718917654
+ 0.2317571228  0.2008114159  0.4718917654
+ 0.8680129287  0.3504874081 -0.3517273552
+ 0.5578135237 -0.0555029103  0.0498189392
+-0.2259811885  0.4702282018  0.2110364131
+ 0.0842182165 -0.1752437040  0.9809163757
+-0.8159632084 -0.4587939735 -0.3517273552
+-0.3051588742 -0.4702282018  0.0498189392
+ 0.7247791497 -0.1752437040  0.6663218655
+ 0.3051588742  0.4702282018 -0.0498189392
+ 0.2259811885 -0.4702282018 -0.2110364131
+ 0.2204861533 -0.4587939735 -0.8607519655
+ 0.0772523743 -0.9845250856  0.1572972551
+-0.1828226219  0.3804226065 -0.3722538870
+ 0.3159753393  0.6754071043 -0.6663218655
+-0.3159753393 -0.6754071043  0.6663218655
+-0.5578135237  0.0555029103 -0.0498189392
+ 0.7204740224 -0.6754071043  0.1572972551
+-0.7247791497  0.1752437040 -0.6663218655
+-0.7204740224  0.6754071043 -0.1572972551
+ 0.3015891505  0.0555029103 -0.4718917654
+-0.0842182165  0.1752437040 -0.9809163757
+ 0.1828226219 -0.3804226065  0.3722538870
+-0.8680129287 -0.3504874081  0.3517273552
+-0.2317571228 -0.2008114159 -0.4718917654
+-0.0772523743  0.9845250856 -0.1572972551
+ 0.8159632084  0.4587939735  0.3517273552
+ 0.8089973662 -0.3504874081 -0.4718917654
+-0.2204861533  0.4587939735  0.8607519655
+-0.2317571228 -0.8506508084 -0.4718917654
+6 0 2 9 16 5 1 
+10 0 3 12 19 38 52 42 23 8 2 3
+6 0 4 14 27 10 3 5
+10 0 1 7 19 39 53 49 31 13 4 7
+6 1 6 17 37 20 7 5
+10 1 5 15 35 44 48 30 13 18 6 3
+10 2 4 14 33 49 58 56 42 25 9 7
+6 2 8 21 30 13 4 5
+6 3 11 28 36 29 12 
+10 3 10 26 46 50 41 21 8 22 11 7
+6 5 7 19 38 34 15 5
+10 5 16 25 44 57 58 53 40 20 7 7
+10 6 11 28 15 34 51 54 45 26 17 7
+6 6 18 32 24 22 11 
+6 8 23 35 15 28 22 
+10 9 24 32 14 27 37 20 29 36 16 3
+6 9 25 44 48 43 24 5
+6 10 12 19 39 45 26 
+10 10 27 33 50 55 56 52 47 29 12 3
+6 13 31 46 26 17 18 5
+6 14 33 50 41 43 32 
+6 16 36 47 52 42 25 5
+10 17 18 32 43 48 57 59 54 40 37 3
+6 20 29 47 51 54 40 
+10 21 23 35 34 38 39 45 46 31 30 3
+6 21 41 55 56 42 23 
+10 22 28 36 47 51 59 55 41 43 24 3
+6 27 37 40 53 49 33 
+6 30 48 57 58 49 31 5
+6 34 35 44 57 59 51 
+6 38 39 53 58 56 52 5
+6 45 46 50 55 59 54 5
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 6 7 3 
+4 5 10 11 0 
+4 4 12 13 5 
+4 3 10 11 4 
+4 7 9 14 1 
+4 0 15 16 6 
+4 9 17 18 2 
+4 8 12 13 9 
+4 1 17 18 8 
+4 7 5 19 3 
+4 2 15 20 6 
+4 5 14 12 10 
+4 11 21 15 0 
+4 4 22 19 12 
+4 13 22 19 5 
+4 3 17 1 10 
+4 11 23 15 4 
+4 7 24 25 9 
+4 13 26 14 9 
+4 14 24 25 1 
+4 15 13 26 16 
+4 16 11 21 6 
+4 9 19 12 17 
+4 18 27 15 2 
+4 8 26 14 12 
+4 18 23 15 8 
+4 24 28 5 7 
+4 19 24 28 3 
+4 22 20 15 13 
+4 20 18 27 6 
+4 12 29 24 10 
+4 5 29 24 14 
+4 21 26 8 15 
+4 27 22 4 15 
+4 1 30 24 10 
+4 3 30 24 17 
+4 11 27 22 23 
+4 25 26 20 9 
+4 25 6 21 1 
+4 22 16 26 20 
+4 16 5 29 11 
+4 12 31 24 17 
+4 9 31 24 19 
+4 18 21 26 23 
+4 28 22 16 5 
+4 28 6 27 3 
+4 31 18 20 9 
+4 12 23 26 29 
+4 18 30 1 21 
+4 11 30 3 27 
+4 22 31 12 23 
+4 25 18 31 26 
+4 30 6 25 18 
+4 29 22 28 11 
+4 28 6 30 11 
+4 26 29 22 31 
+great snub dodecicosidodecahedron
+great hexagonal hexecontahedron
+|5/3 5/2 3
+(3.5/3.3.5/2.3.3)
+icosahedral group
+A5
+80{3}+12{5/2}+12{5/3}
+68 60 180 104 60 10 0 0 -16 3 6 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 1.0000000000  0.0000000000  0.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+ 0.7861513778  0.6180339887  0.0000000000
+-0.6180339887  0.7861513778  0.0000000000
+-1.0000000000 -0.0000000000  0.0000000000
+ 0.0000000000 -1.0000000000  0.0000000000
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000 -0.7861513778 -0.6180339887
+ 0.0000000000  0.6180339887 -0.7861513778
+ 0.6180339887  0.0000000000 -0.7861513778
+-0.7861513778  0.0000000000 -0.6180339887
+-0.6180339887 -0.0000000000  0.7861513778
+ 0.7861513778 -0.0000000000  0.6180339887
+-0.4858682718  0.6180339887  0.6180339887
+ 0.3819660113 -0.4858682718  0.7861513778
+ 0.6180339887 -0.7861513778  0.0000000000
+-0.7861513778 -0.6180339887 -0.0000000000
+-0.4858682718 -0.3819660113 -0.7861513778
+-0.6180339887 -0.4858682718  0.6180339887
+-0.0000000000  0.7861513778  0.6180339887
+ 0.0000000000 -0.6180339887  0.7861513778
+ 0.6180339887  0.4858682718 -0.6180339887
+ 0.7861513778 -0.3819660113  0.4858682718
+-0.7861513778  0.4858682718  0.3819660113
+ 0.6180339887  0.6180339887  0.4858682718
+ 0.4858682718 -0.7861513778  0.3819660113
+-0.6180339887 -0.6180339887 -0.4858682718
+-0.4858682718  0.7861513778 -0.3819660113
+ 0.3819660113  0.7861513778 -0.4858682718
+ 0.4858682718 -0.6180339887 -0.6180339887
+-0.3819660113 -0.7861513778  0.4858682718
+-0.3819660113  0.4858682718 -0.7861513778
+-0.3177508827 -0.8678342830 -0.3819660113
+ 0.8678342830 -0.1039022605 -0.4858682718
+ 0.4858682718  0.3819660113  0.7861513778
+-0.8678342830  0.1039022605  0.4858682718
+-0.1039022605  0.9183170948 -0.3819660113
+-0.7861513778  0.3819660113 -0.4858682718
+ 0.7861513778 -0.4858682718 -0.3819660113
+-0.3819660113  0.3177508827  0.8678342830
+-0.4858682718 -0.8678342830  0.1039022605
+ 0.4858682718  0.8678342830 -0.1039022605
+-0.3819660113  0.1039022605 -0.9183170948
+ 0.8678342830  0.3819660113 -0.3177508827
+ 0.1039022605  0.4858682718  0.8678342830
+-0.8678342830 -0.3819660113  0.3177508827
+-0.1039022605 -0.4858682718 -0.8678342830
+-0.9183170948  0.3819660113 -0.1039022605
+ 0.9183170948 -0.3819660113  0.1039022605
+ 0.3177508827  0.8678342830  0.3819660113
+-0.2360679775 -0.3177508827  0.9183170948
+ 0.1039022605 -0.9183170948  0.3819660113
+ 0.9183170948  0.2360679775  0.3177508827
+ 0.3819660113 -0.3177508827 -0.8678342830
+ 0.3819660113 -0.1039022605  0.9183170948
+ 0.3177508827 -0.9183170948 -0.2360679775
+-0.3177508827  0.9183170948  0.2360679775
+ 0.2360679775  0.3177508827 -0.9183170948
+-0.9183170948 -0.2360679775 -0.3177508827
+ 0.5773502692  0.5773502692  0.5773502692
+ 0.2805161775  0.5773502692  0.5773502692
+ 0.0970626198  0.8107067993  0.5773502692
+-0.5773502692  0.2805161775  0.5773502692
+-0.5773502692 -0.5773502692  0.5773502692
+ 0.5773502692 -0.5773502692  0.5773502692
+ 0.5773502692 -0.5773502692 -0.5773502692
+ 0.5773502692 -0.2805161775 -0.5773502692
+ 0.5773502692 -0.0970626198 -0.8107067993
+ 0.5773502692  0.5773502692 -0.2805161775
+-0.0970626198  0.5773502692 -0.8107067993
+-0.8107067993  0.5773502692  0.0970626198
+ 0.0970626198  0.5773502692  0.8107067993
+ 0.3938967115  0.4331280021  0.8107067993
+ 0.8107067993 -0.0970626198  0.2805161775
+ 0.8107067993 -0.0970626198 -0.5773502692
+ 0.0970626198  0.8107067993 -0.5773502692
+-0.8107067993  0.0970626198 -0.5773502692
+-0.8107067993  0.0970626198 -0.2805161775
+-0.9941603570 -0.0471596473 -0.0970626198
+-0.5773502692  0.8107067993 -0.0970626198
+-0.5773502692 -0.0970626198 -0.8107067993
+-0.5773502692 -0.8107067993  0.0970626198
+-0.5773502692 -0.5773502692  0.2805161775
+-0.8107067993 -0.5773502692  0.0970626198
+-0.2805161775 -0.5773502692 -0.5773502692
+ 0.8107067993 -0.3938967115 -0.4331280021
+ 0.2805161775 -0.8107067993  0.0970626198
+-0.2805161775  0.8107067993 -0.0970626198
+-0.0970626198  0.9941603570  0.0471596473
+ 0.9941603570 -0.0970626198  0.0471596473
+ 0.2805161775 -0.8107067993 -0.5138727076
+-0.2805161775  0.0970626198 -0.9549290665
+-0.0970626198  0.2805161775 -0.8107067993
+ 0.0471596473  0.0970626198 -0.9941603570
+-0.4331280021 -0.8107067993  0.3938967115
+ 0.0970626198 -0.2805161775  0.8107067993
+ 0.5138727076 -0.8107067993  0.2805161775
+ 0.9549290665  0.0970626198 -0.2805161775
+ 0.3938967115  0.8107067993  0.4331280021
+-0.2805161775  0.8107067993 -0.0970626198
+-0.9549290665  0.2805161775 -0.0970626198
+-0.5138727076 -0.2805161775  0.8107067993
+ 0.0471596473 -0.9941603570  0.0970626198
+ 0.2805161775 -0.8107067993  0.0970626198
+ 0.5381189786 -0.8415485325 -0.0471596473
+ 0.2805161775 -0.5138727076  0.8107067993
+-0.2805161775 -0.9549290665 -0.0970626198
+ 0.4331280021 -0.3938967115 -0.8107067993
+-0.8415485325  0.3696504405 -0.3938967115
+-0.0970626198  0.2805161775 -0.8107067993
+ 0.0970626198 -0.2805161775  0.8107067993
+ 0.0970626198 -0.0471596473  0.9941603570
+ 0.8107067993  0.5138727076  0.2805161775
+-0.0970626198  0.9549290665 -0.2805161775
+ 0.8107067993 -0.2805161775  0.5138727076
+-0.0970626198  0.2805161775  0.9549290665
+-0.8107067993 -0.4331280021  0.3938967115
+-0.0471596473 -0.5381189786  0.8415485325
+-0.3938967115  0.8415485325 -0.3696504405
+-0.8107067993  0.0970626198 -0.2805161775
+ 0.8107067993 -0.0970626198  0.2805161775
+ 0.8415485325  0.0471596473  0.5381189786
+-0.7215725363  0.5138727076  0.4639697352
+ 0.2805161775  0.9549290665  0.0970626198
+ 0.1605401813  0.3938967115 -0.9050260940
+-0.3696504405  0.3938967115 -0.8415485325
+-0.6907308032  0.0471596473  0.7215725363
+-0.8107067993 -0.5138727076 -0.2805161775
+ 0.2496744444 -0.9549290665 -0.1605401813
+ 0.4639697352  0.7215725363 -0.5138727076
+ 0.0970626198 -0.2805161775 -0.9549290665
+-0.9050260940 -0.1605401813 -0.3938967115
+ 0.2104431538 -0.9050260940  0.3696504405
+-0.5773502692 -0.5773502692  0.2805161775
+ 0.5773502692  0.5773502692 -0.2805161775
+ 0.7215725363  0.6907308032 -0.0471596473
+-0.2805161775  0.8107067993  0.5138727076
+-0.1605401813 -0.2496744444  0.9549290665
+ 0.6907308032  0.4830309745 -0.5381189786
+-0.5138727076 -0.4639697352 -0.7215725363
+-0.9549290665 -0.0970626198  0.2805161775
+-0.3938967115  0.9050260940  0.1605401813
+-0.0471596473 -0.7215725363 -0.6907308032
+ 0.5138727076  0.2805161775 -0.8107067993
+ 0.9549290665  0.1605401813  0.2496744444
+ 0.3696504405 -0.2104431538  0.9050260940
+ 0.2805161775  0.5773502692  0.5773502692
+-0.2805161775 -0.5773502692 -0.5773502692
+-0.5381189786 -0.6907308032 -0.4830309745
+ 0.9050260940 -0.3696504405  0.2104431538
+ 0.5773502692 -0.2805161775 -0.5773502692
+-0.5773502692  0.2805161775  0.5773502692
+-0.0970626198 -0.8107067993  0.5773502692
+-0.4639697352  0.2496744444  0.8499380899
+-0.4830309745  0.5381189786  0.6907308032
+ 0.8499380899  0.4639697352 -0.2496744444
+ 0.5773502692  0.0970626198  0.8107067993
+-0.8499380899  0.2104431538  0.4830309745
+-0.2496744444 -0.8499380899 -0.4639697352
+ 0.8107067993 -0.5773502692 -0.0970626198
+ 0.4830309745  0.8499380899 -0.2104431538
+-0.2104431538 -0.4830309745 -0.8499380899
+-0.5773502692  0.5773502692 -0.5773502692
+3 0 2 1 
+5 0 3 14 13 2 3
+3 0 4 3 
+5 0 5 20 19 4 2
+3 0 6 5 
+3 0 1 6 
+3 1 7 6 
+5 1 8 22 16 7 3
+3 1 9 8 
+5 1 2 10 25 9 2
+3 2 11 10 
+3 2 12 11 
+3 2 13 12 
+3 3 15 14 
+5 3 16 35 34 15 2
+3 3 7 16 
+3 3 4 7 
+3 4 17 7 
+5 4 18 36 32 17 3
+3 4 19 18 
+3 5 9 20 
+3 5 8 9 
+3 5 21 8 
+5 5 6 12 27 21 3
+3 6 11 12 
+5 6 7 17 30 11 2
+3 8 23 22 
+5 8 21 39 41 23 2
+5 9 24 42 38 20 3
+3 9 25 24 
+3 10 26 25 
+3 10 27 26 
+3 10 28 27 
+5 10 11 29 47 28 3
+3 11 30 29 
+3 12 26 27 
+5 12 13 31 45 26 2
+3 13 30 31 
+3 13 29 30 
+3 13 14 29 
+5 14 32 50 48 29 2
+3 14 17 32 
+3 14 15 17 
+3 15 30 17 
+5 15 33 49 31 30 3
+3 15 34 33 
+3 16 19 35 
+3 16 18 19 
+3 16 22 18 
+3 18 37 36 
+5 18 22 38 54 37 2
+5 19 23 40 52 35 3
+3 19 20 23 
+3 20 22 23 
+3 20 38 22 
+3 21 25 39 
+3 21 24 25 
+3 21 27 24 
+3 23 41 40 
+3 24 43 42 
+5 24 27 28 46 43 2
+5 25 26 44 55 39 3
+3 26 45 44 
+3 28 45 46 
+3 28 44 45 
+3 28 47 44 
+3 29 48 47 
+3 31 48 45 
+3 31 47 48 
+3 31 49 47 
+3 32 34 50 
+3 32 33 34 
+3 32 36 33 
+3 33 51 49 
+5 33 36 52 59 51 2
+5 34 37 53 58 50 3
+3 34 35 37 
+3 35 36 37 
+3 35 52 36 
+3 37 54 53 
+3 38 41 54 
+3 38 40 41 
+3 38 42 40 
+3 39 43 41 
+3 39 42 43 
+3 39 55 42 
+3 40 53 52 
+5 40 42 55 57 53 2
+5 41 43 56 59 54 3
+3 43 46 56 
+3 44 56 55 
+5 44 47 49 58 56 2
+5 45 48 51 57 46 3
+3 46 55 56 
+3 46 57 55 
+3 48 50 51 
+3 49 50 58 
+3 49 51 50 
+3 51 59 57 
+3 52 54 59 
+3 52 53 54 
+3 53 57 58 
+3 56 58 59 
+3 57 59 58 
+6 5 0 1 2 3 4 
+6 5 6 7 8 9 0 
+6 9 10 11 12 1 0 
+6 1 13 14 15 16 2 
+6 16 17 18 19 3 2 
+6 3 20 21 22 23 4 
+6 23 24 25 6 5 4 
+6 25 17 16 15 7 6 
+6 7 26 27 22 21 8 
+6 20 28 29 9 8 21 
+6 9 30 31 32 33 10 
+6 33 34 25 24 11 10 
+6 23 35 36 12 11 24 
+6 36 37 38 39 1 12 
+6 39 40 41 42 13 1 
+6 42 43 44 45 14 13 
+6 14 46 47 48 7 15 
+6 25 43 42 41 18 17 
+6 18 49 50 48 47 19 
+6 46 51 52 3 19 47 
+6 52 53 54 28 20 3 
+6 27 55 56 57 23 22 
+6 50 54 53 26 7 48 
+6 51 58 27 26 53 52 
+6 28 59 60 57 56 29 
+6 55 61 30 9 29 56 
+6 61 62 36 35 31 30 
+6 60 32 31 35 23 57 
+6 60 63 64 65 33 32 
+6 33 66 40 39 38 34 
+6 37 44 43 25 34 38 
+6 36 67 68 69 44 37 
+6 40 70 71 72 18 41 
+6 44 73 74 72 71 45 
+6 70 75 76 14 45 71 
+6 76 77 78 51 46 14 
+6 74 78 77 49 18 72 
+6 75 79 50 49 77 76 
+6 50 80 81 82 28 54 
+6 27 83 84 85 61 55 
+6 51 86 87 82 81 58 
+6 80 88 83 27 58 81 
+6 87 85 84 59 28 82 
+6 88 89 60 59 84 83 
+6 61 90 91 65 64 62 
+6 63 92 67 36 62 64 
+6 89 93 94 92 63 60 
+6 91 69 68 66 33 65 
+6 92 95 40 66 68 67 
+6 91 96 97 73 44 69 
+6 95 97 96 75 70 40 
+6 92 98 74 73 97 95 
+6 74 99 100 86 51 78 
+6 75 101 87 86 100 79 
+6 99 88 80 50 79 100 
+6 87 94 93 90 61 85 
+6 88 102 91 90 93 89 
+6 101 103 98 92 94 87 
+6 102 103 101 75 96 91 
+6 98 74 99 88 102 103 
+great dodecahemicosahedron
+great dodecahemicosacron
+5/4 5|3
+(6.5/4.6.5)
+icosahedral group
+A5
+10{6}+6{5}+6{5/4}
+69 30 60 22 30 0 1 1 -8 3 4 120 5 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8660254038  0.0000000000  0.5000000000
+-0.8660254038  0.0000000000  0.5000000000
+ 0.6454972244  0.5773502692  0.5000000000
+-0.6454972244 -0.5773502692  0.5000000000
+ 0.8660254038  0.0000000000 -0.5000000000
+ 0.1102640897  0.5773502692  0.8090169944
+ 0.7557613141 -0.5773502692 -0.3090169944
+-0.7557613141  0.5773502692 -0.3090169944
+-0.1102640897 -0.5773502692  0.8090169944
+-0.8660254038 -0.0000000000 -0.5000000000
+ 0.6454972244  0.5773502692 -0.5000000000
+ 0.4670861795 -0.3568220898  0.8090169944
+ 0.1784110449  0.9341723590 -0.3090169944
+-0.1784110449 -0.9341723590 -0.3090169944
+-0.4670861795  0.3568220898  0.8090169944
+-0.6454972244 -0.5773502692 -0.5000000000
+ 0.1102640897  0.5773502692 -0.8090169944
+ 0.7557613141 -0.5773502692  0.3090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.7557613141  0.5773502692  0.3090169944
+-0.3568220898  0.9341723590 -0.0000000000
+ 0.9341723590  0.3568220898 -0.0000000000
+-0.1102640897 -0.5773502692 -0.8090169944
+-0.9341723590 -0.3568220898 -0.0000000000
+ 0.3568220898 -0.9341723590 -0.0000000000
+ 0.4670861795 -0.3568220898 -0.8090169944
+ 0.1784110449  0.9341723590  0.3090169944
+-0.1784110449 -0.9341723590  0.3090169944
+-0.4670861795  0.3568220898 -0.8090169944
+ 0.0000000000  1.0000000000  0.0000000000
+-0.3035309991  0.7946544723  0.5257311121
+-0.6666666667  0.7453559925 -0.0000000000
+ 0.3035309991 -0.7946544723  0.5257311121
+ 0.3333333333  0.7453559925 -0.5773502692
+ 0.6070619982  0.7946544723  0.0000000000
+-0.6070619982 -0.7946544723  0.0000000000
+ 0.3333333333  0.7453559925  0.5773502692
+-0.7453559925  0.3333333333  0.5773502692
+ 0.9822469464 -0.1875924741  0.0000000000
+-0.9822469464  0.1875924741 -0.0000000000
+-0.7453559925  0.3333333333 -0.5773502692
+ 0.3035309991 -0.7946544723 -0.5257311121
+-0.4911234732 -0.1875924741  0.8506508084
+ 0.8726779962  0.3333333333 -0.3568220898
+-0.1273220038  0.3333333333 -0.9341723590
+ 0.4911234732  0.1875924741 -0.8506508084
+-0.4911234732 -0.1875924741 -0.8506508084
+-0.1273220038  0.3333333333  0.9341723590
+ 0.8726779962  0.3333333333  0.3568220898
+ 0.4911234732  0.1875924741  0.8506508084
+-0.3035309991  0.7946544723 -0.5257311121
+6 0 1 5 19 10 2 
+5 0 2 8 13 3 4
+6 0 3 11 19 16 4 
+5 0 1 7 14 4 
+6 1 7 23 10 20 6 
+5 1 6 21 17 5 4
+5 2 10 23 25 9 
+6 2 9 18 5 17 8 
+6 3 13 29 16 28 12 
+5 3 12 25 26 11 
+5 4 16 29 21 15 4
+6 4 15 27 11 26 14 
+5 5 18 28 16 19 
+5 6 20 24 28 12 
+6 6 12 25 23 29 21 
+6 7 14 24 20 27 22 
+5 7 22 13 29 23 4
+5 8 17 26 14 24 
+6 8 24 28 18 22 13 
+6 9 25 26 17 21 15 
+5 9 15 27 22 18 4
+5 10 19 11 27 20 4
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 1 8 9 2 
+4 10 2 3 11 
+4 5 7 12 0 
+4 13 4 5 14 
+4 3 15 16 4 
+4 17 7 1 18 
+4 6 19 20 7 
+4 21 0 6 4 
+4 9 11 21 2 
+4 13 8 9 14 
+4 16 18 1 8 
+4 17 11 3 15 
+4 10 19 20 11 
+4 12 2 10 8 
+4 5 19 17 7 
+4 20 18 12 7 
+4 12 0 21 2 
+4 21 15 13 4 
+4 10 14 5 19 
+4 20 15 16 18 
+4 16 14 6 4 
+4 13 18 17 15 
+4 9 19 6 14 
+4 9 11 17 19 
+4 21 11 20 15 
+4 13 8 12 18 
+4 16 8 10 14 
+great stellated truncated dodecahedron
+great triakisicosahedron
+2 3|5/3
+(10/3.10/3.3)
+icosahedral group
+A5
+12{10/3}+20{3}
+70 60 90 32 60 13 0 0 2 2 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9876921901  0.0000000000 -0.1564101584
+-0.6303417987  0.7603979742 -0.1564101584
+-0.1831282032 -0.9705668053 -0.1564101584
+-0.2530769525  0.7603979742 -0.5981195340
+-0.4238973457 -0.6801206241 -0.5981195340
+ 0.7469230475  0.2904461812 -0.5981195340
+-0.7002905480  0.3896744429 -0.5981195340
+-0.6570598434 -0.6801206241 -0.3251281267
+-0.4739316403  0.2904461812  0.8312820317
+ 0.0788547642 -0.5502291431  0.8312820317
+ 0.5260683597 -0.1795056119  0.8312820317
+-0.1975384380  0.5195659239  0.8312820317
+ 0.7901537521  0.5195659239 -0.3251281267
+ 0.8333844566 -0.5502291431 -0.0521367195
+ 0.9033332059 -0.1795056119  0.3895726561
+-0.4383075806  0.8100121051  0.3895726561
+ 0.9389572656  0.3400603121 -0.0521367195
+-0.5082563299 -0.8596262360 -0.0521367195
+-0.7147007828  0.5808923624  0.3895726561
+ 0.0089060149 -0.9209526744  0.3895726561
+ 0.3861708611 -0.9209526744 -0.0521367195
+ 0.3162221118  0.8100121051 -0.4938460950
+ 0.0953674240  0.3400603121  0.9355554706
+-0.1309914837 -0.8596262360 -0.4938460950
+ 0.2729914073  0.5808923624 -0.7668375023
+-0.6214357837 -0.1605547002 -0.7668375023
+-0.0953674240 -0.3400603121 -0.9355554706
+ 0.3518461715  0.0306632192 -0.9355554706
+ 0.8690085163 -0.0306632192 -0.4938460950
+-0.3518461715 -0.0306632192  0.9355554706
+-0.8545982815 -0.1605547002 -0.4938460950
+-0.9389572656 -0.3400603121  0.0521367195
+-0.8690085163  0.0306632192  0.4938460950
+-0.8333844566  0.5502291431  0.0521367195
+-0.3162221118 -0.8100121051  0.4938460950
+ 0.8545982815  0.1605547002  0.4938460950
+-0.3861708611  0.9209526744  0.0521367195
+ 0.1309914837  0.8596262360  0.4938460950
+ 0.5082563299  0.8596262360  0.0521367195
+-0.0788547642  0.5502291431 -0.8312820317
+ 0.4383075806 -0.8100121051 -0.3895726561
+ 0.6214357837  0.1605547002  0.7668375023
+-0.0089060149  0.9209526744 -0.3895726561
+ 0.6570598434  0.6801206241  0.3251281267
+-0.7901537521 -0.5195659239  0.3251281267
+-0.9033332059  0.1795056119 -0.3895726561
+-0.2729914073 -0.5808923624  0.7668375023
+ 0.7147007828 -0.5808923624 -0.3895726561
+-0.5260683597  0.1795056119 -0.8312820317
+ 0.4238973457  0.6801206241  0.5981195340
+ 0.1975384380 -0.5195659239 -0.8312820317
+ 0.4739316403 -0.2904461812 -0.8312820317
+ 0.2530769525 -0.7603979742  0.5981195340
+ 0.7002905480 -0.3896744429  0.5981195340
+-0.7469230475 -0.2904461812  0.5981195340
+ 0.6303417987 -0.7603979742  0.1564101584
+-0.9876921901 -0.0000000000  0.1564101584
+ 0.1831282032  0.9705668053  0.1564101584
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.3997648726  0.8506508084  0.3414399638
+-0.9100220386 -0.2351141009  0.3414399638
+ 0.3997648726 -0.4822469333  0.3414399638
+ 0.1949008944 -0.2351141009 -0.9522263391
+-0.1526965938  0.1842019375 -0.6720927788
+-0.6877040871  0.1842019375 -0.0456950952
+ 0.6307125431 -0.7608452130 -0.1526965938
+-0.0535007493  0.7099330497 -0.0456950952
+-0.0521673844 -0.7608452130  0.6468331514
+ 0.2879392144  0.2980449957  0.5807025884
+-0.3462641233 -0.2276861164  0.5807025884
+ 0.7573254447 -0.0898055953  0.6468331514
+ 0.6185920295  0.2980449957  0.1935675295
+ 0.5193961850 -0.2276861164 -0.4328301541
+ 0.0521673844  0.7608452130 -0.6468331514
+-0.7573254447  0.0898055953 -0.6468331514
+ 0.1274369665 -0.5526058126 -0.4328301541
+-0.4075705268 -0.5526058126  0.1935675295
+-0.6307125431  0.7608452130  0.1526965938
+-0.6185920295 -0.2980449957 -0.1935675295
+ 0.4075705268  0.5526058126 -0.1935675295
+-0.2879392144 -0.2980449957 -0.5807025884
+-0.1274369665  0.5526058126  0.4328301541
+-0.1949008944  0.2351141009  0.9522263391
+-0.5193961850  0.2276861164  0.4328301541
+ 0.3462641233  0.2276861164 -0.5807025884
+ 0.9100220386  0.2351141009 -0.3414399638
+ 0.6877040871 -0.1842019375  0.0456950952
+ 0.0535007493 -0.7099330497  0.0456950952
+-0.3997648726 -0.8506508084 -0.3414399638
+ 0.1526965938 -0.1842019375  0.6720927788
+-0.3997648726  0.4822469333 -0.3414399638
+10 0 2 6 11 19 25 15 9 4 1 3
+10 0 3 7 12 20 26 16 10 5 2 3
+3 0 1 3 
+10 1 4 8 14 22 31 21 13 7 3 3
+3 2 5 6 
+3 4 9 8 
+10 5 10 17 27 35 36 28 18 11 6 3
+3 7 13 12 
+10 8 9 15 24 33 42 41 32 23 14 3
+3 10 16 17 
+3 11 18 19 
+10 12 13 21 30 39 48 47 38 29 20 3
+3 14 23 22 
+3 15 25 24 
+10 16 26 29 38 46 52 44 34 27 17 3
+10 18 28 37 45 51 43 33 24 25 19 3
+3 20 29 26 
+3 21 31 30 
+10 22 23 32 40 50 55 49 39 30 31 3
+3 27 34 35 
+3 28 36 37 
+3 32 41 40 
+3 33 43 42 
+10 34 44 53 57 58 54 45 37 36 35 3
+3 38 47 46 
+3 39 49 48 
+10 40 41 42 43 51 54 58 59 56 50 3
+3 44 52 53 
+3 45 54 51 
+10 46 47 48 49 55 56 59 57 53 52 3
+3 50 56 55 
+3 57 59 58 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 3 2 
+3 3 5 0 
+3 4 6 1 
+3 0 6 4 
+3 1 7 3 
+3 3 8 5 
+3 8 0 5 
+3 6 9 1 
+3 0 10 6 
+3 1 11 7 
+3 11 3 7 
+3 3 12 8 
+3 8 13 0 
+3 9 14 1 
+3 6 14 9 
+3 10 15 6 
+3 0 15 10 
+3 1 16 11 
+3 11 17 3 
+3 3 18 12 
+3 18 8 12 
+3 8 15 13 
+3 13 0 15 
+3 14 16 1 
+3 6 19 14 
+3 15 20 6 
+3 14 11 16 
+3 11 18 17 
+3 17 3 18 
+3 18 21 8 
+3 8 22 15 
+3 19 23 14 
+3 6 23 19 
+3 20 23 6 
+3 15 23 20 
+3 14 24 11 
+3 11 25 18 
+3 18 26 21 
+3 26 8 21 
+3 26 22 8 
+3 26 15 22 
+3 23 27 14 
+3 15 28 23 
+3 14 29 24 
+3 29 11 24 
+3 29 25 11 
+3 29 18 25 
+3 18 30 26 
+3 26 28 15 
+3 27 29 14 
+3 23 29 27 
+3 26 23 28 
+3 29 30 18 
+3 29 26 30 
+3 23 31 29 
+3 26 31 23 
+3 29 26 31 
+great rhombicosidodecahedron
+great deltoidal hexecontahedron
+5/3 3|2
+(4.5/3.4.3)
+icosahedral group
+A5
+30{4}+20{3}+12{5/3}
+71 60 120 62 60 13 0 0 2 3 4 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9996324920  0.0000000000  0.0271086873
+-0.9468654869  0.3204853643  0.0271086873
+-0.3453645319  0.9380770007  0.0271086873
+ 0.0263835025 -0.9992842588  0.0271086873
+ 0.0527670051  0.3204853643 -0.9457826254
+ 0.0364611038  0.9380770007 -0.3445027268
+ 0.2398305218  0.7400061526  0.6283885859
+-0.3352869307 -0.8768697425 -0.3445027268
+-0.3189810294 -0.0612072581 -0.9457826254
+ 0.8677149793  0.3583135302 -0.3445027268
+-0.7334184677 -0.2592781062  0.6283885859
+-0.9367878857 -0.0612072581 -0.3445027268
+ 0.6216561575  0.7400061526  0.2567771718
+-0.3678987333  0.3583135302  0.8580570704
+ 0.6480396600 -0.2592781062 -0.7161141409
+ 0.8514090780 -0.4573489542  0.2567771718
+ 0.5060445461  0.4807280465 -0.7161141409
+ 0.2336022217 -0.4573489542  0.8580570704
+-0.7233408665 -0.6409707286  0.2567771718
+ 0.4796610435 -0.8390415766  0.2567771718
+ 0.4633551422 -0.2214499403  0.8580570704
+-0.4672044434 -0.5185562123 -0.7161141409
+ 0.2762916255 -0.6409707286 -0.7161141409
+-0.7295691665  0.4807280465  0.4864456563
+ 0.2436798229 -0.8390415766  0.4864456563
+ 0.8451807779 -0.2214499403  0.4864456563
+-0.7031856640 -0.5185562123 -0.4864456563
+-0.4998162460 -0.7166270604  0.4864456563
+-0.8451807779  0.2214499403 -0.4864456563
+ 0.4998162460 -0.7166270604 -0.4864456563
+-0.4998162460  0.7166270604  0.4864456563
+ 0.7031856640  0.5185562123  0.4864456563
+ 0.7295691665 -0.4807280465 -0.4864456563
+-0.2436798229  0.8390415766 -0.4864456563
+ 0.4998162460  0.7166270604 -0.4864456563
+-0.4633551422  0.2214499403 -0.8580570704
+ 0.4672044434  0.5185562123  0.7161141409
+-0.5060445461 -0.4807280465  0.7161141409
+-0.4796610435  0.8390415766 -0.2567771718
+-0.2762916255  0.6409707286  0.7161141409
+ 0.3678987333 -0.3583135302 -0.8580570704
+ 0.7233408665  0.6409707286 -0.2567771718
+-0.2336022217  0.4573489542 -0.8580570704
+-0.6480396600  0.2592781062  0.7161141409
+-0.6216561575 -0.7400061526 -0.2567771718
+-0.8514090780  0.4573489542 -0.2567771718
+-0.8677149793 -0.3583135302  0.3445027268
+ 0.7334184677  0.2592781062 -0.6283885859
+-0.2398305218 -0.7400061526 -0.6283885859
+ 0.9367878857  0.0612072581  0.3445027268
+-0.0364611038 -0.9380770007  0.3445027268
+ 0.3189810294  0.0612072581  0.9457826254
+ 0.3352869307  0.8768697425  0.3445027268
+-0.0527670051 -0.3204853643  0.9457826254
+ 0.3453645319 -0.9380770007 -0.0271086873
+ 0.9468654869 -0.3204853643 -0.0271086873
+-0.0263835025  0.9992842588 -0.0271086873
+-0.9996324920 -0.0000000000 -0.0271086873
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.1602426822  0.9732489895  0.1646471601
+-0.1272308741  0.1239160115  0.1646471601
+-0.9686806297 -0.1858740172  0.1646471601
+ 0.1602426822 -0.1560677326  0.1646471601
+ 0.1908463112 -0.1858740172 -0.9638612635
+ 0.1680357129  0.1239160115 -0.1227207474
+-0.1920048196 -0.0368425940 -0.1972823210
+-0.2898817352 -0.4156269378  0.8621037224
+ 0.4078312422  0.3007504775  0.8621037224
+ 0.0317621374  0.1929103266 -0.1972823210
+-0.1194378434 -0.1712477161 -0.1227207474
+ 0.8696452057 -0.4156269378 -0.2664047011
+-0.1980708480  0.1929103266  0.0264023998
+ 0.8507311228  0.3007504775  0.4310518612
+ 0.2494630659  0.1192251386  0.0264023998
+-0.6904884406  0.6724985120 -0.2664047011
+ 0.0534142274 -0.2297529205  0.0548823867
+ 0.4384348713 -0.8583725292 -0.2664047011
+ 0.2310826560 -0.0473317046  0.0548823867
+-0.1125994760 -0.2525228959  0.0264023998
+-0.2781921891 -0.8583725292  0.4310518612
+-0.2475885600  0.6724985120 -0.6974565623
+ 0.0196300805  0.1192251386  0.2500871207
+ 0.0485978695 -0.0473317046  0.2324855208
+ 0.0294451207 -0.2525228959 -0.1118423604
+ 0.0189140829 -0.7163774153 -0.6974565623
+-0.0485978695  0.0473317046 -0.2324855208
+-0.6977129774 -0.7163774153  0.0000000000
+-0.1186655045 -0.0227699753  0.2500871207
+-0.6787988945  0.2297529205 -0.6974565623
+ 0.7166270604  0.0000000000 -0.6974565623
+ 0.6977129774  0.7163774153  0.0000000000
+ 0.2532120777 -0.0227699753 -0.1118423604
+-0.2310826560  0.0473317046 -0.0548823867
+-0.7166270604 -0.0000000000  0.6974565623
+-0.0189140829  0.7163774153  0.6974565623
+ 0.6787988945 -0.2297529205  0.6974565623
+-0.2532120777  0.0227699753  0.1118423604
+ 0.2781921891  0.8583725292 -0.4310518612
+ 0.1186655045  0.0227699753 -0.2500871207
+-0.0534142274  0.2297529205 -0.0548823867
+-0.0294451207  0.2525228959  0.1118423604
+ 0.2475885600 -0.6724985120  0.6974565623
+-0.0196300805 -0.1192251386 -0.2500871207
+-0.8507311228 -0.3007504775 -0.4310518612
+-0.4384348713  0.8583725292  0.2664047011
+ 0.6904884406 -0.6724985120  0.2664047011
+ 0.1125994760  0.2525228959 -0.0264023998
+-0.2494630659 -0.1192251386 -0.0264023998
+-0.4078312422 -0.3007504775 -0.8621037224
+ 0.1194378434  0.1712477161  0.1227207474
+ 0.1980708480 -0.1929103266 -0.0264023998
+-0.8696452057  0.4156269378  0.2664047011
+-0.1680357129 -0.1239160115  0.1227207474
+ 0.2898817352  0.4156269378 -0.8621037224
+-0.0317621374 -0.1929103266  0.1972823210
+ 0.1272308741 -0.1239160115 -0.1646471601
+-0.1908463112  0.1858740172  0.9638612635
+ 0.9686806297  0.1858740172 -0.1646471601
+ 0.1920048196  0.0368425940  0.1972823210
+-0.1602426822 -0.9732489895 -0.1646471601
+-0.1602426822  0.1560677326 -0.1646471601
+4 0 2 5 1 
+5 0 3 11 7 2 3
+4 0 4 9 3 
+3 0 1 4 
+4 1 6 12 4 
+5 1 5 13 15 6 3
+3 2 8 5 
+4 2 7 16 8 
+4 3 10 20 11 
+3 3 9 10 
+5 4 12 23 19 9 3
+4 5 8 18 13 
+3 6 14 12 
+4 6 15 25 14 
+3 7 17 16 
+4 7 11 22 17 
+5 8 16 28 30 18 3
+4 9 19 21 10 
+5 10 21 33 32 20 3
+3 11 20 22 
+4 12 14 26 23 
+4 13 24 27 15 
+3 13 18 24 
+5 14 25 37 38 26 3
+3 15 27 25 
+4 16 17 29 28 
+5 17 22 34 41 29 3
+4 18 30 36 24 
+3 19 31 21 
+4 19 23 35 31 
+4 20 32 34 22 
+4 21 31 43 33 
+3 23 26 35 
+5 24 36 47 39 27 3
+4 25 27 39 37 
+4 26 38 46 35 
+4 28 40 42 30 
+3 28 29 40 
+4 29 41 50 40 
+3 30 42 36 
+5 31 35 46 53 43 3
+3 32 44 34 
+4 32 33 45 44 
+3 33 43 45 
+4 34 44 51 41 
+4 36 42 52 47 
+4 37 48 49 38 
+3 37 39 48 
+3 38 49 46 
+4 39 47 55 48 
+5 40 50 57 52 42 3
+3 41 51 50 
+4 43 53 54 45 
+5 44 45 54 58 51 3
+4 46 49 56 53 
+3 47 52 55 
+5 48 55 59 56 49 3
+4 50 51 58 57 
+4 52 57 59 55 
+3 53 56 54 
+4 54 56 59 58 
+3 57 58 59 
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 8 9 2 
+4 2 10 4 3 
+4 5 11 6 0 
+4 4 12 13 5 
+4 7 14 15 1 
+4 11 16 7 6 
+4 9 17 10 2 
+4 8 18 17 9 
+4 15 19 8 1 
+4 10 20 12 4 
+4 5 21 22 11 
+4 20 23 13 12 
+4 13 24 21 5 
+4 16 25 14 7 
+4 25 26 15 14 
+4 22 27 16 11 
+4 17 28 29 10 
+4 19 30 18 8 
+4 18 31 28 17 
+4 26 30 19 15 
+4 29 32 20 10 
+4 21 33 27 22 
+4 23 34 24 13 
+4 32 35 23 20 
+4 34 33 21 24 
+4 16 36 37 25 
+4 37 38 26 25 
+4 27 39 36 16 
+4 31 40 29 28 
+4 30 41 42 18 
+4 42 43 31 18 
+4 26 44 41 30 
+4 40 35 32 29 
+4 33 45 39 27 
+4 23 46 47 34 
+4 35 48 46 23 
+4 47 49 33 34 
+4 36 50 38 37 
+4 38 51 44 26 
+4 45 50 36 39 
+4 43 52 40 31 
+4 44 53 42 41 
+4 53 52 43 42 
+4 40 54 48 35 
+4 49 55 45 33 
+4 46 56 49 47 
+4 54 56 46 48 
+4 50 57 51 38 
+4 57 53 44 51 
+4 55 58 50 45 
+4 52 59 54 40 
+4 53 60 59 52 
+4 56 58 55 49 
+4 60 56 54 59 
+4 58 61 57 50 
+4 61 60 53 57 
+4 56 58 61 60 
+great truncated icosidodecahedron
+great disdyakistriacontahedron
+5/3 2 3|
+(10/3.4.6)
+icosahedral group
+A5
+20{6}+30{4}+12{10/3}
+72 120 180 62 120 13 0 0 2 3 3 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8541299615  0.0000000000  0.5200596205
+ 0.0775955677  0.8505979773  0.5200596205
+-0.8315867367 -0.1949397099  0.5200596205
+ 0.4038441822  0.8505979773  0.3367387081
+ 0.8766731863 -0.1949397099 -0.4398211385
+-0.7539911690  0.6556582674  0.0401192410
+ 0.8837688310  0.3248995166  0.3367387081
+-0.8090435119 -0.3898794199 -0.4398211385
+ 0.4263874070  0.6556582674 -0.6231420509
+-0.1719938631  0.3248995166  0.9299776423
+ 0.0450864496 -0.3898794199 -0.9197615180
+-0.7794046424 -0.0649799033 -0.6231420509
+ 0.3079307858 -0.2007989442  0.9299776423
+ 0.8583553576 -0.3957386541 -0.3265225838
+-0.7453804233  0.5811979239 -0.3265225838
+-0.1269074134 -0.0649799033 -0.9897838757
+ 0.6341794002 -0.2007989442  0.7466567299
+-0.7252886834 -0.3957386541  0.5633358175
+ 0.1087495382  0.5811979239 -0.8064629633
+-0.8412938197 -0.4701989976  0.2667163504
+ 0.0267686209 -0.5906783641 -0.8064629633
+ 0.2825173124 -0.9214371149  0.2667163504
+-0.1423549936  0.6497990331  0.7466567299
+-0.8072696007  0.1759788297  0.5633358175
+ 0.6653333707 -0.4701989976 -0.5798658539
+-0.7027454586 -0.5906783641 -0.3965449415
+ 0.0808845798 -0.9214371149  0.3800149051
+ 0.7117749679  0.6497990331  0.2667163504
+ 0.9009903223  0.1759788297 -0.3965449415
+-0.0351205564 -0.9958974583  0.0833954380
+-0.7776307312  0.5008783463  0.3800149051
+-0.1931819403 -0.7914773082 -0.5798658539
+-0.6180542463  0.7797588398 -0.0999254744
+-0.8326830741 -0.5446593410 -0.0999254744
+-0.0150288165 -0.2292402645  0.9732538393
+ 0.0894953255 -0.9958974583  0.0133730803
+ 0.7289964592  0.5008783463 -0.4665672992
+-0.3948146729 -0.7914773082 -0.4665672992
+ 0.2360757152  0.7797588398 -0.5798658539
+ 0.3476955019 -0.5446593410 -0.7631867663
+ 0.8391011449 -0.2292402645  0.4933134598
+ 0.8347157954 -0.5505185752  0.0133730803
+-0.7550875064  0.3059386363 -0.5798658539
+ 0.0922056206  0.9462572293  0.3099925474
+ 0.6766544115 -0.3460984252 -0.6498882116
+-0.6434677197  0.0591206691 -0.7631867663
+-0.0404422899 -0.9498784352  0.3099925474
+-0.4226796312 -0.5505185752  0.7199105693
+-0.1025902774  0.3059386363 -0.9465076787
+ 0.2168215026  0.9462572293  0.2399701898
+-0.9069896296 -0.3460984252  0.2399701898
+-0.3172191052  0.0591206691 -0.9465076787
+ 0.2858063246 -0.9498784352  0.1266716350
+ 0.3590165427 -0.4205587686 -0.8332091240
+ 0.8983788839  0.4205587686  0.1266716350
+ 0.1147488454  0.7513175194 -0.6498882116
+ 0.2263686321  0.5044995522 -0.8332091240
+ 0.6147652341 -0.7513175194  0.2399701898
+ 0.8293940619 -0.5044995522  0.2399701898
+-0.8983788839 -0.4205587686 -0.1266716350
+-0.3590165427  0.4205587686  0.8332091240
+-0.6147652341  0.7513175194 -0.2399701898
+-0.8293940619  0.5044995522 -0.2399701898
+-0.1147488454 -0.7513175194  0.6498882116
+-0.2263686321 -0.5044995522  0.8332091240
+ 0.4226796312  0.5505185752 -0.7199105693
+-0.2168215026 -0.9462572293 -0.2399701898
+ 0.9069896296  0.3460984252 -0.2399701898
+-0.2858063246  0.9498784352 -0.1266716350
+ 0.1025902774 -0.3059386363  0.9465076787
+ 0.3172191052 -0.0591206691  0.9465076787
+-0.8347157954  0.5505185752 -0.0133730803
+-0.0922056206 -0.9462572293 -0.3099925474
+-0.6766544115  0.3460984252  0.6498882116
+ 0.0404422899  0.9498784352 -0.3099925474
+ 0.7550875064 -0.3059386363  0.5798658539
+ 0.6434677197 -0.0591206691  0.7631867663
+-0.0894953255  0.9958974583 -0.0133730803
+-0.7289964592 -0.5008783463  0.4665672992
+ 0.3948146729  0.7914773082  0.4665672992
+-0.8391011449  0.2292402645 -0.4933134598
+-0.3476955019  0.5446593410  0.7631867663
+-0.2360757152 -0.7797588398  0.5798658539
+ 0.0351205564  0.9958974583 -0.0833954380
+ 0.7776307312 -0.5008783463 -0.3800149051
+ 0.1931819403  0.7914773082  0.5798658539
+ 0.0150288165  0.2292402645 -0.9732538393
+ 0.8326830741  0.5446593410  0.0999254744
+ 0.6180542463 -0.7797588398  0.0999254744
+ 0.7027454586  0.5906783641  0.3965449415
+-0.6653333707  0.4701989976  0.5798658539
+-0.0808845798  0.9214371149 -0.3800149051
+-0.9009903223 -0.1759788297  0.3965449415
+-0.7117749679 -0.6497990331 -0.2667163504
+-0.0267686209  0.5906783641  0.8064629633
+ 0.8412938197  0.4701989976 -0.2667163504
+-0.2825173124  0.9214371149 -0.2667163504
+ 0.8072696007 -0.1759788297 -0.5633358175
+ 0.1423549936 -0.6497990331 -0.7466567299
+ 0.1269074134  0.0649799033  0.9897838757
+ 0.7252886834  0.3957386541 -0.5633358175
+-0.6341794002  0.2007989442 -0.7466567299
+-0.1087495382 -0.5811979239  0.8064629633
+ 0.7794046424  0.0649799033  0.6231420509
+-0.8583553576  0.3957386541  0.3265225838
+-0.3079307858  0.2007989442 -0.9299776423
+ 0.7453804233 -0.5811979239  0.3265225838
+-0.4263874070 -0.6556582674  0.6231420509
+ 0.1719938631 -0.3248995166 -0.9299776423
+-0.0450864496  0.3898794199  0.9197615180
+ 0.7539911690 -0.6556582674 -0.0401192410
+-0.8837688310 -0.3248995166 -0.3367387081
+ 0.8090435119  0.3898794199  0.4398211385
+-0.8766731863  0.1949397099  0.4398211385
+-0.4038441822 -0.8505979773 -0.3367387081
+ 0.8315867367  0.1949397099 -0.5200596205
+-0.0775955677 -0.8505979773 -0.5200596205
+-0.8541299615  0.0000000000 -0.5200596205
+-0.0000000000  0.0000000000 -1.0000000000
+ 0.1125484940  0.1027486297  0.2002978807
+-0.1451976151  0.1262614479  0.2002978807
+ 0.1125484940 -0.9732489895  0.2002978807
+ 0.2465918377  0.1262614479 -0.0198507936
+ 0.2605224485  0.6488326596 -0.7149435178
+-0.2508908076  0.0175515613 -0.0094567831
+-0.7461418850  0.6488326596 -0.1492932256
+ 0.1224008564  0.0175515613 -0.2192114469
+ 0.2245940980 -0.1148764603  0.1162085697
+-0.1348570368  0.0368425940 -0.2399994678
+-0.0175451002 -0.1148764603  0.2522679329
+-0.1568547765 -0.2042953142 -0.1039401045
+-0.8375948183 -0.3536689320  0.4163570665
+ 0.1014417091 -0.2122013592 -0.0895759354
+ 0.2339533531  0.8785855802  0.4163570665
+-0.0072045220 -0.2042953142 -0.1880294155
+ 0.7912222885 -0.3536689320 -0.4988843319
+-0.1292652270 -0.2122013592  0.0400595761
+ 0.1425004198 -0.1239160115  0.9820073587
+ 0.0180479902  0.2752928712  0.0321192587
+-0.1632456053 -0.1490314232  0.1681786220
+ 0.7646531932 -0.1239160115  0.6324162524
+ 0.2285438474 -0.1490314232 -0.0519700523
+-0.1276525148  0.2411379082 -0.0519700523
+ 0.0063908288 -0.0552638910 -0.2721187265
+-0.0953526143  0.1595466752 -0.1696950876
+ 0.1854901192 -0.4956640459 -0.8484754382
+ 0.0953526143 -0.1595466752  0.1696950876
+ 0.0219977397  0.2411379082 -0.1360593633
+-0.2357483694 -0.0552638910 -0.1360593633
+-0.8211742143 -0.4956640459 -0.2828251461
+ 0.2421391982  0.0000000000 -0.1360593633
+ 0.1292652270  0.2122013592 -0.0400595761
+ 0.8211742143  0.4956640459  0.2828251461
+-0.2421391982  0.0000000000  0.1360593633
+-0.1014417091  0.2122013592  0.0895759354
+-0.1854901192  0.4956640459  0.8484754382
+-0.7646531932  0.1239160115 -0.6324162524
+-0.0219977397 -0.2411379082  0.1360593633
+ 0.2357483694  0.0552638910  0.1360593633
+-0.1425004198  0.1239160115 -0.9820073587
+ 0.1276525148 -0.2411379082  0.0519700523
+-0.0063908288  0.0552638910  0.2721187265
+-0.2285438474  0.1490314232  0.0519700523
+-0.1224008564 -0.0175515613  0.2192114469
+-0.7912222885  0.3536689320  0.4988843319
+ 0.1632456053  0.1490314232 -0.1681786220
+ 0.2508908076 -0.0175515613  0.0094567831
+ 0.8375948183  0.3536689320 -0.4163570665
+ 0.0072045220  0.2042953142  0.1880294155
+-0.2339533531 -0.8785855802 -0.4163570665
+-0.0180479902 -0.2752928712 -0.0321192587
+ 0.1568547765  0.2042953142  0.1039401045
+ 0.7461418850 -0.6488326596  0.1492932256
+ 0.0175451002  0.1148764603 -0.2522679329
+-0.1125484940 -0.1027486297 -0.2002978807
+-0.2605224485 -0.6488326596  0.7149435178
+-0.2245940980  0.1148764603 -0.1162085697
+ 0.1348570368 -0.0368425940  0.2399994678
+-0.2465918377 -0.1262614479  0.0198507936
+-0.1125484940  0.9732489895 -0.2002978807
+ 0.1451976151 -0.1262614479 -0.2002978807
+10 0 2 7 13 23 28 17 10 4 1 3
+4 0 3 6 2 
+6 0 1 5 11 8 3 
+4 1 4 9 5 
+6 2 6 12 21 14 7 
+10 3 8 15 24 34 43 31 20 12 6 3
+6 4 10 18 26 16 9 
+10 5 9 16 25 37 49 40 29 19 11 3
+4 7 14 22 13 
+4 8 11 19 15 
+4 10 17 27 18 
+4 12 20 30 21 
+6 13 22 32 46 33 23 
+10 14 21 30 42 54 67 58 45 32 22 3
+6 15 19 29 41 35 24 
+4 16 26 36 25 
+6 17 28 39 52 38 27 
+10 18 27 38 51 64 73 60 48 36 26 3
+6 20 31 44 55 42 30 
+4 23 33 39 28 
+4 24 35 47 34 
+6 25 36 48 61 50 37 
+4 29 40 53 41 
+4 31 43 56 44 
+4 32 45 57 46 
+10 33 46 57 69 81 87 75 63 52 39 3
+6 34 47 59 68 56 43 
+10 35 41 53 65 77 89 83 71 59 47 3
+4 37 50 62 49 
+4 38 52 63 51 
+6 40 49 62 74 65 53 
+4 42 55 66 54 
+10 44 56 68 80 92 101 90 78 66 55 3
+6 45 58 70 82 69 57 
+4 48 60 72 61 
+10 50 61 72 84 95 105 97 86 74 62 3
+6 51 63 75 88 76 64 
+6 54 66 78 91 79 67 
+4 58 67 79 70 
+4 59 71 80 68 
+6 60 73 85 96 84 72 
+4 64 76 85 73 
+4 65 74 86 77 
+4 69 82 93 81 
+10 70 79 91 100 108 114 110 103 93 82 3
+6 71 83 94 102 92 80 
+4 75 87 98 88 
+10 76 88 98 107 113 116 111 104 96 85 3
+6 77 86 97 106 99 89 
+4 78 90 100 91 
+6 81 93 103 107 98 87 
+4 83 89 99 94 
+4 84 96 104 95 
+6 90 101 109 115 108 100 
+4 92 102 109 101 
+10 94 99 106 112 117 119 118 115 109 102 3
+6 95 104 111 117 112 105 
+4 97 105 112 106 
+4 103 110 113 107 
+4 108 115 118 114 
+6 110 114 118 119 116 113 
+4 111 116 119 117 
+3 2 0 1 
+3 2 3 0 
+3 0 4 1 
+3 1 5 2 
+3 3 6 0 
+3 2 7 3 
+3 4 5 1 
+3 0 8 4 
+3 5 9 2 
+3 7 6 3 
+3 6 10 0 
+3 9 7 2 
+3 4 11 5 
+3 0 12 8 
+3 8 13 4 
+3 5 14 9 
+3 7 15 6 
+3 10 16 0 
+3 6 17 10 
+3 14 7 9 
+3 11 18 5 
+3 13 11 4 
+3 12 13 8 
+3 0 19 12 
+3 5 20 14 
+3 7 21 15 
+3 15 17 6 
+3 17 16 10 
+3 16 19 0 
+3 14 22 7 
+3 13 18 11 
+3 18 23 5 
+3 12 24 13 
+3 19 25 12 
+3 5 26 20 
+3 20 27 14 
+3 21 17 15 
+3 7 28 21 
+3 17 29 16 
+3 16 25 19 
+3 22 30 7 
+3 27 22 14 
+3 13 31 18 
+3 23 26 5 
+3 18 32 23 
+3 24 33 13 
+3 25 24 12 
+3 26 27 20 
+3 21 34 17 
+3 30 28 7 
+3 28 35 21 
+3 17 36 29 
+3 29 25 16 
+3 27 30 22 
+3 13 37 31 
+3 31 32 18 
+3 32 26 23 
+3 25 33 24 
+3 33 38 13 
+3 26 39 27 
+3 34 40 17 
+3 35 34 21 
+3 30 35 28 
+3 36 25 29 
+3 17 41 36 
+3 27 42 30 
+3 37 32 31 
+3 38 37 13 
+3 32 39 26 
+3 25 43 33 
+3 33 44 38 
+3 39 45 27 
+3 35 40 34 
+3 40 41 17 
+3 42 35 30 
+3 36 46 25 
+3 41 47 36 
+3 27 48 42 
+3 37 49 32 
+3 44 37 38 
+3 32 45 39 
+3 25 50 43 
+3 43 44 33 
+3 45 51 27 
+3 35 52 40 
+3 40 47 41 
+3 48 35 42 
+3 46 50 25 
+3 47 46 36 
+3 51 48 27 
+3 49 53 32 
+3 44 49 37 
+3 32 54 45 
+3 50 44 43 
+3 45 55 51 
+3 35 56 52 
+3 52 47 40 
+3 48 57 35 
+3 47 50 46 
+3 55 48 51 
+3 44 53 49 
+3 53 54 32 
+3 54 55 45 
+3 50 58 44 
+3 56 47 52 
+3 57 56 35 
+3 55 57 48 
+3 47 58 50 
+3 44 59 53 
+3 53 55 54 
+3 58 60 44 
+3 56 61 47 
+3 55 56 57 
+3 47 60 58 
+3 60 59 44 
+3 59 55 53 
+3 61 60 47 
+3 55 61 56 
+3 60 55 59 
+3 61 60 55 
+great inverted snub icosidodecahedron
+great inverted pentagonal hexecontahedron
+|5/3 2 3
+(3.5/3.3.3.3)
+icosahedral group
+A5
+80{3}+12{5/3}
+73 60 150 92 60 13 0 0 2 2 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9794318115  0.0000000000 -0.2017754361
+-0.2475810566  0.9476234979 -0.2017754361
+ 0.6794635566  0.7054189880 -0.2017754361
+-0.8542645893  0.4790810838 -0.2017754361
+-0.2475810566 -0.9476234979 -0.2017754361
+-0.3699948910  0.4790810838 -0.7959805875
+-0.3699948910 -0.4790810838 -0.7959805875
+-0.6672097581 -0.2368765739  0.7062015487
+ 0.8324770646  0.1197554578  0.5409626302
+-0.6675126287  0.5116505870  0.5409626302
+ 0.4660769426 -0.5329649671  0.7062015487
+ 0.0883725112 -0.5988365416 -0.7959805875
+-0.2922587145 -0.6448753495  0.7062015487
+-0.6672097581  0.2368765739  0.7062015487
+ 0.7719508391  0.5856635302  0.2471641790
+ 0.4639966765 -0.7751694770 -0.4287416077
+ 0.4639966765  0.7751694770 -0.4287416077
+ 0.7719508391 -0.5856635302  0.2471641790
+ 0.1640284216 -0.8884116786 -0.4287416077
+ 0.1634158680  0.6254788577 -0.7629360738
+-0.5776256146 -0.6946432777 -0.4287416077
+ 0.7239072399  0.1089797474 -0.6812354385
+ 0.9573414162  0.1496906193  0.2471641790
+-0.4246121066  0.8491824202  0.3139964587
+-0.5949197891 -0.2529802202 -0.7629360738
+ 0.3170419295 -0.8949249348  0.3139964587
+-0.2548514500 -0.3832743477  0.8877789775
+-0.8776864208 -0.0000000000 -0.4792353772
+-0.2548514500  0.3832743477  0.8877789775
+-0.7254217428 -0.6728494848 -0.1450409111
+ 0.2582173913 -0.1829926907  0.9485976249
+-0.9980199890  0.0131730113  0.0615026278
+-0.5400311657  0.8290533603 -0.1450409111
+ 0.4846651202  0.2204107171  0.8464743570
+-0.0709753758 -0.9955801941  0.0615026278
+ 0.0229317766  0.1398845177 -0.9899022453
+ 0.8076938496  0.3434590203 -0.4792353772
+ 0.0262977179  0.5317796470  0.8464743570
+ 0.9516406439 -0.2960883932 -0.0819252605
+ 0.1085698247  0.9689378780  0.2221980688
+-0.2763633567  0.7320613041 -0.6226632655
+ 0.7613145044 -0.4132095093 -0.4996580098
+ 0.2099866077  0.9742658140 -0.0819252605
+ 0.1401812208 -0.3162174531 -0.9382727469
+-0.6959163498 -0.6395474135  0.3266183398
+-0.9330524663  0.2829153818  0.2221980688
+ 0.5310965183  0.7818292322  0.3266183398
+-0.7386751889  0.4524387678 -0.4996580098
+-0.4475438832 -0.8410410515  0.3038987040
+-0.2811491679  0.0431081729 -0.9586953796
+-0.8643913313 -0.2155621938  0.4542692670
+ 0.4802495600  0.5116505870  0.7124423043
+ 0.8209889390 -0.3458563213  0.4542692670
+-0.2034129914  0.8143987354  0.5434867567
+ 0.1802813051 -0.6781774208  0.7124423043
+ 0.5734078824 -0.3353176516 -0.7475061691
+ 0.4705702928 -0.8817519234  0.0328198885
+ 0.3836942965  0.4026708396 -0.8310444524
+-0.9121320599 -0.2694460771 -0.3088914320
+ 0.5471106816  0.7084162097  0.4458882998
+ 0.1585623966  0.6069020586  0.4458882998
+-0.1306762499  0.8854983579  0.4458882998
+-0.8237082743 -0.3502689009  0.4458882998
+ 0.5471106816 -0.7084162097  0.4458882998
+ 0.2705130889 -0.3502689009 -0.8967353934
+ 0.3101487853 -0.0000000000 -0.7043410035
+ 0.2705130889  0.3502689009 -0.8967353934
+-0.9604690280  0.1731867527 -0.2179577823
+-0.0615354041  0.6208598148  0.7815027091
+ 0.3573599567  0.5114170284  0.7815027091
+ 0.9224380568 -0.3187513710 -0.2179577823
+-0.0646114894  0.4378252958 -0.8967353934
+-0.7910432524 -0.5716161107 -0.2179577823
+-0.7056730782 -0.3000763028  0.0653317492
+-0.9604690280 -0.1731867527 -0.2179577823
+-0.1982961578  0.9730547528  0.1176566270
+ 0.6473614019  0.2164780859 -0.7307943990
+ 0.6473614019 -0.2164780859 -0.7307943990
+-0.1982961578 -0.9730547528  0.1176566270
+-0.0527175450 -0.6819118559  0.3528535099
+ 0.2461720631 -0.7517075429  0.6118292942
+ 0.8671240119 -0.1070352996 -0.4864559514
+ 0.2454877182  0.9396111859  0.2384671877
+-0.8086646931  0.3307899962 -0.4864559514
+-0.5824039347 -0.5352294570  0.6118292942
+ 0.4577817420 -0.8362546538 -0.3018510074
+ 0.5750948931 -0.4964545016 -0.1228304115
+ 0.5632615562 -0.8178589961  0.1176566270
+ 0.1797689355  0.2646385431  0.9474437035
+-0.9806571218 -0.0363866537  0.1923216597
+-0.7065204582 -0.6810588971  0.1923216597
+ 0.3153129089 -0.0541128280  0.9474437035
+ 0.4814093527 -0.1213684016  0.5880503928
+ 0.7334393435 -0.4281941574  0.5279360691
+-0.4997822658 -0.8660194532 -0.0150994524
+ 0.0376080229 -0.0000000000 -0.9992925681
+-0.4997822658  0.8660194532 -0.0150994524
+ 0.7334393435  0.4281941574  0.5279360691
+-0.1557358302 -0.6543033817  0.7400225914
+-0.4304322977 -0.7911034807  0.4346070868
+-0.5013032036 -0.1867132865 -0.8448865289
+-0.4814093527  0.1213684016 -0.5880503928
+-0.2943558888  0.1819512721 -0.9382155111
+ 0.4997822658  0.8660194532  0.0150994524
+ 0.8504349518 -0.4980243781  0.1695054916
+ 0.6797650274 -0.5277891775 -0.5092721195
+ 0.4153963271  0.8513025630 -0.3205149570
+ 0.0527175450  0.6819118559 -0.3528535099
+-0.1583640613  0.7024638389 -0.6938770635
+ 0.3960752728 -0.6013809101 -0.6938770635
+ 0.8604797042 -0.0147168902  0.5092721195
+ 0.6020633561  0.2164780859  0.7685420962
+-0.7654892092  0.4378252958  0.4715244224
+-0.5750948931  0.4964545016  0.1228304115
+-0.9394255243  0.3307899962  0.0897644851
+-0.1797689355 -0.2646385431 -0.9474437035
+ 0.2198683340 -0.9487067242  0.2271859747
+ 0.9191528491  0.2826295391  0.2743694290
+-0.3960752728  0.6013809101  0.6938770635
+-0.4843157361  0.5017858901 -0.7166932316
+-0.8191635253 -0.0947258962 -0.5656837662
+-0.5616372200  0.3064419676  0.7685420962
+-0.3101487853 -0.0000000000  0.7043410035
+-0.3882607088 -0.3679950751  0.8448865289
+-0.7334393435 -0.4281941574 -0.5279360691
+-0.2833476244  0.9005462671 -0.3297431494
+ 0.0712557971  0.9925336575 -0.0989926775
+-0.8671240119  0.1070352996  0.4864559514
+ 0.3965077344 -0.4525421860  0.7987410009
+ 0.1666692405 -0.8178589961 -0.5507522372
+ 0.5824039347  0.5352294570 -0.6118292942
+-0.7752096022  0.5954285393 -0.2109856093
+-0.4937747326  0.7686152920  0.4067149449
+ 0.7215564288  0.6208598148 -0.3064137896
+ 0.7056730782  0.3000763028 -0.0653317492
+ 0.8755232855  0.2333858350 -0.4230721316
+ 0.1982961578 -0.9730547528 -0.1176566270
+-0.0585650429 -0.1278384441  0.9900643757
+-0.1657176196  0.2889865716  0.9428809214
+ 0.9604690280 -0.1731867527  0.2179577823
+ 0.2734834501  0.6720295560 -0.6881737269
+-0.4581201091 -0.5411818279 -0.7051582764
+-0.1585623966 -0.6069020586 -0.4458882998
+-0.5045884113 -0.7880941967 -0.3525593176
+ 0.0646114894 -0.4378252958  0.8967353934
+ 0.9976445893  0.0243480286 -0.0641283625
+ 0.7485209820  0.6512940977  0.1246288001
+-0.5471106816  0.7084162097 -0.4458882998
+-0.6991764131 -0.0995950201  0.7079782309
+-0.1184473574 -0.9590900905 -0.2571311373
+-0.0432600651 -0.5595774856 -0.8276482371
+3 0 2 1 
+5 0 3 10 9 2 3
+3 0 4 3 
+3 0 5 4 
+3 0 1 5 
+3 1 6 5 
+5 1 7 17 16 6 3
+3 1 2 7 
+3 2 8 7 
+3 2 9 8 
+3 3 11 10 
+3 3 12 11 
+3 3 4 12 
+3 4 13 12 
+5 4 5 14 25 13 3
+3 5 6 14 
+3 6 15 14 
+3 6 16 15 
+3 7 18 17 
+3 7 8 18 
+5 8 19 31 30 18 3
+3 8 9 19 
+3 9 20 19 
+3 9 10 20 
+3 10 21 20 
+3 10 11 21 
+3 11 22 21 
+5 11 12 23 35 22 3
+3 12 13 23 
+3 13 24 23 
+3 13 25 24 
+3 14 26 25 
+3 14 15 26 
+5 15 27 39 38 26 3
+3 15 16 27 
+3 16 28 27 
+3 16 17 28 
+3 17 29 28 
+3 17 18 29 
+3 18 30 29 
+3 19 32 31 
+3 19 20 32 
+5 20 21 33 44 32 3
+3 21 22 33 
+3 22 34 33 
+3 22 35 34 
+3 23 36 35 
+3 23 24 36 
+5 24 37 48 47 36 3
+3 24 25 37 
+3 25 26 37 
+3 26 38 37 
+3 27 40 39 
+3 27 28 40 
+5 28 29 41 51 40 3
+3 29 30 41 
+3 30 42 41 
+3 30 31 42 
+3 31 43 42 
+3 31 32 43 
+3 32 44 43 
+3 33 45 44 
+3 33 34 45 
+5 34 46 55 54 45 3
+3 34 35 46 
+3 35 36 46 
+3 36 47 46 
+3 37 38 48 
+3 38 49 48 
+3 38 39 49 
+3 39 50 49 
+3 39 40 50 
+3 40 51 50 
+3 41 52 51 
+3 41 42 52 
+5 42 43 53 58 52 3
+3 43 44 53 
+3 44 45 53 
+3 45 54 53 
+3 46 47 55 
+3 47 56 55 
+3 47 48 56 
+3 48 49 56 
+5 49 50 57 59 56 3
+3 50 51 57 
+3 51 52 57 
+3 52 58 57 
+3 53 54 58 
+3 54 59 58 
+3 54 55 59 
+3 55 56 59 
+3 57 58 59 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 1 10 11 12 2 
+5 12 13 14 3 2 
+5 14 15 5 4 3 
+5 15 16 17 6 5 
+5 6 18 19 8 7 
+5 19 20 21 9 8 
+5 21 22 23 1 9 
+5 23 24 25 10 1 
+5 25 26 27 11 10 
+5 27 28 13 12 11 
+5 28 29 30 14 13 
+5 14 31 32 16 15 
+5 32 33 34 17 16 
+5 34 35 36 6 17 
+5 36 37 38 18 6 
+5 38 39 20 19 18 
+5 20 40 41 22 21 
+5 41 42 24 23 22 
+5 42 43 26 25 24 
+5 43 44 45 27 26 
+5 27 46 47 29 28 
+5 47 48 49 30 29 
+5 49 50 31 14 30 
+5 50 51 33 32 31 
+5 33 52 53 35 34 
+5 53 54 37 36 35 
+5 54 55 39 38 37 
+5 55 56 57 20 39 
+5 57 58 59 40 20 
+5 59 60 42 41 40 
+5 42 61 62 44 43 
+5 62 63 64 45 44 
+5 64 65 46 27 45 
+5 65 66 48 47 46 
+5 48 67 51 50 49 
+5 67 68 69 33 51 
+5 69 70 71 52 33 
+5 71 72 54 53 52 
+5 54 73 74 56 55 
+5 74 75 58 57 56 
+5 75 76 60 59 58 
+5 76 77 61 42 60 
+5 77 78 63 62 61 
+5 63 79 66 65 64 
+5 79 80 81 48 66 
+5 81 82 68 67 48 
+5 82 83 70 69 68 
+5 83 84 72 71 70 
+5 84 85 73 54 72 
+5 85 86 75 74 73 
+5 75 87 78 77 76 
+5 87 88 89 63 78 
+5 89 90 80 79 63 
+5 90 83 82 81 80 
+5 83 91 86 85 84 
+5 91 88 87 75 86 
+5 88 89 90 83 91 
+great dodecahemidodecahedron
+great dodecahemidodecacron
+5/3 5/2|5/3
+(10/3.5/3.10/3.5/2)
+icosahedral group
+A5
+6{10/3}+6{5/2}+6{5/3}
+74 30 60 18 30 0 1 1 -12 3 4 120 5 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9510565163  0.0000000000 -0.3090169944
+-0.9510565163  0.0000000000 -0.3090169944
+-0.4253254042  0.8506508084 -0.3090169944
+ 0.4253254042 -0.8506508084 -0.3090169944
+-0.5877852523 -0.0000000000 -0.8090169944
+-0.1624598481 -0.8506508084  0.5000000000
+ 0.1624598481  0.8506508084  0.5000000000
+ 0.5877852523 -0.0000000000 -0.8090169944
+ 0.2628655561 -0.5257311121 -0.8090169944
+-0.6881909602 -0.5257311121  0.5000000000
+ 0.6881909602  0.5257311121  0.5000000000
+-0.2628655561  0.5257311121 -0.8090169944
+ 0.5257311121  0.8506508084 -0.0000000000
+-0.5877852523 -0.0000000000  0.8090169944
+-0.8506508084  0.5257311121 -0.0000000000
+ 0.8506508084 -0.5257311121  0.0000000000
+ 0.5877852523  0.0000000000  0.8090169944
+-0.5257311121 -0.8506508084 -0.0000000000
+ 0.2628655561 -0.5257311121  0.8090169944
+-0.2628655561  0.5257311121  0.8090169944
+ 0.9510565163  0.0000000000  0.3090169944
+-0.1624598481 -0.8506508084 -0.5000000000
+ 0.6881909602  0.5257311121 -0.5000000000
+ 0.1624598481  0.8506508084 -0.5000000000
+-0.6881909602 -0.5257311121 -0.5000000000
+-0.9510565163 -0.0000000000  0.3090169944
+-0.4253254042  0.8506508084  0.3090169944
+ 0.4253254042 -0.8506508084  0.3090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-0.7236067977  0.4472135955  0.5257311121
+-0.8944271910 -0.4472135955  0.0000000000
+ 0.7236067977 -0.4472135955  0.5257311121
+-0.2763932023 -0.4472135955 -0.8506508084
+ 0.2763932023  0.4472135955 -0.8506508084
+-0.2763932023 -0.4472135955 -0.8506508084
+-0.2763932023 -0.4472135955  0.8506508084
+ 0.7236067977 -0.4472135955 -0.5257311121
+-0.8944271910 -0.4472135955 -0.0000000000
+ 0.8944271910  0.4472135955 -0.0000000000
+-0.7236067977  0.4472135955 -0.5257311121
+ 0.0000000000 -1.0000000000 -0.0000000000
+-0.0000000000  1.0000000000 -0.0000000000
+ 0.2763932023  0.4472135955  0.8506508084
+-0.2763932023 -0.4472135955  0.8506508084
+ 0.7236067977 -0.4472135955 -0.5257311121
+-0.7236067977  0.4472135955 -0.5257311121
+10 0 1 5 14 21 29 26 17 8 2 3
+5 0 2 7 10 3 3
+10 0 3 9 19 27 29 28 20 12 4 3
+5 0 1 6 11 4 2
+10 1 6 15 23 28 26 24 16 10 3 3
+5 1 3 9 13 5 3
+5 2 8 18 12 4 2
+10 2 4 11 15 22 21 27 25 16 7 3
+10 5 13 19 25 24 17 18 12 11 6 3
+5 5 6 15 22 14 2
+5 7 16 24 17 8 2
+10 7 8 18 20 23 22 14 13 9 10 3
+5 9 10 16 25 19 3
+5 11 15 23 20 12 3
+5 13 14 21 27 19 2
+5 17 26 28 20 18 2
+5 21 22 23 28 29 2
+5 24 26 29 27 25 3
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 1 4 5 2 
+4 6 2 3 7 
+4 5 8 9 0 
+4 3 8 9 4 
+4 10 7 1 11 
+4 10 0 6 11 
+4 5 11 12 2 
+4 12 4 1 11 
+4 13 7 3 8 
+4 13 2 6 8 
+4 14 11 5 8 
+4 9 11 14 0 
+4 9 7 13 4 
+4 12 7 10 4 
+4 15 0 10 8 
+4 15 11 6 8 
+4 12 8 14 2 
+4 15 2 13 11 
+4 14 7 16 0 
+4 16 11 9 7 
+4 16 4 13 11 
+4 17 4 10 8 
+4 17 7 12 8 
+4 17 0 15 4 
+4 17 2 14 7 
+4 16 2 15 4 
+4 16 0 17 2 
+great icosihemidodecahedron
+great icosihemidodecacron
+3/2 3|5/3
+(10/3.3/2.10/3.3)
+icosahedral group
+A5
+6{10/3}+10{3}+10{3/2}
+75 30 60 26 30 0 1 1 -4 3 4 120 5 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9510565163  0.0000000000 -0.3090169944
+-0.9510565163  0.0000000000 -0.3090169944
+ 0.4253254042  0.8506508084 -0.3090169944
+-0.4253254042 -0.8506508084 -0.3090169944
+-0.5877852523  0.0000000000 -0.8090169944
+-0.1624598481  0.8506508084  0.5000000000
+ 0.1624598481 -0.8506508084  0.5000000000
+ 0.5877852523 -0.0000000000 -0.8090169944
+-0.2628655561 -0.5257311121 -0.8090169944
+ 0.6881909602 -0.5257311121  0.5000000000
+-0.6881909602  0.5257311121  0.5000000000
+ 0.2628655561  0.5257311121 -0.8090169944
+ 0.5257311121 -0.8506508084 -0.0000000000
+-0.5877852523 -0.0000000000  0.8090169944
+-0.8506508084 -0.5257311121 -0.0000000000
+ 0.8506508084  0.5257311121  0.0000000000
+ 0.5877852523  0.0000000000  0.8090169944
+-0.5257311121  0.8506508084 -0.0000000000
+-0.2628655561 -0.5257311121  0.8090169944
+ 0.2628655561  0.5257311121  0.8090169944
+ 0.9510565163  0.0000000000  0.3090169944
+-0.1624598481  0.8506508084 -0.5000000000
+ 0.6881909602 -0.5257311121 -0.5000000000
+-0.6881909602  0.5257311121 -0.5000000000
+ 0.1624598481 -0.8506508084 -0.5000000000
+-0.9510565163 -0.0000000000  0.3090169944
+ 0.4253254042  0.8506508084  0.3090169944
+-0.4253254042 -0.8506508084  0.3090169944
+ 0.0000000000 -0.0000000000 -1.0000000000
+ 0.0000000000  1.0000000000  0.0000000000
+-0.4911234732  0.7946544723  0.3568220898
+-0.8944271910  0.4472135955  0.0000000000
+ 0.4911234732 -0.7946544723  0.3568220898
+-0.2763932023  0.4472135955 -0.8506508084
+ 0.1875924741  0.7946544723 -0.5773502692
+-0.1875924741 -0.7946544723 -0.5773502692
+-0.2763932023  0.4472135955  0.8506508084
+ 0.7946544723 -0.1875924741 -0.5773502692
+-0.7946544723  0.1875924741 -0.5773502692
+ 0.7236067977  0.4472135955 -0.5257311121
+-0.6070619982 -0.7946544723 -0.0000000000
+-0.3035309991 -0.1875924741  0.9341723590
+ 0.7236067977  0.4472135955  0.5257311121
+ 0.3035309991  0.1875924741  0.9341723590
+ 0.6070619982  0.7946544723 -0.0000000000
+-0.9822469464 -0.1875924741 -0.0000000000
+ 0.9822469464  0.1875924741 -0.0000000000
+ 0.1875924741  0.7946544723  0.5773502692
+-0.3035309991 -0.1875924741 -0.9341723590
+ 0.3035309991  0.1875924741 -0.9341723590
+-0.1875924741 -0.7946544723  0.5773502692
+ 0.7946544723 -0.1875924741  0.5773502692
+-0.7946544723  0.1875924741  0.5773502692
+ 0.4911234732 -0.7946544723 -0.3568220898
+-0.4911234732  0.7946544723 -0.3568220898
+10 0 1 5 14 21 29 26 17 8 2 3
+3 0 2 3 2
+10 0 3 9 19 27 29 28 20 12 4 3
+3 0 1 4 
+10 1 4 11 16 25 26 27 23 15 6 3
+3 1 6 5 2
+3 2 8 7 
+10 2 7 16 24 28 21 22 15 10 3 3
+3 3 10 9 
+3 4 12 11 2
+10 5 6 10 9 18 17 25 24 20 13 3
+3 5 13 14 
+3 6 15 10 
+10 7 8 18 19 23 22 14 13 12 11 3
+3 7 11 16 2
+3 8 17 18 2
+3 9 18 19 2
+3 12 20 13 
+3 14 22 21 2
+3 15 23 22 2
+3 16 25 24 
+3 17 26 25 
+3 19 23 27 
+3 20 28 24 2
+3 21 28 29 
+3 26 29 27 2
+4 3 0 1 2 
+4 3 4 5 0 
+4 6 0 1 7 
+4 8 7 1 2 
+4 9 2 3 4 
+4 5 10 11 0 
+4 12 4 5 10 
+4 6 13 14 7 
+4 15 0 6 13 
+4 8 10 16 2 
+4 12 7 8 10 
+4 9 13 14 4 
+4 17 2 9 13 
+4 17 10 11 13 
+4 18 13 11 0 
+4 19 4 12 7 
+4 20 4 14 7 
+4 21 0 15 10 
+4 16 13 15 10 
+4 22 13 16 2 
+4 23 2 17 10 
+4 18 7 24 0 
+4 19 13 18 7 
+4 22 4 19 13 
+4 20 10 23 7 
+4 21 4 20 10 
+4 25 0 21 4 
+4 25 2 22 4 
+4 24 2 23 7 
+4 24 0 25 2 
+small retrosnub icosicosidodecahedron
+small hexagrammic hexecontahedron
+|3/2 3/2 5/2
+(3.3/2.3.3/2.3.5/2)
+icosahedral group
+A5
+60{3}+12{5/2}+40{3/2}
+76 60 180 112 60 38 0 0 -8 3 6 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8757465433  0.0000000000 -0.4827711589
+-0.8174044834 -0.3142959094 -0.4827711589
+ 0.6501517764  0.5867151573 -0.4827711589
+-0.3962731062 -0.7809607118 -0.4827711589
+ 0.0895951656  0.8711513729 -0.4827711589
+ 0.2290203992 -0.8452701727 -0.4827711589
+-0.3122207301 -0.8452701727  0.4336318148
+-0.3795312117  0.8711513729  0.3115306484
+-0.6140944004 -0.7809607118 -0.1139668111
+-0.1089106471  0.5867151573  0.8024361627
+ 0.8534618594 -0.5085414639 -0.1139668111
+ 0.3122207301 -0.5085414639  0.8024361627
+-0.9791144009  0.1683643544 -0.1139668111
+ 0.3018736703 -0.9010110667  0.3115306484
+ 0.9485998144 -0.0557408940  0.3115306484
+-0.4185577901  0.9010110667 -0.1139668111
+ 0.5724942349 -0.1683643544  0.8024361627
+ 0.7140366257 -0.6907700508 -0.1139668111
+-0.5947789188 -0.0483139995  0.8024361627
+ 0.5931883546  0.7969561732 -0.1139668111
+-0.9400878225  0.1385046605  0.3115306484
+ 0.7342041525  0.5224056964  0.4336318148
+-0.1810253991  0.1385046605 -0.9736766732
+ 0.1865681885  0.7969561732  0.5745025405
+ 0.4155885877 -0.0483139995 -0.9082686184
+ 0.2449102485 -0.6907700508  0.6803349963
+ 0.9791144009 -0.1683643544  0.1139668111
+-0.3018736703  0.9010110667 -0.3115306484
+ 0.7307785202 -0.0557408940  0.6803349963
+ 0.4185577901 -0.9010110667  0.1139668111
+-0.5724942349  0.1683643544 -0.8024361627
+-0.4155885877  0.0483139995  0.9082686184
+-0.2449102485  0.6907700508 -0.6803349963
+-0.7204314604 -0.3884911091  0.5745025405
+ 0.1553150829 -0.3884911091 -0.9082686184
+-0.7140366257  0.6907700508  0.1139668111
+ 0.5947789188  0.0483139995 -0.8024361627
+ 0.3795312117 -0.8711513729 -0.3115306484
+ 0.6140944004  0.7809607118  0.1139668111
+-0.7307785202  0.0557408940 -0.6803349963
+-0.5931883546 -0.7969561732  0.1139668111
+ 0.9400878225 -0.1385046605 -0.3115306484
+ 0.1089106471 -0.5867151573 -0.8024361627
+-0.8534618594  0.5085414639  0.1139668111
+-0.1553150829  0.3884911091  0.9082686184
+-0.3122207301  0.5085414639 -0.8024361627
+-0.9485998144  0.0557408940 -0.3115306484
+ 0.7204314604  0.3884911091 -0.5745025405
+-0.6501517764 -0.5867151573  0.4827711589
+ 0.1810253991 -0.1385046605  0.9736766732
+-0.1865681885 -0.7969561732 -0.5745025405
+ 0.3962731062  0.7809607118  0.4827711589
+-0.0895951656 -0.8711513729  0.4827711589
+ 0.3122207301  0.8452701727 -0.4336318148
+-0.2290203992  0.8452701727  0.4827711589
+-0.8757465433  0.0000000000  0.4827711589
+-0.7342041525 -0.5224056964 -0.4336318148
+ 0.8174044834  0.3142959094  0.4827711589
+-0.0000000000 -0.0000000000 -1.0000000000
+ 0.1814588279 -0.9775412010  0.1071722635
+-0.5201989819  0.8472940016  0.1071722635
+ 0.7896280312 -0.6041536876  0.1071722635
+-0.9538473568  0.2805161775  0.1071722635
+ 0.9909764414  0.0804971962  0.1071722635
+ 0.1814588279 -0.1388362820  0.1071722635
+ 0.5722705843  0.0804971962  0.8161045152
+-0.3666342546  0.2805161775 -0.8870682034
+ 0.4750653790 -0.6041536876  0.6397743410
+-0.1572813261  0.8472940016 -0.5073021381
+-0.2265924308 -0.7344008871  0.6397743410
+-0.0257718743 -0.2505849906 -0.0152212496
+ 0.4508878772 -0.7344008871 -0.5073021381
+-0.0520716024  0.7667968054  0.6397743410
+-0.0842536226 -0.4538847096 -0.8870682034
+ 0.1572813261 -0.1203377912 -0.1564292618
+ 0.4160557770  0.2000189813 -0.8870682034
+-0.7537294122 -0.1502689781  0.6397743410
+ 0.8267571157 -0.2431403140 -0.5073021381
+ 0.2351248029  0.0904066044 -0.0152212496
+ 0.6495862074  0.4107633769  0.6397743410
+-0.8589391359 -0.0697717819 -0.5073021381
+ 0.7073653437 -0.3005379561  0.6397743410
+-0.3666342546  0.2805161775 -0.8870682034
+ 0.0719611847 -0.5734064947  0.8161045152
+ 0.7494414927 -0.5734064947 -0.3309719638
+-0.9538473568  0.2805161775  0.1071722635
+ 0.9017757544 -0.3005379561  0.3106081546
+-0.8589391359 -0.0697717819 -0.5073021381
+ 0.8738816538  0.4107633769  0.2600082756
+ 0.1001815169  0.0904066044  0.2132581137
+-0.0451336029 -0.2431403140  0.9689405274
+ 0.1964013458 -0.1502689781 -0.9689405274
+-0.5759871832  0.2000189813  0.7926103532
+-0.0610614972 -0.1203377912  0.2132581137
+-0.8175221318 -0.4538847096  0.3544661259
+ 0.5351414998  0.7667968054 -0.3544661259
+-0.4187058571 -0.9077694191 -0.0252999395
+ 0.6001646849  0.7170468022  0.3544661259
+-0.3479751379 -0.6415295512 -0.6836323123
+-0.7666809950 -0.6415295512  0.0252999395
+ 0.6001646849  0.7170468022  0.3544661259
+-0.2242954464 -0.9077694191 -0.3544661259
+-0.1001815169 -0.0904066044 -0.2132581137
+ 0.0451336029  0.2431403140 -0.9689405274
+-0.1964013458  0.1502689781  0.9689405274
+ 0.5759871832 -0.2000189813 -0.7926103532
+-0.7537294122 -0.1502689781  0.6397743410
+ 0.9561443412  0.1071476454 -0.2725938019
+ 0.1466267277 -0.9508907518 -0.2725938019
+-0.0520716024  0.7667968054  0.6397743410
+ 0.3436872184 -0.5036347128 -0.7926103532
+-0.1964013458  0.1502689781  0.9689405274
+-0.2228758320 -0.1071476454 -0.9689405274
+ 0.0610614972  0.1203377912 -0.2132581137
+ 0.8175221318  0.4538847096 -0.3544661259
+-0.5351414998 -0.7667968054  0.3544661259
+ 0.4187058571  0.9077694191  0.0252999395
+ 0.5282035002  0.5036347128 -0.6836323123
+-0.5351414998 -0.7667968054  0.3544661259
+ 0.7666809950  0.6415295512 -0.0252999395
+-0.6001646849 -0.7170468022 -0.3544661259
+ 0.2242954464  0.9077694191  0.3544661259
+-0.3436872184  0.5036347128  0.7926103532
+ 0.1964013458 -0.1502689781 -0.9689405274
+ 0.2228758320  0.1071476454  0.9689405274
+-0.1679359245 -0.9508907518  0.2600082756
+-0.1572813261  0.8472940016 -0.5073021381
+ 0.5259065158 -0.7917985292  0.3106081546
+-0.5201989819  0.8472940016  0.1071722635
+-0.6001646849 -0.7170468022 -0.3544661259
+ 0.3479751379  0.6415295512  0.6836323123
+ 0.0520716024 -0.7667968054 -0.6397743410
+ 0.0520716024 -0.7667968054 -0.6397743410
+ 0.0842536226  0.4538847096  0.8870682034
+-0.1572813261  0.1203377912  0.1564292618
+-0.9561443412 -0.1071476454  0.2725938019
+ 0.7537294122  0.1502689781 -0.6397743410
+-0.5282035002 -0.5036347128  0.6836323123
+ 0.5351414998  0.7667968054 -0.3544661259
+-0.4160557770 -0.2000189813  0.8870682034
+ 0.7537294122  0.1502689781 -0.6397743410
+-0.8267571157  0.2431403140  0.5073021381
+-0.2351248029 -0.0904066044  0.0152212496
+-0.9017757544  0.3005379561 -0.3106081546
+ 0.8589391359  0.0697717819  0.5073021381
+-0.8738816538 -0.4107633769 -0.2600082756
+-0.6495862074 -0.4107633769 -0.6397743410
+ 0.8589391359  0.0697717819  0.5073021381
+-0.7073653437  0.3005379561 -0.6397743410
+-0.5722705843 -0.0804971962 -0.8161045152
+ 0.3666342546 -0.2805161775  0.8870682034
+-0.4750653790  0.6041536876 -0.6397743410
+ 0.1679359245  0.9508907518 -0.2600082756
+ 0.3666342546 -0.2805161775  0.8870682034
+-0.0719611847  0.5734064947 -0.8161045152
+ 0.1572813261 -0.8472940016  0.5073021381
+ 0.1572813261 -0.8472940016  0.5073021381
+ 0.2265924308  0.7344008871 -0.6397743410
+ 0.0257718743  0.2505849906  0.0152212496
+-0.5259065158  0.7917985292 -0.3106081546
+-0.4508878772  0.7344008871  0.5073021381
+-0.1466267277  0.9508907518  0.2725938019
+ 0.5201989819 -0.8472940016 -0.1071722635
+ 0.5201989819 -0.8472940016 -0.1071722635
+-0.7896280312  0.6041536876 -0.1071722635
+-0.7494414927  0.5734064947  0.3309719638
+ 0.9538473568 -0.2805161775 -0.1071722635
+ 0.9538473568 -0.2805161775 -0.1071722635
+-0.9909764414 -0.0804971962 -0.1071722635
+-0.1814588279  0.1388362820 -0.1071722635
+-0.1814588279  0.9775412010 -0.1071722635
+3 0 2 1 
+3 0 3 2 2
+3 0 4 3 
+3 0 5 4 2
+3 0 6 5 
+5 0 1 7 22 6 2
+3 1 8 7 
+3 1 9 8 2
+3 1 10 9 
+3 1 2 10 2
+3 2 11 10 
+5 2 12 35 34 11 2
+3 2 3 12 
+3 3 13 12 2
+3 3 14 13 
+5 3 4 15 23 14 2
+3 4 16 15 
+3 4 17 16 2
+3 4 5 17 
+5 5 18 24 25 17 2
+3 5 19 18 
+3 5 6 19 2
+3 6 20 19 
+3 6 21 20 2
+3 6 22 21 
+3 7 23 22 
+3 7 24 23 2
+3 7 25 24 
+3 7 8 25 2
+3 8 26 25 
+5 8 27 19 20 26 2
+3 8 9 27 
+3 9 28 27 2
+3 9 29 28 
+5 9 10 30 21 29 2
+3 10 31 30 
+3 10 11 31 2
+3 11 32 31 
+3 11 33 32 2
+3 11 34 33 
+3 12 36 35 
+3 12 37 36 2
+3 12 13 37 
+5 13 38 33 41 37 2
+3 13 39 38 
+3 13 14 39 2
+3 14 40 39 
+3 14 24 40 2
+3 14 23 24 
+3 15 34 23 
+3 15 33 34 2
+3 15 41 33 
+3 15 16 41 2
+3 16 42 41 
+5 16 43 39 40 42 2
+3 16 17 43 
+3 17 44 43 2
+3 17 25 44 
+3 18 40 24 
+3 18 45 40 2
+3 18 46 45 
+3 18 19 46 2
+3 19 27 46 
+3 20 47 26 
+3 20 30 47 2
+3 20 21 30 
+3 21 35 29 
+3 21 22 35 2
+3 22 34 35 
+3 22 23 34 2
+3 25 26 44 2
+3 26 48 44 
+3 26 47 48 2
+3 27 49 46 2
+3 27 28 49 
+5 28 50 47 52 49 2
+3 28 51 50 
+3 28 29 51 2
+3 29 36 51 
+3 29 35 36 2
+3 30 52 47 
+3 30 31 52 2
+3 31 53 52 
+5 31 32 51 36 53 2
+3 32 54 51 
+3 32 38 54 2
+3 32 33 38 
+3 36 37 53 
+3 37 55 53 2
+3 37 41 55 
+3 38 56 54 
+3 38 39 56 2
+3 39 43 56 
+3 40 45 42 
+3 41 42 55 2
+3 42 57 55 
+3 42 45 57 2
+3 43 58 56 2
+3 43 44 58 
+5 44 48 45 46 58 2
+3 45 48 57 
+3 46 49 58 
+3 47 50 48 
+3 48 50 57 2
+3 49 59 58 2
+3 49 52 59 
+3 50 54 57 
+3 50 51 54 2
+3 52 53 59 2
+3 53 55 59 
+5 54 56 59 55 57 2
+3 56 58 59 
+6 5 0 1 2 3 4 
+6 5 6 7 8 9 0 
+6 9 10 11 12 1 0 
+6 12 13 14 15 2 1 
+6 15 16 17 18 3 2 
+6 18 19 20 21 4 3 
+6 21 22 23 24 5 4 
+6 5 25 26 27 28 6 
+6 28 29 30 31 7 6 
+6 31 32 33 34 8 7 
+6 34 35 36 10 9 8 
+6 36 37 38 39 11 10 
+6 11 40 41 42 13 12 
+6 42 43 44 45 14 13 
+6 45 46 47 48 15 14 
+6 15 49 50 51 52 16 
+6 52 53 54 55 17 16 
+6 55 56 57 19 18 17 
+6 19 58 59 60 61 20 
+6 61 62 30 22 21 20 
+6 30 63 64 65 23 22 
+6 65 34 66 67 24 23 
+6 67 68 69 25 5 24 
+6 69 49 15 48 26 25 
+6 47 58 19 27 26 48 
+6 57 70 29 28 27 19 
+6 70 71 72 63 30 29 
+6 62 73 74 32 31 30 
+6 74 75 76 77 33 32 
+6 77 78 79 66 34 33 
+6 64 80 81 35 34 65 
+6 81 82 83 37 36 35 
+6 83 84 85 86 38 37 
+6 86 43 51 50 39 38 
+6 68 11 39 50 49 69 
+6 79 40 11 68 67 66 
+6 78 83 87 41 40 79 
+6 87 88 89 43 42 41 
+6 85 90 91 44 43 86 
+6 91 92 54 46 45 44 
+6 54 93 59 58 47 46 
+6 89 94 53 52 51 43 
+6 94 95 96 93 54 53 
+6 92 97 98 56 55 54 
+6 98 99 71 70 57 56 
+6 96 100 99 60 59 93 
+6 99 101 73 62 61 60 
+6 72 102 75 80 64 63 
+6 100 103 102 72 71 99 
+6 101 104 105 75 74 73 
+6 103 106 107 76 75 102 
+6 107 84 83 78 77 76 
+6 105 108 82 81 80 75 
+6 108 109 88 87 83 82 
+6 106 110 90 85 84 107 
+6 109 110 95 94 89 88 
+6 110 111 97 92 91 90 
+6 95 96 100 103 106 110 
+6 111 104 101 99 98 97 
+6 104 105 108 109 110 111 
+great rhombidodecahedron
+great rhombidodecacron
+3/2 5/3 2|
+(4.10/3.4/3.10/7)
+icosahedral group
+A5
+15{4}+6{10/3}+6{10/7}+15{4/3}
+77 60 120 42 60 0 0 1 -18 4 4 120 5 0 2
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.9996324920  0.0000000000  0.0271086873
+-0.9468654869  0.3204853643  0.0271086873
+ 0.0263835025 -0.9992842588  0.0271086873
+-0.3453645319  0.9380770007  0.0271086873
+ 0.0527670051  0.3204853643 -0.9457826254
+ 0.0364611038  0.9380770007 -0.3445027268
+-0.3352869307 -0.8768697425 -0.3445027268
+ 0.2398305218  0.7400061526  0.6283885859
+-0.3189810294 -0.0612072581 -0.9457826254
+-0.9367878857 -0.0612072581 -0.3445027268
+ 0.8677149793  0.3583135302 -0.3445027268
+-0.7334184677 -0.2592781062  0.6283885859
+ 0.6216561575  0.7400061526  0.2567771718
+-0.3678987333  0.3583135302  0.8580570704
+ 0.6480396600 -0.2592781062 -0.7161141409
+ 0.8514090780 -0.4573489542  0.2567771718
+ 0.2336022217 -0.4573489542  0.8580570704
+ 0.5060445461  0.4807280465 -0.7161141409
+-0.7233408665 -0.6409707286  0.2567771718
+ 0.2762916255 -0.6409707286 -0.7161141409
+ 0.4796610435 -0.8390415766  0.2567771718
+ 0.4633551422 -0.2214499403  0.8580570704
+-0.4672044434 -0.5185562123 -0.7161141409
+-0.7295691665  0.4807280465  0.4864456563
+ 0.2436798229 -0.8390415766  0.4864456563
+ 0.8451807779 -0.2214499403  0.4864456563
+-0.7031856640 -0.5185562123 -0.4864456563
+-0.4998162460 -0.7166270604  0.4864456563
+ 0.4998162460 -0.7166270604 -0.4864456563
+-0.8451807779  0.2214499403 -0.4864456563
+-0.4998162460  0.7166270604  0.4864456563
+ 0.4998162460  0.7166270604 -0.4864456563
+ 0.7031856640  0.5185562123  0.4864456563
+ 0.7295691665 -0.4807280465 -0.4864456563
+-0.2436798229  0.8390415766 -0.4864456563
+-0.4633551422  0.2214499403 -0.8580570704
+ 0.4672044434  0.5185562123  0.7161141409
+-0.5060445461 -0.4807280465  0.7161141409
+-0.4796610435  0.8390415766 -0.2567771718
+-0.2762916255  0.6409707286  0.7161141409
+ 0.7233408665  0.6409707286 -0.2567771718
+ 0.3678987333 -0.3583135302 -0.8580570704
+-0.2336022217  0.4573489542 -0.8580570704
+-0.8514090780  0.4573489542 -0.2567771718
+-0.6480396600  0.2592781062  0.7161141409
+-0.6216561575 -0.7400061526 -0.2567771718
+-0.8677149793 -0.3583135302  0.3445027268
+ 0.7334184677  0.2592781062 -0.6283885859
+-0.2398305218 -0.7400061526 -0.6283885859
+ 0.9367878857  0.0612072581  0.3445027268
+ 0.3189810294  0.0612072581  0.9457826254
+-0.0364611038 -0.9380770007  0.3445027268
+ 0.3352869307  0.8768697425  0.3445027268
+-0.0527670051 -0.3204853643  0.9457826254
+ 0.3453645319 -0.9380770007 -0.0271086873
+ 0.9468654869 -0.3204853643 -0.0271086873
+-0.0263835025  0.9992842588 -0.0271086873
+-0.9996324920  0.0000000000 -0.0271086873
+ 0.0000000000  0.0000000000 -1.0000000000
+ 0.1602426822  0.9732489895  0.1646471601
+-0.2254435660 -0.1662507751  0.1646471601
+-0.9686806297 -0.1858740172  0.1646471601
+ 0.1602426822  0.2297529205  0.1646471601
+ 0.1908463112 -0.1858740172 -0.9638612635
+ 0.1706981301 -0.1662507751 -0.2208973453
+-0.0716627060  0.3082458890 -0.0736324484
+-0.2898817352 -0.4156269378  0.8621037224
+-0.3100299164  0.0635021454 -0.0736324484
+ 0.4078312422  0.3007504775  0.8621037224
+ 0.8696452057 -0.4156269378 -0.2664047011
+ 0.8507311228  0.3007504775  0.4310518612
+-0.0652008839  0.0635021454 -0.3119120569
+-0.6904884406  0.6724985120 -0.2664047011
+ 0.0652008839 -0.0635021454  0.3119120569
+ 0.4384348713 -0.8583725292 -0.2664047011
+-0.2781921891 -0.8583725292  0.4310518612
+ 0.3100299164 -0.0635021454  0.0736324484
+-0.2475885600  0.6724985120 -0.6974565623
+ 0.0189140829 -0.7163774153 -0.6974565623
+-0.6977129774 -0.7163774153 -0.0000000000
+ 0.0716627060 -0.3082458890  0.0736324484
+-0.6787988945  0.2297529205 -0.6974565623
+ 0.7166270604  0.0000000000 -0.6974565623
+ 0.6977129774  0.7163774153 -0.0000000000
+-0.7166270604  0.0000000000  0.6974565623
+-0.0189140829  0.7163774153  0.6974565623
+ 0.6787988945 -0.2297529205  0.6974565623
+-0.1602426822 -0.2297529205 -0.1646471601
+ 0.2781921891  0.8583725292 -0.4310518612
+ 0.2475885600 -0.6724985120  0.6974565623
+ 0.2254435660  0.1662507751 -0.1646471601
+-0.8507311228 -0.3007504775 -0.4310518612
+-0.4384348713  0.8583725292  0.2664047011
+-0.1706981301  0.1662507751  0.2208973453
+ 0.6904884406 -0.6724985120  0.2664047011
+-0.4078312422 -0.3007504775 -0.8621037224
+-0.8696452057  0.4156269378  0.2664047011
+ 0.2898817352  0.4156269378 -0.8621037224
+-0.1908463112  0.1858740172  0.9638612635
+ 0.9686806297  0.1858740172 -0.1646471601
+-0.1602426822 -0.9732489895 -0.1646471601
+4 0 2 5 1 
+10 0 3 10 14 25 27 24 17 7 2 3
+4 0 4 9 3 3
+10 0 1 6 14 26 32 31 22 11 4 7
+4 1 3 10 6 3
+10 1 5 7 16 18 23 21 11 9 3 3
+10 2 8 18 30 40 41 36 24 13 5 7
+4 2 7 16 8 3
+10 4 12 23 35 45 46 43 31 19 9 3
+4 4 11 21 12 
+4 5 13 17 7 3
+4 6 15 25 14 
+10 6 10 20 32 44 49 48 39 27 15 3
+4 8 12 23 18 
+10 8 16 28 40 50 52 45 33 21 12 3
+4 9 19 22 11 
+4 10 20 26 14 3
+10 13 15 25 37 48 55 51 41 29 17 3
+4 13 24 27 15 
+4 16 18 30 28 
+4 17 24 36 29 3
+10 19 20 26 38 49 56 54 46 34 22 7
+4 19 31 32 20 3
+4 21 23 35 33 3
+4 22 31 43 34 
+4 25 37 39 27 3
+4 26 38 44 32 
+4 28 29 41 40 3
+10 28 30 42 52 58 59 55 47 36 29 7
+4 30 42 50 40 
+4 33 34 46 45 
+10 33 35 42 50 57 59 56 53 43 34 3
+4 35 42 52 45 3
+4 36 41 51 47 
+10 37 38 44 53 54 58 57 51 47 39 3
+4 37 48 49 38 
+4 39 48 55 47 3
+4 43 46 54 53 3
+4 44 49 56 53 
+4 50 57 58 52 3
+4 51 57 59 55 
+4 54 58 59 56 3
+4 3 0 1 2 
+4 3 4 5 0 
+4 0 6 7 1 
+4 1 4 5 2 
+4 2 8 9 3 
+4 5 10 6 0 
+4 3 11 12 4 
+4 7 5 10 1 
+4 6 13 14 7 
+4 5 15 8 2 
+4 1 16 12 4 
+4 9 5 15 3 
+4 8 13 14 9 
+4 10 17 18 6 
+4 3 16 1 11 
+4 11 17 18 12 
+4 14 19 5 7 
+4 17 20 1 10 
+4 6 19 5 13 
+4 15 21 22 8 
+4 16 21 22 12 
+4 14 23 5 9 
+4 21 24 3 15 
+4 8 23 5 13 
+4 18 1 20 6 
+4 1 25 17 11 
+4 3 26 21 16 
+4 25 12 18 1 
+4 14 27 28 19 
+4 17 27 28 20 
+4 6 29 28 19 
+4 22 3 24 8 
+4 26 12 22 3 
+4 14 30 31 23 
+4 21 30 31 24 
+4 8 32 31 23 
+4 28 33 6 20 
+4 25 34 35 17 
+4 26 34 35 21 
+4 34 36 12 25 
+4 14 29 6 27 
+4 17 33 6 27 
+4 29 31 32 28 
+4 31 37 8 24 
+4 34 38 12 26 
+4 14 32 8 30 
+4 21 37 8 30 
+4 28 36 34 33 
+4 35 12 36 17 
+4 38 21 35 12 
+4 14 39 31 29 
+4 17 40 34 33 
+4 39 28 32 14 
+4 31 38 34 37 
+4 21 41 34 37 
+4 28 40 17 36 
+4 31 41 21 38 
+4 39 34 40 31 
+4 41 28 39 34 
+4 28 40 31 41 
+great retrosnub icosidodecahedron
+great pentagrammic hexecontahedron
+|3/2 5/3 2
+(3.3/2.3.5/3.3)
+icosahedral group
+A5
+60{3}+12{5/3}+20{3/2}
+78 60 150 92 60 37 0 0 2 3 5 120 5 0 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.8737818460  0.0000000000 -0.4863180910
+-0.8272355164 -0.2813825063 -0.4863180910
+ 0.6925555704  0.5327865392 -0.4863180910
+-0.4840908004 -0.7274275300 -0.4863180910
+-0.8272355164  0.2813825063 -0.4863180910
+-0.0881336164 -0.5327865392  0.8416477703
+-0.6603580332  0.7274275300 -0.1864844676
+ 0.3909285122  0.9013314827 -0.1864844676
+ 0.2550110996 -0.4760234971  0.8416477703
+-0.3947197174  0.3685449435  0.8416477703
+ 0.9714370516  0.1467433071 -0.1864844676
+-0.5280509481  0.7309574441  0.4322770073
+ 0.0271688654 -0.9013314827  0.4322770073
+ 0.8594330536  0.4760234971 -0.1864844676
+ 0.5434572030 -0.3685449435 -0.7542074602
+ 0.3094806701 -0.1467433071  0.9395148305
+ 0.1209150724 -0.7309574441 -0.6716254612
+-0.2457391435 -0.2385878386  0.9395148305
+-0.3958253444 -0.5239211808 -0.7542074602
+-0.1243023628  0.9920238341  0.0209197322
+ 0.9269841826 -0.3745166086  0.0209197322
+-0.6079004419 -0.2482501956 -0.7542074602
+-0.3554430809 -0.9344637933  0.0209197322
+ 0.7014236118  0.2385878386 -0.6716254612
+-0.8515098127  0.5239211808  0.0209197322
+-0.0421712056 -0.9920238341 -0.1187867923
+ 0.4690884602  0.3745166086  0.7998083060
+-0.9546457693  0.2482501956 -0.1643876381
+-0.1545791184  0.9344637933 -0.3207533555
+ 0.6370715704 -0.5866558879 -0.4999746827
+ 0.7298299438 -0.4103101843  0.5468032605
+-0.7507169498 -0.5775303855 -0.3207533555
+-0.2094526036  0.8106391313  0.5468032605
+ 0.6206411698 -0.6903443834  0.3717918378
+ 0.2121565789  0.4199725414 -0.8823903051
+-0.1270493712  0.5866558879  0.7998083060
+ 0.8327162674  0.4103101843  0.3717918378
+-0.6453556930  0.5775303855 -0.4999746827
+ 0.3759261720 -0.8106391313 -0.4489362004
+ 0.6266939873  0.6903443834  0.3614958903
+-0.6678410472 -0.4199725414  0.6145009358
+ 0.2128398940  0.9715469400  0.1039024685
+-0.9414323712 -0.3088032958  0.1354459853
+ 0.1638510745  0.8784128377 -0.4489362004
+-0.1706686884  0.0204768941 -0.9851156763
+-0.6425523214  0.4577282099  0.6145009358
+ 0.1942959817 -0.9715469400  0.1354459853
+-0.3394853505  0.3088032958 -0.8884763482
+-0.3125885602 -0.8784128377  0.3614958903
+-0.9437754648 -0.0204768941  0.3299523735
+ 0.2244549438 -0.4577282099 -0.8602934756
+ 0.7424891904 -0.6682227370  0.0467779432
+-0.7746867276 -0.0891832664  0.6260246154
+ 0.9191603379 -0.2151178849  0.3299523735
+ 0.4019596432  0.6682227370  0.6260246154
+ 0.1702647736  0.0891832664 -0.9813542948
+ 0.7353106948  0.2151178849  0.6426838084
+-0.1028863235  0.5557051842 -0.8249885773
+-0.7708955225 -0.5557051842  0.3113066683
+ 0.1624562657 -0.9820828321  0.0955053542
+-0.4700607175  0.8774517931  0.0955053542
+ 0.7275849321 -0.6793370989  0.0955053542
+-0.1940488224 -0.0660053188  0.0955053542
+ 0.1624562657  0.9820828321  0.0955053542
+-0.1451481861 -0.8774517931 -0.4571765031
+ 0.4372885599  0.6793370989  0.5893045235
+-0.0109186081  0.0660053188 -0.2160023198
+-0.6327600026  0.5023295310  0.5893045235
+ 0.4199804802 -0.7839681379 -0.4571765031
+ 0.1451481861  0.1116632412  0.1326508383
+-0.6500680822  0.6069605700 -0.4571765031
+ 0.3232856579 -0.7404097257  0.5893045235
+-0.1420677659  0.5244844560 -0.8394836540
+ 0.2072009579 -0.5023295310 -0.8394836540
+-0.1952284234  0.7839681379  0.5893045235
+ 0.1864960831 -0.1116632412  0.0623173475
+-0.7156123975 -0.6069605700 -0.3456844847
+ 0.6721432584  0.7404097257 -0.0041083120
+-0.8026157016 -0.5244844560  0.2841198533
+ 0.9287592421 -0.2380801948  0.2841198533
+-0.8747711150  0.4845189553 -0.0041083120
+ 0.8729502462 -0.3441803374 -0.3456844847
+-0.9253114997 -0.0276453741  0.3781988390
+-0.2639851185 -0.8872865915  0.3781988390
+-0.1088354609  0.9320177463 -0.3456844847
+ 0.0900414998 -0.1398813892 -0.1531621544
+ 0.3069392403 -0.1981146941  0.9308806963
+-0.6354632109  0.1224416147 -0.7623611733
+ 0.6999311915  0.2380801948  0.6733603404
+-0.4290067871 -0.4845189553 -0.7623611733
+ 0.1224786701  0.3441803374  0.9308806963
+-0.1195324424  0.0276453741 -0.9924453277
+ 0.2020825408  0.8872865915 -0.4145903415
+-0.3549814808 -0.9320177463  0.0730141688
+-0.0900414998  0.1398813892  0.1531621544
+ 0.9626567586  0.1981146941 -0.1845061871
+-0.9751746089 -0.1224416147 -0.1845061871
+ 0.8263177513  0.3812005018  0.4145903415
+-0.0231391970 -0.2214684501  0.0393601759
+ 0.7319039452  0.2017076057 -0.6508691550
+-0.5067407650  0.0146004527  0.8619748395
+ 0.1813680862  0.1395273955 -0.9734668578
+-0.1158237709 -0.4935425313  0.8619748395
+ 0.3826352213  0.6557130703 -0.6508691550
+-0.6865649131 -0.4465908350  0.5737466742
+-0.9435278101  0.2518694250 -0.2152139965
+ 0.7641147853 -0.3812005018  0.5203986667
+ 0.0231391970  0.2214684501 -0.0393601759
+-0.2127795223 -0.2017076057  0.9560538252
+ 0.5067407650 -0.0146004527 -0.8619748395
+-0.7623950866 -0.1395273955  0.6318906850
+ 0.6968507713  0.4935425313 -0.5203986667
+-0.3826352213 -0.6557130703  0.6508691550
+ 0.1674404903  0.4465908350 -0.8789313445
+-0.6469047265 -0.2518694250 -0.7197750118
+ 0.6354632109 -0.1224416147  0.7623611733
+-0.3194267921  0.2655619217 -0.9096391539
+-0.1666620447  0.5559875283  0.8143105251
+ 0.4989740095 -0.3819252966 -0.7779190226
+-0.1864960831  0.1116632412 -0.0623173475
+ 0.8394638530  0.4913219899 -0.2321705015
+-0.6721432584 -0.7404097257  0.0041083120
+ 0.6639956781  0.6539122663  0.3626409897
+-0.8240367351 -0.3275425045 -0.4622546559
+ 0.9751746089  0.1224416147  0.1845061871
+-0.9501692068 -0.2655619217  0.1632646447
+ 0.6304789864 -0.5559875283 -0.5416402091
+-0.4370714318  0.3819252966  0.8143105251
+-0.1451481861 -0.1116632412 -0.1326508383
+ 0.2053800891 -0.4913219899  0.8464169902
+-0.3232856579  0.7404097257 -0.5893045235
+ 0.6397822240 -0.6539122663  0.4038284955
+-0.8046536985  0.3275425045 -0.4952255378
+ 0.1940488224  0.0660053188 -0.0955053542
+ 0.0485023878 -0.0191231611  0.9986399867
+-0.1224786701 -0.3441803374 -0.9308806963
+ 0.4594979286  0.4223387451  0.7813396432
+-0.0914262111 -0.9906050450 -0.1017000132
+ 0.3697500488  0.9182285161 -0.1419200256
+ 0.0109186081 -0.0660053188  0.2160023198
+ 0.8961810797  0.0191231611 -0.4432761860
+-0.8729502462  0.3441803374  0.3456844847
+ 0.9061825512 -0.4223387451  0.0215213446
+-0.1333258458  0.9906050450 -0.0304280072
+ 0.0558089959 -0.9182285161  0.3920991561
+-0.4714704631 -0.7039773520 -0.5311605127
+ 0.1451481861  0.8774517931  0.4571765031
+ 0.1583802720 -0.7508056718 -0.6412538753
+-0.6934030289  0.7039773520 -0.1536493650
+ 0.4700607175 -0.8774517931 -0.0955053542
+-0.4832928034  0.7508056718  0.4502431669
+3 0 2 1 
+3 0 3 2 2
+3 0 4 3 
+5 0 5 13 12 4 3
+3 0 1 5 
+3 1 6 5 2
+3 1 7 6 
+5 1 2 8 17 7 3
+3 2 9 8 
+3 2 3 9 
+5 3 10 21 20 9 3
+3 3 4 10 
+3 4 11 10 2
+3 4 12 11 
+3 5 14 13 
+3 5 6 14 
+5 6 15 27 26 14 3
+3 6 7 15 
+3 7 16 15 2
+3 7 17 16 
+3 8 18 17 
+3 8 19 18 
+3 8 9 19 2
+3 9 20 19 
+3 10 22 21 
+3 10 11 22 
+5 11 23 35 34 22 3
+3 11 12 23 
+3 12 24 23 2
+3 12 13 24 
+3 13 25 24 
+3 13 14 25 2
+3 14 26 25 
+3 15 28 27 
+3 15 16 28 
+5 16 29 41 40 28 3
+3 16 17 29 
+3 17 18 29 2
+3 18 30 29 
+5 18 19 31 43 30 3
+3 19 20 31 
+3 20 32 31 2
+3 20 21 32 
+3 21 33 32 
+3 21 22 33 2
+3 22 34 33 
+3 23 36 35 
+3 23 24 36 
+5 24 25 37 48 36 3
+3 25 26 37 
+3 26 38 37 2
+3 26 27 38 
+3 27 39 38 
+3 27 28 39 2
+3 28 40 39 
+3 29 30 41 
+3 30 42 41 2
+3 30 43 42 
+3 31 44 43 
+3 31 32 44 
+5 32 33 45 53 44 3
+3 33 34 45 
+3 34 46 45 2
+3 34 35 46 
+3 35 47 46 
+3 35 36 47 2
+3 36 48 47 
+3 37 49 48 
+3 37 38 49 
+5 38 39 50 56 49 3
+3 39 40 50 
+3 40 51 50 2
+3 40 41 51 
+3 41 42 51 
+5 42 52 58 57 51 3
+3 42 43 52 
+3 43 44 52 2
+3 44 53 52 
+3 45 54 53 
+3 45 46 54 
+5 46 47 55 59 54 3
+3 47 48 55 
+3 48 49 55 2
+3 49 56 55 
+3 50 57 56 
+3 50 51 57 
+3 52 53 58 
+3 53 54 58 2
+3 54 59 58 
+3 55 56 59 
+3 56 57 59 2
+3 57 58 59 
+5 4 0 1 2 3 
+5 4 5 6 7 0 
+5 7 8 9 1 0 
+5 9 10 11 2 1 
+5 11 12 13 3 2 
+5 3 14 15 5 4 
+5 15 16 17 6 5 
+5 17 18 19 7 6 
+5 7 20 21 22 8 
+5 22 23 10 9 8 
+5 10 24 25 12 11 
+5 25 26 27 13 12 
+5 27 28 29 3 13 
+5 29 30 31 14 3 
+5 31 32 16 15 14 
+5 16 33 34 18 17 
+5 34 35 36 19 18 
+5 36 37 20 7 19 
+5 37 38 39 21 20 
+5 39 40 23 22 21 
+5 40 41 42 10 23 
+5 42 43 44 24 10 
+5 44 45 26 25 24 
+5 26 46 47 28 27 
+5 47 48 30 29 28 
+5 48 49 32 31 30 
+5 49 50 51 16 32 
+5 51 52 53 33 16 
+5 53 54 35 34 33 
+5 35 55 38 37 36 
+5 55 56 57 39 38 
+5 39 58 59 41 40 
+5 59 60 43 42 41 
+5 60 61 45 44 43 
+5 61 62 63 26 45 
+5 63 64 65 46 26 
+5 65 66 48 47 46 
+5 48 67 68 50 49 
+5 68 69 52 51 50 
+5 69 70 54 53 52 
+5 70 71 72 35 54 
+5 72 73 56 55 35 
+5 73 74 75 57 56 
+5 75 76 58 39 57 
+5 76 77 60 59 58 
+5 60 78 79 62 61 
+5 79 80 64 63 62 
+5 80 81 66 65 64 
+5 81 82 67 48 66 
+5 82 83 69 68 67 
+5 69 84 85 71 70 
+5 85 74 73 72 71 
+5 74 86 77 76 75 
+5 86 87 78 60 77 
+5 87 88 80 79 78 
+5 80 89 83 82 81 
+5 89 90 84 69 83 
+5 90 91 74 85 84 
+5 91 88 87 86 74 
+5 88 80 89 90 91 
+great dirhombicosidodecahedron
+great dirhombicosidodecacron
+|3/2 5/3 3 5/2
+(4.5/3.4.3.4.5/2.4.3/2)
+icosahedral group
+A5
+60{4}+20{3}+12{5/2}+12{5/3}+20{3/2}
+79 60 240 124 60 0 1 0 -56 5 8 120 5 1 -1
+ 0.0000000000  0.0000000000  1.0000000000
+ 1.0000000000  0.0000000000  0.0000000000
+-1.0000000000  0.0000000000  0.0000000000
+-0.6180339887  0.7861513778  0.0000000000
+ 0.6180339887 -0.7861513778  0.0000000000
+ 0.7861513778  0.6180339887  0.0000000000
+-0.7861513778 -0.6180339887  0.0000000000
+ 0.0000000000 -1.0000000000  0.0000000000
+-0.0000000000  1.0000000000  0.0000000000
+-0.0000000000 -0.6180339887  0.7861513778
+ 0.0000000000  0.6180339887 -0.7861513778
+-0.0000000000  0.7861513778  0.6180339887
+ 0.0000000000 -0.7861513778 -0.6180339887
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.6180339887 -0.4858682718  0.6180339887
+ 0.6180339887  0.4858682718 -0.6180339887
+-0.4858682718 -0.3819660113 -0.7861513778
+ 0.4858682718  0.3819660113  0.7861513778
+-0.3819660113  0.4858682718  0.7861513778
+ 0.3819660113 -0.4858682718 -0.7861513778
+ 0.4858682718 -0.6180339887  0.6180339887
+-0.4858682718  0.6180339887 -0.6180339887
+-0.7861513778 -0.0000000000  0.6180339887
+ 0.7861513778 -0.0000000000 -0.6180339887
+-0.6180339887 -0.0000000000 -0.7861513778
+ 0.6180339887 -0.0000000000  0.7861513778
+ 0.6180339887 -0.6180339887 -0.4858682718
+-0.6180339887  0.6180339887  0.4858682718
+-0.7861513778 -0.4858682718 -0.3819660113
+ 0.7861513778  0.4858682718  0.3819660113
+ 0.7861513778 -0.3819660113  0.4858682718
+-0.7861513778  0.3819660113 -0.4858682718
+-0.8678342830  0.3177508827  0.3819660113
+ 0.8678342830 -0.3177508827 -0.3819660113
+ 0.1039022605  0.8678342830 -0.4858682718
+-0.1039022605 -0.8678342830  0.4858682718
+-0.9183170948 -0.1039022605 -0.3819660113
+ 0.9183170948  0.1039022605  0.3819660113
+ 0.3819660113  0.7861513778  0.4858682718
+-0.3819660113 -0.7861513778 -0.4858682718
+-0.4858682718 -0.7861513778  0.3819660113
+ 0.4858682718  0.7861513778 -0.3819660113
+ 0.3819660113 -0.8678342830  0.3177508827
+-0.3819660113  0.8678342830 -0.3177508827
+-0.4858682718  0.1039022605  0.8678342830
+ 0.4858682718 -0.1039022605 -0.8678342830
+-0.3819660113 -0.9183170948 -0.1039022605
+ 0.3819660113  0.9183170948  0.1039022605
+ 0.3177508827 -0.2360679775  0.9183170948
+-0.3177508827  0.2360679775 -0.9183170948
+-0.2360679775  0.9183170948  0.3177508827
+ 0.2360679775 -0.9183170948 -0.3177508827
+-0.3177508827 -0.3819660113  0.8678342830
+ 0.3177508827  0.3819660113 -0.8678342830
+-0.8678342830  0.4858682718 -0.1039022605
+ 0.8678342830 -0.4858682718  0.1039022605
+ 0.1039022605  0.3819660113  0.9183170948
+-0.1039022605 -0.3819660113 -0.9183170948
+ 0.9183170948  0.3177508827 -0.2360679775
+-0.9183170948 -0.3177508827  0.2360679775
+ 0.0000000000  1.0000000000  0.0000000000
+-0.5773502692  0.2805161775  0.5773502692
+-0.7861513778 -0.6180339887 -0.0000000000
+ 0.8107067993 -0.0970626198  0.5773502692
+-0.6180339887  0.7861513778  0.0000000000
+-0.2805161775 -0.5773502692  0.5773502692
+ 1.0000000000  0.0000000000  0.0000000000
+ 0.5773502692  0.5773502692  0.5773502692
+ 0.0000000000  0.0000000000  1.0000000000
+ 0.5773502692 -0.5773502692  0.2805161775
+ 0.0000000000 -0.7861513778 -0.6180339887
+ 0.5773502692  0.8107067993 -0.0970626198
+-0.0000000000 -0.6180339887  0.7861513778
+ 0.5773502692 -0.2805161775 -0.5773502692
+-0.5773502692 -0.5773502692 -0.5773502692
+-0.5773502692  0.5773502692 -0.2805161775
+-0.5773502692 -0.8107067993  0.0970626198
+ 0.4858682718  0.3819660113  0.7861513778
+-0.2805161775  0.5138727076 -0.8107067993
+-0.6180339887 -0.4858682718  0.6180339887
+ 0.0970626198  0.8107067993  0.2805161775
+ 0.0000000000 -0.0000000000 -1.0000000000
+-0.8107067993  0.0970626198 -0.5773502692
+ 0.2805161775 -0.5138727076  0.8107067993
+-0.0970626198 -0.8107067993 -0.2805161775
+ 0.4858682718 -0.6180339887  0.6180339887
+ 0.9549290665 -0.2805161775 -0.0970626198
+ 0.3819660113 -0.4858682718 -0.7861513778
+ 0.2805161775  0.5773502692 -0.5773502692
+-0.9549290665  0.2805161775  0.0970626198
+-0.6180339887 -0.0000000000 -0.7861513778
+ 0.0970626198 -0.5773502692 -0.8107067993
+ 0.7861513778 -0.0000000000 -0.6180339887
+-0.0970626198  0.5773502692  0.8107067993
+ 0.7861513778  0.4858682718  0.3819660113
+-0.8107067993 -0.2805161775  0.5138727076
+ 0.6180339887 -0.6180339887 -0.4858682718
+ 0.2805161775  0.0970626198  0.8107067993
+-1.0000000000  0.0000000000 -0.0000000000
+ 0.8107067993  0.2805161775 -0.5138727076
+-0.2805161775 -0.0970626198 -0.8107067993
+ 0.6180339887  0.4858682718 -0.6180339887
+-0.0970626198  0.9549290665 -0.2805161775
+-0.7861513778  0.3819660113 -0.4858682718
+ 0.0970626198 -0.9549290665  0.2805161775
+-0.0000000000  0.7861513778  0.6180339887
+-0.8107067993 -0.2805161775 -0.0970626198
+ 0.6180339887 -0.7861513778 -0.0000000000
+ 0.8107067993  0.2805161775  0.0970626198
+ 0.1039022605  0.8678342830 -0.4858682718
+ 0.2805161775  0.0970626198 -0.9549290665
+ 0.8678342830 -0.3177508827 -0.3819660113
+-0.2805161775 -0.0970626198  0.9549290665
+-0.9183170948 -0.1039022605 -0.3819660113
+-0.8107067993 -0.2805161775  0.5138727076
+-0.1039022605 -0.8678342830  0.4858682718
+ 0.2805161775  0.0970626198  0.8107067993
+ 0.7861513778  0.6180339887  0.0000000000
+ 0.8107067993  0.2805161775 -0.5138727076
+-0.2805161775 -0.0970626198 -0.8107067993
+-0.7861513778 -0.0000000000  0.6180339887
+ 0.5138727076 -0.8107067993 -0.2805161775
+ 0.3819660113  0.7861513778  0.4858682718
+-0.5138727076  0.8107067993  0.2805161775
+-0.4858682718  0.6180339887 -0.6180339887
+-0.8107067993 -0.2805161775 -0.0970626198
+ 0.0000000000 -1.0000000000  0.0000000000
+ 0.8107067993  0.2805161775  0.0970626198
+-0.6180339887  0.6180339887  0.4858682718
+ 0.2805161775  0.0970626198 -0.9549290665
+-0.4858682718 -0.7861513778  0.3819660113
+-0.2805161775 -0.0970626198  0.9549290665
+ 0.6180339887  0.0000000000  0.7861513778
+-0.0970626198 -0.8107067993 -0.2805161775
+ 0.0000000000  0.6180339887 -0.7861513778
+ 0.0970626198  0.8107067993  0.2805161775
+-0.4858682718  0.1039022605  0.8678342830
+-0.9549290665  0.2805161775  0.0970626198
+-0.3819660113  0.8678342830 -0.3177508827
+ 0.9549290665 -0.2805161775 -0.0970626198
+-0.3819660113 -0.9183170948 -0.1039022605
+ 0.5138727076 -0.8107067993 -0.2805161775
+ 0.4858682718 -0.1039022605 -0.8678342830
+-0.5138727076  0.8107067993  0.2805161775
+ 0.3177508827 -0.2360679775  0.9183170948
+-0.0970626198  0.5773502692  0.8107067993
+ 0.3819660113  0.9183170948  0.1039022605
+-0.5773502692  0.5773502692 -0.2805161775
+-0.4858682718 -0.3819660113 -0.7861513778
+ 0.0970626198 -0.5773502692 -0.8107067993
+ 0.5773502692 -0.5773502692  0.2805161775
+-0.3819660113  0.4858682718  0.7861513778
+ 0.3177508827  0.3819660113 -0.8678342830
+-0.5773502692 -0.8107067993  0.0970626198
+-0.2360679775  0.9183170948  0.3177508827
+ 0.5773502692  0.8107067993 -0.0970626198
+ 0.8678342830 -0.4858682718  0.1039022605
+-0.0970626198  0.9549290665 -0.2805161775
+-0.3177508827 -0.3819660113  0.8678342830
+ 0.0970626198 -0.9549290665  0.2805161775
+-0.1039022605 -0.3819660113 -0.9183170948
+ 0.2805161775 -0.5138727076  0.8107067993
+-0.8678342830  0.4858682718 -0.1039022605
+-0.2805161775  0.5138727076 -0.8107067993
+ 0.9183170948  0.3177508827 -0.2360679775
+ 0.8107067993 -0.0970626198  0.5773502692
+ 0.1039022605  0.3819660113  0.9183170948
+-0.2805161775 -0.5773502692  0.5773502692
+-0.7861513778 -0.4858682718 -0.3819660113
+-0.8107067993  0.0970626198 -0.5773502692
+ 0.2805161775  0.5773502692 -0.5773502692
+ 0.7861513778 -0.3819660113  0.4858682718
+-0.8678342830  0.3177508827  0.3819660113
+ 0.2360679775 -0.9183170948 -0.3177508827
+ 0.5773502692  0.5773502692  0.5773502692
+-0.9183170948 -0.3177508827  0.2360679775
+-0.5773502692 -0.5773502692 -0.5773502692
+-0.3177508827  0.2360679775 -0.9183170948
+-0.5773502692  0.2805161775  0.5773502692
+ 0.9183170948  0.1039022605  0.3819660113
+ 0.5773502692 -0.2805161775 -0.5773502692
+-0.3819660113 -0.7861513778 -0.4858682718
+ 0.4858682718  0.7861513778 -0.3819660113
+ 0.3819660113 -0.8678342830  0.3177508827
+4 0 1 13 2 
+5 0 2 11 14 3 3
+4 0 3 13 4 
+3 0 4 5 
+4 0 5 13 6 
+5 0 6 20 22 7 2
+4 0 7 13 8 
+3 0 1 8 2
+4 1 8 2 7 
+5 1 7 25 26 9 3
+4 1 9 2 10 
+3 1 10 11 
+4 1 11 2 12 
+5 1 12 15 4 13 2
+3 2 13 7 
+5 2 8 24 27 10 2
+3 2 9 12 2
+4 3 14 4 15 
+3 3 15 16 
+4 3 16 4 17 
+5 3 17 34 18 5 2
+4 3 5 4 6 
+3 3 6 13 2
+3 4 14 17 2
+5 4 16 35 19 6 3
+4 5 18 6 19 
+3 5 19 20 2
+4 5 20 6 21 
+5 5 21 23 8 13 3
+3 6 18 21 
+4 7 22 8 23 
+3 7 23 24 2
+4 7 24 8 25 
+3 8 22 25 
+4 9 26 10 27 
+3 9 27 28 
+4 9 28 10 29 
+5 9 29 44 30 11 2
+4 9 11 10 12 
+3 10 26 29 2
+5 10 28 45 31 12 3
+4 11 30 12 31 
+3 11 31 15 2
+4 11 15 12 14 
+3 12 30 14 
+4 14 30 15 31 
+5 14 31 46 32 16 2
+4 14 16 15 17 
+5 15 30 47 33 17 3
+4 16 32 17 33 
+3 16 33 34 2
+4 16 34 17 35 
+3 17 32 35 
+4 18 34 19 35 
+3 18 35 36 2
+4 18 36 19 37 
+5 18 37 52 38 20 3
+4 18 20 19 21 
+3 19 34 37 
+5 19 36 53 39 21 2
+4 20 38 21 39 
+3 20 39 23 
+4 20 23 21 22 
+3 21 38 22 2
+4 22 38 23 39 
+5 22 39 54 40 24 3
+4 22 24 23 25 
+5 23 38 55 41 25 2
+4 24 40 25 41 
+3 24 41 26 
+4 24 26 25 27 
+3 25 40 27 2
+4 26 41 27 40 
+5 26 40 57 42 28 2
+4 26 28 27 29 
+5 27 41 56 43 29 3
+4 28 42 29 43 
+3 28 43 44 2
+4 28 44 29 45 
+3 29 42 45 
+4 30 44 31 45 
+3 30 45 46 2
+4 30 46 31 47 
+3 31 44 47 
+4 32 46 33 47 
+3 32 47 48 2
+4 32 48 33 49 
+5 32 49 50 36 34 3
+4 32 34 33 35 
+3 33 46 49 
+5 33 48 51 37 35 2
+4 34 36 35 37 
+4 36 50 37 51 
+3 36 51 52 
+4 36 52 37 53 
+3 37 50 53 2
+4 38 52 39 53 
+3 38 53 54 
+4 38 54 39 55 
+3 39 52 55 2
+4 40 54 41 55 
+3 40 55 56 
+4 40 56 41 57 
+3 41 54 57 2
+4 42 57 43 56 
+3 42 56 58 2
+4 42 58 43 59 
+5 42 59 48 46 44 3
+4 42 44 43 45 
+3 43 57 59 
+5 43 58 49 47 45 2
+4 44 46 45 47 
+4 46 48 47 49 
+4 48 59 49 58 
+3 48 58 50 
+4 48 50 49 51 
+3 49 59 51 2
+4 50 58 51 59 
+5 50 59 56 54 52 2
+4 50 52 51 53 
+5 51 58 57 55 53 3
+4 52 54 53 55 
+4 54 56 55 57 
+4 56 59 57 58 
+8 7 0 1 2 3 4 5 6 
+8 7 8 9 10 11 12 13 0 
+8 14 0 1 12 16 10 15 8 
+8 1 17 18 19 20 21 22 2 
+8 13 2 3 21 24 19 23 17 
+8 20 25 26 27 28 4 3 21 
+8 22 4 5 27 29 25 24 21 
+8 5 30 31 32 9 8 14 6 
+8 28 6 7 8 15 32 33 30 
+8 9 34 35 36 37 38 16 10 
+8 15 34 39 36 40 38 11 10 
+8 37 41 42 43 1 12 11 38 
+8 40 41 44 43 13 12 16 38 
+8 13 0 14 6 28 4 22 2 
+8 44 45 46 47 23 17 1 43 
+8 42 45 48 47 18 17 13 43 
+8 46 49 50 51 24 19 18 47 
+8 48 49 52 51 20 19 23 47 
+8 20 53 54 55 56 57 29 25 
+8 24 53 58 55 59 57 26 25 
+8 56 60 61 62 5 27 26 57 
+8 59 60 63 62 28 27 29 57 
+8 63 64 65 66 33 30 5 62 
+8 61 64 67 66 31 30 28 62 
+8 65 68 69 70 15 32 31 66 
+8 67 68 71 70 9 32 33 66 
+8 69 72 73 74 39 34 9 70 
+8 71 72 75 74 35 34 15 70 
+8 73 76 77 78 40 36 35 74 
+8 75 76 79 78 37 36 39 74 
+8 37 80 81 82 48 45 44 41 
+8 40 80 83 82 46 45 42 41 
+8 46 84 85 86 87 88 52 49 
+8 48 84 89 86 90 88 50 49 
+8 87 91 58 53 20 51 50 88 
+8 90 91 54 53 24 51 52 88 
+8 87 92 93 94 59 55 54 91 
+8 90 92 95 94 56 55 58 91 
+8 56 96 97 98 67 64 63 60 
+8 59 96 99 98 65 64 61 60 
+8 65 100 101 102 73 72 71 68 
+8 67 100 103 102 75 72 69 68 
+8 73 104 105 106 107 108 79 76 
+8 75 104 109 106 110 108 77 76 
+8 107 111 83 80 37 78 77 108 
+8 110 111 81 80 40 78 79 108 
+8 107 112 89 84 46 82 81 111 
+8 110 112 85 84 48 82 83 111 
+8 107 113 114 115 90 86 85 112 
+8 110 113 116 115 87 86 89 112 
+8 114 117 118 119 95 92 87 115 
+8 116 117 120 119 93 92 90 115 
+8 118 121 99 96 56 94 93 119 
+8 120 121 97 96 59 94 95 119 
+8 118 122 103 100 65 98 97 121 
+8 120 122 101 100 67 98 99 121 
+8 118 123 105 104 75 102 101 122 
+8 120 123 109 104 73 102 103 122 
+8 105 106 110 113 114 117 120 123 
+8 107 106 109 123 118 117 116 113 
--- /dev/null
+++ b/lib/print/defprinter
@@ -1,0 +1,1 @@
+printer0
--- /dev/null
+++ b/lib/print/dj895.map
@@ -1,0 +1,729 @@
+255 110 110 108 
+71 252 188 4 
+34 253 187 6 
+19 253 181 4 
+12 254 168 4 
+8 254 154 3 
+6 254 140 3 
+3 253 128 2 
+0 255 112 0 
+59 193 46 252 
+85 249 15 39 
+47 253 133 10 
+24 253 164 7 
+13 253 165 3 
+8 254 158 3 
+4 253 149 1 
+1 253 141 0 
+0 255 131 0 
+11 175 65 253 
+39 227 28 225 
+54 253 21 45 
+31 252 92 18 
+16 253 128 8 
+6 254 138 3 
+1 252 140 0 
+0 255 138 0 
+0 247 133 0 
+2 167 52 253 
+11 194 48 251 
+28 243 20 166 
+23 237 40 56 
+11 242 75 29 
+4 250 91 13 
+0 245 100 0 
+0 231 112 0 
+0 230 119 0 
+0 164 39 254 
+1 177 40 253 
+8 225 28 239 
+11 231 21 128 
+3 228 48 59 
+0 228 59 30 
+0 229 61 8 
+0 210 73 0 
+0 205 90 0 
+0 162 23 254 
+0 168 24 253 
+2 203 20 252 
+0 222 24 193 
+0 226 33 105 
+0 223 37 43 
+0 218 38 18 
+0 208 40 0 
+0 196 59 0 
+0 164 11 255 
+0 166 13 253 
+0 188 10 253 
+0 200 10 217 
+0 204 9 135 
+0 224 10 66 
+0 221 20 26 
+0 219 24 7 
+0 203 34 0 
+0 170 0 255 
+0 163 0 251 
+0 177 0 255 
+0 184 0 228 
+0 184 2 166 
+0 205 0 100 
+0 220 0 44 
+0 233 12 18 
+0 221 15 0 
+0 183 0 255 
+0 172 0 255 
+0 173 0 255 
+0 175 0 235 
+0 173 0 191 
+0 188 0 136 
+0 209 0 81 
+0 231 0 37 
+0 255 0 0 
+88 11 252 203 
+56 94 251 31 
+30 206 250 12 
+18 250 241 7 
+12 254 213 2 
+8 254 194 2 
+5 253 179 0 
+1 253 167 0 
+0 232 142 0 
+27 112 124 253 
+81 110 118 108 
+46 244 188 13 
+23 253 183 6 
+12 254 173 3 
+6 254 160 3 
+2 253 149 0 
+0 255 137 0 
+0 246 121 0 
+0 118 84 252 
+31 175 67 242 
+45 199 61 80 
+25 233 120 31 
+13 250 137 7 
+4 253 139 1 
+0 255 136 0 
+0 247 131 0 
+0 237 120 0 
+0 120 52 253 
+6 172 58 252 
+14 212 59 203 
+13 206 66 85 
+4 219 96 48 
+0 232 100 18 
+0 225 99 0 
+0 218 108 0 
+0 218 112 0 
+0 132 36 254 
+0 164 39 254 
+5 194 31 240 
+0 201 51 152 
+1 204 58 74 
+0 197 59 31 
+0 196 56 3 
+0 191 72 0 
+0 197 89 0 
+0 136 21 255 
+0 154 17 253 
+0 186 12 248 
+0 179 15 172 
+0 182 19 92 
+0 184 29 41 
+0 179 32 15 
+0 174 39 0 
+0 176 57 0 
+0 136 7 253 
+0 147 0 251 
+0 163 0 235 
+0 160 0 181 
+0 166 0 120 
+0 179 3 61 
+0 178 11 22 
+0 174 16 4 
+0 169 33 0 
+0 138 0 255 
+0 136 0 226 
+0 139 0 206 
+0 141 0 179 
+0 145 0 141 
+0 156 0 90 
+0 171 0 45 
+0 176 0 10 
+0 176 13 0 
+0 146 0 255 
+0 135 0 206 
+0 136 0 196 
+0 137 0 180 
+0 140 0 156 
+0 147 0 118 
+0 163 0 73 
+0 181 0 35 
+0 190 0 0 
+46 8 247 246 
+42 26 253 103 
+28 77 253 30 
+18 175 253 10 
+11 243 254 2 
+8 253 215 3 
+2 252 217 0 
+0 246 195 0 
+0 214 165 0 
+10 70 169 253 
+52 39 215 183 
+38 120 243 33 
+15 223 246 14 
+6 251 220 5 
+3 253 198 0 
+0 255 180 0 
+0 248 163 0 
+0 226 140 0 
+0 80 94 253 
+14 108 130 246 
+23 134 143 132 
+7 200 186 74 
+6 234 158 13 
+0 245 144 0 
+0 240 136 0 
+0 237 127 0 
+0 222 115 0 
+0 84 57 253 
+0 116 74 253 
+10 146 79 206 
+3 179 119 129 
+0 176 108 52 
+0 198 99 11 
+0 205 100 0 
+0 208 106 0 
+0 208 104 0 
+0 92 36 255 
+0 118 40 254 
+2 156 42 234 
+0 149 48 143 
+0 157 58 71 
+0 159 58 29 
+0 170 58 3 
+0 176 73 0 
+0 185 86 0 
+0 101 23 255 
+0 121 19 254 
+0 145 14 234 
+0 142 18 161 
+0 147 26 97 
+0 147 28 43 
+0 148 30 15 
+0 152 39 0 
+0 162 58 0 
+0 107 7 255 
+0 117 0 255 
+0 127 0 219 
+0 130 0 166 
+0 130 0 110 
+0 141 3 59 
+0 144 8 24 
+0 142 13 2 
+0 148 31 0 
+0 114 0 255 
+0 107 0 223 
+0 113 0 186 
+0 118 0 161 
+0 121 0 128 
+0 127 0 85 
+0 138 0 45 
+0 142 0 11 
+0 144 10 0 
+0 119 0 255 
+0 107 0 205 
+0 113 0 176 
+0 118 0 159 
+0 119 0 137 
+0 121 0 107 
+0 131 0 69 
+0 146 0 35 
+0 147 0 0 
+8 38 229 253 
+28 14 254 170 
+22 32 253 69 
+13 67 253 30 
+9 150 254 7 
+0 216 250 0 
+0 228 235 0 
+0 216 209 0 
+0 196 182 0 
+4 44 183 254 
+28 20 238 231 
+29 32 248 81 
+13 92 249 24 
+1 175 243 2 
+0 215 226 0 
+0 225 209 0 
+0 221 189 0 
+0 207 166 0 
+0 49 117 254 
+5 67 163 251 
+7 90 198 182 
+7 108 194 68 
+0 161 181 16 
+0 195 165 0 
+0 211 158 0 
+0 215 147 0 
+0 209 135 0 
+0 60 66 254 
+0 76 89 253 
+3 95 114 210 
+0 118 126 116 
+0 124 117 48 
+0 157 105 10 
+0 181 106 0 
+0 195 107 0 
+0 196 105 0 
+0 66 40 255 
+0 76 45 253 
+0 102 57 235 
+0 103 60 147 
+0 109 64 75 
+0 120 65 30 
+0 138 63 3 
+0 157 75 0 
+0 172 84 0 
+0 73 26 254 
+0 82 24 254 
+0 101 23 240 
+0 104 25 160 
+0 103 30 97 
+0 110 33 46 
+0 115 33 15 
+0 129 43 0 
+0 145 60 0 
+0 77 9 253 
+0 81 0 251 
+0 95 0 229 
+0 98 0 161 
+0 99 5 109 
+0 104 8 61 
+0 107 12 24 
+0 109 12 0 
+0 127 33 0 
+0 85 0 255 
+0 83 0 232 
+0 87 0 193 
+0 97 0 156 
+0 101 0 122 
+0 101 0 83 
+0 106 0 43 
+0 110 0 11 
+0 114 10 0 
+0 92 0 248 
+0 84 0 209 
+0 90 0 179 
+0 99 0 153 
+0 103 0 130 
+0 102 0 101 
+0 106 0 67 
+0 116 0 34 
+0 116 0 0 
+5 29 224 254 
+16 14 254 212 
+16 19 253 112 
+8 34 253 55 
+3 55 253 26 
+0 120 246 0 
+0 174 232 0 
+0 186 214 0 
+0 175 193 0 
+2 30 192 253 
+5 34 243 247 
+16 18 250 135 
+6 36 250 53 
+2 67 250 12 
+0 127 230 0 
+0 174 218 0 
+0 191 209 0 
+0 185 189 0 
+0 36 138 255 
+2 40 179 253 
+0 58 215 202 
+2 57 206 92 
+0 77 202 26 
+0 125 185 0 
+0 170 187 0 
+0 188 179 0 
+0 190 162 0 
+0 38 79 255 
+0 45 101 254 
+0 59 132 213 
+0 56 128 118 
+0 74 130 47 
+0 106 121 8 
+0 143 124 0 
+0 169 128 0 
+0 181 123 0 
+0 44 44 254 
+0 51 55 254 
+1 60 67 223 
+0 63 68 144 
+0 70 74 71 
+0 84 73 29 
+0 106 70 2 
+0 137 80 0 
+0 159 86 0 
+0 52 28 254 
+0 56 30 254 
+0 64 32 228 
+0 66 33 161 
+0 71 37 98 
+0 75 40 48 
+0 84 39 13 
+0 102 49 0 
+0 125 63 0 
+0 58 11 253 
+0 61 7 253 
+0 65 7 231 
+0 69 9 169 
+0 73 10 112 
+0 75 13 63 
+0 80 15 25 
+0 85 17 2 
+0 104 36 0 
+0 63 0 255 
+0 62 0 236 
+0 64 0 201 
+0 70 0 161 
+0 77 0 122 
+0 79 0 82 
+0 81 0 43 
+0 84 0 11 
+0 92 11 0 
+0 68 0 243 
+0 64 0 206 
+0 67 0 180 
+0 75 0 157 
+0 85 0 130 
+0 87 0 99 
+0 87 0 69 
+0 91 0 35 
+0 93 0 0 
+3 20 220 254 
+0 28 253 240 
+1 24 254 165 
+3 23 254 80 
+0 26 254 35 
+0 33 252 8 
+0 92 238 0 
+0 140 217 0 
+0 153 197 0 
+1 20 198 254 
+0 24 246 251 
+0 23 252 182 
+0 23 250 81 
+0 24 250 19 
+0 42 235 0 
+0 99 221 0 
+0 149 214 0 
+0 163 199 0 
+0 24 153 254 
+1 22 190 251 
+0 23 204 192 
+0 26 202 100 
+0 32 206 32 
+0 48 195 0 
+0 106 196 0 
+0 151 197 0 
+0 167 187 0 
+0 26 93 255 
+0 28 114 254 
+0 29 135 205 
+0 28 135 121 
+0 33 141 53 
+0 50 140 9 
+0 98 146 0 
+0 138 156 0 
+0 158 150 0 
+0 28 55 254 
+0 32 62 254 
+0 35 73 216 
+0 35 78 141 
+0 40 84 79 
+0 50 84 27 
+0 75 83 0 
+0 113 98 0 
+0 138 103 0 
+0 34 34 255 
+0 35 35 254 
+0 37 40 222 
+0 36 39 152 
+0 42 45 94 
+0 43 47 45 
+0 58 47 14 
+0 82 55 0 
+0 110 68 0 
+0 37 15 253 
+0 39 14 253 
+0 41 15 221 
+0 43 14 163 
+0 46 16 111 
+0 50 19 62 
+0 53 20 26 
+0 61 23 2 
+0 83 41 0 
+0 44 0 255 
+0 44 0 238 
+0 44 0 200 
+0 46 0 162 
+0 51 0 123 
+0 55 0 78 
+0 55 0 41 
+0 57 0 10 
+0 70 13 0 
+0 52 0 225 
+0 48 0 196 
+0 48 0 174 
+0 53 0 153 
+0 60 0 130 
+0 67 0 99 
+0 68 0 68 
+0 70 0 36 
+0 71 0 0 
+1 12 217 253 
+0 11 249 247 
+0 9 253 188 
+0 10 253 98 
+0 12 254 43 
+0 11 254 11 
+0 19 247 0 
+0 69 223 0 
+0 115 204 0 
+1 11 200 253 
+1 6 239 251 
+0 2 242 191 
+0 4 239 95 
+0 7 240 30 
+0 12 235 0 
+0 33 223 0 
+0 80 214 0 
+0 123 204 0 
+0 13 163 253 
+0 5 193 248 
+0 5 193 183 
+0 7 195 109 
+0 10 199 43 
+0 13 197 3 
+0 40 198 0 
+0 88 201 0 
+0 130 195 0 
+0 14 108 253 
+0 11 126 251 
+0 8 137 191 
+0 10 138 122 
+0 13 144 60 
+0 15 150 15 
+0 41 160 0 
+0 90 169 0 
+0 130 171 0 
+0 17 64 253 
+0 17 70 253 
+0 14 76 207 
+0 16 84 139 
+0 17 91 79 
+0 22 95 31 
+0 36 99 0 
+0 82 120 0 
+0 116 130 0 
+0 21 38 255 
+0 20 39 253 
+0 20 42 211 
+0 19 46 151 
+0 22 53 96 
+0 24 55 48 
+0 34 56 12 
+0 62 68 0 
+0 94 83 0 
+0 22 22 255 
+0 24 21 252 
+0 21 19 208 
+0 23 20 157 
+0 22 23 106 
+0 25 25 58 
+0 29 31 30 
+0 39 29 0 
+0 68 47 0 
+0 24 0 250 
+0 25 0 242 
+0 26 0 203 
+0 27 0 160 
+0 28 0 117 
+0 31 2 74 
+0 33 4 39 
+0 35 6 11 
+0 52 18 0 
+0 35 0 214 
+0 33 0 188 
+0 34 0 168 
+0 35 0 147 
+0 38 0 124 
+0 43 0 95 
+0 47 0 64 
+0 48 0 34 
+0 50 0 0 
+0 0 212 250 
+0 0 243 251 
+0 0 251 208 
+0 0 249 125 
+0 0 248 56 
+0 3 253 23 
+0 1 253 1 
+0 13 244 0 
+0 57 217 0 
+0 0 198 255 
+0 0 215 235 
+0 0 215 187 
+0 0 218 121 
+0 0 221 53 
+0 0 225 14 
+0 8 221 0 
+0 23 215 0 
+0 62 209 0 
+0 0 165 255 
+0 0 179 228 
+0 0 178 175 
+0 0 182 125 
+0 0 189 61 
+0 0 192 16 
+0 10 194 0 
+0 30 200 0 
+0 70 201 0 
+0 0 116 250 
+0 0 128 232 
+0 0 138 177 
+0 0 140 127 
+0 0 145 72 
+0 0 149 24 
+0 9 158 0 
+0 35 176 0 
+0 78 183 0 
+0 3 72 253 
+0 0 73 243 
+0 0 83 191 
+0 0 90 134 
+0 0 94 81 
+0 2 100 36 
+0 4 108 4 
+0 36 133 0 
+0 78 146 0 
+0 6 42 253 
+0 5 43 249 
+0 4 47 204 
+0 4 52 148 
+0 4 58 97 
+0 6 62 50 
+0 8 65 13 
+0 33 83 0 
+0 70 102 0 
+0 10 22 255 
+0 11 23 247 
+0 8 22 201 
+0 7 25 154 
+0 8 29 107 
+0 9 32 61 
+0 12 36 28 
+0 22 39 0 
+0 54 60 0 
+0 11 7 255 
+0 12 6 243 
+0 10 4 200 
+0 12 5 159 
+0 11 7 117 
+0 11 8 73 
+0 14 10 38 
+0 22 22 22 
+0 36 26 0 
+0 18 0 230 
+0 18 0 198 
+0 19 0 171 
+0 19 0 145 
+0 22 0 120 
+0 22 0 91 
+0 24 0 60 
+0 25 0 31 
+0 28 0 0 
+0 0 229 255 
+0 0 240 255 
+0 0 242 218 
+0 0 241 155 
+0 0 239 88 
+0 0 242 45 
+0 0 246 19 
+0 0 251 5 
+0 0 255 0 
+0 0 195 251 
+0 0 193 214 
+0 0 196 182 
+0 0 203 142 
+0 0 208 84 
+0 0 212 40 
+0 0 216 14 
+0 0 219 0 
+0 0 220 0 
+0 0 163 239 
+0 0 168 209 
+0 0 170 172 
+0 0 175 137 
+0 0 180 88 
+0 0 185 42 
+0 0 189 14 
+0 0 195 0 
+0 0 200 0 
+0 0 122 226 
+0 0 131 204 
+0 0 140 171 
+0 0 145 136 
+0 0 148 94 
+0 0 154 49 
+0 0 158 15 
+0 0 168 0 
+0 5 181 0 
+0 0 82 224 
+0 0 86 202 
+0 0 96 172 
+0 0 106 136 
+0 0 109 98 
+0 0 113 57 
+0 0 119 20 
+0 0 132 0 
+0 11 155 0 
+0 0 51 233 
+0 0 53 205 
+0 0 58 176 
+0 0 66 143 
+0 0 72 105 
+0 0 76 64 
+0 0 79 28 
+0 0 88 0 
+0 12 115 0 
+0 0 28 248 
+0 0 29 220 
+0 0 32 179 
+0 0 35 144 
+0 0 39 112 
+0 0 44 72 
+0 0 48 35 
+0 0 52 6 
+0 10 73 0 
+0 0 9 255 
+0 0 0 236 
+0 0 7 194 
+0 0 8 156 
+0 0 10 118 
+0 0 15 77 
+0 0 17 41 
+0 0 19 13 
+0 0 35 0 
+0 0 0 255 
+0 0 0 218 
+0 0 0 187 
+0 0 0 158 
+0 0 0 124 
+0 0 0 90 
+0 0 0 55 
+0 0 0 25 
+0 0 0 0 
--- /dev/null
+++ b/lib/print/dj970.map
@@ -1,0 +1,732 @@
+255 48 48 58 
+57 254 183 16 
+35 255 185 23 
+23 255 180 22 
+16 254 175 20 
+10 254 173 21 
+1 255 179 29 
+0 255 169 18 
+0 255 153 0 
+60 213 12 255 
+69 255 46 46 
+37 255 141 33 
+22 255 163 26 
+14 255 165 20 
+4 255 173 26 
+0 255 172 24 
+0 255 163 12 
+0 255 150 0 
+31 209 29 255 
+43 255 17 206 
+30 255 61 61 
+17 255 122 45 
+8 254 139 25 
+0 255 152 20 
+0 255 147 0 
+0 250 144 0 
+0 243 141 0 
+10 204 42 255 
+18 233 27 255 
+28 255 25 177 
+14 255 71 71 
+6 254 101 45 
+0 250 113 17 
+0 229 113 0 
+0 222 119 0 
+0 221 123 0 
+3 205 31 255 
+2 220 34 255 
+15 254 20 227 
+14 255 26 148 
+5 242 68 71 
+0 240 77 34 
+0 220 81 0 
+0 203 91 0 
+0 199 99 0 
+2 209 16 255 
+2 215 18 255 
+1 241 26 255 
+0 255 30 210 
+4 239 32 127 
+2 231 50 52 
+0 226 53 18 
+0 204 63 0 
+0 192 77 0 
+1 214 7 255 
+1 215 10 255 
+1 229 9 255 
+0 250 7 237 
+0 241 19 175 
+0 231 27 102 
+0 243 30 33 
+0 224 35 6 
+0 193 54 0 
+0 214 0 250 
+0 216 3 255 
+0 224 0 255 
+0 231 0 239 
+0 229 0 194 
+0 223 14 138 
+0 235 12 78 
+0 248 9 13 
+0 210 29 0 
+0 217 0 255 
+0 215 0 255 
+0 218 0 255 
+0 220 0 242 
+0 215 0 209 
+0 199 0 153 
+0 197 0 100 
+0 226 0 54 
+0 245 0 0 
+71 0 247 247 
+55 98 255 36 
+35 221 245 26 
+24 255 213 18 
+17 255 192 18 
+11 255 185 21 
+2 254 187 29 
+0 255 177 19 
+0 255 161 0 
+67 72 53 255 
+86 119 117 120 
+40 230 186 39 
+20 255 185 20 
+6 254 187 25 
+0 254 185 23 
+0 255 170 7 
+0 240 156 0 
+0 228 144 0 
+25 162 49 255 
+51 201 39 222 
+41 191 90 108 
+16 220 133 58 
+0 244 156 29 
+0 244 149 0 
+0 234 144 0 
+0 225 140 0 
+0 220 135 0 
+7 180 50 255 
+16 208 37 255 
+21 216 58 190 
+16 197 86 104 
+5 206 106 57 
+0 214 110 16 
+0 209 111 0 
+0 208 118 0 
+0 208 120 0 
+4 185 32 255 
+3 204 30 255 
+3 237 43 240 
+4 206 58 157 
+0 196 77 92 
+0 192 78 42 
+0 189 75 0 
+0 186 87 0 
+0 189 97 0 
+1 195 16 255 
+0 207 10 255 
+0 227 10 246 
+0 206 27 186 
+0 188 42 119 
+0 185 52 64 
+0 182 51 23 
+0 176 56 0 
+0 173 72 0 
+0 200 5 255 
+0 200 0 241 
+0 202 0 226 
+0 194 0 189 
+0 185 17 141 
+0 178 25 89 
+0 179 31 39 
+0 177 31 7 
+0 171 48 0 
+0 200 0 255 
+0 182 0 216 
+0 181 0 205 
+0 180 0 188 
+0 175 0 156 
+0 173 8 113 
+0 175 13 67 
+0 181 14 20 
+0 177 25 0 
+0 196 0 246 
+0 178 0 210 
+0 175 0 201 
+0 173 0 189 
+0 173 0 169 
+0 171 0 134 
+0 168 0 89 
+0 182 0 45 
+0 193 0 0 
+42 12 242 255 
+41 38 255 116 
+22 108 255 48 
+20 181 255 21 
+3 241 247 31 
+0 254 222 25 
+0 254 202 20 
+0 255 188 8 
+0 249 174 0 
+40 46 140 255 
+59 66 189 173 
+29 130 211 70 
+3 206 235 34 
+0 234 212 8 
+0 235 192 0 
+0 234 178 0 
+0 226 165 0 
+0 217 151 0 
+20 91 76 255 
+45 104 78 215 
+17 151 150 149 
+0 191 175 95 
+0 199 159 24 
+0 205 150 0 
+0 207 148 0 
+0 205 142 0 
+0 202 135 0 
+8 141 54 255 
+12 157 56 255 
+15 169 86 193 
+1 181 119 133 
+0 178 117 67 
+0 183 111 15 
+0 189 114 0 
+0 193 120 0 
+0 193 120 0 
+4 164 37 255 
+4 175 36 255 
+6 188 47 222 
+0 176 70 158 
+0 169 79 95 
+0 166 79 42 
+0 167 76 0 
+0 173 89 0 
+0 179 99 0 
+1 176 19 255 
+0 185 12 255 
+0 197 16 231 
+0 173 29 171 
+0 163 39 115 
+0 158 49 63 
+0 157 49 22 
+0 156 54 0 
+0 158 70 0 
+0 180 5 255 
+0 176 0 237 
+0 172 0 206 
+0 163 0 170 
+0 157 12 131 
+0 152 20 84 
+0 153 26 38 
+0 151 28 7 
+0 149 45 0 
+0 178 0 248 
+0 161 0 211 
+0 156 0 190 
+0 155 0 171 
+0 153 0 142 
+0 147 0 102 
+0 149 8 60 
+0 152 11 18 
+0 149 21 0 
+0 173 0 235 
+0 156 0 202 
+0 148 0 181 
+0 147 0 167 
+0 146 0 146 
+0 146 0 122 
+0 147 0 86 
+0 152 0 41 
+0 157 0 0 
+21 26 232 255 
+28 25 255 175 
+17 58 255 92 
+7 98 255 54 
+0 162 255 19 
+0 206 237 0 
+0 226 215 0 
+0 231 199 0 
+0 229 184 0 
+17 46 182 255 
+31 36 232 226 
+20 71 220 113 
+6 111 233 42 
+0 151 218 0 
+0 189 204 0 
+0 204 190 0 
+0 207 175 0 
+0 204 162 0 
+14 67 117 255 
+26 64 139 239 
+4 115 183 179 
+1 126 183 98 
+0 141 170 21 
+0 167 163 0 
+0 185 160 0 
+0 190 152 0 
+0 188 142 0 
+6 88 74 255 
+12 94 73 255 
+22 107 97 186 
+0 132 131 129 
+0 138 126 67 
+0 148 119 13 
+0 162 122 0 
+0 173 125 0 
+0 175 122 0 
+1 125 46 255 
+2 135 47 255 
+7 138 56 214 
+0 136 78 157 
+0 135 84 97 
+0 136 83 42 
+0 142 82 0 
+0 155 94 0 
+0 162 101 0 
+0 148 25 255 
+0 155 22 255 
+0 157 25 226 
+0 141 34 167 
+0 133 43 115 
+0 132 50 65 
+0 133 51 22 
+0 136 57 0 
+0 144 74 0 
+0 154 7 255 
+0 150 0 239 
+0 144 0 206 
+0 138 0 166 
+0 134 14 127 
+0 130 20 84 
+0 130 26 38 
+0 129 29 6 
+0 131 44 0 
+0 153 0 242 
+0 139 0 209 
+0 134 0 189 
+0 134 0 163 
+0 132 0 133 
+0 127 0 99 
+0 127 5 57 
+0 129 9 17 
+0 127 19 0 
+0 150 0 226 
+0 135 0 199 
+0 130 0 179 
+0 129 0 157 
+0 128 0 137 
+0 127 0 115 
+0 126 0 83 
+0 126 0 41 
+0 128 0 0 
+3 36 226 255 
+18 18 255 208 
+11 32 255 131 
+0 65 255 76 
+0 68 255 21 
+0 125 241 0 
+0 168 222 0 
+0 196 210 0 
+0 205 195 0 
+5 38 193 255 
+10 36 243 245 
+10 35 234 145 
+4 62 223 69 
+0 79 219 9 
+0 121 209 0 
+0 160 202 0 
+0 181 189 0 
+0 187 174 0 
+6 47 148 255 
+8 49 171 249 
+0 74 192 189 
+0 76 183 106 
+0 84 181 35 
+0 112 175 0 
+0 148 173 0 
+0 168 166 0 
+0 172 154 0 
+3 66 100 255 
+9 67 109 249 
+7 77 126 194 
+0 88 137 138 
+0 92 138 69 
+0 106 130 11 
+0 133 133 0 
+0 151 136 0 
+0 157 131 0 
+0 77 61 255 
+0 91 67 255 
+0 91 74 213 
+0 99 93 162 
+0 98 97 95 
+0 105 92 42 
+0 115 90 0 
+0 131 101 0 
+0 142 106 0 
+0 103 28 255 
+0 111 27 255 
+0 113 34 222 
+0 106 42 168 
+0 102 50 117 
+0 104 56 68 
+0 107 55 22 
+0 114 62 0 
+0 126 77 0 
+0 125 7 255 
+0 122 0 244 
+0 119 0 214 
+0 112 10 171 
+0 108 17 125 
+0 105 23 84 
+0 105 28 40 
+0 106 30 6 
+0 112 46 0 
+0 130 0 239 
+0 118 0 210 
+0 114 0 191 
+0 112 0 165 
+0 110 0 129 
+0 106 0 94 
+0 100 0 52 
+0 105 9 17 
+0 106 18 0 
+0 128 0 217 
+0 118 0 197 
+0 114 0 180 
+0 112 0 158 
+0 112 0 133 
+0 108 0 108 
+0 105 0 79 
+0 104 0 41 
+0 104 0 0 
+2 22 221 255 
+2 29 255 235 
+0 30 255 174 
+0 29 255 89 
+0 34 254 23 
+0 43 246 0 
+0 101 230 0 
+0 143 218 0 
+0 173 209 0 
+2 22 199 255 
+1 25 235 249 
+0 24 238 179 
+0 29 222 89 
+0 39 216 27 
+0 57 209 0 
+0 102 206 0 
+0 134 199 0 
+0 159 188 0 
+2 30 166 255 
+2 29 186 251 
+0 33 186 185 
+0 35 179 110 
+0 45 179 49 
+0 52 175 0 
+0 96 180 0 
+0 127 177 0 
+0 148 168 0 
+0 43 119 255 
+0 43 130 255 
+0 45 139 199 
+0 47 140 136 
+0 51 141 76 
+0 57 140 18 
+0 89 144 0 
+0 120 148 0 
+0 136 143 0 
+0 53 76 255 
+0 57 82 250 
+0 57 90 203 
+0 58 96 152 
+0 60 101 101 
+0 66 102 44 
+0 78 98 0 
+0 107 109 0 
+0 123 113 0 
+0 53 38 255 
+0 64 39 255 
+0 68 45 215 
+0 69 54 167 
+0 69 62 121 
+0 68 68 66 
+0 78 64 22 
+0 90 69 0 
+0 105 80 0 
+0 81 12 255 
+0 85 9 255 
+0 84 12 217 
+0 81 19 170 
+0 78 24 127 
+0 78 29 86 
+0 79 33 42 
+0 80 33 5 
+0 90 48 0 
+0 101 0 242 
+0 94 0 213 
+0 89 0 191 
+0 86 0 164 
+0 83 0 129 
+0 79 0 91 
+0 80 5 56 
+0 81 11 19 
+0 83 19 0 
+0 108 0 212 
+0 98 0 194 
+0 94 0 177 
+0 92 0 156 
+0 90 0 131 
+0 87 0 102 
+0 83 0 73 
+0 80 0 40 
+0 81 0 0 
+1 11 216 255 
+0 15 249 246 
+0 11 255 191 
+0 11 255 111 
+0 12 255 36 
+0 14 247 0 
+0 28 238 0 
+0 82 226 0 
+0 124 218 0 
+0 10 201 255 
+0 3 226 249 
+0 0 220 183 
+0 0 212 105 
+0 11 210 40 
+0 15 201 0 
+0 41 202 0 
+0 84 203 0 
+0 118 200 0 
+0 16 173 255 
+0 7 184 248 
+0 0 176 179 
+0 8 175 117 
+0 13 174 55 
+0 20 173 9 
+0 42 177 0 
+0 81 182 0 
+0 111 180 0 
+0 21 128 255 
+0 16 136 250 
+0 15 137 192 
+0 16 139 133 
+0 19 140 80 
+0 25 144 28 
+0 39 146 0 
+0 76 154 0 
+0 106 155 0 
+0 29 86 255 
+0 27 89 245 
+0 26 95 197 
+0 26 100 148 
+0 28 105 100 
+0 30 107 48 
+0 37 109 6 
+0 69 118 0 
+0 97 122 0 
+0 35 48 255 
+1 37 50 239 
+0 36 56 198 
+0 34 62 156 
+0 35 67 114 
+0 37 72 73 
+0 42 74 23 
+0 60 78 0 
+0 83 86 0 
+0 37 23 255 
+0 44 20 249 
+0 44 24 210 
+0 44 27 168 
+0 44 33 128 
+0 44 38 90 
+0 40 40 39 
+0 53 41 6 
+0 67 51 0 
+0 60 0 251 
+0 57 0 228 
+0 55 0 197 
+0 53 0 165 
+0 50 0 127 
+0 53 7 95 
+0 53 10 58 
+0 55 13 20 
+0 59 21 0 
+0 78 0 217 
+0 74 0 194 
+0 71 0 174 
+0 69 0 153 
+0 67 0 130 
+0 63 0 100 
+0 59 0 69 
+0 56 0 38 
+0 58 0 0 
+0 4 213 255 
+0 0 241 250 
+0 0 255 214 
+0 0 255 143 
+0 0 250 68 
+0 0 249 15 
+0 4 244 0 
+0 17 238 0 
+0 66 229 0 
+0 0 199 255 
+0 0 201 226 
+0 0 200 186 
+0 0 202 132 
+0 0 202 69 
+0 0 201 20 
+0 7 198 0 
+0 25 199 0 
+0 66 204 0 
+0 0 171 255 
+0 0 171 226 
+0 0 168 177 
+0 0 171 131 
+0 0 172 78 
+0 0 171 25 
+0 7 170 0 
+0 28 176 0 
+0 65 183 0 
+0 3 132 255 
+0 0 133 232 
+0 0 134 183 
+0 0 136 134 
+0 0 139 89 
+0 0 138 36 
+0 7 142 0 
+0 29 152 0 
+0 64 161 0 
+0 9 93 255 
+0 5 93 235 
+0 0 93 188 
+0 0 99 142 
+0 0 104 97 
+0 0 108 53 
+0 8 114 11 
+0 26 120 0 
+0 59 128 0 
+0 19 58 255 
+0 16 57 228 
+0 12 60 190 
+0 9 66 151 
+0 10 72 112 
+0 11 77 71 
+0 12 80 27 
+0 22 85 0 
+0 52 93 0 
+0 26 30 255 
+0 25 30 227 
+0 19 30 193 
+0 17 33 156 
+0 16 38 121 
+0 16 43 84 
+0 17 48 45 
+0 21 50 6 
+0 43 58 0 
+0 22 11 255 
+0 22 6 233 
+0 21 7 200 
+0 21 7 166 
+0 22 11 131 
+0 23 13 96 
+0 23 16 60 
+0 20 20 19 
+0 35 26 0 
+0 37 0 240 
+0 36 0 201 
+0 34 0 178 
+0 36 0 154 
+0 37 0 130 
+0 35 0 101 
+0 32 0 70 
+0 31 0 38 
+0 34 0 0 
+0 0 222 255 
+0 0 237 255 
+0 0 255 233 
+0 0 255 178 
+0 0 249 112 
+0 0 255 61 
+0 0 255 25 
+0 0 255 6 
+0 0 255 0 
+0 0 197 255 
+0 0 186 210 
+0 0 191 188 
+0 0 197 155 
+0 0 200 106 
+0 0 203 59 
+0 0 205 27 
+0 0 206 9 
+0 0 208 0 
+0 0 169 242 
+0 0 160 204 
+0 0 161 174 
+0 0 167 144 
+0 0 171 106 
+0 0 173 60 
+0 0 174 26 
+0 0 175 6 
+0 0 177 0 
+0 0 132 226 
+0 0 132 205 
+0 0 134 176 
+0 0 139 141 
+0 0 143 108 
+0 0 144 67 
+0 0 145 26 
+0 0 147 0 
+0 0 152 0 
+0 0 98 222 
+0 0 99 201 
+0 0 103 177 
+0 0 109 144 
+0 0 115 111 
+0 0 116 74 
+0 0 118 32 
+0 0 120 0 
+0 0 126 0 
+0 0 62 243 
+0 0 63 208 
+0 0 68 176 
+0 0 73 143 
+0 0 81 113 
+0 0 84 78 
+0 0 86 41 
+0 0 90 9 
+0 0 97 0 
+0 0 25 244 
+0 0 28 213 
+0 0 33 187 
+0 0 39 146 
+0 0 45 116 
+0 0 51 84 
+0 0 54 48 
+0 0 58 14 
+0 0 66 0 
+0 0 0 242 
+0 0 0 207 
+0 0 2 191 
+0 0 7 160 
+0 0 11 123 
+0 0 18 92 
+0 0 22 56 
+0 0 25 23 
+0 0 33 0 
+0 0 0 255 
+0 0 0 212 
+0 0 0 185 
+0 0 0 157 
+0 0 0 130 
+0 0 0 106 
+0 0 0 71 
+0 0 0 37 
+0 0 0 0 
+0 0 0 0 
+0 0 0 0 
+0 0 0 0 
--- /dev/null
+++ b/lib/print/paper.cfg
@@ -1,0 +1,8 @@
+A4=
+	hpcode=26
+	width_inches=8.3
+	height_inches=11.7
+A5=
+	hpcode=25
+	width_inches=4.15
+	height_inches=5.85
--- /dev/null
+++ b/lib/print/pmode.cfg
@@ -1,0 +1,7 @@
+HPnormal=
+	desc=300x300 dpi
+	resx=300
+	resy=300
+	blackdepth=1
+	coldepth=1
+	blackresmult=1
--- /dev/null
+++ b/lib/print/popt.cfg
@@ -1,0 +1,10 @@
+printer0=
+	duplex=0
+	orientation=1
+	paper=A4
+	mode=HPnormal
+testprinter=
+	duplex=0
+	orientation=1
+	paper=A4
+	mode=HPnormal
--- /dev/null
+++ b/lib/print/printer.cfg
@@ -1,0 +1,6 @@
+printer0=
+	ptype=HP Deskjet 970
+	device=/dev/lpt1data
+testprinter=
+	ptype=HP Deskjet 970
+	device=/tmp/printer.out
--- /dev/null
+++ b/lib/print/ptype.cfg
@@ -1,0 +1,4 @@
+HP Deskjet 970=
+	driver=hp_driver.dis
+	hpmapfile=dj970
+	modes=HPnormal
--- /dev/null
+++ b/lib/proto/FreeBSD
@@ -1,0 +1,19 @@
+FreeBSD
+	386
+		bin
+			emu.new	0775	inferno	inferno	/FreeBSD/386/bin/emu
+			asm
+			iar
+			data2c
+			data2s
+			ksize
+			kstrip
+			limbo
+			mk
+			mkext
+			ndate
+			inm
+			iyacc
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/Hp
@@ -1,0 +1,46 @@
+Hp
+	s800
+		bin
+			emu.new	0775	inferno	inferno	/Linux/386/bin/emu
+			0a
+			0c
+			0l
+			5a
+			5c
+			5cv
+			5coff
+			5l
+			8a
+			8c
+			8l
+			acid
+			asm
+			data2c
+			iar
+			data2s
+			ka
+			kc
+			kl
+			ksize
+			kstrip
+
+			limbo
+			mk
+			mkppcimage
+			mkext
+			ms2
+			ndate
+			inm
+			qa
+			qc
+			ql
+			sqz
+			srclist
+			tc
+			va
+			vc
+			vl
+			iyacc
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/Irix
@@ -1,0 +1,54 @@
+Irix
+	mips
+		bin
+			emu.new	0775	inferno	inferno	/Irix/mips/bin/emu
+			0a
+			0c
+			0l
+			1a
+			1c
+			1l
+			2a
+			2c
+			2l
+			5a
+			5c
+			5cv
+			5coff
+			5l
+			8a
+			8c
+			8l
+			acid
+			asm
+			awk
+			data2c
+			data2s
+			ftl
+			iar
+			ka
+			kc
+			kl
+			ksize
+			kstrip
+
+			limbo
+			mk
+			mkppcimage
+			mkext
+			ms2
+			ndate
+			inm
+			qa
+			qc
+			ql
+			sqz
+			srclist
+			tc
+			va
+			vc
+			vl
+			iyacc
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/Linux
@@ -1,0 +1,40 @@
+Linux
+	386
+		bin
+			emu.new	0775	inferno	inferno	/Linux/386/bin/emu
+			asm
+			iar
+			data2c
+			data2s
+			ksize
+			kstrip
+			limbo
+			mk
+			mkext
+			ndate
+			iyacc
+		include
+			+
+		lib
+	arm
+		bin
+		include
+			+
+		lib
+	power
+		bin
+			emu.new	0775	inferno	inferno	/Linux/power/bin/emu
+			data2c
+			mk
+			limbo
+			mkext
+			ndate
+			iyacc
+		include
+			+
+		lib
+	spim
+		bin
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/MacOSX
@@ -1,0 +1,47 @@
+MacOSX
+	README
+	power
+		bin
+			emu.new	0775	inferno	inferno	/MacOSX/power/bin/emu
+			asm
+			iar
+			data2c
+			data2s
+			ksize
+			kstrip
+
+			limbo
+			mk
+			mkext
+			ms2
+			ndate
+			inm
+			sqz
+			srclist
+			iyacc
+		include
+			+
+		lib
+	tcshrc
+	386
+		bin
+			emu.new	0775	inferno	inferno	/MacOSX/386/bin/emu
+			asm
+			iar
+			data2c
+			data2s
+			ksize
+			kstrip
+
+			limbo
+			mk
+			mkext
+			ms2
+			ndate
+			inm
+			sqz
+			srclist
+			iyacc
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/NetBSD
@@ -1,0 +1,19 @@
+NetBSD
+	386
+		bin
+			emu.new	0775	inferno	inferno	/NetBSD/386/bin/emu
+			asm
+			iar
+			data2c
+			data2s
+			ksize
+			kstrip
+			limbo
+			mk
+			mkext
+			ndate
+			inm
+			iyacc
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/Nt
@@ -1,0 +1,63 @@
+Nt
+	386
+		bin
+			emu.new	0775	inferno	inferno	/Nt/386/bin/emu.exe
+			ie.exe
+			0a.exe
+			0c.exe
+			0l.exe
+			5a.exe
+			5c.exe
+			5cv.exe
+			5coff.exe
+			5l.exe
+			8a.exe
+			8c.exe
+			8l.exe
+			acid.exe
+			asm.exe
+			awk.exe
+			iar.exe
+			c2l.exe
+			cp.exe
+			data2c.exe
+			data2s.exe
+			echo.exe
+			format.exe
+			gzip.exe
+			infdb.exe
+			inm.exe
+			ka.exe
+			kc.exe
+			kl.exe
+			ksize.exe
+			kstrip.exe
+			limbo.exe
+			mk.exe
+			mkdir.exe
+			mkppcimage.exe
+			mkext.exe
+			ms2.exe
+			mv.exe
+			ndate.exe
+			ntsrv.exe
+			ntsrv4.exe
+			odbc.exe
+			qa.exe
+			qc.exe
+			ql.exe
+			rcsh.exe
+			rm.exe
+			sed.exe
+			sqz.exe
+			srclist.exe
+			tc.exe
+			test.exe
+			tr.exe
+			va.exe
+			vc.exe
+			vl.exe
+			iyacc.exe
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/Plan9
@@ -1,0 +1,36 @@
+Plan9
+	386
+		bin
+			emu.new	775	inferno	inferno	/Plan9/386/bin/emu
+			5a
+			5c
+			5l
+			asm
+			data2c
+			data2s
+			iar
+			limbo
+			inm
+		include
+			lib9.h
+			u.h
+		lib
+	mips
+		bin
+		include
+			lib9.h
+			u.h
+		lib
+	sparc
+		bin
+		include
+			lib9.h
+			os.h
+			u.h
+		lib
+	power
+		bin
+		include
+			lib9.h
+			u.h
+		lib
--- /dev/null
+++ b/lib/proto/Solaris
@@ -1,0 +1,46 @@
+Solaris
+	sparc
+		bin
+			emu.new	0775	inferno	inferno	/Solaris/sparc/bin/emu
+			0a
+			0c
+			0l
+			5a
+			5c
+			5cv
+			5coff
+			5l
+			8a
+			8c
+			8l
+			acid
+			asm
+			iar
+			data2c
+			data2s
+			ka
+			kc
+			kl
+			ksize
+			kstrip
+
+			limbo
+			mk
+			mkppcimage
+			mkext
+			ms2
+			ndate
+			inm
+			qa
+			qc
+			ql
+			sqz
+			srclist
+			tc
+			va
+			vc
+			vl
+			iyacc
+		include
+			+
+		lib
--- /dev/null
+++ b/lib/proto/inferno
@@ -1,0 +1,2443 @@
+CHANGES
+LICENCE
+NOTICE
+FreeBSD
+	386
+		bin
+		include
+		lib
+Hp
+	s800
+		bin
+		include
+		lib
+Irix
+	mips
+		bin
+		include
+		lib
+Linux
+	386
+		bin
+		include
+		lib
+	arm
+		bin
+		include
+		lib
+	power
+		bin
+		include
+		lib
+	spim
+		bin
+		include
+		lib
+MacOSX
+	386
+		bin
+		include
+		lib
+	power
+		bin
+		include
+		lib
+Nt
+	386
+		bin
+		include
+		lib
+Plan9
+	386
+		bin
+		include
+		lib
+	sparc
+		bin
+		include
+		lib
+	mips
+		bin
+		include
+		lib
+	power
+		bin
+		include
+		lib
+Solaris
+	sparc
+		bin
+		include
+		lib
+include
+	NOTICE
+	a.out.h
+	cursor.h
+	draw.h
+	drawif.h
+	dynld.h
+	fcall.h
+	freetype.h
+	freetype
+		+
+	interp.h
+	isa.h
+	kernel.h
+	keyboard.h
+	libsec.h
+	mathi.h
+	memdraw.h
+	memlayer.h
+	mp.h
+	pool.h
+	pooldefs.h
+	prefab.h
+	raise.h
+	rdbg.h
+	styx.h
+	tk.h
+	version.h
+	vm.h
+acme
+	+
+appl
+	NOTICE
+	acme
+		acme
+			acid
+				guide
+				mkfile
+				readme
+				src
+					Acid.b
+					Acid0.b
+					mkfile
+			bin
+				guide
+				mkfile
+				readme
+				src
+					adiff.b
+					agrep.b
+					awd.b
+					cd.b
+					mkfile
+					new.b
+					spout.b
+					win.b
+					winm.b
+			edit
+				guide
+				mkfile
+				readme
+				src
+					a.b
+					c.b
+					d.b
+					e.b
+					findfile.b
+					g.b
+					i.b
+					input.b
+					mkfile
+					p.b
+					pipe.b
+					x.b
+					xxx.b
+			mail
+				guide
+				mkbox.b
+				mkfile
+				readme
+				src
+					Mail.b
+					Mailp.b
+					Mailpop3.b
+					mashfile
+					mkfile
+			mkfile
+		acme.b
+		acme.m
+		buff.b
+		buff.m
+		col.b
+		col.m
+		common.m
+		dat.b
+		dat.m
+		disk.b
+		disk.m
+		ecmd.b
+		ecmd.m
+		edit.b
+		edit.m
+		elog.b
+		elog.m
+		exec.b
+		exec.m
+		file.b
+		file.m
+		frame.b
+		frame.m
+		fsys.b
+		fsys.m
+		graph.b
+		graph.m
+		gui.b
+		gui.m
+		look.b
+		look.m
+		mkfile
+		regx.b
+		regx.m
+		row.b
+		row.m
+		scrl.b
+		scrl.m
+		styxaux.b
+		styxaux.m
+		text.b
+		text.m
+		time.b
+		time.m
+		util.b
+		util.m
+		wind.b
+		wind.m
+		xfid.b
+		xfid.m
+	alphabet
+		abc
+			abc.b
+			autoconvert.b
+			autodeclare.b
+			declare.b
+			declares.b
+			define.b
+			eval.b
+			import.b
+			mkfile
+			newtypeset.b
+			rewrite.b
+			type.b
+			typeset.b
+			undeclare.b
+		alphabet.b
+		alphabet.shmod.b
+		auxi
+			endpoints.b
+			endpointsrv.b
+			fsfilter.b
+			mkfile
+			rexecsrv.b
+		eval.b
+		extvalues.b
+		fs
+			and.b
+			bundle.b
+			bundle.m
+			chstat.b
+			compose.b
+			depth.b
+			entries.b
+			exec.b
+			filter.b
+			ls.b
+			match.b
+			merge.b
+			mergewrite.b
+			mkext.b
+			mkfile
+			mode.b
+			newer.b
+			not.b
+			or.b
+			path.b
+			pipe.b
+			print.b
+			proto.b
+			query.b
+			run.b
+			select.b
+			setroot.b
+			size.b
+			unbundle.b
+			unbundle.m
+			walk.b
+			write.b
+		grid
+			farm.b
+			line2rec.b
+			local.b
+			mkfile
+			remote.b
+			rexec.b
+		main
+			auth.b
+			cat.b
+			create.b
+			dial.b
+			echo.b
+			export.b
+			fd.b
+			filter.b
+			genfilter.b
+			mkfile
+			mount.b
+			par.b
+			parse.b
+			pretty.b
+			print.b
+			read.b
+			readall.b
+			rewrite.b
+			rw.b
+			seq.b
+			unparse.b
+			w2fd.b
+			wait.b
+		mkfile
+		proxy.b
+		reports.b
+		typesets
+			abc.b
+			abctypes.b
+			fs.b
+			fstypes.b
+			grid.b
+			gridtypes.b
+			mkfile
+		declare.sh
+		fsdecl.sh
+		getendpoint.sh
+		mkendpoint.sh
+		rexecsrv.sh
+		setup
+		newtypesets
+		alphabet.proto
+	charon
+		build.b
+		build.m
+		charon.b
+		charon.m
+		chutils.b
+		chutils.m
+		common.m
+		cookiesrv.b
+		cookiesrv.m
+		ctype.b
+		ctype.m
+		date.b
+		date.m
+		event.b
+		event.m
+		file.b
+		ftp.b
+		gui.b
+		gui.m
+		http.b
+		img.b
+		img.m
+		jscript.b
+		layout.b
+		layout.m
+		lex.b
+		lex.m
+		mkfile
+		paginate.b
+		paginate.m
+		rgb.inc
+		script.m
+		transport.m
+		url.b
+		url.m
+		xxx.inc
+		ycbcr.inc
+	cmd
+		9win.b
+		9660srv.b
+		9export.b
+		9srvfs.b
+		B.b
+		ar.b
+		archfs.b
+		auplay.b
+		auth
+			aescbc.b
+			changelogin.b
+			countersigner.b
+			convpasswd.b
+			createsignerkey.b
+			dsagen.b
+			factotum
+				authio.m
+				mkfile
+				factotum.b
+				feedkey.b
+				proto
+					infauth.b
+					keyreps.b
+					keyreps.m
+					mkfile
+					p9any.b
+					pass.b
+				rpc.b
+			getpk.b
+			keyfs.b
+			keysrv.b
+			logind.b
+			mkauthinfo.b
+			mkfile
+			passwd.b
+			rsagen.b
+			secstore.b
+			signer.b
+			verify.b
+		auxi
+			cpuslave.b
+			digest.b
+			fpgaload.b
+			mangaload.b
+			mkfile
+			pcmcia.b
+			rdbgsrv.b
+			rstyxd.b
+		avr
+			burn.b
+			mkfile
+		basename.b
+		bind.b
+		bit2gif.b
+		broke.b
+		bytes.b
+		cal.b
+		calc.b
+		cat.b
+		cd.b
+		cddb.b
+		chgrp.b
+		chmod.b
+		cleanname.b
+		cmp.b
+		comm.b
+		cook.b
+		cp.b
+		cprof.b
+		cpu.b
+		crypt.b
+		date.b
+		dbfs.b
+		dbm
+			delete.b
+			fetch.b
+			keys.b
+			list.b
+			mkfile
+			store.b
+		dd.b
+		dial.b
+		diff.b
+		disdep.b
+		disdump.b
+		disk
+			format.b
+			ftl.b
+			kfs.b
+			kfscmd.b
+			mbr.b
+			mkext.b
+			mkfile
+			mkfs.b
+			prep
+				calc.tab.b
+				calc.tab.m
+				calc.y
+				fdisk.b
+				mkfile
+				pedit.b
+				pedit.m
+				prep.b
+		dossrv.b
+		du.b
+		echo.b
+		ed.b
+		emuinit.b
+		env.b
+		export.b
+		fc.b
+		fcp.b
+		fmt.b
+		fone.b
+		fortune.b
+		freq.b
+		fs.b
+		fs
+			and.b
+			bundle.b
+			chstat.b
+			compose.b
+			depth.b
+			entries.b
+			eval.b
+			exec.b
+			filter.b
+			ls.b
+			match.b
+			merge.b
+			mergewrite.b
+			mkfile
+			mode.b
+			not.b
+			or.b
+			path.b
+			pipe.b
+			print.b
+			proto.b
+			query.b
+			readfile.b
+			run.b
+			select.b
+			setroot.b
+			size.b
+			template.b
+			unbundle.b
+			void.b
+			walk.b
+			write.b
+		ftest.b
+		ftpfs.b
+		getauthinfo.b
+		getfile.b
+		gettar.b
+		gif2bit.b
+		grep.b
+		gunzip.b
+		gzip.b
+		idea.b
+		import.b
+		install
+			NOTICE
+			applylog.b
+			arch.b
+			arch.m
+			archfs.b
+			archfs.m
+			ckproto.b
+			create.b
+			eproto.b
+			info.b
+			inst.b
+			install.b
+			log.b
+			logs.b
+			logs.m
+			mergelog.b
+			mkfile
+			mkproto.b
+			proto.b
+			proto.m
+			proto2list.b
+			protocaller.m
+			updatelog.b
+			wdiff.b
+			wfind.b
+			wrap.b
+			wrap.m
+			wrap2list.b
+		iostats.b
+		ip
+			bootpd.b
+			dhcp.b
+			mkfile
+			nppp
+				mkfile
+				modem.b
+				modem.m
+				pppchat.b
+				ppplink.b
+				ppptest.b
+				script.b
+				script.m
+			ping.b
+			ppp
+				mkfile
+				modem.b
+				modem.m
+				pppclient.b
+				pppclient.m
+				pppdial.b
+				pppgui.b
+				pppgui.m
+				ppptest.b
+				script.b
+				script.m
+			rip.b
+			sntp.b
+			tftpd.b
+			virgild.b
+		irtest.b
+		itest.b
+		itreplay.b
+		kill.b
+		lego
+			clock.b
+			clockface.b
+			firmdl.b
+			link.b
+			mkfile
+			rcxsend.b
+			rcxsend.m
+			send.b
+			timers.b
+			timers.m
+		limbo
+			arg.m
+			asm.b
+			com.b
+			decls.b
+			dis.b
+			disoptab.m
+			ecom.b
+			gen.b
+			isa.m
+			lex.b
+			limbo.b
+			limbo.m
+			limbo.y
+			mkfile
+			nodes.b
+			opname.m
+			optim.b
+			sbl.b
+			stubs.b
+			typecheck.b
+			types.b
+		listen.b
+		lockfs.b
+		logfile.b
+		look.b
+		ls.b
+		lstar.b
+		m4.b
+		man2html.b
+		man2txt.b
+		manufacture.b
+		mash
+			builtins.b
+			depends.b
+			dump.b
+			exec.b
+			expr.b
+			eyacc.b
+			eyaccpar
+			history.b
+			lex.b
+			make.b
+			mash.b
+			mash.m
+			mash.y
+			mashfile
+			mashlib.b
+			mashparse.b
+			mashparse.m
+			misc.b
+			mkfile
+			serve.b
+			symb.b
+			tk.b
+			xeq.b
+		mc.b
+		md5sum.b
+		mdb.b
+		memfs.b
+		metamorph.b
+		mk
+			ar.m
+			mk.b
+			mkbinds
+			mkconfig
+			mkfile
+			mksubdirs
+		mkdir.b
+		mkfile
+		mntgen.b
+		mount.b
+		mouse.b
+		mpc
+			mkfile
+			qconfig.b
+			qflash.b
+		mprof.b
+		mv.b
+		ndb
+			mkfile
+			cs.b
+			csquery.b
+			dns.b
+			dnsquery.b
+			mkhash.b
+			query.b
+			registry.b
+			regquery.b
+		netkey.b
+		netstat.b
+		newer.b
+		ns.b
+		nsbuild.b
+		os.b
+		p.b
+		palm
+			connex.b
+			desklink.b
+			desklink.m
+			mkfile
+			palmsrv.b
+		pause.b
+		plumb.b
+		plumber.b
+		prof.b
+		promptstring.b
+		ps.b
+		puttar.b
+		pwd.b
+		ramfile.b
+		randpass.b
+		raw2iaf.b
+		rawdbfs.b
+		rcmd.b
+		rdp.b
+		read.b
+		rioimport.b
+		rm.b
+		runas.b
+		sed.b
+		sendmail.b
+		sh
+			arg.b
+			csv.b
+			doc
+				History
+			echo.b
+			expr.b
+			file2chan.b
+			mload.b
+			mkfile
+			mpexpr.b
+			regex.b
+			sexprs.b
+			sh.b
+			sh.y
+			std.b
+			string.b
+			test.b
+			tk.b
+		sha1sum.b
+		sleep.b
+		sort.b
+		spki
+			mkfile
+			verify.b
+		src.b
+		stack.b
+		stackv.b
+		stream.b
+		strings.b
+		styxchat.b
+		styxlisten.b
+		styxmon.b
+		sum.b
+		tail.b
+		tarfs.b
+		tclsh.b
+		tcs.b
+		tee.b
+		telnet.b
+		test.b
+		time.b
+		timestamp.b
+		tkcmd.b
+		tokenize.b
+		touch.b
+		touchcal.b
+		tr.b
+		trfs.b
+		tsort.b
+		unicode.b
+		units.b
+		units.y
+		uniq.b
+		unmount.b
+		usb
+			usbd.b
+			mkfile
+		uuencode.b
+		uudecode.b
+		vacfs.b
+		vacget.b
+		vacput.b
+		wav2iaf.b
+		wc.b
+		webgrab.b
+		wish.b
+		wmimport.b
+		wmexport.b
+		xargs.b
+		xd.b
+		xmount.b
+		yacc.b
+		zeros.b
+	collab
+		clients
+			chat.b
+			poll.b
+			poller.b
+			whiteboard.b
+		collabsrv.b
+		connect.b
+		lib
+			messages.b
+			messages.m
+		mkfile
+		proxy.b
+		proxy.m
+		runcollab
+		servers
+			chatsrv.b
+			memfssrv.b
+			mpx.b
+			wbsrv.b
+		service.m
+		srvmgr.b
+		srvmgr.m
+	demo
+		camera
+			camera.b
+			camload.bit
+			camproc.bit
+			mkfile
+			runcam.sh
+			runcamlocal.sh
+			tkinterface.b
+		chat
+			chat.b
+			chatclient.sh
+			chatsrv.b
+			mkfile
+		cpupool
+			mkfile
+			regpoll.b
+			runrstyx.sh
+		lego
+			clockface.b
+			clockreg.sh
+			firmdl.b
+			legolink.b
+			mkfile
+			rcxsend.b
+			rcxsend.m
+			styx.srec
+			timers.b
+			timers.m
+		mkfile
+		ns
+			mkfile
+			ns.b
+			runns.sh
+		odbc
+			mkfile
+			odbcmnt.b
+			runodbc.sh
+		spree
+			mkfile
+			spreeclient.sh
+		whiteboard
+			mkfile
+			runwb.sh
+			wbsrv.b
+			whiteboard.b
+	ebook
+		checkxml.b
+		cssfont.b
+		cssfont.m
+		cssparser.b
+		cssparser.m
+		dtd
+			*
+		ebook.b
+		mimeimage.b
+		mimeimage.m
+		mkfile
+		oebpackage.b
+		oebpackage.m
+		reader.b
+		reader.m
+		strcache.m
+		strmap.b
+		strmap.m
+		stylesheet.b
+		stylesheet.m
+		table.b
+		table.m
+		tst.txt
+		understandingoeb.opf
+		units.b
+		units.m
+	grid
+		README
+		demo
+			block.b
+			blur.b
+			mkfile
+		lib
+			announce.b
+			browser.b
+			browser.m
+			fbrowse.b
+			mkfile
+			pathreader.m
+			srvbrowse.b
+		mkfile
+		blurdemo.b
+		cpupool.b
+		find.b
+		jpg2bit.b
+		query.b
+		readjpg.b
+		register.b
+		reglisten.b
+		regstyxlisten.b
+		remotelogon.b
+		usercreatesrv.b
+	lib
+		NOTICE
+		arg.b
+		asn1.b
+		attrdb.b
+		attrhash.b
+		auth.b
+		auth9.b
+		bloomfilter.b
+		bufio.b
+		cfg.b
+		cfgfile.b
+		chanfill.b
+		complete.b
+		convcs
+			8bit_stob.b
+			big5_btos.b
+			big5_stob.b
+			convcs.b
+			cp_btos.b
+			cp_stob.b
+			cp932_btos.b
+			euc-jp_btos.b
+			gb2312_btos.b
+			genbig5.b
+			gencp.b
+			gencp932.b
+			gengb2312.b
+			genjisx0201kana.b
+			genjisx0208-1997.b
+			genjisx0212.b
+			ibm437.b
+			ibm850.b
+			ibm866.b
+			iso8859-1.b
+			iso8859-10.b
+			iso8859-15.b
+			iso8859-2.b
+			iso8859-3.b
+			iso8859-4.b
+			iso8859-5.b
+			iso8859-6.b
+			iso8859-7.b
+			iso8859-8.b
+			iso8859-9.b
+			koi8-r.b
+			mkdata
+			mkfile
+			utf8_btos.b
+			utf8_stob.b
+			utf16_btos.b
+			utf16_stob.b
+			windows-1250.b
+			windows-1251.b
+			windows-1252.b
+		crc.b
+		crypt
+			mkfile
+			pkcs.b
+			ssl3.b
+			sslsession.b
+			x509.b
+		csv.b
+		daytime.b
+		db.b
+		dbm.b
+		dbsrv.b
+		debug.b
+		deflate.b
+		devpointer.b
+		dhcpclient.b
+		dial.b
+		dialog.b
+		dict.b
+		dis.b
+		diskblocks.b
+		disks.b
+		dividers.b
+		ecmascript
+			builtin.b
+			date.b
+			ecmascript.b
+			exec.b
+			mkfile
+			obj.b
+			pprint.b
+			regexp.b
+			uri.b
+		encoding
+			base16.b
+			base32.b
+			base32a.b
+			base64.b
+			mkfile
+		env.b
+		ether.b
+		exception.b
+		factotum.b
+		filepat.b
+		format.b
+		fsfilter.b
+		fslib.b
+		fsproto.b
+		gamer.b
+		hash.b
+		html.b
+		ida
+			NOTICE
+			ida.b
+			idatab.b
+			idatest.b
+			mkfile
+			mktab.b
+			idatab.dis
+		imageremap.b
+		inflate.b
+		ip.b
+		ipattr.b
+		ir.b
+		irmpath.b
+		irsage.b
+		irsim.b
+		itslib.b
+		json.b
+		keyset.b
+		libc.b
+		libc0.b
+		lists.b
+		lock.b
+		login.b
+		man.b
+		memfs.b
+		mkfile
+		mpeg.b
+		msgio.b
+		nametree.b
+		names.b
+		newns.b
+		palm.b
+		palmdb.b
+		palmfile.b
+		parseman.b
+		plumbing.b
+		plumbing.m
+		plumbmsg.b
+		pop3.b
+		popup.b
+		powerman.b
+		print
+			hp_driver.b
+			mkfile
+			print.b
+			scaler.b
+			scaler.m
+		profile.b
+		pslib.b
+		quicktime.b
+		rand.b
+		random.b
+		readdir.b
+		readgif.b
+		readjpg.b
+		readpicfile.b
+		readpng.b
+		readxbitmap.b
+		regex.b
+		regexutils.b
+		registries.b
+		rfc822.b
+		riff.b
+		secstore.b
+		scoretable.b
+		scsiio.b
+		selectfile.b
+		sets.b
+		sets32.b
+		sexprs.b
+		slip.b
+		smtp.b
+		sort.b
+		spki
+			mkfile
+			spki.b
+			verifier.b
+		strokes
+			buildstrokes.b
+			mkfile
+			readstrokes.b
+			strokes.b
+			writestrokes.b
+		styxconv
+			mkfile
+			ostyx.b
+			ostyx.m
+			osys.m
+			styxconv.b
+		styxpersist.b
+		ssl.b
+		string.b
+		strinttab.b
+		styx.b
+		styxflush.b
+		styxlib.b
+		styxservers.b
+		tables.b
+		tabs.b
+		tcl.m
+		tcl_calc.b
+		tcl_core.b
+		tcl_inthash.b
+		tcl_io.b
+		tcl_list.b
+		tcl_modhash.b
+		tcl_stack.b
+		tcl_strhash.b
+		tcl_string.b
+		tcl_symhash.b
+		tcl_tk.b
+		tcl_utils.b
+		tftp.b
+		timers.b
+		titlebar.b
+		tkclient.b
+		translate.b
+		ubfa.b
+		url.b
+		usb
+			mkfile
+			usb.b
+			usbmass.b
+			usbmct.b
+			usbmouse.b
+		utils.m
+		vac.b
+		venti.b
+		virgil.b
+		volume.b
+		w3c
+			css.b
+			mkfile
+			uris.b
+			xpointers.b
+		wait.b
+		watchvars.b
+		winplace.b
+		wmclient.b
+		wmlib.b
+		wmsrv.b
+		workdir.b
+		writegif.b
+		xml.b
+	math
+		ack.b
+		crackerbarrel.b
+		doc.txt
+		factor.b
+		ffts.b
+		fibonacci.b
+		fit.b
+		genprimes.b
+		geodesy.b
+		gr.b
+		graph0.b
+		hist0.b
+		linalg.b
+		linbench.b
+		mersenne.b
+		mkfile
+		parts.b
+		perms.b
+		pi.b
+		polyfill.b
+		polyhedra.b
+		powers.b
+		primes.b
+		sieve.b
+	mkfile
+#	mux
+#		audioctl.b
+#		comics.b
+#		connect4.b
+#		email.b
+#		emio.b
+#		fnn.b
+#		gamed.b
+#		games.b
+#		mkfile
+#		movie.b
+#		mux.b
+#		news.b
+#		news.m
+#		othello.b
+#		paper.m
+#		pizza.b
+#		popmail.b
+#		readlnw.b
+#		readnews.b
+#		rec-pb.b
+#		register.b
+#		rmux.b
+#		rmuxslave.b
+#		tv.b
+#		tvlist.b
+#		web.b
+	spree
+		archives.b
+		gather.m
+		join.m
+		join.b
+		joinsession.b
+		joinsession.m
+		mkfile
+		spree.b
+		spree.m
+		clients
+			bounce.b
+			cards.b
+			chat.b
+			gather.b
+			lobby.b
+			othello.b
+		engines
+			afghan.b
+			bounce.b
+			canfield.b
+			chat.b
+			debug.b
+			freecell.b
+			gather.b
+			hearts.b
+			liars.b
+			liars.y
+			lobby.b
+			othello.b
+			racingdemon.b
+			snap.b
+			spider.b
+			spit.b
+			whist.b
+		lib
+			allow.b
+			allow.m
+			base64.b
+			base64.m
+			cardlib.b
+			cardlib.m
+			commandline.b
+			commandline.m
+			objstore.b
+			objstore.m
+			testsets.b
+			tricks.b
+			tricks.m
+		other
+			tst.b
+			tstboing.b
+			tstlines.sh
+			tstwin.b
+	svc
+		auth.sh
+		httpd
+			alarms.b
+			alarms.m
+			cache.b
+			cache.m
+			cgiparse.b
+			cgiparse.m
+			contents.b
+			contents.m
+			date.b
+			date.m
+			echo.b
+			httpd.b
+			httpd.m
+			httpd.debug
+			httpd.log
+			httpd.rewrite
+			httpd.suff
+			imagemap.b
+			mkfile
+			parser.b
+			parser.m
+			redirect.b
+			redirect.m
+			stats.b
+		mkfile
+		net.sh
+		registry.sh
+		rstyx.sh
+		styx.sh
+		webget
+			date.b
+			date.m
+			file.b
+			ftp.b
+			http.b
+			image2enc.b
+			image2enc.m
+			message.b
+			message.m
+			mkfile
+			transport.m
+			webget.b
+			webget.log
+			wgutils.b
+			wgutils.m
+	tiny
+		mkfile
+		rm.b
+		sh.b
+	wm
+		about.b
+		avi.b
+		bounce.b
+		brutus
+			excerpt.b
+			image.b
+			mkfile
+			mod.b
+			table.b
+		brutus.b
+		c4.b
+		calendar.b
+		clock.b
+		coffee.b
+		collide.b
+		colors.b
+		cprof.b
+		date.b
+		deb.b
+		debdata.b
+		debsrc.b
+		dir.b
+		drawmux
+			dmview.b
+			dmwm.b
+			drawmux.b
+			drawmux.m
+			drawoffs.m
+			mkfile
+		edit.b
+		filename.b
+		ftree
+			cptree.b
+			cptree.m
+			ftree.b
+			items.b
+			items.m
+			mkfile
+			wmsetup
+		getauthinfo.b
+		hebrew.m
+		keyboard.b
+		logon.b
+		logwindow.b
+		man.b
+		mand.b
+		mash.b
+		memory.b
+		minitel
+			README
+			event.b
+			event.m
+			keyb.b
+			miniterm.b
+			miniterm.m
+			mkfile
+			modem.b
+			screen.b
+			socket.b
+			swkeyb.b
+			swkeyb.m
+		mkfile
+		mpeg.b
+		mpeg
+			c0.tab
+			c0.vlc
+			c1.tab
+			c1.vlc
+			c2.tab
+			c2.vlc
+			c3.tab
+			c3.vlc
+			c4.tab
+			c4.vlc
+			c5.tab
+			c5.vlc
+			c6.tab
+			c6.vlc
+			c7.tab
+			c7.vlc
+			cbp.tab
+			cbp.vlc
+			cdc.tab
+			cdc.vlc
+			closest.m
+			decode.b
+			decode4.b
+			fixidct.b
+			fltidct.b
+			mai.tab
+			mai.vlc
+			makergbvmap.b
+			maketables
+			mbb.tab
+			mbb.vlc
+			mbi.tab
+			mbi.vlc
+			mbp.tab
+			mbp.vlc
+			mkfile
+			motion.tab
+			motion.vlc
+			mpeg.b
+			mpegio.b
+			mpegio.m
+			refidct.b
+			remap.b
+			remap1.b
+			remap2.b
+			remap24.b
+			remap4.b
+			remap8.b
+			rgbvmap.m
+			rl0f.tab
+			rl0f.vlc
+			rl0n.tab
+			rl0n.vlc
+			scidct.b
+			vlc.b
+			ydc.tab
+			ydc.vlc
+		mprof.b
+		pen.b
+		polyhedra.b
+		prof.b
+		qt.b
+		readmail.b
+		remotelogon.b
+		reversi.b
+		rmtdir.b
+		rt.b
+		sam.b
+		samstub.b
+		samstub.m
+		samterm.m
+		samtk.b
+		samtk.m
+		sendmail.b
+		sh.b
+		smenu.b
+		smenu.m
+		snake.b
+		stopwatch.b
+		sweeper.b
+		task.b
+		telnet.b
+		tetris.b
+		toolbar.b
+		unibrowse.b
+		view.b
+		vt.b
+		wish.b
+		wm.b
+		wmdeb.m
+		wmplay.b
+chan
+dev
+dis
+	9660srv.dis
+	9export.dis
+	9srvfs.dis
+	9win.dis
+	ar.dis
+	archfs.dis
+	B.dis
+	acme
+		+
+	acme.dis
+	alphabet
+		+
+	auhdr.dis
+	auplay.dis
+	auth
+		+
+	auxi
+		+
+	avr
+		+
+	basename.dis
+	bind.dis
+	broke.dis
+	bytes.dis
+	cal.dis
+	calc.dis
+	cat.dis
+	cd.dis
+	cddb.dis
+	charon
+		+
+	charon.dis
+	chgrp.dis
+	chmod.dis
+	cleanname.dis
+	cmp.dis
+	collab
+		+
+	comm.dis
+	cook.dis
+	cp.dis
+	cprof.dis
+	cpu.dis
+	crypt.dis
+	date.dis
+	dbfs.dis
+	dbm
+		+
+	dd.dis
+	demo
+		+
+	dial.dis
+	diff.dis
+	disdep.dis
+	disdump.dis
+	disk
+		+
+	dossrv.dis
+	du.dis
+	ebook
+		*
+	echo.dis
+	ed.dis
+	emuinit.dis
+	env.dis
+	export.dis
+	fc.dis
+	fcp.dis
+	fmt.dis
+	fone.dis
+	fortune.dis
+	freq.dis
+	fs.dis
+	fs
+		+
+	ftest.dis
+	ftpfs.dis
+	getauthinfo.dis
+	gettar.dis
+	grep.dis
+	grid
+		*
+		demo
+			*
+		lib
+			+
+	gunzip.dis
+	gzip.dis
+	idea.dis
+	import.dis
+	install
+		+
+	iostats.dis
+	ip
+		+
+	itest.dis
+	itreplay.dis
+	kill.dis
+	lc
+	lego
+		+
+	lib
+		arg.dis
+		asn1.dis
+		attrdb.dis
+		attrhash.dis
+		auth.dis
+		auth9.dis
+		bloomfilter.dis
+		bufio.dis
+		cfg.dis
+		cfgfile.dis
+		chanfill.dis
+		complete.dis
+		convcs
+			+
+		crc.dis
+		crypt
+			+
+		csv.dis
+		daytime.dis
+		db.dis
+		dbm.dis
+		dbsrv.dis
+		debug.dis
+		deflate.dis
+		devpointer.dis
+		dhcpclient.dis
+		dial.dis
+		dialog.dis
+		dict.dis
+		dis.dis
+		diskblocks.dis
+		disks.dis
+		dividers.dis
+		drawmux.dis
+		ecmascript.dis
+		encoding
+			+
+		env.dis
+		ether.dis
+		exception.dis
+		factotum.dis
+		filepat.dis
+		format.dis
+		fsfilter.dis
+		fslib.dis
+		fsproto.dis
+		ftree
+			+
+		gamer.dis
+		hash.dis
+		html.dis
+		ida
+			+
+		imageremap.dis
+		inflate.dis
+		ip.dis
+		ipattr.dis
+		ir.dis
+		irsage.dis
+		irsim.dis
+		itslib.dis
+		json.dis
+		keyset.dis
+		libc.dis
+		libc0.dis
+		lists.dis
+		lock.dis
+		login.dis
+		man.dis
+		mash
+			+
+		mashlib.dis
+		mashparse.dis
+		memfs.dis
+		mpeg.dis
+		msgio.dis
+		nametree.dis
+		names.dis
+		newns.dis
+		palm.dis
+		palmdb.dis
+		palmfile.dis
+		parseman.dis
+		plumbing.dis
+		plumbmsg.dis
+		pop3.dis
+		popup.dis
+		powerman.dis
+		print
+			+
+		profile.dis
+		pslib.dis
+		quicktime.dis
+		rand.dis
+		random.dis
+		readdir.dis
+		readgif.dis
+		readjpg.dis
+		readpicfile.dis
+		readpng.dis
+		readxbitmap.dis
+		regex.dis
+		regexutils.dis
+		registries.dis
+		rfc822.dis
+		riff.dis
+		secstore.dis
+		scoretable.dis
+		scsiio.dis
+		selectfile.dis
+		sets.dis
+		sets32.dis
+		sexprs.dis
+		slip.dis
+		smtp.dis
+		sort.dis
+		spki
+			*
+		ssl.dis
+		string.dis
+		strinttab.dis
+		strokes
+			+
+		styx.dis
+		styxconv
+			+
+		styxflush.dis
+		styxlib.dis
+		styxpersist.dis
+		styxservers.dis
+		tables.dis
+		tabs.dis
+		tcl_calc.dis
+		tcl_core.dis
+		tcl_inthash.dis
+		tcl_io.dis
+		tcl_list.dis
+		tcl_modhash.dis
+		tcl_stack.dis
+		tcl_strhash.dis
+		tcl_string.dis
+		tcl_symhash.dis
+		tcl_tk.dis
+		tcl_utils.dis
+		tftp.dis
+		timers.dis
+		titlebar.dis
+		tkclient.dis
+		translate.dis
+		ubfa.dis
+		url.dis
+		usb
+			usb.dis
+			usbmass.dis
+			usbmct.dis
+			usbmouse.dis
+		vac.dis
+		venti.dis
+		virgil.dis
+		volume.dis
+		w3c
+			+
+		wait.dis
+		watchvars.dis
+		winplace.dis
+		wmclient.dis
+		wmlib.dis
+		wmsrv.dis
+		workdir.dis
+		writegif.dis
+		xml.dis
+	limbo.dis
+	listen.dis
+	lockfs.dis
+	logfile.dis
+	look.dis
+	lookman
+	ls.dis
+	lstar.dis
+	m4.dis
+	man
+	man2html.dis
+	man2txt.dis
+	mash.dis
+	math
+		+
+	mc.dis
+	md5sum.dis
+	mdb.dis
+	memfs.dis
+	metamorph.dis
+	mk.dis
+	mkdir.dis
+	mntgen.dis
+	mount.dis
+	mouse.dis
+	mpc
+		+
+	mpeg
+		+
+	mprof.dis
+#	mux
+#		+
+	mv.dis
+	ndb
+		+
+	netkey.dis
+	netstat.dis
+	newer.dis
+	ns.dis
+	nsbuild.dis
+	os.dis
+	p.dis
+	palm
+		+
+	pause.dis
+	plumb.dis
+	plumber.dis
+	prof.dis
+	ps.dis
+	puttar.dis
+	pwd.dis
+	ramfile.dis
+	randpass.dis
+	raw2iaf.dis
+	rawdbfs.dis
+	rcmd.dis
+	rdp.dis
+	read.dis
+	rioimport.dis
+	rm.dis
+	runas.dis
+	sed.dis
+	sendmail.dis
+	sh
+		+
+	sh.dis
+	sha1sum.dis
+	shutdown
+	sleep.dis
+	sort.dis
+	spki
+		+
+	spree
+		+
+	src.dis
+	stack.dis
+	stream.dis
+	strings.dis
+	styxchat.dis
+	styxlisten.dis
+	styxmon.dis
+	sum.dis
+	svc
+		+
+	tail.dis
+	tarfs.dis
+	tclsh.dis
+	tcs.dis
+	tee.dis
+	telnet.dis
+	test.dis
+	time.dis
+	timestamp.dis
+	tiny
+		+
+	tkcmd.dis
+	tokenize.dis
+	touch.dis
+	touchcal.dis
+	tr.dis
+	trfs.dis
+	tsort.dis
+	unicode.dis
+	uniq.dis
+	unmount.dis
+	usb
+		usbd.dis
+	uudecode.dis
+	uuencode.dis
+	vacfs.dis
+	vacget.dis
+	vacput.dis
+	wav2iaf.dis
+	wc.dis
+	webgrab.dis
+	wish.dis
+	wm
+		about.dis
+		avi.dis
+		bounce.dis
+		brutus
+			*
+		brutus.dis
+		c4.dis
+		calendar.dis
+		chat.dis
+		clock.dis
+		coffee.dis
+		collide.dis
+		colors.dis
+		cprof.dis
+		date.dis
+		deb.dis
+		debdata.dis
+		debsrc.dis
+		dir.dis
+		dmview.dis
+		dmwm.dis
+		edit.dis
+		filename.dis
+		ftree.dis
+		getauthinfo.dis
+		keyboard.dis
+		logon.dis
+		logwindow.dis
+		man.dis
+		mand.dis
+		mash.dis
+		memory.dis
+		minitel
+			*
+		mpeg.dis
+		mprof.dis
+		pen.dis
+		polyhedra.dis
+		prof.dis
+		qt.dis
+		readmail.dis
+		remotelogon.dis
+		reversi.dis
+		rmtdir.dis
+		rt.dis
+		sendmail.dis
+		sh.dis
+		smenu.dis
+		snake.dis
+		stopwatch.dis
+		sweeper.dis
+		task.dis
+		telnet.dis
+		tetris.dis
+		toolbar.dis
+		unibrowse.dis
+		view.dis
+		vt.dis
+		wish.dis
+		wm.dis
+		wmplay.dis
+	wmimport.dis
+	wmexport.dis
+	xargs.dis
+	xd.dis
+	xmount.dis
+	yacc.dis
+	zeros.dis
+doc
+	20010618.ms
+	20010618.pdf
+	20011003.ms
+	20011003.pdf
+	20020628.ms
+	20020628.pdf
+	changes.ms
+	changes.pdf
+	acid.ms
+	acid.pdf
+	acidpaper.ms
+	acidpaper.pdf
+	acidtut.ms
+	acidtut.pdf
+	acme
+		acme.ms
+		acme.pdf
+	asm.ms
+	asm.pdf
+	backmatter.pdf
+	bltj.ms
+	bltj.pdf
+	compiler.ms
+	compiler.pdf
+	descent
+		descent.ms
+		descent.pdf
+	dev.ms
+	dev.pdf
+	dis.ms
+	dis.pdf
+	ebookimp.ms
+	ebookimp.pdf
+	fonts
+	fonts.pal
+	mkfile
+	frontmatter.pdf
+	gridinstall.ms
+	gridinstall.pdf
+	hotchips.ms
+	hotchips.pdf
+	install.ms
+	install.pdf
+	lprof.ms
+	lprof.pdf
+	limbo
+		limbo.rc
+		synsum
+		limbo.ms
+		limbo.pdf
+		addendum.ms
+		addendum.pdf
+		mkfile
+	lego.ms
+	lego.pdf
+	limbotk
+		tk.ms
+		tk.pdf
+	manhow.pdf
+	mk.ms
+	mk.pdf
+	perform
+		perform.ms
+		perform.pdf
+	port.ms
+	port.pdf
+	realinferno
+		real.ms
+		real.pdf
+	sh.ms
+	sh.pdf
+	styx.ms
+	styx.pdf
+env
+fonts
+	LICENCE
+	big5
+		+
+	charon
+		+
+	chinese
+		+
+	gb
+		+
+	jis
+		+
+	lucida
+		+
+	lucidasans
+		+
+	lucm
+		+
+	minitel
+		+
+	misc
+		+
+	pelm
+		+
+	psrename
+icons
+	+
+keydb
+	countersigned
+	keys 600 inferno inferno /keydb/keys.dist
+	signed
+lib
+	acid
+		+
+	convcs
+		+
+	ebook
+		+
+	ebooks
+		+
+	emptydirs
+	games
+		+
+	keyboard
+	legal
+		*
+	lego
+		*
+	mashinit
+	mimetype
+	mk
+		*
+	ndb
+		common
+		dns	664	inferno inferno /lib/ndb/dns.dist
+		inferno
+		local 664	inferno inferno /lib/ndb/local.dist
+		registry 664	inferno inferno /lib/ndb/registry.dist
+		services
+	polyhedra
+	polyhedra.all
+	print
+		*
+	proto
+		FreeBSD
+		Hp
+		Irix
+		Linux
+		MacOSX
+		Nt
+		Plan9
+		Solaris
+		inferno
+		src
+		utils
+	scsicodes
+	scores
+		+
+	sexp
+	sh
+		+
+	strokes
+		+
+	tbsetup
+	unicode
+	unidata
+		+
+	units
+	usbdb
+	video.specs
+	wmcharon
+	wmsetup
+	wmsetup.grid
+	words
+	yaccpar
+locale
+	NOTICE
+	Australia_ACT
+	Australia_Broken-Hill
+	Australia_LHI
+	Australia_NSW
+	Australia_North
+	Australia_Queensland
+	Australia_South
+	Australia_Sturt
+	Australia_Tasmania
+	Australia_Victoria
+	Australia_West
+	Australia_Yancowinna
+	Brazil_Acre
+	Brazil_DeNoronha
+	Brazil_East
+	Brazil_West
+	CET
+	CST.CDT
+	Canada_Atlantic
+	Canada_Central
+	Canada_East-Saskatchewan
+	Canada_Eastern
+	Canada_Mountain
+	Canada_Newfoundland
+	Canada_Pacific
+	Canada_Yukon
+	Chile_Continental
+	Chile_EasterIsland
+	Cuba
+	EET
+	EST.EDT
+	Egypt
+	GB-Eire
+	GMT
+	HST
+	Hongkong
+	Iceland
+	Iran
+	Israel
+	Jamaica
+	Japan
+	Libya
+	MET
+	MST.MDT
+	Mexico_BajaNorte
+	Mexico_BajaSur
+	Mexico_General
+	NZ
+	NZ_CHAT
+	Navajo
+	PRC
+	PST.PDT
+	Poland
+	README
+	ROC
+	ROK
+	Singapore
+	Turkey
+	US_Alaska
+	US_Arizona
+	US_Central
+	US_East-Indiana
+	US_Eastern
+	US_Hawaii
+	US_Michigan
+	US_Mountain
+	US_Pacific
+	US_Yukon
+	W-SU
+	WET
+	en_US
+		dict
+			calendar
+		location
+	location
+	timezone
+mail
+man
+	1
+		+
+	2
+		+
+	3
+		+
+	4
+		+
+	5
+		+
+	6
+		+
+	7
+		+
+	8
+		+
+	9
+		+
+	10
+		+
+	index
+mkconfig
+mkfiles
+	*
+mnt
+	*
+	spki
+		keys
+module
+	NOTICE
+	alphabet.m
+	alphabet
+		+
+	arg.m
+	asn1.m
+	attrdb.m
+	auth9.m
+	bench.m
+	bloomfilter.m
+	brutus.m
+	brutusext.m
+	bufio.m
+	bundle.m
+	cci.m
+	cfg.m
+	cfgfile.m
+	complete.m
+	convcs.m
+	crc.m
+	css.m
+	csv.m
+	cvsimages.m
+	daytime.m
+	db.m
+	dbm.m
+	debug.m
+	devpointer.m
+	dhcp.m
+	dial.m
+	dialog.m
+	dict.m
+	dis.m
+	diskblocks.m
+	disks.m
+	dividers.m
+	draw.m
+	ecmascript.m
+	emio.m
+	encoding.m
+	env.m
+	ether.m
+	exception.m
+	factotum.m
+	ffts.m
+	filepat.m
+	filter.m
+	format.m
+	freetype.m
+	fslib.m
+	fsproto.m
+	gamer.m
+	gr.m
+	grid
+		announce.m
+		browse.m
+		browser.m
+		demo
+			exproc.m
+			block.m
+		fbrowse.m
+		pathreader.m
+		readjpg.m
+		regpoll.m
+		srvbrowse.m
+	hash.m
+	html.m
+	ida.m
+	imagefile.m
+	inflate.m
+	ip.m
+	ipattr.m
+	ir.m
+	itslib.m
+	json.m
+	keyboard.m
+	keyring.m
+	keyset.m
+	libc.m
+	libc0.m
+	linalg.m
+	lists.m
+	loader.m
+	lock.m
+	man.m
+	math.m
+	math
+		*
+	memfs.m
+	mpeg.m
+	msgio.m
+	multistyx.m
+	muxclient.m
+	names.m
+	newns.m
+	palm.m
+	palmfile.m
+	pkcs.m
+	plumbmsg.m
+	pop3.m
+	popup.m
+	powerman.m
+	prefab.m
+	print.m
+	profile.m
+	pslib.m
+	quicktime.m
+	rand.m
+	readdir.m
+	regex.m
+	regexutils.m
+	registries.m
+	rfc822.m
+	riff.m
+	runt.m
+	scoretable.m
+	scsiio.m
+	secstore.m
+	security.m
+	selectfile.m
+	sets.m
+	sets32.m
+	sexprs.m
+	sh.m
+	smtp.m
+	sort.m
+	spki.m
+	strokes.m
+	srv.m
+	srvrunt.b
+	ssl3.m
+	sslsession.m
+	string.m
+	strinttab.m
+	styx.m
+	styxconv.m
+	styxflush.m
+	styxlib.m
+	styxpersist.m
+	styxservers.m
+	sys.m
+	tables.m
+	tabs.m
+	tcllib.m
+	tftp.m
+	timers.m
+	titlebar.m
+	tk.m
+	tkclient.m
+	translate.m
+	ubfa.m
+	unbundle.m
+	uris.m
+	url.m
+	usb.m
+	vac.m
+	venti.m
+	volume.m
+	wait.m
+	watchvars.m
+	webget.m
+	winplace.m
+	wmclient.m
+	wmlib.m
+	wmsrv.m
+	workdir.m
+	x509.m
+	xml.m
+	xpointers.m
+n
+	cd
+	client
+		chan
+		dev
+	disk
+	dist
+	dump
+	ftp
+	kfs
+	local
+	rdbg
+	registry
+	remote
+net
+net.alt
+nvfs
+prof
+prog
+services
+	httpd
+		httpd.rewrite
+		httpd.suff
+	logs
+	ppp
+	webget
+		help.html
+		inferno.gif
+		start.html
+		vnlogo.gif
+src
+sys
+#mux
+#	basic
+#	email
+#		+
+#	comics
+#		+
+#	namespace
+#	namespace.init
+#	news
+#		+
+#	pizza
+#		+
+#	price
+#	rec-pb
+#		+
+#	tvlist
+#		+
+tmp
+usr
+	inferno
+		charon
+		keyring
+		lib
+			plumbing
+		namespace
+wrap
--- /dev/null
+++ b/lib/proto/os
@@ -1,0 +1,1000 @@
+Inferno
+	386
+		bin
+		include
+			*
+		lib
+	arm
+		bin
+		include
+			*
+		lib
+	mips
+		bin
+		include
+			*
+		lib
+	power
+		bin
+		include
+			*
+		lib
+	sparc
+		bin
+		include
+			*
+		lib
+	spim
+		bin
+		include
+			*
+		lib
+	thumb
+		bin
+		include
+			*
+		lib
+include
+	flate.h
+	kern.h
+	logfs.h
+	nandecc.h
+	nandfs.h
+	trace.h
+lib
+	proto
+		os
+libkern
+	NOTICE
+	abort.c
+	abs.c
+	atol.c
+	charstod.c
+	cistrcmp.c
+	cistrncmp.c
+	cistrstr.c
+	cleanname.c
+	convD2M.c
+	convM2D.c
+	convM2S.c
+	convS2M.c
+	div-arm.s
+	dofmt.c
+	exp.c
+	fcallfmt.c
+	floor.c
+	fmt.c
+	fmtdef.h
+	fmtprint.c
+	fmtquote.c
+	fmtstr.c
+	fmtvprint.c
+	frexp-386.c
+	frexp-68000.c
+	frexp-arm.c
+	frexp-mips.c
+	frexp-power.c
+	frexp-sparc.c
+	frexp-spim.c
+	frexp-thumb.c
+	getfcr-386.s
+	getfcr-68000.s
+	getfcr-arm.s
+	getfcr-mips.s
+	getfcr-power.s
+	getfcr-sparc.s
+	getfcr-spim.s
+	getfcr-thumb.s
+	getfields.c
+	log.c
+	memccpy-power.s
+	memccpy.c
+	memchr.c
+	memcmp-power.s
+	memcmp.c
+	memmove.c
+	memmove-386.s
+	memmove-68000.s
+	memmove-arm.s
+	memmove-mips.s
+	memmove-power.s
+	memmove-spim.s
+	memmove-sparc.s
+	memmove-thumb.s
+	memset-386.s
+	memset-68000.s
+	memset-arm.s
+	memset-mips.s
+	memset-power.s
+	memset-sparc.s
+	memset-spim.s
+	memset-thumb.s
+	memset.c
+	mkfile
+	mkfile-386
+	mkfile-68000
+	mkfile-arm
+	mkfile-mips
+	mkfile-power
+	mkfile-sparc
+	mkfile-spim
+	mkfile-thumb
+	muldiv-68000.s
+	nan-386.c
+	nan-68000.c
+	nan-arm.c
+	nan-mips.c
+	nan-power.c
+	nan-spim.c
+	nan-sparc.c
+	nan-thumb.c
+	netmkaddr.c
+	pow.c
+	pow10.c
+	qsort.c
+	rune.c
+	runestrlen.c
+	seprint.c
+	sin.c
+	smprint.c
+	snprint.c
+	sqrt.c
+	strcat.c
+	strchr-386.s
+	strchr-68000.s
+	strchr-arm.s
+	strchr-mips.c
+	strchr-mips.s
+	strchr-power.s
+	strchr-sparc.s
+	strchr-spim.c
+	strchr-thumb.s
+	strchr.c
+	strcmp-power.s
+	strcmp.c
+	strcpy.c
+	strdup.c
+	strecpy.c
+	strlen.c
+	strncmp-power.s
+	strncmp.c
+	strncpy.c
+	strrchr.c
+	strstr.c
+	strtod.c
+	strtol.c
+	strtoll.c
+	strtoul.c
+	strtoull.c
+	tokenize.c
+	toupper.c
+	u16.c
+	u32.c
+	u64.c
+	utfecpy.c
+	utflen.c
+	utfnlen.c
+	utfrrune.c
+	utfrune.c
+	vlop-386.s
+	vlop-arm.s
+	vlop-mips.s
+	vlop-power.s
+	vlop-sparc.s
+	vlop-spim.s
+	vlop-thumb.s
+	vlrt-386.c
+	vlrt-68000.c
+	vlrt-arm.c
+	vlrt-mips.c
+	vlrt-power.c
+	vlrt-sparc.c
+	vlrt-spim.c
+	vlrt-thumb.c
+	vseprint.c
+	vsmprint.c
+	vsnprint.c
+libnandfs
+	NOTICE
+	calcformat.c
+	correctauxilliary.c
+	ecc.c
+	eraseblock.c
+	extracttags.c
+	findfreeblock.c
+	formatblock.c
+	getblockstatus.c
+	hamming31_26.c
+	init.c
+	local.h
+	markblockbad.c
+	mkfile
+	open.c
+	readblock.c
+	readpage.c
+	readpageauxilliary.c
+	reformatblock.c
+	setget.c
+	updatepage.c
+	writeblock.c
+	writepageauxilliary.c
+liblogfs
+	NOTICE
+	boot.c
+	clunk.c
+	conv.c
+	create.c
+	dump.c
+	error.c
+	extentlist.c
+	fidmap.c
+	findfreeblock.c
+	flush.c
+	format.c
+	gn.c
+	group.c
+	groupset.c
+	is.c
+	local.h
+	log.c
+	map.c
+	mkfile
+	open.c
+	path.c
+	perm.c
+	read.c
+	remove.c
+	replace.c
+	replay.c
+	scan.c
+	srv.c
+	sweep.c
+	tagname.c
+	test.c
+	ust.c
+	walk.c
+	write.c
+	wstat.c
+os
+	NOTICE
+	README
+	boot
+		README
+		libflate
+			LICENCE
+			NOTICE
+			adler.c
+			crc.c
+			deflate.c
+			deflateblock.c
+			deflatezlib.c
+			deflatezlibblock.c
+			flateerr.c
+			inflate.c
+			inflateblock.c
+			inflatezlib.c
+			inflatezlibblock.c
+			mkfile
+			zlib.h
+		arm1110
+			Mk
+			dat.h
+			donprint.c
+			fns.h
+			il.s
+			imain.c
+			inflate.c
+			io.h
+			l.s
+			lib.h
+			map
+			mem.h
+			mkfile
+			print.c
+			uart.c
+		mpc
+			NOTICE
+			alarm.c
+			all.h
+			archfads.c
+			archfads.h
+			archpaq.c
+			archpaq.h
+			boot.h
+			bootp.c
+			clock.c
+			conf.c
+			console.c
+			cpm.c
+			crc32.c
+			dat.h
+			defont0.c
+			dload.c
+			donprint.c
+			dosboot.c
+			dosfs.h
+			devether.c
+			etherif.h
+			etherscc.c
+			fblt.c
+			flash.c
+			fns.h
+			gbitbltclip.c
+			gnot.h
+			i2c.c
+			initfads.c
+			initpaq.c
+			initrpcg.c
+			io.h
+			ip.h
+			l.s
+			lib.h
+			main.c
+			mem.c
+			mem.h
+			mkfile
+			ms2.c
+			plan9boot.c
+			qio.c
+			rmap.c
+			screen.c
+			sload.c
+			squeeze.h
+			trap.c
+			devuart.c
+			uartboot.c
+			ureg.h
+			zqs.c
+		pc
+			8250.c
+			LICENCE
+			NOTICE
+			ahci.h
+			alarm.c
+			aoe.h
+			apm.c
+			bcom.c
+			boot.c
+			bootld.c
+			bootp.c
+			cga.c
+			cis.c
+			clock.c
+			conf.c
+			console.c
+			dat.h
+			devbios.c
+			devbios.h
+			devfloppy.c
+			devfloppy.h
+			devi82365.c
+			devpccard.c
+			devsd.c
+			dma.c
+			dosboot.c
+			dosfs.h
+			eipfmt.c
+			error.h
+			ether.c
+			ether2000.c
+			ether2114x.c
+			ether589.c
+			ether79c970.c
+			ether8003.c
+			ether8139.c
+			ether8169.c
+			ether82557.c
+			ether82563.c
+			ether83815.c
+			ether8390.c
+			ether8390.h
+			etherdp83820.c
+			etherec2t.c
+			etherelnk3.c
+			etherelnk3x.c
+			etherga620.c
+			etherga620fw.h
+			etherif.h
+			etherigbe.c
+			ethermii.c
+			ethermii.h
+			etherrhine.c
+			fns.h
+			fs.c
+			fs.h
+			getcallerpc.c
+			ilock.c
+			inflate.c
+			io.h
+			ip.h
+			kbd.c
+			kfs.h
+			kfsboot.c
+			l.s
+			lib.h
+			load.c
+			mbr.s
+			mem.h
+			memory.c
+			mkfile
+			noether.c
+			part.c
+			pbs.s
+			pbsdisk
+			pbsdisk.s
+			pbsdisklba
+			pbsdisklba.s
+			pbslba.s
+			pci.c
+			print.c
+			queue.c
+			sd.h
+			sd53c8xx.c
+			sd53c8xx.i
+			sdaoe.c
+			sdata.c
+			sdbios.c
+			sdiahci.c
+			sdmylex.c
+			sdscsi.c
+			trap.c
+			ureg.h
+			x16.h
+		puma
+			8250.c
+			alarm.c
+			armv4.h
+			boot.h
+			bootp.c
+			cga.c
+			clock.c
+			conf.c
+			console.c
+			dat.h
+			div.s
+			donprint.c
+			dosboot.c
+			dosfs.h
+			ebsit.trap.c
+			ether.c
+			ether.h
+			ether8900.c
+			flash.c
+			fns.h
+			hard.c
+			io.h
+			ip.h
+			kbd.c
+			l.s
+			lib.h
+			main.c
+			mem.h
+			mkfile
+			outb.c
+			plan9boot.c
+			puma.c
+			puma.h
+			qio.c
+			rmap.c
+			squeeze.h
+			sum.c
+			trap.c
+			ureg.h
+			zqs.c
+		rpcg
+			NOTICE
+			alarm.c
+			all.h
+			archrpcg.c
+			archrpcg.h
+			boot.h
+			bootp.c
+			clock.c
+			conf.c
+			console.c
+			cpm.c
+			crc32.c
+			dat.h
+			defont0.c
+			devether.c
+			devuart.c
+			dload.c
+			donprint.c
+			dosboot.c
+			dosfs.h
+			etherif.h
+			etherscc.c
+			fblt.c
+			flash.c
+			fns.h
+			g.mx
+			gbitbltclip.c
+			gnot.h
+			i2c.c
+			initfads.c
+			initpaq.c
+			initrpcg.c
+			io.h
+			ip.h
+			l.s
+			lib.h
+			libg.h
+			main.c
+			mem.c
+			mem.h
+			mkfile
+			ms2.c
+			plan9boot.c
+			qbromrpcg
+			qio.c
+			rmap.c
+			screen.c
+			sload
+			sload.c
+			squeeze.h
+			trap.c
+			uartboot.c
+			ureg.h
+			zqs.c
+	cerf1110
+		Mk
+		NOTICE
+		README
+		archcerf.c
+		cerf
+		dat.h
+		devata.c
+		devcerf.c
+		ether8900.c
+		fns.h
+		io.h
+		main.c
+		mem.h
+		mkfile
+	cerf250
+		NOTICE
+		README
+		archcerf.c
+		cerf
+		dat.h
+#		devata.c
+#		devcerf.c
+		devpcf8563.c
+		ether91c111.c
+		fns.h
+		io.h
+		main.c
+		mem.h
+		mkfile
+		uart.h
+	cerf405
+		NOTICE
+		README
+		cerf
+		clock.c
+		compile.c
+		dat.h
+		devboot.c
+		devether.c
+		devrtc.c
+		devuart.c
+		etheremac.c
+		etherif.h
+		fns.h
+		fpi.h
+		fpipower.c
+		gpio.c
+		iic.c
+		inb.s
+		io.h
+		l.s
+		main.c
+		mal.c
+		mem.h
+		mkfile
+		mmu.c
+		nand.c
+		nofp.s
+		pci.c
+		physmem.h
+		powerbreak.c
+		rmap.c
+		tlb.s
+		trap.c
+		uart.c
+		uart.h
+	fads
+		NOTICE
+		archfads.c
+		archfads.h
+		dat.h
+		fads
+		fns.h
+		io.h
+		main.c
+		mem.h
+		mkfile
+		mmu.c
+		tlb.s
+	init
+		README
+		bootinit.b
+		cerf405.b
+		cerfinit.b
+		evalinit.b
+		geninit.b
+		i4e.b
+		init.b
+		ipaqinit.b
+		ipeinit.b
+		jsinit.b
+		mkfile
+		mpcinit.b
+		pcdemo.b
+		pcinit.b
+		reminit.b
+		rpcginit.b
+		soeinit.b
+		shell.b
+		srvinit.b
+		wminit.b
+	ip
+		*
+	ipaq1110
+		Mk
+		NOTICE
+		README
+		archipaq.c
+		dat.h
+		defont.c
+		devaudio.c
+		devipaq.c
+		etherwavelan.c
+		fns.h
+		inflate
+		io.h
+		ipaq
+		lcd.c
+		main.c
+		mem.h
+		mkfile
+		screen.c
+		screen.h
+		tstdraw.b
+		upd
+	ipengine
+		NOTICE
+		README
+		archipe.c
+		archipe.h
+		dat.h
+		devfpga.c
+		flash28f320b3b.c
+		fns.h
+		fpga
+		io.h
+		ipe
+		main.c
+		mem.h
+		mkfile
+		mmu.c
+		tlb.s
+	js
+		README
+		audio.h
+		clock.c
+		cs4231.h
+		dat.h
+		devcs4231.c
+		devrtc.c
+		fns.h
+		fsv.c
+		io.h
+		js
+		kbd.c
+		l.s
+		main.c
+		mem.h
+		mkfile
+		mmu.c
+		ns16552.h
+		iob.c
+		rom.c
+		rom.h
+		screen.c
+		screen.h
+		softcursor.h
+		superio.c
+		trap.c
+		ureg.h
+	ks32
+		Mk
+		NOTICE
+		archevaluator7t.c
+		armv7.h
+		clock.c
+		dat.h
+		devuart.c
+		download.ps
+		evaluator7t
+		fns.h
+		fpi.h
+		fpiarm.c
+		io.h
+		l.s
+		main.c
+		mem.h
+		mkfile
+		not.c
+		squirt
+		trap.c
+	mpc
+		800io.h
+		NOTICE
+		clock.c
+		cpm.c
+		cpmtimer.c
+		devata.c
+		devbench.c
+		devboot.c
+		devether.c
+		devpcmcia.c
+		devrtc.c
+		devtouch.c
+		devuart.c
+#		devusb.c
+#		devusbc.c
+#		devusbh.c
+#		devvid.c
+		dsp.c
+		dsp.h
+		etherif.h
+		etherscc.c
+		faultpower.c
+		fp.s
+		fpi.h
+		fpipower.c
+		i2c.c
+		i2c_spi.srx
+		inb.s
+		kbd.c
+		l.s
+		nofp.s
+		pcmcia.h
+		pit.c
+		powerbreak.c
+		rmap.c
+		screen.c
+		screen.h
+		spi.c
+		trap.c
+		usb.h
+	pc
+		NOTICE
+		README
+		apbootstrap.h
+		apbootstrap.s
+		apic.c
+		apm.c
+		apmjump.s
+		archmp.c
+		audio.h
+		cga.c
+		cgamemscr.c
+		crystal.h
+		dat.h
+		devarch.c
+		devds1620.c
+		devether.c
+		devfloppy.c
+		devi82365.c
+		devlm78.c
+		devlpt.c
+		devmouse.c
+		devmpeg.c
+		devpccard.c
+		devpnp.c
+		devrtc.c
+		devtv.c
+		devusb.c
+		devvga.c
+		devzt5512.c
+		dma.c
+		ether2000.c
+		ether2114x.c
+		ether589.c
+		ether79c960.c
+		ether79c970.c
+		ether8003.c
+		ether8139.c
+		ether82543gc.c
+		ether82557.c
+		ether83815.c
+		ether8390.c
+		ether8390.h
+		etherec2t.c
+		etherelnk3.c
+		etherga620.c
+		etherga620fw.h
+		etherif.h
+		etherigbe.c
+		etherrhine.c
+		ethersmc.c
+		etherwavelan.c
+		flashif.h
+		flashzpc.c
+		floppy.h
+		fns.h
+		fpi.h
+		fpi387.c
+		fpsave.s
+		i8250.c
+		i8253.c
+		i8259.c
+		io.h
+		kbd.c
+		l.s
+		main.c
+		mem.h
+		memory.c
+		mkfile
+		mmu.c
+		mouse.c
+		mp.c
+		mp.h
+		pc
+		pc4e
+		pcdisk
+		pci.acid
+		pci.c
+		pcidb.acid
+		pcmciamodem.c
+		piix4smbus.c
+		pix
+		ps2mouse.c
+		ptclbsum386.s
+		screen.c
+		screen.h
+		sd53c8xx.c
+		sd53c8xx.i
+		sd53c8xx.n
+		sdata.c
+		sdmylex.c
+		sdscsi.c
+		trap.c
+		tv.h
+		uarti8250.c
+		uartisa.c
+		uartpci.c
+		usb.h
+		usbuhci.c
+		vga.c
+		vga.h
+		vga3dfx.c
+		vgaark2000pv.c
+		vgabt485.c
+		vgaclgd542x.c
+		vgaclgd546x.c
+		vgact65545.c
+		vgacyber938x.c
+		vgaet4000.c
+		vgahiqvideo.c
+		vgai81x.c
+		vgamach64xx.c
+		vgamga2164w.c
+		vgamga4xx.c
+		vganeomagic.c
+		vganvidia.c
+		vgargb524.c
+		vgas3.c
+		vgasavage.c
+		vgat2r4.c
+		vgatvp3020.c
+		vgatvp3026.c
+		vgavmware.c
+		vgax.c
+		wavelan.c
+		wavelan.h
+		x86break.c
+		zoran.h
+	port
+		*
+	pxa
+		NOTICE
+		clock.c
+		devether.c
+#		devgpio.c
+#		devpcmcia.c
+#		devpower.c
+		devrtc.c
+		devuart.c
+#		devuart0.c
+		dma.c
+		etherif.h
+		fpi.h
+		fpiarm.c
+		gpio.c
+#		gscreen.c
+#		gscreen.h
+		i2c.c
+		l.s
+		mmu.c
+		pxaio.h
+		sa1110break.c
+#		softcursor.c
+#		suspend.c
+		trap.c
+	omap
+		README
+	manga
+		Mk
+		archmanga.c
+		clock.c
+		dat.h
+#		devesw.c
+		devether.c
+		devusb.c
+#		esw.c
+#		esw.h
+		eswnotes
+		ether8139.c
+		etherif.h
+		etherks8695.c
+		flashif.h
+		fns.h
+		fpi.h
+		fpiarm.c
+		gpio.c
+		inb.c
+		io.h
+		ioring.c
+		l.s
+		main.c
+		manga
+		mem.h
+		mkfile
+		mmu.c
+		pci.c
+		pinflate
+		trap.c
+		uartks8695.c
+		usb.h
+		usbuhci.c
+	rpcg
+		NOTICE
+		archrpcg.c
+		archrpcg.h
+		clock.c
+		dat.h
+		fns.h
+		io.h
+		main.c
+		mem.h
+		mkfile
+		mmu.c
+		rpcg
+		tlb.s
+	sa1110
+		clock.c
+		devether.c
+		devgpio.c
+		devpcmcia.c
+		devpower.c
+		devrtc.c
+		devuart.c
+		dma.c
+		etherif.h
+		fpi.h
+		fpiarm.c
+		gscreen.c
+		gscreen.h
+		i2c.h
+		i2cgpio.c
+		l.s
+		l3gpio.c
+		mmu.c
+		sa1110break.c
+		sa1110io.h
+		softcursor.c
+		suspend.c
+		trap.c
--- /dev/null
+++ b/lib/proto/src
@@ -1,0 +1,825 @@
+INSTALL
+include
+	styxserver.h
+asm
+	NOTICE
+	asm.h
+	asm.y
+	assem.c
+	lex.c
+	mkfile
+emu
+	NOTICE
+	mkfile
+	port
+		*
+	Plan9
+		asm-386.s
+		asm-mips.s
+		asm-power.s
+		asm-sparc.s
+		cmd.c
+		devfs.c
+		devsrv9.c
+		emu
+		emusig
+		mkfile
+		os.c
+		win.c
+	FreeBSD
+		+
+	Hp
+		+
+	Irix
+		+
+	Linux
+		+
+	MacOSX
+		+
+	Nt
+		+
+	Solaris
+		+
+	Unixware
+		+
+libdraw
+	NOTICE
+	alloc.c
+	allocimagemix.c
+	arith.c
+	bezier.c
+	border.c
+	buildfont.c
+	bytesperline.c
+	chan.c
+	cloadimage.c
+	computil.c
+	creadimage.c
+	defont.c
+	draw.c
+	drawrepl.c
+	ellipse.c
+	font.c
+	freesubfont.c
+	getdefont.c
+	getsubfont.c
+	init.c
+	line.c
+	loadimage.c
+	mkfile
+	mkfont.c
+	openfont.c
+	poly.c
+	readcolmap.c
+	readimage.c
+	readsubfont.c
+	rectclip.c
+	replclipr.c
+	rgb.c
+	string.c
+	stringbg.c
+	stringsubfont.c
+	stringwidth.c
+	subfont.c
+	subfontcache.c
+	subfontname.c
+	test.c
+	unloadimage.c
+	window.c
+	writecolmap.c
+	writeimage.c
+	writesubfont.c
+libdynld
+	NOTICE
+	dynld-386.c
+	dynld-68000.c
+	dynld-arm.c
+	dynld-mips.c
+	dynld-power.c
+	dynld-sparc.c
+	dynld-spim.c
+	dynld.c
+	dynloadfd.c
+	mkfile
+libfreetype
+	NOTICE
+		+
+	adler32.c
+	ahangles.c
+	ahangles.h
+	aherrors.h
+	ahglobal.c
+	ahglobal.h
+	ahglyph.c
+	ahglyph.h
+	ahhint.c
+	ahhint.h
+	ahloader.h
+	ahmodule.c
+	ahmodule.h
+	ahoptim.c
+	ahoptim.h
+	ahtypes.h
+	autohint.c
+	bdf.c
+	bdf.h
+	bdfdrivr.c
+	bdfdrivr.h
+	bdferror.h
+	bdflib.c
+	cff.c
+	cffcmap.c
+	cffcmap.h
+	cffdrivr.c
+	cffdrivr.h
+	cfferrs.h
+	cffgload.c
+	cffgload.h
+	cffload.c
+	cffload.h
+	cffobjs.c
+	cffobjs.h
+	cffparse.c
+	cffparse.h
+	cfftoken.h
+	ciderrs.h
+	cidgload.c
+	cidgload.h
+	cidload.c
+	cidload.h
+	cidobjs.c
+	cidobjs.h
+	cidparse.c
+	cidparse.h
+	cidriver.c
+	cidriver.h
+	cidtoken.h
+	fnterrs.h
+	freetype.c
+	ft2system.c
+	ftapi.c
+	ftbase.c
+	ftbbox.c
+	ftbdf.c
+	ftcache.c
+	ftcalc.c
+	ftccache.c
+	ftccmap.c
+	ftcerror.h
+	ftcglyph.c
+	ftcimage.c
+	ftcmanag.c
+	ftcsbits.c
+	ftdbgmem.c
+	ftdebug.c
+	ftexcept.c
+	ftgloadr.c
+	ftglyph.c
+	ftgrays.c
+	ftgrays.h
+	ftgzip.c
+	fthash.c
+	ftinit.c
+	ftlist.c
+	ftlru.c
+	ftmac.c
+	ftmm.c
+	ftnames.c
+	ftobject.c
+	ftobjs.c
+	ftoutln.c
+	ftpfr.c
+	ftraster.c
+	ftraster.h
+	ftrend1.c
+	ftrend1.h
+	ftsmerrs.h
+	ftsmooth.c
+	ftsmooth.h
+	ftstream.c
+	ftstroker.c
+	ftsynth.c
+	ftsysio.c
+	ftsysmem.c
+	ftsystem.c
+	ftsystem_inf.c
+	fttrigon.c
+	fttype1.c
+	ftutil.c
+	ftxf86.c
+	infblock.c
+	infblock.h
+	infcodes.c
+	infcodes.h
+	inffixed.h
+	inflate.c
+	inftrees.c
+	inftrees.h
+	infutil.c
+	infutil.h
+	mkfile
+	otlayout.h
+	otlbase.c
+	otlbase.h
+	otlcommn.c
+	otlcommn.h
+	otlconf.h
+	otlgdef.c
+	otlgdef.h
+	otlgpos.c
+	otlgpos.h
+	otlgsub.c
+	otlgsub.h
+	otljstf.c
+	otljstf.h
+	otlparse.c
+	otlparse.h
+	otltable.h
+	otltags.h
+	otlutils.h
+	pcf.c
+	pcf.h
+	pcfdriver.c
+	pcfdriver.h
+	pcferror.h
+	pcfread.c
+	pcfutil.c
+	pcfutil.h
+	pfr.c
+	pfrcmap.c
+	pfrcmap.h
+	pfrdrivr.c
+	pfrdrivr.h
+	pfrerror.h
+	pfrgload.c
+	pfrgload.h
+	pfrload.c
+	pfrload.h
+	pfrobjs.c
+	pfrobjs.h
+	pfrsbit.c
+	pfrsbit.h
+	pfrtypes.h
+	psaux.c
+	psauxerr.h
+	psauxmod.c
+	psauxmod.h
+	pshalgo.h
+	pshalgo1.c
+	pshalgo1.h
+	pshalgo2.c
+	pshalgo2.h
+	pshalgo3.c
+	pshalgo3.h
+	pshglob.c
+	pshglob.h
+	pshinter.c
+	pshmod.c
+	pshmod.h
+	pshrec.c
+	pshrec.h
+	psmodule.c
+	psmodule.h
+	psnamerr.h
+	psnames.c
+	psobjs.c
+	psobjs.h
+	pstables.h
+	raster.c
+	rasterrs.h
+	sfdriver.c
+	sfdriver.h
+	sferrors.h
+	sfnt.c
+	sfobjs.c
+	sfobjs.h
+	smooth.c
+	stddef.h
+	t1afm.c
+	t1afm.h
+	t1cmap.c
+	t1cmap.h
+	t1decode.c
+	t1decode.h
+	t1driver.c
+	t1driver.h
+	t1errors.h
+	t1gload.c
+	t1gload.h
+	t1load.c
+	t1load.h
+	t1objs.c
+	t1objs.h
+	t1parse.c
+	t1parse.h
+	t1tokens.h
+	t42drivr.c
+	t42drivr.h
+	t42error.h
+	t42objs.c
+	t42objs.h
+	t42parse.c
+	t42parse.h
+	test_bbox.c
+	test_trig.c
+	truetype.c
+	ttcmap.c
+	ttcmap.h
+	ttcmap0.c
+	ttcmap0.h
+	ttdriver.c
+	ttdriver.h
+	tterrors.h
+	ttgload.c
+	ttgload.h
+	ttinterp.c
+	ttinterp.h
+	ttload.c
+	ttload.h
+	ttobjs.c
+	ttobjs.h
+	ttpload.c
+	ttpload.h
+	ttpost.c
+	ttpost.h
+	ttsbit.c
+	ttsbit.h
+	type1.c
+	type1cid.c
+	type42.c
+	winfnt.c
+	winfnt.h
+	zconf.h
+	zlib.h
+	zutil.c
+	zutil.h
+libinterp
+	NOTICE
+	README
+	alt.c
+	comp-386.c
+	comp-68020.c
+	comp-arm.c
+	comp-mips.c
+	comp-power.c
+	comp-s800.c
+	comp-sparc.c
+	comp-spim.c
+	comp-thumb.c
+	conv.c
+	das-386.c
+	das-68000.c
+	das-68020.c
+	das-arm.c
+	das-mips.c
+	das-power.c
+	das-s800.c
+	das-sparc.c
+	das-stub.c
+	das-spim.c
+	das-thumb.c
+	dec.c
+	decgen.c
+	dlm-Inferno.c
+	dlm-Nt.c
+	dlm-Plan9.c
+	dlm-Posix.c
+	draw.c
+	drawmod.h
+	freetype.c
+	freetypemod.h
+	gc.c
+	geom.c
+	heap.c
+	heapaudit.c
+	ipint.c
+	keyring.c
+	keyring.h
+	link.c
+	load.c
+	loader.c
+	loadermod.h
+	math.c
+	mathmod.h
+	mkfile
+	mkoptab
+	optab.h
+	prefab.c
+	raise.c
+	readmod.c
+	runt.c
+	runt.h
+	sign.c
+	stack.c
+	string.c
+	sysmod.h
+	tab.h
+	tk.c
+	tkmod.h
+	validstk.c
+	xec.c
+libkeyring
+	NOTICE
+	dsaalg.c
+	egalg.c
+	keys.h
+	mkfile
+	rsaalg.c
+limbo
+	NOTICE
+	asm.c
+	com.c
+	decls.c
+	dis.c
+	dtocanon.c
+	ecom.c
+	fns.h
+	gen.c
+	lex.c
+	limbo.h
+	limbo.y
+	mkfile
+	nodes.c
+	optab.c
+	optim.c
+	runt.h
+	sbl.c
+	stubs.c
+	typecheck.c
+	types.c
+libmath
+	NOTICE
+	FPcontrol-FreeBSD.c
+	FPcontrol-Hp.c
+	FPcontrol-Inferno.c
+	FPcontrol-Irix.c
+	FPcontrol-Linux.c
+	FPcontrol-MacOSX.c
+	FPcontrol-Nt.c
+	FPcontrol-Plan9.c
+	FPcontrol-Solaris.c
+	FPcontrol-Unixware.c
+	bin
+		fdlibm-stubs
+		unif_dtoa
+		unif_fdlibm
+	blas.c
+	dtoa.c
+	fdim.c
+	fdlibm
+		*
+	g_fmt.c
+	gemm.c
+	gfltconv.c
+	mkfile
+	pow10.c
+libmemdraw
+	NOTICE
+	alloc.c
+	arc.c
+	cload.c
+	cmap.c
+	cread.c
+	defont.c
+	draw.c
+	drawtest.c
+	ellipse.c
+	fillpoly.c
+	hwdraw.c
+	icossin.c
+	icossin2.c
+	iprint.c
+	line.c
+	load.c
+	mkfile
+	mkfile-Inferno
+	mkfile-Irix
+	mkfile-Linux
+	mkfile-MacOSX
+	mkfile-Nt
+	mkfile-Plan9
+	mkfile-Solaris
+	mkfile-FreeBSD
+	mkfile-os
+	openmemsubfont.c
+	poly.c
+	read.c
+	string.c
+	subfont.c
+	unload.c
+	write.c
+libmemlayer
+	NOTICE
+	draw.c
+	lalloc-x11.c
+	lalloc.c
+	layerop.c
+	ldelete.c
+	lhide.c
+	line.c
+	load.c
+	lorigin.c
+	lreshape.c
+	lsetrefresh.c
+	ltofront.c
+	ltorear.c
+	mkfile
+	mkfile-FreeBSD
+	mkfile-Hp
+	mkfile-Inferno
+	mkfile-Irix
+	mkfile-Linux
+	mkfile-MacOSX
+	mkfile-NetBSD
+	mkfile-Nt
+	mkfile-Plan9
+	mkfile-Posix
+	mkfile-Solaris
+	mkfile-Unixware
+	mkfile-os
+	unload.c
+libmp
+	NOTICE
+	Inferno-386
+		mkfile
+		mpdigdiv.s
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	Inferno-amd64
+		mkfile
+		mpdigdiv.s
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	Inferno-mips
+		mkfile
+		mpdigdiv.s
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	Inferno-power
+		mkfile
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	Plan9-386
+		mkfile
+		mpdigdiv.s
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	Plan9-amd64
+		mkfile
+		mpdigdiv.s
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	Plan9-mips
+		mkfile
+		mpdigdiv.s
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	Plan9-power
+		mkfile
+		mpvecadd.s
+		mpvecdigmuladd.s
+		mpvecdigmulsub.s
+		mpvecsub.s
+	bigtest.c
+	mkfile
+	mtest.c
+	port
+		betomp.c
+		crt.c
+		crttest.c
+		dat.h
+		letomp.c
+		mkfile
+		mpadd.c
+		mpaux.c
+		mpcmp.c
+		mpdigdiv.c
+		mpdiv.c
+		mpeuclid.c
+		mpexp.c
+		mpextendedgcd.c
+		mpfactorial.c
+		mpfmt.c
+		mpinvert.c
+		mpleft.c
+		mpmod.c
+		mpmul.c
+		mprand.c
+		mpright.c
+		mpsub.c
+		mptobe.c
+		mptoi.c
+		mptole.c
+		mptoui.c
+		mptouv.c
+		mptov.c
+		mpvecadd.c
+		mpveccmp.c
+		mpvecdigmuladd.c
+		mpvecsub.c
+		os.h
+		reduce-nt
+		reduce-rc
+		reduce-sh
+		strtomp.c
+	test.c
+libprefab
+	NOTICE
+	box.c
+	compound.c
+	element.c
+	elistelement.c
+	iconbox.c
+	iconelement.c
+	mkfile
+	textbox.c
+	textelement.c
+libsec
+	NOTICE
+	Inferno-386
+		md5block.s
+		mkfile
+		sha1block.s
+	Inferno-mips
+		md5block.s
+		mkfile
+		sha1block.s
+	Plan9-386
+		md5block.s
+		mkfile
+		sha1block.s
+	Plan9-mips
+		md5block.s
+		mkfile
+		sha1block.s
+	mkfile
+	port
+		aes.c
+		blowfish.c
+		decodepem.c
+		des.c
+		des3CBC.c
+		des3ECB.c
+		desCBC.c
+		desECB.c
+		desmodes.c
+		dsaalloc.c
+		dsagen.c
+		dsaprimes.c
+		dsaprivtopub.c
+		dsasign.c
+		dsaverify.c
+		egalloc.c
+		egdecrypt.c
+		egencrypt.c
+		eggen.c
+		egprivtopub.c
+		egsign.c
+		egtest.c
+		egverify.c
+		fastrand.c
+		genprime.c
+		genrandom.c
+		gensafeprime.c
+		genstrongprime.c
+		hmac.c
+		hmactest.c
+		idea.c
+		md4.c
+		md4test.c
+		md5.c
+		md5block.c
+		md5pickle.c
+		mkfile
+		nfastrand.c
+		primetest.c
+		prng.c
+		probably_prime.c
+		rc4.c
+		reduce-nt
+		reduce-rc
+		reduce-sh
+		rsaalloc.c
+		rsadecrypt.c
+		rsaencrypt.c
+		rsafill.c
+		rsagen.c
+		rsaprivtopub.c
+		rsatest.c
+		sha1.c
+		sha1block.c
+		sha1pickle.c
+		smallprimes.c
+		smallprimetest.c
+libtk
+	NOTICE
+	buton.c
+	canvs.c
+	canvs.h
+	canvu.c
+	carcs.c
+	cbits.c
+	cimag.c
+	cline.c
+	colrs.c
+	coval.c
+	cpoly.c
+	crect.c
+	ctext.c
+	cwind.c
+	ebind.c
+	entry.c
+	extns.c
+	frame.c
+	frame.h
+	grids.c
+	image.c
+	label.c
+	label.h
+	listb.c
+	listb.h
+	mail.tk
+	menu.tk
+	menus.c
+	mkfile
+	mkfile-std
+	packr.c
+	panel.c
+	parse.c
+	radio.tk
+	scale.c
+	scrol.c
+	textu.c
+	textw.c
+	textw.h
+	tindx.c
+	tmark.c
+	ttags.c
+	twind.c
+	utils.c
+	windw.c
+	xdata.c
+man
+	lib
+		checkman.awk
+		colophon
+		lookman
+			+
+		man
+		notes
+		permind
+		preface
+		secindex
+		title
+		trademarks
+tools
+	NOTICE
+	db
+		infdb.c
+		mkfile
+	libstyx
+		Nt.c
+		Plan9.c
+		Posix.c
+		mkfile
+		styxaux.h
+		styxserver.c
+	mkfile
+	odbc
+		mkfile
+		mkfile-Linux
+		mkfile-MacOSX
+		mkfile-Nt
+		mkfile-Plan9
+		mkfile-Solaris
+		odbc.c
+	styxtest
+		mkfile
+		mkfile-FreeBSD
+		mkfile-Irix
+		mkfile-Linux
+		mkfile-MacOSX
+		mkfile-Nt
+		mkfile-Plan9
+		mkfile-Solaris
+		styxtest.c
+		styxtest0.c
+utils
+	ntsrv
+		domk
+		ntsrv.c
+		mkfile
--- /dev/null
+++ b/lib/proto/utils
@@ -1,0 +1,752 @@
+include
+	bio.h
+lib9
+	NOTICE
+	argv0.c
+	charstod.c
+	cistrcmp.c
+	cistrncmp.c
+	cistrstr.c
+	cleanname.c
+	convD2M.c
+	convM2D.c
+	convM2S.c
+	convS2M.c
+	create.c
+	dirstat-Nt.c
+	dirstat-posix.c
+	dirwstat.c
+	dofmt.c
+	dorfmt.c
+	errfmt.c
+	errstr-Nt.c
+	errstr-Plan9.c
+	errstr-posix.c
+	exits.c
+	fcallfmt.c
+	fltfmt.c
+	fmt.c
+	fmtdef.h
+	fmtfd.c
+	fmtlock.c
+	fmtprint.c
+	fmtquote.c
+	fmtrune.c
+	fmtstr.c
+	fmtvprint.c
+	fprint.c
+	getcallerpc-FreeBSD-386.S
+	getcallerpc-Hp-s800.s
+	getcallerpc-Irix-mips.s
+	getcallerpc-Linux-386.S
+	getcallerpc-Linux-arm.S
+	getcallerpc-Linux-spim.S
+	getcallerpc-MacOSX-power.s
+	getcallerpc-MacOSX-386.s
+	getcallerpc-Solaris-386.s
+	getcallerpc-Solaris-sparc.s
+	getcallerpc-Unixware-386.s
+	getfields.c
+	getuser-Nt.c
+	getuser-posix.c
+	getwd-Nt.c
+	getwd-posix.c
+	lock.c
+	lock-Hp-s800.s
+	lock-Irix-mips.s
+	lock-MacOSX-power.s
+	lock-Nt-386.c
+	lock-Solaris-386.s
+	lock-Solaris-sparc.s
+	lock-Unixware-386.s
+	mkfile
+	mkfile-Nt
+	mkfile-Plan9
+	mkfile-Posix
+	nulldir.c
+	pow10.c
+	print.c
+	qsort.c
+	readn.c
+	rerrstr.c
+	rune.c
+	runeseprint.c
+	runesmprint.c
+	runesnprint.c
+	runestrlen.c
+	runevseprint.c
+	sbrk-posix.c
+	seek.c
+	seprint.c
+	setbinmode-Nt.c
+	smprint.c
+	snprint.c
+	sprint.c
+	strdup.c
+	strecpy.c
+	strtoll.c
+	sysfatal.c
+	tokenize.c
+	u16.c
+	u32.c
+	u64.c
+	utfecpy.c
+	utflen.c
+	utfnlen.c
+	utfrrune.c
+	utfrune.c
+	vfprint.c
+	vseprint.c
+	vsmprint.c
+	vsnprint.c
+libbio
+	NOTICE
+	bbuffered.c
+	bfildes.c
+	bflush.c
+	bgetc.c
+	bgetd.c
+	bgetrune.c
+	binit.c
+	boffset.c
+	bprint.c
+	bputc.c
+	bputrune.c
+	brdline.c
+	bread.c
+	bseek.c
+	bwrite.c
+	mkfile
+mkfile
+makemk.sh
+utils
+	NOTICE
+	0a
+		a.h
+		a.y
+		l.s
+		lex.c
+		mkfile
+	0c
+		cgen.c
+		enam.c
+		gc.h
+		list.c
+		mkenam
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+		v.out.h
+	0l
+		Plan9.c
+		Nt.c
+		Posix.c
+		asm.c
+		enam.c
+		l.h
+		list.c
+		mkfile
+		noop.c
+		obj.c
+		optab.c
+		pass.c
+		sched.c
+		span.c
+	1a
+		a.h
+		a.y
+		l.s
+		lex.c
+		mkfile
+	1c
+		cgen.c
+		enam.c
+		gc.h
+		list.c
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+	1l
+		Plan9.c
+		Nt.c
+		Posix.c
+		asm.c
+		l.h
+		list.c
+		mkfile
+		obj.c
+		optab.c
+		pass.c
+		span.c
+	2a
+		a.h
+		a.y
+		l.s
+		lex.c
+		mkfile
+	2c
+		2.out.h
+		Update
+		cgen.c
+		enam.c
+		gc.h
+		list.c
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+	2l
+		Plan9.c
+		Nt.c
+		Posix.c
+		asm.c
+		l.h
+		list.c
+		mkfile
+		obj.c
+		optab.c
+		pass.c
+		span.c
+	5a
+		a.h
+		a.y
+		lex.c
+		mkfile
+	5c
+		5.out.h
+		cgen.c
+		enam.c
+		gc.h
+		list.c
+		mkenam
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+	5cv
+		5cv.c
+		mkfile
+	5coff
+		NOTICE
+		5coff.c
+		auxi.c
+		auxi.h
+		coff.c
+		mkfile
+		readcoff.c
+	5l
+		Plan9.c
+		Nt.c
+		Posix.c
+		asm.c
+		l.h
+		list.c
+		mkfile
+		noop.c
+		obj.c
+		optab.c
+		pass.c
+		span.c
+		thumb.c
+	6c
+		6.out.h
+	8a
+		a.h
+		a.y
+		l.s
+		lex.c
+		mkfile
+	8c
+		8.out.h
+		cgen.c
+		cgen64.c
+		div.c
+		enam.c
+		gc.h
+		list.c
+		machcap.c
+		mkenam
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+	8l
+		Plan9.c
+		Nt.c
+		Posix.c
+		asm.c
+		l.h
+		list.c
+		mkfile
+		obj.c
+		optab.c
+		pass.c
+		span.c
+	acid
+		386
+		B.sh
+		acid.h
+		arm
+		builtin.c
+		dbg.y
+		dot.c
+		exec.c
+		expr.c
+		lex.c
+		list.c
+		main.c
+		mips
+		mkfile
+		os-Plan9.c
+		os-Nt.c
+		os-Posix.c
+		port
+		print.c
+		proc.c
+		rdebug.c
+		sparc
+		util.c
+	iar
+		Plan9.c
+		Nt.c
+		Posix.c
+		ar.c
+		mkfile
+	awk
+		FIXES
+		NOTICE
+		README
+		awk.1
+		awk.h
+		awkgram.y
+		b.c
+		buildwin.bat
+		lex.c
+		lib.c
+		mac.code
+		main.c
+		makefile
+		maketab.c
+		missing95.c
+		mkfile
+		parse.c
+		proctab.c
+		proto.h
+		run.c
+		tran.c
+		ytab.c
+		ytab.h
+		ytabc.bak
+		ytabh.bak
+	c2l
+		Plan9.c
+		Nt.c
+		Posix.c
+		acid.c
+		bits.c
+		c2l.c
+		cc.h
+		cc.y
+		com.c
+		com64.c
+		dcl.c
+		dpchk.c
+		lex.c
+		lexbody
+		mac.c
+		macbody
+		mkfile
+		mpatof.c
+		out.c
+		scon.c
+		sub.c
+	cat
+		cat.c
+		mkfile
+	cc
+		Plan9.c
+		Nt.c
+		Posix.c
+		acid.c
+		bits.c
+		cc.h
+		cc.y
+		com.c
+		com64.c
+		dcl.c
+		dpchk.c
+		funct.c
+		lex.c
+		lexbody
+		mac.c
+		macbody
+		machcap.c
+		mkfile
+		mpatof.c
+		pickle.c
+		scon.c
+		sub.c
+	cp
+		cp.c
+		mkfile
+	cvbit
+		cvbit.c
+		mkfile
+	data2c
+		data2c.c
+		mkfile
+	data2s
+		data2s.c
+		mkfile
+	echo
+		echo.c
+		mkfile
+	format
+		Plan9.c
+		Nt.c
+		format.c
+		mkfile
+	ftl
+		ftl.c
+		mkfile
+	idea
+		NOTICE
+		idea.c
+		mkfile
+	include
+		a.out.h
+		ar.h
+		mach.h
+		regexp.h
+	ka
+		a.h
+		a.y
+		l.s
+		lex.c
+		mkfile
+		note
+	kc
+		cgen.c
+		enam.c
+		gc.h
+		k.out.h
+		list.c
+		mkenam
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+	kl
+		Plan9.c
+		Nt.c
+		Posix.c
+		asm.c
+		foo.c
+		l.h
+		list.c
+		mkfile
+		noop.c
+		obj.c
+		optab.c
+		pass.c
+		sched.c
+		span.c
+	kprof
+		kprof.c
+		mkfile
+	ksize
+		ksize.c
+		mkfile
+	kstrip
+		kstrip.c
+		mkfile
+	lib
+		rcmain
+		yaccpar
+	libmach
+		NOTICE
+		2.c
+		2db.c
+		2obj.c
+		4.c
+		4db.c
+		5.c
+		5db.c
+		5obj.c
+		6.c
+		6obj.c
+		8.c
+		8db.c
+		8obj.c
+		a.out.h
+		access.c
+		ar.h
+		bootexec.h
+		elf.h
+		executable.c
+		k.c
+		kdb.c
+		kobj.c
+		mach.h
+		machdata.c
+		map.c
+		mkfile
+		obj.c
+		obj.h
+		q.c
+		qdb.c
+		qobj.c
+		setmach.c
+		swap.c
+		sym.c
+		t.c
+		tdb.c
+		tobj.c
+		uregt.h
+		ureg2.h
+		ureg4.h
+		ureg5.h
+		ureg6.h
+		ureg8.h
+		uregk.h
+		uregq.h
+		uregv.h
+		v.c
+		vcodas.c
+		vdb.c
+		vobj.c
+	libregexp
+		NOTICE
+		mkfile
+		regaux.c
+		regcomp.c
+		regcomp.h
+		regerror.c
+		regexec.c
+		regsub.c
+		rregexec.c
+		rregsub.c
+		test.c
+		test2.c
+	md5sum
+		md5sum.c
+		mkfile
+	mkext
+		mkext.c
+		mkfile
+	mk
+		Plan9.c
+		Nt.c
+		Posix.c
+		README
+		arc.c
+		archive.c
+		bufblock.c
+		env.c
+		file.c
+		fns.h
+		graph.c
+		job.c
+		lex.c
+		main.c
+		match.c
+		mk.c
+		mk.h
+		mkfile
+		mkfile-Plan9
+		mkfile-Nt
+		mkfile-Posix
+		parse.c
+		rc.c
+		recipe.c
+		rule.c
+		run.c
+		sh.c
+		shprint.c
+		symtab.c
+		var.c
+		varsub.c
+		word.c
+	mkdir
+		mkdir.c
+		mkfile
+	mkfile
+	mkppcimage
+		mkfile
+		mkppcimage.c
+	ms2
+		mkfile
+		ms2.c
+	mv
+		mkfile
+		mv.c
+	na
+		mkfile
+		na.h
+		na.man
+		na.y
+	ndate
+		mkfile
+		ndate.c
+	nm
+		mkfile
+		nm.c
+	qa
+		Ins
+		a.h
+		a.y
+		branch
+		lex.c
+		mkfile
+	qc
+		cgen.c
+		enam.c
+		gc.h
+		list.c
+		mkenam
+		mkfile
+		mul.c
+		peep.c
+		q.out.h
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+	ql
+		Plan9.c
+		Ins
+		Notes
+		Nt.c
+		Posix.c
+		asm.c
+		asmout.c
+		cnam.c
+		l.h
+		list.c
+		mkcname
+		mkfile
+		noop.c
+		obj.c
+		optab.c
+		pass.c
+		sched.c
+		span.c
+	rcsh
+		Nt.c
+		code.c
+		exec.c
+		glob.c
+		here.c
+		io.c
+		lex.c
+		main.c
+		mkfile
+		pcmd.c
+		pfnc.c
+		rc.h
+		rcmain
+		rcpath
+		simple.c
+		syn.y
+		trap.c
+		tree.c
+		var.c
+		word.c
+	rm
+		mkfile
+		rm-Nt.c
+	sed
+		mkfile
+		sed.c
+	sqz
+		NOTICE
+		mkfile
+		squeeze.h
+		sqz.c
+		zqs.c
+	srclist
+		Plan9.c
+		Nt.c
+		Posix.c
+		mkfile
+		srclist.c
+	tc
+		5.out.h
+		cgen.c
+		enam.c
+		gc.h
+		list.c
+		mkenam
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+	test
+		mkfile
+		test-Nt.c
+	tr
+		mkfile
+		tr.c
+	va
+		a.h
+		a.y
+		l.s
+		lex.c
+		mkfile
+		note
+	vc
+		cgen.c
+		enam.c
+		gc.h
+		list.c
+		mkenam
+		mkfile
+		mul.c
+		peep.c
+		reg.c
+		sgen.c
+		swt.c
+		txt.c
+		v.out.h
+	vl
+		Plan9.c
+		Nt.c
+		Posix.c
+		asm.c
+		compat.c
+		l.h
+		list.c
+		mkfile
+		noop.c
+		obj.c
+		optab.c
+		pass.c
+		sched.c
+		span.c
+	iyacc
+		mkfile
+		yacc.c
+		yaccpar
--- /dev/null
+++ b/lib/scores/snake
@@ -1,0 +1,10 @@
+internet 194 12.442264511089631551711111423114516203162831133321313110111112321328244264119361518212319114745217111142231882541163110114371714171117163831151411351311582151911213357127133189101631195172031114161512112722711012143120321213111261811311961984731031203131419312115133113221919220271451433131103186515102139151181251531154132142316192031161515121131712181010156520206161111411121662919111131215113151174182718273114120672327412041735174141121311625422441125103120312531261621125617125451018116191162384221328102146131811412312115171027642541441411632226171112136201011210225623312193192431561531191228136573449315121032514185172820258165511214141144191131411018191411114201724519322918210131516611116315251184591314382013313116212211142419212171531167261511320417117916712125172151415252627225311813323118795151414151514181410161561531211313144410511911311311311311311315142218211241541119118106181345519541622113115282234201189164146171114616191155415727181101013162612114282817271010111451974814132206510231615164341415343499121113281271261151151925516311612011314111431133171342513110115117332181922213241152312029291281171164212111738315146231221222712571615151515151511761765313114951514141413154520325925141111617 30.30.1110000000000000000000000000001010000000000000000000000000001010000000000000000000000000001011111111111111111111100000001000000000000000000000100000001
\ No newline at end of file
+rog 155 0.51419612154514662414183619717141556151716173441104919419131812516145169419861971341461611518182117171011011179618114554112619211744216110816161201519191511651104431311261211392773549104856234183924717118145491718455621319113111163351819125712941911312116101979115211151179211519112111511071341851917511419110162461102316122248671022114111118619141221822711319191818119171818122151118824115110181727374210122916171716119611726111111111111111111163311116168292101919123161111111121122513136199531015251211011118113131717141101919111441218123151511311019110191148161291811411311211211521181141141141141141157161241518111112110111111113611243161121121111121186201136132719202011111247125132411611511921119117112110171711011687171272220112111110191121101954122341311111261016122612161511211211011011011011018121410316391812523251171171171171171131012113739185615311713120917191911532192510261221221211131161731361411411311311411411411716161202612312212111811611811614201025123121120120120119119141411411598162612612814251241221221221201221320120119317118117115116113212115111111101611812071521612231423124124126212812512312111911914201191201191161192111611954121131418462727201181171161186111620318114119261161151151141147431010201711611511612151126362261151151161912511611711911912225211151131121121121121131141197
\ No newline at end of file
+chris 148 12.2811622620451487146166102171284225239581758219171111071067214456267746492145118523135179141428612213116222203697114561812201111101910121115141445107557891397314528711075391620621101163201261111154619214126143161178111111899841372152413310494119571792011411039101317914162782061749855992124121731111121128314691791151923614114248163413716810720614114117161259941511411511791152410166212512421219416610111761021011111111426154310423202721012117101129617131983101711512051661891151015185514714614151455141111221231048191911141422282221116116117195232571520141511331466855188214241816455111181161225198414312111672631011171551461112141411781641512151154176153826462158185119121067722121115112110116425134481146191151151131131131151115822682521058132061171411319181201171151111123111138101321877910113787206392621311465171141141131131121131119721818118118119257651528811115115117119523202032226235151141161161171171161151199221324521118118117117118636661857417120118118119118114117105762111131111111111011052314611372018171419261419119119119120122212411411411411511711811911812012222619117117116116513694131131131212323116117115114111110110191919112185151215810262419171131131131121112194 30.30.000011111111111111111111000000000010000000000000000001000000000010000000000000000001000000000010000000000000000001000000000010000000000000000001111100102010000000000000000001111111100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000000000000001111110100010000000
\ No newline at end of file
+chris 134 
+rog 106 
+chris 99 12.25152251095148514462610481411424875510126117189561052135811638815261311119269888912113488181011277823128186710114818201012581914114515991211513101011610111116315101912219231714151214121313131755649111242012292021122611211381311210124941315616164818418111021771816731041017124638919277208546611875815181103864131312661051341736412176349121662521822072254554101121423105122221121481411227117515123486142271451671924219820102319223156125517173142142126163517737423217126815510192223511101229281141141101111161522011518171149114610681144554127694211161161151166192661352141122931217115115115117121923262511218122211911911912118233121111111142312199102127119181181181181207795320222524221201114 30.30.000000000000010000000000000000000000000000011111111111100000000011111111111111111111100000000011111111111111111111111000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000002000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000111111131111111111111000000000000000010000000000000000000000000000010000000000000000
+rog 95 30.30.000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000001311000000111111111111111111110001000000111111110000000000010001000000000000011100000000010001000000000000000111111111010001000000000001111111111111010001000000000000000000000000010001000000000000000000000000010011000000000000000000011111110010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000011111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+rog 90 
+chris 86 
+rog 85 
--- /dev/null
+++ b/lib/scores/tetris
@@ -1,0 +1,10 @@
+rog 10294 619 61 1018459656
+chris 8198 488 48 966856907
+rog 7382 444 44 948217793
+rog 6717 398 39 1016489333
+chris 6662 400 40 949931938
+chris 5772 339 33 951416793
+rog 4543 265 26 1016041766
+rog 4503 267 26 950535599
+chris 4362 254 25 947854282
+rog 4331 255 25 1018374770
--- /dev/null
+++ b/lib/scores/x
@@ -1,0 +1,10 @@
+rog 155 51419612154514662414183619717141556151716173441104919419131812516145169419861971341461611518182117171011011179618114554112619211744216110816161201519191511651104431311261211392773549104856234183924717118145491718455621319113111163351819125712941911312116101979115211151179211519112111511071341851917511419110162461102316122248671022114111118619141221822711319191818119171818122151118824115110181727374210122916171716119611726111111111111111111163311116168292101919123161111111121122513136199531015251211011118113131717141101919111441218123151511311019110191148161291811411311211211521181141141141141141157161241518111112110111111113611243161121121111121186201136132719202011111247125132411611511921119117112110171711011687171272220112111110191121101954122341311111261016122612161511211211011011011011018121410316391812523251171171171171171131012113739185615311713120917191911532192510261221221211131161731361411411311311411411411716161202612312212111811611811614201025123121120120120119119141411411598162612612814251241221221221201221320120119317118117115116113212115111111101611812071521612231423124124126212812512312111911914201191201191161192111611954121131418462727201181171161186111620318114119261161151151141147431010201711611511612151126362261151151161912511611711911912225211151131121121121121131141197
\ No newline at end of file
+chris 134 
+rog 106 
+rog 95 30.30.000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000001311000000111111111111111111110001000000111111110000000000010001000000000000011100000000010001000000000000000111111111010001000000000001111111111111010001000000000000000000000000010001000000000000000000000000010011000000000000000000011111110010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000010000000010000000000000000000011111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+rog 90 
+chris 86 101171152141171718354961757517147113207317163165869862451311671385191241112152108273911994818824109111815391791921359101116218119782135455831711042814112420761010462121058622916111110812152839510631461491515201417112266822101131257101411179961091414616183208258439661661816755838291151710699217412293728181154578192454542123542843418116814146921810110114484141611711411610127136417611536882595752867661425117116121104541053836631531820113114116114111542102154472352021311761611653142185352336517514146141115110112110642939417107363159191918274711842491462162514113 30.30.000000000000000000000000000000001111110000000000000000000000001111110000000000000000000000111111111111111111111113111111000000000000000000000001000000000000000000000000000001111111000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000200000001000000000000000000000000000001000000000000000000001111111111000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001110000000000000000000000000000010000000000000000000000000000010000000000000000000000000000010000000000000000000000111111110000000000000000000000000000000000000000000000000000000000000000000
+rog 85 85227341327545131535331113163991152361774712132611316641816111571111398171821711719591564725184121041116121131215412617551257457121612255315112114771819839911152641681912351181145711015158472410117202031061618519619585154281341611419106110271124351114181222101711424714165514816121541928122010214611051719169592101919171111081724711071118181711471631221422115113715111191611146293176115172091443241151121111106675119111113113111114110118161108161311311311311311419114164131411018191919191104999211151167913111110111111151016111111111111110191344113517335 30.30.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011111111111111111100000000000010000000000000000100000000000010000000000000000100000000000010000000000000000111100000000010000000000001111100100000000011111111111111000100100000000000000000000000000120100000000000000000000000000100100000000000000000000000000111300000000000000000000111111111100000000000000000000111111111110000000000000000000011111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+rog 84 
+rog 83 5224106119351638185114114818172415519181018491038797106911013712111635212175181313361511362351252791125371162071021062719620116383178185371883415176166116719291012112418415152518616319434615161127110131735411010324144731127811341161131143174141131851128716419151851162105110125141102251862718717183429101941256162419207113811511514158196142081118196711911051161423239278101011258922111181611094194169181876113411811711611311311610526747163 30.30.000000001111111111111111100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000001111100000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001111111000000000000000000000000000001000000000000000000000000111111000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000001111111111111111100000000000001113111111100000000000000000000001000000000000000000000000000001200000000000000000000
+rog 80 1161556116676121638116747174495110461029516151855113396511471865163915713514511276364181664729114789119821108111512418542116745219171132514113471711916341513135181912061999221339252186151418444815161125177110571820181978113411711411552011481451137141191111720715151723181222311619191101103592175811611117131721271461142251121192266142018110728121919191191845711621211111011385101916132124107110717118101733521146110118121101171511111011131411211612114113115202211911912381085117111101111111124111951261101651 30.30.000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000111111111111100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000100000000000000200000000000000100000000000000000000000000001100000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000000000000000001000000000000000100000000000001111111111111111100000000000000000000000000000100000000000000000000000000000100000000000000000000000000000111110000000000000000000000000130000000000000000000000000000010000000000000000000000000000010000000000000000000000000000011111111111100000000000000000000111111111100000000000000000
--- /dev/null
+++ b/lib/scsicodes
@@ -1,0 +1,487 @@
+# hget http://www.t10.org/lists/asc-num.htm |
+#   grep '^[0-9]' |tr -d '
' |tr A-Z a-z |
+#   sed 's/(..)\/(..)  ..............  (.*)/\1\2 \3/' > scsicodes
+# (and then put this header back)
+0000 no additional sense information
+0001 filemark detected
+0002 end-of-partition/medium detected
+0003 setmark detected
+0004 beginning-of-partition/medium detected
+0005 end-of-data detected
+0006 i/o process terminated
+0011 audio play operation in progress
+0012 audio play operation paused
+0013 audio play operation successfully completed
+0014 audio play operation stopped due to error
+0015 no current audio status to return
+0016 operation in progress
+0017 cleaning requested
+0100 no index/sector signal
+0200 no seek complete
+0300 peripheral device write fault
+0301 no write current
+0302 excessive write errors
+0400 logical unit not ready, cause not reportable
+0401 logical unit is in process of becoming ready
+0402 logical unit not ready, initializing cmd. required
+0403 logical unit not ready, manual intervention required
+0404 logical unit not ready, format in progress
+0405 logical unit not ready, rebuild in progress
+0406 logical unit not ready, recalculation in progress
+0407 logical unit not ready, operation in progress
+0408 logical unit not ready, long write in progress
+0409 logical unit not ready, self-test in progress
+0410 auxiliary memory code 2 (99-148) [proposed]
+0500 logical unit does not respond to selection
+0600 no reference position found
+0700 multiple peripheral devices selected
+0800 logical unit communication failure
+0801 logical unit communication time-out
+0802 logical unit communication parity error
+0803 logical unit communication crc error (ultra-dma/32)
+0804 unreachable copy target
+0900 track following error
+0901 tracking servo failure
+0902 focus servo failure
+0903 spindle servo failure
+0904 head select fault
+0a00 error log overflow
+0b00 warning
+0b01 warning - specified temperature exceeded
+0b02 warning - enclosure degraded
+0c00 write error
+0c01 write error - recovered with auto reallocation
+0c02 write error - auto reallocation failed
+0c03 write error - recommend reassignment
+0c04 compression check miscompare error
+0c05 data expansion occurred during compression
+0c06 block not compressible
+0c07 write error - recovery needed
+0c08 write error - recovery failed
+0c09 write error - loss of streaming
+0c0a write error - padding blocks added
+0c0b auxiliary memory code 4 (99-148) [proposed]
+0d/00
+0e/00
+0f/00
+1000 id crc or ecc error
+1100 unrecovered read error
+1101 read retries exhausted
+1102 error too long to correct
+1103 multiple read errors
+1104 unrecovered read error - auto reallocate failed
+1105 l-ec uncorrectable error
+1106 circ unrecovered error
+1107 data re-synchronization error
+1108 incomplete block read
+1109 no gap found
+110a miscorrected error
+110b unrecovered read error - recommend reassignment
+110c unrecovered read error - recommend rewrite the data
+110d de-compression crc error
+110e cannot decompress using declared algorithm
+110f error reading upc/ean number
+1110 error reading isrc number
+1111 read error - loss of streaming
+1112 auxiliary memory code 3 (99-148) [proposed]
+1200 address mark not found for id field
+1300 address mark not found for data field
+1400 recorded entity not found
+1401 record not found
+1402 filemark or setmark not found
+1403 end-of-data not found
+1404 block sequence error
+1405 record not found - recommend reassignment
+1406 record not found - data auto-reallocated
+1500 random positioning error
+1501 mechanical positioning error
+1502 positioning error detected by read of medium
+1600 data synchronization mark error
+1601 data sync error - data rewritten
+1602 data sync error - recommend rewrite
+1603 data sync error - data auto-reallocated
+1604 data sync error - recommend reassignment
+1700 recovered data with no error correction applied
+1701 recovered data with retries
+1702 recovered data with positive head offset
+1703 recovered data with negative head offset
+1704 recovered data with retries and/or circ applied
+1705 recovered data using previous sector id
+1706 recovered data without ecc - data auto-reallocated
+1707 recovered data without ecc - recommend reassignment
+1708 recovered data without ecc - recommend rewrite
+1709 recovered data without ecc - data rewritten
+1800 recovered data with error correction applied
+1801 recovered data with error corr. & retries applied
+1802 recovered data - data auto-reallocated
+1803 recovered data with circ
+1804 recovered data with l-ec
+1805 recovered data - recommend reassignment
+1806 recovered data - recommend rewrite
+1807 recovered data with ecc - data rewritten
+1900 defect list error
+1901 defect list not available
+1902 defect list error in primary list
+1903 defect list error in grown list
+1a00 parameter list length error
+1b00 synchronous data transfer error
+1c00 defect list not found
+1c01 primary defect list not found
+1c02 grown defect list not found
+1d00 miscompare during verify operation
+1e00 recovered id with ecc correction
+1f00 partial defect list transfer
+2000 invalid command operation code
+2001 access controls code 1 (99-314) [proposed]
+2002 access controls code 2 (99-314) [proposed]
+2003 access controls code 3 (99-314) [proposed]
+2100 logical block address out of range
+2101 invalid element address
+2200 illegal function (use 20 00, 24 00, or 26 00)
+23/00
+2400 invalid field in cdb
+2401 cdb decryption error
+2500 logical unit not supported
+2600 invalid field in parameter list
+2601 parameter not supported
+2602 parameter value invalid
+2603 threshold parameters not supported
+2604 invalid release of persistent reservation
+2605 data decryption error
+2606 too many target descriptors
+2607 unsupported target descriptor type code
+2608 too many segment descriptors
+2609 unsupported segment descriptor type code
+260a unexpected inexact segment
+260b inline data length exceeded
+260c invalid operation for copy source or destination
+260d copy segment granularity violation
+2700 write protected
+2701 hardware write protected
+2702 logical unit software write protected
+2703 associated write protect
+2704 persistent write protect
+2705 permanent write protect
+2800 not ready to ready change, medium may have changed
+2801 import or export element accessed
+2900 power on, reset, or bus device reset occurred
+2901 power on occurred
+2902 scsi bus reset occurred
+2903 bus device reset function occurred
+2904 device internal reset
+2905 transceiver mode changed to single-ended
+2906 transceiver mode changed to lvd
+2a00 parameters changed
+2a01 mode parameters changed
+2a02 log parameters changed
+2a03 reservations preempted
+2a04 reservations released
+2a05 registrations preempted
+2b00 copy cannot execute since host cannot disconnect
+2c00 command sequence error
+2c01 too many windows specified
+2c02 invalid combination of windows specified
+2c03 current program area is not empty
+2c04 current program area is empty
+2c05 illegal power condition request
+2d00 overwrite error on update in place
+2e00 error detected by third party temporary initiator
+2e01 third party device failure
+2e02 copy target device not reachable
+2e03 incorrect copy target device type
+2e04 copy target device data underrun
+2e05 copy target device data overrun
+2f00 commands cleared by another initiator
+3000 incompatible medium installed
+3001 cannot read medium - unknown format
+3002 cannot read medium - incompatible format
+3003 cleaning cartridge installed
+3004 cannot write medium - unknown format
+3005 cannot write medium - incompatible format
+3006 cannot format medium - incompatible medium
+3007 cleaning failure
+3008 cannot write - application code mismatch
+3009 current session not fixated for append
+3100 medium format corrupted
+3101 format command failed
+3200 no defect spare location available
+3201 defect list update failure
+3300 tape length error
+3400 enclosure failure
+3500 enclosure services failure
+3501 unsupported enclosure function
+3502 enclosure services unavailable
+3503 enclosure services transfer failure
+3504 enclosure services transfer refused
+3600 ribbon, ink, or toner failure
+3700 rounded parameter
+3800 event status notification
+3802 esn - power management class event
+3804 esn - media class event
+3806 esn - device busy class event
+3900 saving parameters not supported
+3a00 medium not present
+3a01 medium not present - tray closed
+3a02 medium not present - tray open
+3a03 medium not present - loadable
+3a04 medium not present - medium auxiliary memory accessible
+3b00 sequential positioning error
+3b01 tape position error at beginning-of-medium
+3b02 tape position error at end-of-medium
+3b03 tape or electronic vertical forms unit not ready
+3b04 slew failure
+3b05 paper jam
+3b06 failed to sense top-of-form
+3b07 failed to sense bottom-of-form
+3b08 reposition error
+3b09 read past end of medium
+3b0a read past beginning of medium
+3b0b position past end of medium
+3b0c position past beginning of medium
+3b0d medium destination element full
+3b0e medium source element empty
+3b0f end of medium reached
+3b11 medium magazine not accessible
+3b12 medium magazine removed
+3b13 medium magazine inserted
+3b14 medium magazine locked
+3b15 medium magazine unlocked
+3b16 mechanical positioning or changer error
+3c/00
+3d00 invalid bits in identify message
+3e00 logical unit has not self-configured yet
+3e01 logical unit failure
+3e02 timeout on logical unit
+3e03 logical unit failed self-test
+3e04 logical unit unable to update self-test log
+3f00 target operating conditions have changed
+3f01 microcode has been changed
+3f02 changed operating definition
+3f03 inquiry data has changed
+3f04 component device attached
+3f05 device identifier changed
+3f06 redundancy group created or modified
+3f07 redundancy group deleted
+3f08 spare created or modified
+3f09 spare deleted
+3f0a volume set created or modified
+3f0b volume set deleted
+3f0c volume set deassigned
+3f0d volume set reassigned
+3f0e reported luns data has changed
+3f0f echo buffer overwritten
+3f10 medium loadable
+3f11 medium auxiliary memory accessible
+4000 ram failure (should use 40 nn)
+40nn diagnostic failure on component nn (80h-ffh)
+4100 data path failure (should use 40 nn)
+4200 power-on or self-test failure (should use 40 nn)
+4300 message error
+4400 internal target failure
+4500 select or reselect failure
+4600 unsuccessful soft reset
+4700 scsi parity error
+4701 data phase crc error detected
+4702 scsi parity error detected during st data phase
+4703 information unit crc error detected
+4704 asynchronous information protection error detected
+4800 initiator detected error message received
+4900 invalid message error
+4a00 command phase error
+4b00 data phase error
+4c00 logical unit failed self-configuration
+4dnn tagged overlapped commands (nn = queue tag)
+4e00 overlapped commands attempted
+4f/00
+5000 write append error
+5001 write append position error
+5002 position error related to timing
+5100 erase failure
+5200 cartridge fault
+5300 media load or eject failed
+5301 unload tape failure
+5302 medium removal prevented
+5400 scsi to host system interface failure
+5500 system resource failure
+5501 system buffer full
+5502 insufficient reservation resources
+5503 insufficient resources
+5504 insufficient registration resources
+5505 access controls code 4 (99-314) [proposed]
+5506 auxiliary memory code 1 (99-148) [proposed]
+56/00
+5700 unable to recover table-of-contents
+5800 generation does not exist
+5900 updated block read
+5a00 operator request or state change input
+5a01 operator medium removal request
+5a02 operator selected write protect
+5a03 operator selected write permit
+5b00 log exception
+5b01 threshold condition met
+5b02 log counter at maximum
+5b03 log list codes exhausted
+5c00 rpl status change
+5c01 spindles synchronized
+5c02 spindles not synchronized
+5d00 failure prediction threshold exceeded
+5d01 media failure prediction threshold exceeded
+5d02 logical unit failure prediction threshold exceeded
+5d10 hardware impending failure general hard drive failure
+5d11 hardware impending failure drive error rate too high
+5d12 hardware impending failure data error rate too high
+5d13 hardware impending failure seek error rate too high
+5d14 hardware impending failure too many block reassigns
+5d15 hardware impending failure access times too high
+5d16 hardware impending failure start unit times too high
+5d17 hardware impending failure channel parametrics
+5d18 hardware impending failure controller detected
+5d19 hardware impending failure throughput performance
+5d1a hardware impending failure seek time performance
+5d1b hardware impending failure spin-up retry count
+5d1c hardware impending failure drive calibration retry count
+5d20 controller impending failure general hard drive failure
+5d21 controller impending failure drive error rate too high
+5d22 controller impending failure data error rate too high
+5d23 controller impending failure seek error rate too high
+5d24 controller impending failure too many block reassigns
+5d25 controller impending failure access times too high
+5d26 controller impending failure start unit times too high
+5d27 controller impending failure channel parametrics
+5d28 controller impending failure controller detected
+5d29 controller impending failure throughput performance
+5d2a controller impending failure seek time performance
+5d2b controller impending failure spin-up retry count
+5d2c controller impending failure drive calibration retry count
+5d30 data channel impending failure general hard drive failure
+5d31 data channel impending failure drive error rate too high
+5d32 data channel impending failure data error rate too high
+5d33 data channel impending failure seek error rate too high
+5d34 data channel impending failure too many block reassigns
+5d35 data channel impending failure access times too high
+5d36 data channel impending failure start unit times too high
+5d37 data channel impending failure channel parametrics
+5d38 data channel impending failure controller detected
+5d39 data channel impending failure throughput performance
+5d3a data channel impending failure seek time performance
+5d3b data channel impending failure spin-up retry count
+5d3c data channel impending failure drive calibration retry count
+5d40 servo impending failure general hard drive failure
+5d41 servo impending failure drive error rate too high
+5d42 servo impending failure data error rate too high
+5d43 servo impending failure seek error rate too high
+5d44 servo impending failure too many block reassigns
+5d45 servo impending failure access times too high
+5d46 servo impending failure start unit times too high
+5d47 servo impending failure channel parametrics
+5d48 servo impending failure controller detected
+5d49 servo impending failure throughput performance
+5d4a servo impending failure seek time performance
+5d4b servo impending failure spin-up retry count
+5d4c servo impending failure drive calibration retry count
+5d50 spindle impending failure general hard drive failure
+5d51 spindle impending failure drive error rate too high
+5d52 spindle impending failure data error rate too high
+5d53 spindle impending failure seek error rate too high
+5d54 spindle impending failure too many block reassigns
+5d55 spindle impending failure access times too high
+5d56 spindle impending failure start unit times too high
+5d57 spindle impending failure channel parametrics
+5d58 spindle impending failure controller detected
+5d59 spindle impending failure throughput performance
+5d5a spindle impending failure seek time performance
+5d5b spindle impending failure spin-up retry count
+5d5c spindle impending failure drive calibration retry count
+5d60 firmware impending failure general hard drive failure
+5d61 firmware impending failure drive error rate too high
+5d62 firmware impending failure data error rate too high
+5d63 firmware impending failure seek error rate too high
+5d64 firmware impending failure too many block reassigns
+5d65 firmware impending failure access times too high
+5d66 firmware impending failure start unit times too high
+5d67 firmware impending failure channel parametrics
+5d68 firmware impending failure controller detected
+5d69 firmware impending failure throughput performance
+5d6a firmware impending failure seek time performance
+5d6b firmware impending failure spin-up retry count
+5d6c firmware impending failure drive calibration retry count
+5dff failure prediction threshold exceeded (false)
+5e00 low power condition on
+5e01 idle condition activated by timer
+5e02 standby condition activated by timer
+5e03 idle condition activated by command
+5e04 standby condition activated by command
+5e41 power state change to active
+5e42 power state change to idle
+5e43 power state change to standby
+5e45 power state change to sleep
+5e47 power state change to device control
+5f/00
+6000 lamp failure
+6100 video acquisition error
+6101 unable to acquire video
+6102 out of focus
+6200 scan head positioning error
+6300 end of user area encountered on this track
+6301 packet does not fit in available space
+6400 illegal mode for this track
+6401 invalid packet size
+6500 voltage fault
+6600 automatic document feeder cover up
+6601 automatic document feeder lift up
+6602 document jam in automatic document feeder
+6603 document miss feed automatic in document feeder
+6700 configuration failure
+6701 configuration of incapable logical units failed
+6702 add logical unit failed
+6703 modification of logical unit failed
+6704 exchange of logical unit failed
+6705 remove of logical unit failed
+6706 attachment of logical unit failed
+6707 creation of logical unit failed
+6708 assign failure occurred
+6709 multiply assigned logical unit
+6800 logical unit not configured
+6900 data loss on logical unit
+6901 multiple logical unit failures
+6902 parity/data mismatch
+6a00 informational, refer to log
+6b00 state change has occurred
+6b01 redundancy level got better
+6b02 redundancy level got worse
+6c00 rebuild failure occurred
+6d00 recalculate failure occurred
+6e00 command to logical unit failed
+6f00 copy protection key exchange failure - authentication failure
+6f01 copy protection key exchange failure - key not present
+6f02 copy protection key exchange failure - key not established
+6f03 read of scrambled sector without authentication
+6f04 media region code is mismatched to logical unit region
+6f05 drive region must be permanent/region reset count error
+70nn decompression exception short algorithm id of nn
+7100 decompression exception long algorithm id
+7200 session fixation error
+7201 session fixation error writing lead-in
+7202 session fixation error writing lead-out
+7203 session fixation error - incomplete track in session
+7204 empty or partially written reserved track
+7205 no more track reservations allowed
+7300 cd control error
+7301 power calibration area almost full
+7302 power calibration area is full
+7303 power calibration area error
+7304 program memory area update failure
+7305 program memory area is full
+7306 rma/pma is full
+74/00
+75/00
+76/00
+77/00
+78/00
+79/00
+7a/00
+7b/00
+7c/00
+7d/00
+7e/00
+7f/00
--- /dev/null
+++ b/lib/sexp
@@ -1,0 +1,699 @@
+Network  Working Group                                         R. Rivest
+Internet Draft                                               May 4, 1997
+Expires November 4, 1997
+
+
+	                      S-Expressions
+                        draft-rivest-sexp-00.txt
+
+
+Status of this Memo
+
+   Distribution of this memo is unlimited.
+
+   This document is an Internet-Draft.  Internet Drafts are working
+   documents of the Internet Engineering Task Force (IETF), its Areas,
+   and its Working Groups.  Note that other groups may also distribute
+   working documents as Internet Drafts.
+
+   Internet Drafts are draft documents valid for a maximum of six
+   months, and may be updated, replaced, or obsoleted by other documents
+   at any time.  It is not appropriate to use Internet Drafts as
+   reference material, or to cite them other than as a ``working draft''
+   or ``work in progress.''
+
+   To learn the current status of any Internet-Draft, please check the
+   ``1id-abstracts.txt'' listing contained in the internet-drafts Shadow
+   Directories on: ftp.is.co.za (Africa), nic.nordu.net (Europe),
+   ds.internic.net (US East Coast), ftp.isi.edu (US West Coast),
+   or munnari.oz.au (Pacific Rim)
+
+
+Abstract
+
+This memo describes a data structure called "S-expressions" that are
+suitable for representing arbitrary complex data structures.  We make
+precise the encodings of S-expressions: we give a "canonical form" for
+S-expressions, described two "transport" representations, and also
+describe an "advanced" format for display to people.
+
+
+
+1. Introduction
+
+S-expressions are data structures for representing complex data.  They
+are either byte-strings ("octet-strings") or lists of simpler
+S-expressions.  Here is a sample S-expression:
+
+	(snicker "abc" (#03# |YWJj|))
+
+It is a list of length three: 
+
+	-- the octet-string "snicker"
+
+	-- the octet-string "abc"
+
+	-- a sub-list containing two elements:
+		- the hexadecimal constant #03#
+		- the base-64 constant |YWJj| (which is the same as "abc")
+
+This note gives a specific proposal for constructing and utilizing
+S-expressions.  The proposal is independent of any particular application.
+
+Here are the design goals for S-expressions:
+
+  -- generality: S-expressions should be good at representing arbitrary
+     data.
+
+  -- readability: it should be easy for someone to examine and 
+     understand the structure of an S-expression.
+
+  -- economy: S-expressions should represent data compactly.
+
+  -- tranportability: S-expressions should be easy to transport
+     over communication media (such as email) that are known to be
+     less than perfect.
+
+  -- flexibility: S-expressions should make it relatively simple to
+     modify and extend data structures.
+
+  -- canonicalization: it should be easy to produce a unique 
+     "canonical" form of an S-expression, for digital signature purposes.
+
+  -- efficiency: S-expressions should admit in-memory representations
+     that allow efficient processing.
+
+
+Section 2 gives an introduction to S-expressions.
+Section 3 discusses the character sets used.
+Section 4 presents the various representations of octet-strings.
+Section 5 describes how to represent lists.
+Section 6 discusses how S-expressions are represented for various uses.
+Section 7 gives a BNF syntax for S-expressions.
+Section 8 talks about how S-expressions might be represented in memory.
+Section 9 briefly describes implementations for handling S-expressions.
+Section 10 discusses how applications might utilize S-expressions.
+Section 11 gives historical notes on S-expressions.
+Section 12 gives references.
+
+2. S-expressions -- informal introduction
+
+Informally, an S-expression is either:
+	-- an octet-string, or
+	-- a finite list of simpler S-expressions.
+
+An octet-string is a finite sequence of eight-bit octets.  There may be
+many different but equivalent ways of representing an octet-string
+
+	abc		-- as a token
+
+	"abc"		-- as a quoted string
+
+	#616263#	-- as a hexadecimal string
+
+	3:abc		-- as a length-prefixed "verbatim" encoding
+
+	{MzphYmM=}	-- as a base-64 encoding of the verbatim encoding
+			   (that is, an encoding of "3:abc")
+
+	|YWJj|		-- as a base-64 encoding of the octet-string "abc"
+
+These encodings are all equivalent; they all denote the same octet string.
+
+We will give details of these encodings later on, and also describe how to
+give a "display type" to a byte string.
+
+A list is a finite sequence of zero or more simpler S-expressions.  A list
+may be represented by using parentheses to surround the sequence of encodings
+of its elements, as in:
+
+	(abc (de #6667#) "ghi jkl")
+
+As we see, there is variability possible in the encoding of an
+S-expression.  In some cases, it is desirable to standardize or
+restrict the encodings; in other cases it is desirable to have no
+restrictions.  The following are the target cases we aim to handle:
+
+	-- a "transport" encoding for transporting the S-expression between
+	   computers.
+
+	-- a "canonical" encoding, used when signing the S-expression.
+
+	-- an "advanced" encoding used for input/output to people.
+
+	-- an "in-memory" encoding used for processing the S-expression in
+	   the computer.
+
+These need not be different; in this proposal the canonical encoding
+is the same as the transport encoding, for example.  In this note we
+propose (related) encoding techniques for each of these uses.
+
+3. Character set 
+
+We will be describing encodings of S-expressions.  Except when giving
+"verbatim" encodings, the character set used is limited to the following
+characters in US-ASCII:
+	Alphabetic:	A B ... Z a b ... z
+	numeric:	0 1 ... 9
+	whitespace:	space, horizontal tab, vertical tab, form-feed
+			carriage-return, line-feed
+	The following graphics characters, which we call "pseudo-alphabetic":
+			- hyphen or minus
+			. period
+			/ slash
+			_ underscore
+			: colon
+			* asterisk
+			+ plus
+			= equal
+	The following graphics characters, which are "reserved punctuation":
+			( left parenthesis
+			) right parenthesis
+			[ left bracket
+			] right bracket
+			{ left brace
+			} right brace
+			| vertical bar
+			# number sign
+			" double quote
+			& ampersand
+			\ backslash
+	The following characters are unused and unavailable, except in
+	"verbatim" encodings:
+			! exclamation point
+			% percent
+			^ circumflex
+			~ tilde
+			; semicolon
+			' apostrophe
+			, comma
+			< less than
+			> greater than
+			? question mark
+
+
+4. Octet string representations
+
+This section describes in detail the ways in which an octet-string may
+be represented.
+
+We recall that an octet-string is any finite sequence of octets, and
+that the octet-string may have length zero.
+
+
+4.1 Verbatim representation
+
+A verbatim encoding of an octet string consists of four parts:
+
+	-- the length (number of octets) of the octet-string, 
+	   given in decimal most significant digit first, with
+	   no leading zeros.
+
+	-- a colon ":"
+
+	-- the octet string itself, verbatim.
+
+There are no blanks or whitespace separating the parts.  No "escape
+sequences" are interpreted in the octet string.  This encoding is also
+called a "binary" or "raw" encoding.
+	
+Here are some sample verbatim encodings:
+
+	3:abc
+	7:subject
+	4:::::
+	12:hello world!
+	10:abcdefghij
+	0:
+
+4.2 Quoted-string representation
+
+The quoted-string representation of an octet-string consists of:
+
+	-- an optional decimal length field
+
+	-- an initial double-quote (")
+
+	-- the octet string with "C" escape conventions (\n,etc)
+
+	-- a final double-quote (")
+
+The specified length is the length of the resulting string after any
+escape sequences have been handled.  The string does not have any
+"terminating NULL" that C includes, and the length does not count such
+a character.
+
+The length is optional.
+
+The escape conventions within the quoted string are as follows (these follow
+the "C" programming language conventions, with an extension for 
+ignoring line terminators of just LF or CRLF):
+	\b		-- backspace
+	\t		-- horizontal tab
+	\v 		-- vertical tab
+	\n		-- new-line
+	\f		-- form-feed
+	\r		-- carriage-return
+	\"		-- double-quote
+	\'		-- single-quote
+	\\		-- back-slash
+	\ooo		-- character with octal value ooo (all three digits
+			   must be present)
+	\xhh		-- character with hexadecimal value hh (both digits
+			   must be present)
+	\<carriage-return> -- causes carriage-return to be ignored.
+	\<line-feed>       -- causes linefeed to be ignored
+	\<carriage-return><line-feed> -- causes CRLF to be ignored.
+	\<line-feed><carriage-return> -- causes LFCR to be ignored.
+
+Here are some examples of quoted-string encodings:
+
+	"subject"
+	"hi there"
+	7"subject"
+	3"\n\n\n"
+	"This has\n two lines."
+	"This has\
+	one."
+	""
+
+4.3 Token representation 
+
+An octet string that meets the following conditions may be given
+directly as a "token".
+
+	-- it does not begin with a digit
+
+	-- it contains only characters that are
+		-- alphabetic (upper or lower case),
+		-- numeric, or
+		-- one of the eight "pseudo-alphabetic" punctuation marks:
+			-   .   /   _   :  *  +  =  
+	(Note: upper and lower case are not equivalent.)
+	(Note: A token may begin with punctuation, including ":").
+
+Here are some examples of token representations:
+
+	subject
+	not-before
+	class-of-1997
+	//microsoft.com/names/smith
+	*
+
+
+4.4 Hexadecimal representation
+
+An octet-string may be represented with a hexadecimal encoding consisting of:
+
+	-- an (optional) decimal length of the octet string
+
+	-- a sharp-sign "#"
+
+	-- a hexadecimal encoding of the octet string, with each octet
+	   represented with two hexadecimal digits, most significant
+	   digit first.
+
+	-- a sharp-sign "#"
+
+There may be whitespace inserted in the midst of the hexadecimal
+encoding arbitrarily; it is ignored.  It is an error to have
+characters other than whitespace and hexadecimal digits.
+
+Here are some examples of hexadecimal encodings:
+
+	#616263#		-- represents "abc"
+	3#616263#		-- also represents "abc"
+	# 616
+	  263 #                 -- also represents "abc"
+	
+
+4.5 Base-64 representation
+
+An octet-string may be represented in a base-64 coding consisting of:
+
+	-- an (optional) decimal length of the octet string
+
+	-- a vertical bar "|"
+
+	-- the rfc 1521 base-64 encoding of the octet string.  
+
+	-- a final vertical bar "|"
+
+The base-64 encoding uses only the characters 
+	A-Z  a-z  0-9  +  /  = 
+It produces four characters of output for each three octets of input.
+If the input has one or two left-over octets of input, it produces an
+output block of length four ending in two or one equals signs, respectively.
+Output routines compliant with this standard MUST output the equals signs
+as specified.  Input routines MAY accept inputs where the equals signs are
+dropped.
+
+There may be whitespace inserted in the midst of the base-64 encoding
+arbitrarily; it is ignored.  It is an error to have characters other
+than whitespace and base-64 characters.  
+
+Here are some examples of base-64 encodings:
+
+	|YWJj|		-- represents "abc"
+	| Y W
+	  J j |		-- also represents "abc"
+	3|YWJj|		-- also represents "abc"
+	|YWJjZA==|	-- represents "abcd"
+	|YWJjZA|	-- also represents "abcd"
+
+
+4.6 Display hint
+
+Any octet string may be preceded by a single "display hint".
+
+The purposes of the display hint is to provide information on how
+to display the octet string to a user.  It has no other function.
+Many of the MIME types work here.
+
+A display-hint is an octet string surrounded by square brackets.
+There may be whitespace separating the octet string from the
+surrounding brackets.  Any of the legal formats may be used for the
+octet string.
+
+Here are some examples of display-hints:
+
+	[image/gif]
+	[URI]
+	[charset=unicode-1-1]
+	[text/richtext]
+	[application/postscript]
+	[audio/basic]
+	["http://abc.com/display-types/funky.html"]
+
+In applications an octet-string that is untyped may be considered to have
+a pre-specified "default" mime type.  The mime type
+		"text/plain; charset=iso-8859-1" 
+is the standard default.
+
+
+4.7  Equality of octet-strings
+
+Two octet strings are considered to be "equal" if and only if they
+have the same display hint and the same data octet strings.
+
+Note that octet-strings are "case-sensitive"; the octet-string "abc"
+is not equal to the octet-string "ABC".
+
+An untyped octet-string can be compared to another octet-string (typed
+or not) by considering it as a typed octet-string with the default
+mime-type.
+
+
+5. Lists
+
+Just as with octet-strings, there are several ways to represent an
+S-expression.  Whitespace may be used to separate list elements, but
+they are only required to separate two octet strings when otherwise
+the two octet strings might be interpreted as one, as when one token
+follows another.  Also,	whitespace may follow the initial left
+parenthesis, or precede the final right parenthesis.
+
+Here are some examples of encodings of lists:
+
+	(a b c)
+
+	( a ( b c ) ( ( d e ) ( e f ) )  )
+
+	(11:certificate(6:issuer3:bob)(7:subject5:alice))
+
+	({3Rt=} "1997" murphy 3:{XC++})
+
+
+6. Representation types
+
+There are three "types" of representations: 
+
+	-- canonical
+
+	-- basic transport
+
+	-- advanced transport
+
+The first two MUST be supported by any implementation; the last is
+optional.
+
+
+6.1  Canonical representation
+
+This canonical representation is used for digital signature purposes,
+transmission, etc.  It is uniquely defined for each S-expression.  It
+is not particularly readable, but that is not the point.  It is
+intended to be very easy to parse, to be reasonably economical, and to
+be unique for any S-expression.
+
+The "canonical" form of an S-expression represents each octet-string
+in verbatim mode, and represents each list with no blanks separating
+elements from each other or from the surrounding parentheses.
+
+Here are some examples of canonical representations of S-expressions:
+	
+	(6:issuer3:bob)
+
+	(4:icon[12:image/bitmap]9:xxxxxxxxx)
+
+	(7:subject(3:ref5:alice6:mother))
+
+
+6.2 Basic transport representation
+
+There are two forms of the "basic transport" representation:
+
+	-- the canonical representation
+
+	-- an rfc-2045 base-64 representation of the canonical representation,
+           surrounded by braces.
+
+The transport mechanism is intended to provide a universal means of
+representing S-expressions for transport from one machine to another.
+
+Here are some examples of an S-expression represented in basic
+transport mode:
+
+	(1:a1:b1:c)
+
+	{KDE6YTE6YjE6YykA}
+				
+		(this is the same S-expression encoded in base-64)
+
+There is a difference between the brace notation for base-64 used here
+and the || notation for base-64'd octet-strings described above.  Here
+the base-64 contents are converted to octets, and then re-scanned as
+if they were given originally as octets.  With the || notation, the
+contents are just turned into an octet-string.
+
+
+6.3 Advanced transport representation
+
+The "advanced transport" representation is intended to provide more
+flexible and readable notations for documentation, design, debugging,
+and (in some cases) user interface.
+
+The advanced transport representation allows all of the representation
+forms described above, include quoted strings, base-64 and hexadecimal
+representation of strings, tokens, representations of strings with
+omitted lengths, and so on.
+
+
+7. BNF for syntax
+
+We give separate BNF's for canonical and advanced forms of S-expressions.
+We use the following notation:
+	<x>* 		means 0 or more occurrences of <x>
+	<x>+		means 1 or more occurrences of <x>  
+	<x>?		means 0 or 1 occurrences of <x>
+	parentheses	are used for grouping, as in (<x> | <y>)*
+
+For canonical and basic transport:
+
+<sexpr>    	:: <string> | <list>
+<string>   	:: <display>? <simple-string> ;
+<simple-string>	:: <raw> ;
+<display>  	:: "[" <simple-string> "]" ;
+<raw>      	:: <decimal> ":" <bytes> ;
+<decimal>  	:: <decimal-digit>+ ;
+		-- decimal numbers should have no unnecessary leading zeros
+<bytes> 	-- any string of bytes, of the indicated length
+<list>     	:: "(" <sexp>* ")" ;
+<decimal-digit> :: "0" | ... | "9" ;
+
+For advanced transport:
+
+<sexpr>    	:: <string> | <list>
+<string>   	:: <display>? <simple-string> ;
+<simple-string>	:: <raw> | <token> | <base-64> | <hexadecimal> | 
+		           <quoted-string> ;
+<display>  	:: "[" <simple-string> "]" ;
+<raw>      	:: <decimal> ":" <bytes> ;
+<decimal>  	:: <decimal-digit>+ ;
+		-- decimal numbers should have no unnecessary leading zeros
+<bytes> 	-- any string of bytes, of the indicated length
+<token>    	:: <tokenchar>+ ;
+<base-64>  	:: <decimal>? "|" ( <base-64-char> | <whitespace> )* "|" ;
+<hexadecimal>   :: "#" ( <hex-digit> | <white-space> )* "#" ;
+<quoted-string> :: <decimal>? <quoted-string-body>  
+<quoted-string-body> :: "\"" <bytes> "\""
+<list>     	:: "(" ( <sexp> | <whitespace> )* ")" ;
+<whitespace> 	:: <whitespace-char>* ;
+<token-char>  	:: <alpha> | <decimal-digit> | <simple-punc> ;
+<alpha>       	:: <upper-case> | <lower-case> | <digit> ;
+<lower-case>  	:: "a" | ... | "z" ;
+<upper-case>  	:: "A" | ... | "Z" ;
+<decimal-digit> :: "0" | ... | "9" ;
+<hex-digit>     :: <decimal-digit> | "A" | ... | "F" | "a" | ... | "f" ;
+<simple-punc> 	:: "-" | "." | "/" | "_" | ":" | "*" | "+" | "=" ;
+<whitespace-char> :: " " | "\t" | "\r" | "\n" ;
+<base-64-char> 	:: <alpha> | <decimal-digit> | "+" | "/" | "=" ;
+<null>        	:: "" ;
+
+8. In-memory representations
+
+For processing, the S-expression would typically be parsed and represented
+in memory in a more more amenable to efficient processing.  We suggest
+two alternatives:
+
+	-- "list-structure"
+
+	-- "array-layout"
+
+We only sketch these here, as they are only suggestive.  The code referenced
+below illustrates these styles in more detail.
+
+
+8.1. List-structure memory representation
+
+Here there are separate records for simple-strings, strings, and
+lists.  An S-expression of the form ("abc" "de") would require two
+records for the simple strings, two for the strings, and two for the
+list elements.  This is a fairly conventional representation, and
+details are omitted here.
+
+8.2 Array-layout memory representation
+
+Here each S-expression is represented as a contiguous array of bytes.
+The first byte codes the "type" of the S-expression:
+
+	01 	octet-string
+
+	02	octet-string with display-hint
+
+	03	beginning of list (and 00 is used for "end of list")
+
+Each of the three types is immediately followed by a k-byte integer
+indicating the size (in bytes) of the following representation.  Here
+k is an integer that depends on the implementation, it might be
+anywhere from 2 to 8, but would be fixed for a given implementation;
+it determines the size of the objects that can be handled.  The transport
+and canonical representations are independent of the choice of k made by
+the implementation.
+
+Although the length of lists are not given in the usual S-expression
+notations, it is easy to fill them in when parsing; when you reach a
+right-parenthesis you know how long the list representation was, and
+where to go back to fill in the missing length.
+
+
+8.2.1 Octet string
+
+This is represented as follows:
+
+	01 <length> <octet-string>
+
+For example (here k = 2)
+
+	01 0003 a b c
+
+8.2.2 Octet-string with display-hint
+
+This is represented as follows:
+
+	02 <length>
+	  01 <length> <octet-string>    /* for display-type */
+	  01 <length> <octet-string>    /* for octet-string */
+
+For example, the S-expression 
+	
+	[gif] #61626364# 
+
+would be represented as (with k = 2)
+
+	02 000d
+	  01 0003  g  i  f
+	  01 0004 61 62 63 64
+
+8.2.3 List
+
+This is represented as
+
+	03 <length> <item1> <item2> <item3> ... <itemn> 00
+
+For example, the list (abc [d]ef (g)) is represented in memory as (with k=2)
+
+	03 001b
+	  01 0003 a b c
+          02 0009 
+            01 0001 d
+            01 0002 e f
+          03 0005
+            01 0001 g
+          00
+        00
+
+9. Code
+
+There is code available for reading and parsing the various
+S-expression formats proposed here.  
+
+See http://theory.lcs.mit.edu/~rivest/sexp.html
+
+
+10. Utilization of S-expressions
+
+This note has described S-expressions in general form.  Application writers
+may wish to restrict their use of S-expressions in various ways.  Here are
+some possible restrictions that might be considered:
+
+	-- no display-hints
+	-- no lengths on hexadecimal, quoted-strings, or base-64 encodings
+	-- no empty lists
+	-- no empty octet-strings
+	-- no lists having another list as its first element
+	-- no base-64 or hexadecimal encodings
+	-- fixed limits on the size of octet-strings
+
+11. Historical note
+
+The S-expression technology described here was originally developed
+for ``SDSI'' (the Simple Distributed Security Infrastructure by
+Lampson and Rivest [SDSI]) in 1996, although the origins clearly date
+back to McCarthy's LISP programming language.  It was further refined
+and improved during the merger of SDSI and SPKI [SPKI] during the
+first half of 1997.  S-expressions are similar to, but more readable
+and flexible than, Bernstein's "net-strings" [BERN].
+
+12. References
+
+[SDSI] "A Simple Distributed Security Architecture", by 
+        Butler Lampson, and Ronald L. Rivest
+	http://theory.lcs.mit.edu/~cis/sdsi.html
+
+[SPKI] <a href="http://www.clark.net/pub/cme/html/spki.html">SPKI--A
+       Simple Public Key Infrastructure</a>
+
+[BERN] Dan Bernstein's "net-strings"; Internet Draft
+       draft-bernstein-netstrings-02.txt
+
+Author's Address
+
+      Ronald L. Rivest
+      Room 324, 545 Technology Square
+      MIT Laboratory for Computer Science
+      Cambridge, MA 02139
+
+      rivest@theory.lcs.mit.edu
+
+
--- /dev/null
+++ b/lib/sh/owen
@@ -1,0 +1,121 @@
+load std sexprs
+
+# load a job.  result is the new job id.
+subfn job {
+	{
+		id := "{read}
+		result=$id
+		or {echo load ${quote $*} >[1=0]} {
+			raise 'load failed'
+		}
+	} $* <> /n/remote/admin/clone
+}
+
+# load a job.  print the new job id.
+fn job {
+	echo ${job $*}
+}
+
+# load a job, then start it.
+fn start {
+	id := ${job $*}
+	ctl $id start
+	echo $id
+}
+
+# send a control message to a job.
+fn ctl {
+	if {~ $#* 0 1} {
+		echo usage: ctl job-id request... >[1=2]
+		raise usage
+	}
+	(id args) := $*
+	echo ${quote $args} > /n/remote/admin/$id/ctl
+}
+
+# mount the scheduler name space
+fn mountsched {
+	configfile := $configfile		# stop changes propagating out.
+	if{no $root}{
+		root=/grid/slave
+	}
+	opts := ()
+	fsopts := ()
+	schedaddr := ()
+	schedfsaddr := ()
+	readconfig {
+		if{~ $attr schedaddr}{
+			schedaddr=$val
+		}{~ $attr auth}{
+			if{~ $val 0}{
+				opts=($opts -A)
+			}
+		}{~ $attr keyfile}{
+			opts=($opts -k $val)
+		}{~ $attr schedfsaddr}{
+			schedfsaddr=$val
+		}{~ $attr fsauth}{
+			if{~ $val 0}{
+				fsopts=($fsopts -A)
+			}
+		}{~ $attr fskey fskeyfile}{		# first form is deprecated
+			fsopts=($opts -k $val)
+		}
+	}
+	if{no $schedaddr}{
+		ifs=' 
+	'
+		schedaddr=`{cat /grid/slave/schedaddr}
+		if{no $schedaddr}{
+			echo no scheduler address found >[1=2]
+			raise error
+		}
+	}
+	mount $opts $schedaddr /n/remote
+	no $schedfsaddr ||
+		mount $fsopts $schedfsaddr /n/gridfs
+}
+
+# print a format(2) file with the given format
+fn fmtcat {
+	if {! ~ $#* 2} {
+		echo usage: fmtread fmt file >[1=2]
+		raise usage
+	}
+	(fmt file) := $*
+	{echo $fmt >[1=0]; read -o 0; cat} <> $file
+}
+
+# readconfig command.
+# on entry $configfile is name of configuration file, or empty for default.
+# $root is default root directory.
+# run command for each entry in the config file, setting $attr and $val
+# to the attribute and the value in the entry.
+fn readconfig {
+	(cmd nil) := $*
+	if{no $configfile}{
+		if{ftest -f $root/config}{
+			configfile = $root/config
+		}
+	} {
+		if{! ~ $configfile '/*' './*'} {
+			configfile = $root/$configfile
+		}
+		if{! ftest -f $configfile}{
+			echo cannot find config file $configfile >[1=2]
+			raise 'config error'
+		}
+	}
+	if{! no $configfile} {
+		< $configfile getsexprs {
+			(attr sval) := ${els $sexp}
+			if{! ~ $#sval 1}{
+				echo bad config line $sexp >[1=2]
+				raise continue;
+			}
+			attr = ${text $attr}
+			val := ${text $sval}
+			$cmd
+		}
+	}
+}
--- /dev/null
+++ b/lib/sh/profile
@@ -1,0 +1,1 @@
+# emu sh initialisation here
--- /dev/null
+++ b/lib/sh/sched
@@ -1,0 +1,121 @@
+load std sexprs
+
+# load a job.  result is the new job id.
+subfn job {
+	{
+		id := "{read}
+		result=$id
+		or {echo load ${quote $*} >[1=0]} {
+			raise 'load failed'
+		}
+	} $* <> /n/remote/admin/clone
+}
+
+# load a job.  print the new job id.
+fn job {
+	echo ${job $*}
+}
+
+# load a job, then start it.
+fn start {
+	id := ${job $*}
+	ctl $id start
+	echo $id
+}
+
+# send a control message to a job.
+fn ctl {
+	if {~ $#* 0 1} {
+		echo usage: ctl job-id request... >[1=2]
+		raise usage
+	}
+	(id args) := $*
+	echo ${quote $args} > /n/remote/admin/$id/ctl
+}
+
+# mount the scheduler name space
+fn mountsched {
+	configfile := $configfile		# stop changes propagating out.
+	if{no $root}{
+		root=/grid/slave
+	}
+	opts := ()
+	fsopts := ()
+	schedaddr := ()
+	schedfsaddr := ()
+	readconfig {
+		if{~ $attr schedaddr}{
+			schedaddr=$val
+		}{~ $attr auth}{
+			if{~ $val 0}{
+				opts=($opts -A)
+			}
+		}{~ $attr keyfile}{
+			opts=($opts -k $val)
+		}{~ $attr schedfsaddr}{
+			schedfsaddr=$val
+		}{~ $attr fsauth}{
+			if{~ $val 0}{
+				fsopts=($fsopts -A)
+			}
+		}{~ $attr fskey fskeyfile}{		# first form is deprecated
+			fsopts=($opts -k $val)
+		}
+	}
+	if{no $schedaddr}{
+		ifs=' 
+	'
+		schedaddr=`{cat /grid/slave/schedaddr}
+		if{no $schedaddr}{
+			echo no scheduler address found >[1=2]
+			raise error
+		}
+	}
+	mount $opts $schedaddr /n/remote
+	no $schedfsaddr ||
+		mount $fsopts $schedfsaddr /n/gridfs
+}
+
+# print a format(2) file with the given format
+fn fmtcat {
+	if {! ~ $#* 2} {
+		echo usage: fmtread fmt file >[1=2]
+		raise usage
+	}
+	(fmt file) := $*
+	{echo $fmt >[1=0]; read -o 0; cat} <> $file
+}
+
+# readconfig command.
+# on entry $configfile is name of configuration file, or empty for default.
+# $root is default root directory.
+# run command for each entry in the config file, setting $attr and $val
+# to the attribute and the value in the entry.
+fn readconfig {
+	(cmd nil) := $*
+	if{no $configfile}{
+		if{ftest -f $root/config}{
+			configfile = $root/config
+		}
+	} {
+		if{! ~ $configfile '/*' './*'} {
+			configfile = $root/$configfile
+		}
+		if{! ftest -f $configfile}{
+			echo cannot find config file $configfile >[1=2]
+			raise 'config error'
+		}
+	}
+	if{! no $configfile} {
+		< $configfile getsexprs {
+			(attr sval) := ${els $sexp}
+			if{! ~ $#sval 1}{
+				echo bad config line $sexp >[1=2]
+				raise continue;
+			}
+			attr = ${text $attr}
+			val := ${text $sval}
+			$cmd
+		}
+	}
+}
--- /dev/null
+++ b/lib/sh/srv
@@ -1,0 +1,24 @@
+# shell functions for starting inferno services
+load std
+
+fn srv {
+	if {! ftest -f /net/cs} {
+		srv.cs
+	}
+	srv.styx
+}
+
+fn srv.cs {
+	ndb/dns -r
+	ndb/cs
+}
+
+fn srv.styx {
+	listen tcp!*!styx {export /&}
+}
+
+fn srv.auth {
+	listen -A tcp!*!inflogin auth/logind
+	listen -A tcp!*!infsigner auth/signer
+	# listen -A tcp!*!infcsigner auth/countersigner
+}
--- /dev/null
+++ b/lib/sh/win
@@ -1,0 +1,42 @@
+load tk std
+
+fn x {
+	or {tk $wid $*} {
+		echo error on tk cmd $"*':' $status >[1=2]
+	}
+}
+
+subfn x {
+	result = ${tk $wid $*}
+	if {~ $result '!*'} {
+		echo error on tk cmd $"*':' $result >[1=2]
+	}
+}
+
+fn tkwin {
+	if {! ~ $#* 2} {
+		echo usage: tkwin name {command} >[1=2]
+		raise usage
+	}
+	wid := ${tk window $1}
+	while {} {
+		tk winctl $wid ${recv $wid}
+	} &
+	$2
+}
+
+# more for interactive use
+fn tkmkwin {
+	if {! ~ $#* 1} {
+		echo usage: tkmkwin name >[1=2]
+		raise usage
+	}
+	wid = ${tk window $1}
+	while {} {
+		tk winctl $wid ${recv $wid}
+	} &
+}
+
+fn onscreen {
+	tk onscreen $wid $1
+}
binary files /dev/null b/lib/strokes/digits.bit differ
--- /dev/null
+++ b/lib/strokes/digits.cl
@@ -1,0 +1,89 @@
+20
+4 0
+28   111 162  110 161  109 160  108 160  107 160  105 162  102 163  100 166  98 170  97 175  97 180  97 187  100 192  105 196  111 198  118 197  126 194  133 189  138 183  142 177  142 170  139 165  134 161  127 159  120 159  113 160  108 162  104 166  
+27   40 155  39 154  38 154  37 153  35 153  32 155  30 157  28 160  27 164  26 169  27 176  29 182  32 188  36 192  40 194  45 193  50 190  54 184  58 178  61 171  62 164  60 158  56 154  50 152  44 153  37 155  32 159  
+29   102 43  103 43  102 43  101 43  99 45  97 47  95 50  94 55  93 60  94 65  95 68  97 73  101 76  106 77  112 77  117 75  122 73  126 69  128 64  128 59  127 53  124 48  120 43  114 40  109 39  104 39  100 41  98 43  97 46  
+26   28 39  27 38  27 39  26 40  24 41  22 44  21 48  20 52  19 58  20 64  22 69  25 73  29 76  34 77  38 75  43 72  47 68  50 63  51 57  51 51  49 46  46 41  42 38  37 37  32 37  29 39  
+8 1
+43   158 35  158 36  157 37  157 40  156 42  156 44  156 47  155 50  155 53  154 55  154 58  153 60  153 62  153 64  153 66  153 69  153 71  153 73  153 74  153 76  153 77  153 79  153 80  153 82  153 80  153 82  153 84  153 86  153 88  153 89  153 91  153 93  154 95  154 97  154 98  154 99  154 100  154 101  154 102  154 103  154 104  154 105  154 106  
+60   46 31  46 32  45 33  45 34  45 36  44 38  44 39  43 41  43 44  42 46  42 48  42 49  42 51  42 54  42 55  42 57  42 59  42 60  42 62  42 63  42 64  42 65  42 66  42 67  42 69  42 71  42 73  42 74  42 73  42 74  42 76  42 77  42 78  42 79  42 80  42 81  42 82  42 83  41 83  41 84  41 85  41 86  41 88  41 89  41 90  41 91  41 92  40 92  40 93  40 94  40 95  40 96  40 97  40 98  40 99  40 100  40 101  40 102  40 103  40 102  
+20   112 25  112 26  112 28  112 30  113 33  113 37  113 41  113 45  113 52  113 56  113 60  113 63  113 67  112 70  112 74  112 77  112 78  111 79  111 80  111 81  
+30   52 28  52 29  52 31  52 33  52 35  52 37  53 40  53 43  53 45  53 48  53 50  53 53  53 55  53 58  53 60  53 62  53 64  53 65  53 67  53 68  53 69  53 70  53 71  53 72  53 73  52 73  52 74  52 75  51 75  51 76  
+15   117 153  117 152  117 153  117 156  117 160  117 166  117 172  117 180  117 186  117 191  117 195  118 197  118 198  119 198  119 197  
+14   35 150  36 149  37 149  37 151  37 155  37 160  36 167  36 175  36 182  36 189  37 193  38 196  38 197  39 196  
+11   109 34  109 35  110 37  110 42  111 48  111 56  111 64  111 72  112 78  112 81  112 82  
+13   26 30  26 32  27 36  27 41  27 48  27 56  27 63  27 69  27 74  27 78  28 79  28 80  28 81  
+4 2
+28   100 163  99 162  100 162  102 161  105 161  110 160  116 160  121 160  126 162  129 165  129 170  127 176  123 183  118 189  113 194  108 198  105 200  104 201  103 201  105 201  107 201  110 200  114 200  119 199  125 199  130 199  134 198  138 198  
+30   27 161  26 160  26 159  27 159  28 158  30 157  33 157  37 157  39 158  42 161  43 165  43 171  42 179  39 186  35 193  30 199  26 202  23 204  21 204  21 202  22 200  25 198  29 196  33 195  38 196  43 197  48 198  52 200  54 201  56 202  
+33   96 39  96 38  96 37  96 36  97 35  99 33  101 32  104 31  106 31  109 31  112 33  113 37  115 42  115 48  115 55  114 62  112 68  109 73  106 77  102 80  100 81  96 82  94 81  94 80  95 79  98 78  102 76  108 76  114 75  119 76  124 76  127 77  129 77  
+25   19 37  18 36  19 35  20 33  23 32  26 31  30 31  34 32  37 34  38 38  37 44  35 51  31 58  26 65  21 71  17 75  15 78  14 78  16 78  19 76  23 76  28 75  32 75  36 75  40 75  
+4 3
+36   84 161  85 160  86 159  88 158  91 157  95 156  100 156  104 156  109 157  112 159  113 163  113 167  110 173  107 177  104 180  102 183  101 184  100 184  101 184  103 183  105 182  108 182  110 182  113 183  115 185  116 187  116 191  115 195  113 199  109 202  105 204  100 206  95 206  91 205  88 204  85 202  
+38   18 163  18 164  19 163  20 163  22 162  24 162  28 161  31 161  35 162  38 163  40 164  41 167  41 169  40 172  38 175  36 177  34 179  32 180  31 180  32 180  33 180  35 180  37 180  40 181  43 182  45 184  47 188  47 191  47 195  44 199  41 202  38 204  35 204  32 203  30 201  28 199  25 197  23 197  
+36   93 34  92 34  93 33  94 31  97 29  101 28  105 27  110 27  113 27  115 30  116 33  115 37  112 42  109 47  106 51  103 54  102 55  101 55  102 54  104 53  107 52  110 52  113 54  115 56  117 59  118 63  118 67  116 71  113 74  109 77  104 78  100 79  95 79  92 77  90 76  88 74  
+36   12 29  13 28  14 27  15 26  18 24  20 23  24 22  27 22  30 22  33 24  34 27  35 30  34 34  31 38  29 42  27 45  25 46  24 47  25 46  27 45  29 45  31 45  34 45  36 48  38 52  39 57  40 62  39 67  37 71  34 74  31 76  27 77  24 76  20 75  18 73  16 71  
+4 4
+26   107 158  107 157  108 158  108 160  109 163  109 167  109 172  108 176  107 181  106 185  106 188  106 190  106 191  108 191  110 191  112 190  116 189  120 188  124 187  130 186  136 185  141 185  147 185  151 185  154 184  155 184  
+24   22 159  23 160  23 161  23 162  24 164  24 167  25 170  25 173  24 176  24 179  24 181  24 182  25 183  26 183  27 183  29 183  32 182  35 182  40 181  45 180  51 179  56 179  60 178  63 177  
+20   104 26  105 26  105 27  106 29  106 34  106 39  106 45  106 50  105 54  105 57  106 59  108 59  110 58  114 58  118 57  123 57  127 56  131 56  135 57  137 57  
+22   19 24  20 24  20 25  21 27  21 31  21 35  21 41  20 47  19 53  18 58  18 62  18 64  19 66  22 66  26 66  31 66  36 65  42 65  46 65  49 65  52 66  53 66  
+4 6
+33   114 148  114 147  113 147  113 148  111 149  110 152  108 155  106 158  104 163  103 168  103 173  103 178  105 182  107 187  111 190  115 193  119 194  123 195  128 194  132 192  135 188  139 186  140 183  141 180  140 178  138 176  134 175  129 174  123 174  118 175  113 176  109 178  107 180  
+35   47 154  47 153  47 152  47 151  47 150  46 149  45 147  43 146  41 146  38 147  35 149  33 152  30 157  28 163  28 169  28 177  29 184  31 190  33 195  36 197  38 198  41 198  44 196  46 194  48 190  49 187  49 184  48 181  47 179  45 178  42 178  39 179  35 180  30 183  26 186  
+41   127 30  127 31  127 30  128 30  128 29  128 28  128 26  127 25  126 23  125 21  123 19  121 18  119 16  117 16  115 16  113 17  110 19  108 22  106 26  103 32  102 38  100 44  100 52  100 59  101 65  103 70  106 74  110 76  114 77  119 76  123 74  126 72  127 68  127 65  125 62  121 61  117 60  113 62  109 64  106 67  105 70  
+30   29 16  28 16  27 17  26 20  24 23  23 28  22 35  21 42  21 50  22 57  23 63  26 67  29 69  32 70  35 69  39 68  42 66  44 64  46 61  47 59  46 56  45 53  43 51  39 49  35 49  30 49  26 51  23 53  21 56  21 60  
+4 7
+26   98 161  97 161  97 160  98 160  99 160  102 160  107 159  112 159  118 158  124 158  130 157  134 157  135 157  136 158  135 159  134 162  133 164  131 169  127 176  124 184  120 192  116 199  114 204  113 207  113 208  113 207  
+27   27 152  26 153  25 153  26 153  28 153  30 154  34 154  38 154  43 154  48 155  52 156  55 156  57 157  58 158  58 157  58 158  57 159  56 161  55 163  53 168  51 175  47 183  44 192  41 201  39 207  38 211  38 213  
+27   102 40  102 41  104 41  106 41  110 40  115 39  120 39  125 38  129 38  132 38  134 38  135 39  136 39  136 40  136 41  136 42  135 43  134 46  133 51  130 57  127 65  125 74  122 81  120 87  119 91  118 94  118 95  
+28   27 36  26 37  25 37  24 37  23 37  24 37  25 36  28 36  32 36  38 36  44 35  51 34  57 34  61 33  64 33  65 34  65 37  63 40  61 45  58 51  55 58  52 66  50 72  48 77  47 81  46 82  46 83  45 83  
+4 8
+43   123 152  124 151  125 151  125 150  125 149  124 148  123 148  121 148  117 149  113 152  109 155  106 158  104 162  104 165  105 168  108 170  112 171  116 173  121 174  125 176  128 179  129 182  129 186  127 189  124 193  119 196  114 197  110 196  108 194  106 190  107 186  109 182  113 177  116 174  121 171  124 168  127 165  129 162  129 159  128 157  126 155  123 154  122 153  
+46   43 146  43 145  43 144  42 143  42 142  41 141  39 140  37 140  33 141  30 142  26 144  23 147  22 150  21 153  22 156  24 159  27 162  29 164  32 165  36 167  39 169  42 171  45 173  47 176  48 179  48 183  47 186  45 188  41 190  37 191  32 191  28 190  24 187  22 184  23 180  25 175  28 170  32 166  37 162  41 159  44 156  45 154  45 152  44 150  42 149  40 149  
+44   120 34  120 33  120 32  120 31  120 30  118 29  117 27  114 26  111 26  108 27  105 29  102 32  100 35  100 40  100 44  102 47  105 50  109 51  113 53  117 54  121 56  124 58  126 61  127 65  127 69  126 72  124 75  120 77  116 79  110 80  106 80  101 79  99 77  98 75  99 70  103 65  108 59  113 53  117 47  121 43  123 39  124 36  123 35  122 34  
+41   38 23  38 22  37 21  35 20  33 20  30 21  26 22  23 24  20 26  19 29  18 32  18 35  20 38  23 40  26 41  30 43  34 44  37 45  41 47  43 49  44 53  44 57  44 61  42 65  40 68  37 70  34 70  30 69  28 67  26 64  26 61  27 56  29 51  32 45  36 39  39 34  41 31  42 27  43 23  42 20  40 19  
+4 9
+34   127 159  127 158  126 157  126 156  125 156  123 155  121 154  118 153  114 153  110 154  107 156  104 159  102 163  102 168  103 172  105 175  108 177  112 176  116 175  119 172  121 170  123 167  124 165  124 164  125 164  125 166  126 169  126 173  127 179  128 192  129 198  130 202  130 204  131 204  
+40   53 158  53 157  53 155  53 154  52 153  51 152  49 150  47 149  44 149  41 150  38 151  34 154  32 157  30 161  31 165  33 168  36 170  40 171  45 171  48 169  52 168  54 166  55 163  56 162  56 160  56 159  56 160  57 163  57 167  58 173  59 180  60 188  60 195  59 201  58 206  56 210  54 211  53 211  51 211  50 210  
+42   127 36  128 36  128 35  128 34  128 33  127 32  125 31  123 30  120 30  115 30  111 31  107 32  104 34  102 36  102 40  103 43  106 46  110 49  113 50  118 50  123 49  127 46  131 44  133 41  135 40  136 39  136 38  136 39  135 40  135 42  135 46  135 52  134 58  133 65  133 72  132 78  131 82  130 84  129 85  127 85  126 85  125 85  
+40   50 34  50 33  50 32  50 31  49 31  47 30  46 29  43 29  40 28  36 29  32 30  28 31  26 33  24 36  24 40  25 44  28 47  32 49  36 50  41 49  45 47  49 43  52 40  54 37  55 35  55 34  55 33  55 35  55 38  55 42  56 48  57 54  58 62  58 70  58 76  57 81  57 84  56 85  55 85  55 83  
+4 B
+12   143 155  142 155  141 155  139 155  135 155  130 155  124 156  116 156  108 157  100 158  95 158  90 158  
+11   58 154  57 154  55 154  53 153  49 153  44 153  39 153  33 154  28 154  24 155  21 157  
+10   142 60  141 59  139 59  136 58  132 58  126 58  119 58  110 59  102 60  96 62  
+12   66 61  67 61  66 61  64 61  61 60  55 60  49 60  41 60  32 61  26 62  21 63  18 64  
+4 N
+11   102 209  104 208  106 206  109 203  113 199  118 194  123 188  128 182  132 177  136 173  138 171  
+14   22 206  22 205  23 203  25 199  28 195  32 190  36 184  41 178  46 173  50 169  54 165  56 163  59 161  60 160  
+11   97 92  97 91  98 90  100 86  103 82  108 75  114 67  122 58  129 49  134 42  138 37  
+13   27 66  27 67  26 67  27 65  28 63  31 59  34 54  38 49  43 43  47 38  50 34  52 32  52 33  
+2 A
+13   13 59  14 59  17 60  21 60  31 60  38 60  48 60  55 60  59 61  63 61  64 61  65 61  64 61  
+14   48 106  49 106  51 106  55 106  59 107  63 107  70 108  80 108  87 108  91 108  95 108  97 108  98 108  97 108  
+2 S
+19   52 111  52 110  52 107  51 105  51 103  50 101  50 99  49 96  49 93  48 89  48 87  48 84  48 82  48 81  48 80  48 79  48 78  48 77  47 77  
+22   102 140  102 139  102 137  103 134  103 131  103 128  104 125  104 121  104 118  105 115  106 112  107 109  108 106  108 103  109 101  109 99  109 97  110 95  110 93  110 92  110 91  110 92  
+2 R
+24   75 27  75 28  74 30  72 32  69 35  67 37  64 41  61 44  58 48  55 52  52 55  49 58  47 61  45 63  43 64  42 65  41 65  40 66  40 65  41 65  42 65  43 64  44 64  45 63  
+21   158 29  158 30  156 32  154 35  151 38  147 42  143 46  136 53  133 57  129 64  126 68  123 71  121 74  120 76  119 77  119 78  118 78  118 79  117 79  116 79  116 80  
+2 P
+26   92 64  90 64  88 65  84 64  80 64  70 63  60 63  50 62  43 62  36 62  32 62  28 62  26 62  26 63  27 63  29 63  32 63  35 63  39 63  49 63  56 63  66 63  73 62  77 62  79 61  80 61  
+28   206 64  205 64  202 64  199 64  195 64  188 64  181 64  178 64  174 65  171 65  167 66  160 67  157 68  154 68  152 68  151 68  152 68  153 68  154 67  156 67  160 67  164 66  171 65  178 65  185 65  192 64  194 64  196 64  
+2 U
+46   20 79  21 79  22 79  24 79  27 79  34 80  41 81  51 81  61 82  68 82  72 82  74 82  77 82  78 82  79 82  80 82  82 82  84 81  86 81  88 81  89 81  91 81  92 81  91 80  90 79  89 78  88 76  88 74  87 72  87 70  87 67  87 65  87 64  87 63  87 62  87 61  87 60  87 59  87 58  87 57  87 56  87 55  87 54  86 54  86 53  86 52  
+41   84 168  85 167  86 167  88 167  92 167  96 168  103 169  110 170  114 170  110 170  114 170  118 171  128 171  135 170  142 170  152 169  159 169  166 169  169 168  171 168  172 168  173 168  173 167  172 167  172 166  171 165  171 164  170 162  169 160  169 158  169 156  169 153  169 151  169 147  169 145  169 142  170 139  170 137  170 136  170 135  170 134  
+2 V
+64   38 107  39 107  39 106  40 105  41 103  42 101  44 98  45 95  46 91  46 88  47 85  48 82  48 80  48 78  48 77  48 75  48 74  48 73  47 72  46 72  45 72  44 72  44 73  43 73  42 73  42 74  42 75  42 76  42 77  41 78  41 79  42 80  42 82  42 84  42 86  43 88  44 89  45 90  45 91  46 91  47 91  48 90  50 89  53 87  56 85  59 84  62 82  66 80  68 79  70 77  72 75  73 73  74 72  76 70  76 69  77 67  78 66  78 65  79 65  79 64  80 63  81 62  81 61  82 61  
+65   88 138  89 137  90 136  92 135  93 133  95 131  97 130  99 128  102 125  104 123  106 121  107 119  108 117  108 115  108 113  108 112  108 111  108 110  108 109  107 109  106 109  105 109  104 109  103 109  102 109  100 108  99 108  99 109  98 110  98 111  98 112  98 113  98 114  98 116  99 117  99 119  99 120  99 122  99 123  100 124  101 124  102 124  103 123  104 121  106 120  109 117  111 115  114 111  117 107  120 103  122 100  124 96  126 93  127 89  129 86  127 89  129 86  130 83  131 81  132 79  133 78  133 77  133 78  132 78  132 79  
+2 W
+69   107 30  107 31  106 32  106 35  104 37  103 39  102 42  100 45  98 48  96 51  93 55  96 51  93 55  91 59  88 62  86 65  83 67  80 69  78 70  76 71  75 71  74 71  73 71  72 70  71 69  70 67  69 66  69 65  68 64  67 63  67 62  67 61  67 60  67 59  68 59  69 58  70 57  72 56  73 56  74 56  75 56  75 57  76 57  77 58  78 59  80 60  81 61  81 63  82 65  82 67  82 68  82 70  82 72  81 74  80 76  78 78  77 79  74 81  72 83  70 85  68 86  66 87  64 89  62 90  60 91  57 93  55 94  53 95  52 95  
+70   201 44  201 45  200 47  200 50  198 57  196 64  195 71  194 78  193 85  192 89  190 92  189 94  187 96  185 98  184 99  182 100  181 101  180 101  179 101  177 101  176 101  175 100  173 99  172 99  171 98  170 97  169 96  169 95  169 94  168 93  169 91  169 90  169 89  170 88  170 87  171 87  172 86  173 85  174 85  175 84  176 84  177 84  178 85  179 86  179 87  180 88  181 90  182 92  182 94  182 96  182 99  181 101  180 104  180 107  178 109  177 111  175 113  173 114  171 115  168 115  165 116  161 117  158 117  154 118  152 119  150 119  149 120  148 120  149 121  150 121  
+2 X
+34   130 88  128 89  126 89  123 89  119 90  116 91  109 91  102 91  95 92  91 92  84 93  82 93  81 93  80 93  79 93  78 93  79 92  79 91  79 89  79 86  78 83  78 79  77 77  76 74  75 71  74 69  74 68  74 67  74 66  73 66  73 65  73 64  72 64  72 63  
+34   218 155  217 155  216 155  214 155  212 155  209 155  205 155  198 155  188 155  181 155  174 156  170 156  168 156  166 156  166 157  165 157  165 155  164 153  164 152  164 150  163 148  163 145  162 143  162 141  162 139  161 138  161 137  161 136  161 135  162 135  162 134  162 133  162 132  163 132  
+4 5
+60   89 34  88 34  87 34  86 34  84 34  81 34  77 33  73 33  69 33  64 33  60 33  56 34  53 34  50 35  48 36  47 38  46 40  46 42  46 45  47 47  48 50  49 53  50 56  50 59  50 62  50 65  50 67  49 68  49 69  49 70  50 70  51 69  52 68  54 67  56 66  59 66  62 66  66 67  69 69  72 72  75 75  77 78  79 81  81 84  81 88  82 91  81 94  80 97  78 99  76 101  73 103  69 105  64 107  59 108  53 108  47 108  41 106  36 102  32 99  29 97  
+59   195 69  194 69  193 69  191 68  190 67  187 67  183 66  180 66  176 66  172 65  168 65  165 65  163 65  160 65  159 65  158 66  158 68  157 70  157 72  157 75  158 79  158 82  159 87  160 90  161 93  162 96  162 97  162 98  162 99  163 98  164 97  166 97  167 96  170 96  173 97  175 98  179 99  181 102  183 105  186 108  188 112  190 117  191 120  192 124  192 127  191 129  189 131  186 133  181 135  176 136  170 137  163 138  156 138  150 138  145 136  140 134  137 132  134 128  131 124  
+52   81 32  80 32  78 31  76 31  74 31  71 31  67 30  64 30  60 30  56 31  53 31  51 32  49 33  48 34  48 36  48 39  48 42  49 46  51 50  52 54  53 58  54 62  55 65  54 67  55 68  56 67  58 67  60 67  62 67  64 67  67 68  70 70  72 72  75 75  76 78  78 81  78 84  78 86  77 88  75 90  72 91  69 93  64 94  59 94  53 94  48 93  43 92  38 90  34 89  31 88  29 87  28 87  
+54   189 68  189 69  187 69  185 68  183 68  179 67  174 67  170 67  164 68  160 69  156 70  154 71  153 72  152 73  152 74  153 76  154 79  155 82  155 85  156 89  156 92  155 95  155 97  154 98  154 99  154 100  155 100  156 101  157 100  159 100  162 101  165 101  169 103  172 105  175 108  178 112  180 116  182 120  183 123  183 127  182 130  181 133  178 136  174 139  168 141  162 143  154 145  146 146  139 145  133 143  128 141  125 139  123 137  122 135  
--- /dev/null
+++ b/lib/strokes/digits.clx
@@ -1,0 +1,20 @@
+0 7 34 9 2 85 77 116 105 73 101 28 63 1 19 19
+1 3 52 0 55 64 55 128
+2 7 2 15 43 1 75 33 56 87 3 127 53 123 107 126
+3 9 14 13 47 0 80 10 77 35 56 59 91 74 86 113 53 128 19 114
+4 5 0 2 6 62 9 121 58 119 108 114
+6 7 69 1 15 23 2 79 48 127 107 101 58 81 4 103
+7 5 4 3 54 2 105 5 79 66 51 128
+8 11 73 12 71 4 63 1 20 31 62 66 85 84 84 110 58 128 30 118 52 66 77 14
+9 7 78 16 46 1 17 27 48 50 86 29 90 78 81 128
+B 3 108 61 54 59 0 70
+N 3 0 128 50 64 108 0
+A 3 0 62 54 65 108 66
+S 3 57 128 53 64 57 0
+R 5 107 0 59 58 9 119 4 124 1 128
+P 5 108 65 54 64 0 67 44 65 88 62
+U 5 0 83 53 87 106 84 105 63 105 41
+V 5 0 128 35 79 18 60 63 62 108 0
+W 5 107 0 84 63 37 68 57 101 1 128
+X 5 108 84 70 88 32 90 7 75 0 37
+5 7 108 5 76 2 45 7 57 60 98 101 53 128 0 109
binary files /dev/null b/lib/strokes/letters.bit differ
--- /dev/null
+++ b/lib/strokes/letters.cl
@@ -1,0 +1,365 @@
+36
+11 a
+36   33 84  33 83  34 83  35 81  36 78  38 75  40 71  43 66  46 61  49 56  51 52  53 48  55 46  56 44  57 43  57 42  58 42  58 41  58 40  59 40  60 42  61 45  62 50  64 56  66 61  68 67  70 73  71 76  73 80  74 82  74 83  75 85  75 86  76 87  76 86  76 85  
+28   172 78  172 79  173 78  174 75  176 72  179 67  182 62  185 55  188 49  191 45  194 41  195 38  196 37  196 38  197 40  199 43  201 48  203 55  206 61  208 67  210 72  212 76  213 79  215 80  215 82  216 82  216 83  215 82  
+32   35 179  35 180  35 179  36 176  37 174  38 170  41 165  44 160  46 154  49 149  52 144  54 140  56 136  56 134  57 133  57 132  57 133  58 135  59 137  61 141  63 147  65 154  68 160  70 166  71 171  73 174  74 176  75 177  75 178  75 179  76 179  76 180  
+28   145 188  146 187  147 185  150 182  153 178  158 172  164 166  170 159  177 153  182 148  186 144  189 142  191 141  192 142  192 144  192 147  193 152  194 159  195 166  197 173  198 179  199 184  200 187  201 189  201 190  202 190  202 191  202 190  
+26   230 176  231 176  232 175  233 172  234 169  237 164  240 159  243 153  246 148  249 144  251 141  252 139  253 139  253 140  254 141  255 143  256 147  258 153  260 159  262 166  264 172  265 176  267 180  268 182  269 183  269 184  
+28   251 96  252 95  252 94  253 91  254 86  257 79  260 72  264 63  269 55  273 48  276 42  278 40  279 39  280 40  281 42  282 45  285 52  287 60  290 69  294 79  297 89  300 96  301 102  303 105  303 107  304 108  304 109  304 108  
+25   54 93  54 94  54 93  55 91  55 88  56 85  58 81  60 76  63 71  66 66  68 61  70 57  72 53  73 51  74 50  74 49  75 50  76 53  78 56  80 62  82 68  84 74  86 78  87 82  88 83  
+28   130 148  130 146  131 144  132 141  135 137  137 131  140 124  143 117  146 111  148 106  149 103  150 102  150 101  151 103  152 106  153 111  155 118  157 125  158 132  160 139  161 143  162 146  163 148  163 149  164 149  164 150  165 150  165 149  
+32   204 159  203 159  203 158  204 156  205 152  208 147  211 139  216 130  220 121  224 113  227 107  230 103  231 101  231 100  232 100  233 102  234 105  236 110  239 118  242 127  245 136  247 145  250 153  252 159  255 166  256 170  257 174  258 176  258 177  258 178  258 177  258 176  
+52   44 100  45 100  46 99  47 98  48 97  48 95  49 93  50 91  52 89  53 86  54 84  56 81  57 78  58 75  60 72  61 69  62 66  63 63  64 61  66 59  67 57  67 55  68 54  68 53  68 52  69 53  70 55  71 58  72 61  74 65  75 68  77 72  78 75  80 78  82 81  80 78  82 81  83 84  84 86  85 87  86 89  87 90  87 91  88 91  88 92  88 93  88 94  89 94  89 95  89 96  90 96  90 97  
+65   170 98  170 97  170 96  170 95  171 93  171 91  172 88  172 86  173 83  174 80  175 78  176 76  178 73  179 71  180 69  182 66  183 64  184 62  185 61  186 59  186 58  187 57  188 55  189 54  190 52  190 50  191 49  191 48  192 48  192 47  192 46  192 47  193 48  194 51  195 54  196 56  198 59  199 62  200 64  201 66  202 69  203 71  204 73  205 75  205 77  206 78  207 80  208 82  209 84  211 86  213 89  215 91  213 89  215 91  217 93  218 95  219 97  220 98  221 100  221 101  222 101  222 102  222 103  222 104  223 104  
+9 b
+49   225 123  225 125  225 129  225 134  226 140  226 147  226 154  226 159  226 162  225 162  225 161  224 157  223 152  222 146  221 138  220 132  221 126  223 120  226 117  230 115  234 115  237 118  239 122  239 127  238 132  235 137  232 141  229 143  227 144  225 143  224 142  225 140  226 139  228 138  232 137  235 138  239 139  243 141  246 144  248 147  249 150  248 154  245 156  241 159  236 160  230 162  225 162  221 161  218 160  
+52   65 132  66 133  66 136  68 140  69 145  69 152  70 159  69 167  68 172  66 176  65 178  63 177  62 174  62 168  61 161  62 153  64 145  68 137  72 131  75 126  79 123  83 123  86 124  88 127  88 132  87 138  85 143  82 148  79 151  76 153  73 154  71 154  70 153  70 152  72 151  74 150  77 149  81 149  85 149  89 150  92 152  94 156  94 159  93 163  90 166  87 170  82 173  77 175  72 176  68 176  64 174  63 172  
+51   123 41  123 40  124 40  124 42  125 44  126 49  127 54  128 61  128 67  128 72  128 76  127 77  127 76  126 73  125 68  124 62  123 55  123 49  123 44  124 39  127 36  131 35  135 34  139 35  143 37  145 40  145 44  144 48  142 52  139 55  136 57  133 58  132 59  131 58  133 57  135 55  138 54  142 53  146 53  150 54  153 56  156 59  157 63  158 66  156 69  153 72  149 73  143 75  138 76  133 76  129 76  
+49   239 156  239 158  240 161  240 166  241 171  241 177  240 182  240 187  239 190  239 191  238 191  238 188  237 183  236 177  236 168  236 159  237 150  238 145  241 139  245 135  250 134  254 136  257 140  258 145  258 149  255 155  252 160  248 164  245 167  242 169  241 169  241 168  243 167  246 165  250 164  255 163  260 164  264 167  266 170  267 173  267 177  266 180  263 183  258 186  253 188  250 190  244 190  238 190  234 189  
+56   172 80  172 81  172 84  172 89  172 97  173 105  172 113  172 119  172 124  172 126  172 125  172 121  172 116  172 110  172 102  171 95  171 88  171 83  172 79  174 76  176 73  179 72  182 72  185 73  187 75  189 79  189 83  189 86  187 90  185 94  183 96  181 98  179 98  177 99  177 98  177 97  178 96  179 95  182 94  186 93  189 93  194 94  198 96  201 99  203 104  204 108  203 112  202 116  199 119  195 121  191 122  187 122  182 122  178 120  175 119  172 117  
+51   64 56  64 58  64 60  65 65  64 71  64 77  64 83  64 89  63 91  63 88  62 84  62 78  61 73  60 67  61 62  62 57  64 52  68 49  72 46  76 45  79 46  81 49  82 53  82 57  81 61  79 65  76 68  74 70  72 70  71 70  71 69  72 68  74 67  77 66  81 66  84 66  88 68  91 69  93 71  95 73  95 75  94 77  91 79  88 82  83 84  78 86  74 87  71 87  68 87  67 85  67 84  
+60   205 151  206 155  206 161  206 167  207 175  207 181  207 187  207 191  206 193  206 194  205 192  205 190  204 186  202 181  201 175  201 169  200 162  200 157  201 151  202 146  203 142  206 138  209 135  212 134  216 134  219 136  223 138  225 141  226 145  226 149  224 153  222 158  218 162  215 165  211 168  209 169  207 169  209 167  212 166  215 165  219 164  224 164  228 165  232 166  235 168  237 170  238 173  239 176  238 179  237 182  235 185  234 187  231 189  227 192  222 194  216 195  210 196  205 195  199 194  195 193  
+58   160 68  161 71  161 74  162 79  163 85  164 90  164 96  164 101  164 103  163 104  163 103  162 101  162 97  161 92  161 86  160 80  160 74  160 69  161 66  162 62  164 60  166 58  169 57  172 57  174 59  175 61  177 64  177 68  176 72  174 76  171 79  168 80  165 81  163 81  162 81  162 80  163 79  165 78  167 77  170 77  174 77  178 77  181 78  184 79  187 81  188 83  189 85  190 88  189 91  187 93  184 96  180 98  176 100  171 102  167 103  163 102  160 101  158 100  
+57   42 46  43 49  43 52  44 56  44 61  45 66  45 70  44 73  44 76  43 77  42 74  42 71  41 67  40 62  40 58  40 53  41 49  42 45  44 42  46 39  49 37  51 36  54 35  57 36  59 38  60 40  61 44  60 48  58 51  56 55  53 58  50 59  48 60  47 60  47 59  49 58  51 57  54 56  57 56  61 56  65 57  69 58  72 59  73 60  74 63  75 65  74 67  73 70  71 72  68 74  64 76  61 77  57 78  53 78  50 78  47 77  45 76  
+9 c
+37   108 124  108 125  109 125  109 126  109 127  108 126  108 124  107 122  105 120  104 118  101 115  99 114  96 113  93 113  90 114  87 117  84 120  81 123  79 128  77 133  76 139  76 144  76 150  77 155  79 160  81 164  83 168  87 170  91 172  96 171  102 170  108 168  114 166  119 163  123 161  125 159  126 158  
+38   202 89  202 90  202 91  202 90  202 89  202 88  202 86  201 85  201 83  200 82  199 81  197 81  195 81  193 81  191 82  188 83  186 85  184 87  182 91  180 95  179 99  178 103  178 108  179 113  180 117  182 120  184 123  187 125  191 126  194 126  198 126  201 124  204 123  207 122  208 120  210 119  210 118  211 117  
+36   81 56  82 56  82 55  82 54  81 54  81 53  80 53  80 52  79 51  78 50  76 49  75 49  74 49  72 50  70 51  68 53  65 55  63 58  62 60  62 62  61 64  62 67  62 70  63 72  64 75  65 77  68 78  70 79  73 80  76 79  79 79  82 77  84 76  87 75  88 74  89 73  
+41   127 144  128 144  127 144  127 143  126 142  125 141  124 140  122 138  120 137  118 137  116 136  113 136  110 136  106 138  103 139  100 142  97 146  94 150  92 156  90 162  89 170  88 177  87 184  88 190  89 196  90 202  93 206  96 210  100 213  105 214  111 214  119 213  126 210  134 207  141 203  147 200  151 197  154 195  156 194  156 193  157 193  
+36   185 56  185 57  185 58  185 57  185 56  185 55  185 53  184 52  183 51  182 50  181 49  179 48  177 48  175 47  172 49  170 51  167 53  164 56  162 60  160 65  159 69  158 74  158 79  159 83  160 87  163 92  167 95  170 96  175 96  181 95  187 93  193 90  198 86  201 84  203 82  204 81  
+36   70 35  71 35  70 35  70 34  69 34  68 33  67 32  64 31  62 30  59 29  57 28  54 27  51 28  49 29  46 31  44 33  41 35  39 38  37 41  35 45  35 49  34 54  35 58  36 61  39 65  42 67  46 69  50 71  55 72  60 72  65 71  71 69  75 68  79 66  82 65  83 64  
+30   131 130  131 129  130 128  129 126  128 124  126 122  124 120  121 119  118 119  116 119  113 120  111 121  108 123  106 127  104 130  102 135  101 140  100 146  99 151  100 155  101 159  103 162  106 164  111 166  116 166  123 165  128 163  133 160  136 158  138 156  
+33   194 43  194 44  194 45  194 44  194 43  194 42  193 41  192 39  191 38  190 37  188 36  186 35  184 35  182 35  180 36  177 38  175 40  173 43  172 47  171 51  170 56  170 61  170 65  171 69  173 73  175 75  179 76  183 77  187 77  192 76  196 75  200 74  202 73  
+38   65 42  65 41  65 40  64 40  63 39  61 38  59 37  58 36  56 36  54 35  53 36  51 36  49 37  47 38  44 39  42 41  40 43  38 45  36 48  35 51  35 55  34 58  35 61  35 64  36 67  37 70  39 73  41 75  43 76  46 77  50 78  53 79  57 79  61 78  64 77  69 76  73 74  75 73  
+9 d
+45   259 144  259 145  259 147  259 150  260 155  261 160  261 166  262 171  262 175  262 178  262 179  262 177  262 175  261 171  260 166  259 161  258 156  257 152  257 148  258 145  259 142  260 139  262 136  264 135  267 134  271 133  274 134  279 136  283 139  286 141  289 145  291 150  292 155  291 160  290 165  288 170  285 174  281 176  277 177  273 178  269 178  266 177  263 176  260 176  258 176  
+44   172 93  173 94  173 95  173 98  174 101  174 105  175 111  175 117  175 122  174 127  174 130  173 132  173 133  173 132  173 129  173 125  173 120  173 115  173 110  172 105  172 101  172 97  173 93  174 90  176 88  178 86  181 86  184 86  188 88  191 91  195 94  197 99  199 103  200 108  200 113  199 117  197 121  195 124  192 126  188 127  184 128  181 128  177 127  175 126  
+51   49 44  49 45  50 48  50 52  51 58  52 64  53 71  53 77  53 82  53 85  52 89  52 92  52 94  52 96  51 96  51 95  51 93  50 91  49 87  49 83  48 78  47 73  46 67  46 62  46 56  46 51  47 46  49 42  51 39  55 36  58 35  63 35  68 35  73 36  77 39  81 42  84 46  86 52  88 57  88 63  87 69  86 74  84 78  82 81  78 83  74 85  69 87  63 88  59 88  55 89  52 88  
+40   85 130  85 131  85 133  86 136  86 140  87 146  87 150  87 156  86 160  86 164  85 164  85 163  85 160  84 155  83 150  82 144  82 139  82 134  82 130  82 127  84 125  86 124  89 124  93 125  97 127  101 130  105 134  108 139  111 144  112 149  112 153  111 158  109 161  106 165  101 167  96 169  89 171  82 172  75 173  70 173  
+44   154 52  154 53  154 55  154 58  155 62  156 67  157 72  157 78  157 82  157 86  156 88  156 89  156 88  155 86  154 83  153 79  152 74  151 69  150 65  150 60  149 56  150 53  150 50  152 48  154 46  157 46  161 46  165 47  169 49  172 51  175 55  177 59  177 62  177 67  176 70  174 74  172 77  169 79  166 81  163 82  160 83  157 84  155 84  153 83  
+41   37 43  37 44  38 45  38 48  39 52  39 56  40 60  40 64  40 67  40 69  39 69  39 67  38 65  38 62  37 59  36 55  35 51  35 48  35 45  37 42  38 40  40 38  43 36  45 36  48 37  51 38  54 41  57 43  60 47  62 52  63 56  64 59  63 62  62 64  59 65  55 67  51 68  46 69  42 70  40 70  39 71  
+39   222 105  223 106  223 108  223 112  223 118  224 125  224 132  224 140  223 146  223 150  222 152  221 149  220 144  219 138  218 130  217 123  215 117  214 112  214 108  214 104  216 102  218 100  222 99  226 99  231 102  235 106  238 112  240 119  240 126  239 133  237 139  234 145  231 149  228 152  225 154  222 156  219 156  217 155  216 154  
+44   141 54  142 55  142 57  142 59  142 63  142 68  142 73  143 78  143 83  142 86  142 89  142 91  142 92  142 91  141 89  141 85  140 80  139 74  139 69  139 64  140 59  141 56  142 53  144 51  147 49  151 49  155 50  159 51  164 54  168 57  171 62  174 67  176 71  176 76  175 80  173 83  171 85  166 88  160 90  154 92  149 93  144 94  141 94  139 94  
+44   32 33  32 34  32 35  32 38  32 42  33 47  33 53  34 58  34 62  34 65  34 66  34 67  33 65  33 63  32 60  31 56  30 52  29 48  29 44  30 40  32 37  33 35  35 32  38 29  41 29  44 29  47 31  50 34  52 38  55 42  56 47  57 52  58 56  58 59  56 62  54 64  51 66  48 67  44 68  41 69  38 70  37 70  35 70  35 71  
+9 e
+56   279 119  279 118  278 117  277 116  277 115  276 114  275 114  273 113  271 113  269 113  266 114  263 116  259 118  255 121  253 124  251 128  250 133  251 137  252 142  254 146  256 149  258 150  261 152  263 152  265 152  267 151  269 150  270 150  270 149  271 149  270 149  268 148  267 148  265 149  263 149  261 150  259 151  257 152  254 154  252 155  250 157  248 160  247 162  247 165  248 169  251 172  254 174  258 176  263 177  268 176  273 175  278 174  283 172  286 170  289 168  290 167  
+54   167 80  167 79  167 78  166 78  165 77  163 76  161 75  159 75  155 75  152 76  149 77  147 79  144 82  143 87  142 93  142 100  144 106  146 112  149 115  153 117  156 116  159 115  162 113  164 112  165 110  166 108  165 107  163 105  161 105  159 104  155 104  152 104  149 105  146 106  143 107  140 109  137 110  136 112  134 115  134 118  134 122  134 126  135 131  136 134  139 138  142 140  145 143  149 143  154 143  159 142  164 140  168 137  171 135  173 134  
+47   62 46  63 47  62 48  62 47  61 45  60 44  59 42  57 42  55 41  53 42  50 43  48 44  45 47  43 51  41 56  40 60  40 64  41 69  43 72  46 74  49 75  52 75  55 75  58 74  60 73  61 72  61 71  60 71  59 70  56 70  53 71  50 72  46 74  43 76  41 78  39 81  38 85  38 90  38 94  40 99  43 102  47 105  51 106  57 106  61 105  66 103  70 100  
+53   263 145  263 144  263 143  262 143  262 142  260 141  259 140  256 140  253 140  250 141  247 143  244 145  242 148  241 150  239 154  239 158  240 162  241 165  243 168  246 169  250 170  253 170  256 170  258 169  259 169  260 169  260 168  260 169  259 169  258 169  257 170  255 170  253 171  250 172  247 173  243 175  240 176  237 178  234 180  233 182  232 183  232 186  233 188  235 190  237 193  240 195  244 197  249 198  254 198  259 197  263 196  267 195  269 193  
+43   183 79  183 78  182 77  181 76  180 75  178 74  174 74  170 74  167 75  163 77  160 80  159 84  158 89  158 95  159 100  161 105  164 108  167 110  169 110  172 109  174 108  175 107  176 104  175 102  174 101  172 101  169 101  166 102  162 104  158 107  155 110  152 114  151 118  150 122  150 126  152 130  154 133  157 135  162 136  167 136  172 135  177 133  182 131  
+39   75 75  75 74  74 73  73 72  71 71  69 69  64 69  60 70  55 70  51 72  47 75  45 79  43 83  43 88  44 93  46 98  48 101  51 102  54 102  56 101  57 99  58 98  58 97  57 97  54 98  51 100  47 103  43 107  39 111  36 115  35 119  34 124  36 128  39 131  43 134  49 135  55 134  61 133  66 130  
+52   256 63  256 64  257 64  256 63  256 62  255 61  254 59  252 57  250 55  248 54  245 54  242 56  239 58  236 62  233 67  231 72  230 77  231 81  232 85  234 88  237 89  241 90  244 89  247 88  249 86  250 84  251 83  250 81  249 80  247 79  245 79  242 79  240 79  237 79  234 80  231 82  228 84  226 87  224 90  223 94  222 98  222 103  223 107  225 111  227 115  231 118  236 119  241 120  247 119  252 117  257 114  261 112  
+54   160 42  160 41  159 40  158 39  157 39  155 38  154 37  152 36  150 35  149 35  148 35  146 36  144 37  142 40  140 43  138 47  137 51  137 55  138 58  139 62  141 65  143 66  145 67  146 68  148 67  149 66  150 65  151 63  152 61  152 60  151 59  149 58  147 59  144 59  141 60  137 61  134 63  130 64  127 66  126 67  124 69  123 71  123 73  124 75  126 78  128 80  132 82  136 84  141 85  146 86  152 85  157 84  161 83  164 81  
+60   71 39  71 38  71 37  71 35  70 34  70 33  69 32  68 31  66 31  64 30  62 30  60 29  57 30  54 31  51 32  48 35  46 38  44 41  43 44  42 47  41 51  42 55  43 58  44 60  47 62  49 63  51 63  54 63  56 63  58 62  59 62  59 61  60 61  59 60  58 60  56 61  54 61  52 62  50 63  48 63  46 64  44 66  42 67  41 69  40 72  39 74  38 77  38 80  38 83  38 86  39 90  40 93  42 95  45 98  47 99  52 99  57 98  62 96  66 95  71 92  
+9 f
+23   288 93  287 93  287 92  285 92  283 92  278 92  273 93  266 95  260 98  254 100  249 102  246 104  245 106  245 109  245 113  246 120  247 128  247 138  247 149  247 159  247 169  246 176  246 180  
+29   199 89  199 88  198 88  196 87  193 85  189 83  185 81  180 79  175 77  171 75  168 74  165 73  164 73  163 73  162 73  163 74  163 76  163 80  163 85  163 93  163 102  162 113  161 123  160 132  160 138  159 143  159 145  158 146  158 145  
+24   80 58  80 59  80 58  79 57  77 56  75 55  70 55  65 54  59 55  55 56  50 57  47 59  46 61  47 64  48 68  49 75  50 85  50 95  50 106  50 115  49 122  49 125  48 127  48 128  
+28   269 62  268 62  267 62  266 61  264 61  261 61  257 61  252 61  246 62  240 62  235 62  231 63  228 63  226 63  225 64  225 65  225 66  226 68  227 72  227 77  228 83  228 89  228 95  227 100  227 105  226 107  225 108  225 107  
+29   175 50  174 49  173 49  171 49  167 48  163 48  158 47  153 48  148 48  144 48  141 49  139 49  138 50  137 52  137 53  138 56  138 60  138 65  139 70  139 76  139 83  138 89  138 95  137 100  137 104  137 107  137 109  137 110  137 111  
+24   72 40  71 40  68 40  65 40  61 40  57 39  53 39  49 39  46 39  44 39  43 40  42 40  42 41  42 42  42 44  43 48  43 53  43 58  44 64  44 70  44 75  44 78  44 80  44 82  
+26   318 111  317 110  316 110  314 109  311 109  307 108  302 108  295 108  289 109  284 109  279 110  276 111  274 112  274 113  273 115  274 118  275 123  276 130  277 140  277 150  277 160  277 170  276 178  276 183  276 187  275 188  
+29   238 52  238 51  237 51  236 51  234 50  232 49  228 49  223 48  217 48  212 48  206 49  202 50  198 51  196 52  195 54  196 57  196 61  197 67  198 75  199 84  199 94  199 103  199 111  198 117  198 120  198 122  197 122  197 121  197 120  
+27   85 42  85 41  84 41  82 41  80 41  76 41  71 40  65 40  59 39  54 39  49 39  46 40  44 41  43 42  43 43  44 45  45 49  46 54  47 61  48 69  48 76  49 84  49 90  49 94  49 97  49 98  49 99  
+9 g
+37   270 90  270 89  270 88  269 86  267 85  265 85  263 86  260 88  257 92  254 97  252 104  252 111  252 117  254 123  257 126  261 128  264 128  269 127  272 126  274 124  276 122  276 119  275 117  273 115  270 113  267 111  264 111  262 110  261 110  260 110  262 110  264 110  266 110  270 109  273 109  276 108  278 107  
+48   182 55  182 56  181 54  181 53  180 51  178 49  175 48  173 46  169 46  165 47  162 49  158 52  154 57  152 63  150 69  148 77  147 85  147 92  149 99  152 104  156 107  162 109  167 110  173 109  179 107  183 104  186 101  187 97  188 93  187 88  185 85  183 81  180 79  176 77  173 77  169 77  166 77  163 78  162 78  161 79  163 79  166 79  169 79  174 78  179 78  183 77  187 76  189 75  
+37   77 46  76 45  76 44  74 42  72 41  70 40  67 40  64 41  61 43  59 47  58 51  58 56  58 60  60 65  62 69  65 72  69 73  73 74  76 73  78 72  80 70  81 68  80 66  79 64  77 62  75 61  72 60  70 60  68 60  68 61  70 61  72 62  74 61  77 61  79 61  81 60  82 60  
+50   174 145  174 144  174 143  173 143  172 141  170 140  169 139  166 138  163 137  160 137  157 138  154 140  151 143  148 147  146 153  145 159  146 165  147 171  150 176  154 179  158 182  162 182  167 181  171 180  174 177  177 174  178 171  179 168  179 166  178 163  176 161  173 160  170 159  168 158  165 159  163 159  161 160  160 160  161 160  162 160  164 160  166 160  170 159  174 158  178 157  181 156  184 155  185 155  186 155  185 155  
+49   213 59  213 58  213 57  212 56  211 56  210 54  208 53  207 52  204 51  201 52  199 53  196 56  193 61  190 66  188 72  187 79  187 85  190 92  193 97  197 101  202 104  207 105  212 104  215 102  218 99  220 96  221 91  220 87  219 83  217 81  214 78  212 77  208 76  205 75  202 75  200 75  198 76  197 76  197 77  198 78  200 79  203 79  207 79  212 79  216 79  221 77  224 76  227 76  229 75  
+41   90 51  90 50  90 49  89 48  87 47  85 46  83 46  81 46  79 46  76 48  74 50  72 54  71 58  70 62  71 67  72 71  73 75  76 79  79 82  82 85  86 86  90 86  94 85  97 83  99 80  100 78  100 75  98 72  96 71  92 70  89 70  86 70  84 71  83 72  83 73  85 73  87 73  91 73  94 72  97 72  100 71  
+57   304 116  304 115  305 116  305 115  304 115  304 114  303 112  302 110  300 108  298 106  295 106  292 106  288 107  284 109  279 112  276 116  272 121  270 126  268 133  267 140  267 146  268 152  270 158  272 162  276 165  280 167  285 168  290 167  295 165  299 163  303 160  305 157  307 155  307 153  307 151  306 150  305 148  302 146  300 145  297 144  294 143  292 144  289 144  287 144  285 144  284 145  285 145  286 145  288 145  291 144  295 144  300 143  304 142  308 141  311 140  313 140  314 139  
+51   201 92  200 92  200 91  200 90  199 89  198 88  197 87  195 87  193 87  191 88  188 90  186 92  183 95  181 99  179 104  178 110  177 117  178 123  179 128  181 132  184 135  187 137  191 137  195 136  199 134  201 132  203 130  204 127  204 125  203 124  201 122  199 121  196 121  194 121  192 121  190 121  189 122  188 122  189 122  190 122  192 122  194 122  197 121  200 121  203 120  205 120  206 119  207 119  208 119  208 118  207 118  
+60   73 51  74 51  74 52  74 51  73 51  73 50  72 49  71 47  69 46  67 45  64 44  61 44  58 45  55 46  53 48  50 51  49 54  48 57  47 61  47 65  47 69  48 73  49 77  51 81  53 85  56 88  59 90  62 91  66 92  70 91  73 90  77 89  79 87  81 85  82 83  83 81  83 79  83 77  82 75  80 74  78 73  76 72  74 72  71 72  69 72  67 72  64 72  63 72  62 72  63 72  64 72  67 72  69 71  72 71  75 70  77 70  80 69  81 69  83 68  84 68  
+9 h
+40   254 104  254 103  254 102  254 103  255 106  256 112  256 120  257 129  257 140  257 150  257 158  256 163  256 166  255 167  255 168  256 167  256 164  256 161  257 158  258 153  260 149  263 144  266 141  270 138  273 136  277 135  280 135  284 135  286 136  288 138  289 141  291 145  291 150  291 156  291 161  290 165  290 168  290 170  289 170  290 169  
+31   155 61  154 60  155 61  155 64  156 70  157 79  158 89  158 97  158 108  158 117  157 122  157 125  157 126  157 125  157 123  158 119  160 115  163 110  167 105  171 101  175 99  178 99  182 100  184 103  186 107  188 111  189 116  189 119  190 122  190 124  189 125  
+40   44 39  44 37  44 36  44 37  44 40  44 44  44 51  43 59  43 68  42 76  42 83  41 88  41 91  41 93  41 94  41 93  41 92  41 91  41 88  41 85  42 81  43 77  45 73  47 70  50 67  53 64  56 62  59 60  62 59  65 58  68 59  69 60  71 63  72 67  74 71  74 76  75 81  75 85  75 89  75 91  
+36   247 106  246 102  245 100  245 99  245 100  245 101  246 105  247 112  248 122  250 135  251 147  252 159  251 168  251 174  251 177  251 178  251 176  252 174  253 171  255 168  258 165  261 162  265 161  270 160  273 161  276 162  279 164  280 166  282 167  282 169  282 171  283 173  283 174  283 176  283 177  283 176  
+38   148 67  147 67  147 66  147 65  148 66  148 67  148 69  149 73  149 80  149 90  149 102  148 113  147 123  146 131  146 135  145 136  146 136  146 135  147 132  148 126  150 119  153 112  156 104  159 98  164 93  168 90  171 89  174 89  177 91  179 95  180 100  182 106  182 112  183 118  183 123  184 128  184 131  184 133  
+25   44 58  43 58  43 59  44 61  44 65  45 71  45 78  45 87  45 95  45 101  45 105  45 107  45 106  46 102  47 98  49 95  51 91  53 89  56 89  58 89  60 91  62 93  63 97  64 100  64 103  
+34   120 121  120 120  120 122  120 126  120 132  120 139  120 148  120 157  119 166  119 174  118 179  118 183  118 185  118 184  118 182  118 179  118 175  119 172  121 166  124 162  127 158  131 155  135 153  138 153  141 153  143 155  145 158  147 162  148 167  148 171  148 175  148 178  148 180  148 181  
+37   176 30  176 29  176 28  176 29  176 32  177 36  177 43  177 52  177 61  177 70  176 79  176 84  175 88  175 90  175 89  175 88  175 85  176 81  178 76  180 71  183 67  186 63  190 61  195 60  199 59  203 60  206 61  209 62  211 65  212 68  212 72  212 77  212 81  211 86  211 89  211 92  211 94  
+27   35 27  34 26  34 27  35 30  35 35  36 42  37 51  37 60  37 68  37 75  37 79  37 81  37 82  37 81  38 79  40 76  42 72  46 68  50 64  54 62  58 62  62 62  65 65  68 68  69 71  70 74  70 76  
+9 i
+12   172 131  173 131  174 134  175 140  176 148  177 159  179 171  180 183  181 193  182 200  182 204  182 205  
+8   77 121  78 124  79 129  80 137  81 145  82 155  83 162  83 168  
+10   282 83  282 82  283 85  284 90  284 97  285 107  286 117  286 125  286 132  286 135  
+14   221 66  222 64  223 63  223 64  222 69  220 77  218 89  215 102  212 115  209 128  208 136  207 141  207 143  207 142  
+17   128 57  128 53  128 49  127 47  127 48  128 51  129 58  130 68  133 81  135 95  137 108  139 119  141 126  142 129  143 131  142 131  142 129  
+11   47 46  46 45  46 46  46 49  45 55  45 63  45 73  45 83  45 91  45 98  45 102  
+17   197 95  198 92  198 91  198 92  198 95  199 101  199 109  199 119  199 131  199 141  198 150  198 158  198 163  198 167  198 170  198 172  198 173  
+11   117 32  118 32  118 33  118 36  119 40  119 46  119 53  120 59  120 64  120 68  120 71  
+12   39 27  39 26  39 29  38 34  38 40  38 47  38 54  38 60  38 64  38 67  38 69  39 69  
+9 j
+26   284 68  285 67  285 66  285 67  286 70  286 75  287 83  288 93  288 105  288 116  288 126  287 135  287 141  286 145  285 147  285 149  284 149  283 149  280 149  276 148  270 147  263 146  254 145  247 142  240 139  236 136  
+25   207 54  208 52  208 51  208 52  209 55  209 60  209 66  210 74  210 82  210 90  210 97  210 102  209 105  208 107  205 108  201 107  195 105  189 104  182 101  176 100  170 99  166 98  164 98  161 98  160 99  
+22   99 37  99 36  99 37  99 38  100 41  100 46  100 52  101 59  101 66  101 72  101 75  101 78  100 79  99 78  98 77  95 76  92 75  87 75  83 75  79 75  77 76  75 77  
+29   297 92  297 89  298 88  298 89  298 91  299 95  299 102  300 111  301 123  302 136  302 148  303 160  304 170  304 177  304 183  304 188  303 192  302 194  301 195  299 196  296 196  292 195  288 195  283 194  277 193  271 193  266 192  262 192  260 192  
+21   204 44  204 43  204 44  204 47  205 52  205 60  206 69  206 80  206 91  205 101  204 110  202 116  200 120  195 122  190 122  184 119  177 116  172 113  168 110  165 107  164 105  
+21   92 28  93 30  93 34  94 39  95 47  95 55  96 64  96 73  95 80  95 86  95 90  94 93  93 95  91 96  89 96  85 95  81 93  77 90  73 87  69 84  65 83  
+24   253 95  254 94  254 92  254 93  254 95  254 100  254 107  254 115  254 125  255 134  255 143  256 150  256 156  256 159  255 162  253 164  250 165  245 165  239 166  232 166  225 166  220 166  216 165  214 165  
+21   198 37  197 38  197 40  198 44  198 49  198 56  198 62  199 68  199 73  198 76  198 78  197 79  195 79  193 79  189 78  184 78  178 78  173 78  168 78  163 77  161 76  
+27   72 34  72 33  72 34  72 35  73 37  73 41  74 46  74 52  74 58  74 65  74 70  74 74  75 78  75 80  75 82  74 82  74 83  73 83  72 83  70 84  67 84  62 85  57 85  53 85  48 85  45 84  42 85  
+9 k
+29   122 132  123 131  124 130  124 131  124 132  123 136  121 140  118 146  113 154  106 161  99 168  91 174  83 178  76 180  70 182  64 182  62 180  62 179  64 177  70 175  77 174  85 174  94 174  102 177  110 180  115 183  118 186  122 189  124 191  
+35   217 51  217 52  217 53  217 55  216 58  216 62  214 66  211 72  207 78  201 84  194 90  186 95  179 99  172 101  167 103  164 104  163 104  162 105  163 105  163 104  164 104  165 104  167 103  170 103  173 103  177 103  185 106  191 110  196 115  202 121  208 128  213 137  218 146  221 154  224 160  
+25   102 41  102 40  102 41  102 42  101 44  100 46  97 49  94 53  89 56  84 60  79 63  74 65  70 66  67 67  65 67  68 66  70 65  74 65  78 66  83 68  87 70  91 73  94 76  96 78  98 80  
+28   110 130  110 131  111 133  111 137  110 142  108 148  105 154  101 159  95 163  88 165  81 166  75 166  70 166  65 164  63 163  63 161  66 160  71 159  78 159  86 159  94 160  102 163  110 166  116 170  121 174  124 177  127 178  128 179  
+24   204 73  205 73  205 75  205 79  203 84  200 91  196 99  191 107  185 113  180 116  174 118  170 118  167 117  165 114  166 111  168 108  173 106  179 105  186 105  194 107  200 109  206 111  210 113  212 114  
+24   92 54  93 54  93 55  93 56  92 59  90 62  87 67  83 71  78 76  73 81  68 84  62 85  59 85  57 83  57 81  58 78  61 76  65 74  71 73  77 73  82 74  88 75  93 77  97 79  
+38   206 115  207 115  208 115  208 117  208 120  207 125  206 131  203 139  200 146  196 153  190 158  186 160  180 162  172 163  165 162  159 161  154 159  152 158  152 156  155 154  159 153  165 151  172 151  179 151  186 152  193 155  199 158  204 162  209 166  213 172  217 177  220 182  223 187  225 190  226 193  227 194  228 195  228 194  
+29   204 53  204 52  204 54  203 56  202 60  200 64  196 69  192 73  187 76  182 78  177 78  173 78  170 77  167 76  167 74  167 72  169 71  171 70  176 70  181 71  187 73  192 76  197 80  201 83  204 87  206 90  207 92  208 94  209 95  
+29   74 35  74 36  74 38  74 41  73 46  71 51  69 57  64 61  60 66  55 69  51 70  47 71  44 70  42 69  41 68  40 67  41 66  43 66  47 65  51 65  56 65  62 66  68 68  73 70  76 72  79 73  80 74  81 75  82 76  
+9 l
+28   152 142  152 141  153 143  154 147  156 153  158 161  160 171  162 181  163 190  164 196  165 201  165 203  165 204  165 205  166 205  168 205  172 204  177 204  183 204  190 204  197 204  204 204  208 204  211 205  213 205  214 204  215 204  214 203  
+24   189 53  189 54  190 56  190 60  191 65  191 71  190 78  190 84  189 89  188 92  188 93  187 94  187 93  188 94  189 94  192 95  196 96  202 98  208 98  216 98  222 98  228 98  232 98  235 97  
+28   69 48  69 45  70 43  70 42  70 43  71 47  70 53  70 62  69 73  67 86  64 97  62 107  60 115  59 120  59 123  58 124  59 124  60 125  63 125  67 125  73 124  79 124  88 122  96 121  104 120  110 118  115 118  117 118  
+21   85 152  85 151  85 153  85 157  86 163  85 171  85 179  85 187  84 193  84 197  85 199  86 199  89 199  92 199  96 198  101 197  106 196  111 196  116 195  119 195  122 195  
+23   170 81  170 78  170 77  170 78  170 82  169 88  168 97  167 108  165 120  164 130  162 138  162 144  162 147  163 149  165 150  169 151  175 151  183 152  192 154  201 156  211 158  219 160  226 162  
+23   42 48  43 47  43 46  43 47  43 49  44 54  43 61  43 70  42 82  41 93  40 103  38 111  38 116  38 119  39 119  42 119  47 118  52 116  58 115  65 114  71 113  76 112  79 111  
+26   233 78  233 77  233 78  233 81  234 87  235 95  235 105  235 116  234 127  234 134  234 140  233 144  233 146  233 147  234 147  235 146  237 146  241 146  246 145  253 144  260 144  267 143  272 142  277 142  279 143  280 143  
+26   134 58  134 56  134 55  134 56  135 59  135 64  135 70  134 77  134 85  133 93  132 100  131 105  130 109  130 110  130 111  131 111  132 110  135 110  139 109  144 109  150 109  156 109  162 109  166 109  169 109  171 110  
+24   27 41  27 40  27 41  27 42  27 45  27 49  27 55  27 61  27 68  27 75  26 80  26 84  26 87  26 88  26 89  27 89  30 89  33 89  37 88  42 87  47 86  52 86  56 86  59 86  
+9 m
+42   266 164  267 165  267 164  267 161  267 157  267 153  268 144  270 135  272 126  274 118  277 112  279 109  281 109  283 111  286 116  288 122  289 131  291 139  291 147  292 153  291 157  291 156  291 152  291 146  292 140  293 133  294 128  296 123  298 120  300 118  303 118  305 120  308 123  311 128  313 135  315 143  316 151  316 158  316 163  315 166  315 168  315 169  
+37   184 146  183 147  183 146  183 145  183 143  183 142  184 138  185 134  186 130  188 127  189 125  191 124  192 124  193 126  194 130  195 133  197 138  198 141  198 144  199 145  200 143  201 140  203 137  205 133  208 129  210 126  211 124  212 124  213 124  213 126  214 129  215 133  217 138  218 142  219 146  219 148  220 149  
+48   64 124  63 125  63 126  62 127  62 126  61 125  62 121  62 115  64 107  65 98  68 90  71 83  72 78  74 75  75 75  75 77  76 81  78 87  80 95  82 103  84 110  85 115  86 118  87 119  87 118  87 115  88 109  89 103  91 95  94 88  96 82  98 78  100 77  101 76  102 75  102 76  103 77  104 80  105 85  106 92  107 100  107 107  108 114  109 119  109 122  110 123  110 125  110 126  
+43   271 175  271 177  271 180  271 182  271 183  271 181  271 178  271 173  271 166  273 158  275 151  277 145  280 141  282 140  284 141  286 144  287 147  288 153  289 159  289 165  290 169  290 171  290 170  291 167  292 162  294 155  296 148  299 141  302 136  305 132  308 130  311 130  313 132  315 136  317 141  318 147  319 153  320 157  321 160  321 163  321 165  321 166  321 167  
+37   191 128  191 130  191 131  191 132  191 131  191 129  191 126  192 120  193 114  195 107  198 100  200 95  203 93  205 93  207 96  209 101  210 108  211 114  212 120  212 124  212 127  213 125  214 121  215 115  217 109  220 102  222 97  224 93  226 92  228 94  230 98  231 105  233 113  235 121  236 129  237 134  237 137  
+46   54 104  54 107  55 109  55 110  54 108  53 104  53 98  52 90  52 82  53 74  56 67  59 62  62 58  67 57  70 57  74 60  76 64  78 70  80 77  81 85  81 92  81 98  81 102  81 103  80 102  81 97  81 92  83 85  85 78  87 71  90 67  93 64  95 61  98 60  100 59  103 60  105 61  107 65  109 70  111 77  112 86  113 94  113 102  113 107  114 111  114 112  
+35   74 202  74 203  74 204  74 203  74 201  74 198  75 195  76 191  78 187  80 184  82 181  84 181  86 181  87 184  89 187  89 191  90 195  90 198  90 200  91 201  91 200  93 198  95 195  97 191  100 187  103 184  105 182  107 182  109 183  110 187  112 192  113 197  114 202  115 206  115 209  
+48   163 118  163 119  163 120  163 119  163 118  163 114  162 108  162 100  164 91  166 83  168 76  171 71  174 69  178 69  181 71  184 74  186 78  188 84  189 92  189 99  189 104  188 109  188 112  187 112  188 111  188 107  189 102  190 96  192 89  194 83  196 78  198 75  199 73  202 72  204 72  206 72  208 72  211 74  213 76  215 80  216 85  217 93  218 100  219 107  219 113  219 117  219 118  219 117  
+47   32 81  32 82  32 81  32 79  32 76  32 71  33 66  34 60  35 54  36 49  37 45  38 42  38 41  39 40  40 40  40 41  42 43  43 47  45 53  47 59  49 64  51 69  52 72  53 74  54 75  54 74  54 73  55 70  56 66  58 61  60 57  63 52  67 48  69 44  71 42  72 41  73 41  74 41  74 43  75 47  75 52  76 58  78 64  78 69  79 73  80 75  81 76  
+9 n
+34   126 204  126 203  126 201  126 199  127 196  128 191  129 185  131 179  133 173  134 169  135 166  136 165  136 166  137 167  138 170  140 174  144 180  147 186  151 192  155 197  158 200  160 202  162 203  163 202  164 199  164 194  164 187  164 178  165 169  165 161  166 154  166 149  167 146  167 144  
+35   211 142  211 143  211 142  211 140  210 137  210 131  210 124  211 116  211 108  212 101  212 97  212 94  213 93  214 96  216 100  219 106  222 113  226 122  230 130  234 136  236 140  238 142  239 142  239 141  240 139  240 135  240 130  241 122  241 112  241 102  241 93  241 84  241 78  240 75  240 74  
+37   95 131  95 132  95 133  94 132  93 130  92 126  92 120  92 111  93 103  95 94  98 86  101 81  104 78  106 76  108 77  109 79  112 83  114 88  117 94  120 101  122 108  124 113  126 118  127 121  129 124  129 126  130 126  130 125  131 120  133 113  135 103  137 93  138 84  139 77  140 73  141 72  141 71  
+34   237 190  237 189  237 188  237 185  238 180  240 174  242 166  244 157  247 149  249 143  251 138  252 136  253 135  254 137  256 141  258 147  261 155  265 165  269 175  272 183  275 189  277 193  279 194  280 194  281 192  281 188  282 181  284 172  285 160  286 149  286 140  286 132  286 127  286 124  
+34   177 117  176 117  175 116  174 114  173 111  172 105  171 99  171 91  170 84  170 79  170 75  170 73  170 72  171 72  173 75  177 80  181 87  187 95  192 103  196 111  199 116  201 119  202 120  202 119  202 115  203 110  203 103  204 95  204 86  205 79  205 73  206 68  206 65  206 64  
+34   54 116  54 115  53 113  53 110  53 106  53 99  53 92  55 85  56 78  58 73  60 69  62 67  63 66  64 65  67 66  68 68  70 70  72 74  74 79  76 85  78 91  79 98  81 103  81 107  82 110  82 108  83 105  84 99  85 92  86 84  87 77  88 72  89 69  90 66  
+39   231 160  230 160  229 159  228 157  227 153  227 149  227 141  227 130  228 119  228 109  229 99  230 93  230 90  231 89  232 90  234 95  237 101  241 109  247 119  253 130  258 139  264 146  268 151  271 155  274 157  275 157  276 157  277 155  277 152  277 147  278 140  278 131  278 121  278 110  278 100  278 91  277 84  276 79  276 77  
+37   148 137  147 138  147 139  146 139  146 138  146 136  145 132  144 128  144 122  144 116  143 110  143 106  143 103  143 102  144 101  144 102  146 104  147 108  150 112  154 118  158 124  161 129  164 133  167 135  168 137  169 137  170 137  170 136  170 134  170 132  170 128  170 124  170 118  170 112  170 107  170 102  170 99  
+36   37 111  37 112  37 111  36 109  36 106  37 101  37 94  37 85  37 77  38 70  38 64  39 61  39 59  39 58  40 60  41 62  44 66  47 73  51 82  55 90  59 98  62 103  64 107  66 108  68 107  68 106  69 104  70 100  71 96  72 90  72 84  72 78  72 72  72 67  72 63  71 61  
+9 o
+26   268 136  267 135  266 134  265 133  263 133  261 134  258 136  255 138  251 143  249 148  247 154  248 161  250 166  254 171  259 174  264 175  269 174  273 172  277 169  279 164  280 159  280 153  279 147  277 142  274 138  270 136  
+31   170 68  170 66  169 64  168 62  166 62  163 62  159 65  155 70  151 77  147 87  146 97  147 108  151 117  156 125  163 129  170 130  178 129  185 125  191 119  194 111  197 101  197 91  196 82  193 74  189 68  183 65  176 63  169 64  162 65  157 68  153 70  
+26   79 51  77 51  76 52  74 54  72 57  70 60  69 65  69 71  70 76  73 81  77 84  81 87  85 87  88 86  91 83  93 79  94 74  94 68  93 63  91 59  88 55  84 53  81 52  78 51  76 52  76 54  
+25   271 158  270 158  267 159  265 160  262 164  260 169  258 176  257 183  258 190  260 196  263 200  268 202  274 201  279 198  285 194  289 189  291 183  292 176  290 170  287 164  283 160  277 157  271 157  265 158  261 159  
+26   175 87  174 86  172 86  170 87  167 89  164 93  161 100  159 108  158 117  160 125  163 131  169 135  176 137  183 137  189 134  195 130  200 124  202 117  203 109  203 101  200 93  195 87  188 84  181 84  173 85  166 88  
+29   62 68  61 67  60 66  58 66  56 68  53 71  51 76  49 83  48 92  49 101  52 109  56 115  62 119  68 120  74 119  79 116  83 111  85 105  87 97  87 89  86 81  83 74  79 70  74 67  67 67  60 68  55 71  51 75  50 78  
+33   264 90  265 87  265 85  263 83  261 83  257 83  253 85  247 89  241 96  236 106  231 118  228 131  228 144  230 154  235 162  243 168  251 170  260 168  270 163  279 155  286 145  291 135  293 127  294 115  291 104  286 95  279 88  271 84  261 84  253 86  244 89  239 94  235 98  
+24   157 117  157 116  155 116  154 117  152 120  149 124  147 130  145 136  144 143  145 149  148 153  151 155  156 155  160 154  165 150  168 146  170 140  171 135  170 129  169 125  166 121  162 119  158 119  154 120  
+25   71 63  69 62  65 63  62 67  58 72  55 81  54 91  53 102  55 112  59 120  64 124  71 125  77 122  82 118  86 111  88 103  89 94  88 85  87 77  84 71  79 66  75 65  70 64  67 65  63 66  
+9 p
+39   262 144  262 143  262 144  263 146  264 150  265 155  266 161  267 167  267 173  267 177  267 180  266 181  265 180  264 177  263 172  262 166  261 159  260 151  260 145  261 139  263 135  267 131  272 128  277 126  283 125  288 127  292 129  296 134  298 138  298 143  297 147  295 152  291 155  287 157  281 158  273 159  265 160  258 160  252 159  
+36   195 93  195 92  196 94  196 97  197 102  198 108  198 115  199 123  199 131  198 136  198 140  197 142  196 139  195 133  194 126  193 117  192 109  192 101  192 94  194 89  196 85  199 83  203 83  207 84  211 86  215 90  217 95  219 100  218 106  217 111  214 115  210 119  205 121  200 122  196 122  193 121  
+36   85 78  86 80  86 84  87 89  89 95  90 103  91 110  92 117  92 122  91 125  91 127  90 126  89 124  88 121  87 114  86 105  85 96  85 88  86 80  87 75  90 72  94 70  97 69  102 69  106 71  110 74  113 78  113 82  112 86  110 89  106 92  102 95  97 98  93 99  89 101  86 101  
+35   248 100  248 103  249 106  250 112  251 121  252 130  253 141  254 150  254 158  255 163  254 167  253 166  251 163  249 157  247 148  244 137  242 126  241 113  242 103  244 94  248 86  253 82  259 80  266 80  273 83  279 89  284 96  287 103  286 111  284 118  279 124  273 128  266 131  259 133  254 132  
+32   148 129  149 130  150 133  151 137  152 143  153 150  154 157  154 162  154 166  154 169  153 169  152 167  151 163  150 158  148 151  147 142  147 134  148 127  149 122  153 119  156 117  160 117  164 119  167 122  169 126  170 130  169 134  166 138  162 141  158 143  152 144  148 145  
+32   57 79  57 80  58 84  58 89  60 95  61 103  62 110  62 117  61 121  60 123  58 122  56 118  54 111  52 103  51 93  51 83  53 74  56 68  61 63  67 61  73 61  79 63  83 66  86 70  87 75  85 81  81 86  76 91  71 95  64 97  61 98  58 98  
+37   209 121  209 122  210 124  211 128  211 133  213 140  214 148  214 155  215 161  215 166  214 169  214 171  212 171  211 169  210 164  209 157  208 147  207 137  208 126  210 116  212 108  215 100  220 95  224 93  228 92  234 93  239 97  243 102  245 108  246 114  244 121  240 126  235 129  229 131  223 132  217 132  212 132  
+38   131 58  131 57  131 58  132 59  133 62  134 66  135 71  136 77  136 83  136 89  136 93  136 95  135 95  134 93  134 88  132 83  131 76  130 69  130 63  130 57  132 52  135 48  138 45  141 43  145 42  149 42  154 45  157 48  159 52  161 57  160 61  159 65  156 68  153 70  148 71  144 71  140 71  136 71  
+37   37 62  37 61  38 60  38 61  38 63  38 66  39 71  40 77  40 84  40 89  40 94  40 97  40 99  39 97  39 94  38 89  37 82  36 75  36 68  37 61  38 56  40 51  42 47  46 44  49 43  53 42  56 43  59 46  61 50  62 54  61 59  59 63  55 66  51 69  46 71  42 72  40 71  
+9 q
+44   277 138  277 139  277 138  276 138  275 137  273 136  271 136  268 137  264 139  259 142  254 148  251 155  248 162  248 170  250 177  254 183  260 187  266 188  272 187  278 184  284 180  288 174  291 167  292 159  291 153  289 147  285 143  280 140  275 139  271 138  267 138  264 138  263 139  264 139  266 140  271 140  276 140  283 139  289 137  295 136  300 134  303 133  306 132  307 132  
+39   170 81  170 79  169 78  167 78  164 80  161 84  158 90  156 99  155 108  155 118  157 126  161 132  167 136  173 137  180 135  186 133  191 128  194 122  196 113  196 104  195 95  191 88  186 82  180 79  175 77  170 77  166 79  165 82  167 86  170 89  176 92  183 94  191 93  200 91  209 88  217 85  224 82  228 80  231 79  
+38   67 65  67 64  67 63  65 63  63 64  60 65  56 69  52 74  48 82  45 92  44 104  44 115  46 125  50 132  55 136  61 136  66 134  73 130  77 124  79 115  81 105  81 95  80 85  78 76  75 71  71 68  65 67  61 68  57 70  55 73  54 76  56 79  59 82  64 83  72 84  77 82  84 80  88 77  
+36   236 157  236 156  235 156  234 157  233 159  232 162  230 165  229 170  228 175  229 179  230 183  233 186  237 188  241 189  244 189  248 188  250 185  252 181  252 177  252 171  252 166  250 161  247 158  244 155  241 155  237 155  234 156  231 157  230 159  231 160  233 160  238 160  244 159  251 157  257 154  263 152  
+43   174 84  174 83  174 81  173 80  172 79  170 78  168 77  164 77  160 78  156 81  151 84  147 90  144 96  142 104  142 112  143 118  145 123  149 127  154 128  160 128  166 126  171 121  176 115  179 108  181 99  182 91  181 84  179 78  176 74  172 71  167 70  163 71  158 72  155 74  154 76  154 78  156 79  160 80  165 80  170 79  176 77  181 76  184 75  
+38   62 54  60 52  58 51  56 51  54 52  51 54  49 56  47 60  46 66  45 73  46 81  47 90  50 96  54 101  59 104  62 104  68 101  73 97  77 90  79 82  79 74  78 68  75 62  72 58  67 55  62 53  58 53  55 53  53 54  52 56  54 58  57 60  62 62  69 63  75 63  82 62  87 60  92 59  
+52   244 122  243 120  242 118  241 117  239 116  236 117  232 119  228 123  224 130  220 138  217 147  216 156  217 166  220 174  225 181  232 185  239 187  246 187  254 184  260 179  267 174  272 168  275 161  278 154  279 148  278 142  276 136  272 130  267 126  262 122  255 119  249 116  243 115  238 114  234 114  232 114  231 115  231 116  232 117  233 118  234 119  235 120  236 120  237 120  240 119  244 118  250 116  258 113  266 110  274 107  280 105  284 103  
+40   165 67  165 66  164 65  162 66  159 67  157 68  154 72  152 76  151 82  151 89  152 95  155 100  158 103  162 104  166 103  170 100  173 96  175 90  176 85  175 80  174 75  172 71  170 69  167 67  164 66  162 65  160 64  158 64  157 63  156 63  157 63  159 64  162 63  166 63  171 62  177 61  187 59  191 59  193 59  195 58  
+49   47 45  47 44  46 44  45 43  44 43  42 43  40 44  38 46  35 50  34 54  33 60  33 66  34 71  37 77  40 81  45 84  50 86  55 85  61 84  65 81  69 77  71 73  72 68  72 63  71 58  68 54  64 50  61 47  58 45  54 43  51 42  49 42  47 42  45 42  44 42  44 43  43 43  43 42  43 43  44 43  46 44  49 44  54 43  59 42  67 41  74 40  80 39  85 38  88 37  
+9 r
+41   244 138  244 140  244 142  245 147  245 152  246 158  246 163  246 167  246 170  245 168  244 164  243 159  241 152  240 144  240 137  242 131  244 127  248 123  252 121  257 121  260 123  261 127  261 132  259 138  255 144  252 149  249 152  246 154  246 155  247 154  250 154  254 154  260 155  266 156  273 159  279 162  284 165  288 168  291 170  292 171  291 170  
+38   145 85  146 83  147 85  149 89  150 96  151 104  152 112  152 119  152 123  151 121  150 115  150 107  149 99  150 90  152 84  155 79  160 76  165 76  169 78  172 81  174 85  174 91  173 97  170 102  168 106  165 109  163 110  162 111  164 112  167 113  171 115  176 117  183 119  190 122  195 124  200 125  203 125  204 125  
+38   51 64  52 63  52 64  53 66  53 70  54 76  54 82  54 88  53 94  53 98  52 100  51 99  51 96  50 90  50 83  51 74  53 66  56 60  59 56  63 54  67 54  70 56  71 59  71 63  70 67  68 72  64 76  63 79  63 82  64 85  68 87  73 90  78 92  84 94  89 96  94 98  98 100  102 100  
+51   244 137  245 138  246 139  247 143  248 149  249 158  250 167  251 176  251 184  251 187  251 190  250 191  248 187  247 182  245 175  243 167  242 158  241 151  242 144  243 138  245 133  249 129  253 126  258 124  264 124  269 125  273 128  276 133  276 140  274 146  270 153  265 159  260 163  256 164  251 166  247 165  246 164  246 163  250 161  255 161  261 162  268 164  275 168  282 173  287 177  291 182  295 187  297 189  298 191  299 192  299 191  
+51   162 51  162 53  163 57  164 62  166 70  167 78  168 87  169 95  169 101  169 106  169 109  168 110  167 109  166 106  164 103  162 98  160 91  157 85  156 78  154 71  154 65  154 59  156 54  159 49  162 45  166 43  170 41  175 41  179 43  182 45  184 50  184 55  182 60  179 66  175 70  170 73  167 75  165 76  164 77  166 77  170 77  176 78  183 80  188 82  196 86  203 89  208 93  212 95  214 96  214 97  213 96  
+48   49 50  49 51  50 54  51 58  52 63  53 69  54 76  53 83  53 88  52 93  51 95  50 94  49 91  48 86  46 81  44 74  42 67  41 61  41 56  41 51  43 47  46 43  50 41  55 39  59 38  64 39  68 40  70 43  70 48  69 53  65 58  62 63  59 66  56 68  55 69  54 70  55 70  58 71  62 72  68 74  74 76  80 79  85 82  90 85  93 88  94 89  95 90  95 89  
+39   200 156  201 159  202 163  203 168  203 175  204 181  204 186  203 190  203 191  202 190  202 186  201 181  200 175  199 168  199 162  199 157  200 153  203 150  205 149  208 149  211 150  213 152  215 154  215 158  214 161  212 164  209 167  208 169  206 170  205 171  206 172  207 173  210 174  215 176  220 178  226 179  233 181  238 182  243 183  
+41   146 58  146 59  146 62  146 66  146 72  147 80  147 87  147 95  146 100  146 103  146 102  146 99  145 95  144 88  143 81  142 74  141 67  141 61  143 56  147 53  152 50  157 48  163 49  167 51  170 54  171 59  169 64  166 69  162 73  158 76  155 77  153 78  153 79  155 80  159 81  169 85  176 89  183 93  188 97  193 99  196 100  
+40   26 51  26 50  26 52  26 56  27 60  28 66  28 73  29 79  29 83  28 86  28 87  27 85  26 81  24 75  24 68  23 61  24 54  26 48  30 43  35 41  40 40  45 40  49 43  50 46  50 52  48 58  43 63  39 68  35 71  32 74  31 75  32 75  35 76  39 77  45 78  51 81  57 84  61 87  64 89  67 90  
+9 s
+39   262 141  262 140  263 139  263 138  263 137  262 135  261 133  258 132  254 131  250 130  245 130  241 132  237 134  234 137  233 141  232 144  234 150  236 155  240 159  244 163  249 166  254 168  258 170  261 173  263 175  263 178  263 182  260 185  257 188  251 190  245 191  238 192  231 191  224 189  219 186  215 182  213 179  212 175  212 173  
+31   194 65  194 64  193 63  192 62  189 61  186 61  181 63  176 65  172 68  169 72  168 76  169 79  172 82  177 86  182 89  187 93  191 97  193 101  193 104  192 108  188 110  184 112  178 113  171 113  165 112  160 111  155 109  153 107  152 106  152 104  154 102  
+30   84 56  84 54  83 53  82 52  80 51  77 52  74 54  70 57  65 60  64 63  62 66  63 69  65 72  70 74  75 76  79 78  82 80  84 83  85 86  84 89  82 92  79 94  74 96  69 98  62 99  57 99  52 99  49 98  48 97  48 95  
+34   270 96  271 94  271 92  270 89  268 87  264 84  260 82  254 81  248 81  242 83  237 87  233 92  232 98  233 102  235 107  240 114  246 121  253 127  260 133  265 138  269 142  271 147  271 151  269 156  266 160  261 163  255 166  248 167  243 167  237 165  231 163  227 160  224 157  223 154  
+33   174 84  174 83  174 82  173 81  171 79  169 78  166 77  161 77  157 78  152 80  148 83  146 86  146 90  147 94  151 99  156 103  161 107  167 111  172 115  175 118  177 121  177 124  176 127  174 130  170 133  166 135  160 136  157 136  151 135  145 134  140 131  136 129  133 127  
+27   80 50  80 49  80 47  79 46  76 46  73 47  69 49  63 52  58 57  55 61  53 66  55 70  58 74  63 76  70 79  75 82  79 86  82 91  82 96  79 100  75 105  70 108  62 110  56 111  51 111  48 110  46 107  
+42   302 74  301 74  300 74  299 72  298 71  296 68  294 66  292 63  289 62  284 62  280 63  275 66  270 70  266 75  264 82  263 90  264 97  266 104  269 109  274 112  279 114  284 115  289 117  293 119  297 122  300 125  301 129  302 135  302 139  300 144  297 148  293 152  288 155  282 157  275 158  268 158  261 157  255 154  250 150  246 147  244 144  242 141  
+37   190 95  190 94  189 93  188 91  186 90  184 89  181 89  178 90  176 92  174 95  172 99  172 102  172 106  173 109  174 112  176 114  178 115  180 116  182 117  184 117  186 118  188 119  190 121  192 123  193 125  193 127  193 130  192 132  190 134  188 136  184 137  181 138  177 139  173 139  170 138  167 137  165 136  
+41   71 42  70 42  69 41  67 41  64 40  60 40  57 40  53 42  50 44  48 46  46 49  45 52  46 56  47 58  48 60  51 62  53 63  56 63  60 63  63 63  67 64  70 65  73 66  75 68  77 70  78 73  79 74  79 77  79 79  78 82  77 84  75 86  72 88  68 89  63 90  59 91  55 91  51 90  48 89  45 88  42 86  
+9 t
+28   240 78  240 79  242 79  245 80  250 81  257 81  264 81  272 81  279 81  285 81  289 81  292 80  293 80  293 81  292 82  292 85  291 90  290 98  288 108  286 118  284 129  281 138  279 146  277 151  276 155  275 157  275 158  274 158  
+27   147 52  145 52  145 51  144 51  144 52  146 53  150 53  155 53  162 53  169 52  175 51  180 50  184 50  186 50  187 50  187 51  186 52  186 56  187 61  187 69  188 79  189 90  190 100  191 110  192 116  193 121  193 123  
+24   38 38  36 38  36 37  39 37  42 37  47 37  53 37  60 37  66 37  71 37  74 38  75 38  75 40  75 42  75 46  74 52  74 59  73 69  73 79  72 88  71 95  70 100  69 102  69 101  
+29   268 93  266 93  265 92  264 92  263 91  264 91  266 90  271 90  278 89  286 88  294 87  302 86  308 86  312 86  314 87  315 87  315 89  315 92  315 98  314 105  314 115  314 126  314 136  315 145  315 152  315 157  316 160  316 162  315 161  
+30   171 77  170 77  169 77  170 77  171 77  175 76  180 76  186 76  192 75  198 75  203 75  206 75  209 76  210 76  211 78  211 81  210 85  210 92  210 102  210 113  210 125  210 136  210 146  210 155  210 163  210 168  211 173  211 175  211 177  210 177  
+27   57 65  56 65  56 64  58 64  61 65  67 64  72 64  78 63  84 63  89 63  92 63  94 63  94 64  94 65  94 68  93 71  93 76  92 85  92 94  92 104  92 112  92 120  92 124  92 126  92 127  92 126  92 125  
+24   258 80  257 80  256 80  258 79  261 79  266 77  271 76  278 74  283 73  286 72  289 72  291 71  292 71  292 72  292 73  292 75  292 80  293 87  293 96  294 105  295 113  295 119  295 123  295 125  
+27   159 50  157 49  157 50  159 50  163 52  168 54  175 56  183 59  190 62  197 64  201 65  204 66  206 67  207 67  207 68  207 69  206 72  205 77  203 84  201 94  198 104  195 112  193 119  193 124  192 126  193 125  193 124  
+25   21 41  22 41  24 42  28 41  34 40  40 40  48 39  56 38  61 38  67 38  69 38  71 39  70 41  70 43  68 47  67 53  64 61  62 70  61 78  59 87  58 93  58 98  58 101  58 100  59 97  
+9 u
+24   229 142  230 140  230 138  231 138  231 140  231 142  231 147  232 154  233 162  235 170  237 178  240 184  244 188  249 189  253 188  257 186  261 181  263 175  265 167  266 159  266 152  266 145  266 141  265 139  
+22   154 93  154 91  154 90  155 92  155 96  157 102  158 110  160 119  162 128  164 135  167 140  170 142  174 142  178 140  181 136  184 131  186 123  187 114  188 105  188 97  188 91  187 89  
+21   60 58  60 59  60 61  60 64  60 69  61 75  62 82  63 90  66 96  70 103  73 106  77 108  81 107  84 104  87 99  90 93  92 85  93 78  93 72  93 66  92 62  
+24   220 119  220 117  220 118  220 120  220 124  220 130  221 137  222 145  224 153  227 160  231 165  236 168  242 168  248 166  253 162  258 157  261 149  263 141  265 133  265 127  265 121  264 117  264 114  263 112  
+21   142 50  141 49  142 52  142 54  143 59  144 65  147 73  150 81  154 87  160 91  165 93  170 93  175 91  178 87  180 82  182 76  182 71  182 66  181 62  180 60  180 59  
+20   44 40  44 41  43 45  43 50  43 57  45 65  47 73  50 81  54 87  59 91  65 92  71 90  74 87  77 82  79 77  80 72  80 67  79 63  79 59  79 57  
+21   224 125  225 127  225 130  226 135  227 141  228 148  230 155  233 161  236 165  240 168  243 168  247 166  250 163  252 158  254 151  255 144  256 136  257 129  257 124  257 121  257 119  
+23   133 67  133 66  133 65  133 66  133 69  134 73  135 80  136 88  138 98  141 106  145 112  150 116  156 116  159 115  164 110  168 102  171 94  173 85  173 77  173 70  172 66  171 63  170 60  
+21   30 53  30 54  30 56  30 60  31 64  33 70  35 76  39 82  42 86  46 88  50 88  54 86  57 83  59 78  61 74  61 68  61 63  60 58  59 54  58 50  57 47  
+9 v
+31   250 157  249 156  250 156  250 157  252 160  254 165  257 171  260 179  263 186  266 192  267 196  269 198  270 198  272 195  274 191  276 184  278 176  281 168  283 162  284 157  285 155  286 154  287 154  289 154  292 155  296 155  301 155  305 155  308 154  311 154  313 153  
+32   164 114  163 112  163 110  163 109  163 111  165 114  167 120  170 127  173 136  175 144  178 151  181 156  184 158  187 158  190 155  193 150  196 143  199 135  201 127  202 120  202 114  203 111  203 109  203 108  204 108  206 108  209 109  213 109  218 109  222 108  226 106  229 105  
+31   60 66  61 65  61 64  61 65  62 66  64 68  67 74  70 81  74 90  77 99  81 107  84 113  86 117  88 117  90 114  92 108  94 101  95 92  95 84  95 77  95 71  94 68  94 65  94 64  96 63  98 62  102 60  107 59  112 58  117 56  120 55  
+34   259 150  258 150  258 151  259 151  260 152  261 155  262 158  264 164  267 170  269 177  271 183  274 188  277 190  281 190  284 187  288 182  291 175  292 169  293 162  294 157  293 153  293 150  292 149  292 148  293 148  294 148  297 148  301 147  306 146  311 144  316 143  319 141  322 141  324 141  
+33   168 101  168 98  168 97  168 96  168 97  169 100  170 104  173 111  175 118  178 126  181 132  183 137  185 140  186 141  187 140  188 136  189 131  191 122  192 113  193 105  194 98  194 94  195 92  195 91  196 91  198 91  200 91  204 91  208 91  212 90  215 89  218 89  219 89  
+32   57 58  57 57  57 56  58 57  58 58  60 62  62 68  64 76  66 86  69 95  71 102  74 106  76 107  79 105  81 100  83 93  85 86  86 78  87 72  87 67  87 63  87 62  86 61  87 61  87 62  89 62  91 62  95 62  99 62  104 61  107 61  110 60  
+31   80 155  80 153  79 152  80 153  81 155  83 160  86 167  90 174  94 181  98 187  102 191  105 192  108 192  111 190  113 185  115 179  116 172  116 165  115 159  115 155  114 153  114 152  114 151  116 151  119 151  124 151  128 151  134 150  138 150  142 149  145 149  
+30   160 93  161 91  162 91  164 94  166 99  168 105  171 112  174 120  177 127  180 132  183 135  185 136  187 135  189 131  190 126  191 118  192 110  192 102  191 96  191 91  191 88  192 86  194 86  197 85  202 84  207 84  212 83  217 82  221 82  223 82  
+29   48 58  48 57  47 56  47 55  48 57  49 59  51 64  54 71  58 79  61 88  63 95  66 100  68 102  70 101  72 97  73 91  74 84  75 76  76 69  76 63  76 59  75 57  76 56  77 56  79 56  81 56  85 56  89 56  93 55  
+9 w
+41   257 148  257 147  257 146  257 147  257 149  257 154  257 161  257 170  258 179  259 187  260 193  262 196  264 197  267 195  269 192  272 187  273 182  275 176  276 170  277 166  278 163  278 162  278 163  279 165  281 168  283 173  286 177  289 182  291 186  294 188  296 188  299 187  300 184  301 178  303 172  304 163  304 154  304 146  304 139  303 133  302 130  
+43   159 64  158 61  158 60  158 61  159 65  161 70  163 79  167 90  171 101  176 113  179 122  183 128  185 131  186 130  188 125  189 117  191 107  194 96  196 85  198 78  199 74  200 72  200 70  200 71  201 72  202 76  204 83  206 92  208 101  211 111  213 119  216 125  218 128  219 129  221 126  223 121  225 112  227 102  229 90  231 79  232 69  232 62  233 57  
+39   37 63  37 61  37 59  36 58  37 61  38 65  38 72  40 80  42 89  44 96  46 101  48 102  50 100  52 96  54 91  56 85  58 79  59 76  60 73  60 72  60 71  61 72  62 74  64 77  67 82  70 87  72 92  75 96  76 98  77 99  79 98  80 95  81 90  82 84  83 76  84 68  84 62  84 58  83 55  
+37   249 123  249 122  249 123  249 124  249 128  248 132  248 139  249 146  250 153  252 159  254 162  257 164  259 163  261 161  263 158  265 154  266 150  266 147  267 146  267 145  268 146  269 149  270 152  272 157  275 161  278 165  282 167  286 166  290 163  294 159  296 153  298 146  299 140  298 135  298 130  297 128  296 126  
+35   159 100  159 98  159 97  158 99  158 103  158 108  158 115  158 123  159 129  161 134  164 136  167 137  171 136  174 134  177 131  179 127  180 125  181 122  181 121  182 122  182 123  183 125  184 129  186 131  189 133  191 135  194 135  196 133  199 131  200 128  202 123  202 117  202 111  201 106  200 101  
+44   35 49  35 47  35 46  34 47  34 48  33 52  32 57  31 64  31 72  31 79  32 88  35 96  38 102  43 105  48 106  54 103  58 99  62 93  65 87  67 81  68 76  68 73  68 71  68 70  68 71  69 73  70 75  71 79  73 84  75 90  77 94  80 98  84 101  87 102  91 101  95 99  98 95  101 89  104 82  104 74  104 66  102 59  99 53  96 48  
+43   229 129  229 127  229 124  230 122  230 121  230 123  230 126  230 132  230 141  230 150  231 160  232 168  234 174  237 177  241 177  245 176  249 172  253 167  256 161  258 156  259 150  260 146  260 144  261 143  261 144  262 146  263 149  264 153  266 158  269 163  270 167  273 170  275 171  277 169  280 166  282 161  284 154  286 146  286 137  286 129  285 122  284 116  282 111  
+37   129 69  128 68  127 67  126 69  126 73  126 78  126 86  126 94  128 103  129 109  130 114  133 116  135 115  138 112  140 107  142 102  144 96  145 92  145 90  146 90  148 92  150 97  153 102  157 108  160 113  163 117  167 119  169 118  171 115  173 109  174 101  175 93  175 85  175 80  174 74  173 71  172 69  
+34   33 39  33 37  32 37  32 39  32 43  32 50  33 57  33 65  34 72  35 77  37 79  38 80  40 78  42 76  45 72  46 68  48 65  49 64  51 64  53 67  55 70  59 73  62 76  65 77  69 78  71 76  73 74  75 70  75 64  76 59  76 53  75 48  74 44  73 41  
+9 x
+37   259 144  258 143  257 142  256 141  255 140  256 141  258 143  261 146  265 150  270 155  276 160  283 165  289 168  295 171  300 172  304 172  308 172  310 170  311 168  311 165  309 163  307 161  304 160  300 161  296 161  291 163  286 166  281 169  276 174  271 178  267 183  264 188  262 191  261 193  261 194  260 195  259 195  
+33   181 87  180 85  180 84  179 84  180 85  180 87  182 91  185 95  188 100  193 106  199 111  205 115  211 116  217 116  222 115  226 113  228 111  229 108  229 107  227 106  224 106  220 107  215 109  208 112  202 115  194 119  187 123  181 128  175 132  171 135  169 138  168 140  168 142  
+30   54 48  53 47  52 47  52 48  54 51  56 56  60 61  65 67  72 74  77 79  83 83  89 85  93 86  97 85  99 83  100 81  100 79  99 76  97 75  94 74  90 74  85 75  79 78  73 82  67 87  61 91  57 95  54 99  53 101  53 103  
+37   227 154  227 153  227 154  227 155  228 157  230 160  233 164  237 169  241 174  246 178  251 181  255 183  258 184  261 184  262 183  263 183  263 181  263 180  263 178  262 177  261 176  260 175  258 175  255 176  251 177  247 178  242 180  238 182  233 185  229 187  226 189  224 190  223 190  222 191  221 191  220 191  218 192  
+37   162 72  161 71  162 72  163 75  165 79  168 84  172 90  177 97  183 103  189 108  195 110  201 111  206 110  212 107  216 103  220 99  222 95  223 92  223 89  222 88  220 86  216 86  213 85  208 85  203 86  198 87  192 89  187 92  181 96  175 100  169 106  163 113  157 119  152 125  147 129  144 131  143 132  
+32   46 52  45 51  45 50  46 52  48 55  51 59  56 65  61 71  66 76  72 80  77 83  81 83  85 83  87 82  89 80  89 78  89 76  89 74  88 73  87 72  85 71  83 71  81 72  78 73  73 75  69 77  63 81  59 85  55 89  53 93  52 95  52 97  
+34   213 130  212 130  211 130  212 131  214 134  216 139  219 144  224 151  229 157  235 161  241 164  247 166  253 166  258 164  261 162  264 159  266 157  266 154  266 152  264 151  261 151  258 151  252 153  246 155  239 159  232 162  224 166  217 170  211 174  206 177  202 180  200 182  198 184  197 186  
+35   141 59  140 59  140 60  140 61  142 63  144 66  147 70  152 76  157 81  162 86  168 89  173 91  177 92  181 91  184 90  186 89  187 89  187 88  186 88  185 87  184 87  183 86  182 87  181 87  180 88  178 88  176 89  170 91  164 94  155 99  146 103  138 108  132 112  127 116  126 118  
+32   33 49  33 50  33 51  34 53  35 56  38 60  40 64  44 69  49 73  54 75  59 77  63 78  67 78  70 78  72 76  72 75  73 74  72 72  71 71  69 70  65 70  61 70  57 71  51 73  45 76  41 79  34 85  28 91  24 96  21 101  20 104  21 104  
+9 y
+48   251 107  251 106  250 106  249 108  247 110  246 114  244 119  243 124  244 130  245 134  248 138  252 139  257 138  262 135  267 131  271 126  273 121  276 118  277 115  277 113  277 115  277 117  278 122  279 128  280 136  281 145  282 154  283 162  283 169  282 174  280 177  277 179  273 179  267 178  261 176  256 173  251 169  248 166  247 162  249 159  254 155  261 151  270 148  280 145  290 142  297 141  302 142  304 142  
+38   140 59  140 58  139 60  138 62  137 66  136 72  135 79  135 85  136 90  139 91  143 90  148 87  152 82  157 77  160 72  162 69  164 68  165 70  165 75  166 83  167 93  168 104  168 115  167 124  164 131  160 135  155 137  149 137  144 136  140 133  138 128  138 123  141 118  146 113  154 108  162 103  171 100  178 99  
+40   22 48  22 47  21 47  22 49  22 53  24 57  26 62  29 66  32 69  35 69  38 67  42 64  44 59  47 55  48 50  49 46  49 44  49 43  50 45  52 50  54 56  58 65  63 75  68 86  71 96  73 105  73 111  72 116  69 118  63 119  57 118  51 115  45 111  40 107  39 101  40 94  43 88  49 81  56 75  63 69  
+40   262 126  262 124  262 123  262 122  262 123  262 126  262 130  262 135  263 140  265 145  266 148  269 149  271 148  274 145  277 142  279 138  281 135  282 133  283 133  284 135  284 140  286 146  288 154  289 163  291 171  291 178  289 183  287 185  283 186  278 185  274 182  269 180  267 177  266 174  268 170  271 166  277 161  284 157  291 154  297 151  
+45   158 75  157 74  156 74  155 76  154 81  153 87  153 96  154 106  156 114  159 120  163 123  168 122  174 117  179 111  183 103  186 95  189 88  190 82  191 79  192 77  192 78  193 82  194 89  195 99  197 111  198 124  200 137  200 150  199 161  196 171  192 179  185 186  177 189  169 190  161 188  156 183  153 176  154 167  159 159  166 152  175 146  185 141  194 138  203 136  209 136  
+37   56 59  56 56  56 54  56 53  56 56  56 59  56 64  57 69  59 74  62 77  65 78  69 77  72 74  74 71  76 67  78 63  79 59  79 58  81 59  82 63  85 69  87 77  89 87  90 97  90 107  88 115  85 120  80 124  75 125  70 124  65 122  63 117  63 112  65 106  70 100  75 95  81 91  
+41   254 107  254 106  254 105  253 105  253 106  252 108  252 112  252 118  252 124  253 130  255 134  258 136  262 136  267 133  272 129  276 125  279 121  281 118  283 116  284 117  285 121  285 126  285 134  286 143  286 153  285 162  282 171  278 178  273 183  265 186  257 186  250 184  245 180  243 175  244 168  250 162  258 157  269 153  279 150  289 150  296 150  
+45   153 62  153 61  152 62  151 63  149 65  147 69  144 75  142 81  141 87  141 93  142 98  145 100  150 100  155 97  161 93  167 88  172 83  175 79  177 76  178 74  179 73  179 74  179 76  179 81  178 87  178 95  177 104  175 113  172 121  168 128  164 134  159 137  153 139  148 139  144 138  142 136  142 132  145 127  150 122  158 118  167 114  177 111  185 110  192 110  196 111  
+47   32 37  32 35  31 35  30 37  29 39  28 43  27 48  27 52  28 59  30 65  32 69  36 71  41 71  45 69  50 65  53 60  56 55  57 51  59 47  59 44  59 43  59 42  60 43  60 46  61 50  62 56  63 64  65 74  67 83  68 92  69 101  69 109  67 115  64 119  60 121  56 121  51 119  47 116  43 111  41 105  41 99  42 93  46 88  52 83  58 79  64 76  71 75  
+11 z
+109   193 53  194 53  197 53  200 52  204 52  208 52  215 52  222 52  232 52  239 52  242 52  244 52  245 51  246 51  247 51  248 51  249 50  249 51  248 53  247 55  246 57  244 60  241 63  239 67  236 70  234 73  232 76  230 79  228 81  227 83  225 85  224 87  223 89  222 90  221 90  220 91  220 92  219 92  218 93  217 95  215 96  213 97  212 99  210 100  209 101  208 102  207 103  206 104  206 105  204 106  203 107  202 108  201 109  201 110  200 111  199 111  199 112  198 112  198 113  197 113  196 114  195 114  194 115  193 115  194 115  193 115  194 115  195 115  198 115  201 115  205 115  209 115  213 115  216 115  217 115  218 115  219 115  221 115  223 114  225 114  227 114  228 114  230 114  230 113  232 113  233 113  234 113  236 114  238 114  240 114  242 114  244 114  245 114  246 114  247 114  248 114  249 114  250 114  251 114  252 114  253 114  254 113  255 113  256 113  257 113  258 113  259 113  260 113  260 112  
+134   22 47  22 46  23 46  24 46  26 46  28 45  32 45  36 45  40 45  47 45  54 45  58 46  61 46  64 46  65 46  67 46  68 46  69 46  70 46  72 46  74 46  76 45  79 45  81 45  83 45  84 45  85 45  86 45  87 45  88 45  89 45  88 46  86 47  85 49  84 51  82 53  81 54  80 56  78 58  76 59  75 61  73 63  71 65  70 66  70 68  69 69  68 70  68 71  67 72  68 71  67 72  66 73  65 74  64 75  62 76  61 77  60 78  60 79  59 79  58 80  57 81  56 82  55 83  54 84  54 85  53 85  52 86  52 87  51 87  50 88  50 89  49 90  49 91  48 91  48 92  47 93  46 94  44 96  44 97  43 98  42 99  41 100  40 101  39 102  38 103  37 103  37 104  36 104  36 105  35 106  34 107  34 108  33 108  32 109  31 111  30 111  30 112  31 111  33 111  36 111  40 111  44 110  47 110  50 110  51 110  52 110  53 110  54 110  55 109  57 109  59 109  62 109  64 109  65 109  67 109  69 109  71 109  73 109  76 109  78 109  79 109  80 108  81 108  82 108  83 108  84 108  85 107  86 107  87 107  89 107  91 107  94 107  95 107  96 107  
+31   249 136  250 135  252 135  256 134  261 132  267 131  274 130  280 129  284 130  287 132  288 135  287 139  284 145  280 152  274 159  268 167  261 174  255 180  252 183  248 187  247 189  248 190  251 190  258 190  266 189  275 189  285 189  292 189  298 189  302 190  304 190  
+27   168 78  167 78  166 78  168 77  170 76  174 75  179 75  184 74  189 74  193 75  195 77  196 82  195 87  192 95  189 103  185 111  181 117  179 121  177 124  177 126  178 126  181 126  186 126  191 126  197 125  202 125  207 125  
+30   56 61  55 61  54 62  53 62  55 61  58 60  63 59  69 58  75 57  80 56  84 57  87 60  87 65  86 71  83 77  80 82  76 90  71 97  66 103  63 108  61 111  62 113  65 113  71 113  76 112  83 112  89 112  95 111  99 111  102 111  
+34   220 73  218 73  220 72  224 71  230 70  238 69  245 68  253 67  259 68  263 70  266 73  266 78  265 86  263 96  258 108  253 121  247 134  240 145  233 156  226 163  221 169  218 173  216 175  218 173  222 170  225 168  233 166  242 163  252 162  261 162  270 163  277 164  282 166  285 167  
+31   140 103  139 103  139 102  141 102  142 102  145 101  149 100  154 99  158 97  162 97  165 97  167 98  167 101  167 106  165 112  161 118  157 124  153 131  148 136  144 139  142 142  140 144  140 145  141 145  144 144  148 144  153 143  159 142  165 142  170 141  175 141  
+26   53 50  51 50  50 50  51 49  53 49  55 49  59 49  63 49  68 50  71 52  72 56  73 60  71 65  69 70  64 74  61 78  58 80  57 81  56 82  56 83  58 82  62 82  65 82  71 81  74 81  77 80  
+36   249 144  247 143  246 143  247 142  248 142  252 141  257 141  263 140  269 140  276 139  280 140  284 141  285 143  284 146  282 151  278 157  272 164  266 172  259 180  252 188  246 194  241 199  238 203  236 205  235 205  240 204  245 202  252 199  261 197  270 195  278 194  286 194  292 195  296 197  298 198  299 200  
+35   173 58  175 58  178 58  182 58  187 58  193 58  198 59  203 59  206 59  208 60  209 62  208 65  207 68  204 74  200 80  195 88  189 96  183 104  178 110  174 115  172 118  170 119  170 120  172 119  174 118  177 117  181 116  187 114  194 113  202 112  210 111  217 110  224 110  229 110  233 111  
+34   33 54  31 53  30 53  29 52  30 52  31 52  33 52  37 52  41 52  46 52  50 52  54 53  56 54  57 57  57 60  56 65  54 71  50 76  46 82  41 88  36 93  32 97  30 100  29 102  30 103  32 102  37 100  43 99  50 97  57 97  64 97  71 98  76 98  78 99  
+9 A
+15   239 59  237 61  236 61  239 62  245 61  253 60  264 59  275 57  286 55  296 54  302 53  307 53  308 53  308 54  307 55  
+12   133 129  130 129  129 129  133 129  139 128  149 128  160 127  171 127  181 126  189 126  194 125  196 125  
+11   60 51  63 52  69 51  79 51  91 51  105 51  119 51  133 51  144 52  153 53  158 53  
+18   175 189  173 189  172 189  175 189  180 188  188 187  198 186  209 184  221 182  234 180  245 178  255 177  263 176  269 175  272 174  274 174  275 175  274 175  
+23   131 120  132 120  135 120  138 120  144 120  151 120  160 120  171 120  184 120  198 119  212 120  227 120  242 120  255 121  267 121  277 121  285 120  290 120  294 120  295 120  295 121  294 121  293 122  
+14   55 77  55 78  56 78  60 77  65 77  73 77  80 77  88 77  94 76  99 76  103 75  104 75  105 75  104 75  
+17   180 151  179 151  181 151  184 152  190 153  197 155  206 158  215 161  225 163  233 166  241 168  247 169  251 169  253 169  254 170  255 170  254 170  
+16   146 104  145 104  146 104  147 104  151 104  158 104  166 103  175 103  186 102  197 100  207 99  216 97  223 97  229 96  231 96  233 96  
+16   23 61  22 61  22 62  23 62  25 62  28 62  34 62  41 62  50 61  59 61  70 61  79 61  87 61  92 61  96 62  98 62  
+9 B
+14   288 170  287 170  285 170  281 169  276 169  269 169  260 168  249 168  240 168  231 169  224 169  219 169  217 169  216 169  
+11   234 116  232 117  229 118  224 120  218 122  210 125  202 126  194 128  187 129  182 129  179 130  
+13   193 92  192 92  191 91  188 90  185 89  179 87  172 85  164 83  156 81  148 80  142 78  138 77  137 76  
+11   297 167  296 167  293 167  289 167  284 166  277 166  270 166  264 165  260 165  257 165  256 164  
+16   202 122  203 122  201 122  198 121  192 121  184 121  174 122  162 122  149 123  136 124  124 124  116 125  109 124  106 124  105 124  106 124  
+12   126 77  125 76  122 76  118 75  113 74  107 73  100 73  94 73  88 73  84 73  81 74  79 74  
+15   321 78  320 78  318 78  315 79  310 79  304 79  297 80  289 81  280 81  272 81  265 82  260 82  257 82  256 81  257 79  
+16   216 128  215 128  214 128  211 128  207 127  201 126  193 126  184 125  174 125  163 124  154 124  145 123  139 123  136 122  133 122  132 121  
+15   123 74  122 74  121 75  118 75  115 74  110 74  103 73  96 73  88 73  80 74  74 74  69 75  67 75  66 75  67 74  
+9 N
+14   253 182  251 183  250 184  249 184  250 182  254 179  258 175  265 170  272 163  280 158  287 153  292 150  296 148  297 146  
+11   185 147  185 146  185 144  187 140  190 134  194 126  199 115  205 104  212 93  217 84  221 78  
+10   75 135  75 134  76 132  77 130  79 125  83 119  88 111  94 102  100 93  106 85  
+10   192 172  192 171  194 169  198 165  203 160  209 153  217 146  225 139  232 132  238 126  
+10   124 135  126 134  130 130  136 125  144 119  153 112  158 108  166 103  172 99  177 96  
+10   49 93  47 95  46 97  47 94  50 90  54 84  59 77  67 69  73 62  78 57  
+14   174 161  174 160  175 158  178 153  182 148  188 140  195 131  203 121  210 111  215 103  219 97  221 94  222 92  222 93  
+11   94 120  96 118  100 113  106 106  114 99  124 89  135 80  146 72  155 66  162 61  167 58  
+12   29 98  29 97  31 95  35 90  40 84  46 77  52 69  58 62  64 57  69 53  71 51  73 50  
+9 P
+23   146 162  144 162  140 162  135 161  128 161  120 161  110 161  100 161  90 162  84 162  76 162  70 162  65 162  63 162  64 162  66 163  71 163  76 163  84 163  94 162  104 161  114 162  124 163  
+20   243 111  244 111  243 111  242 110  238 110  234 109  227 109  220 109  211 110  202 111  194 112  187 114  183 115  181 116  183 116  187 116  194 116  203 115  213 115  222 114  
+18   147 71  146 71  144 70  140 69  135 69  129 68  121 68  112 69  105 70  98 70  94 71  92 71  94 72  98 72  105 72  113 72  122 71  130 70  
+21   288 147  289 147  287 147  284 147  279 147  273 149  264 151  255 154  246 157  239 159  233 161  230 162  229 162  230 162  233 162  240 161  249 160  261 157  273 155  285 152  294 150  
+21   219 126  219 125  217 125  214 125  210 124  204 123  197 123  190 122  182 122  174 121  168 121  163 121  160 121  159 122  160 122  163 123  169 123  177 123  186 123  195 123  203 122  
+19   137 92  136 92  134 91  130 89  126 87  121 85  114 82  107 80  101 79  96 78  92 77  90 78  91 79  94 80  98 82  104 84  111 86  118 88  123 89  
+25   301 155  300 155  299 154  297 154  294 154  288 154  283 154  276 154  270 155  266 155  263 156  262 156  261 156  262 156  263 156  265 156  269 156  274 156  282 156  292 155  303 155  314 154  323 153  329 153  334 153  
+24   234 117  233 117  232 117  229 116  225 115  219 115  211 116  201 117  191 118  182 119  174 120  167 121  163 121  160 122  159 122  160 122  164 121  170 120  179 119  189 118  200 117  210 117  218 118  224 118  
+20   110 82  111 82  110 82  108 81  104 80  100 79  93 79  86 79  80 79  74 80  70 80  68 81  68 82  71 82  75 82  81 82  89 81  96 80  103 80  108 79  
+9 R
+12   292 99  293 99  293 100  292 102  288 105  283 111  275 118  265 127  253 138  243 147  234 155  228 160  
+10   227 79  229 78  230 78  229 79  226 81  222 85  217 90  210 97  202 105  195 112  
+9   137 79  138 78  137 78  135 80  132 84  128 90  123 97  118 105  113 113  
+13   285 79  284 80  282 82  278 85  272 91  264 98  255 107  245 116  235 126  225 134  217 140  211 144  207 147  
+10   197 61  197 60  197 61  195 64  191 68  186 77  179 88  172 99  166 110  161 118  
+13   123 54  123 55  121 56  118 58  114 62  109 66  103 71  97 76  92 80  89 83  87 85  86 85  87 84  
+16   229 72  230 72  230 71  230 72  229 73  227 77  223 83  218 94  210 107  201 120  192 134  185 145  179 153  176 158  174 161  173 162  
+14   142 94  143 94  142 94  142 95  139 97  136 100  132 105  126 111  120 117  114 123  110 127  107 129  105 130  105 129  
+10   84 38  83 39  81 41  78 46  73 53  67 61  60 69  55 76  50 81  48 84  
+9 S
+14   255 169  256 170  257 170  257 167  257 163  256 157  255 148  253 134  252 118  250 103  249 89  248 78  247 70  246 67  
+12   213 161  213 162  212 160  211 158  210 153  209 147  208 139  207 131  206 124  205 119  205 115  205 113  
+13   140 136  140 137  140 136  140 135  139 133  138 128  137 120  136 110  134 99  131 88  129 79  127 72  126 68  
+12   239 158  240 160  240 161  240 158  241 153  241 145  242 134  243 120  244 108  245 98  245 90  246 85  
+9   154 144  153 141  153 137  153 130  154 120  154 109  155 99  157 90  157 84  
+10   82 124  82 125  82 123  82 119  82 112  83 103  83 93  84 84  85 76  85 72  
+14   210 134  210 135  210 134  209 133  209 132  209 129  210 125  210 121  211 116  211 111  212 108  212 105  213 103  213 102  
+16   142 121  142 122  142 121  142 119  142 116  142 109  142 100  143 89  143 76  144 64  144 53  144 46  144 40  144 36  144 34  145 33  
+11   62 117  63 118  63 117  63 114  63 109  63 102  63 93  64 83  65 73  67 65  68 61  
+9 U
+26   238 155  237 155  239 155  243 155  249 156  256 156  264 156  272 157  279 157  285 157  290 157  293 158  296 158  297 158  298 159  299 159  299 158  298 157  298 155  297 152  297 148  296 142  296 136  296 130  296 125  296 122  
+27   125 140  122 140  120 140  121 140  124 140  128 140  135 141  144 142  153 142  162 143  171 144  179 145  185 145  189 145  191 145  193 146  193 145  192 143  192 140  191 136  191 130  191 124  191 116  192 110  194 103  195 99  195 95  
+22   72 74  71 75  73 75  76 75  82 75  89 75  98 74  106 74  114 74  120 74  124 73  127 73  128 73  129 72  128 71  128 68  128 64  128 60  128 55  128 51  128 49  127 47  
+29   212 183  211 183  211 184  212 184  216 184  221 184  229 184  240 184  251 184  262 184  274 184  284 184  293 183  300 183  306 183  310 182  312 183  313 183  314 183  313 182  313 180  312 178  310 174  309 169  307 163  306 157  306 152  306 148  306 146  
+24   156 142  156 141  157 141  161 140  166 140  174 140  182 140  191 141  199 141  207 142  214 142  219 142  222 141  225 141  226 140  227 139  227 137  227 133  227 129  226 123  226 115  225 107  224 99  223 93  
+24   47 99  46 100  46 101  48 101  52 101  58 101  65 101  75 102  83 102  90 103  96 104  100 105  103 105  104 105  104 103  103 101  102 98  102 94  101 90  100 85  100 80  100 76  100 73  100 72  
+30   210 183  208 183  209 183  211 183  216 182  223 182  233 182  243 182  254 182  265 182  274 182  281 182  286 182  290 182  292 182  293 182  292 182  292 181  291 179  290 177  288 174  287 169  286 164  286 160  285 156  285 154  284 152  284 151  284 150  284 149  
+27   159 120  157 121  154 122  155 121  159 121  165 120  173 119  183 118  193 118  202 118  211 118  218 118  223 118  227 118  229 118  231 118  231 119  231 118  230 116  229 113  228 108  226 101  224 93  222 86  219 80  217 76  215 73  
+28   31 85  30 85  31 86  35 86  40 86  47 87  55 87  63 88  72 89  79 90  85 91  90 91  94 92  98 92  100 92  101 92  102 92  102 91  101 90  101 89  99 86  97 81  95 76  94 71  92 65  91 61  91 58  90 56  
+9 V
+34   158 185  157 185  156 184  157 184  158 184  161 184  165 183  169 182  175 179  179 176  185 171  189 166  193 161  194 156  195 152  194 149  192 148  190 147  188 148  186 149  184 151  184 153  185 156  188 158  192 160  197 159  204 158  212 154  220 148  229 142  237 136  244 130  248 124  251 119  
+37   104 168  105 168  106 167  107 166  110 164  113 161  117 157  120 152  123 146  125 142  126 137  126 134  125 132  124 131  123 131  122 131  121 132  120 133  119 135  118 137  118 139  119 142  120 144  123 146  127 147  131 148  135 146  139 144  143 140  146 136  148 129  151 121  152 112  154 102  155 94  155 88  155 84  
+31   46 135  45 135  45 136  46 135  48 134  51 132  54 128  57 124  60 118  63 112  64 106  64 101  63 98  61 98  58 99  57 102  56 107  56 111  58 114  61 116  65 116  70 114  74 110  78 106  81 100  83 95  85 91  88 87  90 84  92 82  93 80  
+38   174 186  173 184  173 183  173 182  173 181  175 181  177 181  181 180  186 177  191 174  196 170  200 166  204 161  206 157  207 153  206 150  205 148  204 147  202 146  200 147  199 147  198 148  198 150  199 151  202 153  206 153  211 153  216 151  222 148  228 143  234 137  239 129  244 121  247 113  249 110  250 104  251 101  250 101  
+32   99 170  98 170  97 171  98 170  100 170  102 169  104 168  108 166  112 162  115 157  118 152  120 146  121 142  120 138  118 136  116 136  113 136  111 138  110 141  110 143  112 146  115 147  119 147  124 146  129 142  135 138  140 133  144 128  149 123  152 118  154 114  156 111  
+30   39 127  38 127  37 128  38 128  39 127  41 126  43 124  46 121  49 117  52 111  54 105  56 99  55 95  54 92  52 91  50 92  48 93  47 96  47 100  48 102  51 105  56 106  61 104  69 100  76 94  82 88  87 81  91 76  94 72  96 70  
+36   178 189  178 188  179 188  180 189  182 189  186 189  190 187  194 184  199 180  204 175  207 169  210 164  212 159  212 156  211 153  210 152  209 152  208 153  207 154  206 155  206 157  206 158  206 160  208 162  211 164  214 164  218 164  225 163  233 160  242 155  251 148  260 141  267 133  272 128  276 124  277 122  
+40   98 162  98 159  98 158  98 157  98 156  98 157  100 157  102 158  105 158  110 158  116 158  122 156  129 153  134 149  139 144  141 139  142 135  142 130  141 127  140 126  138 125  136 125  135 125  133 126  133 128  133 130  135 131  139 131  144 130  150 127  156 122  163 115  169 106  174 97  179 87  182 78  184 70  186 65  186 61  186 59  
+32   35 109  34 110  34 111  36 111  39 110  43 107  48 103  53 98  56 92  59 85  61 79  60 75  59 71  56 69  54 68  51 69  49 72  48 76  48 80  50 84  54 87  58 87  65 84  72 80  78 74  84 68  89 62  93 56  96 52  98 49  100 47  101 46  
+9 W
+36   308 133  307 132  308 132  308 133  309 135  310 138  310 142  310 148  309 153  307 159  304 163  300 167  295 169  291 169  286 169  282 167  279 166  278 165  278 164  279 163  281 163  284 164  287 166  290 168  291 170  292 173  291 177  287 180  281 184  274 187  266 190  257 193  250 194  244 195  240 196  237 197  
+37   234 68  234 67  235 67  236 68  236 69  236 72  237 76  237 81  236 88  235 95  232 102  228 109  223 115  218 119  213 121  209 122  205 120  203 118  202 116  202 115  203 113  206 113  209 114  211 115  214 118  216 123  217 128  215 134  211 140  206 145  199 150  191 153  183 156  174 157  167 157  160 156  156 156  
+34   136 48  137 48  138 50  139 53  140 56  140 61  140 66  138 72  135 77  130 82  125 86  121 87  117 87  114 86  113 84  112 82  113 81  116 80  118 80  121 82  124 84  125 88  125 94  123 100  119 106  113 113  106 118  99 122  91 125  84 126  78 126  74 126  72 126  71 125  
+37   282 80  282 79  283 80  284 80  285 82  288 85  290 90  292 96  294 102  294 109  294 115  291 121  288 125  284 127  280 129  276 129  273 129  271 128  269 128  268 127  269 126  272 126  275 127  278 128  282 131  285 134  287 139  287 143  286 148  283 152  279 156  274 158  268 161  263 163  260 164  257 164  256 164  
+36   209 72  210 73  210 74  211 77  211 82  211 87  210 94  209 100  207 105  203 109  199 112  194 113  190 113  186 112  183 111  182 109  182 108  183 106  185 105  188 105  191 106  194 108  196 112  196 115  196 120  194 125  190 129  184 133  178 137  170 140  162 142  155 143  149 142  143 141  140 140  137 139  
+34   98 61  98 62  99 63  100 65  101 68  103 72  103 77  103 83  102 88  99 93  95 97  90 99  86 100  83 99  80 97  79 95  79 93  80 91  83 91  85 91  87 92  90 95  91 99  91 103  89 109  84 114  78 120  71 125  63 128  55 130  48 131  43 131  39 130  37 129  
+42   291 76  292 76  292 77  293 77  294 79  295 81  296 83  296 89  296 95  295 102  294 109  291 116  288 120  284 123  280 125  276 125  272 124  269 122  266 120  264 118  263 116  263 113  264 111  266 110  269 110  274 110  279 112  284 116  288 121  290 126  290 131  287 137  281 142  274 148  264 154  253 159  242 163  233 166  225 168  218 169  214 169  212 168  
+36   212 63  212 62  212 63  212 64  213 65  214 68  216 72  217 77  218 80  218 85  217 90  214 95  211 98  205 101  200 103  194 103  189 103  186 102  184 101  184 100  186 98  189 97  193 97  197 99  201 102  204 106  205 111  203 117  200 122  193 128  185 133  176 138  167 142  159 144  153 146  149 146  
+34   93 57  93 56  93 55  93 56  93 58  95 61  96 65  96 70  97 76  96 82  95 87  92 92  89 96  85 98  80 98  76 96  73 94  71 92  71 89  72 88  75 88  79 88  81 90  85 93  87 99  88 105  87 113  84 120  80 127  74 132  68 137  61 140  57 141  54 141  
+9 X
+26   335 197  335 198  336 198  335 198  334 198  332 198  328 198  323 199  316 199  308 200  300 201  293 203  286 203  282 204  279 205  277 205  276 206  276 205  276 204  276 201  276 197  277 191  277 184  277 180  278 174  278 171  
+23   234 160  234 161  234 160  232 160  229 159  225 159  218 158  211 158  202 158  193 160  185 161  178 162  173 163  170 164  168 164  168 163  167 161  167 158  167 154  167 149  168 144  168 139  169 137  
+25   152 107  152 108  151 108  150 107  148 107  145 106  140 107  134 106  127 107  119 108  111 108  105 108  99 109  96 109  94 109  93 109  93 110  93 109  93 108  93 106  94 102  95 97  96 91  97 86  97 83  
+25   307 74  306 74  305 74  302 73  298 73  295 72  290 72  282 72  273 71  257 72  249 72  244 72  241 72  240 72  239 72  238 72  238 71  238 70  238 68  237 65  237 61  237 55  237 51  237 47  237 46  
+24   260 156  258 156  256 155  253 155  249 154  243 154  237 154  230 154  223 155  217 155  213 156  209 156  208 157  207 157  207 156  207 155  207 154  208 151  208 148  209 143  209 138  208 134  208 131  207 130  
+24   134 109  133 109  133 110  131 109  129 109  126 109  121 108  115 108  108 108  100 108  93 109  88 109  83 109  80 110  79 111  78 111  79 111  79 109  80 107  81 102  82 97  83 91  84 86  84 83  
+25   262 180  262 179  261 179  260 179  257 179  253 179  249 179  243 180  236 180  228 180  220 179  212 178  203 177  196 177  190 177  185 177  182 177  180 177  178 177  178 175  179 172  180 168  181 162  182 155  183 149  
+24   265 97  263 97  261 98  257 98  253 98  247 98  239 98  232 98  225 99  219 99  215 100  212 101  211 102  210 102  210 101  210 100  209 98  208 94  208 88  207 82  206 76  206 70  205 67  205 65  
+22   113 98  112 97  111 97  109 96  105 97  101 98  96 99  89 100  83 101  77 102  72 101  68 101  65 101  63 101  62 101  63 99  63 96  63 92  64 87  64 82  64 77  64 75  
--- /dev/null
+++ b/lib/strokes/letters.clx
@@ -1,0 +1,36 @@
+a 5 0 117 27 60 61 6 86 64 108 123
+b 13 10 28 16 75 14 123 3 67 18 11 42 0 65 11 63 45 33 69 71 62 105 89 62 124 7 123
+c 5 78 23 19 17 0 81 43 126 108 105
+d 9 9 16 16 67 16 119 3 28 87 22 107 64 92 106 50 124 8 128
+e 9 95 13 67 1 37 13 28 55 68 65 23 71 20 120 61 127 103 115
+f 5 107 5 56 0 4 6 5 67 1 129
+g 11 82 18 26 10 0 69 7 99 33 124 70 124 100 96 78 76 50 76 77 74 108 69
+h 7 13 0 16 57 14 115 37 85 72 74 92 100 95 128
+i 3 50 0 56 64 58 129
+j 5 100 3 106 58 107 113 55 124 0 117
+k 5 92 0 66 66 3 93 54 88 105 128
+l 5 3 0 5 62 4 124 55 125 107 123
+m 9 0 114 4 60 24 9 41 51 48 95 59 52 83 8 102 63 108 121
+n 7 7 129 4 76 16 23 55 68 92 115 104 59 107 0
+o 7 50 4 0 74 66 124 103 88 104 43 72 8 27 12
+p 9 7 36 21 82 21 128 2 45 72 3 106 29 87 63 49 76 11 78
+q 9 41 14 1 60 23 122 55 115 74 83 72 39 36 11 68 16 108 3
+r 9 5 30 12 76 12 122 0 57 35 5 50 41 28 82 67 100 108 124
+s 7 103 13 65 2 32 33 70 67 107 101 57 128 2 111
+t 5 4 2 53 0 103 4 101 66 97 128
+u 5 0 5 12 71 57 124 104 74 105 7
+v 5 0 24 17 72 39 119 60 48 108 10
+w 9 1 14 3 69 19 123 39 99 52 70 67 95 89 119 108 64 103 5
+x 5 15 0 50 58 107 66 52 73 2 129
+y 11 10 0 4 23 15 47 44 40 73 19 85 59 87 99 58 127 20 112 56 77 104 64
+z 7 0 8 36 2 73 8 53 67 10 126 58 125 108 124
+A 3 0 66 51 63 108 61
+B 3 108 69 54 62 0 63
+N 3 0 129 48 63 108 0
+P 5 108 69 53 53 1 71 45 69 91 62
+R 3 108 0 57 63 1 128
+S 3 51 128 52 64 59 0
+U 5 0 98 53 100 106 100 106 63 103 26
+V 5 0 128 35 93 30 66 77 57 108 0
+W 5 100 0 105 47 65 62 64 110 0 128
+X 5 108 93 56 92 3 93 2 63 2 33
binary files /dev/null b/lib/strokes/punc.bit differ
--- /dev/null
+++ b/lib/strokes/punc.cl
@@ -1,0 +1,156 @@
+33
+4 !
+13   109 187  109 186  109 185  110 183  110 179  110 175  110 169  110 162  111 155  111 148  111 143  111 139  112 136  
+14   37 182  37 183  36 183  36 181  36 179  36 175  36 170  36 163  35 156  35 150  35 144  35 139  36 136  36 135  
+12   110 87  110 86  111 84  111 82  112 78  112 73  113 66  113 59  113 51  113 44  113 39  113 35  
+15   36 89  37 89  37 88  36 86  36 83  36 79  36 74  35 67  35 59  35 52  35 46  35 42  35 39  35 38  35 37  
+4 #
+44   95 125  95 124  95 123  95 125  96 128  97 133  97 139  98 145  99 150  99 154  100 156  101 155  102 152  104 148  107 143  109 137  113 132  116 127  118 123  120 120  122 117  123 116  123 115  124 115  124 116  123 117  124 119  124 121  124 124  124 129  125 134  126 139  127 144  128 148  128 152  129 156  129 159  129 162  130 163  130 165  130 164  130 163  130 160  130 156  
+38   24 112  24 111  24 112  25 115  25 119  26 125  27 133  27 141  28 148  28 153  28 156  29 157  29 156  30 153  31 149  32 144  34 138  36 132  38 127  40 123  43 119  44 116  46 115  47 114  48 114  48 115  49 117  49 120  50 124  51 129  52 134  53 140  54 145  55 150  55 153  56 155  55 153  55 151  
+40   92 28  92 27  92 28  92 29  92 31  93 35  93 40  93 47  93 53  93 59  93 62  94 64  95 63  97 61  99 57  101 52  104 46  107 40  111 35  113 31  116 27  118 25  120 23  120 22  121 21  121 22  121 24  121 27  122 32  122 37  122 43  123 48  124 53  125 57  125 60  126 62  126 63  127 64  126 63  126 62  
+40   19 27  19 29  19 33  19 38  20 44  20 49  20 55  20 61  20 65  20 67  20 68  21 66  22 63  23 59  25 54  27 50  29 45  32 39  34 35  37 31  39 27  41 25  42 23  43 23  43 24  43 25  43 28  43 31  44 35  44 41  45 47  46 53  46 58  47 62  47 65  48 66  48 65  48 64  48 63  48 62  
+4 $
+42   123 123  123 122  123 121  122 120  122 119  121 119  119 118  118 119  115 119  112 120  110 121  108 122  107 123  106 125  106 128  107 130  108 131  109 133  111 134  114 135  117 136  119 137  122 137  124 138  126 139  127 140  128 142  129 143  128 145  128 147  126 149  125 151  122 153  120 154  116 154  113 154  109 153  106 152  103 150  100 149  99 148  99 147  
+38   55 117  55 116  55 115  54 114  52 114  50 114  47 115  44 115  41 117  39 118  37 120  36 122  36 124  37 125  39 127  41 128  43 129  46 130  49 131  52 132  56 133  58 134  60 135  62 137  63 139  63 142  63 144  62 146  60 147  58 148  56 149  52 150  48 150  44 150  40 149  37 149  34 148  33 147  
+37   117 33  117 32  117 31  116 30  115 29  113 28  112 28  109 29  106 29  104 30  102 32  100 34  100 36  99 39  100 41  101 42  102 44  105 45  107 45  110 46  113 47  116 47  118 49  119 50  120 53  121 55  120 58  119 60  118 63  116 65  113 66  109 67  105 68  102 68  98 68  96 67  95 65  
+43   43 29  44 28  44 27  44 26  43 26  43 25  41 25  39 24  37 24  35 25  32 26  30 28  28 30  26 32  25 35  24 37  25 39  25 40  27 41  29 42  31 42  33 42  36 43  39 43  41 44  44 46  46 47  48 49  49 51  50 54  50 56  49 59  48 61  46 63  44 65  41 66  37 67  34 67  31 66  28 65  26 64  25 62  25 60  
+4 %
+56   26 164  25 164  26 163  27 162  28 162  30 162  32 164  35 168  37 173  40 180  41 187  42 195  41 200  40 204  38 206  37 207  36 206  35 203  35 200  35 196  37 192  40 187  43 184  47 180  51 177  55 175  58 174  61 174  63 175  65 176  66 179  68 183  69 186  70 191  71 195  70 199  70 202  69 204  67 206  66 207  64 207  64 206  63 204  63 201  63 197  65 192  67 187  70 182  73 177  77 173  80 170  84 169  87 170  89 172  91 174  92 177  
+57   96 114  95 114  96 114  96 113  97 113  99 114  101 116  102 119  104 123  105 128  105 134  105 139  103 143  102 146  101 146  100 145  100 143  99 140  99 136  99 133  100 131  101 129  103 127  105 124  109 122  112 120  115 118  117 116  118 116  119 115  120 116  121 117  122 119  123 121  124 124  125 128  125 131  126 135  126 139  125 141  124 143  123 145  122 145  121 144  120 142  121 139  122 136  123 132  125 128  127 124  130 121  133 118  137 116  140 114  143 113  145 113  146 113  
+52   25 90  26 90  27 90  29 90  31 93  33 97  35 102  37 108  38 114  38 120  38 124  37 126  36 126  35 125  33 122  33 119  32 115  32 112  33 109  35 106  38 103  42 100  45 98  49 96  52 95  55 94  56 94  57 96  58 97  59 100  59 103  60 106  61 109  61 113  61 116  61 119  60 121  59 122  58 122  57 121  56 119  56 116  56 113  57 110  59 107  60 104  64 101  67 97  71 95  74 93  76 92  78 92  
+56   23 30  24 30  25 32  27 35  28 38  30 43  31 48  31 53  31 56  31 59  30 61  29 60  28 59  27 57  27 54  27 51  27 48  28 45  30 43  32 41  34 38  37 37  39 35  41 33  44 32  45 32  47 31  47 32  48 33  50 34  51 35  52 37  53 39  54 42  55 45  56 48  56 51  55 54  54 57  53 60  52 62  51 62  50 61  50 59  50 55  51 51  52 46  54 42  56 38  59 36  62 34  64 32  67 32  69 32  71 33  72 34  
+4 &
+41   126 139  126 138  126 137  125 136  123 136  121 135  117 135  112 136  108 137  104 139  101 142  99 144  99 147  101 150  104 153  108 155  112 158  117 162  121 165  124 169  127 172  128 176  128 180  126 182  123 183  119 184  114 183  109 182  104 180  101 177  99 174  100 169  103 165  107 160  113 154  118 150  122 145  125 142  126 139  125 136  123 135  
+42   51 138  51 137  51 136  50 136  49 135  48 134  46 134  43 135  39 137  36 138  33 141  32 144  32 146  33 148  35 151  38 152  42 154  46 157  50 159  53 163  55 166  56 169  55 172  53 175  49 177  46 178  42 178  39 176  37 173  36 170  36 166  38 161  41 157  44 153  48 150  52 146  54 142  55 140  55 137  53 136  51 135  48 135  
+40   113 44  112 44  112 43  111 43  109 42  107 42  104 43  101 44  98 46  95 48  93 50  93 53  93 56  95 58  97 61  101 63  105 65  109 67  112 69  115 72  117 75  117 77  116 80  113 82  110 84  107 84  103 84  100 83  98 80  97 77  97 73  98 69  101 66  104 61  108 57  111 53  114 49  115 45  115 43  113 43  
+40   45 40  45 39  44 39  44 38  43 37  41 36  38 37  35 37  32 39  29 41  27 43  25 46  24 49  25 51  26 53  29 55  31 56  35 58  38 60  41 62  43 65  45 68  45 71  44 75  42 78  39 79  35 80  33 79  31 77  30 74  30 70  32 65  35 61  39 56  43 53  46 49  48 46  48 43  47 41  45 41  
+4 '
+12   110 132  111 134  111 137  111 141  110 147  110 154  110 161  110 166  110 171  110 174  111 175  111 176  
+14   37 128  37 127  37 128  37 131  36 135  36 142  36 151  35 160  35 167  35 173  36 176  36 177  36 176  37 175  
+12   109 34  110 36  110 38  110 42  111 47  111 53  111 60  111 66  111 71  111 74  111 76  111 77  
+14   33 33  33 34  34 36  34 39  34 43  33 48  33 54  33 59  32 65  32 69  32 72  32 74  33 75  33 76  
+4 +
+28   133 117  134 116  134 117  134 118  133 120  132 124  131 128  128 132  125 137  121 142  117 145  112 146  108 146  104 146  101 144  99 142  98 140  98 138  100 136  104 135  109 135  115 135  121 137  127 138  131 140  135 141  137 142  138 142  
+28   59 115  59 114  58 114  58 115  58 116  56 118  55 122  52 126  49 130  45 135  40 139  35 142  30 144  26 145  22 144  20 144  20 142  21 140  23 138  28 137  32 137  38 137  43 139  48 142  51 144  54 147  56 148  58 149  
+24   122 31  122 32  121 34  120 36  119 40  116 45  114 49  110 53  106 55  102 57  99 57  95 56  93 54  92 52  92 50  94 49  97 48  101 48  106 49  111 50  115 52  118 54  121 56  122 57  
+26   47 29  48 29  47 31  47 33  45 36  43 39  40 44  36 48  32 52  28 55  24 58  20 59  17 59  16 58  15 57  16 55  18 54  21 53  25 53  30 53  34 54  39 56  43 58  46 59  49 61  51 61  
+4 ,
+11   128 139  127 139  126 140  125 142  122 145  118 149  115 154  111 159  107 164  105 167  104 169  
+13   54 136  54 137  54 138  54 140  53 143  52 147  51 151  49 155  46 159  43 162  40 163  38 165  37 165  
+9   114 50  114 51  112 53  109 55  104 58  100 62  95 66  92 69  90 71  
+11   47 45  47 46  47 47  46 49  46 52  44 56  42 60  39 65  36 69  33 71  30 74  
+4 /
+10   94 185  95 183  96 180  98 175  101 169  105 162  109 155  113 149  116 145  118 143  
+12   41 181  40 182  41 179  43 176  45 171  49 165  53 159  58 152  60 148  63 144  65 141  66 140  
+11   98 78  98 77  99 76  100 73  102 70  106 65  109 60  113 54  117 50  120 46  122 44  
+11   31 72  31 73  31 72  32 70  34 66  37 62  40 57  44 51  48 46  51 43  53 40  
+4 <
+29   127 178  127 177  126 177  125 176  124 176  123 175  122 174  119 172  116 169  113 166  109 163  105 159  102 156  100 154  98 153  98 152  98 151  99 151  100 151  102 150  105 149  108 147  113 144  117 141  123 138  127 135  131 133  133 132  135 132  
+23   60 173  59 172  57 171  56 169  54 168  51 166  47 163  43 160  40 157  37 155  35 154  34 153  35 154  36 154  37 153  40 152  43 151  47 148  51 146  54 144  58 141  61 140  64 139  
+26   126 88  126 89  125 88  124 87  123 86  120 84  116 82  112 80  107 78  102 76  98 74  95 74  94 74  95 74  96 74  98 73  100 72  103 70  107 68  112 65  118 62  123 59  128 57  131 55  133 54  134 54  
+24   50 85  49 84  48 83  47 82  45 80  42 77  38 74  33 71  28 69  24 67  21 65  19 64  20 63  22 62  26 62  30 61  36 60  42 59  49 57  55 55  60 53  63 52  65 51  66 51  
+4 =
+34   97 132  97 131  98 131  100 131  103 131  107 131  112 130  118 130  123 129  126 128  128 129  129 130  129 131  127 134  125 137  122 142  118 147  115 153  111 159  108 165  105 170  103 174  101 176  101 177  101 178  103 177  106 176  110 175  115 174  121 173  126 173  131 173  134 173  136 173  
+32   26 128  26 127  28 127  30 127  33 127  37 127  41 127  45 126  48 126  50 126  51 126  50 128  49 131  48 134  45 138  42 144  38 150  35 156  31 162  28 168  26 172  25 175  25 176  27 176  31 175  35 174  39 173  44 173  48 173  52 173  54 173  56 173  
+31   102 36  101 36  102 35  104 35  107 34  111 34  115 33  120 32  125 32  128 32  130 33  131 34  130 37  128 40  126 45  122 49  119 54  115 59  111 64  109 67  107 70  107 72  108 73  109 73  113 72  118 71  123 70  128 69  133 69  137 69  140 69  
+31   23 35  22 35  23 35  25 34  28 33  33 32  38 31  43 30  47 30  50 30  51 31  52 32  51 35  49 38  46 43  43 48  40 53  37 58  34 63  32 66  31 68  31 70  32 70  35 70  38 70  43 69  47 68  52 68  56 68  59 68  61 68  
+4 @
+30   116 130  116 129  116 128  116 127  114 128  112 128  111 129  108 131  104 135  102 139  100 144  100 149  101 154  103 159  106 163  110 165  115 166  119 164  124 160  128 156  131 150  132 145  132 140  131 136  127 132  123 130  118 129  114 129  111 130  109 132  
+31   51 124  51 123  50 122  50 121  49 120  48 119  45 119  42 120  39 122  36 125  33 129  30 135  29 139  29 145  30 150  33 155  37 158  41 160  46 160  52 159  56 156  60 151  63 146  64 141  64 135  63 131  60 127  56 125  52 124  49 123  46 124  
+29   115 46  115 45  114 45  112 45  110 46  107 48  104 50  101 54  99 58  98 63  98 67  99 72  102 75  106 77  110 78  116 78  121 76  126 73  129 69  132 64  134 59  134 54  132 49  129 46  125 43  121 42  117 42  113 44  110 46  
+30   39 40  39 39  38 39  37 39  35 40  32 41  29 42  27 45  24 48  23 52  23 57  25 61  27 66  30 69  34 71  39 71  44 70  49 67  53 63  57 58  60 54  61 50  61 46  60 42  56 40  52 38  47 38  43 38  38 40  35 42  
+4 ^
+26   94 185  93 185  93 183  94 181  95 176  97 170  99 164  101 157  103 151  105 146  106 142  108 140  109 140  110 141  111 143  113 146  116 151  118 158  121 166  124 174  126 180  128 185  129 189  130 190  131 191  131 192  
+21   26 165  27 162  28 158  29 154  31 149  33 143  36 138  39 134  41 130  43 127  45 126  47 127  48 129  49 132  51 137  53 144  55 150  57 156  59 160  61 164  62 166  
+24   92 81  91 82  92 81  92 79  94 76  96 71  99 66  102 60  105 54  108 49  111 45  112 42  114 41  115 41  116 44  118 47  119 53  121 59  122 66  124 72  125 78  127 81  128 84  129 85  
+23   22 75  21 75  22 73  23 71  24 67  27 62  29 55  33 49  36 44  39 39  41 36  43 33  45 33  46 34  46 36  47 40  49 45  51 51  53 57  54 63  56 67  58 70  59 73  
+4 |
+21   89 170  89 169  88 169  88 167  88 163  88 158  89 152  89 145  89 139  89 134  89 132  88 135  88 140  87 147  87 155  87 162  87 168  87 173  87 176  87 177  86 176  
+24   36 178  36 177  36 176  35 173  35 169  34 164  34 157  33 153  33 146  33 139  33 135  33 132  33 131  34 134  34 138  35 144  35 152  35 160  35 167  35 173  35 176  35 178  36 177  36 176  
+21   87 82  87 81  87 79  87 74  88 69  88 62  89 55  90 48  90 42  90 38  90 37  90 40  90 44  90 51  91 59  92 66  92 73  93 79  93 83  93 85  93 84  
+24   31 88  31 87  31 86  31 84  31 81  31 77  31 72  31 65  31 60  31 53  31 46  30 42  30 40  30 43  30 47  31 53  32 60  33 66  34 72  35 77  36 80  36 81  35 81  35 79  
+4 ~
+40   123 121  123 120  122 120  122 122  122 126  122 131  122 137  122 144  122 152  122 159  121 166  121 170  120 174  120 175  119 175  119 173  118 169  117 164  116 158  115 151  113 144  111 137  108 132  106 128  103 125  101 124  99 125  97 125  96 126  95 128  95 130  95 133  95 138  95 144  94 150  93 157  92 163  92 167  91 170  90 171  
+41   60 117  61 117  61 118  60 120  60 123  60 128  59 135  58 143  56 152  55 159  54 165  54 169  53 171  53 170  53 167  52 164  50 159  48 153  45 146  42 139  40 133  37 128  35 125  34 123  33 123  32 123  32 124  32 126  32 128  32 132  31 136  31 142  30 149  29 155  27 162  26 168  24 173  23 176  22 179  22 180  22 179  
+39   121 25  120 25  120 26  120 27  120 29  119 33  118 37  117 43  116 49  115 55  114 60  113 63  113 65  112 64  112 62  111 59  110 55  108 49  105 43  103 38  101 33  98 29  97 26  95 25  94 26  93 27  93 28  92 30  92 32  92 35  92 38  92 44  91 49  91 55  90 61  90 65  89 69  89 70  88 70  
+37   47 23  47 24  47 27  47 30  47 34  47 40  47 46  47 52  46 57  46 62  46 65  45 67  44 66  43 64  41 61  39 58  38 55  35 50  32 45  30 39  29 35  28 30  26 28  26 26  25 25  25 27  24 28  23 30  22 34  22 39  21 44  20 51  20 57  20 63  20 67  21 70  21 72  
+4 ?
+29   29 38  28 38  27 38  27 37  27 36  28 35  29 33  32 31  36 29  40 28  45 27  49 27  53 28  56 31  57 34  57 37  56 41  54 45  51 49  48 53  44 57  42 61  39 65  38 68  38 71  38 73  38 76  38 77  39 77  
+30   95 36  94 36  93 36  93 35  93 34  94 32  95 30  96 28  99 26  102 25  106 25  110 26  113 28  115 30  116 33  116 36  114 40  113 44  111 48  109 51  107 54  106 57  106 59  107 62  107 66  107 69  108 71  108 73  108 74  108 75  
+26   35 134  34 133  33 132  33 130  34 129  35 127  38 125  42 124  46 123  50 122  54 122  57 123  59 125  59 128  59 131  58 135  56 139  53 142  51 146  50 150  49 153  49 157  49 159  49 162  49 163  49 165  
+31   99 139  99 140  99 139  99 138  99 137  99 135  99 132  100 130  101 127  104 125  107 123  110 122  114 122  118 122  120 124  122 127  123 130  122 134  121 138  119 142  117 146  115 150  114 153  113 157  112 160  112 163  112 166  112 168  113 170  113 171  114 172  
+4 >
+26   25 92  25 93  26 92  28 90  31 87  34 84  38 81  43 77  47 75  51 72  54 70  55 69  56 69  56 68  55 68  54 67  51 66  49 64  45 62  40 60  35 59  29 57  25 55  21 55  20 55  21 55  
+25   96 100  95 101  96 100  98 99  101 97  105 94  110 92  113 90  118 87  122 85  125 83  127 82  127 81  126 80  125 80  124 80  123 80  120 79  117 77  113 75  109 73  103 71  99 68  95 65  92 64  
+30   32 184  31 184  32 184  33 182  36 180  40 177  46 174  52 170  59 166  66 163  71 161  74 160  75 159  74 159  73 160  72 160  70 160  69 160  67 160  66 158  63 156  59 154  56 152  51 149  47 147  42 146  39 145  36 145  35 146  36 147  
+28   108 197  107 198  108 198  109 198  112 196  116 194  121 191  126 187  132 184  136 182  139 180  141 180  142 179  141 180  141 181  140 181  139 181  138 181  137 180  135 178  133 176  130 174  126 170  122 167  117 163  114 159  110 157  108 156  
+4 )
+16   27 28  28 29  29 30  32 32  35 35  38 41  41 48  42 56  42 63  41 69  39 74  37 77  35 79  33 81  32 81  31 81  
+14   91 28  91 29  93 30  96 32  99 35  103 39  105 46  106 54  105 61  104 68  101 74  99 78  96 80  94 82  
+17   34 124  33 124  34 124  36 125  39 127  42 131  46 137  49 144  51 151  52 158  51 165  50 170  48 173  46 175  44 176  42 177  41 177  
+18   98 128  97 127  97 128  98 129  101 132  104 135  108 140  111 146  113 152  114 157  114 164  112 170  108 176  105 180  101 184  98 186  96 187  94 188  
+8 (
+117   159 21  158 22  158 23  157 24  156 24  156 25  156 26  155 26  155 27  154 27  154 28  153 28  153 29  153 30  152 30  152 31  151 32  151 33  150 33  150 34  150 35  149 36  148 37  148 38  147 39  147 40  146 41  146 42  146 43  145 44  145 45  144 46  144 47  144 48  144 49  144 50  143 50  143 51  143 52  143 51  143 52  143 53  142 53  142 54  142 55  142 56  142 57  142 58  141 59  141 60  141 61  141 62  141 63  141 64  140 64  140 65  140 66  140 67  140 68  140 69  140 70  140 71  140 72  140 73  140 74  140 75  140 76  140 77  141 78  141 79  141 80  141 81  141 82  142 83  142 84  142 85  142 86  143 86  143 87  143 88  144 89  144 90  144 91  145 92  145 93  145 94  146 94  146 95  146 96  147 96  147 97  148 97  148 98  149 99  149 100  150 100  150 101  151 101  151 102  152 103  152 104  153 104  153 105  153 106  154 106  154 107  155 107  156 107  156 108  157 108  157 109  158 109  158 110  159 110  159 111  160 111  160 112  
+101   63 19  63 20  62 20  62 21  62 22  61 22  61 23  60 23  60 24  60 25  59 25  59 26  58 26  58 27  58 28  57 28  57 29  57 30  56 30  56 31  56 32  55 32  55 33  55 34  54 34  54 35  54 36  53 37  53 38  52 38  52 39  52 40  52 41  51 41  51 42  51 43  51 44  51 45  51 46  51 47  50 47  50 48  50 49  50 50  50 51  50 52  50 53  50 54  50 55  50 56  50 57  50 58  50 59  50 60  50 61  50 62  50 63  50 64  50 65  50 66  50 67  50 68  50 69  50 70  50 71  50 72  50 73  50 74  51 74  51 75  51 76  52 77  52 78  52 79  53 80  54 81  54 82  55 82  55 83  56 84  57 85  57 86  58 86  58 87  59 88  60 89  60 90  61 90  61 91  63 92  64 93  65 93  65 94  66 94  67 94  68 94  68 95  69 95  70 95  70 96  71 96  
+15   39 27  38 27  38 26  36 27  35 27  33 29  30 32  28 38  26 45  25 53  26 60  27 67  28 72  31 75  32 77  
+13   113 27  112 27  110 28  108 30  105 34  102 40  99 48  98 57  97 66  98 73  99 77  101 80  103 81  
+16   46 124  45 123  44 123  43 123  41 125  38 127  35 131  32 137  29 144  27 152  27 160  28 166  30 172  33 176  35 177  37 178  
+17   113 128  113 127  112 127  111 127  109 128  107 131  104 136  101 142  99 150  98 159  98 166  98 173  100 177  102 180  105 182  106 183  107 183  
+40   50 24  50 25  49 26  49 27  49 28  49 29  49 30  49 32  47 33  47 35  45 37  45 40  44 42  43 45  43 47  43 50  43 52  43 54  43 55  43 57  43 59  43 60  43 61  44 63  43 61  44 63  45 64  45 65  47 66  47 67  48 68  49 69  50 69  51 70  52 71  53 71  53 72  54 72  55 72  55 73  
+40   140 25  139 27  138 28  137 29  135 31  134 33  133 34  132 36  131 37  129 39  128 41  126 44  124 46  122 49  121 51  119 53  118 55  117 58  116 60  115 63  115 65  115 68  115 71  115 73  116 75  117 78  118 80  119 82  121 83  122 85  124 87  125 89  127 90  128 91  129 92  130 92  131 93  132 93  133 93  133 94  
+4 .
+21   133 137  133 138  132 138  130 139  126 139  122 139  116 139  109 139  103 140  98 141  94 142  91 143  92 143  95 142  100 141  107 140  115 139  124 138  131 138  137 138  140 138  
+21   61 137  61 136  60 135  58 135  55 134  51 134  46 134  41 136  36 137  32 139  29 140  29 141  30 140  34 140  40 139  46 138  53 138  59 138  65 138  68 137  70 138  
+19   126 50  125 50  124 50  122 51  119 51  115 51  111 51  105 52  99 52  95 53  92 53  91 53  92 54  96 54  101 53  106 53  112 52  116 52  120 52  
+18   56 54  54 54  53 54  50 54  46 54  41 55  37 55  33 56  30 56  29 56  30 57  32 57  35 57  39 57  43 57  47 57  50 57  52 57  
+4 -
+12   87 151  88 151  91 151  96 151  103 150  111 150  118 150  124 149  129 149  132 150  134 150  133 151  
+12   23 131  22 131  23 131  25 131  29 130  34 129  41 129  49 129  57 129  65 130  70 130  74 131  
+12   108 62  107 62  105 62  107 62  111 62  116 62  123 62  131 61  139 61  146 61  151 60  153 60  
+14   27 60  25 60  24 60  23 60  25 59  27 59  33 59  40 58  47 58  56 57  63 57  70 57  74 57  76 57  
+4 T
+68   39 103  39 102  39 101  39 100  39 99  39 100  39 99  39 98  38 97  38 95  38 94  38 92  38 91  37 89  37 88  37 87  37 85  37 84  37 83  37 81  37 80  37 79  37 78  37 77  37 75  37 74  37 73  37 72  37 71  37 70  37 69  37 68  37 67  37 66  37 65  37 64  37 63  38 62  38 61  38 60  38 59  38 58  38 57  38 56  38 55  38 54  38 53  39 53  40 53  42 53  44 53  46 53  49 53  51 54  53 54  55 54  57 54  59 54  61 54  62 54  63 54  64 54  65 53  66 53  67 53  68 53  69 53  70 53  
+45   112 99  112 98  112 97  112 95  112 93  112 91  112 87  111 84  111 81  111 77  110 74  111 77  110 74  110 72  110 69  110 68  110 66  110 65  110 63  110 62  110 61  110 59  110 58  110 56  110 55  110 54  110 53  111 53  114 54  116 54  120 55  123 55  125 55  128 55  130 55  132 55  133 55  134 55  136 55  137 55  138 55  139 55  140 55  141 55  142 55  
+57   32 191  32 190  33 189  33 187  33 185  33 183  34 181  34 179  34 177  34 175  34 173  34 170  34 169  34 167  34 165  34 164  34 163  34 162  34 160  34 159  34 158  34 157  34 156  35 156  35 155  35 154  35 153  35 152  35 151  36 151  36 150  36 149  36 148  37 147  37 146  37 145  38 145  38 144  39 144  41 144  43 145  46 145  50 145  54 145  58 145  61 145  64 145  65 145  66 145  67 145  68 145  69 145  70 145  71 145  72 144  73 144  74 144  
+51   108 190  108 189  108 187  107 185  107 183  107 181  107 179  107 177  107 175  107 173  107 171  107 173  107 171  107 169  107 167  107 165  108 163  108 161  108 159  108 158  108 156  108 155  108 154  108 153  108 152  108 151  108 150  109 149  109 148  109 147  109 146  109 145  109 144  109 143  110 143  110 142  110 141  110 140  110 139  111 138  112 138  114 138  117 138  121 138  125 138  129 139  133 139  137 139  140 139  142 139  143 139  
+4 _
+69   17 55  18 55  19 55  20 55  22 55  23 55  26 55  28 55  31 55  34 56  37 56  40 57  43 57  46 57  48 58  50 58  52 58  53 58  54 58  55 57  56 57  57 57  58 57  59 57  60 57  61 57  63 57  65 57  67 56  69 56  71 56  71 57  70 57  69 57  67 57  64 57  62 57  58 57  56 57  54 57  52 57  50 57  49 57  48 57  47 57  46 57  45 57  44 58  42 58  41 58  40 58  41 58  40 58  39 58  38 58  37 58  36 58  35 58  34 58  32 58  31 58  31 59  30 59  29 59  28 59  27 59  26 59  25 59  24 59  
+44   98 78  99 78  101 78  104 78  107 78  110 78  114 78  121 78  125 78  128 78  131 78  133 78  135 78  137 78  138 78  139 78  138 78  137 78  136 78  134 78  131 78  129 78  126 78  124 79  122 79  120 79  117 79  115 78  113 78  111 78  110 78  108 78  108 79  107 79  106 79  105 79  104 79  103 79  102 79  101 79  100 79  99 79  98 79  97 79  
+26   21 124  22 124  24 124  28 125  32 125  39 125  46 126  59 126  69 126  76 127  80 127  83 127  84 127  85 127  85 128  84 128  80 128  76 128  66 128  59 127  52 127  45 126  41 125  38 125  35 124  34 124  
+36   86 165  86 164  87 164  89 164  91 164  93 163  96 163  99 164  102 164  106 164  109 163  106 164  109 163  112 164  116 164  120 164  123 164  125 164  126 164  126 165  125 165  123 165  122 165  120 165  118 165  116 165  114 165  112 165  109 165  102 164  95 163  88 163  84 162  82 162  80 162  81 162  
+2 *
+57   35 128  35 129  38 131  41 134  44 137  46 139  49 141  51 143  53 145  56 147  60 148  63 149  66 150  69 150  73 149  76 147  79 146  81 143  83 141  85 139  86 137  87 135  87 134  87 133  86 133  86 132  85 132  83 132  82 133  79 133  76 134  73 135  69 135  67 136  63 137  61 138  59 139  58 139  57 140  55 141  54 142  53 143  51 145  50 146  49 147  48 148  47 149  46 150  45 152  43 153  41 155  39 157  38 158  37 159  36 160  35 161  34 162  
+56   26 38  26 39  26 40  26 41  26 43  27 46  27 49  28 52  29 55  30 57  31 60  33 63  35 66  37 68  39 70  43 71  47 72  51 73  58 73  65 73  68 73  71 72  73 71  75 69  76 68  77 66  77 65  78 65  78 64  77 63  76 63  75 62  75 63  73 63  71 63  68 64  65 65  62 65  59 66  56 67  53 68  51 69  48 70  46 71  45 72  43 73  41 74  40 75  39 76  38 77  37 78  35 79  34 81  33 81  33 82  33 83  
+2 `
+33   90 187  90 186  90 185  89 185  89 184  89 183  88 181  87 180  86 178  85 175  83 172  82 169  80 165  77 161  75 157  73 154  71 151  70 148  69 147  68 145  67 145  66 145  67 145  67 148  69 151  72 155  75 162  78 169  81 176  83 180  84 183  85 184  85 185  
+37   69 103  69 102  69 101  68 101  67 99  67 98  66 96  65 94  65 92  64 90  62 87  61 84  60 81  59 78  59 75  58 73  58 70  57 68  57 67  57 66  57 67  58 68  59 70  60 72  62 76  64 79  66 83  68 86  69 89  70 92  71 94  72 96  73 98  74 99  75 100  75 101  76 102  
+2 ;
+40   113 53  113 54  113 56  111 59  109 63  107 66  105 70  103 73  101 77  99 81  97 84  95 86  93 88  92 90  91 91  89 93  88 94  88 95  87 95  87 94  88 93  89 92  90 90  92 88  93 85  95 82  97 79  99 75  101 72  103 69  104 66  105 64  105 63  106 62  107 61  108 60  109 58  111 57  112 55  113 54  
+34   71 32  71 33  71 34  69 36  67 39  64 42  61 46  57 50  53 54  50 58  48 61  47 64  46 66  45 68  46 67  47 67  47 66  48 64  49 62  50 59  52 57  54 54  56 51  59 47  61 45  64 42  67 39  71 37  78 34  82 32  86 30  89 28  91 27  93 25  
+2 :
+32   100 31  101 32  101 34  102 37  102 40  103 44  104 48  104 55  105 59  106 63  106 66  107 68  107 70  107 71  108 72  108 73  107 73  107 72  107 71  107 69  108 67  108 65  108 62  108 59  108 56  108 52  108 48  109 45  109 42  108 40  108 39  107 39  
+35   36 26  36 27  36 28  36 30  37 33  37 37  38 41  38 48  38 55  38 59  39 63  39 66  39 69  39 72  38 73  38 74  39 73  39 72  39 69  40 65  41 61  41 57  42 50  42 46  43 39  43 35  43 32  43 29  43 27  43 26  43 27  43 26  43 25  43 26  43 27  
+3 F
+12   184 33  183 32  183 31  185 33  187 36  189 41  192 47  195 55  198 62  200 67  203 72  205 74  
+14   112 34  111 33  112 33  113 34  114 38  117 43  120 50  122 57  125 64  128 69  129 72  131 74  132 75  132 74  
+13   43 37  42 37  42 39  44 41  47 45  49 50  53 56  56 61  59 67  62 70  63 73  64 74  65 74  
+3 G
+41   219 44  219 43  218 42  217 41  216 40  215 40  214 39  212 39  211 40  209 41  206 42  203 44  201 47  198 50  196 54  195 58  195 63  196 66  199 69  201 71  205 72  208 72  211 72  212 71  213 71  213 70  211 71  209 71  206 73  202 75  199 77  196 80  194 83  194 87  194 91  196 94  199 96  203 98  207 98  211 98  215 97  
+40   145 43  145 42  145 40  144 39  142 38  139 38  136 39  132 41  128 44  124 47  121 51  120 54  119 58  120 61  122 64  124 65  127 66  129 66  131 65  133 64  134 63  134 62  133 61  132 61  130 62  128 63  125 65  122 67  119 70  117 73  116 76  117 80  118 83  121 86  124 87  129 88  134 87  138 86  142 85  145 84  
+43   62 44  62 43  63 43  63 42  63 41  62 40  61 38  60 37  58 37  55 37  52 39  49 41  46 43  44 47  42 51  41 56  41 61  42 65  44 68  46 71  48 72  50 72  52 71  53 70  54 69  53 68  53 67  51 67  50 67  48 68  45 70  43 72  41 74  38 80  38 84  39 87  41 90  44 93  48 94  52 94  56 93  60 91  63 90  
+3 H
+41   215 55  214 55  213 54  214 53  215 51  217 50  219 48  223 46  227 45  230 45  234 47  236 50  238 54  237 59  235 63  232 67  228 70  225 73  223 74  222 75  221 75  222 75  223 74  226 74  228 74  231 75  234 76  237 79  239 82  240 85  240 89  239 92  237 95  233 97  230 99  224 100  219 101  213 101  208 100  204 98  201 96  
+40   135 54  134 54  133 54  134 53  135 52  137 50  140 49  144 48  148 49  152 50  155 53  157 56  157 60  156 64  154 68  151 71  149 73  146 75  144 76  143 77  143 76  144 76  146 75  148 75  150 76  153 77  155 78  157 80  158 83  159 85  158 88  157 90  154 93  152 94  148 95  144 96  139 96  135 96  131 95  128 94  
+41   52 52  52 51  51 51  52 50  52 49  53 47  55 45  57 44  60 43  64 44  68 45  72 48  74 50  75 54  74 56  73 59  71 62  68 64  66 66  65 67  65 68  66 68  67 68  69 67  71 68  72 69  74 71  76 74  78 77  79 81  79 84  78 87  75 89  72 91  67 93  62 94  55 94  50 94  45 93  42 91  41 90  
+3 I
+50   223 96  224 96  224 97  223 98  222 99  221 101  219 102  216 104  214 106  210 106  207 106  203 104  199 103  195 101  192 98  189 96  187 93  186 90  186 87  188 85  190 84  194 83  198 82  202 82  205 83  208 83  210 84  211 84  211 85  210 85  209 85  207 85  204 85  200 84  196 84  190 83  185 83  180 82  177 81  174 79  174 76  176 73  180 70  185 67  191 63  197 61  202 59  207 59  210 59  211 60  
+50   152 94  152 95  151 96  149 98  147 99  144 100  139 102  134 104  128 105  122 105  118 104  114 102  112 100  111 97  111 94  113 91  115 88  118 85  121 83  125 82  128 81  131 81  133 82  135 83  136 84  136 85  136 86  135 86  134 87  133 86  131 86  128 85  124 84  121 82  117 80  113 79  109 76  106 74  103 72  102 70  103 69  105 67  109 64  114 62  121 60  128 57  134 56  139 56  142 56  145 57  
+47   64 95  64 96  64 97  63 97  62 99  60 100  57 101  54 101  50 102  46 101  42 100  38 98  35 96  32 92  31 89  31 86  32 83  35 80  37 79  41 78  46 77  50 77  54 78  56 79  57 79  58 80  57 80  56 80  54 80  51 79  47 78  44 77  39 75  36 73  32 70  30 67  29 64  29 61  30 57  34 54  39 51  44 50  50 49  56 49  61 51  65 52  67 54  
+3 J
+52   208 104  207 104  206 104  206 105  207 106  209 107  212 108  216 109  221 109  226 109  231 108  235 106  239 104  241 101  243 98  243 95  242 92  239 90  235 88  231 87  227 87  223 88  220 88  218 89  217 89  217 90  218 90  220 90  222 90  225 90  227 89  231 88  234 87  237 86  239 84  242 82  243 79  245 76  245 72  244 68  241 64  238 60  233 58  226 56  219 56  213 58  207 60  204 63  202 67  202 70  203 72  206 74  
+48   126 101  124 100  123 100  122 100  121 101  122 101  123 102  125 103  128 104  132 104  138 103  143 101  148 99  153 96  156 93  157 89  158 87  157 84  155 82  151 80  149 79  145 79  142 79  139 79  137 79  135 79  136 79  137 79  140 78  144 78  147 77  152 75  156 73  159 71  161 69  163 66  163 64  163 60  161 56  158 53  154 50  151 49  145 48  139 48  133 49  128 51  124 53  122 55  
+49   42 95  41 96  40 97  41 98  42 100  43 101  46 102  49 103  53 103  58 103  62 102  67 100  71 97  73 94  75 90  75 87  75 84  73 82  71 80  68 78  65 78  63 77  60 77  58 78  57 78  56 78  56 79  57 79  58 79  60 78  63 77  66 76  70 75  73 72  75 71  77 68  78 65  77 62  76 59  73 56  70 54  66 52  61 51  56 50  52 51  47 51  45 52  44 52  44 53  
+3 K
+35   200 146  199 145  199 144  198 142  198 140  197 136  197 131  197 127  197 122  197 117  197 114  197 112  198 112  199 114  201 117  203 121  206 126  209 131  213 137  217 141  220 144  224 145  227 146  229 145  230 144  231 143  231 141  232 138  231 135  231 130  230 124  230 118  229 112  228 108  227 104  
+35   137 85  137 84  137 82  137 80  136 77  136 73  136 67  135 61  135 54  135 49  135 44  135 42  136 41  137 43  139 46  141 50  144 56  147 63  151 69  155 75  158 80  161 82  164 83  166 84  167 82  169 80  170 76  171 71  171 65  171 57  171 49  171 42  171 36  170 32  170 30  
+37   44 83  44 84  43 83  43 81  43 78  42 74  42 69  41 63  41 57  40 52  39 48  39 45  39 44  40 45  41 47  43 51  46 55  50 60  53 66  57 70  60 73  63 75  65 77  66 77  67 77  68 76  69 74  69 73  69 69  69 65  68 59  68 53  67 46  67 39  67 34  67 31  67 29  
--- /dev/null
+++ b/lib/strokes/punc.clx
@@ -1,0 +1,33 @@
+! 3 54 128 53 64 55 0
+# 7 0 12 6 61 14 110 43 62 83 14 97 64 108 116
+$ 7 85 14 50 3 15 33 69 62 104 103 56 127 3 116
+% 9 0 30 20 63 15 96 20 61 55 41 69 69 64 97 70 59 108 38
+& 9 82 9 48 4 20 30 58 67 89 111 47 126 33 85 67 47 81 7
+' 3 53 0 54 64 54 128
++ 5 105 12 69 86 1 102 50 86 108 116
+, 3 108 0 63 70 0 128
+/ 3 10 128 49 64 98 0
+< 5 83 128 43 92 2 60 53 30 107 0
+= 7 0 10 41 3 83 3 51 64 14 126 60 121 108 120
+@ 7 54 10 0 67 55 122 96 89 107 46 82 8 39 11
+^ 5 0 122 21 60 59 2 85 62 108 126
+| 5 54 128 52 64 51 1 53 63 58 126
+~ 7 101 0 96 57 87 115 61 62 31 12 15 70 7 129
+? 5 18 34 44 2 88 9 69 69 57 128
+> 5 6 128 54 93 103 60 55 27 3 0
+) 3 34 0 75 64 44 128
+( 3 76 0 35 65 64 128
+. 5 108 57 54 58 0 70 52 68 106 65
+- 3 0 67 54 63 108 63
+T 5 3 128 1 72 4 15 51 2 108 1
+_ 5 0 62 54 63 108 64 58 65 8 64
+* 5 0 14 43 80 108 58 58 66 9 114
+` 5 79 128 51 64 25 1 55 61 83 121
+; 5 83 13 45 71 3 124 45 60 108 3
+: 5 40 0 51 65 58 127 65 71 67 12
+F 3 19 0 54 64 90 128
+G 9 91 13 89 6 81 1 28 33 55 73 36 78 20 109 51 128 88 122
+H 9 35 19 54 0 82 5 93 36 67 66 100 91 78 124 43 128 8 120
+I 9 108 104 60 126 18 92 44 69 77 71 38 66 0 39 44 7 94 3
+J 9 8 115 51 126 92 95 75 75 50 72 95 51 84 8 45 1 7 18
+K 7 12 128 4 80 4 33 44 84 96 119 105 60 100 0
--- /dev/null
+++ b/lib/tbsetup
@@ -1,0 +1,22 @@
+#
+# This file defines the format of the toolbar
+#
+#The entries are 2 ":" separated fields
+#<Button Label/Bitmap>:<application path>
+!EXEC=/dis/plumber.dis -w
+!EXEC=/dis/svc/cs/cs.dis
+!EXEC=/dis/dbfs.dis -e /data/vmails /mnt/vmail
+!EXEC=/dis/dbfs.dis -e /data/incalls /mnt/incall
+!EXEC=/dis/wm/sword/answerphone.dis
+!EXEC=/dis/wm/sword/vmail_led.dis /mnt/vmail /cvt/cons/0/ctl
+!NELEMS=7
+!HEIGHT=44
+phone:Virtual Phonepad:/dis/wm/sword/phonepad.dis
+www:HTML Browser:/dis/charon.dis
+mail:Mail:/dis/wm/mailtool.dis
+config:Configuration:/dis/wm/sword/config.dis
+addr:PIM:/dis/wm/sword/addrbook.dis
+shell:Shell:/dis/wm/sh.dis
+sds:SDS:/sds/dis/sdc.dis
+calls:Call History:/dis/wm/sword/callhist.dis
+vmails:Voice Mail:/dis/wm/sword/vmail.dis
--- /dev/null
+++ b/lib/unicode
@@ -1,0 +1,6588 @@
+0000	null
+0001	start of heading
+0002	start of text
+0003	end of text
+0004	end of transmission
+0005	enquiry
+0006	acknowledge
+0007	bell
+0008	backspace
+0009	horizontal tabulation
+000a	line feed
+000b	vertical tabulation
+000c	form feed
+000d	carriage return
+000e	shift out
+000f	shift in
+0010	data link escape
+0011	device control one
+0012	device control two
+0013	device control three
+0014	device control four
+0015	negative acknowledge
+0016	synchronous idle
+0017	end of transmission block
+0018	cancel
+0019	end of medium
+001a	substitute
+001b	escape
+001c	file separator
+001d	group separator
+001e	record separator
+001f	unit separator
+0020	space
+0021	exclamation mark
+0022	quotation mark
+0023	number sign
+0024	dollar sign
+0025	percent sign
+0026	ampersand
+0027	apostrophe
+0028	left parenthesis
+0029	right parenthesis
+002a	asterisk
+002b	plus sign
+002c	comma
+002d	hyphen-minus
+002e	full stop
+002f	solidus
+0030	digit zero
+0031	digit one
+0032	digit two
+0033	digit three
+0034	digit four
+0035	digit five
+0036	digit six
+0037	digit seven
+0038	digit eight
+0039	digit nine
+003a	colon
+003b	semicolon
+003c	less-than sign
+003d	equals sign
+003e	greater-than sign
+003f	question mark
+0040	commercial at
+0041	latin capital letter a
+0042	latin capital letter b
+0043	latin capital letter c
+0044	latin capital letter d
+0045	latin capital letter e
+0046	latin capital letter f
+0047	latin capital letter g
+0048	latin capital letter h
+0049	latin capital letter i
+004a	latin capital letter j
+004b	latin capital letter k
+004c	latin capital letter l
+004d	latin capital letter m
+004e	latin capital letter n
+004f	latin capital letter o
+0050	latin capital letter p
+0051	latin capital letter q
+0052	latin capital letter r
+0053	latin capital letter s
+0054	latin capital letter t
+0055	latin capital letter u
+0056	latin capital letter v
+0057	latin capital letter w
+0058	latin capital letter x
+0059	latin capital letter y
+005a	latin capital letter z
+005b	left square bracket
+005c	reverse solidus
+005d	right square bracket
+005e	circumflex accent
+005f	low line
+0060	grave accent
+0061	latin small letter a;0041
+0062	latin small letter b;0042
+0063	latin small letter c;0043
+0064	latin small letter d;0044
+0065	latin small letter e;0045
+0066	latin small letter f;0046
+0067	latin small letter g;0047
+0068	latin small letter h;0048
+0069	latin small letter i;0049
+006a	latin small letter j;004a
+006b	latin small letter k;004b
+006c	latin small letter l;004c
+006d	latin small letter m;004d
+006e	latin small letter n;004e
+006f	latin small letter o;004f
+0070	latin small letter p;0050
+0071	latin small letter q;0051
+0072	latin small letter r;0052
+0073	latin small letter s;0053
+0074	latin small letter t;0054
+0075	latin small letter u;0055
+0076	latin small letter v;0056
+0077	latin small letter w;0057
+0078	latin small letter x;0058
+0079	latin small letter y;0059
+007a	latin small letter z;005a
+007b	left curly bracket
+007c	vertical line
+007d	right curly bracket
+007e	tilde
+007f	<control>
+0080	<control>
+0081	<control>
+0082	<control>
+0083	<control>
+0084	<control>
+0085	<control>
+0086	<control>
+0087	<control>
+0088	<control>
+0089	<control>
+008a	<control>
+008b	<control>
+008c	<control>
+008d	<control>
+008e	<control>
+008f	<control>
+0090	<control>
+0091	<control>
+0092	<control>
+0093	<control>
+0094	<control>
+0095	<control>
+0096	<control>
+0097	<control>
+0098	<control>
+0099	<control>
+009a	<control>
+009b	<control>
+009c	<control>
+009d	<control>
+009e	<control>
+009f	<control>
+00a0	no-break space
+00a1	inverted exclamation mark
+00a2	cent sign
+00a3	pound sign
+00a4	currency sign
+00a5	yen sign
+00a6	broken bar
+00a7	section sign
+00a8	diaeresis
+00a9	copyright sign
+00aa	feminine ordinal indicator
+00ab	left-pointing double angle quotation mark
+00ac	not sign
+00ad	soft hyphen
+00ae	registered sign
+00af	macron
+00b0	degree sign
+00b1	plus-minus sign
+00b2	superscript two
+00b3	superscript three
+00b4	acute accent
+00b5	micro sign
+00b6	pilcrow sign
+00b7	middle dot
+00b8	cedilla
+00b9	superscript one
+00ba	masculine ordinal indicator
+00bb	right-pointing double angle quotation mark
+00bc	vulgar fraction one quarter
+00bd	vulgar fraction one half
+00be	vulgar fraction three quarters
+00bf	inverted question mark
+00c0	latin capital letter a with grave
+00c1	latin capital letter a with acute
+00c2	latin capital letter a with circumflex
+00c3	latin capital letter a with tilde
+00c4	latin capital letter a with diaeresis
+00c5	latin capital letter a with ring above
+00c6	latin capital letter ae
+00c7	latin capital letter c with cedilla
+00c8	latin capital letter e with grave
+00c9	latin capital letter e with acute
+00ca	latin capital letter e with circumflex
+00cb	latin capital letter e with diaeresis
+00cc	latin capital letter i with grave
+00cd	latin capital letter i with acute
+00ce	latin capital letter i with circumflex
+00cf	latin capital letter i with diaeresis
+00d0	latin capital letter eth
+00d1	latin capital letter n with tilde
+00d2	latin capital letter o with grave
+00d3	latin capital letter o with acute
+00d4	latin capital letter o with circumflex
+00d5	latin capital letter o with tilde
+00d6	latin capital letter o with diaeresis
+00d7	multiplication sign
+00d8	latin capital letter o with stroke
+00d9	latin capital letter u with grave
+00da	latin capital letter u with acute
+00db	latin capital letter u with circumflex
+00dc	latin capital letter u with diaeresis
+00dd	latin capital letter y with acute
+00de	latin capital letter thorn
+00df	latin small letter sharp s
+00e0	latin small letter a with grave;00c0
+00e1	latin small letter a with acute;00c1
+00e2	latin small letter a with circumflex;00c2
+00e3	latin small letter a with tilde;00c3
+00e4	latin small letter a with diaeresis;00c4
+00e5	latin small letter a with ring above;00c5
+00e6	latin small letter ae;00c6
+00e7	latin small letter c with cedilla;00c7
+00e8	latin small letter e with grave;00c8
+00e9	latin small letter e with acute;00c9
+00ea	latin small letter e with circumflex;00ca
+00eb	latin small letter e with diaeresis;00cb
+00ec	latin small letter i with grave;00cc
+00ed	latin small letter i with acute;00cd
+00ee	latin small letter i with circumflex;00ce
+00ef	latin small letter i with diaeresis;00cf
+00f0	latin small letter eth;00d0
+00f1	latin small letter n with tilde;00d1
+00f2	latin small letter o with grave;00d2
+00f3	latin small letter o with acute;00d3
+00f4	latin small letter o with circumflex;00d4
+00f5	latin small letter o with tilde;00d5
+00f6	latin small letter o with diaeresis;00d6
+00f7	division sign
+00f8	latin small letter o with stroke;00d8
+00f9	latin small letter u with grave;00d9
+00fa	latin small letter u with acute;00da
+00fb	latin small letter u with circumflex;00db
+00fc	latin small letter u with diaeresis;00dc
+00fd	latin small letter y with acute;00dd
+00fe	latin small letter thorn;00de
+00ff	latin small letter y with diaeresis;0178
+0100	latin capital letter a with macron
+0101	latin small letter a with macron;0100
+0102	latin capital letter a with breve
+0103	latin small letter a with breve;0102
+0104	latin capital letter a with ogonek
+0105	latin small letter a with ogonek;0104
+0106	latin capital letter c with acute
+0107	latin small letter c with acute;0106
+0108	latin capital letter c with circumflex
+0109	latin small letter c with circumflex;0108
+010a	latin capital letter c with dot above
+010b	latin small letter c with dot above;010a
+010c	latin capital letter c with caron
+010d	latin small letter c with caron;010c
+010e	latin capital letter d with caron
+010f	latin small letter d with caron;010e
+0110	latin capital letter d with stroke
+0111	latin small letter d with stroke;0110
+0112	latin capital letter e with macron
+0113	latin small letter e with macron;0112
+0114	latin capital letter e with breve
+0115	latin small letter e with breve;0114
+0116	latin capital letter e with dot above
+0117	latin small letter e with dot above;0116
+0118	latin capital letter e with ogonek
+0119	latin small letter e with ogonek;0118
+011a	latin capital letter e with caron
+011b	latin small letter e with caron;011a
+011c	latin capital letter g with circumflex
+011d	latin small letter g with circumflex;011c
+011e	latin capital letter g with breve
+011f	latin small letter g with breve;011e
+0120	latin capital letter g with dot above
+0121	latin small letter g with dot above;0120
+0122	latin capital letter g with cedilla
+0123	latin small letter g with cedilla;0122
+0124	latin capital letter h with circumflex
+0125	latin small letter h with circumflex;0124
+0126	latin capital letter h with stroke
+0127	latin small letter h with stroke;0126
+0128	latin capital letter i with tilde
+0129	latin small letter i with tilde;0128
+012a	latin capital letter i with macron
+012b	latin small letter i with macron;012a
+012c	latin capital letter i with breve
+012d	latin small letter i with breve;012c
+012e	latin capital letter i with ogonek
+012f	latin small letter i with ogonek;012e
+0130	latin capital letter i with dot above
+0131	latin small letter dotless i;0049
+0132	latin capital ligature ij
+0133	latin small ligature ij;0132
+0134	latin capital letter j with circumflex
+0135	latin small letter j with circumflex;0134
+0136	latin capital letter k with cedilla
+0137	latin small letter k with cedilla;0136
+0138	latin small letter kra
+0139	latin capital letter l with acute
+013a	latin small letter l with acute;0139
+013b	latin capital letter l with cedilla
+013c	latin small letter l with cedilla;013b
+013d	latin capital letter l with caron
+013e	latin small letter l with caron;013d
+013f	latin capital letter l with middle dot
+0140	latin small letter l with middle dot;013f
+0141	latin capital letter l with stroke
+0142	latin small letter l with stroke;0141
+0143	latin capital letter n with acute
+0144	latin small letter n with acute;0143
+0145	latin capital letter n with cedilla
+0146	latin small letter n with cedilla;0145
+0147	latin capital letter n with caron
+0148	latin small letter n with caron;0147
+0149	latin small letter n preceded by apostrophe
+014a	latin capital letter eng
+014b	latin small letter eng;014a
+014c	latin capital letter o with macron
+014d	latin small letter o with macron;014c
+014e	latin capital letter o with breve
+014f	latin small letter o with breve;014e
+0150	latin capital letter o with double acute
+0151	latin small letter o with double acute;0150
+0152	latin capital ligature oe
+0153	latin small ligature oe;0152
+0154	latin capital letter r with acute
+0155	latin small letter r with acute;0154
+0156	latin capital letter r with cedilla
+0157	latin small letter r with cedilla;0156
+0158	latin capital letter r with caron
+0159	latin small letter r with caron;0158
+015a	latin capital letter s with acute
+015b	latin small letter s with acute;015a
+015c	latin capital letter s with circumflex
+015d	latin small letter s with circumflex;015c
+015e	latin capital letter s with cedilla
+015f	latin small letter s with cedilla;015e
+0160	latin capital letter s with caron
+0161	latin small letter s with caron;0160
+0162	latin capital letter t with cedilla
+0163	latin small letter t with cedilla;0162
+0164	latin capital letter t with caron
+0165	latin small letter t with caron;0164
+0166	latin capital letter t with stroke
+0167	latin small letter t with stroke;0166
+0168	latin capital letter u with tilde
+0169	latin small letter u with tilde;0168
+016a	latin capital letter u with macron
+016b	latin small letter u with macron;016a
+016c	latin capital letter u with breve
+016d	latin small letter u with breve;016c
+016e	latin capital letter u with ring above
+016f	latin small letter u with ring above;016e
+0170	latin capital letter u with double acute
+0171	latin small letter u with double acute;0170
+0172	latin capital letter u with ogonek
+0173	latin small letter u with ogonek;0172
+0174	latin capital letter w with circumflex
+0175	latin small letter w with circumflex;0174
+0176	latin capital letter y with circumflex
+0177	latin small letter y with circumflex;0176
+0178	latin capital letter y with diaeresis
+0179	latin capital letter z with acute
+017a	latin small letter z with acute;0179
+017b	latin capital letter z with dot above
+017c	latin small letter z with dot above;017b
+017d	latin capital letter z with caron
+017e	latin small letter z with caron;017d
+017f	latin small letter long s;0053
+0180	latin small letter b with stroke
+0181	latin capital letter b with hook
+0182	latin capital letter b with topbar
+0183	latin small letter b with topbar;0182
+0184	latin capital letter tone six
+0185	latin small letter tone six;0184
+0186	latin capital letter open o
+0187	latin capital letter c with hook
+0188	latin small letter c with hook;0187
+0189	latin capital letter african d
+018a	latin capital letter d with hook
+018b	latin capital letter d with topbar
+018c	latin small letter d with topbar;018b
+018d	latin small letter turned delta
+018e	latin capital letter reversed e
+018f	latin capital letter schwa
+0190	latin capital letter open e
+0191	latin capital letter f with hook
+0192	latin small letter f with hook;0191
+0193	latin capital letter g with hook
+0194	latin capital letter gamma
+0195	latin small letter hv
+0196	latin capital letter iota
+0197	latin capital letter i with stroke
+0198	latin capital letter k with hook
+0199	latin small letter k with hook;0198
+019a	latin small letter l with bar
+019b	latin small letter lambda with stroke
+019c	latin capital letter turned m
+019d	latin capital letter n with left hook
+019e	latin small letter n with long right leg
+019f	latin capital letter o with middle tilde
+01a0	latin capital letter o with horn
+01a1	latin small letter o with horn;01a0
+01a2	latin capital letter oi
+01a3	latin small letter oi;01a2
+01a4	latin capital letter p with hook
+01a5	latin small letter p with hook;01a4
+01a6	latin letter yr
+01a7	latin capital letter tone two
+01a8	latin small letter tone two;01a7
+01a9	latin capital letter esh
+01aa	latin letter reversed esh loop
+01ab	latin small letter t with palatal hook
+01ac	latin capital letter t with hook
+01ad	latin small letter t with hook;01ac
+01ae	latin capital letter t with retroflex hook
+01af	latin capital letter u with horn
+01b0	latin small letter u with horn;01af
+01b1	latin capital letter upsilon
+01b2	latin capital letter v with hook
+01b3	latin capital letter y with hook
+01b4	latin small letter y with hook;01b3
+01b5	latin capital letter z with stroke
+01b6	latin small letter z with stroke;01b5
+01b7	latin capital letter ezh
+01b8	latin capital letter ezh reversed
+01b9	latin small letter ezh reversed;01b8
+01ba	latin small letter ezh with tail
+01bb	latin letter two with stroke
+01bc	latin capital letter tone five
+01bd	latin small letter tone five;01bc
+01be	latin letter inverted glottal stop with stroke
+01bf	latin letter wynn
+01c0	latin letter dental click
+01c1	latin letter lateral click
+01c2	latin letter alveolar click
+01c3	latin letter retroflex click
+01c4	latin capital letter dz with caron;01c5
+01c5	latin capital letter d with small letter z with caron
+01c6	latin small letter dz with caron;01c5
+01c7	latin capital letter lj;01c8
+01c8	latin capital letter l with small letter j
+01c9	latin small letter lj;01c8
+01ca	latin capital letter nj;01cb
+01cb	latin capital letter n with small letter j
+01cc	latin small letter nj;01cb
+01cd	latin capital letter a with caron
+01ce	latin small letter a with caron;01cd
+01cf	latin capital letter i with caron
+01d0	latin small letter i with caron;01cf
+01d1	latin capital letter o with caron
+01d2	latin small letter o with caron;01d1
+01d3	latin capital letter u with caron
+01d4	latin small letter u with caron;01d3
+01d5	latin capital letter u with diaeresis and macron
+01d6	latin small letter u with diaeresis and macron;01d5
+01d7	latin capital letter u with diaeresis and acute
+01d8	latin small letter u with diaeresis and acute;01d7
+01d9	latin capital letter u with diaeresis and caron
+01da	latin small letter u with diaeresis and caron;01d9
+01db	latin capital letter u with diaeresis and grave
+01dc	latin small letter u with diaeresis and grave;01db
+01dd	latin small letter turned e
+01de	latin capital letter a with diaeresis and macron
+01df	latin small letter a with diaeresis and macron;01de
+01e0	latin capital letter a with dot above and macron
+01e1	latin small letter a with dot above and macron;01e0
+01e2	latin capital letter ae with macron
+01e3	latin small letter ae with macron;01e2
+01e4	latin capital letter g with stroke
+01e5	latin small letter g with stroke;01e4
+01e6	latin capital letter g with caron
+01e7	latin small letter g with caron;01e6
+01e8	latin capital letter k with caron
+01e9	latin small letter k with caron;01e8
+01ea	latin capital letter o with ogonek
+01eb	latin small letter o with ogonek;01ea
+01ec	latin capital letter o with ogonek and macron
+01ed	latin small letter o with ogonek and macron;01ec
+01ee	latin capital letter ezh with caron
+01ef	latin small letter ezh with caron;01ee
+01f0	latin small letter j with caron
+01f1	latin capital letter dz;01f2
+01f2	latin capital letter d with small letter z
+01f3	latin small letter dz;01f2
+01f4	latin capital letter g with acute
+01f5	latin small letter g with acute;01f4
+01fa	latin capital letter a with ring above and acute
+01fb	latin small letter a with ring above and acute;01fa
+01fc	latin capital letter ae with acute
+01fd	latin small letter ae with acute;01fc
+01fe	latin capital letter o with stroke and acute
+01ff	latin small letter o with stroke and acute;01fe
+0200	latin capital letter a with double grave
+0201	latin small letter a with double grave;0200
+0202	latin capital letter a with inverted breve
+0203	latin small letter a with inverted breve;0202
+0204	latin capital letter e with double grave
+0205	latin small letter e with double grave;0204
+0206	latin capital letter e with inverted breve
+0207	latin small letter e with inverted breve;0206
+0208	latin capital letter i with double grave
+0209	latin small letter i with double grave;0208
+020a	latin capital letter i with inverted breve
+020b	latin small letter i with inverted breve;020a
+020c	latin capital letter o with double grave
+020d	latin small letter o with double grave;020c
+020e	latin capital letter o with inverted breve
+020f	latin small letter o with inverted breve;020e
+0210	latin capital letter r with double grave
+0211	latin small letter r with double grave;0210
+0212	latin capital letter r with inverted breve
+0213	latin small letter r with inverted breve;0212
+0214	latin capital letter u with double grave
+0215	latin small letter u with double grave;0214
+0216	latin capital letter u with inverted breve
+0217	latin small letter u with inverted breve;0216
+0250	latin small letter turned a
+0251	latin small letter alpha
+0252	latin small letter turned alpha
+0253	latin small letter b with hook;0181
+0254	latin small letter open o;0186
+0255	latin small letter c with curl
+0256	latin small letter d with tail;0189
+0257	latin small letter d with hook;018a
+0258	latin small letter reversed e;018e
+0259	latin small letter schwa;018f
+025a	latin small letter schwa with hook
+025b	latin small letter open e;0190
+025c	latin small letter reversed open e
+025d	latin small letter reversed open e with hook
+025e	latin small letter closed reversed open e
+025f	latin small letter dotless j with stroke
+0260	latin small letter g with hook;0193
+0261	latin small letter script g
+0262	latin letter small capital g
+0263	latin small letter gamma;0194
+0264	latin small letter rams horn
+0265	latin small letter turned h
+0266	latin small letter h with hook
+0267	latin small letter heng with hook
+0268	latin small letter i with stroke;0197
+0269	latin small letter iota;0196
+026a	latin letter small capital i
+026b	latin small letter l with middle tilde
+026c	latin small letter l with belt
+026d	latin small letter l with retroflex hook
+026e	latin small letter lezh
+026f	latin small letter turned m;019c
+0270	latin small letter turned m with long leg
+0271	latin small letter m with hook
+0272	latin small letter n with left hook;019d
+0273	latin small letter n with retroflex hook
+0274	latin letter small capital n
+0275	latin small letter barred o
+0276	latin letter small capital oe
+0277	latin small letter closed omega
+0278	latin small letter phi
+0279	latin small letter turned r
+027a	latin small letter turned r with long leg
+027b	latin small letter turned r with hook
+027c	latin small letter r with long leg
+027d	latin small letter r with tail
+027e	latin small letter r with fishhook
+027f	latin small letter reversed r with fishhook
+0280	latin letter small capital r
+0281	latin letter small capital inverted r
+0282	latin small letter s with hook
+0283	latin small letter esh;01a9
+0284	latin small letter dotless j with stroke and hook
+0285	latin small letter squat reversed esh
+0286	latin small letter esh with curl
+0287	latin small letter turned t
+0288	latin small letter t with retroflex hook;01ae
+0289	latin small letter u bar
+028a	latin small letter upsilon;01b1
+028b	latin small letter v with hook;01b2
+028c	latin small letter turned v
+028d	latin small letter turned w
+028e	latin small letter turned y
+028f	latin letter small capital y
+0290	latin small letter z with retroflex hook
+0291	latin small letter z with curl
+0292	latin small letter ezh;01b7
+0293	latin small letter ezh with curl
+0294	latin letter glottal stop
+0295	latin letter pharyngeal voiced fricative
+0296	latin letter inverted glottal stop
+0297	latin letter stretched c
+0298	latin letter bilabial click
+0299	latin letter small capital b
+029a	latin small letter closed open e
+029b	latin letter small capital g with hook
+029c	latin letter small capital h
+029d	latin small letter j with crossed-tail
+029e	latin small letter turned k
+029f	latin letter small capital l
+02a0	latin small letter q with hook
+02a1	latin letter glottal stop with stroke
+02a2	latin letter reversed glottal stop with stroke
+02a3	latin small letter dz digraph
+02a4	latin small letter dezh digraph
+02a5	latin small letter dz digraph with curl
+02a6	latin small letter ts digraph
+02a7	latin small letter tesh digraph
+02a8	latin small letter tc digraph with curl
+02b0	modifier letter small h
+02b1	modifier letter small h with hook
+02b2	modifier letter small j
+02b3	modifier letter small r
+02b4	modifier letter small turned r
+02b5	modifier letter small turned r with hook
+02b6	modifier letter small capital inverted r
+02b7	modifier letter small w
+02b8	modifier letter small y
+02b9	modifier letter prime
+02ba	modifier letter double prime
+02bb	modifier letter turned comma
+02bc	modifier letter apostrophe
+02bd	modifier letter reversed comma
+02be	modifier letter right half ring
+02bf	modifier letter left half ring
+02c0	modifier letter glottal stop
+02c1	modifier letter reversed glottal stop
+02c2	modifier letter left arrowhead
+02c3	modifier letter right arrowhead
+02c4	modifier letter up arrowhead
+02c5	modifier letter down arrowhead
+02c6	modifier letter circumflex accent
+02c7	caron
+02c8	modifier letter vertical line
+02c9	modifier letter macron
+02ca	modifier letter acute accent
+02cb	modifier letter grave accent
+02cc	modifier letter low vertical line
+02cd	modifier letter low macron
+02ce	modifier letter low grave accent
+02cf	modifier letter low acute accent
+02d0	modifier letter triangular colon
+02d1	modifier letter half triangular colon
+02d2	modifier letter centred right half ring
+02d3	modifier letter centred left half ring
+02d4	modifier letter up tack
+02d5	modifier letter down tack
+02d6	modifier letter plus sign
+02d7	modifier letter minus sign
+02d8	breve
+02d9	dot above
+02da	ring above
+02db	ogonek
+02dc	small tilde
+02dd	double acute accent
+02de	modifier letter rhotic hook
+02e0	modifier letter small gamma
+02e1	modifier letter small l
+02e2	modifier letter small s
+02e3	modifier letter small x
+02e4	modifier letter small reversed glottal stop
+02e5	modifier letter extra-high tone bar
+02e6	modifier letter high tone bar
+02e7	modifier letter mid tone bar
+02e8	modifier letter low tone bar
+02e9	modifier letter extra-low tone bar
+0300	combining grave accent
+0301	combining acute accent
+0302	combining circumflex accent
+0303	combining tilde
+0304	combining macron
+0305	combining overline
+0306	combining breve
+0307	combining dot above
+0308	combining diaeresis
+0309	combining hook above
+030a	combining ring above
+030b	combining double acute accent
+030c	combining caron
+030d	combining vertical line above
+030e	combining double vertical line above
+030f	combining double grave accent
+0310	combining candrabindu
+0311	combining inverted breve
+0312	combining turned comma above
+0313	combining comma above
+0314	combining reversed comma above
+0315	combining comma above right
+0316	combining grave accent below
+0317	combining acute accent below
+0318	combining left tack below
+0319	combining right tack below
+031a	combining left angle above
+031b	combining horn
+031c	combining left half ring below
+031d	combining up tack below
+031e	combining down tack below
+031f	combining plus sign below
+0320	combining minus sign below
+0321	combining palatalized hook below
+0322	combining retroflex hook below
+0323	combining dot below
+0324	combining diaeresis below
+0325	combining ring below
+0326	combining comma below
+0327	combining cedilla
+0328	combining ogonek
+0329	combining vertical line below
+032a	combining bridge below
+032b	combining inverted double arch below
+032c	combining caron below
+032d	combining circumflex accent below
+032e	combining breve below
+032f	combining inverted breve below
+0330	combining tilde below
+0331	combining macron below
+0332	combining low line
+0333	combining double low line
+0334	combining tilde overlay
+0335	combining short stroke overlay
+0336	combining long stroke overlay
+0337	combining short solidus overlay
+0338	combining long solidus overlay
+0339	combining right half ring below
+033a	combining inverted bridge below
+033b	combining square below
+033c	combining seagull below
+033d	combining x above
+033e	combining vertical tilde
+033f	combining double overline
+0340	combining grave tone mark
+0341	combining acute tone mark
+0342	combining greek perispomeni
+0343	combining greek koronis
+0344	combining greek dialytika tonos
+0345	combining greek ypogegrammeni
+0360	combining double tilde
+0361	combining double inverted breve
+0374	greek numeral sign
+0375	greek lower numeral sign
+037a	greek ypogegrammeni
+037e	greek question mark
+0384	greek tonos
+0385	greek dialytika tonos
+0386	greek capital letter alpha with tonos
+0387	greek ano teleia
+0388	greek capital letter epsilon with tonos
+0389	greek capital letter eta with tonos
+038a	greek capital letter iota with tonos
+038c	greek capital letter omicron with tonos
+038e	greek capital letter upsilon with tonos
+038f	greek capital letter omega with tonos
+0390	greek small letter iota with dialytika and tonos
+0391	greek capital letter alpha
+0392	greek capital letter beta
+0393	greek capital letter gamma
+0394	greek capital letter delta
+0395	greek capital letter epsilon
+0396	greek capital letter zeta
+0397	greek capital letter eta
+0398	greek capital letter theta
+0399	greek capital letter iota
+039a	greek capital letter kappa
+039b	greek capital letter lamda
+039c	greek capital letter mu
+039d	greek capital letter nu
+039e	greek capital letter xi
+039f	greek capital letter omicron
+03a0	greek capital letter pi
+03a1	greek capital letter rho
+03a3	greek capital letter sigma
+03a4	greek capital letter tau
+03a5	greek capital letter upsilon
+03a6	greek capital letter phi
+03a7	greek capital letter chi
+03a8	greek capital letter psi
+03a9	greek capital letter omega
+03aa	greek capital letter iota with dialytika
+03ab	greek capital letter upsilon with dialytika
+03ac	greek small letter alpha with tonos;0386
+03ad	greek small letter epsilon with tonos;0388
+03ae	greek small letter eta with tonos;0389
+03af	greek small letter iota with tonos;038a
+03b0	greek small letter upsilon with dialytika and tonos
+03b1	greek small letter alpha;0391
+03b2	greek small letter beta;0392
+03b3	greek small letter gamma;0393
+03b4	greek small letter delta;0394
+03b5	greek small letter epsilon;0395
+03b6	greek small letter zeta;0396
+03b7	greek small letter eta;0397
+03b8	greek small letter theta;0398
+03b9	greek small letter iota;0399
+03ba	greek small letter kappa;039a
+03bb	greek small letter lamda;039b
+03bc	greek small letter mu;039c
+03bd	greek small letter nu;039d
+03be	greek small letter xi;039e
+03bf	greek small letter omicron;039f
+03c0	greek small letter pi;03a0
+03c1	greek small letter rho;03a1
+03c2	greek small letter final sigma
+03c3	greek small letter sigma;03a3
+03c4	greek small letter tau;03a4
+03c5	greek small letter upsilon;03a5
+03c6	greek small letter phi;03a6
+03c7	greek small letter chi;03a7
+03c8	greek small letter psi;03a8
+03c9	greek small letter omega;03a9
+03ca	greek small letter iota with dialytika;03aa
+03cb	greek small letter upsilon with dialytika;03ab
+03cc	greek small letter omicron with tonos;038c
+03cd	greek small letter upsilon with tonos;038e
+03ce	greek small letter omega with tonos;038f
+03d0	greek beta symbol
+03d1	greek theta symbol
+03d2	greek upsilon with hook symbol
+03d3	greek upsilon with acute and hook symbol
+03d4	greek upsilon with diaeresis and hook symbol
+03d5	greek phi symbol
+03d6	greek pi symbol
+03da	greek letter stigma
+03dc	greek letter digamma
+03de	greek letter koppa
+03e0	greek letter sampi
+03e2	coptic capital letter shei
+03e3	coptic small letter shei;03e2
+03e4	coptic capital letter fei
+03e5	coptic small letter fei;03e4
+03e6	coptic capital letter khei
+03e7	coptic small letter khei;03e6
+03e8	coptic capital letter hori
+03e9	coptic small letter hori;03e8
+03ea	coptic capital letter gangia
+03eb	coptic small letter gangia;03ea
+03ec	coptic capital letter shima
+03ed	coptic small letter shima;03ec
+03ee	coptic capital letter dei
+03ef	coptic small letter dei;03ee
+03f0	greek kappa symbol
+03f1	greek rho symbol
+03f2	greek lunate sigma symbol
+03f3	greek letter yot
+0401	cyrillic capital letter io
+0402	cyrillic capital letter dje
+0403	cyrillic capital letter gje
+0404	cyrillic capital letter ukrainian ie
+0405	cyrillic capital letter dze
+0406	cyrillic capital letter byelorussian-ukrainian i
+0407	cyrillic capital letter yi
+0408	cyrillic capital letter je
+0409	cyrillic capital letter lje
+040a	cyrillic capital letter nje
+040b	cyrillic capital letter tshe
+040c	cyrillic capital letter kje
+040e	cyrillic capital letter short u
+040f	cyrillic capital letter dzhe
+0410	cyrillic capital letter a
+0411	cyrillic capital letter be
+0412	cyrillic capital letter ve
+0413	cyrillic capital letter ghe
+0414	cyrillic capital letter de
+0415	cyrillic capital letter ie
+0416	cyrillic capital letter zhe
+0417	cyrillic capital letter ze
+0418	cyrillic capital letter i
+0419	cyrillic capital letter short i
+041a	cyrillic capital letter ka
+041b	cyrillic capital letter el
+041c	cyrillic capital letter em
+041d	cyrillic capital letter en
+041e	cyrillic capital letter o
+041f	cyrillic capital letter pe
+0420	cyrillic capital letter er
+0421	cyrillic capital letter es
+0422	cyrillic capital letter te
+0423	cyrillic capital letter u
+0424	cyrillic capital letter ef
+0425	cyrillic capital letter ha
+0426	cyrillic capital letter tse
+0427	cyrillic capital letter che
+0428	cyrillic capital letter sha
+0429	cyrillic capital letter shcha
+042a	cyrillic capital letter hard sign
+042b	cyrillic capital letter yeru
+042c	cyrillic capital letter soft sign
+042d	cyrillic capital letter e
+042e	cyrillic capital letter yu
+042f	cyrillic capital letter ya
+0430	cyrillic small letter a;0410
+0431	cyrillic small letter be;0411
+0432	cyrillic small letter ve;0412
+0433	cyrillic small letter ghe;0413
+0434	cyrillic small letter de;0414
+0435	cyrillic small letter ie;0415
+0436	cyrillic small letter zhe;0416
+0437	cyrillic small letter ze;0417
+0438	cyrillic small letter i;0418
+0439	cyrillic small letter short i;0419
+043a	cyrillic small letter ka;041a
+043b	cyrillic small letter el;041b
+043c	cyrillic small letter em;041c
+043d	cyrillic small letter en;041d
+043e	cyrillic small letter o;041e
+043f	cyrillic small letter pe;041f
+0440	cyrillic small letter er;0420
+0441	cyrillic small letter es;0421
+0442	cyrillic small letter te;0422
+0443	cyrillic small letter u;0423
+0444	cyrillic small letter ef;0424
+0445	cyrillic small letter ha;0425
+0446	cyrillic small letter tse;0426
+0447	cyrillic small letter che;0427
+0448	cyrillic small letter sha;0428
+0449	cyrillic small letter shcha;0429
+044a	cyrillic small letter hard sign;042a
+044b	cyrillic small letter yeru;042b
+044c	cyrillic small letter soft sign;042c
+044d	cyrillic small letter e;042d
+044e	cyrillic small letter yu;042e
+044f	cyrillic small letter ya;042f
+0451	cyrillic small letter io;0401
+0452	cyrillic small letter dje;0402
+0453	cyrillic small letter gje;0403
+0454	cyrillic small letter ukrainian ie;0404
+0455	cyrillic small letter dze;0405
+0456	cyrillic small letter byelorussian-ukrainian i;0406
+0457	cyrillic small letter yi;0407
+0458	cyrillic small letter je;0408
+0459	cyrillic small letter lje;0409
+045a	cyrillic small letter nje;040a
+045b	cyrillic small letter tshe;040b
+045c	cyrillic small letter kje;040c
+045e	cyrillic small letter short u;040e
+045f	cyrillic small letter dzhe;040f
+0460	cyrillic capital letter omega
+0461	cyrillic small letter omega;0460
+0462	cyrillic capital letter yat
+0463	cyrillic small letter yat;0462
+0464	cyrillic capital letter iotified e
+0465	cyrillic small letter iotified e;0464
+0466	cyrillic capital letter little yus
+0467	cyrillic small letter little yus;0466
+0468	cyrillic capital letter iotified little yus
+0469	cyrillic small letter iotified little yus;0468
+046a	cyrillic capital letter big yus
+046b	cyrillic small letter big yus;046a
+046c	cyrillic capital letter iotified big yus
+046d	cyrillic small letter iotified big yus;046c
+046e	cyrillic capital letter ksi
+046f	cyrillic small letter ksi;046e
+0470	cyrillic capital letter psi
+0471	cyrillic small letter psi;0470
+0472	cyrillic capital letter fita
+0473	cyrillic small letter fita;0472
+0474	cyrillic capital letter izhitsa
+0475	cyrillic small letter izhitsa;0474
+0476	cyrillic capital letter izhitsa with double grave accent
+0477	cyrillic small letter izhitsa with double grave accent;0476
+0478	cyrillic capital letter uk
+0479	cyrillic small letter uk;0478
+047a	cyrillic capital letter round omega
+047b	cyrillic small letter round omega;047a
+047c	cyrillic capital letter omega with titlo
+047d	cyrillic small letter omega with titlo;047c
+047e	cyrillic capital letter ot
+047f	cyrillic small letter ot;047e
+0480	cyrillic capital letter koppa
+0481	cyrillic small letter koppa;0480
+0482	cyrillic thousands sign
+0483	combining cyrillic titlo
+0484	combining cyrillic palatalization
+0485	combining cyrillic dasia pneumata
+0486	combining cyrillic psili pneumata
+0490	cyrillic capital letter ghe with upturn
+0491	cyrillic small letter ghe with upturn;0490
+0492	cyrillic capital letter ghe with stroke
+0493	cyrillic small letter ghe with stroke;0492
+0494	cyrillic capital letter ghe with middle hook
+0495	cyrillic small letter ghe with middle hook;0494
+0496	cyrillic capital letter zhe with descender
+0497	cyrillic small letter zhe with descender;0496
+0498	cyrillic capital letter ze with descender
+0499	cyrillic small letter ze with descender;0498
+049a	cyrillic capital letter ka with descender
+049b	cyrillic small letter ka with descender;049a
+049c	cyrillic capital letter ka with vertical stroke
+049d	cyrillic small letter ka with vertical stroke;049c
+049e	cyrillic capital letter ka with stroke
+049f	cyrillic small letter ka with stroke;049e
+04a0	cyrillic capital letter bashkir ka
+04a1	cyrillic small letter bashkir ka;04a0
+04a2	cyrillic capital letter en with descender
+04a3	cyrillic small letter en with descender;04a2
+04a4	cyrillic capital ligature en ghe
+04a5	cyrillic small ligature en ghe;04a4
+04a6	cyrillic capital letter pe with middle hook
+04a7	cyrillic small letter pe with middle hook;04a6
+04a8	cyrillic capital letter abkhasian ha
+04a9	cyrillic small letter abkhasian ha;04a8
+04aa	cyrillic capital letter es with descender
+04ab	cyrillic small letter es with descender;04aa
+04ac	cyrillic capital letter te with descender
+04ad	cyrillic small letter te with descender;04ac
+04ae	cyrillic capital letter straight u
+04af	cyrillic small letter straight u;04ae
+04b0	cyrillic capital letter straight u with stroke
+04b1	cyrillic small letter straight u with stroke;04b0
+04b2	cyrillic capital letter ha with descender
+04b3	cyrillic small letter ha with descender;04b2
+04b4	cyrillic capital ligature te tse
+04b5	cyrillic small ligature te tse;04b4
+04b6	cyrillic capital letter che with descender
+04b7	cyrillic small letter che with descender;04b6
+04b8	cyrillic capital letter che with vertical stroke
+04b9	cyrillic small letter che with vertical stroke;04b8
+04ba	cyrillic capital letter shha
+04bb	cyrillic small letter shha;04ba
+04bc	cyrillic capital letter abkhasian che
+04bd	cyrillic small letter abkhasian che;04bc
+04be	cyrillic capital letter abkhasian che with descender
+04bf	cyrillic small letter abkhasian che with descender;04be
+04c0	cyrillic letter palochka
+04c1	cyrillic capital letter zhe with breve
+04c2	cyrillic small letter zhe with breve;04c1
+04c3	cyrillic capital letter ka with hook
+04c4	cyrillic small letter ka with hook;04c3
+04c7	cyrillic capital letter en with hook
+04c8	cyrillic small letter en with hook;04c7
+04cb	cyrillic capital letter khakassian che
+04cc	cyrillic small letter khakassian che;04cb
+04d0	cyrillic capital letter a with breve
+04d1	cyrillic small letter a with breve;04d0
+04d2	cyrillic capital letter a with diaeresis
+04d3	cyrillic small letter a with diaeresis;04d2
+04d4	cyrillic capital ligature a ie
+04d5	cyrillic small ligature a ie;04d4
+04d6	cyrillic capital letter ie with breve
+04d7	cyrillic small letter ie with breve;04d6
+04d8	cyrillic capital letter schwa
+04d9	cyrillic small letter schwa;04d8
+04da	cyrillic capital letter schwa with diaeresis
+04db	cyrillic small letter schwa with diaeresis;04da
+04dc	cyrillic capital letter zhe with diaeresis
+04dd	cyrillic small letter zhe with diaeresis;04dc
+04de	cyrillic capital letter ze with diaeresis
+04df	cyrillic small letter ze with diaeresis;04de
+04e0	cyrillic capital letter abkhasian dze
+04e1	cyrillic small letter abkhasian dze;04e0
+04e2	cyrillic capital letter i with macron
+04e3	cyrillic small letter i with macron;04e2
+04e4	cyrillic capital letter i with diaeresis
+04e5	cyrillic small letter i with diaeresis;04e4
+04e6	cyrillic capital letter o with diaeresis
+04e7	cyrillic small letter o with diaeresis;04e6
+04e8	cyrillic capital letter barred o
+04e9	cyrillic small letter barred o;04e8
+04ea	cyrillic capital letter barred o with diaeresis
+04eb	cyrillic small letter barred o with diaeresis;04ea
+04ee	cyrillic capital letter u with macron
+04ef	cyrillic small letter u with macron;04ee
+04f0	cyrillic capital letter u with diaeresis
+04f1	cyrillic small letter u with diaeresis;04f0
+04f2	cyrillic capital letter u with double acute
+04f3	cyrillic small letter u with double acute;04f2
+04f4	cyrillic capital letter che with diaeresis
+04f5	cyrillic small letter che with diaeresis;04f4
+04f8	cyrillic capital letter yeru with diaeresis
+04f9	cyrillic small letter yeru with diaeresis;04f8
+0531	armenian capital letter ayb
+0532	armenian capital letter ben
+0533	armenian capital letter gim
+0534	armenian capital letter da
+0535	armenian capital letter ech
+0536	armenian capital letter za
+0537	armenian capital letter eh
+0538	armenian capital letter et
+0539	armenian capital letter to
+053a	armenian capital letter zhe
+053b	armenian capital letter ini
+053c	armenian capital letter liwn
+053d	armenian capital letter xeh
+053e	armenian capital letter ca
+053f	armenian capital letter ken
+0540	armenian capital letter ho
+0541	armenian capital letter ja
+0542	armenian capital letter ghad
+0543	armenian capital letter cheh
+0544	armenian capital letter men
+0545	armenian capital letter yi
+0546	armenian capital letter now
+0547	armenian capital letter sha
+0548	armenian capital letter vo
+0549	armenian capital letter cha
+054a	armenian capital letter peh
+054b	armenian capital letter jheh
+054c	armenian capital letter ra
+054d	armenian capital letter seh
+054e	armenian capital letter vew
+054f	armenian capital letter tiwn
+0550	armenian capital letter reh
+0551	armenian capital letter co
+0552	armenian capital letter yiwn
+0553	armenian capital letter piwr
+0554	armenian capital letter keh
+0555	armenian capital letter oh
+0556	armenian capital letter feh
+0559	armenian modifier letter left half ring
+055a	armenian apostrophe
+055b	armenian emphasis mark
+055c	armenian exclamation mark
+055d	armenian comma
+055e	armenian question mark
+055f	armenian abbreviation mark
+0561	armenian small letter ayb;0531
+0562	armenian small letter ben;0532
+0563	armenian small letter gim;0533
+0564	armenian small letter da;0534
+0565	armenian small letter ech;0535
+0566	armenian small letter za;0536
+0567	armenian small letter eh;0537
+0568	armenian small letter et;0538
+0569	armenian small letter to;0539
+056a	armenian small letter zhe;053a
+056b	armenian small letter ini;053b
+056c	armenian small letter liwn;053c
+056d	armenian small letter xeh;053d
+056e	armenian small letter ca;053e
+056f	armenian small letter ken;053f
+0570	armenian small letter ho;0540
+0571	armenian small letter ja;0541
+0572	armenian small letter ghad;0542
+0573	armenian small letter cheh;0543
+0574	armenian small letter men;0544
+0575	armenian small letter yi;0545
+0576	armenian small letter now;0546
+0577	armenian small letter sha;0547
+0578	armenian small letter vo;0548
+0579	armenian small letter cha;0549
+057a	armenian small letter peh;054a
+057b	armenian small letter jheh;054b
+057c	armenian small letter ra;054c
+057d	armenian small letter seh;054d
+057e	armenian small letter vew;054e
+057f	armenian small letter tiwn;054f
+0580	armenian small letter reh;0550
+0581	armenian small letter co;0551
+0582	armenian small letter yiwn;0552
+0583	armenian small letter piwr;0553
+0584	armenian small letter keh;0554
+0585	armenian small letter oh;0555
+0586	armenian small letter feh;0556
+0587	armenian small ligature ech yiwn
+0589	armenian full stop
+0591	hebrew accent etnahta
+0592	hebrew accent segol
+0593	hebrew accent shalshelet
+0594	hebrew accent zaqef qatan
+0595	hebrew accent zaqef gadol
+0596	hebrew accent tipeha
+0597	hebrew accent revia
+0598	hebrew accent zarqa
+0599	hebrew accent pashta
+059a	hebrew accent yetiv
+059b	hebrew accent tevir
+059c	hebrew accent geresh
+059d	hebrew accent geresh muqdam
+059e	hebrew accent gershayim
+059f	hebrew accent qarney para
+05a0	hebrew accent telisha gedola
+05a1	hebrew accent pazer
+05a3	hebrew accent munah
+05a4	hebrew accent mahapakh
+05a5	hebrew accent merkha
+05a6	hebrew accent merkha kefula
+05a7	hebrew accent darga
+05a8	hebrew accent qadma
+05a9	hebrew accent telisha qetana
+05aa	hebrew accent yerah ben yomo
+05ab	hebrew accent ole
+05ac	hebrew accent iluy
+05ad	hebrew accent dehi
+05ae	hebrew accent zinor
+05af	hebrew mark masora circle
+05b0	hebrew point sheva
+05b1	hebrew point hataf segol
+05b2	hebrew point hataf patah
+05b3	hebrew point hataf qamats
+05b4	hebrew point hiriq
+05b5	hebrew point tsere
+05b6	hebrew point segol
+05b7	hebrew point patah
+05b8	hebrew point qamats
+05b9	hebrew point holam
+05bb	hebrew point qubuts
+05bc	hebrew point dagesh or mapiq
+05bd	hebrew point meteg
+05be	hebrew punctuation maqaf
+05bf	hebrew point rafe
+05c0	hebrew punctuation paseq
+05c1	hebrew point shin dot
+05c2	hebrew point sin dot
+05c3	hebrew punctuation sof pasuq
+05c4	hebrew mark upper dot
+05d0	hebrew letter alef
+05d1	hebrew letter bet
+05d2	hebrew letter gimel
+05d3	hebrew letter dalet
+05d4	hebrew letter he
+05d5	hebrew letter vav
+05d6	hebrew letter zayin
+05d7	hebrew letter het
+05d8	hebrew letter tet
+05d9	hebrew letter yod
+05da	hebrew letter final kaf
+05db	hebrew letter kaf
+05dc	hebrew letter lamed
+05dd	hebrew letter final mem
+05de	hebrew letter mem
+05df	hebrew letter final nun
+05e0	hebrew letter nun
+05e1	hebrew letter samekh
+05e2	hebrew letter ayin
+05e3	hebrew letter final pe
+05e4	hebrew letter pe
+05e5	hebrew letter final tsadi
+05e6	hebrew letter tsadi
+05e7	hebrew letter qof
+05e8	hebrew letter resh
+05e9	hebrew letter shin
+05ea	hebrew letter tav
+05f0	hebrew ligature yiddish double vav
+05f1	hebrew ligature yiddish vav yod
+05f2	hebrew ligature yiddish double yod
+05f3	hebrew punctuation geresh
+05f4	hebrew punctuation gershayim
+060c	arabic comma
+061b	arabic semicolon
+061f	arabic question mark
+0621	arabic letter hamza
+0622	arabic letter alef with madda above
+0623	arabic letter alef with hamza above
+0624	arabic letter waw with hamza above
+0625	arabic letter alef with hamza below
+0626	arabic letter yeh with hamza above
+0627	arabic letter alef
+0628	arabic letter beh
+0629	arabic letter teh marbuta
+062a	arabic letter teh
+062b	arabic letter theh
+062c	arabic letter jeem
+062d	arabic letter hah
+062e	arabic letter khah
+062f	arabic letter dal
+0630	arabic letter thal
+0631	arabic letter reh
+0632	arabic letter zain
+0633	arabic letter seen
+0634	arabic letter sheen
+0635	arabic letter sad
+0636	arabic letter dad
+0637	arabic letter tah
+0638	arabic letter zah
+0639	arabic letter ain
+063a	arabic letter ghain
+0640	arabic tatweel
+0641	arabic letter feh
+0642	arabic letter qaf
+0643	arabic letter kaf
+0644	arabic letter lam
+0645	arabic letter meem
+0646	arabic letter noon
+0647	arabic letter heh
+0648	arabic letter waw
+0649	arabic letter alef maksura
+064a	arabic letter yeh
+064b	arabic fathatan
+064c	arabic dammatan
+064d	arabic kasratan
+064e	arabic fatha
+064f	arabic damma
+0650	arabic kasra
+0651	arabic shadda
+0652	arabic sukun
+0660	arabic-indic digit zero
+0661	arabic-indic digit one
+0662	arabic-indic digit two
+0663	arabic-indic digit three
+0664	arabic-indic digit four
+0665	arabic-indic digit five
+0666	arabic-indic digit six
+0667	arabic-indic digit seven
+0668	arabic-indic digit eight
+0669	arabic-indic digit nine
+066a	arabic percent sign
+066b	arabic decimal separator
+066c	arabic thousands separator
+066d	arabic five pointed star
+0670	arabic letter superscript alef
+0671	arabic letter alef wasla
+0672	arabic letter alef with wavy hamza above
+0673	arabic letter alef with wavy hamza below
+0674	arabic letter high hamza
+0675	arabic letter high hamza alef
+0676	arabic letter high hamza waw
+0677	arabic letter u with hamza above
+0678	arabic letter high hamza yeh
+0679	arabic letter tteh
+067a	arabic letter tteheh
+067b	arabic letter beeh
+067c	arabic letter teh with ring
+067d	arabic letter teh with three dots above downwards
+067e	arabic letter peh
+067f	arabic letter teheh
+0680	arabic letter beheh
+0681	arabic letter hah with hamza above
+0682	arabic letter hah with two dots vertical above
+0683	arabic letter nyeh
+0684	arabic letter dyeh
+0685	arabic letter hah with three dots above
+0686	arabic letter tcheh
+0687	arabic letter tcheheh
+0688	arabic letter ddal
+0689	arabic letter dal with ring
+068a	arabic letter dal with dot below
+068b	arabic letter dal with dot below and small tah
+068c	arabic letter dahal
+068d	arabic letter ddahal
+068e	arabic letter dul
+068f	arabic letter dal with three dots above downwards
+0690	arabic letter dal with four dots above
+0691	arabic letter rreh
+0692	arabic letter reh with small v
+0693	arabic letter reh with ring
+0694	arabic letter reh with dot below
+0695	arabic letter reh with small v below
+0696	arabic letter reh with dot below and dot above
+0697	arabic letter reh with two dots above
+0698	arabic letter jeh
+0699	arabic letter reh with four dots above
+069a	arabic letter seen with dot below and dot above
+069b	arabic letter seen with three dots below
+069c	arabic letter seen with three dots below and three dots above
+069d	arabic letter sad with two dots below
+069e	arabic letter sad with three dots above
+069f	arabic letter tah with three dots above
+06a0	arabic letter ain with three dots above
+06a1	arabic letter dotless feh
+06a2	arabic letter feh with dot moved below
+06a3	arabic letter feh with dot below
+06a4	arabic letter veh
+06a5	arabic letter feh with three dots below
+06a6	arabic letter peheh
+06a7	arabic letter qaf with dot above
+06a8	arabic letter qaf with three dots above
+06a9	arabic letter keheh
+06aa	arabic letter swash kaf
+06ab	arabic letter kaf with ring
+06ac	arabic letter kaf with dot above
+06ad	arabic letter ng
+06ae	arabic letter kaf with three dots below
+06af	arabic letter gaf
+06b0	arabic letter gaf with ring
+06b1	arabic letter ngoeh
+06b2	arabic letter gaf with two dots below
+06b3	arabic letter gueh
+06b4	arabic letter gaf with three dots above
+06b5	arabic letter lam with small v
+06b6	arabic letter lam with dot above
+06b7	arabic letter lam with three dots above
+06ba	arabic letter noon ghunna
+06bb	arabic letter rnoon
+06bc	arabic letter noon with ring
+06bd	arabic letter noon with three dots above
+06be	arabic letter heh doachashmee
+06c0	arabic letter heh with yeh above
+06c1	arabic letter heh goal
+06c2	arabic letter heh goal with hamza above
+06c3	arabic letter teh marbuta goal
+06c4	arabic letter waw with ring
+06c5	arabic letter kirghiz oe
+06c6	arabic letter oe
+06c7	arabic letter u
+06c8	arabic letter yu
+06c9	arabic letter kirghiz yu
+06ca	arabic letter waw with two dots above
+06cb	arabic letter ve
+06cc	arabic letter farsi yeh
+06cd	arabic letter yeh with tail
+06ce	arabic letter yeh with small v
+06d0	arabic letter e
+06d1	arabic letter yeh with three dots below
+06d2	arabic letter yeh barree
+06d3	arabic letter yeh barree with hamza above
+06d4	arabic full stop
+06d5	arabic letter ae
+06d6	arabic small high ligature sad with lam with alef maksura
+06d7	arabic small high ligature qaf with lam with alef maksura
+06d8	arabic small high meem initial form
+06d9	arabic small high lam alef
+06da	arabic small high jeem
+06db	arabic small high three dots
+06dc	arabic small high seen
+06dd	arabic end of ayah
+06de	arabic start of rub el hizb
+06df	arabic small high rounded zero
+06e0	arabic small high upright rectangular zero
+06e1	arabic small high dotless head of khah
+06e2	arabic small high meem isolated form
+06e3	arabic small low seen
+06e4	arabic small high madda
+06e5	arabic small waw
+06e6	arabic small yeh
+06e7	arabic small high yeh
+06e8	arabic small high noon
+06e9	arabic place of sajdah
+06ea	arabic empty centre low stop
+06eb	arabic empty centre high stop
+06ec	arabic rounded high stop with filled centre
+06ed	arabic small low meem
+06f0	extended arabic-indic digit zero
+06f1	extended arabic-indic digit one
+06f2	extended arabic-indic digit two
+06f3	extended arabic-indic digit three
+06f4	extended arabic-indic digit four
+06f5	extended arabic-indic digit five
+06f6	extended arabic-indic digit six
+06f7	extended arabic-indic digit seven
+06f8	extended arabic-indic digit eight
+06f9	extended arabic-indic digit nine
+0901	devanagari sign candrabindu
+0902	devanagari sign anusvara
+0903	devanagari sign visarga
+0905	devanagari letter a
+0906	devanagari letter aa
+0907	devanagari letter i
+0908	devanagari letter ii
+0909	devanagari letter u
+090a	devanagari letter uu
+090b	devanagari letter vocalic r
+090c	devanagari letter vocalic l
+090d	devanagari letter candra e
+090e	devanagari letter short e
+090f	devanagari letter e
+0910	devanagari letter ai
+0911	devanagari letter candra o
+0912	devanagari letter short o
+0913	devanagari letter o
+0914	devanagari letter au
+0915	devanagari letter ka
+0916	devanagari letter kha
+0917	devanagari letter ga
+0918	devanagari letter gha
+0919	devanagari letter nga
+091a	devanagari letter ca
+091b	devanagari letter cha
+091c	devanagari letter ja
+091d	devanagari letter jha
+091e	devanagari letter nya
+091f	devanagari letter tta
+0920	devanagari letter ttha
+0921	devanagari letter dda
+0922	devanagari letter ddha
+0923	devanagari letter nna
+0924	devanagari letter ta
+0925	devanagari letter tha
+0926	devanagari letter da
+0927	devanagari letter dha
+0928	devanagari letter na
+0929	devanagari letter nnna
+092a	devanagari letter pa
+092b	devanagari letter pha
+092c	devanagari letter ba
+092d	devanagari letter bha
+092e	devanagari letter ma
+092f	devanagari letter ya
+0930	devanagari letter ra
+0931	devanagari letter rra
+0932	devanagari letter la
+0933	devanagari letter lla
+0934	devanagari letter llla
+0935	devanagari letter va
+0936	devanagari letter sha
+0937	devanagari letter ssa
+0938	devanagari letter sa
+0939	devanagari letter ha
+093c	devanagari sign nukta
+093d	devanagari sign avagraha
+093e	devanagari vowel sign aa
+093f	devanagari vowel sign i
+0940	devanagari vowel sign ii
+0941	devanagari vowel sign u
+0942	devanagari vowel sign uu
+0943	devanagari vowel sign vocalic r
+0944	devanagari vowel sign vocalic rr
+0945	devanagari vowel sign candra e
+0946	devanagari vowel sign short e
+0947	devanagari vowel sign e
+0948	devanagari vowel sign ai
+0949	devanagari vowel sign candra o
+094a	devanagari vowel sign short o
+094b	devanagari vowel sign o
+094c	devanagari vowel sign au
+094d	devanagari sign virama
+0950	devanagari om
+0951	devanagari stress sign udatta
+0952	devanagari stress sign anudatta
+0953	devanagari grave accent
+0954	devanagari acute accent
+0958	devanagari letter qa
+0959	devanagari letter khha
+095a	devanagari letter ghha
+095b	devanagari letter za
+095c	devanagari letter dddha
+095d	devanagari letter rha
+095e	devanagari letter fa
+095f	devanagari letter yya
+0960	devanagari letter vocalic rr
+0961	devanagari letter vocalic ll
+0962	devanagari vowel sign vocalic l
+0963	devanagari vowel sign vocalic ll
+0964	devanagari danda
+0965	devanagari double danda
+0966	devanagari digit zero
+0967	devanagari digit one
+0968	devanagari digit two
+0969	devanagari digit three
+096a	devanagari digit four
+096b	devanagari digit five
+096c	devanagari digit six
+096d	devanagari digit seven
+096e	devanagari digit eight
+096f	devanagari digit nine
+0970	devanagari abbreviation sign
+0981	bengali sign candrabindu
+0982	bengali sign anusvara
+0983	bengali sign visarga
+0985	bengali letter a
+0986	bengali letter aa
+0987	bengali letter i
+0988	bengali letter ii
+0989	bengali letter u
+098a	bengali letter uu
+098b	bengali letter vocalic r
+098c	bengali letter vocalic l
+098f	bengali letter e
+0990	bengali letter ai
+0993	bengali letter o
+0994	bengali letter au
+0995	bengali letter ka
+0996	bengali letter kha
+0997	bengali letter ga
+0998	bengali letter gha
+0999	bengali letter nga
+099a	bengali letter ca
+099b	bengali letter cha
+099c	bengali letter ja
+099d	bengali letter jha
+099e	bengali letter nya
+099f	bengali letter tta
+09a0	bengali letter ttha
+09a1	bengali letter dda
+09a2	bengali letter ddha
+09a3	bengali letter nna
+09a4	bengali letter ta
+09a5	bengali letter tha
+09a6	bengali letter da
+09a7	bengali letter dha
+09a8	bengali letter na
+09aa	bengali letter pa
+09ab	bengali letter pha
+09ac	bengali letter ba
+09ad	bengali letter bha
+09ae	bengali letter ma
+09af	bengali letter ya
+09b0	bengali letter ra
+09b2	bengali letter la
+09b6	bengali letter sha
+09b7	bengali letter ssa
+09b8	bengali letter sa
+09b9	bengali letter ha
+09bc	bengali sign nukta
+09be	bengali vowel sign aa
+09bf	bengali vowel sign i
+09c0	bengali vowel sign ii
+09c1	bengali vowel sign u
+09c2	bengali vowel sign uu
+09c3	bengali vowel sign vocalic r
+09c4	bengali vowel sign vocalic rr
+09c7	bengali vowel sign e
+09c8	bengali vowel sign ai
+09cb	bengali vowel sign o
+09cc	bengali vowel sign au
+09cd	bengali sign virama
+09d7	bengali au length mark
+09dc	bengali letter rra
+09dd	bengali letter rha
+09df	bengali letter yya
+09e0	bengali letter vocalic rr
+09e1	bengali letter vocalic ll
+09e2	bengali vowel sign vocalic l
+09e3	bengali vowel sign vocalic ll
+09e6	bengali digit zero
+09e7	bengali digit one
+09e8	bengali digit two
+09e9	bengali digit three
+09ea	bengali digit four
+09eb	bengali digit five
+09ec	bengali digit six
+09ed	bengali digit seven
+09ee	bengali digit eight
+09ef	bengali digit nine
+09f0	bengali letter ra with middle diagonal
+09f1	bengali letter ra with lower diagonal
+09f2	bengali rupee mark
+09f3	bengali rupee sign
+09f4	bengali currency numerator one
+09f5	bengali currency numerator two
+09f6	bengali currency numerator three
+09f7	bengali currency numerator four
+09f8	bengali currency numerator one less than the denominator
+09f9	bengali currency denominator sixteen
+09fa	bengali isshar
+0a02	gurmukhi sign bindi
+0a05	gurmukhi letter a
+0a06	gurmukhi letter aa
+0a07	gurmukhi letter i
+0a08	gurmukhi letter ii
+0a09	gurmukhi letter u
+0a0a	gurmukhi letter uu
+0a0f	gurmukhi letter ee
+0a10	gurmukhi letter ai
+0a13	gurmukhi letter oo
+0a14	gurmukhi letter au
+0a15	gurmukhi letter ka
+0a16	gurmukhi letter kha
+0a17	gurmukhi letter ga
+0a18	gurmukhi letter gha
+0a19	gurmukhi letter nga
+0a1a	gurmukhi letter ca
+0a1b	gurmukhi letter cha
+0a1c	gurmukhi letter ja
+0a1d	gurmukhi letter jha
+0a1e	gurmukhi letter nya
+0a1f	gurmukhi letter tta
+0a20	gurmukhi letter ttha
+0a21	gurmukhi letter dda
+0a22	gurmukhi letter ddha
+0a23	gurmukhi letter nna
+0a24	gurmukhi letter ta
+0a25	gurmukhi letter tha
+0a26	gurmukhi letter da
+0a27	gurmukhi letter dha
+0a28	gurmukhi letter na
+0a2a	gurmukhi letter pa
+0a2b	gurmukhi letter pha
+0a2c	gurmukhi letter ba
+0a2d	gurmukhi letter bha
+0a2e	gurmukhi letter ma
+0a2f	gurmukhi letter ya
+0a30	gurmukhi letter ra
+0a32	gurmukhi letter la
+0a33	gurmukhi letter lla
+0a35	gurmukhi letter va
+0a36	gurmukhi letter sha
+0a38	gurmukhi letter sa
+0a39	gurmukhi letter ha
+0a3c	gurmukhi sign nukta
+0a3e	gurmukhi vowel sign aa
+0a3f	gurmukhi vowel sign i
+0a40	gurmukhi vowel sign ii
+0a41	gurmukhi vowel sign u
+0a42	gurmukhi vowel sign uu
+0a47	gurmukhi vowel sign ee
+0a48	gurmukhi vowel sign ai
+0a4b	gurmukhi vowel sign oo
+0a4c	gurmukhi vowel sign au
+0a4d	gurmukhi sign virama
+0a59	gurmukhi letter khha
+0a5a	gurmukhi letter ghha
+0a5b	gurmukhi letter za
+0a5c	gurmukhi letter rra
+0a5e	gurmukhi letter fa
+0a66	gurmukhi digit zero
+0a67	gurmukhi digit one
+0a68	gurmukhi digit two
+0a69	gurmukhi digit three
+0a6a	gurmukhi digit four
+0a6b	gurmukhi digit five
+0a6c	gurmukhi digit six
+0a6d	gurmukhi digit seven
+0a6e	gurmukhi digit eight
+0a6f	gurmukhi digit nine
+0a70	gurmukhi tippi
+0a71	gurmukhi addak
+0a72	gurmukhi iri
+0a73	gurmukhi ura
+0a74	gurmukhi ek onkar
+0a81	gujarati sign candrabindu
+0a82	gujarati sign anusvara
+0a83	gujarati sign visarga
+0a85	gujarati letter a
+0a86	gujarati letter aa
+0a87	gujarati letter i
+0a88	gujarati letter ii
+0a89	gujarati letter u
+0a8a	gujarati letter uu
+0a8b	gujarati letter vocalic r
+0a8d	gujarati vowel candra e
+0a8f	gujarati letter e
+0a90	gujarati letter ai
+0a91	gujarati vowel candra o
+0a93	gujarati letter o
+0a94	gujarati letter au
+0a95	gujarati letter ka
+0a96	gujarati letter kha
+0a97	gujarati letter ga
+0a98	gujarati letter gha
+0a99	gujarati letter nga
+0a9a	gujarati letter ca
+0a9b	gujarati letter cha
+0a9c	gujarati letter ja
+0a9d	gujarati letter jha
+0a9e	gujarati letter nya
+0a9f	gujarati letter tta
+0aa0	gujarati letter ttha
+0aa1	gujarati letter dda
+0aa2	gujarati letter ddha
+0aa3	gujarati letter nna
+0aa4	gujarati letter ta
+0aa5	gujarati letter tha
+0aa6	gujarati letter da
+0aa7	gujarati letter dha
+0aa8	gujarati letter na
+0aaa	gujarati letter pa
+0aab	gujarati letter pha
+0aac	gujarati letter ba
+0aad	gujarati letter bha
+0aae	gujarati letter ma
+0aaf	gujarati letter ya
+0ab0	gujarati letter ra
+0ab2	gujarati letter la
+0ab3	gujarati letter lla
+0ab5	gujarati letter va
+0ab6	gujarati letter sha
+0ab7	gujarati letter ssa
+0ab8	gujarati letter sa
+0ab9	gujarati letter ha
+0abc	gujarati sign nukta
+0abd	gujarati sign avagraha
+0abe	gujarati vowel sign aa
+0abf	gujarati vowel sign i
+0ac0	gujarati vowel sign ii
+0ac1	gujarati vowel sign u
+0ac2	gujarati vowel sign uu
+0ac3	gujarati vowel sign vocalic r
+0ac4	gujarati vowel sign vocalic rr
+0ac5	gujarati vowel sign candra e
+0ac7	gujarati vowel sign e
+0ac8	gujarati vowel sign ai
+0ac9	gujarati vowel sign candra o
+0acb	gujarati vowel sign o
+0acc	gujarati vowel sign au
+0acd	gujarati sign virama
+0ad0	gujarati om
+0ae0	gujarati letter vocalic rr
+0ae6	gujarati digit zero
+0ae7	gujarati digit one
+0ae8	gujarati digit two
+0ae9	gujarati digit three
+0aea	gujarati digit four
+0aeb	gujarati digit five
+0aec	gujarati digit six
+0aed	gujarati digit seven
+0aee	gujarati digit eight
+0aef	gujarati digit nine
+0b01	oriya sign candrabindu
+0b02	oriya sign anusvara
+0b03	oriya sign visarga
+0b05	oriya letter a
+0b06	oriya letter aa
+0b07	oriya letter i
+0b08	oriya letter ii
+0b09	oriya letter u
+0b0a	oriya letter uu
+0b0b	oriya letter vocalic r
+0b0c	oriya letter vocalic l
+0b0f	oriya letter e
+0b10	oriya letter ai
+0b13	oriya letter o
+0b14	oriya letter au
+0b15	oriya letter ka
+0b16	oriya letter kha
+0b17	oriya letter ga
+0b18	oriya letter gha
+0b19	oriya letter nga
+0b1a	oriya letter ca
+0b1b	oriya letter cha
+0b1c	oriya letter ja
+0b1d	oriya letter jha
+0b1e	oriya letter nya
+0b1f	oriya letter tta
+0b20	oriya letter ttha
+0b21	oriya letter dda
+0b22	oriya letter ddha
+0b23	oriya letter nna
+0b24	oriya letter ta
+0b25	oriya letter tha
+0b26	oriya letter da
+0b27	oriya letter dha
+0b28	oriya letter na
+0b2a	oriya letter pa
+0b2b	oriya letter pha
+0b2c	oriya letter ba
+0b2d	oriya letter bha
+0b2e	oriya letter ma
+0b2f	oriya letter ya
+0b30	oriya letter ra
+0b32	oriya letter la
+0b33	oriya letter lla
+0b36	oriya letter sha
+0b37	oriya letter ssa
+0b38	oriya letter sa
+0b39	oriya letter ha
+0b3c	oriya sign nukta
+0b3d	oriya sign avagraha
+0b3e	oriya vowel sign aa
+0b3f	oriya vowel sign i
+0b40	oriya vowel sign ii
+0b41	oriya vowel sign u
+0b42	oriya vowel sign uu
+0b43	oriya vowel sign vocalic r
+0b47	oriya vowel sign e
+0b48	oriya vowel sign ai
+0b4b	oriya vowel sign o
+0b4c	oriya vowel sign au
+0b4d	oriya sign virama
+0b56	oriya ai length mark
+0b57	oriya au length mark
+0b5c	oriya letter rra
+0b5d	oriya letter rha
+0b5f	oriya letter yya
+0b60	oriya letter vocalic rr
+0b61	oriya letter vocalic ll
+0b66	oriya digit zero
+0b67	oriya digit one
+0b68	oriya digit two
+0b69	oriya digit three
+0b6a	oriya digit four
+0b6b	oriya digit five
+0b6c	oriya digit six
+0b6d	oriya digit seven
+0b6e	oriya digit eight
+0b6f	oriya digit nine
+0b70	oriya isshar
+0b82	tamil sign anusvara
+0b83	tamil sign visarga
+0b85	tamil letter a
+0b86	tamil letter aa
+0b87	tamil letter i
+0b88	tamil letter ii
+0b89	tamil letter u
+0b8a	tamil letter uu
+0b8e	tamil letter e
+0b8f	tamil letter ee
+0b90	tamil letter ai
+0b92	tamil letter o
+0b93	tamil letter oo
+0b94	tamil letter au
+0b95	tamil letter ka
+0b99	tamil letter nga
+0b9a	tamil letter ca
+0b9c	tamil letter ja
+0b9e	tamil letter nya
+0b9f	tamil letter tta
+0ba3	tamil letter nna
+0ba4	tamil letter ta
+0ba8	tamil letter na
+0ba9	tamil letter nnna
+0baa	tamil letter pa
+0bae	tamil letter ma
+0baf	tamil letter ya
+0bb0	tamil letter ra
+0bb1	tamil letter rra
+0bb2	tamil letter la
+0bb3	tamil letter lla
+0bb4	tamil letter llla
+0bb5	tamil letter va
+0bb7	tamil letter ssa
+0bb8	tamil letter sa
+0bb9	tamil letter ha
+0bbe	tamil vowel sign aa
+0bbf	tamil vowel sign i
+0bc0	tamil vowel sign ii
+0bc1	tamil vowel sign u
+0bc2	tamil vowel sign uu
+0bc6	tamil vowel sign e
+0bc7	tamil vowel sign ee
+0bc8	tamil vowel sign ai
+0bca	tamil vowel sign o
+0bcb	tamil vowel sign oo
+0bcc	tamil vowel sign au
+0bcd	tamil sign virama
+0bd7	tamil au length mark
+0be7	tamil digit one
+0be8	tamil digit two
+0be9	tamil digit three
+0bea	tamil digit four
+0beb	tamil digit five
+0bec	tamil digit six
+0bed	tamil digit seven
+0bee	tamil digit eight
+0bef	tamil digit nine
+0bf0	tamil number ten
+0bf1	tamil number one hundred
+0bf2	tamil number one thousand
+0c01	telugu sign candrabindu
+0c02	telugu sign anusvara
+0c03	telugu sign visarga
+0c05	telugu letter a
+0c06	telugu letter aa
+0c07	telugu letter i
+0c08	telugu letter ii
+0c09	telugu letter u
+0c0a	telugu letter uu
+0c0b	telugu letter vocalic r
+0c0c	telugu letter vocalic l
+0c0e	telugu letter e
+0c0f	telugu letter ee
+0c10	telugu letter ai
+0c12	telugu letter o
+0c13	telugu letter oo
+0c14	telugu letter au
+0c15	telugu letter ka
+0c16	telugu letter kha
+0c17	telugu letter ga
+0c18	telugu letter gha
+0c19	telugu letter nga
+0c1a	telugu letter ca
+0c1b	telugu letter cha
+0c1c	telugu letter ja
+0c1d	telugu letter jha
+0c1e	telugu letter nya
+0c1f	telugu letter tta
+0c20	telugu letter ttha
+0c21	telugu letter dda
+0c22	telugu letter ddha
+0c23	telugu letter nna
+0c24	telugu letter ta
+0c25	telugu letter tha
+0c26	telugu letter da
+0c27	telugu letter dha
+0c28	telugu letter na
+0c2a	telugu letter pa
+0c2b	telugu letter pha
+0c2c	telugu letter ba
+0c2d	telugu letter bha
+0c2e	telugu letter ma
+0c2f	telugu letter ya
+0c30	telugu letter ra
+0c31	telugu letter rra
+0c32	telugu letter la
+0c33	telugu letter lla
+0c35	telugu letter va
+0c36	telugu letter sha
+0c37	telugu letter ssa
+0c38	telugu letter sa
+0c39	telugu letter ha
+0c3e	telugu vowel sign aa
+0c3f	telugu vowel sign i
+0c40	telugu vowel sign ii
+0c41	telugu vowel sign u
+0c42	telugu vowel sign uu
+0c43	telugu vowel sign vocalic r
+0c44	telugu vowel sign vocalic rr
+0c46	telugu vowel sign e
+0c47	telugu vowel sign ee
+0c48	telugu vowel sign ai
+0c4a	telugu vowel sign o
+0c4b	telugu vowel sign oo
+0c4c	telugu vowel sign au
+0c4d	telugu sign virama
+0c55	telugu length mark
+0c56	telugu ai length mark
+0c60	telugu letter vocalic rr
+0c61	telugu letter vocalic ll
+0c66	telugu digit zero
+0c67	telugu digit one
+0c68	telugu digit two
+0c69	telugu digit three
+0c6a	telugu digit four
+0c6b	telugu digit five
+0c6c	telugu digit six
+0c6d	telugu digit seven
+0c6e	telugu digit eight
+0c6f	telugu digit nine
+0c82	kannada sign anusvara
+0c83	kannada sign visarga
+0c85	kannada letter a
+0c86	kannada letter aa
+0c87	kannada letter i
+0c88	kannada letter ii
+0c89	kannada letter u
+0c8a	kannada letter uu
+0c8b	kannada letter vocalic r
+0c8c	kannada letter vocalic l
+0c8e	kannada letter e
+0c8f	kannada letter ee
+0c90	kannada letter ai
+0c92	kannada letter o
+0c93	kannada letter oo
+0c94	kannada letter au
+0c95	kannada letter ka
+0c96	kannada letter kha
+0c97	kannada letter ga
+0c98	kannada letter gha
+0c99	kannada letter nga
+0c9a	kannada letter ca
+0c9b	kannada letter cha
+0c9c	kannada letter ja
+0c9d	kannada letter jha
+0c9e	kannada letter nya
+0c9f	kannada letter tta
+0ca0	kannada letter ttha
+0ca1	kannada letter dda
+0ca2	kannada letter ddha
+0ca3	kannada letter nna
+0ca4	kannada letter ta
+0ca5	kannada letter tha
+0ca6	kannada letter da
+0ca7	kannada letter dha
+0ca8	kannada letter na
+0caa	kannada letter pa
+0cab	kannada letter pha
+0cac	kannada letter ba
+0cad	kannada letter bha
+0cae	kannada letter ma
+0caf	kannada letter ya
+0cb0	kannada letter ra
+0cb1	kannada letter rra
+0cb2	kannada letter la
+0cb3	kannada letter lla
+0cb5	kannada letter va
+0cb6	kannada letter sha
+0cb7	kannada letter ssa
+0cb8	kannada letter sa
+0cb9	kannada letter ha
+0cbe	kannada vowel sign aa
+0cbf	kannada vowel sign i
+0cc0	kannada vowel sign ii
+0cc1	kannada vowel sign u
+0cc2	kannada vowel sign uu
+0cc3	kannada vowel sign vocalic r
+0cc4	kannada vowel sign vocalic rr
+0cc6	kannada vowel sign e
+0cc7	kannada vowel sign ee
+0cc8	kannada vowel sign ai
+0cca	kannada vowel sign o
+0ccb	kannada vowel sign oo
+0ccc	kannada vowel sign au
+0ccd	kannada sign virama
+0cd5	kannada length mark
+0cd6	kannada ai length mark
+0cde	kannada letter fa
+0ce0	kannada letter vocalic rr
+0ce1	kannada letter vocalic ll
+0ce6	kannada digit zero
+0ce7	kannada digit one
+0ce8	kannada digit two
+0ce9	kannada digit three
+0cea	kannada digit four
+0ceb	kannada digit five
+0cec	kannada digit six
+0ced	kannada digit seven
+0cee	kannada digit eight
+0cef	kannada digit nine
+0d02	malayalam sign anusvara
+0d03	malayalam sign visarga
+0d05	malayalam letter a
+0d06	malayalam letter aa
+0d07	malayalam letter i
+0d08	malayalam letter ii
+0d09	malayalam letter u
+0d0a	malayalam letter uu
+0d0b	malayalam letter vocalic r
+0d0c	malayalam letter vocalic l
+0d0e	malayalam letter e
+0d0f	malayalam letter ee
+0d10	malayalam letter ai
+0d12	malayalam letter o
+0d13	malayalam letter oo
+0d14	malayalam letter au
+0d15	malayalam letter ka
+0d16	malayalam letter kha
+0d17	malayalam letter ga
+0d18	malayalam letter gha
+0d19	malayalam letter nga
+0d1a	malayalam letter ca
+0d1b	malayalam letter cha
+0d1c	malayalam letter ja
+0d1d	malayalam letter jha
+0d1e	malayalam letter nya
+0d1f	malayalam letter tta
+0d20	malayalam letter ttha
+0d21	malayalam letter dda
+0d22	malayalam letter ddha
+0d23	malayalam letter nna
+0d24	malayalam letter ta
+0d25	malayalam letter tha
+0d26	malayalam letter da
+0d27	malayalam letter dha
+0d28	malayalam letter na
+0d2a	malayalam letter pa
+0d2b	malayalam letter pha
+0d2c	malayalam letter ba
+0d2d	malayalam letter bha
+0d2e	malayalam letter ma
+0d2f	malayalam letter ya
+0d30	malayalam letter ra
+0d31	malayalam letter rra
+0d32	malayalam letter la
+0d33	malayalam letter lla
+0d34	malayalam letter llla
+0d35	malayalam letter va
+0d36	malayalam letter sha
+0d37	malayalam letter ssa
+0d38	malayalam letter sa
+0d39	malayalam letter ha
+0d3e	malayalam vowel sign aa
+0d3f	malayalam vowel sign i
+0d40	malayalam vowel sign ii
+0d41	malayalam vowel sign u
+0d42	malayalam vowel sign uu
+0d43	malayalam vowel sign vocalic r
+0d46	malayalam vowel sign e
+0d47	malayalam vowel sign ee
+0d48	malayalam vowel sign ai
+0d4a	malayalam vowel sign o
+0d4b	malayalam vowel sign oo
+0d4c	malayalam vowel sign au
+0d4d	malayalam sign virama
+0d57	malayalam au length mark
+0d60	malayalam letter vocalic rr
+0d61	malayalam letter vocalic ll
+0d66	malayalam digit zero
+0d67	malayalam digit one
+0d68	malayalam digit two
+0d69	malayalam digit three
+0d6a	malayalam digit four
+0d6b	malayalam digit five
+0d6c	malayalam digit six
+0d6d	malayalam digit seven
+0d6e	malayalam digit eight
+0d6f	malayalam digit nine
+0e01	thai character ko kai
+0e02	thai character kho khai
+0e03	thai character kho khuat
+0e04	thai character kho khwai
+0e05	thai character kho khon
+0e06	thai character kho rakhang
+0e07	thai character ngo ngu
+0e08	thai character cho chan
+0e09	thai character cho ching
+0e0a	thai character cho chang
+0e0b	thai character so so
+0e0c	thai character cho choe
+0e0d	thai character yo ying
+0e0e	thai character do chada
+0e0f	thai character to patak
+0e10	thai character tho than
+0e11	thai character tho nangmontho
+0e12	thai character tho phuthao
+0e13	thai character no nen
+0e14	thai character do dek
+0e15	thai character to tao
+0e16	thai character tho thung
+0e17	thai character tho thahan
+0e18	thai character tho thong
+0e19	thai character no nu
+0e1a	thai character bo baimai
+0e1b	thai character po pla
+0e1c	thai character pho phung
+0e1d	thai character fo fa
+0e1e	thai character pho phan
+0e1f	thai character fo fan
+0e20	thai character pho samphao
+0e21	thai character mo ma
+0e22	thai character yo yak
+0e23	thai character ro rua
+0e24	thai character ru
+0e25	thai character lo ling
+0e26	thai character lu
+0e27	thai character wo waen
+0e28	thai character so sala
+0e29	thai character so rusi
+0e2a	thai character so sua
+0e2b	thai character ho hip
+0e2c	thai character lo chula
+0e2d	thai character o ang
+0e2e	thai character ho nokhuk
+0e2f	thai character paiyannoi
+0e30	thai character sara a
+0e31	thai character mai han-akat
+0e32	thai character sara aa
+0e33	thai character sara am
+0e34	thai character sara i
+0e35	thai character sara ii
+0e36	thai character sara ue
+0e37	thai character sara uee
+0e38	thai character sara u
+0e39	thai character sara uu
+0e3a	thai character phinthu
+0e3f	thai currency symbol baht
+0e40	thai character sara e
+0e41	thai character sara ae
+0e42	thai character sara o
+0e43	thai character sara ai maimuan
+0e44	thai character sara ai maimalai
+0e45	thai character lakkhangyao
+0e46	thai character maiyamok
+0e47	thai character maitaikhu
+0e48	thai character mai ek
+0e49	thai character mai tho
+0e4a	thai character mai tri
+0e4b	thai character mai chattawa
+0e4c	thai character thanthakhat
+0e4d	thai character nikhahit
+0e4e	thai character yamakkan
+0e4f	thai character fongman
+0e50	thai digit zero
+0e51	thai digit one
+0e52	thai digit two
+0e53	thai digit three
+0e54	thai digit four
+0e55	thai digit five
+0e56	thai digit six
+0e57	thai digit seven
+0e58	thai digit eight
+0e59	thai digit nine
+0e5a	thai character angkhankhu
+0e5b	thai character khomut
+0e81	lao letter ko
+0e82	lao letter kho sung
+0e84	lao letter kho tam
+0e87	lao letter ngo
+0e88	lao letter co
+0e8a	lao letter so tam
+0e8d	lao letter nyo
+0e94	lao letter do
+0e95	lao letter to
+0e96	lao letter tho sung
+0e97	lao letter tho tam
+0e99	lao letter no
+0e9a	lao letter bo
+0e9b	lao letter po
+0e9c	lao letter pho sung
+0e9d	lao letter fo tam
+0e9e	lao letter pho tam
+0e9f	lao letter fo sung
+0ea1	lao letter mo
+0ea2	lao letter yo
+0ea3	lao letter lo ling
+0ea5	lao letter lo loot
+0ea7	lao letter wo
+0eaa	lao letter so sung
+0eab	lao letter ho sung
+0ead	lao letter o
+0eae	lao letter ho tam
+0eaf	lao ellipsis
+0eb0	lao vowel sign a
+0eb1	lao vowel sign mai kan
+0eb2	lao vowel sign aa
+0eb3	lao vowel sign am
+0eb4	lao vowel sign i
+0eb5	lao vowel sign ii
+0eb6	lao vowel sign y
+0eb7	lao vowel sign yy
+0eb8	lao vowel sign u
+0eb9	lao vowel sign uu
+0ebb	lao vowel sign mai kon
+0ebc	lao semivowel sign lo
+0ebd	lao semivowel sign nyo
+0ec0	lao vowel sign e
+0ec1	lao vowel sign ei
+0ec2	lao vowel sign o
+0ec3	lao vowel sign ay
+0ec4	lao vowel sign ai
+0ec6	lao ko la
+0ec8	lao tone mai ek
+0ec9	lao tone mai tho
+0eca	lao tone mai ti
+0ecb	lao tone mai catawa
+0ecc	lao cancellation mark
+0ecd	lao niggahita
+0ed0	lao digit zero
+0ed1	lao digit one
+0ed2	lao digit two
+0ed3	lao digit three
+0ed4	lao digit four
+0ed5	lao digit five
+0ed6	lao digit six
+0ed7	lao digit seven
+0ed8	lao digit eight
+0ed9	lao digit nine
+0edc	lao ho no
+0edd	lao ho mo
+0f00	tibetan syllable om
+0f01	tibetan mark gter yig mgo truncated a
+0f02	tibetan mark gter yig mgo -um rnam bcad ma
+0f03	tibetan mark gter yig mgo -um gter tsheg ma
+0f04	tibetan mark initial yig mgo mdun ma
+0f05	tibetan mark closing yig mgo sgab ma
+0f06	tibetan mark caret yig mgo phur shad ma
+0f07	tibetan mark yig mgo tsheg shad ma
+0f08	tibetan mark sbrul shad
+0f09	tibetan mark bskur yig mgo
+0f0a	tibetan mark bka- shog yig mgo
+0f0b	tibetan mark intersyllabic tsheg
+0f0c	tibetan mark delimiter tsheg bstar
+0f0d	tibetan mark shad
+0f0e	tibetan mark nyis shad
+0f0f	tibetan mark tsheg shad
+0f10	tibetan mark nyis tsheg shad
+0f11	tibetan mark rin chen spungs shad
+0f12	tibetan mark rgya gram shad
+0f13	tibetan mark caret -dzud rtags me long can
+0f14	tibetan mark gter tsheg
+0f15	tibetan logotype sign chad rtags
+0f16	tibetan logotype sign lhag rtags
+0f17	tibetan astrological sign sgra gcan -char rtags
+0f18	tibetan astrological sign -khyud pa
+0f19	tibetan astrological sign sdong tshugs
+0f1a	tibetan sign rdel dkar gcig
+0f1b	tibetan sign rdel dkar gnyis
+0f1c	tibetan sign rdel dkar gsum
+0f1d	tibetan sign rdel nag gcig
+0f1e	tibetan sign rdel nag gnyis
+0f1f	tibetan sign rdel dkar rdel nag
+0f20	tibetan digit zero
+0f21	tibetan digit one
+0f22	tibetan digit two
+0f23	tibetan digit three
+0f24	tibetan digit four
+0f25	tibetan digit five
+0f26	tibetan digit six
+0f27	tibetan digit seven
+0f28	tibetan digit eight
+0f29	tibetan digit nine
+0f2a	tibetan digit half one
+0f2b	tibetan digit half two
+0f2c	tibetan digit half three
+0f2d	tibetan digit half four
+0f2e	tibetan digit half five
+0f2f	tibetan digit half six
+0f30	tibetan digit half seven
+0f31	tibetan digit half eight
+0f32	tibetan digit half nine
+0f33	tibetan digit half zero
+0f34	tibetan mark bsdus rtags
+0f35	tibetan mark ngas bzung nyi zla
+0f36	tibetan mark caret -dzud rtags bzhi mig can
+0f37	tibetan mark ngas bzung sgor rtags
+0f38	tibetan mark che mgo
+0f39	tibetan mark tsa -phru
+0f3a	tibetan mark gug rtags gyon
+0f3b	tibetan mark gug rtags gyas
+0f3c	tibetan mark ang khang gyon
+0f3d	tibetan mark ang khang gyas
+0f3e	tibetan sign yar tshes
+0f3f	tibetan sign mar tshes
+0f40	tibetan letter ka
+0f41	tibetan letter kha
+0f42	tibetan letter ga
+0f43	tibetan letter gha
+0f44	tibetan letter nga
+0f45	tibetan letter ca
+0f46	tibetan letter cha
+0f47	tibetan letter ja
+0f49	tibetan letter nya
+0f4a	tibetan letter tta
+0f4b	tibetan letter ttha
+0f4c	tibetan letter dda
+0f4d	tibetan letter ddha
+0f4e	tibetan letter nna
+0f4f	tibetan letter ta
+0f50	tibetan letter tha
+0f51	tibetan letter da
+0f52	tibetan letter dha
+0f53	tibetan letter na
+0f54	tibetan letter pa
+0f55	tibetan letter pha
+0f56	tibetan letter ba
+0f57	tibetan letter bha
+0f58	tibetan letter ma
+0f59	tibetan letter tsa
+0f5a	tibetan letter tsha
+0f5b	tibetan letter dza
+0f5c	tibetan letter dzha
+0f5d	tibetan letter wa
+0f5e	tibetan letter zha
+0f5f	tibetan letter za
+0f60	tibetan letter -a
+0f61	tibetan letter ya
+0f62	tibetan letter ra
+0f63	tibetan letter la
+0f64	tibetan letter sha
+0f65	tibetan letter ssa
+0f66	tibetan letter sa
+0f67	tibetan letter ha
+0f68	tibetan letter a
+0f69	tibetan letter kssa
+0f71	tibetan vowel sign aa
+0f72	tibetan vowel sign i
+0f73	tibetan vowel sign ii
+0f74	tibetan vowel sign u
+0f75	tibetan vowel sign uu
+0f76	tibetan vowel sign vocalic r
+0f77	tibetan vowel sign vocalic rr
+0f78	tibetan vowel sign vocalic l
+0f79	tibetan vowel sign vocalic ll
+0f7a	tibetan vowel sign e
+0f7b	tibetan vowel sign ee
+0f7c	tibetan vowel sign o
+0f7d	tibetan vowel sign oo
+0f7e	tibetan sign rjes su nga ro
+0f7f	tibetan sign rnam bcad
+0f80	tibetan vowel sign reversed i
+0f81	tibetan vowel sign reversed ii
+0f82	tibetan sign nyi zla naa da
+0f83	tibetan sign sna ldan
+0f84	tibetan mark halanta
+0f85	tibetan mark paluta
+0f86	tibetan sign lci rtags
+0f87	tibetan sign yang rtags
+0f88	tibetan sign lce tsa can
+0f89	tibetan sign mchu can
+0f8a	tibetan sign gru can rgyings
+0f8b	tibetan sign gru med rgyings
+0f90	tibetan subjoined letter ka
+0f91	tibetan subjoined letter kha
+0f92	tibetan subjoined letter ga
+0f93	tibetan subjoined letter gha
+0f94	tibetan subjoined letter nga
+0f95	tibetan subjoined letter ca
+0f97	tibetan subjoined letter ja
+0f99	tibetan subjoined letter nya
+0f9a	tibetan subjoined letter tta
+0f9b	tibetan subjoined letter ttha
+0f9c	tibetan subjoined letter dda
+0f9d	tibetan subjoined letter ddha
+0f9e	tibetan subjoined letter nna
+0f9f	tibetan subjoined letter ta
+0fa0	tibetan subjoined letter tha
+0fa1	tibetan subjoined letter da
+0fa2	tibetan subjoined letter dha
+0fa3	tibetan subjoined letter na
+0fa4	tibetan subjoined letter pa
+0fa5	tibetan subjoined letter pha
+0fa6	tibetan subjoined letter ba
+0fa7	tibetan subjoined letter bha
+0fa8	tibetan subjoined letter ma
+0fa9	tibetan subjoined letter tsa
+0faa	tibetan subjoined letter tsha
+0fab	tibetan subjoined letter dza
+0fac	tibetan subjoined letter dzha
+0fad	tibetan subjoined letter wa
+0fb1	tibetan subjoined letter ya
+0fb2	tibetan subjoined letter ra
+0fb3	tibetan subjoined letter la
+0fb4	tibetan subjoined letter sha
+0fb5	tibetan subjoined letter ssa
+0fb6	tibetan subjoined letter sa
+0fb7	tibetan subjoined letter ha
+0fb9	tibetan subjoined letter kssa
+10a0	georgian capital letter an
+10a1	georgian capital letter ban
+10a2	georgian capital letter gan
+10a3	georgian capital letter don
+10a4	georgian capital letter en
+10a5	georgian capital letter vin
+10a6	georgian capital letter zen
+10a7	georgian capital letter tan
+10a8	georgian capital letter in
+10a9	georgian capital letter kan
+10aa	georgian capital letter las
+10ab	georgian capital letter man
+10ac	georgian capital letter nar
+10ad	georgian capital letter on
+10ae	georgian capital letter par
+10af	georgian capital letter zhar
+10b0	georgian capital letter rae
+10b1	georgian capital letter san
+10b2	georgian capital letter tar
+10b3	georgian capital letter un
+10b4	georgian capital letter phar
+10b5	georgian capital letter khar
+10b6	georgian capital letter ghan
+10b7	georgian capital letter qar
+10b8	georgian capital letter shin
+10b9	georgian capital letter chin
+10ba	georgian capital letter can
+10bb	georgian capital letter jil
+10bc	georgian capital letter cil
+10bd	georgian capital letter char
+10be	georgian capital letter xan
+10bf	georgian capital letter jhan
+10c0	georgian capital letter hae
+10c1	georgian capital letter he
+10c2	georgian capital letter hie
+10c3	georgian capital letter we
+10c4	georgian capital letter har
+10c5	georgian capital letter hoe
+10d0	georgian letter an
+10d1	georgian letter ban
+10d2	georgian letter gan
+10d3	georgian letter don
+10d4	georgian letter en
+10d5	georgian letter vin
+10d6	georgian letter zen
+10d7	georgian letter tan
+10d8	georgian letter in
+10d9	georgian letter kan
+10da	georgian letter las
+10db	georgian letter man
+10dc	georgian letter nar
+10dd	georgian letter on
+10de	georgian letter par
+10df	georgian letter zhar
+10e0	georgian letter rae
+10e1	georgian letter san
+10e2	georgian letter tar
+10e3	georgian letter un
+10e4	georgian letter phar
+10e5	georgian letter khar
+10e6	georgian letter ghan
+10e7	georgian letter qar
+10e8	georgian letter shin
+10e9	georgian letter chin
+10ea	georgian letter can
+10eb	georgian letter jil
+10ec	georgian letter cil
+10ed	georgian letter char
+10ee	georgian letter xan
+10ef	georgian letter jhan
+10f0	georgian letter hae
+10f1	georgian letter he
+10f2	georgian letter hie
+10f3	georgian letter we
+10f4	georgian letter har
+10f5	georgian letter hoe
+10f6	georgian letter fi
+10fb	georgian paragraph separator
+1100	hangul choseong kiyeok
+1101	hangul choseong ssangkiyeok
+1102	hangul choseong nieun
+1103	hangul choseong tikeut
+1104	hangul choseong ssangtikeut
+1105	hangul choseong rieul
+1106	hangul choseong mieum
+1107	hangul choseong pieup
+1108	hangul choseong ssangpieup
+1109	hangul choseong sios
+110a	hangul choseong ssangsios
+110b	hangul choseong ieung
+110c	hangul choseong cieuc
+110d	hangul choseong ssangcieuc
+110e	hangul choseong chieuch
+110f	hangul choseong khieukh
+1110	hangul choseong thieuth
+1111	hangul choseong phieuph
+1112	hangul choseong hieuh
+1113	hangul choseong nieun-kiyeok
+1114	hangul choseong ssangnieun
+1115	hangul choseong nieun-tikeut
+1116	hangul choseong nieun-pieup
+1117	hangul choseong tikeut-kiyeok
+1118	hangul choseong rieul-nieun
+1119	hangul choseong ssangrieul
+111a	hangul choseong rieul-hieuh
+111b	hangul choseong kapyeounrieul
+111c	hangul choseong mieum-pieup
+111d	hangul choseong kapyeounmieum
+111e	hangul choseong pieup-kiyeok
+111f	hangul choseong pieup-nieun
+1120	hangul choseong pieup-tikeut
+1121	hangul choseong pieup-sios
+1122	hangul choseong pieup-sios-kiyeok
+1123	hangul choseong pieup-sios-tikeut
+1124	hangul choseong pieup-sios-pieup
+1125	hangul choseong pieup-ssangsios
+1126	hangul choseong pieup-sios-cieuc
+1127	hangul choseong pieup-cieuc
+1128	hangul choseong pieup-chieuch
+1129	hangul choseong pieup-thieuth
+112a	hangul choseong pieup-phieuph
+112b	hangul choseong kapyeounpieup
+112c	hangul choseong kapyeounssangpieup
+112d	hangul choseong sios-kiyeok
+112e	hangul choseong sios-nieun
+112f	hangul choseong sios-tikeut
+1130	hangul choseong sios-rieul
+1131	hangul choseong sios-mieum
+1132	hangul choseong sios-pieup
+1133	hangul choseong sios-pieup-kiyeok
+1134	hangul choseong sios-ssangsios
+1135	hangul choseong sios-ieung
+1136	hangul choseong sios-cieuc
+1137	hangul choseong sios-chieuch
+1138	hangul choseong sios-khieukh
+1139	hangul choseong sios-thieuth
+113a	hangul choseong sios-phieuph
+113b	hangul choseong sios-hieuh
+113c	hangul choseong chitueumsios
+113d	hangul choseong chitueumssangsios
+113e	hangul choseong ceongchieumsios
+113f	hangul choseong ceongchieumssangsios
+1140	hangul choseong pansios
+1141	hangul choseong ieung-kiyeok
+1142	hangul choseong ieung-tikeut
+1143	hangul choseong ieung-mieum
+1144	hangul choseong ieung-pieup
+1145	hangul choseong ieung-sios
+1146	hangul choseong ieung-pansios
+1147	hangul choseong ssangieung
+1148	hangul choseong ieung-cieuc
+1149	hangul choseong ieung-chieuch
+114a	hangul choseong ieung-thieuth
+114b	hangul choseong ieung-phieuph
+114c	hangul choseong yesieung
+114d	hangul choseong cieuc-ieung
+114e	hangul choseong chitueumcieuc
+114f	hangul choseong chitueumssangcieuc
+1150	hangul choseong ceongchieumcieuc
+1151	hangul choseong ceongchieumssangcieuc
+1152	hangul choseong chieuch-khieukh
+1153	hangul choseong chieuch-hieuh
+1154	hangul choseong chitueumchieuch
+1155	hangul choseong ceongchieumchieuch
+1156	hangul choseong phieuph-pieup
+1157	hangul choseong kapyeounphieuph
+1158	hangul choseong ssanghieuh
+1159	hangul choseong yeorinhieuh
+115f	hangul choseong filler
+1160	hangul jungseong filler
+1161	hangul jungseong a
+1162	hangul jungseong ae
+1163	hangul jungseong ya
+1164	hangul jungseong yae
+1165	hangul jungseong eo
+1166	hangul jungseong e
+1167	hangul jungseong yeo
+1168	hangul jungseong ye
+1169	hangul jungseong o
+116a	hangul jungseong wa
+116b	hangul jungseong wae
+116c	hangul jungseong oe
+116d	hangul jungseong yo
+116e	hangul jungseong u
+116f	hangul jungseong weo
+1170	hangul jungseong we
+1171	hangul jungseong wi
+1172	hangul jungseong yu
+1173	hangul jungseong eu
+1174	hangul jungseong yi
+1175	hangul jungseong i
+1176	hangul jungseong a-o
+1177	hangul jungseong a-u
+1178	hangul jungseong ya-o
+1179	hangul jungseong ya-yo
+117a	hangul jungseong eo-o
+117b	hangul jungseong eo-u
+117c	hangul jungseong eo-eu
+117d	hangul jungseong yeo-o
+117e	hangul jungseong yeo-u
+117f	hangul jungseong o-eo
+1180	hangul jungseong o-e
+1181	hangul jungseong o-ye
+1182	hangul jungseong o-o
+1183	hangul jungseong o-u
+1184	hangul jungseong yo-ya
+1185	hangul jungseong yo-yae
+1186	hangul jungseong yo-yeo
+1187	hangul jungseong yo-o
+1188	hangul jungseong yo-i
+1189	hangul jungseong u-a
+118a	hangul jungseong u-ae
+118b	hangul jungseong u-eo-eu
+118c	hangul jungseong u-ye
+118d	hangul jungseong u-u
+118e	hangul jungseong yu-a
+118f	hangul jungseong yu-eo
+1190	hangul jungseong yu-e
+1191	hangul jungseong yu-yeo
+1192	hangul jungseong yu-ye
+1193	hangul jungseong yu-u
+1194	hangul jungseong yu-i
+1195	hangul jungseong eu-u
+1196	hangul jungseong eu-eu
+1197	hangul jungseong yi-u
+1198	hangul jungseong i-a
+1199	hangul jungseong i-ya
+119a	hangul jungseong i-o
+119b	hangul jungseong i-u
+119c	hangul jungseong i-eu
+119d	hangul jungseong i-araea
+119e	hangul jungseong araea
+119f	hangul jungseong araea-eo
+11a0	hangul jungseong araea-u
+11a1	hangul jungseong araea-i
+11a2	hangul jungseong ssangaraea
+11a8	hangul jongseong kiyeok
+11a9	hangul jongseong ssangkiyeok
+11aa	hangul jongseong kiyeok-sios
+11ab	hangul jongseong nieun
+11ac	hangul jongseong nieun-cieuc
+11ad	hangul jongseong nieun-hieuh
+11ae	hangul jongseong tikeut
+11af	hangul jongseong rieul
+11b0	hangul jongseong rieul-kiyeok
+11b1	hangul jongseong rieul-mieum
+11b2	hangul jongseong rieul-pieup
+11b3	hangul jongseong rieul-sios
+11b4	hangul jongseong rieul-thieuth
+11b5	hangul jongseong rieul-phieuph
+11b6	hangul jongseong rieul-hieuh
+11b7	hangul jongseong mieum
+11b8	hangul jongseong pieup
+11b9	hangul jongseong pieup-sios
+11ba	hangul jongseong sios
+11bb	hangul jongseong ssangsios
+11bc	hangul jongseong ieung
+11bd	hangul jongseong cieuc
+11be	hangul jongseong chieuch
+11bf	hangul jongseong khieukh
+11c0	hangul jongseong thieuth
+11c1	hangul jongseong phieuph
+11c2	hangul jongseong hieuh
+11c3	hangul jongseong kiyeok-rieul
+11c4	hangul jongseong kiyeok-sios-kiyeok
+11c5	hangul jongseong nieun-kiyeok
+11c6	hangul jongseong nieun-tikeut
+11c7	hangul jongseong nieun-sios
+11c8	hangul jongseong nieun-pansios
+11c9	hangul jongseong nieun-thieuth
+11ca	hangul jongseong tikeut-kiyeok
+11cb	hangul jongseong tikeut-rieul
+11cc	hangul jongseong rieul-kiyeok-sios
+11cd	hangul jongseong rieul-nieun
+11ce	hangul jongseong rieul-tikeut
+11cf	hangul jongseong rieul-tikeut-hieuh
+11d0	hangul jongseong ssangrieul
+11d1	hangul jongseong rieul-mieum-kiyeok
+11d2	hangul jongseong rieul-mieum-sios
+11d3	hangul jongseong rieul-pieup-sios
+11d4	hangul jongseong rieul-pieup-hieuh
+11d5	hangul jongseong rieul-kapyeounpieup
+11d6	hangul jongseong rieul-ssangsios
+11d7	hangul jongseong rieul-pansios
+11d8	hangul jongseong rieul-khieukh
+11d9	hangul jongseong rieul-yeorinhieuh
+11da	hangul jongseong mieum-kiyeok
+11db	hangul jongseong mieum-rieul
+11dc	hangul jongseong mieum-pieup
+11dd	hangul jongseong mieum-sios
+11de	hangul jongseong mieum-ssangsios
+11df	hangul jongseong mieum-pansios
+11e0	hangul jongseong mieum-chieuch
+11e1	hangul jongseong mieum-hieuh
+11e2	hangul jongseong kapyeounmieum
+11e3	hangul jongseong pieup-rieul
+11e4	hangul jongseong pieup-phieuph
+11e5	hangul jongseong pieup-hieuh
+11e6	hangul jongseong kapyeounpieup
+11e7	hangul jongseong sios-kiyeok
+11e8	hangul jongseong sios-tikeut
+11e9	hangul jongseong sios-rieul
+11ea	hangul jongseong sios-pieup
+11eb	hangul jongseong pansios
+11ec	hangul jongseong ieung-kiyeok
+11ed	hangul jongseong ieung-ssangkiyeok
+11ee	hangul jongseong ssangieung
+11ef	hangul jongseong ieung-khieukh
+11f0	hangul jongseong yesieung
+11f1	hangul jongseong yesieung-sios
+11f2	hangul jongseong yesieung-pansios
+11f3	hangul jongseong phieuph-pieup
+11f4	hangul jongseong kapyeounphieuph
+11f5	hangul jongseong hieuh-nieun
+11f6	hangul jongseong hieuh-rieul
+11f7	hangul jongseong hieuh-mieum
+11f8	hangul jongseong hieuh-pieup
+11f9	hangul jongseong yeorinhieuh
+1e00	latin capital letter a with ring below
+1e01	latin small letter a with ring below;1e00
+1e02	latin capital letter b with dot above
+1e03	latin small letter b with dot above;1e02
+1e04	latin capital letter b with dot below
+1e05	latin small letter b with dot below;1e04
+1e06	latin capital letter b with line below
+1e07	latin small letter b with line below;1e06
+1e08	latin capital letter c with cedilla and acute
+1e09	latin small letter c with cedilla and acute;1e08
+1e0a	latin capital letter d with dot above
+1e0b	latin small letter d with dot above;1e0a
+1e0c	latin capital letter d with dot below
+1e0d	latin small letter d with dot below;1e0c
+1e0e	latin capital letter d with line below
+1e0f	latin small letter d with line below;1e0e
+1e10	latin capital letter d with cedilla
+1e11	latin small letter d with cedilla;1e10
+1e12	latin capital letter d with circumflex below
+1e13	latin small letter d with circumflex below;1e12
+1e14	latin capital letter e with macron and grave
+1e15	latin small letter e with macron and grave;1e14
+1e16	latin capital letter e with macron and acute
+1e17	latin small letter e with macron and acute;1e16
+1e18	latin capital letter e with circumflex below
+1e19	latin small letter e with circumflex below;1e18
+1e1a	latin capital letter e with tilde below
+1e1b	latin small letter e with tilde below;1e1a
+1e1c	latin capital letter e with cedilla and breve
+1e1d	latin small letter e with cedilla and breve;1e1c
+1e1e	latin capital letter f with dot above
+1e1f	latin small letter f with dot above;1e1e
+1e20	latin capital letter g with macron
+1e21	latin small letter g with macron;1e20
+1e22	latin capital letter h with dot above
+1e23	latin small letter h with dot above;1e22
+1e24	latin capital letter h with dot below
+1e25	latin small letter h with dot below;1e24
+1e26	latin capital letter h with diaeresis
+1e27	latin small letter h with diaeresis;1e26
+1e28	latin capital letter h with cedilla
+1e29	latin small letter h with cedilla;1e28
+1e2a	latin capital letter h with breve below
+1e2b	latin small letter h with breve below;1e2a
+1e2c	latin capital letter i with tilde below
+1e2d	latin small letter i with tilde below;1e2c
+1e2e	latin capital letter i with diaeresis and acute
+1e2f	latin small letter i with diaeresis and acute;1e2e
+1e30	latin capital letter k with acute
+1e31	latin small letter k with acute;1e30
+1e32	latin capital letter k with dot below
+1e33	latin small letter k with dot below;1e32
+1e34	latin capital letter k with line below
+1e35	latin small letter k with line below;1e34
+1e36	latin capital letter l with dot below
+1e37	latin small letter l with dot below;1e36
+1e38	latin capital letter l with dot below and macron
+1e39	latin small letter l with dot below and macron;1e38
+1e3a	latin capital letter l with line below
+1e3b	latin small letter l with line below;1e3a
+1e3c	latin capital letter l with circumflex below
+1e3d	latin small letter l with circumflex below;1e3c
+1e3e	latin capital letter m with acute
+1e3f	latin small letter m with acute;1e3e
+1e40	latin capital letter m with dot above
+1e41	latin small letter m with dot above;1e40
+1e42	latin capital letter m with dot below
+1e43	latin small letter m with dot below;1e42
+1e44	latin capital letter n with dot above
+1e45	latin small letter n with dot above;1e44
+1e46	latin capital letter n with dot below
+1e47	latin small letter n with dot below;1e46
+1e48	latin capital letter n with line below
+1e49	latin small letter n with line below;1e48
+1e4a	latin capital letter n with circumflex below
+1e4b	latin small letter n with circumflex below;1e4a
+1e4c	latin capital letter o with tilde and acute
+1e4d	latin small letter o with tilde and acute;1e4c
+1e4e	latin capital letter o with tilde and diaeresis
+1e4f	latin small letter o with tilde and diaeresis;1e4e
+1e50	latin capital letter o with macron and grave
+1e51	latin small letter o with macron and grave;1e50
+1e52	latin capital letter o with macron and acute
+1e53	latin small letter o with macron and acute;1e52
+1e54	latin capital letter p with acute
+1e55	latin small letter p with acute;1e54
+1e56	latin capital letter p with dot above
+1e57	latin small letter p with dot above;1e56
+1e58	latin capital letter r with dot above
+1e59	latin small letter r with dot above;1e58
+1e5a	latin capital letter r with dot below
+1e5b	latin small letter r with dot below;1e5a
+1e5c	latin capital letter r with dot below and macron
+1e5d	latin small letter r with dot below and macron;1e5c
+1e5e	latin capital letter r with line below
+1e5f	latin small letter r with line below;1e5e
+1e60	latin capital letter s with dot above
+1e61	latin small letter s with dot above;1e60
+1e62	latin capital letter s with dot below
+1e63	latin small letter s with dot below;1e62
+1e64	latin capital letter s with acute and dot above
+1e65	latin small letter s with acute and dot above;1e64
+1e66	latin capital letter s with caron and dot above
+1e67	latin small letter s with caron and dot above;1e66
+1e68	latin capital letter s with dot below and dot above
+1e69	latin small letter s with dot below and dot above;1e68
+1e6a	latin capital letter t with dot above
+1e6b	latin small letter t with dot above;1e6a
+1e6c	latin capital letter t with dot below
+1e6d	latin small letter t with dot below;1e6c
+1e6e	latin capital letter t with line below
+1e6f	latin small letter t with line below;1e6e
+1e70	latin capital letter t with circumflex below
+1e71	latin small letter t with circumflex below;1e70
+1e72	latin capital letter u with diaeresis below
+1e73	latin small letter u with diaeresis below;1e72
+1e74	latin capital letter u with tilde below
+1e75	latin small letter u with tilde below;1e74
+1e76	latin capital letter u with circumflex below
+1e77	latin small letter u with circumflex below;1e76
+1e78	latin capital letter u with tilde and acute
+1e79	latin small letter u with tilde and acute;1e78
+1e7a	latin capital letter u with macron and diaeresis
+1e7b	latin small letter u with macron and diaeresis;1e7a
+1e7c	latin capital letter v with tilde
+1e7d	latin small letter v with tilde;1e7c
+1e7e	latin capital letter v with dot below
+1e7f	latin small letter v with dot below;1e7e
+1e80	latin capital letter w with grave
+1e81	latin small letter w with grave;1e80
+1e82	latin capital letter w with acute
+1e83	latin small letter w with acute;1e82
+1e84	latin capital letter w with diaeresis
+1e85	latin small letter w with diaeresis;1e84
+1e86	latin capital letter w with dot above
+1e87	latin small letter w with dot above;1e86
+1e88	latin capital letter w with dot below
+1e89	latin small letter w with dot below;1e88
+1e8a	latin capital letter x with dot above
+1e8b	latin small letter x with dot above;1e8a
+1e8c	latin capital letter x with diaeresis
+1e8d	latin small letter x with diaeresis;1e8c
+1e8e	latin capital letter y with dot above
+1e8f	latin small letter y with dot above;1e8e
+1e90	latin capital letter z with circumflex
+1e91	latin small letter z with circumflex;1e90
+1e92	latin capital letter z with dot below
+1e93	latin small letter z with dot below;1e92
+1e94	latin capital letter z with line below
+1e95	latin small letter z with line below;1e94
+1e96	latin small letter h with line below
+1e97	latin small letter t with diaeresis
+1e98	latin small letter w with ring above
+1e99	latin small letter y with ring above
+1e9a	latin small letter a with right half ring
+1e9b	latin small letter long s with dot above
+1ea0	latin capital letter a with dot below
+1ea1	latin small letter a with dot below;1ea0
+1ea2	latin capital letter a with hook above
+1ea3	latin small letter a with hook above;1ea2
+1ea4	latin capital letter a with circumflex and acute
+1ea5	latin small letter a with circumflex and acute;1ea4
+1ea6	latin capital letter a with circumflex and grave
+1ea7	latin small letter a with circumflex and grave;1ea6
+1ea8	latin capital letter a with circumflex and hook above
+1ea9	latin small letter a with circumflex and hook above;1ea8
+1eaa	latin capital letter a with circumflex and tilde
+1eab	latin small letter a with circumflex and tilde;1eaa
+1eac	latin capital letter a with circumflex and dot below
+1ead	latin small letter a with circumflex and dot below;1eac
+1eae	latin capital letter a with breve and acute
+1eaf	latin small letter a with breve and acute;1eae
+1eb0	latin capital letter a with breve and grave
+1eb1	latin small letter a with breve and grave;1eb0
+1eb2	latin capital letter a with breve and hook above
+1eb3	latin small letter a with breve and hook above;1eb2
+1eb4	latin capital letter a with breve and tilde
+1eb5	latin small letter a with breve and tilde;1eb4
+1eb6	latin capital letter a with breve and dot below
+1eb7	latin small letter a with breve and dot below;1eb6
+1eb8	latin capital letter e with dot below
+1eb9	latin small letter e with dot below;1eb8
+1eba	latin capital letter e with hook above
+1ebb	latin small letter e with hook above;1eba
+1ebc	latin capital letter e with tilde
+1ebd	latin small letter e with tilde;1ebc
+1ebe	latin capital letter e with circumflex and acute
+1ebf	latin small letter e with circumflex and acute;1ebe
+1ec0	latin capital letter e with circumflex and grave
+1ec1	latin small letter e with circumflex and grave;1ec0
+1ec2	latin capital letter e with circumflex and hook above
+1ec3	latin small letter e with circumflex and hook above;1ec2
+1ec4	latin capital letter e with circumflex and tilde
+1ec5	latin small letter e with circumflex and tilde;1ec4
+1ec6	latin capital letter e with circumflex and dot below
+1ec7	latin small letter e with circumflex and dot below;1ec6
+1ec8	latin capital letter i with hook above
+1ec9	latin small letter i with hook above;1ec8
+1eca	latin capital letter i with dot below
+1ecb	latin small letter i with dot below;1eca
+1ecc	latin capital letter o with dot below
+1ecd	latin small letter o with dot below;1ecc
+1ece	latin capital letter o with hook above
+1ecf	latin small letter o with hook above;1ece
+1ed0	latin capital letter o with circumflex and acute
+1ed1	latin small letter o with circumflex and acute;1ed0
+1ed2	latin capital letter o with circumflex and grave
+1ed3	latin small letter o with circumflex and grave;1ed2
+1ed4	latin capital letter o with circumflex and hook above
+1ed5	latin small letter o with circumflex and hook above;1ed4
+1ed6	latin capital letter o with circumflex and tilde
+1ed7	latin small letter o with circumflex and tilde;1ed6
+1ed8	latin capital letter o with circumflex and dot below
+1ed9	latin small letter o with circumflex and dot below;1ed8
+1eda	latin capital letter o with horn and acute
+1edb	latin small letter o with horn and acute;1eda
+1edc	latin capital letter o with horn and grave
+1edd	latin small letter o with horn and grave;1edc
+1ede	latin capital letter o with horn and hook above
+1edf	latin small letter o with horn and hook above;1ede
+1ee0	latin capital letter o with horn and tilde
+1ee1	latin small letter o with horn and tilde;1ee0
+1ee2	latin capital letter o with horn and dot below
+1ee3	latin small letter o with horn and dot below;1ee2
+1ee4	latin capital letter u with dot below
+1ee5	latin small letter u with dot below;1ee4
+1ee6	latin capital letter u with hook above
+1ee7	latin small letter u with hook above;1ee6
+1ee8	latin capital letter u with horn and acute
+1ee9	latin small letter u with horn and acute;1ee8
+1eea	latin capital letter u with horn and grave
+1eeb	latin small letter u with horn and grave;1eea
+1eec	latin capital letter u with horn and hook above
+1eed	latin small letter u with horn and hook above;1eec
+1eee	latin capital letter u with horn and tilde
+1eef	latin small letter u with horn and tilde;1eee
+1ef0	latin capital letter u with horn and dot below
+1ef1	latin small letter u with horn and dot below;1ef0
+1ef2	latin capital letter y with grave
+1ef3	latin small letter y with grave;1ef2
+1ef4	latin capital letter y with dot below
+1ef5	latin small letter y with dot below;1ef4
+1ef6	latin capital letter y with hook above
+1ef7	latin small letter y with hook above;1ef6
+1ef8	latin capital letter y with tilde
+1ef9	latin small letter y with tilde;1ef8
+1f00	greek small letter alpha with psili;1f08
+1f01	greek small letter alpha with dasia;1f09
+1f02	greek small letter alpha with psili and varia;1f0a
+1f03	greek small letter alpha with dasia and varia;1f0b
+1f04	greek small letter alpha with psili and oxia;1f0c
+1f05	greek small letter alpha with dasia and oxia;1f0d
+1f06	greek small letter alpha with psili and perispomeni;1f0e
+1f07	greek small letter alpha with dasia and perispomeni;1f0f
+1f08	greek capital letter alpha with psili
+1f09	greek capital letter alpha with dasia
+1f0a	greek capital letter alpha with psili and varia
+1f0b	greek capital letter alpha with dasia and varia
+1f0c	greek capital letter alpha with psili and oxia
+1f0d	greek capital letter alpha with dasia and oxia
+1f0e	greek capital letter alpha with psili and perispomeni
+1f0f	greek capital letter alpha with dasia and perispomeni
+1f10	greek small letter epsilon with psili;1f18
+1f11	greek small letter epsilon with dasia;1f19
+1f12	greek small letter epsilon with psili and varia;1f1a
+1f13	greek small letter epsilon with dasia and varia;1f1b
+1f14	greek small letter epsilon with psili and oxia;1f1c
+1f15	greek small letter epsilon with dasia and oxia;1f1d
+1f18	greek capital letter epsilon with psili
+1f19	greek capital letter epsilon with dasia
+1f1a	greek capital letter epsilon with psili and varia
+1f1b	greek capital letter epsilon with dasia and varia
+1f1c	greek capital letter epsilon with psili and oxia
+1f1d	greek capital letter epsilon with dasia and oxia
+1f20	greek small letter eta with psili;1f28
+1f21	greek small letter eta with dasia;1f29
+1f22	greek small letter eta with psili and varia;1f2a
+1f23	greek small letter eta with dasia and varia;1f2b
+1f24	greek small letter eta with psili and oxia;1f2c
+1f25	greek small letter eta with dasia and oxia;1f2d
+1f26	greek small letter eta with psili and perispomeni;1f2e
+1f27	greek small letter eta with dasia and perispomeni;1f2f
+1f28	greek capital letter eta with psili
+1f29	greek capital letter eta with dasia
+1f2a	greek capital letter eta with psili and varia
+1f2b	greek capital letter eta with dasia and varia
+1f2c	greek capital letter eta with psili and oxia
+1f2d	greek capital letter eta with dasia and oxia
+1f2e	greek capital letter eta with psili and perispomeni
+1f2f	greek capital letter eta with dasia and perispomeni
+1f30	greek small letter iota with psili;1f38
+1f31	greek small letter iota with dasia;1f39
+1f32	greek small letter iota with psili and varia;1f3a
+1f33	greek small letter iota with dasia and varia;1f3b
+1f34	greek small letter iota with psili and oxia;1f3c
+1f35	greek small letter iota with dasia and oxia;1f3d
+1f36	greek small letter iota with psili and perispomeni;1f3e
+1f37	greek small letter iota with dasia and perispomeni;1f3f
+1f38	greek capital letter iota with psili
+1f39	greek capital letter iota with dasia
+1f3a	greek capital letter iota with psili and varia
+1f3b	greek capital letter iota with dasia and varia
+1f3c	greek capital letter iota with psili and oxia
+1f3d	greek capital letter iota with dasia and oxia
+1f3e	greek capital letter iota with psili and perispomeni
+1f3f	greek capital letter iota with dasia and perispomeni
+1f40	greek small letter omicron with psili;1f48
+1f41	greek small letter omicron with dasia;1f49
+1f42	greek small letter omicron with psili and varia;1f4a
+1f43	greek small letter omicron with dasia and varia;1f4b
+1f44	greek small letter omicron with psili and oxia;1f4c
+1f45	greek small letter omicron with dasia and oxia;1f4d
+1f48	greek capital letter omicron with psili
+1f49	greek capital letter omicron with dasia
+1f4a	greek capital letter omicron with psili and varia
+1f4b	greek capital letter omicron with dasia and varia
+1f4c	greek capital letter omicron with psili and oxia
+1f4d	greek capital letter omicron with dasia and oxia
+1f50	greek small letter upsilon with psili
+1f51	greek small letter upsilon with dasia;1f59
+1f52	greek small letter upsilon with psili and varia
+1f53	greek small letter upsilon with dasia and varia;1f5b
+1f54	greek small letter upsilon with psili and oxia
+1f55	greek small letter upsilon with dasia and oxia;1f5d
+1f56	greek small letter upsilon with psili and perispomeni
+1f57	greek small letter upsilon with dasia and perispomeni;1f5f
+1f59	greek capital letter upsilon with dasia
+1f5b	greek capital letter upsilon with dasia and varia
+1f5d	greek capital letter upsilon with dasia and oxia
+1f5f	greek capital letter upsilon with dasia and perispomeni
+1f60	greek small letter omega with psili;1f68
+1f61	greek small letter omega with dasia;1f69
+1f62	greek small letter omega with psili and varia;1f6a
+1f63	greek small letter omega with dasia and varia;1f6b
+1f64	greek small letter omega with psili and oxia;1f6c
+1f65	greek small letter omega with dasia and oxia;1f6d
+1f66	greek small letter omega with psili and perispomeni;1f6e
+1f67	greek small letter omega with dasia and perispomeni;1f6f
+1f68	greek capital letter omega with psili
+1f69	greek capital letter omega with dasia
+1f6a	greek capital letter omega with psili and varia
+1f6b	greek capital letter omega with dasia and varia
+1f6c	greek capital letter omega with psili and oxia
+1f6d	greek capital letter omega with dasia and oxia
+1f6e	greek capital letter omega with psili and perispomeni
+1f6f	greek capital letter omega with dasia and perispomeni
+1f70	greek small letter alpha with varia;1fba
+1f71	greek small letter alpha with oxia;1fbb
+1f72	greek small letter epsilon with varia;1fc8
+1f73	greek small letter epsilon with oxia;1fc9
+1f74	greek small letter eta with varia;1fca
+1f75	greek small letter eta with oxia;1fcb
+1f76	greek small letter iota with varia;1fda
+1f77	greek small letter iota with oxia;1fdb
+1f78	greek small letter omicron with varia;1ff8
+1f79	greek small letter omicron with oxia;1ff9
+1f7a	greek small letter upsilon with varia;1fea
+1f7b	greek small letter upsilon with oxia;1feb
+1f7c	greek small letter omega with varia;1ffa
+1f7d	greek small letter omega with oxia;1ffb
+1f80	greek small letter alpha with psili and ypogegrammeni;1f88
+1f81	greek small letter alpha with dasia and ypogegrammeni;1f89
+1f82	greek small letter alpha with psili and varia and ypogegrammeni;1f8a
+1f83	greek small letter alpha with dasia and varia and ypogegrammeni;1f8b
+1f84	greek small letter alpha with psili and oxia and ypogegrammeni;1f8c
+1f85	greek small letter alpha with dasia and oxia and ypogegrammeni;1f8d
+1f86	greek small letter alpha with psili and perispomeni and ypogegrammeni;1f8e
+1f87	greek small letter alpha with dasia and perispomeni and ypogegrammeni;1f8f
+1f88	greek capital letter alpha with psili and prosgegrammeni
+1f89	greek capital letter alpha with dasia and prosgegrammeni
+1f8a	greek capital letter alpha with psili and varia and prosgegrammeni
+1f8b	greek capital letter alpha with dasia and varia and prosgegrammeni
+1f8c	greek capital letter alpha with psili and oxia and prosgegrammeni
+1f8d	greek capital letter alpha with dasia and oxia and prosgegrammeni
+1f8e	greek capital letter alpha with psili and perispomeni and prosgegrammeni
+1f8f	greek capital letter alpha with dasia and perispomeni and prosgegrammeni
+1f90	greek small letter eta with psili and ypogegrammeni;1f98
+1f91	greek small letter eta with dasia and ypogegrammeni;1f99
+1f92	greek small letter eta with psili and varia and ypogegrammeni;1f9a
+1f93	greek small letter eta with dasia and varia and ypogegrammeni;1f9b
+1f94	greek small letter eta with psili and oxia and ypogegrammeni;1f9c
+1f95	greek small letter eta with dasia and oxia and ypogegrammeni;1f9d
+1f96	greek small letter eta with psili and perispomeni and ypogegrammeni;1f9e
+1f97	greek small letter eta with dasia and perispomeni and ypogegrammeni;1f9f
+1f98	greek capital letter eta with psili and prosgegrammeni
+1f99	greek capital letter eta with dasia and prosgegrammeni
+1f9a	greek capital letter eta with psili and varia and prosgegrammeni
+1f9b	greek capital letter eta with dasia and varia and prosgegrammeni
+1f9c	greek capital letter eta with psili and oxia and prosgegrammeni
+1f9d	greek capital letter eta with dasia and oxia and prosgegrammeni
+1f9e	greek capital letter eta with psili and perispomeni and prosgegrammeni
+1f9f	greek capital letter eta with dasia and perispomeni and prosgegrammeni
+1fa0	greek small letter omega with psili and ypogegrammeni;1fa8
+1fa1	greek small letter omega with dasia and ypogegrammeni;1fa9
+1fa2	greek small letter omega with psili and varia and ypogegrammeni;1faa
+1fa3	greek small letter omega with dasia and varia and ypogegrammeni;1fab
+1fa4	greek small letter omega with psili and oxia and ypogegrammeni;1fac
+1fa5	greek small letter omega with dasia and oxia and ypogegrammeni;1fad
+1fa6	greek small letter omega with psili and perispomeni and ypogegrammeni;1fae
+1fa7	greek small letter omega with dasia and perispomeni and ypogegrammeni;1faf
+1fa8	greek capital letter omega with psili and prosgegrammeni
+1fa9	greek capital letter omega with dasia and prosgegrammeni
+1faa	greek capital letter omega with psili and varia and prosgegrammeni
+1fab	greek capital letter omega with dasia and varia and prosgegrammeni
+1fac	greek capital letter omega with psili and oxia and prosgegrammeni
+1fad	greek capital letter omega with dasia and oxia and prosgegrammeni
+1fae	greek capital letter omega with psili and perispomeni and prosgegrammeni
+1faf	greek capital letter omega with dasia and perispomeni and prosgegrammeni
+1fb0	greek small letter alpha with vrachy;1fb8
+1fb1	greek small letter alpha with macron;1fb9
+1fb2	greek small letter alpha with varia and ypogegrammeni
+1fb3	greek small letter alpha with ypogegrammeni;1fbc
+1fb4	greek small letter alpha with oxia and ypogegrammeni
+1fb6	greek small letter alpha with perispomeni
+1fb7	greek small letter alpha with perispomeni and ypogegrammeni
+1fb8	greek capital letter alpha with vrachy
+1fb9	greek capital letter alpha with macron
+1fba	greek capital letter alpha with varia
+1fbb	greek capital letter alpha with oxia
+1fbc	greek capital letter alpha with prosgegrammeni
+1fbd	greek koronis
+1fbe	greek prosgegrammeni
+1fbf	greek psili
+1fc0	greek perispomeni
+1fc1	greek dialytika and perispomeni
+1fc2	greek small letter eta with varia and ypogegrammeni
+1fc3	greek small letter eta with ypogegrammeni;1fcc
+1fc4	greek small letter eta with oxia and ypogegrammeni
+1fc6	greek small letter eta with perispomeni
+1fc7	greek small letter eta with perispomeni and ypogegrammeni
+1fc8	greek capital letter epsilon with varia
+1fc9	greek capital letter epsilon with oxia
+1fca	greek capital letter eta with varia
+1fcb	greek capital letter eta with oxia
+1fcc	greek capital letter eta with prosgegrammeni
+1fcd	greek psili and varia
+1fce	greek psili and oxia
+1fcf	greek psili and perispomeni
+1fd0	greek small letter iota with vrachy;1fd8
+1fd1	greek small letter iota with macron;1fd9
+1fd2	greek small letter iota with dialytika and varia
+1fd3	greek small letter iota with dialytika and oxia
+1fd6	greek small letter iota with perispomeni
+1fd7	greek small letter iota with dialytika and perispomeni
+1fd8	greek capital letter iota with vrachy
+1fd9	greek capital letter iota with macron
+1fda	greek capital letter iota with varia
+1fdb	greek capital letter iota with oxia
+1fdd	greek dasia and varia
+1fde	greek dasia and oxia
+1fdf	greek dasia and perispomeni
+1fe0	greek small letter upsilon with vrachy;1fe8
+1fe1	greek small letter upsilon with macron;1fe9
+1fe2	greek small letter upsilon with dialytika and varia
+1fe3	greek small letter upsilon with dialytika and oxia
+1fe4	greek small letter rho with psili
+1fe5	greek small letter rho with dasia;1fec
+1fe6	greek small letter upsilon with perispomeni
+1fe7	greek small letter upsilon with dialytika and perispomeni
+1fe8	greek capital letter upsilon with vrachy
+1fe9	greek capital letter upsilon with macron
+1fea	greek capital letter upsilon with varia
+1feb	greek capital letter upsilon with oxia
+1fec	greek capital letter rho with dasia
+1fed	greek dialytika and varia
+1fee	greek dialytika and oxia
+1fef	greek varia
+1ff2	greek small letter omega with varia and ypogegrammeni
+1ff3	greek small letter omega with ypogegrammeni;1ffc
+1ff4	greek small letter omega with oxia and ypogegrammeni
+1ff6	greek small letter omega with perispomeni
+1ff7	greek small letter omega with perispomeni and ypogegrammeni
+1ff8	greek capital letter omicron with varia
+1ff9	greek capital letter omicron with oxia
+1ffa	greek capital letter omega with varia
+1ffb	greek capital letter omega with oxia
+1ffc	greek capital letter omega with prosgegrammeni
+1ffd	greek oxia
+1ffe	greek dasia
+2000	en quad
+2001	em quad
+2002	en space
+2003	em space
+2004	three-per-em space
+2005	four-per-em space
+2006	six-per-em space
+2007	figure space
+2008	punctuation space
+2009	thin space
+200a	hair space
+200b	zero width space
+200c	zero width non-joiner
+200d	zero width joiner
+200e	left-to-right mark
+200f	right-to-left mark
+2010	hyphen
+2011	non-breaking hyphen
+2012	figure dash
+2013	en dash
+2014	em dash
+2015	horizontal bar
+2016	double vertical line
+2017	double low line
+2018	left single quotation mark
+2019	right single quotation mark
+201a	single low-9 quotation mark
+201b	single high-reversed-9 quotation mark
+201c	left double quotation mark
+201d	right double quotation mark
+201e	double low-9 quotation mark
+201f	double high-reversed-9 quotation mark
+2020	dagger
+2021	double dagger
+2022	bullet
+2023	triangular bullet
+2024	one dot leader
+2025	two dot leader
+2026	horizontal ellipsis
+2027	hyphenation point
+2028	line separator
+2029	paragraph separator
+202a	left-to-right embedding
+202b	right-to-left embedding
+202c	pop directional formatting
+202d	left-to-right override
+202e	right-to-left override
+2030	per mille sign
+2031	per ten thousand sign
+2032	prime
+2033	double prime
+2034	triple prime
+2035	reversed prime
+2036	reversed double prime
+2037	reversed triple prime
+2038	caret
+2039	single left-pointing angle quotation mark
+203a	single right-pointing angle quotation mark
+203b	reference mark
+203c	double exclamation mark
+203d	interrobang
+203e	overline
+203f	undertie
+2040	character tie
+2041	caret insertion point
+2042	asterism
+2043	hyphen bullet
+2044	fraction slash
+2045	left square bracket with quill
+2046	right square bracket with quill
+206a	inhibit symmetric swapping
+206b	activate symmetric swapping
+206c	inhibit arabic form shaping
+206d	activate arabic form shaping
+206e	national digit shapes
+206f	nominal digit shapes
+2070	superscript zero
+2074	superscript four
+2075	superscript five
+2076	superscript six
+2077	superscript seven
+2078	superscript eight
+2079	superscript nine
+207a	superscript plus sign
+207b	superscript minus
+207c	superscript equals sign
+207d	superscript left parenthesis
+207e	superscript right parenthesis
+207f	superscript latin small letter n
+2080	subscript zero
+2081	subscript one
+2082	subscript two
+2083	subscript three
+2084	subscript four
+2085	subscript five
+2086	subscript six
+2087	subscript seven
+2088	subscript eight
+2089	subscript nine
+208a	subscript plus sign
+208b	subscript minus
+208c	subscript equals sign
+208d	subscript left parenthesis
+208e	subscript right parenthesis
+20a0	euro-currency sign
+20a1	colon sign
+20a2	cruzeiro sign
+20a3	french franc sign
+20a4	lira sign
+20a5	mill sign
+20a6	naira sign
+20a7	peseta sign
+20a8	rupee sign
+20a9	won sign
+20aa	new sheqel sign
+20ab	dong sign
+20d0	combining left harpoon above
+20d1	combining right harpoon above
+20d2	combining long vertical line overlay
+20d3	combining short vertical line overlay
+20d4	combining anticlockwise arrow above
+20d5	combining clockwise arrow above
+20d6	combining left arrow above
+20d7	combining right arrow above
+20d8	combining ring overlay
+20d9	combining clockwise ring overlay
+20da	combining anticlockwise ring overlay
+20db	combining three dots above
+20dc	combining four dots above
+20dd	combining enclosing circle
+20de	combining enclosing square
+20df	combining enclosing diamond
+20e0	combining enclosing circle backslash
+20e1	combining left right arrow above
+2100	account of
+2101	addressed to the subject
+2102	double-struck capital c
+2103	degree celsius
+2104	centre line symbol
+2105	care of
+2106	cada una
+2107	euler constant
+2108	scruple
+2109	degree fahrenheit
+210a	script small g
+210b	script capital h
+210c	black-letter capital h
+210d	double-struck capital h
+210e	planck constant
+210f	planck constant over two pi
+2110	script capital i
+2111	black-letter capital i
+2112	script capital l
+2113	script small l
+2114	l b bar symbol
+2115	double-struck capital n
+2116	numero sign
+2117	sound recording copyright
+2118	script capital p
+2119	double-struck capital p
+211a	double-struck capital q
+211b	script capital r
+211c	black-letter capital r
+211d	double-struck capital r
+211e	prescription take
+211f	response
+2120	service mark
+2121	telephone sign
+2122	trade mark sign
+2123	versicle
+2124	double-struck capital z
+2125	ounce sign
+2126	ohm sign
+2127	inverted ohm sign
+2128	black-letter capital z
+2129	turned greek small letter iota
+212a	kelvin sign
+212b	angstrom sign
+212c	script capital b
+212d	black-letter capital c
+212e	estimated symbol
+212f	script small e
+2130	script capital e
+2131	script capital f
+2132	turned capital f
+2133	script capital m
+2134	script small o
+2135	alef symbol
+2136	bet symbol
+2137	gimel symbol
+2138	dalet symbol
+2153	vulgar fraction one third
+2154	vulgar fraction two thirds
+2155	vulgar fraction one fifth
+2156	vulgar fraction two fifths
+2157	vulgar fraction three fifths
+2158	vulgar fraction four fifths
+2159	vulgar fraction one sixth
+215a	vulgar fraction five sixths
+215b	vulgar fraction one eighth
+215c	vulgar fraction three eighths
+215d	vulgar fraction five eighths
+215e	vulgar fraction seven eighths
+215f	fraction numerator one
+2160	roman numeral one
+2161	roman numeral two
+2162	roman numeral three
+2163	roman numeral four
+2164	roman numeral five
+2165	roman numeral six
+2166	roman numeral seven
+2167	roman numeral eight
+2168	roman numeral nine
+2169	roman numeral ten
+216a	roman numeral eleven
+216b	roman numeral twelve
+216c	roman numeral fifty
+216d	roman numeral one hundred
+216e	roman numeral five hundred
+216f	roman numeral one thousand
+2170	small roman numeral one;2160
+2171	small roman numeral two;2161
+2172	small roman numeral three;2162
+2173	small roman numeral four;2163
+2174	small roman numeral five;2164
+2175	small roman numeral six;2165
+2176	small roman numeral seven;2166
+2177	small roman numeral eight;2167
+2178	small roman numeral nine;2168
+2179	small roman numeral ten;2169
+217a	small roman numeral eleven;216a
+217b	small roman numeral twelve;216b
+217c	small roman numeral fifty;216c
+217d	small roman numeral one hundred;216d
+217e	small roman numeral five hundred;216e
+217f	small roman numeral one thousand;216f
+2180	roman numeral one thousand c d
+2181	roman numeral five thousand
+2182	roman numeral ten thousand
+2190	leftwards arrow
+2191	upwards arrow
+2192	rightwards arrow
+2193	downwards arrow
+2194	left right arrow
+2195	up down arrow
+2196	north west arrow
+2197	north east arrow
+2198	south east arrow
+2199	south west arrow
+219a	leftwards arrow with stroke
+219b	rightwards arrow with stroke
+219c	leftwards wave arrow
+219d	rightwards wave arrow
+219e	leftwards two headed arrow
+219f	upwards two headed arrow
+21a0	rightwards two headed arrow
+21a1	downwards two headed arrow
+21a2	leftwards arrow with tail
+21a3	rightwards arrow with tail
+21a4	leftwards arrow from bar
+21a5	upwards arrow from bar
+21a6	rightwards arrow from bar
+21a7	downwards arrow from bar
+21a8	up down arrow with base
+21a9	leftwards arrow with hook
+21aa	rightwards arrow with hook
+21ab	leftwards arrow with loop
+21ac	rightwards arrow with loop
+21ad	left right wave arrow
+21ae	left right arrow with stroke
+21af	downwards zigzag arrow
+21b0	upwards arrow with tip leftwards
+21b1	upwards arrow with tip rightwards
+21b2	downwards arrow with tip leftwards
+21b3	downwards arrow with tip rightwards
+21b4	rightwards arrow with corner downwards
+21b5	downwards arrow with corner leftwards
+21b6	anticlockwise top semicircle arrow
+21b7	clockwise top semicircle arrow
+21b8	north west arrow to long bar
+21b9	leftwards arrow to bar over rightwards arrow to bar
+21ba	anticlockwise open circle arrow
+21bb	clockwise open circle arrow
+21bc	leftwards harpoon with barb upwards
+21bd	leftwards harpoon with barb downwards
+21be	upwards harpoon with barb rightwards
+21bf	upwards harpoon with barb leftwards
+21c0	rightwards harpoon with barb upwards
+21c1	rightwards harpoon with barb downwards
+21c2	downwards harpoon with barb rightwards
+21c3	downwards harpoon with barb leftwards
+21c4	rightwards arrow over leftwards arrow
+21c5	upwards arrow leftwards of downwards arrow
+21c6	leftwards arrow over rightwards arrow
+21c7	leftwards paired arrows
+21c8	upwards paired arrows
+21c9	rightwards paired arrows
+21ca	downwards paired arrows
+21cb	leftwards harpoon over rightwards harpoon
+21cc	rightwards harpoon over leftwards harpoon
+21cd	leftwards double arrow with stroke
+21ce	left right double arrow with stroke
+21cf	rightwards double arrow with stroke
+21d0	leftwards double arrow
+21d1	upwards double arrow
+21d2	rightwards double arrow
+21d3	downwards double arrow
+21d4	left right double arrow
+21d5	up down double arrow
+21d6	north west double arrow
+21d7	north east double arrow
+21d8	south east double arrow
+21d9	south west double arrow
+21da	leftwards triple arrow
+21db	rightwards triple arrow
+21dc	leftwards squiggle arrow
+21dd	rightwards squiggle arrow
+21de	upwards arrow with double stroke
+21df	downwards arrow with double stroke
+21e0	leftwards dashed arrow
+21e1	upwards dashed arrow
+21e2	rightwards dashed arrow
+21e3	downwards dashed arrow
+21e4	leftwards arrow to bar
+21e5	rightwards arrow to bar
+21e6	leftwards white arrow
+21e7	upwards white arrow
+21e8	rightwards white arrow
+21e9	downwards white arrow
+21ea	upwards white arrow from bar
+2200	for all
+2201	complement
+2202	partial differential
+2203	there exists
+2204	there does not exist
+2205	empty set
+2206	increment
+2207	nabla
+2208	element of
+2209	not an element of
+220a	small element of
+220b	contains as member
+220c	does not contain as member
+220d	small contains as member
+220e	end of proof
+220f	n-ary product
+2210	n-ary coproduct
+2211	n-ary summation
+2212	minus sign
+2213	minus-or-plus sign
+2214	dot plus
+2215	division slash
+2216	set minus
+2217	asterisk operator
+2218	ring operator
+2219	bullet operator
+221a	square root
+221b	cube root
+221c	fourth root
+221d	proportional to
+221e	infinity
+221f	right angle
+2220	angle
+2221	measured angle
+2222	spherical angle
+2223	divides
+2224	does not divide
+2225	parallel to
+2226	not parallel to
+2227	logical and
+2228	logical or
+2229	intersection
+222a	union
+222b	integral
+222c	double integral
+222d	triple integral
+222e	contour integral
+222f	surface integral
+2230	volume integral
+2231	clockwise integral
+2232	clockwise contour integral
+2233	anticlockwise contour integral
+2234	therefore
+2235	because
+2236	ratio
+2237	proportion
+2238	dot minus
+2239	excess
+223a	geometric proportion
+223b	homothetic
+223c	tilde operator
+223d	reversed tilde
+223e	inverted lazy s
+223f	sine wave
+2240	wreath product
+2241	not tilde
+2242	minus tilde
+2243	asymptotically equal to
+2244	not asymptotically equal to
+2245	approximately equal to
+2246	approximately but not actually equal to
+2247	neither approximately nor actually equal to
+2248	almost equal to
+2249	not almost equal to
+224a	almost equal or equal to
+224b	triple tilde
+224c	all equal to
+224d	equivalent to
+224e	geometrically equivalent to
+224f	difference between
+2250	approaches the limit
+2251	geometrically equal to
+2252	approximately equal to or the image of
+2253	image of or approximately equal to
+2254	colon equals
+2255	equals colon
+2256	ring in equal to
+2257	ring equal to
+2258	corresponds to
+2259	estimates
+225a	equiangular to
+225b	star equals
+225c	delta equal to
+225d	equal to by definition
+225e	measured by
+225f	questioned equal to
+2260	not equal to
+2261	identical to
+2262	not identical to
+2263	strictly equivalent to
+2264	less-than or equal to
+2265	greater-than or equal to
+2266	less-than over equal to
+2267	greater-than over equal to
+2268	less-than but not equal to
+2269	greater-than but not equal to
+226a	much less-than
+226b	much greater-than
+226c	between
+226d	not equivalent to
+226e	not less-than
+226f	not greater-than
+2270	neither less-than nor equal to
+2271	neither greater-than nor equal to
+2272	less-than or equivalent to
+2273	greater-than or equivalent to
+2274	neither less-than nor equivalent to
+2275	neither greater-than nor equivalent to
+2276	less-than or greater-than
+2277	greater-than or less-than
+2278	neither less-than nor greater-than
+2279	neither greater-than nor less-than
+227a	precedes
+227b	succeeds
+227c	precedes or equal to
+227d	succeeds or equal to
+227e	precedes or equivalent to
+227f	succeeds or equivalent to
+2280	does not precede
+2281	does not succeed
+2282	subset of
+2283	superset of
+2284	not a subset of
+2285	not a superset of
+2286	subset of or equal to
+2287	superset of or equal to
+2288	neither a subset of nor equal to
+2289	neither a superset of nor equal to
+228a	subset of with not equal to
+228b	superset of with not equal to
+228c	multiset
+228d	multiset multiplication
+228e	multiset union
+228f	square image of
+2290	square original of
+2291	square image of or equal to
+2292	square original of or equal to
+2293	square cap
+2294	square cup
+2295	circled plus
+2296	circled minus
+2297	circled times
+2298	circled division slash
+2299	circled dot operator
+229a	circled ring operator
+229b	circled asterisk operator
+229c	circled equals
+229d	circled dash
+229e	squared plus
+229f	squared minus
+22a0	squared times
+22a1	squared dot operator
+22a2	right tack
+22a3	left tack
+22a4	down tack
+22a5	up tack
+22a6	assertion
+22a7	models
+22a8	true
+22a9	forces
+22aa	triple vertical bar right turnstile
+22ab	double vertical bar double right turnstile
+22ac	does not prove
+22ad	not true
+22ae	does not force
+22af	negated double vertical bar double right turnstile
+22b0	precedes under relation
+22b1	succeeds under relation
+22b2	normal subgroup of
+22b3	contains as normal subgroup
+22b4	normal subgroup of or equal to
+22b5	contains as normal subgroup or equal to
+22b6	original of
+22b7	image of
+22b8	multimap
+22b9	hermitian conjugate matrix
+22ba	intercalate
+22bb	xor
+22bc	nand
+22bd	nor
+22be	right angle with arc
+22bf	right triangle
+22c0	n-ary logical and
+22c1	n-ary logical or
+22c2	n-ary intersection
+22c3	n-ary union
+22c4	diamond operator
+22c5	dot operator
+22c6	star operator
+22c7	division times
+22c8	bowtie
+22c9	left normal factor semidirect product
+22ca	right normal factor semidirect product
+22cb	left semidirect product
+22cc	right semidirect product
+22cd	reversed tilde equals
+22ce	curly logical or
+22cf	curly logical and
+22d0	double subset
+22d1	double superset
+22d2	double intersection
+22d3	double union
+22d4	pitchfork
+22d5	equal and parallel to
+22d6	less-than with dot
+22d7	greater-than with dot
+22d8	very much less-than
+22d9	very much greater-than
+22da	less-than equal to or greater-than
+22db	greater-than equal to or less-than
+22dc	equal to or less-than
+22dd	equal to or greater-than
+22de	equal to or precedes
+22df	equal to or succeeds
+22e0	does not precede or equal
+22e1	does not succeed or equal
+22e2	not square image of or equal to
+22e3	not square original of or equal to
+22e4	square image of or not equal to
+22e5	square original of or not equal to
+22e6	less-than but not equivalent to
+22e7	greater-than but not equivalent to
+22e8	precedes but not equivalent to
+22e9	succeeds but not equivalent to
+22ea	not normal subgroup of
+22eb	does not contain as normal subgroup
+22ec	not normal subgroup of or equal to
+22ed	does not contain as normal subgroup or equal
+22ee	vertical ellipsis
+22ef	midline horizontal ellipsis
+22f0	up right diagonal ellipsis
+22f1	down right diagonal ellipsis
+2300	diameter sign
+2302	house
+2303	up arrowhead
+2304	down arrowhead
+2305	projective
+2306	perspective
+2307	wavy line
+2308	left ceiling
+2309	right ceiling
+230a	left floor
+230b	right floor
+230c	bottom right crop
+230d	bottom left crop
+230e	top right crop
+230f	top left crop
+2310	reversed not sign
+2311	square lozenge
+2312	arc
+2313	segment
+2314	sector
+2315	telephone recorder
+2316	position indicator
+2317	viewdata square
+2318	place of interest sign
+2319	turned not sign
+231a	watch
+231b	hourglass
+231c	top left corner
+231d	top right corner
+231e	bottom left corner
+231f	bottom right corner
+2320	top half integral
+2321	bottom half integral
+2322	frown
+2323	smile
+2324	up arrowhead between two horizontal bars
+2325	option key
+2326	erase to the right
+2327	x in a rectangle box
+2328	keyboard
+2329	left-pointing angle bracket
+232a	right-pointing angle bracket
+232b	erase to the left
+232c	benzene ring
+232d	cylindricity
+232e	all around-profile
+232f	symmetry
+2330	total runout
+2331	dimension origin
+2332	conical taper
+2333	slope
+2334	counterbore
+2335	countersink
+2336	apl functional symbol i-beam
+2337	apl functional symbol squish quad
+2338	apl functional symbol quad equal
+2339	apl functional symbol quad divide
+233a	apl functional symbol quad diamond
+233b	apl functional symbol quad jot
+233c	apl functional symbol quad circle
+233d	apl functional symbol circle stile
+233e	apl functional symbol circle jot
+233f	apl functional symbol slash bar
+2340	apl functional symbol backslash bar
+2341	apl functional symbol quad slash
+2342	apl functional symbol quad backslash
+2343	apl functional symbol quad less-than
+2344	apl functional symbol quad greater-than
+2345	apl functional symbol leftwards vane
+2346	apl functional symbol rightwards vane
+2347	apl functional symbol quad leftwards arrow
+2348	apl functional symbol quad rightwards arrow
+2349	apl functional symbol circle backslash
+234a	apl functional symbol down tack underbar
+234b	apl functional symbol delta stile
+234c	apl functional symbol quad down caret
+234d	apl functional symbol quad delta
+234e	apl functional symbol down tack jot
+234f	apl functional symbol upwards vane
+2350	apl functional symbol quad upwards arrow
+2351	apl functional symbol up tack overbar
+2352	apl functional symbol del stile
+2353	apl functional symbol quad up caret
+2354	apl functional symbol quad del
+2355	apl functional symbol up tack jot
+2356	apl functional symbol downwards vane
+2357	apl functional symbol quad downwards arrow
+2358	apl functional symbol quote underbar
+2359	apl functional symbol delta underbar
+235a	apl functional symbol diamond underbar
+235b	apl functional symbol jot underbar
+235c	apl functional symbol circle underbar
+235d	apl functional symbol up shoe jot
+235e	apl functional symbol quote quad
+235f	apl functional symbol circle star
+2360	apl functional symbol quad colon
+2361	apl functional symbol up tack diaeresis
+2362	apl functional symbol del diaeresis
+2363	apl functional symbol star diaeresis
+2364	apl functional symbol jot diaeresis
+2365	apl functional symbol circle diaeresis
+2366	apl functional symbol down shoe stile
+2367	apl functional symbol left shoe stile
+2368	apl functional symbol tilde diaeresis
+2369	apl functional symbol greater-than diaeresis
+236a	apl functional symbol comma bar
+236b	apl functional symbol del tilde
+236c	apl functional symbol zilde
+236d	apl functional symbol stile tilde
+236e	apl functional symbol semicolon underbar
+236f	apl functional symbol quad not equal
+2370	apl functional symbol quad question
+2371	apl functional symbol down caret tilde
+2372	apl functional symbol up caret tilde
+2373	apl functional symbol iota
+2374	apl functional symbol rho
+2375	apl functional symbol omega
+2376	apl functional symbol alpha underbar
+2377	apl functional symbol epsilon underbar
+2378	apl functional symbol iota underbar
+2379	apl functional symbol omega underbar
+237a	apl functional symbol alpha
+2400	symbol for null
+2401	symbol for start of heading
+2402	symbol for start of text
+2403	symbol for end of text
+2404	symbol for end of transmission
+2405	symbol for enquiry
+2406	symbol for acknowledge
+2407	symbol for bell
+2408	symbol for backspace
+2409	symbol for horizontal tabulation
+240a	symbol for line feed
+240b	symbol for vertical tabulation
+240c	symbol for form feed
+240d	symbol for carriage return
+240e	symbol for shift out
+240f	symbol for shift in
+2410	symbol for data link escape
+2411	symbol for device control one
+2412	symbol for device control two
+2413	symbol for device control three
+2414	symbol for device control four
+2415	symbol for negative acknowledge
+2416	symbol for synchronous idle
+2417	symbol for end of transmission block
+2418	symbol for cancel
+2419	symbol for end of medium
+241a	symbol for substitute
+241b	symbol for escape
+241c	symbol for file separator
+241d	symbol for group separator
+241e	symbol for record separator
+241f	symbol for unit separator
+2420	symbol for space
+2421	symbol for delete
+2422	blank symbol
+2423	open box
+2424	symbol for newline
+2440	ocr hook
+2441	ocr chair
+2442	ocr fork
+2443	ocr inverted fork
+2444	ocr belt buckle
+2445	ocr bow tie
+2446	ocr branch bank identification
+2447	ocr amount of check
+2448	ocr dash
+2449	ocr customer account number
+244a	ocr double backslash
+2460	circled digit one
+2461	circled digit two
+2462	circled digit three
+2463	circled digit four
+2464	circled digit five
+2465	circled digit six
+2466	circled digit seven
+2467	circled digit eight
+2468	circled digit nine
+2469	circled number ten
+246a	circled number eleven
+246b	circled number twelve
+246c	circled number thirteen
+246d	circled number fourteen
+246e	circled number fifteen
+246f	circled number sixteen
+2470	circled number seventeen
+2471	circled number eighteen
+2472	circled number nineteen
+2473	circled number twenty
+2474	parenthesized digit one
+2475	parenthesized digit two
+2476	parenthesized digit three
+2477	parenthesized digit four
+2478	parenthesized digit five
+2479	parenthesized digit six
+247a	parenthesized digit seven
+247b	parenthesized digit eight
+247c	parenthesized digit nine
+247d	parenthesized number ten
+247e	parenthesized number eleven
+247f	parenthesized number twelve
+2480	parenthesized number thirteen
+2481	parenthesized number fourteen
+2482	parenthesized number fifteen
+2483	parenthesized number sixteen
+2484	parenthesized number seventeen
+2485	parenthesized number eighteen
+2486	parenthesized number nineteen
+2487	parenthesized number twenty
+2488	digit one full stop
+2489	digit two full stop
+248a	digit three full stop
+248b	digit four full stop
+248c	digit five full stop
+248d	digit six full stop
+248e	digit seven full stop
+248f	digit eight full stop
+2490	digit nine full stop
+2491	number ten full stop
+2492	number eleven full stop
+2493	number twelve full stop
+2494	number thirteen full stop
+2495	number fourteen full stop
+2496	number fifteen full stop
+2497	number sixteen full stop
+2498	number seventeen full stop
+2499	number eighteen full stop
+249a	number nineteen full stop
+249b	number twenty full stop
+249c	parenthesized latin small letter a
+249d	parenthesized latin small letter b
+249e	parenthesized latin small letter c
+249f	parenthesized latin small letter d
+24a0	parenthesized latin small letter e
+24a1	parenthesized latin small letter f
+24a2	parenthesized latin small letter g
+24a3	parenthesized latin small letter h
+24a4	parenthesized latin small letter i
+24a5	parenthesized latin small letter j
+24a6	parenthesized latin small letter k
+24a7	parenthesized latin small letter l
+24a8	parenthesized latin small letter m
+24a9	parenthesized latin small letter n
+24aa	parenthesized latin small letter o
+24ab	parenthesized latin small letter p
+24ac	parenthesized latin small letter q
+24ad	parenthesized latin small letter r
+24ae	parenthesized latin small letter s
+24af	parenthesized latin small letter t
+24b0	parenthesized latin small letter u
+24b1	parenthesized latin small letter v
+24b2	parenthesized latin small letter w
+24b3	parenthesized latin small letter x
+24b4	parenthesized latin small letter y
+24b5	parenthesized latin small letter z
+24b6	circled latin capital letter a
+24b7	circled latin capital letter b
+24b8	circled latin capital letter c
+24b9	circled latin capital letter d
+24ba	circled latin capital letter e
+24bb	circled latin capital letter f
+24bc	circled latin capital letter g
+24bd	circled latin capital letter h
+24be	circled latin capital letter i
+24bf	circled latin capital letter j
+24c0	circled latin capital letter k
+24c1	circled latin capital letter l
+24c2	circled latin capital letter m
+24c3	circled latin capital letter n
+24c4	circled latin capital letter o
+24c5	circled latin capital letter p
+24c6	circled latin capital letter q
+24c7	circled latin capital letter r
+24c8	circled latin capital letter s
+24c9	circled latin capital letter t
+24ca	circled latin capital letter u
+24cb	circled latin capital letter v
+24cc	circled latin capital letter w
+24cd	circled latin capital letter x
+24ce	circled latin capital letter y
+24cf	circled latin capital letter z
+24d0	circled latin small letter a;24b6
+24d1	circled latin small letter b;24b7
+24d2	circled latin small letter c;24b8
+24d3	circled latin small letter d;24b9
+24d4	circled latin small letter e;24ba
+24d5	circled latin small letter f;24bb
+24d6	circled latin small letter g;24bc
+24d7	circled latin small letter h;24bd
+24d8	circled latin small letter i;24be
+24d9	circled latin small letter j;24bf
+24da	circled latin small letter k;24c0
+24db	circled latin small letter l;24c1
+24dc	circled latin small letter m;24c2
+24dd	circled latin small letter n;24c3
+24de	circled latin small letter o;24c4
+24df	circled latin small letter p;24c5
+24e0	circled latin small letter q;24c6
+24e1	circled latin small letter r;24c7
+24e2	circled latin small letter s;24c8
+24e3	circled latin small letter t;24c9
+24e4	circled latin small letter u;24ca
+24e5	circled latin small letter v;24cb
+24e6	circled latin small letter w;24cc
+24e7	circled latin small letter x;24cd
+24e8	circled latin small letter y;24ce
+24e9	circled latin small letter z;24cf
+24ea	circled digit zero
+2500	box drawings light horizontal
+2501	box drawings heavy horizontal
+2502	box drawings light vertical
+2503	box drawings heavy vertical
+2504	box drawings light triple dash horizontal
+2505	box drawings heavy triple dash horizontal
+2506	box drawings light triple dash vertical
+2507	box drawings heavy triple dash vertical
+2508	box drawings light quadruple dash horizontal
+2509	box drawings heavy quadruple dash horizontal
+250a	box drawings light quadruple dash vertical
+250b	box drawings heavy quadruple dash vertical
+250c	box drawings light down and right
+250d	box drawings down light and right heavy
+250e	box drawings down heavy and right light
+250f	box drawings heavy down and right
+2510	box drawings light down and left
+2511	box drawings down light and left heavy
+2512	box drawings down heavy and left light
+2513	box drawings heavy down and left
+2514	box drawings light up and right
+2515	box drawings up light and right heavy
+2516	box drawings up heavy and right light
+2517	box drawings heavy up and right
+2518	box drawings light up and left
+2519	box drawings up light and left heavy
+251a	box drawings up heavy and left light
+251b	box drawings heavy up and left
+251c	box drawings light vertical and right
+251d	box drawings vertical light and right heavy
+251e	box drawings up heavy and right down light
+251f	box drawings down heavy and right up light
+2520	box drawings vertical heavy and right light
+2521	box drawings down light and right up heavy
+2522	box drawings up light and right down heavy
+2523	box drawings heavy vertical and right
+2524	box drawings light vertical and left
+2525	box drawings vertical light and left heavy
+2526	box drawings up heavy and left down light
+2527	box drawings down heavy and left up light
+2528	box drawings vertical heavy and left light
+2529	box drawings down light and left up heavy
+252a	box drawings up light and left down heavy
+252b	box drawings heavy vertical and left
+252c	box drawings light down and horizontal
+252d	box drawings left heavy and right down light
+252e	box drawings right heavy and left down light
+252f	box drawings down light and horizontal heavy
+2530	box drawings down heavy and horizontal light
+2531	box drawings right light and left down heavy
+2532	box drawings left light and right down heavy
+2533	box drawings heavy down and horizontal
+2534	box drawings light up and horizontal
+2535	box drawings left heavy and right up light
+2536	box drawings right heavy and left up light
+2537	box drawings up light and horizontal heavy
+2538	box drawings up heavy and horizontal light
+2539	box drawings right light and left up heavy
+253a	box drawings left light and right up heavy
+253b	box drawings heavy up and horizontal
+253c	box drawings light vertical and horizontal
+253d	box drawings left heavy and right vertical light
+253e	box drawings right heavy and left vertical light
+253f	box drawings vertical light and horizontal heavy
+2540	box drawings up heavy and down horizontal light
+2541	box drawings down heavy and up horizontal light
+2542	box drawings vertical heavy and horizontal light
+2543	box drawings left up heavy and right down light
+2544	box drawings right up heavy and left down light
+2545	box drawings left down heavy and right up light
+2546	box drawings right down heavy and left up light
+2547	box drawings down light and up horizontal heavy
+2548	box drawings up light and down horizontal heavy
+2549	box drawings right light and left vertical heavy
+254a	box drawings left light and right vertical heavy
+254b	box drawings heavy vertical and horizontal
+254c	box drawings light double dash horizontal
+254d	box drawings heavy double dash horizontal
+254e	box drawings light double dash vertical
+254f	box drawings heavy double dash vertical
+2550	box drawings double horizontal
+2551	box drawings double vertical
+2552	box drawings down single and right double
+2553	box drawings down double and right single
+2554	box drawings double down and right
+2555	box drawings down single and left double
+2556	box drawings down double and left single
+2557	box drawings double down and left
+2558	box drawings up single and right double
+2559	box drawings up double and right single
+255a	box drawings double up and right
+255b	box drawings up single and left double
+255c	box drawings up double and left single
+255d	box drawings double up and left
+255e	box drawings vertical single and right double
+255f	box drawings vertical double and right single
+2560	box drawings double vertical and right
+2561	box drawings vertical single and left double
+2562	box drawings vertical double and left single
+2563	box drawings double vertical and left
+2564	box drawings down single and horizontal double
+2565	box drawings down double and horizontal single
+2566	box drawings double down and horizontal
+2567	box drawings up single and horizontal double
+2568	box drawings up double and horizontal single
+2569	box drawings double up and horizontal
+256a	box drawings vertical single and horizontal double
+256b	box drawings vertical double and horizontal single
+256c	box drawings double vertical and horizontal
+256d	box drawings light arc down and right
+256e	box drawings light arc down and left
+256f	box drawings light arc up and left
+2570	box drawings light arc up and right
+2571	box drawings light diagonal upper right to lower left
+2572	box drawings light diagonal upper left to lower right
+2573	box drawings light diagonal cross
+2574	box drawings light left
+2575	box drawings light up
+2576	box drawings light right
+2577	box drawings light down
+2578	box drawings heavy left
+2579	box drawings heavy up
+257a	box drawings heavy right
+257b	box drawings heavy down
+257c	box drawings light left and heavy right
+257d	box drawings light up and heavy down
+257e	box drawings heavy left and light right
+257f	box drawings heavy up and light down
+2580	upper half block
+2581	lower one eighth block
+2582	lower one quarter block
+2583	lower three eighths block
+2584	lower half block
+2585	lower five eighths block
+2586	lower three quarters block
+2587	lower seven eighths block
+2588	full block
+2589	left seven eighths block
+258a	left three quarters block
+258b	left five eighths block
+258c	left half block
+258d	left three eighths block
+258e	left one quarter block
+258f	left one eighth block
+2590	right half block
+2591	light shade
+2592	medium shade
+2593	dark shade
+2594	upper one eighth block
+2595	right one eighth block
+25a0	black square
+25a1	white square
+25a2	white square with rounded corners
+25a3	white square containing black small square
+25a4	square with horizontal fill
+25a5	square with vertical fill
+25a6	square with orthogonal crosshatch fill
+25a7	square with upper left to lower right fill
+25a8	square with upper right to lower left fill
+25a9	square with diagonal crosshatch fill
+25aa	black small square
+25ab	white small square
+25ac	black rectangle
+25ad	white rectangle
+25ae	black vertical rectangle
+25af	white vertical rectangle
+25b0	black parallelogram
+25b1	white parallelogram
+25b2	black up-pointing triangle
+25b3	white up-pointing triangle
+25b4	black up-pointing small triangle
+25b5	white up-pointing small triangle
+25b6	black right-pointing triangle
+25b7	white right-pointing triangle
+25b8	black right-pointing small triangle
+25b9	white right-pointing small triangle
+25ba	black right-pointing pointer
+25bb	white right-pointing pointer
+25bc	black down-pointing triangle
+25bd	white down-pointing triangle
+25be	black down-pointing small triangle
+25bf	white down-pointing small triangle
+25c0	black left-pointing triangle
+25c1	white left-pointing triangle
+25c2	black left-pointing small triangle
+25c3	white left-pointing small triangle
+25c4	black left-pointing pointer
+25c5	white left-pointing pointer
+25c6	black diamond
+25c7	white diamond
+25c8	white diamond containing black small diamond
+25c9	fisheye
+25ca	lozenge
+25cb	white circle
+25cc	dotted circle
+25cd	circle with vertical fill
+25ce	bullseye
+25cf	black circle
+25d0	circle with left half black
+25d1	circle with right half black
+25d2	circle with lower half black
+25d3	circle with upper half black
+25d4	circle with upper right quadrant black
+25d5	circle with all but upper left quadrant black
+25d6	left half black circle
+25d7	right half black circle
+25d8	inverse bullet
+25d9	inverse white circle
+25da	upper half inverse white circle
+25db	lower half inverse white circle
+25dc	upper left quadrant circular arc
+25dd	upper right quadrant circular arc
+25de	lower right quadrant circular arc
+25df	lower left quadrant circular arc
+25e0	upper half circle
+25e1	lower half circle
+25e2	black lower right triangle
+25e3	black lower left triangle
+25e4	black upper left triangle
+25e5	black upper right triangle
+25e6	white bullet
+25e7	square with left half black
+25e8	square with right half black
+25e9	square with upper left diagonal half black
+25ea	square with lower right diagonal half black
+25eb	white square with vertical bisecting line
+25ec	white up-pointing triangle with dot
+25ed	up-pointing triangle with left half black
+25ee	up-pointing triangle with right half black
+25ef	large circle
+2600	black sun with rays
+2601	cloud
+2602	umbrella
+2603	snowman
+2604	comet
+2605	black star
+2606	white star
+2607	lightning
+2608	thunderstorm
+2609	sun
+260a	ascending node
+260b	descending node
+260c	conjunction
+260d	opposition
+260e	black telephone
+260f	white telephone
+2610	ballot box
+2611	ballot box with check
+2612	ballot box with x
+2613	saltire
+261a	black left pointing index
+261b	black right pointing index
+261c	white left pointing index
+261d	white up pointing index
+261e	white right pointing index
+261f	white down pointing index
+2620	skull and crossbones
+2621	caution sign
+2622	radioactive sign
+2623	biohazard sign
+2624	caduceus
+2625	ankh
+2626	orthodox cross
+2627	chi rho
+2628	cross of lorraine
+2629	cross of jerusalem
+262a	star and crescent
+262b	farsi symbol
+262c	adi shakti
+262d	hammer and sickle
+262e	peace symbol
+262f	yin yang
+2630	trigram for heaven
+2631	trigram for lake
+2632	trigram for fire
+2633	trigram for thunder
+2634	trigram for wind
+2635	trigram for water
+2636	trigram for mountain
+2637	trigram for earth
+2638	wheel of dharma
+2639	white frowning face
+263a	white smiling face
+263b	black smiling face
+263c	white sun with rays
+263d	first quarter moon
+263e	last quarter moon
+263f	mercury
+2640	female sign
+2641	earth
+2642	male sign
+2643	jupiter
+2644	saturn
+2645	uranus
+2646	neptune
+2647	pluto
+2648	aries
+2649	taurus
+264a	gemini
+264b	cancer
+264c	leo
+264d	virgo
+264e	libra
+264f	scorpius
+2650	sagittarius
+2651	capricorn
+2652	aquarius
+2653	pisces
+2654	white chess king
+2655	white chess queen
+2656	white chess rook
+2657	white chess bishop
+2658	white chess knight
+2659	white chess pawn
+265a	black chess king
+265b	black chess queen
+265c	black chess rook
+265d	black chess bishop
+265e	black chess knight
+265f	black chess pawn
+2660	black spade suit
+2661	white heart suit
+2662	white diamond suit
+2663	black club suit
+2664	white spade suit
+2665	black heart suit
+2666	black diamond suit
+2667	white club suit
+2668	hot springs
+2669	quarter note
+266a	eighth note
+266b	beamed eighth notes
+266c	beamed sixteenth notes
+266d	music flat sign
+266e	music natural sign
+266f	music sharp sign
+2701	upper blade scissors
+2702	black scissors
+2703	lower blade scissors
+2704	white scissors
+2706	telephone location sign
+2707	tape drive
+2708	airplane
+2709	envelope
+270c	victory hand
+270d	writing hand
+270e	lower right pencil
+270f	pencil
+2710	upper right pencil
+2711	white nib
+2712	black nib
+2713	check mark
+2714	heavy check mark
+2715	multiplication x
+2716	heavy multiplication x
+2717	ballot x
+2718	heavy ballot x
+2719	outlined greek cross
+271a	heavy greek cross
+271b	open centre cross
+271c	heavy open centre cross
+271d	latin cross
+271e	shadowed white latin cross
+271f	outlined latin cross
+2720	maltese cross
+2721	star of david
+2722	four teardrop-spoked asterisk
+2723	four balloon-spoked asterisk
+2724	heavy four balloon-spoked asterisk
+2725	four club-spoked asterisk
+2726	black four pointed star
+2727	white four pointed star
+2729	stress outlined white star
+272a	circled white star
+272b	open centre black star
+272c	black centre white star
+272d	outlined black star
+272e	heavy outlined black star
+272f	pinwheel star
+2730	shadowed white star
+2731	heavy asterisk
+2732	open centre asterisk
+2733	eight spoked asterisk
+2734	eight pointed black star
+2735	eight pointed pinwheel star
+2736	six pointed black star
+2737	eight pointed rectilinear black star
+2738	heavy eight pointed rectilinear black star
+2739	twelve pointed black star
+273a	sixteen pointed asterisk
+273b	teardrop-spoked asterisk
+273c	open centre teardrop-spoked asterisk
+273d	heavy teardrop-spoked asterisk
+273e	six petalled black and white florette
+273f	black florette
+2740	white florette
+2741	eight petalled outlined black florette
+2742	circled open centre eight pointed star
+2743	heavy teardrop-spoked pinwheel asterisk
+2744	snowflake
+2745	tight trifoliate snowflake
+2746	heavy chevron snowflake
+2747	sparkle
+2748	heavy sparkle
+2749	balloon-spoked asterisk
+274a	eight teardrop-spoked propeller asterisk
+274b	heavy eight teardrop-spoked propeller asterisk
+274d	shadowed white circle
+274f	lower right drop-shadowed white square
+2750	upper right drop-shadowed white square
+2751	lower right shadowed white square
+2752	upper right shadowed white square
+2756	black diamond minus white x
+2758	light vertical bar
+2759	medium vertical bar
+275a	heavy vertical bar
+275b	heavy single turned comma quotation mark ornament
+275c	heavy single comma quotation mark ornament
+275d	heavy double turned comma quotation mark ornament
+275e	heavy double comma quotation mark ornament
+2761	curved stem paragraph sign ornament
+2762	heavy exclamation mark ornament
+2763	heavy heart exclamation mark ornament
+2764	heavy black heart
+2765	rotated heavy black heart bullet
+2766	floral heart
+2767	rotated floral heart bullet
+2776	dingbat negative circled digit one
+2777	dingbat negative circled digit two
+2778	dingbat negative circled digit three
+2779	dingbat negative circled digit four
+277a	dingbat negative circled digit five
+277b	dingbat negative circled digit six
+277c	dingbat negative circled digit seven
+277d	dingbat negative circled digit eight
+277e	dingbat negative circled digit nine
+277f	dingbat negative circled number ten
+2780	dingbat circled sans-serif digit one
+2781	dingbat circled sans-serif digit two
+2782	dingbat circled sans-serif digit three
+2783	dingbat circled sans-serif digit four
+2784	dingbat circled sans-serif digit five
+2785	dingbat circled sans-serif digit six
+2786	dingbat circled sans-serif digit seven
+2787	dingbat circled sans-serif digit eight
+2788	dingbat circled sans-serif digit nine
+2789	dingbat circled sans-serif number ten
+278a	dingbat negative circled sans-serif digit one
+278b	dingbat negative circled sans-serif digit two
+278c	dingbat negative circled sans-serif digit three
+278d	dingbat negative circled sans-serif digit four
+278e	dingbat negative circled sans-serif digit five
+278f	dingbat negative circled sans-serif digit six
+2790	dingbat negative circled sans-serif digit seven
+2791	dingbat negative circled sans-serif digit eight
+2792	dingbat negative circled sans-serif digit nine
+2793	dingbat negative circled sans-serif number ten
+2794	heavy wide-headed rightwards arrow
+2798	heavy south east arrow
+2799	heavy rightwards arrow
+279a	heavy north east arrow
+279b	drafting point rightwards arrow
+279c	heavy round-tipped rightwards arrow
+279d	triangle-headed rightwards arrow
+279e	heavy triangle-headed rightwards arrow
+279f	dashed triangle-headed rightwards arrow
+27a0	heavy dashed triangle-headed rightwards arrow
+27a1	black rightwards arrow
+27a2	three-d top-lighted rightwards arrowhead
+27a3	three-d bottom-lighted rightwards arrowhead
+27a4	black rightwards arrowhead
+27a5	heavy black curved downwards and rightwards arrow
+27a6	heavy black curved upwards and rightwards arrow
+27a7	squat black rightwards arrow
+27a8	heavy concave-pointed black rightwards arrow
+27a9	right-shaded white rightwards arrow
+27aa	left-shaded white rightwards arrow
+27ab	back-tilted shadowed white rightwards arrow
+27ac	front-tilted shadowed white rightwards arrow
+27ad	heavy lower right-shadowed white rightwards arrow
+27ae	heavy upper right-shadowed white rightwards arrow
+27af	notched lower right-shadowed white rightwards arrow
+27b1	notched upper right-shadowed white rightwards arrow
+27b2	circled heavy white rightwards arrow
+27b3	white-feathered rightwards arrow
+27b4	black-feathered south east arrow
+27b5	black-feathered rightwards arrow
+27b6	black-feathered north east arrow
+27b7	heavy black-feathered south east arrow
+27b8	heavy black-feathered rightwards arrow
+27b9	heavy black-feathered north east arrow
+27ba	teardrop-barbed rightwards arrow
+27bb	heavy teardrop-shanked rightwards arrow
+27bc	wedge-tailed rightwards arrow
+27bd	heavy wedge-tailed rightwards arrow
+27be	open-outlined rightwards arrow
+3000	ideographic space
+3001	ideographic comma
+3002	ideographic full stop
+3003	ditto mark
+3004	japanese industrial standard symbol
+3005	ideographic iteration mark
+3006	ideographic closing mark
+3007	ideographic number zero
+3008	left angle bracket
+3009	right angle bracket
+300a	left double angle bracket
+300b	right double angle bracket
+300c	left corner bracket
+300d	right corner bracket
+300e	left white corner bracket
+300f	right white corner bracket
+3010	left black lenticular bracket
+3011	right black lenticular bracket
+3012	postal mark
+3013	geta mark
+3014	left tortoise shell bracket
+3015	right tortoise shell bracket
+3016	left white lenticular bracket
+3017	right white lenticular bracket
+3018	left white tortoise shell bracket
+3019	right white tortoise shell bracket
+301a	left white square bracket
+301b	right white square bracket
+301c	wave dash
+301d	reversed double prime quotation mark
+301e	double prime quotation mark
+301f	low double prime quotation mark
+3020	postal mark face
+3021	hangzhou numeral one
+3022	hangzhou numeral two
+3023	hangzhou numeral three
+3024	hangzhou numeral four
+3025	hangzhou numeral five
+3026	hangzhou numeral six
+3027	hangzhou numeral seven
+3028	hangzhou numeral eight
+3029	hangzhou numeral nine
+302a	ideographic level tone mark
+302b	ideographic rising tone mark
+302c	ideographic departing tone mark
+302d	ideographic entering tone mark
+302e	hangul single dot tone mark
+302f	hangul double dot tone mark
+3030	wavy dash
+3031	vertical kana repeat mark
+3032	vertical kana repeat with voiced sound mark
+3033	vertical kana repeat mark upper half
+3034	vertical kana repeat with voiced sound mark upper half
+3035	vertical kana repeat mark lower half
+3036	circled postal mark
+3037	ideographic telegraph line feed separator symbol
+303f	ideographic half fill space
+3041	hiragana letter small a
+3042	hiragana letter a
+3043	hiragana letter small i
+3044	hiragana letter i
+3045	hiragana letter small u
+3046	hiragana letter u
+3047	hiragana letter small e
+3048	hiragana letter e
+3049	hiragana letter small o
+304a	hiragana letter o
+304b	hiragana letter ka
+304c	hiragana letter ga
+304d	hiragana letter ki
+304e	hiragana letter gi
+304f	hiragana letter ku
+3050	hiragana letter gu
+3051	hiragana letter ke
+3052	hiragana letter ge
+3053	hiragana letter ko
+3054	hiragana letter go
+3055	hiragana letter sa
+3056	hiragana letter za
+3057	hiragana letter si
+3058	hiragana letter zi
+3059	hiragana letter su
+305a	hiragana letter zu
+305b	hiragana letter se
+305c	hiragana letter ze
+305d	hiragana letter so
+305e	hiragana letter zo
+305f	hiragana letter ta
+3060	hiragana letter da
+3061	hiragana letter ti
+3062	hiragana letter di
+3063	hiragana letter small tu
+3064	hiragana letter tu
+3065	hiragana letter du
+3066	hiragana letter te
+3067	hiragana letter de
+3068	hiragana letter to
+3069	hiragana letter do
+306a	hiragana letter na
+306b	hiragana letter ni
+306c	hiragana letter nu
+306d	hiragana letter ne
+306e	hiragana letter no
+306f	hiragana letter ha
+3070	hiragana letter ba
+3071	hiragana letter pa
+3072	hiragana letter hi
+3073	hiragana letter bi
+3074	hiragana letter pi
+3075	hiragana letter hu
+3076	hiragana letter bu
+3077	hiragana letter pu
+3078	hiragana letter he
+3079	hiragana letter be
+307a	hiragana letter pe
+307b	hiragana letter ho
+307c	hiragana letter bo
+307d	hiragana letter po
+307e	hiragana letter ma
+307f	hiragana letter mi
+3080	hiragana letter mu
+3081	hiragana letter me
+3082	hiragana letter mo
+3083	hiragana letter small ya
+3084	hiragana letter ya
+3085	hiragana letter small yu
+3086	hiragana letter yu
+3087	hiragana letter small yo
+3088	hiragana letter yo
+3089	hiragana letter ra
+308a	hiragana letter ri
+308b	hiragana letter ru
+308c	hiragana letter re
+308d	hiragana letter ro
+308e	hiragana letter small wa
+308f	hiragana letter wa
+3090	hiragana letter wi
+3091	hiragana letter we
+3092	hiragana letter wo
+3093	hiragana letter n
+3094	hiragana letter vu
+3099	combining katakana-hiragana voiced sound mark
+309a	combining katakana-hiragana semi-voiced sound mark
+309b	katakana-hiragana voiced sound mark
+309c	katakana-hiragana semi-voiced sound mark
+309d	hiragana iteration mark
+309e	hiragana voiced iteration mark
+30a1	katakana letter small a
+30a2	katakana letter a
+30a3	katakana letter small i
+30a4	katakana letter i
+30a5	katakana letter small u
+30a6	katakana letter u
+30a7	katakana letter small e
+30a8	katakana letter e
+30a9	katakana letter small o
+30aa	katakana letter o
+30ab	katakana letter ka
+30ac	katakana letter ga
+30ad	katakana letter ki
+30ae	katakana letter gi
+30af	katakana letter ku
+30b0	katakana letter gu
+30b1	katakana letter ke
+30b2	katakana letter ge
+30b3	katakana letter ko
+30b4	katakana letter go
+30b5	katakana letter sa
+30b6	katakana letter za
+30b7	katakana letter si
+30b8	katakana letter zi
+30b9	katakana letter su
+30ba	katakana letter zu
+30bb	katakana letter se
+30bc	katakana letter ze
+30bd	katakana letter so
+30be	katakana letter zo
+30bf	katakana letter ta
+30c0	katakana letter da
+30c1	katakana letter ti
+30c2	katakana letter di
+30c3	katakana letter small tu
+30c4	katakana letter tu
+30c5	katakana letter du
+30c6	katakana letter te
+30c7	katakana letter de
+30c8	katakana letter to
+30c9	katakana letter do
+30ca	katakana letter na
+30cb	katakana letter ni
+30cc	katakana letter nu
+30cd	katakana letter ne
+30ce	katakana letter no
+30cf	katakana letter ha
+30d0	katakana letter ba
+30d1	katakana letter pa
+30d2	katakana letter hi
+30d3	katakana letter bi
+30d4	katakana letter pi
+30d5	katakana letter hu
+30d6	katakana letter bu
+30d7	katakana letter pu
+30d8	katakana letter he
+30d9	katakana letter be
+30da	katakana letter pe
+30db	katakana letter ho
+30dc	katakana letter bo
+30dd	katakana letter po
+30de	katakana letter ma
+30df	katakana letter mi
+30e0	katakana letter mu
+30e1	katakana letter me
+30e2	katakana letter mo
+30e3	katakana letter small ya
+30e4	katakana letter ya
+30e5	katakana letter small yu
+30e6	katakana letter yu
+30e7	katakana letter small yo
+30e8	katakana letter yo
+30e9	katakana letter ra
+30ea	katakana letter ri
+30eb	katakana letter ru
+30ec	katakana letter re
+30ed	katakana letter ro
+30ee	katakana letter small wa
+30ef	katakana letter wa
+30f0	katakana letter wi
+30f1	katakana letter we
+30f2	katakana letter wo
+30f3	katakana letter n
+30f4	katakana letter vu
+30f5	katakana letter small ka
+30f6	katakana letter small ke
+30f7	katakana letter va
+30f8	katakana letter vi
+30f9	katakana letter ve
+30fa	katakana letter vo
+30fb	katakana middle dot
+30fc	katakana-hiragana prolonged sound mark
+30fd	katakana iteration mark
+30fe	katakana voiced iteration mark
+3105	bopomofo letter b
+3106	bopomofo letter p
+3107	bopomofo letter m
+3108	bopomofo letter f
+3109	bopomofo letter d
+310a	bopomofo letter t
+310b	bopomofo letter n
+310c	bopomofo letter l
+310d	bopomofo letter g
+310e	bopomofo letter k
+310f	bopomofo letter h
+3110	bopomofo letter j
+3111	bopomofo letter q
+3112	bopomofo letter x
+3113	bopomofo letter zh
+3114	bopomofo letter ch
+3115	bopomofo letter sh
+3116	bopomofo letter r
+3117	bopomofo letter z
+3118	bopomofo letter c
+3119	bopomofo letter s
+311a	bopomofo letter a
+311b	bopomofo letter o
+311c	bopomofo letter e
+311d	bopomofo letter eh
+311e	bopomofo letter ai
+311f	bopomofo letter ei
+3120	bopomofo letter au
+3121	bopomofo letter ou
+3122	bopomofo letter an
+3123	bopomofo letter en
+3124	bopomofo letter ang
+3125	bopomofo letter eng
+3126	bopomofo letter er
+3127	bopomofo letter i
+3128	bopomofo letter u
+3129	bopomofo letter iu
+312a	bopomofo letter v
+312b	bopomofo letter ng
+312c	bopomofo letter gn
+3131	hangul letter kiyeok
+3132	hangul letter ssangkiyeok
+3133	hangul letter kiyeok-sios
+3134	hangul letter nieun
+3135	hangul letter nieun-cieuc
+3136	hangul letter nieun-hieuh
+3137	hangul letter tikeut
+3138	hangul letter ssangtikeut
+3139	hangul letter rieul
+313a	hangul letter rieul-kiyeok
+313b	hangul letter rieul-mieum
+313c	hangul letter rieul-pieup
+313d	hangul letter rieul-sios
+313e	hangul letter rieul-thieuth
+313f	hangul letter rieul-phieuph
+3140	hangul letter rieul-hieuh
+3141	hangul letter mieum
+3142	hangul letter pieup
+3143	hangul letter ssangpieup
+3144	hangul letter pieup-sios
+3145	hangul letter sios
+3146	hangul letter ssangsios
+3147	hangul letter ieung
+3148	hangul letter cieuc
+3149	hangul letter ssangcieuc
+314a	hangul letter chieuch
+314b	hangul letter khieukh
+314c	hangul letter thieuth
+314d	hangul letter phieuph
+314e	hangul letter hieuh
+314f	hangul letter a
+3150	hangul letter ae
+3151	hangul letter ya
+3152	hangul letter yae
+3153	hangul letter eo
+3154	hangul letter e
+3155	hangul letter yeo
+3156	hangul letter ye
+3157	hangul letter o
+3158	hangul letter wa
+3159	hangul letter wae
+315a	hangul letter oe
+315b	hangul letter yo
+315c	hangul letter u
+315d	hangul letter weo
+315e	hangul letter we
+315f	hangul letter wi
+3160	hangul letter yu
+3161	hangul letter eu
+3162	hangul letter yi
+3163	hangul letter i
+3164	hangul filler
+3165	hangul letter ssangnieun
+3166	hangul letter nieun-tikeut
+3167	hangul letter nieun-sios
+3168	hangul letter nieun-pansios
+3169	hangul letter rieul-kiyeok-sios
+316a	hangul letter rieul-tikeut
+316b	hangul letter rieul-pieup-sios
+316c	hangul letter rieul-pansios
+316d	hangul letter rieul-yeorinhieuh
+316e	hangul letter mieum-pieup
+316f	hangul letter mieum-sios
+3170	hangul letter mieum-pansios
+3171	hangul letter kapyeounmieum
+3172	hangul letter pieup-kiyeok
+3173	hangul letter pieup-tikeut
+3174	hangul letter pieup-sios-kiyeok
+3175	hangul letter pieup-sios-tikeut
+3176	hangul letter pieup-cieuc
+3177	hangul letter pieup-thieuth
+3178	hangul letter kapyeounpieup
+3179	hangul letter kapyeounssangpieup
+317a	hangul letter sios-kiyeok
+317b	hangul letter sios-nieun
+317c	hangul letter sios-tikeut
+317d	hangul letter sios-pieup
+317e	hangul letter sios-cieuc
+317f	hangul letter pansios
+3180	hangul letter ssangieung
+3181	hangul letter yesieung
+3182	hangul letter yesieung-sios
+3183	hangul letter yesieung-pansios
+3184	hangul letter kapyeounphieuph
+3185	hangul letter ssanghieuh
+3186	hangul letter yeorinhieuh
+3187	hangul letter yo-ya
+3188	hangul letter yo-yae
+3189	hangul letter yo-i
+318a	hangul letter yu-yeo
+318b	hangul letter yu-ye
+318c	hangul letter yu-i
+318d	hangul letter araea
+318e	hangul letter araeae
+3190	ideographic annotation linking mark
+3191	ideographic annotation reverse mark
+3192	ideographic annotation one mark
+3193	ideographic annotation two mark
+3194	ideographic annotation three mark
+3195	ideographic annotation four mark
+3196	ideographic annotation top mark
+3197	ideographic annotation middle mark
+3198	ideographic annotation bottom mark
+3199	ideographic annotation first mark
+319a	ideographic annotation second mark
+319b	ideographic annotation third mark
+319c	ideographic annotation fourth mark
+319d	ideographic annotation heaven mark
+319e	ideographic annotation earth mark
+319f	ideographic annotation man mark
+3200	parenthesized hangul kiyeok
+3201	parenthesized hangul nieun
+3202	parenthesized hangul tikeut
+3203	parenthesized hangul rieul
+3204	parenthesized hangul mieum
+3205	parenthesized hangul pieup
+3206	parenthesized hangul sios
+3207	parenthesized hangul ieung
+3208	parenthesized hangul cieuc
+3209	parenthesized hangul chieuch
+320a	parenthesized hangul khieukh
+320b	parenthesized hangul thieuth
+320c	parenthesized hangul phieuph
+320d	parenthesized hangul hieuh
+320e	parenthesized hangul kiyeok a
+320f	parenthesized hangul nieun a
+3210	parenthesized hangul tikeut a
+3211	parenthesized hangul rieul a
+3212	parenthesized hangul mieum a
+3213	parenthesized hangul pieup a
+3214	parenthesized hangul sios a
+3215	parenthesized hangul ieung a
+3216	parenthesized hangul cieuc a
+3217	parenthesized hangul chieuch a
+3218	parenthesized hangul khieukh a
+3219	parenthesized hangul thieuth a
+321a	parenthesized hangul phieuph a
+321b	parenthesized hangul hieuh a
+321c	parenthesized hangul cieuc u
+3220	parenthesized ideograph one
+3221	parenthesized ideograph two
+3222	parenthesized ideograph three
+3223	parenthesized ideograph four
+3224	parenthesized ideograph five
+3225	parenthesized ideograph six
+3226	parenthesized ideograph seven
+3227	parenthesized ideograph eight
+3228	parenthesized ideograph nine
+3229	parenthesized ideograph ten
+322a	parenthesized ideograph moon
+322b	parenthesized ideograph fire
+322c	parenthesized ideograph water
+322d	parenthesized ideograph wood
+322e	parenthesized ideograph metal
+322f	parenthesized ideograph earth
+3230	parenthesized ideograph sun
+3231	parenthesized ideograph stock
+3232	parenthesized ideograph have
+3233	parenthesized ideograph society
+3234	parenthesized ideograph name
+3235	parenthesized ideograph special
+3236	parenthesized ideograph financial
+3237	parenthesized ideograph congratulation
+3238	parenthesized ideograph labor
+3239	parenthesized ideograph represent
+323a	parenthesized ideograph call
+323b	parenthesized ideograph study
+323c	parenthesized ideograph supervise
+323d	parenthesized ideograph enterprise
+323e	parenthesized ideograph resource
+323f	parenthesized ideograph alliance
+3240	parenthesized ideograph festival
+3241	parenthesized ideograph rest
+3242	parenthesized ideograph self
+3243	parenthesized ideograph reach
+3260	circled hangul kiyeok
+3261	circled hangul nieun
+3262	circled hangul tikeut
+3263	circled hangul rieul
+3264	circled hangul mieum
+3265	circled hangul pieup
+3266	circled hangul sios
+3267	circled hangul ieung
+3268	circled hangul cieuc
+3269	circled hangul chieuch
+326a	circled hangul khieukh
+326b	circled hangul thieuth
+326c	circled hangul phieuph
+326d	circled hangul hieuh
+326e	circled hangul kiyeok a
+326f	circled hangul nieun a
+3270	circled hangul tikeut a
+3271	circled hangul rieul a
+3272	circled hangul mieum a
+3273	circled hangul pieup a
+3274	circled hangul sios a
+3275	circled hangul ieung a
+3276	circled hangul cieuc a
+3277	circled hangul chieuch a
+3278	circled hangul khieukh a
+3279	circled hangul thieuth a
+327a	circled hangul phieuph a
+327b	circled hangul hieuh a
+327f	korean standard symbol
+3280	circled ideograph one
+3281	circled ideograph two
+3282	circled ideograph three
+3283	circled ideograph four
+3284	circled ideograph five
+3285	circled ideograph six
+3286	circled ideograph seven
+3287	circled ideograph eight
+3288	circled ideograph nine
+3289	circled ideograph ten
+328a	circled ideograph moon
+328b	circled ideograph fire
+328c	circled ideograph water
+328d	circled ideograph wood
+328e	circled ideograph metal
+328f	circled ideograph earth
+3290	circled ideograph sun
+3291	circled ideograph stock
+3292	circled ideograph have
+3293	circled ideograph society
+3294	circled ideograph name
+3295	circled ideograph special
+3296	circled ideograph financial
+3297	circled ideograph congratulation
+3298	circled ideograph labor
+3299	circled ideograph secret
+329a	circled ideograph male
+329b	circled ideograph female
+329c	circled ideograph suitable
+329d	circled ideograph excellent
+329e	circled ideograph print
+329f	circled ideograph attention
+32a0	circled ideograph item
+32a1	circled ideograph rest
+32a2	circled ideograph copy
+32a3	circled ideograph correct
+32a4	circled ideograph high
+32a5	circled ideograph centre
+32a6	circled ideograph low
+32a7	circled ideograph left
+32a8	circled ideograph right
+32a9	circled ideograph medicine
+32aa	circled ideograph religion
+32ab	circled ideograph study
+32ac	circled ideograph supervise
+32ad	circled ideograph enterprise
+32ae	circled ideograph resource
+32af	circled ideograph alliance
+32b0	circled ideograph night
+32c0	ideographic telegraph symbol for january
+32c1	ideographic telegraph symbol for february
+32c2	ideographic telegraph symbol for march
+32c3	ideographic telegraph symbol for april
+32c4	ideographic telegraph symbol for may
+32c5	ideographic telegraph symbol for june
+32c6	ideographic telegraph symbol for july
+32c7	ideographic telegraph symbol for august
+32c8	ideographic telegraph symbol for september
+32c9	ideographic telegraph symbol for october
+32ca	ideographic telegraph symbol for november
+32cb	ideographic telegraph symbol for december
+32d0	circled katakana a
+32d1	circled katakana i
+32d2	circled katakana u
+32d3	circled katakana e
+32d4	circled katakana o
+32d5	circled katakana ka
+32d6	circled katakana ki
+32d7	circled katakana ku
+32d8	circled katakana ke
+32d9	circled katakana ko
+32da	circled katakana sa
+32db	circled katakana si
+32dc	circled katakana su
+32dd	circled katakana se
+32de	circled katakana so
+32df	circled katakana ta
+32e0	circled katakana ti
+32e1	circled katakana tu
+32e2	circled katakana te
+32e3	circled katakana to
+32e4	circled katakana na
+32e5	circled katakana ni
+32e6	circled katakana nu
+32e7	circled katakana ne
+32e8	circled katakana no
+32e9	circled katakana ha
+32ea	circled katakana hi
+32eb	circled katakana hu
+32ec	circled katakana he
+32ed	circled katakana ho
+32ee	circled katakana ma
+32ef	circled katakana mi
+32f0	circled katakana mu
+32f1	circled katakana me
+32f2	circled katakana mo
+32f3	circled katakana ya
+32f4	circled katakana yu
+32f5	circled katakana yo
+32f6	circled katakana ra
+32f7	circled katakana ri
+32f8	circled katakana ru
+32f9	circled katakana re
+32fa	circled katakana ro
+32fb	circled katakana wa
+32fc	circled katakana wi
+32fd	circled katakana we
+32fe	circled katakana wo
+3300	square apaato
+3301	square aruhua
+3302	square anpea
+3303	square aaru
+3304	square iningu
+3305	square inti
+3306	square uon
+3307	square esukuudo
+3308	square eekaa
+3309	square onsu
+330a	square oomu
+330b	square kairi
+330c	square karatto
+330d	square karorii
+330e	square garon
+330f	square ganma
+3310	square giga
+3311	square ginii
+3312	square kyurii
+3313	square girudaa
+3314	square kiro
+3315	square kiroguramu
+3316	square kiromeetoru
+3317	square kirowatto
+3318	square guramu
+3319	square guramuton
+331a	square kuruzeiro
+331b	square kuroone
+331c	square keesu
+331d	square koruna
+331e	square koopo
+331f	square saikuru
+3320	square santiimu
+3321	square siringu
+3322	square senti
+3323	square sento
+3324	square daasu
+3325	square desi
+3326	square doru
+3327	square ton
+3328	square nano
+3329	square notto
+332a	square haitu
+332b	square paasento
+332c	square paatu
+332d	square baareru
+332e	square piasutoru
+332f	square pikuru
+3330	square piko
+3331	square biru
+3332	square huaraddo
+3333	square huiito
+3334	square bussyeru
+3335	square huran
+3336	square hekutaaru
+3337	square peso
+3338	square penihi
+3339	square herutu
+333a	square pensu
+333b	square peezi
+333c	square beeta
+333d	square pointo
+333e	square boruto
+333f	square hon
+3340	square pondo
+3341	square hooru
+3342	square hoon
+3343	square maikuro
+3344	square mairu
+3345	square mahha
+3346	square maruku
+3347	square mansyon
+3348	square mikuron
+3349	square miri
+334a	square miribaaru
+334b	square mega
+334c	square megaton
+334d	square meetoru
+334e	square yaado
+334f	square yaaru
+3350	square yuan
+3351	square rittoru
+3352	square rira
+3353	square rupii
+3354	square ruuburu
+3355	square remu
+3356	square rentogen
+3357	square watto
+3358	ideographic telegraph symbol for hour zero
+3359	ideographic telegraph symbol for hour one
+335a	ideographic telegraph symbol for hour two
+335b	ideographic telegraph symbol for hour three
+335c	ideographic telegraph symbol for hour four
+335d	ideographic telegraph symbol for hour five
+335e	ideographic telegraph symbol for hour six
+335f	ideographic telegraph symbol for hour seven
+3360	ideographic telegraph symbol for hour eight
+3361	ideographic telegraph symbol for hour nine
+3362	ideographic telegraph symbol for hour ten
+3363	ideographic telegraph symbol for hour eleven
+3364	ideographic telegraph symbol for hour twelve
+3365	ideographic telegraph symbol for hour thirteen
+3366	ideographic telegraph symbol for hour fourteen
+3367	ideographic telegraph symbol for hour fifteen
+3368	ideographic telegraph symbol for hour sixteen
+3369	ideographic telegraph symbol for hour seventeen
+336a	ideographic telegraph symbol for hour eighteen
+336b	ideographic telegraph symbol for hour nineteen
+336c	ideographic telegraph symbol for hour twenty
+336d	ideographic telegraph symbol for hour twenty-one
+336e	ideographic telegraph symbol for hour twenty-two
+336f	ideographic telegraph symbol for hour twenty-three
+3370	ideographic telegraph symbol for hour twenty-four
+3371	square hpa
+3372	square da
+3373	square au
+3374	square bar
+3375	square ov
+3376	square pc
+337b	square era name heisei
+337c	square era name syouwa
+337d	square era name taisyou
+337e	square era name meizi
+337f	square corporation
+3380	square pa amps
+3381	square na
+3382	square mu a
+3383	square ma
+3384	square ka
+3385	square kb
+3386	square mb
+3387	square gb
+3388	square cal
+3389	square kcal
+338a	square pf
+338b	square nf
+338c	square mu f
+338d	square mu g
+338e	square mg
+338f	square kg
+3390	square hz
+3391	square khz
+3392	square mhz
+3393	square ghz
+3394	square thz
+3395	square mu l
+3396	square ml
+3397	square dl
+3398	square kl
+3399	square fm
+339a	square nm
+339b	square mu m
+339c	square mm
+339d	square cm
+339e	square km
+339f	square mm squared
+33a0	square cm squared
+33a1	square m squared
+33a2	square km squared
+33a3	square mm cubed
+33a4	square cm cubed
+33a5	square m cubed
+33a6	square km cubed
+33a7	square m over s
+33a8	square m over s squared
+33a9	square pa
+33aa	square kpa
+33ab	square mpa
+33ac	square gpa
+33ad	square rad
+33ae	square rad over s
+33af	square rad over s squared
+33b0	square ps
+33b1	square ns
+33b2	square mu s
+33b3	square ms
+33b4	square pv
+33b5	square nv
+33b6	square mu v
+33b7	square mv
+33b8	square kv
+33b9	square mv mega
+33ba	square pw
+33bb	square nw
+33bc	square mu w
+33bd	square mw
+33be	square kw
+33bf	square mw mega
+33c0	square k ohm
+33c1	square m ohm
+33c2	square am
+33c3	square bq
+33c4	square cc
+33c5	square cd
+33c6	square c over kg
+33c7	square co
+33c8	square db
+33c9	square gy
+33ca	square ha
+33cb	square hp
+33cc	square in
+33cd	square kk
+33ce	square km capital
+33cf	square kt
+33d0	square lm
+33d1	square ln
+33d2	square log
+33d3	square lx
+33d4	square mb small
+33d5	square mil
+33d6	square mol
+33d7	square ph
+33d8	square pm
+33d9	square ppm
+33da	square pr
+33db	square sr
+33dc	square sv
+33dd	square wb
+33e0	ideographic telegraph symbol for day one
+33e1	ideographic telegraph symbol for day two
+33e2	ideographic telegraph symbol for day three
+33e3	ideographic telegraph symbol for day four
+33e4	ideographic telegraph symbol for day five
+33e5	ideographic telegraph symbol for day six
+33e6	ideographic telegraph symbol for day seven
+33e7	ideographic telegraph symbol for day eight
+33e8	ideographic telegraph symbol for day nine
+33e9	ideographic telegraph symbol for day ten
+33ea	ideographic telegraph symbol for day eleven
+33eb	ideographic telegraph symbol for day twelve
+33ec	ideographic telegraph symbol for day thirteen
+33ed	ideographic telegraph symbol for day fourteen
+33ee	ideographic telegraph symbol for day fifteen
+33ef	ideographic telegraph symbol for day sixteen
+33f0	ideographic telegraph symbol for day seventeen
+33f1	ideographic telegraph symbol for day eighteen
+33f2	ideographic telegraph symbol for day nineteen
+33f3	ideographic telegraph symbol for day twenty
+33f4	ideographic telegraph symbol for day twenty-one
+33f5	ideographic telegraph symbol for day twenty-two
+33f6	ideographic telegraph symbol for day twenty-three
+33f7	ideographic telegraph symbol for day twenty-four
+33f8	ideographic telegraph symbol for day twenty-five
+33f9	ideographic telegraph symbol for day twenty-six
+33fa	ideographic telegraph symbol for day twenty-seven
+33fb	ideographic telegraph symbol for day twenty-eight
+33fc	ideographic telegraph symbol for day twenty-nine
+33fd	ideographic telegraph symbol for day thirty
+33fe	ideographic telegraph symbol for day thirty-one
+4e00	<cjk ideograph, first>
+9fa5	<cjk ideograph, last>
+ac00	<hangul syllable, first>
+d7a3	<hangul syllable, last>
+d800	<unassigned high surrogate, first>
+db7f	<unassigned high surrogate, last>
+db80	<private use high surrogate, first>
+dbff	<private use high surrogate, last>
+dc00	<low surrogate, first>
+dfff	<low surrogate, last>
+e000	<private use, first>
+f8ff	<private use, last>
+f900	<cjk compatibility ideograph, first>
+fa2d	<cjk compatibility ideograph, last>
+fb00	latin small ligature ff
+fb01	latin small ligature fi
+fb02	latin small ligature fl
+fb03	latin small ligature ffi
+fb04	latin small ligature ffl
+fb05	latin small ligature long s t
+fb06	latin small ligature st
+fb13	armenian small ligature men now
+fb14	armenian small ligature men ech
+fb15	armenian small ligature men ini
+fb16	armenian small ligature vew now
+fb17	armenian small ligature men xeh
+fb1e	hebrew point judeo-spanish varika
+fb1f	hebrew ligature yiddish yod yod patah
+fb20	hebrew letter alternative ayin
+fb21	hebrew letter wide alef
+fb22	hebrew letter wide dalet
+fb23	hebrew letter wide he
+fb24	hebrew letter wide kaf
+fb25	hebrew letter wide lamed
+fb26	hebrew letter wide final mem
+fb27	hebrew letter wide resh
+fb28	hebrew letter wide tav
+fb29	hebrew letter alternative plus sign
+fb2a	hebrew letter shin with shin dot
+fb2b	hebrew letter shin with sin dot
+fb2c	hebrew letter shin with dagesh and shin dot
+fb2d	hebrew letter shin with dagesh and sin dot
+fb2e	hebrew letter alef with patah
+fb2f	hebrew letter alef with qamats
+fb30	hebrew letter alef with mapiq
+fb31	hebrew letter bet with dagesh
+fb32	hebrew letter gimel with dagesh
+fb33	hebrew letter dalet with dagesh
+fb34	hebrew letter he with mapiq
+fb35	hebrew letter vav with dagesh
+fb36	hebrew letter zayin with dagesh
+fb38	hebrew letter tet with dagesh
+fb39	hebrew letter yod with dagesh
+fb3a	hebrew letter final kaf with dagesh
+fb3b	hebrew letter kaf with dagesh
+fb3c	hebrew letter lamed with dagesh
+fb3e	hebrew letter mem with dagesh
+fb40	hebrew letter nun with dagesh
+fb41	hebrew letter samekh with dagesh
+fb43	hebrew letter final pe with dagesh
+fb44	hebrew letter pe with dagesh
+fb46	hebrew letter tsadi with dagesh
+fb47	hebrew letter qof with dagesh
+fb48	hebrew letter resh with dagesh
+fb49	hebrew letter shin with dagesh
+fb4a	hebrew letter tav with dagesh
+fb4b	hebrew letter vav with holam
+fb4c	hebrew letter bet with rafe
+fb4d	hebrew letter kaf with rafe
+fb4e	hebrew letter pe with rafe
+fb4f	hebrew ligature alef lamed
+fb50	arabic letter alef wasla isolated form
+fb51	arabic letter alef wasla final form
+fb52	arabic letter beeh isolated form
+fb53	arabic letter beeh final form
+fb54	arabic letter beeh initial form
+fb55	arabic letter beeh medial form
+fb56	arabic letter peh isolated form
+fb57	arabic letter peh final form
+fb58	arabic letter peh initial form
+fb59	arabic letter peh medial form
+fb5a	arabic letter beheh isolated form
+fb5b	arabic letter beheh final form
+fb5c	arabic letter beheh initial form
+fb5d	arabic letter beheh medial form
+fb5e	arabic letter tteheh isolated form
+fb5f	arabic letter tteheh final form
+fb60	arabic letter tteheh initial form
+fb61	arabic letter tteheh medial form
+fb62	arabic letter teheh isolated form
+fb63	arabic letter teheh final form
+fb64	arabic letter teheh initial form
+fb65	arabic letter teheh medial form
+fb66	arabic letter tteh isolated form
+fb67	arabic letter tteh final form
+fb68	arabic letter tteh initial form
+fb69	arabic letter tteh medial form
+fb6a	arabic letter veh isolated form
+fb6b	arabic letter veh final form
+fb6c	arabic letter veh initial form
+fb6d	arabic letter veh medial form
+fb6e	arabic letter peheh isolated form
+fb6f	arabic letter peheh final form
+fb70	arabic letter peheh initial form
+fb71	arabic letter peheh medial form
+fb72	arabic letter dyeh isolated form
+fb73	arabic letter dyeh final form
+fb74	arabic letter dyeh initial form
+fb75	arabic letter dyeh medial form
+fb76	arabic letter nyeh isolated form
+fb77	arabic letter nyeh final form
+fb78	arabic letter nyeh initial form
+fb79	arabic letter nyeh medial form
+fb7a	arabic letter tcheh isolated form
+fb7b	arabic letter tcheh final form
+fb7c	arabic letter tcheh initial form
+fb7d	arabic letter tcheh medial form
+fb7e	arabic letter tcheheh isolated form
+fb7f	arabic letter tcheheh final form
+fb80	arabic letter tcheheh initial form
+fb81	arabic letter tcheheh medial form
+fb82	arabic letter ddahal isolated form
+fb83	arabic letter ddahal final form
+fb84	arabic letter dahal isolated form
+fb85	arabic letter dahal final form
+fb86	arabic letter dul isolated form
+fb87	arabic letter dul final form
+fb88	arabic letter ddal isolated form
+fb89	arabic letter ddal final form
+fb8a	arabic letter jeh isolated form
+fb8b	arabic letter jeh final form
+fb8c	arabic letter rreh isolated form
+fb8d	arabic letter rreh final form
+fb8e	arabic letter keheh isolated form
+fb8f	arabic letter keheh final form
+fb90	arabic letter keheh initial form
+fb91	arabic letter keheh medial form
+fb92	arabic letter gaf isolated form
+fb93	arabic letter gaf final form
+fb94	arabic letter gaf initial form
+fb95	arabic letter gaf medial form
+fb96	arabic letter gueh isolated form
+fb97	arabic letter gueh final form
+fb98	arabic letter gueh initial form
+fb99	arabic letter gueh medial form
+fb9a	arabic letter ngoeh isolated form
+fb9b	arabic letter ngoeh final form
+fb9c	arabic letter ngoeh initial form
+fb9d	arabic letter ngoeh medial form
+fb9e	arabic letter noon ghunna isolated form
+fb9f	arabic letter noon ghunna final form
+fba0	arabic letter rnoon isolated form
+fba1	arabic letter rnoon final form
+fba2	arabic letter rnoon initial form
+fba3	arabic letter rnoon medial form
+fba4	arabic letter heh with yeh above isolated form
+fba5	arabic letter heh with yeh above final form
+fba6	arabic letter heh goal isolated form
+fba7	arabic letter heh goal final form
+fba8	arabic letter heh goal initial form
+fba9	arabic letter heh goal medial form
+fbaa	arabic letter heh doachashmee isolated form
+fbab	arabic letter heh doachashmee final form
+fbac	arabic letter heh doachashmee initial form
+fbad	arabic letter heh doachashmee medial form
+fbae	arabic letter yeh barree isolated form
+fbaf	arabic letter yeh barree final form
+fbb0	arabic letter yeh barree with hamza above isolated form
+fbb1	arabic letter yeh barree with hamza above final form
+fbd3	arabic letter ng isolated form
+fbd4	arabic letter ng final form
+fbd5	arabic letter ng initial form
+fbd6	arabic letter ng medial form
+fbd7	arabic letter u isolated form
+fbd8	arabic letter u final form
+fbd9	arabic letter oe isolated form
+fbda	arabic letter oe final form
+fbdb	arabic letter yu isolated form
+fbdc	arabic letter yu final form
+fbdd	arabic letter u with hamza above isolated form
+fbde	arabic letter ve isolated form
+fbdf	arabic letter ve final form
+fbe0	arabic letter kirghiz oe isolated form
+fbe1	arabic letter kirghiz oe final form
+fbe2	arabic letter kirghiz yu isolated form
+fbe3	arabic letter kirghiz yu final form
+fbe4	arabic letter e isolated form
+fbe5	arabic letter e final form
+fbe6	arabic letter e initial form
+fbe7	arabic letter e medial form
+fbe8	arabic letter uighur kazakh kirghiz alef maksura initial form
+fbe9	arabic letter uighur kazakh kirghiz alef maksura medial form
+fbea	arabic ligature yeh with hamza above with alef isolated form
+fbeb	arabic ligature yeh with hamza above with alef final form
+fbec	arabic ligature yeh with hamza above with ae isolated form
+fbed	arabic ligature yeh with hamza above with ae final form
+fbee	arabic ligature yeh with hamza above with waw isolated form
+fbef	arabic ligature yeh with hamza above with waw final form
+fbf0	arabic ligature yeh with hamza above with u isolated form
+fbf1	arabic ligature yeh with hamza above with u final form
+fbf2	arabic ligature yeh with hamza above with oe isolated form
+fbf3	arabic ligature yeh with hamza above with oe final form
+fbf4	arabic ligature yeh with hamza above with yu isolated form
+fbf5	arabic ligature yeh with hamza above with yu final form
+fbf6	arabic ligature yeh with hamza above with e isolated form
+fbf7	arabic ligature yeh with hamza above with e final form
+fbf8	arabic ligature yeh with hamza above with e initial form
+fbf9	arabic ligature uighur kirghiz yeh with hamza above with alef maksura isolated form
+fbfa	arabic ligature uighur kirghiz yeh with hamza above with alef maksura final form
+fbfb	arabic ligature uighur kirghiz yeh with hamza above with alef maksura initial form
+fbfc	arabic letter farsi yeh isolated form
+fbfd	arabic letter farsi yeh final form
+fbfe	arabic letter farsi yeh initial form
+fbff	arabic letter farsi yeh medial form
+fc00	arabic ligature yeh with hamza above with jeem isolated form
+fc01	arabic ligature yeh with hamza above with hah isolated form
+fc02	arabic ligature yeh with hamza above with meem isolated form
+fc03	arabic ligature yeh with hamza above with alef maksura isolated form
+fc04	arabic ligature yeh with hamza above with yeh isolated form
+fc05	arabic ligature beh with jeem isolated form
+fc06	arabic ligature beh with hah isolated form
+fc07	arabic ligature beh with khah isolated form
+fc08	arabic ligature beh with meem isolated form
+fc09	arabic ligature beh with alef maksura isolated form
+fc0a	arabic ligature beh with yeh isolated form
+fc0b	arabic ligature teh with jeem isolated form
+fc0c	arabic ligature teh with hah isolated form
+fc0d	arabic ligature teh with khah isolated form
+fc0e	arabic ligature teh with meem isolated form
+fc0f	arabic ligature teh with alef maksura isolated form
+fc10	arabic ligature teh with yeh isolated form
+fc11	arabic ligature theh with jeem isolated form
+fc12	arabic ligature theh with meem isolated form
+fc13	arabic ligature theh with alef maksura isolated form
+fc14	arabic ligature theh with yeh isolated form
+fc15	arabic ligature jeem with hah isolated form
+fc16	arabic ligature jeem with meem isolated form
+fc17	arabic ligature hah with jeem isolated form
+fc18	arabic ligature hah with meem isolated form
+fc19	arabic ligature khah with jeem isolated form
+fc1a	arabic ligature khah with hah isolated form
+fc1b	arabic ligature khah with meem isolated form
+fc1c	arabic ligature seen with jeem isolated form
+fc1d	arabic ligature seen with hah isolated form
+fc1e	arabic ligature seen with khah isolated form
+fc1f	arabic ligature seen with meem isolated form
+fc20	arabic ligature sad with hah isolated form
+fc21	arabic ligature sad with meem isolated form
+fc22	arabic ligature dad with jeem isolated form
+fc23	arabic ligature dad with hah isolated form
+fc24	arabic ligature dad with khah isolated form
+fc25	arabic ligature dad with meem isolated form
+fc26	arabic ligature tah with hah isolated form
+fc27	arabic ligature tah with meem isolated form
+fc28	arabic ligature zah with meem isolated form
+fc29	arabic ligature ain with jeem isolated form
+fc2a	arabic ligature ain with meem isolated form
+fc2b	arabic ligature ghain with jeem isolated form
+fc2c	arabic ligature ghain with meem isolated form
+fc2d	arabic ligature feh with jeem isolated form
+fc2e	arabic ligature feh with hah isolated form
+fc2f	arabic ligature feh with khah isolated form
+fc30	arabic ligature feh with meem isolated form
+fc31	arabic ligature feh with alef maksura isolated form
+fc32	arabic ligature feh with yeh isolated form
+fc33	arabic ligature qaf with hah isolated form
+fc34	arabic ligature qaf with meem isolated form
+fc35	arabic ligature qaf with alef maksura isolated form
+fc36	arabic ligature qaf with yeh isolated form
+fc37	arabic ligature kaf with alef isolated form
+fc38	arabic ligature kaf with jeem isolated form
+fc39	arabic ligature kaf with hah isolated form
+fc3a	arabic ligature kaf with khah isolated form
+fc3b	arabic ligature kaf with lam isolated form
+fc3c	arabic ligature kaf with meem isolated form
+fc3d	arabic ligature kaf with alef maksura isolated form
+fc3e	arabic ligature kaf with yeh isolated form
+fc3f	arabic ligature lam with jeem isolated form
+fc40	arabic ligature lam with hah isolated form
+fc41	arabic ligature lam with khah isolated form
+fc42	arabic ligature lam with meem isolated form
+fc43	arabic ligature lam with alef maksura isolated form
+fc44	arabic ligature lam with yeh isolated form
+fc45	arabic ligature meem with jeem isolated form
+fc46	arabic ligature meem with hah isolated form
+fc47	arabic ligature meem with khah isolated form
+fc48	arabic ligature meem with meem isolated form
+fc49	arabic ligature meem with alef maksura isolated form
+fc4a	arabic ligature meem with yeh isolated form
+fc4b	arabic ligature noon with jeem isolated form
+fc4c	arabic ligature noon with hah isolated form
+fc4d	arabic ligature noon with khah isolated form
+fc4e	arabic ligature noon with meem isolated form
+fc4f	arabic ligature noon with alef maksura isolated form
+fc50	arabic ligature noon with yeh isolated form
+fc51	arabic ligature heh with jeem isolated form
+fc52	arabic ligature heh with meem isolated form
+fc53	arabic ligature heh with alef maksura isolated form
+fc54	arabic ligature heh with yeh isolated form
+fc55	arabic ligature yeh with jeem isolated form
+fc56	arabic ligature yeh with hah isolated form
+fc57	arabic ligature yeh with khah isolated form
+fc58	arabic ligature yeh with meem isolated form
+fc59	arabic ligature yeh with alef maksura isolated form
+fc5a	arabic ligature yeh with yeh isolated form
+fc5b	arabic ligature thal with superscript alef isolated form
+fc5c	arabic ligature reh with superscript alef isolated form
+fc5d	arabic ligature alef maksura with superscript alef isolated form
+fc5e	arabic ligature shadda with dammatan isolated form
+fc5f	arabic ligature shadda with kasratan isolated form
+fc60	arabic ligature shadda with fatha isolated form
+fc61	arabic ligature shadda with damma isolated form
+fc62	arabic ligature shadda with kasra isolated form
+fc63	arabic ligature shadda with superscript alef isolated form
+fc64	arabic ligature yeh with hamza above with reh final form
+fc65	arabic ligature yeh with hamza above with zain final form
+fc66	arabic ligature yeh with hamza above with meem final form
+fc67	arabic ligature yeh with hamza above with noon final form
+fc68	arabic ligature yeh with hamza above with alef maksura final form
+fc69	arabic ligature yeh with hamza above with yeh final form
+fc6a	arabic ligature beh with reh final form
+fc6b	arabic ligature beh with zain final form
+fc6c	arabic ligature beh with meem final form
+fc6d	arabic ligature beh with noon final form
+fc6e	arabic ligature beh with alef maksura final form
+fc6f	arabic ligature beh with yeh final form
+fc70	arabic ligature teh with reh final form
+fc71	arabic ligature teh with zain final form
+fc72	arabic ligature teh with meem final form
+fc73	arabic ligature teh with noon final form
+fc74	arabic ligature teh with alef maksura final form
+fc75	arabic ligature teh with yeh final form
+fc76	arabic ligature theh with reh final form
+fc77	arabic ligature theh with zain final form
+fc78	arabic ligature theh with meem final form
+fc79	arabic ligature theh with noon final form
+fc7a	arabic ligature theh with alef maksura final form
+fc7b	arabic ligature theh with yeh final form
+fc7c	arabic ligature feh with alef maksura final form
+fc7d	arabic ligature feh with yeh final form
+fc7e	arabic ligature qaf with alef maksura final form
+fc7f	arabic ligature qaf with yeh final form
+fc80	arabic ligature kaf with alef final form
+fc81	arabic ligature kaf with lam final form
+fc82	arabic ligature kaf with meem final form
+fc83	arabic ligature kaf with alef maksura final form
+fc84	arabic ligature kaf with yeh final form
+fc85	arabic ligature lam with meem final form
+fc86	arabic ligature lam with alef maksura final form
+fc87	arabic ligature lam with yeh final form
+fc88	arabic ligature meem with alef final form
+fc89	arabic ligature meem with meem final form
+fc8a	arabic ligature noon with reh final form
+fc8b	arabic ligature noon with zain final form
+fc8c	arabic ligature noon with meem final form
+fc8d	arabic ligature noon with noon final form
+fc8e	arabic ligature noon with alef maksura final form
+fc8f	arabic ligature noon with yeh final form
+fc90	arabic ligature alef maksura with superscript alef final form
+fc91	arabic ligature yeh with reh final form
+fc92	arabic ligature yeh with zain final form
+fc93	arabic ligature yeh with meem final form
+fc94	arabic ligature yeh with noon final form
+fc95	arabic ligature yeh with alef maksura final form
+fc96	arabic ligature yeh with yeh final form
+fc97	arabic ligature yeh with hamza above with jeem initial form
+fc98	arabic ligature yeh with hamza above with hah initial form
+fc99	arabic ligature yeh with hamza above with khah initial form
+fc9a	arabic ligature yeh with hamza above with meem initial form
+fc9b	arabic ligature yeh with hamza above with heh initial form
+fc9c	arabic ligature beh with jeem initial form
+fc9d	arabic ligature beh with hah initial form
+fc9e	arabic ligature beh with khah initial form
+fc9f	arabic ligature beh with meem initial form
+fca0	arabic ligature beh with heh initial form
+fca1	arabic ligature teh with jeem initial form
+fca2	arabic ligature teh with hah initial form
+fca3	arabic ligature teh with khah initial form
+fca4	arabic ligature teh with meem initial form
+fca5	arabic ligature teh with heh initial form
+fca6	arabic ligature theh with meem initial form
+fca7	arabic ligature jeem with hah initial form
+fca8	arabic ligature jeem with meem initial form
+fca9	arabic ligature hah with jeem initial form
+fcaa	arabic ligature hah with meem initial form
+fcab	arabic ligature khah with jeem initial form
+fcac	arabic ligature khah with meem initial form
+fcad	arabic ligature seen with jeem initial form
+fcae	arabic ligature seen with hah initial form
+fcaf	arabic ligature seen with khah initial form
+fcb0	arabic ligature seen with meem initial form
+fcb1	arabic ligature sad with hah initial form
+fcb2	arabic ligature sad with khah initial form
+fcb3	arabic ligature sad with meem initial form
+fcb4	arabic ligature dad with jeem initial form
+fcb5	arabic ligature dad with hah initial form
+fcb6	arabic ligature dad with khah initial form
+fcb7	arabic ligature dad with meem initial form
+fcb8	arabic ligature tah with hah initial form
+fcb9	arabic ligature zah with meem initial form
+fcba	arabic ligature ain with jeem initial form
+fcbb	arabic ligature ain with meem initial form
+fcbc	arabic ligature ghain with jeem initial form
+fcbd	arabic ligature ghain with meem initial form
+fcbe	arabic ligature feh with jeem initial form
+fcbf	arabic ligature feh with hah initial form
+fcc0	arabic ligature feh with khah initial form
+fcc1	arabic ligature feh with meem initial form
+fcc2	arabic ligature qaf with hah initial form
+fcc3	arabic ligature qaf with meem initial form
+fcc4	arabic ligature kaf with jeem initial form
+fcc5	arabic ligature kaf with hah initial form
+fcc6	arabic ligature kaf with khah initial form
+fcc7	arabic ligature kaf with lam initial form
+fcc8	arabic ligature kaf with meem initial form
+fcc9	arabic ligature lam with jeem initial form
+fcca	arabic ligature lam with hah initial form
+fccb	arabic ligature lam with khah initial form
+fccc	arabic ligature lam with meem initial form
+fccd	arabic ligature lam with heh initial form
+fcce	arabic ligature meem with jeem initial form
+fccf	arabic ligature meem with hah initial form
+fcd0	arabic ligature meem with khah initial form
+fcd1	arabic ligature meem with meem initial form
+fcd2	arabic ligature noon with jeem initial form
+fcd3	arabic ligature noon with hah initial form
+fcd4	arabic ligature noon with khah initial form
+fcd5	arabic ligature noon with meem initial form
+fcd6	arabic ligature noon with heh initial form
+fcd7	arabic ligature heh with jeem initial form
+fcd8	arabic ligature heh with meem initial form
+fcd9	arabic ligature heh with superscript alef initial form
+fcda	arabic ligature yeh with jeem initial form
+fcdb	arabic ligature yeh with hah initial form
+fcdc	arabic ligature yeh with khah initial form
+fcdd	arabic ligature yeh with meem initial form
+fcde	arabic ligature yeh with heh initial form
+fcdf	arabic ligature yeh with hamza above with meem medial form
+fce0	arabic ligature yeh with hamza above with heh medial form
+fce1	arabic ligature beh with meem medial form
+fce2	arabic ligature beh with heh medial form
+fce3	arabic ligature teh with meem medial form
+fce4	arabic ligature teh with heh medial form
+fce5	arabic ligature theh with meem medial form
+fce6	arabic ligature theh with heh medial form
+fce7	arabic ligature seen with meem medial form
+fce8	arabic ligature seen with heh medial form
+fce9	arabic ligature sheen with meem medial form
+fcea	arabic ligature sheen with heh medial form
+fceb	arabic ligature kaf with lam medial form
+fcec	arabic ligature kaf with meem medial form
+fced	arabic ligature lam with meem medial form
+fcee	arabic ligature noon with meem medial form
+fcef	arabic ligature noon with heh medial form
+fcf0	arabic ligature yeh with meem medial form
+fcf1	arabic ligature yeh with heh medial form
+fcf2	arabic ligature shadda with fatha medial form
+fcf3	arabic ligature shadda with damma medial form
+fcf4	arabic ligature shadda with kasra medial form
+fcf5	arabic ligature tah with alef maksura isolated form
+fcf6	arabic ligature tah with yeh isolated form
+fcf7	arabic ligature ain with alef maksura isolated form
+fcf8	arabic ligature ain with yeh isolated form
+fcf9	arabic ligature ghain with alef maksura isolated form
+fcfa	arabic ligature ghain with yeh isolated form
+fcfb	arabic ligature seen with alef maksura isolated form
+fcfc	arabic ligature seen with yeh isolated form
+fcfd	arabic ligature sheen with alef maksura isolated form
+fcfe	arabic ligature sheen with yeh isolated form
+fcff	arabic ligature hah with alef maksura isolated form
+fd00	arabic ligature hah with yeh isolated form
+fd01	arabic ligature jeem with alef maksura isolated form
+fd02	arabic ligature jeem with yeh isolated form
+fd03	arabic ligature khah with alef maksura isolated form
+fd04	arabic ligature khah with yeh isolated form
+fd05	arabic ligature sad with alef maksura isolated form
+fd06	arabic ligature sad with yeh isolated form
+fd07	arabic ligature dad with alef maksura isolated form
+fd08	arabic ligature dad with yeh isolated form
+fd09	arabic ligature sheen with jeem isolated form
+fd0a	arabic ligature sheen with hah isolated form
+fd0b	arabic ligature sheen with khah isolated form
+fd0c	arabic ligature sheen with meem isolated form
+fd0d	arabic ligature sheen with reh isolated form
+fd0e	arabic ligature seen with reh isolated form
+fd0f	arabic ligature sad with reh isolated form
+fd10	arabic ligature dad with reh isolated form
+fd11	arabic ligature tah with alef maksura final form
+fd12	arabic ligature tah with yeh final form
+fd13	arabic ligature ain with alef maksura final form
+fd14	arabic ligature ain with yeh final form
+fd15	arabic ligature ghain with alef maksura final form
+fd16	arabic ligature ghain with yeh final form
+fd17	arabic ligature seen with alef maksura final form
+fd18	arabic ligature seen with yeh final form
+fd19	arabic ligature sheen with alef maksura final form
+fd1a	arabic ligature sheen with yeh final form
+fd1b	arabic ligature hah with alef maksura final form
+fd1c	arabic ligature hah with yeh final form
+fd1d	arabic ligature jeem with alef maksura final form
+fd1e	arabic ligature jeem with yeh final form
+fd1f	arabic ligature khah with alef maksura final form
+fd20	arabic ligature khah with yeh final form
+fd21	arabic ligature sad with alef maksura final form
+fd22	arabic ligature sad with yeh final form
+fd23	arabic ligature dad with alef maksura final form
+fd24	arabic ligature dad with yeh final form
+fd25	arabic ligature sheen with jeem final form
+fd26	arabic ligature sheen with hah final form
+fd27	arabic ligature sheen with khah final form
+fd28	arabic ligature sheen with meem final form
+fd29	arabic ligature sheen with reh final form
+fd2a	arabic ligature seen with reh final form
+fd2b	arabic ligature sad with reh final form
+fd2c	arabic ligature dad with reh final form
+fd2d	arabic ligature sheen with jeem initial form
+fd2e	arabic ligature sheen with hah initial form
+fd2f	arabic ligature sheen with khah initial form
+fd30	arabic ligature sheen with meem initial form
+fd31	arabic ligature seen with heh initial form
+fd32	arabic ligature sheen with heh initial form
+fd33	arabic ligature tah with meem initial form
+fd34	arabic ligature seen with jeem medial form
+fd35	arabic ligature seen with hah medial form
+fd36	arabic ligature seen with khah medial form
+fd37	arabic ligature sheen with jeem medial form
+fd38	arabic ligature sheen with hah medial form
+fd39	arabic ligature sheen with khah medial form
+fd3a	arabic ligature tah with meem medial form
+fd3b	arabic ligature zah with meem medial form
+fd3c	arabic ligature alef with fathatan final form
+fd3d	arabic ligature alef with fathatan isolated form
+fd3e	ornate left parenthesis
+fd3f	ornate right parenthesis
+fd50	arabic ligature teh with jeem with meem initial form
+fd51	arabic ligature teh with hah with jeem final form
+fd52	arabic ligature teh with hah with jeem initial form
+fd53	arabic ligature teh with hah with meem initial form
+fd54	arabic ligature teh with khah with meem initial form
+fd55	arabic ligature teh with meem with jeem initial form
+fd56	arabic ligature teh with meem with hah initial form
+fd57	arabic ligature teh with meem with khah initial form
+fd58	arabic ligature jeem with meem with hah final form
+fd59	arabic ligature jeem with meem with hah initial form
+fd5a	arabic ligature hah with meem with yeh final form
+fd5b	arabic ligature hah with meem with alef maksura final form
+fd5c	arabic ligature seen with hah with jeem initial form
+fd5d	arabic ligature seen with jeem with hah initial form
+fd5e	arabic ligature seen with jeem with alef maksura final form
+fd5f	arabic ligature seen with meem with hah final form
+fd60	arabic ligature seen with meem with hah initial form
+fd61	arabic ligature seen with meem with jeem initial form
+fd62	arabic ligature seen with meem with meem final form
+fd63	arabic ligature seen with meem with meem initial form
+fd64	arabic ligature sad with hah with hah final form
+fd65	arabic ligature sad with hah with hah initial form
+fd66	arabic ligature sad with meem with meem final form
+fd67	arabic ligature sheen with hah with meem final form
+fd68	arabic ligature sheen with hah with meem initial form
+fd69	arabic ligature sheen with jeem with yeh final form
+fd6a	arabic ligature sheen with meem with khah final form
+fd6b	arabic ligature sheen with meem with khah initial form
+fd6c	arabic ligature sheen with meem with meem final form
+fd6d	arabic ligature sheen with meem with meem initial form
+fd6e	arabic ligature dad with hah with alef maksura final form
+fd6f	arabic ligature dad with khah with meem final form
+fd70	arabic ligature dad with khah with meem initial form
+fd71	arabic ligature tah with meem with hah final form
+fd72	arabic ligature tah with meem with hah initial form
+fd73	arabic ligature tah with meem with meem initial form
+fd74	arabic ligature tah with meem with yeh final form
+fd75	arabic ligature ain with jeem with meem final form
+fd76	arabic ligature ain with meem with meem final form
+fd77	arabic ligature ain with meem with meem initial form
+fd78	arabic ligature ain with meem with alef maksura final form
+fd79	arabic ligature ghain with meem with meem final form
+fd7a	arabic ligature ghain with meem with yeh final form
+fd7b	arabic ligature ghain with meem with alef maksura final form
+fd7c	arabic ligature feh with khah with meem final form
+fd7d	arabic ligature feh with khah with meem initial form
+fd7e	arabic ligature qaf with meem with hah final form
+fd7f	arabic ligature qaf with meem with meem final form
+fd80	arabic ligature lam with hah with meem final form
+fd81	arabic ligature lam with hah with yeh final form
+fd82	arabic ligature lam with hah with alef maksura final form
+fd83	arabic ligature lam with jeem with jeem initial form
+fd84	arabic ligature lam with jeem with jeem final form
+fd85	arabic ligature lam with khah with meem final form
+fd86	arabic ligature lam with khah with meem initial form
+fd87	arabic ligature lam with meem with hah final form
+fd88	arabic ligature lam with meem with hah initial form
+fd89	arabic ligature meem with hah with jeem initial form
+fd8a	arabic ligature meem with hah with meem initial form
+fd8b	arabic ligature meem with hah with yeh final form
+fd8c	arabic ligature meem with jeem with hah initial form
+fd8d	arabic ligature meem with jeem with meem initial form
+fd8e	arabic ligature meem with khah with jeem initial form
+fd8f	arabic ligature meem with khah with meem initial form
+fd92	arabic ligature meem with jeem with khah initial form
+fd93	arabic ligature heh with meem with jeem initial form
+fd94	arabic ligature heh with meem with meem initial form
+fd95	arabic ligature noon with hah with meem initial form
+fd96	arabic ligature noon with hah with alef maksura final form
+fd97	arabic ligature noon with jeem with meem final form
+fd98	arabic ligature noon with jeem with meem initial form
+fd99	arabic ligature noon with jeem with alef maksura final form
+fd9a	arabic ligature noon with meem with yeh final form
+fd9b	arabic ligature noon with meem with alef maksura final form
+fd9c	arabic ligature yeh with meem with meem final form
+fd9d	arabic ligature yeh with meem with meem initial form
+fd9e	arabic ligature beh with khah with yeh final form
+fd9f	arabic ligature teh with jeem with yeh final form
+fda0	arabic ligature teh with jeem with alef maksura final form
+fda1	arabic ligature teh with khah with yeh final form
+fda2	arabic ligature teh with khah with alef maksura final form
+fda3	arabic ligature teh with meem with yeh final form
+fda4	arabic ligature teh with meem with alef maksura final form
+fda5	arabic ligature jeem with meem with yeh final form
+fda6	arabic ligature jeem with hah with alef maksura final form
+fda7	arabic ligature jeem with meem with alef maksura final form
+fda8	arabic ligature seen with khah with alef maksura final form
+fda9	arabic ligature sad with hah with yeh final form
+fdaa	arabic ligature sheen with hah with yeh final form
+fdab	arabic ligature dad with hah with yeh final form
+fdac	arabic ligature lam with jeem with yeh final form
+fdad	arabic ligature lam with meem with yeh final form
+fdae	arabic ligature yeh with hah with yeh final form
+fdaf	arabic ligature yeh with jeem with yeh final form
+fdb0	arabic ligature yeh with meem with yeh final form
+fdb1	arabic ligature meem with meem with yeh final form
+fdb2	arabic ligature qaf with meem with yeh final form
+fdb3	arabic ligature noon with hah with yeh final form
+fdb4	arabic ligature qaf with meem with hah initial form
+fdb5	arabic ligature lam with hah with meem initial form
+fdb6	arabic ligature ain with meem with yeh final form
+fdb7	arabic ligature kaf with meem with yeh final form
+fdb8	arabic ligature noon with jeem with hah initial form
+fdb9	arabic ligature meem with khah with yeh final form
+fdba	arabic ligature lam with jeem with meem initial form
+fdbb	arabic ligature kaf with meem with meem final form
+fdbc	arabic ligature lam with jeem with meem final form
+fdbd	arabic ligature noon with jeem with hah final form
+fdbe	arabic ligature jeem with hah with yeh final form
+fdbf	arabic ligature hah with jeem with yeh final form
+fdc0	arabic ligature meem with jeem with yeh final form
+fdc1	arabic ligature feh with meem with yeh final form
+fdc2	arabic ligature beh with hah with yeh final form
+fdc3	arabic ligature kaf with meem with meem initial form
+fdc4	arabic ligature ain with jeem with meem initial form
+fdc5	arabic ligature sad with meem with meem initial form
+fdc6	arabic ligature seen with khah with yeh final form
+fdc7	arabic ligature noon with jeem with yeh final form
+fdf0	arabic ligature salla used as koranic stop sign isolated form
+fdf1	arabic ligature qala used as koranic stop sign isolated form
+fdf2	arabic ligature allah isolated form
+fdf3	arabic ligature akbar isolated form
+fdf4	arabic ligature mohammad isolated form
+fdf5	arabic ligature salam isolated form
+fdf6	arabic ligature rasoul isolated form
+fdf7	arabic ligature alayhe isolated form
+fdf8	arabic ligature wasallam isolated form
+fdf9	arabic ligature salla isolated form
+fdfa	arabic ligature sallallahou alayhe wasallam
+fdfb	arabic ligature jallajalalouhou
+fe20	combining ligature left half
+fe21	combining ligature right half
+fe22	combining double tilde left half
+fe23	combining double tilde right half
+fe30	presentation form for vertical two dot leader
+fe31	presentation form for vertical em dash
+fe32	presentation form for vertical en dash
+fe33	presentation form for vertical low line
+fe34	presentation form for vertical wavy low line
+fe35	presentation form for vertical left parenthesis
+fe36	presentation form for vertical right parenthesis
+fe37	presentation form for vertical left curly bracket
+fe38	presentation form for vertical right curly bracket
+fe39	presentation form for vertical left tortoise shell bracket
+fe3a	presentation form for vertical right tortoise shell bracket
+fe3b	presentation form for vertical left black lenticular bracket
+fe3c	presentation form for vertical right black lenticular bracket
+fe3d	presentation form for vertical left double angle bracket
+fe3e	presentation form for vertical right double angle bracket
+fe3f	presentation form for vertical left angle bracket
+fe40	presentation form for vertical right angle bracket
+fe41	presentation form for vertical left corner bracket
+fe42	presentation form for vertical right corner bracket
+fe43	presentation form for vertical left white corner bracket
+fe44	presentation form for vertical right white corner bracket
+fe49	dashed overline
+fe4a	centreline overline
+fe4b	wavy overline
+fe4c	double wavy overline
+fe4d	dashed low line
+fe4e	centreline low line
+fe4f	wavy low line
+fe50	small comma
+fe51	small ideographic comma
+fe52	small full stop
+fe54	small semicolon
+fe55	small colon
+fe56	small question mark
+fe57	small exclamation mark
+fe58	small em dash
+fe59	small left parenthesis
+fe5a	small right parenthesis
+fe5b	small left curly bracket
+fe5c	small right curly bracket
+fe5d	small left tortoise shell bracket
+fe5e	small right tortoise shell bracket
+fe5f	small number sign
+fe60	small ampersand
+fe61	small asterisk
+fe62	small plus sign
+fe63	small hyphen-minus
+fe64	small less-than sign
+fe65	small greater-than sign
+fe66	small equals sign
+fe68	small reverse solidus
+fe69	small dollar sign
+fe6a	small percent sign
+fe6b	small commercial at
+fe70	arabic fathatan isolated form
+fe71	arabic tatweel with fathatan above
+fe72	arabic dammatan isolated form
+fe74	arabic kasratan isolated form
+fe76	arabic fatha isolated form
+fe77	arabic fatha medial form
+fe78	arabic damma isolated form
+fe79	arabic damma medial form
+fe7a	arabic kasra isolated form
+fe7b	arabic kasra medial form
+fe7c	arabic shadda isolated form
+fe7d	arabic shadda medial form
+fe7e	arabic sukun isolated form
+fe7f	arabic sukun medial form
+fe80	arabic letter hamza isolated form
+fe81	arabic letter alef with madda above isolated form
+fe82	arabic letter alef with madda above final form
+fe83	arabic letter alef with hamza above isolated form
+fe84	arabic letter alef with hamza above final form
+fe85	arabic letter waw with hamza above isolated form
+fe86	arabic letter waw with hamza above final form
+fe87	arabic letter alef with hamza below isolated form
+fe88	arabic letter alef with hamza below final form
+fe89	arabic letter yeh with hamza above isolated form
+fe8a	arabic letter yeh with hamza above final form
+fe8b	arabic letter yeh with hamza above initial form
+fe8c	arabic letter yeh with hamza above medial form
+fe8d	arabic letter alef isolated form
+fe8e	arabic letter alef final form
+fe8f	arabic letter beh isolated form
+fe90	arabic letter beh final form
+fe91	arabic letter beh initial form
+fe92	arabic letter beh medial form
+fe93	arabic letter teh marbuta isolated form
+fe94	arabic letter teh marbuta final form
+fe95	arabic letter teh isolated form
+fe96	arabic letter teh final form
+fe97	arabic letter teh initial form
+fe98	arabic letter teh medial form
+fe99	arabic letter theh isolated form
+fe9a	arabic letter theh final form
+fe9b	arabic letter theh initial form
+fe9c	arabic letter theh medial form
+fe9d	arabic letter jeem isolated form
+fe9e	arabic letter jeem final form
+fe9f	arabic letter jeem initial form
+fea0	arabic letter jeem medial form
+fea1	arabic letter hah isolated form
+fea2	arabic letter hah final form
+fea3	arabic letter hah initial form
+fea4	arabic letter hah medial form
+fea5	arabic letter khah isolated form
+fea6	arabic letter khah final form
+fea7	arabic letter khah initial form
+fea8	arabic letter khah medial form
+fea9	arabic letter dal isolated form
+feaa	arabic letter dal final form
+feab	arabic letter thal isolated form
+feac	arabic letter thal final form
+fead	arabic letter reh isolated form
+feae	arabic letter reh final form
+feaf	arabic letter zain isolated form
+feb0	arabic letter zain final form
+feb1	arabic letter seen isolated form
+feb2	arabic letter seen final form
+feb3	arabic letter seen initial form
+feb4	arabic letter seen medial form
+feb5	arabic letter sheen isolated form
+feb6	arabic letter sheen final form
+feb7	arabic letter sheen initial form
+feb8	arabic letter sheen medial form
+feb9	arabic letter sad isolated form
+feba	arabic letter sad final form
+febb	arabic letter sad initial form
+febc	arabic letter sad medial form
+febd	arabic letter dad isolated form
+febe	arabic letter dad final form
+febf	arabic letter dad initial form
+fec0	arabic letter dad medial form
+fec1	arabic letter tah isolated form
+fec2	arabic letter tah final form
+fec3	arabic letter tah initial form
+fec4	arabic letter tah medial form
+fec5	arabic letter zah isolated form
+fec6	arabic letter zah final form
+fec7	arabic letter zah initial form
+fec8	arabic letter zah medial form
+fec9	arabic letter ain isolated form
+feca	arabic letter ain final form
+fecb	arabic letter ain initial form
+fecc	arabic letter ain medial form
+fecd	arabic letter ghain isolated form
+fece	arabic letter ghain final form
+fecf	arabic letter ghain initial form
+fed0	arabic letter ghain medial form
+fed1	arabic letter feh isolated form
+fed2	arabic letter feh final form
+fed3	arabic letter feh initial form
+fed4	arabic letter feh medial form
+fed5	arabic letter qaf isolated form
+fed6	arabic letter qaf final form
+fed7	arabic letter qaf initial form
+fed8	arabic letter qaf medial form
+fed9	arabic letter kaf isolated form
+feda	arabic letter kaf final form
+fedb	arabic letter kaf initial form
+fedc	arabic letter kaf medial form
+fedd	arabic letter lam isolated form
+fede	arabic letter lam final form
+fedf	arabic letter lam initial form
+fee0	arabic letter lam medial form
+fee1	arabic letter meem isolated form
+fee2	arabic letter meem final form
+fee3	arabic letter meem initial form
+fee4	arabic letter meem medial form
+fee5	arabic letter noon isolated form
+fee6	arabic letter noon final form
+fee7	arabic letter noon initial form
+fee8	arabic letter noon medial form
+fee9	arabic letter heh isolated form
+feea	arabic letter heh final form
+feeb	arabic letter heh initial form
+feec	arabic letter heh medial form
+feed	arabic letter waw isolated form
+feee	arabic letter waw final form
+feef	arabic letter alef maksura isolated form
+fef0	arabic letter alef maksura final form
+fef1	arabic letter yeh isolated form
+fef2	arabic letter yeh final form
+fef3	arabic letter yeh initial form
+fef4	arabic letter yeh medial form
+fef5	arabic ligature lam with alef with madda above isolated form
+fef6	arabic ligature lam with alef with madda above final form
+fef7	arabic ligature lam with alef with hamza above isolated form
+fef8	arabic ligature lam with alef with hamza above final form
+fef9	arabic ligature lam with alef with hamza below isolated form
+fefa	arabic ligature lam with alef with hamza below final form
+fefb	arabic ligature lam with alef isolated form
+fefc	arabic ligature lam with alef final form
+feff	zero width no-break space
+ff01	fullwidth exclamation mark
+ff02	fullwidth quotation mark
+ff03	fullwidth number sign
+ff04	fullwidth dollar sign
+ff05	fullwidth percent sign
+ff06	fullwidth ampersand
+ff07	fullwidth apostrophe
+ff08	fullwidth left parenthesis
+ff09	fullwidth right parenthesis
+ff0a	fullwidth asterisk
+ff0b	fullwidth plus sign
+ff0c	fullwidth comma
+ff0d	fullwidth hyphen-minus
+ff0e	fullwidth full stop
+ff0f	fullwidth solidus
+ff10	fullwidth digit zero
+ff11	fullwidth digit one
+ff12	fullwidth digit two
+ff13	fullwidth digit three
+ff14	fullwidth digit four
+ff15	fullwidth digit five
+ff16	fullwidth digit six
+ff17	fullwidth digit seven
+ff18	fullwidth digit eight
+ff19	fullwidth digit nine
+ff1a	fullwidth colon
+ff1b	fullwidth semicolon
+ff1c	fullwidth less-than sign
+ff1d	fullwidth equals sign
+ff1e	fullwidth greater-than sign
+ff1f	fullwidth question mark
+ff20	fullwidth commercial at
+ff21	fullwidth latin capital letter a
+ff22	fullwidth latin capital letter b
+ff23	fullwidth latin capital letter c
+ff24	fullwidth latin capital letter d
+ff25	fullwidth latin capital letter e
+ff26	fullwidth latin capital letter f
+ff27	fullwidth latin capital letter g
+ff28	fullwidth latin capital letter h
+ff29	fullwidth latin capital letter i
+ff2a	fullwidth latin capital letter j
+ff2b	fullwidth latin capital letter k
+ff2c	fullwidth latin capital letter l
+ff2d	fullwidth latin capital letter m
+ff2e	fullwidth latin capital letter n
+ff2f	fullwidth latin capital letter o
+ff30	fullwidth latin capital letter p
+ff31	fullwidth latin capital letter q
+ff32	fullwidth latin capital letter r
+ff33	fullwidth latin capital letter s
+ff34	fullwidth latin capital letter t
+ff35	fullwidth latin capital letter u
+ff36	fullwidth latin capital letter v
+ff37	fullwidth latin capital letter w
+ff38	fullwidth latin capital letter x
+ff39	fullwidth latin capital letter y
+ff3a	fullwidth latin capital letter z
+ff3b	fullwidth left square bracket
+ff3c	fullwidth reverse solidus
+ff3d	fullwidth right square bracket
+ff3e	fullwidth circumflex accent
+ff3f	fullwidth low line
+ff40	fullwidth grave accent
+ff41	fullwidth latin small letter a;ff21
+ff42	fullwidth latin small letter b;ff22
+ff43	fullwidth latin small letter c;ff23
+ff44	fullwidth latin small letter d;ff24
+ff45	fullwidth latin small letter e;ff25
+ff46	fullwidth latin small letter f;ff26
+ff47	fullwidth latin small letter g;ff27
+ff48	fullwidth latin small letter h;ff28
+ff49	fullwidth latin small letter i;ff29
+ff4a	fullwidth latin small letter j;ff2a
+ff4b	fullwidth latin small letter k;ff2b
+ff4c	fullwidth latin small letter l;ff2c
+ff4d	fullwidth latin small letter m;ff2d
+ff4e	fullwidth latin small letter n;ff2e
+ff4f	fullwidth latin small letter o;ff2f
+ff50	fullwidth latin small letter p;ff30
+ff51	fullwidth latin small letter q;ff31
+ff52	fullwidth latin small letter r;ff32
+ff53	fullwidth latin small letter s;ff33
+ff54	fullwidth latin small letter t;ff34
+ff55	fullwidth latin small letter u;ff35
+ff56	fullwidth latin small letter v;ff36
+ff57	fullwidth latin small letter w;ff37
+ff58	fullwidth latin small letter x;ff38
+ff59	fullwidth latin small letter y;ff39
+ff5a	fullwidth latin small letter z;ff3a
+ff5b	fullwidth left curly bracket
+ff5c	fullwidth vertical line
+ff5d	fullwidth right curly bracket
+ff5e	fullwidth tilde
+ff61	halfwidth ideographic full stop
+ff62	halfwidth left corner bracket
+ff63	halfwidth right corner bracket
+ff64	halfwidth ideographic comma
+ff65	halfwidth katakana middle dot
+ff66	halfwidth katakana letter wo
+ff67	halfwidth katakana letter small a
+ff68	halfwidth katakana letter small i
+ff69	halfwidth katakana letter small u
+ff6a	halfwidth katakana letter small e
+ff6b	halfwidth katakana letter small o
+ff6c	halfwidth katakana letter small ya
+ff6d	halfwidth katakana letter small yu
+ff6e	halfwidth katakana letter small yo
+ff6f	halfwidth katakana letter small tu
+ff70	halfwidth katakana-hiragana prolonged sound mark
+ff71	halfwidth katakana letter a
+ff72	halfwidth katakana letter i
+ff73	halfwidth katakana letter u
+ff74	halfwidth katakana letter e
+ff75	halfwidth katakana letter o
+ff76	halfwidth katakana letter ka
+ff77	halfwidth katakana letter ki
+ff78	halfwidth katakana letter ku
+ff79	halfwidth katakana letter ke
+ff7a	halfwidth katakana letter ko
+ff7b	halfwidth katakana letter sa
+ff7c	halfwidth katakana letter si
+ff7d	halfwidth katakana letter su
+ff7e	halfwidth katakana letter se
+ff7f	halfwidth katakana letter so
+ff80	halfwidth katakana letter ta
+ff81	halfwidth katakana letter ti
+ff82	halfwidth katakana letter tu
+ff83	halfwidth katakana letter te
+ff84	halfwidth katakana letter to
+ff85	halfwidth katakana letter na
+ff86	halfwidth katakana letter ni
+ff87	halfwidth katakana letter nu
+ff88	halfwidth katakana letter ne
+ff89	halfwidth katakana letter no
+ff8a	halfwidth katakana letter ha
+ff8b	halfwidth katakana letter hi
+ff8c	halfwidth katakana letter hu
+ff8d	halfwidth katakana letter he
+ff8e	halfwidth katakana letter ho
+ff8f	halfwidth katakana letter ma
+ff90	halfwidth katakana letter mi
+ff91	halfwidth katakana letter mu
+ff92	halfwidth katakana letter me
+ff93	halfwidth katakana letter mo
+ff94	halfwidth katakana letter ya
+ff95	halfwidth katakana letter yu
+ff96	halfwidth katakana letter yo
+ff97	halfwidth katakana letter ra
+ff98	halfwidth katakana letter ri
+ff99	halfwidth katakana letter ru
+ff9a	halfwidth katakana letter re
+ff9b	halfwidth katakana letter ro
+ff9c	halfwidth katakana letter wa
+ff9d	halfwidth katakana letter n
+ff9e	halfwidth katakana voiced sound mark
+ff9f	halfwidth katakana semi-voiced sound mark
+ffa0	halfwidth hangul filler
+ffa1	halfwidth hangul letter kiyeok
+ffa2	halfwidth hangul letter ssangkiyeok
+ffa3	halfwidth hangul letter kiyeok-sios
+ffa4	halfwidth hangul letter nieun
+ffa5	halfwidth hangul letter nieun-cieuc
+ffa6	halfwidth hangul letter nieun-hieuh
+ffa7	halfwidth hangul letter tikeut
+ffa8	halfwidth hangul letter ssangtikeut
+ffa9	halfwidth hangul letter rieul
+ffaa	halfwidth hangul letter rieul-kiyeok
+ffab	halfwidth hangul letter rieul-mieum
+ffac	halfwidth hangul letter rieul-pieup
+ffad	halfwidth hangul letter rieul-sios
+ffae	halfwidth hangul letter rieul-thieuth
+ffaf	halfwidth hangul letter rieul-phieuph
+ffb0	halfwidth hangul letter rieul-hieuh
+ffb1	halfwidth hangul letter mieum
+ffb2	halfwidth hangul letter pieup
+ffb3	halfwidth hangul letter ssangpieup
+ffb4	halfwidth hangul letter pieup-sios
+ffb5	halfwidth hangul letter sios
+ffb6	halfwidth hangul letter ssangsios
+ffb7	halfwidth hangul letter ieung
+ffb8	halfwidth hangul letter cieuc
+ffb9	halfwidth hangul letter ssangcieuc
+ffba	halfwidth hangul letter chieuch
+ffbb	halfwidth hangul letter khieukh
+ffbc	halfwidth hangul letter thieuth
+ffbd	halfwidth hangul letter phieuph
+ffbe	halfwidth hangul letter hieuh
+ffc2	halfwidth hangul letter a
+ffc3	halfwidth hangul letter ae
+ffc4	halfwidth hangul letter ya
+ffc5	halfwidth hangul letter yae
+ffc6	halfwidth hangul letter eo
+ffc7	halfwidth hangul letter e
+ffca	halfwidth hangul letter yeo
+ffcb	halfwidth hangul letter ye
+ffcc	halfwidth hangul letter o
+ffcd	halfwidth hangul letter wa
+ffce	halfwidth hangul letter wae
+ffcf	halfwidth hangul letter oe
+ffd2	halfwidth hangul letter yo
+ffd3	halfwidth hangul letter u
+ffd4	halfwidth hangul letter weo
+ffd5	halfwidth hangul letter we
+ffd6	halfwidth hangul letter wi
+ffd7	halfwidth hangul letter yu
+ffda	halfwidth hangul letter eu
+ffdb	halfwidth hangul letter yi
+ffdc	halfwidth hangul letter i
+ffe0	fullwidth cent sign
+ffe1	fullwidth pound sign
+ffe2	fullwidth not sign
+ffe3	fullwidth macron
+ffe4	fullwidth broken bar
+ffe5	fullwidth yen sign
+ffe6	fullwidth won sign
+ffe8	halfwidth forms light vertical
+ffe9	halfwidth leftwards arrow
+ffea	halfwidth upwards arrow
+ffeb	halfwidth rightwards arrow
+ffec	halfwidth downwards arrow
+ffed	halfwidth black square
+ffee	halfwidth white circle
+fffd	replacement character
--- /dev/null
+++ b/lib/unidata/blocks.txt
@@ -1,0 +1,172 @@
+# Blocks-4.1.0.txt
+# Date: 2005-1-31, 16:50 [KW]
+#
+# Unicode Character Database
+# Copyright (c) 1991-2005 Unicode, Inc.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+# For documentation, see UCD.html
+#
+# Note:   The casing of block names is not normative.
+#         For example, "Basic Latin" and "BASIC LATIN" are equivalent.
+#
+# Format:
+# Start Code..End Code; Block Name
+
+# ================================================
+
+# Note:   When comparing block names, casing, whitespace, hyphens,
+#         and underbars are ignored.
+#         For example, "Latin Extended-A" and "latin extended a" are equivalent.
+#         For more information on the comparison of property values, 
+#            see UCD.html.
+#
+#  All code points not explicitly listed for Block
+#  have the value No_Block.
+
+# Property:	Block
+
+0000..007F; Basic Latin
+0080..00FF; Latin-1 Supplement
+0100..017F; Latin Extended-A
+0180..024F; Latin Extended-B
+0250..02AF; IPA Extensions
+02B0..02FF; Spacing Modifier Letters
+0300..036F; Combining Diacritical Marks
+0370..03FF; Greek and Coptic
+0400..04FF; Cyrillic
+0500..052F; Cyrillic Supplement
+0530..058F; Armenian
+0590..05FF; Hebrew
+0600..06FF; Arabic
+0700..074F; Syriac
+0750..077F; Arabic Supplement
+0780..07BF; Thaana
+0900..097F; Devanagari
+0980..09FF; Bengali
+0A00..0A7F; Gurmukhi
+0A80..0AFF; Gujarati
+0B00..0B7F; Oriya
+0B80..0BFF; Tamil
+0C00..0C7F; Telugu
+0C80..0CFF; Kannada
+0D00..0D7F; Malayalam
+0D80..0DFF; Sinhala
+0E00..0E7F; Thai
+0E80..0EFF; Lao
+0F00..0FFF; Tibetan
+1000..109F; Myanmar
+10A0..10FF; Georgian
+1100..11FF; Hangul Jamo
+1200..137F; Ethiopic
+1380..139F; Ethiopic Supplement
+13A0..13FF; Cherokee
+1400..167F; Unified Canadian Aboriginal Syllabics
+1680..169F; Ogham
+16A0..16FF; Runic
+1700..171F; Tagalog
+1720..173F; Hanunoo
+1740..175F; Buhid
+1760..177F; Tagbanwa
+1780..17FF; Khmer
+1800..18AF; Mongolian
+1900..194F; Limbu
+1950..197F; Tai Le
+1980..19DF; New Tai Lue
+19E0..19FF; Khmer Symbols
+1A00..1A1F; Buginese
+1D00..1D7F; Phonetic Extensions
+1D80..1DBF; Phonetic Extensions Supplement
+1DC0..1DFF; Combining Diacritical Marks Supplement
+1E00..1EFF; Latin Extended Additional
+1F00..1FFF; Greek Extended
+2000..206F; General Punctuation
+2070..209F; Superscripts and Subscripts
+20A0..20CF; Currency Symbols
+20D0..20FF; Combining Diacritical Marks for Symbols
+2100..214F; Letterlike Symbols
+2150..218F; Number Forms
+2190..21FF; Arrows
+2200..22FF; Mathematical Operators
+2300..23FF; Miscellaneous Technical
+2400..243F; Control Pictures
+2440..245F; Optical Character Recognition
+2460..24FF; Enclosed Alphanumerics
+2500..257F; Box Drawing
+2580..259F; Block Elements
+25A0..25FF; Geometric Shapes
+2600..26FF; Miscellaneous Symbols
+2700..27BF; Dingbats
+27C0..27EF; Miscellaneous Mathematical Symbols-A
+27F0..27FF; Supplemental Arrows-A
+2800..28FF; Braille Patterns
+2900..297F; Supplemental Arrows-B
+2980..29FF; Miscellaneous Mathematical Symbols-B
+2A00..2AFF; Supplemental Mathematical Operators
+2B00..2BFF; Miscellaneous Symbols and Arrows
+2C00..2C5F; Glagolitic
+2C80..2CFF; Coptic
+2D00..2D2F; Georgian Supplement
+2D30..2D7F; Tifinagh
+2D80..2DDF; Ethiopic Extended
+2E00..2E7F; Supplemental Punctuation
+2E80..2EFF; CJK Radicals Supplement
+2F00..2FDF; Kangxi Radicals
+2FF0..2FFF; Ideographic Description Characters
+3000..303F; CJK Symbols and Punctuation
+3040..309F; Hiragana
+30A0..30FF; Katakana
+3100..312F; Bopomofo
+3130..318F; Hangul Compatibility Jamo
+3190..319F; Kanbun
+31A0..31BF; Bopomofo Extended
+31C0..31EF; CJK Strokes
+31F0..31FF; Katakana Phonetic Extensions
+3200..32FF; Enclosed CJK Letters and Months
+3300..33FF; CJK Compatibility
+3400..4DBF; CJK Unified Ideographs Extension A
+4DC0..4DFF; Yijing Hexagram Symbols
+4E00..9FFF; CJK Unified Ideographs
+A000..A48F; Yi Syllables
+A490..A4CF; Yi Radicals
+A700..A71F; Modifier Tone Letters
+A800..A82F; Syloti Nagri
+AC00..D7AF; Hangul Syllables
+D800..DB7F; High Surrogates
+DB80..DBFF; High Private Use Surrogates
+DC00..DFFF; Low Surrogates
+E000..F8FF; Private Use Area
+F900..FAFF; CJK Compatibility Ideographs
+FB00..FB4F; Alphabetic Presentation Forms
+FB50..FDFF; Arabic Presentation Forms-A
+FE00..FE0F; Variation Selectors
+FE10..FE1F; Vertical Forms
+FE20..FE2F; Combining Half Marks
+FE30..FE4F; CJK Compatibility Forms
+FE50..FE6F; Small Form Variants
+FE70..FEFF; Arabic Presentation Forms-B
+FF00..FFEF; Halfwidth and Fullwidth Forms
+FFF0..FFFF; Specials
+10000..1007F; Linear B Syllabary
+10080..100FF; Linear B Ideograms
+10100..1013F; Aegean Numbers
+10140..1018F; Ancient Greek Numbers
+10300..1032F; Old Italic
+10330..1034F; Gothic
+10380..1039F; Ugaritic
+103A0..103DF; Old Persian
+10400..1044F; Deseret
+10450..1047F; Shavian
+10480..104AF; Osmanya
+10800..1083F; Cypriot Syllabary
+10A00..10A5F; Kharoshthi
+1D000..1D0FF; Byzantine Musical Symbols
+1D100..1D1FF; Musical Symbols
+1D200..1D24F; Ancient Greek Musical Notation
+1D300..1D35F; Tai Xuan Jing Symbols
+1D400..1D7FF; Mathematical Alphanumeric Symbols
+20000..2A6DF; CJK Unified Ideographs Extension B
+2F800..2FA1F; CJK Compatibility Ideographs Supplement
+E0000..E007F; Tags
+E0100..E01EF; Variation Selectors Supplement
+F0000..FFFFF; Supplementary Private Use Area-A
+100000..10FFFF; Supplementary Private Use Area-B
--- /dev/null
+++ b/lib/unidata/index2.txt
@@ -1,0 +1,4307 @@
+8859-1 (Latin-1), Based on ISO	00A0
+8859-2, -3, -4, -9 (European Latin), Based on ISO	0100
+8859-5 (Cyrillic), Based on ISO	0400
+8859-6 (Arabic), Based on ISO	0600
+8859-7 (Greek), Based on ISO	0370
+8859-8 (Hebrew), Based on ISO	05D0
+A, COMBINING LATIN SMALL LETTER	0363
+a, latin small letter script	0251
+A, LATIN SMALL LETTER TURNED	0250
+ABBREVIATION MARK, ARMENIAN	055F
+ABBREVIATION MARK, SYRIAC	070F
+ABBREVIATION SIGN, DEVANAGARI	0970
+Abbreviations, Squared Latin	3371
+Aboriginal Syllabics, Unified Canadian	1400
+above, cedilla	0312
+ABOVE, COMBINING ALMOST EQUAL TO	034C
+ABOVE, COMBINING BRIDGE	0346
+ABOVE, COMBINING CLOCKWISE ARROW	20D5
+ABOVE, COMBINING COMMA	0313
+ABOVE, COMBINING DOT	0307
+ABOVE, COMBINING DOUBLE VERTICAL LINE	030E
+ABOVE, COMBINING FOUR DOTS	20DC
+ABOVE, COMBINING HOMOTHETIC	034B
+ABOVE, COMBINING HOOK	0309
+ABOVE, COMBINING LEFT ANGLE	031A
+ABOVE, COMBINING LEFT ARROW	20D6
+ABOVE, COMBINING LEFT HARPOON	20D0
+ABOVE, COMBINING LEFT RIGHT ARROW	20E1
+ABOVE, COMBINING NOT TILDE	034A
+ABOVE, COMBINING REVERSED COMMA	0314
+ABOVE, COMBINING RING	030A
+ABOVE, COMBINING THREE DOTS	20DB
+ABOVE, COMBINING TURNED COMMA	0312
+ABOVE, COMBINING VERTICAL LINE	030D
+ABOVE, COMBINING WIDE BRIDGE	20E9
+ABOVE, COMBINING X	033D
+ABOVE, DOT	02D9
+above, double dot	0308
+ABOVE, RING	02DA
+above, vee	030C
+ABOVE RIGHT, COMBINING COMMA	0315
+absolute continuity	2AA1
+ACCENT, ACUTE	00B4
+ACCENT, ALMOST EQUAL TO WITH CIRCUMFLEX	2A6F
+ACCENT, CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX	2A36
+ACCENT, CIRCUMFLEX	005E
+ACCENT, COMBINING ACUTE	0301
+ACCENT, COMBINING CIRCUMFLEX	0302
+ACCENT, COMBINING DOUBLE ACUTE	030B
+ACCENT, COMBINING DOUBLE GRAVE	030F
+ACCENT, COMBINING GRAVE	0300
+ACCENT, DOUBLE ACUTE	02DD
+ACCENT, GRAVE	0060
+ACCENT, MODIFIER LETTER ACUTE	02CA
+ACCENT, MODIFIER LETTER CIRCUMFLEX	02C6
+ACCENT, MODIFIER LETTER CROSS	02DF
+ACCENT, MODIFIER LETTER GRAVE	02CB
+ACCENT, MODIFIER LETTER LOW ACUTE	02CF
+ACCENT, MODIFIER LETTER LOW GRAVE	02CE
+accent, swedish grave	02DF
+ACCENT ABOVE, PLUS SIGN WITH CIRCUMFLEX	2A23
+ACCENT BELOW, COMBINING ACUTE	0317
+ACCENT BELOW, COMBINING CIRCUMFLEX	032D
+ACCENT BELOW, COMBINING GRAVE	0316
+ACCOUNT OF	2100
+acknowledge	0006
+acknowledge, graphic for negative	237B
+acknowledge, negative	0015
+ACKNOWLEDGE, SYMBOL FOR	2406
+ACKNOWLEDGE, SYMBOL FOR NEGATIVE	2415
+ACTIVATE ARABIC FORM SHAPING	206D
+ACTIVATE SYMMETRIC SWAPPING	206B
+actuarial bend	20E7
+acute, spacing	00B4
+ACUTE ACCENT	00B4
+ACUTE ACCENT, COMBINING	0301
+ACUTE ACCENT, COMBINING DOUBLE	030B
+ACUTE ACCENT, DEVANAGARI	0954
+ACUTE ACCENT, DOUBLE	02DD
+ACUTE ACCENT, MODIFIER LETTER	02CA
+ACUTE ACCENT, MODIFIER LETTER LOW	02CF
+ACUTE ACCENT BELOW, COMBINING	0317
+ACUTE ANGLE	299F
+ACUTE TONE MARK, COMBINING	0341
+ADDRESSED TO THE SUBJECT	2101
+Addu dialect, consonant for	0780
+AE, LATIN SMALL LETTER	00E6
+Aegean Numbers	10100
+AEGEAN CHECK MARK	10102
+AEGEAN WORD SEPARATOR DOT	10101
+AEGEAN WORD SEPARATOR LINE	10100
+Ainu, Phonetic Extensions For	31F0
+AIRPLANE	2708
+aldus leaf	2766
+ALEF SYMBOL	2135
+ALL, FOR	2200
+ALL AROUND-PROFILE	232E
+ALL EQUAL TO	224C
+ALMOST EQUAL TO	2248
+ALMOST EQUAL TO, PRECEDES ABOVE	2AB7
+ALMOST EQUAL TO, PRECEDES ABOVE NOT	2AB9
+ALMOST EQUAL TO, SUBSET OF ABOVE	2AC9
+ALMOST EQUAL TO, SUCCEEDS ABOVE	2AB8
+ALMOST EQUAL TO, SUCCEEDS ABOVE NOT	2ABA
+ALMOST EQUAL TO, SUPERSET OF ABOVE	2ACA
+ALMOST EQUAL TO ABOVE, COMBINING	034C
+ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT	2A6F
+ALPHA, LATIN SMALL LETTER	0251
+ALPHA, LATIN SMALL LETTER TURNED	0252
+Alphabetic Presentation Forms	FB00
+Alphanumerics, Enclosed	2460
+alternating current	223F
+ALTERNATION MARK, PART	303D
+ALTERNATIVE KEY SYMBOL	2387
+ALVEOLAR CLICK, LATIN LETTER	01C2
+always (modal operator)	25FB
+always (modal operator), was	27E4
+always be (modal operator), will	27E5
+AMALGAMATION OR COPRODUCT	2A3F
+AMPERSAND	0026
+AMPERSAND, TURNED	214B
+AND, CURLY LOGICAL	22CF
+AND, LOGICAL	2227
+AND, N-ARY LOGICAL	22C0
+andrew's, cross st.	2613
+Ands and Ors, Logical	2A51
+ANGLE	2220
+ANGLE, ACUTE	299F
+ANGLE, MEASURED	2221
+ANGLE, RIGHT	221F
+ANGLE, SPHERICAL	2222
+ANGLE, TURNED	29A2
+ANGLE ABOVE, COMBINING LEFT	031A
+angle arc	2222
+ANGLE BELOW, COMBINING LEFT	0349
+ANGLE BRACKET, LEFT	3008
+ANGLE BRACKET, LEFT DOUBLE	300A
+ANGLE BRACKET, LEFT-POINTING	2329
+ANGLE BRACKET, MATHEMATICAL LEFT	27E8
+ANGLE BRACKET, MATHEMATICAL LEFT DOUBLE	27EA
+ANGLE BRACKET, RIGHT-POINTING	232A
+ANGLE OPENING LEFT, SPHERICAL	29A0
+ANGLE OPENING UP, SPHERICAL	29A1
+ANGLE QUOTATION MARK, LEFT-POINTING DOUBLE	00AB
+ANGLE QUOTATION MARK, RIGHT-POINTING DOUBLE	00BB
+ANGLE QUOTATION MARK, SINGLE LEFT-POINTING	2039
+ANGLE QUOTATION MARK, SINGLE RIGHT-POINTING	203A
+Angle Quotation Marks, Ornamental	276E
+ANGLE WITH ARC, RIGHT	22BE
+ANGLE WITH DOWNWARDS ZIGZAG ARROW, RIGHT	237C
+angled dash	00AC
+Angles and Measured Angles	299B
+ANGSTROM SIGN	212B
+ANKH	2625
+Annotation, Interlinear	FFF9
+Annotation, Kanbun Ideographic	3190
+Annotation Signs, Koranic	06D6
+ANNUITY SYMBOL, COMBINING	20E7
+ano teleia	00B7
+ANTICLOCKWISE INTEGRATION	2A11
+ANTICLOCKWISE-ROTATED DIVISION SIGN, CIRCLED	29BC
+ANTIRESTRICTION, Z NOTATION DOMAIN	2A64
+ANTIRESTRICTION, Z NOTATION RANGE	2A65
+APL	2336
+APL Functional Symbols	2336
+apl jot	2218
+apl overbar	00AF
+apl quote	0022
+apl stile	2223
+apl tilde	223C
+apl upstile	2308
+APOSTROPHE	0027
+apostrophe	02BC
+apostrophe	2019
+APOSTROPHE, ARMENIAN	055A
+APOSTROPHE, MODIFIER LETTER	02BC
+APOSTROPHE, MODIFIER LETTER DOUBLE	02EE
+apostrophe-quote	0027
+APPLICATION, FUNCTION	2061
+application program command	009F
+APPROACHES THE LIMIT	2250
+APPROXIMATE, GREATER-THAN AND NOT	2A8A
+APPROXIMATE, GREATER-THAN OR	2A86
+APPROXIMATE, LESS-THAN AND NOT	2A89
+APPROXIMATE, LESS-THAN OR	2A85
+APPROXIMATELY EQUAL OR EQUAL TO	2A70
+APPROXIMATELY EQUAL TO	2245
+approximately equal to	2257
+AQUARIUS	2652
+Arabic	0600
+Arabic, Extended	0671
+ARABIC COMMA	060C
+ARABIC DECIMAL SEPARATOR	066B
+ARABIC END OF AYAH	06DD
+ARABIC FIVE POINTED STAR	066D
+ARABIC FOOTNOTE MARKER	0602
+ARABIC FORM SHAPING, ACTIVATE	206D
+ARABIC FORM SHAPING, INHIBIT	206C
+ARABIC FULL STOP	06D4
+Arabic Honorifics	0610
+ARABIC LETTER DOTLESS BEH	066E
+ARABIC LETTER DOTLESS QAF	066F
+Arabic Letters	0627
+ARABIC NUMBER SIGN	0600
+ARABIC PERCENT SIGN	066A
+Arabic Points	064B
+Arabic Presentation Forms-A	FB50
+Arabic Presentation Forms-B	FE70
+ARABIC QUESTION MARK	061F
+ARABIC SEMICOLON	061B
+ARABIC SIGN SAFHA	0603
+ARABIC SIGN SANAH	0601
+Arabic Poetic Marks	0610
+Arabic Subtending Marks	0600
+ARABIC TAIL FRAGMENT	FE73
+ARABIC THOUSANDS SEPARATOR	066C
+Arabic-Indic Digits	0660
+Arabic-Indic Digits for Persian and Urdu, Eastern	06F0
+ARC	2312
+arc, angle	2222
+ARC, RIGHT ANGLE WITH	22BE
+ARCH BELOW, COMBINING INVERTED DOUBLE	032B
+Arcs	25DC
+area, end of guarded	0097
+area, end of selected	0087
+area, start of guarded	0096
+area, start of selected	0086
+ARIES	2648
+Armenian	0530
+ARMENIAN ABBREVIATION MARK	055F
+ARMENIAN APOSTROPHE	055A
+Armenian Capital Letters	0531
+ARMENIAN COMMA	055D
+ARMENIAN EMPHASIS MARK	055B
+ARMENIAN EXCLAMATION MARK	055C
+ARMENIAN FULL STOP	0589
+ARMENIAN HYPHEN	058A
+Armenian Ligatures	FB13
+ARMENIAN QUESTION MARK	055E
+Armenian Small Letters	0561
+ARROW, BLACK CIRCLE WITH DOWN	29ED
+ARROW, BLACK DIAMOND WITH DOWN	29EA
+arrow, colon right	29F4
+ARROW, ELECTRIC	2301
+ARROW, RIGHT ANGLE WITH DOWNWARDS ZIGZAG	237C
+ARROW, WHITE CIRCLE WITH DOWN	29EC
+ARROW ABOVE, COMBINING CLOCKWISE	20D5
+ARROW ABOVE, COMBINING LEFT	20D6
+ARROW ABOVE, COMBINING LEFT RIGHT	20E1
+ARROW BELOW, COMBINING DOUBLE RIGHTWARDS	0362
+ARROW BELOW, COMBINING LEFT RIGHT	034D
+ARROW BELOW, COMBINING UPWARDS	034E
+Arrow Dingbats	2794
+ARROW OVERLAY, COMBINING LEFTWARDS	20EA
+ARROW THROUGH CIRCLE, UP	29BD
+ARROW WITH HOOK, INTEGRAL WITH LEFTWARDS	2A17
+ARROWHEAD, UP	2303
+Arrowheads, Modifier Letter	02C2
+Arrows	2190
+Arrows, Long	27F5
+Arrows, Other White and Black	2B00
+arrows extension	23AF
+Arrows-A, Supplemental	27F0
+Arrows-B, Supplemental	2900
+ASCENDING NODE	260A
+ASCII	0020
+ASCII C0 Control Codes	0000
+ASCII Digits	0030
+ASCII Variants, Fullwidth	FF01
+ash	00E6
+ASSERTION	22A6
+ASTERISK	002A
+ASTERISK, EQUALS WITH	2A6E
+ASTERISK, LOW	204E
+ASTERISK, SQUARED	29C6
+Asterisk Dingbats	2722
+ASTERISK OPERATOR	2217
+ASTERISK OPERATOR, CIRCLED	229B
+ASTERISKS ALIGNED VERTICALLY, TWO	2051
+Asterisks and Snowflakes, Stars, 	2721
+ASTERISM	2042
+Astrological Symbols	263D
+asymptotic to	2248
+ASYMPTOTICALLY EQUAL TO	2243
+AT, COMMERCIAL	0040
+AVERAGE WITH SLASH, INTEGRAL	2A0F
+AYAH, ARABIC END OF	06DD
+B, LATIN LETTER SMALL CAPITAL	0299
+B, SCRIPT CAPITAL	212C
+baby gamma, latin small letter	0264
+backslash	005C
+BACKSLASH, COMBINING ENCLOSING CIRCLE	20E0
+backspace	0008
+BACKSPACE, SYMBOL FOR	2408
+backward difference	2207
+bag bracket, z notation left	27E6
+BAG MEMBERSHIP, Z NOTATION	22FF
+bag subtraction, z notation	2A41
+BAHT, THAI CURRENCY SYMBOL	0E3F
+BALLOT BOX	2610
+BALLOT BOX WITH CHECK	2611
+BALLOT BOX WITH X	2612
+BALLOT X	2717
+BALLOT X, HEAVY	2718
+bang	0021
+bar, broken vertical	00A6
+BAR, CIRCLED VERTICAL	29B6
+BAR, HORIZONTAL	2015
+BAR, N-ARY WHITE VERTICAL	2AFF
+bar, vertical	007C
+BAR, WHITE VERTICAL	2AFE
+BAR BINARY RELATION, TRIPLE VERTICAL	2AF4
+BAR DELIMITER, TRIPLE VERTICAL	2980
+Bar Dingbats, Vertical	2758
+BAR OPERATOR, LARGE TRIPLE VERTICAL	2AFC
+Bar Symbols, Error	29EE
+BAR WITH DOUBLE VERTICAL STROKE, TRIPLE HORIZONTAL	2A68
+BAR WITH HORIZONTAL STROKE, TRIPLE VERTICAL	2AF5
+BAR WITH TRIPLE VERTICAL STROKE, TRIPLE HORIZONTAL	2A69
+barred o, latin capital letter	019F
+BARRED O, LATIN SMALL LETTER	0275
+Basic Latin, C0 Controls and	0000
+Basic Russian Alphabet	0410
+BEAMED EIGHTH NOTES	266B
+BEAMED SIXTEENTH NOTES	266C
+BECAUSE	2235
+beginning of line	2310
+bell	0007
+BELL, SYMBOL FOR	2407
+BELL SYMBOL	237E
+BELOW, COMBINING ACUTE ACCENT	0317
+BELOW, COMBINING BREVE	032E
+BELOW, COMBINING BRIDGE	032A
+BELOW, COMBINING CARON	032C
+BELOW, COMBINING CIRCUMFLEX ACCENT	032D
+BELOW, COMBINING COMMA	0326
+BELOW, COMBINING DIAERESIS	0324
+BELOW, COMBINING DOT	0323
+BELOW, COMBINING DOUBLE RIGHTWARDS ARROW	0362
+BELOW, COMBINING DOUBLE VERTICAL LINE	0348
+BELOW, COMBINING EQUALS SIGN	0347
+BELOW, COMBINING GRAVE ACCENT	0316
+BELOW, COMBINING INVERTED BREVE	032F
+BELOW, COMBINING INVERTED BRIDGE	033A
+BELOW, COMBINING INVERTED DOUBLE ARCH	032B
+BELOW, COMBINING LEFT ANGLE	0349
+BELOW, COMBINING LEFT HALF RING	031C
+BELOW, COMBINING LEFT RIGHT ARROW	034D
+BELOW, COMBINING LEFT TACK	0318
+BELOW, COMBINING MACRON	0331
+BELOW, COMBINING MINUS SIGN	0320
+BELOW, COMBINING PALATALIZED HOOK	0321
+BELOW, COMBINING PLUS SIGN	031F
+BELOW, COMBINING RETROFLEX HOOK	0322
+BELOW, COMBINING RIGHT HALF RING	0339
+BELOW, COMBINING RING	0325
+BELOW, COMBINING SEAGULL	033C
+BELOW, COMBINING SQUARE	033B
+BELOW, COMBINING TILDE	0330
+BELOW, COMBINING UP TACK	031D
+BELOW, COMBINING UPWARDS ARROW	034E
+BELOW, COMBINING VERTICAL LINE	0329
+below, greek non-spacing iota	0345
+bend, actuarial	20E7
+Bengali	0980
+Bengali Currency Signs	09F2
+Bengali Digits	09E6
+Bengali Letters	0985
+BENGALI RUPEE MARK	09F2
+BENGALI RUPEE SIGN	09F3
+BENZENE RING	232C
+bernoulli function	212C
+BET SYMBOL	2136
+Betty BOOP	263A
+BETWEEN	226C
+BEVERAGE, HOT	2615
+BIDENTAL PERCUSSIVE, LATIN LETTER	02AD
+Bidirectional Formatting Controls	202A
+Big 5, Duplicates from	FA0C
+BIG REVERSE SOLIDUS	29F9
+BIG SOLIDUS	29F8
+bijection, z notation	2917
+bijective mapping	2916
+BILABIAL CLICK, LATIN LETTER	0298
+BILABIAL PERCUSSIVE, LATIN LETTER	02AC
+BINARY RELATION, TRIPLE SOLIDUS	2AFB
+BINARY RELATION, TRIPLE VERTICAL BAR	2AF4
+BIOHAZARD SIGN	2623
+BLACK, BOWTIE WITH LEFT HALF	29D1
+BLACK, BOWTIE WITH RIGHT HALF	29D2
+BLACK, DOWN-POINTING TRIANGLE WITH LEFT HALF	29E8
+BLACK, DOWN-POINTING TRIANGLE WITH RIGHT HALF	29E9
+BLACK, TIMES WITH LEFT HALF	29D4
+BLACK, TIMES WITH RIGHT HALF	29D5
+BLACK BOWTIE	29D3
+BLACK CIRCLE WITH DOWN ARROW	29ED
+BLACK CIRCLE WITH TWO WHITE DOTS	2689
+BLACK CIRCLE WITH WHITE DOT RIGHT	2688
+Black Circled Numbers, White On	24EB
+BLACK DIAMOND WITH DOWN ARROW	29EA
+BLACK FLAG	2691
+BLACK HOURGLASS	29D7
+BLACK LEFT POINTING INDEX	261A
+BLACK LEFTWARDS BULLET	204C
+BLACK LENTICULAR BRACKET, LEFT	3010
+BLACK LOZENGE	29EB
+BLACK MEDIUM SMALL SQUARE	25FE
+BLACK MEDIUM SQUARE	25FC
+BLACK NIB	2712
+BLACK PARALLELOGRAM	25B0
+BLACK SCISSORS	2702
+BLACK SHOGI PIECE	2617
+black small circle	2022
+BLACK SMILING FACE	263B
+BLACK STAR	2605
+BLACK SUN WITH RAYS	2600
+BLACK TELEPHONE	260E
+BLACK TRIANGLE, PLUS SIGN WITH	2A28
+BLACK UNIVERSAL RECYCLING SYMBOL	267B
+BLACK-LETTER CAPITAL C	212D
+BLACK-LETTER CAPITAL H	210C
+BLACK-LETTER CAPITAL I	2111
+BLACK-LETTER CAPITAL R	211C
+BLACK-LETTER CAPITAL Z	2128
+BLANK SYMBOL	2422
+block, end of transmission	0017
+BLOCK, SYMBOL FOR END OF TRANSMISSION	2417
+Block Elements	2580
+bom	FEFF
+Bopomofo, Chinese	3100
+Bopomofo Extended for Minnan and Hakka, Chinese	31A0
+BOWTIE	22C8
+bowtie, large	2A1D
+Bowtie Symbols	29D1
+BOX, BALLOT	2610
+BOX, OPEN	2423
+BOX, SHOULDERED OPEN	237D
+BOX, X IN A RECTANGLE	2327
+Box Drawing	2500
+BOX LINE, LEFT VERTICAL	23B8
+BOX LINE, RIGHT VERTICAL	23B9
+BOX OPERATOR, SQUARE LEFT OPEN	2ACD
+BOX OPERATOR, SQUARE RIGHT OPEN	2ACE
+BOX WITH CHECK, BALLOT	2611
+BOX WITH X, BALLOT	2612
+bra	27E6
+brace, closing	007D
+brace, opening	007B
+bracket, z notation left bag	27E6
+bracket, closing curly	007D
+bracket, closing square	005D
+BRACKET, LEFT ANGLE	3008
+BRACKET, LEFT BLACK LENTICULAR	3010
+BRACKET, LEFT CORNER	300C
+BRACKET, LEFT CURLY	007B
+BRACKET, LEFT DOUBLE ANGLE	300A
+BRACKET, LEFT SQUARE	005B
+BRACKET, LEFT TORTOISE SHELL	3014
+BRACKET, LEFT WHITE CORNER	300E
+BRACKET, LEFT WHITE LENTICULAR	3016
+BRACKET, LEFT WHITE SQUARE	301A
+BRACKET, LEFT WHITE TORTOISE SHELL	3018
+BRACKET, LEFT-POINTING ANGLE	2329
+bracket, opening curly	007B
+bracket, opening square	005B
+BRACKET, RIGHT CURLY	007D
+BRACKET, RIGHT SQUARE	005D
+Bracket Pieces	239B
+Bracket Pieces	23B0
+BRACKET WITH QUILL, LEFT SQUARE	2045
+Brackets	2983
+Brackets, CJK Angle	3008
+Brackets, Corner	2308
+Brackets, CJK Corner	300C
+Brackets, CJK	3010
+Brackets, CJK	3014
+Brackets, Fullwidth	FF5F
+Brackets, Mathematical	27E6
+Brackets, Ornamental	2768
+Brackets, Ornamental	2770
+Brackets, Vertical	23B4
+Braille Patterns	2800
+brazilian currency	20A2
+break here, no	0083
+break permitted here	0082
+breathing, rough	0314
+breathing, smooth	0313
+BREVE	02D8
+BREVE, COMBINING	0306
+BREVE, COMBINING DOUBLE INVERTED	0361
+BREVE, COMBINING INVERTED	0311
+BREVE BELOW, COMBINING	032E
+BREVE BELOW, COMBINING INVERTED	032F
+BRIDGE ABOVE, COMBINING	0346
+BRIDGE ABOVE, COMBINING WIDE	20E9
+BRIDGE BELOW, COMBINING	032A
+BRIDGE BELOW, COMBINING INVERTED	033A
+broken vertical bar	00A6
+Buhid	1740
+BULLET	2022
+BULLET, BLACK LEFTWARDS	204C
+BULLET, HYPHEN	2043
+BULLET, REVERSED ROTATED FLORAL HEART	2619
+bullet, tainome (japanese, a kind of)	25C9
+BULLET, TRIANGULAR	2023
+BULLET, WHITE	25E6
+BULLET OPERATOR	2219
+BULLSEYE	25CE
+bullseye, latin letter	0298
+BUMPY ABOVE, EQUALS SIGN WITH	2AAE
+BY, MEASURED	225E
+by definition, equal to	225C
+BY DEFINITION, EQUAL TO	225D
+byte order mark	FEFF
+C, BLACK-LETTER CAPITAL	212D
+C, COMBINING LATIN SMALL LETTER	0368
+C, DOUBLE-STRUCK CAPITAL	2102
+C, LATIN LETTER STRETCHED	0297
+C0 Controls and Basic Latin	0000
+C1 Controls and Latin-1 Supplement	0080
+CADA UNA	2106
+CADUCEUS	2624
+Canadian Aboriginal Syllabics, Unified	1400
+cancel	0018
+CANCEL, SYMBOL FOR	2418
+cancel character	0094
+CANCER	264B
+CANDRABINDU, COMBINING	0310
+Cantillation Marks, Hebrew	0591
+cap	2229
+CAP, SQUARE	2293
+Capital Letters, Armenian	0531
+Capital Letters, Cyrillic	0401
+Capital Letters, Georgian	10A0
+Capital Letters, Greek	0391
+Capital Letters, Latin	0041
+CAPRICORN	2651
+caps lock	21EA
+caps lock	21EC
+Card Suits, Playing	2660
+cardinal (countable), first transfinite	2135
+cardinal (functions of a real variable), third transfinite	2137
+cardinal (the continuum), second transfinite	2136
+CARE OF	2105
+caret	028C
+CARET	2038
+CARET INSERTION POINT	2041
+CARON	02C7
+CARON, COMBINING	030C
+CARON BELOW, COMBINING	032C
+carriage return	000D
+carriage return	21B5
+CARRIAGE RETURN, SYMBOL FOR	240D
+CAUTION SIGN	2621
+CEDILLA	00B8
+CEDILLA, COMBINING	0327
+cedilla, spacing	00B8
+cedilla above	0312
+CEILING, LEFT	2308
+CELSIUS, DEGREE	2103
+CENT SIGN	00A2
+centigrade, degrees	2103
+CENTRE LINE SYMBOL	2104
+CENTRED LEFT HALF RING, MODIFIER LETTER	02D3
+CENTRELINE LOW LINE	FE4E
+CENTRELINE OVERLINE	FE4A
+cgj	034F
+character introducer, single	009A
+character tabulation set	0088
+character tabulation with justification	0089
+CHARACTER TIE	2040
+Chart Components, Form and	2500
+CHECK, BALLOT BOX WITH	2611
+CHECK MARK	2713
+CHECK MARK, AEGEAN	10102
+CHECK MARK, HEAVY	2714
+CHECK MARK, NOT	237B
+Cherokee	13A0
+Chess Pieces	2654
+Chess Symbols, Japanese	2616
+chevrons	00AB
+CHI RHO	2627
+Chinese Bopomofo	3100
+Chinese Bopomofo Extended for Minnan and Hakka	31A0
+choice, dijkstra	2AFE
+choice, n-ary dijkstra	2AFF
+CIRCLE, BLACK	25CF
+circle, black small	2022
+CIRCLE, COMBINING ENCLOSING	20DD
+CIRCLE, DOTTED	25CC
+circle, jis composition	20DD
+CIRCLE, LARGE	25EF
+CIRCLE, MULTIPLICATION SIGN IN DOUBLE	2A37
+CIRCLE, MULTIPLICATION SIGN IN LEFT HALF	2A34
+CIRCLE, MULTIPLICATION SIGN IN RIGHT HALF	2A35
+CIRCLE, PLUS SIGN IN LEFT HALF	2A2D
+CIRCLE, PLUS SIGN IN RIGHT HALF	2A2E
+CIRCLE, SQUARED SMALL	29C7
+CIRCLE ABOVE, PLUS SIGN WITH SMALL	2A22
+CIRCLE ABOVE, UP TACK WITH	27DF
+CIRCLE ABOVE, VERTICAL LINE WITH	2AEF
+CIRCLE BACKSLASH, COMBINING ENCLOSING	20E0
+CIRCLE BELOW, DOWN TACK WITH	2AF1
+CIRCLE BELOW, VERTICAL LINE WITH	2AF0
+CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR	29BA
+CIRCLE INSIDE, GREATER-THAN WITH	2A7A
+CIRCLE INSIDE, LESS-THAN WITH	2A79
+Circle Symbols	29B5
+CIRCLE WITH DOT RIGHT, WHITE	2686
+CIRCLE WITH DOWN ARROW, BLACK	29ED
+CIRCLE WITH DOWN ARROW, WHITE	29EC
+CIRCLE WITH TWO DOTS, WHITE	2687
+CIRCLE WITH TWO WHITE DOTS, BLACK	2689
+CIRCLE WITH WHITE DOT RIGHT, BLACK	2688
+CIRCLED ASTERISK OPERATOR	229B
+CIRCLED DASH	229D
+CIRCLED DIGIT ZERO	24EA
+Circled Digits, Dingbat	2776
+CIRCLED DIVISION SIGN	2A38
+CIRCLED DIVISION SLASH	2298
+CIRCLED DOT OPERATOR	2299
+CIRCLED DOT OPERATOR, N-ARY	2A00
+CIRCLED EQUALS	229C
+Circled Ideographs	3280
+Circled Inverse Numbers	2776
+Circled Japanese Katakana	32D0
+Circled Korean Hangul Elements	3260
+Circled Korean Hangul Syllables	326E
+Circled Latin Letters	24B6
+CIRCLED MINUS	2296
+CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT	2A36
+Circled Numbers	2460
+Circled Numbers	3251
+Circled Numbers	32B1
+Circled Numbers, Double	24F5
+Circled Numbers, White On Black	24EB
+CIRCLED PLUS	2295
+CIRCLED PLUS OPERATOR, N-ARY	2A01
+CIRCLED POSTAL MARK	3036
+CIRCLED RING OPERATOR	229A
+CIRCLED TIMES	2297
+CIRCLED TIMES OPERATOR, N-ARY	2A02
+Circles	25CB
+CIRCULATION FUNCTION	2A10
+circumflex, spacing	005E
+CIRCUMFLEX ACCENT	005E
+CIRCUMFLEX ACCENT, ALMOST EQUAL TO WITH	2A6F
+CIRCUMFLEX ACCENT, CIRCLED MULTIPLICATION SIGN WITH	2A36
+CIRCUMFLEX ACCENT, COMBINING	0302
+CIRCUMFLEX ACCENT, MODIFIER LETTER	02C6
+CIRCUMFLEX ACCENT ABOVE, PLUS SIGN WITH	2A23
+CIRCUMFLEX ACCENT BELOW, COMBINING	032D
+CJK Compatibility	3300
+CJK Compatibility Forms	FE30
+CJK Compatibility Ideographs	F900
+CJK Compatibility Ideographs, IBM	FA0E
+CJK Ideographs Area	3400
+CJK Letters and Ideographs, Enclosed	3200
+CJK Phonetics and Symbols Area	2E00
+CJK Radicals Supplement	2E80
+CJK Symbols and Punctuation	3000
+CJK Unified Ideographs	4E00
+CJK Unified Ideographs Extension A	3400
+clear key	2327
+CLEAR SCREEN SYMBOL	239A
+clear weather	2600
+CLICK, LATIN LETTER ALVEOLAR	01C2
+CLICK, LATIN LETTER BILABIAL	0298
+CLICK, LATIN LETTER DENTAL	01C0
+CLICK, LATIN LETTER LATERAL	01C1
+CLICK, LATIN LETTER RETROFLEX	01C3
+CLOCKWISE ARROW ABOVE, COMBINING	20D5
+CLOCKWISE CONTOUR INTEGRAL	2232
+CLOCKWISE INTEGRAL	2231
+CLOCKWISE RING OVERLAY, COMBINING	20D9
+clone	2104
+Clones of Diacritics, Spacing	02D8
+CLOSE UP	2050
+closed epsilon, latin small letter	029A
+CLOSED INTERSECTION WITH SERIFS	2A4D
+CLOSED OMEGA, LATIN SMALL LETTER	0277
+CLOSED OPEN E, LATIN SMALL LETTER	029A
+closed reversed epsilon, latin small letter	025E
+CLOSED REVERSED OPEN E, LATIN SMALL LETTER	025E
+CLOSED SUBSET	2ACF
+CLOSED SUBSET OR EQUAL TO	2AD1
+CLOSED SUPERSET	2AD0
+CLOSED SUPERSET OR EQUAL TO	2AD2
+CLOSED UNION WITH SERIFS	2A4C
+CLOSED UNION WITH SERIFS AND SMASH PRODUCT	2A50
+closing brace	007D
+closing curly bracket	007D
+CLOSING MARK, IDEOGRAPHIC	3006
+closing parenthesis	0029
+closing square bracket	005D
+CLOUD	2601
+cloudy weather	2601
+Codes, Process Internal	FDD0
+coffee	2615
+COLON	003A
+COLON, ETHIOPIC	1365
+COLON, MODIFIER LETTER HALF TRIANGULAR	02D1
+COLON, MODIFIER LETTER TRIANGULAR	02D0
+COLON, MONGOLIAN	1804
+COLON, Z NOTATION TYPE	2982
+COLON EQUAL, DOUBLE	2A74
+COLON EQUALS	2254
+COLON OPERATOR, TRIPLE	2AF6
+colon right arrow	29F4
+COLON SIGN	20A1
+COMBINING ACUTE ACCENT	0301
+COMBINING ACUTE ACCENT BELOW	0317
+COMBINING ACUTE TONE MARK	0341
+COMBINING ALMOST EQUAL TO ABOVE	034C
+Combining Alphabet, Korean Hangul Jamo	1100
+COMBINING ANNUITY SYMBOL	20E7
+COMBINING BREVE	0306
+COMBINING BREVE BELOW	032E
+COMBINING BRIDGE ABOVE	0346
+COMBINING BRIDGE BELOW	032A
+COMBINING CANDRABINDU	0310
+COMBINING CARON	030C
+COMBINING CARON BELOW	032C
+COMBINING CEDILLA	0327
+Combining Characters, Cyrillic	0483
+COMBINING CIRCUMFLEX ACCENT	0302
+COMBINING CIRCUMFLEX ACCENT BELOW	032D
+COMBINING CLOCKWISE ARROW ABOVE	20D5
+COMBINING CLOCKWISE RING OVERLAY	20D9
+COMBINING COMMA ABOVE	0313
+COMBINING COMMA ABOVE RIGHT	0315
+COMBINING COMMA BELOW	0326
+Combining Diacritical Marks	0300
+Combining Diacritical Marks for Symbols	20D0
+COMBINING DIAERESIS	0308
+COMBINING DIAERESIS BELOW	0324
+COMBINING DOT ABOVE	0307
+COMBINING DOT BELOW	0323
+COMBINING DOUBLE ACUTE ACCENT	030B
+COMBINING DOUBLE GRAVE ACCENT	030F
+COMBINING DOUBLE INVERTED BREVE	0361
+COMBINING DOUBLE LOW LINE	0333
+COMBINING DOUBLE OVERLINE	033F
+COMBINING DOUBLE RIGHTWARDS ARROW BELOW	0362
+COMBINING DOUBLE TILDE	0360
+COMBINING DOUBLE TILDE LEFT HALF	FE22
+COMBINING DOUBLE VERTICAL LINE ABOVE	030E
+COMBINING DOUBLE VERTICAL LINE BELOW	0348
+COMBINING DOUBLE VERTICAL STROKE OVERLAY	20E6
+COMBINING DOWN TACK BELOW	031E
+COMBINING ENCLOSING CIRCLE	20DD
+COMBINING ENCLOSING CIRCLE BACKSLASH	20E0
+COMBINING ENCLOSING DIAMOND	20DF
+COMBINING ENCLOSING KEYCAP	20E3
+COMBINING ENCLOSING SCREEN	20E2
+COMBINING ENCLOSING SQUARE	20DE
+COMBINING ENCLOSING UPWARD POINTING TRIANGLE	20E4
+COMBINING EQUALS SIGN BELOW	0347
+COMBINING FOUR DOTS ABOVE	20DC
+COMBINING GRAPHEME JOINER	034F
+COMBINING GRAVE ACCENT	0300
+COMBINING GRAVE ACCENT BELOW	0316
+COMBINING GRAVE TONE MARK	0340
+COMBINING GREEK DIALYTIKA TONOS	0344
+COMBINING GREEK KORONIS	0343
+COMBINING GREEK PERISPOMENI	0342
+COMBINING GREEK YPOGEGRAMMENI	0345
+combining hacek	030C
+Combining Half Marks	FE20
+COMBINING HOMOTHETIC ABOVE	034B
+COMBINING HOOK ABOVE	0309
+COMBINING HORN	031B
+COMBINING INVERTED BREVE	0311
+COMBINING INVERTED BREVE BELOW	032F
+COMBINING INVERTED BRIDGE BELOW	033A
+COMBINING INVERTED DOUBLE ARCH BELOW	032B
+COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK	3099
+Combining Latin Small Letters	0363
+COMBINING LEFT ANGLE ABOVE	031A
+COMBINING LEFT ANGLE BELOW	0349
+COMBINING LEFT ARROW ABOVE	20D6
+COMBINING LEFT HALF RING BELOW	031C
+COMBINING LEFT HARPOON ABOVE	20D0
+COMBINING LEFT RIGHT ARROW ABOVE	20E1
+COMBINING LEFT RIGHT ARROW BELOW	034D
+COMBINING LEFT TACK BELOW	0318
+COMBINING LEFTWARDS ARROW OVERLAY	20EA
+COMBINING LIGATURE LEFT HALF	FE20
+COMBINING LONG SOLIDUS OVERLAY	0338
+COMBINING LONG STROKE OVERLAY	0336
+COMBINING LONG VERTICAL LINE OVERLAY	20D2
+COMBINING LOW LINE	0332
+COMBINING MACRON	0304
+COMBINING MACRON BELOW	0331
+COMBINING MINUS SIGN BELOW	0320
+COMBINING NOT TILDE ABOVE	034A
+COMBINING OGONEK	0328
+COMBINING OVERLINE	0305
+COMBINING PALATALIZED HOOK BELOW	0321
+COMBINING PLUS SIGN BELOW	031F
+COMBINING RETROFLEX HOOK BELOW	0322
+COMBINING REVERSE SOLIDUS OVERLAY	20E5
+COMBINING REVERSED COMMA ABOVE	0314
+COMBINING RIGHT HALF RING BELOW	0339
+COMBINING RING ABOVE	030A
+COMBINING RING BELOW	0325
+COMBINING RING OVERLAY	20D8
+COMBINING SEAGULL BELOW	033C
+COMBINING SHORT SOLIDUS OVERLAY	0337
+COMBINING SHORT STROKE OVERLAY	0335
+COMBINING SHORT VERTICAL LINE OVERLAY	20D3
+COMBINING SQUARE BELOW	033B
+COMBINING THREE DOTS ABOVE	20DB
+COMBINING TILDE	0303
+COMBINING TILDE BELOW	0330
+COMBINING TILDE OVERLAY	0334
+COMBINING TRIPLE UNDERDOT	20E8
+COMBINING TURNED COMMA ABOVE	0312
+COMBINING UP TACK BELOW	031D
+COMBINING UPWARDS ARROW BELOW	034E
+COMBINING VERTICAL LINE ABOVE	030D
+COMBINING VERTICAL LINE BELOW	0329
+COMBINING VERTICAL TILDE	033E
+COMBINING WIDE BRIDGE ABOVE	20E9
+COMBINING X ABOVE	033D
+COMET	2604
+COMMA	002C
+COMMA, ARABIC	060C
+COMMA, ARMENIAN	055D
+COMMA, ETHIOPIC	1363
+comma, georgian	00B7
+COMMA, IDEOGRAPHIC	3001
+comma, invisible	2063
+COMMA, MODIFIER LETTER REVERSED	02BD
+COMMA, MODIFIER LETTER TURNED	02BB
+COMMA, MONGOLIAN	1802
+COMMA ABOVE, COMBINING	0313
+COMMA ABOVE, COMBINING REVERSED	0314
+COMMA ABOVE, COMBINING TURNED	0312
+COMMA ABOVE, MINUS SIGN WITH	2A29
+COMMA ABOVE RIGHT, COMBINING	0315
+COMMA BELOW, COMBINING	0326
+comma quotation mark, double	201D
+comma quotation mark, double reversed	201F
+comma quotation mark, double turned	201C
+comma quotation mark, low double	201E
+comma quotation mark, low single	201A
+comma quotation mark, single	2019
+comma quotation mark, single reversed	201B
+comma quotation mark, single turned	2018
+command, application program	009F
+command, operating system	009D
+command key	2318
+COMMERCIAL AT	0040
+COMMERCIAL MINUS SIGN	2052
+compass	263C
+Compatibility, CJK	3300
+Compatibility and Specials Area	F900
+Compatibility Forms, CJK	FE30
+Compatibility Ideographs, CJK	F900
+Compatibility Ideographs, IBM CJK	FA0E
+Compatibility Jamo, Korean Hangul	3130
+COMPLEMENT	2201
+complex numbers, the set of	2102
+component, radial	27DF
+Components, Form and Chart	2500
+composite function	2218
+COMPOSITION, Z NOTATION RELATIONAL	2A3E
+COMPOSITION, Z NOTATION SCHEMA	2A1F
+composition circle, jis	20DD
+COMPOSITION SYMBOL	2384
+concatenation, z notation sequence	2040
+CONCAVE-SIDED DIAMOND, WHITE	27E1
+CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK, WHITE	27E2
+CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK, WHITE	27E3
+conductance	2127
+CONGRUENT WITH DOT ABOVE	2A6D
+CONICAL TAPER	2332
+CONJUGATE MATRIX, HERMITIAN	22B9
+conjunction	2227
+CONJUNCTION	260C
+CONSECUTIVE EQUALS SIGNS, THREE	2A76
+CONSECUTIVE EQUALS SIGNS, TWO	2A75
+consonant for Addu dialect	0780
+CONTAINS AS MEMBER	220B
+CONTAINS AS MEMBER, SMALL	220D
+CONTAINS AS NORMAL SUBGROUP	22B3
+CONTAINS WITH LONG HORIZONTAL STROKE	22FA
+CONTAINS WITH OVERBAR	22FD
+CONTAINS WITH OVERBAR, SMALL	22FE
+CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE	22FB
+CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE, SMALL	22FC
+continuity, absolute	2AA1
+CONTINUOUS UNDERLINE SYMBOL	2381
+continuum, second transfinite cardinal	2136
+CONTOUR INTEGRAL	222E
+CONTOUR INTEGRAL, CLOCKWISE	2232
+CONTOURED OUTLINE, SQUARE WITH	29E0
+contraction operator	20E9
+control, graphic for	2388
+Control, Syriac Format	070F
+Control Code Graphics	25F0
+Control Codes, ASCII C0	0000
+Control Codes, C1	0080
+Control Codes, Graphic Pictures for	2400
+Control Codes, Graphics for	237B
+control sequence introducer	009B
+control string, device	0090
+Controls, Bidirectional Formatting	202A
+Controls, Mongolian Format	180B
+Controls and Basic Latin, C0	0000
+Controls and Latin-1 Supplement, C1	0080
+COPRODUCT, AMALGAMATION OR	2A3F
+COPRODUCT, N-ARY	2210
+Coptic, Greek and	0370
+Coptic-unique Letters	03E2
+COPYRIGHT, SOUND RECORDING	2117
+COPYRIGHT SIGN	00A9
+CORNER, TOP LEFT	231C
+CORNER BRACKET, LEFT	300C
+CORNER BRACKET, LEFT WHITE	300E
+Corner brackets	2308
+Corner brackets, CJK	300C
+CORNER WITH DOT, LOWER RIGHT	27D3
+CORNER WITH DOT, UPPER LEFT	27D4
+corners, Quine	231C
+CORPORATION, SQUARE	337F
+CORRESPONDS TO	2258
+corresponds to	2259
+costa rican currency	20A1
+countable, first transfinite cardinal	2135
+COUNTERBORE	2334
+COUNTERSINK	2335
+cr	000D
+CRESCENT, STAR AND	262A
+Croatian, Additions for Slovenian and	0200
+Croatian Digraphs Matching Serbian Cyrillic Letters	01C4
+CROP, TOP LEFT	230F
+CROSS, EAST SYRIAC	2671
+CROSS, LATIN	271D
+cross, long	2020
+CROSS, MALTESE	2720
+CROSS, ORTHODOX	2626
+cross, st. andrew's	2613
+CROSS, WEST SYRIAC	2670
+CROSS ACCENT, MODIFIER LETTER	02DF
+Cross Dingbats	2719
+CROSS OF JERUSALEM	2629
+CROSS OF LORRAINE	2628
+CROSS PRODUCT, VECTOR OR	2A2F
+cross ratio	211E
+CROSSBONES, SKULL AND	2620
+crosshatch	0023
+CRUZEIRO SIGN	20A2
+CUBE ROOT	221B
+cubed	00B3
+cup	222A
+CUP, SQUARE	2294
+curly bracket, closing	007D
+CURLY BRACKET, LEFT	007B
+curly bracket, opening	007B
+CURLY BRACKET, RIGHT	007D
+CURLY LOGICAL AND	22CF
+CURLY LOGICAL OR	22CE
+currency, brazilian	20A2
+currency, costa rican	20A1
+currency, el salvadorian	20A1
+currency, euro european	20AC
+currency, french	20A3
+currency, greek	20AF
+currency, hebrew	20AA
+currency, indian	20A8
+currency, iranian	FDFC
+currency, israeli	20AA
+currency, italian	20A4
+currency, korean	20A9
+currency, laotian	20AD
+currency, mongolian	20AE
+currency, nigerian	20A6
+currency, phillipine	20B1
+currency, spanish	20A7
+currency, turkish	20A4
+currency, vietnamese	20AB
+CURRENCY SIGN	00A4
+Currency Signs, Bengali	09F2
+currency symbol, florin	0192
+CURRENCY SYMBOL BAHT, THAI	0E3F
+Currency Symbols	20A0
+current, alternating	223F
+CURRENT SYMBOL FORM TWO, DIRECT	2393
+cycle	223C
+CYLINDRICITY	232D
+Cypriot Syllabary	10800
+Cyrillic	0400
+Cyrillic, Extended	048C
+Cyrillic Capital Letters	0401
+Cyrillic Combining Characters	0483
+Cyrillic Extensions	0450
+Cyrillic Historic Letters	0460
+Cyrillic Komi Letters	0500
+Cyrillic Small Letters	0430
+Cyrillic Supplementary	0500
+D, COMBINING LATIN SMALL LETTER	0369
+D, DOUBLE-STRUCK ITALIC CAPITAL	2145
+D, DOUBLE-STRUCK ITALIC SMALL	2146
+D, LATIN CAPITAL LETTER AFRICAN	0189
+d retroflex hook, latin small letter	0256
+D WITH TAIL, LATIN SMALL LETTER	0256
+DAGGER	2020
+DAGGER, DOUBLE	2021
+d'alembertian	29E0
+DALET SYMBOL	2138
+DANDA, DEVANAGARI	0964
+DANDA, DEVANAGARI DOUBLE	0965
+dash, angled	00AC
+DASH, CIRCLED	229D
+DASH, EM	2014
+DASH, EN	2013
+DASH, FIGURE	2012
+dash, long	2015
+dash, quotation	2015
+DASH, SWUNG	2053
+DASH, WAVE	301C
+DASH, WAVY	3030
+DASHED LOW LINE	FE4D
+DASHED OVERLINE	FE49
+Dashes	2010
+dasia	0314
+data link escape	0010
+DATA LINK ESCAPE, SYMBOL FOR	2410
+Database Theory Operators	27D5
+DAVID, STAR OF	2721
+Days, Telegraph Symbols for	33E0
+DAY SIGN, TAMIL	0BF3
+decimal point	002E
+decimal separator	002C
+DECIMAL SEPARATOR, ARABIC	066B
+DECIMAL SEPARATOR KEY SYMBOL	2396
+deergh viram	0965
+definition, equal to by	225C
+DEFINITION, EQUAL TO BY	225D
+DEGREE CELSIUS	2103
+DEGREE FAHRENHEIT	2109
+DEGREE SIGN	00B0
+degrees centigrade	2103
+degrees kelvin	212A
+del	2207
+delete	007F
+DELETE, SYMBOL FOR	2421
+delete, undoable	2425
+DELETE FORM TWO, SYMBOL FOR	2425
+delete to the left key	232B
+delete to the right key	2326
+DELIMITER, TRIPLE VERTICAL BAR	2980
+DELTA, LATIN SMALL LETTER TURNED	018D
+DELTA EQUAL TO	225C
+DENTAL CLICK, LATIN LETTER	01C0
+Dentistry Notation Symbols	23BE
+depth symbol	21A7
+derivative	0307
+derivative, double	0308
+derivative, fourth	20DC
+derivative, third	20DB
+DESCENDING NODE	260B
+Description Characters, Ideographic	2FF0
+Devanagari	0900
+DEVANAGARI DANDA	0964
+Devanagari Digits	0966
+DEVANAGARI DOUBLE DANDA	0965
+Devanagari Letters	0905
+DEVANAGARI OM	0950
+device control four	0014
+DEVICE CONTROL FOUR, SYMBOL FOR	2414
+device control one	0011
+DEVICE CONTROL ONE, SYMBOL FOR	2411
+device control string	0090
+device control three	0013
+DEVICE CONTROL THREE, SYMBOL FOR	2413
+device control two	0012
+DEVICE CONTROL TWO, SYMBOL FOR	2412
+DHARMA, WHEEL OF	2638
+Diacritic-vowel Combinations, Pinyin	01CD
+Diacritical Marks, Combining	0300
+Diacritical Marks for Symbols, Combining	20D0
+Diacritics, Double	0360
+Diacritics, Enclosing	20DD
+Diacritics, Medieval Superscript Letter	0363
+Diacritics, Overstruck	0334
+Diacritics, Spacing Clones of	02D8
+Diacritics for Greek	0342
+Diacritics for IPA	0346
+DIAERESIS	00A8
+DIAERESIS, COMBINING	0308
+diaeresis, greek capital letter upsilon hook	03D4
+diaeresis, spacing	00A8
+DIAERESIS AND HOOK SYMBOL, GREEK UPSILON WITH	03D4
+DIAERESIS BELOW, COMBINING	0324
+DIAGONAL ELLIPSIS, UP RIGHT	22F0
+DIAGONAL SLASH, SQUARED FALLING	29C5
+DIAGONAL SLASH, SQUARED RISING	29C4
+dialytika	0308
+DIALYTIKA TONOS, COMBINING GREEK	0344
+DIAMETER SIGN	2300
+diameter symbol	2205
+DIAMOND, COMBINING ENCLOSING	20DF
+DIAMOND, WHITE CONCAVE-SIDED	27E1
+DIAMOND OPERATOR	22C4
+DIAMOND WITH CENTRED DOT, WHITE	27D0
+DIAMOND WITH DOWN ARROW, BLACK	29EA
+DIAMOND WITH LEFTWARDS TICK, WHITE CONCAVE-SIDED	27E2
+DIAMOND WITH RIGHTWARDS TICK, WHITE CONCAVE-SIDED	27E3
+Diamonds	25C6
+Dice	2680
+diesis	2021
+difference, backward	2207
+difference, forward	2206
+difference, sum or positive 	2A26
+difference, symmetric	2238
+difference, symmetric	2296
+difference between	223C
+DIFFERENCE BETWEEN	224F
+difference or sum, positive	2A24
+DIFFERENTIAL, PARTIAL	2202
+DIGIT SHAPES, NATIONAL	206E
+DIGIT SHAPES, NOMINAL	206F
+Digits, Arabic-Indic	0660
+Digits, ASCII	0030
+Digits, Bengali	09E6
+Digits, Devanagari	0966
+Digits, Dingbat Circled	2776
+Digits, Ethiopic	1369
+Digits, Gujarati	0AE6
+Digits, Gurmukhi	0A66
+Digits, Kannada	0CE6
+Digits, Khmer	17E0
+Digits, Lao	0ED0
+Digits, Malayalam	0D66
+Digits, Mongolian	1810
+Digits, Myanmar	1040
+Digits, Oriya	0B66
+Digits, Osmanya	104A0
+Digits, Subscript	2080
+Digits, Superscript	2070
+Digits, Tamil	0BE7
+Digits, Telugu	0C66
+Digits, Thai	0E50
+Digits, Tibetan	0F20
+Digits for Persian and Urdu, Eastern Arabic-Indic	06F0
+DIGRAPH KOTO, KATAKANA	30FF
+DIGRAPH YORI, HIRAGANA	309F
+Digraphs, Phonetic	02A3
+Digraphs, Yiddish	05F0
+Digraphs Matching Serbian Cyrillic Letters, Croatian	01C4
+Digram Symbols, Yijing Monogram and	268A
+Digram Symbols, Tai Xuan Jing	1D301
+dijkstra choice	2AFE
+dijkstra choice, n-ary	2AFF
+DIMENSION ORIGIN	2331
+Dingbat Circled Digits	2776
+Dingbats	2700
+Dingbats, Arrow	2794
+Dingbats, Asterisk	2722
+Dingbats, Cross	2719
+Dingbats, Drop-Shadowed	274D
+Dingbats, Hazard	2620
+Dingbats, Heart	2763
+Dingbats, Miscellaneous	2600
+Dingbats, Music	2669
+Dingbats, Pencil	270E
+Dingbats, Pointing Index Finger	261A
+Dingbats, Quotation Mark	275B
+Dingbats, Scissors	2701
+Dingbats, Snowflake	2744
+Dingbats, Star	2726
+Dingbats, Vertical Bar	2758
+Dingbats, Warning	2620
+Dingbats, Weather	2600
+Dingbats, Zapf	2700
+Dingbats Series 100, ITC Zapf	2700
+DIRECT CURRENT SYMBOL FORM TWO	2393
+direct product	2299
+direct sum	2295
+DIRECTIONAL FORMATTING, POP	202C
+Directional Formatting Controls	202A
+DISCONTINUOUS UNDERLINE SYMBOL	2382
+discretionary hyphen	00AD
+disjunction	2228
+DITTO MARK	3003
+DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR, CIRCLE	29BA
+DIVIDED BY HORIZONTAL RULE, LOZENGE	27E0
+DIVIDED BY VERTICAL BAR, CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF	29BA
+DIVIDES	2223
+Divination Lore, Khmer Symbols for	17F0
+DIVISION SIGN	00F7
+DIVISION SIGN, CIRCLED	2A38
+DIVISION SIGN, CIRCLED ANTICLOCKWISE-ROTATED	29BC
+Division Sign Operators, Multiplication and	2A2F
+DIVISION SLASH	2215
+DIVISION SLASH, CIRCLED	2298
+DIVISION TIMES	22C7
+DOES NOT DIVIDE WITH REVERSED NEGATION SLASH	2AEE
+does not yield	22A3
+DOLLAR SIGN	0024
+DOMAIN ANTIRESTRICTION, Z NOTATION	2A64
+DONG SIGN	20AB
+dot	002E
+DOT, AEGEAN LINE SEPARATOR	10101
+dot, greek middle	00B7
+DOT, KATAKANA MIDDLE	30FB
+DOT, MIDDLE	00B7
+DOT, SESAME	FE45
+DOT, WHITE SESAME	FE46
+DOT ABOVE	02D9
+DOT ABOVE, COMBINING	0307
+dot above, double	0308
+DOT ABOVE, LATIN CAPITAL LETTER I WITH	0130
+DOT BELOW, COMBINING	0323
+DOT MINUS	2238
+DOT OPERATOR	22C5
+DOT OPERATOR, CIRCLED	2299
+DOT OPERATOR, N-ARY CIRCLED	2A00
+DOT OPERATOR, SQUARED	22A1
+DOT PLUS	2214
+DOTLESS BEH, ARABIC LETTER	066E
+DOTLESS I, LATIN SMALL LETTER	0131
+DOTLESS QAF, ARABIC LETTER	066F
+DOTS ABOVE, COMBINING FOUR	20DC
+DOTS ABOVE, COMBINING THREE	20DB
+DOTTED CIRCLE	25CC
+DOTTED FENCE	2999
+DOUBLE ACUTE ACCENT	02DD
+DOUBLE ACUTE ACCENT, COMBINING	030B
+DOUBLE ANGLE BRACKET, LEFT	300A
+DOUBLE ANGLE QUOTATION MARK, LEFT-POINTING	00AB
+DOUBLE ANGLE QUOTATION MARK, RIGHT-POINTING	00BB
+DOUBLE APOSTROPHE, MODIFIER LETTER	02EE
+DOUBLE ARCH BELOW, COMBINING INVERTED	032B
+double bar, latin letter pipe	01C2
+DOUBLE CIRCLE, MULTIPLICATION SIGN IN	2A37
+Double Circled Numbers	24F5
+DOUBLE COLON EQUAL	2A74
+double comma quotation mark	201D
+double comma quotation mark, low	201E
+DOUBLE DAGGER	2021
+DOUBLE DANDA, DEVANAGARI	0965
+double derivative	0308
+Double Diacritics	0360
+double dot above	0308
+DOUBLE DOWN TACK	2AEA
+DOUBLE EXCLAMATION MARK	203C
+DOUBLE GRAVE ACCENT, COMBINING	030F
+DOUBLE HIGH-REVERSED-9 QUOTATION MARK	201F
+DOUBLE HYPHEN, KATAKANA-HIRAGANA	30A0
+DOUBLE INTEGRAL	222C
+DOUBLE INTERSECTION	22D2
+DOUBLE INVERTED BREVE, COMBINING	0361
+DOUBLE LEFT TURNSTILE, DOUBLE VERTICAL BAR	2AE5
+DOUBLE LEFT TURNSTILE, VERTICAL BAR	2AE4
+DOUBLE LOGICAL AND	2A53
+DOUBLE LOGICAL OR	2A54
+DOUBLE LOW LINE	2017
+DOUBLE LOW LINE, COMBINING	0333
+DOUBLE LOW-9 QUOTATION MARK	201E
+DOUBLE NESTED GREATER-THAN	2AA2
+DOUBLE NESTED LESS-THAN	2AA1
+DOUBLE NESTED LESS-THAN WITH UNDERBAR	2AA3
+double obelisk	2021
+DOUBLE OVERBAR, LOGICAL AND WITH	2A5E
+DOUBLE OVERBAR, LOGICAL OR WITH	2A62
+DOUBLE OVERLINE, COMBINING	033F
+double pipe	01C1
+DOUBLE PLUS	29FA
+DOUBLE PRECEDES	2ABB
+DOUBLE PRIME	2033
+DOUBLE PRIME, MODIFIER LETTER	02BA
+DOUBLE PRIME, REVERSED	2036
+DOUBLE PRIME QUOTATION MARK	301E
+DOUBLE PRIME QUOTATION MARK, LOW	301F
+DOUBLE PRIME QUOTATION MARK, REVERSED	301D
+DOUBLE PUNCTUATION, PHILIPPINE	1736
+Double punctuation for vertical text	2047
+DOUBLE QUESTION MARK	2047
+DOUBLE QUOTATION MARK, LEFT	201C
+DOUBLE QUOTATION MARK, RIGHT	201D
+double reversed comma quotation mark	201F
+DOUBLE RIGHTWARDS ARROW BELOW, COMBINING	0362
+DOUBLE SOLIDUS OPERATOR	2AFD
+DOUBLE SQUARE INTERSECTION	2A4E
+DOUBLE SQUARE UNION	2A4F
+DOUBLE STROKE, INTEGRAL WITH	2A0E
+DOUBLE STROKE NOT SIGN	2AEC
+DOUBLE STROKE NOT SIGN, REVERSED	2AED
+DOUBLE SUBSET	22D0
+DOUBLE SUCCEEDS	2ABC
+DOUBLE SUPERSET	22D1
+DOUBLE TILDE, COMBINING	0360
+DOUBLE TILDE LEFT HALF, COMBINING	FE22
+double turned comma quotation mark	201C
+DOUBLE TURNSTILE, LEFT AND RIGHT	27DA
+DOUBLE UNDERBAR, LOGICAL AND WITH	2A60
+DOUBLE UNDERBAR, LOGICAL OR WITH	2A63
+double underline	0333
+double underscore	0333
+double underscore, spacing	2017
+DOUBLE UNION	22D3
+DOUBLE UP TACK	2AEB
+DOUBLE VERTICAL, LONG DASH FROM LEFT MEMBER OF	2AE6
+DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE	2AE5
+DOUBLE VERTICAL BAR LEFT TURNSTILE	2AE3
+DOUBLE VERTICAL LINE	2016
+DOUBLE VERTICAL LINE ABOVE, COMBINING	030E
+DOUBLE VERTICAL LINE BELOW, COMBINING	0348
+DOUBLE VERTICAL STROKE, RIGHTWARDS ARROW WITH TAIL WITH	2915
+DOUBLE VERTICAL STROKE, TRIPLE HORIZONTAL BAR WITH	2A68
+DOUBLE VERTICAL STROKE OVERLAY, COMBINING	20E6
+DOUBLE WAVY OVERLINE	FE4C
+DOUBLE WIGGLY FENCE, LEFT	29DA
+DOUBLE WIGGLY FENCE, RIGHT	29DB
+double-barred pipe	01C2
+DOUBLE-ENDED MULTIMAP	29DF
+DOUBLE-STRUCK CAPITAL C	2102
+DOUBLE-STRUCK CAPITAL H	210D
+DOUBLE-STRUCK CAPITAL N	2115
+DOUBLE-STRUCK CAPITAL P	2119
+DOUBLE-STRUCK CAPITAL Q	211A
+DOUBLE-STRUCK CAPITAL R	211D
+DOUBLE-STRUCK CAPITAL Z	2124
+Double-struck Greek Letters	213D
+Double-Struck Italic Mathematical Symbols	2145
+DOUBLE-STRUCK N-ARY SUMMATION	2140
+down, page	21DF
+DOWN TACK	22A4
+DOWN TACK BELOW, COMBINING	031E
+DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK	29E8
+DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK	29E9
+DRACHMA SIGN	20AF
+Drafting Symbols	232D
+dram	0292
+drop	264F
+Duplicates from Big 5	FA0C
+E, COMBINING LATIN SMALL LETTER	0364
+E, DOUBLE-STRUCK ITALIC SMALL	2147
+E, LATIN CAPITAL LETTER OPEN	0190
+E, LATIN CAPITAL LETTER REVERSED	018E
+e, latin capital letter turned	018E
+E, LATIN SMALL LETTER CLOSED OPEN	029A
+E, LATIN SMALL LETTER CLOSED REVERSED OPEN	025E
+E, LATIN SMALL LETTER OPEN	025B
+E, LATIN SMALL LETTER REVERSED	0258
+E, LATIN SMALL LETTER REVERSED OPEN	025C
+E, LATIN SMALL LETTER TURNED	01DD
+E, SCRIPT CAPITAL	2130
+E, SCRIPT SMALL	212F
+EARTH	2641
+Eastern Arabic-Indic Digits for Persian and Urdu	06F0
+ecu	20A0
+EIGHTH NOTE	266A
+EIGHTH NOTES, BEAMED	266B
+Eighths, Fractions	215B
+EJECT SYMBOL	23CF
+EK ONKAR, GURMUKHI	0A74
+el salvadorian currency	20A1
+ELECTRIC ARROW	2301
+electro-magnetic force, emf	2130
+electrolysis	21AF
+Electrotechnical Symbols from IR 181	238D
+element, unique	2129
+ELEMENT OF	2208
+ELEMENT OF, NOT AN	2209
+ELEMENT OF, SMALL	220A
+ELEMENT OF OPENING DOWNWARDS	2AD9
+ELEMENT OF OPENING UPWARDS	27D2
+ELEMENT OF WITH DOT ABOVE	22F5
+ELEMENT OF WITH LONG HORIZONTAL STROKE	22F2
+ELEMENT OF WITH OVERBAR	22F6
+ELEMENT OF WITH OVERBAR, SMALL	22F7
+ELEMENT OF WITH TWO HORIZONTAL STROKES	22F9
+ELEMENT OF WITH UNDERBAR	22F8
+ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE	22F3
+ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE, SMALL	22F4
+ell, mathematical symbol	2113
+ELLIPSIS, HORIZONTAL	2026
+ELLIPSIS, MIDLINE HORIZONTAL	22EF
+ELLIPSIS, UP RIGHT DIAGONAL	22F0
+ELLIPSIS, VERTICAL	22EE
+elliptic function, weierstrass	2118
+EM DASH	2014
+EM QUAD	2001
+EM SPACE	2003
+EMBEDDING, LEFT-TO-RIGHT	202A
+EMBEDDING, RIGHT-TO-LEFT	202B
+emf	2130
+EMPHASIS MARK, ARMENIAN	055B
+Emphasis Marks, Sidelining	FE45
+EMPHASIS SYMBOL	2383
+EMPTY SET	2205
+Empty Sets	29B0
+EN DASH	2013
+EN QUAD	2000
+EN SPACE	2002
+Enclosed Alphanumerics	2460
+Enclosed CJK Letters and Ideographs	3200
+ENCLOSING CIRCLE, COMBINING	20DD
+ENCLOSING CIRCLE BACKSLASH, COMBINING	20E0
+Enclosing Diacritics	20DD
+ENCLOSING DIAMOND, COMBINING	20DF
+ENCLOSING KEYCAP, COMBINING	20E3
+ENCLOSING SCREEN, COMBINING	20E2
+ENCLOSING SQUARE, COMBINING	20DE
+ENCLOSING UPWARD POINTING TRIANGLE, COMBINING	20E4
+end	21F2
+end of guarded area	0097
+end of medium	0019
+end of medium, graphic for	237F
+END OF MEDIUM, SYMBOL FOR	2419
+END OF PROOF	220E
+end of selected area	0087
+end of text	0003
+END OF TEXT, SYMBOL FOR	2403
+end of transmission	0004
+end of transmission, graphic for	2301
+END OF TRANSMISSION, SYMBOL FOR	2404
+end of transmission block	0017
+END OF TRANSMISSION BLOCK, SYMBOL FOR	2417
+ENG, LATIN SMALL LETTER	014B
+enotikon, greek	203F
+enquiry	0005
+ENQUIRY, SYMBOL FOR	2405
+enter key	2324
+ENTER SYMBOL	2386
+ENVELOPE	2709
+epsilon, latin capital letter	0190
+epsilon, latin small letter	025B
+epsilon, latin small letter closed	029A
+epsilon, latin small letter closed reversed	025E
+epsilon, reversed straight	03F6
+epsilon, reversed straight	220D
+epsilon, straight	03F5
+epsilon, straight	220A
+EPSILON SYMBOL, GREEK LUNATE	03F5
+EPSILON SYMBOL, GREEK REVERSED LUNATE	03F6
+EQUAL, DOUBLE COLON	2A74
+EQUAL, GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE	2A92
+EQUAL, GREATER-THAN ABOVE SIMILAR OR	2A8E
+EQUAL, GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED	2A94
+EQUAL, GREATER-THAN CLOSED BY CURVE ABOVE SLANTED	2AA9
+EQUAL, LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE	2A91
+EQUAL, LESS-THAN ABOVE SIMILAR OR	2A8D
+EQUAL, LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED	2A93
+EQUAL, LESS-THAN CLOSED BY CURVE ABOVE SLANTED	2AA8
+EQUAL ABOVE GREATER-THAN, LESS-THAN ABOVE DOUBLE-LINE	2A8B
+EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL, LESS-THAN ABOVE SLANTED	2A93
+EQUAL ABOVE LESS-THAN, GREATER-THAN ABOVE DOUBLE-LINE	2A8C
+EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL, GREATER-THAN ABOVE SLANTED	2A94
+EQUAL OR EQUAL TO, APPROXIMATELY	2A70
+EQUAL TO, ALL	224C
+EQUAL TO, ALMOST	2248
+EQUAL TO, APPROXIMATELY	2245
+equal to, approximately	2257
+EQUAL TO, APPROXIMATELY EQUAL OR	2A70
+EQUAL TO, ASYMPTOTICALLY	2243
+EQUAL TO, CLOSED SUBSET OR	2AD1
+EQUAL TO, CLOSED SUPERSET OR	2AD2
+EQUAL TO, DELTA	225C
+EQUAL TO, DOUBLE-LINE SLANTED GREATER-THAN OR	2AFA
+EQUAL TO, DOUBLE-LINE SLANTED LESS-THAN OR	2AF9
+EQUAL TO, GEOMETRICALLY	2251
+EQUAL TO, GREATER-THAN AND SINGLE-LINE NOT	2A88
+EQUAL TO, GREATER-THAN OR	2265
+EQUAL TO, GREATER-THAN OR SLANTED	2A7E
+EQUAL TO, LARGER THAN OR	2AAD
+EQUAL TO, LESS-THAN AND SINGLE-LINE NOT	2A87
+EQUAL TO, LESS-THAN OR	2264
+EQUAL TO, LESS-THAN OR SLANTED	2A7D
+EQUAL TO, NOT	2260
+EQUAL TO, PRECEDES ABOVE ALMOST	2AB7
+EQUAL TO, PRECEDES ABOVE NOT	2AB5
+EQUAL TO, PRECEDES ABOVE NOT ALMOST	2AB9
+EQUAL TO, PRECEDES ABOVE SINGLE-LINE NOT	2AB1
+EQUAL TO, QUESTIONED	225F
+EQUAL TO, RING	2257
+EQUAL TO, RING IN	2256
+EQUAL TO, SMALLER THAN OR	2AAC
+EQUAL TO, SUBSET OF ABOVE ALMOST	2AC9
+EQUAL TO, SUBSET OF ABOVE NOT	2ACB
+EQUAL TO, SUCCEEDS ABOVE ALMOST	2AB8
+EQUAL TO, SUCCEEDS ABOVE NOT	2AB6
+EQUAL TO, SUCCEEDS ABOVE NOT ALMOST	2ABA
+EQUAL TO, SUCCEEDS ABOVE SINGLE-LINE NOT	2AB2
+EQUAL TO, SUPERSET OF ABOVE ALMOST	2ACA
+EQUAL TO, SUPERSET OF ABOVE NOT	2ACC
+EQUAL TO ABOVE, COMBINING ALMOST	034C
+equal to by definition	225C
+EQUAL TO BY DEFINITION	225D
+EQUAL TO OR GREATER-THAN, DOUBLE-LINE	2A9A
+EQUAL TO OR GREATER-THAN, DOUBLE-LINE SLANTED	2A9C
+EQUAL TO OR GREATER-THAN, SLANTED	2A96
+EQUAL TO OR GREATER-THAN WITH DOT INSIDE, SLANTED	2A98
+EQUAL TO OR LESS-THAN, DOUBLE-LINE	2A99
+EQUAL TO OR LESS-THAN, DOUBLE-LINE SLANTED	2A9B
+EQUAL TO OR LESS-THAN, SLANTED	2A95
+EQUAL TO OR LESS-THAN WITH DOT INSIDE, SLANTED	2A97
+EQUAL TO WITH CIRCUMFLEX ACCENT, ALMOST	2A6F
+EQUAL TO WITH DOT ABOVE, GREATER-THAN OR SLANTED	2A82
+EQUAL TO WITH DOT ABOVE, LESS-THAN OR SLANTED	2A81
+EQUAL TO WITH DOT ABOVE, SUBSET OF OR	2AC3
+EQUAL TO WITH DOT ABOVE, SUPERSET OF OR	2AC4
+EQUAL TO WITH DOT ABOVE LEFT, GREATER-THAN OR SLANTED	2A84
+EQUAL TO WITH DOT ABOVE RIGHT, LESS-THAN OR SLANTED	2A83
+EQUAL TO WITH DOT INSIDE, GREATER-THAN OR SLANTED	2A80
+EQUAL TO WITH DOT INSIDE, LESS-THAN OR SLANTED	2A7F
+EQUALS, CIRCLED	229C
+EQUALS, REVERSED TILDE	22CD
+EQUALS, STAR	225B
+EQUALS COLON	2255
+EQUALS SIGN	003D
+EQUALS SIGN, PLUS SIGN ABOVE	2A72
+EQUALS SIGN, PRECEDES ABOVE	2AB3
+EQUALS SIGN, PRECEDES ABOVE SINGLE-LINE	2AAF
+EQUALS SIGN, SIMILAR ABOVE GREATER-THAN ABOVE	2AA0
+EQUALS SIGN, SIMILAR ABOVE LESS-THAN ABOVE	2A9F
+EQUALS SIGN, SUBSCRIPT	208C
+EQUALS SIGN, SUBSET OF ABOVE	2AC5
+EQUALS SIGN, SUCCEEDS ABOVE	2AB4
+EQUALS SIGN, SUCCEEDS ABOVE SINGLE-LINE	2AB0
+EQUALS SIGN, SUPERSCRIPT	207C
+EQUALS SIGN, SUPERSET OF ABOVE	2AC6
+EQUALS SIGN ABOVE PLUS SIGN	2A71
+EQUALS SIGN ABOVE TILDE OPERATOR	2A73
+EQUALS SIGN AND SLANTED PARALLEL	29E3
+EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE	29E4
+EQUALS SIGN BELOW, COMBINING	0347
+EQUALS SIGN WITH BUMPY ABOVE	2AAE
+EQUALS SIGN WITH DOT BELOW	2A66
+EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW	2A77
+EQUALS SIGNS, THREE CONSECUTIVE	2A76
+EQUALS SIGNS, TWO CONSECUTIVE	2A75
+EQUALS WITH ASTERISK	2A6E
+equiangular	225C
+EQUIANGULAR TO	225A
+equivalent, tautological	29E6
+EQUIVALENT TO	224D
+EQUIVALENT TO, GEOMETRICALLY	224E
+EQUIVALENT TO, STRICTLY	2263
+EQUIVALENT WITH FOUR DOTS ABOVE	2A78
+Era Names, Japanese	337B
+ERASE TO THE LEFT	232B
+ERASE TO THE RIGHT	2326
+error	212F
+Error Bar Symbols	29EE
+escape	001B
+escape, data link	0010
+ESCAPE, SYMBOL FOR	241B
+ESCAPE, SYMBOL FOR DATA LINK	2410
+escudo	0024
+ESH, LATIN CAPITAL LETTER	01A9
+ESH, LATIN SMALL LETTER	0283
+ESH, LATIN SMALL LETTER SQUAT REVERSED	0285
+ESH LOOP, LATIN LETTER REVERSED	01AA
+ESTIMATED SYMBOL	212E
+ESTIMATES	2259
+eszett	00DF
+ET, TIRONIAN SIGN	204A
+ETH, LATIN SMALL LETTER	00F0
+ethel	0153
+Ethiopic	1200
+ETHIOPIC COLON	1365
+ETHIOPIC COMMA	1363
+Ethiopic Digits	1369
+ETHIOPIC FULL STOP	1362
+ETHIOPIC QUESTION MARK	1367
+ETHIOPIC SEMICOLON	1364
+ETHIOPIC WORDSPACE	1361
+EULER CONSTANT	2107
+EURO SIGN	20AC
+European Latin	0100
+european paragraph sign	00A7
+european section sign	00B6
+EXCESS	2239
+EXCLAMATION MARK	0021
+EXCLAMATION MARK, ARMENIAN	055C
+EXCLAMATION MARK, DOUBLE	203C
+EXCLAMATION MARK, INVERTED	00A1
+exclamation mark, latin letter	01C3
+EXCLAMATION MARK, QUESTION	2048
+EXCLAMATION MARK ORNAMENT, HEAVY	2762
+EXCLAMATION QUESTION MARK	2049
+EXISTS, THERE	2203
+Extended Additional, Latin	1E00
+Extended Arabic	0671
+Extended Cyrillic	048C
+Extended for Minnan and Hakka, Chinese Bopomofo	31A0
+Extended Greek	1F00
+Extended-A, Latin	0100
+Extended-B, Latin	0180
+extension, arrows	23AF
+EXTENSION, HORIZONTAL LINE	23AF
+EXTENSION, INTEGRAL	23AE
+EXTENSION, VERTICAL LINE	23D0
+Extension A, CJK Unified Ideographs	3400
+Extensions, Cyrillic	0450
+Extensions, IPA	0250
+Extensions, Katakana Phonetic	31F0
+Extensions, Special Characters	23AE
+Extensions for Sanskrit and Tibetan, Mongolian	1880
+Extensions for Vietnamese, Latin	1EA0
+EZH, LATIN CAPITAL LETTER	01B7
+EZH, LATIN SMALL LETTER	0292
+EZH REVERSED, LATIN SMALL LETTER	01B9
+F, SCRIPT CAPITAL	2131
+F, TURNED CAPITAL	2132
+F WITH HOOK, LATIN SMALL LETTER	0192
+FACE, BLACK SMILING	263B
+FACE, POSTAL MARK	3020
+FACE, WHITE FROWNING	2639
+FACE, WHITE SMILING	263A
+FACSIMILE SIGN	213B
+factorial	0021
+FAHRENHEIT, DEGREE	2109
+FALLING DIAGONAL SLASH, SQUARED	29C5
+FALLING DOTS, MINUS SIGN WITH	2A2B
+feet	2032
+FEMALE SIGN	2640
+FEMININE ORDINAL INDICATOR	00AA
+FENCE, DOTTED	2999
+FENCE, LEFT DOUBLE WIGGLY	29DA
+FENCE, LEFT WIGGLY	29D8
+FENCE, RIGHT DOUBLE WIGGLY	29DB
+FENCE, RIGHT WIGGLY	29D9
+Fences	2999
+Fences	29D8
+Fifths, Fractions	2155
+FIGURE DASH	2012
+FIGURE SPACE	2007
+file separator	001C
+FILE SEPARATOR, SYMBOL FOR	241C
+Finger Dingbats, Pointing Index	261A
+finite function, z notation	20E6
+finite function, z notation	21FB
+finite injection, z notation	2915
+FINITE PART INTEGRAL	2A0D
+finite relation, z notation	21FC
+finite surjection, z notation	2901
+finite surjective injection, z notation	2918
+FIRST QUARTER MOON	263D
+first transfinite cardinal (countable)	2135
+Fish Tails	297C
+FISHEYE	25C9
+fist	261E
+FIVE, LATIN SMALL LETTER TONE	01BD
+FIVE POINTED STAR, ARABIC	066D
+FLAG, BLACK	2691
+FLAT SIGN, MUSIC	266D
+FLOOR, LEFT	230A
+FLORAL HEART BULLET, REVERSED ROTATED	2619
+florin currency symbol	0192
+folder	0192
+FOOT, SQUARE	23CD
+FOONOTE MARKER, ARABIC	0602
+FOR ALL	2200
+FORCES	22A9
+FORKING	2ADC
+Forks	2AD9
+Form and Chart Components	2500
+form feed	000C
+form feed	21A1
+FORM FEED, SYMBOL FOR	240C
+Format Control, Syriac	070F
+Format Controls, Mongolian	180B
+FORMATTING, POP DIRECTIONAL	202C
+Formatting Characters	200C
+Formatting Characters	2028
+Formatting Controls, Bidirectional	202A
+forward difference	2206
+FOUR DOTS ABOVE, COMBINING	20DC
+FOUR-PER-EM SPACE	2005
+fourier transform	2131
+fourth derivative	20DC
+FOURTH ROOT	221C
+fourth transfinite cardinal	2138
+Fourths, Fractions	00BC
+FRACTION NUMERATOR ONE	215F
+FRACTION ONE HALF, VULGAR	00BD
+FRACTION ONE QUARTER, VULGAR	00BC
+FRACTION SLASH	2044
+FRACTION THREE QUARTERS, VULGAR	00BE
+Fractions	2153
+FRAGMENT, ARABIC TAIL	FE73
+framus, white	29D6
+FRANC SIGN, FRENCH	20A3
+FRICATIVE, LATIN LETTER PHARYNGEAL VOICED	0295
+FROWN	2322
+FROWNING FACE, WHITE	2639
+FULL BLOCK	2588
+FULL OUTER JOIN	27D7
+FULL STOP	002E
+FULL STOP, ARABIC	06D4
+FULL STOP, ARMENIAN	0589
+FULL STOP, ETHIOPIC	1362
+full stop, georgian	0589
+FULL STOP, IDEOGRAPHIC	3002
+FULL STOP, MONGOLIAN	1803
+Fullwidth ASCII Variants	FF01
+Fullwidth Brackets	FF5F
+Fullwidth Forms, Halfwidth and	FF00
+Fullwidth Symbol Variants	FFE0
+FUNCTION, CIRCULATION	2A10
+function, gamma	0393
+function, z notation finite	20E6
+function, z notation finite	21FB
+function, z notation partial	21F8
+FUNCTION APPLICATION	2061
+function symbol	0192
+fvs	180B
+G, LATIN LETTER SMALL CAPITAL	0262
+G, LATIN SMALL LETTER SCRIPT	0261
+G, SCRIPT SMALL	210A
+G, TURNED SANS-SERIF CAPITAL	2141
+game	2141
+GAMMA, DOUBLE-STRUCK CAPITAL	213E
+GAMMA, DOUBLE-STRUCK SMALL	213D
+GAMMA, LATIN CAPITAL LETTER	0194
+GAMMA, LATIN SMALL LETTER	0263
+gamma, latin small letter baby	0264
+GAMMA, MODIFIER LETTER SMALL	02E0
+gamma function	0393
+GB 2312 (Chinese), Based on	3100
+GEMINI	264A
+General Punctuation	2000
+General Scripts Area	0000
+GENERIC MATERIALS, RECYCLING SYMBOL FOR	267A
+Generic punctuation for Philippine scripts	1735
+GEOMETRIC PROPORTION	223A
+Geometric Shapes	25A0
+GEOMETRICALLY EQUAL TO	2251
+GEOMETRICALLY EQUIVALENT TO	224E
+Georgian	10A0
+Georgian Capital Letters	10A0
+georgian comma	00B7
+georgian full stop	0589
+GEORGIAN PARAGRAPH SEPARATOR	10FB
+Georgian Small Letters	10D0
+german mark	2133
+GERMAN PENNY SIGN	20B0
+GETA MARK	3013
+GIMEL SYMBOL	2137
+GLEICH STARK	29E6
+glottal stop	02BC
+GLOTTAL STOP, LATIN LETTER	0294
+GLOTTAL STOP, LATIN LETTER INVERTED	0296
+glottal stop, latin letter reversed	0295
+GLOTTAL STOP, MODIFIER LETTER	02C0
+GLOTTAL STOP, MODIFIER LETTER REVERSED	02C1
+GLOTTAL STOP, MODIFIER LETTER SMALL REVERSED	02E4
+Go Markers	2686
+Golden Number Runes	16EE
+GRAPHEME JOINER, COMBINING	034F
+Graphic Characters, Terminal	23B7
+Graphic Characters, Terminal	2596
+Graphic Pictures for Control Codes	2400
+Graphics, Control Code	25F0
+Graphics, Scan Lines For Terminal	23BA
+Graphics for Control Codes	237B
+grave, spacing	0060
+GRAVE ACCENT	0060
+GRAVE ACCENT, COMBINING	0300
+GRAVE ACCENT, COMBINING DOUBLE	030F
+GRAVE ACCENT, DEVANAGARI	0953
+GRAVE ACCENT, MODIFIER LETTER	02CB
+GRAVE ACCENT, MODIFIER LETTER LOW	02CE
+grave accent, swedish	02DF
+GRAVE ACCENT BELOW, COMBINING	0316
+GRAVE TONE MARK, COMBINING	0340
+GREATER-THAN, CIRCLED	29C1
+GREATER-THAN, DOUBLE NESTED	2AA2
+GREATER-THAN, DOUBLE-LINE EQUAL TO OR	2A9A
+GREATER-THAN, DOUBLE-LINE SLANTED EQUAL TO OR	2A9C
+GREATER-THAN, LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE	2A8B
+GREATER-THAN, LESS-THAN ABOVE SIMILAR ABOVE	2A8F
+GREATER-THAN, MUCH	226B
+GREATER-THAN, SIMILAR OR	2A9E
+GREATER-THAN, SLANTED EQUAL TO OR	2A96
+GREATER-THAN, TRIPLE NESTED	2AF8
+GREATER-THAN, VERY MUCH	22D9
+GREATER-THAN ABOVE DOUBLE-LINE EQUAL, LESS-THAN ABOVE	2A91
+GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN	2A8C
+GREATER-THAN ABOVE EQUALS SIGN, SIMILAR ABOVE	2AA0
+GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL	2A92
+GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN	2A90
+GREATER-THAN ABOVE SIMILAR OR EQUAL	2A8E
+GREATER-THAN ABOVE SLANTED EQUAL, LESS-THAN ABOVE SLANTED EQUAL ABOVE	2A93
+GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL	2A94
+GREATER-THAN AND NOT APPROXIMATE	2A8A
+GREATER-THAN AND SINGLE-LINE NOT EQUAL TO	2A88
+GREATER-THAN BESIDE LESS-THAN	2AA5
+GREATER-THAN CLOSED BY CURVE	2AA7
+GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL	2AA9
+GREATER-THAN OR APPROXIMATE	2A86
+GREATER-THAN OR EQUAL TO	2265
+GREATER-THAN OR EQUAL TO, DOUBLE-LINE SLANTED	2AFA
+GREATER-THAN OR SLANTED EQUAL TO	2A7E
+GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE	2A82
+GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT	2A84
+GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE	2A80
+GREATER-THAN OVERLAPPING LESS-THAN	2AA4
+GREATER-THAN SIGN	003E
+GREATER-THAN WITH CIRCLE INSIDE	2A7A
+GREATER-THAN WITH DOT INSIDE, SLANTED EQUAL TO OR	2A98
+GREATER-THAN WITH QUESTION MARK ABOVE	2A7C
+Greek, Diacritics for	0342
+Greek, Extended	1F00
+Greek and Coptic	0370
+Greek Capital Letters	0391
+greek currency	20AF
+GREEK DIALYTIKA TONOS, COMBINING	0344
+greek enotikon	203F
+GREEK KORONIS, COMBINING	0343
+greek middle dot	00B7
+greek non-spacing iota below	0345
+GREEK PERISPOMENI, COMBINING	0342
+GREEK QUESTION MARK	037E
+GREEK SMALL LETTER IOTA, TURNED	2129
+Greek Small Letters	03B1
+Greek Symbols	03D0
+GREEK YPOGEGRAMMENI, COMBINING	0345
+group lock	21F0
+group separator	001D
+GROUP SEPARATOR, SYMBOL FOR	241D
+guarded area, end of	0097
+guarded area, start of	0096
+gui icons	231A
+guillemet, left pointing	00AB
+guillemet, left pointing single	2039
+guillemet, right pointing	00BB
+guillemet, right pointing single	203A
+Gujarati	0A80
+Gujarati Digits	0AE6
+Gujarati Letters	0A85
+GUJARATI RUPEE SIGN	0AF1
+Gurmukhi	0A00
+Gurmukhi Digits	0A66
+Gurmukhi Letters	0A05
+H, BLACK-LETTER CAPITAL	210C
+H, COMBINING LATIN SMALL LETTER	036A
+H, DOUBLE-STRUCK CAPITAL	210D
+H, LATIN LETTER SMALL CAPITAL	029C
+H, LATIN SMALL LETTER TURNED	0265
+H, MODIFIER LETTER SMALL	02B0
+H, SCRIPT CAPITAL	210B
+hacek, combining	030C
+hacek, modifier letter	02C7
+HAIR SPACE	200A
+Hakka, Chinese Bopomofo Extended for Minnan and	31A0
+halant, bengali	09CD
+halant, devanagari	094D
+HALF, COMBINING DOUBLE TILDE LEFT	FE22
+HALF, COMBINING LIGATURE LEFT	FE20
+HALF, VULGAR FRACTION ONE	00BD
+HALF CIRCLE, MULTIPLICATION SIGN IN LEFT	2A34
+HALF CIRCLE, MULTIPLICATION SIGN IN RIGHT	2A35
+HALF CIRCLE, PLUS SIGN IN LEFT	2A2D
+HALF CIRCLE, PLUS SIGN IN RIGHT	2A2E
+HALF FILL SPACE, IDEOGRAPHIC	303F
+HALF INTEGRAL, TOP	2320
+Half Marks, Combining	FE20
+HALF RING, MODIFIER LETTER CENTRED LEFT	02D3
+HALF RING, MODIFIER LETTER LEFT	02BF
+HALF RING BELOW, COMBINING LEFT	031C
+HALF RING BELOW, COMBINING RIGHT	0339
+HALF TRIANGULAR COLON, MODIFIER LETTER	02D1
+Halfwidth and Fullwidth Forms	FF00
+Halfwidth Japanese Katakana Variants	FF61
+Halfwidth Korean Hangul Variants	FFA0
+hamiltonian function	210B
+HAMMER AND SICKLE	262D
+Han Ideographs	4E00
+HAND, VICTORY	270C
+HAND, WRITING	270D
+Hand Symbols, Pointing	261A
+Hangul, Based on KS C 5601 (Korean)	3130
+HANGUL CHOSEONG FILLER	115F
+Hangul Compatibility Jamo, Korean	3130
+Hangul Elements, Circled Korean	3260
+Hangul Elements, Parenthesized Korean	3200
+HANGUL FILLER	3164
+Hangul Jamo Combining Alphabet, Korean	1100
+HANGUL JUNGSEONG FILLER	1160
+Hangul Syllables, Circled Korean	326E
+Hangul Syllables, Parenthesized Korean	320E
+Hangul Syllables Area, Korean	AC00
+Hangul Variants, Halfwidth Korean	FFA0
+Hangzhou-style Numerals	3021
+Hanunoo	1720
+HANUNOO SIGN PAMUDPOD	1734
+Hanun�o-specific punctuation	1734
+HARPOON ABOVE, COMBINING LEFT	20D0
+hasant	09CD
+hash	0023
+hat	0302
+hat	2229
+have a nice day!	263A
+Hazard Dingbats	2620
+heading, start of	0001
+HEADING, SYMBOL FOR START OF	2401
+Heart Ornaments	2763
+HEAVY BALLOT X	2718
+HEAVY CHECK MARK	2714
+HEAVY MULTIPLICATION X	2716
+Hebrew	0590
+Hebrew Cantillation Marks	0591
+hebrew currency	20AA
+Hebrew Letters	05D0
+Hebrew Points	05B0
+Hebrew Presentation Forms	FB1D
+HELM SYMBOL	2388
+HERMITIAN CONJUGATE MATRIX	22B9
+Hexagram Symbols, Yijing	4DC0
+hiding, z notation schema	29F9
+High Surrogates	D800
+HIGH VOLTAGE SIGN	26A1
+HIGH-REVERSED-9 QUOTATION MARK, DOUBLE	201F
+HIGH-REVERSED-9 QUOTATION MARK, SINGLE	201B
+higher rank than	227B
+hilbert space	210C
+Hiragana, Based on JIS X 0208 (Japanese)	3040
+HIRAGANA DIGRAPH YORI	309F
+HIRAGANA ITERATION MARK	309D
+histogram marker	25AE
+Historic Letters, Cyrillic	0460
+home	21B8
+home	21F1
+HOMOTHETIC	223B
+HOMOTHETIC ABOVE, COMBINING	034B
+Honorific Signs, Arabic	0610
+HOOK, MODIFIER LETTER RHOTIC	02DE
+hook, nasal	0328
+HOOK ABOVE, COMBINING	0309
+HOOK BELOW, COMBINING PALATALIZED	0321
+HOOK BELOW, COMBINING RETROFLEX	0322
+HORIZONTAL BAR	2015
+HORIZONTAL BAR, CIRCLE WITH	29B5
+HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE, TRIPLE	2A68
+HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE, TRIPLE	2A69
+HORIZONTAL ELLIPSIS	2026
+HORIZONTAL ELLIPSIS, MIDLINE	22EF
+HORIZONTAL LINE EXTENSION	23AF
+HORIZONTAL RULE, LOZENGE DIVIDED BY	27E0
+horizontal tabulation	0009
+HORIZONTAL TABULATION, SYMBOL FOR	2409
+HORN, COMBINING	031B
+HORN, LATIN SMALL LETTER RAMS	0264
+HOT BEVERAGE	2615
+HOT SPRINGS	2668
+HOURGLASS	231B
+HOURGLASS, BLACK	29D7
+HOURGLASS, WHITE	29D6
+Hours, Telegraph Symbols for	3358
+HOUSE	2302
+HV, LATIN SMALL LETTER	0195
+HWAIR, LATIN CAPITAL LETTER	01F6
+HYPHEN	2010
+HYPHEN, ARMENIAN	058A
+hyphen, discretionary	00AD
+HYPHEN, KATAKANA-HIRAGANA DOUBLE	30A0
+HYPHEN, NON-BREAKING	2011
+HYPHEN, SOFT	00AD
+HYPHEN BULLET	2043
+hyphen or minus sign	002D
+HYPHEN-MINUS	002D
+HYPHENATION POINT	2027
+hyphus	002D
+HYSTERESIS SYMBOL	238E
+I, BLACK-LETTER CAPITAL	2111
+I, COMBINING LATIN SMALL LETTER	0365
+I, DOUBLE-STRUCK ITALIC SMALL	2148
+I, LATIN LETTER SMALL CAPITAL	026A
+I, LATIN SMALL LETTER DOTLESS	0131
+I, SCRIPT CAPITAL	2110
+I, SUPERSCRIPT LATIN SMALL LETTER	2071
+I WITH DOT ABOVE, LATIN CAPITAL LETTER	0130
+IBM CJK Compatibility Ideographs	FA0E
+icons, gui	231A
+identical and parallel to	2A68
+IDENTICAL TO	2261
+IDENTICAL TO AND SLANTED PARALLEL	29E5
+IDENTICAL WITH DOT ABOVE	2A67
+Ideographic Annotation, Japanese Kanbun	3190
+IDEOGRAPHIC CLOSING MARK	3006
+IDEOGRAPHIC COMMA	3001
+Ideographic Description Characters	2FF0
+IDEOGRAPHIC FULL STOP	3002
+IDEOGRAPHIC HALF FILL SPACE	303F
+IDEOGRAPHIC ITERATION MARK	3005
+IDEOGRAPHIC ITERATION MARK, VERTICAL	303B
+IDEOGRAPHIC NUMBER ZERO	3007
+IDEOGRAPHIC SPACE	3000
+Ideographic Tone Marks	302A
+Ideographs, Circled	3280
+Ideographs, CJK Compatibility	F900
+Ideographs, CJK Unified	4E00
+Ideographs, Enclosed CJK Letters and	3200
+Ideographs, Han	4E00
+Ideographs, IBM CJK Compatibility	FA0E
+Ideographs, Parenthesized	3220
+Ideographs Area, CJK	3400
+Ideographs Extension A, CJK Unified	3400
+IDLE, SYMBOL FOR SYNCHRONOUS	2416
+idle, synchronous	0016
+IJ, LATIN SMALL LIGATURE	0133
+IMAGE OF	22B7
+IMAGE OF, SQUARE	228F
+imaginary part	2111
+implies	22A2
+inches	2033
+included in set	2282
+includes in set	2283
+INCOMPLETE INFINITY	29DC
+incorporated, japanese	337F
+INCREASES AS	29E1
+INCREMENT	2206
+independence	2AEB
+independent	2ADD
+independent, not	2ADC
+index	0084
+Index Finger Dingbats, Pointing	261A
+indian currency	20A8
+inferior order to, of	2134
+INFINITY	221E
+INFINITY, INCOMPLETE	29DC
+INFINITY, TIE OVER	29DD
+INFINITY NEGATED WITH VERTICAL BAR	29DE
+INFORMATION SOURCE	2139
+INHIBIT ARABIC FORM SHAPING	206C
+INHIBIT SYMMETRIC SWAPPING	206A
+injection, z notation finite	2915
+injection, z notation finite surjective	2918
+injection, z notation partial	2914
+injection, z notation surjective	2917
+INSERTION POINT, CARET	2041
+INSERTION SYMBOL	2380
+integers, the set of	2124
+INTEGRAL	222B
+INTEGRAL, CLOCKWISE	2231
+INTEGRAL, CLOCKWISE CONTOUR	2232
+INTEGRAL, CONTOUR	222E
+INTEGRAL, DOUBLE	222C
+integral, riemann	211B
+INTEGRAL, SURFACE	222F
+INTEGRAL, TOP HALF	2320
+INTEGRAL, TRIPLE	222D
+INTEGRAL, VOLUME	2230
+Integrals, Summations and	2A0A
+INTERCALATE	22BA
+INTERIOR PRODUCT	2A3C
+INTERIOR PRODUCT, RIGHTHAND	2A3D
+interleave	2AF4
+Interlinear Annotation	FFF9
+Internal Codes, Process	FDD0
+International Phonetic Alphabet	0250
+INTERROBANG	203D
+INTERSECTION	2229
+INTERSECTION, DOUBLE	22D2
+INTERSECTION, INTEGRAL WITH	2A19
+INTERSECTION, N-ARY	22C2
+intersection, proper	22D4
+INTERSECTION, TRANSVERSAL	2ADB
+INTERSECTION OPERATOR, N-ARY SQUARE	2A05
+INTERSECTION WITH DOT	2A40
+Intersections and Unions	2A40
+introducer, control sequence	009B
+introducer, single character	009A
+Inverse Numbers, Circled	2776
+INVERTED BREVE, COMBINING	0311
+INVERTED BREVE, COMBINING DOUBLE	0361
+INVERTED BREVE BELOW, COMBINING	032F
+INVERTED BRIDGE BELOW, COMBINING	033A
+INVERTED DOUBLE ARCH BELOW, COMBINING	032B
+INVERTED EXCLAMATION MARK	00A1
+INVERTED GLOTTAL STOP, LATIN LETTER	0296
+INVERTED LAZY S	223E
+INVERTED OHM SIGN	2127
+INVERTED QUESTION MARK	00BF
+INVERTED R, LATIN LETTER SMALL CAPITAL	0281
+INVERTED R, MODIFIER LETTER SMALL CAPITAL	02B6
+INVERTED UNDERTIE	2054
+Invisible Operators	2063
+IOTA, LATIN CAPITAL LETTER	0196
+IOTA, LATIN SMALL LETTER	0269
+IOTA, TURNED GREEK SMALL LETTER	2129
+iota below, greek non-spacing	0345
+IPA, Diacritics for	0346
+IPA Extensions	0250
+IR 181, Electrotechnical Symbols from	238D
+iran, symbol of	262B
+irish punt	00A3
+ISCII 1988 (Devanagari), Based on	0901
+ISO 8859-1 (Latin-1), Based on	00A0
+ISO 8859-2, -3, -4, -9 (European Latin), Based on	0100
+ISO 8859-5 (Cyrillic), Based on	0400
+ISO 8859-6 (Arabic), Based on	0600
+ISO 8859-7 (Greek), Based on	0370
+ISO 8859-8 (Hebrew), Based on	05D0
+ISO 9995-7, Keyboard Symbols from	2380
+ISO 9995-7, Keyboard Symbols from	2396
+israeli currency	20AA
+italian currency	20A4
+Italic Mathematical Symbols, Double-Struck	2145
+ITC Zapf Dingbats Series 100	2700
+ITERATION MARK, HIRAGANA	309D
+ITERATION MARK, IDEOGRAPHIC	3005
+ITERATION MARK, KATAKANA	30FD
+ITERATION MARK, VERTICAL IDEOGRAPHIC	303B
+ivy leaf	2767
+J, DOUBLE-STRUCK ITALIC SMALL	2149
+J, MODIFIER LETTER SMALL	02B2
+jack	2749
+Jamo, Korean Hangul Compatibility	3130
+Jamo Combining Alphabet, Korean Hangul	1100
+Japanese Chess Symbols	2616
+Japanese Era Names	337B
+Japanese Hiragana	3040
+japanese incorporated	337F
+JAPANESE INDUSTRIAL STANDARD SYMBOL	3004
+Japanese Kanbun (Ideographic Annotation)	3190
+Japanese Katakana	30A0
+Japanese Katakana, Circled	32D0
+Japanese Katakana Variants, Halfwidth	FF61
+Japanese Katakana Words, Squared	3300
+japanese kome	203B
+JERUSALEM, CROSS OF	2629
+jis composition circle	20DD
+JIS X 0208, Based on	3040
+JIS X 0213 Compatibility Ideographs	FA30
+JOIN	2A1D
+JOIN, FULL OUTER	27D7
+JOIN, LEFT OUTER	27D5
+JOIN, RIGHT OUTER	27D6
+JOINER, COMBINING GRAPHEME	034F
+JOINER, WORD	2060
+JOINER, ZERO WIDTH	200D
+jot, apl	2218
+JUPITER	2643
+justification, character tabulation with	0089
+K, LATIN SMALL LETTER TURNED	029E
+kabusiki-gaisya	337F
+Kana Repeat Marks	3031
+Kanbun (Ideographic Annotation), Japanese	3190
+Kangxi Radicals	2F00
+Kannada	0C80
+Kannada Digits	0CE6
+Kannada Letters	0C85
+Katakana, Circled Japanese	32D0
+Katakana, Japanese	30A0
+KATAKANA DIGRAPH KOTO	30FF
+KATAKANA ITERATION MARK	30FD
+KATAKANA MIDDLE DOT	30FB
+Katakana Phonetic Extensions	31F0
+Katakana Variants, Halfwidth Japanese	FF61
+Katakana Words, Squared Japanese	3300
+KATAKANA-HIRAGANA DOUBLE HYPHEN	30A0
+KATAKANA-HIRAGANA PROLONGED SOUND MARK	30FC
+KATAKANA-HIRAGANA VOICED SOUND MARK	309B
+KATAKANA-HIRAGANA VOICED SOUND MARK, COMBINING	3099
+KELVIN SIGN	212A
+ket	27E7
+key, clear	2327
+key, command	2318
+key, delete to the left	232B
+key, delete to the right	2326
+key, enter	2324
+KEY, OPTION	2325
+KEY SYMBOL, ALTERNATIVE	2387
+KEY SYMBOL, DECIMAL SEPARATOR	2396
+KEYBOARD	2328
+Keyboard Symbols	2324
+Keyboard Symbols from ISO 9995-7	2380
+Keyboard Symbols from ISO 9995-7	2396
+Keyboard and UI Symbols	23CE
+KEYCAP, COMBINING ENCLOSING	20E3
+Khmer	1780
+Khmer Digits	17E0
+Khmer Lunar Date Symbols	19E0
+Khmer Symbols	19E0
+Khmer Symbols for Divination Lore	17F0
+KIP SIGN	20AD
+kome, japanese	203B
+Komi Letters, Cyrillic	0500
+Koranic Annotation Signs	06D6
+korean currency	20A9
+Korean Hangul Compatibility Jamo	3130
+Korean Hangul Elements, Circled	3260
+Korean Hangul Elements, Parenthesized	3200
+Korean Hangul Jamo Combining Alphabet	1100
+Korean Hangul Syllables, Circled	326E
+Korean Hangul Syllables, Parenthesized	320E
+Korean Hangul Syllables Area	AC00
+Korean Hangul Variants, Halfwidth	FFA0
+KOREAN STANDARD SYMBOL	327F
+KORONIS, COMBINING GREEK	0343
+KOTO, KATAKANA DIGRAPH	30FF
+KRA, LATIN SMALL LETTER	0138
+KS C 5601 (Korean Hangul), Based on	3130
+L, LATIN LETTER SMALL CAPITAL	029F
+L, MODIFIER LETTER SMALL	02E1
+L, REVERSED SANS-SERIF CAPITAL	2143
+L, SCRIPT CAPITAL	2112
+L, SCRIPT SMALL	2113
+L, TURNED SANS-SERIF CAPITAL	2142
+L B BAR SYMBOL	2114
+L WITH MIDDLE DOT, LATIN SMALL LETTER	0140
+L WITH MIDDLE TILDE, LATIN SMALL LETTER	026B
+lambda bar, latin letter	019B
+Lao	0E80
+Lao Digits	0ED0
+Lao Letters	0E81
+laotian currency	20AD
+laplace operator	2206
+laplace operator	2207
+laplace symbol	2112
+LARGE AND, SLOPING	2A58
+large bowtie	2A1D
+LARGE DOWN TACK	27D9
+LARGE LEFT TRIANGLE OPERATOR	2A1E
+LARGE OR, SLOPING	2A57
+LARGE TRIPLE VERTICAL BAR OPERATOR	2AFC
+LARGE UP TACK	27D8
+LARGER THAN	2AAB
+LARGER THAN OR EQUAL TO	2AAD
+LAST QUARTER MOON	263E
+LATERAL CLICK, LATIN LETTER	01C1
+Latin, Based on ISO 8859-2, -3, -4, -9 (European)	0100
+Latin, C0 Controls and Basic	0000
+Latin, European	0100
+Latin Abbreviations, Squared	3371
+LATIN CAPITAL LETTER N WITH LONG RIGHT LEG	0220
+Latin Capital Letters	0041
+LATIN CROSS	271D
+Latin Extended Additional	1E00
+Latin Extended-A	0100
+Latin Extended-B	0180
+Latin Extensions for Vietnamese	1EA0
+Latin Letters, Circled	24B6
+Latin Letters, Parenthesized	249C
+Latin Letters, Phonetic Modifiers Derived from	02B0
+Latin Ligatures	FB00
+Latin Small Letters	0061
+Latin Small Letters, Combining	0363
+Latin-1, ISO 8859-1 aka	00A0
+Latin-1 Supplement, C1 Controls and	0080
+lazy s	223D
+LAZY S, INVERTED	223E
+LEADER, ONE DOT	2024
+leader, three dot	2026
+LEADER, TWO DOT	2025
+leaf, aldus	2766
+leaf, ivy	2767
+LEFT-TO-RIGHT EMBEDDING	202A
+LEFT-TO-RIGHT MARK	200E
+LEFT-TO-RIGHT OVERRIDE	202D
+leftward tab	21E4
+LEG, LATIN CAPITAL LETTER N WITH LONG RIGHT	0220
+LENTICULAR BRACKET, LEFT BLACK	3010
+LENTICULAR BRACKET, LEFT WHITE	3016
+LEO	264C
+LESS-THAN, CIRCLED	29C0
+LESS-THAN, DOUBLE NESTED	2AA1
+LESS-THAN, DOUBLE-LINE EQUAL TO OR	2A99
+LESS-THAN, DOUBLE-LINE SLANTED EQUAL TO OR	2A9B
+LESS-THAN, GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE	2A8C
+LESS-THAN, GREATER-THAN ABOVE SIMILAR ABOVE	2A90
+LESS-THAN, GREATER-THAN BESIDE	2AA5
+LESS-THAN, GREATER-THAN OVERLAPPING	2AA4
+LESS-THAN, MUCH	226A
+LESS-THAN, SIMILAR OR	2A9D
+LESS-THAN, SLANTED EQUAL TO OR	2A95
+LESS-THAN, TRIPLE NESTED	2AF7
+LESS-THAN, VERY MUCH	22D8
+LESS-THAN ABOVE DOUBLE-LINE EQUAL, GREATER-THAN ABOVE	2A92
+LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN	2A8B
+LESS-THAN ABOVE EQUALS SIGN, SIMILAR ABOVE	2A9F
+LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL	2A91
+LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN	2A8F
+LESS-THAN ABOVE SIMILAR OR EQUAL	2A8D
+LESS-THAN ABOVE SLANTED EQUAL, GREATER-THAN ABOVE SLANTED EQUAL ABOVE	2A94
+LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL	2A93
+LESS-THAN AND NOT APPROXIMATE	2A89
+LESS-THAN AND SINGLE-LINE NOT EQUAL TO	2A87
+LESS-THAN CLOSED BY CURVE	2AA6
+LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL	2AA8
+LESS-THAN OR APPROXIMATE	2A85
+LESS-THAN OR EQUAL TO	2264
+LESS-THAN OR EQUAL TO, DOUBLE-LINE SLANTED	2AF9
+LESS-THAN OR SLANTED EQUAL TO	2A7D
+LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE	2A81
+LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT	2A83
+LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE	2A7F
+LESS-THAN SIGN	003C
+LESS-THAN WITH CIRCLE INSIDE	2A79
+LESS-THAN WITH DOT INSIDE, SLANTED EQUAL TO OR	2A97
+LESS-THAN WITH QUESTION MARK ABOVE	2A7B
+LESS-THAN WITH UNDERBAR, DOUBLE NESTED	2AA3
+Letterlike Symbols	2100
+level 2 lock	21EB
+level 3 lock	21EF
+level 3 select	21EE
+LEZH, LATIN SMALL LETTER	026E
+lf	000A
+LIABILITY SIGN, LIMITED	32CF
+LIBRA	264E
+ligature ae, latin small	00E6
+LIGATURE IJ, LATIN SMALL	0133
+LIGATURE LEFT HALF, COMBINING	FE20
+LIGATURE OE, LATIN SMALL	0153
+ligature tie	0361
+Ligatures, Armenian	FB13
+Ligatures, Latin	FB00
+LIGHTNING	2607
+LIMIT, APPROACHES THE	2250
+Limbu	1900
+Limbu Digits	1946
+LIMITED LIABILITY SIGN	32CF
+LINE, AEGEAN WORD SEPARATOR	10100
+line, beginning of	2310
+LINE, CENTRELINE LOW	FE4E
+LINE, COMBINING DOUBLE LOW	0333
+LINE, COMBINING LOW	0332
+LINE, DASHED LOW	FE4D
+LINE, DOUBLE LOW	2017
+LINE, DOUBLE VERTICAL	2016
+LINE, LOW	005F
+LINE, MODIFIER LETTER LOW VERTICAL	02CC
+LINE, MODIFIER LETTER VERTICAL	02C8
+line, new	21B5
+line, next	0085
+LINE, VERTICAL	007C
+LINE, WAVY	2307
+LINE, WAVY LOW	FE4F
+LINE ABOVE, COMBINING DOUBLE VERTICAL	030E
+LINE ABOVE, COMBINING VERTICAL	030D
+LINE BELOW, COMBINING DOUBLE VERTICAL	0348
+LINE BELOW, COMBINING VERTICAL	0329
+line down, partial	008B
+line feed	000A
+line feed	21B4
+line feed, reverse	008D
+LINE FEED, SYMBOL FOR	240A
+line marker	2319
+LINE OVERLAY, COMBINING LONG VERTICAL	20D2
+LINE OVERLAY, COMBINING SHORT VERTICAL	20D3
+LINE SEPARATOR	2028
+LINE SYMBOL, CENTRE	2104
+line tabulation set	008A
+line up, partial	008C
+LINE WITH MIDDLE DOT, VERTICAL	237F
+Linear B Ideograms	10080
+Linear B Syllabary	10000
+Lines For Terminal Graphics, Scan	23BA
+Lira, Italian	00A3
+LIRA SIGN	20A4
+liter	2113
+Livonian, Additions for	022A
+LOCATION SIGN, TELEPHONE	2706
+lock, caps	21EA
+lock, caps	21EC
+lock, group	21F0
+lock, level 2	21EB
+lock, level 3	21EF
+lock, numerics	21ED
+Logic Operators, Modal	27E0
+LOGICAL AND	2227
+LOGICAL AND, CURLY	22CF
+LOGICAL AND, INTERSECTION WITH	2A44
+LOGICAL AND, N-ARY	22C0
+LOGICAL AND OPERATOR, TWO	2A07
+Logical Ands and Ors	2A51
+LOGICAL OR	2228
+LOGICAL OR, CURLY	22CE
+LOGICAL OR, N-ARY	22C1
+LOGICAL OR, UNION WITH	2A45
+LOGICAL OR OPERATOR, TWO	2A08
+long	0304
+Long Arrows	27F5
+long cross	2020
+long dash	2015
+LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL	2AE6
+LONG HORIZONTAL STROKE, CONTAINS WITH	22FA
+LONG HORIZONTAL STROKE, ELEMENT OF WITH	22F2
+LONG LEFT TACK	27DE
+LONG RIGHT LEG, LATIN CAPITAL LETTER N WITH	0220
+LONG RIGHT TACK	27DD
+LONG S, LATIN SMALL LETTER	017F
+long slash overlay	0338
+LONG SOLIDUS OVERLAY, COMBINING	0338
+LONG STROKE OVERLAY, COMBINING	0336
+LONG VERTICAL LINE OVERLAY, COMBINING	20D2
+LORRAINE, CROSS OF	2628
+LOW ACUTE ACCENT, MODIFIER LETTER	02CF
+LOW ASTERISK	204E
+low double comma quotation mark	201E
+LOW DOUBLE PRIME QUOTATION MARK	301F
+LOW GRAVE ACCENT, MODIFIER LETTER	02CE
+LOW LINE	005F
+LOW LINE, CENTRELINE	FE4E
+LOW LINE, COMBINING	0332
+LOW LINE, COMBINING DOUBLE	0333
+LOW LINE, DASHED	FE4D
+LOW LINE, DOUBLE	2017
+LOW LINE, WAVY	FE4F
+LOW MACRON, MODIFIER LETTER	02CD
+low single comma quotation mark	201A
+Low Surrogates	DC00
+LOW VERTICAL LINE, MODIFIER LETTER	02CC
+LOW-9 QUOTATION MARK, DOUBLE	201E
+LOW-9 QUOTATION MARK, SINGLE	201A
+lower rank than	227A
+LOZENGE	25CA
+LOZENGE, BLACK	29EB
+LOZENGE, SQUARE	2311
+LOZENGE DIVIDED BY HORIZONTAL RULE	27E0
+lre	202A
+lrm	200E
+lro	202D
+M, COMBINING LATIN SMALL LETTER	036B
+M, LATIN CAPITAL LETTER TURNED	019C
+M, LATIN SMALL LETTER TURNED	026F
+M, SCRIPT CAPITAL	2133
+m-matrix	2133
+MACRON	00AF
+MACRON, COMBINING	0304
+MACRON, MODIFIER LETTER	02C9
+MACRON, MODIFIER LETTER LOW	02CD
+macron, spacing	00AF
+MACRON BELOW, COMBINING	0331
+Malayalam	0D00
+Malayalam Digits	0D66
+Malayalam Letters	0D05
+MALE SIGN	2642
+MALTESE CROSS	2720
+Manchu Letters, Mongolian	1873
+Map Markers	2690
+mapping, bijective	2916
+maps from	27FB
+maps from	2906
+maps to	27FC
+maps to	2905
+maps to	2907
+mark, german	2133
+marker, histogram	25AE
+Markers, Go	2686
+Markers, Map	2690
+mars	2642
+MASCULINE ORDINAL INDICATOR	00BA
+MASU MARK	303C
+MATERIALS, RECYCLING SYMBOL FOR GENERIC	267A
+Mathematical Brackets	27E6
+Mathematical Operators	2200
+Mathematical Operators, Supplemental	2A00
+MATHEMATICAL SPACE, MEDIUM	205F
+Mathematical Symbols, Double-Struck Italic	2145
+Mathematical Symbols-A, Miscellaneous	27C0
+Mathematical Symbols-B, Miscellaneous	2980
+MATRIX, HERMITIAN CONJUGATE	22B9
+MEASURED ANGLE	2221
+Measured Angles, Angles and	299B
+MEASURED BY	225E
+Medieval Superscript Letter Diacritics	0363
+medium, end of	0019
+MEDIUM, SYMBOL FOR END OF	2419
+MEDIUM MATHEMATICAL SPACE	205F
+MEDIUM SMALL SQUARE, BLACK	25FE
+MEDIUM SMALL SQUARE, WHITE	25FD
+MEDIUM SQUARE, BLACK	25FC
+MEDIUM SQUARE, WHITE	25FB
+MEMBER, CONTAINS AS	220B
+MEMBER, SMALL CONTAINS AS	220D
+MEMBER OF DOUBLE VERTICAL, LONG DASH FROM LEFT	2AE6
+MEMBERSHIP, Z NOTATION BAG	22FF
+MERCURY	263F
+merge	2A07
+message, privacy	009E
+message waiting	0095
+mho	2127
+MICRO SIGN	00B5
+mid space	2005
+MIDDLE DOT	00B7
+middle dot, greek	00B7
+MIDDLE DOT, KATAKANA	30FB
+MIDDLE DOT, LATIN SMALL LETTER L WITH	0140
+MIDDLE DOT, VERTICAL LINE WITH	237F
+MIDDLE TILDE, LATIN CAPITAL LETTER O WITH	019F
+MIDDLE TILDE, LATIN SMALL LETTER L WITH	026B
+MIDLINE HORIZONTAL ELLIPSIS	22EF
+midpoint	00B7
+MILL SIGN	20A5
+MILLE SIGN, PER	2030
+milreis	0024
+minim	264F
+minim (alternate glyph)	264D
+Minnan and Hakka, Chinese Bopomofo Extended for	31A0
+MINUS, CIRCLED	2296
+MINUS, DOT	2238
+MINUS, SET	2216
+MINUS, SQUARED	229F
+MINUS, SUBSCRIPT	208B
+MINUS, SUPERSCRIPT	207B
+MINUS SIGN	2212
+MINUS SIGN, COMMERCIAL	2052
+minus sign, hyphen or	002D
+MINUS SIGN, MODIFIER LETTER	02D7
+MINUS SIGN, UNION WITH	2A41
+MINUS SIGN BELOW, COMBINING	0320
+MINUS SIGN IN TRIANGLE	2A3A
+Minus Sign Operators, Plus and	2A22
+MINUS SIMILAR, SIMILAR	2A6C
+MINUS TILDE	2242
+MINUS-OR-PLUS SIGN	2213
+minutes	2032
+MINY	29FF
+Miscellaneous Mathematical Symbols-A	27C0
+Miscellaneous Mathematical Symbols-B	2980
+Miscellaneous Symbols	2600
+Miscellaneous Symbols and Arrows	2B00
+Miscellaneous Technical	2300
+MISRA, ARABIC SIGN	060F
+mmsp	205F
+Modal Logic Operators	27E0
+MODELS	22A7
+Modifier Letters, Spacing	02B0
+MODULO TWO SUM	2A0A
+Mongolian	1800
+MONGOLIAN COLON	1804
+MONGOLIAN COMMA	1802
+mongolian currency	20AE
+Mongolian Digits	1810
+Mongolian Extensions for Sanskrit and Tibetan	1880
+Mongolian Format Controls	180B
+MONGOLIAN FULL STOP	1803
+Mongolian Manchu Letters	1873
+Mongolian Sibe Letters	185D
+Mongolian Todo Letters	1843
+Monogram and Digram Symbols, Yijing	268C
+Monogram Symbol, Tai Xuan Jing	1D300
+MONOSTABLE SYMBOL	238D
+MONTH SIGN, TAMIL	0BF4
+Months, Enclosed CJK Letters and	3200
+Months, Telegraph Symbols for	32C0
+MOON, FIRST QUARTER	263D
+MOON, LAST QUARTER	263E
+most positive	223E
+MUCH GREATER-THAN	226B
+MUCH GREATER-THAN, VERY	22D9
+MUCH LESS-THAN	226A
+MUCH LESS-THAN, VERY	22D8
+MULTIMAP	22B8
+MULTIMAP, DOUBLE-ENDED	29DF
+MULTIMAP, LEFT	27DC
+MULTIPLICATION, MULTISET	228D
+Multiplication and Division Sign Operators	2A2F
+MULTIPLICATION SIGN	00D7
+MULTIPLICATION SIGN BELOW, SUBSET WITH	2AC1
+MULTIPLICATION SIGN BELOW, SUPERSET WITH	2AC2
+MULTIPLICATION X	2715
+MULTIPLICATION X, HEAVY	2716
+MULTISET	228C
+MULTISET MULTIPLICATION	228D
+MULTISET UNION	228E
+MUSIC FLAT SIGN	266D
+MUSIC NATURAL SIGN	266E
+MUSIC SHARP SIGN	266F
+Musical Symbols	2669
+mutton	2003
+mutton quad	2001
+mvs	180E
+Myanmar	1000
+Myanmar Digits	1040
+N, DOUBLE-STRUCK CAPITAL	2115
+N, LATIN LETTER SMALL CAPITAL	0274
+N WITH LONG RIGHT LEG, LATIN CAPITAL LETTER	0220
+N-ARY COPRODUCT	2210
+n-ary dijkstra choice	2AFF
+N-ARY INTERSECTION	22C2
+N-ARY LOGICAL AND	22C0
+N-ARY LOGICAL OR	22C1
+N-ary Operators	2A00
+N-ARY PRODUCT	220F
+N-ARY SUMMATION	2211
+N-ARY SUMMATION, DOUBLE-STRUCK	2140
+N-ARY UNION	22C3
+N-ARY WHITE VERTICAL BAR	2AFF
+NABLA	2207
+NAIRA SIGN	20A6
+NAND	22BC
+nang	0323
+NARROW NO-BREAK SPACE	202F
+nasal hook	0328
+NATIONAL DIGIT SHAPES	206E
+natural number	2115
+NATURAL SIGN, MUSIC	266E
+nbsp	0080
+necessarily satisfies	2AF1
+NEGATED WITH VERTICAL BAR, INFINITY	29DE
+negation	20D3
+NEGATION SLASH, DOES NOT DIVIDE WITH REVERSED	2AEE
+negative acknowledge	0015
+negative acknowledge, graphic for	237B
+NEGATIVE ACKNOWLEDGE, SYMBOL FOR	2415
+NEPTUNE	2646
+never (modal operator)	27E1
+never (modal operator), was	27E2
+never be (modal operator), will	27E3
+new line	21B5
+NEW SHEQEL SIGN	20AA
+NEWLINE, SYMBOL FOR	2424
+next line	0085
+NEXT PAGE	2398
+NIB, BLACK	2712
+nigerian currency	20A6
+nim-addition	2A27
+nnbsp	202F
+no break here	0083
+no break space, graphic for	237D
+NO-BREAK SPACE	00A0
+NO-BREAK SPACE, NARROW	202F
+NO-BREAK SPACE, ZERO WIDTH	FEFF
+NODE, ASCENDING	260A
+NODE, DESCENDING	260B
+NOMINAL DIGIT SHAPES	206F
+NON-BREAKING HYPHEN	2011
+non-breaking space	00A0
+NON-JOINER, ZERO WIDTH	200C
+non-theorem	22A3
+Noncharacters	FDD0
+Noncharacters	FFFE
+Noncharacters	1FFFE
+Noncharacters	2FFFE
+Noncharacters	3FFFE
+Noncharacters	4FFFE
+Noncharacters	5FFFE
+Noncharacters	6FFFE
+Noncharacters	7FFFE
+Noncharacters	8FFFE
+Noncharacters	9FFFE
+Noncharacters	AFFFE
+Noncharacters	BFFFE
+Noncharacters	CFFFE
+Noncharacters	DFFFE
+Noncharacters	EFFFE
+Noncharacters	FFFFE
+Noncharacters	10FFFE
+NONFORKING	2ADD
+NOR	22BD
+NORMAL SUBGROUP, CONTAINS AS	22B3
+NORMAL SUBGROUP OF	22B2
+not	223C
+Not a Character	FFFE
+Not a Character	FFFF
+NOT ALMOST EQUAL TO, PRECEDES ABOVE	2AB9
+NOT ALMOST EQUAL TO, SUCCEEDS ABOVE	2ABA
+NOT AN ELEMENT OF	2209
+NOT APPROXIMATE, GREATER-THAN AND	2A8A
+NOT APPROXIMATE, LESS-THAN AND	2A89
+NOT CHECK MARK	237B
+NOT DIVIDE WITH REVERSED NEGATION SLASH, DOES	2AEE
+NOT EQUAL TO	2260
+NOT EQUAL TO, GREATER-THAN AND SINGLE-LINE	2A88
+NOT EQUAL TO, LESS-THAN AND SINGLE-LINE	2A87
+NOT EQUAL TO, PRECEDES ABOVE	2AB5
+NOT EQUAL TO, PRECEDES ABOVE SINGLE-LINE	2AB1
+NOT EQUAL TO, SUBSET OF ABOVE	2ACB
+NOT EQUAL TO, SUCCEEDS ABOVE	2AB6
+NOT EQUAL TO, SUCCEEDS ABOVE SINGLE-LINE	2AB2
+NOT EQUAL TO, SUPERSET OF ABOVE	2ACC
+not independent	2ADC
+NOT SIGN	00AC
+NOT SIGN, DOUBLE STROKE	2AEC
+NOT SIGN, REVERSED	2310
+NOT SIGN, REVERSED DOUBLE STROKE	2AED
+NOT SIGN, TURNED	2319
+NOT TILDE ABOVE, COMBINING	034A
+not yield, does	22A3
+NOTE, EIGHTH	266A
+NOTE, QUARTER	2669
+NOTES, BEAMED EIGHTH	266B
+NOTES, BEAMED SIXTEENTH	266C
+null	0000
+NULL, SYMBOL FOR	2400
+null set	2205
+number, natural	2115
+Number Forms	2150
+Number Runes, Golden	16EE
+NUMBER SIGN	0023
+NUBMER SIGN, ARABIC	0600
+NUMBER SIGN, TAMIl	0BFA
+number symbol, real	210A
+NUMBER ZERO, IDEOGRAPHIC	3007
+Numbers, Aegean	10100
+Numbers, Circled	2460
+Numbers, Circled	3251
+Numbers, Circled	32B1
+Numbers, Circled Inverse	2776
+Numbers, Double Circled	24F5
+Numbers, Parenthesized	2474
+numbers, the set of complex	2102
+numbers, the set of rational	211A
+numbers, the set of real	211D
+Numbers, White On Black Circled	24EB
+Numbers Period	2488
+Numerals, Hangzhou-style	3021
+Numerals, Old Italic	10320
+Numerals, Roman	2160
+NUMERATOR ONE, FRACTION	215F
+numerics lock	21ED
+NUMERO SIGN	2116
+nut	2002
+O, COMBINING LATIN SMALL LETTER	0366
+o, latin capital letter barred	019F
+O, LATIN CAPITAL LETTER OPEN	0186
+O, LATIN SMALL LETTER BARRED	0275
+O, LATIN SMALL LETTER OPEN	0254
+O, SCRIPT SMALL	2134
+o bar	019F
+o bar	0275
+o e, latin small letter	0153
+O WITH MIDDLE TILDE, LATIN CAPITAL LETTER	019F
+obelisk	2020
+obelisk, double	2021
+OBJECT REPLACEMENT CHARACTER	FFFC
+OCR, Optical Character Recognition	2440
+octothorpe	0023
+OE, LATIN LETTER SMALL CAPITAL	0276
+OE, LATIN SMALL LIGATURE	0153
+Ogham	1680
+OGHAM SPACE MARK	1680
+OGONEK	02DB
+OGONEK, COMBINING	0328
+OHM SIGN	2126
+OHM SIGN, INVERTED	2127
+OI, LATIN SMALL LETTER	01A3
+OM, DEVANAGARI	0950
+OMEGA, LATIN SMALL LETTER CLOSED	0277
+ONE, FRACTION NUMERATOR	215F
+ONE, SUPERSCRIPT	00B9
+ONE DOT LEADER	2024
+ONE HALF, VULGAR FRACTION	00BD
+ONE QUARTER, VULGAR FRACTION	00BC
+OPEN BOX	2423
+OPEN BOX, SHOULDERED	237D
+OPEN E, LATIN CAPITAL LETTER	0190
+OPEN E, LATIN SMALL LETTER	025B
+OPEN E, LATIN SMALL LETTER CLOSED	029A
+OPEN E, LATIN SMALL LETTER CLOSED REVERSED	025E
+OPEN E, LATIN SMALL LETTER REVERSED	025C
+OPEN O, LATIN CAPITAL LETTER	0186
+OPEN O, LATIN SMALL LETTER	0254
+opening brace	007B
+opening curly bracket	007B
+opening parenthesis	0028
+opening square bracket	005B
+operating system command	009D
+OPERATOR, ASTERISK	2217
+OPERATOR, BULLET	2219
+OPERATOR, CIRCLED ASTERISK	229B
+OPERATOR, CIRCLED DOT	2299
+OPERATOR, CIRCLED RING	229A
+OPERATOR, DIAMOND	22C4
+OPERATOR, DOT	22C5
+OPERATOR, RING	2218
+OPERATOR, SQUARED DOT	22A1
+OPERATOR, STAR	22C6
+OPERATOR, TILDE	223C
+Operators, Database Theory	27D5
+Operators, Invisible	2063
+Operators, Mathematical	2200
+Operators, Modal Logic	27E0
+Operators, Multiplication and Division Sign	2A2F
+Operators, N-Ary	2A00
+Operators, Plus and Minus Sign	2A22
+Operators, Relational	2A66
+Operators, Specialized plus sign	29FA
+Operators, Supplemental Mathematical	2A00
+Operators, Vertical Line	2AEE
+OPPOSITION	260D
+Optical Character Recognition (OCR)	2440
+OPTION KEY	2325
+OR, CURLY LOGICAL	22CE
+OR, DOUBLE LOGICAL	2A54
+OR, LOGICAL	2228
+OR, N-ARY LOGICAL	22C1
+OR, SLOPING LARGE	2A57
+OR, TWO INTERSECTING LOGICAL	2A56
+OR, UNION WITH LOGICAL	2A45
+OR OPERATOR, TWO LOGICAL	2A08
+OR WITH DOT ABOVE, LOGICAL	2A52
+OR WITH DOUBLE OVERBAR, LOGICAL	2A62
+OR WITH DOUBLE UNDERBAR, LOGICAL	2A63
+OR WITH HORIZONTAL DASH, LOGICAL	2A5D
+OR WITH MIDDLE STEM, LOGICAL	2A5B
+order	2134
+ORDINAL INDICATOR, FEMININE	00AA
+ORDINAL INDICATOR, MASCULINE	00BA
+ordinarily satisfies	2AE2
+ORIGIN, DIMENSION	2331
+ORIGINAL OF	22B6
+ORIGINAL OF, SQUARE	2290
+Oriya	0B00
+Oriya Digits	0B66
+Oriya Letters	0B05
+Ornamental Angle Quotation Marks	276E
+Ornamental Brackets	2768
+Ornamental Brackets	2770
+Ornaments, Heart	2763
+Ornaments, Punctuation	275B
+ORNATE LEFT PARENTHESIS	FD3E
+ors, logical ands and	2A51
+ORTHODOX CROSS	2626
+orthogonal to	22A5
+Osmanya	10480
+Osmanya Digits	104A0
+OU, LATIN SMALL LETTER	0223
+OUNCE SIGN	2125
+OUTER JOIN, FULL	27D7
+OUTER JOIN, LEFT	27D5
+OUTER JOIN, RIGHT	27D6
+OUTLINE, SQUARE WITH CONTOURED	29E0
+OVER INFINITY, TIE	29DD
+OVER TOP SQUARE BRACKET, BOTTOM SQUARE BRACKET	23B6
+overbar, apl	00AF
+OVERLAPPING LESS-THAN, GREATER-THAN	2AA4
+OVERLAPPING LOGICAL AND, LOGICAL OR	2A59
+OVERLAY, COMBINING CLOCKWISE RING	20D9
+OVERLAY, COMBINING DOUBLE VERTICAL STROKE	20E6
+OVERLAY, COMBINING LEFTWARDS ARROW	20EA
+OVERLAY, COMBINING LONG SOLIDUS	0338
+OVERLAY, COMBINING LONG STROKE	0336
+OVERLAY, COMBINING LONG VERTICAL LINE	20D2
+OVERLAY, COMBINING REVERSE SOLIDUS	20E5
+OVERLAY, COMBINING RING	20D8
+OVERLAY, COMBINING SHORT SOLIDUS	0337
+OVERLAY, COMBINING SHORT STROKE	0335
+OVERLAY, COMBINING SHORT VERTICAL LINE	20D3
+OVERLAY, COMBINING TILDE	0334
+overlay, long slash	0338
+overlay, short slash	0337
+overline	00AF
+OVERLINE	203E
+OVERLINE, CENTRELINE	FE4A
+OVERLINE, COMBINING	0305
+OVERLINE, COMBINING DOUBLE	033F
+OVERLINE, DASHED	FE49
+OVERLINE, DOUBLE WAVY	FE4C
+OVERLINE, WAVY	FE4B
+OVERRIDE, LEFT-TO-RIGHT	202D
+OVERRIDE, RIGHT-TO-LEFT	202E
+overscore	0305
+overscore, spacing	203E
+Overscores and Underscores	FE49
+Overstruck Diacritics	0334
+oxia	0301
+P, DOUBLE-STRUCK CAPITAL	2119
+P, SCRIPT CAPITAL	2118
+PAGE, NEXT	2398
+PAGE, PREVIOUS	2397
+page down	21DF
+page up	21DE
+PALATALIZED HOOK BELOW, COMBINING	0321
+PAMUDPOD, HANUNOO SIGN	1734
+PAPER SYMBOL, PARTIALLY-RECYCLED	267D
+PAPER SYMBOL, RECYCLED	267C
+PARAGRAPH SEPARATOR	2029
+PARAGRAPH SEPARATOR, GEORGIAN	10FB
+paragraph separator, urdu	203B
+paragraph sign	00B6
+paragraph sign, european	00A7
+PARAGRAPH SIGN ORNAMENT, CURVED STEM	2761
+PARALLEL, CIRCLED	29B7
+PARALLEL, EQUALS SIGN AND SLANTED	29E3
+PARALLEL, IDENTICAL TO AND SLANTED	29E5
+PARALLEL TO	2225
+parallel to, identical and	2A68
+PARALLEL WITH HORIZONTAL STROKE	2AF2
+PARALLEL WITH TILDE ABOVE, EQUALS SIGN AND SLANTED	29E4
+PARALLEL WITH TILDE OPERATOR	2AF3
+PARALLELOGRAM, BLACK	25B0
+parenthesis, closing	0029
+PARENTHESIS, LEFT	0028
+parenthesis, opening	0028
+PARENTHESIS, ORNATE LEFT	FD3E
+PARENTHESIS, RIGHT	0029
+PARENTHESIS, SUBSCRIPT LEFT	208D
+PARENTHESIS, SUPERSCRIPT LEFT	207D
+Parenthesized Ideographs	3220
+Parenthesized Korean Hangul Elements	3200
+Parenthesized Korean Hangul Syllables	320E
+Parenthesized Latin Letters	249C
+Parenthesized Numbers	2474
+PART ALTERNATION MARK	303D
+PART INTEGRAL, FINITE	2A0D
+parted rule	00A6
+PARTIAL DIFFERENTIAL	2202
+partial function, z notation	21F8
+partial injection, z notation	2914
+partial line down	008B
+partial line up	008C
+partial relation, z notation	21F9
+partial surjection, z notation	2900
+PARTIALLY-RECYCLED PAPER SYMBOL	267D
+PARTNERSHIP SIGN	3250
+Parts, Summation Sign	23B2
+pdf	202C
+PEACE SYMBOL	262E
+PENCIL, UPPER RIGHT	2710
+Pencil Dingbats	270E
+PENNY SIGN, GERMAN	20B0
+per	2118
+PER MILLE SIGN	2030
+PER TEN THOUSAND SIGN	2031
+PERCENT SIGN	0025
+PERCENT SIGN, ARABIC	066A
+PERCUSSIVE, LATIN LETTER BIDENTAL	02AD
+PERCUSSIVE, LATIN LETTER BILABIAL	02AC
+period	002E
+PERISPOMENI, COMBINING GREEK	0342
+perpendicular	22A5
+PERPENDICULAR, CIRCLED	29B9
+PERPENDICULAR WITH S	2AE1
+Persian and Urdu, Eastern Arabic-Indic Digits for	06F0
+PERSPECTIVE	2306
+PESETA SIGN	20A7
+PESO SIGN	20B1
+PHARYNGEAL VOICED FRICATIVE, LATIN LETTER	0295
+PHI, LATIN SMALL LETTER	0278
+Philippine Scripts, Generic Punctuation For	1735
+Phonetic Alphabet, International	0250
+Phonetic Extensions	1D00
+Phonetic Extensions, Katakana	31F0
+Phonetic Extensions, non-IPA	1D00
+Phonetic Extensions for Ainu	31F0
+Phonetic Modifiers Derived from Latin Letters	02B0
+Phonetics and Symbols Area, CJK	2E00
+phonorecord sign	2117
+PI, DOUBLE-STRUCK CAPITAL	213F
+pi, mathematical constant	03C0
+Pictures for Control Codes, Graphic	2400
+Pieces, Bracket	239B
+Pieces, Bracket	23B0
+PILCROW SIGN	00B6
+PILCROW SIGN, REVERSED	204B
+Pinyin Diacritic-vowel Combinations	01CD
+pipe	01C0
+pipe, double	01C1
+pipe, double-barred	01C2
+PIPING, Z NOTATION SCHEMA	2A20
+PISCES	2653
+PITCHFORK	22D4
+PITCHFORK WITH TEE TOP	2ADA
+PLACE OF INTEREST SIGN	2318
+plaintiff	226C
+PLANCK CONSTANT	210E
+PLANCK CONSTANT OVER TWO PI	210F
+Planet Symbols	263F
+Playing Card Suits	2660
+PLUS, CIRCLED	2295
+PLUS, DOT	2214
+PLUS, DOUBLE	29FA
+PLUS, N-ARY UNION OPERATOR WITH	2A04
+PLUS, SQUARED	229E
+PLUS, TRIPLE	29FB
+Plus and Minus Sign Operators	2A22
+PLUS OPERATOR, N-ARY CIRCLED	2A01
+PLUS SIGN	002B
+PLUS SIGN, EQUALS SIGN ABOVE	2A71
+PLUS SIGN, MODIFIER LETTER	02D6
+PLUS SIGN, SUBSCRIPT	208A
+PLUS SIGN, SUPERSCRIPT	207A
+PLUS SIGN ABOVE EQUALS SIGN	2A72
+PLUS SIGN BELOW, COMBINING	031F
+PLUS SIGN BELOW, SUBSET WITH	2ABF
+PLUS SIGN BELOW, SUPERSET WITH	2AC0
+PLUS SIGN IN LEFT HALF CIRCLE	2A2D
+PLUS SIGN IN RIGHT HALF CIRCLE	2A2E
+PLUS SIGN IN TRIANGLE	2A39
+Plus Sign Operators, Specialized	29FA
+PLUS-MINUS SIGN	00B1
+PLUTO	2647
+POETIC VERSE SIGN, ARABIC	060E
+POINT OPERATOR, INTEGRAL AROUND A	2A15
+Pointers	25BA
+Points, Arabic	064B
+Points, Hebrew	05B0
+poison	2620
+Political Symbols, Religious and	2626
+POP DIRECTIONAL FORMATTING	202C
+POSITION INDICATOR	2316
+positive, most	223E
+positive difference, sum or	2A26
+positive difference or sum	2A24
+POSTAL MARK	3012
+POSTAL MARK, CIRCLED	3036
+POSTAL MARK FACE	3020
+pound sign	0023
+POUND SIGN	00A3
+pound sterling	00A3
+pounds	2114
+power set	2118
+PRECEDES	227A
+PRECEDES, DOUBLE	2ABB
+PRECEDES ABOVE ALMOST EQUAL TO	2AB7
+PRECEDES ABOVE EQUALS SIGN	2AB3
+PRECEDES ABOVE NOT ALMOST EQUAL TO	2AB9
+PRECEDES ABOVE NOT EQUAL TO	2AB5
+PRECEDES ABOVE SINGLE-LINE EQUALS SIGN	2AAF
+PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO	2AB1
+PRECEDES UNDER RELATION	22B0
+PRESCRIPTION TAKE	211E
+Presentation Forms, Alphabetic	FB00
+Presentation Forms, Hebrew	FB1D
+Presentation Forms-A, Arabic	FB50
+Presentation Forms-B, Arabic	FE70
+PREVIOUS PAGE	2397
+PRIME	2032
+PRIME, DOUBLE	2033
+PRIME, MODIFIER LETTER	02B9
+PRIME, MODIFIER LETTER DOUBLE	02BA
+PRIME, QUADRUPLE	2057
+PRIME, REVERSED	2035
+PRIME, REVERSED DOUBLE	2036
+PRIME, REVERSED TRIPLE	2037
+PRIME, TRIPLE	2034
+PRIME QUOTATION MARK, DOUBLE	301E
+PRIME QUOTATION MARK, LOW DOUBLE	301F
+PRIME QUOTATION MARK, REVERSED DOUBLE	301D
+PRINT SCREEN SYMBOL	2399
+privacy message	009E
+Private Use Area	E000
+Private Use Area-A, Supplementary	F0000
+Private Use Area-B, Supplementary	100000
+private use one	0091
+private use two	0092
+PRODUCT, CLOSED UNION WITH SERIFS AND SMASH	2A50
+product, direct	2299
+PRODUCT, INTERIOR	2A3C
+PRODUCT, LEFT SEMIDIRECT	22CB
+PRODUCT, N-ARY	220F
+PRODUCT, RIGHTHAND INTERIOR	2A3D
+PRODUCT, SHUFFLE	29E2
+PRODUCT, SMASH	2A33
+product, tensor	2297
+PRODUCT, VECTOR OR CROSS	2A2F
+PRODUCT, WREATH	2240
+PRODUCT WITH BOTTOM CLOSED, SEMIDIRECT	2A32
+PROFILE, ALL AROUND-	232E
+prohibition	20E0
+PROJECTION, Z NOTATION SCHEMA	2A21
+PROJECTIVE	2305
+PROOF, END OF	220E
+PROPERTY LINE	214A
+PROPORTION	2237
+PROPORTION, GEOMETRIC	223A
+PROPORTIONAL TO	221D
+proportional to, varies with	223C
+proves	22A2
+psili	0313
+published	2117
+pullback	27D3
+Punctuation, CJK Symbols and	3000
+Punctuation, General	2000
+Punctuation, Hanun�o-Specific	1734
+Punctuation, Katakana	30A0
+PUNCTUATION, PHILIPPINE DOUBLE	1736
+PUNCTUATION, PHILIPPINE SINGLE	1735
+Punctuation For Philippine Scripts, Generic	1735
+Punctuation For Vertical Text, Double	2047
+Punctuation Ornaments	275B
+PUNCTUATION SPACE	2008
+punt, irish	00A3
+purna viram	0964
+pushout	27D4
+Q, DOUBLE-STRUCK CAPITAL	211A
+Q, ROTATED CAPITAL	213A
+QAF, ARABIC LETTER DOTLESS	066F
+qed	220E
+QUAD, EM	2001
+QUAD, EN	2000
+quad, mutton	2001
+Quadrants	2596
+quadrature	25A1
+QUADRUPLE INTEGRAL OPERATOR	2A0C
+QUADRUPLE PRIME	2057
+quantic	226C
+QUARTER MOON, FIRST	263D
+QUARTER MOON, LAST	263E
+QUARTER NOTE	2669
+Quarters, Fractions	00BC
+QUATERNION INTEGRAL OPERATOR	2A16
+QUESTION EXCLAMATION MARK	2048
+QUESTION MARK	003F
+QUESTION MARK, ARABIC	061F
+QUESTION MARK, ARMENIAN	055E
+QUESTION MARK, DOUBLE	2047
+QUESTION MARK, ETHIOPIC	1367
+QUESTION MARK, EXCLAMATION	2049
+QUESTION MARK, GREEK	037E
+QUESTION MARK, INVERTED	00BF
+QUESTION MARK ABOVE, GREATER-THAN WITH	2A7C
+QUESTION MARK ABOVE, LESS-THAN WITH	2A7B
+QUESTIONED EQUAL TO	225F
+QUILL, LEFT SQUARE BRACKET WITH	2045
+Quine Corners	231C
+quotation dash	2015
+QUOTATION MARK	0022
+quotation mark, double comma	201D
+QUOTATION MARK, DOUBLE HIGH-REVERSED-9	201F
+QUOTATION MARK, DOUBLE LOW-9	201E
+QUOTATION MARK, DOUBLE PRIME	301E
+quotation mark, double reversed comma	201F
+quotation mark, double turned comma	201C
+QUOTATION MARK, LEFT DOUBLE	201C
+QUOTATION MARK, LEFT SINGLE	2018
+QUOTATION MARK, LEFT-POINTING DOUBLE ANGLE	00AB
+quotation mark, low double comma	201E
+QUOTATION MARK, LOW DOUBLE PRIME	301F
+quotation mark, low single comma	201A
+QUOTATION MARK, REVERSED DOUBLE PRIME	301D
+QUOTATION MARK, RIGHT DOUBLE	201D
+QUOTATION MARK, RIGHT SINGLE	2019
+QUOTATION MARK, RIGHT-POINTING DOUBLE ANGLE	00BB
+quotation mark, single comma	2019
+QUOTATION MARK, SINGLE HIGH-REVERSED-9	201B
+QUOTATION MARK, SINGLE LEFT-POINTING ANGLE	2039
+QUOTATION MARK, SINGLE LOW-9	201A
+quotation mark, single reversed comma	201B
+QUOTATION MARK, SINGLE RIGHT-POINTING ANGLE	203A
+quotation mark, single turned comma	2018
+Quotation Mark Ornaments	275B
+Quotation Marks, Ornamental Angle	276E
+quote, apl	0022
+R, BLACK-LETTER CAPITAL	211C
+R, COMBINING LATIN SMALL LETTER	036C
+R, DOUBLE-STRUCK CAPITAL	211D
+R, LATIN LETTER SMALL CAPITAL	0280
+R, LATIN LETTER SMALL CAPITAL INVERTED	0281
+R, LATIN SMALL LETTER TURNED	0279
+R, MODIFIER LETTER SMALL	02B3
+R, MODIFIER LETTER SMALL CAPITAL INVERTED	02B6
+R, MODIFIER LETTER SMALL TURNED	02B4
+R, SCRIPT CAPITAL	211B
+radial component	27DF
+radical sign	221A
+Radicals, Kangxi	2F00
+Radicals, Yi	A490
+Radicals Supplement, CJK	2E80
+RADIOACTIVE SIGN	2622
+RAIN DROPS, UMBRELLA WITH	2614
+rainy weather	2602
+RAMS HORN, LATIN SMALL LETTER	0264
+RANGE ANTIRESTRICTION, Z NOTATION	2A65
+RATIO	2236
+ratio, cross	211E
+rational numbers, the set of	211A
+real number symbol	210A
+real numbers, the set of	211D
+real part	211C
+recipe	211E
+record separator	001E
+RECORD SEPARATOR, SYMBOL FOR	241E
+RECORDER, TELEPHONE	2315
+RECORDING COPYRIGHT, SOUND	2117
+Rectangles	25AC
+RECTANGULAR PATH AROUND POLE, LINE INTEGRATION WITH	2A12
+RECYCLED PAPER SYMBOL	267C
+RECYCLING SYMBOL, BLACK UNIVERSAL	267B
+RECYCLING SYMBOL, UNIVERSAL	2672
+RECYCLING SYMBOL FOR GENERIC MATERIALS	267A
+Recycling Symbols	2672
+Recycling Symbols For Plastics	2673
+reduces to	22A6
+reducible	22A2
+REFERENCE MARK	203B
+registered trade mark sign	00AE
+RELATION, TRIPLE SOLIDUS BINARY	2AFB
+RELATION, TRIPLE VERTICAL BAR BINARY	2AF4
+relation, z notation finite	21FC
+relation, z notation partial	21F9
+RELATIONAL COMPOSITION, Z NOTATION	2A3E
+Relational Operators	2A66
+Relations	29E3
+Relations	2AF7
+Relations, Subset and superset	2ABD
+Religious and Political Symbols	2626
+Repeat Marks, Kana	3031
+REPLACEMENT CHARACTER	FFFD
+REPLACEMENT CHARACTER, OBJECT	FFFC
+resistance	2126
+RESPONSE	211F
+results in	22A8
+RETROFLEX CLICK, LATIN LETTER	01C3
+retroflex hook, latin small letter d	0256
+RETROFLEX HOOK BELOW, COMBINING	0322
+return, carriage	000D
+return, carriage	21B5
+RETURN, SYMBOL FOR CARRIAGE	240D
+RETURN SYMBOL	23CE
+reverse line feed	008D
+REVERSE SOLIDUS	005C
+REVERSE SOLIDUS, BIG	29F9
+REVERSE SOLIDUS, CIRCLED	29B8
+REVERSE SOLIDUS OPERATOR	29F5
+REVERSE SOLIDUS OVERLAY, COMBINING	20E5
+REVERSE SOLIDUS WITH HORIZONTAL STROKE	29F7
+reverse turnstile	22A3
+REVERSED, LATIN SMALL LETTER EZH	01B9
+REVERSED COMMA, MODIFIER LETTER	02BD
+REVERSED COMMA ABOVE, COMBINING	0314
+reversed comma quotation mark, double	201F
+reversed comma quotation mark, single	201B
+REVERSED DOUBLE PRIME	2036
+REVERSED DOUBLE PRIME QUOTATION MARK	301D
+REVERSED DOUBLE STROKE NOT SIGN	2AED
+REVERSED E, LATIN CAPITAL LETTER	018E
+REVERSED E, LATIN SMALL LETTER	0258
+reversed epsilon, latin small letter closed	025E
+REVERSED ESH, LATIN SMALL LETTER SQUAT	0285
+REVERSED ESH LOOP, LATIN LETTER	01AA
+reversed glottal stop, latin letter	0295
+REVERSED GLOTTAL STOP, MODIFIER LETTER	02C1
+REVERSED GLOTTAL STOP, MODIFIER LETTER SMALL	02E4
+REVERSED NEGATION SLASH, DOES NOT DIVIDE WITH	2AEE
+REVERSED NOT SIGN	2310
+REVERSED OPEN E, LATIN SMALL LETTER	025C
+REVERSED OPEN E, LATIN SMALL LETTER CLOSED	025E
+REVERSED PILCROW SIGN	204B
+REVERSED PRIME	2035
+REVERSED SANS-SERIF CAPITAL L	2143
+REVERSED SEMICOLON	204F
+reversed straight epsilon	220D
+REVERSED TILDE	223D
+REVERSED TILDE EQUALS	22CD
+REVERSED TRIPLE PRIME	2037
+RHOTIC HOOK, MODIFIER LETTER	02DE
+riemann integral	211B
+RIGHT ANGLE	221F
+RIGHT ANGLE WITH ARC	22BE
+RIGHT TRIANGLE	22BF
+RIGHT-TO-LEFT EMBEDDING	202B
+RIGHT-TO-LEFT MARK	200F
+RIGHT-TO-LEFT OVERRIDE	202E
+RIGHTHAND INTERIOR PRODUCT	2A3D
+RING, BENZENE	232C
+RING, MODIFIER LETTER CENTRED LEFT HALF	02D3
+RING, MODIFIER LETTER LEFT HALF	02BF
+RING ABOVE	02DA
+RING ABOVE, COMBINING	030A
+RING BELOW, COMBINING	0325
+RING BELOW, COMBINING LEFT HALF	031C
+RING BELOW, COMBINING RIGHT HALF	0339
+RING EQUAL TO	2257
+RING IN EQUAL TO	2256
+RING OPERATOR	2218
+RING OPERATOR, CIRCLED	229A
+RING OVERLAY, COMBINING	20D8
+RING OVERLAY, COMBINING CLOCKWISE	20D9
+RISING DIAGONAL SLASH, SQUARED	29C4
+RISING DOTS, MINUS SIGN WITH	2A2C
+RISING DOTS, TILDE OPERATOR WITH	2A6B
+rle	202B
+rlm	200F
+rlo	202E
+Roman Numerals	2160
+Romanian, Additions for	0218
+ROOT, CUBE	221B
+ROOT, FOURTH	221C
+ROOT, SQUARE	221A
+ROTATED CAPITAL Q	213A
+rotation	20D5
+rough breathing	0314
+RULE, LOZENGE DIVIDED BY HORIZONTAL	27E0
+rule, parted	00A6
+RULE-DELAYED	29F4
+Runes, Golden Number	16EE
+Runic	16A0
+RUNOUT, TOTAL	2330
+RUPEE MARK, BENGALI	09F2
+RUPEE SIGN	20A8
+RUPEE SIGN, BENGALI	09F3
+RUPEE SIGN, GUJARATI	0AF1
+RUPEE SIGN, TAMIL	0BF9
+Russian Alphabet, Basic	0410
+S, INVERTED LAZY	223E
+S, LATIN SMALL LETTER LONG	017F
+S, LATIN SMALL LETTER SHARP	00DF
+s, lazy	223D
+S, MODIFIER LETTER SMALL	02E2
+S, PERPENDICULAR WITH	2AE1
+S IN TRIANGLE	29CC
+SAFHA, ARABIC SIGN	0603
+SAGITTARIUS	2650
+SALTIRE	2613
+sam	070F
+SANAH, ARABIC SIGN	0601
+SANS-SERIF CAPITAL G, TURNED	2141
+SANS-SERIF CAPITAL L, REVERSED	2143
+SANS-SERIF CAPITAL L, TURNED	2142
+SANS-SERIF CAPITAL Y, TURNED	2144
+Sanskrit and Tibetan, Mongolian Extensions for	1880
+satisfies	22A8
+satisfies, necessarily	2AF1
+satisfies, ordinarily	2AE2
+SATURN	2644
+SCHEMA COMPOSITION, Z NOTATION	2A1F
+schema hiding, z notation	29F9
+SCHEMA PIPING, Z NOTATION	2A20
+SCHEMA PROJECTION, Z NOTATION	2A21
+SCHWA, LATIN CAPITAL LETTER	018F
+SCHWA, LATIN SMALL LETTER	0259
+Scissors Dingbats	2701
+SCORPIUS	264F
+SCREEN, COMBINING ENCLOSING	20E2
+script a, latin small letter	0251
+SCRIPT CAPITAL B	212C
+SCRIPT CAPITAL E	2130
+SCRIPT CAPITAL F	2131
+SCRIPT CAPITAL H	210B
+SCRIPT CAPITAL I	2110
+SCRIPT CAPITAL L	2112
+SCRIPT CAPITAL M	2133
+SCRIPT CAPITAL P	2118
+SCRIPT CAPITAL R	211B
+script f, latin small letter	0192
+SCRIPT G, LATIN SMALL LETTER	0261
+SCRIPT SMALL E	212F
+SCRIPT SMALL G	210A
+SCRIPT SMALL L	2113
+SCRIPT SMALL O	2134
+script v, latin capital letter	01B2
+script v, latin small letter	028B
+Scripts Area, General	0000
+scrolling	21F3
+SCRUPLE	2108
+SEAGULL BELOW, COMBINING	033C
+second transfinite cardinal (the continuum)	2136
+seconds	2033
+SECTION SIGN	00A7
+section sign, european	00B6
+SECTOR	2314
+SEGMENT	2313
+selected area, end of	0087
+selected area, start of	0086
+Selectors, Variation	FE00
+SEMICIRCULAR PATH AROUND POLE, LINE INTEGRATION WITH	2A13
+SEMICOLON	003B
+SEMICOLON, ARABIC	061B
+SEMICOLON, ETHIOPIC	1364
+SEMICOLON, REVERSED	204F
+SEMIDIRECT PRODUCT, LEFT	22CB
+SEMIDIRECT PRODUCT WITH BOTTOM CLOSED	2A32
+SEPARATOR DOT, AEGEAN WORD	10101
+SEPARATOR LINE, AEGEAN WORD 	10100
+SEPARATOR, ARABIC DECIMAL	066B
+SEPARATOR, ARABIC THOUSANDS	066C
+separator, decimal	002C
+separator, devanagari phrase	0964
+separator, file	001C
+SEPARATOR, GEORGIAN PARAGRAPH	10FB
+separator, group	001D
+SEPARATOR, INVISIBLE	2063
+SEPARATOR, LINE	2028
+SEPARATOR, PARAGRAPH	2029
+separator, record	001E
+SEPARATOR, SYMBOL FOR FILE	241C
+SEPARATOR, SYMBOL FOR GROUP	241D
+SEPARATOR, SYMBOL FOR RECORD	241E
+SEPARATOR, SYMBOL FOR UNIT	241F
+separator, unit	001F
+separator, urdu paragraph	203B
+SEPARATOR KEY SYMBOL, DECIMAL	2396
+sequence concatenation, z notation	2040
+sequence introducer, control	009B
+Serbian Cyrillic Letters, Croatian Digraphs Matching	01C4
+SERIFS, CLOSED INTERSECTION WITH	2A4D
+SERIFS, CLOSED UNION WITH	2A4C
+SERIFS AND SMASH PRODUCT, CLOSED UNION WITH	2A50
+SERIFS AT BOTTOM, TRIANGLE WITH	29CD
+SERVICE MARK	2120
+SESAME DOT	FE45
+SESAME DOT, WHITE	FE46
+SET, EMPTY	2205
+set, included in	2282
+set, includes in	2283
+set, null	2205
+set, power	2118
+SET MINUS	2216
+set of complex numbers, the	2102
+set of integers, the	2124
+set of rational numbers, the	211A
+set of real numbers, the	211D
+set transmit state	0093
+Sets, Empty	29B0
+sextile	2736
+Shade Characters	2591
+shamrock	2663
+Shapes, Geometric	25A0
+SHARP S, LATIN SMALL LETTER	00DF
+SHARP SIGN, MUSIC	266F
+Shavian	10450
+SHEQEL SIGN, NEW	20AA
+shift	21E7
+shift in	000F
+SHIFT IN, SYMBOL FOR	240F
+shift out	000E
+SHIFT OUT, SYMBOL FOR	240E
+shilling	002F
+SHOGI PIECE, BLACK	2617
+SHOGI PIECE, WHITE	2616
+short	0306
+SHORT DOWN TACK	2ADF
+SHORT DOWN TACK, SHORT UP TACK ABOVE	2AE9
+SHORT DOWN TACK WITH OVERBAR	2AE7
+SHORT I WITH TAIL, CYRILLIC CAPITAL LETTER	048A
+SHORT I WITH TAIL, CYRILLIC SMALL LETTER	048B
+SHORT LEFT TACK	2ADE
+short slash overlay	0337
+SHORT SOLIDUS OVERLAY, COMBINING	0337
+SHORT STROKE OVERLAY, COMBINING	0335
+SHORT UP TACK	2AE0
+SHORT UP TACK ABOVE SHORT DOWN TACK	2AE9
+SHORT UP TACK WITH UNDERBAR	2AE8
+SHORT VERTICAL LINE OVERLAY, COMBINING	20D3
+SHOULDERED OPEN BOX	237D
+SHUFFLE PRODUCT	29E2
+shy	00AD
+Sibe Letters, Mongolian	185D
+Sidelining Emphasis Marks	FE45
+SIMILAR, SIMILAR MINUS	2A6C
+SIMILAR ABOVE GREATER-THAN, LESS-THAN ABOVE	2A8F
+SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN	2AA0
+SIMILAR ABOVE LESS-THAN, GREATER-THAN ABOVE	2A90
+SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN	2A9F
+SIMILAR MINUS SIMILAR	2A6C
+SIMILAR OR EQUAL, GREATER-THAN ABOVE	2A8E
+SIMILAR OR EQUAL, LESS-THAN ABOVE	2A8D
+SIMILAR OR GREATER-THAN	2A9E
+SIMILAR OR LESS-THAN	2A9D
+similar to	223C
+SINE WAVE	223F
+single character introducer	009A
+single comma quotation mark	2019
+single comma quotation mark, low	201A
+single guillemet, left pointing	2039
+single guillemet, right pointing	203A
+SINGLE HIGH-REVERSED-9 QUOTATION MARK	201B
+SINGLE LEFT-POINTING ANGLE QUOTATION MARK	2039
+SINGLE LOW-9 QUOTATION MARK	201A
+SINGLE PUNCTUATION, PHILIPPINE	1735
+SINGLE QUOTATION MARK, LEFT	2018
+SINGLE QUOTATION MARK, RIGHT	2019
+single reversed comma quotation mark	201B
+SINGLE RIGHT-POINTING ANGLE QUOTATION MARK	203A
+single shift three	008F
+single shift two	008E
+single turned comma quotation mark	2018
+Sinhala	0D80
+SIX-PER-EM SPACE	2006
+SIXTEENTH NOTES, BEAMED	266C
+Sixths, Fractions	2159
+SKULL AND CROSSBONES	2620
+slash	002F
+SLASH, CIRCLED DIVISION	2298
+SLASH, DIVISION	2215
+SLASH, DOES NOT DIVIDE WITH REVERSED NEGATION	2AEE
+SLASH, FRACTION	2044
+SLASH, INTEGRAL AVERAGE WITH	2A0F
+SLASH, SQUARED FALLING DIAGONAL	29C5
+SLASH, SQUARED RISING DIAGONAL	29C4
+slash overlay, long	0338
+slash overlay, short	0337
+SLOPE	2333
+SLOPING LARGE AND	2A58
+SLOPING LARGE OR	2A57
+Slovenian and Croatian, Additions for	0200
+SMALL CAPITAL B, LATIN LETTER	0299
+SMALL CAPITAL G, LATIN LETTER	0262
+SMALL CAPITAL H, LATIN LETTER	029C
+SMALL CAPITAL I, LATIN LETTER	026A
+SMALL CAPITAL INVERTED R, LATIN LETTER	0281
+SMALL CAPITAL INVERTED R, MODIFIER LETTER	02B6
+SMALL CAPITAL L, LATIN LETTER	029F
+SMALL CAPITAL N, LATIN LETTER	0274
+SMALL CAPITAL OE, LATIN LETTER	0276
+SMALL CAPITAL R, LATIN LETTER	0280
+SMALL CAPITAL Y, LATIN LETTER	028F
+small circle, black	2022
+SMALL CIRCLE, SQUARED	29C7
+SMALL CIRCLE ABOVE, PLUS SIGN WITH	2A22
+SMALL CIRCLE TO THE RIGHT, CIRCLE WITH	29C2
+SMALL CONTAINS AS MEMBER	220D
+SMALL CONTAINS WITH OVERBAR	22FE
+SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE	22FC
+SMALL D, DOUBLE-STRUCK ITALIC	2146
+SMALL E, DOUBLE-STRUCK ITALIC	2147
+SMALL ELEMENT OF	220A
+SMALL ELEMENT OF WITH OVERBAR	22F7
+SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE	22F4
+Small Form Variants	FE50
+SMALL GAMMA, DOUBLE-STRUCK	213D
+SMALL I, DOUBLE-STRUCK ITALIC	2148
+SMALL J, DOUBLE-STRUCK ITALIC	2149
+Small Letters, Armenian	0561
+Small Letters, Combining Latin	0363
+Small Letters, Cyrillic	0430
+Small Letters, Georgian	10D0
+Small Letters, Greek	03B1
+Small Letters, Latin	0061
+SMALL SQUARE, BLACK MEDIUM	25FE
+SMALL SQUARE, WHITE MEDIUM	25FD
+SMALL VEE WITH UNDERBAR	2A61
+SMALLER THAN	2AAA
+SMALLER THAN OR EQUAL TO	2AAC
+SMASH PRODUCT	2A33
+SMASH PRODUCT, CLOSED UNION WITH SERIFS AND	2A50
+SMILE	2323
+SMILING FACE, BLACK	263B
+SMILING FACE, WHITE	263A
+smooth breathing	0313
+Snowflake Dingbats	2744
+Snowflakes, Stars, Asterisks and	2721
+SNOWMAN	2603
+snowy weather	2603
+SOFT HYPHEN	00AD
+SOFTWARE-FUNCTION SYMBOL	2394
+solid	2588
+SOLIDUS	002F
+solidus	2044
+SOLIDUS, BIG	29F8
+SOLIDUS, BIG REVERSE	29F9
+SOLIDUS, CIRCLED REVERSE	29B8
+SOLIDUS, REVERSE	005C
+SOLIDUS BINARY RELATION, TRIPLE	2AFB
+SOLIDUS OPERATOR, DOUBLE	2AFD
+SOLIDUS OPERATOR, REVERSE	29F5
+SOLIDUS OVERLAY, COMBINING LONG	0338
+SOLIDUS OVERLAY, COMBINING REVERSE	20E5
+SOLIDUS OVERLAY, COMBINING SHORT	0337
+SOLIDUS WITH HORIZONTAL STROKE, REVERSE	29F7
+SOLIDUS WITH OVERBAR	29F6
+SOUND RECORDING COPYRIGHT	2117
+SOURCE, INFORMATION	2139
+SPACE	0020
+SPACE, EM	2003
+SPACE, EN	2002
+SPACE, FIGURE	2007
+SPACE, FOUR-PER-EM	2005
+space, graphic for	2422
+space, graphic for	2423
+space, graphic for no break	237D
+SPACE, HAIR	200A
+SPACE, IDEOGRAPHIC	3000
+SPACE, MEDIUM MATHEMATICAL	205F
+space, mid	2005
+SPACE, NARROW NO-BREAK	202F
+SPACE, NO-BREAK	00A0
+SPACE, PUNCTUATION	2008
+SPACE, SIX-PER-EM	2006
+SPACE, SYMBOL FOR	2420
+space, thick	2004
+SPACE, THIN	2009
+SPACE, THREE-PER-EM	2004
+SPACE, ZERO WIDTH	200B
+SPACE, ZERO WIDTH NO-BREAK	FEFF
+SPACE MARK, OGHAM	1680
+Spaces	2000
+spacing acute	00B4
+spacing cedilla	00B8
+spacing circumflex	005E
+Spacing Clones of Diacritics	02D8
+spacing diaeresis	00A8
+spacing double underscore	2017
+spacing grave	0060
+spacing macron	00AF
+Spacing Modifier Letters	02B0
+spacing overscore	203E
+spacing underscore	005F
+spanish currency	20A7
+Special character extensions	23AE
+Specialized plus sign operators	29FA
+Specials	FFF0
+Specials Area, Compatibility and	F900
+SPHERICAL ANGLE	2222
+SPHERICAL ANGLE OPENING LEFT	29A0
+SPHERICAL ANGLE OPENING UP	29A1
+SPOT, Z NOTATION	2981
+SQUARE, BLACK MEDIUM	25FC
+SQUARE, BLACK MEDIUM SMALL	25FE
+SQUARE, COMBINING ENCLOSING	20DE
+SQUARE, VIEWDATA	2317
+SQUARE, WHITE MEDIUM	25FB
+SQUARE, WHITE MEDIUM SMALL	25FD
+SQUARE BELOW, COMBINING	033B
+square bracket, closing	005D
+SQUARE BRACKET, LEFT	005B
+SQUARE BRACKET, LEFT WHITE	301A
+square bracket, opening	005B
+SQUARE BRACKET, RIGHT	005D
+SQUARE BRACKET WITH QUILL, LEFT	2045
+SQUARE CAP	2293
+SQUARE CORPORATION	337F
+SQUARE CUP	2294
+SQUARE FOOT	23CD
+SQUARE IMAGE OF	228F
+SQUARE INTERSECTION, DOUBLE	2A4E
+SQUARE INTERSECTION OPERATOR, N-ARY	2A05
+SQUARE LEFT OPEN BOX OPERATOR	2ACD
+SQUARE LOZENGE	2311
+SQUARE ORIGINAL OF	2290
+SQUARE RIGHT OPEN BOX OPERATOR	2ACE
+SQUARE ROOT	221A
+Square Symbols	29C4
+SQUARE UNION, DOUBLE	2A4F
+SQUARE UNION OPERATOR, N-ARY	2A06
+SQUARE WITH CONTOURED OUTLINE	29E0
+SQUARE WITH LEFTWARDS TICK, WHITE	27E4
+SQUARE WITH RIGHTWARDS TICK, WHITE	27E5
+squared	00B2
+SQUARED DOT OPERATOR	22A1
+Squared Japanese Katakana Words	3300
+Squared Latin Abbreviations	3371
+SQUARED MINUS	229F
+SQUARED PLUS	229E
+SQUARED TIMES	22A0
+Squares	25A0
+SQUAT REVERSED ESH, LATIN SMALL LETTER	0285
+st. andrew's cross	2613
+star	002A
+STAR, ARABIC FIVE POINTED	066D
+STAR, BLACK	2605
+STAR AND CRESCENT	262A
+Star Dingbats	2726
+STAR EQUALS	225B
+STAR OF DAVID	2721
+STAR OPERATOR	22C6
+starburst	273A
+STARK, GLEICH	29E6
+Stars, Asterisks and Snowflakes	2721
+start of guarded area	0096
+start of heading	0001
+START OF HEADING, SYMBOL FOR	2401
+start of selected area	0086
+start of string	0098
+start of text	0002
+START OF TEXT, SYMBOL FOR	2402
+statement is true	22A8
+sterling, pound	00A3
+stile, apl	2223
+straight epsilon	220A
+straight epsilon, reversed	220D
+stress mark	0301
+STRETCHED C, LATIN LETTER	0297
+STRICTLY EQUIVALENT TO	2263
+string, device control	0090
+string, start of	0098
+string terminator	009C
+STROKE OVERLAY, COMBINING LONG	0336
+STROKE OVERLAY, COMBINING SHORT	0335
+SUBGROUP, CONTAINS AS NORMAL	22B3
+SUBGROUP OF, NORMAL	22B2
+subscript, iota	0345
+Subscript Digits	2080
+SUBSCRIPT EQUALS SIGN	208C
+SUBSCRIPT LEFT PARENTHESIS	208D
+SUBSCRIPT MINUS	208B
+SUBSCRIPT PLUS SIGN	208A
+SUBSCRIPT TWO, PLUS SIGN WITH	2A27
+Subscripts	2080
+SUBSET, DOUBLE	22D0
+Subset and Superset Relations	2ABD
+SUBSET OF	2282
+substitute	001A
+SUBSTITUTE, SYMBOL FOR	241A
+SUBSTITUTE FORM TWO, SYMBOL FOR	2426
+Subtending Marks, Arabic	0600
+subtraction, z notation bag	2A41
+SUCCEEDS	227B
+SUCCEEDS, DOUBLE	2ABC
+SUCCEEDS ABOVE ALMOST EQUAL TO	2AB8
+SUCCEEDS ABOVE EQUALS SIGN	2AB4
+SUCCEEDS ABOVE NOT ALMOST EQUAL TO	2ABA
+SUCCEEDS ABOVE NOT EQUAL TO	2AB6
+SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN	2AB0
+SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO	2AB2
+SUCCEEDS UNDER RELATION	22B1
+such that	220B
+such that	2223
+Suits, Playing Card	2660
+sum, direct	2295
+SUM, MODULO TWO	2A0A
+sum, positive difference or	2A24
+sum or positive difference	2A26
+SUMMATION, DOUBLE-STRUCK N-ARY	2140
+SUMMATION, N-ARY	2211
+SUMMATION BOTTOM	23B3
+Summation Sign Parts	23B2
+SUMMATION TOP	23B2
+Summations and Integrals	2A0A
+SUN	2609
+SUN WITH RAYS, BLACK	2600
+SUPERIMPOSED X, CIRCLE WITH	29BB
+SUPERSCRIPT ALEF, ARABIC LETTER	0670
+Superscript Digits	2070
+SUPERSCRIPT EQUALS SIGN	207C
+SUPERSCRIPT LATIN SMALL LETTER I	2071
+SUPERSCRIPT LEFT PARENTHESIS	207D
+Superscript Letter Diacritics, Medieval	0363
+SUPERSCRIPT MINUS	207B
+SUPERSCRIPT ONE	00B9
+SUPERSCRIPT PLUS SIGN	207A
+SUPERSCRIPT THREE	00B3
+SUPERSCRIPT TWO	00B2
+SUPERSCRIPT ZERO	2070
+Superscripts	2070
+Superscripts and Subscripts	2070
+SUPERSET, DOUBLE	22D1
+SUPERSET OF	2283
+Superset Relations, Subset and	2ABD
+Supplemental Arrows-A	27F0
+Supplemental Arrows-B	2900
+Supplemental Mathematical Operators	2A00
+Supplementary, Cyrillic	0500
+Supplementary Private Use Area-A	F0000
+Supplementary Private Use Area-B	100000
+SURFACE INTEGRAL	222F
+surjection, z notation finite	2901
+surjection, z notation partial	2900
+surjective injection, z notation	2917
+surjective injection, z notation finite	2918
+Surrogates, High	D800
+Surrogates, Low	DC00
+Surrogates Area	D800
+swedish grave accent	02DF
+SWUNG DASH	2053
+Syllabics, Unified Canadian Aboriginal	1400
+Syllables, Yi	A000
+Syllables Area, Korean Hangul	AC00
+Symbol Variants, Fullwidth	FFE0
+Symbols, Bowtie	29D1
+Symbols, Circle	29B5
+Symbols, Combining Diacritical Marks for	20D0
+Symbols, Dentistry Notation	23BE
+Symbols, Double-Struck Italic Mathematical	2145
+Symbols, Error Bar	29EE
+Symbols, Greek	03D0
+Symbols, Japanese Chess	2616
+Symbols, Letterlike	2100
+Symbols, Miscellaneous	2600
+Symbols, Recycling	2672
+Symbols, Square	29C4
+Symbols, Triangle	29CA
+Symbols and Arrows, Miscellaneous	2B00
+Symbols and Punctuation, CJK	3000
+Symbols Area	2000
+Symbols Area, CJK Phonetics and	2E00
+Symbols for Control Codes, Graphic	2400
+Symbols For Plastics, Recycling	2673
+Symbols-A, Miscellaneous Mathematical	27C0
+Symbols-B, Miscellaneous Mathematical	2980
+symmetric difference	2238
+symmetric difference	2296
+SYMMETRIC SWAPPING, ACTIVATE	206B
+SYMMETRIC SWAPPING, INHIBIT	206A
+SYMMETRY	232F
+synchronous idle	0016
+SYNCHRONOUS IDLE, SYMBOL FOR	2416
+Syriac	0700
+SYRIAC ABBREVIATION MARK	070F
+SYRIAC CROSS, EAST	2671
+SYRIAC CROSS, WEST	2670
+Syriac Format Control	070F
+T, COMBINING LATIN SMALL LETTER	036D
+T, LATIN SMALL LETTER TURNED	0287
+tab	0009
+tab, leftward	21E4
+tab, rightward	21E5
+tab, symbol for	2409
+tab with shift tab	21B9
+tabulation, horizontal	0009
+TABULATION, SYMBOL FOR HORIZONTAL	2409
+TABULATION, SYMBOL FOR VERTICAL	240B
+tabulation, vertical	000B
+tabulation set, character	0088
+tabulation set, line	008A
+tabulation with justification, character	0089
+TACK, LEFT	22A3
+TACK, MODIFIER LETTER UP	02D4
+TACK, RIGHT	22A2
+TACK, UP	22A5
+TACK BELOW, COMBINING LEFT	0318
+TACK BELOW, COMBINING UP	031D
+Tacks and Turnstiles	27D8
+Tacks and Turnstiles	2ADE
+Tagalog	1700
+TAGALOG SIGN VIRAMA	1714
+Tagbanwa	1760
+Tai Le	1950
+Tai Xuan Jing Symbols	1D300
+TAIL FRAGMENT, ARABIC	FE73
+Tails, Fish	297C
+tainome (japanese, a kind of bullet)	25C9
+TAKE, PRESCRIPTION	211E
+Tamil	0B80
+Tamil Digits	0BE7
+Tamil Letters	0B85
+TAMIL RUPEE SIGN	0BF9
+TAMIL NUMBER SIGN	0BFA
+Tamil Symbols	0BF3
+TAPE DRIVE	2707
+TAPER, CONICAL	2332
+TAURUS	2649
+tautological equivalent	29E6
+tautology	22A8
+tea	2615
+Technical, Miscellaneous	2300
+TEE TOP, PITCHFORK WITH	2ADA
+Telegraph Symbols for Days	33E0
+Telegraph Symbols for Hours	3358
+Telegraph Symbols for Months	32C0
+TELEPHONE, BLACK	260E
+TELEPHONE LOCATION SIGN	2706
+TELEPHONE RECORDER	2315
+TELEPHONE SIGN	2121
+Telugu	0C00
+Telugu Digits	0C66
+Telugu Letters	0C05
+TEN THOUSAND SIGN, PER	2031
+tensor	20E1
+tensor product	2297
+Terminal graphic characters	23B7
+Terminal Graphic Characters	2596
+Terminal Graphics, Scan Lines For	23BA
+terminator, string	009C
+Tetragram Symbols, Tai Xuan Jing	1D306
+text, end of	0003
+text, start of	0002
+TEXT, SYMBOL FOR END OF	2403
+TEXT, SYMBOL FOR START OF	2402
+Thaana	0780
+Thai	0E00
+THAI CURRENCY SYMBOL BAHT	0E3F
+Thai Digits	0E50
+Thai Letters	0E01
+THERE EXISTS	2203
+THEREFORE	2234
+THERMODYNAMIC	29E7
+thick space	2004
+THIN SPACE	2009
+third derivative	20DB
+third transfinite cardinal (functions of a real variable)	2137
+Thirds, Fractions	2153
+THORN, LATIN CAPITAL LETTER	00DE
+THORN, LATIN SMALL LETTER	00FE
+THOUSANDS SEPARATOR, ARABIC	066C
+THOUSANDS SIGN, CYRILLIC	0482
+THREE, SUPERSCRIPT	00B3
+three dot leader	2026
+THREE DOTS ABOVE, COMBINING	20DB
+THREE QUARTERS, VULGAR FRACTION	00BE
+THREE-PER-EM SPACE	2004
+THUNDERSTORM	2608
+Tibetan	0F00
+Tibetan, Mongolian Extensions for Sanskrit and	1880
+Tibetan Digits	0F20
+Tibetan Letters	0F40
+TICK, WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS	27E2
+TICK, WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS	27E3
+TICK, WHITE SQUARE WITH LEFTWARDS	27E4
+TICK, WHITE SQUARE WITH RIGHTWARDS	27E5
+TIE, CHARACTER	2040
+tie, ligature	0361
+TIE OVER INFINITY	29DD
+TILDE	007E
+tilde, apl	223C
+TILDE, COMBINING	0303
+TILDE, COMBINING DOUBLE	0360
+TILDE, COMBINING VERTICAL	033E
+TILDE, MINUS	2242
+TILDE, REVERSED	223D
+TILDE, SMALL	02DC
+TILDE, TRIPLE	224B
+TILDE ABOVE, COMBINING NOT	034A
+TILDE BELOW, COMBINING	0330
+TILDE EQUALS, REVERSED	22CD
+TILDE LEFT HALF, COMBINING DOUBLE	FE22
+TILDE OPERATOR	223C
+TILDE OPERATOR, EQUALS SIGN ABOVE	2A73
+TILDE OPERATOR, PARALLEL WITH	2AF3
+TILDE OPERATOR, SUBSET OF ABOVE	2AC7
+TILDE OPERATOR, SUPERSET OF ABOVE	2AC8
+TILDE OPERATOR WITH DOT ABOVE	2A6A
+TILDE OPERATOR WITH RISING DOTS	2A6B
+TILDE OVERLAY, COMBINING	0334
+TIMES, CIRCLED	2297
+TIMES, DIVISION	22C7
+TIMES, INVISIBLE	2062
+TIMES, SQUARED	22A0
+TIMES OPERATOR, N-ARY	2A09
+TIMES OPERATOR, N-ARY CIRCLED	2A02
+TIMES SIGN, INTEGRAL WITH	2A18
+TIMES WITH LEFT HALF BLACK	29D4
+TIMES WITH RIGHT HALF BLACK	29D5
+TINY	29FE
+TIRONIAN SIGN ET	204A
+TIS 620-2529 (Thai), Based on	0E01
+Todo Letters, Mongolian	1843
+Tone Bar Letters	02E5
+TONE FIVE, LATIN SMALL LETTER	01BD
+TONE MARK, COMBINING ACUTE	0341
+TONE MARK, COMBINING GRAVE	0340
+Tone Marks, Ideographic	302A
+Tone Marks, Vietnamese	0340
+TONE SIX, LATIN SMALL LETTER	0185
+TONE TWO, LATIN SMALL LETTER	01A8
+tonos	0301
+TONOS, COMBINING GREEK DIALYTIKA	0344
+TOP HALF INTEGRAL	2320
+TOP LEFT CORNER	231C
+TOP LEFT CROP	230F
+TORTOISE SHELL BRACKET, LEFT	3014
+TORTOISE SHELL BRACKET, LEFT WHITE	3018
+TOTAL RUNOUT	2330
+TRADE MARK SIGN	2122
+trade mark sign, registered	00AE
+transfinite cardinal, fourth	2138
+transfinite cardinal (countable), first	2135
+transfinite cardinal (functions of a real variable), third	2137
+transfinite cardinal (the continuum), second	2136
+transmission, end of	0004
+transmission, graphic for end of	2301
+TRANSMISSION, SYMBOL FOR END OF	2404
+transmission block, end of	0017
+TRANSMISSION BLOCK, SYMBOL FOR END OF	2417
+transmit state, set	0093
+TRANSVERSAL INTERSECTION	2ADB
+TRIANGLE, COMBINING ENCLOSING UPWARD POINTING	20E4
+TRIANGLE, LOWER LEFT	25FA
+TRIANGLE, LOWER RIGHT	25FF
+TRIANGLE, MINUS SIGN IN	2A3A
+TRIANGLE, MULTIPLICATION SIGN IN	2A3B
+TRIANGLE, PLUS SIGN IN	2A39
+TRIANGLE, PLUS SIGN WITH BLACK	2A28
+TRIANGLE, RIGHT	22BF
+TRIANGLE, UPPER LEFT	25F8
+TRIANGLE, UPPER RIGHT	25F9
+TRIANGLE, VERTICAL BAR BESIDE RIGHT	29D0
+TRIANGLE OPERATOR, LARGE LEFT	2A1E
+Triangle symbols	29CA
+TRIANGLE WITH LEFT HALF BLACK, DOWN-POINTING	29E8
+TRIANGLE WITH RIGHT HALF BLACK, DOWN-POINTING	29E9
+Triangles	25B2
+TRIANGULAR BULLET	2023
+TRIANGULAR COLON, MODIFIER LETTER	02D0
+TRIANGULAR COLON, MODIFIER LETTER HALF	02D1
+Trigram Symbols, Yijing	2630
+trine	25B3
+TRIPLE COLON OPERATOR	2AF6
+TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE	2A68
+TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE	2A69
+TRIPLE INTEGRAL	222D
+TRIPLE NESTED GREATER-THAN	2AF8
+TRIPLE NESTED LESS-THAN	2AF7
+TRIPLE PLUS	29FB
+TRIPLE PRIME	2034
+TRIPLE PRIME, REVERSED	2037
+TRIPLE RIGHT TURNSTILE, VERTICAL BAR	2AE2
+TRIPLE SOLIDUS BINARY RELATION	2AFB
+TRIPLE TILDE	224B
+TRIPLE UNDERDOT, COMBINING	20E8
+TRIPLE VERTICAL BAR BINARY RELATION	2AF4
+TRIPLE VERTICAL BAR DELIMITER	2980
+TRIPLE VERTICAL BAR OPERATOR, LARGE	2AFC
+TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE	2AF5
+TRIPLE VERTICAL STROKE, TRIPLE HORIZONTAL BAR WITH	2A69
+TRUE	22A8
+TUGRIK SIGN	20AE
+turbofan	274B
+turkish currency	20A4
+TURNED A, LATIN SMALL LETTER	0250
+TURNED ALPHA, LATIN SMALL LETTER	0252
+TURNED AMPERSAND	214B
+TURNED ANGLE	29A2
+TURNED CAPITAL F	2132
+TURNED COMMA, MODIFIER LETTER	02BB
+TURNED COMMA ABOVE, COMBINING	0312
+turned comma quotation mark, double	201C
+turned comma quotation mark, single	2018
+TURNED DELTA, LATIN SMALL LETTER	018D
+turned e, latin capital letter	018E
+TURNED E, LATIN SMALL LETTER	01DD
+TURNED GREEK SMALL LETTER IOTA	2129
+TURNED H, LATIN SMALL LETTER	0265
+TURNED K, LATIN SMALL LETTER	029E
+TURNED M, LATIN CAPITAL LETTER	019C
+TURNED M, LATIN SMALL LETTER	026F
+TURNED NOT SIGN	2319
+turned question mark	00BF
+TURNED R, LATIN SMALL LETTER	0279
+TURNED R, MODIFIER LETTER SMALL	02B4
+TURNED SANS-SERIF CAPITAL G	2141
+TURNED SANS-SERIF CAPITAL L	2142
+TURNED SANS-SERIF CAPITAL Y	2144
+TURNED T, LATIN SMALL LETTER	0287
+TURNED V, LATIN SMALL LETTER	028C
+TURNED W, LATIN SMALL LETTER	028D
+TURNED Y, LATIN SMALL LETTER	028E
+turnstile	22A2
+turnstile, reverse	22A3
+Turnstiles, Tacks and	27D8
+Turnstiles, Tacks and	2ADE
+TWO, SUPERSCRIPT	00B2
+TWO DOT LEADER	2025
+TWO-HEADED ARROW FROM BAR, RIGHTWARDS	2905
+TWO-HEADED ARROW WITH TAIL, RIGHTWARDS	2916
+TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE, RIGHTWARDS	2917
+TYPE COLON, Z NOTATION	2982
+U, COMBINING LATIN SMALL LETTER	0367
+Ugaritic	10380
+UMBRELLA	2602
+UMBRELLA WITH RAIN DROPS	2614
+umlaut	0308
+UNASPIRATED, MODIFIER LETTER	02ED
+UNDERDOT, COMBINING TRIPLE	20E8
+underline	0332
+underline, double	0333
+UNDERLINE SYMBOL, CONTINUOUS	2381
+UNDERLINE SYMBOL, DISCONTINUOUS	2382
+underscore	0332
+underscore, double	0333
+underscore, spacing	005F
+underscore, spacing double	2017
+Underscores, Overscores and	FE49
+UNDERTIE	203F
+UNDERTIE, INVERTED	2054
+UNDO SYMBOL	238C
+undoable delete	2425
+UNION	222A
+UNION, DOUBLE	22D3
+UNION, DOUBLE SQUARE	2A4F
+UNION, INTEGRAL WITH	2A1A
+UNION, INTERSECTION ABOVE	2A47
+UNION, INTERSECTION ABOVE BAR ABOVE	2A49
+UNION, MULTISET	228E
+UNION, N-ARY	22C3
+UNION, UNION BESIDE AND JOINED WITH	2A4A
+UNION ABOVE BAR ABOVE INTERSECTION	2A48
+UNION ABOVE INTERSECTION	2A46
+UNION BESIDE AND JOINED WITH UNION	2A4A
+UNION OPERATOR, N-ARY SQUARE	2A06
+UNION OPERATOR WITH DOT, N-ARY	2A03
+UNION OPERATOR WITH PLUS, N-ARY	2A04
+UNION WITH LOGICAL OR	2A45
+UNION WITH MINUS SIGN	2A41
+UNION WITH OVERBAR	2A42
+UNION WITH SERIFS, CLOSED	2A4C
+UNION WITH SERIFS AND SMASH PRODUCT, CLOSED	2A50
+Unions, Intersections and	2A40
+unique element	2129
+unit separator	001F
+UNIT SEPARATOR, SYMBOL FOR	241F
+UNIVERSAL RECYCLING SYMBOL	2672
+UNIVERSAL RECYCLING SYMBOL, BLACK	267B
+up, page	21DE
+UP ARROWHEAD	2303
+UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS	2324
+UP RIGHT DIAGONAL ELLIPSIS	22F0
+UP TACK	22A5
+UP TACK, MODIFIER LETTER	02D4
+UP TACK BELOW, COMBINING	031D
+UPA Modifiers	02EF
+UPPER BLADE SCISSORS	2701
+UPPER RIGHT PENCIL	2710
+UPSILON, LATIN CAPITAL LETTER	01B1
+UPSILON, LATIN SMALL LETTER	028A
+upstile, apl	2308
+UPWARDS ARROW BELOW, COMBINING	034E
+URANUS	2645
+Urdu, Eastern Arabic-Indic Digits for Persian and	06F0
+urdu paragraph separator	203B
+V, COMBINING LATIN SMALL LETTER	036E
+v, latin capital letter script	01B2
+v, latin small letter script	028B
+V, LATIN SMALL LETTER TURNED	028C
+V WITH HOOK, LATIN CAPITAL LETTER	01B2
+valentine	2665
+valid	22A8
+varia	0300
+Variation Selectors	FE00
+Variation Selectors Supplement	E0100
+varies with (proportional to)	223C
+vector	20D0
+vector	20D6
+VECTOR OR CROSS PRODUCT	2A2F
+vector pointing into page	2295
+vector pointing into page	2297
+vector pointing out of page	2299
+vee	2228
+vee above	030C
+VEE WITH UNDERBAR, SMALL	2A61
+venus	2640
+VERSICLE	2123
+VERTICAL, LONG DASH FROM LEFT MEMBER OF DOUBLE	2AE6
+vertical bar	007C
+vertical bar, broken	00A6
+VERTICAL BAR, CIRCLED	29B6
+VERTICAL BAR, N-ARY WHITE	2AFF
+VERTICAL BAR, WHITE	2AFE
+VERTICAL BAR BINARY RELATION, TRIPLE	2AF4
+VERTICAL BAR DELIMITER, TRIPLE	2980
+Vertical Bar Dingbats	2758
+VERTICAL BAR OPERATOR, LARGE TRIPLE	2AFC
+VERTICAL BAR WITH HORIZONTAL STROKE, TRIPLE	2AF5
+vertical bowtie	29D6
+VERTICAL BOX LINE, LEFT	23B8
+VERTICAL BOX LINE, RIGHT	23B9
+Vertical brackets	23B4
+VERTICAL ELLIPSIS	22EE
+VERTICAL IDEOGRAPHIC ITERATION MARK	303B
+VERTICAL KANA REPEAT MARK	3031
+VERTICAL LINE	007C
+VERTICAL LINE, DOUBLE	2016
+VERTICAL LINE, MODIFIER LETTER	02C8
+VERTICAL LINE, MODIFIER LETTER LOW	02CC
+VERTICAL LINE ABOVE, COMBINING	030D
+VERTICAL LINE ABOVE, COMBINING DOUBLE	030E
+VERTICAL LINE BELOW, COMBINING	0329
+VERTICAL LINE BELOW, COMBINING DOUBLE	0348
+VERTICAL LINE EXTENSION	23D0
+Vertical Line Operators	2AEE
+VERTICAL LINE OVERLAY, COMBINING LONG	20D2
+VERTICAL LINE OVERLAY, COMBINING SHORT	20D3
+VERTICAL LINE WITH CIRCLE ABOVE	2AEF
+VERTICAL LINE WITH CIRCLE BELOW	2AF0
+VERTICAL LINE WITH MIDDLE DOT	237F
+VERTICAL STROKE OVERLAY, COMBINING DOUBLE	20E6
+vertical tabulation	000B
+VERTICAL TABULATION, SYMBOL FOR	240B
+Vertical Text, Double Punctuation For	2047
+VERTICAL TILDE, COMBINING	033E
+Vertical Variants, Glyphs for	FE30
+VERTICAL ZIGZAG LINE	299A
+VERY MUCH GREATER-THAN	22D9
+VERY MUCH LESS-THAN	22D8
+VICTORY HAND	270C
+Vietnamese, Latin Extensions for	1EA0
+vietnamese currency	20AB
+Vietnamese Tone Marks	0340
+VIEWDATA SQUARE	2317
+vinculum	0305
+viram, deergh	0965
+viram, purna	0964
+VIRAMA, BENGALI SIGN	09CD
+VIRAMA, DEVANAGARI SIGN	094D
+VIRAMA, GUJARATI SIGN	0ACD
+VIRAMA, GURMUKHI SIGN	0A4D
+VIRAMA, KANNADA SIGN	0CCD
+VIRAMA, MALAYALAM SIGN	0D4D
+VIRAMA, ORIYA SIGN	0B4D
+VIRAMA, TAGALOG SIGN	1714
+VIRAMA, TAMIL SIGN	0BCD
+VIRAMA, TELUGU SIGN	0C4D
+VIRGO	264D
+virgule	002F
+VOICED FRICATIVE, LATIN LETTER PHARYNGEAL	0295
+VOICED SOUND MARK, COMBINING KATAKANA-HIRAGANA	3099
+VOICED SOUND MARK, KATAKANA-HIRAGANA	309B
+VOICING, MODIFIER LETTER	02EC
+VOLUME INTEGRAL	2230
+VOLTAGE SIGN, HIGH	26A1
+vrachy	0306
+VS1	FE00
+W, LATIN SMALL LETTER TURNED	028D
+W, MODIFIER LETTER SMALL	02B7
+WARNING SIGN	26A0
+Warning Signs	2620
+Warning Signs	26A0
+WATCH	231A
+WAVE, SINE	223F
+WAVE DASH	301C
+WAVY DASH	3030
+WAVY LINE	2307
+WAVY LOW LINE	FE4F
+WAVY OVERLINE	FE4B
+WAVY OVERLINE, DOUBLE	FE4C
+Weather and Astrological Symbols	2600
+wedge	028C
+wedge	2227
+weierstrass elliptic function	2118
+WHEEL OF DHARMA	2638
+WHITE BULLET, CIRCLED	29BE
+WHITE CIRCLE WITH DOT RIGHT	2686
+WHITE CIRCLE WITH DOWN ARROW	29EC
+WHITE CIRCLE WITH TWO DOTS	2687
+WHITE CONCAVE-SIDED DIAMOND	27E1
+WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK	27E2
+WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK	27E3
+WHITE DIAMOND WITH CENTRED DOT	27D0
+WHITE DOT RIGHT, BLACK CIRCLE WITH	2688
+WHITE DOTS, BLACK CIRCLE WITH TWO	2689
+WHITE FLAG	2690
+white framus	29D6
+WHITE HOURGLASS	29D6
+WHITE MEDIUM SMALL SQUARE	25FD
+WHITE MEDIUM SQUARE	25FB
+White On Black Circled Numbers	24EB
+WHITE SESAME DOT	FE46
+WHITE SHOGI PIECE	2616
+WHITE SQUARE WITH LEFTWARDS TICK	27E4
+WHITE SQUARE WITH RIGHTWARDS TICK	27E5
+WHITE VERTICAL BAR	2AFE
+WHITE VERTICAL BAR, N-ARY	2AFF
+WIDE BRIDGE ABOVE, COMBINING	20E9
+WIGGLY FENCE, LEFT	29D8
+WIGGLY FENCE, LEFT DOUBLE	29DA
+WIGGLY FENCE, RIGHT	29D9
+WIGGLY FENCE, RIGHT DOUBLE	29DB
+wj	2060
+WON SIGN	20A9
+WORD DIVIDER, UGARITIC	1039F
+WORD JOINER	2060
+Word Separators, Aegean	10100
+Words, Squared Japanese Katakana	3300
+WORDSPACE, ETHIOPIC	1361
+WREATH PRODUCT	2240
+WRITING HAND	270D
+WYNN, LATIN CAPITAL LETTER	01F7
+WYNN, LATIN LETTER	01BF
+X, BALLOT	2717
+X, BALLOT BOX WITH	2612
+X, CIRCLE WITH SUPERIMPOSED	29BB
+X, COMBINING LATIN SMALL LETTER	036F
+X, HEAVY BALLOT	2718
+X, HEAVY MULTIPLICATION	2716
+X, MODIFIER LETTER SMALL	02E3
+X, MULTIPLICATION	2715
+X ABOVE, COMBINING	033D
+X IN A RECTANGLE BOX	2327
+XOR	22BB
+Y, LATIN LETTER SMALL CAPITAL	028F
+Y, LATIN SMALL LETTER TURNED	028E
+Y, MODIFIER LETTER SMALL	02B8
+Y, TURNED SANS-SERIF CAPITAL	2144
+YANG, YIN	262F
+YEN SIGN	00A5
+Yi Radicals	A490
+Yi Syllables	A000
+Yiddish Digraphs	05F0
+yields	22A2
+Yijing Monogram and Digram Symbols	268A
+Yijing Hexagram Symbols	4DC0
+Yijing Trigram Symbols	2630
+YIN YANG	262F
+yogh, latin capital letter	01B7
+YOGH, LATIN SMALL LETTER	021D
+yogh, latin small letter	0292
+YPOGEGRAMMENI, COMBINING GREEK	0345
+YR, LATIN LETTER	01A6
+yuan sign	00A5
+Z, BLACK-LETTER CAPITAL	2128
+Z, DOUBLE-STRUCK CAPITAL	2124
+Z NOTATION BAG MEMBERSHIP	22FF
+z notation bag subtraction	2A41
+z notation bijection	2917
+Z Notation Binding Brackets	2989
+Z NOTATION DOMAIN ANTIRESTRICTION	2A64
+z notation finite function	20E6
+z notation finite function	21FB
+z notation finite injection	2915
+z notation finite relation	21FC
+z notation finite surjection	2901
+z notation finite surjective injection	2918
+Z Notation Image Brackets	2987
+z notation left bag bracket	27E6
+z notation partial function	21F8
+z notation partial injection	2914
+z notation partial relation	21F9
+z notation partial surjection	2900
+Z NOTATION RANGE ANTIRESTRICTION	2A65
+Z NOTATION RELATIONAL COMPOSITION	2A3E
+Z NOTATION SCHEMA COMPOSITION	2A1F
+z notation schema hiding	29F9
+Z NOTATION SCHEMA PIPING	2A20
+Z NOTATION SCHEMA PROJECTION	2A21
+z notations sequence concatenation	2040
+Z NOTATION SPOT	2981
+z notation surjective injection	2917
+Z NOTATION TYPE COLON	2982
+Zapf Dingbats Series 100, ITC	2700
+ZERO, CIRCLED DIGIT	24EA
+ZERO, IDEOGRAPHIC NUMBER	3007
+ZERO, SUPERSCRIPT	2070
+ZERO WIDTH JOINER	200D
+ZERO WIDTH NO-BREAK SPACE	FEFF
+ZERO WIDTH NON-JOINER	200C
+ZERO WIDTH SPACE	200B
+ZIGZAG ARROW, RIGHT ANGLE WITH DOWNWARDS	237C
+ZIGZAG LINE, VERTICAL	299A
+Zodiacal Symbols	2648
+zwj	200D
+zwnbsp	FEFF
+zwnj	200C
+zwsp	200B
+	
--- /dev/null
+++ b/lib/unidata/unidata2.txt
@@ -1,0 +1,16351 @@
+0000;<control>;Cc;0;BN;;;;;N;NULL;;;;
+0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;;
+0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;;
+0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;;
+0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;;
+0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;;
+0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;;
+0007;<control>;Cc;0;BN;;;;;N;BELL;;;;
+0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;;
+0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
+000A;<control>;Cc;0;B;;;;;N;LINE FEED (LF);;;;
+000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
+000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
+000D;<control>;Cc;0;B;;;;;N;CARRIAGE RETURN (CR);;;;
+000E;<control>;Cc;0;BN;;;;;N;SHIFT OUT;;;;
+000F;<control>;Cc;0;BN;;;;;N;SHIFT IN;;;;
+0010;<control>;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;;
+0011;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;;
+0012;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;;
+0013;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;;
+0014;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;;
+0015;<control>;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;;
+0016;<control>;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;;
+0017;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;;
+0018;<control>;Cc;0;BN;;;;;N;CANCEL;;;;
+0019;<control>;Cc;0;BN;;;;;N;END OF MEDIUM;;;;
+001A;<control>;Cc;0;BN;;;;;N;SUBSTITUTE;;;;
+001B;<control>;Cc;0;BN;;;;;N;ESCAPE;;;;
+001C;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR FOUR;;;;
+001D;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR THREE;;;;
+001E;<control>;Cc;0;B;;;;;N;INFORMATION SEPARATOR TWO;;;;
+001F;<control>;Cc;0;S;;;;;N;INFORMATION SEPARATOR ONE;;;;
+0020;SPACE;Zs;0;WS;;;;;N;;;;;
+0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;;
+0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;;
+0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;;
+0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+0026;AMPERSAND;Po;0;ON;;;;;N;;;;;
+0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;;
+0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;;
+0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;;
+002A;ASTERISK;Po;0;ON;;;;;N;;;;;
+002B;PLUS SIGN;Sm;0;ES;;;;;N;;;;;
+002C;COMMA;Po;0;CS;;;;;N;;;;;
+002D;HYPHEN-MINUS;Pd;0;ES;;;;;N;;;;;
+002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;;
+002F;SOLIDUS;Po;0;CS;;;;;N;SLASH;;;;
+0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;;
+0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;;
+0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;;
+0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;;
+0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;;
+0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;;
+0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;;
+0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
+0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;;
+0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;;
+003A;COLON;Po;0;CS;;;;;N;;;;;
+003B;SEMICOLON;Po;0;ON;;;;;N;;;;;
+003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;;
+003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003F;QUESTION MARK;Po;0;ON;;;;;N;;;;;
+0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;;
+0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061;
+0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062;
+0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063;
+0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064;
+0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065;
+0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066;
+0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067;
+0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068;
+0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069;
+004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A;
+004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B;
+004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C;
+004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D;
+004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E;
+004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F;
+0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070;
+0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071;
+0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072;
+0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073;
+0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074;
+0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075;
+0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076;
+0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077;
+0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078;
+0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079;
+005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A;
+005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;;
+005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;;
+005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;;
+005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;;
+005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;;
+0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;;
+0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041
+0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042
+0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043
+0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044
+0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045
+0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046
+0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047
+0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048
+0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049
+006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A
+006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B
+006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C
+006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D
+006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E
+006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F
+0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050
+0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051
+0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052
+0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053
+0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054
+0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055
+0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056
+0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057
+0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058
+0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059
+007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
+007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;;
+007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;;
+007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;;
+007E;TILDE;Sm;0;ON;;;;;N;;;;;
+007F;<control>;Cc;0;BN;;;;;N;DELETE;;;;
+0080;<control>;Cc;0;BN;;;;;N;;;;;
+0081;<control>;Cc;0;BN;;;;;N;;;;;
+0082;<control>;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;;
+0083;<control>;Cc;0;BN;;;;;N;NO BREAK HERE;;;;
+0084;<control>;Cc;0;BN;;;;;N;;;;;
+0085;<control>;Cc;0;B;;;;;N;NEXT LINE (NEL);;;;
+0086;<control>;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;;
+0087;<control>;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;;
+0088;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;;
+0089;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;;
+008A;<control>;Cc;0;BN;;;;;N;LINE TABULATION SET;;;;
+008B;<control>;Cc;0;BN;;;;;N;PARTIAL LINE FORWARD;;;;
+008C;<control>;Cc;0;BN;;;;;N;PARTIAL LINE BACKWARD;;;;
+008D;<control>;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;;
+008E;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;;
+008F;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;;
+0090;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;;
+0091;<control>;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;;
+0092;<control>;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;;
+0093;<control>;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;;
+0094;<control>;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;;
+0095;<control>;Cc;0;BN;;;;;N;MESSAGE WAITING;;;;
+0096;<control>;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;;
+0097;<control>;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;;
+0098;<control>;Cc;0;BN;;;;;N;START OF STRING;;;;
+0099;<control>;Cc;0;BN;;;;;N;;;;;
+009A;<control>;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;;
+009B;<control>;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;;
+009C;<control>;Cc;0;BN;;;;;N;STRING TERMINATOR;;;;
+009D;<control>;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;;
+009E;<control>;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;;
+009F;<control>;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;;
+00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
+00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;;
+00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;;
+00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;;
+00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;;
+00A7;SECTION SIGN;So;0;ON;;;;;N;;;;;
+00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;;
+00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;;
+00AA;FEMININE ORDINAL INDICATOR;Ll;0;L;<super> 0061;;;;N;;;;;
+00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;*;;;
+00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;;
+00AD;SOFT HYPHEN;Cf;0;BN;;;;;N;;;;;
+00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;;
+00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;;
+00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;;
+00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;;
+00B2;SUPERSCRIPT TWO;No;0;EN;<super> 0032;;2;2;N;SUPERSCRIPT DIGIT TWO;;;;
+00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;;3;3;N;SUPERSCRIPT DIGIT THREE;;;;
+00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;;
+00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C
+00B6;PILCROW SIGN;So;0;ON;;;;;N;PARAGRAPH SIGN;;;;
+00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;;
+00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;;1;1;N;SUPERSCRIPT DIGIT ONE;;;;
+00BA;MASCULINE ORDINAL INDICATOR;Ll;0;L;<super> 006F;;;;N;;;;;
+00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;*;;;
+00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;;
+00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;;
+00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;;
+00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;;
+00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0;
+00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1;
+00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2;
+00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3;
+00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4;
+00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5;
+00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;ash *;;00E6;
+00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7;
+00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8;
+00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9;
+00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA;
+00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB;
+00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC;
+00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED;
+00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE;
+00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF;
+00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;Icelandic;;00F0;
+00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1;
+00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2;
+00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3;
+00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4;
+00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5;
+00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6;
+00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;;
+00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8;
+00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9;
+00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA;
+00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB;
+00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC;
+00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD;
+00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;Icelandic;;00FE;
+00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;German;;;
+00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0
+00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1
+00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2
+00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3
+00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4
+00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5
+00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;ash *;00C6;;00C6
+00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7
+00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8
+00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9
+00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA
+00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB
+00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC
+00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD
+00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE
+00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF
+00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;Icelandic;00D0;;00D0
+00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1
+00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2
+00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3
+00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4
+00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5
+00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6
+00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8
+00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9
+00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA
+00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB
+00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC
+00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD
+00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;Icelandic;00DE;;00DE
+00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178
+0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101;
+0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100
+0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103;
+0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102
+0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105;
+0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104
+0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107;
+0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106
+0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109;
+0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108
+010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B;
+010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A
+010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D;
+010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C
+010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F;
+010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E
+0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111;
+0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110
+0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113;
+0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112
+0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115;
+0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114
+0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117;
+0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116
+0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119;
+0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118
+011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B;
+011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A
+011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D;
+011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C
+011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F;
+011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E
+0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121;
+0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120
+0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123;
+0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122
+0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125;
+0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124
+0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127;
+0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126
+0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129;
+0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128
+012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B;
+012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A
+012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D;
+012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C
+012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F;
+012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E
+0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069;
+0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
+0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L;<compat> 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133;
+0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
+0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135;
+0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134
+0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137;
+0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136
+0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;Greenlandic;;;
+0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
+013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139
+013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C;
+013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B
+013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E;
+013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D
+013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
+0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L;<compat> 006C 00B7;;;;N;;;013F;;013F
+0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142;
+0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141
+0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144;
+0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143
+0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146;
+0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145
+0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148;
+0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
+0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L;<compat> 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;;
+014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;Sami;;014B;
+014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;Sami;014A;;014A
+014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D;
+014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C
+014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F;
+014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E
+0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151;
+0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150
+0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153;
+0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152
+0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155;
+0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154
+0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157;
+0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156
+0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159;
+0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158
+015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B;
+015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A
+015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D;
+015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C
+015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;*;;015F;
+015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;*;015E;;015E
+0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161;
+0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160
+0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;*;;0163;
+0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;*;0162;;0162
+0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165;
+0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164
+0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167;
+0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166
+0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169;
+0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168
+016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B;
+016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A
+016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D;
+016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C
+016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F;
+016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E
+0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171;
+0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170
+0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173;
+0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172
+0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175;
+0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174
+0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177;
+0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176
+0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF;
+0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A;
+017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179
+017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C;
+017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B
+017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E;
+017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D
+017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053
+0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;;;
+0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253;
+0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183;
+0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182
+0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185;
+0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184
+0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254;
+0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188;
+0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187
+0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;*;;0256;
+018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257;
+018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C;
+018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B
+018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;;
+018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD;
+018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259;
+0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B;
+0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192;
+0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191
+0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260;
+0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263;
+0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;hwair;01F6;;01F6
+0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269;
+0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268;
+0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199;
+0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198
+019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;023D;;023D
+019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;;
+019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F;
+019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272;
+019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;0220;;0220
+019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;*;;0275;
+01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1;
+01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0
+01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;gha;;01A3;
+01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;gha;01A2;;01A2
+01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5;
+01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4
+01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;*;;0280;
+01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8;
+01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7
+01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283;
+01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;;
+01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;;
+01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD;
+01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC
+01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288;
+01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0;
+01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF
+01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A;
+01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B;
+01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4;
+01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3
+01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6;
+01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5
+01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292;
+01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9;
+01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8
+01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;;
+01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;;
+01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD;
+01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC
+01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;;
+01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7
+01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;;
+01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;;
+01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;;
+01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;;
+01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L;<compat> 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5
+01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L;<compat> 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;01C5
+01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L;<compat> 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5
+01C7;LATIN CAPITAL LETTER LJ;Lu;0;L;<compat> 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8
+01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L;<compat> 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;01C8
+01C9;LATIN SMALL LETTER LJ;Ll;0;L;<compat> 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8
+01CA;LATIN CAPITAL LETTER NJ;Lu;0;L;<compat> 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB
+01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L;<compat> 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;01CB
+01CC;LATIN SMALL LETTER NJ;Ll;0;L;<compat> 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB
+01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE;
+01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD
+01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0;
+01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF
+01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2;
+01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1
+01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4;
+01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3
+01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6;
+01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5
+01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8;
+01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7
+01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA;
+01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9
+01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC;
+01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB
+01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E
+01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF;
+01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE
+01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1;
+01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0
+01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;ash *;;01E3;
+01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;ash *;01E2;;01E2
+01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5;
+01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4
+01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7;
+01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6
+01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9;
+01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8
+01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB;
+01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA
+01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED;
+01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC
+01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF;
+01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE
+01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;;
+01F1;LATIN CAPITAL LETTER DZ;Lu;0;L;<compat> 0044 005A;;;;N;;;;01F3;01F2
+01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L;<compat> 0044 007A;;;;N;;;01F1;01F3;01F2
+01F3;LATIN SMALL LETTER DZ;Ll;0;L;<compat> 0064 007A;;;;N;;;01F1;;01F2
+01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5;
+01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4
+01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195;
+01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF;
+01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9;
+01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8
+01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB;
+01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA
+01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;ash *;;01FD;
+01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;ash *;01FC;;01FC
+01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF;
+01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE
+0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201;
+0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200
+0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203;
+0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202
+0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205;
+0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204
+0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207;
+0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206
+0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209;
+0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208
+020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B;
+020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A
+020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D;
+020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C
+020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F;
+020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E
+0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211;
+0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210
+0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213;
+0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212
+0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215;
+0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214
+0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217;
+0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216
+0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;*;;0219;
+0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;*;0218;;0218
+021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;*;;021B;
+021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;*;021A;;021A
+021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D;
+021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C
+021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F;
+021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E
+0220;LATIN CAPITAL LETTER N WITH LONG RIGHT LEG;Lu;0;L;;;;;N;;;;019E;
+0221;LATIN SMALL LETTER D WITH CURL;Ll;0;L;;;;;N;;;;;
+0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223;
+0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222
+0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225;
+0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224
+0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227;
+0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226
+0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229;
+0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228
+022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B;
+022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A
+022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D;
+022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C
+022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F;
+022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E
+0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231;
+0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230
+0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233;
+0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232
+0234;LATIN SMALL LETTER L WITH CURL;Ll;0;L;;;;;N;;;;;
+0235;LATIN SMALL LETTER N WITH CURL;Ll;0;L;;;;;N;;;;;
+0236;LATIN SMALL LETTER T WITH CURL;Ll;0;L;;;;;N;;;;;
+0237;LATIN SMALL LETTER DOTLESS J;Ll;0;L;;;;;N;;;;;
+0238;LATIN SMALL LETTER DB DIGRAPH;Ll;0;L;;;;;N;;;;;
+0239;LATIN SMALL LETTER QP DIGRAPH;Ll;0;L;;;;;N;;;;;
+023A;LATIN CAPITAL LETTER A WITH STROKE;Lu;0;L;;;;;N;;;;;
+023B;LATIN CAPITAL LETTER C WITH STROKE;Lu;0;L;;;;;N;;;;023C;
+023C;LATIN SMALL LETTER C WITH STROKE;Ll;0;L;;;;;N;;;023B;;023B
+023D;LATIN CAPITAL LETTER L WITH BAR;Lu;0;L;;;;;N;;;;019A;
+023E;LATIN CAPITAL LETTER T WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;;
+023F;LATIN SMALL LETTER S WITH SWASH TAIL;Ll;0;L;;;;;N;;;;;
+0240;LATIN SMALL LETTER Z WITH SWASH TAIL;Ll;0;L;;;;;N;;;;;
+0241;LATIN CAPITAL LETTER GLOTTAL STOP;Lu;0;L;;;;;N;;;;0294;
+0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;;;
+0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;;;
+0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;;;
+0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181
+0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186
+0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;;
+0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189
+0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A
+0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;;
+0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F
+025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;;
+025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190
+025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;;;
+025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;;
+025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;;
+025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;;
+0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193
+0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;;;
+0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;;
+0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194
+0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;;
+0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;;;
+0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;;
+0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;;
+0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197
+0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196
+026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;;
+026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;;
+026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;;
+026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;;
+026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C
+0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;;;
+0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D
+0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;;
+0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;;
+0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F
+0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;;
+0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;;
+0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;;
+0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;;
+027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;;
+027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;;;
+027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;;
+027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;;
+0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;*;01A6;;01A6
+0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;;
+0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;;;
+0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9
+0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;;
+0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;;
+0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;;
+0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;;
+0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE
+0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;;;
+028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1
+028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2
+028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;;;
+028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;;
+028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;;
+028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;;
+0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;;
+0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;;
+0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7
+0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;;
+0294;LATIN LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;0241;;0241
+0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;;
+0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;;
+0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;;
+0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;;
+0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;;
+029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;;
+029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;;
+029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;;
+029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;;
+029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;;;
+029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;;
+02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;;
+02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;;
+02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;;
+02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;;
+02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;;
+02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;;
+02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;;
+02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;;
+02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;;
+02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02AE;LATIN SMALL LETTER TURNED H WITH FISHHOOK;Ll;0;L;;;;;N;;;;;
+02AF;LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL;Ll;0;L;;;;;N;;;;;
+02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;;
+02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;;
+02B2;MODIFIER LETTER SMALL J;Lm;0;L;<super> 006A;;;;N;;;;;
+02B3;MODIFIER LETTER SMALL R;Lm;0;L;<super> 0072;;;;N;;;;;
+02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L;<super> 0279;;;;N;;;;;
+02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L;<super> 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;;
+02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L;<super> 0281;;;;N;;;;;
+02B7;MODIFIER LETTER SMALL W;Lm;0;L;<super> 0077;;;;N;;;;;
+02B8;MODIFIER LETTER SMALL Y;Lm;0;L;<super> 0079;;;;N;;;;;
+02B9;MODIFIER LETTER PRIME;Lm;0;ON;;;;;N;;;;;
+02BA;MODIFIER LETTER DOUBLE PRIME;Lm;0;ON;;;;;N;;;;;
+02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;;
+02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;;
+02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;;
+02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;;
+02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;;
+02C7;CARON;Lm;0;ON;;;;;N;MODIFIER LETTER HACEK;Mandarin Chinese third tone;;;
+02C8;MODIFIER LETTER VERTICAL LINE;Lm;0;ON;;;;;N;;;;;
+02C9;MODIFIER LETTER MACRON;Lm;0;ON;;;;;N;;Mandarin Chinese first tone;;;
+02CA;MODIFIER LETTER ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER ACUTE;Mandarin Chinese second tone;;;
+02CB;MODIFIER LETTER GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER GRAVE;Mandarin Chinese fourth tone;;;
+02CC;MODIFIER LETTER LOW VERTICAL LINE;Lm;0;ON;;;;;N;;;;;
+02CD;MODIFIER LETTER LOW MACRON;Lm;0;ON;;;;;N;;;;;
+02CE;MODIFIER LETTER LOW GRAVE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;;
+02CF;MODIFIER LETTER LOW ACUTE ACCENT;Lm;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;;
+02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;;
+02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;;
+02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;;
+02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;;
+02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D8;BREVE;Sk;0;ON;<compat> 0020 0306;;;;N;SPACING BREVE;;;;
+02D9;DOT ABOVE;Sk;0;ON;<compat> 0020 0307;;;;N;SPACING DOT ABOVE;Mandarin Chinese light tone;;;
+02DA;RING ABOVE;Sk;0;ON;<compat> 0020 030A;;;;N;SPACING RING ABOVE;;;;
+02DB;OGONEK;Sk;0;ON;<compat> 0020 0328;;;;N;SPACING OGONEK;;;;
+02DC;SMALL TILDE;Sk;0;ON;<compat> 0020 0303;;;;N;SPACING TILDE;;;;
+02DD;DOUBLE ACUTE ACCENT;Sk;0;ON;<compat> 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;;
+02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;;
+02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;;
+02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L;<super> 0263;;;;N;;;;;
+02E1;MODIFIER LETTER SMALL L;Lm;0;L;<super> 006C;;;;N;;;;;
+02E2;MODIFIER LETTER SMALL S;Lm;0;L;<super> 0073;;;;N;;;;;
+02E3;MODIFIER LETTER SMALL X;Lm;0;L;<super> 0078;;;;N;;;;;
+02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L;<super> 0295;;;;N;;;;;
+02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EC;MODIFIER LETTER VOICING;Sk;0;ON;;;;;N;;;;;
+02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;;
+02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;;
+02EF;MODIFIER LETTER LOW DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F0;MODIFIER LETTER LOW UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F1;MODIFIER LETTER LOW LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F2;MODIFIER LETTER LOW RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02F3;MODIFIER LETTER LOW RING;Sk;0;ON;;;;;N;;;;;
+02F4;MODIFIER LETTER MIDDLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F5;MODIFIER LETTER MIDDLE DOUBLE GRAVE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F6;MODIFIER LETTER MIDDLE DOUBLE ACUTE ACCENT;Sk;0;ON;;;;;N;;;;;
+02F7;MODIFIER LETTER LOW TILDE;Sk;0;ON;;;;;N;;;;;
+02F8;MODIFIER LETTER RAISED COLON;Sk;0;ON;;;;;N;;;;;
+02F9;MODIFIER LETTER BEGIN HIGH TONE;Sk;0;ON;;;;;N;;;;;
+02FA;MODIFIER LETTER END HIGH TONE;Sk;0;ON;;;;;N;;;;;
+02FB;MODIFIER LETTER BEGIN LOW TONE;Sk;0;ON;;;;;N;;;;;
+02FC;MODIFIER LETTER END LOW TONE;Sk;0;ON;;;;;N;;;;;
+02FD;MODIFIER LETTER SHELF;Sk;0;ON;;;;;N;;;;;
+02FE;MODIFIER LETTER OPEN SHELF;Sk;0;ON;;;;;N;;;;;
+02FF;MODIFIER LETTER LOW LEFT ARROW;Sk;0;ON;;;;;N;;;;;
+0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;Varia;;;
+0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;Oxia, Tonos;;;
+0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;;
+0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;;
+0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;;
+0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;;
+0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;Vrachy;;;
+0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;;
+0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;Dialytika;;;
+0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;;
+030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;;
+030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;;
+030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;;
+030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;;;;
+030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;;
+030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;;
+0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;;
+0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;;
+0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;;
+0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;Psili;;;
+0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;Dasia;;;
+0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;;
+0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;;
+0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;;
+0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;;
+0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;;
+031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;;
+031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;;
+031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;;
+031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;;
+031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;;
+031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;;
+0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;;
+0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;;
+0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;;
+0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;;
+0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;;
+0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;;
+0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;;
+0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;;
+0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;;
+0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;;
+032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;;
+032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;;
+032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;;
+032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;;
+032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;;
+032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;;
+0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;;
+0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;;
+0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;;
+0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;;
+0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;;
+0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;;
+0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;;
+0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;;
+0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;;
+0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;;
+033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;;
+033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;;
+033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;;
+033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;;
+033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;;
+033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;;
+0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;Vietnamese;;;
+0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;Vietnamese;;;
+0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;;
+0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;;
+0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;;
+0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399
+0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;;
+0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;;
+034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;;
+034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;;
+034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;;
+034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+034F;COMBINING GRAPHEME JOINER;Mn;0;NSM;;;;;N;;;;;
+0350;COMBINING RIGHT ARROWHEAD ABOVE;Mn;230;NSM;;;;;N;;;;;
+0351;COMBINING LEFT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+0352;COMBINING FERMATA;Mn;230;NSM;;;;;N;;;;;
+0353;COMBINING X BELOW;Mn;220;NSM;;;;;N;;;;;
+0354;COMBINING LEFT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0355;COMBINING RIGHT ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0356;COMBINING RIGHT ARROWHEAD AND UP ARROWHEAD BELOW;Mn;220;NSM;;;;;N;;;;;
+0357;COMBINING RIGHT HALF RING ABOVE;Mn;230;NSM;;;;;N;;;;;
+0358;COMBINING DOT ABOVE RIGHT;Mn;232;NSM;;;;;N;;;;;
+0359;COMBINING ASTERISK BELOW;Mn;220;NSM;;;;;N;;;;;
+035A;COMBINING DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;
+035B;COMBINING ZIGZAG ABOVE;Mn;230;NSM;;;;;N;;;;;
+035C;COMBINING DOUBLE BREVE BELOW;Mn;233;NSM;;;;;N;;;;;
+035D;COMBINING DOUBLE BREVE;Mn;234;NSM;;;;;N;;;;;
+035E;COMBINING DOUBLE MACRON;Mn;234;NSM;;;;;N;;;;;
+035F;COMBINING DOUBLE MACRON BELOW;Mn;233;NSM;;;;;N;;;;;
+0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;;
+0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;;
+0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;;
+0363;COMBINING LATIN SMALL LETTER A;Mn;230;NSM;;;;;N;;;;;
+0364;COMBINING LATIN SMALL LETTER E;Mn;230;NSM;;;;;N;;;;;
+0365;COMBINING LATIN SMALL LETTER I;Mn;230;NSM;;;;;N;;;;;
+0366;COMBINING LATIN SMALL LETTER O;Mn;230;NSM;;;;;N;;;;;
+0367;COMBINING LATIN SMALL LETTER U;Mn;230;NSM;;;;;N;;;;;
+0368;COMBINING LATIN SMALL LETTER C;Mn;230;NSM;;;;;N;;;;;
+0369;COMBINING LATIN SMALL LETTER D;Mn;230;NSM;;;;;N;;;;;
+036A;COMBINING LATIN SMALL LETTER H;Mn;230;NSM;;;;;N;;;;;
+036B;COMBINING LATIN SMALL LETTER M;Mn;230;NSM;;;;;N;;;;;
+036C;COMBINING LATIN SMALL LETTER R;Mn;230;NSM;;;;;N;;;;;
+036D;COMBINING LATIN SMALL LETTER T;Mn;230;NSM;;;;;N;;;;;
+036E;COMBINING LATIN SMALL LETTER V;Mn;230;NSM;;;;;N;;;;;
+036F;COMBINING LATIN SMALL LETTER X;Mn;230;NSM;;;;;N;;;;;
+0374;GREEK NUMERAL SIGN;Sk;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;;
+0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;Aristeri keraia;;;
+037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;;
+037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;Erotimatiko;;;
+0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;;
+0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;;
+0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC;
+0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;;
+0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD;
+0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE;
+038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF;
+038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC;
+038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD;
+038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE;
+0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;;
+0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1;
+0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2;
+0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3;
+0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4;
+0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5;
+0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6;
+0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7;
+0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
+0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9;
+039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA;
+039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB;
+039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC;
+039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD;
+039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE;
+039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF;
+03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0;
+03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1;
+03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3;
+03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4;
+03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5;
+03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6;
+03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7;
+03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8;
+03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9;
+03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA;
+03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB;
+03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386
+03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388
+03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389
+03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A
+03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;;
+03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391
+03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392
+03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393
+03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394
+03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395
+03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396
+03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397
+03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
+03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399
+03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A
+03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B
+03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C
+03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D
+03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E
+03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F
+03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0
+03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1
+03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4
+03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5
+03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6
+03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7
+03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8
+03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9
+03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA
+03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB
+03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C
+03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E
+03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F
+03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392
+03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
+03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;;
+03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;;
+03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;;
+03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6
+03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0
+03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;;;
+03D8;GREEK LETTER ARCHAIC KOPPA;Lu;0;L;;;;;N;;*;;03D9;
+03D9;GREEK SMALL LETTER ARCHAIC KOPPA;Ll;0;L;;;;;N;;*;03D8;;03D8
+03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB;
+03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA
+03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD;
+03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC
+03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF;
+03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE
+03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1;
+03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0
+03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3;
+03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2
+03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5;
+03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4
+03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7;
+03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6
+03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9;
+03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8
+03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB;
+03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA
+03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED;
+03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC
+03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF;
+03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE
+03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A
+03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1
+03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03F9;;03F9
+03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;;;
+03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
+03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395
+03F6;GREEK REVERSED LUNATE EPSILON SYMBOL;Sm;0;ON;;;;;N;;;;;
+03F7;GREEK CAPITAL LETTER SHO;Lu;0;L;;;;;N;;;;03F8;
+03F8;GREEK SMALL LETTER SHO;Ll;0;L;;;;;N;;;03F7;;03F7
+03F9;GREEK CAPITAL LUNATE SIGMA SYMBOL;Lu;0;L;<compat> 03A3;;;;N;;;;03F2;
+03FA;GREEK CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;03FB;
+03FB;GREEK SMALL LETTER SAN;Ll;0;L;;;;;N;;;03FA;;03FA
+03FC;GREEK RHO WITH STROKE SYMBOL;Ll;0;L;;;;;N;;;;;
+03FD;GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;;
+03FE;GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;;
+03FF;GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL;Lu;0;L;;;;;N;;;;;
+0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450;
+0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451;
+0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;Serbocroatian;;0452;
+0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453;
+0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454;
+0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455;
+0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456;
+0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;Ukrainian;;0457;
+0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458;
+0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459;
+040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A;
+040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;Serbocroatian;;045B;
+040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C;
+040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D;
+040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;Byelorussian;;045E;
+040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F;
+0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430;
+0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431;
+0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432;
+0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433;
+0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434;
+0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435;
+0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436;
+0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437;
+0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438;
+0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439;
+041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A;
+041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B;
+041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C;
+041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D;
+041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E;
+041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F;
+0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440;
+0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441;
+0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442;
+0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443;
+0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444;
+0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445;
+0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446;
+0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447;
+0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448;
+0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449;
+042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A;
+042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B;
+042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C;
+042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D;
+042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E;
+042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F;
+0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410
+0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411
+0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412
+0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413
+0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414
+0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415
+0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416
+0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417
+0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418
+0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419
+043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A
+043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B
+043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C
+043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D
+043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E
+043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F
+0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420
+0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421
+0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422
+0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423
+0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424
+0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425
+0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426
+0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427
+0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428
+0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429
+044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A
+044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B
+044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C
+044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D
+044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E
+044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F
+0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400
+0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401
+0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;Serbocroatian;0402;;0402
+0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403
+0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404
+0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405
+0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406
+0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;Ukrainian;0407;;0407
+0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408
+0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409
+045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A
+045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;Serbocroatian;040B;;040B
+045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C
+045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D
+045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;Byelorussian;040E;;040E
+045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F
+0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461;
+0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460
+0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463;
+0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462
+0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465;
+0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464
+0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467;
+0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466
+0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469;
+0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468
+046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B;
+046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A
+046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D;
+046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C
+046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F;
+046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E
+0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471;
+0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470
+0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473;
+0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472
+0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475;
+0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474
+0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477;
+0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476
+0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479;
+0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478
+047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B;
+047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A
+047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D;
+047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C
+047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F;
+047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E
+0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481;
+0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480
+0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;;
+0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;;
+0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;;
+0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;;
+0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;;
+0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;;
+0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
+048A;CYRILLIC CAPITAL LETTER SHORT I WITH TAIL;Lu;0;L;;;;;N;;;;048B;
+048B;CYRILLIC SMALL LETTER SHORT I WITH TAIL;Ll;0;L;;;;;N;;;048A;;048A
+048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D;
+048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C
+048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F;
+048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E
+0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491;
+0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490
+0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493;
+0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492
+0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495;
+0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494
+0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497;
+0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496
+0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499;
+0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498
+049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B;
+049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A
+049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D;
+049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C
+049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F;
+049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E
+04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1;
+04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0
+04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3;
+04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2
+04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5;
+04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4
+04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;Abkhasian;;04A7;
+04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;Abkhasian;04A6;;04A6
+04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9;
+04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8
+04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB;
+04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA
+04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD;
+04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC
+04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF;
+04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE
+04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1;
+04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0
+04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3;
+04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2
+04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;Abkhasian;;04B5;
+04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;Abkhasian;04B4;;04B4
+04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7;
+04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6
+04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9;
+04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8
+04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB;
+04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA
+04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD;
+04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC
+04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF;
+04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE
+04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;;
+04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2;
+04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1
+04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4;
+04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3
+04C5;CYRILLIC CAPITAL LETTER EL WITH TAIL;Lu;0;L;;;;;N;;;;04C6;
+04C6;CYRILLIC SMALL LETTER EL WITH TAIL;Ll;0;L;;;;;N;;;04C5;;04C5
+04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8;
+04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7
+04C9;CYRILLIC CAPITAL LETTER EN WITH TAIL;Lu;0;L;;;;;N;;;;04CA;
+04CA;CYRILLIC SMALL LETTER EN WITH TAIL;Ll;0;L;;;;;N;;;04C9;;04C9
+04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC;
+04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB
+04CD;CYRILLIC CAPITAL LETTER EM WITH TAIL;Lu;0;L;;;;;N;;;;04CE;
+04CE;CYRILLIC SMALL LETTER EM WITH TAIL;Ll;0;L;;;;;N;;;04CD;;04CD
+04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1;
+04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0
+04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3;
+04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2
+04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5;
+04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4
+04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7;
+04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6
+04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9;
+04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8
+04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB;
+04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA
+04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD;
+04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC
+04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF;
+04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE
+04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1;
+04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0
+04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3;
+04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2
+04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5;
+04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4
+04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7;
+04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6
+04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9;
+04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8
+04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB;
+04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA
+04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED;
+04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC
+04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF;
+04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE
+04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1;
+04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0
+04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3;
+04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2
+04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5;
+04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4
+04F6;CYRILLIC CAPITAL LETTER GHE WITH DESCENDER;Lu;0;L;;;;;N;;;;04F7;
+04F7;CYRILLIC SMALL LETTER GHE WITH DESCENDER;Ll;0;L;;;;;N;;;04F6;;04F6
+04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9;
+04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8
+0500;CYRILLIC CAPITAL LETTER KOMI DE;Lu;0;L;;;;;N;;;;0501;
+0501;CYRILLIC SMALL LETTER KOMI DE;Ll;0;L;;;;;N;;;0500;;0500
+0502;CYRILLIC CAPITAL LETTER KOMI DJE;Lu;0;L;;;;;N;;;;0503;
+0503;CYRILLIC SMALL LETTER KOMI DJE;Ll;0;L;;;;;N;;;0502;;0502
+0504;CYRILLIC CAPITAL LETTER KOMI ZJE;Lu;0;L;;;;;N;;;;0505;
+0505;CYRILLIC SMALL LETTER KOMI ZJE;Ll;0;L;;;;;N;;;0504;;0504
+0506;CYRILLIC CAPITAL LETTER KOMI DZJE;Lu;0;L;;;;;N;;;;0507;
+0507;CYRILLIC SMALL LETTER KOMI DZJE;Ll;0;L;;;;;N;;;0506;;0506
+0508;CYRILLIC CAPITAL LETTER KOMI LJE;Lu;0;L;;;;;N;;;;0509;
+0509;CYRILLIC SMALL LETTER KOMI LJE;Ll;0;L;;;;;N;;;0508;;0508
+050A;CYRILLIC CAPITAL LETTER KOMI NJE;Lu;0;L;;;;;N;;;;050B;
+050B;CYRILLIC SMALL LETTER KOMI NJE;Ll;0;L;;;;;N;;;050A;;050A
+050C;CYRILLIC CAPITAL LETTER KOMI SJE;Lu;0;L;;;;;N;;;;050D;
+050D;CYRILLIC SMALL LETTER KOMI SJE;Ll;0;L;;;;;N;;;050C;;050C
+050E;CYRILLIC CAPITAL LETTER KOMI TJE;Lu;0;L;;;;;N;;;;050F;
+050F;CYRILLIC SMALL LETTER KOMI TJE;Ll;0;L;;;;;N;;;050E;;050E
+0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561;
+0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562;
+0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563;
+0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564;
+0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565;
+0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566;
+0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567;
+0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568;
+0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569;
+053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A;
+053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B;
+053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C;
+053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D;
+053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E;
+053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F;
+0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570;
+0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571;
+0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572;
+0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573;
+0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574;
+0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575;
+0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576;
+0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577;
+0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578;
+0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579;
+054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A;
+054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B;
+054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C;
+054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D;
+054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E;
+054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F;
+0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580;
+0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581;
+0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582;
+0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583;
+0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584;
+0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585;
+0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586;
+0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;;
+055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;;
+055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;;
+055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;;
+055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;;
+055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;;
+0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531
+0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532
+0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533
+0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534
+0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535
+0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536
+0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537
+0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538
+0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539
+056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A
+056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B
+056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C
+056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D
+056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E
+056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F
+0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540
+0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541
+0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542
+0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543
+0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544
+0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545
+0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546
+0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547
+0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548
+0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549
+057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A
+057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B
+057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C
+057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D
+057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E
+057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F
+0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550
+0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551
+0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552
+0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553
+0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554
+0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555
+0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556
+0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;;
+0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;;
+058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;;
+0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;;
+0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;;
+0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;;
+0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;;
+0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;;
+0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;*;;;
+0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;;
+0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;*;;;
+0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;;
+059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;;
+059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;;
+059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;;
+059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;;
+059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;;
+059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;;
+05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;;
+05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;;
+05A2;HEBREW ACCENT ATNAH HAFUKH;Mn;220;NSM;;;;;N;;;;;
+05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;;
+05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;;
+05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;*;;;
+05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;;
+05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;;
+05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;*;;;
+05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;;
+05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;*;;;
+05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;;
+05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;;
+05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;;
+05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;;
+05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;;
+05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;;
+05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;;
+05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;;
+05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;;
+05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;;
+05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;;
+05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;;
+05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;;
+05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;;
+05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;;
+05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;;
+05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;or shuruq;;;
+05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;*;;;
+05BE;HEBREW PUNCTUATION MAQAF;Po;0;R;;;;;N;;;;;
+05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;;
+05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;*;;;
+05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;;
+05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;;
+05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;*;;;
+05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;;
+05C5;HEBREW MARK LOWER DOT;Mn;220;NSM;;;;;N;;;;;
+05C6;HEBREW PUNCTUATION NUN HAFUKHA;Po;0;R;;;;;N;;;;;
+05C7;HEBREW POINT QAMATS QATAN;Mn;18;NSM;;;;;N;;;;;
+05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;;
+05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;;
+05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;;
+05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;;
+05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;;
+05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;;
+05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;;
+05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;;
+05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;;
+05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;;
+05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;;
+05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;;
+05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;;
+05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;;
+05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;;
+05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;;
+05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;;
+05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;;
+05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;;
+05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;;
+05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;;
+05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;;
+05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;;
+05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;;
+05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;;
+05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;;
+05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;;
+05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;;
+0600;ARABIC NUMBER SIGN;Cf;0;AL;;;;;N;;;;;
+0601;ARABIC SIGN SANAH;Cf;0;AL;;;;;N;;;;;
+0602;ARABIC FOOTNOTE MARKER;Cf;0;AL;;;;;N;;;;;
+0603;ARABIC SIGN SAFHA;Cf;0;AL;;;;;N;;;;;
+060B;AFGHANI SIGN;Sc;0;AL;;;;;N;;;;;
+060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;;
+060D;ARABIC DATE SEPARATOR;Po;0;AL;;;;;N;;;;;
+060E;ARABIC POETIC VERSE SIGN;So;0;ON;;;;;N;;;;;
+060F;ARABIC SIGN MISRA;So;0;ON;;;;;N;;;;;
+0610;ARABIC SIGN SALLALLAHOU ALAYHE WASSALLAM;Mn;230;NSM;;;;;N;;;;;
+0611;ARABIC SIGN ALAYHE ASSALLAM;Mn;230;NSM;;;;;N;;;;;
+0612;ARABIC SIGN RAHMATULLAH ALAYHE;Mn;230;NSM;;;;;N;;;;;
+0613;ARABIC SIGN RADI ALLAHOU ANHU;Mn;230;NSM;;;;;N;;;;;
+0614;ARABIC SIGN TAKHALLUS;Mn;230;NSM;;;;;N;;;;;
+0615;ARABIC SMALL HIGH TAH;Mn;230;NSM;;;;;N;;;;;
+061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;;
+061E;ARABIC TRIPLE DOT PUNCTUATION MARK;Po;0;AL;;;;;N;;;;;
+061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;;
+0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;;
+0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;;
+0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;;
+0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;;
+0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;;
+0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;;
+0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;;
+0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;;
+0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;;
+062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;;
+062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;;
+062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;;
+062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;;
+062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;;
+062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;;
+0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;;
+0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;;
+0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;;
+0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;;
+0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;;
+0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;;
+0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;;
+0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;;
+0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;;
+063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;;
+0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;;
+0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;;
+0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;;
+0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;;
+0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;;
+0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;;
+0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;;
+0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;;
+0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;;
+064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;;
+064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;;
+064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;;
+064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;;
+064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;;
+064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;;
+0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;;
+0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;;
+0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;;
+0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;;
+0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;;
+0656;ARABIC SUBSCRIPT ALEF;Mn;220;NSM;;;;;N;;;;;
+0657;ARABIC INVERTED DAMMA;Mn;230;NSM;;;;;N;;;;;
+0658;ARABIC MARK NOON GHUNNA;Mn;230;NSM;;;;;N;;;;;
+0659;ARABIC ZWARAKAY;Mn;230;NSM;;;;;N;;;;;
+065A;ARABIC VOWEL SIGN SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;
+065B;ARABIC VOWEL SIGN INVERTED SMALL V ABOVE;Mn;230;NSM;;;;;N;;;;;
+065C;ARABIC VOWEL SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+065D;ARABIC REVERSED DAMMA;Mn;230;NSM;;;;;N;;;;;
+065E;ARABIC FATHA WITH TWO DOTS;Mn;230;NSM;;;;;N;;;;;
+0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
+0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
+0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
+0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
+0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
+0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
+0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
+0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
+0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
+0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
+066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;;
+066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;;
+066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;;
+066E;ARABIC LETTER DOTLESS BEH;Lo;0;AL;;;;;N;;;;;
+066F;ARABIC LETTER DOTLESS QAF;Lo;0;AL;;;;;N;;;;;
+0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;;
+0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;;
+0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;;
+0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;;
+0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;;
+0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL;<compat> 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;;
+0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL;<compat> 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;;
+0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL;<compat> 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;;
+0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL;<compat> 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;;
+0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;;
+067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;;
+067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;;
+067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;;
+067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;;
+067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;;
+067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;;
+0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;;
+0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;;
+0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;;
+0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;;
+0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;;
+0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;;
+0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;;
+0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;;
+0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;;
+0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;;
+068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;
+068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;;
+068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;;
+068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;;
+068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;;
+0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;;
+0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;;
+0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;;
+0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;;
+0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;;
+0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;;
+0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;;
+0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;;
+0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;;
+069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;;
+06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;;
+06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;;
+06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;;
+06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;;
+06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;;
+06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;;
+06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;;
+06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;;
+06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;;
+06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;;
+06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;;
+06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;*;;;
+06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;;
+06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;;
+06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;;
+06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;;
+06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;;
+06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;;
+06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;;
+06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;;
+06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;;
+06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;;
+06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;;
+06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;;
+06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;;
+06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;;
+06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;;
+06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;;
+06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;;
+06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;;
+06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;;
+06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;;
+06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;;
+06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;*;;;
+06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;;
+06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;;
+06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;;
+06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;;
+06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;;
+06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;;
+06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;;
+06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;;
+06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;;
+06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;;
+06DD;ARABIC END OF AYAH;Cf;0;AL;;;;;N;;;;;
+06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;;
+06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;;
+06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;;
+06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;;
+06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;;
+06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;;
+06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;;
+06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;;
+06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;;
+06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;;
+06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;;
+06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;;
+06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;;
+06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;;
+06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;;
+06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;;
+06EE;ARABIC LETTER DAL WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+06EF;ARABIC LETTER REH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;;
+06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;;
+06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;;
+06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;;
+06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;;
+06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;;
+06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;;
+06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;;
+06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;;
+06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;;
+06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;;
+06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;;
+06FF;ARABIC LETTER HEH WITH INVERTED V;Lo;0;AL;;;;;N;;;;;
+0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;;
+0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;;
+0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;;
+0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;;
+0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;;
+070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;;
+070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;;
+070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;;
+070F;SYRIAC ABBREVIATION MARK;Cf;0;BN;;;;;N;;;;;
+0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;;
+0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;;
+0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;;
+0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;;
+0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;;
+0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;;
+0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;;
+0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;;
+0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;;
+071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;;
+071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;;
+071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;;
+071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;;
+071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;;
+0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;;
+0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;;
+0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;;
+0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;;
+0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;;
+0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;;
+0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;;
+0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;;
+0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;;
+0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;;
+072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;;
+072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;;
+072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;;
+072D;SYRIAC LETTER PERSIAN BHETH;Lo;0;AL;;;;;N;;;;;
+072E;SYRIAC LETTER PERSIAN GHAMAL;Lo;0;AL;;;;;N;;;;;
+072F;SYRIAC LETTER PERSIAN DHALATH;Lo;0;AL;;;;;N;;;;;
+0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;;
+0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;;
+073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;;
+073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;;
+0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;;
+0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;;
+0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;;
+0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;;
+074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;;
+074D;SYRIAC LETTER SOGDIAN ZHAIN;Lo;0;AL;;;;;N;;;;;
+074E;SYRIAC LETTER SOGDIAN KHAPH;Lo;0;AL;;;;;N;;;;;
+074F;SYRIAC LETTER SOGDIAN FE;Lo;0;AL;;;;;N;;;;;
+0750;ARABIC LETTER BEH WITH THREE DOTS HORIZONTALLY BELOW;Lo;0;AL;;;;;N;;;;;
+0751;ARABIC LETTER BEH WITH DOT BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0752;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0753;ARABIC LETTER BEH WITH THREE DOTS POINTING UPWARDS BELOW AND TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0754;ARABIC LETTER BEH WITH TWO DOTS BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0755;ARABIC LETTER BEH WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
+0756;ARABIC LETTER BEH WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+0757;ARABIC LETTER HAH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0758;ARABIC LETTER HAH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0759;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;
+075A;ARABIC LETTER DAL WITH INVERTED SMALL V BELOW;Lo;0;AL;;;;;N;;;;;
+075B;ARABIC LETTER REH WITH STROKE;Lo;0;AL;;;;;N;;;;;
+075C;ARABIC LETTER SEEN WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+075D;ARABIC LETTER AIN WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+075E;ARABIC LETTER AIN WITH THREE DOTS POINTING DOWNWARDS ABOVE;Lo;0;AL;;;;;N;;;;;
+075F;ARABIC LETTER AIN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+0760;ARABIC LETTER FEH WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+0761;ARABIC LETTER FEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0762;ARABIC LETTER KEHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0763;ARABIC LETTER KEHEH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0764;ARABIC LETTER KEHEH WITH THREE DOTS POINTING UPWARDS BELOW;Lo;0;AL;;;;;N;;;;;
+0765;ARABIC LETTER MEEM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+0766;ARABIC LETTER MEEM WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+0767;ARABIC LETTER NOON WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+0768;ARABIC LETTER NOON WITH SMALL TAH;Lo;0;AL;;;;;N;;;;;
+0769;ARABIC LETTER NOON WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+076A;ARABIC LETTER LAM WITH BAR;Lo;0;AL;;;;;N;;;;;
+076B;ARABIC LETTER REH WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+076C;ARABIC LETTER REH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;;;;;
+076D;ARABIC LETTER SEEN WITH TWO DOTS VERTICALLY ABOVE;Lo;0;AL;;;;;N;;;;;
+0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;;
+0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;;
+0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;;
+0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;;
+0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;;
+0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;;
+0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;;
+0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;;
+078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;;
+078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;;
+078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;;
+078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;;
+078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;;
+078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;;
+0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;;
+0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;;
+0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;;
+0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;;
+0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;;
+0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;;
+0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;;
+0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;;
+0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;;
+079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;;
+079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;;
+079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;;
+079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;;
+079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;;
+079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;;
+07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;;
+07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;;
+07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;;
+07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;;
+07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;;
+07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;;
+07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;;
+07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;;
+07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;;
+07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;;
+07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;;
+07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;;
+07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;;
+07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;;
+07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;;
+07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;;
+07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;;
+07B1;THAANA LETTER NAA;Lo;0;AL;;;;;N;;;;;
+0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0904;DEVANAGARI LETTER SHORT A;Lo;0;L;;;;;N;;;;;
+0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;;
+0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;;
+0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;;
+0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;;
+0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;;
+090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;;
+090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;;
+090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;;
+090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;;
+0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;;
+0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;;
+0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;;
+0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;;
+0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;;
+0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;;
+0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;;
+0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;;
+091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;;
+091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;;
+091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;;
+091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;;
+091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;;
+091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;;
+0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;;
+0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;;
+0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;;
+0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;;
+092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;;
+092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;;
+092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;;
+092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;;
+092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;;
+092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;;
+0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;;
+0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;;
+0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;;
+0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;;
+0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;;
+0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;;
+0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;;
+093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;
+0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;
+094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;;
+0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;;
+0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;;
+0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;;
+0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;;
+095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;;
+095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;;
+095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;;
+095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;;
+095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;;
+095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;;
+0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;;
+0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+097D;DEVANAGARI LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;;
+0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;;
+0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;;
+0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;;
+0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;;
+098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;;
+098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;;
+0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;;
+0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;;
+0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;;
+0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;;
+0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;;
+0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;;
+099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;;
+099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;;
+099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;;
+099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;;
+099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;;
+099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;;
+09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;;
+09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;;
+09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;;
+09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;;
+09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;;
+09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;;
+09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;;
+09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;;
+09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;;
+09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;;
+09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;;
+09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;;
+09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;;
+09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;;
+09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;;
+09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;;
+09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;;
+09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;;
+09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;;
+09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+09BD;BENGALI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;;
+09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;;
+09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+09CE;BENGALI LETTER KHANDA TA;Lo;0;L;;;;;N;;;;;
+09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;;
+09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;;
+09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;;
+09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;Assamese;;;
+09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;Assamese;;;
+09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;;
+09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1;N;;;;;
+09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;2;N;;;;;
+09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3;N;;;;;
+09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;4;N;;;;;
+09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;;N;;;;;
+09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;;
+09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;;
+0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;;
+0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;;
+0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;;
+0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;;
+0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;;
+0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;;
+0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;;
+0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;;
+0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;;
+0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;;
+0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;;
+0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;;
+0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;;
+0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;;
+0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;;
+0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;;
+0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;;
+0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;;
+0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;;
+0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;;
+0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;;
+0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;;
+0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;;
+0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;;
+0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;;
+0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;;
+0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;;
+0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;;
+0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;;
+0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;;
+0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;;
+0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;;
+0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;;
+0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;;
+0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;;
+0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;;
+0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;;
+0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0A8C;GUJARATI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;;
+0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;;
+0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;;
+0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;;
+0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;;
+0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;;
+0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;;
+0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;;
+0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;;
+0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;;
+0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;;
+0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;;
+0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;;
+0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;;
+0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;;
+0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;;
+0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;;
+0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;;
+0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0AE1;GUJARATI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0AE2;GUJARATI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0AE3;GUJARATI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0AF1;GUJARATI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;;
+0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;;
+0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;;
+0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;;
+0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;;
+0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;;
+0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;;
+0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;;
+0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;;
+0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;;
+0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;;
+0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;;
+0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;;
+0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;;
+0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;;
+0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;;
+0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;;
+0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;;
+0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;;
+0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;;
+0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;;
+0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;;
+0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;;
+0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;;
+0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0B35;ORIYA LETTER VA;Lo;0;L;;;;;N;;;;;
+0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;;
+0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;;
+0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;;
+0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;;
+0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;;
+0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;;
+0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;;
+0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;;
+0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;;
+0B71;ORIYA LETTER WA;Lo;0;L;;;;;N;;;;;
+0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0B83;TAMIL SIGN VISARGA;Lo;0;L;;;;;N;;;;;
+0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;;
+0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;;
+0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;;
+0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;;
+0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;;
+0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;;
+0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;;
+0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;;
+0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;;
+0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;;
+0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;;
+0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;;
+0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;;
+0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;;
+0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;;
+0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;;
+0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;;
+0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;;
+0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;;
+0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;;
+0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;;
+0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;;
+0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;;
+0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;;
+0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;;
+0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;;
+0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;;
+0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;;
+0BB6;TAMIL LETTER SHA;Lo;0;L;;;;;N;;;;;
+0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;;
+0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;;
+0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;;
+0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;;
+0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;;
+0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;;
+0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0BE6;TAMIL DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;;
+0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+0BF3;TAMIL DAY SIGN;So;0;ON;;;;;N;;Naal;;;
+0BF4;TAMIL MONTH SIGN;So;0;ON;;;;;N;;Maatham;;;
+0BF5;TAMIL YEAR SIGN;So;0;ON;;;;;N;;Varudam;;;
+0BF6;TAMIL DEBIT SIGN;So;0;ON;;;;;N;;Patru;;;
+0BF7;TAMIL CREDIT SIGN;So;0;ON;;;;;N;;Varavu;;;
+0BF8;TAMIL AS ABOVE SIGN;So;0;ON;;;;;N;;Merpadi;;;
+0BF9;TAMIL RUPEE SIGN;Sc;0;ET;;;;;N;;Rupai;;;
+0BFA;TAMIL NUMBER SIGN;So;0;ON;;;;;N;;Enn;;;
+0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
+0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;;
+0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;;
+0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;;
+0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;;
+0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;;
+0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;;
+0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;;
+0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;;
+0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;;
+0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;;
+0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;;
+0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;;
+0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;;
+0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;;
+0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;;
+0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;;
+0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;;
+0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;;
+0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;;
+0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;;
+0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;;
+0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;;
+0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;;
+0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;;
+0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;;
+0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;;
+0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;;
+0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;;
+0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;;
+0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;;
+0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;;
+0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;;
+0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;;
+0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;;
+0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;;
+0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;;
+0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;;
+0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;;
+0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;;
+0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;;
+0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;;
+0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;;
+0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;;
+0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;;
+0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;;
+0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;;
+0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;;
+0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;;
+0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;;
+0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;;
+0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;;
+0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;;
+0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;;
+0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;;
+0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;;
+0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;;
+0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;;
+0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;;
+0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;;
+0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;;
+0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;;
+0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;;
+0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;;
+0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;;
+0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;;
+0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;;
+0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;;
+0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;;
+0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;;
+0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;;
+0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;;
+0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;;
+0CBC;KANNADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0CBD;KANNADA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0CBF;KANNADA VOWEL SIGN I;Mn;0;L;;;;;N;;;;;
+0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;;
+0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0CC6;KANNADA VOWEL SIGN E;Mn;0;L;;;;;N;;;;;
+0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;;
+0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;;
+0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;;
+0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;;
+0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;;
+0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;;
+0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;;
+0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;;
+0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;;
+0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;;
+0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;;
+0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;;
+0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;;
+0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;;
+0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;;
+0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;;
+0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;;
+0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;;
+0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;;
+0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;;
+0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;;
+0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;;
+0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;;
+0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;;
+0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;;
+0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;;
+0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;;
+0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;;
+0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;;
+0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;;
+0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;;
+0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;;
+0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;;
+0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;;
+0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;;
+0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;;
+0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;;
+0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;;
+0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;;
+0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;;
+0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;;
+0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;;
+0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;;
+0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;;
+0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;;
+0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;;
+0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;;
+0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;;
+0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;;
+0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;;
+0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
+0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;;
+0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;;
+0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;;
+0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;;
+0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;;
+0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;;
+0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;;
+0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;;
+0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;;
+0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;;
+0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;;
+0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;;
+0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;;
+0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;;
+0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;;
+0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;;
+0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;;
+0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;;
+0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;;
+0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;;
+0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;;
+0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;;
+0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;;
+0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;;
+0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;;
+0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;;
+0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;;
+0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;;
+0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;;
+0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;;
+0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;;
+0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;;
+0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;;
+0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;;
+0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;;
+0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;;
+0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;;
+0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;;
+0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;;
+0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;;
+0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;;
+0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;;
+0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;;
+0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;;
+0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;;
+0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;;
+0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;;
+0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;;
+0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;;
+0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;;
+0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;;
+0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;;
+0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;;
+0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;;
+0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;;
+0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;;
+0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;;
+0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;;
+0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;;
+0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;;
+0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;;
+0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;;
+0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;;
+0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;;
+0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;;
+0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;;
+0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;;
+0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;;
+0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;;
+0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;;
+0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;;
+0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;;
+0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;;
+0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;;
+0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;;
+0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;;
+0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;;
+0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;;
+0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;;
+0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;;
+0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;;
+0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;;
+0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;;
+0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;paiyan noi;;;
+0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;;
+0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;;
+0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;;
+0E33;THAI CHARACTER SARA AM;Lo;0;L;<compat> 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;;
+0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;;
+0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;;
+0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;;
+0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;sara uue;;;
+0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;;
+0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;;
+0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;;
+0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;;
+0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;;
+0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;;
+0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;;
+0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;sara ai mai muan;;;
+0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;sara ai mai malai;;;
+0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;lakkhang yao;;;
+0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;mai yamok;;;
+0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;mai taikhu;;;
+0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;;
+0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;;
+0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;;
+0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;;
+0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;;
+0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;nikkhahit;;;
+0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;;
+0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;;
+0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;;
+0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;;
+0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;;
+0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;;
+0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;;
+0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;;
+0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;;
+0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;;
+0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;;
+0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;;
+0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;;
+0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;;
+0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;;
+0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;;
+0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;;
+0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;;
+0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;;
+0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;;
+0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;;
+0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;;
+0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;;
+0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;;
+0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;;
+0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;;
+0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;;
+0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;;
+0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;;
+0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;;
+0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;;
+0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;;
+0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;;
+0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;;
+0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;
+0EB3;LAO VOWEL SIGN AM;Lo;0;L;<compat> 0ECD 0EB2;;;;N;;;;;
+0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;;
+0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;;
+0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;;
+0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;;
+0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;;
+0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;;
+0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;;
+0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;;
+0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;;
+0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;;
+0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;;
+0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;;
+0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;;
+0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;;
+0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;;
+0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;;
+0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;;
+0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;;
+0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;;
+0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;;
+0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;ter yik go a thung;;;
+0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;ter yik go wum nam chey ma;;;
+0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;ter yik go wum ter tsek ma;;;
+0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;yik go dun ma;;;
+0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;yik go kab ma;;;
+0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;yik go pur shey ma;;;
+0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;yik go tsek shey ma;;;
+0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;drul shey;;;
+0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;kur yik go;;;
+0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;ka sho yik go;;;
+0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;tsek;;;
+0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L;<noBreak> 0F0B;;;;N;;tsek tar;;;
+0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;shey;;;
+0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;nyi shey;;;
+0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;tsek shey;;;
+0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;nyi tsek shey;;;
+0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;rinchen pung shey;;;
+0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;gya tram shey;;;
+0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;dzu ta me long chen;;;
+0F14;TIBETAN MARK GTER TSHEG;So;0;L;;;;;N;TIBETAN COMMA;ter tsek;;;
+0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;che ta;;;
+0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;hlak ta;;;
+0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;trachen char ta;;;
+0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;kyu pa;;;
+0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;dong tsu;;;
+0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;deka chig;;;
+0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;deka nyi;;;
+0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;deka sum;;;
+0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;dena chig;;;
+0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;dena nyi;;;
+0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;deka dena;;;
+0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;;
+0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;;
+0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;;
+0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;;
+0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;;
+0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;;
+0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;;
+0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;;
+0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;;
+0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;;
+0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;du ta;;;
+0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;nge zung nyi da;;;
+0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;dzu ta shi mig chen;;;
+0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;nge zung gor ta;;;
+0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;che go;;;
+0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;tsa tru;;;
+0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;N;;gug ta yun;;;
+0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;N;;gug ta ye;;;
+0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;N;TIBETAN LEFT BRACE;ang kang yun;;;
+0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;N;TIBETAN RIGHT BRACE;ang kang ye;;;
+0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;yar tse;;;
+0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;mar tse;;;
+0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;;
+0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;;
+0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;;
+0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;;
+0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;;
+0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;;
+0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;;
+0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;;
+0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;;
+0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;;
+0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;;
+0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;;
+0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;;
+0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;;
+0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;;
+0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;;
+0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;;
+0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;;
+0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;;
+0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;;
+0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;;
+0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;;
+0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;;
+0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;;
+0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;;
+0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;;
+0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;;
+0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;;
+0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;;
+0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;*;;;
+0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;;
+0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;;
+0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;;
+0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;;
+0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;;
+0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;;
+0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;*;;;
+0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;;
+0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;;
+0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;;
+0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;;
+0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;;
+0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;;
+0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM;<compat> 0FB2 0F81;;;;N;;;;;
+0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;;
+0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM;<compat> 0FB3 0F81;;;;N;;;;;
+0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;;
+0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;;
+0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;;
+0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;;
+0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;je su nga ro;;;
+0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;nam chey;;;
+0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;;
+0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;;
+0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;nyi da na da;;;
+0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;nan de;;;
+0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;;
+0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;;
+0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;ji ta;;;
+0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;yang ta;;;
+0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;che tsa chen;;;
+0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;chu chen;;;
+0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;tru chen ging;;;
+0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;tru me ging;;;
+0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;;
+0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;;
+0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;;
+0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;;
+0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;;
+0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;;
+0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;;
+0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;;
+0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;;
+0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;;
+0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;;
+0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;;
+0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;;
+0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;;
+0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;;
+0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;;
+0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;;
+0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;;
+0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;;
+0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;;
+0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;;
+0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;;
+0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;;
+0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;;
+0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;;
+0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;;
+0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;;
+0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;;
+0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;*;;;
+0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;;
+0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;;
+0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;;
+0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;*;;;
+0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;*;;;
+0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;;
+0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;;
+0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;;
+0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;;
+0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;;
+0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;;
+0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;;
+0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;*;;;
+0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;*;;;
+0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;*;;;
+0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;kuruka;;;
+0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;kuruka shi mik chen;;;
+0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;;
+0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;;
+0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;chang tyu;;;
+0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;bub chey;;;
+0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;drilbu;;;
+0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;dorje;;;
+0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;pema den;;;
+0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;dorje gya dram;;;
+0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;phurba;;;
+0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;norbu;;;
+0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;norbu nyi khyi;;;
+0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;norbu sum khyi;;;
+0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;norbu shi khyi;;;
+0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;dena sum;;;
+0FD0;TIBETAN MARK BSKA- SHOG GI MGO RGYAN;Po;0;L;;;;;N;;ka shog gi go gyen;;;
+0FD1;TIBETAN MARK MNYAM YIG GI MGO RGYAN;Po;0;L;;;;;N;;nyam yig gi go gyen;;;
+1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;;
+1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;;
+1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;;
+1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;;
+1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;;
+1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;;
+1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;;
+1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;;
+1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;;
+1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;;
+100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;;
+100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;;
+100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;;
+100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;;
+100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;;
+100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;;
+1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;;
+1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;;
+1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;;
+1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;;
+1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;;
+1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;;
+1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;;
+1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;;
+1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;;
+1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;;
+101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;;
+101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;;
+101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;;
+101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;;
+101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;;
+101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;;
+1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;;
+1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;;
+1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;;
+1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;;
+1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;;
+1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;;
+1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;;
+1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;;
+102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;;
+102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;;
+1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;;
+104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;;
+104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;;
+104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;;
+104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;;
+104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;;
+1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;;
+1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;;
+1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;2D00;
+10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;2D01;
+10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;2D02;
+10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;2D03;
+10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;2D04;
+10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;2D05;
+10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;2D06;
+10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;2D07;
+10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;2D08;
+10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;2D09;
+10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;2D0A;
+10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;2D0B;
+10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;2D0C;
+10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;2D0D;
+10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;2D0E;
+10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;2D0F;
+10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;2D10;
+10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;2D11;
+10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;2D12;
+10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;2D13;
+10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;2D14;
+10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;2D15;
+10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;2D16;
+10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;2D17;
+10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;2D18;
+10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;2D19;
+10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;2D1A;
+10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;2D1B;
+10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;2D1C;
+10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;2D1D;
+10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;2D1E;
+10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;2D1F;
+10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;2D20;
+10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;2D21;
+10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;2D22;
+10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;2D23;
+10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;2D24;
+10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;2D25;
+10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;;
+10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;;
+10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;;
+10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;;
+10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;;
+10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;;
+10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;;
+10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;;
+10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;;
+10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;;
+10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;;
+10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;;
+10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;;
+10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;;
+10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;;
+10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;;
+10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;;
+10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;;
+10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;;
+10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;;
+10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;;
+10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;;
+10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;;
+10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;;
+10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;;
+10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;;
+10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;;
+10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;;
+10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;;
+10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;;
+10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;;
+10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;;
+10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;;
+10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;;
+10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;;
+10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;;
+10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;;
+10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;;
+10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;;
+10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;;
+10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;;
+10F9;GEORGIAN LETTER TURNED GAN;Lo;0;L;;;;;N;;;;;
+10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;;
+10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;;
+1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;;
+1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;;
+1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;n *;;;
+1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;;
+1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;dd *;;;
+1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;r *;;;
+1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;m *;;;
+1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;b *;;;
+1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;bb *;;;
+1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;s *;;;
+110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;;
+110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;;
+110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;j *;;;
+110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;jj *;;;
+110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;;
+110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;;
+1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;;
+1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;;
+1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;h *;;;
+1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;;
+1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;;
+1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;;
+111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;;
+111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;;
+1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;
+1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;;
+1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;;
+112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;;
+112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;;
+112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;;
+1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;;
+1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;
+113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;;
+113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;;
+113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;;
+113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;;
+113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;;
+1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;;
+1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;;
+1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;;
+1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;;
+114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;;
+114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;;
+114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;;
+114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;;
+114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;;
+1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;;
+1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;;
+1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;;
+1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;;
+1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;;
+1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;;
+1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;;
+1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;;
+1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;;
+1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;;
+1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;;
+116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;;
+116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;;
+116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;;
+116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;;
+116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;;
+116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;;
+1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;;
+1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;;
+1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;;
+1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;;
+1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;;
+1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;;
+1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;;
+1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;;
+1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;;
+1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;;
+117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;;
+117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;;
+117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;;
+117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;;
+117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;;
+117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;;
+1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;;
+1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;;
+1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;;
+1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;;
+1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;;
+1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;;
+1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;;
+1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;;
+1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;;
+1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;;
+118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;;
+118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;;
+118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;;
+118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;;
+118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;;
+118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;;
+1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;;
+1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;;
+1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;;
+1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;;
+1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;;
+1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;;
+1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;;
+1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;;
+1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;;
+1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;;
+119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;;
+119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;;
+119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;;
+119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;;
+119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;;
+119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;;
+11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;;
+11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;;
+11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;;
+11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;;
+11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;;
+11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;gs *;;;
+11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;n *;;;
+11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;nj *;;;
+11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;nh *;;;
+11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;;
+11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;l *;;;
+11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;lg *;;;
+11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;lm *;;;
+11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;lb *;;;
+11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;ls *;;;
+11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;lt *;;;
+11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;lp *;;;
+11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;lh *;;;
+11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;m *;;;
+11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;b *;;;
+11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;bs *;;;
+11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;s *;;;
+11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;;
+11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;ng *;;;
+11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;j *;;;
+11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;;
+11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;;
+11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;;
+11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;;
+11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;h *;;;
+11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;;
+11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;;
+11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;;
+11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;;
+11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;;
+11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;;
+11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;;
+11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;;
+11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;;
+11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;;
+11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;;
+11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;;
+11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;;
+11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;;
+11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;;
+11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;;
+11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;;
+11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;;
+1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;;
+1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;;
+1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;;
+1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+1207;ETHIOPIC SYLLABLE HOA;Lo;0;L;;;;;N;;;;;
+1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;;
+120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;;
+120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;;
+1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;;
+1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;;
+1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;;
+1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;;
+1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;;
+1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;;
+1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;;
+1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;;
+1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;;
+121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;;
+121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;;
+1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;;
+1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;;
+1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;;
+1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;;
+1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;;
+1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;;
+1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;;
+1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;;
+1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;;
+122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;;
+122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;;
+122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;;
+1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;;
+1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;;
+1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;;
+1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;;
+123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;;
+123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;;
+123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;;
+1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;;
+1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;;
+1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;;
+1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;;
+1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+1247;ETHIOPIC SYLLABLE QOA;Lo;0;L;;;;;N;;;;;
+1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;;
+124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;;
+124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;;
+124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;;
+124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;;
+1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;;
+1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;;
+1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;;
+1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;;
+1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;;
+1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;;
+1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;;
+1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;;
+125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;;
+125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;;
+125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;;
+125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;;
+1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;;
+1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;;
+1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;;
+1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;;
+126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;;
+126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;;
+126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;;
+1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;;
+1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;;
+1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;;
+1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;;
+127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;;
+127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;;
+1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;;
+1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;;
+1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;;
+1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;;
+1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;;
+1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+1287;ETHIOPIC SYLLABLE XOA;Lo;0;L;;;;;N;;;;;
+1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;;
+128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;;
+128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;;
+128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;;
+128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;;
+1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;;
+1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;;
+1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;;
+1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;;
+1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;;
+129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;;
+129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;;
+129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;;
+12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;;
+12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;;
+12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;;
+12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;;
+12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;;
+12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;;
+12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;;
+12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;;
+12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;;
+12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;;
+12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+12AF;ETHIOPIC SYLLABLE KOA;Lo;0;L;;;;;N;;;;;
+12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;;
+12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;;
+12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;;
+12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;;
+12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;;
+12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;;
+12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;;
+12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;;
+12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;;
+12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;;
+12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;;
+12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;;
+12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;;
+12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;;
+12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;;
+12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;;
+12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;;
+12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;;
+12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;;
+12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;;
+12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;;
+12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+12CF;ETHIOPIC SYLLABLE WOA;Lo;0;L;;;;;N;;;;;
+12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;;
+12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;;
+12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;;
+12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;;
+12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;;
+12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;;
+12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;;
+12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;;
+12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;;
+12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;;
+12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;;
+12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;;
+12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;;
+12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;;
+12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;;
+12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;;
+12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;;
+12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;;
+12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+12EF;ETHIOPIC SYLLABLE YOA;Lo;0;L;;;;;N;;;;;
+12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;;
+12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;;
+12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;;
+12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;;
+12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;;
+12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;;
+1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;;
+1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;;
+1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;;
+1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;;
+1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;;
+1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;;
+130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;;
+130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+130F;ETHIOPIC SYLLABLE GOA;Lo;0;L;;;;;N;;;;;
+1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;;
+1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;;
+1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;;
+1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;;
+1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;;
+1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;;
+131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;;
+131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+131F;ETHIOPIC SYLLABLE GGWAA;Lo;0;L;;;;;N;;;;;
+1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;;
+1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;;
+1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;;
+1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;;
+1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;;
+1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;;
+1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;;
+1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;;
+1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;;
+132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;;
+132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;;
+132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;;
+1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;;
+1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;;
+1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;;
+1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;;
+1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;;
+1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;;
+1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;;
+1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;;
+1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;;
+1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;;
+133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;;
+133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;;
+133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;;
+133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;;
+133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;;
+133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;;
+1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;;
+1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;;
+1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;;
+1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;;
+1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;;
+1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;;
+1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;;
+1347;ETHIOPIC SYLLABLE TZOA;Lo;0;L;;;;;N;;;;;
+1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;;
+134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;;
+134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;;
+134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;;
+1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;;
+1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;;
+1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;;
+1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;;
+1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;;
+1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;;
+135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;;
+135F;ETHIOPIC COMBINING GEMINATION MARK;Mn;230;NSM;;;;;N;;;;;
+1360;ETHIOPIC SECTION MARK;So;0;L;;;;;N;;;;;
+1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;;
+1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;;
+1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;;
+1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;;
+1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;;
+1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;;
+1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;;
+1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+1369;ETHIOPIC DIGIT ONE;No;0;L;;;1;1;N;;;;;
+136A;ETHIOPIC DIGIT TWO;No;0;L;;;2;2;N;;;;;
+136B;ETHIOPIC DIGIT THREE;No;0;L;;;3;3;N;;;;;
+136C;ETHIOPIC DIGIT FOUR;No;0;L;;;4;4;N;;;;;
+136D;ETHIOPIC DIGIT FIVE;No;0;L;;;5;5;N;;;;;
+136E;ETHIOPIC DIGIT SIX;No;0;L;;;6;6;N;;;;;
+136F;ETHIOPIC DIGIT SEVEN;No;0;L;;;7;7;N;;;;;
+1370;ETHIOPIC DIGIT EIGHT;No;0;L;;;8;8;N;;;;;
+1371;ETHIOPIC DIGIT NINE;No;0;L;;;9;9;N;;;;;
+1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;;
+1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;;
+1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;;
+137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;;
+137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;
+1380;ETHIOPIC SYLLABLE SEBATBEIT MWA;Lo;0;L;;;;;N;;;;;
+1381;ETHIOPIC SYLLABLE MWI;Lo;0;L;;;;;N;;;;;
+1382;ETHIOPIC SYLLABLE MWEE;Lo;0;L;;;;;N;;;;;
+1383;ETHIOPIC SYLLABLE MWE;Lo;0;L;;;;;N;;;;;
+1384;ETHIOPIC SYLLABLE SEBATBEIT BWA;Lo;0;L;;;;;N;;;;;
+1385;ETHIOPIC SYLLABLE BWI;Lo;0;L;;;;;N;;;;;
+1386;ETHIOPIC SYLLABLE BWEE;Lo;0;L;;;;;N;;;;;
+1387;ETHIOPIC SYLLABLE BWE;Lo;0;L;;;;;N;;;;;
+1388;ETHIOPIC SYLLABLE SEBATBEIT FWA;Lo;0;L;;;;;N;;;;;
+1389;ETHIOPIC SYLLABLE FWI;Lo;0;L;;;;;N;;;;;
+138A;ETHIOPIC SYLLABLE FWEE;Lo;0;L;;;;;N;;;;;
+138B;ETHIOPIC SYLLABLE FWE;Lo;0;L;;;;;N;;;;;
+138C;ETHIOPIC SYLLABLE SEBATBEIT PWA;Lo;0;L;;;;;N;;;;;
+138D;ETHIOPIC SYLLABLE PWI;Lo;0;L;;;;;N;;;;;
+138E;ETHIOPIC SYLLABLE PWEE;Lo;0;L;;;;;N;;;;;
+138F;ETHIOPIC SYLLABLE PWE;Lo;0;L;;;;;N;;;;;
+1390;ETHIOPIC TONAL MARK YIZET;So;0;ON;;;;;N;;;;;
+1391;ETHIOPIC TONAL MARK DERET;So;0;ON;;;;;N;;;;;
+1392;ETHIOPIC TONAL MARK RIKRIK;So;0;ON;;;;;N;;;;;
+1393;ETHIOPIC TONAL MARK SHORT RIKRIK;So;0;ON;;;;;N;;;;;
+1394;ETHIOPIC TONAL MARK DIFAT;So;0;ON;;;;;N;;;;;
+1395;ETHIOPIC TONAL MARK KENAT;So;0;ON;;;;;N;;;;;
+1396;ETHIOPIC TONAL MARK CHIRET;So;0;ON;;;;;N;;;;;
+1397;ETHIOPIC TONAL MARK HIDET;So;0;ON;;;;;N;;;;;
+1398;ETHIOPIC TONAL MARK DERET-HIDET;So;0;ON;;;;;N;;;;;
+1399;ETHIOPIC TONAL MARK KURT;So;0;ON;;;;;N;;;;;
+13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;;
+13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;;
+13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;;
+13A3;CHEROKEE LETTER O;Lo;0;L;;;;;N;;;;;
+13A4;CHEROKEE LETTER U;Lo;0;L;;;;;N;;;;;
+13A5;CHEROKEE LETTER V;Lo;0;L;;;;;N;;;;;
+13A6;CHEROKEE LETTER GA;Lo;0;L;;;;;N;;;;;
+13A7;CHEROKEE LETTER KA;Lo;0;L;;;;;N;;;;;
+13A8;CHEROKEE LETTER GE;Lo;0;L;;;;;N;;;;;
+13A9;CHEROKEE LETTER GI;Lo;0;L;;;;;N;;;;;
+13AA;CHEROKEE LETTER GO;Lo;0;L;;;;;N;;;;;
+13AB;CHEROKEE LETTER GU;Lo;0;L;;;;;N;;;;;
+13AC;CHEROKEE LETTER GV;Lo;0;L;;;;;N;;;;;
+13AD;CHEROKEE LETTER HA;Lo;0;L;;;;;N;;;;;
+13AE;CHEROKEE LETTER HE;Lo;0;L;;;;;N;;;;;
+13AF;CHEROKEE LETTER HI;Lo;0;L;;;;;N;;;;;
+13B0;CHEROKEE LETTER HO;Lo;0;L;;;;;N;;;;;
+13B1;CHEROKEE LETTER HU;Lo;0;L;;;;;N;;;;;
+13B2;CHEROKEE LETTER HV;Lo;0;L;;;;;N;;;;;
+13B3;CHEROKEE LETTER LA;Lo;0;L;;;;;N;;;;;
+13B4;CHEROKEE LETTER LE;Lo;0;L;;;;;N;;;;;
+13B5;CHEROKEE LETTER LI;Lo;0;L;;;;;N;;;;;
+13B6;CHEROKEE LETTER LO;Lo;0;L;;;;;N;;;;;
+13B7;CHEROKEE LETTER LU;Lo;0;L;;;;;N;;;;;
+13B8;CHEROKEE LETTER LV;Lo;0;L;;;;;N;;;;;
+13B9;CHEROKEE LETTER MA;Lo;0;L;;;;;N;;;;;
+13BA;CHEROKEE LETTER ME;Lo;0;L;;;;;N;;;;;
+13BB;CHEROKEE LETTER MI;Lo;0;L;;;;;N;;;;;
+13BC;CHEROKEE LETTER MO;Lo;0;L;;;;;N;;;;;
+13BD;CHEROKEE LETTER MU;Lo;0;L;;;;;N;;;;;
+13BE;CHEROKEE LETTER NA;Lo;0;L;;;;;N;;;;;
+13BF;CHEROKEE LETTER HNA;Lo;0;L;;;;;N;;;;;
+13C0;CHEROKEE LETTER NAH;Lo;0;L;;;;;N;;;;;
+13C1;CHEROKEE LETTER NE;Lo;0;L;;;;;N;;;;;
+13C2;CHEROKEE LETTER NI;Lo;0;L;;;;;N;;;;;
+13C3;CHEROKEE LETTER NO;Lo;0;L;;;;;N;;;;;
+13C4;CHEROKEE LETTER NU;Lo;0;L;;;;;N;;;;;
+13C5;CHEROKEE LETTER NV;Lo;0;L;;;;;N;;;;;
+13C6;CHEROKEE LETTER QUA;Lo;0;L;;;;;N;;;;;
+13C7;CHEROKEE LETTER QUE;Lo;0;L;;;;;N;;;;;
+13C8;CHEROKEE LETTER QUI;Lo;0;L;;;;;N;;;;;
+13C9;CHEROKEE LETTER QUO;Lo;0;L;;;;;N;;;;;
+13CA;CHEROKEE LETTER QUU;Lo;0;L;;;;;N;;;;;
+13CB;CHEROKEE LETTER QUV;Lo;0;L;;;;;N;;;;;
+13CC;CHEROKEE LETTER SA;Lo;0;L;;;;;N;;;;;
+13CD;CHEROKEE LETTER S;Lo;0;L;;;;;N;;;;;
+13CE;CHEROKEE LETTER SE;Lo;0;L;;;;;N;;;;;
+13CF;CHEROKEE LETTER SI;Lo;0;L;;;;;N;;;;;
+13D0;CHEROKEE LETTER SO;Lo;0;L;;;;;N;;;;;
+13D1;CHEROKEE LETTER SU;Lo;0;L;;;;;N;;;;;
+13D2;CHEROKEE LETTER SV;Lo;0;L;;;;;N;;;;;
+13D3;CHEROKEE LETTER DA;Lo;0;L;;;;;N;;;;;
+13D4;CHEROKEE LETTER TA;Lo;0;L;;;;;N;;;;;
+13D5;CHEROKEE LETTER DE;Lo;0;L;;;;;N;;;;;
+13D6;CHEROKEE LETTER TE;Lo;0;L;;;;;N;;;;;
+13D7;CHEROKEE LETTER DI;Lo;0;L;;;;;N;;;;;
+13D8;CHEROKEE LETTER TI;Lo;0;L;;;;;N;;;;;
+13D9;CHEROKEE LETTER DO;Lo;0;L;;;;;N;;;;;
+13DA;CHEROKEE LETTER DU;Lo;0;L;;;;;N;;;;;
+13DB;CHEROKEE LETTER DV;Lo;0;L;;;;;N;;;;;
+13DC;CHEROKEE LETTER DLA;Lo;0;L;;;;;N;;;;;
+13DD;CHEROKEE LETTER TLA;Lo;0;L;;;;;N;;;;;
+13DE;CHEROKEE LETTER TLE;Lo;0;L;;;;;N;;;;;
+13DF;CHEROKEE LETTER TLI;Lo;0;L;;;;;N;;;;;
+13E0;CHEROKEE LETTER TLO;Lo;0;L;;;;;N;;;;;
+13E1;CHEROKEE LETTER TLU;Lo;0;L;;;;;N;;;;;
+13E2;CHEROKEE LETTER TLV;Lo;0;L;;;;;N;;;;;
+13E3;CHEROKEE LETTER TSA;Lo;0;L;;;;;N;;;;;
+13E4;CHEROKEE LETTER TSE;Lo;0;L;;;;;N;;;;;
+13E5;CHEROKEE LETTER TSI;Lo;0;L;;;;;N;;;;;
+13E6;CHEROKEE LETTER TSO;Lo;0;L;;;;;N;;;;;
+13E7;CHEROKEE LETTER TSU;Lo;0;L;;;;;N;;;;;
+13E8;CHEROKEE LETTER TSV;Lo;0;L;;;;;N;;;;;
+13E9;CHEROKEE LETTER WA;Lo;0;L;;;;;N;;;;;
+13EA;CHEROKEE LETTER WE;Lo;0;L;;;;;N;;;;;
+13EB;CHEROKEE LETTER WI;Lo;0;L;;;;;N;;;;;
+13EC;CHEROKEE LETTER WO;Lo;0;L;;;;;N;;;;;
+13ED;CHEROKEE LETTER WU;Lo;0;L;;;;;N;;;;;
+13EE;CHEROKEE LETTER WV;Lo;0;L;;;;;N;;;;;
+13EF;CHEROKEE LETTER YA;Lo;0;L;;;;;N;;;;;
+13F0;CHEROKEE LETTER YE;Lo;0;L;;;;;N;;;;;
+13F1;CHEROKEE LETTER YI;Lo;0;L;;;;;N;;;;;
+13F2;CHEROKEE LETTER YO;Lo;0;L;;;;;N;;;;;
+13F3;CHEROKEE LETTER YU;Lo;0;L;;;;;N;;;;;
+13F4;CHEROKEE LETTER YV;Lo;0;L;;;;;N;;;;;
+1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;;
+1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;;
+1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;;
+1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;;
+1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;;
+1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;;
+1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;;
+1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;;
+1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;;
+140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;;
+140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;;
+140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;;
+140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;;
+140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;;
+140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;;
+1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;;
+1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;;
+1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;;
+1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;;
+1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;;
+1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;;
+1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;;
+1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;;
+1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;;
+1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;;
+141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;;
+141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;;
+141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;;
+141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;;
+141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;;
+1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;;
+1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;;
+1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;;
+1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;;
+1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;;
+1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;;
+1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;;
+1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;;
+1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;;
+1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;;
+142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;;
+142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;;
+142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;;
+142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;;
+142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;;
+142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;;
+1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;;
+1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;;
+1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;;
+1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;;
+1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;;
+1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;;
+1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;;
+1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;;
+1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;;
+1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;;
+143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;;
+143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;;
+143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;;
+143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;;
+143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;;
+143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;;
+1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;;
+1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;;
+1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;;
+1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;;
+1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;;
+1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;;
+1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;;
+1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;;
+144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;;
+144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;;
+144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;;
+144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;;
+144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;;
+144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;;
+1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;;
+1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;;
+1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;;
+1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;;
+1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;;
+1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;;
+1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;;
+1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;;
+1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;;
+1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;;
+145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;;
+145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;;
+145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;;
+145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;;
+145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;;
+145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;;
+1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;;
+1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;;
+1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;;
+1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;;
+1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;;
+1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;;
+1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;;
+1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;;
+1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;;
+1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;;
+146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;;
+146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;;
+146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;;
+146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;;
+146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;;
+146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;;
+1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;;
+1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;;
+1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;;
+1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;;
+1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;;
+1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;;
+1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;;
+1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;;
+1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;;
+1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;;
+147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;;
+147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;;
+147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;;
+147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;;
+147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;;
+147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;;
+1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;;
+1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;;
+1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;;
+1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;;
+1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;;
+1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;;
+1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;;
+1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;;
+1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;;
+1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;;
+148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;;
+148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;;
+148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;;
+148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;;
+148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;;
+148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;;
+1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;;
+1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;;
+1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;;
+1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;;
+1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;;
+1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;;
+1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;;
+1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;;
+1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;;
+1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;;
+149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;;
+149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;;
+149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;;
+149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;;
+149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;;
+149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;;
+14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;;
+14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;;
+14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;;
+14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;;
+14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;;
+14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;;
+14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;;
+14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;;
+14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;;
+14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;;
+14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;;
+14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;;
+14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;;
+14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;;
+14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;;
+14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;;
+14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;;
+14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;;
+14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;;
+14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;;
+14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;;
+14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;;
+14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;;
+14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;;
+14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;;
+14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;;
+14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;;
+14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;;
+14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;;
+14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;;
+14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;;
+14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;;
+14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;;
+14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;;
+14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;;
+14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;;
+14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;;
+14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;;
+14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;;
+14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;;
+14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;;
+14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;;
+14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;;
+14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;;
+14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;;
+14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;;
+14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;;
+14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;;
+14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;;
+14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;;
+14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;;
+14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;;
+14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;;
+14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;;
+14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;;
+14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;;
+14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;;
+14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;;
+14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;;
+14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;;
+14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;;
+14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;;
+14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;;
+14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;;
+14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;;
+14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;;
+14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;;
+14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;;
+14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;;
+14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;;
+14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;;
+14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;;
+14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;;
+14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;;
+14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;;
+14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;;
+14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;;
+14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;;
+14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;;
+14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;;
+14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;;
+14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;;
+14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;;
+14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;;
+14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;;
+14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;;
+14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;;
+14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;;
+14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;;
+14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;;
+14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;;
+14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;;
+14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;;
+14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;;
+14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;;
+14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;;
+1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;;
+1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;;
+1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;;
+1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;;
+1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;;
+1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;;
+1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;;
+1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;;
+1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;;
+1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;;
+150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;;
+150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;;
+150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;;
+150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;;
+150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;;
+150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;;
+1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;;
+1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;;
+1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;;
+1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;;
+1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;;
+1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;;
+1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;;
+1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;;
+1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;;
+1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;;
+151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;;
+151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;;
+151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;;
+151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;;
+151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;;
+151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;;
+1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;;
+1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;;
+1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;;
+1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;;
+1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;;
+1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;;
+1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;;
+1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;;
+1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;;
+1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;;
+152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;;
+152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;;
+152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;;
+152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;;
+152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;;
+152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;;
+1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;;
+1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;;
+1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;;
+1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;;
+1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;;
+1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;;
+1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;;
+1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;;
+1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;;
+1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;;
+153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;;
+153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;;
+153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;;
+153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;;
+153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;;
+153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;;
+1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;;
+1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;;
+1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;;
+1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;;
+1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;;
+1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;;
+1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;;
+1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;;
+1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;;
+1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;;
+154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;;
+154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;;
+154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;;
+154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;;
+154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;;
+154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;;
+1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;;
+1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;;
+1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;;
+1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;;
+1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;;
+1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;;
+1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;;
+1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;;
+1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;;
+1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;;
+155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;;
+155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;;
+155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;;
+155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;;
+155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;;
+155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;;
+1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;;
+1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;;
+1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;;
+1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;;
+1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;;
+1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;;
+1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;;
+1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;;
+1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;;
+1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;;
+156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;;
+156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;;
+156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;;
+156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;;
+156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;;
+156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;;
+1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;;
+1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;;
+1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;;
+1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;;
+1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;;
+1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;;
+1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;;
+1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;;
+1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;;
+1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;;
+157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;;
+157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;;
+157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;;
+157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;;
+157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;;
+157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;;
+1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;;
+1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;;
+1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;;
+1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;;
+1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;;
+1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;;
+1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;;
+1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;;
+1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;;
+1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;;
+158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;;
+158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;;
+158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;;
+158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;;
+158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;;
+158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;;
+1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;;
+1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;;
+1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;;
+1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;;
+1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;;
+1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;;
+1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;;
+1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;;
+1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;;
+1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;;
+159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;;
+159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;;
+159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;;
+159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;;
+159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;;
+159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;;
+15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;;
+15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;;
+15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;;
+15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;;
+15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;;
+15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;;
+15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;;
+15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;;
+15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;;
+15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;;
+15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;;
+15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;;
+15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;;
+15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;;
+15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;;
+15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;;
+15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;;
+15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;;
+15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;;
+15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;;
+15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;;
+15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;;
+15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;;
+15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;;
+15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;;
+15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;;
+15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;;
+15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;;
+15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;;
+15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;;
+15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;;
+15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;;
+15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;;
+15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;;
+15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;;
+15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;;
+15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;;
+15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;;
+15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;;
+15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;;
+15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;;
+15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;;
+15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;;
+15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;;
+15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;;
+15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;;
+15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;;
+15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;;
+15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;;
+15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;;
+15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;;
+15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;;
+15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;;
+15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;;
+15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;;
+15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;;
+15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;;
+15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;;
+15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;;
+15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;;
+15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;;
+15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;;
+15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;;
+15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;;
+15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;;
+15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;;
+15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;;
+15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;;
+15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;;
+15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;;
+15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;;
+15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;;
+15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;;
+15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;;
+15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;;
+15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;;
+15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;;
+15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;;
+15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;;
+15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;;
+15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;;
+15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;;
+15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;;
+15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;;
+15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;;
+15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;;
+15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;;
+15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;;
+15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;;
+15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;;
+15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;;
+15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;;
+15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;;
+15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;;
+15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;;
+15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;;
+1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;;
+1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;;
+1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;;
+1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;;
+1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;;
+1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;;
+1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;;
+1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;;
+1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;;
+1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;;
+160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;;
+160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;;
+160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;;
+160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;;
+160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;;
+160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;;
+1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;;
+1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;;
+1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;;
+1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;;
+1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;;
+1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;;
+1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;;
+1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;;
+1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;;
+1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;;
+161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;;
+161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;;
+161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;;
+161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;;
+161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;;
+161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;;
+1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;;
+1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;;
+1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;;
+1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;;
+1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;;
+1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;;
+1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;;
+1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;;
+1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;;
+1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;;
+162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;;
+162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;;
+162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;;
+162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;;
+162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;;
+162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;;
+1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;;
+1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;;
+1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;;
+1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;;
+1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;;
+1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;;
+1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;;
+1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;;
+1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;;
+1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;;
+163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;;
+163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;;
+163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;;
+163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;;
+163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;;
+163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;;
+1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;;
+1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;;
+1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;;
+1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;;
+1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;;
+1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;;
+1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;;
+1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;;
+1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;;
+1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;;
+164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;;
+164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;;
+164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;;
+164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;;
+164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;;
+164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;;
+1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;;
+1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;;
+1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;;
+1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;;
+1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;;
+1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;;
+1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;;
+1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;;
+1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;;
+1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;;
+165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;;
+165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;;
+165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;;
+165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;;
+165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;;
+165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;;
+1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;;
+1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;;
+1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;;
+1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;;
+1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;;
+1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;;
+1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;;
+1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;;
+1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;;
+1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;;
+166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;;
+166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;;
+166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;;
+166D;CANADIAN SYLLABICS CHI SIGN;Po;0;L;;;;;N;;;;;
+166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;;
+166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;;
+1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;;
+1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;;
+1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;;
+1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;;
+1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;;
+1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;;
+1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;;
+1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
+1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;;
+1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;;
+1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;;
+1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;;
+1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;;
+1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;;
+1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;;
+1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;;
+1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;;
+168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;;
+168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;;
+168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;;
+168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;;
+168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;;
+168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;;
+1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;;
+1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;;
+1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;;
+1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;;
+1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;;
+1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;;
+1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;;
+1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;;
+1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;;
+1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;;
+169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;;
+169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;N;;;;;
+169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;N;;;;;
+16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;;
+16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;;
+16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;;
+16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;;
+16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;;
+16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;;
+16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;;
+16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;;
+16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;;
+16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;;
+16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;;
+16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;;
+16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;;
+16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;;
+16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;;
+16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;;
+16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;;
+16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;;
+16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;;
+16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;;
+16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;;
+16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;;
+16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;;
+16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;;
+16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;;
+16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;;
+16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;;
+16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;;
+16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;;
+16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;;
+16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;;
+16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;;
+16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;;
+16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;;
+16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;;
+16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;;
+16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;;
+16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;;
+16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;;
+16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;;
+16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;;
+16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;;
+16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;;
+16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;;
+16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;;
+16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;;
+16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;;
+16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;;
+16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;;
+16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;;
+16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;;
+16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;;
+16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;;
+16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;;
+16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;;
+16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;;
+16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;;
+16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;;
+16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;;
+16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;;
+16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;;
+16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;;
+16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;;
+16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;;
+16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;;
+16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;;
+16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;;
+16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;;
+16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;;
+16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;;
+16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;;
+16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;golden number 17;;;
+16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;golden number 18;;;
+16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;golden number 19;;;
+1700;TAGALOG LETTER A;Lo;0;L;;;;;N;;;;;
+1701;TAGALOG LETTER I;Lo;0;L;;;;;N;;;;;
+1702;TAGALOG LETTER U;Lo;0;L;;;;;N;;;;;
+1703;TAGALOG LETTER KA;Lo;0;L;;;;;N;;;;;
+1704;TAGALOG LETTER GA;Lo;0;L;;;;;N;;;;;
+1705;TAGALOG LETTER NGA;Lo;0;L;;;;;N;;;;;
+1706;TAGALOG LETTER TA;Lo;0;L;;;;;N;;;;;
+1707;TAGALOG LETTER DA;Lo;0;L;;;;;N;;;;;
+1708;TAGALOG LETTER NA;Lo;0;L;;;;;N;;;;;
+1709;TAGALOG LETTER PA;Lo;0;L;;;;;N;;;;;
+170A;TAGALOG LETTER BA;Lo;0;L;;;;;N;;;;;
+170B;TAGALOG LETTER MA;Lo;0;L;;;;;N;;;;;
+170C;TAGALOG LETTER YA;Lo;0;L;;;;;N;;;;;
+170E;TAGALOG LETTER LA;Lo;0;L;;;;;N;;;;;
+170F;TAGALOG LETTER WA;Lo;0;L;;;;;N;;;;;
+1710;TAGALOG LETTER SA;Lo;0;L;;;;;N;;;;;
+1711;TAGALOG LETTER HA;Lo;0;L;;;;;N;;;;;
+1712;TAGALOG VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1713;TAGALOG VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1714;TAGALOG SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1720;HANUNOO LETTER A;Lo;0;L;;;;;N;;;;;
+1721;HANUNOO LETTER I;Lo;0;L;;;;;N;;;;;
+1722;HANUNOO LETTER U;Lo;0;L;;;;;N;;;;;
+1723;HANUNOO LETTER KA;Lo;0;L;;;;;N;;;;;
+1724;HANUNOO LETTER GA;Lo;0;L;;;;;N;;;;;
+1725;HANUNOO LETTER NGA;Lo;0;L;;;;;N;;;;;
+1726;HANUNOO LETTER TA;Lo;0;L;;;;;N;;;;;
+1727;HANUNOO LETTER DA;Lo;0;L;;;;;N;;;;;
+1728;HANUNOO LETTER NA;Lo;0;L;;;;;N;;;;;
+1729;HANUNOO LETTER PA;Lo;0;L;;;;;N;;;;;
+172A;HANUNOO LETTER BA;Lo;0;L;;;;;N;;;;;
+172B;HANUNOO LETTER MA;Lo;0;L;;;;;N;;;;;
+172C;HANUNOO LETTER YA;Lo;0;L;;;;;N;;;;;
+172D;HANUNOO LETTER RA;Lo;0;L;;;;;N;;;;;
+172E;HANUNOO LETTER LA;Lo;0;L;;;;;N;;;;;
+172F;HANUNOO LETTER WA;Lo;0;L;;;;;N;;;;;
+1730;HANUNOO LETTER SA;Lo;0;L;;;;;N;;;;;
+1731;HANUNOO LETTER HA;Lo;0;L;;;;;N;;;;;
+1732;HANUNOO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1733;HANUNOO VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1734;HANUNOO SIGN PAMUDPOD;Mn;9;NSM;;;;;N;;;;;
+1735;PHILIPPINE SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+1736;PHILIPPINE DOUBLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+1740;BUHID LETTER A;Lo;0;L;;;;;N;;;;;
+1741;BUHID LETTER I;Lo;0;L;;;;;N;;;;;
+1742;BUHID LETTER U;Lo;0;L;;;;;N;;;;;
+1743;BUHID LETTER KA;Lo;0;L;;;;;N;;;;;
+1744;BUHID LETTER GA;Lo;0;L;;;;;N;;;;;
+1745;BUHID LETTER NGA;Lo;0;L;;;;;N;;;;;
+1746;BUHID LETTER TA;Lo;0;L;;;;;N;;;;;
+1747;BUHID LETTER DA;Lo;0;L;;;;;N;;;;;
+1748;BUHID LETTER NA;Lo;0;L;;;;;N;;;;;
+1749;BUHID LETTER PA;Lo;0;L;;;;;N;;;;;
+174A;BUHID LETTER BA;Lo;0;L;;;;;N;;;;;
+174B;BUHID LETTER MA;Lo;0;L;;;;;N;;;;;
+174C;BUHID LETTER YA;Lo;0;L;;;;;N;;;;;
+174D;BUHID LETTER RA;Lo;0;L;;;;;N;;;;;
+174E;BUHID LETTER LA;Lo;0;L;;;;;N;;;;;
+174F;BUHID LETTER WA;Lo;0;L;;;;;N;;;;;
+1750;BUHID LETTER SA;Lo;0;L;;;;;N;;;;;
+1751;BUHID LETTER HA;Lo;0;L;;;;;N;;;;;
+1752;BUHID VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1753;BUHID VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1760;TAGBANWA LETTER A;Lo;0;L;;;;;N;;;;;
+1761;TAGBANWA LETTER I;Lo;0;L;;;;;N;;;;;
+1762;TAGBANWA LETTER U;Lo;0;L;;;;;N;;;;;
+1763;TAGBANWA LETTER KA;Lo;0;L;;;;;N;;;;;
+1764;TAGBANWA LETTER GA;Lo;0;L;;;;;N;;;;;
+1765;TAGBANWA LETTER NGA;Lo;0;L;;;;;N;;;;;
+1766;TAGBANWA LETTER TA;Lo;0;L;;;;;N;;;;;
+1767;TAGBANWA LETTER DA;Lo;0;L;;;;;N;;;;;
+1768;TAGBANWA LETTER NA;Lo;0;L;;;;;N;;;;;
+1769;TAGBANWA LETTER PA;Lo;0;L;;;;;N;;;;;
+176A;TAGBANWA LETTER BA;Lo;0;L;;;;;N;;;;;
+176B;TAGBANWA LETTER MA;Lo;0;L;;;;;N;;;;;
+176C;TAGBANWA LETTER YA;Lo;0;L;;;;;N;;;;;
+176E;TAGBANWA LETTER LA;Lo;0;L;;;;;N;;;;;
+176F;TAGBANWA LETTER WA;Lo;0;L;;;;;N;;;;;
+1770;TAGBANWA LETTER SA;Lo;0;L;;;;;N;;;;;
+1772;TAGBANWA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1773;TAGBANWA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;;
+1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;;
+1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;;
+1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;;
+1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;;
+1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;;
+1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;;
+1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;;
+1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;;
+1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;;
+178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;;
+178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;;
+178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;;
+178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;;
+178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;;
+178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;;
+1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;;
+1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;;
+1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;;
+1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;;
+1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;;
+1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;;
+1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;;
+1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;;
+1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;;
+1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;;
+179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;;
+179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;;
+179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;;
+179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;;
+179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;;
+179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;;
+17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;;
+17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;;
+17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;;
+17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;*;;;
+17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;*;;;
+17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;;
+17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;;
+17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;;
+17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;;
+17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;;
+17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;;
+17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;;
+17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;;
+17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;;
+17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;;
+17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;;
+17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;;
+17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;;
+17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;;
+17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;;
+17B4;KHMER VOWEL INHERENT AQ;Cf;0;L;;;;;N;;*;;;
+17B5;KHMER VOWEL INHERENT AA;Cf;0;L;;;;;N;;*;;;
+17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;;
+17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;;
+17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;;
+17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;;
+17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;;
+17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;;
+17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;;
+17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;;
+17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;;
+17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;;
+17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;;
+17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;;
+17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;;
+17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;;
+17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;;
+17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;;
+17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;;
+17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;*;;;
+17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;;
+17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;;
+17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;;
+17D7;KHMER SIGN LEK TOO;Lm;0;L;;;;;N;;;;;
+17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;*;;;
+17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;;
+17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;;
+17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;;
+17DC;KHMER SIGN AVAKRAHASANYA;Lo;0;L;;;;;N;;;;;
+17DD;KHMER SIGN ATTHACAN;Mn;230;NSM;;;;;N;;;;;
+17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+17F0;KHMER SYMBOL LEK ATTAK SON;No;0;ON;;;;0;N;;;;;
+17F1;KHMER SYMBOL LEK ATTAK MUOY;No;0;ON;;;;1;N;;;;;
+17F2;KHMER SYMBOL LEK ATTAK PII;No;0;ON;;;;2;N;;;;;
+17F3;KHMER SYMBOL LEK ATTAK BEI;No;0;ON;;;;3;N;;;;;
+17F4;KHMER SYMBOL LEK ATTAK BUON;No;0;ON;;;;4;N;;;;;
+17F5;KHMER SYMBOL LEK ATTAK PRAM;No;0;ON;;;;5;N;;;;;
+17F6;KHMER SYMBOL LEK ATTAK PRAM-MUOY;No;0;ON;;;;6;N;;;;;
+17F7;KHMER SYMBOL LEK ATTAK PRAM-PII;No;0;ON;;;;7;N;;;;;
+17F8;KHMER SYMBOL LEK ATTAK PRAM-BEI;No;0;ON;;;;8;N;;;;;
+17F9;KHMER SYMBOL LEK ATTAK PRAM-BUON;No;0;ON;;;;9;N;;;;;
+1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;;
+1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;;
+1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;;
+1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;;
+1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;;
+1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;;
+1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;;
+1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;;
+1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;;
+1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;;
+180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;;
+180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Mn;0;NSM;;;;;N;;;;;
+180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Mn;0;NSM;;;;;N;;;;;
+180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Mn;0;NSM;;;;;N;;;;;
+180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
+1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;;
+1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;;
+1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;;
+1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;;
+1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;;
+1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;;
+1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;;
+1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;;
+1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;;
+1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;;
+182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;;
+182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;;
+182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;;
+182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;;
+182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;;
+182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;;
+1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;;
+1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;;
+1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;;
+1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;;
+1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;;
+1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;;
+1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;;
+1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;;
+183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;;
+183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;;
+183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;;
+1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;;
+1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;;
+1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;;
+1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;;
+1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;;
+1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;;
+1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;;
+1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;;
+1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;;
+1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;;
+184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;;
+184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;;
+184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;;
+184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;;
+184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;;
+184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;;
+1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;;
+1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;;
+1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;;
+1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;;
+1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;;
+1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;;
+1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;;
+1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;;
+1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;;
+1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;;
+185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;;
+185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;;
+185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;;
+185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;;
+185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;;
+185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;;
+1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;;
+1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;;
+1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;;
+1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;;
+1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;;
+1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;;
+1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;;
+1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;;
+1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;;
+1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;;
+186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;;
+186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;;
+186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;;
+186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;;
+186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;;
+186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;;
+1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;;
+1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;;
+1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;;
+1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;;
+1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;;
+1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;;
+1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;;
+1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;;
+1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;;
+1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;;
+1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;;
+1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;;
+1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;;
+1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;;
+1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;;
+1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;;
+1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;;
+1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;;
+188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;;
+188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;;
+188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;;
+188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;;
+1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;;
+1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;;
+1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;;
+1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;;
+1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;;
+189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;;
+189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;;
+189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;;
+18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;;
+18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;;
+18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;;
+18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;;
+18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;;
+18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;;
+18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;;
+1900;LIMBU VOWEL-CARRIER LETTER;Lo;0;L;;;;;N;;;;;
+1901;LIMBU LETTER KA;Lo;0;L;;;;;N;;;;;
+1902;LIMBU LETTER KHA;Lo;0;L;;;;;N;;;;;
+1903;LIMBU LETTER GA;Lo;0;L;;;;;N;;;;;
+1904;LIMBU LETTER GHA;Lo;0;L;;;;;N;;;;;
+1905;LIMBU LETTER NGA;Lo;0;L;;;;;N;;;;;
+1906;LIMBU LETTER CA;Lo;0;L;;;;;N;;;;;
+1907;LIMBU LETTER CHA;Lo;0;L;;;;;N;;;;;
+1908;LIMBU LETTER JA;Lo;0;L;;;;;N;;;;;
+1909;LIMBU LETTER JHA;Lo;0;L;;;;;N;;;;;
+190A;LIMBU LETTER YAN;Lo;0;L;;;;;N;;;;;
+190B;LIMBU LETTER TA;Lo;0;L;;;;;N;;;;;
+190C;LIMBU LETTER THA;Lo;0;L;;;;;N;;;;;
+190D;LIMBU LETTER DA;Lo;0;L;;;;;N;;;;;
+190E;LIMBU LETTER DHA;Lo;0;L;;;;;N;;;;;
+190F;LIMBU LETTER NA;Lo;0;L;;;;;N;;;;;
+1910;LIMBU LETTER PA;Lo;0;L;;;;;N;;;;;
+1911;LIMBU LETTER PHA;Lo;0;L;;;;;N;;;;;
+1912;LIMBU LETTER BA;Lo;0;L;;;;;N;;;;;
+1913;LIMBU LETTER BHA;Lo;0;L;;;;;N;;;;;
+1914;LIMBU LETTER MA;Lo;0;L;;;;;N;;;;;
+1915;LIMBU LETTER YA;Lo;0;L;;;;;N;;;;;
+1916;LIMBU LETTER RA;Lo;0;L;;;;;N;;;;;
+1917;LIMBU LETTER LA;Lo;0;L;;;;;N;;;;;
+1918;LIMBU LETTER WA;Lo;0;L;;;;;N;;;;;
+1919;LIMBU LETTER SHA;Lo;0;L;;;;;N;;;;;
+191A;LIMBU LETTER SSA;Lo;0;L;;;;;N;;;;;
+191B;LIMBU LETTER SA;Lo;0;L;;;;;N;;;;;
+191C;LIMBU LETTER HA;Lo;0;L;;;;;N;;;;;
+1920;LIMBU VOWEL SIGN A;Mn;0;NSM;;;;;N;;;;;
+1921;LIMBU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+1922;LIMBU VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1923;LIMBU VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+1924;LIMBU VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+1925;LIMBU VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+1926;LIMBU VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+1927;LIMBU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+1928;LIMBU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+1929;LIMBU SUBJOINED LETTER YA;Mc;0;NSM;;;;;N;;;;;
+192A;LIMBU SUBJOINED LETTER RA;Mc;0;NSM;;;;;N;;;;;
+192B;LIMBU SUBJOINED LETTER WA;Mc;0;NSM;;;;;N;;;;;
+1930;LIMBU SMALL LETTER KA;Mc;0;L;;;;;N;;;;;
+1931;LIMBU SMALL LETTER NGA;Mc;0;L;;;;;N;;;;;
+1932;LIMBU SMALL LETTER ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1933;LIMBU SMALL LETTER TA;Mc;0;L;;;;;N;;;;;
+1934;LIMBU SMALL LETTER NA;Mc;0;L;;;;;N;;;;;
+1935;LIMBU SMALL LETTER PA;Mc;0;L;;;;;N;;;;;
+1936;LIMBU SMALL LETTER MA;Mc;0;L;;;;;N;;;;;
+1937;LIMBU SMALL LETTER RA;Mc;0;L;;;;;N;;;;;
+1938;LIMBU SMALL LETTER LA;Mc;0;L;;;;;N;;;;;
+1939;LIMBU SIGN MUKPHRENG;Mn;222;NSM;;;;;N;;;;;
+193A;LIMBU SIGN KEMPHRENG;Mn;230;NSM;;;;;N;;;;;
+193B;LIMBU SIGN SA-I;Mn;220;NSM;;;;;N;;;;;
+1940;LIMBU SIGN LOO;So;0;ON;;;;;N;;;;;
+1944;LIMBU EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+1945;LIMBU QUESTION MARK;Po;0;ON;;;;;N;;;;;
+1946;LIMBU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1947;LIMBU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1948;LIMBU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1949;LIMBU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+194A;LIMBU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+194B;LIMBU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+194C;LIMBU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+194D;LIMBU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+194E;LIMBU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+194F;LIMBU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1950;TAI LE LETTER KA;Lo;0;L;;;;;N;;;;;
+1951;TAI LE LETTER XA;Lo;0;L;;;;;N;;;;;
+1952;TAI LE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1953;TAI LE LETTER TSA;Lo;0;L;;;;;N;;;;;
+1954;TAI LE LETTER SA;Lo;0;L;;;;;N;;;;;
+1955;TAI LE LETTER YA;Lo;0;L;;;;;N;;;;;
+1956;TAI LE LETTER TA;Lo;0;L;;;;;N;;;;;
+1957;TAI LE LETTER THA;Lo;0;L;;;;;N;;;;;
+1958;TAI LE LETTER LA;Lo;0;L;;;;;N;;;;;
+1959;TAI LE LETTER PA;Lo;0;L;;;;;N;;;;;
+195A;TAI LE LETTER PHA;Lo;0;L;;;;;N;;;;;
+195B;TAI LE LETTER MA;Lo;0;L;;;;;N;;;;;
+195C;TAI LE LETTER FA;Lo;0;L;;;;;N;;;;;
+195D;TAI LE LETTER VA;Lo;0;L;;;;;N;;;;;
+195E;TAI LE LETTER HA;Lo;0;L;;;;;N;;;;;
+195F;TAI LE LETTER QA;Lo;0;L;;;;;N;;;;;
+1960;TAI LE LETTER KHA;Lo;0;L;;;;;N;;;;;
+1961;TAI LE LETTER TSHA;Lo;0;L;;;;;N;;;;;
+1962;TAI LE LETTER NA;Lo;0;L;;;;;N;;;;;
+1963;TAI LE LETTER A;Lo;0;L;;;;;N;;;;;
+1964;TAI LE LETTER I;Lo;0;L;;;;;N;;;;;
+1965;TAI LE LETTER EE;Lo;0;L;;;;;N;;;;;
+1966;TAI LE LETTER EH;Lo;0;L;;;;;N;;;;;
+1967;TAI LE LETTER U;Lo;0;L;;;;;N;;;;;
+1968;TAI LE LETTER OO;Lo;0;L;;;;;N;;;;;
+1969;TAI LE LETTER O;Lo;0;L;;;;;N;;;;;
+196A;TAI LE LETTER UE;Lo;0;L;;;;;N;;;;;
+196B;TAI LE LETTER E;Lo;0;L;;;;;N;;;;;
+196C;TAI LE LETTER AUE;Lo;0;L;;;;;N;;;;;
+196D;TAI LE LETTER AI;Lo;0;L;;;;;N;;;;;
+1970;TAI LE LETTER TONE-2;Lo;0;L;;;;;N;;;;;
+1971;TAI LE LETTER TONE-3;Lo;0;L;;;;;N;;;;;
+1972;TAI LE LETTER TONE-4;Lo;0;L;;;;;N;;;;;
+1973;TAI LE LETTER TONE-5;Lo;0;L;;;;;N;;;;;
+1974;TAI LE LETTER TONE-6;Lo;0;L;;;;;N;;;;;
+1980;NEW TAI LUE LETTER HIGH QA;Lo;0;L;;;;;N;;;;;
+1981;NEW TAI LUE LETTER LOW QA;Lo;0;L;;;;;N;;;;;
+1982;NEW TAI LUE LETTER HIGH KA;Lo;0;L;;;;;N;;;;;
+1983;NEW TAI LUE LETTER HIGH XA;Lo;0;L;;;;;N;;;;;
+1984;NEW TAI LUE LETTER HIGH NGA;Lo;0;L;;;;;N;;;;;
+1985;NEW TAI LUE LETTER LOW KA;Lo;0;L;;;;;N;;;;;
+1986;NEW TAI LUE LETTER LOW XA;Lo;0;L;;;;;N;;;;;
+1987;NEW TAI LUE LETTER LOW NGA;Lo;0;L;;;;;N;;;;;
+1988;NEW TAI LUE LETTER HIGH TSA;Lo;0;L;;;;;N;;;;;
+1989;NEW TAI LUE LETTER HIGH SA;Lo;0;L;;;;;N;;;;;
+198A;NEW TAI LUE LETTER HIGH YA;Lo;0;L;;;;;N;;;;;
+198B;NEW TAI LUE LETTER LOW TSA;Lo;0;L;;;;;N;;;;;
+198C;NEW TAI LUE LETTER LOW SA;Lo;0;L;;;;;N;;;;;
+198D;NEW TAI LUE LETTER LOW YA;Lo;0;L;;;;;N;;;;;
+198E;NEW TAI LUE LETTER HIGH TA;Lo;0;L;;;;;N;;;;;
+198F;NEW TAI LUE LETTER HIGH THA;Lo;0;L;;;;;N;;;;;
+1990;NEW TAI LUE LETTER HIGH NA;Lo;0;L;;;;;N;;;;;
+1991;NEW TAI LUE LETTER LOW TA;Lo;0;L;;;;;N;;;;;
+1992;NEW TAI LUE LETTER LOW THA;Lo;0;L;;;;;N;;;;;
+1993;NEW TAI LUE LETTER LOW NA;Lo;0;L;;;;;N;;;;;
+1994;NEW TAI LUE LETTER HIGH PA;Lo;0;L;;;;;N;;;;;
+1995;NEW TAI LUE LETTER HIGH PHA;Lo;0;L;;;;;N;;;;;
+1996;NEW TAI LUE LETTER HIGH MA;Lo;0;L;;;;;N;;;;;
+1997;NEW TAI LUE LETTER LOW PA;Lo;0;L;;;;;N;;;;;
+1998;NEW TAI LUE LETTER LOW PHA;Lo;0;L;;;;;N;;;;;
+1999;NEW TAI LUE LETTER LOW MA;Lo;0;L;;;;;N;;;;;
+199A;NEW TAI LUE LETTER HIGH FA;Lo;0;L;;;;;N;;;;;
+199B;NEW TAI LUE LETTER HIGH VA;Lo;0;L;;;;;N;;;;;
+199C;NEW TAI LUE LETTER HIGH LA;Lo;0;L;;;;;N;;;;;
+199D;NEW TAI LUE LETTER LOW FA;Lo;0;L;;;;;N;;;;;
+199E;NEW TAI LUE LETTER LOW VA;Lo;0;L;;;;;N;;;;;
+199F;NEW TAI LUE LETTER LOW LA;Lo;0;L;;;;;N;;;;;
+19A0;NEW TAI LUE LETTER HIGH HA;Lo;0;L;;;;;N;;;;;
+19A1;NEW TAI LUE LETTER HIGH DA;Lo;0;L;;;;;N;;;;;
+19A2;NEW TAI LUE LETTER HIGH BA;Lo;0;L;;;;;N;;;;;
+19A3;NEW TAI LUE LETTER LOW HA;Lo;0;L;;;;;N;;;;;
+19A4;NEW TAI LUE LETTER LOW DA;Lo;0;L;;;;;N;;;;;
+19A5;NEW TAI LUE LETTER LOW BA;Lo;0;L;;;;;N;;;;;
+19A6;NEW TAI LUE LETTER HIGH KVA;Lo;0;L;;;;;N;;;;;
+19A7;NEW TAI LUE LETTER HIGH XVA;Lo;0;L;;;;;N;;;;;
+19A8;NEW TAI LUE LETTER LOW KVA;Lo;0;L;;;;;N;;;;;
+19A9;NEW TAI LUE LETTER LOW XVA;Lo;0;L;;;;;N;;;;;
+19B0;NEW TAI LUE VOWEL SIGN VOWEL SHORTENER;Mc;0;L;;;;;N;;;;;
+19B1;NEW TAI LUE VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+19B2;NEW TAI LUE VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+19B3;NEW TAI LUE VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+19B4;NEW TAI LUE VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+19B5;NEW TAI LUE VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+19B6;NEW TAI LUE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+19B7;NEW TAI LUE VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+19B8;NEW TAI LUE VOWEL SIGN OA;Mc;0;L;;;;;N;;;;;
+19B9;NEW TAI LUE VOWEL SIGN UE;Mc;0;L;;;;;N;;;;;
+19BA;NEW TAI LUE VOWEL SIGN AY;Mc;0;L;;;;;N;;;;;
+19BB;NEW TAI LUE VOWEL SIGN AAY;Mc;0;L;;;;;N;;;;;
+19BC;NEW TAI LUE VOWEL SIGN UY;Mc;0;L;;;;;N;;;;;
+19BD;NEW TAI LUE VOWEL SIGN OY;Mc;0;L;;;;;N;;;;;
+19BE;NEW TAI LUE VOWEL SIGN OAY;Mc;0;L;;;;;N;;;;;
+19BF;NEW TAI LUE VOWEL SIGN UEY;Mc;0;L;;;;;N;;;;;
+19C0;NEW TAI LUE VOWEL SIGN IY;Mc;0;L;;;;;N;;;;;
+19C1;NEW TAI LUE LETTER FINAL V;Lo;0;L;;;;;N;;;;;
+19C2;NEW TAI LUE LETTER FINAL NG;Lo;0;L;;;;;N;;;;;
+19C3;NEW TAI LUE LETTER FINAL N;Lo;0;L;;;;;N;;;;;
+19C4;NEW TAI LUE LETTER FINAL M;Lo;0;L;;;;;N;;;;;
+19C5;NEW TAI LUE LETTER FINAL K;Lo;0;L;;;;;N;;;;;
+19C6;NEW TAI LUE LETTER FINAL D;Lo;0;L;;;;;N;;;;;
+19C7;NEW TAI LUE LETTER FINAL B;Lo;0;L;;;;;N;;;;;
+19C8;NEW TAI LUE TONE MARK-1;Mc;0;L;;;;;N;;;;;
+19C9;NEW TAI LUE TONE MARK-2;Mc;0;L;;;;;N;;;;;
+19D0;NEW TAI LUE DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+19D1;NEW TAI LUE DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+19D2;NEW TAI LUE DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+19D3;NEW TAI LUE DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+19D4;NEW TAI LUE DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+19D5;NEW TAI LUE DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+19D6;NEW TAI LUE DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+19D7;NEW TAI LUE DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+19D8;NEW TAI LUE DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+19D9;NEW TAI LUE DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+19DE;NEW TAI LUE SIGN LAE;Po;0;ON;;;;;N;;;;;
+19DF;NEW TAI LUE SIGN LAEV;Po;0;ON;;;;;N;;;;;
+19E0;KHMER SYMBOL PATHAMASAT;So;0;ON;;;;;N;;;;;
+19E1;KHMER SYMBOL MUOY KOET;So;0;ON;;;;;N;;;;;
+19E2;KHMER SYMBOL PII KOET;So;0;ON;;;;;N;;;;;
+19E3;KHMER SYMBOL BEI KOET;So;0;ON;;;;;N;;;;;
+19E4;KHMER SYMBOL BUON KOET;So;0;ON;;;;;N;;;;;
+19E5;KHMER SYMBOL PRAM KOET;So;0;ON;;;;;N;;;;;
+19E6;KHMER SYMBOL PRAM-MUOY KOET;So;0;ON;;;;;N;;;;;
+19E7;KHMER SYMBOL PRAM-PII KOET;So;0;ON;;;;;N;;;;;
+19E8;KHMER SYMBOL PRAM-BEI KOET;So;0;ON;;;;;N;;;;;
+19E9;KHMER SYMBOL PRAM-BUON KOET;So;0;ON;;;;;N;;;;;
+19EA;KHMER SYMBOL DAP KOET;So;0;ON;;;;;N;;;;;
+19EB;KHMER SYMBOL DAP-MUOY KOET;So;0;ON;;;;;N;;;;;
+19EC;KHMER SYMBOL DAP-PII KOET;So;0;ON;;;;;N;;;;;
+19ED;KHMER SYMBOL DAP-BEI KOET;So;0;ON;;;;;N;;;;;
+19EE;KHMER SYMBOL DAP-BUON KOET;So;0;ON;;;;;N;;;;;
+19EF;KHMER SYMBOL DAP-PRAM KOET;So;0;ON;;;;;N;;;;;
+19F0;KHMER SYMBOL TUTEYASAT;So;0;ON;;;;;N;;;;;
+19F1;KHMER SYMBOL MUOY ROC;So;0;ON;;;;;N;;;;;
+19F2;KHMER SYMBOL PII ROC;So;0;ON;;;;;N;;;;;
+19F3;KHMER SYMBOL BEI ROC;So;0;ON;;;;;N;;;;;
+19F4;KHMER SYMBOL BUON ROC;So;0;ON;;;;;N;;;;;
+19F5;KHMER SYMBOL PRAM ROC;So;0;ON;;;;;N;;;;;
+19F6;KHMER SYMBOL PRAM-MUOY ROC;So;0;ON;;;;;N;;;;;
+19F7;KHMER SYMBOL PRAM-PII ROC;So;0;ON;;;;;N;;;;;
+19F8;KHMER SYMBOL PRAM-BEI ROC;So;0;ON;;;;;N;;;;;
+19F9;KHMER SYMBOL PRAM-BUON ROC;So;0;ON;;;;;N;;;;;
+19FA;KHMER SYMBOL DAP ROC;So;0;ON;;;;;N;;;;;
+19FB;KHMER SYMBOL DAP-MUOY ROC;So;0;ON;;;;;N;;;;;
+19FC;KHMER SYMBOL DAP-PII ROC;So;0;ON;;;;;N;;;;;
+19FD;KHMER SYMBOL DAP-BEI ROC;So;0;ON;;;;;N;;;;;
+19FE;KHMER SYMBOL DAP-BUON ROC;So;0;ON;;;;;N;;;;;
+19FF;KHMER SYMBOL DAP-PRAM ROC;So;0;ON;;;;;N;;;;;
+1A00;BUGINESE LETTER KA;Lo;0;L;;;;;N;;;;;
+1A01;BUGINESE LETTER GA;Lo;0;L;;;;;N;;;;;
+1A02;BUGINESE LETTER NGA;Lo;0;L;;;;;N;;;;;
+1A03;BUGINESE LETTER NGKA;Lo;0;L;;;;;N;;;;;
+1A04;BUGINESE LETTER PA;Lo;0;L;;;;;N;;;;;
+1A05;BUGINESE LETTER BA;Lo;0;L;;;;;N;;;;;
+1A06;BUGINESE LETTER MA;Lo;0;L;;;;;N;;;;;
+1A07;BUGINESE LETTER MPA;Lo;0;L;;;;;N;;;;;
+1A08;BUGINESE LETTER TA;Lo;0;L;;;;;N;;;;;
+1A09;BUGINESE LETTER DA;Lo;0;L;;;;;N;;;;;
+1A0A;BUGINESE LETTER NA;Lo;0;L;;;;;N;;;;;
+1A0B;BUGINESE LETTER NRA;Lo;0;L;;;;;N;;;;;
+1A0C;BUGINESE LETTER CA;Lo;0;L;;;;;N;;;;;
+1A0D;BUGINESE LETTER JA;Lo;0;L;;;;;N;;;;;
+1A0E;BUGINESE LETTER NYA;Lo;0;L;;;;;N;;;;;
+1A0F;BUGINESE LETTER NYCA;Lo;0;L;;;;;N;;;;;
+1A10;BUGINESE LETTER YA;Lo;0;L;;;;;N;;;;;
+1A11;BUGINESE LETTER RA;Lo;0;L;;;;;N;;;;;
+1A12;BUGINESE LETTER LA;Lo;0;L;;;;;N;;;;;
+1A13;BUGINESE LETTER VA;Lo;0;L;;;;;N;;;;;
+1A14;BUGINESE LETTER SA;Lo;0;L;;;;;N;;;;;
+1A15;BUGINESE LETTER A;Lo;0;L;;;;;N;;;;;
+1A16;BUGINESE LETTER HA;Lo;0;L;;;;;N;;;;;
+1A17;BUGINESE VOWEL SIGN I;Mn;230;NSM;;;;;N;;;;;
+1A18;BUGINESE VOWEL SIGN U;Mn;220;NSM;;;;;N;;;;;
+1A19;BUGINESE VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1A1A;BUGINESE VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+1A1B;BUGINESE VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+1A1E;BUGINESE PALLAWA;Po;0;L;;;;;N;;;;;
+1A1F;BUGINESE END OF SECTION;Po;0;L;;;;;N;;;;;
+1D00;LATIN LETTER SMALL CAPITAL A;Ll;0;L;;;;;N;;;;;
+1D01;LATIN LETTER SMALL CAPITAL AE;Ll;0;L;;;;;N;;;;;
+1D02;LATIN SMALL LETTER TURNED AE;Ll;0;L;;;;;N;;;;;
+1D03;LATIN LETTER SMALL CAPITAL BARRED B;Ll;0;L;;;;;N;;;;;
+1D04;LATIN LETTER SMALL CAPITAL C;Ll;0;L;;;;;N;;;;;
+1D05;LATIN LETTER SMALL CAPITAL D;Ll;0;L;;;;;N;;;;;
+1D06;LATIN LETTER SMALL CAPITAL ETH;Ll;0;L;;;;;N;;;;;
+1D07;LATIN LETTER SMALL CAPITAL E;Ll;0;L;;;;;N;;;;;
+1D08;LATIN SMALL LETTER TURNED OPEN E;Ll;0;L;;;;;N;;;;;
+1D09;LATIN SMALL LETTER TURNED I;Ll;0;L;;;;;N;;;;;
+1D0A;LATIN LETTER SMALL CAPITAL J;Ll;0;L;;;;;N;;;;;
+1D0B;LATIN LETTER SMALL CAPITAL K;Ll;0;L;;;;;N;;;;;
+1D0C;LATIN LETTER SMALL CAPITAL L WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D0D;LATIN LETTER SMALL CAPITAL M;Ll;0;L;;;;;N;;;;;
+1D0E;LATIN LETTER SMALL CAPITAL REVERSED N;Ll;0;L;;;;;N;;;;;
+1D0F;LATIN LETTER SMALL CAPITAL O;Ll;0;L;;;;;N;;;;;
+1D10;LATIN LETTER SMALL CAPITAL OPEN O;Ll;0;L;;;;;N;;;;;
+1D11;LATIN SMALL LETTER SIDEWAYS O;Ll;0;L;;;;;N;;;;;
+1D12;LATIN SMALL LETTER SIDEWAYS OPEN O;Ll;0;L;;;;;N;;;;;
+1D13;LATIN SMALL LETTER SIDEWAYS O WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D14;LATIN SMALL LETTER TURNED OE;Ll;0;L;;;;;N;;;;;
+1D15;LATIN LETTER SMALL CAPITAL OU;Ll;0;L;;;;;N;;;;;
+1D16;LATIN SMALL LETTER TOP HALF O;Ll;0;L;;;;;N;;;;;
+1D17;LATIN SMALL LETTER BOTTOM HALF O;Ll;0;L;;;;;N;;;;;
+1D18;LATIN LETTER SMALL CAPITAL P;Ll;0;L;;;;;N;;;;;
+1D19;LATIN LETTER SMALL CAPITAL REVERSED R;Ll;0;L;;;;;N;;;;;
+1D1A;LATIN LETTER SMALL CAPITAL TURNED R;Ll;0;L;;;;;N;;;;;
+1D1B;LATIN LETTER SMALL CAPITAL T;Ll;0;L;;;;;N;;;;;
+1D1C;LATIN LETTER SMALL CAPITAL U;Ll;0;L;;;;;N;;;;;
+1D1D;LATIN SMALL LETTER SIDEWAYS U;Ll;0;L;;;;;N;;;;;
+1D1E;LATIN SMALL LETTER SIDEWAYS DIAERESIZED U;Ll;0;L;;;;;N;;;;;
+1D1F;LATIN SMALL LETTER SIDEWAYS TURNED M;Ll;0;L;;;;;N;;;;;
+1D20;LATIN LETTER SMALL CAPITAL V;Ll;0;L;;;;;N;;;;;
+1D21;LATIN LETTER SMALL CAPITAL W;Ll;0;L;;;;;N;;;;;
+1D22;LATIN LETTER SMALL CAPITAL Z;Ll;0;L;;;;;N;;;;;
+1D23;LATIN LETTER SMALL CAPITAL EZH;Ll;0;L;;;;;N;;;;;
+1D24;LATIN LETTER VOICED LARYNGEAL SPIRANT;Ll;0;L;;;;;N;;;;;
+1D25;LATIN LETTER AIN;Ll;0;L;;;;;N;;;;;
+1D26;GREEK LETTER SMALL CAPITAL GAMMA;Ll;0;L;;;;;N;;;;;
+1D27;GREEK LETTER SMALL CAPITAL LAMDA;Ll;0;L;;;;;N;;;;;
+1D28;GREEK LETTER SMALL CAPITAL PI;Ll;0;L;;;;;N;;;;;
+1D29;GREEK LETTER SMALL CAPITAL RHO;Ll;0;L;;;;;N;;;;;
+1D2A;GREEK LETTER SMALL CAPITAL PSI;Ll;0;L;;;;;N;;;;;
+1D2B;CYRILLIC LETTER SMALL CAPITAL EL;Ll;0;L;;;;;N;;;;;
+1D2C;MODIFIER LETTER CAPITAL A;Lm;0;L;<super> 0041;;;;N;;;;;
+1D2D;MODIFIER LETTER CAPITAL AE;Lm;0;L;<super> 00C6;;;;N;;;;;
+1D2E;MODIFIER LETTER CAPITAL B;Lm;0;L;<super> 0042;;;;N;;;;;
+1D2F;MODIFIER LETTER CAPITAL BARRED B;Lm;0;L;;;;;N;;;;;
+1D30;MODIFIER LETTER CAPITAL D;Lm;0;L;<super> 0044;;;;N;;;;;
+1D31;MODIFIER LETTER CAPITAL E;Lm;0;L;<super> 0045;;;;N;;;;;
+1D32;MODIFIER LETTER CAPITAL REVERSED E;Lm;0;L;<super> 018E;;;;N;;;;;
+1D33;MODIFIER LETTER CAPITAL G;Lm;0;L;<super> 0047;;;;N;;;;;
+1D34;MODIFIER LETTER CAPITAL H;Lm;0;L;<super> 0048;;;;N;;;;;
+1D35;MODIFIER LETTER CAPITAL I;Lm;0;L;<super> 0049;;;;N;;;;;
+1D36;MODIFIER LETTER CAPITAL J;Lm;0;L;<super> 004A;;;;N;;;;;
+1D37;MODIFIER LETTER CAPITAL K;Lm;0;L;<super> 004B;;;;N;;;;;
+1D38;MODIFIER LETTER CAPITAL L;Lm;0;L;<super> 004C;;;;N;;;;;
+1D39;MODIFIER LETTER CAPITAL M;Lm;0;L;<super> 004D;;;;N;;;;;
+1D3A;MODIFIER LETTER CAPITAL N;Lm;0;L;<super> 004E;;;;N;;;;;
+1D3B;MODIFIER LETTER CAPITAL REVERSED N;Lm;0;L;;;;;N;;;;;
+1D3C;MODIFIER LETTER CAPITAL O;Lm;0;L;<super> 004F;;;;N;;;;;
+1D3D;MODIFIER LETTER CAPITAL OU;Lm;0;L;<super> 0222;;;;N;;;;;
+1D3E;MODIFIER LETTER CAPITAL P;Lm;0;L;<super> 0050;;;;N;;;;;
+1D3F;MODIFIER LETTER CAPITAL R;Lm;0;L;<super> 0052;;;;N;;;;;
+1D40;MODIFIER LETTER CAPITAL T;Lm;0;L;<super> 0054;;;;N;;;;;
+1D41;MODIFIER LETTER CAPITAL U;Lm;0;L;<super> 0055;;;;N;;;;;
+1D42;MODIFIER LETTER CAPITAL W;Lm;0;L;<super> 0057;;;;N;;;;;
+1D43;MODIFIER LETTER SMALL A;Lm;0;L;<super> 0061;;;;N;;;;;
+1D44;MODIFIER LETTER SMALL TURNED A;Lm;0;L;<super> 0250;;;;N;;;;;
+1D45;MODIFIER LETTER SMALL ALPHA;Lm;0;L;<super> 0251;;;;N;;;;;
+1D46;MODIFIER LETTER SMALL TURNED AE;Lm;0;L;<super> 1D02;;;;N;;;;;
+1D47;MODIFIER LETTER SMALL B;Lm;0;L;<super> 0062;;;;N;;;;;
+1D48;MODIFIER LETTER SMALL D;Lm;0;L;<super> 0064;;;;N;;;;;
+1D49;MODIFIER LETTER SMALL E;Lm;0;L;<super> 0065;;;;N;;;;;
+1D4A;MODIFIER LETTER SMALL SCHWA;Lm;0;L;<super> 0259;;;;N;;;;;
+1D4B;MODIFIER LETTER SMALL OPEN E;Lm;0;L;<super> 025B;;;;N;;;;;
+1D4C;MODIFIER LETTER SMALL TURNED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;
+1D4D;MODIFIER LETTER SMALL G;Lm;0;L;<super> 0067;;;;N;;;;;
+1D4E;MODIFIER LETTER SMALL TURNED I;Lm;0;L;;;;;N;;;;;
+1D4F;MODIFIER LETTER SMALL K;Lm;0;L;<super> 006B;;;;N;;;;;
+1D50;MODIFIER LETTER SMALL M;Lm;0;L;<super> 006D;;;;N;;;;;
+1D51;MODIFIER LETTER SMALL ENG;Lm;0;L;<super> 014B;;;;N;;;;;
+1D52;MODIFIER LETTER SMALL O;Lm;0;L;<super> 006F;;;;N;;;;;
+1D53;MODIFIER LETTER SMALL OPEN O;Lm;0;L;<super> 0254;;;;N;;;;;
+1D54;MODIFIER LETTER SMALL TOP HALF O;Lm;0;L;<super> 1D16;;;;N;;;;;
+1D55;MODIFIER LETTER SMALL BOTTOM HALF O;Lm;0;L;<super> 1D17;;;;N;;;;;
+1D56;MODIFIER LETTER SMALL P;Lm;0;L;<super> 0070;;;;N;;;;;
+1D57;MODIFIER LETTER SMALL T;Lm;0;L;<super> 0074;;;;N;;;;;
+1D58;MODIFIER LETTER SMALL U;Lm;0;L;<super> 0075;;;;N;;;;;
+1D59;MODIFIER LETTER SMALL SIDEWAYS U;Lm;0;L;<super> 1D1D;;;;N;;;;;
+1D5A;MODIFIER LETTER SMALL TURNED M;Lm;0;L;<super> 026F;;;;N;;;;;
+1D5B;MODIFIER LETTER SMALL V;Lm;0;L;<super> 0076;;;;N;;;;;
+1D5C;MODIFIER LETTER SMALL AIN;Lm;0;L;<super> 1D25;;;;N;;;;;
+1D5D;MODIFIER LETTER SMALL BETA;Lm;0;L;<super> 03B2;;;;N;;;;;
+1D5E;MODIFIER LETTER SMALL GREEK GAMMA;Lm;0;L;<super> 03B3;;;;N;;;;;
+1D5F;MODIFIER LETTER SMALL DELTA;Lm;0;L;<super> 03B4;;;;N;;;;;
+1D60;MODIFIER LETTER SMALL GREEK PHI;Lm;0;L;<super> 03C6;;;;N;;;;;
+1D61;MODIFIER LETTER SMALL CHI;Lm;0;L;<super> 03C7;;;;N;;;;;
+1D62;LATIN SUBSCRIPT SMALL LETTER I;Ll;0;L;<sub> 0069;;;;N;;;;;
+1D63;LATIN SUBSCRIPT SMALL LETTER R;Ll;0;L;<sub> 0072;;;;N;;;;;
+1D64;LATIN SUBSCRIPT SMALL LETTER U;Ll;0;L;<sub> 0075;;;;N;;;;;
+1D65;LATIN SUBSCRIPT SMALL LETTER V;Ll;0;L;<sub> 0076;;;;N;;;;;
+1D66;GREEK SUBSCRIPT SMALL LETTER BETA;Ll;0;L;<sub> 03B2;;;;N;;;;;
+1D67;GREEK SUBSCRIPT SMALL LETTER GAMMA;Ll;0;L;<sub> 03B3;;;;N;;;;;
+1D68;GREEK SUBSCRIPT SMALL LETTER RHO;Ll;0;L;<sub> 03C1;;;;N;;;;;
+1D69;GREEK SUBSCRIPT SMALL LETTER PHI;Ll;0;L;<sub> 03C6;;;;N;;;;;
+1D6A;GREEK SUBSCRIPT SMALL LETTER CHI;Ll;0;L;<sub> 03C7;;;;N;;;;;
+1D6B;LATIN SMALL LETTER UE;Ll;0;L;;;;;N;;;;;
+1D6C;LATIN SMALL LETTER B WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6D;LATIN SMALL LETTER D WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6E;LATIN SMALL LETTER F WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D6F;LATIN SMALL LETTER M WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D70;LATIN SMALL LETTER N WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D71;LATIN SMALL LETTER P WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D72;LATIN SMALL LETTER R WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D73;LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D74;LATIN SMALL LETTER S WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D75;LATIN SMALL LETTER T WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D76;LATIN SMALL LETTER Z WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+1D77;LATIN SMALL LETTER TURNED G;Ll;0;L;;;;;N;;;;;
+1D78;MODIFIER LETTER CYRILLIC EN;Lm;0;L;<super> 043D;;;;N;;;;;
+1D79;LATIN SMALL LETTER INSULAR G;Ll;0;L;;;;;N;;;;;
+1D7A;LATIN SMALL LETTER TH WITH STRIKETHROUGH;Ll;0;L;;;;;N;;;;;
+1D7B;LATIN SMALL CAPITAL LETTER I WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7C;LATIN SMALL LETTER IOTA WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7D;LATIN SMALL LETTER P WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7E;LATIN SMALL CAPITAL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D7F;LATIN SMALL LETTER UPSILON WITH STROKE;Ll;0;L;;;;;N;;;;;
+1D80;LATIN SMALL LETTER B WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D81;LATIN SMALL LETTER D WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D82;LATIN SMALL LETTER F WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D83;LATIN SMALL LETTER G WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D84;LATIN SMALL LETTER K WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D85;LATIN SMALL LETTER L WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D86;LATIN SMALL LETTER M WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D87;LATIN SMALL LETTER N WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D88;LATIN SMALL LETTER P WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D89;LATIN SMALL LETTER R WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8A;LATIN SMALL LETTER S WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8B;LATIN SMALL LETTER ESH WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8C;LATIN SMALL LETTER V WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8D;LATIN SMALL LETTER X WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8E;LATIN SMALL LETTER Z WITH PALATAL HOOK;Ll;0;L;;;;;N;;;;;
+1D8F;LATIN SMALL LETTER A WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D90;LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D91;LATIN SMALL LETTER D WITH HOOK AND TAIL;Ll;0;L;;;;;N;;;;;
+1D92;LATIN SMALL LETTER E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D93;LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D94;LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D95;LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D96;LATIN SMALL LETTER I WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D97;LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D98;LATIN SMALL LETTER ESH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D99;LATIN SMALL LETTER U WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D9A;LATIN SMALL LETTER EZH WITH RETROFLEX HOOK;Ll;0;L;;;;;N;;;;;
+1D9B;MODIFIER LETTER SMALL TURNED ALPHA;Lm;0;L;<super> 0252;;;;N;;;;;
+1D9C;MODIFIER LETTER SMALL C;Lm;0;L;<super> 0063;;;;N;;;;;
+1D9D;MODIFIER LETTER SMALL C WITH CURL;Lm;0;L;<super> 0255;;;;N;;;;;
+1D9E;MODIFIER LETTER SMALL ETH;Lm;0;L;<super> 00F0;;;;N;;;;;
+1D9F;MODIFIER LETTER SMALL REVERSED OPEN E;Lm;0;L;<super> 025C;;;;N;;;;;
+1DA0;MODIFIER LETTER SMALL F;Lm;0;L;<super> 0066;;;;N;;;;;
+1DA1;MODIFIER LETTER SMALL DOTLESS J WITH STROKE;Lm;0;L;<super> 025F;;;;N;;;;;
+1DA2;MODIFIER LETTER SMALL SCRIPT G;Lm;0;L;<super> 0261;;;;N;;;;;
+1DA3;MODIFIER LETTER SMALL TURNED H;Lm;0;L;<super> 0265;;;;N;;;;;
+1DA4;MODIFIER LETTER SMALL I WITH STROKE;Lm;0;L;<super> 0268;;;;N;;;;;
+1DA5;MODIFIER LETTER SMALL IOTA;Lm;0;L;<super> 0269;;;;N;;;;;
+1DA6;MODIFIER LETTER SMALL CAPITAL I;Lm;0;L;<super> 026A;;;;N;;;;;
+1DA7;MODIFIER LETTER SMALL CAPITAL I WITH STROKE;Lm;0;L;<super> 1D7B;;;;N;;;;;
+1DA8;MODIFIER LETTER SMALL J WITH CROSSED-TAIL;Lm;0;L;<super> 029D;;;;N;;;;;
+1DA9;MODIFIER LETTER SMALL L WITH RETROFLEX HOOK;Lm;0;L;<super> 026D;;;;N;;;;;
+1DAA;MODIFIER LETTER SMALL L WITH PALATAL HOOK;Lm;0;L;<super> 1D85;;;;N;;;;;
+1DAB;MODIFIER LETTER SMALL CAPITAL L;Lm;0;L;<super> 029F;;;;N;;;;;
+1DAC;MODIFIER LETTER SMALL M WITH HOOK;Lm;0;L;<super> 0271;;;;N;;;;;
+1DAD;MODIFIER LETTER SMALL TURNED M WITH LONG LEG;Lm;0;L;<super> 0270;;;;N;;;;;
+1DAE;MODIFIER LETTER SMALL N WITH LEFT HOOK;Lm;0;L;<super> 0272;;;;N;;;;;
+1DAF;MODIFIER LETTER SMALL N WITH RETROFLEX HOOK;Lm;0;L;<super> 0273;;;;N;;;;;
+1DB0;MODIFIER LETTER SMALL CAPITAL N;Lm;0;L;<super> 0274;;;;N;;;;;
+1DB1;MODIFIER LETTER SMALL BARRED O;Lm;0;L;<super> 0275;;;;N;;;;;
+1DB2;MODIFIER LETTER SMALL PHI;Lm;0;L;<super> 0278;;;;N;;;;;
+1DB3;MODIFIER LETTER SMALL S WITH HOOK;Lm;0;L;<super> 0282;;;;N;;;;;
+1DB4;MODIFIER LETTER SMALL ESH;Lm;0;L;<super> 0283;;;;N;;;;;
+1DB5;MODIFIER LETTER SMALL T WITH PALATAL HOOK;Lm;0;L;<super> 01AB;;;;N;;;;;
+1DB6;MODIFIER LETTER SMALL U BAR;Lm;0;L;<super> 0289;;;;N;;;;;
+1DB7;MODIFIER LETTER SMALL UPSILON;Lm;0;L;<super> 028A;;;;N;;;;;
+1DB8;MODIFIER LETTER SMALL CAPITAL U;Lm;0;L;<super> 1D1C;;;;N;;;;;
+1DB9;MODIFIER LETTER SMALL V WITH HOOK;Lm;0;L;<super> 028B;;;;N;;;;;
+1DBA;MODIFIER LETTER SMALL TURNED V;Lm;0;L;<super> 028C;;;;N;;;;;
+1DBB;MODIFIER LETTER SMALL Z;Lm;0;L;<super> 007A;;;;N;;;;;
+1DBC;MODIFIER LETTER SMALL Z WITH RETROFLEX HOOK;Lm;0;L;<super> 0290;;;;N;;;;;
+1DBD;MODIFIER LETTER SMALL Z WITH CURL;Lm;0;L;<super> 0291;;;;N;;;;;
+1DBE;MODIFIER LETTER SMALL EZH;Lm;0;L;<super> 0292;;;;N;;;;;
+1DBF;MODIFIER LETTER SMALL THETA;Lm;0;L;<super> 03B8;;;;N;;;;;
+1DC0;COMBINING DOTTED GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;
+1DC1;COMBINING DOTTED ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;
+1DC2;COMBINING SNAKE BELOW;Mn;220;NSM;;;;;N;;;;;
+1DC3;COMBINING SUSPENSION MARK;Mn;230;NSM;;;;;N;;;;;
+1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01;
+1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00
+1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03;
+1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02
+1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05;
+1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04
+1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07;
+1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06
+1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09;
+1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08
+1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B;
+1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A
+1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D;
+1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C
+1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F;
+1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E
+1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11;
+1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10
+1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13;
+1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12
+1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15;
+1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14
+1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17;
+1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16
+1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19;
+1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18
+1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B;
+1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A
+1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D;
+1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C
+1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F;
+1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E
+1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21;
+1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20
+1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23;
+1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22
+1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25;
+1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24
+1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27;
+1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26
+1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29;
+1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28
+1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B;
+1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A
+1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D;
+1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C
+1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F;
+1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E
+1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31;
+1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30
+1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33;
+1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32
+1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35;
+1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34
+1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37;
+1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36
+1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39;
+1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38
+1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B;
+1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A
+1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D;
+1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C
+1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F;
+1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E
+1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41;
+1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40
+1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43;
+1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42
+1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45;
+1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44
+1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47;
+1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46
+1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49;
+1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48
+1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B;
+1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A
+1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D;
+1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C
+1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F;
+1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E
+1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51;
+1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50
+1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53;
+1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52
+1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55;
+1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54
+1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57;
+1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56
+1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59;
+1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58
+1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B;
+1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A
+1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D;
+1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C
+1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F;
+1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E
+1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61;
+1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60
+1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63;
+1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62
+1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65;
+1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64
+1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67;
+1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66
+1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69;
+1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68
+1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B;
+1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A
+1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D;
+1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C
+1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F;
+1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E
+1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71;
+1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70
+1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73;
+1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72
+1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75;
+1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74
+1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77;
+1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76
+1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79;
+1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78
+1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B;
+1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A
+1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D;
+1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C
+1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F;
+1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E
+1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81;
+1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80
+1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83;
+1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82
+1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85;
+1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84
+1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87;
+1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86
+1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89;
+1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88
+1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B;
+1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A
+1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D;
+1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C
+1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F;
+1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E
+1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91;
+1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90
+1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93;
+1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92
+1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95;
+1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94
+1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;;
+1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;;
+1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;;
+1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;;
+1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;;
+1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60
+1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1;
+1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0
+1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3;
+1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2
+1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5;
+1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4
+1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7;
+1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6
+1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9;
+1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8
+1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB;
+1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA
+1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD;
+1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC
+1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF;
+1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE
+1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1;
+1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0
+1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3;
+1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2
+1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5;
+1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4
+1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7;
+1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6
+1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9;
+1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8
+1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB;
+1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA
+1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD;
+1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC
+1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF;
+1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE
+1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1;
+1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0
+1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3;
+1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2
+1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5;
+1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4
+1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7;
+1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6
+1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9;
+1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8
+1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB;
+1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA
+1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD;
+1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC
+1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF;
+1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE
+1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1;
+1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0
+1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3;
+1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2
+1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5;
+1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4
+1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7;
+1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6
+1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9;
+1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8
+1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB;
+1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA
+1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD;
+1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC
+1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF;
+1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE
+1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1;
+1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0
+1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3;
+1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2
+1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5;
+1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4
+1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7;
+1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6
+1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9;
+1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8
+1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB;
+1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA
+1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED;
+1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC
+1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF;
+1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE
+1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1;
+1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0
+1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3;
+1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2
+1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5;
+1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4
+1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7;
+1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6
+1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9;
+1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8
+1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08
+1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09
+1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A
+1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B
+1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C
+1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D
+1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E
+1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F
+1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00;
+1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01;
+1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02;
+1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03;
+1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04;
+1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05;
+1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06;
+1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07;
+1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18
+1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19
+1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A
+1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B
+1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C
+1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D
+1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10;
+1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11;
+1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12;
+1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13;
+1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14;
+1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15;
+1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28
+1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29
+1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A
+1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B
+1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C
+1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D
+1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E
+1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F
+1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20;
+1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21;
+1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22;
+1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23;
+1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24;
+1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25;
+1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26;
+1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27;
+1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38
+1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39
+1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A
+1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B
+1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C
+1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D
+1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E
+1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F
+1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30;
+1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31;
+1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32;
+1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33;
+1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34;
+1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35;
+1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36;
+1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37;
+1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48
+1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49
+1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A
+1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B
+1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C
+1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D
+1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40;
+1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41;
+1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42;
+1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43;
+1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44;
+1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45;
+1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;;
+1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59
+1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;;
+1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B
+1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;;
+1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D
+1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;;
+1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F
+1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51;
+1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53;
+1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55;
+1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57;
+1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68
+1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69
+1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A
+1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B
+1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C
+1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D
+1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E
+1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F
+1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60;
+1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61;
+1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62;
+1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63;
+1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64;
+1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65;
+1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66;
+1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67;
+1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA
+1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB
+1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8
+1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9
+1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA
+1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB
+1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA
+1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB
+1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8
+1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9
+1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA
+1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB
+1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA
+1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB
+1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88
+1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89
+1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A
+1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B
+1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C
+1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D
+1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E
+1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F
+1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80;
+1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81;
+1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82;
+1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83;
+1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84;
+1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85;
+1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86;
+1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87;
+1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98
+1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99
+1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A
+1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B
+1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C
+1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D
+1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E
+1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F
+1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90;
+1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91;
+1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92;
+1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93;
+1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94;
+1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95;
+1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96;
+1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97;
+1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8
+1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9
+1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA
+1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB
+1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC
+1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD
+1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE
+1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF
+1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0;
+1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1;
+1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2;
+1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3;
+1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4;
+1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5;
+1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6;
+1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7;
+1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8
+1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9
+1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;;
+1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC
+1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;;
+1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;;
+1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;;
+1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0;
+1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1;
+1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70;
+1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71;
+1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3;
+1FBD;GREEK KORONIS;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399
+1FBF;GREEK PSILI;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FC0;GREEK PERISPOMENI;Sk;0;ON;<compat> 0020 0342;;;;N;;;;;
+1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;;
+1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;;
+1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC
+1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;;
+1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;;
+1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;;
+1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72;
+1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73;
+1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74;
+1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75;
+1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3;
+1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;;
+1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;;
+1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;;
+1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8
+1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9
+1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;;
+1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;;
+1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;;
+1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;;
+1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0;
+1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1;
+1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76;
+1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77;
+1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;;
+1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;;
+1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;;
+1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8
+1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9
+1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;;
+1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;;
+1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;;
+1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC
+1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;;
+1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;;
+1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0;
+1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1;
+1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A;
+1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B;
+1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5;
+1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;;
+1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;;
+1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;;
+1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;;
+1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC
+1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;;
+1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;;
+1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;;
+1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78;
+1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79;
+1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C;
+1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D;
+1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3;
+1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;;
+1FFE;GREEK DASIA;Sk;0;ON;<compat> 0020 0314;;;;N;;;;;
+2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
+2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
+2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
+2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200B;ZERO WIDTH SPACE;Cf;0;BN;;;;;N;;;;;
+200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;;
+200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;;
+200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;;
+200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;;
+2010;HYPHEN;Pd;0;ON;;;;;N;;;;;
+2011;NON-BREAKING HYPHEN;Pd;0;ON;<noBreak> 2010;;;;N;;;;;
+2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;;
+2013;EN DASH;Pd;0;ON;;;;;N;;;;;
+2014;EM DASH;Pd;0;ON;;;;;N;;;;;
+2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;;
+2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;;
+2017;DOUBLE LOW LINE;Po;0;ON;<compat> 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;;
+2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;;
+2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;;
+201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;;
+201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;;
+201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;;
+201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;;
+201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;;
+201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;;
+2020;DAGGER;Po;0;ON;;;;;N;;;;;
+2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;;
+2022;BULLET;Po;0;ON;;;;;N;;;;;
+2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;;
+2024;ONE DOT LEADER;Po;0;ON;<compat> 002E;;;;N;;;;;
+2025;TWO DOT LEADER;Po;0;ON;<compat> 002E 002E;;;;N;;;;;
+2026;HORIZONTAL ELLIPSIS;Po;0;ON;<compat> 002E 002E 002E;;;;N;;;;;
+2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;;
+2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;;
+2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;;
+202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;;
+202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;;
+202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;;
+202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;;
+202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;;
+202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
+2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;;
+2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;;
+2032;PRIME;Po;0;ET;;;;;N;;;;;
+2033;DOUBLE PRIME;Po;0;ET;<compat> 2032 2032;;;;N;;;;;
+2034;TRIPLE PRIME;Po;0;ET;<compat> 2032 2032 2032;;;;N;;;;;
+2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;;
+2036;REVERSED DOUBLE PRIME;Po;0;ON;<compat> 2035 2035;;;;N;;;;;
+2037;REVERSED TRIPLE PRIME;Po;0;ON;<compat> 2035 2035 2035;;;;N;;;;;
+2038;CARET;Po;0;ON;;;;;N;;;;;
+2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;;
+203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;;
+203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;;
+203C;DOUBLE EXCLAMATION MARK;Po;0;ON;<compat> 0021 0021;;;;N;;;;;
+203D;INTERROBANG;Po;0;ON;;;;;N;;;;;
+203E;OVERLINE;Po;0;ON;<compat> 0020 0305;;;;N;SPACING OVERSCORE;;;;
+203F;UNDERTIE;Pc;0;ON;;;;;N;;Enotikon;;;
+2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;;
+2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;;
+2042;ASTERISM;Po;0;ON;;;;;N;;;;;
+2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;;
+2044;FRACTION SLASH;Sm;0;CS;;;;;N;;;;;
+2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;;
+2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;;
+2047;DOUBLE QUESTION MARK;Po;0;ON;<compat> 003F 003F;;;;N;;;;;
+2048;QUESTION EXCLAMATION MARK;Po;0;ON;<compat> 003F 0021;;;;N;;;;;
+2049;EXCLAMATION QUESTION MARK;Po;0;ON;<compat> 0021 003F;;;;N;;;;;
+204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;;
+204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;;
+204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+204E;LOW ASTERISK;Po;0;ON;;;;;N;;;;;
+204F;REVERSED SEMICOLON;Po;0;ON;;;;;N;;;;;
+2050;CLOSE UP;Po;0;ON;;;;;N;;;;;
+2051;TWO ASTERISKS ALIGNED VERTICALLY;Po;0;ON;;;;;N;;;;;
+2052;COMMERCIAL MINUS SIGN;Sm;0;ON;;;;;N;;;;;
+2053;SWUNG DASH;Po;0;ON;;;;;N;;;;;
+2054;INVERTED UNDERTIE;Pc;0;ON;;;;;N;;;;;
+2055;FLOWER PUNCTUATION MARK;Po;0;ON;;;;;N;;;;;
+2056;THREE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2057;QUADRUPLE PRIME;Po;0;ON;<compat> 2032 2032 2032 2032;;;;N;;;;;
+2058;FOUR DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+2059;FIVE DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+205A;TWO DOT PUNCTUATION;Po;0;ON;;;;;N;;;;;
+205B;FOUR DOT MARK;Po;0;ON;;;;;N;;;;;
+205C;DOTTED CROSS;Po;0;ON;;;;;N;;;;;
+205D;TRICOLON;Po;0;ON;;;;;N;;;;;
+205E;VERTICAL FOUR DOTS;Po;0;ON;;;;;N;;;;;
+205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2060;WORD JOINER;Cf;0;BN;;;;;N;;;;;
+2061;FUNCTION APPLICATION;Cf;0;BN;;;;;N;;;;;
+2062;INVISIBLE TIMES;Cf;0;BN;;;;;N;;;;;
+2063;INVISIBLE SEPARATOR;Cf;0;BN;;;;;N;;;;;
+206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+2070;SUPERSCRIPT ZERO;No;0;EN;<super> 0030;;0;0;N;SUPERSCRIPT DIGIT ZERO;;;;
+2071;SUPERSCRIPT LATIN SMALL LETTER I;Ll;0;L;<super> 0069;;;;N;;;;;
+2074;SUPERSCRIPT FOUR;No;0;EN;<super> 0034;;4;4;N;SUPERSCRIPT DIGIT FOUR;;;;
+2075;SUPERSCRIPT FIVE;No;0;EN;<super> 0035;;5;5;N;SUPERSCRIPT DIGIT FIVE;;;;
+2076;SUPERSCRIPT SIX;No;0;EN;<super> 0036;;6;6;N;SUPERSCRIPT DIGIT SIX;;;;
+2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;;
+2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;;
+2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;;9;9;N;SUPERSCRIPT DIGIT NINE;;;;
+207A;SUPERSCRIPT PLUS SIGN;Sm;0;ES;<super> 002B;;;;N;;;;;
+207B;SUPERSCRIPT MINUS;Sm;0;ES;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;;
+207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;;
+207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;;
+207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;;
+207F;SUPERSCRIPT LATIN SMALL LETTER N;Ll;0;L;<super> 006E;;;;N;;;;;
+2080;SUBSCRIPT ZERO;No;0;EN;<sub> 0030;;0;0;N;SUBSCRIPT DIGIT ZERO;;;;
+2081;SUBSCRIPT ONE;No;0;EN;<sub> 0031;;1;1;N;SUBSCRIPT DIGIT ONE;;;;
+2082;SUBSCRIPT TWO;No;0;EN;<sub> 0032;;2;2;N;SUBSCRIPT DIGIT TWO;;;;
+2083;SUBSCRIPT THREE;No;0;EN;<sub> 0033;;3;3;N;SUBSCRIPT DIGIT THREE;;;;
+2084;SUBSCRIPT FOUR;No;0;EN;<sub> 0034;;4;4;N;SUBSCRIPT DIGIT FOUR;;;;
+2085;SUBSCRIPT FIVE;No;0;EN;<sub> 0035;;5;5;N;SUBSCRIPT DIGIT FIVE;;;;
+2086;SUBSCRIPT SIX;No;0;EN;<sub> 0036;;6;6;N;SUBSCRIPT DIGIT SIX;;;;
+2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;;7;7;N;SUBSCRIPT DIGIT SEVEN;;;;
+2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;;8;8;N;SUBSCRIPT DIGIT EIGHT;;;;
+2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;;9;9;N;SUBSCRIPT DIGIT NINE;;;;
+208A;SUBSCRIPT PLUS SIGN;Sm;0;ES;<sub> 002B;;;;N;;;;;
+208B;SUBSCRIPT MINUS;Sm;0;ES;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;;
+208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;;
+208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;;
+208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;;
+2090;LATIN SUBSCRIPT SMALL LETTER A;Lm;0;L;<sub> 0061;;;;N;;;;;
+2091;LATIN SUBSCRIPT SMALL LETTER E;Lm;0;L;<sub> 0065;;;;N;;;;;
+2092;LATIN SUBSCRIPT SMALL LETTER O;Lm;0;L;<sub> 006F;;;;N;;;;;
+2093;LATIN SUBSCRIPT SMALL LETTER X;Lm;0;L;<sub> 0078;;;;N;;;;;
+2094;LATIN SUBSCRIPT SMALL LETTER SCHWA;Lm;0;L;<sub> 0259;;;;N;;;;;
+20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;;
+20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;;
+20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;;
+20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;;
+20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;;
+20A8;RUPEE SIGN;Sc;0;ET;<compat> 0052 0073;;;;N;;;;;
+20A9;WON SIGN;Sc;0;ET;;;;;N;;;;;
+20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;;
+20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;;
+20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;;
+20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;;
+20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;;
+20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;;
+20B0;GERMAN PENNY SIGN;Sc;0;ET;;;;;N;;;;;
+20B1;PESO SIGN;Sc;0;ET;;;;;N;;;;;
+20B2;GUARANI SIGN;Sc;0;ET;;;;;N;;;;;
+20B3;AUSTRAL SIGN;Sc;0;ET;;;;;N;;;;;
+20B4;HRYVNIA SIGN;Sc;0;ET;;;;;N;;;;;
+20B5;CEDI SIGN;Sc;0;ET;;;;;N;;;;;
+20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;;
+20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;;
+20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;;
+20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;;
+20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;;
+20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;;
+20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;;
+20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;;
+20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;;
+20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;;
+20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;;
+20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;;
+20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;;
+20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;;
+20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;;
+20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;;
+20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;;
+20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;;
+20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;;
+20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;;
+20E4;COMBINING ENCLOSING UPWARD POINTING TRIANGLE;Me;0;NSM;;;;;N;;;;;
+20E5;COMBINING REVERSE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20E6;COMBINING DOUBLE VERTICAL STROKE OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20E7;COMBINING ANNUITY SYMBOL;Mn;230;NSM;;;;;N;;;;;
+20E8;COMBINING TRIPLE UNDERDOT;Mn;220;NSM;;;;;N;;;;;
+20E9;COMBINING WIDE BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+20EA;COMBINING LEFTWARDS ARROW OVERLAY;Mn;1;NSM;;;;;N;;;;;
+20EB;COMBINING LONG DOUBLE SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;;;;;
+2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;;
+2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;;
+2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;;
+2103;DEGREE CELSIUS;So;0;ON;<compat> 00B0 0043;;;;N;DEGREES CENTIGRADE;;;;
+2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;;
+2105;CARE OF;So;0;ON;<compat> 0063 002F 006F;;;;N;;;;;
+2106;CADA UNA;So;0;ON;<compat> 0063 002F 0075;;;;N;;;;;
+2107;EULER CONSTANT;Lu;0;L;<compat> 0190;;;;N;EULERS;;;;
+2108;SCRUPLE;So;0;ON;;;;;N;;;;;
+2109;DEGREE FAHRENHEIT;So;0;ON;<compat> 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;;
+210A;SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+210B;SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;SCRIPT H;;;;
+210C;BLACK-LETTER CAPITAL H;Lu;0;L;<font> 0048;;;;N;BLACK-LETTER H;;;;
+210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L;<font> 0048;;;;N;DOUBLE-STRUCK H;;;;
+210E;PLANCK CONSTANT;Ll;0;L;<font> 0068;;;;N;;;;;
+210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L;<font> 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;;
+2110;SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;SCRIPT I;;;;
+2111;BLACK-LETTER CAPITAL I;Lu;0;L;<font> 0049;;;;N;BLACK-LETTER I;;;;
+2112;SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;SCRIPT L;;;;
+2113;SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;;
+2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L;<font> 004E;;;;N;DOUBLE-STRUCK N;;;;
+2116;NUMERO SIGN;So;0;ON;<compat> 004E 006F;;;;N;NUMERO;;;;
+2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;;
+2118;SCRIPT CAPITAL P;So;0;ON;;;;;N;SCRIPT P;;;;
+2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L;<font> 0050;;;;N;DOUBLE-STRUCK P;;;;
+211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L;<font> 0051;;;;N;DOUBLE-STRUCK Q;;;;
+211B;SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;SCRIPT R;;;;
+211C;BLACK-LETTER CAPITAL R;Lu;0;L;<font> 0052;;;;N;BLACK-LETTER R;;;;
+211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L;<font> 0052;;;;N;DOUBLE-STRUCK R;;;;
+211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;;
+211F;RESPONSE;So;0;ON;;;;;N;;;;;
+2120;SERVICE MARK;So;0;ON;<super> 0053 004D;;;;N;;;;;
+2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;;
+2122;TRADE MARK SIGN;So;0;ON;<super> 0054 004D;;;;N;TRADEMARK;;;;
+2123;VERSICLE;So;0;ON;;;;;N;;;;;
+2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L;<font> 005A;;;;N;DOUBLE-STRUCK Z;;;;
+2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;;
+2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9;
+2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;;
+2128;BLACK-LETTER CAPITAL Z;Lu;0;L;<font> 005A;;;;N;BLACK-LETTER Z;;;;
+2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;;
+212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
+212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5;
+212C;SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;SCRIPT B;;;;
+212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043;;;;N;BLACK-LETTER C;;;;
+212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;;
+212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;;
+2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;;
+2132;TURNED CAPITAL F;So;0;ON;;;;;N;TURNED F;;;;
+2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;;
+2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;;
+2136;BET SYMBOL;Lo;0;L;<compat> 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;;
+2137;GIMEL SYMBOL;Lo;0;L;<compat> 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;;
+2138;DALET SYMBOL;Lo;0;L;<compat> 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;;
+2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;;
+213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;;
+213B;FACSIMILE SIGN;So;0;ON;<compat> 0046 0041 0058;;;;N;;;;;
+213C;DOUBLE-STRUCK SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+213D;DOUBLE-STRUCK SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+213E;DOUBLE-STRUCK CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+213F;DOUBLE-STRUCK CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+2140;DOUBLE-STRUCK N-ARY SUMMATION;Sm;0;ON;<font> 2211;;;;Y;;;;;
+2141;TURNED SANS-SERIF CAPITAL G;Sm;0;ON;;;;;N;;;;;
+2142;TURNED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;
+2143;REVERSED SANS-SERIF CAPITAL L;Sm;0;ON;;;;;N;;;;;
+2144;TURNED SANS-SERIF CAPITAL Y;Sm;0;ON;;;;;N;;;;;
+2145;DOUBLE-STRUCK ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+2146;DOUBLE-STRUCK ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+2147;DOUBLE-STRUCK ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+2148;DOUBLE-STRUCK ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+2149;DOUBLE-STRUCK ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+214A;PROPERTY LINE;So;0;ON;;;;;N;;;;;
+214B;TURNED AMPERSAND;Sm;0;ON;;;;;N;;;;;
+214C;PER SIGN;So;0;ON;;;;;N;;;;;
+2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;;
+2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;;
+2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;;
+2156;VULGAR FRACTION TWO FIFTHS;No;0;ON;<fraction> 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;;
+2157;VULGAR FRACTION THREE FIFTHS;No;0;ON;<fraction> 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;;
+2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON;<fraction> 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;;
+2159;VULGAR FRACTION ONE SIXTH;No;0;ON;<fraction> 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;;
+215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON;<fraction> 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;;
+215B;VULGAR FRACTION ONE EIGHTH;No;0;ON;<fraction> 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;;
+215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON;<fraction> 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;;
+215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON;<fraction> 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;;
+215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON;<fraction> 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;;
+215F;FRACTION NUMERATOR ONE;No;0;ON;<fraction> 0031 2044;;;1;N;;;;;
+2160;ROMAN NUMERAL ONE;Nl;0;L;<compat> 0049;;;1;N;;;;2170;
+2161;ROMAN NUMERAL TWO;Nl;0;L;<compat> 0049 0049;;;2;N;;;;2171;
+2162;ROMAN NUMERAL THREE;Nl;0;L;<compat> 0049 0049 0049;;;3;N;;;;2172;
+2163;ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0049 0056;;;4;N;;;;2173;
+2164;ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0056;;;5;N;;;;2174;
+2165;ROMAN NUMERAL SIX;Nl;0;L;<compat> 0056 0049;;;6;N;;;;2175;
+2166;ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0056 0049 0049;;;7;N;;;;2176;
+2167;ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0056 0049 0049 0049;;;8;N;;;;2177;
+2168;ROMAN NUMERAL NINE;Nl;0;L;<compat> 0049 0058;;;9;N;;;;2178;
+2169;ROMAN NUMERAL TEN;Nl;0;L;<compat> 0058;;;10;N;;;;2179;
+216A;ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0058 0049;;;11;N;;;;217A;
+216B;ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0058 0049 0049;;;12;N;;;;217B;
+216C;ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 004C;;;50;N;;;;217C;
+216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0043;;;100;N;;;;217D;
+216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0044;;;500;N;;;;217E;
+216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 004D;;;1000;N;;;;217F;
+2170;SMALL ROMAN NUMERAL ONE;Nl;0;L;<compat> 0069;;;1;N;;;2160;;2160
+2171;SMALL ROMAN NUMERAL TWO;Nl;0;L;<compat> 0069 0069;;;2;N;;;2161;;2161
+2172;SMALL ROMAN NUMERAL THREE;Nl;0;L;<compat> 0069 0069 0069;;;3;N;;;2162;;2162
+2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0069 0076;;;4;N;;;2163;;2163
+2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0076;;;5;N;;;2164;;2164
+2175;SMALL ROMAN NUMERAL SIX;Nl;0;L;<compat> 0076 0069;;;6;N;;;2165;;2165
+2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0076 0069 0069;;;7;N;;;2166;;2166
+2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0076 0069 0069 0069;;;8;N;;;2167;;2167
+2178;SMALL ROMAN NUMERAL NINE;Nl;0;L;<compat> 0069 0078;;;9;N;;;2168;;2168
+2179;SMALL ROMAN NUMERAL TEN;Nl;0;L;<compat> 0078;;;10;N;;;2169;;2169
+217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0078 0069;;;11;N;;;216A;;216A
+217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0078 0069 0069;;;12;N;;;216B;;216B
+217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 006C;;;50;N;;;216C;;216C
+217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0063;;;100;N;;;216D;;216D
+217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0064;;;500;N;;;216E;;216E
+217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 006D;;;1000;N;;;216F;;216F
+2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;;
+2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;;
+2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;;
+2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Nl;0;L;;;;;N;;;;;
+2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;;
+2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;;
+2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;;
+2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;;
+2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;
+2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;;
+2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;;
+2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;;
+2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;;
+2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;;
+219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;;
+219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;;
+219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;;
+219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;;
+219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;;
+219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;;
+21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;;
+21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;;
+21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;;
+21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;;
+21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;;
+21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;;
+21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;;
+21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;;
+21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;;
+21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;;
+21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;;
+21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;;
+21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;;
+21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;;
+21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;;
+21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;;
+21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;;
+21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;;
+21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;;
+21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;;
+21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;;
+21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;;
+21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;;
+21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;;
+21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;;
+21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;;
+21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;;
+21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;;
+21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;;
+21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;;
+21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;;
+21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;;
+21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;;
+21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;;
+21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;;
+21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;;
+21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;;
+21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;;
+21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;;
+21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;;
+21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;;
+21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;;
+21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;;
+21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;;
+21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;;
+21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;;
+21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;;
+21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;;
+21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;;
+21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;;
+21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;;
+21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;;
+21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;;
+21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;;
+21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;;
+21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;;
+21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;;
+21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;;
+21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;;
+21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;;
+21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;;
+21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;;
+21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;;
+21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;;
+21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;;
+21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;;
+21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;;
+21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;;
+21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;;
+21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;
+21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;
+21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;;
+21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;;
+21F4;RIGHT ARROW WITH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+21F5;DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+21F6;THREE RIGHTWARDS ARROWS;Sm;0;ON;;;;;N;;;;;
+21F7;LEFTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21F8;RIGHTWARDS ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21F9;LEFT RIGHT ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FA;LEFTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FB;RIGHTWARDS ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FC;LEFT RIGHT ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+21FD;LEFTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+21FE;RIGHTWARDS OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+21FF;LEFT RIGHT OPEN-HEADED ARROW;Sm;0;ON;;;;;N;;;;;
+2200;FOR ALL;Sm;0;ON;;;;;N;;;;;
+2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;;
+2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;;
+2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;;
+2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;;
+2205;EMPTY SET;Sm;0;ON;;;;;N;;;;;
+2206;INCREMENT;Sm;0;ON;;;;;N;;;;;
+2207;NABLA;Sm;0;ON;;;;;N;;;;;
+2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;;
+220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;;
+220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220E;END OF PROOF;Sm;0;ON;;;;;N;;;;;
+220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;;
+2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;;
+2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;;
+2212;MINUS SIGN;Sm;0;ES;;;;;N;;;;;
+2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;;
+2214;DOT PLUS;Sm;0;ON;;;;;N;;;;;
+2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2216;SET MINUS;Sm;0;ON;;;;;Y;;;;;
+2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;;
+221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;;
+221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;;
+221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;;
+221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;;
+221E;INFINITY;Sm;0;ON;;;;;N;;;;;
+221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;;
+2220;ANGLE;Sm;0;ON;;;;;Y;;;;;
+2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;;
+2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;;
+2223;DIVIDES;Sm;0;ON;;;;;N;;;;;
+2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;;
+2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;;
+2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2229;INTERSECTION;Sm;0;ON;;;;;N;;;;;
+222A;UNION;Sm;0;ON;;;;;N;;;;;
+222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222C;DOUBLE INTEGRAL;Sm;0;ON;<compat> 222B 222B;;;;Y;;;;;
+222D;TRIPLE INTEGRAL;Sm;0;ON;<compat> 222B 222B 222B;;;;Y;;;;;
+222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222F;SURFACE INTEGRAL;Sm;0;ON;<compat> 222E 222E;;;;Y;;;;;
+2230;VOLUME INTEGRAL;Sm;0;ON;<compat> 222E 222E 222E;;;;Y;;;;;
+2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2234;THEREFORE;Sm;0;ON;;;;;N;;;;;
+2235;BECAUSE;Sm;0;ON;;;;;N;;;;;
+2236;RATIO;Sm;0;ON;;;;;N;;;;;
+2237;PROPORTION;Sm;0;ON;;;;;N;;;;;
+2238;DOT MINUS;Sm;0;ON;;;;;N;;;;;
+2239;EXCESS;Sm;0;ON;;;;;Y;;;;;
+223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;;
+223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;;
+223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;lazy S;;;
+223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;;
+223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;;
+2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;;
+2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;;
+2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;;
+2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;;
+2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;;
+224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;;
+224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;;
+2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;;
+2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;;
+2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;;
+2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;;
+2259;ESTIMATES;Sm;0;ON;;;;;N;;;;;
+225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;;
+225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;;
+225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;;
+225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;;
+225E;MEASURED BY;Sm;0;ON;;;;;N;;;;;
+225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;;
+2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;;
+2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;;
+2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;;
+2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;;
+2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;;
+2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;;
+2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;;
+2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;;
+226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;;
+226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;;
+226C;BETWEEN;Sm;0;ON;;;;;N;;;;;
+226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;;
+226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;;
+226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;;
+2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;;
+2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;;
+2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;;
+2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;;
+2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;;
+2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;;
+2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;;
+2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;;
+2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;;
+2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;;
+227A;PRECEDES;Sm;0;ON;;;;;Y;;;;;
+227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;;
+2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;;
+2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;;
+2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;;
+2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;;
+2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;;
+2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;;
+2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;;
+228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;;
+228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;;
+228C;MULTISET;Sm;0;ON;;;;;Y;;;;;
+228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;;
+228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;;
+228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;;
+2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;;
+2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;;
+2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;;
+2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;;
+229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;;
+229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;;
+229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;;
+22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;;
+22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;;
+22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;;
+22A5;UP TACK;Sm;0;ON;;;;;N;;;;;
+22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;;
+22A7;MODELS;Sm;0;ON;;;;;Y;;;;;
+22A8;TRUE;Sm;0;ON;;;;;Y;;;;;
+22A9;FORCES;Sm;0;ON;;;;;Y;;;;;
+22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;;
+22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;;
+22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;;
+22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;;
+22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;;
+22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;;
+22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;;
+22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;;
+22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;;
+22BB;XOR;Sm;0;ON;;;;;N;;;;;
+22BC;NAND;Sm;0;ON;;;;;N;;;;;
+22BD;NOR;Sm;0;ON;;;;;N;;;;;
+22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;;
+22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;;
+22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;;
+22C8;BOWTIE;Sm;0;ON;;;;;N;;;;;
+22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;;
+22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;;
+22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;;
+22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;;
+22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;;
+22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;;
+22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;;
+22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;;
+22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;;
+22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;;
+22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;;
+22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;;
+22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;;
+22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;;
+22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;;
+22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;;
+22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;;
+22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;;
+22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;;
+22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;;
+22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;;
+22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;;
+22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;;
+22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+22F2;ELEMENT OF WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F3;ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F4;SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22F5;ELEMENT OF WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+22F6;ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22F7;SMALL ELEMENT OF WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22F8;ELEMENT OF WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+22F9;ELEMENT OF WITH TWO HORIZONTAL STROKES;Sm;0;ON;;;;;Y;;;;;
+22FA;CONTAINS WITH LONG HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FB;CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FC;SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+22FD;CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22FE;SMALL CONTAINS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+22FF;Z NOTATION BAG MEMBERSHIP;Sm;0;ON;;;;;Y;;;;;
+2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;;
+2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;;
+2302;HOUSE;So;0;ON;;;;;N;;;;;
+2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;;
+2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;;
+2305;PROJECTIVE;So;0;ON;;;;;N;;;;;
+2306;PERSPECTIVE;So;0;ON;;;;;N;;;;;
+2307;WAVY LINE;So;0;ON;;;;;N;;;;;
+2308;LEFT CEILING;Sm;0;ON;;;;;Y;;;;;
+2309;RIGHT CEILING;Sm;0;ON;;;;;Y;;;;;
+230A;LEFT FLOOR;Sm;0;ON;;;;;Y;;;;;
+230B;RIGHT FLOOR;Sm;0;ON;;;;;Y;;;;;
+230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;;
+230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;;
+230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;;
+230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;;
+2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;;
+2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;;
+2312;ARC;So;0;ON;;;;;N;;;;;
+2313;SEGMENT;So;0;ON;;;;;N;;;;;
+2314;SECTOR;So;0;ON;;;;;N;;;;;
+2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;;
+2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;;
+2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;;
+2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;;
+2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;;
+231A;WATCH;So;0;ON;;;;;N;;;;;
+231B;HOURGLASS;So;0;ON;;;;;N;;;;;
+231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;;
+231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;;
+231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;;
+231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;;
+2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2322;FROWN;So;0;ON;;;;;N;;;;;
+2323;SMILE;So;0;ON;;;;;N;;;;;
+2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;;
+2325;OPTION KEY;So;0;ON;;;;;N;;;;;
+2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;;
+2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;;
+2328;KEYBOARD;So;0;ON;;;;;N;;;;;
+2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;;
+232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;;
+232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;;
+232C;BENZENE RING;So;0;ON;;;;;N;;;;;
+232D;CYLINDRICITY;So;0;ON;;;;;N;;;;;
+232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;;
+232F;SYMMETRY;So;0;ON;;;;;N;;;;;
+2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;;
+2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;;
+2332;CONICAL TAPER;So;0;ON;;;;;N;;;;;
+2333;SLOPE;So;0;ON;;;;;N;;;;;
+2334;COUNTERBORE;So;0;ON;;;;;N;;;;;
+2335;COUNTERSINK;So;0;ON;;;;;N;;;;;
+2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;;
+2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;;
+2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;;
+2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;;
+233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;;
+233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;;
+233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;;
+233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;;
+233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;;
+233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;;
+2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;;
+2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;;
+2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;;
+2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;;
+2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;;
+2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;;
+2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;;
+2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;;
+2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;;
+2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;;
+234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;*;;;
+234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;;
+234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;;
+234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;;
+234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;*;;;
+234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;;
+2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;;
+2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;*;;;
+2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;;
+2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;;
+2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;;
+2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;*;;;
+2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;;
+2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;;
+2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;;
+2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;;
+235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;;
+235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;;
+235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;;
+235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;;
+235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;;
+235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;;
+2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;;
+2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;*;;;
+2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;;
+2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;;
+2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;;
+2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;;
+2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;;
+2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;;
+2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;;
+2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;;
+236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;;
+236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;;
+236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;;
+236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;;
+236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;;
+236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;;
+2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;;
+2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;;
+2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;;
+2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;;
+2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;;
+2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;;
+2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;;
+2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;;
+2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;;
+2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;;
+237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;;
+237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;;
+237C;RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW;Sm;0;ON;;;;;N;;;;;
+237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;;
+237E;BELL SYMBOL;So;0;ON;;;;;N;;;;;
+237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;;
+2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;;
+2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;;
+2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;;
+2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;;
+2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;;
+2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2388;HELM SYMBOL;So;0;ON;;;;;N;;;;;
+2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;pause;;;
+238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;break;;;
+238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;escape;;;
+238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;;
+238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;;
+238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;;
+238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;;
+2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;;
+2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;;
+2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;;
+2398;NEXT PAGE;So;0;ON;;;;;N;;;;;
+2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+239B;LEFT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+239C;LEFT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;
+239D;LEFT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+239E;RIGHT PARENTHESIS UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+239F;RIGHT PARENTHESIS EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A0;RIGHT PARENTHESIS LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23A1;LEFT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;
+23A2;LEFT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A3;LEFT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;
+23A4;RIGHT SQUARE BRACKET UPPER CORNER;Sm;0;ON;;;;;N;;;;;
+23A5;RIGHT SQUARE BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23A6;RIGHT SQUARE BRACKET LOWER CORNER;Sm;0;ON;;;;;N;;;;;
+23A7;LEFT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+23A8;LEFT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;
+23A9;LEFT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23AA;CURLY BRACKET EXTENSION;Sm;0;ON;;;;;N;;;;;
+23AB;RIGHT CURLY BRACKET UPPER HOOK;Sm;0;ON;;;;;N;;;;;
+23AC;RIGHT CURLY BRACKET MIDDLE PIECE;Sm;0;ON;;;;;N;;;;;
+23AD;RIGHT CURLY BRACKET LOWER HOOK;Sm;0;ON;;;;;N;;;;;
+23AE;INTEGRAL EXTENSION;Sm;0;ON;;;;;N;;;;;
+23AF;HORIZONTAL LINE EXTENSION;Sm;0;ON;;;;;N;;;;;
+23B0;UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;
+23B1;UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION;Sm;0;ON;;;;;N;;;;;
+23B2;SUMMATION TOP;Sm;0;ON;;;;;N;;;;;
+23B3;SUMMATION BOTTOM;Sm;0;ON;;;;;N;;;;;
+23B4;TOP SQUARE BRACKET;Ps;0;ON;;;;;N;;;;;
+23B5;BOTTOM SQUARE BRACKET;Pe;0;ON;;;;;N;;;;;
+23B6;BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET;Po;0;ON;;;;;N;;;;;
+23B7;RADICAL SYMBOL BOTTOM;So;0;ON;;;;;N;;;;;
+23B8;LEFT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;
+23B9;RIGHT VERTICAL BOX LINE;So;0;ON;;;;;N;;;;;
+23BA;HORIZONTAL SCAN LINE-1;So;0;ON;;;;;N;;;;;
+23BB;HORIZONTAL SCAN LINE-3;So;0;ON;;;;;N;;;;;
+23BC;HORIZONTAL SCAN LINE-7;So;0;ON;;;;;N;;;;;
+23BD;HORIZONTAL SCAN LINE-9;So;0;ON;;;;;N;;;;;
+23BE;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP RIGHT;So;0;ON;;;;;N;;;;;
+23BF;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM RIGHT;So;0;ON;;;;;N;;;;;
+23C0;DENTISTRY SYMBOL LIGHT VERTICAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C1;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C2;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH CIRCLE;So;0;ON;;;;;N;;;;;
+23C3;DENTISTRY SYMBOL LIGHT VERTICAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C4;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C5;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH TRIANGLE;So;0;ON;;;;;N;;;;;
+23C6;DENTISTRY SYMBOL LIGHT VERTICAL AND WAVE;So;0;ON;;;;;N;;;;;
+23C7;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;
+23C8;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL WITH WAVE;So;0;ON;;;;;N;;;;;
+23C9;DENTISTRY SYMBOL LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;;;;;
+23CA;DENTISTRY SYMBOL LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;;;;;
+23CB;DENTISTRY SYMBOL LIGHT VERTICAL AND TOP LEFT;So;0;ON;;;;;N;;;;;
+23CC;DENTISTRY SYMBOL LIGHT VERTICAL AND BOTTOM LEFT;So;0;ON;;;;;N;;;;;
+23CD;SQUARE FOOT;So;0;ON;;;;;N;;;;;
+23CE;RETURN SYMBOL;So;0;ON;;;;;N;;;;;
+23CF;EJECT SYMBOL;So;0;ON;;;;;N;;;;;
+23D0;VERTICAL LINE EXTENSION;So;0;ON;;;;;N;;;;;
+23D1;METRICAL BREVE;So;0;ON;;;;;N;;;;;
+23D2;METRICAL LONG OVER SHORT;So;0;ON;;;;;N;;;;;
+23D3;METRICAL SHORT OVER LONG;So;0;ON;;;;;N;;;;;
+23D4;METRICAL LONG OVER TWO SHORTS;So;0;ON;;;;;N;;;;;
+23D5;METRICAL TWO SHORTS OVER LONG;So;0;ON;;;;;N;;;;;
+23D6;METRICAL TWO SHORTS JOINED;So;0;ON;;;;;N;;;;;
+23D7;METRICAL TRISEME;So;0;ON;;;;;N;;;;;
+23D8;METRICAL TETRASEME;So;0;ON;;;;;N;;;;;
+23D9;METRICAL PENTASEME;So;0;ON;;;;;N;;;;;
+23DA;EARTH GROUND;So;0;ON;;;;;N;;;;;
+23DB;FUSE;So;0;ON;;;;;N;;;;;
+2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;;
+2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;;
+2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;;
+2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;;
+2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;;
+2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;;
+2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;;
+2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;;
+2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;;
+2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;;
+240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;;
+240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;;
+240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;;
+240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;;
+240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;;
+240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;;
+2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;;
+2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;;
+2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;;
+2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;;
+2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;;
+2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;;
+2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;;
+2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;;
+2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;;
+2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;;
+241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;;
+241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;;
+241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;;
+241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;;
+241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;;
+241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;;
+2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;;
+2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;;
+2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;;
+2423;OPEN BOX;So;0;ON;;;;;N;;;;;
+2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;;
+2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;;
+2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;;
+2440;OCR HOOK;So;0;ON;;;;;N;;;;;
+2441;OCR CHAIR;So;0;ON;;;;;N;;;;;
+2442;OCR FORK;So;0;ON;;;;;N;;;;;
+2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;;
+2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;;
+2445;OCR BOW TIE;So;0;ON;;;;;N;;;;;
+2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;;
+2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;;
+2448;OCR DASH;So;0;ON;;;;;N;;;;;
+2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;;
+244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;;
+2460;CIRCLED DIGIT ONE;No;0;ON;<circle> 0031;;1;1;N;;;;;
+2461;CIRCLED DIGIT TWO;No;0;ON;<circle> 0032;;2;2;N;;;;;
+2462;CIRCLED DIGIT THREE;No;0;ON;<circle> 0033;;3;3;N;;;;;
+2463;CIRCLED DIGIT FOUR;No;0;ON;<circle> 0034;;4;4;N;;;;;
+2464;CIRCLED DIGIT FIVE;No;0;ON;<circle> 0035;;5;5;N;;;;;
+2465;CIRCLED DIGIT SIX;No;0;ON;<circle> 0036;;6;6;N;;;;;
+2466;CIRCLED DIGIT SEVEN;No;0;ON;<circle> 0037;;7;7;N;;;;;
+2467;CIRCLED DIGIT EIGHT;No;0;ON;<circle> 0038;;8;8;N;;;;;
+2468;CIRCLED DIGIT NINE;No;0;ON;<circle> 0039;;9;9;N;;;;;
+2469;CIRCLED NUMBER TEN;No;0;ON;<circle> 0031 0030;;;10;N;;;;;
+246A;CIRCLED NUMBER ELEVEN;No;0;ON;<circle> 0031 0031;;;11;N;;;;;
+246B;CIRCLED NUMBER TWELVE;No;0;ON;<circle> 0031 0032;;;12;N;;;;;
+246C;CIRCLED NUMBER THIRTEEN;No;0;ON;<circle> 0031 0033;;;13;N;;;;;
+246D;CIRCLED NUMBER FOURTEEN;No;0;ON;<circle> 0031 0034;;;14;N;;;;;
+246E;CIRCLED NUMBER FIFTEEN;No;0;ON;<circle> 0031 0035;;;15;N;;;;;
+246F;CIRCLED NUMBER SIXTEEN;No;0;ON;<circle> 0031 0036;;;16;N;;;;;
+2470;CIRCLED NUMBER SEVENTEEN;No;0;ON;<circle> 0031 0037;;;17;N;;;;;
+2471;CIRCLED NUMBER EIGHTEEN;No;0;ON;<circle> 0031 0038;;;18;N;;;;;
+2472;CIRCLED NUMBER NINETEEN;No;0;ON;<circle> 0031 0039;;;19;N;;;;;
+2473;CIRCLED NUMBER TWENTY;No;0;ON;<circle> 0032 0030;;;20;N;;;;;
+2474;PARENTHESIZED DIGIT ONE;No;0;ON;<compat> 0028 0031 0029;;1;1;N;;;;;
+2475;PARENTHESIZED DIGIT TWO;No;0;ON;<compat> 0028 0032 0029;;2;2;N;;;;;
+2476;PARENTHESIZED DIGIT THREE;No;0;ON;<compat> 0028 0033 0029;;3;3;N;;;;;
+2477;PARENTHESIZED DIGIT FOUR;No;0;ON;<compat> 0028 0034 0029;;4;4;N;;;;;
+2478;PARENTHESIZED DIGIT FIVE;No;0;ON;<compat> 0028 0035 0029;;5;5;N;;;;;
+2479;PARENTHESIZED DIGIT SIX;No;0;ON;<compat> 0028 0036 0029;;6;6;N;;;;;
+247A;PARENTHESIZED DIGIT SEVEN;No;0;ON;<compat> 0028 0037 0029;;7;7;N;;;;;
+247B;PARENTHESIZED DIGIT EIGHT;No;0;ON;<compat> 0028 0038 0029;;8;8;N;;;;;
+247C;PARENTHESIZED DIGIT NINE;No;0;ON;<compat> 0028 0039 0029;;9;9;N;;;;;
+247D;PARENTHESIZED NUMBER TEN;No;0;ON;<compat> 0028 0031 0030 0029;;;10;N;;;;;
+247E;PARENTHESIZED NUMBER ELEVEN;No;0;ON;<compat> 0028 0031 0031 0029;;;11;N;;;;;
+247F;PARENTHESIZED NUMBER TWELVE;No;0;ON;<compat> 0028 0031 0032 0029;;;12;N;;;;;
+2480;PARENTHESIZED NUMBER THIRTEEN;No;0;ON;<compat> 0028 0031 0033 0029;;;13;N;;;;;
+2481;PARENTHESIZED NUMBER FOURTEEN;No;0;ON;<compat> 0028 0031 0034 0029;;;14;N;;;;;
+2482;PARENTHESIZED NUMBER FIFTEEN;No;0;ON;<compat> 0028 0031 0035 0029;;;15;N;;;;;
+2483;PARENTHESIZED NUMBER SIXTEEN;No;0;ON;<compat> 0028 0031 0036 0029;;;16;N;;;;;
+2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;ON;<compat> 0028 0031 0037 0029;;;17;N;;;;;
+2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;ON;<compat> 0028 0031 0038 0029;;;18;N;;;;;
+2486;PARENTHESIZED NUMBER NINETEEN;No;0;ON;<compat> 0028 0031 0039 0029;;;19;N;;;;;
+2487;PARENTHESIZED NUMBER TWENTY;No;0;ON;<compat> 0028 0032 0030 0029;;;20;N;;;;;
+2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;;
+2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;;
+248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;;
+248B;DIGIT FOUR FULL STOP;No;0;EN;<compat> 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;;
+248C;DIGIT FIVE FULL STOP;No;0;EN;<compat> 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;;
+248D;DIGIT SIX FULL STOP;No;0;EN;<compat> 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;;
+248E;DIGIT SEVEN FULL STOP;No;0;EN;<compat> 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;;
+248F;DIGIT EIGHT FULL STOP;No;0;EN;<compat> 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;;
+2490;DIGIT NINE FULL STOP;No;0;EN;<compat> 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;;
+2491;NUMBER TEN FULL STOP;No;0;EN;<compat> 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;;
+2492;NUMBER ELEVEN FULL STOP;No;0;EN;<compat> 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;;
+2493;NUMBER TWELVE FULL STOP;No;0;EN;<compat> 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;;
+2494;NUMBER THIRTEEN FULL STOP;No;0;EN;<compat> 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;;
+2495;NUMBER FOURTEEN FULL STOP;No;0;EN;<compat> 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;;
+2496;NUMBER FIFTEEN FULL STOP;No;0;EN;<compat> 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;;
+2497;NUMBER SIXTEEN FULL STOP;No;0;EN;<compat> 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;;
+2498;NUMBER SEVENTEEN FULL STOP;No;0;EN;<compat> 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;;
+2499;NUMBER EIGHTEEN FULL STOP;No;0;EN;<compat> 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;;
+249A;NUMBER NINETEEN FULL STOP;No;0;EN;<compat> 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;;
+249B;NUMBER TWENTY FULL STOP;No;0;EN;<compat> 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;;
+249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L;<compat> 0028 0061 0029;;;;N;;;;;
+249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L;<compat> 0028 0062 0029;;;;N;;;;;
+249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L;<compat> 0028 0063 0029;;;;N;;;;;
+249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L;<compat> 0028 0064 0029;;;;N;;;;;
+24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L;<compat> 0028 0065 0029;;;;N;;;;;
+24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L;<compat> 0028 0066 0029;;;;N;;;;;
+24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L;<compat> 0028 0067 0029;;;;N;;;;;
+24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L;<compat> 0028 0068 0029;;;;N;;;;;
+24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L;<compat> 0028 0069 0029;;;;N;;;;;
+24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L;<compat> 0028 006A 0029;;;;N;;;;;
+24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L;<compat> 0028 006B 0029;;;;N;;;;;
+24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L;<compat> 0028 006C 0029;;;;N;;;;;
+24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L;<compat> 0028 006D 0029;;;;N;;;;;
+24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L;<compat> 0028 006E 0029;;;;N;;;;;
+24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L;<compat> 0028 006F 0029;;;;N;;;;;
+24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L;<compat> 0028 0070 0029;;;;N;;;;;
+24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L;<compat> 0028 0071 0029;;;;N;;;;;
+24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L;<compat> 0028 0072 0029;;;;N;;;;;
+24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L;<compat> 0028 0073 0029;;;;N;;;;;
+24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L;<compat> 0028 0074 0029;;;;N;;;;;
+24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L;<compat> 0028 0075 0029;;;;N;;;;;
+24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L;<compat> 0028 0076 0029;;;;N;;;;;
+24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L;<compat> 0028 0077 0029;;;;N;;;;;
+24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L;<compat> 0028 0078 0029;;;;N;;;;;
+24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L;<compat> 0028 0079 0029;;;;N;;;;;
+24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L;<compat> 0028 007A 0029;;;;N;;;;;
+24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L;<circle> 0041;;;;N;;;;24D0;
+24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L;<circle> 0042;;;;N;;;;24D1;
+24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;24D2;
+24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L;<circle> 0044;;;;N;;;;24D3;
+24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L;<circle> 0045;;;;N;;;;24D4;
+24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L;<circle> 0046;;;;N;;;;24D5;
+24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L;<circle> 0047;;;;N;;;;24D6;
+24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L;<circle> 0048;;;;N;;;;24D7;
+24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L;<circle> 0049;;;;N;;;;24D8;
+24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L;<circle> 004A;;;;N;;;;24D9;
+24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L;<circle> 004B;;;;N;;;;24DA;
+24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L;<circle> 004C;;;;N;;;;24DB;
+24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L;<circle> 004D;;;;N;;;;24DC;
+24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L;<circle> 004E;;;;N;;;;24DD;
+24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L;<circle> 004F;;;;N;;;;24DE;
+24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L;<circle> 0050;;;;N;;;;24DF;
+24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L;<circle> 0051;;;;N;;;;24E0;
+24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;24E1;
+24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L;<circle> 0053;;;;N;;;;24E2;
+24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L;<circle> 0054;;;;N;;;;24E3;
+24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L;<circle> 0055;;;;N;;;;24E4;
+24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L;<circle> 0056;;;;N;;;;24E5;
+24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L;<circle> 0057;;;;N;;;;24E6;
+24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L;<circle> 0058;;;;N;;;;24E7;
+24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L;<circle> 0059;;;;N;;;;24E8;
+24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L;<circle> 005A;;;;N;;;;24E9;
+24D0;CIRCLED LATIN SMALL LETTER A;So;0;L;<circle> 0061;;;;N;;;24B6;;24B6
+24D1;CIRCLED LATIN SMALL LETTER B;So;0;L;<circle> 0062;;;;N;;;24B7;;24B7
+24D2;CIRCLED LATIN SMALL LETTER C;So;0;L;<circle> 0063;;;;N;;;24B8;;24B8
+24D3;CIRCLED LATIN SMALL LETTER D;So;0;L;<circle> 0064;;;;N;;;24B9;;24B9
+24D4;CIRCLED LATIN SMALL LETTER E;So;0;L;<circle> 0065;;;;N;;;24BA;;24BA
+24D5;CIRCLED LATIN SMALL LETTER F;So;0;L;<circle> 0066;;;;N;;;24BB;;24BB
+24D6;CIRCLED LATIN SMALL LETTER G;So;0;L;<circle> 0067;;;;N;;;24BC;;24BC
+24D7;CIRCLED LATIN SMALL LETTER H;So;0;L;<circle> 0068;;;;N;;;24BD;;24BD
+24D8;CIRCLED LATIN SMALL LETTER I;So;0;L;<circle> 0069;;;;N;;;24BE;;24BE
+24D9;CIRCLED LATIN SMALL LETTER J;So;0;L;<circle> 006A;;;;N;;;24BF;;24BF
+24DA;CIRCLED LATIN SMALL LETTER K;So;0;L;<circle> 006B;;;;N;;;24C0;;24C0
+24DB;CIRCLED LATIN SMALL LETTER L;So;0;L;<circle> 006C;;;;N;;;24C1;;24C1
+24DC;CIRCLED LATIN SMALL LETTER M;So;0;L;<circle> 006D;;;;N;;;24C2;;24C2
+24DD;CIRCLED LATIN SMALL LETTER N;So;0;L;<circle> 006E;;;;N;;;24C3;;24C3
+24DE;CIRCLED LATIN SMALL LETTER O;So;0;L;<circle> 006F;;;;N;;;24C4;;24C4
+24DF;CIRCLED LATIN SMALL LETTER P;So;0;L;<circle> 0070;;;;N;;;24C5;;24C5
+24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L;<circle> 0071;;;;N;;;24C6;;24C6
+24E1;CIRCLED LATIN SMALL LETTER R;So;0;L;<circle> 0072;;;;N;;;24C7;;24C7
+24E2;CIRCLED LATIN SMALL LETTER S;So;0;L;<circle> 0073;;;;N;;;24C8;;24C8
+24E3;CIRCLED LATIN SMALL LETTER T;So;0;L;<circle> 0074;;;;N;;;24C9;;24C9
+24E4;CIRCLED LATIN SMALL LETTER U;So;0;L;<circle> 0075;;;;N;;;24CA;;24CA
+24E5;CIRCLED LATIN SMALL LETTER V;So;0;L;<circle> 0076;;;;N;;;24CB;;24CB
+24E6;CIRCLED LATIN SMALL LETTER W;So;0;L;<circle> 0077;;;;N;;;24CC;;24CC
+24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD
+24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE
+24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF
+24EA;CIRCLED DIGIT ZERO;No;0;ON;<circle> 0030;;0;0;N;;;;;
+24EB;NEGATIVE CIRCLED NUMBER ELEVEN;No;0;ON;;;;11;N;;;;;
+24EC;NEGATIVE CIRCLED NUMBER TWELVE;No;0;ON;;;;12;N;;;;;
+24ED;NEGATIVE CIRCLED NUMBER THIRTEEN;No;0;ON;;;;13;N;;;;;
+24EE;NEGATIVE CIRCLED NUMBER FOURTEEN;No;0;ON;;;;14;N;;;;;
+24EF;NEGATIVE CIRCLED NUMBER FIFTEEN;No;0;ON;;;;15;N;;;;;
+24F0;NEGATIVE CIRCLED NUMBER SIXTEEN;No;0;ON;;;;16;N;;;;;
+24F1;NEGATIVE CIRCLED NUMBER SEVENTEEN;No;0;ON;;;;17;N;;;;;
+24F2;NEGATIVE CIRCLED NUMBER EIGHTEEN;No;0;ON;;;;18;N;;;;;
+24F3;NEGATIVE CIRCLED NUMBER NINETEEN;No;0;ON;;;;19;N;;;;;
+24F4;NEGATIVE CIRCLED NUMBER TWENTY;No;0;ON;;;;20;N;;;;;
+24F5;DOUBLE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;;;;;
+24F6;DOUBLE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;;;;;
+24F7;DOUBLE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;;;;;
+24F8;DOUBLE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;;;;;
+24F9;DOUBLE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;;;;;
+24FA;DOUBLE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;;;;;
+24FB;DOUBLE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;;;;;
+24FC;DOUBLE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;;;;;
+24FD;DOUBLE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;;;;;
+24FE;DOUBLE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;;;;;
+24FF;NEGATIVE CIRCLED DIGIT ZERO;No;0;ON;;;0;0;N;;;;;
+2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;;
+2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;;
+2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;;
+2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;;
+2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;;
+2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;;
+2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;;
+2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;;
+2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;;
+2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;;
+250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;;
+250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;;
+250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;;
+250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;;
+250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;;
+250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;;
+2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;;
+2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;;
+2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;;
+2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;;
+2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;;
+2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;;
+2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;;
+2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;;
+2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;;
+2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;;
+251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;;
+251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;;
+251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;;
+251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;;
+251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;;
+251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;;
+2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;;
+2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;;
+2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;;
+2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;;
+2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;;
+2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;;
+2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;;
+2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;;
+2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;;
+252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;;
+252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;;
+252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;;
+252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;;
+252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;;
+252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;;
+2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;;
+2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;;
+2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;;
+2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;;
+2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;;
+2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;;
+2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;;
+2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;;
+2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;;
+2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;;
+253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;;
+253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;;
+253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;;
+253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;;
+253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;;
+253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;;
+2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;;
+2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;;
+2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;;
+2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;;
+2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;;
+2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;;
+2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;;
+2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;;
+2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;;
+254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;;
+254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;;
+254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;;
+254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;;
+254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;;
+254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;;
+2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;;
+2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;;
+2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;;
+2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;;
+2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;;
+2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;;
+2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;;
+2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;;
+2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;;
+2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;;
+255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;;
+255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;;
+255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;;
+255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;;
+255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;;
+255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;;
+2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;;
+2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;;
+2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;;
+2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;;
+2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;;
+2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;;
+2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;;
+2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;;
+2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;;
+2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;;
+256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;;
+256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;;
+256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;;
+256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;;
+256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;;
+256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;;
+2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;;
+2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;;
+2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;;
+2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;;
+2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;;
+2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;;
+2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;;
+2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;;
+2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;;
+2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;;
+257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;;
+257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;;
+257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;;
+257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;;
+257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;;
+257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;;
+2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;;
+2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2588;FULL BLOCK;So;0;ON;;;;;N;;;;;
+2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;;
+258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;;
+258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;;
+2591;LIGHT SHADE;So;0;ON;;;;;N;;;;;
+2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+2593;DARK SHADE;So;0;ON;;;;;N;;;;;
+2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2596;QUADRANT LOWER LEFT;So;0;ON;;;;;N;;;;;
+2597;QUADRANT LOWER RIGHT;So;0;ON;;;;;N;;;;;
+2598;QUADRANT UPPER LEFT;So;0;ON;;;;;N;;;;;
+2599;QUADRANT UPPER LEFT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259A;QUADRANT UPPER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259B;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;
+259C;QUADRANT UPPER LEFT AND UPPER RIGHT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+259D;QUADRANT UPPER RIGHT;So;0;ON;;;;;N;;;;;
+259E;QUADRANT UPPER RIGHT AND LOWER LEFT;So;0;ON;;;;;N;;;;;
+259F;QUADRANT UPPER RIGHT AND LOWER LEFT AND LOWER RIGHT;So;0;ON;;;;;N;;;;;
+25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;;
+25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;;
+25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;
+25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;;
+25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;;
+25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;;
+25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;;
+25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;;
+25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;;
+25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;;
+25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;;
+25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;;
+25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;;
+25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;;
+25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;;
+25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;;
+25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;;
+25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;;
+25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;;
+25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;;
+25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;;
+25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;;
+25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;;
+25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;;
+25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;;
+25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;;
+25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;;
+25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;;
+25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;;
+25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;;
+25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+25C9;FISHEYE;So;0;ON;;;;;N;;;;;
+25CA;LOZENGE;So;0;ON;;;;;N;;;;;
+25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;;
+25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25CE;BULLSEYE;So;0;ON;;;;;N;;;;;
+25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;;
+25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E6;WHITE BULLET;So;0;ON;;;;;N;;;;;
+25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;;
+25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;;
+25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;;
+25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;;
+25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;;
+25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F8;UPPER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25F9;UPPER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25FA;LOWER LEFT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+25FB;WHITE MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;
+25FC;BLACK MEDIUM SQUARE;Sm;0;ON;;;;;N;;;;;
+25FD;WHITE MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;
+25FE;BLACK MEDIUM SMALL SQUARE;Sm;0;ON;;;;;N;;;;;
+25FF;LOWER RIGHT TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+2601;CLOUD;So;0;ON;;;;;N;;;;;
+2602;UMBRELLA;So;0;ON;;;;;N;;;;;
+2603;SNOWMAN;So;0;ON;;;;;N;;;;;
+2604;COMET;So;0;ON;;;;;N;;;;;
+2605;BLACK STAR;So;0;ON;;;;;N;;;;;
+2606;WHITE STAR;So;0;ON;;;;;N;;;;;
+2607;LIGHTNING;So;0;ON;;;;;N;;;;;
+2608;THUNDERSTORM;So;0;ON;;;;;N;;;;;
+2609;SUN;So;0;ON;;;;;N;;;;;
+260A;ASCENDING NODE;So;0;ON;;;;;N;;;;;
+260B;DESCENDING NODE;So;0;ON;;;;;N;;;;;
+260C;CONJUNCTION;So;0;ON;;;;;N;;;;;
+260D;OPPOSITION;So;0;ON;;;;;N;;;;;
+260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;;
+260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;;
+2610;BALLOT BOX;So;0;ON;;;;;N;;;;;
+2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;;
+2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;;
+2613;SALTIRE;So;0;ON;;;;;N;;;;;
+2614;UMBRELLA WITH RAIN DROPS;So;0;ON;;;;;N;;;;;
+2615;HOT BEVERAGE;So;0;ON;;;;;N;;;;;
+2616;WHITE SHOGI PIECE;So;0;ON;;;;;N;;;;;
+2617;BLACK SHOGI PIECE;So;0;ON;;;;;N;;;;;
+2618;SHAMROCK;So;0;ON;;;;;N;;;;;
+2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;;
+261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;
+2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;;
+2621;CAUTION SIGN;So;0;ON;;;;;N;;;;;
+2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;;
+2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;;
+2624;CADUCEUS;So;0;ON;;;;;N;;;;;
+2625;ANKH;So;0;ON;;;;;N;;;;;
+2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;;
+2627;CHI RHO;So;0;ON;;;;;N;;;;;
+2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;;
+2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;;
+262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;;
+262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;;
+262C;ADI SHAKTI;So;0;ON;;;;;N;;;;;
+262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;;
+262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;;
+262F;YIN YANG;So;0;ON;;;;;N;;;;;
+2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;;
+2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;;
+2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;;
+2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;;
+2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;;
+2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;;
+2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;;
+2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;;
+2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;;
+263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;;
+263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;;
+263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263F;MERCURY;So;0;ON;;;;;N;;;;;
+2640;FEMALE SIGN;So;0;ON;;;;;N;;;;;
+2641;EARTH;So;0;ON;;;;;N;;;;;
+2642;MALE SIGN;So;0;ON;;;;;N;;;;;
+2643;JUPITER;So;0;ON;;;;;N;;;;;
+2644;SATURN;So;0;ON;;;;;N;;;;;
+2645;URANUS;So;0;ON;;;;;N;;;;;
+2646;NEPTUNE;So;0;ON;;;;;N;;;;;
+2647;PLUTO;So;0;ON;;;;;N;;;;;
+2648;ARIES;So;0;ON;;;;;N;;;;;
+2649;TAURUS;So;0;ON;;;;;N;;;;;
+264A;GEMINI;So;0;ON;;;;;N;;;;;
+264B;CANCER;So;0;ON;;;;;N;;;;;
+264C;LEO;So;0;ON;;;;;N;;;;;
+264D;VIRGO;So;0;ON;;;;;N;;;;;
+264E;LIBRA;So;0;ON;;;;;N;;;;;
+264F;SCORPIUS;So;0;ON;;;;;N;;;;;
+2650;SAGITTARIUS;So;0;ON;;;;;N;;;;;
+2651;CAPRICORN;So;0;ON;;;;;N;;;;;
+2652;AQUARIUS;So;0;ON;;;;;N;;;;;
+2653;PISCES;So;0;ON;;;;;N;;;;;
+2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;;
+2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;;
+2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;;
+2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;;
+2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;;
+265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;;
+265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;;
+265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;;
+265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;;
+265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;;
+2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;;
+2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;;
+2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;;
+2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;;
+2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;;
+2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;;
+2668;HOT SPRINGS;So;0;ON;;;;;N;;;;;
+2669;QUARTER NOTE;So;0;ON;;;;;N;;;;;
+266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;;
+266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;;
+266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;;
+266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;;
+266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;;
+266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;;
+2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2672;UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;
+2673;RECYCLING SYMBOL FOR TYPE-1 PLASTICS;So;0;ON;;;;;N;;pete;;;
+2674;RECYCLING SYMBOL FOR TYPE-2 PLASTICS;So;0;ON;;;;;N;;hdpe;;;
+2675;RECYCLING SYMBOL FOR TYPE-3 PLASTICS;So;0;ON;;;;;N;;pvc;;;
+2676;RECYCLING SYMBOL FOR TYPE-4 PLASTICS;So;0;ON;;;;;N;;ldpe;;;
+2677;RECYCLING SYMBOL FOR TYPE-5 PLASTICS;So;0;ON;;;;;N;;pp;;;
+2678;RECYCLING SYMBOL FOR TYPE-6 PLASTICS;So;0;ON;;;;;N;;ps;;;
+2679;RECYCLING SYMBOL FOR TYPE-7 PLASTICS;So;0;ON;;;;;N;;other;;;
+267A;RECYCLING SYMBOL FOR GENERIC MATERIALS;So;0;ON;;;;;N;;;;;
+267B;BLACK UNIVERSAL RECYCLING SYMBOL;So;0;ON;;;;;N;;;;;
+267C;RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;
+267D;PARTIALLY-RECYCLED PAPER SYMBOL;So;0;ON;;;;;N;;;;;
+267E;PERMANENT PAPER SIGN;So;0;ON;;;;;N;;;;;
+267F;WHEELCHAIR SYMBOL;So;0;ON;;;;;N;;;;;
+2680;DIE FACE-1;So;0;ON;;;;;N;;;;;
+2681;DIE FACE-2;So;0;ON;;;;;N;;;;;
+2682;DIE FACE-3;So;0;ON;;;;;N;;;;;
+2683;DIE FACE-4;So;0;ON;;;;;N;;;;;
+2684;DIE FACE-5;So;0;ON;;;;;N;;;;;
+2685;DIE FACE-6;So;0;ON;;;;;N;;;;;
+2686;WHITE CIRCLE WITH DOT RIGHT;So;0;ON;;;;;N;;;;;
+2687;WHITE CIRCLE WITH TWO DOTS;So;0;ON;;;;;N;;;;;
+2688;BLACK CIRCLE WITH WHITE DOT RIGHT;So;0;ON;;;;;N;;;;;
+2689;BLACK CIRCLE WITH TWO WHITE DOTS;So;0;ON;;;;;N;;;;;
+268A;MONOGRAM FOR YANG;So;0;ON;;;;;N;;;;;
+268B;MONOGRAM FOR YIN;So;0;ON;;;;;N;;;;;
+268C;DIGRAM FOR GREATER YANG;So;0;ON;;;;;N;;;;;
+268D;DIGRAM FOR LESSER YIN;So;0;ON;;;;;N;;;;;
+268E;DIGRAM FOR LESSER YANG;So;0;ON;;;;;N;;;;;
+268F;DIGRAM FOR GREATER YIN;So;0;ON;;;;;N;;;;;
+2690;WHITE FLAG;So;0;ON;;;;;N;;;;;
+2691;BLACK FLAG;So;0;ON;;;;;N;;;;;
+2692;HAMMER AND PICK;So;0;ON;;;;;N;;;;;
+2693;ANCHOR;So;0;ON;;;;;N;;;;;
+2694;CROSSED SWORDS;So;0;ON;;;;;N;;;;;
+2695;STAFF OF AESCULAPIUS;So;0;ON;;;;;N;;;;;
+2696;SCALES;So;0;ON;;;;;N;;;;;
+2697;ALEMBIC;So;0;ON;;;;;N;;;;;
+2698;FLOWER;So;0;ON;;;;;N;;;;;
+2699;GEAR;So;0;ON;;;;;N;;;;;
+269A;STAFF OF HERMES;So;0;ON;;;;;N;;;;;
+269B;ATOM SYMBOL;So;0;ON;;;;;N;;;;;
+269C;FLEUR-DE-LIS;So;0;ON;;;;;N;;;;;
+26A0;WARNING SIGN;So;0;ON;;;;;N;;;;;
+26A1;HIGH VOLTAGE SIGN;So;0;ON;;;;;N;;;;;
+26A2;DOUBLED FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A3;DOUBLED MALE SIGN;So;0;ON;;;;;N;;;;;
+26A4;INTERLOCKED FEMALE AND MALE SIGN;So;0;ON;;;;;N;;;;;
+26A5;MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A6;MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26A7;MALE WITH STROKE AND MALE AND FEMALE SIGN;So;0;ON;;;;;N;;;;;
+26A8;VERTICAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26A9;HORIZONTAL MALE WITH STROKE SIGN;So;0;ON;;;;;N;;;;;
+26AA;MEDIUM WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+26AB;MEDIUM BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+26AC;MEDIUM SMALL WHITE CIRCLE;So;0;L;;;;;N;;;;;
+26AD;MARRIAGE SYMBOL;So;0;ON;;;;;N;;;;;
+26AE;DIVORCE SYMBOL;So;0;ON;;;;;N;;;;;
+26AF;UNMARRIED PARTNERSHIP SYMBOL;So;0;ON;;;;;N;;;;;
+26B0;COFFIN;So;0;ON;;;;;N;;;;;
+26B1;FUNERAL URN;So;0;ON;;;;;N;;;;;
+2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;;
+2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;;
+2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;;
+2707;TAPE DRIVE;So;0;ON;;;;;N;;;;;
+2708;AIRPLANE;So;0;ON;;;;;N;;;;;
+2709;ENVELOPE;So;0;ON;;;;;N;;;;;
+270C;VICTORY HAND;So;0;ON;;;;;N;;;;;
+270D;WRITING HAND;So;0;ON;;;;;N;;;;;
+270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+270F;PENCIL;So;0;ON;;;;;N;;;;;
+2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+2711;WHITE NIB;So;0;ON;;;;;N;;;;;
+2712;BLACK NIB;So;0;ON;;;;;N;;;;;
+2713;CHECK MARK;So;0;ON;;;;;N;;;;;
+2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;;
+2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2717;BALLOT X;So;0;ON;;;;;N;;;;;
+2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;;
+2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;;
+271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;
+271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;;
+271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;;
+271D;LATIN CROSS;So;0;ON;;;;;N;;;;;
+271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;;
+271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;;
+2720;MALTESE CROSS;So;0;ON;;;;;N;;;;;
+2721;STAR OF DAVID;So;0;ON;;;;;N;;;;;
+2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;;
+272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;;
+272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;;
+272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;;
+272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;;
+2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;;
+2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;;
+2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;;
+273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;;
+273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;;
+2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;;
+2744;SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2747;SPARKLE;So;0;ON;;;;;N;;;;;
+2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;;
+2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;;
+2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;;
+2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;;
+2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;;
+2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;;
+2766;FLORAL HEART;So;0;ON;;;;;N;;;;;
+2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+2768;MEDIUM LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2769;MEDIUM RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276A;MEDIUM FLATTENED LEFT PARENTHESIS ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276B;MEDIUM FLATTENED RIGHT PARENTHESIS ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276C;MEDIUM LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276D;MEDIUM RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+276E;HEAVY LEFT-POINTING ANGLE QUOTATION MARK ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+276F;HEAVY RIGHT-POINTING ANGLE QUOTATION MARK ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2770;HEAVY LEFT-POINTING ANGLE BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2771;HEAVY RIGHT-POINTING ANGLE BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2772;LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2773;LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2774;MEDIUM LEFT CURLY BRACKET ORNAMENT;Ps;0;ON;;;;;Y;;;;;
+2775;MEDIUM RIGHT CURLY BRACKET ORNAMENT;Pe;0;ON;;;;;Y;;;;;
+2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;;
+2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;;
+2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;;
+2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;;
+277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;;
+277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;;
+277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;;
+277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;;
+277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;;
+277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;;
+2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;;
+2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;;
+2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;;
+2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;;
+2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;;
+2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;;
+2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;;
+2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;;
+278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;;
+278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;;
+278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;;
+278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;;
+278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;;
+278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;;
+2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;;
+2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;;
+2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;;
+2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;;
+2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;;
+279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;;
+279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;;
+279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;;
+279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;;
+279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;;
+279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;;
+27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;;
+27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;;
+27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;;
+27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;;
+27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;;
+27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;;
+27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;;
+27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;;
+27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;;
+27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;;
+27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;;
+27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;;
+27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;;
+27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;;
+27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;;
+27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;;
+27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;;
+27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;;
+27C0;THREE DIMENSIONAL ANGLE;Sm;0;ON;;;;;Y;;;;;
+27C1;WHITE TRIANGLE CONTAINING SMALL WHITE TRIANGLE;Sm;0;ON;;;;;N;;;;;
+27C2;PERPENDICULAR;Sm;0;ON;;;;;N;;;;;
+27C3;OPEN SUBSET;Sm;0;ON;;;;;Y;;;;;
+27C4;OPEN SUPERSET;Sm;0;ON;;;;;Y;;;;;
+27C5;LEFT S-SHAPED BAG DELIMITER;Ps;0;ON;;;;;Y;;;;;
+27C6;RIGHT S-SHAPED BAG DELIMITER;Pe;0;ON;;;;;Y;;;;;
+27D0;WHITE DIAMOND WITH CENTRED DOT;Sm;0;ON;;;;;N;;;;;
+27D1;AND WITH DOT;Sm;0;ON;;;;;N;;;;;
+27D2;ELEMENT OF OPENING UPWARDS;Sm;0;ON;;;;;N;;;;;
+27D3;LOWER RIGHT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;
+27D4;UPPER LEFT CORNER WITH DOT;Sm;0;ON;;;;;Y;;;;;
+27D5;LEFT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;
+27D6;RIGHT OUTER JOIN;Sm;0;ON;;;;;Y;;;;;
+27D7;FULL OUTER JOIN;Sm;0;ON;;;;;N;;;;;
+27D8;LARGE UP TACK;Sm;0;ON;;;;;N;;;;;
+27D9;LARGE DOWN TACK;Sm;0;ON;;;;;N;;;;;
+27DA;LEFT AND RIGHT DOUBLE TURNSTILE;Sm;0;ON;;;;;N;;;;;
+27DB;LEFT AND RIGHT TACK;Sm;0;ON;;;;;N;;;;;
+27DC;LEFT MULTIMAP;Sm;0;ON;;;;;Y;;;;;
+27DD;LONG RIGHT TACK;Sm;0;ON;;;;;Y;;;;;
+27DE;LONG LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+27DF;UP TACK WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+27E0;LOZENGE DIVIDED BY HORIZONTAL RULE;Sm;0;ON;;;;;N;;;;;
+27E1;WHITE CONCAVE-SIDED DIAMOND;Sm;0;ON;;;;;N;;;;;
+27E2;WHITE CONCAVE-SIDED DIAMOND WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E3;WHITE CONCAVE-SIDED DIAMOND WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E4;WHITE SQUARE WITH LEFTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E5;WHITE SQUARE WITH RIGHTWARDS TICK;Sm;0;ON;;;;;Y;;;;;
+27E6;MATHEMATICAL LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27E7;MATHEMATICAL RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27E8;MATHEMATICAL LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27E9;MATHEMATICAL RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27EA;MATHEMATICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+27EB;MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+27F0;UPWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F1;DOWNWARDS QUADRUPLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F2;ANTICLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F3;CLOCKWISE GAPPED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F4;RIGHT ARROW WITH CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+27F5;LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+27F6;LONG RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+27F7;LONG LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;
+27F8;LONG LEFTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27F9;LONG RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27FA;LONG LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+27FB;LONG LEFTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FC;LONG RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FD;LONG LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FE;LONG RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+27FF;LONG RIGHTWARDS SQUIGGLE ARROW;Sm;0;ON;;;;;N;;;;;
+2800;BRAILLE PATTERN BLANK;So;0;L;;;;;N;;;;;
+2801;BRAILLE PATTERN DOTS-1;So;0;L;;;;;N;;;;;
+2802;BRAILLE PATTERN DOTS-2;So;0;L;;;;;N;;;;;
+2803;BRAILLE PATTERN DOTS-12;So;0;L;;;;;N;;;;;
+2804;BRAILLE PATTERN DOTS-3;So;0;L;;;;;N;;;;;
+2805;BRAILLE PATTERN DOTS-13;So;0;L;;;;;N;;;;;
+2806;BRAILLE PATTERN DOTS-23;So;0;L;;;;;N;;;;;
+2807;BRAILLE PATTERN DOTS-123;So;0;L;;;;;N;;;;;
+2808;BRAILLE PATTERN DOTS-4;So;0;L;;;;;N;;;;;
+2809;BRAILLE PATTERN DOTS-14;So;0;L;;;;;N;;;;;
+280A;BRAILLE PATTERN DOTS-24;So;0;L;;;;;N;;;;;
+280B;BRAILLE PATTERN DOTS-124;So;0;L;;;;;N;;;;;
+280C;BRAILLE PATTERN DOTS-34;So;0;L;;;;;N;;;;;
+280D;BRAILLE PATTERN DOTS-134;So;0;L;;;;;N;;;;;
+280E;BRAILLE PATTERN DOTS-234;So;0;L;;;;;N;;;;;
+280F;BRAILLE PATTERN DOTS-1234;So;0;L;;;;;N;;;;;
+2810;BRAILLE PATTERN DOTS-5;So;0;L;;;;;N;;;;;
+2811;BRAILLE PATTERN DOTS-15;So;0;L;;;;;N;;;;;
+2812;BRAILLE PATTERN DOTS-25;So;0;L;;;;;N;;;;;
+2813;BRAILLE PATTERN DOTS-125;So;0;L;;;;;N;;;;;
+2814;BRAILLE PATTERN DOTS-35;So;0;L;;;;;N;;;;;
+2815;BRAILLE PATTERN DOTS-135;So;0;L;;;;;N;;;;;
+2816;BRAILLE PATTERN DOTS-235;So;0;L;;;;;N;;;;;
+2817;BRAILLE PATTERN DOTS-1235;So;0;L;;;;;N;;;;;
+2818;BRAILLE PATTERN DOTS-45;So;0;L;;;;;N;;;;;
+2819;BRAILLE PATTERN DOTS-145;So;0;L;;;;;N;;;;;
+281A;BRAILLE PATTERN DOTS-245;So;0;L;;;;;N;;;;;
+281B;BRAILLE PATTERN DOTS-1245;So;0;L;;;;;N;;;;;
+281C;BRAILLE PATTERN DOTS-345;So;0;L;;;;;N;;;;;
+281D;BRAILLE PATTERN DOTS-1345;So;0;L;;;;;N;;;;;
+281E;BRAILLE PATTERN DOTS-2345;So;0;L;;;;;N;;;;;
+281F;BRAILLE PATTERN DOTS-12345;So;0;L;;;;;N;;;;;
+2820;BRAILLE PATTERN DOTS-6;So;0;L;;;;;N;;;;;
+2821;BRAILLE PATTERN DOTS-16;So;0;L;;;;;N;;;;;
+2822;BRAILLE PATTERN DOTS-26;So;0;L;;;;;N;;;;;
+2823;BRAILLE PATTERN DOTS-126;So;0;L;;;;;N;;;;;
+2824;BRAILLE PATTERN DOTS-36;So;0;L;;;;;N;;;;;
+2825;BRAILLE PATTERN DOTS-136;So;0;L;;;;;N;;;;;
+2826;BRAILLE PATTERN DOTS-236;So;0;L;;;;;N;;;;;
+2827;BRAILLE PATTERN DOTS-1236;So;0;L;;;;;N;;;;;
+2828;BRAILLE PATTERN DOTS-46;So;0;L;;;;;N;;;;;
+2829;BRAILLE PATTERN DOTS-146;So;0;L;;;;;N;;;;;
+282A;BRAILLE PATTERN DOTS-246;So;0;L;;;;;N;;;;;
+282B;BRAILLE PATTERN DOTS-1246;So;0;L;;;;;N;;;;;
+282C;BRAILLE PATTERN DOTS-346;So;0;L;;;;;N;;;;;
+282D;BRAILLE PATTERN DOTS-1346;So;0;L;;;;;N;;;;;
+282E;BRAILLE PATTERN DOTS-2346;So;0;L;;;;;N;;;;;
+282F;BRAILLE PATTERN DOTS-12346;So;0;L;;;;;N;;;;;
+2830;BRAILLE PATTERN DOTS-56;So;0;L;;;;;N;;;;;
+2831;BRAILLE PATTERN DOTS-156;So;0;L;;;;;N;;;;;
+2832;BRAILLE PATTERN DOTS-256;So;0;L;;;;;N;;;;;
+2833;BRAILLE PATTERN DOTS-1256;So;0;L;;;;;N;;;;;
+2834;BRAILLE PATTERN DOTS-356;So;0;L;;;;;N;;;;;
+2835;BRAILLE PATTERN DOTS-1356;So;0;L;;;;;N;;;;;
+2836;BRAILLE PATTERN DOTS-2356;So;0;L;;;;;N;;;;;
+2837;BRAILLE PATTERN DOTS-12356;So;0;L;;;;;N;;;;;
+2838;BRAILLE PATTERN DOTS-456;So;0;L;;;;;N;;;;;
+2839;BRAILLE PATTERN DOTS-1456;So;0;L;;;;;N;;;;;
+283A;BRAILLE PATTERN DOTS-2456;So;0;L;;;;;N;;;;;
+283B;BRAILLE PATTERN DOTS-12456;So;0;L;;;;;N;;;;;
+283C;BRAILLE PATTERN DOTS-3456;So;0;L;;;;;N;;;;;
+283D;BRAILLE PATTERN DOTS-13456;So;0;L;;;;;N;;;;;
+283E;BRAILLE PATTERN DOTS-23456;So;0;L;;;;;N;;;;;
+283F;BRAILLE PATTERN DOTS-123456;So;0;L;;;;;N;;;;;
+2840;BRAILLE PATTERN DOTS-7;So;0;L;;;;;N;;;;;
+2841;BRAILLE PATTERN DOTS-17;So;0;L;;;;;N;;;;;
+2842;BRAILLE PATTERN DOTS-27;So;0;L;;;;;N;;;;;
+2843;BRAILLE PATTERN DOTS-127;So;0;L;;;;;N;;;;;
+2844;BRAILLE PATTERN DOTS-37;So;0;L;;;;;N;;;;;
+2845;BRAILLE PATTERN DOTS-137;So;0;L;;;;;N;;;;;
+2846;BRAILLE PATTERN DOTS-237;So;0;L;;;;;N;;;;;
+2847;BRAILLE PATTERN DOTS-1237;So;0;L;;;;;N;;;;;
+2848;BRAILLE PATTERN DOTS-47;So;0;L;;;;;N;;;;;
+2849;BRAILLE PATTERN DOTS-147;So;0;L;;;;;N;;;;;
+284A;BRAILLE PATTERN DOTS-247;So;0;L;;;;;N;;;;;
+284B;BRAILLE PATTERN DOTS-1247;So;0;L;;;;;N;;;;;
+284C;BRAILLE PATTERN DOTS-347;So;0;L;;;;;N;;;;;
+284D;BRAILLE PATTERN DOTS-1347;So;0;L;;;;;N;;;;;
+284E;BRAILLE PATTERN DOTS-2347;So;0;L;;;;;N;;;;;
+284F;BRAILLE PATTERN DOTS-12347;So;0;L;;;;;N;;;;;
+2850;BRAILLE PATTERN DOTS-57;So;0;L;;;;;N;;;;;
+2851;BRAILLE PATTERN DOTS-157;So;0;L;;;;;N;;;;;
+2852;BRAILLE PATTERN DOTS-257;So;0;L;;;;;N;;;;;
+2853;BRAILLE PATTERN DOTS-1257;So;0;L;;;;;N;;;;;
+2854;BRAILLE PATTERN DOTS-357;So;0;L;;;;;N;;;;;
+2855;BRAILLE PATTERN DOTS-1357;So;0;L;;;;;N;;;;;
+2856;BRAILLE PATTERN DOTS-2357;So;0;L;;;;;N;;;;;
+2857;BRAILLE PATTERN DOTS-12357;So;0;L;;;;;N;;;;;
+2858;BRAILLE PATTERN DOTS-457;So;0;L;;;;;N;;;;;
+2859;BRAILLE PATTERN DOTS-1457;So;0;L;;;;;N;;;;;
+285A;BRAILLE PATTERN DOTS-2457;So;0;L;;;;;N;;;;;
+285B;BRAILLE PATTERN DOTS-12457;So;0;L;;;;;N;;;;;
+285C;BRAILLE PATTERN DOTS-3457;So;0;L;;;;;N;;;;;
+285D;BRAILLE PATTERN DOTS-13457;So;0;L;;;;;N;;;;;
+285E;BRAILLE PATTERN DOTS-23457;So;0;L;;;;;N;;;;;
+285F;BRAILLE PATTERN DOTS-123457;So;0;L;;;;;N;;;;;
+2860;BRAILLE PATTERN DOTS-67;So;0;L;;;;;N;;;;;
+2861;BRAILLE PATTERN DOTS-167;So;0;L;;;;;N;;;;;
+2862;BRAILLE PATTERN DOTS-267;So;0;L;;;;;N;;;;;
+2863;BRAILLE PATTERN DOTS-1267;So;0;L;;;;;N;;;;;
+2864;BRAILLE PATTERN DOTS-367;So;0;L;;;;;N;;;;;
+2865;BRAILLE PATTERN DOTS-1367;So;0;L;;;;;N;;;;;
+2866;BRAILLE PATTERN DOTS-2367;So;0;L;;;;;N;;;;;
+2867;BRAILLE PATTERN DOTS-12367;So;0;L;;;;;N;;;;;
+2868;BRAILLE PATTERN DOTS-467;So;0;L;;;;;N;;;;;
+2869;BRAILLE PATTERN DOTS-1467;So;0;L;;;;;N;;;;;
+286A;BRAILLE PATTERN DOTS-2467;So;0;L;;;;;N;;;;;
+286B;BRAILLE PATTERN DOTS-12467;So;0;L;;;;;N;;;;;
+286C;BRAILLE PATTERN DOTS-3467;So;0;L;;;;;N;;;;;
+286D;BRAILLE PATTERN DOTS-13467;So;0;L;;;;;N;;;;;
+286E;BRAILLE PATTERN DOTS-23467;So;0;L;;;;;N;;;;;
+286F;BRAILLE PATTERN DOTS-123467;So;0;L;;;;;N;;;;;
+2870;BRAILLE PATTERN DOTS-567;So;0;L;;;;;N;;;;;
+2871;BRAILLE PATTERN DOTS-1567;So;0;L;;;;;N;;;;;
+2872;BRAILLE PATTERN DOTS-2567;So;0;L;;;;;N;;;;;
+2873;BRAILLE PATTERN DOTS-12567;So;0;L;;;;;N;;;;;
+2874;BRAILLE PATTERN DOTS-3567;So;0;L;;;;;N;;;;;
+2875;BRAILLE PATTERN DOTS-13567;So;0;L;;;;;N;;;;;
+2876;BRAILLE PATTERN DOTS-23567;So;0;L;;;;;N;;;;;
+2877;BRAILLE PATTERN DOTS-123567;So;0;L;;;;;N;;;;;
+2878;BRAILLE PATTERN DOTS-4567;So;0;L;;;;;N;;;;;
+2879;BRAILLE PATTERN DOTS-14567;So;0;L;;;;;N;;;;;
+287A;BRAILLE PATTERN DOTS-24567;So;0;L;;;;;N;;;;;
+287B;BRAILLE PATTERN DOTS-124567;So;0;L;;;;;N;;;;;
+287C;BRAILLE PATTERN DOTS-34567;So;0;L;;;;;N;;;;;
+287D;BRAILLE PATTERN DOTS-134567;So;0;L;;;;;N;;;;;
+287E;BRAILLE PATTERN DOTS-234567;So;0;L;;;;;N;;;;;
+287F;BRAILLE PATTERN DOTS-1234567;So;0;L;;;;;N;;;;;
+2880;BRAILLE PATTERN DOTS-8;So;0;L;;;;;N;;;;;
+2881;BRAILLE PATTERN DOTS-18;So;0;L;;;;;N;;;;;
+2882;BRAILLE PATTERN DOTS-28;So;0;L;;;;;N;;;;;
+2883;BRAILLE PATTERN DOTS-128;So;0;L;;;;;N;;;;;
+2884;BRAILLE PATTERN DOTS-38;So;0;L;;;;;N;;;;;
+2885;BRAILLE PATTERN DOTS-138;So;0;L;;;;;N;;;;;
+2886;BRAILLE PATTERN DOTS-238;So;0;L;;;;;N;;;;;
+2887;BRAILLE PATTERN DOTS-1238;So;0;L;;;;;N;;;;;
+2888;BRAILLE PATTERN DOTS-48;So;0;L;;;;;N;;;;;
+2889;BRAILLE PATTERN DOTS-148;So;0;L;;;;;N;;;;;
+288A;BRAILLE PATTERN DOTS-248;So;0;L;;;;;N;;;;;
+288B;BRAILLE PATTERN DOTS-1248;So;0;L;;;;;N;;;;;
+288C;BRAILLE PATTERN DOTS-348;So;0;L;;;;;N;;;;;
+288D;BRAILLE PATTERN DOTS-1348;So;0;L;;;;;N;;;;;
+288E;BRAILLE PATTERN DOTS-2348;So;0;L;;;;;N;;;;;
+288F;BRAILLE PATTERN DOTS-12348;So;0;L;;;;;N;;;;;
+2890;BRAILLE PATTERN DOTS-58;So;0;L;;;;;N;;;;;
+2891;BRAILLE PATTERN DOTS-158;So;0;L;;;;;N;;;;;
+2892;BRAILLE PATTERN DOTS-258;So;0;L;;;;;N;;;;;
+2893;BRAILLE PATTERN DOTS-1258;So;0;L;;;;;N;;;;;
+2894;BRAILLE PATTERN DOTS-358;So;0;L;;;;;N;;;;;
+2895;BRAILLE PATTERN DOTS-1358;So;0;L;;;;;N;;;;;
+2896;BRAILLE PATTERN DOTS-2358;So;0;L;;;;;N;;;;;
+2897;BRAILLE PATTERN DOTS-12358;So;0;L;;;;;N;;;;;
+2898;BRAILLE PATTERN DOTS-458;So;0;L;;;;;N;;;;;
+2899;BRAILLE PATTERN DOTS-1458;So;0;L;;;;;N;;;;;
+289A;BRAILLE PATTERN DOTS-2458;So;0;L;;;;;N;;;;;
+289B;BRAILLE PATTERN DOTS-12458;So;0;L;;;;;N;;;;;
+289C;BRAILLE PATTERN DOTS-3458;So;0;L;;;;;N;;;;;
+289D;BRAILLE PATTERN DOTS-13458;So;0;L;;;;;N;;;;;
+289E;BRAILLE PATTERN DOTS-23458;So;0;L;;;;;N;;;;;
+289F;BRAILLE PATTERN DOTS-123458;So;0;L;;;;;N;;;;;
+28A0;BRAILLE PATTERN DOTS-68;So;0;L;;;;;N;;;;;
+28A1;BRAILLE PATTERN DOTS-168;So;0;L;;;;;N;;;;;
+28A2;BRAILLE PATTERN DOTS-268;So;0;L;;;;;N;;;;;
+28A3;BRAILLE PATTERN DOTS-1268;So;0;L;;;;;N;;;;;
+28A4;BRAILLE PATTERN DOTS-368;So;0;L;;;;;N;;;;;
+28A5;BRAILLE PATTERN DOTS-1368;So;0;L;;;;;N;;;;;
+28A6;BRAILLE PATTERN DOTS-2368;So;0;L;;;;;N;;;;;
+28A7;BRAILLE PATTERN DOTS-12368;So;0;L;;;;;N;;;;;
+28A8;BRAILLE PATTERN DOTS-468;So;0;L;;;;;N;;;;;
+28A9;BRAILLE PATTERN DOTS-1468;So;0;L;;;;;N;;;;;
+28AA;BRAILLE PATTERN DOTS-2468;So;0;L;;;;;N;;;;;
+28AB;BRAILLE PATTERN DOTS-12468;So;0;L;;;;;N;;;;;
+28AC;BRAILLE PATTERN DOTS-3468;So;0;L;;;;;N;;;;;
+28AD;BRAILLE PATTERN DOTS-13468;So;0;L;;;;;N;;;;;
+28AE;BRAILLE PATTERN DOTS-23468;So;0;L;;;;;N;;;;;
+28AF;BRAILLE PATTERN DOTS-123468;So;0;L;;;;;N;;;;;
+28B0;BRAILLE PATTERN DOTS-568;So;0;L;;;;;N;;;;;
+28B1;BRAILLE PATTERN DOTS-1568;So;0;L;;;;;N;;;;;
+28B2;BRAILLE PATTERN DOTS-2568;So;0;L;;;;;N;;;;;
+28B3;BRAILLE PATTERN DOTS-12568;So;0;L;;;;;N;;;;;
+28B4;BRAILLE PATTERN DOTS-3568;So;0;L;;;;;N;;;;;
+28B5;BRAILLE PATTERN DOTS-13568;So;0;L;;;;;N;;;;;
+28B6;BRAILLE PATTERN DOTS-23568;So;0;L;;;;;N;;;;;
+28B7;BRAILLE PATTERN DOTS-123568;So;0;L;;;;;N;;;;;
+28B8;BRAILLE PATTERN DOTS-4568;So;0;L;;;;;N;;;;;
+28B9;BRAILLE PATTERN DOTS-14568;So;0;L;;;;;N;;;;;
+28BA;BRAILLE PATTERN DOTS-24568;So;0;L;;;;;N;;;;;
+28BB;BRAILLE PATTERN DOTS-124568;So;0;L;;;;;N;;;;;
+28BC;BRAILLE PATTERN DOTS-34568;So;0;L;;;;;N;;;;;
+28BD;BRAILLE PATTERN DOTS-134568;So;0;L;;;;;N;;;;;
+28BE;BRAILLE PATTERN DOTS-234568;So;0;L;;;;;N;;;;;
+28BF;BRAILLE PATTERN DOTS-1234568;So;0;L;;;;;N;;;;;
+28C0;BRAILLE PATTERN DOTS-78;So;0;L;;;;;N;;;;;
+28C1;BRAILLE PATTERN DOTS-178;So;0;L;;;;;N;;;;;
+28C2;BRAILLE PATTERN DOTS-278;So;0;L;;;;;N;;;;;
+28C3;BRAILLE PATTERN DOTS-1278;So;0;L;;;;;N;;;;;
+28C4;BRAILLE PATTERN DOTS-378;So;0;L;;;;;N;;;;;
+28C5;BRAILLE PATTERN DOTS-1378;So;0;L;;;;;N;;;;;
+28C6;BRAILLE PATTERN DOTS-2378;So;0;L;;;;;N;;;;;
+28C7;BRAILLE PATTERN DOTS-12378;So;0;L;;;;;N;;;;;
+28C8;BRAILLE PATTERN DOTS-478;So;0;L;;;;;N;;;;;
+28C9;BRAILLE PATTERN DOTS-1478;So;0;L;;;;;N;;;;;
+28CA;BRAILLE PATTERN DOTS-2478;So;0;L;;;;;N;;;;;
+28CB;BRAILLE PATTERN DOTS-12478;So;0;L;;;;;N;;;;;
+28CC;BRAILLE PATTERN DOTS-3478;So;0;L;;;;;N;;;;;
+28CD;BRAILLE PATTERN DOTS-13478;So;0;L;;;;;N;;;;;
+28CE;BRAILLE PATTERN DOTS-23478;So;0;L;;;;;N;;;;;
+28CF;BRAILLE PATTERN DOTS-123478;So;0;L;;;;;N;;;;;
+28D0;BRAILLE PATTERN DOTS-578;So;0;L;;;;;N;;;;;
+28D1;BRAILLE PATTERN DOTS-1578;So;0;L;;;;;N;;;;;
+28D2;BRAILLE PATTERN DOTS-2578;So;0;L;;;;;N;;;;;
+28D3;BRAILLE PATTERN DOTS-12578;So;0;L;;;;;N;;;;;
+28D4;BRAILLE PATTERN DOTS-3578;So;0;L;;;;;N;;;;;
+28D5;BRAILLE PATTERN DOTS-13578;So;0;L;;;;;N;;;;;
+28D6;BRAILLE PATTERN DOTS-23578;So;0;L;;;;;N;;;;;
+28D7;BRAILLE PATTERN DOTS-123578;So;0;L;;;;;N;;;;;
+28D8;BRAILLE PATTERN DOTS-4578;So;0;L;;;;;N;;;;;
+28D9;BRAILLE PATTERN DOTS-14578;So;0;L;;;;;N;;;;;
+28DA;BRAILLE PATTERN DOTS-24578;So;0;L;;;;;N;;;;;
+28DB;BRAILLE PATTERN DOTS-124578;So;0;L;;;;;N;;;;;
+28DC;BRAILLE PATTERN DOTS-34578;So;0;L;;;;;N;;;;;
+28DD;BRAILLE PATTERN DOTS-134578;So;0;L;;;;;N;;;;;
+28DE;BRAILLE PATTERN DOTS-234578;So;0;L;;;;;N;;;;;
+28DF;BRAILLE PATTERN DOTS-1234578;So;0;L;;;;;N;;;;;
+28E0;BRAILLE PATTERN DOTS-678;So;0;L;;;;;N;;;;;
+28E1;BRAILLE PATTERN DOTS-1678;So;0;L;;;;;N;;;;;
+28E2;BRAILLE PATTERN DOTS-2678;So;0;L;;;;;N;;;;;
+28E3;BRAILLE PATTERN DOTS-12678;So;0;L;;;;;N;;;;;
+28E4;BRAILLE PATTERN DOTS-3678;So;0;L;;;;;N;;;;;
+28E5;BRAILLE PATTERN DOTS-13678;So;0;L;;;;;N;;;;;
+28E6;BRAILLE PATTERN DOTS-23678;So;0;L;;;;;N;;;;;
+28E7;BRAILLE PATTERN DOTS-123678;So;0;L;;;;;N;;;;;
+28E8;BRAILLE PATTERN DOTS-4678;So;0;L;;;;;N;;;;;
+28E9;BRAILLE PATTERN DOTS-14678;So;0;L;;;;;N;;;;;
+28EA;BRAILLE PATTERN DOTS-24678;So;0;L;;;;;N;;;;;
+28EB;BRAILLE PATTERN DOTS-124678;So;0;L;;;;;N;;;;;
+28EC;BRAILLE PATTERN DOTS-34678;So;0;L;;;;;N;;;;;
+28ED;BRAILLE PATTERN DOTS-134678;So;0;L;;;;;N;;;;;
+28EE;BRAILLE PATTERN DOTS-234678;So;0;L;;;;;N;;;;;
+28EF;BRAILLE PATTERN DOTS-1234678;So;0;L;;;;;N;;;;;
+28F0;BRAILLE PATTERN DOTS-5678;So;0;L;;;;;N;;;;;
+28F1;BRAILLE PATTERN DOTS-15678;So;0;L;;;;;N;;;;;
+28F2;BRAILLE PATTERN DOTS-25678;So;0;L;;;;;N;;;;;
+28F3;BRAILLE PATTERN DOTS-125678;So;0;L;;;;;N;;;;;
+28F4;BRAILLE PATTERN DOTS-35678;So;0;L;;;;;N;;;;;
+28F5;BRAILLE PATTERN DOTS-135678;So;0;L;;;;;N;;;;;
+28F6;BRAILLE PATTERN DOTS-235678;So;0;L;;;;;N;;;;;
+28F7;BRAILLE PATTERN DOTS-1235678;So;0;L;;;;;N;;;;;
+28F8;BRAILLE PATTERN DOTS-45678;So;0;L;;;;;N;;;;;
+28F9;BRAILLE PATTERN DOTS-145678;So;0;L;;;;;N;;;;;
+28FA;BRAILLE PATTERN DOTS-245678;So;0;L;;;;;N;;;;;
+28FB;BRAILLE PATTERN DOTS-1245678;So;0;L;;;;;N;;;;;
+28FC;BRAILLE PATTERN DOTS-345678;So;0;L;;;;;N;;;;;
+28FD;BRAILLE PATTERN DOTS-1345678;So;0;L;;;;;N;;;;;
+28FE;BRAILLE PATTERN DOTS-2345678;So;0;L;;;;;N;;;;;
+28FF;BRAILLE PATTERN DOTS-12345678;So;0;L;;;;;N;;;;;
+2900;RIGHTWARDS TWO-HEADED ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2901;RIGHTWARDS TWO-HEADED ARROW WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2902;LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2903;RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2904;LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2905;RIGHTWARDS TWO-HEADED ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2906;LEFTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2907;RIGHTWARDS DOUBLE ARROW FROM BAR;Sm;0;ON;;;;;N;;;;;
+2908;DOWNWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2909;UPWARDS ARROW WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+290A;UPWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;
+290B;DOWNWARDS TRIPLE ARROW;Sm;0;ON;;;;;N;;;;;
+290C;LEFTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290D;RIGHTWARDS DOUBLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290E;LEFTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+290F;RIGHTWARDS TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+2910;RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW;Sm;0;ON;;;;;N;;;;;
+2911;RIGHTWARDS ARROW WITH DOTTED STEM;Sm;0;ON;;;;;N;;;;;
+2912;UPWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;
+2913;DOWNWARDS ARROW TO BAR;Sm;0;ON;;;;;N;;;;;
+2914;RIGHTWARDS ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2915;RIGHTWARDS ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2916;RIGHTWARDS TWO-HEADED ARROW WITH TAIL;Sm;0;ON;;;;;N;;;;;
+2917;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2918;RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2919;LEFTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291A;RIGHTWARDS ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291B;LEFTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291C;RIGHTWARDS DOUBLE ARROW-TAIL;Sm;0;ON;;;;;N;;;;;
+291D;LEFTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+291E;RIGHTWARDS ARROW TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+291F;LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+2920;RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+2921;NORTH WEST AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2922;NORTH EAST AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+2923;NORTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2924;NORTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2925;SOUTH EAST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2926;SOUTH WEST ARROW WITH HOOK;Sm;0;ON;;;;;N;;;;;
+2927;NORTH WEST ARROW AND NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2928;NORTH EAST ARROW AND SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2929;SOUTH EAST ARROW AND SOUTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+292A;SOUTH WEST ARROW AND NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+292B;RISING DIAGONAL CROSSING FALLING DIAGONAL;Sm;0;ON;;;;;N;;;;;
+292C;FALLING DIAGONAL CROSSING RISING DIAGONAL;Sm;0;ON;;;;;N;;;;;
+292D;SOUTH EAST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+292E;NORTH EAST ARROW CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+292F;FALLING DIAGONAL CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2930;RISING DIAGONAL CROSSING SOUTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2931;NORTH EAST ARROW CROSSING NORTH WEST ARROW;Sm;0;ON;;;;;N;;;;;
+2932;NORTH WEST ARROW CROSSING NORTH EAST ARROW;Sm;0;ON;;;;;N;;;;;
+2933;WAVE ARROW POINTING DIRECTLY RIGHT;Sm;0;ON;;;;;N;;;;;
+2934;ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS;Sm;0;ON;;;;;N;;;;;
+2935;ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS;Sm;0;ON;;;;;N;;;;;
+2936;ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS;Sm;0;ON;;;;;N;;;;;
+2937;ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS;Sm;0;ON;;;;;N;;;;;
+2938;RIGHT-SIDE ARC CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+2939;LEFT-SIDE ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293A;TOP ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293B;BOTTOM ARC ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293C;TOP ARC CLOCKWISE ARROW WITH MINUS;Sm;0;ON;;;;;N;;;;;
+293D;TOP ARC ANTICLOCKWISE ARROW WITH PLUS;Sm;0;ON;;;;;N;;;;;
+293E;LOWER RIGHT SEMICIRCULAR CLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+293F;LOWER LEFT SEMICIRCULAR ANTICLOCKWISE ARROW;Sm;0;ON;;;;;N;;;;;
+2940;ANTICLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+2941;CLOCKWISE CLOSED CIRCLE ARROW;Sm;0;ON;;;;;N;;;;;
+2942;RIGHTWARDS ARROW ABOVE SHORT LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2943;LEFTWARDS ARROW ABOVE SHORT RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2944;SHORT RIGHTWARDS ARROW ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2945;RIGHTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;
+2946;LEFTWARDS ARROW WITH PLUS BELOW;Sm;0;ON;;;;;N;;;;;
+2947;RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;
+2948;LEFT RIGHT ARROW THROUGH SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+2949;UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+294A;LEFT BARB UP RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;
+294B;LEFT BARB DOWN RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;
+294C;UP BARB RIGHT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;
+294D;UP BARB LEFT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;
+294E;LEFT BARB UP RIGHT BARB UP HARPOON;Sm;0;ON;;;;;N;;;;;
+294F;UP BARB RIGHT DOWN BARB RIGHT HARPOON;Sm;0;ON;;;;;N;;;;;
+2950;LEFT BARB DOWN RIGHT BARB DOWN HARPOON;Sm;0;ON;;;;;N;;;;;
+2951;UP BARB LEFT DOWN BARB LEFT HARPOON;Sm;0;ON;;;;;N;;;;;
+2952;LEFTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;
+2953;RIGHTWARDS HARPOON WITH BARB UP TO BAR;Sm;0;ON;;;;;N;;;;;
+2954;UPWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;
+2955;DOWNWARDS HARPOON WITH BARB RIGHT TO BAR;Sm;0;ON;;;;;N;;;;;
+2956;LEFTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;
+2957;RIGHTWARDS HARPOON WITH BARB DOWN TO BAR;Sm;0;ON;;;;;N;;;;;
+2958;UPWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;
+2959;DOWNWARDS HARPOON WITH BARB LEFT TO BAR;Sm;0;ON;;;;;N;;;;;
+295A;LEFTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;
+295B;RIGHTWARDS HARPOON WITH BARB UP FROM BAR;Sm;0;ON;;;;;N;;;;;
+295C;UPWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;
+295D;DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR;Sm;0;ON;;;;;N;;;;;
+295E;LEFTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;
+295F;RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR;Sm;0;ON;;;;;N;;;;;
+2960;UPWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;
+2961;DOWNWARDS HARPOON WITH BARB LEFT FROM BAR;Sm;0;ON;;;;;N;;;;;
+2962;LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2963;UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2964;RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2965;DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2966;LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;
+2967;LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+2968;RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP;Sm;0;ON;;;;;N;;;;;
+2969;RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN;Sm;0;ON;;;;;N;;;;;
+296A;LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;
+296B;LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;
+296C;RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH;Sm;0;ON;;;;;N;;;;;
+296D;RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH;Sm;0;ON;;;;;N;;;;;
+296E;UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+296F;DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT;Sm;0;ON;;;;;N;;;;;
+2970;RIGHT DOUBLE ARROW WITH ROUNDED HEAD;Sm;0;ON;;;;;N;;;;;
+2971;EQUALS SIGN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2972;TILDE OPERATOR ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2973;LEFTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2974;RIGHTWARDS ARROW ABOVE TILDE OPERATOR;Sm;0;ON;;;;;N;;;;;
+2975;RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2976;LESS-THAN ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2977;LEFTWARDS ARROW THROUGH LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2978;GREATER-THAN ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+2979;SUBSET ABOVE RIGHTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+297A;LEFTWARDS ARROW THROUGH SUBSET;Sm;0;ON;;;;;N;;;;;
+297B;SUPERSET ABOVE LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+297C;LEFT FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297D;RIGHT FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297E;UP FISH TAIL;Sm;0;ON;;;;;N;;;;;
+297F;DOWN FISH TAIL;Sm;0;ON;;;;;N;;;;;
+2980;TRIPLE VERTICAL BAR DELIMITER;Sm;0;ON;;;;;N;;;;;
+2981;Z NOTATION SPOT;Sm;0;ON;;;;;N;;;;;
+2982;Z NOTATION TYPE COLON;Sm;0;ON;;;;;N;;;;;
+2983;LEFT WHITE CURLY BRACKET;Ps;0;ON;;;;;Y;;;;;
+2984;RIGHT WHITE CURLY BRACKET;Pe;0;ON;;;;;Y;;;;;
+2985;LEFT WHITE PARENTHESIS;Ps;0;ON;;;;;Y;;;;;
+2986;RIGHT WHITE PARENTHESIS;Pe;0;ON;;;;;Y;;;;;
+2987;Z NOTATION LEFT IMAGE BRACKET;Ps;0;ON;;;;;Y;;;;;
+2988;Z NOTATION RIGHT IMAGE BRACKET;Pe;0;ON;;;;;Y;;;;;
+2989;Z NOTATION LEFT BINDING BRACKET;Ps;0;ON;;;;;Y;;;;;
+298A;Z NOTATION RIGHT BINDING BRACKET;Pe;0;ON;;;;;Y;;;;;
+298B;LEFT SQUARE BRACKET WITH UNDERBAR;Ps;0;ON;;;;;Y;;;;;
+298C;RIGHT SQUARE BRACKET WITH UNDERBAR;Pe;0;ON;;;;;Y;;;;;
+298D;LEFT SQUARE BRACKET WITH TICK IN TOP CORNER;Ps;0;ON;;;;;Y;;;;;
+298E;RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Pe;0;ON;;;;;Y;;;;;
+298F;LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER;Ps;0;ON;;;;;Y;;;;;
+2990;RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER;Pe;0;ON;;;;;Y;;;;;
+2991;LEFT ANGLE BRACKET WITH DOT;Ps;0;ON;;;;;Y;;;;;
+2992;RIGHT ANGLE BRACKET WITH DOT;Pe;0;ON;;;;;Y;;;;;
+2993;LEFT ARC LESS-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;
+2994;RIGHT ARC GREATER-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;
+2995;DOUBLE LEFT ARC GREATER-THAN BRACKET;Ps;0;ON;;;;;Y;;;;;
+2996;DOUBLE RIGHT ARC LESS-THAN BRACKET;Pe;0;ON;;;;;Y;;;;;
+2997;LEFT BLACK TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;;;;;
+2998;RIGHT BLACK TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;;;;;
+2999;DOTTED FENCE;Sm;0;ON;;;;;N;;;;;
+299A;VERTICAL ZIGZAG LINE;Sm;0;ON;;;;;N;;;;;
+299B;MEASURED ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
+299C;RIGHT ANGLE VARIANT WITH SQUARE;Sm;0;ON;;;;;Y;;;;;
+299D;MEASURED RIGHT ANGLE WITH DOT;Sm;0;ON;;;;;Y;;;;;
+299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;;
+299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
+29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;;
+29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+29A5;REVERSED ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+29A6;OBLIQUE ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A7;OBLIQUE ANGLE OPENING DOWN;Sm;0;ON;;;;;Y;;;;;
+29A8;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT;Sm;0;ON;;;;;Y;;;;;
+29A9;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT;Sm;0;ON;;;;;Y;;;;;
+29AA;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT;Sm;0;ON;;;;;Y;;;;;
+29AB;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT;Sm;0;ON;;;;;Y;;;;;
+29AC;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP;Sm;0;ON;;;;;Y;;;;;
+29AD;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP;Sm;0;ON;;;;;Y;;;;;
+29AE;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN;Sm;0;ON;;;;;Y;;;;;
+29AF;MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN;Sm;0;ON;;;;;Y;;;;;
+29B0;REVERSED EMPTY SET;Sm;0;ON;;;;;N;;;;;
+29B1;EMPTY SET WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+29B2;EMPTY SET WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+29B3;EMPTY SET WITH RIGHT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;
+29B4;EMPTY SET WITH LEFT ARROW ABOVE;Sm;0;ON;;;;;N;;;;;
+29B5;CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;;
+29B6;CIRCLED VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29B7;CIRCLED PARALLEL;Sm;0;ON;;;;;N;;;;;
+29B8;CIRCLED REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29B9;CIRCLED PERPENDICULAR;Sm;0;ON;;;;;N;;;;;
+29BA;CIRCLE DIVIDED BY HORIZONTAL BAR AND TOP HALF DIVIDED BY VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29BB;CIRCLE WITH SUPERIMPOSED X;Sm;0;ON;;;;;N;;;;;
+29BC;CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+29BD;UP ARROW THROUGH CIRCLE;Sm;0;ON;;;;;N;;;;;
+29BE;CIRCLED WHITE BULLET;Sm;0;ON;;;;;N;;;;;
+29BF;CIRCLED BULLET;Sm;0;ON;;;;;N;;;;;
+29C0;CIRCLED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+29C1;CIRCLED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+29C2;CIRCLE WITH SMALL CIRCLE TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;
+29C3;CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT;Sm;0;ON;;;;;Y;;;;;
+29C4;SQUARED RISING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;
+29C5;SQUARED FALLING DIAGONAL SLASH;Sm;0;ON;;;;;Y;;;;;
+29C6;SQUARED ASTERISK;Sm;0;ON;;;;;N;;;;;
+29C7;SQUARED SMALL CIRCLE;Sm;0;ON;;;;;N;;;;;
+29C8;SQUARED SQUARE;Sm;0;ON;;;;;N;;;;;
+29C9;TWO JOINED SQUARES;Sm;0;ON;;;;;Y;;;;;
+29CA;TRIANGLE WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+29CB;TRIANGLE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+29CC;S IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+29CD;TRIANGLE WITH SERIFS AT BOTTOM;Sm;0;ON;;;;;N;;;;;
+29CE;RIGHT TRIANGLE ABOVE LEFT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+29CF;LEFT TRIANGLE BESIDE VERTICAL BAR;Sm;0;ON;;;;;Y;;;;;
+29D0;VERTICAL BAR BESIDE RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+29D1;BOWTIE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D2;BOWTIE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D3;BLACK BOWTIE;Sm;0;ON;;;;;N;;;;;
+29D4;TIMES WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D5;TIMES WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29D6;WHITE HOURGLASS;Sm;0;ON;;;;;N;;;;;
+29D7;BLACK HOURGLASS;Sm;0;ON;;;;;N;;;;;
+29D8;LEFT WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;
+29D9;RIGHT WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;
+29DA;LEFT DOUBLE WIGGLY FENCE;Ps;0;ON;;;;;Y;;;;;
+29DB;RIGHT DOUBLE WIGGLY FENCE;Pe;0;ON;;;;;Y;;;;;
+29DC;INCOMPLETE INFINITY;Sm;0;ON;;;;;Y;;;;;
+29DD;TIE OVER INFINITY;Sm;0;ON;;;;;N;;;;;
+29DE;INFINITY NEGATED WITH VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+29DF;DOUBLE-ENDED MULTIMAP;Sm;0;ON;;;;;N;;;;;
+29E0;SQUARE WITH CONTOURED OUTLINE;Sm;0;ON;;;;;N;;;;;
+29E1;INCREASES AS;Sm;0;ON;;;;;Y;;;;;
+29E2;SHUFFLE PRODUCT;Sm;0;ON;;;;;N;;;;;
+29E3;EQUALS SIGN AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;
+29E4;EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;
+29E5;IDENTICAL TO AND SLANTED PARALLEL;Sm;0;ON;;;;;Y;;;;;
+29E6;GLEICH STARK;Sm;0;ON;;;;;N;;;;;
+29E7;THERMODYNAMIC;Sm;0;ON;;;;;N;;;;;
+29E8;DOWN-POINTING TRIANGLE WITH LEFT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29E9;DOWN-POINTING TRIANGLE WITH RIGHT HALF BLACK;Sm;0;ON;;;;;Y;;;;;
+29EA;BLACK DIAMOND WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29EB;BLACK LOZENGE;Sm;0;ON;;;;;N;;;;;
+29EC;WHITE CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29ED;BLACK CIRCLE WITH DOWN ARROW;Sm;0;ON;;;;;N;;;;;
+29EE;ERROR-BARRED WHITE SQUARE;Sm;0;ON;;;;;N;;;;;
+29EF;ERROR-BARRED BLACK SQUARE;Sm;0;ON;;;;;N;;;;;
+29F0;ERROR-BARRED WHITE DIAMOND;Sm;0;ON;;;;;N;;;;;
+29F1;ERROR-BARRED BLACK DIAMOND;Sm;0;ON;;;;;N;;;;;
+29F2;ERROR-BARRED WHITE CIRCLE;Sm;0;ON;;;;;N;;;;;
+29F3;ERROR-BARRED BLACK CIRCLE;Sm;0;ON;;;;;N;;;;;
+29F4;RULE-DELAYED;Sm;0;ON;;;;;Y;;;;;
+29F5;REVERSE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;
+29F6;SOLIDUS WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+29F7;REVERSE SOLIDUS WITH HORIZONTAL STROKE;Sm;0;ON;;;;;Y;;;;;
+29F8;BIG SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29F9;BIG REVERSE SOLIDUS;Sm;0;ON;;;;;Y;;;;;
+29FA;DOUBLE PLUS;Sm;0;ON;;;;;N;;;;;
+29FB;TRIPLE PLUS;Sm;0;ON;;;;;N;;;;;
+29FC;LEFT-POINTING CURVED ANGLE BRACKET;Ps;0;ON;;;;;Y;;;;;
+29FD;RIGHT-POINTING CURVED ANGLE BRACKET;Pe;0;ON;;;;;Y;;;;;
+29FE;TINY;Sm;0;ON;;;;;N;;;;;
+29FF;MINY;Sm;0;ON;;;;;N;;;;;
+2A00;N-ARY CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A01;N-ARY CIRCLED PLUS OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A02;N-ARY CIRCLED TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A03;N-ARY UNION OPERATOR WITH DOT;Sm;0;ON;;;;;N;;;;;
+2A04;N-ARY UNION OPERATOR WITH PLUS;Sm;0;ON;;;;;N;;;;;
+2A05;N-ARY SQUARE INTERSECTION OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A06;N-ARY SQUARE UNION OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A07;TWO LOGICAL AND OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A08;TWO LOGICAL OR OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A09;N-ARY TIMES OPERATOR;Sm;0;ON;;;;;N;;;;;
+2A0A;MODULO TWO SUM;Sm;0;ON;;;;;Y;;;;;
+2A0B;SUMMATION WITH INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2A0C;QUADRUPLE INTEGRAL OPERATOR;Sm;0;ON;<compat> 222B 222B 222B 222B;;;;Y;;;;;
+2A0D;FINITE PART INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2A0E;INTEGRAL WITH DOUBLE STROKE;Sm;0;ON;;;;;Y;;;;;
+2A0F;INTEGRAL AVERAGE WITH SLASH;Sm;0;ON;;;;;Y;;;;;
+2A10;CIRCULATION FUNCTION;Sm;0;ON;;;;;Y;;;;;
+2A11;ANTICLOCKWISE INTEGRATION;Sm;0;ON;;;;;Y;;;;;
+2A12;LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;
+2A13;LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE;Sm;0;ON;;;;;Y;;;;;
+2A14;LINE INTEGRATION NOT INCLUDING THE POLE;Sm;0;ON;;;;;Y;;;;;
+2A15;INTEGRAL AROUND A POINT OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A16;QUATERNION INTEGRAL OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A17;INTEGRAL WITH LEFTWARDS ARROW WITH HOOK;Sm;0;ON;;;;;Y;;;;;
+2A18;INTEGRAL WITH TIMES SIGN;Sm;0;ON;;;;;Y;;;;;
+2A19;INTEGRAL WITH INTERSECTION;Sm;0;ON;;;;;Y;;;;;
+2A1A;INTEGRAL WITH UNION;Sm;0;ON;;;;;Y;;;;;
+2A1B;INTEGRAL WITH OVERBAR;Sm;0;ON;;;;;Y;;;;;
+2A1C;INTEGRAL WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+2A1D;JOIN;Sm;0;ON;;;;;N;;;;;
+2A1E;LARGE LEFT TRIANGLE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A1F;Z NOTATION SCHEMA COMPOSITION;Sm;0;ON;;;;;Y;;;;;
+2A20;Z NOTATION SCHEMA PIPING;Sm;0;ON;;;;;Y;;;;;
+2A21;Z NOTATION SCHEMA PROJECTION;Sm;0;ON;;;;;Y;;;;;
+2A22;PLUS SIGN WITH SMALL CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+2A23;PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A24;PLUS SIGN WITH TILDE ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A25;PLUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A26;PLUS SIGN WITH TILDE BELOW;Sm;0;ON;;;;;Y;;;;;
+2A27;PLUS SIGN WITH SUBSCRIPT TWO;Sm;0;ON;;;;;N;;;;;
+2A28;PLUS SIGN WITH BLACK TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A29;MINUS SIGN WITH COMMA ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A2A;MINUS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A2B;MINUS SIGN WITH FALLING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A2C;MINUS SIGN WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A2D;PLUS SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A2E;PLUS SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A2F;VECTOR OR CROSS PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A30;MULTIPLICATION SIGN WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A31;MULTIPLICATION SIGN WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A32;SEMIDIRECT PRODUCT WITH BOTTOM CLOSED;Sm;0;ON;;;;;N;;;;;
+2A33;SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A34;MULTIPLICATION SIGN IN LEFT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A35;MULTIPLICATION SIGN IN RIGHT HALF CIRCLE;Sm;0;ON;;;;;Y;;;;;
+2A36;CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;N;;;;;
+2A37;MULTIPLICATION SIGN IN DOUBLE CIRCLE;Sm;0;ON;;;;;N;;;;;
+2A38;CIRCLED DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+2A39;PLUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3A;MINUS SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3B;MULTIPLICATION SIGN IN TRIANGLE;Sm;0;ON;;;;;N;;;;;
+2A3C;INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2A3D;RIGHTHAND INTERIOR PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2A3E;Z NOTATION RELATIONAL COMPOSITION;Sm;0;ON;;;;;Y;;;;;
+2A3F;AMALGAMATION OR COPRODUCT;Sm;0;ON;;;;;N;;;;;
+2A40;INTERSECTION WITH DOT;Sm;0;ON;;;;;N;;;;;
+2A41;UNION WITH MINUS SIGN;Sm;0;ON;;;;;N;;;;;
+2A42;UNION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A43;INTERSECTION WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A44;INTERSECTION WITH LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A45;UNION WITH LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A46;UNION ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A47;INTERSECTION ABOVE UNION;Sm;0;ON;;;;;N;;;;;
+2A48;UNION ABOVE BAR ABOVE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A49;INTERSECTION ABOVE BAR ABOVE UNION;Sm;0;ON;;;;;N;;;;;
+2A4A;UNION BESIDE AND JOINED WITH UNION;Sm;0;ON;;;;;N;;;;;
+2A4B;INTERSECTION BESIDE AND JOINED WITH INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A4C;CLOSED UNION WITH SERIFS;Sm;0;ON;;;;;N;;;;;
+2A4D;CLOSED INTERSECTION WITH SERIFS;Sm;0;ON;;;;;N;;;;;
+2A4E;DOUBLE SQUARE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2A4F;DOUBLE SQUARE UNION;Sm;0;ON;;;;;N;;;;;
+2A50;CLOSED UNION WITH SERIFS AND SMASH PRODUCT;Sm;0;ON;;;;;N;;;;;
+2A51;LOGICAL AND WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A52;LOGICAL OR WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A53;DOUBLE LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A54;DOUBLE LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A55;TWO INTERSECTING LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A56;TWO INTERSECTING LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2A57;SLOPING LARGE OR;Sm;0;ON;;;;;Y;;;;;
+2A58;SLOPING LARGE AND;Sm;0;ON;;;;;Y;;;;;
+2A59;LOGICAL OR OVERLAPPING LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2A5A;LOGICAL AND WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;
+2A5B;LOGICAL OR WITH MIDDLE STEM;Sm;0;ON;;;;;N;;;;;
+2A5C;LOGICAL AND WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;
+2A5D;LOGICAL OR WITH HORIZONTAL DASH;Sm;0;ON;;;;;N;;;;;
+2A5E;LOGICAL AND WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A5F;LOGICAL AND WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A60;LOGICAL AND WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A61;SMALL VEE WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A62;LOGICAL OR WITH DOUBLE OVERBAR;Sm;0;ON;;;;;N;;;;;
+2A63;LOGICAL OR WITH DOUBLE UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2A64;Z NOTATION DOMAIN ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;
+2A65;Z NOTATION RANGE ANTIRESTRICTION;Sm;0;ON;;;;;Y;;;;;
+2A66;EQUALS SIGN WITH DOT BELOW;Sm;0;ON;;;;;N;;;;;
+2A67;IDENTICAL WITH DOT ABOVE;Sm;0;ON;;;;;N;;;;;
+2A68;TRIPLE HORIZONTAL BAR WITH DOUBLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2A69;TRIPLE HORIZONTAL BAR WITH TRIPLE VERTICAL STROKE;Sm;0;ON;;;;;N;;;;;
+2A6A;TILDE OPERATOR WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A6B;TILDE OPERATOR WITH RISING DOTS;Sm;0;ON;;;;;Y;;;;;
+2A6C;SIMILAR MINUS SIMILAR;Sm;0;ON;;;;;Y;;;;;
+2A6D;CONGRUENT WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A6E;EQUALS WITH ASTERISK;Sm;0;ON;;;;;N;;;;;
+2A6F;ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT;Sm;0;ON;;;;;Y;;;;;
+2A70;APPROXIMATELY EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A71;EQUALS SIGN ABOVE PLUS SIGN;Sm;0;ON;;;;;N;;;;;
+2A72;PLUS SIGN ABOVE EQUALS SIGN;Sm;0;ON;;;;;N;;;;;
+2A73;EQUALS SIGN ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2A74;DOUBLE COLON EQUAL;Sm;0;ON;<compat> 003A 003A 003D;;;;Y;;;;;
+2A75;TWO CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D;;;;N;;;;;
+2A76;THREE CONSECUTIVE EQUALS SIGNS;Sm;0;ON;<compat> 003D 003D 003D;;;;N;;;;;
+2A77;EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW;Sm;0;ON;;;;;N;;;;;
+2A78;EQUIVALENT WITH FOUR DOTS ABOVE;Sm;0;ON;;;;;N;;;;;
+2A79;LESS-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A7A;GREATER-THAN WITH CIRCLE INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A7B;LESS-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A7C;GREATER-THAN WITH QUESTION MARK ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A7D;LESS-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A7E;GREATER-THAN OR SLANTED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A7F;LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A80;GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A81;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A82;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2A83;LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT;Sm;0;ON;;;;;Y;;;;;
+2A84;GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT;Sm;0;ON;;;;;Y;;;;;
+2A85;LESS-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A86;GREATER-THAN OR APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A87;LESS-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A88;GREATER-THAN AND SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2A89;LESS-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A8A;GREATER-THAN AND NOT APPROXIMATE;Sm;0;ON;;;;;Y;;;;;
+2A8B;LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A8C;GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A8D;LESS-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A8E;GREATER-THAN ABOVE SIMILAR OR EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A8F;LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A90;GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A91;LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A92;GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A93;LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A94;GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2A95;SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A96;SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A97;SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A98;SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE;Sm;0;ON;;;;;Y;;;;;
+2A99;DOUBLE-LINE EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9A;DOUBLE-LINE EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9B;DOUBLE-LINE SLANTED EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9C;DOUBLE-LINE SLANTED EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9D;SIMILAR OR LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9E;SIMILAR OR GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2A9F;SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AA0;SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AA1;DOUBLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2AA2;DOUBLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2AA3;DOUBLE NESTED LESS-THAN WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
+2AA4;GREATER-THAN OVERLAPPING LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2AA5;GREATER-THAN BESIDE LESS-THAN;Sm;0;ON;;;;;N;;;;;
+2AA6;LESS-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;
+2AA7;GREATER-THAN CLOSED BY CURVE;Sm;0;ON;;;;;Y;;;;;
+2AA8;LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2AA9;GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL;Sm;0;ON;;;;;Y;;;;;
+2AAA;SMALLER THAN;Sm;0;ON;;;;;Y;;;;;
+2AAB;LARGER THAN;Sm;0;ON;;;;;Y;;;;;
+2AAC;SMALLER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AAD;LARGER THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AAE;EQUALS SIGN WITH BUMPY ABOVE;Sm;0;ON;;;;;N;;;;;
+2AAF;PRECEDES ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB0;SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB1;PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB2;SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB3;PRECEDES ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB4;SUCCEEDS ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AB5;PRECEDES ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB6;SUCCEEDS ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB7;PRECEDES ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB8;SUCCEEDS ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AB9;PRECEDES ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ABA;SUCCEEDS ABOVE NOT ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ABB;DOUBLE PRECEDES;Sm;0;ON;;;;;Y;;;;;
+2ABC;DOUBLE SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+2ABD;SUBSET WITH DOT;Sm;0;ON;;;;;Y;;;;;
+2ABE;SUPERSET WITH DOT;Sm;0;ON;;;;;Y;;;;;
+2ABF;SUBSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC0;SUPERSET WITH PLUS SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC1;SUBSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC2;SUPERSET WITH MULTIPLICATION SIGN BELOW;Sm;0;ON;;;;;Y;;;;;
+2AC3;SUBSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2AC4;SUPERSET OF OR EQUAL TO WITH DOT ABOVE;Sm;0;ON;;;;;Y;;;;;
+2AC5;SUBSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AC6;SUPERSET OF ABOVE EQUALS SIGN;Sm;0;ON;;;;;Y;;;;;
+2AC7;SUBSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AC8;SUPERSET OF ABOVE TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AC9;SUBSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACA;SUPERSET OF ABOVE ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACB;SUBSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACC;SUPERSET OF ABOVE NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2ACD;SQUARE LEFT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2ACE;SQUARE RIGHT OPEN BOX OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2ACF;CLOSED SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD0;CLOSED SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD1;CLOSED SUBSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AD2;CLOSED SUPERSET OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AD3;SUBSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD4;SUPERSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD5;SUBSET ABOVE SUBSET;Sm;0;ON;;;;;Y;;;;;
+2AD6;SUPERSET ABOVE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+2AD7;SUPERSET BESIDE SUBSET;Sm;0;ON;;;;;N;;;;;
+2AD8;SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET;Sm;0;ON;;;;;N;;;;;
+2AD9;ELEMENT OF OPENING DOWNWARDS;Sm;0;ON;;;;;N;;;;;
+2ADA;PITCHFORK WITH TEE TOP;Sm;0;ON;;;;;N;;;;;
+2ADB;TRANSVERSAL INTERSECTION;Sm;0;ON;;;;;N;;;;;
+2ADC;FORKING;Sm;0;ON;2ADD 0338;;;;Y;;not independent;;;
+2ADD;NONFORKING;Sm;0;ON;;;;;N;;independent;;;
+2ADE;SHORT LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+2ADF;SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AE0;SHORT UP TACK;Sm;0;ON;;;;;N;;;;;
+2AE1;PERPENDICULAR WITH S;Sm;0;ON;;;;;N;;;;;
+2AE2;VERTICAL BAR TRIPLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE3;DOUBLE VERTICAL BAR LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE4;VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE5;DOUBLE VERTICAL BAR DOUBLE LEFT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+2AE6;LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL;Sm;0;ON;;;;;Y;;;;;
+2AE7;SHORT DOWN TACK WITH OVERBAR;Sm;0;ON;;;;;N;;;;;
+2AE8;SHORT UP TACK WITH UNDERBAR;Sm;0;ON;;;;;N;;;;;
+2AE9;SHORT UP TACK ABOVE SHORT DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AEA;DOUBLE DOWN TACK;Sm;0;ON;;;;;N;;;;;
+2AEB;DOUBLE UP TACK;Sm;0;ON;;;;;N;;;;;
+2AEC;DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;
+2AED;REVERSED DOUBLE STROKE NOT SIGN;Sm;0;ON;;;;;Y;;;;;
+2AEE;DOES NOT DIVIDE WITH REVERSED NEGATION SLASH;Sm;0;ON;;;;;Y;;;;;
+2AEF;VERTICAL LINE WITH CIRCLE ABOVE;Sm;0;ON;;;;;N;;;;;
+2AF0;VERTICAL LINE WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;
+2AF1;DOWN TACK WITH CIRCLE BELOW;Sm;0;ON;;;;;N;;;;;
+2AF2;PARALLEL WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2AF3;PARALLEL WITH TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AF4;TRIPLE VERTICAL BAR BINARY RELATION;Sm;0;ON;;;;;N;;;;;
+2AF5;TRIPLE VERTICAL BAR WITH HORIZONTAL STROKE;Sm;0;ON;;;;;N;;;;;
+2AF6;TRIPLE COLON OPERATOR;Sm;0;ON;;;;;N;;;;;
+2AF7;TRIPLE NESTED LESS-THAN;Sm;0;ON;;;;;Y;;;;;
+2AF8;TRIPLE NESTED GREATER-THAN;Sm;0;ON;;;;;Y;;;;;
+2AF9;DOUBLE-LINE SLANTED LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AFA;DOUBLE-LINE SLANTED GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2AFB;TRIPLE SOLIDUS BINARY RELATION;Sm;0;ON;;;;;Y;;;;;
+2AFC;LARGE TRIPLE VERTICAL BAR OPERATOR;Sm;0;ON;;;;;N;;;;;
+2AFD;DOUBLE SOLIDUS OPERATOR;Sm;0;ON;;;;;Y;;;;;
+2AFE;WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+2AFF;N-ARY WHITE VERTICAL BAR;Sm;0;ON;;;;;N;;;;;
+2B00;NORTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B01;NORTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B02;SOUTH EAST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B03;SOUTH WEST WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B04;LEFT RIGHT WHITE ARROW;So;0;ON;;;;;N;;;;;
+2B05;LEFTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B06;UPWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B07;DOWNWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B08;NORTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B09;NORTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0A;SOUTH EAST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0B;SOUTH WEST BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0C;LEFT RIGHT BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0D;UP DOWN BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B0E;RIGHTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2B0F;RIGHTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2B10;LEFTWARDS ARROW WITH TIP DOWNWARDS;So;0;ON;;;;;N;;;;;
+2B11;LEFTWARDS ARROW WITH TIP UPWARDS;So;0;ON;;;;;N;;;;;
+2B12;SQUARE WITH TOP HALF BLACK;So;0;ON;;;;;N;;;;;
+2B13;SQUARE WITH BOTTOM HALF BLACK;So;0;ON;;;;;N;;;;;
+2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30;
+2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31;
+2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32;
+2C03;GLAGOLITIC CAPITAL LETTER GLAGOLI;Lu;0;L;;;;;N;;;;2C33;
+2C04;GLAGOLITIC CAPITAL LETTER DOBRO;Lu;0;L;;;;;N;;;;2C34;
+2C05;GLAGOLITIC CAPITAL LETTER YESTU;Lu;0;L;;;;;N;;;;2C35;
+2C06;GLAGOLITIC CAPITAL LETTER ZHIVETE;Lu;0;L;;;;;N;;;;2C36;
+2C07;GLAGOLITIC CAPITAL LETTER DZELO;Lu;0;L;;;;;N;;;;2C37;
+2C08;GLAGOLITIC CAPITAL LETTER ZEMLJA;Lu;0;L;;;;;N;;;;2C38;
+2C09;GLAGOLITIC CAPITAL LETTER IZHE;Lu;0;L;;;;;N;;;;2C39;
+2C0A;GLAGOLITIC CAPITAL LETTER INITIAL IZHE;Lu;0;L;;;;;N;;;;2C3A;
+2C0B;GLAGOLITIC CAPITAL LETTER I;Lu;0;L;;;;;N;;;;2C3B;
+2C0C;GLAGOLITIC CAPITAL LETTER DJERVI;Lu;0;L;;;;;N;;;;2C3C;
+2C0D;GLAGOLITIC CAPITAL LETTER KAKO;Lu;0;L;;;;;N;;;;2C3D;
+2C0E;GLAGOLITIC CAPITAL LETTER LJUDIJE;Lu;0;L;;;;;N;;;;2C3E;
+2C0F;GLAGOLITIC CAPITAL LETTER MYSLITE;Lu;0;L;;;;;N;;;;2C3F;
+2C10;GLAGOLITIC CAPITAL LETTER NASHI;Lu;0;L;;;;;N;;;;2C40;
+2C11;GLAGOLITIC CAPITAL LETTER ONU;Lu;0;L;;;;;N;;;;2C41;
+2C12;GLAGOLITIC CAPITAL LETTER POKOJI;Lu;0;L;;;;;N;;;;2C42;
+2C13;GLAGOLITIC CAPITAL LETTER RITSI;Lu;0;L;;;;;N;;;;2C43;
+2C14;GLAGOLITIC CAPITAL LETTER SLOVO;Lu;0;L;;;;;N;;;;2C44;
+2C15;GLAGOLITIC CAPITAL LETTER TVRIDO;Lu;0;L;;;;;N;;;;2C45;
+2C16;GLAGOLITIC CAPITAL LETTER UKU;Lu;0;L;;;;;N;;;;2C46;
+2C17;GLAGOLITIC CAPITAL LETTER FRITU;Lu;0;L;;;;;N;;;;2C47;
+2C18;GLAGOLITIC CAPITAL LETTER HERU;Lu;0;L;;;;;N;;;;2C48;
+2C19;GLAGOLITIC CAPITAL LETTER OTU;Lu;0;L;;;;;N;;;;2C49;
+2C1A;GLAGOLITIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;2C4A;
+2C1B;GLAGOLITIC CAPITAL LETTER SHTA;Lu;0;L;;;;;N;;;;2C4B;
+2C1C;GLAGOLITIC CAPITAL LETTER TSI;Lu;0;L;;;;;N;;;;2C4C;
+2C1D;GLAGOLITIC CAPITAL LETTER CHRIVI;Lu;0;L;;;;;N;;;;2C4D;
+2C1E;GLAGOLITIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;2C4E;
+2C1F;GLAGOLITIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;;;;2C4F;
+2C20;GLAGOLITIC CAPITAL LETTER YERI;Lu;0;L;;;;;N;;;;2C50;
+2C21;GLAGOLITIC CAPITAL LETTER YATI;Lu;0;L;;;;;N;;;;2C51;
+2C22;GLAGOLITIC CAPITAL LETTER SPIDERY HA;Lu;0;L;;;;;N;;;;2C52;
+2C23;GLAGOLITIC CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;2C53;
+2C24;GLAGOLITIC CAPITAL LETTER SMALL YUS;Lu;0;L;;;;;N;;;;2C54;
+2C25;GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL;Lu;0;L;;;;;N;;;;2C55;
+2C26;GLAGOLITIC CAPITAL LETTER YO;Lu;0;L;;;;;N;;;;2C56;
+2C27;GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS;Lu;0;L;;;;;N;;;;2C57;
+2C28;GLAGOLITIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;2C58;
+2C29;GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS;Lu;0;L;;;;;N;;;;2C59;
+2C2A;GLAGOLITIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;2C5A;
+2C2B;GLAGOLITIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;2C5B;
+2C2C;GLAGOLITIC CAPITAL LETTER SHTAPIC;Lu;0;L;;;;;N;;;;2C5C;
+2C2D;GLAGOLITIC CAPITAL LETTER TROKUTASTI A;Lu;0;L;;;;;N;;;;2C5D;
+2C2E;GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE;Lu;0;L;;;;;N;;;;2C5E;
+2C30;GLAGOLITIC SMALL LETTER AZU;Ll;0;L;;;;;N;;;2C00;;2C00
+2C31;GLAGOLITIC SMALL LETTER BUKY;Ll;0;L;;;;;N;;;2C01;;2C01
+2C32;GLAGOLITIC SMALL LETTER VEDE;Ll;0;L;;;;;N;;;2C02;;2C02
+2C33;GLAGOLITIC SMALL LETTER GLAGOLI;Ll;0;L;;;;;N;;;2C03;;2C03
+2C34;GLAGOLITIC SMALL LETTER DOBRO;Ll;0;L;;;;;N;;;2C04;;2C04
+2C35;GLAGOLITIC SMALL LETTER YESTU;Ll;0;L;;;;;N;;;2C05;;2C05
+2C36;GLAGOLITIC SMALL LETTER ZHIVETE;Ll;0;L;;;;;N;;;2C06;;2C06
+2C37;GLAGOLITIC SMALL LETTER DZELO;Ll;0;L;;;;;N;;;2C07;;2C07
+2C38;GLAGOLITIC SMALL LETTER ZEMLJA;Ll;0;L;;;;;N;;;2C08;;2C08
+2C39;GLAGOLITIC SMALL LETTER IZHE;Ll;0;L;;;;;N;;;2C09;;2C09
+2C3A;GLAGOLITIC SMALL LETTER INITIAL IZHE;Ll;0;L;;;;;N;;;2C0A;;2C0A
+2C3B;GLAGOLITIC SMALL LETTER I;Ll;0;L;;;;;N;;;2C0B;;2C0B
+2C3C;GLAGOLITIC SMALL LETTER DJERVI;Ll;0;L;;;;;N;;;2C0C;;2C0C
+2C3D;GLAGOLITIC SMALL LETTER KAKO;Ll;0;L;;;;;N;;;2C0D;;2C0D
+2C3E;GLAGOLITIC SMALL LETTER LJUDIJE;Ll;0;L;;;;;N;;;2C0E;;2C0E
+2C3F;GLAGOLITIC SMALL LETTER MYSLITE;Ll;0;L;;;;;N;;;2C0F;;2C0F
+2C40;GLAGOLITIC SMALL LETTER NASHI;Ll;0;L;;;;;N;;;2C10;;2C10
+2C41;GLAGOLITIC SMALL LETTER ONU;Ll;0;L;;;;;N;;;2C11;;2C11
+2C42;GLAGOLITIC SMALL LETTER POKOJI;Ll;0;L;;;;;N;;;2C12;;2C12
+2C43;GLAGOLITIC SMALL LETTER RITSI;Ll;0;L;;;;;N;;;2C13;;2C13
+2C44;GLAGOLITIC SMALL LETTER SLOVO;Ll;0;L;;;;;N;;;2C14;;2C14
+2C45;GLAGOLITIC SMALL LETTER TVRIDO;Ll;0;L;;;;;N;;;2C15;;2C15
+2C46;GLAGOLITIC SMALL LETTER UKU;Ll;0;L;;;;;N;;;2C16;;2C16
+2C47;GLAGOLITIC SMALL LETTER FRITU;Ll;0;L;;;;;N;;;2C17;;2C17
+2C48;GLAGOLITIC SMALL LETTER HERU;Ll;0;L;;;;;N;;;2C18;;2C18
+2C49;GLAGOLITIC SMALL LETTER OTU;Ll;0;L;;;;;N;;;2C19;;2C19
+2C4A;GLAGOLITIC SMALL LETTER PE;Ll;0;L;;;;;N;;;2C1A;;2C1A
+2C4B;GLAGOLITIC SMALL LETTER SHTA;Ll;0;L;;;;;N;;;2C1B;;2C1B
+2C4C;GLAGOLITIC SMALL LETTER TSI;Ll;0;L;;;;;N;;;2C1C;;2C1C
+2C4D;GLAGOLITIC SMALL LETTER CHRIVI;Ll;0;L;;;;;N;;;2C1D;;2C1D
+2C4E;GLAGOLITIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;2C1E;;2C1E
+2C4F;GLAGOLITIC SMALL LETTER YERU;Ll;0;L;;;;;N;;;2C1F;;2C1F
+2C50;GLAGOLITIC SMALL LETTER YERI;Ll;0;L;;;;;N;;;2C20;;2C20
+2C51;GLAGOLITIC SMALL LETTER YATI;Ll;0;L;;;;;N;;;2C21;;2C21
+2C52;GLAGOLITIC SMALL LETTER SPIDERY HA;Ll;0;L;;;;;N;;;2C22;;2C22
+2C53;GLAGOLITIC SMALL LETTER YU;Ll;0;L;;;;;N;;;2C23;;2C23
+2C54;GLAGOLITIC SMALL LETTER SMALL YUS;Ll;0;L;;;;;N;;;2C24;;2C24
+2C55;GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL;Ll;0;L;;;;;N;;;2C25;;2C25
+2C56;GLAGOLITIC SMALL LETTER YO;Ll;0;L;;;;;N;;;2C26;;2C26
+2C57;GLAGOLITIC SMALL LETTER IOTATED SMALL YUS;Ll;0;L;;;;;N;;;2C27;;2C27
+2C58;GLAGOLITIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;2C28;;2C28
+2C59;GLAGOLITIC SMALL LETTER IOTATED BIG YUS;Ll;0;L;;;;;N;;;2C29;;2C29
+2C5A;GLAGOLITIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;2C2A;;2C2A
+2C5B;GLAGOLITIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;2C2B;;2C2B
+2C5C;GLAGOLITIC SMALL LETTER SHTAPIC;Ll;0;L;;;;;N;;;2C2C;;2C2C
+2C5D;GLAGOLITIC SMALL LETTER TROKUTASTI A;Ll;0;L;;;;;N;;;2C2D;;2C2D
+2C5E;GLAGOLITIC SMALL LETTER LATINATE MYSLITE;Ll;0;L;;;;;N;;;2C2E;;2C2E
+2C80;COPTIC CAPITAL LETTER ALFA;Lu;0;L;;;;;N;;;;2C81;
+2C81;COPTIC SMALL LETTER ALFA;Ll;0;L;;;;;N;;;2C80;;2C80
+2C82;COPTIC CAPITAL LETTER VIDA;Lu;0;L;;;;;N;;;;2C83;
+2C83;COPTIC SMALL LETTER VIDA;Ll;0;L;;;;;N;;;2C82;;2C82
+2C84;COPTIC CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;2C85;
+2C85;COPTIC SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;2C84;;2C84
+2C86;COPTIC CAPITAL LETTER DALDA;Lu;0;L;;;;;N;;;;2C87;
+2C87;COPTIC SMALL LETTER DALDA;Ll;0;L;;;;;N;;;2C86;;2C86
+2C88;COPTIC CAPITAL LETTER EIE;Lu;0;L;;;;;N;;;;2C89;
+2C89;COPTIC SMALL LETTER EIE;Ll;0;L;;;;;N;;;2C88;;2C88
+2C8A;COPTIC CAPITAL LETTER SOU;Lu;0;L;;;;;N;;;;2C8B;
+2C8B;COPTIC SMALL LETTER SOU;Ll;0;L;;;;;N;;;2C8A;;2C8A
+2C8C;COPTIC CAPITAL LETTER ZATA;Lu;0;L;;;;;N;;;;2C8D;
+2C8D;COPTIC SMALL LETTER ZATA;Ll;0;L;;;;;N;;;2C8C;;2C8C
+2C8E;COPTIC CAPITAL LETTER HATE;Lu;0;L;;;;;N;;;;2C8F;
+2C8F;COPTIC SMALL LETTER HATE;Ll;0;L;;;;;N;;;2C8E;;2C8E
+2C90;COPTIC CAPITAL LETTER THETHE;Lu;0;L;;;;;N;;;;2C91;
+2C91;COPTIC SMALL LETTER THETHE;Ll;0;L;;;;;N;;;2C90;;2C90
+2C92;COPTIC CAPITAL LETTER IAUDA;Lu;0;L;;;;;N;;;;2C93;
+2C93;COPTIC SMALL LETTER IAUDA;Ll;0;L;;;;;N;;;2C92;;2C92
+2C94;COPTIC CAPITAL LETTER KAPA;Lu;0;L;;;;;N;;;;2C95;
+2C95;COPTIC SMALL LETTER KAPA;Ll;0;L;;;;;N;;;2C94;;2C94
+2C96;COPTIC CAPITAL LETTER LAULA;Lu;0;L;;;;;N;;;;2C97;
+2C97;COPTIC SMALL LETTER LAULA;Ll;0;L;;;;;N;;;2C96;;2C96
+2C98;COPTIC CAPITAL LETTER MI;Lu;0;L;;;;;N;;;;2C99;
+2C99;COPTIC SMALL LETTER MI;Ll;0;L;;;;;N;;;2C98;;2C98
+2C9A;COPTIC CAPITAL LETTER NI;Lu;0;L;;;;;N;;;;2C9B;
+2C9B;COPTIC SMALL LETTER NI;Ll;0;L;;;;;N;;;2C9A;;2C9A
+2C9C;COPTIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;2C9D;
+2C9D;COPTIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;2C9C;;2C9C
+2C9E;COPTIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;2C9F;
+2C9F;COPTIC SMALL LETTER O;Ll;0;L;;;;;N;;;2C9E;;2C9E
+2CA0;COPTIC CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;2CA1;
+2CA1;COPTIC SMALL LETTER PI;Ll;0;L;;;;;N;;;2CA0;;2CA0
+2CA2;COPTIC CAPITAL LETTER RO;Lu;0;L;;;;;N;;;;2CA3;
+2CA3;COPTIC SMALL LETTER RO;Ll;0;L;;;;;N;;;2CA2;;2CA2
+2CA4;COPTIC CAPITAL LETTER SIMA;Lu;0;L;;;;;N;;;;2CA5;
+2CA5;COPTIC SMALL LETTER SIMA;Ll;0;L;;;;;N;;;2CA4;;2CA4
+2CA6;COPTIC CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;2CA7;
+2CA7;COPTIC SMALL LETTER TAU;Ll;0;L;;;;;N;;;2CA6;;2CA6
+2CA8;COPTIC CAPITAL LETTER UA;Lu;0;L;;;;;N;;;;2CA9;
+2CA9;COPTIC SMALL LETTER UA;Ll;0;L;;;;;N;;;2CA8;;2CA8
+2CAA;COPTIC CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;2CAB;
+2CAB;COPTIC SMALL LETTER FI;Ll;0;L;;;;;N;;;2CAA;;2CAA
+2CAC;COPTIC CAPITAL LETTER KHI;Lu;0;L;;;;;N;;;;2CAD;
+2CAD;COPTIC SMALL LETTER KHI;Ll;0;L;;;;;N;;;2CAC;;2CAC
+2CAE;COPTIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;2CAF;
+2CAF;COPTIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;2CAE;;2CAE
+2CB0;COPTIC CAPITAL LETTER OOU;Lu;0;L;;;;;N;;;;2CB1;
+2CB1;COPTIC SMALL LETTER OOU;Ll;0;L;;;;;N;;;2CB0;;2CB0
+2CB2;COPTIC CAPITAL LETTER DIALECT-P ALEF;Lu;0;L;;;;;N;;;;2CB3;
+2CB3;COPTIC SMALL LETTER DIALECT-P ALEF;Ll;0;L;;;;;N;;;2CB2;;2CB2
+2CB4;COPTIC CAPITAL LETTER OLD COPTIC AIN;Lu;0;L;;;;;N;;;;2CB5;
+2CB5;COPTIC SMALL LETTER OLD COPTIC AIN;Ll;0;L;;;;;N;;;2CB4;;2CB4
+2CB6;COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE;Lu;0;L;;;;;N;;;;2CB7;
+2CB7;COPTIC SMALL LETTER CRYPTOGRAMMIC EIE;Ll;0;L;;;;;N;;;2CB6;;2CB6
+2CB8;COPTIC CAPITAL LETTER DIALECT-P KAPA;Lu;0;L;;;;;N;;;;2CB9;
+2CB9;COPTIC SMALL LETTER DIALECT-P KAPA;Ll;0;L;;;;;N;;;2CB8;;2CB8
+2CBA;COPTIC CAPITAL LETTER DIALECT-P NI;Lu;0;L;;;;;N;;;;2CBB;
+2CBB;COPTIC SMALL LETTER DIALECT-P NI;Ll;0;L;;;;;N;;;2CBA;;2CBA
+2CBC;COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI;Lu;0;L;;;;;N;;;;2CBD;
+2CBD;COPTIC SMALL LETTER CRYPTOGRAMMIC NI;Ll;0;L;;;;;N;;;2CBC;;2CBC
+2CBE;COPTIC CAPITAL LETTER OLD COPTIC OOU;Lu;0;L;;;;;N;;;;2CBF;
+2CBF;COPTIC SMALL LETTER OLD COPTIC OOU;Ll;0;L;;;;;N;;;2CBE;;2CBE
+2CC0;COPTIC CAPITAL LETTER SAMPI;Lu;0;L;;;;;N;;;;2CC1;
+2CC1;COPTIC SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;2CC0;;2CC0
+2CC2;COPTIC CAPITAL LETTER CROSSED SHEI;Lu;0;L;;;;;N;;;;2CC3;
+2CC3;COPTIC SMALL LETTER CROSSED SHEI;Ll;0;L;;;;;N;;;2CC2;;2CC2
+2CC4;COPTIC CAPITAL LETTER OLD COPTIC SHEI;Lu;0;L;;;;;N;;;;2CC5;
+2CC5;COPTIC SMALL LETTER OLD COPTIC SHEI;Ll;0;L;;;;;N;;;2CC4;;2CC4
+2CC6;COPTIC CAPITAL LETTER OLD COPTIC ESH;Lu;0;L;;;;;N;;;;2CC7;
+2CC7;COPTIC SMALL LETTER OLD COPTIC ESH;Ll;0;L;;;;;N;;;2CC6;;2CC6
+2CC8;COPTIC CAPITAL LETTER AKHMIMIC KHEI;Lu;0;L;;;;;N;;;;2CC9;
+2CC9;COPTIC SMALL LETTER AKHMIMIC KHEI;Ll;0;L;;;;;N;;;2CC8;;2CC8
+2CCA;COPTIC CAPITAL LETTER DIALECT-P HORI;Lu;0;L;;;;;N;;;;2CCB;
+2CCB;COPTIC SMALL LETTER DIALECT-P HORI;Ll;0;L;;;;;N;;;2CCA;;2CCA
+2CCC;COPTIC CAPITAL LETTER OLD COPTIC HORI;Lu;0;L;;;;;N;;;;2CCD;
+2CCD;COPTIC SMALL LETTER OLD COPTIC HORI;Ll;0;L;;;;;N;;;2CCC;;2CCC
+2CCE;COPTIC CAPITAL LETTER OLD COPTIC HA;Lu;0;L;;;;;N;;;;2CCF;
+2CCF;COPTIC SMALL LETTER OLD COPTIC HA;Ll;0;L;;;;;N;;;2CCE;;2CCE
+2CD0;COPTIC CAPITAL LETTER L-SHAPED HA;Lu;0;L;;;;;N;;;;2CD1;
+2CD1;COPTIC SMALL LETTER L-SHAPED HA;Ll;0;L;;;;;N;;;2CD0;;2CD0
+2CD2;COPTIC CAPITAL LETTER OLD COPTIC HEI;Lu;0;L;;;;;N;;;;2CD3;
+2CD3;COPTIC SMALL LETTER OLD COPTIC HEI;Ll;0;L;;;;;N;;;2CD2;;2CD2
+2CD4;COPTIC CAPITAL LETTER OLD COPTIC HAT;Lu;0;L;;;;;N;;;;2CD5;
+2CD5;COPTIC SMALL LETTER OLD COPTIC HAT;Ll;0;L;;;;;N;;;2CD4;;2CD4
+2CD6;COPTIC CAPITAL LETTER OLD COPTIC GANGIA;Lu;0;L;;;;;N;;;;2CD7;
+2CD7;COPTIC SMALL LETTER OLD COPTIC GANGIA;Ll;0;L;;;;;N;;;2CD6;;2CD6
+2CD8;COPTIC CAPITAL LETTER OLD COPTIC DJA;Lu;0;L;;;;;N;;;;2CD9;
+2CD9;COPTIC SMALL LETTER OLD COPTIC DJA;Ll;0;L;;;;;N;;;2CD8;;2CD8
+2CDA;COPTIC CAPITAL LETTER OLD COPTIC SHIMA;Lu;0;L;;;;;N;;;;2CDB;
+2CDB;COPTIC SMALL LETTER OLD COPTIC SHIMA;Ll;0;L;;;;;N;;;2CDA;;2CDA
+2CDC;COPTIC CAPITAL LETTER OLD NUBIAN SHIMA;Lu;0;L;;;;;N;;;;2CDD;
+2CDD;COPTIC SMALL LETTER OLD NUBIAN SHIMA;Ll;0;L;;;;;N;;;2CDC;;2CDC
+2CDE;COPTIC CAPITAL LETTER OLD NUBIAN NGI;Lu;0;L;;;;;N;;;;2CDF;
+2CDF;COPTIC SMALL LETTER OLD NUBIAN NGI;Ll;0;L;;;;;N;;;2CDE;;2CDE
+2CE0;COPTIC CAPITAL LETTER OLD NUBIAN NYI;Lu;0;L;;;;;N;;;;2CE1;
+2CE1;COPTIC SMALL LETTER OLD NUBIAN NYI;Ll;0;L;;;;;N;;;2CE0;;2CE0
+2CE2;COPTIC CAPITAL LETTER OLD NUBIAN WAU;Lu;0;L;;;;;N;;;;2CE3;
+2CE3;COPTIC SMALL LETTER OLD NUBIAN WAU;Ll;0;L;;;;;N;;;2CE2;;2CE2
+2CE4;COPTIC SYMBOL KAI;Ll;0;L;;;;;N;;;;;
+2CE5;COPTIC SYMBOL MI RO;So;0;ON;;;;;N;;;;;
+2CE6;COPTIC SYMBOL PI RO;So;0;ON;;;;;N;;;;;
+2CE7;COPTIC SYMBOL STAUROS;So;0;ON;;;;;N;;;;;
+2CE8;COPTIC SYMBOL TAU RO;So;0;ON;;;;;N;;;;;
+2CE9;COPTIC SYMBOL KHI RO;So;0;ON;;;;;N;;;;;
+2CEA;COPTIC SYMBOL SHIMA SIMA;So;0;ON;;;;;N;;;;;
+2CF9;COPTIC OLD NUBIAN FULL STOP;Po;0;ON;;;;;N;;;;;
+2CFA;COPTIC OLD NUBIAN DIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;
+2CFB;COPTIC OLD NUBIAN INDIRECT QUESTION MARK;Po;0;ON;;;;;N;;;;;
+2CFC;COPTIC OLD NUBIAN VERSE DIVIDER;Po;0;ON;;;;;N;;;;;
+2CFD;COPTIC FRACTION ONE HALF;No;0;ON;;;;1/2;N;;;;;
+2CFE;COPTIC FULL STOP;Po;0;ON;;;;;N;;;;;
+2CFF;COPTIC MORPHOLOGICAL DIVIDER;Po;0;ON;;;;;N;;;;;
+2D00;GEORGIAN SMALL LETTER AN;Ll;0;L;;;;;N;;Khutsuri;10A0;;10A0
+2D01;GEORGIAN SMALL LETTER BAN;Ll;0;L;;;;;N;;Khutsuri;10A1;;10A1
+2D02;GEORGIAN SMALL LETTER GAN;Ll;0;L;;;;;N;;Khutsuri;10A2;;10A2
+2D03;GEORGIAN SMALL LETTER DON;Ll;0;L;;;;;N;;Khutsuri;10A3;;10A3
+2D04;GEORGIAN SMALL LETTER EN;Ll;0;L;;;;;N;;Khutsuri;10A4;;10A4
+2D05;GEORGIAN SMALL LETTER VIN;Ll;0;L;;;;;N;;Khutsuri;10A5;;10A5
+2D06;GEORGIAN SMALL LETTER ZEN;Ll;0;L;;;;;N;;Khutsuri;10A6;;10A6
+2D07;GEORGIAN SMALL LETTER TAN;Ll;0;L;;;;;N;;Khutsuri;10A7;;10A7
+2D08;GEORGIAN SMALL LETTER IN;Ll;0;L;;;;;N;;Khutsuri;10A8;;10A8
+2D09;GEORGIAN SMALL LETTER KAN;Ll;0;L;;;;;N;;Khutsuri;10A9;;10A9
+2D0A;GEORGIAN SMALL LETTER LAS;Ll;0;L;;;;;N;;Khutsuri;10AA;;10AA
+2D0B;GEORGIAN SMALL LETTER MAN;Ll;0;L;;;;;N;;Khutsuri;10AB;;10AB
+2D0C;GEORGIAN SMALL LETTER NAR;Ll;0;L;;;;;N;;Khutsuri;10AC;;10AC
+2D0D;GEORGIAN SMALL LETTER ON;Ll;0;L;;;;;N;;Khutsuri;10AD;;10AD
+2D0E;GEORGIAN SMALL LETTER PAR;Ll;0;L;;;;;N;;Khutsuri;10AE;;10AE
+2D0F;GEORGIAN SMALL LETTER ZHAR;Ll;0;L;;;;;N;;Khutsuri;10AF;;10AF
+2D10;GEORGIAN SMALL LETTER RAE;Ll;0;L;;;;;N;;Khutsuri;10B0;;10B0
+2D11;GEORGIAN SMALL LETTER SAN;Ll;0;L;;;;;N;;Khutsuri;10B1;;10B1
+2D12;GEORGIAN SMALL LETTER TAR;Ll;0;L;;;;;N;;Khutsuri;10B2;;10B2
+2D13;GEORGIAN SMALL LETTER UN;Ll;0;L;;;;;N;;Khutsuri;10B3;;10B3
+2D14;GEORGIAN SMALL LETTER PHAR;Ll;0;L;;;;;N;;Khutsuri;10B4;;10B4
+2D15;GEORGIAN SMALL LETTER KHAR;Ll;0;L;;;;;N;;Khutsuri;10B5;;10B5
+2D16;GEORGIAN SMALL LETTER GHAN;Ll;0;L;;;;;N;;Khutsuri;10B6;;10B6
+2D17;GEORGIAN SMALL LETTER QAR;Ll;0;L;;;;;N;;Khutsuri;10B7;;10B7
+2D18;GEORGIAN SMALL LETTER SHIN;Ll;0;L;;;;;N;;Khutsuri;10B8;;10B8
+2D19;GEORGIAN SMALL LETTER CHIN;Ll;0;L;;;;;N;;Khutsuri;10B9;;10B9
+2D1A;GEORGIAN SMALL LETTER CAN;Ll;0;L;;;;;N;;Khutsuri;10BA;;10BA
+2D1B;GEORGIAN SMALL LETTER JIL;Ll;0;L;;;;;N;;Khutsuri;10BB;;10BB
+2D1C;GEORGIAN SMALL LETTER CIL;Ll;0;L;;;;;N;;Khutsuri;10BC;;10BC
+2D1D;GEORGIAN SMALL LETTER CHAR;Ll;0;L;;;;;N;;Khutsuri;10BD;;10BD
+2D1E;GEORGIAN SMALL LETTER XAN;Ll;0;L;;;;;N;;Khutsuri;10BE;;10BE
+2D1F;GEORGIAN SMALL LETTER JHAN;Ll;0;L;;;;;N;;Khutsuri;10BF;;10BF
+2D20;GEORGIAN SMALL LETTER HAE;Ll;0;L;;;;;N;;Khutsuri;10C0;;10C0
+2D21;GEORGIAN SMALL LETTER HE;Ll;0;L;;;;;N;;Khutsuri;10C1;;10C1
+2D22;GEORGIAN SMALL LETTER HIE;Ll;0;L;;;;;N;;Khutsuri;10C2;;10C2
+2D23;GEORGIAN SMALL LETTER WE;Ll;0;L;;;;;N;;Khutsuri;10C3;;10C3
+2D24;GEORGIAN SMALL LETTER HAR;Ll;0;L;;;;;N;;Khutsuri;10C4;;10C4
+2D25;GEORGIAN SMALL LETTER HOE;Ll;0;L;;;;;N;;Khutsuri;10C5;;10C5
+2D30;TIFINAGH LETTER YA;Lo;0;L;;;;;N;;;;;
+2D31;TIFINAGH LETTER YAB;Lo;0;L;;;;;N;;;;;
+2D32;TIFINAGH LETTER YABH;Lo;0;L;;;;;N;;;;;
+2D33;TIFINAGH LETTER YAG;Lo;0;L;;;;;N;;;;;
+2D34;TIFINAGH LETTER YAGHH;Lo;0;L;;;;;N;;;;;
+2D35;TIFINAGH LETTER BERBER ACADEMY YAJ;Lo;0;L;;;;;N;;;;;
+2D36;TIFINAGH LETTER YAJ;Lo;0;L;;;;;N;;;;;
+2D37;TIFINAGH LETTER YAD;Lo;0;L;;;;;N;;;;;
+2D38;TIFINAGH LETTER YADH;Lo;0;L;;;;;N;;;;;
+2D39;TIFINAGH LETTER YADD;Lo;0;L;;;;;N;;;;;
+2D3A;TIFINAGH LETTER YADDH;Lo;0;L;;;;;N;;;;;
+2D3B;TIFINAGH LETTER YEY;Lo;0;L;;;;;N;;;;;
+2D3C;TIFINAGH LETTER YAF;Lo;0;L;;;;;N;;;;;
+2D3D;TIFINAGH LETTER YAK;Lo;0;L;;;;;N;;;;;
+2D3E;TIFINAGH LETTER TUAREG YAK;Lo;0;L;;;;;N;;;;;
+2D3F;TIFINAGH LETTER YAKHH;Lo;0;L;;;;;N;;;;;
+2D40;TIFINAGH LETTER YAH;Lo;0;L;;;;;N;;Tuareg yab;;;
+2D41;TIFINAGH LETTER BERBER ACADEMY YAH;Lo;0;L;;;;;N;;;;;
+2D42;TIFINAGH LETTER TUAREG YAH;Lo;0;L;;;;;N;;;;;
+2D43;TIFINAGH LETTER YAHH;Lo;0;L;;;;;N;;;;;
+2D44;TIFINAGH LETTER YAA;Lo;0;L;;;;;N;;;;;
+2D45;TIFINAGH LETTER YAKH;Lo;0;L;;;;;N;;;;;
+2D46;TIFINAGH LETTER TUAREG YAKH;Lo;0;L;;;;;N;;;;;
+2D47;TIFINAGH LETTER YAQ;Lo;0;L;;;;;N;;;;;
+2D48;TIFINAGH LETTER TUAREG YAQ;Lo;0;L;;;;;N;;;;;
+2D49;TIFINAGH LETTER YI;Lo;0;L;;;;;N;;;;;
+2D4A;TIFINAGH LETTER YAZH;Lo;0;L;;;;;N;;;;;
+2D4B;TIFINAGH LETTER AHAGGAR YAZH;Lo;0;L;;;;;N;;;;;
+2D4C;TIFINAGH LETTER TUAREG YAZH;Lo;0;L;;;;;N;;;;;
+2D4D;TIFINAGH LETTER YAL;Lo;0;L;;;;;N;;;;;
+2D4E;TIFINAGH LETTER YAM;Lo;0;L;;;;;N;;;;;
+2D4F;TIFINAGH LETTER YAN;Lo;0;L;;;;;N;;;;;
+2D50;TIFINAGH LETTER TUAREG YAGN;Lo;0;L;;;;;N;;;;;
+2D51;TIFINAGH LETTER TUAREG YANG;Lo;0;L;;;;;N;;;;;
+2D52;TIFINAGH LETTER YAP;Lo;0;L;;;;;N;;;;;
+2D53;TIFINAGH LETTER YU;Lo;0;L;;;;;N;;Tuareg yaw;;;
+2D54;TIFINAGH LETTER YAR;Lo;0;L;;;;;N;;;;;
+2D55;TIFINAGH LETTER YARR;Lo;0;L;;;;;N;;;;;
+2D56;TIFINAGH LETTER YAGH;Lo;0;L;;;;;N;;;;;
+2D57;TIFINAGH LETTER TUAREG YAGH;Lo;0;L;;;;;N;;;;;
+2D58;TIFINAGH LETTER AYER YAGH;Lo;0;L;;;;;N;;Adrar yaj;;;
+2D59;TIFINAGH LETTER YAS;Lo;0;L;;;;;N;;;;;
+2D5A;TIFINAGH LETTER YASS;Lo;0;L;;;;;N;;;;;
+2D5B;TIFINAGH LETTER YASH;Lo;0;L;;;;;N;;;;;
+2D5C;TIFINAGH LETTER YAT;Lo;0;L;;;;;N;;;;;
+2D5D;TIFINAGH LETTER YATH;Lo;0;L;;;;;N;;;;;
+2D5E;TIFINAGH LETTER YACH;Lo;0;L;;;;;N;;;;;
+2D5F;TIFINAGH LETTER YATT;Lo;0;L;;;;;N;;;;;
+2D60;TIFINAGH LETTER YAV;Lo;0;L;;;;;N;;;;;
+2D61;TIFINAGH LETTER YAW;Lo;0;L;;;;;N;;;;;
+2D62;TIFINAGH LETTER YAY;Lo;0;L;;;;;N;;;;;
+2D63;TIFINAGH LETTER YAZ;Lo;0;L;;;;;N;;;;;
+2D64;TIFINAGH LETTER TAWELLEMET YAZ;Lo;0;L;;;;;N;;harpoon yaz;;;
+2D65;TIFINAGH LETTER YAZZ;Lo;0;L;;;;;N;;;;;
+2D6F;TIFINAGH MODIFIER LETTER LABIALIZATION MARK;Lm;0;L;<super> 2D61;;;;N;;tamatart;;;
+2D80;ETHIOPIC SYLLABLE LOA;Lo;0;L;;;;;N;;;;;
+2D81;ETHIOPIC SYLLABLE MOA;Lo;0;L;;;;;N;;;;;
+2D82;ETHIOPIC SYLLABLE ROA;Lo;0;L;;;;;N;;;;;
+2D83;ETHIOPIC SYLLABLE SOA;Lo;0;L;;;;;N;;;;;
+2D84;ETHIOPIC SYLLABLE SHOA;Lo;0;L;;;;;N;;;;;
+2D85;ETHIOPIC SYLLABLE BOA;Lo;0;L;;;;;N;;;;;
+2D86;ETHIOPIC SYLLABLE TOA;Lo;0;L;;;;;N;;;;;
+2D87;ETHIOPIC SYLLABLE COA;Lo;0;L;;;;;N;;;;;
+2D88;ETHIOPIC SYLLABLE NOA;Lo;0;L;;;;;N;;;;;
+2D89;ETHIOPIC SYLLABLE NYOA;Lo;0;L;;;;;N;;;;;
+2D8A;ETHIOPIC SYLLABLE GLOTTAL OA;Lo;0;L;;;;;N;;;;;
+2D8B;ETHIOPIC SYLLABLE ZOA;Lo;0;L;;;;;N;;;;;
+2D8C;ETHIOPIC SYLLABLE DOA;Lo;0;L;;;;;N;;;;;
+2D8D;ETHIOPIC SYLLABLE DDOA;Lo;0;L;;;;;N;;;;;
+2D8E;ETHIOPIC SYLLABLE JOA;Lo;0;L;;;;;N;;;;;
+2D8F;ETHIOPIC SYLLABLE THOA;Lo;0;L;;;;;N;;;;;
+2D90;ETHIOPIC SYLLABLE CHOA;Lo;0;L;;;;;N;;;;;
+2D91;ETHIOPIC SYLLABLE PHOA;Lo;0;L;;;;;N;;;;;
+2D92;ETHIOPIC SYLLABLE POA;Lo;0;L;;;;;N;;;;;
+2D93;ETHIOPIC SYLLABLE GGWA;Lo;0;L;;;;;N;;;;;
+2D94;ETHIOPIC SYLLABLE GGWI;Lo;0;L;;;;;N;;;;;
+2D95;ETHIOPIC SYLLABLE GGWEE;Lo;0;L;;;;;N;;;;;
+2D96;ETHIOPIC SYLLABLE GGWE;Lo;0;L;;;;;N;;;;;
+2DA0;ETHIOPIC SYLLABLE SSA;Lo;0;L;;;;;N;;;;;
+2DA1;ETHIOPIC SYLLABLE SSU;Lo;0;L;;;;;N;;;;;
+2DA2;ETHIOPIC SYLLABLE SSI;Lo;0;L;;;;;N;;;;;
+2DA3;ETHIOPIC SYLLABLE SSAA;Lo;0;L;;;;;N;;;;;
+2DA4;ETHIOPIC SYLLABLE SSEE;Lo;0;L;;;;;N;;;;;
+2DA5;ETHIOPIC SYLLABLE SSE;Lo;0;L;;;;;N;;;;;
+2DA6;ETHIOPIC SYLLABLE SSO;Lo;0;L;;;;;N;;;;;
+2DA8;ETHIOPIC SYLLABLE CCA;Lo;0;L;;;;;N;;;;;
+2DA9;ETHIOPIC SYLLABLE CCU;Lo;0;L;;;;;N;;;;;
+2DAA;ETHIOPIC SYLLABLE CCI;Lo;0;L;;;;;N;;;;;
+2DAB;ETHIOPIC SYLLABLE CCAA;Lo;0;L;;;;;N;;;;;
+2DAC;ETHIOPIC SYLLABLE CCEE;Lo;0;L;;;;;N;;;;;
+2DAD;ETHIOPIC SYLLABLE CCE;Lo;0;L;;;;;N;;;;;
+2DAE;ETHIOPIC SYLLABLE CCO;Lo;0;L;;;;;N;;;;;
+2DB0;ETHIOPIC SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;
+2DB1;ETHIOPIC SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;
+2DB2;ETHIOPIC SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;
+2DB3;ETHIOPIC SYLLABLE ZZAA;Lo;0;L;;;;;N;;;;;
+2DB4;ETHIOPIC SYLLABLE ZZEE;Lo;0;L;;;;;N;;;;;
+2DB5;ETHIOPIC SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;
+2DB6;ETHIOPIC SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;
+2DB8;ETHIOPIC SYLLABLE CCHA;Lo;0;L;;;;;N;;;;;
+2DB9;ETHIOPIC SYLLABLE CCHU;Lo;0;L;;;;;N;;;;;
+2DBA;ETHIOPIC SYLLABLE CCHI;Lo;0;L;;;;;N;;;;;
+2DBB;ETHIOPIC SYLLABLE CCHAA;Lo;0;L;;;;;N;;;;;
+2DBC;ETHIOPIC SYLLABLE CCHEE;Lo;0;L;;;;;N;;;;;
+2DBD;ETHIOPIC SYLLABLE CCHE;Lo;0;L;;;;;N;;;;;
+2DBE;ETHIOPIC SYLLABLE CCHO;Lo;0;L;;;;;N;;;;;
+2DC0;ETHIOPIC SYLLABLE QYA;Lo;0;L;;;;;N;;;;;
+2DC1;ETHIOPIC SYLLABLE QYU;Lo;0;L;;;;;N;;;;;
+2DC2;ETHIOPIC SYLLABLE QYI;Lo;0;L;;;;;N;;;;;
+2DC3;ETHIOPIC SYLLABLE QYAA;Lo;0;L;;;;;N;;;;;
+2DC4;ETHIOPIC SYLLABLE QYEE;Lo;0;L;;;;;N;;;;;
+2DC5;ETHIOPIC SYLLABLE QYE;Lo;0;L;;;;;N;;;;;
+2DC6;ETHIOPIC SYLLABLE QYO;Lo;0;L;;;;;N;;;;;
+2DC8;ETHIOPIC SYLLABLE KYA;Lo;0;L;;;;;N;;;;;
+2DC9;ETHIOPIC SYLLABLE KYU;Lo;0;L;;;;;N;;;;;
+2DCA;ETHIOPIC SYLLABLE KYI;Lo;0;L;;;;;N;;;;;
+2DCB;ETHIOPIC SYLLABLE KYAA;Lo;0;L;;;;;N;;;;;
+2DCC;ETHIOPIC SYLLABLE KYEE;Lo;0;L;;;;;N;;;;;
+2DCD;ETHIOPIC SYLLABLE KYE;Lo;0;L;;;;;N;;;;;
+2DCE;ETHIOPIC SYLLABLE KYO;Lo;0;L;;;;;N;;;;;
+2DD0;ETHIOPIC SYLLABLE XYA;Lo;0;L;;;;;N;;;;;
+2DD1;ETHIOPIC SYLLABLE XYU;Lo;0;L;;;;;N;;;;;
+2DD2;ETHIOPIC SYLLABLE XYI;Lo;0;L;;;;;N;;;;;
+2DD3;ETHIOPIC SYLLABLE XYAA;Lo;0;L;;;;;N;;;;;
+2DD4;ETHIOPIC SYLLABLE XYEE;Lo;0;L;;;;;N;;;;;
+2DD5;ETHIOPIC SYLLABLE XYE;Lo;0;L;;;;;N;;;;;
+2DD6;ETHIOPIC SYLLABLE XYO;Lo;0;L;;;;;N;;;;;
+2DD8;ETHIOPIC SYLLABLE GYA;Lo;0;L;;;;;N;;;;;
+2DD9;ETHIOPIC SYLLABLE GYU;Lo;0;L;;;;;N;;;;;
+2DDA;ETHIOPIC SYLLABLE GYI;Lo;0;L;;;;;N;;;;;
+2DDB;ETHIOPIC SYLLABLE GYAA;Lo;0;L;;;;;N;;;;;
+2DDC;ETHIOPIC SYLLABLE GYEE;Lo;0;L;;;;;N;;;;;
+2DDD;ETHIOPIC SYLLABLE GYE;Lo;0;L;;;;;N;;;;;
+2DDE;ETHIOPIC SYLLABLE GYO;Lo;0;L;;;;;N;;;;;
+2E00;RIGHT ANGLE SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;
+2E01;RIGHT ANGLE DOTTED SUBSTITUTION MARKER;Po;0;ON;;;;;N;;;;;
+2E02;LEFT SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E03;RIGHT SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E04;LEFT DOTTED SUBSTITUTION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E05;RIGHT DOTTED SUBSTITUTION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E06;RAISED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;
+2E07;RAISED DOTTED INTERPOLATION MARKER;Po;0;ON;;;;;N;;;;;
+2E08;DOTTED TRANSPOSITION MARKER;Po;0;ON;;;;;N;;;;;
+2E09;LEFT TRANSPOSITION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E0A;RIGHT TRANSPOSITION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E0B;RAISED SQUARE;Po;0;ON;;;;;N;;;;;
+2E0C;LEFT RAISED OMISSION BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E0D;RIGHT RAISED OMISSION BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E0E;EDITORIAL CORONIS;Po;0;ON;;;;;N;;;;;
+2E0F;PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E10;FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E11;REVERSED FORKED PARAGRAPHOS;Po;0;ON;;;;;N;;;;;
+2E12;HYPODIASTOLE;Po;0;ON;;;;;N;;;;;
+2E13;DOTTED OBELOS;Po;0;ON;;;;;N;;;;;
+2E14;DOWNWARDS ANCORA;Po;0;ON;;;;;N;;;;;
+2E15;UPWARDS ANCORA;Po;0;ON;;;;;N;;;;;
+2E16;DOTTED RIGHT-POINTING ANGLE;Po;0;ON;;;;;N;;;;;
+2E17;DOUBLE OBLIQUE HYPHEN;Pd;0;ON;;;;;N;;;;;
+2E1C;LEFT LOW PARAPHRASE BRACKET;Pi;0;ON;;;;;Y;;;;;
+2E1D;RIGHT LOW PARAPHRASE BRACKET;Pf;0;ON;;;;;Y;;;;;
+2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;
+2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;
+2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;
+2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;;
+2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;;
+2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;;
+2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;;
+2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;;
+2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;;
+2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;;
+2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;;
+2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;;
+2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;;
+2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;;
+2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;;
+2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;;
+2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;;
+2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;;
+2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;;
+2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;;
+2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;;
+2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;;
+2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;;
+2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;;
+2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;;
+2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;;
+2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;;
+2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;;
+2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;;
+2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;;
+2E9F;CJK RADICAL MOTHER;So;0;ON;<compat> 6BCD;;;;N;;;;;
+2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;;
+2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;;
+2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;;
+2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;;
+2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;;
+2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;;
+2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;;
+2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;;
+2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;;
+2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;;
+2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;;
+2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;;
+2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;;
+2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;;
+2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;;
+2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;;
+2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;;
+2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;;
+2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;;
+2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;;
+2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;;
+2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;;
+2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;;
+2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;;
+2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;;
+2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;;
+2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;;
+2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;;
+2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;;
+2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;;
+2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;;
+2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;;
+2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;;
+2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;;
+2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;;
+2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;;
+2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;;
+2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;;
+2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;;
+2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;;
+2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;;
+2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;;
+2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;;
+2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;;
+2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;;
+2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;;
+2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;;
+2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;;
+2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;;
+2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;;
+2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;;
+2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;;
+2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;;
+2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;;
+2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;;
+2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;;
+2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;;
+2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;;
+2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;;
+2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;;
+2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;;
+2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;;
+2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;;
+2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;;
+2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;;
+2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;;
+2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;;
+2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;;
+2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;;
+2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;;
+2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;;
+2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;;
+2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;;
+2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;;
+2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;;
+2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;;
+2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;;
+2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON;<compat> 9F9F;;;;N;;;;;
+2F00;KANGXI RADICAL ONE;So;0;ON;<compat> 4E00;;;;N;;;;;
+2F01;KANGXI RADICAL LINE;So;0;ON;<compat> 4E28;;;;N;;;;;
+2F02;KANGXI RADICAL DOT;So;0;ON;<compat> 4E36;;;;N;;;;;
+2F03;KANGXI RADICAL SLASH;So;0;ON;<compat> 4E3F;;;;N;;;;;
+2F04;KANGXI RADICAL SECOND;So;0;ON;<compat> 4E59;;;;N;;;;;
+2F05;KANGXI RADICAL HOOK;So;0;ON;<compat> 4E85;;;;N;;;;;
+2F06;KANGXI RADICAL TWO;So;0;ON;<compat> 4E8C;;;;N;;;;;
+2F07;KANGXI RADICAL LID;So;0;ON;<compat> 4EA0;;;;N;;;;;
+2F08;KANGXI RADICAL MAN;So;0;ON;<compat> 4EBA;;;;N;;;;;
+2F09;KANGXI RADICAL LEGS;So;0;ON;<compat> 513F;;;;N;;;;;
+2F0A;KANGXI RADICAL ENTER;So;0;ON;<compat> 5165;;;;N;;;;;
+2F0B;KANGXI RADICAL EIGHT;So;0;ON;<compat> 516B;;;;N;;;;;
+2F0C;KANGXI RADICAL DOWN BOX;So;0;ON;<compat> 5182;;;;N;;;;;
+2F0D;KANGXI RADICAL COVER;So;0;ON;<compat> 5196;;;;N;;;;;
+2F0E;KANGXI RADICAL ICE;So;0;ON;<compat> 51AB;;;;N;;;;;
+2F0F;KANGXI RADICAL TABLE;So;0;ON;<compat> 51E0;;;;N;;;;;
+2F10;KANGXI RADICAL OPEN BOX;So;0;ON;<compat> 51F5;;;;N;;;;;
+2F11;KANGXI RADICAL KNIFE;So;0;ON;<compat> 5200;;;;N;;;;;
+2F12;KANGXI RADICAL POWER;So;0;ON;<compat> 529B;;;;N;;;;;
+2F13;KANGXI RADICAL WRAP;So;0;ON;<compat> 52F9;;;;N;;;;;
+2F14;KANGXI RADICAL SPOON;So;0;ON;<compat> 5315;;;;N;;;;;
+2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON;<compat> 531A;;;;N;;;;;
+2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON;<compat> 5338;;;;N;;;;;
+2F17;KANGXI RADICAL TEN;So;0;ON;<compat> 5341;;;;N;;;;;
+2F18;KANGXI RADICAL DIVINATION;So;0;ON;<compat> 535C;;;;N;;;;;
+2F19;KANGXI RADICAL SEAL;So;0;ON;<compat> 5369;;;;N;;;;;
+2F1A;KANGXI RADICAL CLIFF;So;0;ON;<compat> 5382;;;;N;;;;;
+2F1B;KANGXI RADICAL PRIVATE;So;0;ON;<compat> 53B6;;;;N;;;;;
+2F1C;KANGXI RADICAL AGAIN;So;0;ON;<compat> 53C8;;;;N;;;;;
+2F1D;KANGXI RADICAL MOUTH;So;0;ON;<compat> 53E3;;;;N;;;;;
+2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON;<compat> 56D7;;;;N;;;;;
+2F1F;KANGXI RADICAL EARTH;So;0;ON;<compat> 571F;;;;N;;;;;
+2F20;KANGXI RADICAL SCHOLAR;So;0;ON;<compat> 58EB;;;;N;;;;;
+2F21;KANGXI RADICAL GO;So;0;ON;<compat> 5902;;;;N;;;;;
+2F22;KANGXI RADICAL GO SLOWLY;So;0;ON;<compat> 590A;;;;N;;;;;
+2F23;KANGXI RADICAL EVENING;So;0;ON;<compat> 5915;;;;N;;;;;
+2F24;KANGXI RADICAL BIG;So;0;ON;<compat> 5927;;;;N;;;;;
+2F25;KANGXI RADICAL WOMAN;So;0;ON;<compat> 5973;;;;N;;;;;
+2F26;KANGXI RADICAL CHILD;So;0;ON;<compat> 5B50;;;;N;;;;;
+2F27;KANGXI RADICAL ROOF;So;0;ON;<compat> 5B80;;;;N;;;;;
+2F28;KANGXI RADICAL INCH;So;0;ON;<compat> 5BF8;;;;N;;;;;
+2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;;
+2F2A;KANGXI RADICAL LAME;So;0;ON;<compat> 5C22;;;;N;;;;;
+2F2B;KANGXI RADICAL CORPSE;So;0;ON;<compat> 5C38;;;;N;;;;;
+2F2C;KANGXI RADICAL SPROUT;So;0;ON;<compat> 5C6E;;;;N;;;;;
+2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON;<compat> 5C71;;;;N;;;;;
+2F2E;KANGXI RADICAL RIVER;So;0;ON;<compat> 5DDB;;;;N;;;;;
+2F2F;KANGXI RADICAL WORK;So;0;ON;<compat> 5DE5;;;;N;;;;;
+2F30;KANGXI RADICAL ONESELF;So;0;ON;<compat> 5DF1;;;;N;;;;;
+2F31;KANGXI RADICAL TURBAN;So;0;ON;<compat> 5DFE;;;;N;;;;;
+2F32;KANGXI RADICAL DRY;So;0;ON;<compat> 5E72;;;;N;;;;;
+2F33;KANGXI RADICAL SHORT THREAD;So;0;ON;<compat> 5E7A;;;;N;;;;;
+2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON;<compat> 5E7F;;;;N;;;;;
+2F35;KANGXI RADICAL LONG STRIDE;So;0;ON;<compat> 5EF4;;;;N;;;;;
+2F36;KANGXI RADICAL TWO HANDS;So;0;ON;<compat> 5EFE;;;;N;;;;;
+2F37;KANGXI RADICAL SHOOT;So;0;ON;<compat> 5F0B;;;;N;;;;;
+2F38;KANGXI RADICAL BOW;So;0;ON;<compat> 5F13;;;;N;;;;;
+2F39;KANGXI RADICAL SNOUT;So;0;ON;<compat> 5F50;;;;N;;;;;
+2F3A;KANGXI RADICAL BRISTLE;So;0;ON;<compat> 5F61;;;;N;;;;;
+2F3B;KANGXI RADICAL STEP;So;0;ON;<compat> 5F73;;;;N;;;;;
+2F3C;KANGXI RADICAL HEART;So;0;ON;<compat> 5FC3;;;;N;;;;;
+2F3D;KANGXI RADICAL HALBERD;So;0;ON;<compat> 6208;;;;N;;;;;
+2F3E;KANGXI RADICAL DOOR;So;0;ON;<compat> 6236;;;;N;;;;;
+2F3F;KANGXI RADICAL HAND;So;0;ON;<compat> 624B;;;;N;;;;;
+2F40;KANGXI RADICAL BRANCH;So;0;ON;<compat> 652F;;;;N;;;;;
+2F41;KANGXI RADICAL RAP;So;0;ON;<compat> 6534;;;;N;;;;;
+2F42;KANGXI RADICAL SCRIPT;So;0;ON;<compat> 6587;;;;N;;;;;
+2F43;KANGXI RADICAL DIPPER;So;0;ON;<compat> 6597;;;;N;;;;;
+2F44;KANGXI RADICAL AXE;So;0;ON;<compat> 65A4;;;;N;;;;;
+2F45;KANGXI RADICAL SQUARE;So;0;ON;<compat> 65B9;;;;N;;;;;
+2F46;KANGXI RADICAL NOT;So;0;ON;<compat> 65E0;;;;N;;;;;
+2F47;KANGXI RADICAL SUN;So;0;ON;<compat> 65E5;;;;N;;;;;
+2F48;KANGXI RADICAL SAY;So;0;ON;<compat> 66F0;;;;N;;;;;
+2F49;KANGXI RADICAL MOON;So;0;ON;<compat> 6708;;;;N;;;;;
+2F4A;KANGXI RADICAL TREE;So;0;ON;<compat> 6728;;;;N;;;;;
+2F4B;KANGXI RADICAL LACK;So;0;ON;<compat> 6B20;;;;N;;;;;
+2F4C;KANGXI RADICAL STOP;So;0;ON;<compat> 6B62;;;;N;;;;;
+2F4D;KANGXI RADICAL DEATH;So;0;ON;<compat> 6B79;;;;N;;;;;
+2F4E;KANGXI RADICAL WEAPON;So;0;ON;<compat> 6BB3;;;;N;;;;;
+2F4F;KANGXI RADICAL DO NOT;So;0;ON;<compat> 6BCB;;;;N;;;;;
+2F50;KANGXI RADICAL COMPARE;So;0;ON;<compat> 6BD4;;;;N;;;;;
+2F51;KANGXI RADICAL FUR;So;0;ON;<compat> 6BDB;;;;N;;;;;
+2F52;KANGXI RADICAL CLAN;So;0;ON;<compat> 6C0F;;;;N;;;;;
+2F53;KANGXI RADICAL STEAM;So;0;ON;<compat> 6C14;;;;N;;;;;
+2F54;KANGXI RADICAL WATER;So;0;ON;<compat> 6C34;;;;N;;;;;
+2F55;KANGXI RADICAL FIRE;So;0;ON;<compat> 706B;;;;N;;;;;
+2F56;KANGXI RADICAL CLAW;So;0;ON;<compat> 722A;;;;N;;;;;
+2F57;KANGXI RADICAL FATHER;So;0;ON;<compat> 7236;;;;N;;;;;
+2F58;KANGXI RADICAL DOUBLE X;So;0;ON;<compat> 723B;;;;N;;;;;
+2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON;<compat> 723F;;;;N;;;;;
+2F5A;KANGXI RADICAL SLICE;So;0;ON;<compat> 7247;;;;N;;;;;
+2F5B;KANGXI RADICAL FANG;So;0;ON;<compat> 7259;;;;N;;;;;
+2F5C;KANGXI RADICAL COW;So;0;ON;<compat> 725B;;;;N;;;;;
+2F5D;KANGXI RADICAL DOG;So;0;ON;<compat> 72AC;;;;N;;;;;
+2F5E;KANGXI RADICAL PROFOUND;So;0;ON;<compat> 7384;;;;N;;;;;
+2F5F;KANGXI RADICAL JADE;So;0;ON;<compat> 7389;;;;N;;;;;
+2F60;KANGXI RADICAL MELON;So;0;ON;<compat> 74DC;;;;N;;;;;
+2F61;KANGXI RADICAL TILE;So;0;ON;<compat> 74E6;;;;N;;;;;
+2F62;KANGXI RADICAL SWEET;So;0;ON;<compat> 7518;;;;N;;;;;
+2F63;KANGXI RADICAL LIFE;So;0;ON;<compat> 751F;;;;N;;;;;
+2F64;KANGXI RADICAL USE;So;0;ON;<compat> 7528;;;;N;;;;;
+2F65;KANGXI RADICAL FIELD;So;0;ON;<compat> 7530;;;;N;;;;;
+2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON;<compat> 758B;;;;N;;;;;
+2F67;KANGXI RADICAL SICKNESS;So;0;ON;<compat> 7592;;;;N;;;;;
+2F68;KANGXI RADICAL DOTTED TENT;So;0;ON;<compat> 7676;;;;N;;;;;
+2F69;KANGXI RADICAL WHITE;So;0;ON;<compat> 767D;;;;N;;;;;
+2F6A;KANGXI RADICAL SKIN;So;0;ON;<compat> 76AE;;;;N;;;;;
+2F6B;KANGXI RADICAL DISH;So;0;ON;<compat> 76BF;;;;N;;;;;
+2F6C;KANGXI RADICAL EYE;So;0;ON;<compat> 76EE;;;;N;;;;;
+2F6D;KANGXI RADICAL SPEAR;So;0;ON;<compat> 77DB;;;;N;;;;;
+2F6E;KANGXI RADICAL ARROW;So;0;ON;<compat> 77E2;;;;N;;;;;
+2F6F;KANGXI RADICAL STONE;So;0;ON;<compat> 77F3;;;;N;;;;;
+2F70;KANGXI RADICAL SPIRIT;So;0;ON;<compat> 793A;;;;N;;;;;
+2F71;KANGXI RADICAL TRACK;So;0;ON;<compat> 79B8;;;;N;;;;;
+2F72;KANGXI RADICAL GRAIN;So;0;ON;<compat> 79BE;;;;N;;;;;
+2F73;KANGXI RADICAL CAVE;So;0;ON;<compat> 7A74;;;;N;;;;;
+2F74;KANGXI RADICAL STAND;So;0;ON;<compat> 7ACB;;;;N;;;;;
+2F75;KANGXI RADICAL BAMBOO;So;0;ON;<compat> 7AF9;;;;N;;;;;
+2F76;KANGXI RADICAL RICE;So;0;ON;<compat> 7C73;;;;N;;;;;
+2F77;KANGXI RADICAL SILK;So;0;ON;<compat> 7CF8;;;;N;;;;;
+2F78;KANGXI RADICAL JAR;So;0;ON;<compat> 7F36;;;;N;;;;;
+2F79;KANGXI RADICAL NET;So;0;ON;<compat> 7F51;;;;N;;;;;
+2F7A;KANGXI RADICAL SHEEP;So;0;ON;<compat> 7F8A;;;;N;;;;;
+2F7B;KANGXI RADICAL FEATHER;So;0;ON;<compat> 7FBD;;;;N;;;;;
+2F7C;KANGXI RADICAL OLD;So;0;ON;<compat> 8001;;;;N;;;;;
+2F7D;KANGXI RADICAL AND;So;0;ON;<compat> 800C;;;;N;;;;;
+2F7E;KANGXI RADICAL PLOW;So;0;ON;<compat> 8012;;;;N;;;;;
+2F7F;KANGXI RADICAL EAR;So;0;ON;<compat> 8033;;;;N;;;;;
+2F80;KANGXI RADICAL BRUSH;So;0;ON;<compat> 807F;;;;N;;;;;
+2F81;KANGXI RADICAL MEAT;So;0;ON;<compat> 8089;;;;N;;;;;
+2F82;KANGXI RADICAL MINISTER;So;0;ON;<compat> 81E3;;;;N;;;;;
+2F83;KANGXI RADICAL SELF;So;0;ON;<compat> 81EA;;;;N;;;;;
+2F84;KANGXI RADICAL ARRIVE;So;0;ON;<compat> 81F3;;;;N;;;;;
+2F85;KANGXI RADICAL MORTAR;So;0;ON;<compat> 81FC;;;;N;;;;;
+2F86;KANGXI RADICAL TONGUE;So;0;ON;<compat> 820C;;;;N;;;;;
+2F87;KANGXI RADICAL OPPOSE;So;0;ON;<compat> 821B;;;;N;;;;;
+2F88;KANGXI RADICAL BOAT;So;0;ON;<compat> 821F;;;;N;;;;;
+2F89;KANGXI RADICAL STOPPING;So;0;ON;<compat> 826E;;;;N;;;;;
+2F8A;KANGXI RADICAL COLOR;So;0;ON;<compat> 8272;;;;N;;;;;
+2F8B;KANGXI RADICAL GRASS;So;0;ON;<compat> 8278;;;;N;;;;;
+2F8C;KANGXI RADICAL TIGER;So;0;ON;<compat> 864D;;;;N;;;;;
+2F8D;KANGXI RADICAL INSECT;So;0;ON;<compat> 866B;;;;N;;;;;
+2F8E;KANGXI RADICAL BLOOD;So;0;ON;<compat> 8840;;;;N;;;;;
+2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON;<compat> 884C;;;;N;;;;;
+2F90;KANGXI RADICAL CLOTHES;So;0;ON;<compat> 8863;;;;N;;;;;
+2F91;KANGXI RADICAL WEST;So;0;ON;<compat> 897E;;;;N;;;;;
+2F92;KANGXI RADICAL SEE;So;0;ON;<compat> 898B;;;;N;;;;;
+2F93;KANGXI RADICAL HORN;So;0;ON;<compat> 89D2;;;;N;;;;;
+2F94;KANGXI RADICAL SPEECH;So;0;ON;<compat> 8A00;;;;N;;;;;
+2F95;KANGXI RADICAL VALLEY;So;0;ON;<compat> 8C37;;;;N;;;;;
+2F96;KANGXI RADICAL BEAN;So;0;ON;<compat> 8C46;;;;N;;;;;
+2F97;KANGXI RADICAL PIG;So;0;ON;<compat> 8C55;;;;N;;;;;
+2F98;KANGXI RADICAL BADGER;So;0;ON;<compat> 8C78;;;;N;;;;;
+2F99;KANGXI RADICAL SHELL;So;0;ON;<compat> 8C9D;;;;N;;;;;
+2F9A;KANGXI RADICAL RED;So;0;ON;<compat> 8D64;;;;N;;;;;
+2F9B;KANGXI RADICAL RUN;So;0;ON;<compat> 8D70;;;;N;;;;;
+2F9C;KANGXI RADICAL FOOT;So;0;ON;<compat> 8DB3;;;;N;;;;;
+2F9D;KANGXI RADICAL BODY;So;0;ON;<compat> 8EAB;;;;N;;;;;
+2F9E;KANGXI RADICAL CART;So;0;ON;<compat> 8ECA;;;;N;;;;;
+2F9F;KANGXI RADICAL BITTER;So;0;ON;<compat> 8F9B;;;;N;;;;;
+2FA0;KANGXI RADICAL MORNING;So;0;ON;<compat> 8FB0;;;;N;;;;;
+2FA1;KANGXI RADICAL WALK;So;0;ON;<compat> 8FB5;;;;N;;;;;
+2FA2;KANGXI RADICAL CITY;So;0;ON;<compat> 9091;;;;N;;;;;
+2FA3;KANGXI RADICAL WINE;So;0;ON;<compat> 9149;;;;N;;;;;
+2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON;<compat> 91C6;;;;N;;;;;
+2FA5;KANGXI RADICAL VILLAGE;So;0;ON;<compat> 91CC;;;;N;;;;;
+2FA6;KANGXI RADICAL GOLD;So;0;ON;<compat> 91D1;;;;N;;;;;
+2FA7;KANGXI RADICAL LONG;So;0;ON;<compat> 9577;;;;N;;;;;
+2FA8;KANGXI RADICAL GATE;So;0;ON;<compat> 9580;;;;N;;;;;
+2FA9;KANGXI RADICAL MOUND;So;0;ON;<compat> 961C;;;;N;;;;;
+2FAA;KANGXI RADICAL SLAVE;So;0;ON;<compat> 96B6;;;;N;;;;;
+2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON;<compat> 96B9;;;;N;;;;;
+2FAC;KANGXI RADICAL RAIN;So;0;ON;<compat> 96E8;;;;N;;;;;
+2FAD;KANGXI RADICAL BLUE;So;0;ON;<compat> 9751;;;;N;;;;;
+2FAE;KANGXI RADICAL WRONG;So;0;ON;<compat> 975E;;;;N;;;;;
+2FAF;KANGXI RADICAL FACE;So;0;ON;<compat> 9762;;;;N;;;;;
+2FB0;KANGXI RADICAL LEATHER;So;0;ON;<compat> 9769;;;;N;;;;;
+2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON;<compat> 97CB;;;;N;;;;;
+2FB2;KANGXI RADICAL LEEK;So;0;ON;<compat> 97ED;;;;N;;;;;
+2FB3;KANGXI RADICAL SOUND;So;0;ON;<compat> 97F3;;;;N;;;;;
+2FB4;KANGXI RADICAL LEAF;So;0;ON;<compat> 9801;;;;N;;;;;
+2FB5;KANGXI RADICAL WIND;So;0;ON;<compat> 98A8;;;;N;;;;;
+2FB6;KANGXI RADICAL FLY;So;0;ON;<compat> 98DB;;;;N;;;;;
+2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;;
+2FB8;KANGXI RADICAL HEAD;So;0;ON;<compat> 9996;;;;N;;;;;
+2FB9;KANGXI RADICAL FRAGRANT;So;0;ON;<compat> 9999;;;;N;;;;;
+2FBA;KANGXI RADICAL HORSE;So;0;ON;<compat> 99AC;;;;N;;;;;
+2FBB;KANGXI RADICAL BONE;So;0;ON;<compat> 9AA8;;;;N;;;;;
+2FBC;KANGXI RADICAL TALL;So;0;ON;<compat> 9AD8;;;;N;;;;;
+2FBD;KANGXI RADICAL HAIR;So;0;ON;<compat> 9ADF;;;;N;;;;;
+2FBE;KANGXI RADICAL FIGHT;So;0;ON;<compat> 9B25;;;;N;;;;;
+2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON;<compat> 9B2F;;;;N;;;;;
+2FC0;KANGXI RADICAL CAULDRON;So;0;ON;<compat> 9B32;;;;N;;;;;
+2FC1;KANGXI RADICAL GHOST;So;0;ON;<compat> 9B3C;;;;N;;;;;
+2FC2;KANGXI RADICAL FISH;So;0;ON;<compat> 9B5A;;;;N;;;;;
+2FC3;KANGXI RADICAL BIRD;So;0;ON;<compat> 9CE5;;;;N;;;;;
+2FC4;KANGXI RADICAL SALT;So;0;ON;<compat> 9E75;;;;N;;;;;
+2FC5;KANGXI RADICAL DEER;So;0;ON;<compat> 9E7F;;;;N;;;;;
+2FC6;KANGXI RADICAL WHEAT;So;0;ON;<compat> 9EA5;;;;N;;;;;
+2FC7;KANGXI RADICAL HEMP;So;0;ON;<compat> 9EBB;;;;N;;;;;
+2FC8;KANGXI RADICAL YELLOW;So;0;ON;<compat> 9EC3;;;;N;;;;;
+2FC9;KANGXI RADICAL MILLET;So;0;ON;<compat> 9ECD;;;;N;;;;;
+2FCA;KANGXI RADICAL BLACK;So;0;ON;<compat> 9ED1;;;;N;;;;;
+2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON;<compat> 9EF9;;;;N;;;;;
+2FCC;KANGXI RADICAL FROG;So;0;ON;<compat> 9EFD;;;;N;;;;;
+2FCD;KANGXI RADICAL TRIPOD;So;0;ON;<compat> 9F0E;;;;N;;;;;
+2FCE;KANGXI RADICAL DRUM;So;0;ON;<compat> 9F13;;;;N;;;;;
+2FCF;KANGXI RADICAL RAT;So;0;ON;<compat> 9F20;;;;N;;;;;
+2FD0;KANGXI RADICAL NOSE;So;0;ON;<compat> 9F3B;;;;N;;;;;
+2FD1;KANGXI RADICAL EVEN;So;0;ON;<compat> 9F4A;;;;N;;;;;
+2FD2;KANGXI RADICAL TOOTH;So;0;ON;<compat> 9F52;;;;N;;;;;
+2FD3;KANGXI RADICAL DRAGON;So;0;ON;<compat> 9F8D;;;;N;;;;;
+2FD4;KANGXI RADICAL TURTLE;So;0;ON;<compat> 9F9C;;;;N;;;;;
+2FD5;KANGXI RADICAL FLUTE;So;0;ON;<compat> 9FA0;;;;N;;;;;
+2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;;
+2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;;
+2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;;
+2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;;
+2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;;
+2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;;
+2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;;
+2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;;
+2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;;
+2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;;
+2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;;
+2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;;
+3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
+3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;;
+3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;;
+3003;DITTO MARK;Po;0;ON;;;;;N;;;;;
+3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;;
+3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;
+3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;;
+3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;;
+3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;;
+3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;;
+300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;;
+300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;;
+300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;;
+300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;;
+300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;;
+300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;;
+3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;;
+3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;;
+3012;POSTAL MARK;So;0;ON;;;;;N;;;;;
+3013;GETA MARK;So;0;ON;;;;;N;;;;;
+3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;;
+3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;;
+3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;;
+3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;;
+3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;;
+3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;;
+301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;;
+301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;;
+301C;WAVE DASH;Pd;0;ON;;;;;N;;;;;
+301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;;
+301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;;
+3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;;
+3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;;
+3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;;
+3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;;
+3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;;
+3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;;
+3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;;
+3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;;
+3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;;
+302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;;
+302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;;
+302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;;
+302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;;
+302E;HANGUL SINGLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;;
+302F;HANGUL DOUBLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;;
+3030;WAVY DASH;Pd;0;ON;;;;;N;;;;;
+3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;;
+3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;;
+3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;;
+3036;CIRCLED POSTAL MARK;So;0;ON;<compat> 3012;;;;N;;;;;
+3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;;
+3038;HANGZHOU NUMERAL TEN;Nl;0;L;<compat> 5341;;;10;N;;;;;
+3039;HANGZHOU NUMERAL TWENTY;Nl;0;L;<compat> 5344;;;20;N;;;;;
+303A;HANGZHOU NUMERAL THIRTY;Nl;0;L;<compat> 5345;;;30;N;;;;;
+303B;VERTICAL IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;
+303C;MASU MARK;Lo;0;L;;;;;N;;;;;
+303D;PART ALTERNATION MARK;Po;0;ON;;;;;N;;;;;
+303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;;
+303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;;
+3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;;
+3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;;
+3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;;
+3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;;
+3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;;
+304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;;
+304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;;
+304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;;
+304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;;
+304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;;
+3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;;
+3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;;
+3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;;
+3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;;
+3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;;
+3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;;
+3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;;
+3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;;
+3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;;
+3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;;
+305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;;
+305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;;
+305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;;
+305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;;
+305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;;
+305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;;
+3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;;
+3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;;
+3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;;
+3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;;
+3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;;
+3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;;
+3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;;
+3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;;
+3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;;
+306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;;
+306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;;
+306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;;
+306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;;
+306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;;
+306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;;
+3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;;
+3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;;
+3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;;
+3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;;
+3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;;
+3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;;
+3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;;
+3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;;
+3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;;
+3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;;
+307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;;
+307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;;
+307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;;
+307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;;
+307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;;
+307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;;
+3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;;
+3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;;
+3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;;
+3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;;
+3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;;
+3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;;
+3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;;
+308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;;
+308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;;
+308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;;
+308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;;
+308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;;
+3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;;
+3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;;
+3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;;
+3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;;
+3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;;
+3095;HIRAGANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;
+3096;HIRAGANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;
+3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;;
+309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;;
+309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON;<compat> 0020 3099;;;;N;;;;;
+309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON;<compat> 0020 309A;;;;N;;;;;
+309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;;
+309F;HIRAGANA DIGRAPH YORI;Lo;0;L;<vertical> 3088 308A;;;;N;;;;;
+30A0;KATAKANA-HIRAGANA DOUBLE HYPHEN;Pd;0;ON;;;;;N;;;;;
+30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;;
+30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;;
+30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;;
+30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;;
+30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;;
+30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;;
+30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;;
+30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;;
+30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;;
+30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;;
+30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;;
+30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;;
+30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;;
+30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;;
+30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;;
+30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;;
+30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;;
+30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;;
+30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;;
+30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;;
+30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;;
+30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;;
+30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;;
+30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;;
+30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;;
+30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;;
+30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;;
+30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;;
+30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;;
+30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;;
+30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;;
+30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;;
+30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;;
+30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;;
+30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;;
+30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;;
+30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;;
+30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;;
+30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;;
+30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;;
+30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;;
+30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;;
+30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;;
+30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;;
+30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;;
+30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;;
+30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;;
+30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;;
+30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;;
+30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;;
+30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;;
+30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;;
+30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;;
+30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;;
+30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;;
+30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;;
+30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;;
+30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;;
+30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;;
+30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;;
+30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;;
+30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;;
+30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;;
+30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;;
+30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;;
+30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;;
+30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;;
+30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;;
+30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;;
+30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;;
+30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;;
+30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;;
+30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;;
+30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;;
+30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;
+30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;
+30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;;
+30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;;
+30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;;
+30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;;
+30FB;KATAKANA MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;;
+30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;;
+30FF;KATAKANA DIGRAPH KOTO;Lo;0;L;<vertical> 30B3 30C8;;;;N;;;;;
+3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;;
+3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;;
+3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;;
+3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;;
+3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;;
+310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;;
+310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;;
+310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;;
+310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;;
+310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;;
+310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;;
+3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;;
+3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;;
+3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;;
+3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;;
+3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;;
+3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;;
+3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;;
+3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;;
+3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;;
+3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;;
+311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;;
+311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;;
+311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;;
+311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;;
+311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;;
+311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;;
+3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;;
+3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;;
+3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;;
+3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;;
+3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;;
+3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;;
+3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;;
+3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;;
+3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;;
+3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;;
+312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;;
+312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;;
+312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;;
+3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;;
+3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;;
+3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
+3134;HANGUL LETTER NIEUN;Lo;0;L;<compat> 1102;;;;N;;;;;
+3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<compat> 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;;
+3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<compat> 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;;
+3137;HANGUL LETTER TIKEUT;Lo;0;L;<compat> 1103;;;;N;HANGUL LETTER DIGEUD;;;;
+3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L;<compat> 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;;
+3139;HANGUL LETTER RIEUL;Lo;0;L;<compat> 1105;;;;N;HANGUL LETTER LIEUL;;;;
+313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<compat> 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;;
+313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<compat> 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;;
+313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<compat> 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;;
+313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L;<compat> 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;;
+313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<compat> 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;;
+313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<compat> 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;;
+3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<compat> 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;;
+3141;HANGUL LETTER MIEUM;Lo;0;L;<compat> 1106;;;;N;;;;;
+3142;HANGUL LETTER PIEUP;Lo;0;L;<compat> 1107;;;;N;HANGUL LETTER BIEUB;;;;
+3143;HANGUL LETTER SSANGPIEUP;Lo;0;L;<compat> 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;;
+3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L;<compat> 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;;
+3145;HANGUL LETTER SIOS;Lo;0;L;<compat> 1109;;;;N;;;;;
+3146;HANGUL LETTER SSANGSIOS;Lo;0;L;<compat> 110A;;;;N;HANGUL LETTER SSANG SIOS;;;;
+3147;HANGUL LETTER IEUNG;Lo;0;L;<compat> 110B;;;;N;;;;;
+3148;HANGUL LETTER CIEUC;Lo;0;L;<compat> 110C;;;;N;HANGUL LETTER JIEUJ;;;;
+3149;HANGUL LETTER SSANGCIEUC;Lo;0;L;<compat> 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;;
+314A;HANGUL LETTER CHIEUCH;Lo;0;L;<compat> 110E;;;;N;HANGUL LETTER CIEUC;;;;
+314B;HANGUL LETTER KHIEUKH;Lo;0;L;<compat> 110F;;;;N;HANGUL LETTER KIYEOK;;;;
+314C;HANGUL LETTER THIEUTH;Lo;0;L;<compat> 1110;;;;N;HANGUL LETTER TIEUT;;;;
+314D;HANGUL LETTER PHIEUPH;Lo;0;L;<compat> 1111;;;;N;HANGUL LETTER PIEUP;;;;
+314E;HANGUL LETTER HIEUH;Lo;0;L;<compat> 1112;;;;N;;;;;
+314F;HANGUL LETTER A;Lo;0;L;<compat> 1161;;;;N;;;;;
+3150;HANGUL LETTER AE;Lo;0;L;<compat> 1162;;;;N;;;;;
+3151;HANGUL LETTER YA;Lo;0;L;<compat> 1163;;;;N;;;;;
+3152;HANGUL LETTER YAE;Lo;0;L;<compat> 1164;;;;N;;;;;
+3153;HANGUL LETTER EO;Lo;0;L;<compat> 1165;;;;N;;;;;
+3154;HANGUL LETTER E;Lo;0;L;<compat> 1166;;;;N;;;;;
+3155;HANGUL LETTER YEO;Lo;0;L;<compat> 1167;;;;N;;;;;
+3156;HANGUL LETTER YE;Lo;0;L;<compat> 1168;;;;N;;;;;
+3157;HANGUL LETTER O;Lo;0;L;<compat> 1169;;;;N;;;;;
+3158;HANGUL LETTER WA;Lo;0;L;<compat> 116A;;;;N;;;;;
+3159;HANGUL LETTER WAE;Lo;0;L;<compat> 116B;;;;N;;;;;
+315A;HANGUL LETTER OE;Lo;0;L;<compat> 116C;;;;N;;;;;
+315B;HANGUL LETTER YO;Lo;0;L;<compat> 116D;;;;N;;;;;
+315C;HANGUL LETTER U;Lo;0;L;<compat> 116E;;;;N;;;;;
+315D;HANGUL LETTER WEO;Lo;0;L;<compat> 116F;;;;N;;;;;
+315E;HANGUL LETTER WE;Lo;0;L;<compat> 1170;;;;N;;;;;
+315F;HANGUL LETTER WI;Lo;0;L;<compat> 1171;;;;N;;;;;
+3160;HANGUL LETTER YU;Lo;0;L;<compat> 1172;;;;N;;;;;
+3161;HANGUL LETTER EU;Lo;0;L;<compat> 1173;;;;N;;;;;
+3162;HANGUL LETTER YI;Lo;0;L;<compat> 1174;;;;N;;;;;
+3163;HANGUL LETTER I;Lo;0;L;<compat> 1175;;;;N;;;;;
+3164;HANGUL FILLER;Lo;0;L;<compat> 1160;;;;N;HANGUL CAE OM;;;;
+3165;HANGUL LETTER SSANGNIEUN;Lo;0;L;<compat> 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;;
+3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L;<compat> 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;;
+3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L;<compat> 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;;
+3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L;<compat> 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;;
+3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L;<compat> 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;;
+316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L;<compat> 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;;
+316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L;<compat> 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;;
+316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L;<compat> 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;;
+316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L;<compat> 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;;
+316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L;<compat> 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;;
+316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L;<compat> 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;;
+3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L;<compat> 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;;
+3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L;<compat> 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;;
+3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L;<compat> 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;;
+3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L;<compat> 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;;
+3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L;<compat> 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;;
+3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L;<compat> 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;;
+3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L;<compat> 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;;
+3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L;<compat> 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;;
+3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L;<compat> 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;;
+3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L;<compat> 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;;
+317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L;<compat> 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;;
+317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L;<compat> 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;;
+317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L;<compat> 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;;
+317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L;<compat> 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;;
+317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L;<compat> 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;;
+317F;HANGUL LETTER PANSIOS;Lo;0;L;<compat> 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;;
+3180;HANGUL LETTER SSANGIEUNG;Lo;0;L;<compat> 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;;
+3181;HANGUL LETTER YESIEUNG;Lo;0;L;<compat> 114C;;;;N;HANGUL LETTER NGIEUNG;;;;
+3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L;<compat> 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;;
+3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L;<compat> 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;;
+3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L;<compat> 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;;
+3185;HANGUL LETTER SSANGHIEUH;Lo;0;L;<compat> 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;;
+3186;HANGUL LETTER YEORINHIEUH;Lo;0;L;<compat> 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;;
+3187;HANGUL LETTER YO-YA;Lo;0;L;<compat> 1184;;;;N;HANGUL LETTER YOYA;;;;
+3188;HANGUL LETTER YO-YAE;Lo;0;L;<compat> 1185;;;;N;HANGUL LETTER YOYAE;;;;
+3189;HANGUL LETTER YO-I;Lo;0;L;<compat> 1188;;;;N;HANGUL LETTER YOI;;;;
+318A;HANGUL LETTER YU-YEO;Lo;0;L;<compat> 1191;;;;N;HANGUL LETTER YUYEO;;;;
+318B;HANGUL LETTER YU-YE;Lo;0;L;<compat> 1192;;;;N;HANGUL LETTER YUYE;;;;
+318C;HANGUL LETTER YU-I;Lo;0;L;<compat> 1194;;;;N;HANGUL LETTER YUI;;;;
+318D;HANGUL LETTER ARAEA;Lo;0;L;<compat> 119E;;;;N;HANGUL LETTER ALAE A;;;;
+318E;HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;;
+3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;Kanbun Tateten;;;
+3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;Kaeriten;;;
+3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L;<super> 4E00;;;1;N;KAERITEN ITI;Kaeriten;;;
+3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L;<super> 4E8C;;;2;N;KAERITEN NI;Kaeriten;;;
+3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L;<super> 4E09;;;3;N;KAERITEN SAN;Kaeriten;;;
+3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L;<super> 56DB;;;4;N;KAERITEN SI;Kaeriten;;;
+3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L;<super> 4E0A;;;;N;KAERITEN ZYOU;Kaeriten;;;
+3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L;<super> 4E2D;;;;N;KAERITEN TYUU;Kaeriten;;;
+3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L;<super> 4E0B;;;;N;KAERITEN GE;Kaeriten;;;
+3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L;<super> 7532;;;;N;KAERITEN KOU;Kaeriten;;;
+319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L;<super> 4E59;;;;N;KAERITEN OTU;Kaeriten;;;
+319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L;<super> 4E19;;;;N;KAERITEN HEI;Kaeriten;;;
+319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L;<super> 4E01;;;;N;KAERITEN TEI;Kaeriten;;;
+319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L;<super> 5929;;;;N;KAERITEN TEN;Kaeriten;;;
+319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L;<super> 5730;;;;N;KAERITEN TI;Kaeriten;;;
+319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L;<super> 4EBA;;;;N;KAERITEN ZIN;Kaeriten;;;
+31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;;
+31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;;
+31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;;
+31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;;
+31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;;
+31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;;
+31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;;
+31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;;
+31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;;
+31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;;
+31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;;
+31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;;
+31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;;
+31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;;
+31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;;
+31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;;
+31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;;
+31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;;
+31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;;
+31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;;
+31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;;
+31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;;
+31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;;
+31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;;
+31C0;CJK STROKE T;So;0;ON;;;;;N;;;;;
+31C1;CJK STROKE WG;So;0;ON;;;;;N;;;;;
+31C2;CJK STROKE XG;So;0;ON;;;;;N;;;;;
+31C3;CJK STROKE BXG;So;0;ON;;;;;N;;;;;
+31C4;CJK STROKE SW;So;0;ON;;;;;N;;;;;
+31C5;CJK STROKE HZZ;So;0;ON;;;;;N;;;;;
+31C6;CJK STROKE HZG;So;0;ON;;;;;N;;;;;
+31C7;CJK STROKE HP;So;0;ON;;;;;N;;;;;
+31C8;CJK STROKE HZWG;So;0;ON;;;;;N;;;;;
+31C9;CJK STROKE SZWG;So;0;ON;;;;;N;;;;;
+31CA;CJK STROKE HZT;So;0;ON;;;;;N;;;;;
+31CB;CJK STROKE HZZP;So;0;ON;;;;;N;;;;;
+31CC;CJK STROKE HPWG;So;0;ON;;;;;N;;;;;
+31CD;CJK STROKE HZW;So;0;ON;;;;;N;;;;;
+31CE;CJK STROKE HZZZ;So;0;ON;;;;;N;;;;;
+31CF;CJK STROKE N;So;0;ON;;;;;N;;;;;
+31F0;KATAKANA LETTER SMALL KU;Lo;0;L;;;;;N;;;;;
+31F1;KATAKANA LETTER SMALL SI;Lo;0;L;;;;;N;;;;;
+31F2;KATAKANA LETTER SMALL SU;Lo;0;L;;;;;N;;;;;
+31F3;KATAKANA LETTER SMALL TO;Lo;0;L;;;;;N;;;;;
+31F4;KATAKANA LETTER SMALL NU;Lo;0;L;;;;;N;;;;;
+31F5;KATAKANA LETTER SMALL HA;Lo;0;L;;;;;N;;;;;
+31F6;KATAKANA LETTER SMALL HI;Lo;0;L;;;;;N;;;;;
+31F7;KATAKANA LETTER SMALL HU;Lo;0;L;;;;;N;;;;;
+31F8;KATAKANA LETTER SMALL HE;Lo;0;L;;;;;N;;;;;
+31F9;KATAKANA LETTER SMALL HO;Lo;0;L;;;;;N;;;;;
+31FA;KATAKANA LETTER SMALL MU;Lo;0;L;;;;;N;;;;;
+31FB;KATAKANA LETTER SMALL RA;Lo;0;L;;;;;N;;;;;
+31FC;KATAKANA LETTER SMALL RI;Lo;0;L;;;;;N;;;;;
+31FD;KATAKANA LETTER SMALL RU;Lo;0;L;;;;;N;;;;;
+31FE;KATAKANA LETTER SMALL RE;Lo;0;L;;;;;N;;;;;
+31FF;KATAKANA LETTER SMALL RO;Lo;0;L;;;;;N;;;;;
+3200;PARENTHESIZED HANGUL KIYEOK;So;0;L;<compat> 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;;
+3201;PARENTHESIZED HANGUL NIEUN;So;0;L;<compat> 0028 1102 0029;;;;N;;;;;
+3202;PARENTHESIZED HANGUL TIKEUT;So;0;L;<compat> 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;;
+3203;PARENTHESIZED HANGUL RIEUL;So;0;L;<compat> 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;;
+3204;PARENTHESIZED HANGUL MIEUM;So;0;L;<compat> 0028 1106 0029;;;;N;;;;;
+3205;PARENTHESIZED HANGUL PIEUP;So;0;L;<compat> 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;;
+3206;PARENTHESIZED HANGUL SIOS;So;0;L;<compat> 0028 1109 0029;;;;N;;;;;
+3207;PARENTHESIZED HANGUL IEUNG;So;0;L;<compat> 0028 110B 0029;;;;N;;;;;
+3208;PARENTHESIZED HANGUL CIEUC;So;0;L;<compat> 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;;
+3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L;<compat> 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;;
+320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L;<compat> 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;;
+320B;PARENTHESIZED HANGUL THIEUTH;So;0;L;<compat> 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;;
+320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L;<compat> 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;;
+320D;PARENTHESIZED HANGUL HIEUH;So;0;L;<compat> 0028 1112 0029;;;;N;;;;;
+320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L;<compat> 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;;
+320F;PARENTHESIZED HANGUL NIEUN A;So;0;L;<compat> 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;;
+3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L;<compat> 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;;
+3211;PARENTHESIZED HANGUL RIEUL A;So;0;L;<compat> 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;;
+3212;PARENTHESIZED HANGUL MIEUM A;So;0;L;<compat> 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;;
+3213;PARENTHESIZED HANGUL PIEUP A;So;0;L;<compat> 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;;
+3214;PARENTHESIZED HANGUL SIOS A;So;0;L;<compat> 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;;
+3215;PARENTHESIZED HANGUL IEUNG A;So;0;L;<compat> 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;;
+3216;PARENTHESIZED HANGUL CIEUC A;So;0;L;<compat> 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;;
+3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L;<compat> 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;;
+3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L;<compat> 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;;
+3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L;<compat> 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;;
+321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L;<compat> 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;;
+321B;PARENTHESIZED HANGUL HIEUH A;So;0;L;<compat> 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;;
+321C;PARENTHESIZED HANGUL CIEUC U;So;0;L;<compat> 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;;
+321D;PARENTHESIZED KOREAN CHARACTER OJEON;So;0;ON;<compat> 0028 110B 1169 110C 1165 11AB 0029;;;;N;;;;;
+321E;PARENTHESIZED KOREAN CHARACTER O HU;So;0;ON;<compat> 0028 110B 1169 1112 116E 0029;;;;N;;;;;
+3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L;<compat> 0028 4E00 0029;;;1;N;;;;;
+3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L;<compat> 0028 4E8C 0029;;;2;N;;;;;
+3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L;<compat> 0028 4E09 0029;;;3;N;;;;;
+3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L;<compat> 0028 56DB 0029;;;4;N;;;;;
+3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L;<compat> 0028 4E94 0029;;;5;N;;;;;
+3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L;<compat> 0028 516D 0029;;;6;N;;;;;
+3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L;<compat> 0028 4E03 0029;;;7;N;;;;;
+3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L;<compat> 0028 516B 0029;;;8;N;;;;;
+3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L;<compat> 0028 4E5D 0029;;;9;N;;;;;
+3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L;<compat> 0028 5341 0029;;;10;N;;;;;
+322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L;<compat> 0028 6708 0029;;;;N;;;;;
+322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L;<compat> 0028 706B 0029;;;;N;;;;;
+322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L;<compat> 0028 6C34 0029;;;;N;;;;;
+322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L;<compat> 0028 6728 0029;;;;N;;;;;
+322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L;<compat> 0028 91D1 0029;;;;N;;;;;
+322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L;<compat> 0028 571F 0029;;;;N;;;;;
+3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L;<compat> 0028 65E5 0029;;;;N;;;;;
+3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L;<compat> 0028 682A 0029;;;;N;;;;;
+3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L;<compat> 0028 6709 0029;;;;N;;;;;
+3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L;<compat> 0028 793E 0029;;;;N;;;;;
+3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L;<compat> 0028 540D 0029;;;;N;;;;;
+3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L;<compat> 0028 7279 0029;;;;N;;;;;
+3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L;<compat> 0028 8CA1 0029;;;;N;;;;;
+3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L;<compat> 0028 795D 0029;;;;N;;;;;
+3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L;<compat> 0028 52B4 0029;;;;N;;;;;
+3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L;<compat> 0028 4EE3 0029;;;;N;;;;;
+323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L;<compat> 0028 547C 0029;;;;N;;;;;
+323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L;<compat> 0028 5B66 0029;;;;N;;;;;
+323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L;<compat> 0028 76E3 0029;;;;N;;;;;
+323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L;<compat> 0028 4F01 0029;;;;N;;;;;
+323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L;<compat> 0028 8CC7 0029;;;;N;;;;;
+323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L;<compat> 0028 5354 0029;;;;N;;;;;
+3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L;<compat> 0028 796D 0029;;;;N;;;;;
+3241;PARENTHESIZED IDEOGRAPH REST;So;0;L;<compat> 0028 4F11 0029;;;;N;;;;;
+3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L;<compat> 0028 81EA 0029;;;;N;;;;;
+3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L;<compat> 0028 81F3 0029;;;;N;;;;;
+3250;PARTNERSHIP SIGN;So;0;ON;<square> 0050 0054 0045;;;;N;;;;;
+3251;CIRCLED NUMBER TWENTY ONE;No;0;ON;<circle> 0032 0031;;;21;N;;;;;
+3252;CIRCLED NUMBER TWENTY TWO;No;0;ON;<circle> 0032 0032;;;22;N;;;;;
+3253;CIRCLED NUMBER TWENTY THREE;No;0;ON;<circle> 0032 0033;;;23;N;;;;;
+3254;CIRCLED NUMBER TWENTY FOUR;No;0;ON;<circle> 0032 0034;;;24;N;;;;;
+3255;CIRCLED NUMBER TWENTY FIVE;No;0;ON;<circle> 0032 0035;;;25;N;;;;;
+3256;CIRCLED NUMBER TWENTY SIX;No;0;ON;<circle> 0032 0036;;;26;N;;;;;
+3257;CIRCLED NUMBER TWENTY SEVEN;No;0;ON;<circle> 0032 0037;;;27;N;;;;;
+3258;CIRCLED NUMBER TWENTY EIGHT;No;0;ON;<circle> 0032 0038;;;28;N;;;;;
+3259;CIRCLED NUMBER TWENTY NINE;No;0;ON;<circle> 0032 0039;;;29;N;;;;;
+325A;CIRCLED NUMBER THIRTY;No;0;ON;<circle> 0033 0030;;;30;N;;;;;
+325B;CIRCLED NUMBER THIRTY ONE;No;0;ON;<circle> 0033 0031;;;31;N;;;;;
+325C;CIRCLED NUMBER THIRTY TWO;No;0;ON;<circle> 0033 0032;;;32;N;;;;;
+325D;CIRCLED NUMBER THIRTY THREE;No;0;ON;<circle> 0033 0033;;;33;N;;;;;
+325E;CIRCLED NUMBER THIRTY FOUR;No;0;ON;<circle> 0033 0034;;;34;N;;;;;
+325F;CIRCLED NUMBER THIRTY FIVE;No;0;ON;<circle> 0033 0035;;;35;N;;;;;
+3260;CIRCLED HANGUL KIYEOK;So;0;L;<circle> 1100;;;;N;CIRCLED HANGUL GIYEOG;;;;
+3261;CIRCLED HANGUL NIEUN;So;0;L;<circle> 1102;;;;N;;;;;
+3262;CIRCLED HANGUL TIKEUT;So;0;L;<circle> 1103;;;;N;CIRCLED HANGUL DIGEUD;;;;
+3263;CIRCLED HANGUL RIEUL;So;0;L;<circle> 1105;;;;N;CIRCLED HANGUL LIEUL;;;;
+3264;CIRCLED HANGUL MIEUM;So;0;L;<circle> 1106;;;;N;;;;;
+3265;CIRCLED HANGUL PIEUP;So;0;L;<circle> 1107;;;;N;CIRCLED HANGUL BIEUB;;;;
+3266;CIRCLED HANGUL SIOS;So;0;L;<circle> 1109;;;;N;;;;;
+3267;CIRCLED HANGUL IEUNG;So;0;L;<circle> 110B;;;;N;;;;;
+3268;CIRCLED HANGUL CIEUC;So;0;L;<circle> 110C;;;;N;CIRCLED HANGUL JIEUJ;;;;
+3269;CIRCLED HANGUL CHIEUCH;So;0;L;<circle> 110E;;;;N;CIRCLED HANGUL CIEUC;;;;
+326A;CIRCLED HANGUL KHIEUKH;So;0;L;<circle> 110F;;;;N;CIRCLED HANGUL KIYEOK;;;;
+326B;CIRCLED HANGUL THIEUTH;So;0;L;<circle> 1110;;;;N;CIRCLED HANGUL TIEUT;;;;
+326C;CIRCLED HANGUL PHIEUPH;So;0;L;<circle> 1111;;;;N;CIRCLED HANGUL PIEUP;;;;
+326D;CIRCLED HANGUL HIEUH;So;0;L;<circle> 1112;;;;N;;;;;
+326E;CIRCLED HANGUL KIYEOK A;So;0;L;<circle> 1100 1161;;;;N;CIRCLED HANGUL GA;;;;
+326F;CIRCLED HANGUL NIEUN A;So;0;L;<circle> 1102 1161;;;;N;CIRCLED HANGUL NA;;;;
+3270;CIRCLED HANGUL TIKEUT A;So;0;L;<circle> 1103 1161;;;;N;CIRCLED HANGUL DA;;;;
+3271;CIRCLED HANGUL RIEUL A;So;0;L;<circle> 1105 1161;;;;N;CIRCLED HANGUL LA;;;;
+3272;CIRCLED HANGUL MIEUM A;So;0;L;<circle> 1106 1161;;;;N;CIRCLED HANGUL MA;;;;
+3273;CIRCLED HANGUL PIEUP A;So;0;L;<circle> 1107 1161;;;;N;CIRCLED HANGUL BA;;;;
+3274;CIRCLED HANGUL SIOS A;So;0;L;<circle> 1109 1161;;;;N;CIRCLED HANGUL SA;;;;
+3275;CIRCLED HANGUL IEUNG A;So;0;L;<circle> 110B 1161;;;;N;CIRCLED HANGUL A;;;;
+3276;CIRCLED HANGUL CIEUC A;So;0;L;<circle> 110C 1161;;;;N;CIRCLED HANGUL JA;;;;
+3277;CIRCLED HANGUL CHIEUCH A;So;0;L;<circle> 110E 1161;;;;N;CIRCLED HANGUL CA;;;;
+3278;CIRCLED HANGUL KHIEUKH A;So;0;L;<circle> 110F 1161;;;;N;CIRCLED HANGUL KA;;;;
+3279;CIRCLED HANGUL THIEUTH A;So;0;L;<circle> 1110 1161;;;;N;CIRCLED HANGUL TA;;;;
+327A;CIRCLED HANGUL PHIEUPH A;So;0;L;<circle> 1111 1161;;;;N;CIRCLED HANGUL PA;;;;
+327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;;
+327C;CIRCLED KOREAN CHARACTER CHAMKO;So;0;ON;<circle> 110E 1161 11B7 1100 1169;;;;N;;;;;
+327D;CIRCLED KOREAN CHARACTER JUEUI;So;0;ON;<circle> 110C 116E 110B 1174;;;;N;;;;;
+327E;CIRCLED HANGUL IEUNG U;So;0;ON;<circle> 110B 116E;;;;N;;;;;
+327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;;
+3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;;
+3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;;
+3282;CIRCLED IDEOGRAPH THREE;No;0;L;<circle> 4E09;;;3;N;;;;;
+3283;CIRCLED IDEOGRAPH FOUR;No;0;L;<circle> 56DB;;;4;N;;;;;
+3284;CIRCLED IDEOGRAPH FIVE;No;0;L;<circle> 4E94;;;5;N;;;;;
+3285;CIRCLED IDEOGRAPH SIX;No;0;L;<circle> 516D;;;6;N;;;;;
+3286;CIRCLED IDEOGRAPH SEVEN;No;0;L;<circle> 4E03;;;7;N;;;;;
+3287;CIRCLED IDEOGRAPH EIGHT;No;0;L;<circle> 516B;;;8;N;;;;;
+3288;CIRCLED IDEOGRAPH NINE;No;0;L;<circle> 4E5D;;;9;N;;;;;
+3289;CIRCLED IDEOGRAPH TEN;No;0;L;<circle> 5341;;;10;N;;;;;
+328A;CIRCLED IDEOGRAPH MOON;So;0;L;<circle> 6708;;;;N;;;;;
+328B;CIRCLED IDEOGRAPH FIRE;So;0;L;<circle> 706B;;;;N;;;;;
+328C;CIRCLED IDEOGRAPH WATER;So;0;L;<circle> 6C34;;;;N;;;;;
+328D;CIRCLED IDEOGRAPH WOOD;So;0;L;<circle> 6728;;;;N;;;;;
+328E;CIRCLED IDEOGRAPH METAL;So;0;L;<circle> 91D1;;;;N;;;;;
+328F;CIRCLED IDEOGRAPH EARTH;So;0;L;<circle> 571F;;;;N;;;;;
+3290;CIRCLED IDEOGRAPH SUN;So;0;L;<circle> 65E5;;;;N;;;;;
+3291;CIRCLED IDEOGRAPH STOCK;So;0;L;<circle> 682A;;;;N;;;;;
+3292;CIRCLED IDEOGRAPH HAVE;So;0;L;<circle> 6709;;;;N;;;;;
+3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L;<circle> 793E;;;;N;;;;;
+3294;CIRCLED IDEOGRAPH NAME;So;0;L;<circle> 540D;;;;N;;;;;
+3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L;<circle> 7279;;;;N;;;;;
+3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L;<circle> 8CA1;;;;N;;;;;
+3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L;<circle> 795D;;;;N;;;;;
+3298;CIRCLED IDEOGRAPH LABOR;So;0;L;<circle> 52B4;;;;N;;;;;
+3299;CIRCLED IDEOGRAPH SECRET;So;0;L;<circle> 79D8;;;;N;;;;;
+329A;CIRCLED IDEOGRAPH MALE;So;0;L;<circle> 7537;;;;N;;;;;
+329B;CIRCLED IDEOGRAPH FEMALE;So;0;L;<circle> 5973;;;;N;;;;;
+329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L;<circle> 9069;;;;N;;;;;
+329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L;<circle> 512A;;;;N;;;;;
+329E;CIRCLED IDEOGRAPH PRINT;So;0;L;<circle> 5370;;;;N;;;;;
+329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L;<circle> 6CE8;;;;N;;;;;
+32A0;CIRCLED IDEOGRAPH ITEM;So;0;L;<circle> 9805;;;;N;;;;;
+32A1;CIRCLED IDEOGRAPH REST;So;0;L;<circle> 4F11;;;;N;;;;;
+32A2;CIRCLED IDEOGRAPH COPY;So;0;L;<circle> 5199;;;;N;;;;;
+32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L;<circle> 6B63;;;;N;;;;;
+32A4;CIRCLED IDEOGRAPH HIGH;So;0;L;<circle> 4E0A;;;;N;;;;;
+32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L;<circle> 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;;
+32A6;CIRCLED IDEOGRAPH LOW;So;0;L;<circle> 4E0B;;;;N;;;;;
+32A7;CIRCLED IDEOGRAPH LEFT;So;0;L;<circle> 5DE6;;;;N;;;;;
+32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L;<circle> 53F3;;;;N;;;;;
+32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L;<circle> 533B;;;;N;;;;;
+32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L;<circle> 5B97;;;;N;;;;;
+32AB;CIRCLED IDEOGRAPH STUDY;So;0;L;<circle> 5B66;;;;N;;;;;
+32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L;<circle> 76E3;;;;N;;;;;
+32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L;<circle> 4F01;;;;N;;;;;
+32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L;<circle> 8CC7;;;;N;;;;;
+32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L;<circle> 5354;;;;N;;;;;
+32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L;<circle> 591C;;;;N;;;;;
+32B1;CIRCLED NUMBER THIRTY SIX;No;0;ON;<circle> 0033 0036;;;36;N;;;;;
+32B2;CIRCLED NUMBER THIRTY SEVEN;No;0;ON;<circle> 0033 0037;;;37;N;;;;;
+32B3;CIRCLED NUMBER THIRTY EIGHT;No;0;ON;<circle> 0033 0038;;;38;N;;;;;
+32B4;CIRCLED NUMBER THIRTY NINE;No;0;ON;<circle> 0033 0039;;;39;N;;;;;
+32B5;CIRCLED NUMBER FORTY;No;0;ON;<circle> 0034 0030;;;40;N;;;;;
+32B6;CIRCLED NUMBER FORTY ONE;No;0;ON;<circle> 0034 0031;;;41;N;;;;;
+32B7;CIRCLED NUMBER FORTY TWO;No;0;ON;<circle> 0034 0032;;;42;N;;;;;
+32B8;CIRCLED NUMBER FORTY THREE;No;0;ON;<circle> 0034 0033;;;43;N;;;;;
+32B9;CIRCLED NUMBER FORTY FOUR;No;0;ON;<circle> 0034 0034;;;44;N;;;;;
+32BA;CIRCLED NUMBER FORTY FIVE;No;0;ON;<circle> 0034 0035;;;45;N;;;;;
+32BB;CIRCLED NUMBER FORTY SIX;No;0;ON;<circle> 0034 0036;;;46;N;;;;;
+32BC;CIRCLED NUMBER FORTY SEVEN;No;0;ON;<circle> 0034 0037;;;47;N;;;;;
+32BD;CIRCLED NUMBER FORTY EIGHT;No;0;ON;<circle> 0034 0038;;;48;N;;;;;
+32BE;CIRCLED NUMBER FORTY NINE;No;0;ON;<circle> 0034 0039;;;49;N;;;;;
+32BF;CIRCLED NUMBER FIFTY;No;0;ON;<circle> 0035 0030;;;50;N;;;;;
+32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L;<compat> 0031 6708;;;;N;;;;;
+32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L;<compat> 0032 6708;;;;N;;;;;
+32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L;<compat> 0033 6708;;;;N;;;;;
+32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L;<compat> 0034 6708;;;;N;;;;;
+32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L;<compat> 0035 6708;;;;N;;;;;
+32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L;<compat> 0036 6708;;;;N;;;;;
+32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L;<compat> 0037 6708;;;;N;;;;;
+32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L;<compat> 0038 6708;;;;N;;;;;
+32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L;<compat> 0039 6708;;;;N;;;;;
+32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L;<compat> 0031 0030 6708;;;;N;;;;;
+32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L;<compat> 0031 0031 6708;;;;N;;;;;
+32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L;<compat> 0031 0032 6708;;;;N;;;;;
+32CC;SQUARE HG;So;0;ON;<square> 0048 0067;;;;N;;;;;
+32CD;SQUARE ERG;So;0;ON;<square> 0065 0072 0067;;;;N;;;;;
+32CE;SQUARE EV;So;0;ON;<square> 0065 0056;;;;N;;;;;
+32CF;LIMITED LIABILITY SIGN;So;0;ON;<square> 004C 0054 0044;;;;N;;;;;
+32D0;CIRCLED KATAKANA A;So;0;L;<circle> 30A2;;;;N;;;;;
+32D1;CIRCLED KATAKANA I;So;0;L;<circle> 30A4;;;;N;;;;;
+32D2;CIRCLED KATAKANA U;So;0;L;<circle> 30A6;;;;N;;;;;
+32D3;CIRCLED KATAKANA E;So;0;L;<circle> 30A8;;;;N;;;;;
+32D4;CIRCLED KATAKANA O;So;0;L;<circle> 30AA;;;;N;;;;;
+32D5;CIRCLED KATAKANA KA;So;0;L;<circle> 30AB;;;;N;;;;;
+32D6;CIRCLED KATAKANA KI;So;0;L;<circle> 30AD;;;;N;;;;;
+32D7;CIRCLED KATAKANA KU;So;0;L;<circle> 30AF;;;;N;;;;;
+32D8;CIRCLED KATAKANA KE;So;0;L;<circle> 30B1;;;;N;;;;;
+32D9;CIRCLED KATAKANA KO;So;0;L;<circle> 30B3;;;;N;;;;;
+32DA;CIRCLED KATAKANA SA;So;0;L;<circle> 30B5;;;;N;;;;;
+32DB;CIRCLED KATAKANA SI;So;0;L;<circle> 30B7;;;;N;;;;;
+32DC;CIRCLED KATAKANA SU;So;0;L;<circle> 30B9;;;;N;;;;;
+32DD;CIRCLED KATAKANA SE;So;0;L;<circle> 30BB;;;;N;;;;;
+32DE;CIRCLED KATAKANA SO;So;0;L;<circle> 30BD;;;;N;;;;;
+32DF;CIRCLED KATAKANA TA;So;0;L;<circle> 30BF;;;;N;;;;;
+32E0;CIRCLED KATAKANA TI;So;0;L;<circle> 30C1;;;;N;;;;;
+32E1;CIRCLED KATAKANA TU;So;0;L;<circle> 30C4;;;;N;;;;;
+32E2;CIRCLED KATAKANA TE;So;0;L;<circle> 30C6;;;;N;;;;;
+32E3;CIRCLED KATAKANA TO;So;0;L;<circle> 30C8;;;;N;;;;;
+32E4;CIRCLED KATAKANA NA;So;0;L;<circle> 30CA;;;;N;;;;;
+32E5;CIRCLED KATAKANA NI;So;0;L;<circle> 30CB;;;;N;;;;;
+32E6;CIRCLED KATAKANA NU;So;0;L;<circle> 30CC;;;;N;;;;;
+32E7;CIRCLED KATAKANA NE;So;0;L;<circle> 30CD;;;;N;;;;;
+32E8;CIRCLED KATAKANA NO;So;0;L;<circle> 30CE;;;;N;;;;;
+32E9;CIRCLED KATAKANA HA;So;0;L;<circle> 30CF;;;;N;;;;;
+32EA;CIRCLED KATAKANA HI;So;0;L;<circle> 30D2;;;;N;;;;;
+32EB;CIRCLED KATAKANA HU;So;0;L;<circle> 30D5;;;;N;;;;;
+32EC;CIRCLED KATAKANA HE;So;0;L;<circle> 30D8;;;;N;;;;;
+32ED;CIRCLED KATAKANA HO;So;0;L;<circle> 30DB;;;;N;;;;;
+32EE;CIRCLED KATAKANA MA;So;0;L;<circle> 30DE;;;;N;;;;;
+32EF;CIRCLED KATAKANA MI;So;0;L;<circle> 30DF;;;;N;;;;;
+32F0;CIRCLED KATAKANA MU;So;0;L;<circle> 30E0;;;;N;;;;;
+32F1;CIRCLED KATAKANA ME;So;0;L;<circle> 30E1;;;;N;;;;;
+32F2;CIRCLED KATAKANA MO;So;0;L;<circle> 30E2;;;;N;;;;;
+32F3;CIRCLED KATAKANA YA;So;0;L;<circle> 30E4;;;;N;;;;;
+32F4;CIRCLED KATAKANA YU;So;0;L;<circle> 30E6;;;;N;;;;;
+32F5;CIRCLED KATAKANA YO;So;0;L;<circle> 30E8;;;;N;;;;;
+32F6;CIRCLED KATAKANA RA;So;0;L;<circle> 30E9;;;;N;;;;;
+32F7;CIRCLED KATAKANA RI;So;0;L;<circle> 30EA;;;;N;;;;;
+32F8;CIRCLED KATAKANA RU;So;0;L;<circle> 30EB;;;;N;;;;;
+32F9;CIRCLED KATAKANA RE;So;0;L;<circle> 30EC;;;;N;;;;;
+32FA;CIRCLED KATAKANA RO;So;0;L;<circle> 30ED;;;;N;;;;;
+32FB;CIRCLED KATAKANA WA;So;0;L;<circle> 30EF;;;;N;;;;;
+32FC;CIRCLED KATAKANA WI;So;0;L;<circle> 30F0;;;;N;;;;;
+32FD;CIRCLED KATAKANA WE;So;0;L;<circle> 30F1;;;;N;;;;;
+32FE;CIRCLED KATAKANA WO;So;0;L;<circle> 30F2;;;;N;;;;;
+3300;SQUARE APAATO;So;0;L;<square> 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;;
+3301;SQUARE ARUHUA;So;0;L;<square> 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;;
+3302;SQUARE ANPEA;So;0;L;<square> 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;;
+3303;SQUARE AARU;So;0;L;<square> 30A2 30FC 30EB;;;;N;SQUARED AARU;;;;
+3304;SQUARE ININGU;So;0;L;<square> 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;;
+3305;SQUARE INTI;So;0;L;<square> 30A4 30F3 30C1;;;;N;SQUARED INTI;;;;
+3306;SQUARE UON;So;0;L;<square> 30A6 30A9 30F3;;;;N;SQUARED UON;;;;
+3307;SQUARE ESUKUUDO;So;0;L;<square> 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;;
+3308;SQUARE EEKAA;So;0;L;<square> 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;;
+3309;SQUARE ONSU;So;0;L;<square> 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;;
+330A;SQUARE OOMU;So;0;L;<square> 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;;
+330B;SQUARE KAIRI;So;0;L;<square> 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;;
+330C;SQUARE KARATTO;So;0;L;<square> 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;;
+330D;SQUARE KARORII;So;0;L;<square> 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;;
+330E;SQUARE GARON;So;0;L;<square> 30AC 30ED 30F3;;;;N;SQUARED GARON;;;;
+330F;SQUARE GANMA;So;0;L;<square> 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;;
+3310;SQUARE GIGA;So;0;L;<square> 30AE 30AC;;;;N;SQUARED GIGA;;;;
+3311;SQUARE GINII;So;0;L;<square> 30AE 30CB 30FC;;;;N;SQUARED GINII;;;;
+3312;SQUARE KYURII;So;0;L;<square> 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;;
+3313;SQUARE GIRUDAA;So;0;L;<square> 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;;
+3314;SQUARE KIRO;So;0;L;<square> 30AD 30ED;;;;N;SQUARED KIRO;;;;
+3315;SQUARE KIROGURAMU;So;0;L;<square> 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;;
+3316;SQUARE KIROMEETORU;So;0;L;<square> 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;;
+3317;SQUARE KIROWATTO;So;0;L;<square> 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;;
+3318;SQUARE GURAMU;So;0;L;<square> 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;;
+3319;SQUARE GURAMUTON;So;0;L;<square> 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;;
+331A;SQUARE KURUZEIRO;So;0;L;<square> 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;;
+331B;SQUARE KUROONE;So;0;L;<square> 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;;
+331C;SQUARE KEESU;So;0;L;<square> 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;;
+331D;SQUARE KORUNA;So;0;L;<square> 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;;
+331E;SQUARE KOOPO;So;0;L;<square> 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;;
+331F;SQUARE SAIKURU;So;0;L;<square> 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;;
+3320;SQUARE SANTIIMU;So;0;L;<square> 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;;
+3321;SQUARE SIRINGU;So;0;L;<square> 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;;
+3322;SQUARE SENTI;So;0;L;<square> 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;;
+3323;SQUARE SENTO;So;0;L;<square> 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;;
+3324;SQUARE DAASU;So;0;L;<square> 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;;
+3325;SQUARE DESI;So;0;L;<square> 30C7 30B7;;;;N;SQUARED DESI;;;;
+3326;SQUARE DORU;So;0;L;<square> 30C9 30EB;;;;N;SQUARED DORU;;;;
+3327;SQUARE TON;So;0;L;<square> 30C8 30F3;;;;N;SQUARED TON;;;;
+3328;SQUARE NANO;So;0;L;<square> 30CA 30CE;;;;N;SQUARED NANO;;;;
+3329;SQUARE NOTTO;So;0;L;<square> 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;;
+332A;SQUARE HAITU;So;0;L;<square> 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;;
+332B;SQUARE PAASENTO;So;0;L;<square> 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;;
+332C;SQUARE PAATU;So;0;L;<square> 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;;
+332D;SQUARE BAARERU;So;0;L;<square> 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;;
+332E;SQUARE PIASUTORU;So;0;L;<square> 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;;
+332F;SQUARE PIKURU;So;0;L;<square> 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;;
+3330;SQUARE PIKO;So;0;L;<square> 30D4 30B3;;;;N;SQUARED PIKO;;;;
+3331;SQUARE BIRU;So;0;L;<square> 30D3 30EB;;;;N;SQUARED BIRU;;;;
+3332;SQUARE HUARADDO;So;0;L;<square> 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;;
+3333;SQUARE HUIITO;So;0;L;<square> 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;;
+3334;SQUARE BUSSYERU;So;0;L;<square> 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;;
+3335;SQUARE HURAN;So;0;L;<square> 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;;
+3336;SQUARE HEKUTAARU;So;0;L;<square> 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;;
+3337;SQUARE PESO;So;0;L;<square> 30DA 30BD;;;;N;SQUARED PESO;;;;
+3338;SQUARE PENIHI;So;0;L;<square> 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;;
+3339;SQUARE HERUTU;So;0;L;<square> 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;;
+333A;SQUARE PENSU;So;0;L;<square> 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;;
+333B;SQUARE PEEZI;So;0;L;<square> 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;;
+333C;SQUARE BEETA;So;0;L;<square> 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;;
+333D;SQUARE POINTO;So;0;L;<square> 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;;
+333E;SQUARE BORUTO;So;0;L;<square> 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;;
+333F;SQUARE HON;So;0;L;<square> 30DB 30F3;;;;N;SQUARED HON;;;;
+3340;SQUARE PONDO;So;0;L;<square> 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;;
+3341;SQUARE HOORU;So;0;L;<square> 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;;
+3342;SQUARE HOON;So;0;L;<square> 30DB 30FC 30F3;;;;N;SQUARED HOON;;;;
+3343;SQUARE MAIKURO;So;0;L;<square> 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;;
+3344;SQUARE MAIRU;So;0;L;<square> 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;;
+3345;SQUARE MAHHA;So;0;L;<square> 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;;
+3346;SQUARE MARUKU;So;0;L;<square> 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;;
+3347;SQUARE MANSYON;So;0;L;<square> 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;;
+3348;SQUARE MIKURON;So;0;L;<square> 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;;
+3349;SQUARE MIRI;So;0;L;<square> 30DF 30EA;;;;N;SQUARED MIRI;;;;
+334A;SQUARE MIRIBAARU;So;0;L;<square> 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;;
+334B;SQUARE MEGA;So;0;L;<square> 30E1 30AC;;;;N;SQUARED MEGA;;;;
+334C;SQUARE MEGATON;So;0;L;<square> 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;;
+334D;SQUARE MEETORU;So;0;L;<square> 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;;
+334E;SQUARE YAADO;So;0;L;<square> 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;;
+334F;SQUARE YAARU;So;0;L;<square> 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;;
+3350;SQUARE YUAN;So;0;L;<square> 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;;
+3351;SQUARE RITTORU;So;0;L;<square> 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;;
+3352;SQUARE RIRA;So;0;L;<square> 30EA 30E9;;;;N;SQUARED RIRA;;;;
+3353;SQUARE RUPII;So;0;L;<square> 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;;
+3354;SQUARE RUUBURU;So;0;L;<square> 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;;
+3355;SQUARE REMU;So;0;L;<square> 30EC 30E0;;;;N;SQUARED REMU;;;;
+3356;SQUARE RENTOGEN;So;0;L;<square> 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;;
+3357;SQUARE WATTO;So;0;L;<square> 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;;
+3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L;<compat> 0030 70B9;;;;N;;;;;
+3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L;<compat> 0031 70B9;;;;N;;;;;
+335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L;<compat> 0032 70B9;;;;N;;;;;
+335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L;<compat> 0033 70B9;;;;N;;;;;
+335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L;<compat> 0034 70B9;;;;N;;;;;
+335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L;<compat> 0035 70B9;;;;N;;;;;
+335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L;<compat> 0036 70B9;;;;N;;;;;
+335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L;<compat> 0037 70B9;;;;N;;;;;
+3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L;<compat> 0038 70B9;;;;N;;;;;
+3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L;<compat> 0039 70B9;;;;N;;;;;
+3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L;<compat> 0031 0030 70B9;;;;N;;;;;
+3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L;<compat> 0031 0031 70B9;;;;N;;;;;
+3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L;<compat> 0031 0032 70B9;;;;N;;;;;
+3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L;<compat> 0031 0033 70B9;;;;N;;;;;
+3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L;<compat> 0031 0034 70B9;;;;N;;;;;
+3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L;<compat> 0031 0035 70B9;;;;N;;;;;
+3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L;<compat> 0031 0036 70B9;;;;N;;;;;
+3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L;<compat> 0031 0037 70B9;;;;N;;;;;
+336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L;<compat> 0031 0038 70B9;;;;N;;;;;
+336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L;<compat> 0031 0039 70B9;;;;N;;;;;
+336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L;<compat> 0032 0030 70B9;;;;N;;;;;
+336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L;<compat> 0032 0031 70B9;;;;N;;;;;
+336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L;<compat> 0032 0032 70B9;;;;N;;;;;
+336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L;<compat> 0032 0033 70B9;;;;N;;;;;
+3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L;<compat> 0032 0034 70B9;;;;N;;;;;
+3371;SQUARE HPA;So;0;L;<square> 0068 0050 0061;;;;N;;;;;
+3372;SQUARE DA;So;0;L;<square> 0064 0061;;;;N;;;;;
+3373;SQUARE AU;So;0;L;<square> 0041 0055;;;;N;;;;;
+3374;SQUARE BAR;So;0;L;<square> 0062 0061 0072;;;;N;;;;;
+3375;SQUARE OV;So;0;L;<square> 006F 0056;;;;N;;;;;
+3376;SQUARE PC;So;0;L;<square> 0070 0063;;;;N;;;;;
+3377;SQUARE DM;So;0;ON;<square> 0064 006D;;;;N;;;;;
+3378;SQUARE DM SQUARED;So;0;ON;<square> 0064 006D 00B2;;;;N;;;;;
+3379;SQUARE DM CUBED;So;0;ON;<square> 0064 006D 00B3;;;;N;;;;;
+337A;SQUARE IU;So;0;ON;<square> 0049 0055;;;;N;;;;;
+337B;SQUARE ERA NAME HEISEI;So;0;L;<square> 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;;
+337C;SQUARE ERA NAME SYOUWA;So;0;L;<square> 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;;
+337D;SQUARE ERA NAME TAISYOU;So;0;L;<square> 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;;
+337E;SQUARE ERA NAME MEIZI;So;0;L;<square> 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;;
+337F;SQUARE CORPORATION;So;0;L;<square> 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;;
+3380;SQUARE PA AMPS;So;0;L;<square> 0070 0041;;;;N;SQUARED PA AMPS;;;;
+3381;SQUARE NA;So;0;L;<square> 006E 0041;;;;N;SQUARED NA;;;;
+3382;SQUARE MU A;So;0;L;<square> 03BC 0041;;;;N;SQUARED MU A;;;;
+3383;SQUARE MA;So;0;L;<square> 006D 0041;;;;N;SQUARED MA;;;;
+3384;SQUARE KA;So;0;L;<square> 006B 0041;;;;N;SQUARED KA;;;;
+3385;SQUARE KB;So;0;L;<square> 004B 0042;;;;N;SQUARED KB;;;;
+3386;SQUARE MB;So;0;L;<square> 004D 0042;;;;N;SQUARED MB;;;;
+3387;SQUARE GB;So;0;L;<square> 0047 0042;;;;N;SQUARED GB;;;;
+3388;SQUARE CAL;So;0;L;<square> 0063 0061 006C;;;;N;SQUARED CAL;;;;
+3389;SQUARE KCAL;So;0;L;<square> 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;;
+338A;SQUARE PF;So;0;L;<square> 0070 0046;;;;N;SQUARED PF;;;;
+338B;SQUARE NF;So;0;L;<square> 006E 0046;;;;N;SQUARED NF;;;;
+338C;SQUARE MU F;So;0;L;<square> 03BC 0046;;;;N;SQUARED MU F;;;;
+338D;SQUARE MU G;So;0;L;<square> 03BC 0067;;;;N;SQUARED MU G;;;;
+338E;SQUARE MG;So;0;L;<square> 006D 0067;;;;N;SQUARED MG;;;;
+338F;SQUARE KG;So;0;L;<square> 006B 0067;;;;N;SQUARED KG;;;;
+3390;SQUARE HZ;So;0;L;<square> 0048 007A;;;;N;SQUARED HZ;;;;
+3391;SQUARE KHZ;So;0;L;<square> 006B 0048 007A;;;;N;SQUARED KHZ;;;;
+3392;SQUARE MHZ;So;0;L;<square> 004D 0048 007A;;;;N;SQUARED MHZ;;;;
+3393;SQUARE GHZ;So;0;L;<square> 0047 0048 007A;;;;N;SQUARED GHZ;;;;
+3394;SQUARE THZ;So;0;L;<square> 0054 0048 007A;;;;N;SQUARED THZ;;;;
+3395;SQUARE MU L;So;0;L;<square> 03BC 2113;;;;N;SQUARED MU L;;;;
+3396;SQUARE ML;So;0;L;<square> 006D 2113;;;;N;SQUARED ML;;;;
+3397;SQUARE DL;So;0;L;<square> 0064 2113;;;;N;SQUARED DL;;;;
+3398;SQUARE KL;So;0;L;<square> 006B 2113;;;;N;SQUARED KL;;;;
+3399;SQUARE FM;So;0;L;<square> 0066 006D;;;;N;SQUARED FM;;;;
+339A;SQUARE NM;So;0;L;<square> 006E 006D;;;;N;SQUARED NM;;;;
+339B;SQUARE MU M;So;0;L;<square> 03BC 006D;;;;N;SQUARED MU M;;;;
+339C;SQUARE MM;So;0;L;<square> 006D 006D;;;;N;SQUARED MM;;;;
+339D;SQUARE CM;So;0;L;<square> 0063 006D;;;;N;SQUARED CM;;;;
+339E;SQUARE KM;So;0;L;<square> 006B 006D;;;;N;SQUARED KM;;;;
+339F;SQUARE MM SQUARED;So;0;L;<square> 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;;
+33A0;SQUARE CM SQUARED;So;0;L;<square> 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;;
+33A1;SQUARE M SQUARED;So;0;L;<square> 006D 00B2;;;;N;SQUARED M SQUARED;;;;
+33A2;SQUARE KM SQUARED;So;0;L;<square> 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;;
+33A3;SQUARE MM CUBED;So;0;L;<square> 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;;
+33A4;SQUARE CM CUBED;So;0;L;<square> 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;;
+33A5;SQUARE M CUBED;So;0;L;<square> 006D 00B3;;;;N;SQUARED M CUBED;;;;
+33A6;SQUARE KM CUBED;So;0;L;<square> 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;;
+33A7;SQUARE M OVER S;So;0;L;<square> 006D 2215 0073;;;;N;SQUARED M OVER S;;;;
+33A8;SQUARE M OVER S SQUARED;So;0;L;<square> 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;;
+33A9;SQUARE PA;So;0;L;<square> 0050 0061;;;;N;SQUARED PA;;;;
+33AA;SQUARE KPA;So;0;L;<square> 006B 0050 0061;;;;N;SQUARED KPA;;;;
+33AB;SQUARE MPA;So;0;L;<square> 004D 0050 0061;;;;N;SQUARED MPA;;;;
+33AC;SQUARE GPA;So;0;L;<square> 0047 0050 0061;;;;N;SQUARED GPA;;;;
+33AD;SQUARE RAD;So;0;L;<square> 0072 0061 0064;;;;N;SQUARED RAD;;;;
+33AE;SQUARE RAD OVER S;So;0;L;<square> 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;;
+33AF;SQUARE RAD OVER S SQUARED;So;0;L;<square> 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;;
+33B0;SQUARE PS;So;0;L;<square> 0070 0073;;;;N;SQUARED PS;;;;
+33B1;SQUARE NS;So;0;L;<square> 006E 0073;;;;N;SQUARED NS;;;;
+33B2;SQUARE MU S;So;0;L;<square> 03BC 0073;;;;N;SQUARED MU S;;;;
+33B3;SQUARE MS;So;0;L;<square> 006D 0073;;;;N;SQUARED MS;;;;
+33B4;SQUARE PV;So;0;L;<square> 0070 0056;;;;N;SQUARED PV;;;;
+33B5;SQUARE NV;So;0;L;<square> 006E 0056;;;;N;SQUARED NV;;;;
+33B6;SQUARE MU V;So;0;L;<square> 03BC 0056;;;;N;SQUARED MU V;;;;
+33B7;SQUARE MV;So;0;L;<square> 006D 0056;;;;N;SQUARED MV;;;;
+33B8;SQUARE KV;So;0;L;<square> 006B 0056;;;;N;SQUARED KV;;;;
+33B9;SQUARE MV MEGA;So;0;L;<square> 004D 0056;;;;N;SQUARED MV MEGA;;;;
+33BA;SQUARE PW;So;0;L;<square> 0070 0057;;;;N;SQUARED PW;;;;
+33BB;SQUARE NW;So;0;L;<square> 006E 0057;;;;N;SQUARED NW;;;;
+33BC;SQUARE MU W;So;0;L;<square> 03BC 0057;;;;N;SQUARED MU W;;;;
+33BD;SQUARE MW;So;0;L;<square> 006D 0057;;;;N;SQUARED MW;;;;
+33BE;SQUARE KW;So;0;L;<square> 006B 0057;;;;N;SQUARED KW;;;;
+33BF;SQUARE MW MEGA;So;0;L;<square> 004D 0057;;;;N;SQUARED MW MEGA;;;;
+33C0;SQUARE K OHM;So;0;L;<square> 006B 03A9;;;;N;SQUARED K OHM;;;;
+33C1;SQUARE M OHM;So;0;L;<square> 004D 03A9;;;;N;SQUARED M OHM;;;;
+33C2;SQUARE AM;So;0;L;<square> 0061 002E 006D 002E;;;;N;SQUARED AM;;;;
+33C3;SQUARE BQ;So;0;L;<square> 0042 0071;;;;N;SQUARED BQ;;;;
+33C4;SQUARE CC;So;0;L;<square> 0063 0063;;;;N;SQUARED CC;;;;
+33C5;SQUARE CD;So;0;L;<square> 0063 0064;;;;N;SQUARED CD;;;;
+33C6;SQUARE C OVER KG;So;0;L;<square> 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;;
+33C7;SQUARE CO;So;0;L;<square> 0043 006F 002E;;;;N;SQUARED CO;;;;
+33C8;SQUARE DB;So;0;L;<square> 0064 0042;;;;N;SQUARED DB;;;;
+33C9;SQUARE GY;So;0;L;<square> 0047 0079;;;;N;SQUARED GY;;;;
+33CA;SQUARE HA;So;0;L;<square> 0068 0061;;;;N;SQUARED HA;;;;
+33CB;SQUARE HP;So;0;L;<square> 0048 0050;;;;N;SQUARED HP;;;;
+33CC;SQUARE IN;So;0;L;<square> 0069 006E;;;;N;SQUARED IN;;;;
+33CD;SQUARE KK;So;0;L;<square> 004B 004B;;;;N;SQUARED KK;;;;
+33CE;SQUARE KM CAPITAL;So;0;L;<square> 004B 004D;;;;N;SQUARED KM CAPITAL;;;;
+33CF;SQUARE KT;So;0;L;<square> 006B 0074;;;;N;SQUARED KT;;;;
+33D0;SQUARE LM;So;0;L;<square> 006C 006D;;;;N;SQUARED LM;;;;
+33D1;SQUARE LN;So;0;L;<square> 006C 006E;;;;N;SQUARED LN;;;;
+33D2;SQUARE LOG;So;0;L;<square> 006C 006F 0067;;;;N;SQUARED LOG;;;;
+33D3;SQUARE LX;So;0;L;<square> 006C 0078;;;;N;SQUARED LX;;;;
+33D4;SQUARE MB SMALL;So;0;L;<square> 006D 0062;;;;N;SQUARED MB SMALL;;;;
+33D5;SQUARE MIL;So;0;L;<square> 006D 0069 006C;;;;N;SQUARED MIL;;;;
+33D6;SQUARE MOL;So;0;L;<square> 006D 006F 006C;;;;N;SQUARED MOL;;;;
+33D7;SQUARE PH;So;0;L;<square> 0050 0048;;;;N;SQUARED PH;;;;
+33D8;SQUARE PM;So;0;L;<square> 0070 002E 006D 002E;;;;N;SQUARED PM;;;;
+33D9;SQUARE PPM;So;0;L;<square> 0050 0050 004D;;;;N;SQUARED PPM;;;;
+33DA;SQUARE PR;So;0;L;<square> 0050 0052;;;;N;SQUARED PR;;;;
+33DB;SQUARE SR;So;0;L;<square> 0073 0072;;;;N;SQUARED SR;;;;
+33DC;SQUARE SV;So;0;L;<square> 0053 0076;;;;N;SQUARED SV;;;;
+33DD;SQUARE WB;So;0;L;<square> 0057 0062;;;;N;SQUARED WB;;;;
+33DE;SQUARE V OVER M;So;0;ON;<square> 0056 2215 006D;;;;N;;;;;
+33DF;SQUARE A OVER M;So;0;ON;<square> 0041 2215 006D;;;;N;;;;;
+33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L;<compat> 0031 65E5;;;;N;;;;;
+33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L;<compat> 0032 65E5;;;;N;;;;;
+33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L;<compat> 0033 65E5;;;;N;;;;;
+33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L;<compat> 0034 65E5;;;;N;;;;;
+33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L;<compat> 0035 65E5;;;;N;;;;;
+33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L;<compat> 0036 65E5;;;;N;;;;;
+33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L;<compat> 0037 65E5;;;;N;;;;;
+33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L;<compat> 0038 65E5;;;;N;;;;;
+33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L;<compat> 0039 65E5;;;;N;;;;;
+33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L;<compat> 0031 0030 65E5;;;;N;;;;;
+33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L;<compat> 0031 0031 65E5;;;;N;;;;;
+33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L;<compat> 0031 0032 65E5;;;;N;;;;;
+33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L;<compat> 0031 0033 65E5;;;;N;;;;;
+33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L;<compat> 0031 0034 65E5;;;;N;;;;;
+33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L;<compat> 0031 0035 65E5;;;;N;;;;;
+33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L;<compat> 0031 0036 65E5;;;;N;;;;;
+33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L;<compat> 0031 0037 65E5;;;;N;;;;;
+33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L;<compat> 0031 0038 65E5;;;;N;;;;;
+33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L;<compat> 0031 0039 65E5;;;;N;;;;;
+33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L;<compat> 0032 0030 65E5;;;;N;;;;;
+33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L;<compat> 0032 0031 65E5;;;;N;;;;;
+33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L;<compat> 0032 0032 65E5;;;;N;;;;;
+33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L;<compat> 0032 0033 65E5;;;;N;;;;;
+33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L;<compat> 0032 0034 65E5;;;;N;;;;;
+33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L;<compat> 0032 0035 65E5;;;;N;;;;;
+33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L;<compat> 0032 0036 65E5;;;;N;;;;;
+33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L;<compat> 0032 0037 65E5;;;;N;;;;;
+33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L;<compat> 0032 0038 65E5;;;;N;;;;;
+33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L;<compat> 0032 0039 65E5;;;;N;;;;;
+33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L;<compat> 0033 0030 65E5;;;;N;;;;;
+33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;;
+33FF;SQUARE GAL;So;0;ON;<square> 0067 0061 006C;;;;N;;;;;
+3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+4DC0;HEXAGRAM FOR THE CREATIVE HEAVEN;So;0;ON;;;;;N;;;;;
+4DC1;HEXAGRAM FOR THE RECEPTIVE EARTH;So;0;ON;;;;;N;;;;;
+4DC2;HEXAGRAM FOR DIFFICULTY AT THE BEGINNING;So;0;ON;;;;;N;;;;;
+4DC3;HEXAGRAM FOR YOUTHFUL FOLLY;So;0;ON;;;;;N;;;;;
+4DC4;HEXAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;
+4DC5;HEXAGRAM FOR CONFLICT;So;0;ON;;;;;N;;;;;
+4DC6;HEXAGRAM FOR THE ARMY;So;0;ON;;;;;N;;;;;
+4DC7;HEXAGRAM FOR HOLDING TOGETHER;So;0;ON;;;;;N;;;;;
+4DC8;HEXAGRAM FOR SMALL TAMING;So;0;ON;;;;;N;;;;;
+4DC9;HEXAGRAM FOR TREADING;So;0;ON;;;;;N;;;;;
+4DCA;HEXAGRAM FOR PEACE;So;0;ON;;;;;N;;;;;
+4DCB;HEXAGRAM FOR STANDSTILL;So;0;ON;;;;;N;;;;;
+4DCC;HEXAGRAM FOR FELLOWSHIP;So;0;ON;;;;;N;;;;;
+4DCD;HEXAGRAM FOR GREAT POSSESSION;So;0;ON;;;;;N;;;;;
+4DCE;HEXAGRAM FOR MODESTY;So;0;ON;;;;;N;;;;;
+4DCF;HEXAGRAM FOR ENTHUSIASM;So;0;ON;;;;;N;;;;;
+4DD0;HEXAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;
+4DD1;HEXAGRAM FOR WORK ON THE DECAYED;So;0;ON;;;;;N;;;;;
+4DD2;HEXAGRAM FOR APPROACH;So;0;ON;;;;;N;;;;;
+4DD3;HEXAGRAM FOR CONTEMPLATION;So;0;ON;;;;;N;;;;;
+4DD4;HEXAGRAM FOR BITING THROUGH;So;0;ON;;;;;N;;;;;
+4DD5;HEXAGRAM FOR GRACE;So;0;ON;;;;;N;;;;;
+4DD6;HEXAGRAM FOR SPLITTING APART;So;0;ON;;;;;N;;;;;
+4DD7;HEXAGRAM FOR RETURN;So;0;ON;;;;;N;;;;;
+4DD8;HEXAGRAM FOR INNOCENCE;So;0;ON;;;;;N;;;;;
+4DD9;HEXAGRAM FOR GREAT TAMING;So;0;ON;;;;;N;;;;;
+4DDA;HEXAGRAM FOR MOUTH CORNERS;So;0;ON;;;;;N;;;;;
+4DDB;HEXAGRAM FOR GREAT PREPONDERANCE;So;0;ON;;;;;N;;;;;
+4DDC;HEXAGRAM FOR THE ABYSMAL WATER;So;0;ON;;;;;N;;;;;
+4DDD;HEXAGRAM FOR THE CLINGING FIRE;So;0;ON;;;;;N;;;;;
+4DDE;HEXAGRAM FOR INFLUENCE;So;0;ON;;;;;N;;;;;
+4DDF;HEXAGRAM FOR DURATION;So;0;ON;;;;;N;;;;;
+4DE0;HEXAGRAM FOR RETREAT;So;0;ON;;;;;N;;;;;
+4DE1;HEXAGRAM FOR GREAT POWER;So;0;ON;;;;;N;;;;;
+4DE2;HEXAGRAM FOR PROGRESS;So;0;ON;;;;;N;;;;;
+4DE3;HEXAGRAM FOR DARKENING OF THE LIGHT;So;0;ON;;;;;N;;;;;
+4DE4;HEXAGRAM FOR THE FAMILY;So;0;ON;;;;;N;;;;;
+4DE5;HEXAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;
+4DE6;HEXAGRAM FOR OBSTRUCTION;So;0;ON;;;;;N;;;;;
+4DE7;HEXAGRAM FOR DELIVERANCE;So;0;ON;;;;;N;;;;;
+4DE8;HEXAGRAM FOR DECREASE;So;0;ON;;;;;N;;;;;
+4DE9;HEXAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;
+4DEA;HEXAGRAM FOR BREAKTHROUGH;So;0;ON;;;;;N;;;;;
+4DEB;HEXAGRAM FOR COMING TO MEET;So;0;ON;;;;;N;;;;;
+4DEC;HEXAGRAM FOR GATHERING TOGETHER;So;0;ON;;;;;N;;;;;
+4DED;HEXAGRAM FOR PUSHING UPWARD;So;0;ON;;;;;N;;;;;
+4DEE;HEXAGRAM FOR OPPRESSION;So;0;ON;;;;;N;;;;;
+4DEF;HEXAGRAM FOR THE WELL;So;0;ON;;;;;N;;;;;
+4DF0;HEXAGRAM FOR REVOLUTION;So;0;ON;;;;;N;;;;;
+4DF1;HEXAGRAM FOR THE CAULDRON;So;0;ON;;;;;N;;;;;
+4DF2;HEXAGRAM FOR THE AROUSING THUNDER;So;0;ON;;;;;N;;;;;
+4DF3;HEXAGRAM FOR THE KEEPING STILL MOUNTAIN;So;0;ON;;;;;N;;;;;
+4DF4;HEXAGRAM FOR DEVELOPMENT;So;0;ON;;;;;N;;;;;
+4DF5;HEXAGRAM FOR THE MARRYING MAIDEN;So;0;ON;;;;;N;;;;;
+4DF6;HEXAGRAM FOR ABUNDANCE;So;0;ON;;;;;N;;;;;
+4DF7;HEXAGRAM FOR THE WANDERER;So;0;ON;;;;;N;;;;;
+4DF8;HEXAGRAM FOR THE GENTLE WIND;So;0;ON;;;;;N;;;;;
+4DF9;HEXAGRAM FOR THE JOYOUS LAKE;So;0;ON;;;;;N;;;;;
+4DFA;HEXAGRAM FOR DISPERSION;So;0;ON;;;;;N;;;;;
+4DFB;HEXAGRAM FOR LIMITATION;So;0;ON;;;;;N;;;;;
+4DFC;HEXAGRAM FOR INNER TRUTH;So;0;ON;;;;;N;;;;;
+4DFD;HEXAGRAM FOR SMALL PREPONDERANCE;So;0;ON;;;;;N;;;;;
+4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;;
+4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;;
+4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
+9FBB;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;
+A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;
+A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;
+A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;;
+A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;;
+A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;;
+A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;;
+A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;;
+A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;;
+A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;;
+A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;;
+A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;;
+A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;;
+A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;;
+A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;;
+A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;;
+A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;;
+A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;;
+A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;;
+A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;;
+A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;;
+A015;YI SYLLABLE WU;Lm;0;L;;;;;N;;;;;
+A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;;
+A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;;
+A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;;
+A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;;
+A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;;
+A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;;
+A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;;
+A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;;
+A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;;
+A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;;
+A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;;
+A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;;
+A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;;
+A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;;
+A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;;
+A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;;
+A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;;
+A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;;
+A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;;
+A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;;
+A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;;
+A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;;
+A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;;
+A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;;
+A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;;
+A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;;
+A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;;
+A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;;
+A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;;
+A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;;
+A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;;
+A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;;
+A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;;
+A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;;
+A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;;
+A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;;
+A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;;
+A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;;
+A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;;
+A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;;
+A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;;
+A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;;
+A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;;
+A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;;
+A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;;
+A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;;
+A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;;
+A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;;
+A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;;
+A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;;
+A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;;
+A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;;
+A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;;
+A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;;
+A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;;
+A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;;
+A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;;
+A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;;
+A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;;
+A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;;
+A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;;
+A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;;
+A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;;
+A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;;
+A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;;
+A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;;
+A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;;
+A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;;
+A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;;
+A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;;
+A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;;
+A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;;
+A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;;
+A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;;
+A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;;
+A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;;
+A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;;
+A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;;
+A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;;
+A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;;
+A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;;
+A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;;
+A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;;
+A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;;
+A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;;
+A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;;
+A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;;
+A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;;
+A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;;
+A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;;
+A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;;
+A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;;
+A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;;
+A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;;
+A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;;
+A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;;
+A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;;
+A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;;
+A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;;
+A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;;
+A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;;
+A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;;
+A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;;
+A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;;
+A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;;
+A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;;
+A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;;
+A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;;
+A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;;
+A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;;
+A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;;
+A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;;
+A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;;
+A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;;
+A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;;
+A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;;
+A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;;
+A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;;
+A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;;
+A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;;
+A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;;
+A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;;
+A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;;
+A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;;
+A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;;
+A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;;
+A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;;
+A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;;
+A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;;
+A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;;
+A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;;
+A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;;
+A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;;
+A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;;
+A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;;
+A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;;
+A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;;
+A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;;
+A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;;
+A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;;
+A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;;
+A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;;
+A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;;
+A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;;
+A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;;
+A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;;
+A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;;
+A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;;
+A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;;
+A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;;
+A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;;
+A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;;
+A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;;
+A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;;
+A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;;
+A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;;
+A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;;
+A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;;
+A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;;
+A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;;
+A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;;
+A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;;
+A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;;
+A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;;
+A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;;
+A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;;
+A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;;
+A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;;
+A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;;
+A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;;
+A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;;
+A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;;
+A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;;
+A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;;
+A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;;
+A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;;
+A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;;
+A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;;
+A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;;
+A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;;
+A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;;
+A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;;
+A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;;
+A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;;
+A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;;
+A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;;
+A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;;
+A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;;
+A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;;
+A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;;
+A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;;
+A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;;
+A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;;
+A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;;
+A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;;
+A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;;
+A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;;
+A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;;
+A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;;
+A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;;
+A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;;
+A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;;
+A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;;
+A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;;
+A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;;
+A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;;
+A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;;
+A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;;
+A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;;
+A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;;
+A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;;
+A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;;
+A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;;
+A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;;
+A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;;
+A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;;
+A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;;
+A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;;
+A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;;
+A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;;
+A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;;
+A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;;
+A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;;
+A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;;
+A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;;
+A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;;
+A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;;
+A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;;
+A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;;
+A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;;
+A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;;
+A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;;
+A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;;
+A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;;
+A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;;
+A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;;
+A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;;
+A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;;
+A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;;
+A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;;
+A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;;
+A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;;
+A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;;
+A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;;
+A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;;
+A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;;
+A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;;
+A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;;
+A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;;
+A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;;
+A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;;
+A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;;
+A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;;
+A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;;
+A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;;
+A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;;
+A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;;
+A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;;
+A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;;
+A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;;
+A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;;
+A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;;
+A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;;
+A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;;
+A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;;
+A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;;
+A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;;
+A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;;
+A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;;
+A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;;
+A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;;
+A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;;
+A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;;
+A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;;
+A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;;
+A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;;
+A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;;
+A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;;
+A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;;
+A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;;
+A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;;
+A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;;
+A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;;
+A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;;
+A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;;
+A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;;
+A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;;
+A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;;
+A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;;
+A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;;
+A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;;
+A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;;
+A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;;
+A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;;
+A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;;
+A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;;
+A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;;
+A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;;
+A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;;
+A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;;
+A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;;
+A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;;
+A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;;
+A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;;
+A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;;
+A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;;
+A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;;
+A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;;
+A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;;
+A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;;
+A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;;
+A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;;
+A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;;
+A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;;
+A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;;
+A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;;
+A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;;
+A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;;
+A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;;
+A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;;
+A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;;
+A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;;
+A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;;
+A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;;
+A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;;
+A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;;
+A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;;
+A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;;
+A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;;
+A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;;
+A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;;
+A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;;
+A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;;
+A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;;
+A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;;
+A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;;
+A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;;
+A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;;
+A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;;
+A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;;
+A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;;
+A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;;
+A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;;
+A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;;
+A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;;
+A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;;
+A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;;
+A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;;
+A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;;
+A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;;
+A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;;
+A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;;
+A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;;
+A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;;
+A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;;
+A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;;
+A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;;
+A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;;
+A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;;
+A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;;
+A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;;
+A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;;
+A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;;
+A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;;
+A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;;
+A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;;
+A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;;
+A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;;
+A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;;
+A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;;
+A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;;
+A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;;
+A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;;
+A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;;
+A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;;
+A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;;
+A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;;
+A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;;
+A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;;
+A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;;
+A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;;
+A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;;
+A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;;
+A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;;
+A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;;
+A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;;
+A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;;
+A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;;
+A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;;
+A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;;
+A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;;
+A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;;
+A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;;
+A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;;
+A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;;
+A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;;
+A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;;
+A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;;
+A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;;
+A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;;
+A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;;
+A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;;
+A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;;
+A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;;
+A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;;
+A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;;
+A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;;
+A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;;
+A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;;
+A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;;
+A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;;
+A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;;
+A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;;
+A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;;
+A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;;
+A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;;
+A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;;
+A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;;
+A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;;
+A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;;
+A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;;
+A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;;
+A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;;
+A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;;
+A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;;
+A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;;
+A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;;
+A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;;
+A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;;
+A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;;
+A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;;
+A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;;
+A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;;
+A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;;
+A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;;
+A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;;
+A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;;
+A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;;
+A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;;
+A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;;
+A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;;
+A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;;
+A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;;
+A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;;
+A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;;
+A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;;
+A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;;
+A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;;
+A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;;
+A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;;
+A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;;
+A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;;
+A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;;
+A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;;
+A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;;
+A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;;
+A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;;
+A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;;
+A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;;
+A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;;
+A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;;
+A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;;
+A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;;
+A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;;
+A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;;
+A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;;
+A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;;
+A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;;
+A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;;
+A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;;
+A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;;
+A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;;
+A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;;
+A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;;
+A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;;
+A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;;
+A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;;
+A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;;
+A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;;
+A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;;
+A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;;
+A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;;
+A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;;
+A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;;
+A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;;
+A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;;
+A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;;
+A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;;
+A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;;
+A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;;
+A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;;
+A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;;
+A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;;
+A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;;
+A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;;
+A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;;
+A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;;
+A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;;
+A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;;
+A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;;
+A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;;
+A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;;
+A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;;
+A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;;
+A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;;
+A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;;
+A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;;
+A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;;
+A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;;
+A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;;
+A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;;
+A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;;
+A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;;
+A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;;
+A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;;
+A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;;
+A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;;
+A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;;
+A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;;
+A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;;
+A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;;
+A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;;
+A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;;
+A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;;
+A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;;
+A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;;
+A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;;
+A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;;
+A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;;
+A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;;
+A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;;
+A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;;
+A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;;
+A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;;
+A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;;
+A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;;
+A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;;
+A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;;
+A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;;
+A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;;
+A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;;
+A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;;
+A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;;
+A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;;
+A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;;
+A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;;
+A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;;
+A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;;
+A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;;
+A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;;
+A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;;
+A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;;
+A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;;
+A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;;
+A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;;
+A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;;
+A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;;
+A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;;
+A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;;
+A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;;
+A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;;
+A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;;
+A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;;
+A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;;
+A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;;
+A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;;
+A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;;
+A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;;
+A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;;
+A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;;
+A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;;
+A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;;
+A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;;
+A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;;
+A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;;
+A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;;
+A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;;
+A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;;
+A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;;
+A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;;
+A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;;
+A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;;
+A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;;
+A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;;
+A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;;
+A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;;
+A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;;
+A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;;
+A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;;
+A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;;
+A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;;
+A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;;
+A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;;
+A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;;
+A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;;
+A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;;
+A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;;
+A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;;
+A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;;
+A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;;
+A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;;
+A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;;
+A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;;
+A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;;
+A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;;
+A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;;
+A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;;
+A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;;
+A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;;
+A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;;
+A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;;
+A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;;
+A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;;
+A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;;
+A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;;
+A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;;
+A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;;
+A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;;
+A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;;
+A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;;
+A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;;
+A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;;
+A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;
+A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;;
+A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;;
+A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;;
+A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;;
+A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;;
+A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;;
+A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;;
+A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;
+A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;;
+A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;;
+A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;
+A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;;
+A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;;
+A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;
+A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;;
+A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;;
+A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;
+A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;;
+A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;;
+A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;;
+A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;;
+A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;;
+A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;;
+A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;;
+A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;;
+A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;;
+A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;;
+A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;;
+A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;;
+A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;;
+A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;;
+A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;;
+A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;;
+A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;;
+A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;;
+A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;;
+A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;;
+A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;;
+A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;;
+A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;;
+A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;;
+A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;;
+A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;;
+A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;;
+A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;;
+A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;;
+A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;;
+A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;;
+A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;;
+A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;;
+A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;;
+A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;;
+A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;;
+A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;;
+A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;;
+A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;;
+A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;;
+A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;;
+A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;;
+A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;;
+A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;;
+A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;;
+A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;;
+A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;;
+A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;;
+A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;;
+A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;;
+A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;;
+A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;;
+A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;;
+A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;;
+A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;;
+A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;;
+A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;;
+A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;;
+A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;;
+A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;;
+A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;;
+A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;;
+A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;;
+A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;;
+A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;;
+A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;;
+A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;;
+A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;;
+A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;;
+A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;;
+A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;;
+A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;;
+A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;;
+A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;;
+A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;;
+A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;;
+A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;;
+A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;;
+A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;;
+A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;;
+A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;;
+A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;;
+A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;;
+A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;;
+A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;;
+A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;;
+A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;;
+A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;;
+A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;;
+A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;;
+A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;;
+A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;;
+A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;;
+A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;;
+A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;;
+A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;;
+A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;;
+A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;;
+A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;;
+A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;;
+A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;;
+A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;;
+A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;;
+A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;;
+A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;;
+A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;;
+A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;;
+A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;;
+A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;;
+A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;;
+A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;;
+A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;;
+A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;;
+A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;;
+A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;;
+A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;;
+A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;;
+A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;;
+A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;;
+A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;;
+A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;;
+A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;;
+A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;;
+A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;;
+A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;;
+A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;;
+A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;;
+A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;;
+A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;;
+A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;;
+A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;;
+A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;;
+A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;;
+A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;;
+A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;;
+A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;;
+A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;;
+A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;;
+A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;;
+A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;;
+A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;;
+A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;;
+A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;;
+A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;;
+A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;;
+A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;;
+A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;;
+A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;;
+A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;;
+A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;;
+A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;;
+A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;;
+A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;;
+A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;;
+A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;;
+A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;;
+A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;;
+A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;;
+A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;;
+A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;;
+A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;;
+A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;;
+A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;;
+A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;;
+A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;;
+A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;;
+A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;;
+A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;;
+A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;;
+A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;;
+A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;;
+A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;;
+A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;;
+A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;;
+A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;;
+A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;;
+A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;;
+A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;;
+A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;;
+A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;;
+A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;;
+A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;;
+A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;;
+A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;;
+A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;;
+A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;;
+A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;;
+A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;;
+A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;;
+A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;;
+A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;;
+A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;;
+A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;;
+A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;;
+A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;;
+A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;;
+A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;;
+A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;;
+A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;;
+A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;;
+A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;;
+A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;;
+A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;;
+A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;;
+A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;;
+A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;;
+A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;;
+A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;;
+A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;;
+A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;;
+A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;;
+A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;;
+A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;;
+A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;;
+A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;;
+A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;;
+A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;;
+A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;;
+A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;;
+A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;;
+A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;;
+A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;;
+A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;;
+A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;;
+A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;;
+A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;;
+A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;;
+A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;;
+A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;;
+A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;;
+A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;;
+A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;;
+A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;;
+A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;;
+A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;;
+A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;;
+A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;;
+A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;;
+A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;;
+A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;;
+A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;;
+A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;;
+A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;;
+A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;;
+A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;;
+A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;;
+A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;;
+A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;;
+A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;;
+A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;;
+A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;;
+A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;;
+A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;;
+A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;;
+A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;;
+A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;;
+A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;;
+A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;;
+A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;;
+A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;;
+A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;;
+A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;;
+A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;;
+A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;;
+A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;;
+A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;;
+A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;;
+A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;;
+A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;;
+A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;;
+A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;;
+A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;;
+A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;;
+A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;;
+A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;;
+A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;;
+A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;;
+A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;;
+A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;;
+A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;;
+A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;;
+A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;;
+A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;;
+A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;;
+A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;;
+A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;;
+A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;;
+A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;;
+A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;;
+A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;;
+A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;;
+A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;;
+A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;;
+A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;;
+A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;;
+A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;;
+A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;;
+A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;;
+A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;;
+A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;;
+A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;;
+A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;;
+A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;;
+A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;;
+A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;;
+A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;;
+A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;;
+A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;;
+A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;;
+A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;;
+A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;;
+A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;;
+A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;;
+A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;;
+A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;;
+A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;;
+A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;;
+A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;;
+A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;;
+A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;;
+A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;;
+A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;;
+A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;;
+A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;;
+A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;;
+A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;;
+A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;;
+A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;;
+A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;;
+A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;;
+A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;;
+A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;;
+A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;;
+A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;;
+A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;;
+A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;;
+A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;;
+A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;;
+A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;;
+A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;;
+A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;;
+A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;;
+A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;;
+A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;;
+A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;;
+A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;;
+A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;;
+A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;;
+A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;;
+A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;;
+A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;;
+A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;;
+A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;;
+A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;;
+A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;;
+A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;;
+A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;;
+A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;;
+A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;;
+A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;;
+A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;;
+A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;;
+A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;;
+A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;;
+A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;;
+A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;;
+A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;;
+A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;;
+A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;;
+A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;;
+A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;;
+A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;;
+A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;;
+A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;;
+A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;;
+A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;;
+A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;;
+A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;;
+A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;;
+A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;;
+A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;;
+A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;;
+A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;;
+A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;;
+A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;;
+A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;;
+A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;;
+A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;;
+A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;;
+A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;;
+A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;;
+A491;YI RADICAL LI;So;0;ON;;;;;N;;;;;
+A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;;
+A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;;
+A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;;
+A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;;
+A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;;
+A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;;
+A498;YI RADICAL MI;So;0;ON;;;;;N;;;;;
+A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;;
+A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;;
+A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;;
+A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;;
+A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;;
+A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;;
+A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;;
+A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;;
+A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;;
+A4A2;YI RADICAL ZUP;So;0;ON;;;;;N;;;;;
+A4A3;YI RADICAL CYT;So;0;ON;;;;;N;;;;;
+A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;;
+A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;;
+A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;;
+A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;;
+A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;;
+A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;;
+A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;;
+A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;;
+A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;;
+A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;;
+A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;;
+A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;;
+A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;;
+A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;;
+A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;;
+A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;;
+A4B4;YI RADICAL NZUP;So;0;ON;;;;;N;;;;;
+A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;;
+A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;;
+A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;;
+A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;;
+A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;;
+A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;;
+A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;;
+A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;;
+A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;;
+A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;;
+A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;;
+A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;;
+A4C1;YI RADICAL ZUR;So;0;ON;;;;;N;;;;;
+A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;;
+A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;;
+A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;;
+A4C5;YI RADICAL NBIE;So;0;ON;;;;;N;;;;;
+A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;;
+A700;MODIFIER LETTER CHINESE TONE YIN PING;Sk;0;ON;;;;;N;;;;;
+A701;MODIFIER LETTER CHINESE TONE YANG PING;Sk;0;ON;;;;;N;;;;;
+A702;MODIFIER LETTER CHINESE TONE YIN SHANG;Sk;0;ON;;;;;N;;;;;
+A703;MODIFIER LETTER CHINESE TONE YANG SHANG;Sk;0;ON;;;;;N;;;;;
+A704;MODIFIER LETTER CHINESE TONE YIN QU;Sk;0;ON;;;;;N;;;;;
+A705;MODIFIER LETTER CHINESE TONE YANG QU;Sk;0;ON;;;;;N;;;;;
+A706;MODIFIER LETTER CHINESE TONE YIN RU;Sk;0;ON;;;;;N;;;;;
+A707;MODIFIER LETTER CHINESE TONE YANG RU;Sk;0;ON;;;;;N;;;;;
+A708;MODIFIER LETTER EXTRA-HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A709;MODIFIER LETTER HIGH DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70A;MODIFIER LETTER MID DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70B;MODIFIER LETTER LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70C;MODIFIER LETTER EXTRA-LOW DOTTED TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70D;MODIFIER LETTER EXTRA-HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70E;MODIFIER LETTER HIGH DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A70F;MODIFIER LETTER MID DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A710;MODIFIER LETTER LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A711;MODIFIER LETTER EXTRA-LOW DOTTED LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A712;MODIFIER LETTER EXTRA-HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A713;MODIFIER LETTER HIGH LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A714;MODIFIER LETTER MID LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A715;MODIFIER LETTER LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A716;MODIFIER LETTER EXTRA-LOW LEFT-STEM TONE BAR;Sk;0;ON;;;;;N;;;;;
+A800;SYLOTI NAGRI LETTER A;Lo;0;L;;;;;N;;;;;
+A801;SYLOTI NAGRI LETTER I;Lo;0;L;;;;;N;;;;;
+A802;SYLOTI NAGRI SIGN DVISVARA;Mc;0;NSM;;;;;N;;;;;
+A803;SYLOTI NAGRI LETTER U;Lo;0;L;;;;;N;;;;;
+A804;SYLOTI NAGRI LETTER E;Lo;0;L;;;;;N;;;;;
+A805;SYLOTI NAGRI LETTER O;Lo;0;L;;;;;N;;;;;
+A806;SYLOTI NAGRI SIGN HASANTA;Mn;9;NSM;;;;;N;;;;;
+A807;SYLOTI NAGRI LETTER KO;Lo;0;L;;;;;N;;;;;
+A808;SYLOTI NAGRI LETTER KHO;Lo;0;L;;;;;N;;;;;
+A809;SYLOTI NAGRI LETTER GO;Lo;0;L;;;;;N;;;;;
+A80A;SYLOTI NAGRI LETTER GHO;Lo;0;L;;;;;N;;;;;
+A80B;SYLOTI NAGRI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+A80C;SYLOTI NAGRI LETTER CO;Lo;0;L;;;;;N;;;;;
+A80D;SYLOTI NAGRI LETTER CHO;Lo;0;L;;;;;N;;;;;
+A80E;SYLOTI NAGRI LETTER JO;Lo;0;L;;;;;N;;;;;
+A80F;SYLOTI NAGRI LETTER JHO;Lo;0;L;;;;;N;;;;;
+A810;SYLOTI NAGRI LETTER TTO;Lo;0;L;;;;;N;;;;;
+A811;SYLOTI NAGRI LETTER TTHO;Lo;0;L;;;;;N;;;;;
+A812;SYLOTI NAGRI LETTER DDO;Lo;0;L;;;;;N;;;;;
+A813;SYLOTI NAGRI LETTER DDHO;Lo;0;L;;;;;N;;;;;
+A814;SYLOTI NAGRI LETTER TO;Lo;0;L;;;;;N;;;;;
+A815;SYLOTI NAGRI LETTER THO;Lo;0;L;;;;;N;;;;;
+A816;SYLOTI NAGRI LETTER DO;Lo;0;L;;;;;N;;;;;
+A817;SYLOTI NAGRI LETTER DHO;Lo;0;L;;;;;N;;;;;
+A818;SYLOTI NAGRI LETTER NO;Lo;0;L;;;;;N;;;;;
+A819;SYLOTI NAGRI LETTER PO;Lo;0;L;;;;;N;;;;;
+A81A;SYLOTI NAGRI LETTER PHO;Lo;0;L;;;;;N;;;;;
+A81B;SYLOTI NAGRI LETTER BO;Lo;0;L;;;;;N;;;;;
+A81C;SYLOTI NAGRI LETTER BHO;Lo;0;L;;;;;N;;;;;
+A81D;SYLOTI NAGRI LETTER MO;Lo;0;L;;;;;N;;;;;
+A81E;SYLOTI NAGRI LETTER RO;Lo;0;L;;;;;N;;;;;
+A81F;SYLOTI NAGRI LETTER LO;Lo;0;L;;;;;N;;;;;
+A820;SYLOTI NAGRI LETTER RRO;Lo;0;L;;;;;N;;;;;
+A821;SYLOTI NAGRI LETTER SO;Lo;0;L;;;;;N;;;;;
+A822;SYLOTI NAGRI LETTER HO;Lo;0;L;;;;;N;;;;;
+A823;SYLOTI NAGRI VOWEL SIGN A;Mc;0;L;;;;;N;;;;;
+A824;SYLOTI NAGRI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+A825;SYLOTI NAGRI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+A826;SYLOTI NAGRI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+A827;SYLOTI NAGRI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+A828;SYLOTI NAGRI POETRY MARK-1;So;0;ON;;;;;N;;;;;
+A829;SYLOTI NAGRI POETRY MARK-2;So;0;ON;;;;;N;;;;;
+A82A;SYLOTI NAGRI POETRY MARK-3;So;0;ON;;;;;N;;;;;
+A82B;SYLOTI NAGRI POETRY MARK-4;So;0;ON;;;;;N;;;;;
+AC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;;
+D7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;;
+D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+E000;<Private Use, First>;Co;0;L;;;;;N;;;;;
+F8FF;<Private Use, Last>;Co;0;L;;;;;N;;;;;
+F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;;
+F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;;
+F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;;
+F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;;
+F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;;
+F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;;
+F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;;
+F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;;
+F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;;
+F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;;
+F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;;
+F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;;
+F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;;
+F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;;
+F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;;
+F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;;
+F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;;
+F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;;
+F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;;
+F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;;
+F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;;
+F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;;
+F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;;
+F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;;
+F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;;
+F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;;
+F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;;
+F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;;
+F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;;
+F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;;
+F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;;
+F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;;
+F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;;
+F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;;
+F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;;
+F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;;
+F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;;
+F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;;
+F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;;
+F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;;
+F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;;
+F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;;
+F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;;
+F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;;
+F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;;
+F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;;
+F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;;
+F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;;
+F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;;
+F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;;
+F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;;
+F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;;
+F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;;
+F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;;
+F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;;
+F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;;
+F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;;
+F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;;
+F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;;
+F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;;
+F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;;
+F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;;
+F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;;
+F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;;
+F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;;
+F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;;
+F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;;
+F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;;
+F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;;
+F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;;
+F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;;
+F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;;
+F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;;
+F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;;
+F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;;
+F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;;
+F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;;
+F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;;
+F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;;
+F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;;
+F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;;
+F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;964B;;;;N;;;;;
+F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;;
+F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;;
+F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;;
+F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;;
+F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;;
+F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;;
+F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;;
+F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;;
+F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;;
+F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;;
+F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;;
+F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;;
+F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;;
+F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;;
+F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;;
+F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;;
+F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;;
+F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;;
+F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;;
+F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;;
+F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;;
+F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;;
+F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;;
+F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;;
+F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;;
+F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;;N;;;;;
+F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;;
+F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;;
+F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;;
+F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;;
+F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;;
+F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;;
+F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;;
+F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;;N;;;;;
+F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;;
+F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;;
+F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;;
+F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;;
+F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;;N;;;;;
+F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;;
+F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;;
+F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;;
+F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;;
+F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;;
+F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;;
+F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;;
+F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;;
+F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;;
+F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;;
+F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;;
+F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;;
+F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;;
+F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;;
+F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;;
+F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;;
+F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;;
+F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;;
+F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;;
+F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;;
+F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;;
+F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;;
+F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;;
+F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;;
+F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;;
+F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;;
+F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;;
+F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;;
+F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;;
+F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;;
+F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;;
+F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;;
+F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;;
+F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;;
+F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;;
+F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;;
+F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;;
+F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;;
+F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;;
+F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;;
+F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;;
+F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;;
+F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;;
+F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;;
+F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;;
+F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;;
+F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;;
+F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;;
+F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;;
+F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;;
+F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;;
+F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;;
+F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;;
+F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;;
+F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;;
+F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;;
+F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;;
+F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;;N;;;;;
+F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;;
+F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;;
+F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;;
+F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;;
+F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;;
+F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;;
+F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;;
+F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;;
+F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;;
+F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;;
+F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;;
+F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;;
+F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;;
+F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;;
+F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;;
+F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;;
+F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;;
+F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;;
+F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;;
+F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;;
+F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;;
+F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;;
+F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;;
+F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;;
+F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;;
+F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;;
+F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;;
+F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;;
+F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;;
+F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;;
+F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;;N;;;;;
+F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;;
+F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;;N;;;;;
+F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;;
+F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;;
+F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;;
+F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;;
+F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;;
+F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;;
+F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;;
+F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;;
+F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;;
+F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;;
+F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;;
+F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;;
+F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;;
+F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;;
+F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;;
+F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;;
+F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;;
+F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;;
+F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;;
+F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;;
+F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;;
+F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;;
+F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;;
+F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;;
+F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;;
+F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;;
+F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;;
+F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;;
+F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;;
+F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;;
+F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;;
+F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;;
+F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;;
+F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;;
+F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;;
+F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;;
+F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;;
+F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;;
+F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;;
+F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;;
+F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;;
+F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;;N;;;;;
+F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;;
+F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;;
+FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;;
+FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;;
+FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;;
+FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;;
+FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;;
+FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;;
+FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;;
+FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;;
+FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;;
+FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;;
+FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;;
+FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;;
+FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;;
+FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;;
+FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;;
+FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;;
+FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;;
+FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;;
+FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;;
+FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;;
+FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;;
+FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;;
+FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;;
+FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;;
+FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;;
+FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;;
+FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;;
+FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;;
+FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;;
+FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;;
+FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;;
+FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;*;;;
+FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;;
+FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;;
+FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;;
+FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;*;;;
+FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;;
+FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;;
+FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;;
+FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;;
+FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;;
+FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;;
+FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;;
+FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;;
+FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;;
+FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;;
+FA30;CJK COMPATIBILITY IDEOGRAPH-FA30;Lo;0;L;4FAE;;;;N;;;;;
+FA31;CJK COMPATIBILITY IDEOGRAPH-FA31;Lo;0;L;50E7;;;;N;;;;;
+FA32;CJK COMPATIBILITY IDEOGRAPH-FA32;Lo;0;L;514D;;;;N;;;;;
+FA33;CJK COMPATIBILITY IDEOGRAPH-FA33;Lo;0;L;52C9;;;;N;;;;;
+FA34;CJK COMPATIBILITY IDEOGRAPH-FA34;Lo;0;L;52E4;;;;N;;;;;
+FA35;CJK COMPATIBILITY IDEOGRAPH-FA35;Lo;0;L;5351;;;;N;;;;;
+FA36;CJK COMPATIBILITY IDEOGRAPH-FA36;Lo;0;L;559D;;;;N;;;;;
+FA37;CJK COMPATIBILITY IDEOGRAPH-FA37;Lo;0;L;5606;;;;N;;;;;
+FA38;CJK COMPATIBILITY IDEOGRAPH-FA38;Lo;0;L;5668;;;;N;;;;;
+FA39;CJK COMPATIBILITY IDEOGRAPH-FA39;Lo;0;L;5840;;;;N;;;;;
+FA3A;CJK COMPATIBILITY IDEOGRAPH-FA3A;Lo;0;L;58A8;;;;N;;;;;
+FA3B;CJK COMPATIBILITY IDEOGRAPH-FA3B;Lo;0;L;5C64;;;;N;;;;;
+FA3C;CJK COMPATIBILITY IDEOGRAPH-FA3C;Lo;0;L;5C6E;;;;N;;;;;
+FA3D;CJK COMPATIBILITY IDEOGRAPH-FA3D;Lo;0;L;6094;;;;N;;;;;
+FA3E;CJK COMPATIBILITY IDEOGRAPH-FA3E;Lo;0;L;6168;;;;N;;;;;
+FA3F;CJK COMPATIBILITY IDEOGRAPH-FA3F;Lo;0;L;618E;;;;N;;;;;
+FA40;CJK COMPATIBILITY IDEOGRAPH-FA40;Lo;0;L;61F2;;;;N;;;;;
+FA41;CJK COMPATIBILITY IDEOGRAPH-FA41;Lo;0;L;654F;;;;N;;;;;
+FA42;CJK COMPATIBILITY IDEOGRAPH-FA42;Lo;0;L;65E2;;;;N;;;;;
+FA43;CJK COMPATIBILITY IDEOGRAPH-FA43;Lo;0;L;6691;;;;N;;;;;
+FA44;CJK COMPATIBILITY IDEOGRAPH-FA44;Lo;0;L;6885;;;;N;;;;;
+FA45;CJK COMPATIBILITY IDEOGRAPH-FA45;Lo;0;L;6D77;;;;N;;;;;
+FA46;CJK COMPATIBILITY IDEOGRAPH-FA46;Lo;0;L;6E1A;;;;N;;;;;
+FA47;CJK COMPATIBILITY IDEOGRAPH-FA47;Lo;0;L;6F22;;;;N;;;;;
+FA48;CJK COMPATIBILITY IDEOGRAPH-FA48;Lo;0;L;716E;;;;N;;;;;
+FA49;CJK COMPATIBILITY IDEOGRAPH-FA49;Lo;0;L;722B;;;;N;;;;;
+FA4A;CJK COMPATIBILITY IDEOGRAPH-FA4A;Lo;0;L;7422;;;;N;;;;;
+FA4B;CJK COMPATIBILITY IDEOGRAPH-FA4B;Lo;0;L;7891;;;;N;;;;;
+FA4C;CJK COMPATIBILITY IDEOGRAPH-FA4C;Lo;0;L;793E;;;;N;;;;;
+FA4D;CJK COMPATIBILITY IDEOGRAPH-FA4D;Lo;0;L;7949;;;;N;;;;;
+FA4E;CJK COMPATIBILITY IDEOGRAPH-FA4E;Lo;0;L;7948;;;;N;;;;;
+FA4F;CJK COMPATIBILITY IDEOGRAPH-FA4F;Lo;0;L;7950;;;;N;;;;;
+FA50;CJK COMPATIBILITY IDEOGRAPH-FA50;Lo;0;L;7956;;;;N;;;;;
+FA51;CJK COMPATIBILITY IDEOGRAPH-FA51;Lo;0;L;795D;;;;N;;;;;
+FA52;CJK COMPATIBILITY IDEOGRAPH-FA52;Lo;0;L;798D;;;;N;;;;;
+FA53;CJK COMPATIBILITY IDEOGRAPH-FA53;Lo;0;L;798E;;;;N;;;;;
+FA54;CJK COMPATIBILITY IDEOGRAPH-FA54;Lo;0;L;7A40;;;;N;;;;;
+FA55;CJK COMPATIBILITY IDEOGRAPH-FA55;Lo;0;L;7A81;;;;N;;;;;
+FA56;CJK COMPATIBILITY IDEOGRAPH-FA56;Lo;0;L;7BC0;;;;N;;;;;
+FA57;CJK COMPATIBILITY IDEOGRAPH-FA57;Lo;0;L;7DF4;;;;N;;;;;
+FA58;CJK COMPATIBILITY IDEOGRAPH-FA58;Lo;0;L;7E09;;;;N;;;;;
+FA59;CJK COMPATIBILITY IDEOGRAPH-FA59;Lo;0;L;7E41;;;;N;;;;;
+FA5A;CJK COMPATIBILITY IDEOGRAPH-FA5A;Lo;0;L;7F72;;;;N;;;;;
+FA5B;CJK COMPATIBILITY IDEOGRAPH-FA5B;Lo;0;L;8005;;;;N;;;;;
+FA5C;CJK COMPATIBILITY IDEOGRAPH-FA5C;Lo;0;L;81ED;;;;N;;;;;
+FA5D;CJK COMPATIBILITY IDEOGRAPH-FA5D;Lo;0;L;8279;;;;N;;;;;
+FA5E;CJK COMPATIBILITY IDEOGRAPH-FA5E;Lo;0;L;8279;;;;N;;;;;
+FA5F;CJK COMPATIBILITY IDEOGRAPH-FA5F;Lo;0;L;8457;;;;N;;;;;
+FA60;CJK COMPATIBILITY IDEOGRAPH-FA60;Lo;0;L;8910;;;;N;;;;;
+FA61;CJK COMPATIBILITY IDEOGRAPH-FA61;Lo;0;L;8996;;;;N;;;;;
+FA62;CJK COMPATIBILITY IDEOGRAPH-FA62;Lo;0;L;8B01;;;;N;;;;;
+FA63;CJK COMPATIBILITY IDEOGRAPH-FA63;Lo;0;L;8B39;;;;N;;;;;
+FA64;CJK COMPATIBILITY IDEOGRAPH-FA64;Lo;0;L;8CD3;;;;N;;;;;
+FA65;CJK COMPATIBILITY IDEOGRAPH-FA65;Lo;0;L;8D08;;;;N;;;;;
+FA66;CJK COMPATIBILITY IDEOGRAPH-FA66;Lo;0;L;8FB6;;;;N;;;;;
+FA67;CJK COMPATIBILITY IDEOGRAPH-FA67;Lo;0;L;9038;;;;N;;;;;
+FA68;CJK COMPATIBILITY IDEOGRAPH-FA68;Lo;0;L;96E3;;;;N;;;;;
+FA69;CJK COMPATIBILITY IDEOGRAPH-FA69;Lo;0;L;97FF;;;;N;;;;;
+FA6A;CJK COMPATIBILITY IDEOGRAPH-FA6A;Lo;0;L;983B;;;;N;;;;;
+FA70;CJK COMPATIBILITY IDEOGRAPH-FA70;Lo;0;L;4E26;;;;N;;;;;
+FA71;CJK COMPATIBILITY IDEOGRAPH-FA71;Lo;0;L;51B5;;;;N;;;;;
+FA72;CJK COMPATIBILITY IDEOGRAPH-FA72;Lo;0;L;5168;;;;N;;;;;
+FA73;CJK COMPATIBILITY IDEOGRAPH-FA73;Lo;0;L;4F80;;;;N;;;;;
+FA74;CJK COMPATIBILITY IDEOGRAPH-FA74;Lo;0;L;5145;;;;N;;;;;
+FA75;CJK COMPATIBILITY IDEOGRAPH-FA75;Lo;0;L;5180;;;;N;;;;;
+FA76;CJK COMPATIBILITY IDEOGRAPH-FA76;Lo;0;L;52C7;;;;N;;;;;
+FA77;CJK COMPATIBILITY IDEOGRAPH-FA77;Lo;0;L;52FA;;;;N;;;;;
+FA78;CJK COMPATIBILITY IDEOGRAPH-FA78;Lo;0;L;559D;;;;N;;;;;
+FA79;CJK COMPATIBILITY IDEOGRAPH-FA79;Lo;0;L;5555;;;;N;;;;;
+FA7A;CJK COMPATIBILITY IDEOGRAPH-FA7A;Lo;0;L;5599;;;;N;;;;;
+FA7B;CJK COMPATIBILITY IDEOGRAPH-FA7B;Lo;0;L;55E2;;;;N;;;;;
+FA7C;CJK COMPATIBILITY IDEOGRAPH-FA7C;Lo;0;L;585A;;;;N;;;;;
+FA7D;CJK COMPATIBILITY IDEOGRAPH-FA7D;Lo;0;L;58B3;;;;N;;;;;
+FA7E;CJK COMPATIBILITY IDEOGRAPH-FA7E;Lo;0;L;5944;;;;N;;;;;
+FA7F;CJK COMPATIBILITY IDEOGRAPH-FA7F;Lo;0;L;5954;;;;N;;;;;
+FA80;CJK COMPATIBILITY IDEOGRAPH-FA80;Lo;0;L;5A62;;;;N;;;;;
+FA81;CJK COMPATIBILITY IDEOGRAPH-FA81;Lo;0;L;5B28;;;;N;;;;;
+FA82;CJK COMPATIBILITY IDEOGRAPH-FA82;Lo;0;L;5ED2;;;;N;;;;;
+FA83;CJK COMPATIBILITY IDEOGRAPH-FA83;Lo;0;L;5ED9;;;;N;;;;;
+FA84;CJK COMPATIBILITY IDEOGRAPH-FA84;Lo;0;L;5F69;;;;N;;;;;
+FA85;CJK COMPATIBILITY IDEOGRAPH-FA85;Lo;0;L;5FAD;;;;N;;;;;
+FA86;CJK COMPATIBILITY IDEOGRAPH-FA86;Lo;0;L;60D8;;;;N;;;;;
+FA87;CJK COMPATIBILITY IDEOGRAPH-FA87;Lo;0;L;614E;;;;N;;;;;
+FA88;CJK COMPATIBILITY IDEOGRAPH-FA88;Lo;0;L;6108;;;;N;;;;;
+FA89;CJK COMPATIBILITY IDEOGRAPH-FA89;Lo;0;L;618E;;;;N;;;;;
+FA8A;CJK COMPATIBILITY IDEOGRAPH-FA8A;Lo;0;L;6160;;;;N;;;;;
+FA8B;CJK COMPATIBILITY IDEOGRAPH-FA8B;Lo;0;L;61F2;;;;N;;;;;
+FA8C;CJK COMPATIBILITY IDEOGRAPH-FA8C;Lo;0;L;6234;;;;N;;;;;
+FA8D;CJK COMPATIBILITY IDEOGRAPH-FA8D;Lo;0;L;63C4;;;;N;;;;;
+FA8E;CJK COMPATIBILITY IDEOGRAPH-FA8E;Lo;0;L;641C;;;;N;;;;;
+FA8F;CJK COMPATIBILITY IDEOGRAPH-FA8F;Lo;0;L;6452;;;;N;;;;;
+FA90;CJK COMPATIBILITY IDEOGRAPH-FA90;Lo;0;L;6556;;;;N;;;;;
+FA91;CJK COMPATIBILITY IDEOGRAPH-FA91;Lo;0;L;6674;;;;N;;;;;
+FA92;CJK COMPATIBILITY IDEOGRAPH-FA92;Lo;0;L;6717;;;;N;;;;;
+FA93;CJK COMPATIBILITY IDEOGRAPH-FA93;Lo;0;L;671B;;;;N;;;;;
+FA94;CJK COMPATIBILITY IDEOGRAPH-FA94;Lo;0;L;6756;;;;N;;;;;
+FA95;CJK COMPATIBILITY IDEOGRAPH-FA95;Lo;0;L;6B79;;;;N;;;;;
+FA96;CJK COMPATIBILITY IDEOGRAPH-FA96;Lo;0;L;6BBA;;;;N;;;;;
+FA97;CJK COMPATIBILITY IDEOGRAPH-FA97;Lo;0;L;6D41;;;;N;;;;;
+FA98;CJK COMPATIBILITY IDEOGRAPH-FA98;Lo;0;L;6EDB;;;;N;;;;;
+FA99;CJK COMPATIBILITY IDEOGRAPH-FA99;Lo;0;L;6ECB;;;;N;;;;;
+FA9A;CJK COMPATIBILITY IDEOGRAPH-FA9A;Lo;0;L;6F22;;;;N;;;;;
+FA9B;CJK COMPATIBILITY IDEOGRAPH-FA9B;Lo;0;L;701E;;;;N;;;;;
+FA9C;CJK COMPATIBILITY IDEOGRAPH-FA9C;Lo;0;L;716E;;;;N;;;;;
+FA9D;CJK COMPATIBILITY IDEOGRAPH-FA9D;Lo;0;L;77A7;;;;N;;;;;
+FA9E;CJK COMPATIBILITY IDEOGRAPH-FA9E;Lo;0;L;7235;;;;N;;;;;
+FA9F;CJK COMPATIBILITY IDEOGRAPH-FA9F;Lo;0;L;72AF;;;;N;;;;;
+FAA0;CJK COMPATIBILITY IDEOGRAPH-FAA0;Lo;0;L;732A;;;;N;;;;;
+FAA1;CJK COMPATIBILITY IDEOGRAPH-FAA1;Lo;0;L;7471;;;;N;;;;;
+FAA2;CJK COMPATIBILITY IDEOGRAPH-FAA2;Lo;0;L;7506;;;;N;;;;;
+FAA3;CJK COMPATIBILITY IDEOGRAPH-FAA3;Lo;0;L;753B;;;;N;;;;;
+FAA4;CJK COMPATIBILITY IDEOGRAPH-FAA4;Lo;0;L;761D;;;;N;;;;;
+FAA5;CJK COMPATIBILITY IDEOGRAPH-FAA5;Lo;0;L;761F;;;;N;;;;;
+FAA6;CJK COMPATIBILITY IDEOGRAPH-FAA6;Lo;0;L;76CA;;;;N;;;;;
+FAA7;CJK COMPATIBILITY IDEOGRAPH-FAA7;Lo;0;L;76DB;;;;N;;;;;
+FAA8;CJK COMPATIBILITY IDEOGRAPH-FAA8;Lo;0;L;76F4;;;;N;;;;;
+FAA9;CJK COMPATIBILITY IDEOGRAPH-FAA9;Lo;0;L;774A;;;;N;;;;;
+FAAA;CJK COMPATIBILITY IDEOGRAPH-FAAA;Lo;0;L;7740;;;;N;;;;;
+FAAB;CJK COMPATIBILITY IDEOGRAPH-FAAB;Lo;0;L;78CC;;;;N;;;;;
+FAAC;CJK COMPATIBILITY IDEOGRAPH-FAAC;Lo;0;L;7AB1;;;;N;;;;;
+FAAD;CJK COMPATIBILITY IDEOGRAPH-FAAD;Lo;0;L;7BC0;;;;N;;;;;
+FAAE;CJK COMPATIBILITY IDEOGRAPH-FAAE;Lo;0;L;7C7B;;;;N;;;;;
+FAAF;CJK COMPATIBILITY IDEOGRAPH-FAAF;Lo;0;L;7D5B;;;;N;;;;;
+FAB0;CJK COMPATIBILITY IDEOGRAPH-FAB0;Lo;0;L;7DF4;;;;N;;;;;
+FAB1;CJK COMPATIBILITY IDEOGRAPH-FAB1;Lo;0;L;7F3E;;;;N;;;;;
+FAB2;CJK COMPATIBILITY IDEOGRAPH-FAB2;Lo;0;L;8005;;;;N;;;;;
+FAB3;CJK COMPATIBILITY IDEOGRAPH-FAB3;Lo;0;L;8352;;;;N;;;;;
+FAB4;CJK COMPATIBILITY IDEOGRAPH-FAB4;Lo;0;L;83EF;;;;N;;;;;
+FAB5;CJK COMPATIBILITY IDEOGRAPH-FAB5;Lo;0;L;8779;;;;N;;;;;
+FAB6;CJK COMPATIBILITY IDEOGRAPH-FAB6;Lo;0;L;8941;;;;N;;;;;
+FAB7;CJK COMPATIBILITY IDEOGRAPH-FAB7;Lo;0;L;8986;;;;N;;;;;
+FAB8;CJK COMPATIBILITY IDEOGRAPH-FAB8;Lo;0;L;8996;;;;N;;;;;
+FAB9;CJK COMPATIBILITY IDEOGRAPH-FAB9;Lo;0;L;8ABF;;;;N;;;;;
+FABA;CJK COMPATIBILITY IDEOGRAPH-FABA;Lo;0;L;8AF8;;;;N;;;;;
+FABB;CJK COMPATIBILITY IDEOGRAPH-FABB;Lo;0;L;8ACB;;;;N;;;;;
+FABC;CJK COMPATIBILITY IDEOGRAPH-FABC;Lo;0;L;8B01;;;;N;;;;;
+FABD;CJK COMPATIBILITY IDEOGRAPH-FABD;Lo;0;L;8AFE;;;;N;;;;;
+FABE;CJK COMPATIBILITY IDEOGRAPH-FABE;Lo;0;L;8AED;;;;N;;;;;
+FABF;CJK COMPATIBILITY IDEOGRAPH-FABF;Lo;0;L;8B39;;;;N;;;;;
+FAC0;CJK COMPATIBILITY IDEOGRAPH-FAC0;Lo;0;L;8B8A;;;;N;;;;;
+FAC1;CJK COMPATIBILITY IDEOGRAPH-FAC1;Lo;0;L;8D08;;;;N;;;;;
+FAC2;CJK COMPATIBILITY IDEOGRAPH-FAC2;Lo;0;L;8F38;;;;N;;;;;
+FAC3;CJK COMPATIBILITY IDEOGRAPH-FAC3;Lo;0;L;9072;;;;N;;;;;
+FAC4;CJK COMPATIBILITY IDEOGRAPH-FAC4;Lo;0;L;9199;;;;N;;;;;
+FAC5;CJK COMPATIBILITY IDEOGRAPH-FAC5;Lo;0;L;9276;;;;N;;;;;
+FAC6;CJK COMPATIBILITY IDEOGRAPH-FAC6;Lo;0;L;967C;;;;N;;;;;
+FAC7;CJK COMPATIBILITY IDEOGRAPH-FAC7;Lo;0;L;96E3;;;;N;;;;;
+FAC8;CJK COMPATIBILITY IDEOGRAPH-FAC8;Lo;0;L;9756;;;;N;;;;;
+FAC9;CJK COMPATIBILITY IDEOGRAPH-FAC9;Lo;0;L;97DB;;;;N;;;;;
+FACA;CJK COMPATIBILITY IDEOGRAPH-FACA;Lo;0;L;97FF;;;;N;;;;;
+FACB;CJK COMPATIBILITY IDEOGRAPH-FACB;Lo;0;L;980B;;;;N;;;;;
+FACC;CJK COMPATIBILITY IDEOGRAPH-FACC;Lo;0;L;983B;;;;N;;;;;
+FACD;CJK COMPATIBILITY IDEOGRAPH-FACD;Lo;0;L;9B12;;;;N;;;;;
+FACE;CJK COMPATIBILITY IDEOGRAPH-FACE;Lo;0;L;9F9C;;;;N;;;;;
+FACF;CJK COMPATIBILITY IDEOGRAPH-FACF;Lo;0;L;2284A;;;;N;;;;;
+FAD0;CJK COMPATIBILITY IDEOGRAPH-FAD0;Lo;0;L;22844;;;;N;;;;;
+FAD1;CJK COMPATIBILITY IDEOGRAPH-FAD1;Lo;0;L;233D5;;;;N;;;;;
+FAD2;CJK COMPATIBILITY IDEOGRAPH-FAD2;Lo;0;L;3B9D;;;;N;;;;;
+FAD3;CJK COMPATIBILITY IDEOGRAPH-FAD3;Lo;0;L;4018;;;;N;;;;;
+FAD4;CJK COMPATIBILITY IDEOGRAPH-FAD4;Lo;0;L;4039;;;;N;;;;;
+FAD5;CJK COMPATIBILITY IDEOGRAPH-FAD5;Lo;0;L;25249;;;;N;;;;;
+FAD6;CJK COMPATIBILITY IDEOGRAPH-FAD6;Lo;0;L;25CD0;;;;N;;;;;
+FAD7;CJK COMPATIBILITY IDEOGRAPH-FAD7;Lo;0;L;27ED3;;;;N;;;;;
+FAD8;CJK COMPATIBILITY IDEOGRAPH-FAD8;Lo;0;L;9F43;;;;N;;;;;
+FAD9;CJK COMPATIBILITY IDEOGRAPH-FAD9;Lo;0;L;9F8E;;;;N;;;;;
+FB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;;
+FB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;;
+FB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;;
+FB03;LATIN SMALL LIGATURE FFI;Ll;0;L;<compat> 0066 0066 0069;;;;N;;;;;
+FB04;LATIN SMALL LIGATURE FFL;Ll;0;L;<compat> 0066 0066 006C;;;;N;;;;;
+FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L;<compat> 017F 0074;;;;N;;;;;
+FB06;LATIN SMALL LIGATURE ST;Ll;0;L;<compat> 0073 0074;;;;N;;;;;
+FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L;<compat> 0574 0576;;;;N;;;;;
+FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L;<compat> 0574 0565;;;;N;;;;;
+FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L;<compat> 0574 056B;;;;N;;;;;
+FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L;<compat> 057E 0576;;;;N;;;;;
+FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L;<compat> 0574 056D;;;;N;;;;;
+FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;;
+FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;;
+FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;;
+FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R;<font> 05E2;;;;N;;;;;
+FB21;HEBREW LETTER WIDE ALEF;Lo;0;R;<font> 05D0;;;;N;;;;;
+FB22;HEBREW LETTER WIDE DALET;Lo;0;R;<font> 05D3;;;;N;;;;;
+FB23;HEBREW LETTER WIDE HE;Lo;0;R;<font> 05D4;;;;N;;;;;
+FB24;HEBREW LETTER WIDE KAF;Lo;0;R;<font> 05DB;;;;N;;;;;
+FB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;;
+FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;;
+FB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;;
+FB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;;
+FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ES;<font> 002B;;;;N;;;;;
+FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;;
+FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;;
+FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;;
+FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;;
+FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;;
+FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;;
+FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;;
+FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;;
+FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;;
+FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;;
+FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;;
+FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;;
+FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;;
+FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;;
+FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;;
+FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;;
+FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;;
+FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;;
+FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;;
+FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;;
+FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;;
+FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;;
+FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;;
+FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;;
+FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;;
+FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;;
+FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;;
+FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;;
+FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;;
+FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;;
+FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;;
+FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;;
+FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R;<compat> 05D0 05DC;;;;N;;;;;
+FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL;<isolated> 0671;;;;N;;;;;
+FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL;<final> 0671;;;;N;;;;;
+FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL;<isolated> 067B;;;;N;;;;;
+FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL;<final> 067B;;;;N;;;;;
+FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL;<initial> 067B;;;;N;;;;;
+FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL;<medial> 067B;;;;N;;;;;
+FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL;<isolated> 067E;;;;N;;;;;
+FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL;<final> 067E;;;;N;;;;;
+FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL;<initial> 067E;;;;N;;;;;
+FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL;<medial> 067E;;;;N;;;;;
+FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0680;;;;N;;;;;
+FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL;<final> 0680;;;;N;;;;;
+FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL;<initial> 0680;;;;N;;;;;
+FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL;<medial> 0680;;;;N;;;;;
+FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067A;;;;N;;;;;
+FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL;<final> 067A;;;;N;;;;;
+FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL;<initial> 067A;;;;N;;;;;
+FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL;<medial> 067A;;;;N;;;;;
+FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067F;;;;N;;;;;
+FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL;<final> 067F;;;;N;;;;;
+FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL;<initial> 067F;;;;N;;;;;
+FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL;<medial> 067F;;;;N;;;;;
+FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL;<isolated> 0679;;;;N;;;;;
+FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL;<final> 0679;;;;N;;;;;
+FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL;<initial> 0679;;;;N;;;;;
+FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL;<medial> 0679;;;;N;;;;;
+FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL;<isolated> 06A4;;;;N;;;;;
+FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL;<final> 06A4;;;;N;;;;;
+FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL;<initial> 06A4;;;;N;;;;;
+FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL;<medial> 06A4;;;;N;;;;;
+FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A6;;;;N;;;;;
+FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL;<final> 06A6;;;;N;;;;;
+FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL;<initial> 06A6;;;;N;;;;;
+FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A6;;;;N;;;;;
+FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL;<isolated> 0684;;;;N;;;;;
+FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL;<final> 0684;;;;N;;;;;
+FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL;<initial> 0684;;;;N;;;;;
+FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL;<medial> 0684;;;;N;;;;;
+FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL;<isolated> 0683;;;;N;;;;;
+FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL;<final> 0683;;;;N;;;;;
+FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL;<initial> 0683;;;;N;;;;;
+FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL;<medial> 0683;;;;N;;;;;
+FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL;<isolated> 0686;;;;N;;;;;
+FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL;<final> 0686;;;;N;;;;;
+FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL;<initial> 0686;;;;N;;;;;
+FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL;<medial> 0686;;;;N;;;;;
+FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0687;;;;N;;;;;
+FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL;<final> 0687;;;;N;;;;;
+FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL;<initial> 0687;;;;N;;;;;
+FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL;<medial> 0687;;;;N;;;;;
+FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068D;;;;N;;;;;
+FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL;<final> 068D;;;;N;;;;;
+FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068C;;;;N;;;;;
+FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL;<final> 068C;;;;N;;;;;
+FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL;<isolated> 068E;;;;N;;;;;
+FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL;<final> 068E;;;;N;;;;;
+FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL;<isolated> 0688;;;;N;;;;;
+FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL;<final> 0688;;;;N;;;;;
+FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL;<isolated> 0698;;;;N;;;;;
+FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL;<final> 0698;;;;N;;;;;
+FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL;<isolated> 0691;;;;N;;;;;
+FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL;<final> 0691;;;;N;;;;;
+FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A9;;;;N;;;;;
+FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL;<final> 06A9;;;;N;;;;;
+FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL;<initial> 06A9;;;;N;;;;;
+FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A9;;;;N;;;;;
+FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL;<isolated> 06AF;;;;N;;;;;
+FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL;<final> 06AF;;;;N;;;;;
+FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL;<initial> 06AF;;;;N;;;;;
+FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL;<medial> 06AF;;;;N;;;;;
+FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL;<isolated> 06B3;;;;N;;;;;
+FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL;<final> 06B3;;;;N;;;;;
+FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL;<initial> 06B3;;;;N;;;;;
+FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL;<medial> 06B3;;;;N;;;;;
+FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL;<isolated> 06B1;;;;N;;;;;
+FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL;<final> 06B1;;;;N;;;;;
+FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL;<initial> 06B1;;;;N;;;;;
+FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL;<medial> 06B1;;;;N;;;;;
+FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL;<isolated> 06BA;;;;N;;;;;
+FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL;<final> 06BA;;;;N;;;;;
+FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL;<isolated> 06BB;;;;N;;;;;
+FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL;<final> 06BB;;;;N;;;;;
+FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL;<initial> 06BB;;;;N;;;;;
+FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL;<medial> 06BB;;;;N;;;;;
+FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06C0;;;;N;;;;;
+FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL;<final> 06C0;;;;N;;;;;
+FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL;<isolated> 06C1;;;;N;;;;;
+FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL;<final> 06C1;;;;N;;;;;
+FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL;<initial> 06C1;;;;N;;;;;
+FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL;<medial> 06C1;;;;N;;;;;
+FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL;<isolated> 06BE;;;;N;;;;;
+FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL;<final> 06BE;;;;N;;;;;
+FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL;<initial> 06BE;;;;N;;;;;
+FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL;<medial> 06BE;;;;N;;;;;
+FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL;<isolated> 06D2;;;;N;;;;;
+FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL;<final> 06D2;;;;N;;;;;
+FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06D3;;;;N;;;;;
+FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 06D3;;;;N;;;;;
+FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL;<isolated> 06AD;;;;N;;;;;
+FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL;<final> 06AD;;;;N;;;;;
+FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL;<initial> 06AD;;;;N;;;;;
+FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL;<medial> 06AD;;;;N;;;;;
+FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL;<isolated> 06C7;;;;N;;;;;
+FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL;<final> 06C7;;;;N;;;;;
+FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL;<isolated> 06C6;;;;N;;;;;
+FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL;<final> 06C6;;;;N;;;;;
+FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL;<isolated> 06C8;;;;N;;;;;
+FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL;<final> 06C8;;;;N;;;;;
+FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0677;;;;N;;;;;
+FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL;<isolated> 06CB;;;;N;;;;;
+FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL;<final> 06CB;;;;N;;;;;
+FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL;<isolated> 06C5;;;;N;;;;;
+FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL;<final> 06C5;;;;N;;;;;
+FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL;<isolated> 06C9;;;;N;;;;;
+FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL;<final> 06C9;;;;N;;;;;
+FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL;<isolated> 06D0;;;;N;;;;;
+FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL;<final> 06D0;;;;N;;;;;
+FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL;<initial> 06D0;;;;N;;;;;
+FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL;<medial> 06D0;;;;N;;;;;
+FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0649;;;;N;;;;;
+FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL;<medial> 0649;;;;N;;;;;
+FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0626 0627;;;;N;;;;;
+FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL;<final> 0626 0627;;;;N;;;;;
+FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D5;;;;N;;;;;
+FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL;<final> 0626 06D5;;;;N;;;;;
+FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL;<isolated> 0626 0648;;;;N;;;;;
+FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL;<final> 0626 0648;;;;N;;;;;
+FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C7;;;;N;;;;;
+FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL;<final> 0626 06C7;;;;N;;;;;
+FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C6;;;;N;;;;;
+FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL;<final> 0626 06C6;;;;N;;;;;
+FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C8;;;;N;;;;;
+FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL;<final> 0626 06C8;;;;N;;;;;
+FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D0;;;;N;;;;;
+FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL;<final> 0626 06D0;;;;N;;;;;
+FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL;<initial> 0626 06D0;;;;N;;;;;
+FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0626 0649;;;;N;;;;;
+FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL;<isolated> 06CC;;;;N;;;;;
+FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL;<final> 06CC;;;;N;;;;;
+FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL;<initial> 06CC;;;;N;;;;;
+FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL;<medial> 06CC;;;;N;;;;;
+FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 062C;;;;N;;;;;
+FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0626 062D;;;;N;;;;;
+FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 0645;;;;N;;;;;
+FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0626 064A;;;;N;;;;;
+FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 062C;;;;N;;;;;
+FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062D;;;;N;;;;;
+FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062E;;;;N;;;;;
+FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 0645;;;;N;;;;;
+FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0628 0649;;;;N;;;;;
+FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0628 064A;;;;N;;;;;
+FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 062C;;;;N;;;;;
+FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062D;;;;N;;;;;
+FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062E;;;;N;;;;;
+FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 0645;;;;N;;;;;
+FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062A 0649;;;;N;;;;;
+FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062A 064A;;;;N;;;;;
+FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 062C;;;;N;;;;;
+FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 0645;;;;N;;;;;
+FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062B 0649;;;;N;;;;;
+FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062B 064A;;;;N;;;;;
+FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062C 062D;;;;N;;;;;
+FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C 0645;;;;N;;;;;
+FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 062C;;;;N;;;;;
+FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 0645;;;;N;;;;;
+FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 062C;;;;N;;;;;
+FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062E 062D;;;;N;;;;;
+FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 0645;;;;N;;;;;
+FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 062C;;;;N;;;;;
+FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062D;;;;N;;;;;
+FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062E;;;;N;;;;;
+FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 0645;;;;N;;;;;
+FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0635 062D;;;;N;;;;;
+FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0645;;;;N;;;;;
+FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 062C;;;;N;;;;;
+FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062D;;;;N;;;;;
+FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062E;;;;N;;;;;
+FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 0645;;;;N;;;;;
+FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0637 062D;;;;N;;;;;
+FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0637 0645;;;;N;;;;;
+FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0638 0645;;;;N;;;;;
+FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 062C;;;;N;;;;;
+FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 0645;;;;N;;;;;
+FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 062C;;;;N;;;;;
+FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 0645;;;;N;;;;;
+FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 062C;;;;N;;;;;
+FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062D;;;;N;;;;;
+FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062E;;;;N;;;;;
+FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 0645;;;;N;;;;;
+FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0641 0649;;;;N;;;;;
+FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0641 064A;;;;N;;;;;
+FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0642 062D;;;;N;;;;;
+FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0642 0645;;;;N;;;;;
+FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0642 0649;;;;N;;;;;
+FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0642 064A;;;;N;;;;;
+FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0643 0627;;;;N;;;;;
+FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 062C;;;;N;;;;;
+FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062D;;;;N;;;;;
+FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062E;;;;N;;;;;
+FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0644;;;;N;;;;;
+FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0645;;;;N;;;;;
+FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0643 0649;;;;N;;;;;
+FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0643 064A;;;;N;;;;;
+FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 062C;;;;N;;;;;
+FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062D;;;;N;;;;;
+FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062E;;;;N;;;;;
+FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 0645;;;;N;;;;;
+FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0644 0649;;;;N;;;;;
+FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0644 064A;;;;N;;;;;
+FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 062C;;;;N;;;;;
+FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D;;;;N;;;;;
+FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062E;;;;N;;;;;
+FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 0645;;;;N;;;;;
+FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0645 0649;;;;N;;;;;
+FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0645 064A;;;;N;;;;;
+FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 062C;;;;N;;;;;
+FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062D;;;;N;;;;;
+FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062E;;;;N;;;;;
+FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 0645;;;;N;;;;;
+FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0646 0649;;;;N;;;;;
+FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0646 064A;;;;N;;;;;
+FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 062C;;;;N;;;;;
+FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 0645;;;;N;;;;;
+FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0647 0649;;;;N;;;;;
+FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0647 064A;;;;N;;;;;
+FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 062C;;;;N;;;;;
+FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062D;;;;N;;;;;
+FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062E;;;;N;;;;;
+FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 0645;;;;N;;;;;
+FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 064A 0649;;;;N;;;;;
+FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A 064A;;;;N;;;;;
+FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0630 0670;;;;N;;;;;
+FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0631 0670;;;;N;;;;;
+FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0649 0670;;;;N;;;;;
+FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C 0651;;;;N;;;;;
+FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D 0651;;;;N;;;;;
+FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E 0651;;;;N;;;;;
+FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F 0651;;;;N;;;;;
+FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650 0651;;;;N;;;;;
+FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651 0670;;;;N;;;;;
+FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL;<final> 0626 0631;;;;N;;;;;
+FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0626 0632;;;;N;;;;;
+FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL;<final> 0626 0645;;;;N;;;;;
+FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL;<final> 0626 0646;;;;N;;;;;
+FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL;<final> 0626 064A;;;;N;;;;;
+FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL;<final> 0628 0631;;;;N;;;;;
+FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0628 0632;;;;N;;;;;
+FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0628 0645;;;;N;;;;;
+FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL;<final> 0628 0646;;;;N;;;;;
+FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0628 0649;;;;N;;;;;
+FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 064A;;;;N;;;;;
+FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL;<final> 062A 0631;;;;N;;;;;
+FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062A 0632;;;;N;;;;;
+FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062A 0645;;;;N;;;;;
+FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062A 0646;;;;N;;;;;
+FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0649;;;;N;;;;;
+FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 064A;;;;N;;;;;
+FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL;<final> 062B 0631;;;;N;;;;;
+FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062B 0632;;;;N;;;;;
+FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062B 0645;;;;N;;;;;
+FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062B 0646;;;;N;;;;;
+FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062B 0649;;;;N;;;;;
+FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062B 064A;;;;N;;;;;
+FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0641 0649;;;;N;;;;;
+FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 064A;;;;N;;;;;
+FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0642 0649;;;;N;;;;;
+FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 064A;;;;N;;;;;
+FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL;<final> 0643 0627;;;;N;;;;;
+FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL;<final> 0643 0644;;;;N;;;;;
+FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645;;;;N;;;;;
+FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0643 0649;;;;N;;;;;
+FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 064A;;;;N;;;;;
+FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 0645;;;;N;;;;;
+FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 0649;;;;N;;;;;
+FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 064A;;;;N;;;;;
+FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0645 0627;;;;N;;;;;
+FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0645 0645;;;;N;;;;;
+FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL;<final> 0646 0631;;;;N;;;;;
+FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0646 0632;;;;N;;;;;
+FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 0645;;;;N;;;;;
+FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL;<final> 0646 0646;;;;N;;;;;
+FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0649;;;;N;;;;;
+FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 064A;;;;N;;;;;
+FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL;<final> 0649 0670;;;;N;;;;;
+FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL;<final> 064A 0631;;;;N;;;;;
+FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 064A 0632;;;;N;;;;;
+FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645;;;;N;;;;;
+FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL;<final> 064A 0646;;;;N;;;;;
+FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 064A 0649;;;;N;;;;;
+FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 064A;;;;N;;;;;
+FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0626 062C;;;;N;;;;;
+FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0626 062D;;;;N;;;;;
+FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0626 062E;;;;N;;;;;
+FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0626 0645;;;;N;;;;;
+FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0626 0647;;;;N;;;;;
+FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0628 062C;;;;N;;;;;
+FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0628 062D;;;;N;;;;;
+FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0628 062E;;;;N;;;;;
+FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0628 0645;;;;N;;;;;
+FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0628 0647;;;;N;;;;;
+FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C;;;;N;;;;;
+FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 062D;;;;N;;;;;
+FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 062E;;;;N;;;;;
+FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645;;;;N;;;;;
+FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 062A 0647;;;;N;;;;;
+FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062B 0645;;;;N;;;;;
+FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 062D;;;;N;;;;;
+FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062C 0645;;;;N;;;;;
+FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062D 062C;;;;N;;;;;
+FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062D 0645;;;;N;;;;;
+FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062E 062C;;;;N;;;;;
+FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062E 0645;;;;N;;;;;
+FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062C;;;;N;;;;;
+FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062D;;;;N;;;;;
+FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0633 062E;;;;N;;;;;
+FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645;;;;N;;;;;
+FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D;;;;N;;;;;
+FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0635 062E;;;;N;;;;;
+FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645;;;;N;;;;;
+FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062C;;;;N;;;;;
+FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0636 062D;;;;N;;;;;
+FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0636 062E;;;;N;;;;;
+FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 0645;;;;N;;;;;
+FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 062D;;;;N;;;;;
+FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0638 0645;;;;N;;;;;
+FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C;;;;N;;;;;
+FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645;;;;N;;;;;
+FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 063A 062C;;;;N;;;;;
+FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 063A 0645;;;;N;;;;;
+FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062C;;;;N;;;;;
+FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0641 062D;;;;N;;;;;
+FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0641 062E;;;;N;;;;;
+FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 0645;;;;N;;;;;
+FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 062D;;;;N;;;;;
+FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0642 0645;;;;N;;;;;
+FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0643 062C;;;;N;;;;;
+FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0643 062D;;;;N;;;;;
+FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0643 062E;;;;N;;;;;
+FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL;<initial> 0643 0644;;;;N;;;;;
+FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645;;;;N;;;;;
+FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C;;;;N;;;;;
+FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 062D;;;;N;;;;;
+FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0644 062E;;;;N;;;;;
+FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645;;;;N;;;;;
+FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0644 0647;;;;N;;;;;
+FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C;;;;N;;;;;
+FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062D;;;;N;;;;;
+FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062E;;;;N;;;;;
+FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 0645;;;;N;;;;;
+FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C;;;;N;;;;;
+FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062D;;;;N;;;;;
+FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0646 062E;;;;N;;;;;
+FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 0645;;;;N;;;;;
+FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0646 0647;;;;N;;;;;
+FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 062C;;;;N;;;;;
+FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645;;;;N;;;;;
+FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL;<initial> 0647 0670;;;;N;;;;;
+FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 064A 062C;;;;N;;;;;
+FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 064A 062D;;;;N;;;;;
+FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 064A 062E;;;;N;;;;;
+FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645;;;;N;;;;;
+FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 064A 0647;;;;N;;;;;
+FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0626 0645;;;;N;;;;;
+FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0626 0647;;;;N;;;;;
+FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0628 0645;;;;N;;;;;
+FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0628 0647;;;;N;;;;;
+FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062A 0645;;;;N;;;;;
+FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062A 0647;;;;N;;;;;
+FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062B 0645;;;;N;;;;;
+FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062B 0647;;;;N;;;;;
+FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 0645;;;;N;;;;;
+FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0633 0647;;;;N;;;;;
+FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 0645;;;;N;;;;;
+FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0634 0647;;;;N;;;;;
+FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL;<medial> 0643 0644;;;;N;;;;;
+FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0643 0645;;;;N;;;;;
+FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0644 0645;;;;N;;;;;
+FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0646 0645;;;;N;;;;;
+FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0646 0647;;;;N;;;;;
+FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 064A 0645;;;;N;;;;;
+FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 064A 0647;;;;N;;;;;
+FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E 0651;;;;N;;;;;
+FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F 0651;;;;N;;;;;
+FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650 0651;;;;N;;;;;
+FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0637 0649;;;;N;;;;;
+FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0637 064A;;;;N;;;;;
+FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0639 0649;;;;N;;;;;
+FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0639 064A;;;;N;;;;;
+FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 063A 0649;;;;N;;;;;
+FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 063A 064A;;;;N;;;;;
+FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0633 0649;;;;N;;;;;
+FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0633 064A;;;;N;;;;;
+FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0634 0649;;;;N;;;;;
+FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0634 064A;;;;N;;;;;
+FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062D 0649;;;;N;;;;;
+FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062D 064A;;;;N;;;;;
+FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062C 0649;;;;N;;;;;
+FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062C 064A;;;;N;;;;;
+FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062E 0649;;;;N;;;;;
+FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062E 064A;;;;N;;;;;
+FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0649;;;;N;;;;;
+FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0635 064A;;;;N;;;;;
+FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0636 0649;;;;N;;;;;
+FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0636 064A;;;;N;;;;;
+FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 062C;;;;N;;;;;
+FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062D;;;;N;;;;;
+FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062E;;;;N;;;;;
+FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 0645;;;;N;;;;;
+FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0634 0631;;;;N;;;;;
+FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0633 0631;;;;N;;;;;
+FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0635 0631;;;;N;;;;;
+FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0636 0631;;;;N;;;;;
+FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0637 0649;;;;N;;;;;
+FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 064A;;;;N;;;;;
+FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0649;;;;N;;;;;
+FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 064A;;;;N;;;;;
+FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0649;;;;N;;;;;
+FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 064A;;;;N;;;;;
+FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 0649;;;;N;;;;;
+FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 064A;;;;N;;;;;
+FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0634 0649;;;;N;;;;;
+FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 064A;;;;N;;;;;
+FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0649;;;;N;;;;;
+FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 064A;;;;N;;;;;
+FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0649;;;;N;;;;;
+FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 064A;;;;N;;;;;
+FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062E 0649;;;;N;;;;;
+FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062E 064A;;;;N;;;;;
+FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0635 0649;;;;N;;;;;
+FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 064A;;;;N;;;;;
+FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 0649;;;;N;;;;;
+FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 064A;;;;N;;;;;
+FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL;<final> 0634 062C;;;;N;;;;;
+FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL;<final> 0634 062D;;;;N;;;;;
+FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 062E;;;;N;;;;;
+FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645;;;;N;;;;;
+FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0634 0631;;;;N;;;;;
+FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0633 0631;;;;N;;;;;
+FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL;<final> 0635 0631;;;;N;;;;;
+FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL;<final> 0636 0631;;;;N;;;;;
+FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062C;;;;N;;;;;
+FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0634 062D;;;;N;;;;;
+FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 062E;;;;N;;;;;
+FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645;;;;N;;;;;
+FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0633 0647;;;;N;;;;;
+FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0634 0647;;;;N;;;;;
+FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645;;;;N;;;;;
+FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 062C;;;;N;;;;;
+FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062D;;;;N;;;;;
+FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062E;;;;N;;;;;
+FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 062C;;;;N;;;;;
+FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062D;;;;N;;;;;
+FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062E;;;;N;;;;;
+FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;;;;;
+FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;;
+FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;;
+FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;;
+FD3E;ORNATE LEFT PARENTHESIS;Ps;0;ON;;;;;N;;;;;
+FD3F;ORNATE RIGHT PARENTHESIS;Pe;0;ON;;;;;N;;;;;
+FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;;
+FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;;
+FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;;
+FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 0645;;;;N;;;;;
+FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062E 0645;;;;N;;;;;
+FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062C;;;;N;;;;;
+FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062D;;;;N;;;;;
+FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062E;;;;N;;;;;
+FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 062C 0645 062D;;;;N;;;;;
+FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 0645 062D;;;;N;;;;;
+FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 0645 064A;;;;N;;;;;
+FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0645 0649;;;;N;;;;;
+FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062D 062C;;;;N;;;;;
+FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062C 062D;;;;N;;;;;
+FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062C 0649;;;;N;;;;;
+FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0633 0645 062D;;;;N;;;;;
+FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062D;;;;N;;;;;
+FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062C;;;;N;;;;;
+FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0633 0645 0645;;;;N;;;;;
+FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 0645;;;;N;;;;;
+FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL;<final> 0635 062D 062D;;;;N;;;;;
+FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D 062D;;;;N;;;;;
+FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0635 0645 0645;;;;N;;;;;
+FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 062D 0645;;;;N;;;;;
+FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062D 0645;;;;N;;;;;
+FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062C 064A;;;;N;;;;;
+FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 0645 062E;;;;N;;;;;
+FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 0645 062E;;;;N;;;;;
+FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645 0645;;;;N;;;;;
+FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645 0645;;;;N;;;;;
+FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 062D 0649;;;;N;;;;;
+FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0636 062E 0645;;;;N;;;;;
+FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062E 0645;;;;N;;;;;
+FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0637 0645 062D;;;;N;;;;;
+FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 0645 062D;;;;N;;;;;
+FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645 0645;;;;N;;;;;
+FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 0645 064A;;;;N;;;;;
+FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 062C 0645;;;;N;;;;;
+FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 0645 0645;;;;N;;;;;
+FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645 0645;;;;N;;;;;
+FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0645 0649;;;;N;;;;;
+FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 063A 0645 0645;;;;N;;;;;
+FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 0645 064A;;;;N;;;;;
+FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0645 0649;;;;N;;;;;
+FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0641 062E 0645;;;;N;;;;;
+FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062E 0645;;;;N;;;;;
+FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0642 0645 062D;;;;N;;;;;
+FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0642 0645 0645;;;;N;;;;;
+FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062D 0645;;;;N;;;;;
+FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062D 064A;;;;N;;;;;
+FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 062D 0649;;;;N;;;;;
+FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 062C;;;;N;;;;;
+FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 062C;;;;N;;;;;
+FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062E 0645;;;;N;;;;;
+FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062E 0645;;;;N;;;;;
+FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0644 0645 062D;;;;N;;;;;
+FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062D;;;;N;;;;;
+FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 062C;;;;N;;;;;
+FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 0645;;;;N;;;;;
+FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062D 064A;;;;N;;;;;
+FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062D;;;;N;;;;;
+FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C 0645;;;;N;;;;;
+FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 062C;;;;N;;;;;
+FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 0645;;;;N;;;;;
+FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062E;;;;N;;;;;
+FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 062C;;;;N;;;;;
+FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 0645;;;;N;;;;;
+FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062D 0645;;;;N;;;;;
+FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062D 0649;;;;N;;;;;
+FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 062C 0645;;;;N;;;;;
+FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C 0645;;;;N;;;;;
+FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062C 0649;;;;N;;;;;
+FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 0645 064A;;;;N;;;;;
+FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0645 0649;;;;N;;;;;
+FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645 0645;;;;N;;;;;
+FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645 0645;;;;N;;;;;
+FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062E 064A;;;;N;;;;;
+FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062C 064A;;;;N;;;;;
+FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062C 0649;;;;N;;;;;
+FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062E 064A;;;;N;;;;;
+FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062E 0649;;;;N;;;;;
+FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 0645 064A;;;;N;;;;;
+FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0645 0649;;;;N;;;;;
+FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 0645 064A;;;;N;;;;;
+FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 062D 0649;;;;N;;;;;
+FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0645 0649;;;;N;;;;;
+FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062E 0649;;;;N;;;;;
+FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 062D 064A;;;;N;;;;;
+FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062D 064A;;;;N;;;;;
+FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 062D 064A;;;;N;;;;;
+FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062C 064A;;;;N;;;;;
+FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 0645 064A;;;;N;;;;;
+FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062D 064A;;;;N;;;;;
+FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062C 064A;;;;N;;;;;
+FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 0645 064A;;;;N;;;;;
+FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 0645 064A;;;;N;;;;;
+FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 0645 064A;;;;N;;;;;
+FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062D 064A;;;;N;;;;;
+FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 0645 062D;;;;N;;;;;
+FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062D 0645;;;;N;;;;;
+FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 0645 064A;;;;N;;;;;
+FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 0645 064A;;;;N;;;;;
+FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062C 062D;;;;N;;;;;
+FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062E 064A;;;;N;;;;;
+FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 0645;;;;N;;;;;
+FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645 0645;;;;N;;;;;
+FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 0645;;;;N;;;;;
+FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0646 062C 062D;;;;N;;;;;
+FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 062D 064A;;;;N;;;;;
+FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 062C 064A;;;;N;;;;;
+FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062C 064A;;;;N;;;;;
+FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 0645 064A;;;;N;;;;;
+FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062D 064A;;;;N;;;;;
+FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645 0645;;;;N;;;;;
+FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C 0645;;;;N;;;;;
+FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645 0645;;;;N;;;;;
+FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 062E 064A;;;;N;;;;;
+FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062C 064A;;;;N;;;;;
+FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 06D2;;;;N;;;;;
+FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0642 0644 06D2;;;;N;;;;;
+FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL;<isolated> 0627 0644 0644 0647;;;;N;;;;;
+FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL;<isolated> 0627 0643 0628 0631;;;;N;;;;;
+FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D 0645 062F;;;;N;;;;;
+FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0639 0645;;;;N;;;;;
+FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL;<isolated> 0631 0633 0648 0644;;;;N;;;;;
+FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL;<isolated> 0639 0644 064A 0647;;;;N;;;;;
+FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL;<isolated> 0648 0633 0644 0645;;;;N;;;;;
+FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0649;;;;N;;;;;
+FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL;<isolated> 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;;
+FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL;<isolated> 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;;
+FDFC;RIAL SIGN;Sc;0;AL;<isolated> 0631 06CC 0627 0644;;;;N;;;;;
+FDFD;ARABIC LIGATURE BISMILLAH AR-RAHMAN AR-RAHEEM;So;0;ON;;;;;N;;;;;
+FE00;VARIATION SELECTOR-1;Mn;0;NSM;;;;;N;;;;;
+FE01;VARIATION SELECTOR-2;Mn;0;NSM;;;;;N;;;;;
+FE02;VARIATION SELECTOR-3;Mn;0;NSM;;;;;N;;;;;
+FE03;VARIATION SELECTOR-4;Mn;0;NSM;;;;;N;;;;;
+FE04;VARIATION SELECTOR-5;Mn;0;NSM;;;;;N;;;;;
+FE05;VARIATION SELECTOR-6;Mn;0;NSM;;;;;N;;;;;
+FE06;VARIATION SELECTOR-7;Mn;0;NSM;;;;;N;;;;;
+FE07;VARIATION SELECTOR-8;Mn;0;NSM;;;;;N;;;;;
+FE08;VARIATION SELECTOR-9;Mn;0;NSM;;;;;N;;;;;
+FE09;VARIATION SELECTOR-10;Mn;0;NSM;;;;;N;;;;;
+FE0A;VARIATION SELECTOR-11;Mn;0;NSM;;;;;N;;;;;
+FE0B;VARIATION SELECTOR-12;Mn;0;NSM;;;;;N;;;;;
+FE0C;VARIATION SELECTOR-13;Mn;0;NSM;;;;;N;;;;;
+FE0D;VARIATION SELECTOR-14;Mn;0;NSM;;;;;N;;;;;
+FE0E;VARIATION SELECTOR-15;Mn;0;NSM;;;;;N;;;;;
+FE0F;VARIATION SELECTOR-16;Mn;0;NSM;;;;;N;;;;;
+FE10;PRESENTATION FORM FOR VERTICAL COMMA;Po;0;ON;<vertical> 002C;;;;N;;;;;
+FE11;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA;Po;0;ON;<vertical> 3001;;;;N;;;;;
+FE12;PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP;Po;0;ON;<vertical> 3002;;;;N;;;;;
+FE13;PRESENTATION FORM FOR VERTICAL COLON;Po;0;ON;<vertical> 003A;;;;N;;;;;
+FE14;PRESENTATION FORM FOR VERTICAL SEMICOLON;Po;0;ON;<vertical> 003B;;;;N;;;;;
+FE15;PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK;Po;0;ON;<vertical> 0021;;;;N;;;;;
+FE16;PRESENTATION FORM FOR VERTICAL QUESTION MARK;Po;0;ON;<vertical> 003F;;;;N;;;;;
+FE17;PRESENTATION FORM FOR VERTICAL LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;<vertical> 3016;;;;N;;;;;
+FE18;PRESENTATION FORM FOR VERTICAL RIGHT WHITE LENTICULAR BRAKCET;Pe;0;ON;<vertical> 3017;;;;N;;;;;
+FE19;PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS;Po;0;ON;<vertical> 2026;;;;N;;;;;
+FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;;
+FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;;
+FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;;
+FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;;
+FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;;
+FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON;<vertical> 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;;
+FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON;<vertical> 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;;
+FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON;<vertical> 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;;
+FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON;<vertical> 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;;
+FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<vertical> 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;;
+FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<vertical> 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;;
+FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;<vertical> 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;;
+FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;<vertical> 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;;
+FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;<vertical> 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;;
+FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;<vertical> 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;;
+FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON;<vertical> 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;;
+FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON;<vertical> 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;;
+FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON;<vertical> 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;;
+FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON;<vertical> 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;;
+FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON;<vertical> 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;;
+FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON;<vertical> 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;;
+FE45;SESAME DOT;Po;0;ON;;;;;N;;;;;
+FE46;WHITE SESAME DOT;Po;0;ON;;;;;N;;;;;
+FE47;PRESENTATION FORM FOR VERTICAL LEFT SQUARE BRACKET;Ps;0;ON;<vertical> 005B;;;;N;;;;;
+FE48;PRESENTATION FORM FOR VERTICAL RIGHT SQUARE BRACKET;Pe;0;ON;<vertical> 005D;;;;N;;;;;
+FE49;DASHED OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DASHED OVERSCORE;;;;
+FE4A;CENTRELINE OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;;
+FE4B;WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING WAVY OVERSCORE;;;;
+FE4C;DOUBLE WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;;
+FE4D;DASHED LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING DASHED UNDERSCORE;;;;
+FE4E;CENTRELINE LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;;
+FE4F;WAVY LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING WAVY UNDERSCORE;;;;
+FE50;SMALL COMMA;Po;0;CS;<small> 002C;;;;N;;;;;
+FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON;<small> 3001;;;;N;;;;;
+FE52;SMALL FULL STOP;Po;0;CS;<small> 002E;;;;N;SMALL PERIOD;;;;
+FE54;SMALL SEMICOLON;Po;0;ON;<small> 003B;;;;N;;;;;
+FE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;;
+FE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;;
+FE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;;
+FE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;;
+FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;N;SMALL OPENING PARENTHESIS;;;;
+FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;N;SMALL CLOSING PARENTHESIS;;;;
+FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;N;SMALL OPENING CURLY BRACKET;;;;
+FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;N;SMALL CLOSING CURLY BRACKET;;;;
+FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;N;SMALL OPENING TORTOISE SHELL BRACKET;;;;
+FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;N;SMALL CLOSING TORTOISE SHELL BRACKET;;;;
+FE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;;
+FE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;;
+FE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;;
+FE62;SMALL PLUS SIGN;Sm;0;ES;<small> 002B;;;;N;;;;;
+FE63;SMALL HYPHEN-MINUS;Pd;0;ES;<small> 002D;;;;N;;;;;
+FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;N;;;;;
+FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;N;;;;;
+FE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;;
+FE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;;
+FE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;;
+FE6A;SMALL PERCENT SIGN;Po;0;ET;<small> 0025;;;;N;;;;;
+FE6B;SMALL COMMERCIAL AT;Po;0;ON;<small> 0040;;;;N;;;;;
+FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;;
+FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL;<medial> 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;;
+FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;;
+FE73;ARABIC TAIL FRAGMENT;Lo;0;AL;;;;;N;;;;;
+FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;;
+FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E;;;;N;ARABIC SPACING FATHAH;;;;
+FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;;
+FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;;
+FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;;
+FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650;;;;N;ARABIC SPACING KASRAH;;;;
+FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;;
+FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;;
+FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL;<medial> 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;;
+FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL;<isolated> 0020 0652;;;;N;ARABIC SPACING SUKUN;;;;
+FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL;<medial> 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;;
+FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL;<isolated> 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;;
+FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;;
+FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;;
+FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;;
+FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;;
+FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;;
+FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;;
+FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;;
+FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;;
+FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;;
+FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;;
+FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL;<initial> 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;;
+FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL;<medial> 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;;
+FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;;
+FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL;<final> 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;;
+FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL;<isolated> 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;;
+FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL;<final> 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;;
+FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL;<initial> 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;;
+FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL;<medial> 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;;
+FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL;<isolated> 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;;
+FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL;<final> 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;;
+FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL;<isolated> 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;;
+FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL;<final> 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;;
+FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL;<initial> 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;;
+FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL;<medial> 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;;
+FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL;<isolated> 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;;
+FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL;<final> 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;;
+FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL;<initial> 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;;
+FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL;<medial> 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;;
+FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;;
+FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL;<final> 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;;
+FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL;<initial> 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;;
+FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL;<medial> 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;;
+FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL;<isolated> 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;;
+FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL;<final> 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;;
+FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL;<initial> 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;;
+FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL;<medial> 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;;
+FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;;
+FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL;<final> 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;;
+FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL;<initial> 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;;
+FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL;<medial> 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;;
+FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL;<isolated> 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;;
+FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL;<final> 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;;
+FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL;<isolated> 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;;
+FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL;<final> 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;;
+FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL;<isolated> 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;;
+FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL;<final> 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;;
+FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL;<isolated> 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;;
+FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL;<final> 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;;
+FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL;<isolated> 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;;
+FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL;<final> 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;;
+FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL;<initial> 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;;
+FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL;<medial> 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;;
+FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL;<isolated> 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;;
+FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL;<final> 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;;
+FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL;<initial> 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;;
+FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL;<medial> 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;;
+FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL;<isolated> 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;;
+FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL;<final> 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;;
+FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL;<initial> 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;;
+FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL;<medial> 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;;
+FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL;<isolated> 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;;
+FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL;<final> 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;;
+FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL;<initial> 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;;
+FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL;<medial> 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;;
+FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL;<isolated> 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;;
+FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL;<final> 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;;
+FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL;<initial> 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;;
+FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL;<medial> 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;;
+FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL;<isolated> 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;;
+FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL;<final> 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;;
+FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL;<initial> 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;;
+FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL;<medial> 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;;
+FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL;<isolated> 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;;
+FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL;<final> 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;;
+FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL;<initial> 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;;
+FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL;<medial> 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;;
+FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL;<isolated> 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;;
+FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL;<final> 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;;
+FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL;<initial> 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;;
+FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL;<medial> 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;;
+FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL;<isolated> 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;;
+FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL;<final> 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;;
+FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL;<initial> 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;;
+FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL;<medial> 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;;
+FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL;<isolated> 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;;
+FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL;<final> 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;;
+FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL;<initial> 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;;
+FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL;<medial> 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;;
+FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL;<isolated> 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;;
+FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL;<final> 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;;
+FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL;<initial> 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;;
+FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL;<medial> 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;;
+FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL;<isolated> 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;;
+FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL;<final> 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;;
+FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL;<initial> 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;;
+FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL;<medial> 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;;
+FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;;
+FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL;<final> 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;;
+FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL;<initial> 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;;
+FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL;<medial> 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;;
+FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL;<isolated> 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;;
+FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL;<final> 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;;
+FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL;<initial> 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;;
+FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL;<medial> 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;;
+FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL;<isolated> 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;;
+FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL;<final> 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;;
+FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL;<initial> 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;;
+FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL;<medial> 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;;
+FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL;<isolated> 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;;
+FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL;<final> 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;;
+FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;;
+FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;;
+FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;;
+FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL;<final> 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;;
+FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL;<initial> 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;;
+FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL;<medial> 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;;
+FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;;
+FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;;
+FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
+FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON;<wide> 0021;;;;N;;;;;
+FF02;FULLWIDTH QUOTATION MARK;Po;0;ON;<wide> 0022;;;;N;;;;;
+FF03;FULLWIDTH NUMBER SIGN;Po;0;ET;<wide> 0023;;;;N;;;;;
+FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET;<wide> 0024;;;;N;;;;;
+FF05;FULLWIDTH PERCENT SIGN;Po;0;ET;<wide> 0025;;;;N;;;;;
+FF06;FULLWIDTH AMPERSAND;Po;0;ON;<wide> 0026;;;;N;;;;;
+FF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;;
+FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;Y;FULLWIDTH OPENING PARENTHESIS;;;;
+FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;Y;FULLWIDTH CLOSING PARENTHESIS;;;;
+FF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;;
+FF0B;FULLWIDTH PLUS SIGN;Sm;0;ES;<wide> 002B;;;;N;;;;;
+FF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;;
+FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ES;<wide> 002D;;;;N;;;;;
+FF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;;
+FF0F;FULLWIDTH SOLIDUS;Po;0;CS;<wide> 002F;;;;N;FULLWIDTH SLASH;;;;
+FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;;
+FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;;
+FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;;
+FF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;;
+FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;;
+FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;;
+FF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;;
+FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;;
+FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;;
+FF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 0039;9;9;9;N;;;;;
+FF1A;FULLWIDTH COLON;Po;0;CS;<wide> 003A;;;;N;;;;;
+FF1B;FULLWIDTH SEMICOLON;Po;0;ON;<wide> 003B;;;;N;;;;;
+FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON;<wide> 003C;;;;Y;;;;;
+FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON;<wide> 003D;;;;N;;;;;
+FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON;<wide> 003E;;;;Y;;;;;
+FF1F;FULLWIDTH QUESTION MARK;Po;0;ON;<wide> 003F;;;;N;;;;;
+FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON;<wide> 0040;;;;N;;;;;
+FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L;<wide> 0041;;;;N;;;;FF41;
+FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L;<wide> 0042;;;;N;;;;FF42;
+FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L;<wide> 0043;;;;N;;;;FF43;
+FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L;<wide> 0044;;;;N;;;;FF44;
+FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L;<wide> 0045;;;;N;;;;FF45;
+FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L;<wide> 0046;;;;N;;;;FF46;
+FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L;<wide> 0047;;;;N;;;;FF47;
+FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L;<wide> 0048;;;;N;;;;FF48;
+FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L;<wide> 0049;;;;N;;;;FF49;
+FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L;<wide> 004A;;;;N;;;;FF4A;
+FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L;<wide> 004B;;;;N;;;;FF4B;
+FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L;<wide> 004C;;;;N;;;;FF4C;
+FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L;<wide> 004D;;;;N;;;;FF4D;
+FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L;<wide> 004E;;;;N;;;;FF4E;
+FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L;<wide> 004F;;;;N;;;;FF4F;
+FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L;<wide> 0050;;;;N;;;;FF50;
+FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L;<wide> 0051;;;;N;;;;FF51;
+FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L;<wide> 0052;;;;N;;;;FF52;
+FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L;<wide> 0053;;;;N;;;;FF53;
+FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L;<wide> 0054;;;;N;;;;FF54;
+FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L;<wide> 0055;;;;N;;;;FF55;
+FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L;<wide> 0056;;;;N;;;;FF56;
+FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L;<wide> 0057;;;;N;;;;FF57;
+FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L;<wide> 0058;;;;N;;;;FF58;
+FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L;<wide> 0059;;;;N;;;;FF59;
+FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L;<wide> 005A;;;;N;;;;FF5A;
+FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON;<wide> 005B;;;;Y;FULLWIDTH OPENING SQUARE BRACKET;;;;
+FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON;<wide> 005C;;;;N;FULLWIDTH BACKSLASH;;;;
+FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON;<wide> 005D;;;;Y;FULLWIDTH CLOSING SQUARE BRACKET;;;;
+FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON;<wide> 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;;
+FF3F;FULLWIDTH LOW LINE;Pc;0;ON;<wide> 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;;
+FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON;<wide> 0060;;;;N;FULLWIDTH SPACING GRAVE;;;;
+FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L;<wide> 0061;;;;N;;;FF21;;FF21
+FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L;<wide> 0062;;;;N;;;FF22;;FF22
+FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L;<wide> 0063;;;;N;;;FF23;;FF23
+FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L;<wide> 0064;;;;N;;;FF24;;FF24
+FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L;<wide> 0065;;;;N;;;FF25;;FF25
+FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L;<wide> 0066;;;;N;;;FF26;;FF26
+FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L;<wide> 0067;;;;N;;;FF27;;FF27
+FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L;<wide> 0068;;;;N;;;FF28;;FF28
+FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L;<wide> 0069;;;;N;;;FF29;;FF29
+FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L;<wide> 006A;;;;N;;;FF2A;;FF2A
+FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L;<wide> 006B;;;;N;;;FF2B;;FF2B
+FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L;<wide> 006C;;;;N;;;FF2C;;FF2C
+FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L;<wide> 006D;;;;N;;;FF2D;;FF2D
+FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L;<wide> 006E;;;;N;;;FF2E;;FF2E
+FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L;<wide> 006F;;;;N;;;FF2F;;FF2F
+FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L;<wide> 0070;;;;N;;;FF30;;FF30
+FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L;<wide> 0071;;;;N;;;FF31;;FF31
+FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L;<wide> 0072;;;;N;;;FF32;;FF32
+FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L;<wide> 0073;;;;N;;;FF33;;FF33
+FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L;<wide> 0074;;;;N;;;FF34;;FF34
+FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L;<wide> 0075;;;;N;;;FF35;;FF35
+FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L;<wide> 0076;;;;N;;;FF36;;FF36
+FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L;<wide> 0077;;;;N;;;FF37;;FF37
+FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L;<wide> 0078;;;;N;;;FF38;;FF38
+FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L;<wide> 0079;;;;N;;;FF39;;FF39
+FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L;<wide> 007A;;;;N;;;FF3A;;FF3A
+FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON;<wide> 007B;;;;Y;FULLWIDTH OPENING CURLY BRACKET;;;;
+FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON;<wide> 007C;;;;N;FULLWIDTH VERTICAL BAR;;;;
+FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON;<wide> 007D;;;;Y;FULLWIDTH CLOSING CURLY BRACKET;;;;
+FF5E;FULLWIDTH TILDE;Sm;0;ON;<wide> 007E;;;;N;FULLWIDTH SPACING TILDE;;;;
+FF5F;FULLWIDTH LEFT WHITE PARENTHESIS;Ps;0;ON;<wide> 2985;;;;Y;;*;;;
+FF60;FULLWIDTH RIGHT WHITE PARENTHESIS;Pe;0;ON;<wide> 2986;;;;Y;;*;;;
+FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;;
+FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;Y;HALFWIDTH OPENING CORNER BRACKET;;;;
+FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;Y;HALFWIDTH CLOSING CORNER BRACKET;;;;
+FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;;
+FF65;HALFWIDTH KATAKANA MIDDLE DOT;Po;0;ON;<narrow> 30FB;;;;N;;;;;
+FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;;
+FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;;
+FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;;
+FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L;<narrow> 30A5;;;;N;;;;;
+FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L;<narrow> 30A7;;;;N;;;;;
+FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L;<narrow> 30A9;;;;N;;;;;
+FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L;<narrow> 30E3;;;;N;;;;;
+FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L;<narrow> 30E5;;;;N;;;;;
+FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L;<narrow> 30E7;;;;N;;;;;
+FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L;<narrow> 30C3;;;;N;;;;;
+FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;<narrow> 30FC;;;;N;;;;;
+FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L;<narrow> 30A2;;;;N;;;;;
+FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L;<narrow> 30A4;;;;N;;;;;
+FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L;<narrow> 30A6;;;;N;;;;;
+FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L;<narrow> 30A8;;;;N;;;;;
+FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L;<narrow> 30AA;;;;N;;;;;
+FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L;<narrow> 30AB;;;;N;;;;;
+FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L;<narrow> 30AD;;;;N;;;;;
+FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L;<narrow> 30AF;;;;N;;;;;
+FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L;<narrow> 30B1;;;;N;;;;;
+FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L;<narrow> 30B3;;;;N;;;;;
+FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L;<narrow> 30B5;;;;N;;;;;
+FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L;<narrow> 30B7;;;;N;;;;;
+FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L;<narrow> 30B9;;;;N;;;;;
+FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L;<narrow> 30BB;;;;N;;;;;
+FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L;<narrow> 30BD;;;;N;;;;;
+FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L;<narrow> 30BF;;;;N;;;;;
+FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L;<narrow> 30C1;;;;N;;;;;
+FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L;<narrow> 30C4;;;;N;;;;;
+FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L;<narrow> 30C6;;;;N;;;;;
+FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L;<narrow> 30C8;;;;N;;;;;
+FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L;<narrow> 30CA;;;;N;;;;;
+FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L;<narrow> 30CB;;;;N;;;;;
+FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L;<narrow> 30CC;;;;N;;;;;
+FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L;<narrow> 30CD;;;;N;;;;;
+FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L;<narrow> 30CE;;;;N;;;;;
+FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L;<narrow> 30CF;;;;N;;;;;
+FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L;<narrow> 30D2;;;;N;;;;;
+FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L;<narrow> 30D5;;;;N;;;;;
+FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L;<narrow> 30D8;;;;N;;;;;
+FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L;<narrow> 30DB;;;;N;;;;;
+FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L;<narrow> 30DE;;;;N;;;;;
+FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L;<narrow> 30DF;;;;N;;;;;
+FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L;<narrow> 30E0;;;;N;;;;;
+FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L;<narrow> 30E1;;;;N;;;;;
+FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L;<narrow> 30E2;;;;N;;;;;
+FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L;<narrow> 30E4;;;;N;;;;;
+FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L;<narrow> 30E6;;;;N;;;;;
+FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L;<narrow> 30E8;;;;N;;;;;
+FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L;<narrow> 30E9;;;;N;;;;;
+FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L;<narrow> 30EA;;;;N;;;;;
+FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L;<narrow> 30EB;;;;N;;;;;
+FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L;<narrow> 30EC;;;;N;;;;;
+FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L;<narrow> 30ED;;;;N;;;;;
+FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L;<narrow> 30EF;;;;N;;;;;
+FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L;<narrow> 30F3;;;;N;;;;;
+FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;halfwidth katakana-hiragana voiced sound mark;;;
+FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;halfwidth katakana-hiragana semi-voiced sound mark;;;
+FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L;<narrow> 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;;
+FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L;<narrow> 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;;
+FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L;<narrow> 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;;
+FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;;
+FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L;<narrow> 3134;;;;N;;;;;
+FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<narrow> 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;;
+FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<narrow> 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;;
+FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L;<narrow> 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;;
+FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L;<narrow> 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;;
+FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L;<narrow> 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;;
+FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<narrow> 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;;
+FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<narrow> 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;;
+FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<narrow> 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;;
+FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L;<narrow> 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;;
+FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<narrow> 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;;
+FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<narrow> 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;;
+FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<narrow> 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;;
+FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L;<narrow> 3141;;;;N;;;;;
+FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L;<narrow> 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;;
+FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L;<narrow> 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;;
+FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L;<narrow> 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;;
+FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L;<narrow> 3145;;;;N;;;;;
+FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L;<narrow> 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;;
+FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L;<narrow> 3147;;;;N;;;;;
+FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L;<narrow> 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;;
+FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L;<narrow> 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;;
+FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L;<narrow> 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;;
+FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L;<narrow> 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;;
+FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L;<narrow> 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;;
+FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L;<narrow> 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;;
+FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L;<narrow> 314E;;;;N;;;;;
+FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L;<narrow> 314F;;;;N;;;;;
+FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L;<narrow> 3150;;;;N;;;;;
+FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L;<narrow> 3151;;;;N;;;;;
+FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L;<narrow> 3152;;;;N;;;;;
+FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L;<narrow> 3153;;;;N;;;;;
+FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L;<narrow> 3154;;;;N;;;;;
+FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L;<narrow> 3155;;;;N;;;;;
+FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L;<narrow> 3156;;;;N;;;;;
+FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L;<narrow> 3157;;;;N;;;;;
+FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L;<narrow> 3158;;;;N;;;;;
+FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L;<narrow> 3159;;;;N;;;;;
+FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L;<narrow> 315A;;;;N;;;;;
+FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L;<narrow> 315B;;;;N;;;;;
+FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L;<narrow> 315C;;;;N;;;;;
+FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L;<narrow> 315D;;;;N;;;;;
+FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L;<narrow> 315E;;;;N;;;;;
+FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L;<narrow> 315F;;;;N;;;;;
+FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L;<narrow> 3160;;;;N;;;;;
+FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L;<narrow> 3161;;;;N;;;;;
+FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L;<narrow> 3162;;;;N;;;;;
+FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;;
+FFE0;FULLWIDTH CENT SIGN;Sc;0;ET;<wide> 00A2;;;;N;;;;;
+FFE1;FULLWIDTH POUND SIGN;Sc;0;ET;<wide> 00A3;;;;N;;;;;
+FFE2;FULLWIDTH NOT SIGN;Sm;0;ON;<wide> 00AC;;;;N;;;;;
+FFE3;FULLWIDTH MACRON;Sk;0;ON;<wide> 00AF;;;;N;FULLWIDTH SPACING MACRON;*;;;
+FFE4;FULLWIDTH BROKEN BAR;So;0;ON;<wide> 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;;
+FFE5;FULLWIDTH YEN SIGN;Sc;0;ET;<wide> 00A5;;;;N;;;;;
+FFE6;FULLWIDTH WON SIGN;Sc;0;ET;<wide> 20A9;;;;N;;;;;
+FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON;<narrow> 2502;;;;N;;;;;
+FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON;<narrow> 2190;;;;N;;;;;
+FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON;<narrow> 2191;;;;N;;;;;
+FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;;
+FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;;
+FFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;;
+FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;;
+FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;ON;;;;;N;;;;;
+FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;ON;;;;;N;;;;;
+FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;ON;;;;;N;;;;;
+FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+10000;LINEAR B SYLLABLE B008 A;Lo;0;L;;;;;N;;;;;
+10001;LINEAR B SYLLABLE B038 E;Lo;0;L;;;;;N;;;;;
+10002;LINEAR B SYLLABLE B028 I;Lo;0;L;;;;;N;;;;;
+10003;LINEAR B SYLLABLE B061 O;Lo;0;L;;;;;N;;;;;
+10004;LINEAR B SYLLABLE B010 U;Lo;0;L;;;;;N;;;;;
+10005;LINEAR B SYLLABLE B001 DA;Lo;0;L;;;;;N;;;;;
+10006;LINEAR B SYLLABLE B045 DE;Lo;0;L;;;;;N;;;;;
+10007;LINEAR B SYLLABLE B007 DI;Lo;0;L;;;;;N;;;;;
+10008;LINEAR B SYLLABLE B014 DO;Lo;0;L;;;;;N;;;;;
+10009;LINEAR B SYLLABLE B051 DU;Lo;0;L;;;;;N;;;;;
+1000A;LINEAR B SYLLABLE B057 JA;Lo;0;L;;;;;N;;;;;
+1000B;LINEAR B SYLLABLE B046 JE;Lo;0;L;;;;;N;;;;;
+1000D;LINEAR B SYLLABLE B036 JO;Lo;0;L;;;;;N;;;;;
+1000E;LINEAR B SYLLABLE B065 JU;Lo;0;L;;;;;N;;;;;
+1000F;LINEAR B SYLLABLE B077 KA;Lo;0;L;;;;;N;;;;;
+10010;LINEAR B SYLLABLE B044 KE;Lo;0;L;;;;;N;;;;;
+10011;LINEAR B SYLLABLE B067 KI;Lo;0;L;;;;;N;;;;;
+10012;LINEAR B SYLLABLE B070 KO;Lo;0;L;;;;;N;;;;;
+10013;LINEAR B SYLLABLE B081 KU;Lo;0;L;;;;;N;;;;;
+10014;LINEAR B SYLLABLE B080 MA;Lo;0;L;;;;;N;;;;;
+10015;LINEAR B SYLLABLE B013 ME;Lo;0;L;;;;;N;;;;;
+10016;LINEAR B SYLLABLE B073 MI;Lo;0;L;;;;;N;;;;;
+10017;LINEAR B SYLLABLE B015 MO;Lo;0;L;;;;;N;;;;;
+10018;LINEAR B SYLLABLE B023 MU;Lo;0;L;;;;;N;;;;;
+10019;LINEAR B SYLLABLE B006 NA;Lo;0;L;;;;;N;;;;;
+1001A;LINEAR B SYLLABLE B024 NE;Lo;0;L;;;;;N;;;;;
+1001B;LINEAR B SYLLABLE B030 NI;Lo;0;L;;;;;N;;;;;
+1001C;LINEAR B SYLLABLE B052 NO;Lo;0;L;;;;;N;;;;;
+1001D;LINEAR B SYLLABLE B055 NU;Lo;0;L;;;;;N;;;;;
+1001E;LINEAR B SYLLABLE B003 PA;Lo;0;L;;;;;N;;;;;
+1001F;LINEAR B SYLLABLE B072 PE;Lo;0;L;;;;;N;;;;;
+10020;LINEAR B SYLLABLE B039 PI;Lo;0;L;;;;;N;;;;;
+10021;LINEAR B SYLLABLE B011 PO;Lo;0;L;;;;;N;;;;;
+10022;LINEAR B SYLLABLE B050 PU;Lo;0;L;;;;;N;;;;;
+10023;LINEAR B SYLLABLE B016 QA;Lo;0;L;;;;;N;;;;;
+10024;LINEAR B SYLLABLE B078 QE;Lo;0;L;;;;;N;;;;;
+10025;LINEAR B SYLLABLE B021 QI;Lo;0;L;;;;;N;;;;;
+10026;LINEAR B SYLLABLE B032 QO;Lo;0;L;;;;;N;;;;;
+10028;LINEAR B SYLLABLE B060 RA;Lo;0;L;;;;;N;;;;;
+10029;LINEAR B SYLLABLE B027 RE;Lo;0;L;;;;;N;;;;;
+1002A;LINEAR B SYLLABLE B053 RI;Lo;0;L;;;;;N;;;;;
+1002B;LINEAR B SYLLABLE B002 RO;Lo;0;L;;;;;N;;;;;
+1002C;LINEAR B SYLLABLE B026 RU;Lo;0;L;;;;;N;;;;;
+1002D;LINEAR B SYLLABLE B031 SA;Lo;0;L;;;;;N;;;;;
+1002E;LINEAR B SYLLABLE B009 SE;Lo;0;L;;;;;N;;;;;
+1002F;LINEAR B SYLLABLE B041 SI;Lo;0;L;;;;;N;;;;;
+10030;LINEAR B SYLLABLE B012 SO;Lo;0;L;;;;;N;;;;;
+10031;LINEAR B SYLLABLE B058 SU;Lo;0;L;;;;;N;;;;;
+10032;LINEAR B SYLLABLE B059 TA;Lo;0;L;;;;;N;;;;;
+10033;LINEAR B SYLLABLE B004 TE;Lo;0;L;;;;;N;;;;;
+10034;LINEAR B SYLLABLE B037 TI;Lo;0;L;;;;;N;;;;;
+10035;LINEAR B SYLLABLE B005 TO;Lo;0;L;;;;;N;;;;;
+10036;LINEAR B SYLLABLE B069 TU;Lo;0;L;;;;;N;;;;;
+10037;LINEAR B SYLLABLE B054 WA;Lo;0;L;;;;;N;;;;;
+10038;LINEAR B SYLLABLE B075 WE;Lo;0;L;;;;;N;;;;;
+10039;LINEAR B SYLLABLE B040 WI;Lo;0;L;;;;;N;;;;;
+1003A;LINEAR B SYLLABLE B042 WO;Lo;0;L;;;;;N;;;;;
+1003C;LINEAR B SYLLABLE B017 ZA;Lo;0;L;;;;;N;;;;;
+1003D;LINEAR B SYLLABLE B074 ZE;Lo;0;L;;;;;N;;;;;
+1003F;LINEAR B SYLLABLE B020 ZO;Lo;0;L;;;;;N;;;;;
+10040;LINEAR B SYLLABLE B025 A2;Lo;0;L;;;;;N;;;;;
+10041;LINEAR B SYLLABLE B043 A3;Lo;0;L;;;;;N;;;;;
+10042;LINEAR B SYLLABLE B085 AU;Lo;0;L;;;;;N;;;;;
+10043;LINEAR B SYLLABLE B071 DWE;Lo;0;L;;;;;N;;;;;
+10044;LINEAR B SYLLABLE B090 DWO;Lo;0;L;;;;;N;;;;;
+10045;LINEAR B SYLLABLE B048 NWA;Lo;0;L;;;;;N;;;;;
+10046;LINEAR B SYLLABLE B029 PU2;Lo;0;L;;;;;N;;;;;
+10047;LINEAR B SYLLABLE B062 PTE;Lo;0;L;;;;;N;;;;;
+10048;LINEAR B SYLLABLE B076 RA2;Lo;0;L;;;;;N;;;;;
+10049;LINEAR B SYLLABLE B033 RA3;Lo;0;L;;;;;N;;;;;
+1004A;LINEAR B SYLLABLE B068 RO2;Lo;0;L;;;;;N;;;;;
+1004B;LINEAR B SYLLABLE B066 TA2;Lo;0;L;;;;;N;;;;;
+1004C;LINEAR B SYLLABLE B087 TWE;Lo;0;L;;;;;N;;;;;
+1004D;LINEAR B SYLLABLE B091 TWO;Lo;0;L;;;;;N;;;;;
+10050;LINEAR B SYMBOL B018;Lo;0;L;;;;;N;;;;;
+10051;LINEAR B SYMBOL B019;Lo;0;L;;;;;N;;;;;
+10052;LINEAR B SYMBOL B022;Lo;0;L;;;;;N;;;;;
+10053;LINEAR B SYMBOL B034;Lo;0;L;;;;;N;;;;;
+10054;LINEAR B SYMBOL B047;Lo;0;L;;;;;N;;;;;
+10055;LINEAR B SYMBOL B049;Lo;0;L;;;;;N;;;;;
+10056;LINEAR B SYMBOL B056;Lo;0;L;;;;;N;;;;;
+10057;LINEAR B SYMBOL B063;Lo;0;L;;;;;N;;;;;
+10058;LINEAR B SYMBOL B064;Lo;0;L;;;;;N;;;;;
+10059;LINEAR B SYMBOL B079;Lo;0;L;;;;;N;;;;;
+1005A;LINEAR B SYMBOL B082;Lo;0;L;;;;;N;;;;;
+1005B;LINEAR B SYMBOL B083;Lo;0;L;;;;;N;;;;;
+1005C;LINEAR B SYMBOL B086;Lo;0;L;;;;;N;;;;;
+1005D;LINEAR B SYMBOL B089;Lo;0;L;;;;;N;;;;;
+10080;LINEAR B IDEOGRAM B100 MAN;Lo;0;L;;;;;N;;;;;
+10081;LINEAR B IDEOGRAM B102 WOMAN;Lo;0;L;;;;;N;;;;;
+10082;LINEAR B IDEOGRAM B104 DEER;Lo;0;L;;;;;N;;;;;
+10083;LINEAR B IDEOGRAM B105 EQUID;Lo;0;L;;;;;N;;;;;
+10084;LINEAR B IDEOGRAM B105F MARE;Lo;0;L;;;;;N;;;;;
+10085;LINEAR B IDEOGRAM B105M STALLION;Lo;0;L;;;;;N;;;;;
+10086;LINEAR B IDEOGRAM B106F EWE;Lo;0;L;;;;;N;;;;;
+10087;LINEAR B IDEOGRAM B106M RAM;Lo;0;L;;;;;N;;;;;
+10088;LINEAR B IDEOGRAM B107F SHE-GOAT;Lo;0;L;;;;;N;;;;;
+10089;LINEAR B IDEOGRAM B107M HE-GOAT;Lo;0;L;;;;;N;;;;;
+1008A;LINEAR B IDEOGRAM B108F SOW;Lo;0;L;;;;;N;;;;;
+1008B;LINEAR B IDEOGRAM B108M BOAR;Lo;0;L;;;;;N;;;;;
+1008C;LINEAR B IDEOGRAM B109F COW;Lo;0;L;;;;;N;;;;;
+1008D;LINEAR B IDEOGRAM B109M BULL;Lo;0;L;;;;;N;;;;;
+1008E;LINEAR B IDEOGRAM B120 WHEAT;Lo;0;L;;;;;N;;;;;
+1008F;LINEAR B IDEOGRAM B121 BARLEY;Lo;0;L;;;;;N;;;;;
+10090;LINEAR B IDEOGRAM B122 OLIVE;Lo;0;L;;;;;N;;;;;
+10091;LINEAR B IDEOGRAM B123 SPICE;Lo;0;L;;;;;N;;;;;
+10092;LINEAR B IDEOGRAM B125 CYPERUS;Lo;0;L;;;;;N;;;;;
+10093;LINEAR B MONOGRAM B127 KAPO;Lo;0;L;;;;;N;;;;;
+10094;LINEAR B MONOGRAM B128 KANAKO;Lo;0;L;;;;;N;;;;;
+10095;LINEAR B IDEOGRAM B130 OIL;Lo;0;L;;;;;N;;;;;
+10096;LINEAR B IDEOGRAM B131 WINE;Lo;0;L;;;;;N;;;;;
+10097;LINEAR B IDEOGRAM B132;Lo;0;L;;;;;N;;;;;
+10098;LINEAR B MONOGRAM B133 AREPA;Lo;0;L;;;;;N;;;;;
+10099;LINEAR B MONOGRAM B135 MERI;Lo;0;L;;;;;N;;;;;
+1009A;LINEAR B IDEOGRAM B140 BRONZE;Lo;0;L;;;;;N;;;;;
+1009B;LINEAR B IDEOGRAM B141 GOLD;Lo;0;L;;;;;N;;;;;
+1009C;LINEAR B IDEOGRAM B142;Lo;0;L;;;;;N;;;;;
+1009D;LINEAR B IDEOGRAM B145 WOOL;Lo;0;L;;;;;N;;;;;
+1009E;LINEAR B IDEOGRAM B146;Lo;0;L;;;;;N;;;;;
+1009F;LINEAR B IDEOGRAM B150;Lo;0;L;;;;;N;;;;;
+100A0;LINEAR B IDEOGRAM B151 HORN;Lo;0;L;;;;;N;;;;;
+100A1;LINEAR B IDEOGRAM B152;Lo;0;L;;;;;N;;;;;
+100A2;LINEAR B IDEOGRAM B153;Lo;0;L;;;;;N;;;;;
+100A3;LINEAR B IDEOGRAM B154;Lo;0;L;;;;;N;;;;;
+100A4;LINEAR B MONOGRAM B156 TURO2;Lo;0;L;;;;;N;;;;;
+100A5;LINEAR B IDEOGRAM B157;Lo;0;L;;;;;N;;;;;
+100A6;LINEAR B IDEOGRAM B158;Lo;0;L;;;;;N;;;;;
+100A7;LINEAR B IDEOGRAM B159 CLOTH;Lo;0;L;;;;;N;;;;;
+100A8;LINEAR B IDEOGRAM B160;Lo;0;L;;;;;N;;;;;
+100A9;LINEAR B IDEOGRAM B161;Lo;0;L;;;;;N;;;;;
+100AA;LINEAR B IDEOGRAM B162 GARMENT;Lo;0;L;;;;;N;;;;;
+100AB;LINEAR B IDEOGRAM B163 ARMOUR;Lo;0;L;;;;;N;;;;;
+100AC;LINEAR B IDEOGRAM B164;Lo;0;L;;;;;N;;;;;
+100AD;LINEAR B IDEOGRAM B165;Lo;0;L;;;;;N;;;;;
+100AE;LINEAR B IDEOGRAM B166;Lo;0;L;;;;;N;;;;;
+100AF;LINEAR B IDEOGRAM B167;Lo;0;L;;;;;N;;;;;
+100B0;LINEAR B IDEOGRAM B168;Lo;0;L;;;;;N;;;;;
+100B1;LINEAR B IDEOGRAM B169;Lo;0;L;;;;;N;;;;;
+100B2;LINEAR B IDEOGRAM B170;Lo;0;L;;;;;N;;;;;
+100B3;LINEAR B IDEOGRAM B171;Lo;0;L;;;;;N;;;;;
+100B4;LINEAR B IDEOGRAM B172;Lo;0;L;;;;;N;;;;;
+100B5;LINEAR B IDEOGRAM B173 MONTH;Lo;0;L;;;;;N;;;;;
+100B6;LINEAR B IDEOGRAM B174;Lo;0;L;;;;;N;;;;;
+100B7;LINEAR B IDEOGRAM B176 TREE;Lo;0;L;;;;;N;;;;;
+100B8;LINEAR B IDEOGRAM B177;Lo;0;L;;;;;N;;;;;
+100B9;LINEAR B IDEOGRAM B178;Lo;0;L;;;;;N;;;;;
+100BA;LINEAR B IDEOGRAM B179;Lo;0;L;;;;;N;;;;;
+100BB;LINEAR B IDEOGRAM B180;Lo;0;L;;;;;N;;;;;
+100BC;LINEAR B IDEOGRAM B181;Lo;0;L;;;;;N;;;;;
+100BD;LINEAR B IDEOGRAM B182;Lo;0;L;;;;;N;;;;;
+100BE;LINEAR B IDEOGRAM B183;Lo;0;L;;;;;N;;;;;
+100BF;LINEAR B IDEOGRAM B184;Lo;0;L;;;;;N;;;;;
+100C0;LINEAR B IDEOGRAM B185;Lo;0;L;;;;;N;;;;;
+100C1;LINEAR B IDEOGRAM B189;Lo;0;L;;;;;N;;;;;
+100C2;LINEAR B IDEOGRAM B190;Lo;0;L;;;;;N;;;;;
+100C3;LINEAR B IDEOGRAM B191 HELMET;Lo;0;L;;;;;N;;;;;
+100C4;LINEAR B IDEOGRAM B220 FOOTSTOOL;Lo;0;L;;;;;N;;;;;
+100C5;LINEAR B IDEOGRAM B225 BATHTUB;Lo;0;L;;;;;N;;;;;
+100C6;LINEAR B IDEOGRAM B230 SPEAR;Lo;0;L;;;;;N;;;;;
+100C7;LINEAR B IDEOGRAM B231 ARROW;Lo;0;L;;;;;N;;;;;
+100C8;LINEAR B IDEOGRAM B232;Lo;0;L;;;;;N;;;;;
+100C9;LINEAR B IDEOGRAM B233 SWORD;Lo;0;L;;;;;N;;pug;;;
+100CA;LINEAR B IDEOGRAM B234;Lo;0;L;;;;;N;;;;;
+100CB;LINEAR B IDEOGRAM B236;Lo;0;L;;;;;N;;gup;;;
+100CC;LINEAR B IDEOGRAM B240 WHEELED CHARIOT;Lo;0;L;;;;;N;;;;;
+100CD;LINEAR B IDEOGRAM B241 CHARIOT;Lo;0;L;;;;;N;;;;;
+100CE;LINEAR B IDEOGRAM B242 CHARIOT FRAME;Lo;0;L;;;;;N;;;;;
+100CF;LINEAR B IDEOGRAM B243 WHEEL;Lo;0;L;;;;;N;;;;;
+100D0;LINEAR B IDEOGRAM B245;Lo;0;L;;;;;N;;;;;
+100D1;LINEAR B IDEOGRAM B246;Lo;0;L;;;;;N;;;;;
+100D2;LINEAR B MONOGRAM B247 DIPTE;Lo;0;L;;;;;N;;;;;
+100D3;LINEAR B IDEOGRAM B248;Lo;0;L;;;;;N;;;;;
+100D4;LINEAR B IDEOGRAM B249;Lo;0;L;;;;;N;;;;;
+100D5;LINEAR B IDEOGRAM B251;Lo;0;L;;;;;N;;;;;
+100D6;LINEAR B IDEOGRAM B252;Lo;0;L;;;;;N;;;;;
+100D7;LINEAR B IDEOGRAM B253;Lo;0;L;;;;;N;;;;;
+100D8;LINEAR B IDEOGRAM B254 DART;Lo;0;L;;;;;N;;;;;
+100D9;LINEAR B IDEOGRAM B255;Lo;0;L;;;;;N;;;;;
+100DA;LINEAR B IDEOGRAM B256;Lo;0;L;;;;;N;;;;;
+100DB;LINEAR B IDEOGRAM B257;Lo;0;L;;;;;N;;;;;
+100DC;LINEAR B IDEOGRAM B258;Lo;0;L;;;;;N;;;;;
+100DD;LINEAR B IDEOGRAM B259;Lo;0;L;;;;;N;;;;;
+100DE;LINEAR B IDEOGRAM VESSEL B155;Lo;0;L;;;;;N;;;;;
+100DF;LINEAR B IDEOGRAM VESSEL B200;Lo;0;L;;;;;N;;;;;
+100E0;LINEAR B IDEOGRAM VESSEL B201;Lo;0;L;;;;;N;;;;;
+100E1;LINEAR B IDEOGRAM VESSEL B202;Lo;0;L;;;;;N;;;;;
+100E2;LINEAR B IDEOGRAM VESSEL B203;Lo;0;L;;;;;N;;;;;
+100E3;LINEAR B IDEOGRAM VESSEL B204;Lo;0;L;;;;;N;;;;;
+100E4;LINEAR B IDEOGRAM VESSEL B205;Lo;0;L;;;;;N;;;;;
+100E5;LINEAR B IDEOGRAM VESSEL B206;Lo;0;L;;;;;N;;;;;
+100E6;LINEAR B IDEOGRAM VESSEL B207;Lo;0;L;;;;;N;;;;;
+100E7;LINEAR B IDEOGRAM VESSEL B208;Lo;0;L;;;;;N;;;;;
+100E8;LINEAR B IDEOGRAM VESSEL B209;Lo;0;L;;;;;N;;;;;
+100E9;LINEAR B IDEOGRAM VESSEL B210;Lo;0;L;;;;;N;;;;;
+100EA;LINEAR B IDEOGRAM VESSEL B211;Lo;0;L;;;;;N;;;;;
+100EB;LINEAR B IDEOGRAM VESSEL B212;Lo;0;L;;;;;N;;;;;
+100EC;LINEAR B IDEOGRAM VESSEL B213;Lo;0;L;;;;;N;;;;;
+100ED;LINEAR B IDEOGRAM VESSEL B214;Lo;0;L;;;;;N;;;;;
+100EE;LINEAR B IDEOGRAM VESSEL B215;Lo;0;L;;;;;N;;;;;
+100EF;LINEAR B IDEOGRAM VESSEL B216;Lo;0;L;;;;;N;;;;;
+100F0;LINEAR B IDEOGRAM VESSEL B217;Lo;0;L;;;;;N;;;;;
+100F1;LINEAR B IDEOGRAM VESSEL B218;Lo;0;L;;;;;N;;;;;
+100F2;LINEAR B IDEOGRAM VESSEL B219;Lo;0;L;;;;;N;;;;;
+100F3;LINEAR B IDEOGRAM VESSEL B221;Lo;0;L;;;;;N;;;;;
+100F4;LINEAR B IDEOGRAM VESSEL B222;Lo;0;L;;;;;N;;;;;
+100F5;LINEAR B IDEOGRAM VESSEL B226;Lo;0;L;;;;;N;;;;;
+100F6;LINEAR B IDEOGRAM VESSEL B227;Lo;0;L;;;;;N;;;;;
+100F7;LINEAR B IDEOGRAM VESSEL B228;Lo;0;L;;;;;N;;;;;
+100F8;LINEAR B IDEOGRAM VESSEL B229;Lo;0;L;;;;;N;;;;;
+100F9;LINEAR B IDEOGRAM VESSEL B250;Lo;0;L;;;;;N;;;;;
+100FA;LINEAR B IDEOGRAM VESSEL B305;Lo;0;L;;;;;N;;;;;
+10100;AEGEAN WORD SEPARATOR LINE;Po;0;L;;;;;N;;;;;
+10101;AEGEAN WORD SEPARATOR DOT;Po;0;ON;;;;;N;;;;;
+10102;AEGEAN CHECK MARK;So;0;L;;;;;N;;;;;
+10107;AEGEAN NUMBER ONE;No;0;L;;;;1;N;;;;;
+10108;AEGEAN NUMBER TWO;No;0;L;;;;2;N;;;;;
+10109;AEGEAN NUMBER THREE;No;0;L;;;;3;N;;;;;
+1010A;AEGEAN NUMBER FOUR;No;0;L;;;;4;N;;;;;
+1010B;AEGEAN NUMBER FIVE;No;0;L;;;;5;N;;;;;
+1010C;AEGEAN NUMBER SIX;No;0;L;;;;6;N;;;;;
+1010D;AEGEAN NUMBER SEVEN;No;0;L;;;;7;N;;;;;
+1010E;AEGEAN NUMBER EIGHT;No;0;L;;;;8;N;;;;;
+1010F;AEGEAN NUMBER NINE;No;0;L;;;;9;N;;;;;
+10110;AEGEAN NUMBER TEN;No;0;L;;;;10;N;;;;;
+10111;AEGEAN NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+10112;AEGEAN NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+10113;AEGEAN NUMBER FORTY;No;0;L;;;;40;N;;;;;
+10114;AEGEAN NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+10115;AEGEAN NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+10116;AEGEAN NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+10117;AEGEAN NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+10118;AEGEAN NUMBER NINETY;No;0;L;;;;90;N;;;;;
+10119;AEGEAN NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+1011A;AEGEAN NUMBER TWO HUNDRED;No;0;L;;;;200;N;;;;;
+1011B;AEGEAN NUMBER THREE HUNDRED;No;0;L;;;;300;N;;;;;
+1011C;AEGEAN NUMBER FOUR HUNDRED;No;0;L;;;;400;N;;;;;
+1011D;AEGEAN NUMBER FIVE HUNDRED;No;0;L;;;;500;N;;;;;
+1011E;AEGEAN NUMBER SIX HUNDRED;No;0;L;;;;600;N;;;;;
+1011F;AEGEAN NUMBER SEVEN HUNDRED;No;0;L;;;;700;N;;;;;
+10120;AEGEAN NUMBER EIGHT HUNDRED;No;0;L;;;;800;N;;;;;
+10121;AEGEAN NUMBER NINE HUNDRED;No;0;L;;;;900;N;;;;;
+10122;AEGEAN NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+10123;AEGEAN NUMBER TWO THOUSAND;No;0;L;;;;2000;N;;;;;
+10124;AEGEAN NUMBER THREE THOUSAND;No;0;L;;;;3000;N;;;;;
+10125;AEGEAN NUMBER FOUR THOUSAND;No;0;L;;;;4000;N;;;;;
+10126;AEGEAN NUMBER FIVE THOUSAND;No;0;L;;;;5000;N;;;;;
+10127;AEGEAN NUMBER SIX THOUSAND;No;0;L;;;;6000;N;;;;;
+10128;AEGEAN NUMBER SEVEN THOUSAND;No;0;L;;;;7000;N;;;;;
+10129;AEGEAN NUMBER EIGHT THOUSAND;No;0;L;;;;8000;N;;;;;
+1012A;AEGEAN NUMBER NINE THOUSAND;No;0;L;;;;9000;N;;;;;
+1012B;AEGEAN NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;
+1012C;AEGEAN NUMBER TWENTY THOUSAND;No;0;L;;;;20000;N;;;;;
+1012D;AEGEAN NUMBER THIRTY THOUSAND;No;0;L;;;;30000;N;;;;;
+1012E;AEGEAN NUMBER FORTY THOUSAND;No;0;L;;;;40000;N;;;;;
+1012F;AEGEAN NUMBER FIFTY THOUSAND;No;0;L;;;;50000;N;;;;;
+10130;AEGEAN NUMBER SIXTY THOUSAND;No;0;L;;;;60000;N;;;;;
+10131;AEGEAN NUMBER SEVENTY THOUSAND;No;0;L;;;;70000;N;;;;;
+10132;AEGEAN NUMBER EIGHTY THOUSAND;No;0;L;;;;80000;N;;;;;
+10133;AEGEAN NUMBER NINETY THOUSAND;No;0;L;;;;90000;N;;;;;
+10137;AEGEAN WEIGHT BASE UNIT;So;0;L;;;;;N;;;;;
+10138;AEGEAN WEIGHT FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+10139;AEGEAN WEIGHT SECOND SUBUNIT;So;0;L;;;;;N;;;;;
+1013A;AEGEAN WEIGHT THIRD SUBUNIT;So;0;L;;;;;N;;;;;
+1013B;AEGEAN WEIGHT FOURTH SUBUNIT;So;0;L;;;;;N;;;;;
+1013C;AEGEAN DRY MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+1013D;AEGEAN LIQUID MEASURE FIRST SUBUNIT;So;0;L;;;;;N;;;;;
+1013E;AEGEAN MEASURE SECOND SUBUNIT;So;0;L;;;;;N;;;;;
+1013F;AEGEAN MEASURE THIRD SUBUNIT;So;0;L;;;;;N;;;;;
+10140;GREEK ACROPHONIC ATTIC ONE QUARTER;Nl;0;ON;;;;1/4;N;;;;;
+10141;GREEK ACROPHONIC ATTIC ONE HALF;Nl;0;ON;;;;1/2;N;;;;;
+10142;GREEK ACROPHONIC ATTIC ONE DRACHMA;Nl;0;ON;;;;1;N;;;;;
+10143;GREEK ACROPHONIC ATTIC FIVE;Nl;0;ON;;;;5;N;;;;;
+10144;GREEK ACROPHONIC ATTIC FIFTY;Nl;0;ON;;;;50;N;;;;;
+10145;GREEK ACROPHONIC ATTIC FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10146;GREEK ACROPHONIC ATTIC FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;
+10147;GREEK ACROPHONIC ATTIC FIFTY THOUSAND;Nl;0;ON;;;;50000;N;;;;;
+10148;GREEK ACROPHONIC ATTIC FIVE TALENTS;Nl;0;ON;;;;5;N;;;;;
+10149;GREEK ACROPHONIC ATTIC TEN TALENTS;Nl;0;ON;;;;10;N;;;;;
+1014A;GREEK ACROPHONIC ATTIC FIFTY TALENTS;Nl;0;ON;;;;50;N;;;;;
+1014B;GREEK ACROPHONIC ATTIC ONE HUNDRED TALENTS;Nl;0;ON;;;;100;N;;;;;
+1014C;GREEK ACROPHONIC ATTIC FIVE HUNDRED TALENTS;Nl;0;ON;;;;500;N;;;;;
+1014D;GREEK ACROPHONIC ATTIC ONE THOUSAND TALENTS;Nl;0;ON;;;;1000;N;;;;;
+1014E;GREEK ACROPHONIC ATTIC FIVE THOUSAND TALENTS;Nl;0;ON;;;;5000;N;;;;;
+1014F;GREEK ACROPHONIC ATTIC FIVE STATERS;Nl;0;ON;;;;5;N;;;;;
+10150;GREEK ACROPHONIC ATTIC TEN STATERS;Nl;0;ON;;;;10;N;;;;;
+10151;GREEK ACROPHONIC ATTIC FIFTY STATERS;Nl;0;ON;;;;50;N;;;;;
+10152;GREEK ACROPHONIC ATTIC ONE HUNDRED STATERS;Nl;0;ON;;;;100;N;;;;;
+10153;GREEK ACROPHONIC ATTIC FIVE HUNDRED STATERS;Nl;0;ON;;;;500;N;;;;;
+10154;GREEK ACROPHONIC ATTIC ONE THOUSAND STATERS;Nl;0;ON;;;;1000;N;;;;;
+10155;GREEK ACROPHONIC ATTIC TEN THOUSAND STATERS;Nl;0;ON;;;;10000;N;;;;;
+10156;GREEK ACROPHONIC ATTIC FIFTY THOUSAND STATERS;Nl;0;ON;;;;50000;N;;;;;
+10157;GREEK ACROPHONIC ATTIC TEN MNAS;Nl;0;ON;;;;10;N;;;;;
+10158;GREEK ACROPHONIC HERAEUM ONE PLETHRON;Nl;0;ON;;;;1;N;;;;;
+10159;GREEK ACROPHONIC THESPIAN ONE;Nl;0;ON;;;;1;N;;;;;
+1015A;GREEK ACROPHONIC HERMIONIAN ONE;Nl;0;ON;;;;1;N;;;;;
+1015B;GREEK ACROPHONIC EPIDAUREAN TWO;Nl;0;ON;;;;2;N;;;;;
+1015C;GREEK ACROPHONIC THESPIAN TWO;Nl;0;ON;;;;2;N;;;;;
+1015D;GREEK ACROPHONIC CYRENAIC TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;
+1015E;GREEK ACROPHONIC EPIDAUREAN TWO DRACHMAS;Nl;0;ON;;;;2;N;;;;;
+1015F;GREEK ACROPHONIC TROEZENIAN FIVE;Nl;0;ON;;;;5;N;;;;;
+10160;GREEK ACROPHONIC TROEZENIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10161;GREEK ACROPHONIC TROEZENIAN TEN ALTERNATE FORM;Nl;0;ON;;;;10;N;;;;;
+10162;GREEK ACROPHONIC HERMIONIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10163;GREEK ACROPHONIC MESSENIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10164;GREEK ACROPHONIC THESPIAN TEN;Nl;0;ON;;;;10;N;;;;;
+10165;GREEK ACROPHONIC THESPIAN THIRTY;Nl;0;ON;;;;30;N;;;;;
+10166;GREEK ACROPHONIC TROEZENIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+10167;GREEK ACROPHONIC TROEZENIAN FIFTY ALTERNATE FORM;Nl;0;ON;;;;50;N;;;;;
+10168;GREEK ACROPHONIC HERMIONIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+10169;GREEK ACROPHONIC THESPIAN FIFTY;Nl;0;ON;;;;50;N;;;;;
+1016A;GREEK ACROPHONIC THESPIAN ONE HUNDRED;Nl;0;ON;;;;100;N;;;;;
+1016B;GREEK ACROPHONIC THESPIAN THREE HUNDRED;Nl;0;ON;;;;300;N;;;;;
+1016C;GREEK ACROPHONIC EPIDAUREAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016D;GREEK ACROPHONIC TROEZENIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016E;GREEK ACROPHONIC THESPIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+1016F;GREEK ACROPHONIC CARYSTIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10170;GREEK ACROPHONIC NAXIAN FIVE HUNDRED;Nl;0;ON;;;;500;N;;;;;
+10171;GREEK ACROPHONIC THESPIAN ONE THOUSAND;Nl;0;ON;;;;1000;N;;;;;
+10172;GREEK ACROPHONIC THESPIAN FIVE THOUSAND;Nl;0;ON;;;;5000;N;;;;;
+10173;GREEK ACROPHONIC DELPHIC FIVE MNAS;Nl;0;ON;;;;5;N;;;;;
+10174;GREEK ACROPHONIC STRATIAN FIFTY MNAS;Nl;0;ON;;;;50;N;;;;;
+10175;GREEK ONE HALF SIGN;No;0;ON;;;;1/2;N;;;;;
+10176;GREEK ONE HALF SIGN ALTERNATE FORM;No;0;ON;;;;1/2;N;;;;;
+10177;GREEK TWO THIRDS SIGN;No;0;ON;;;;2/3;N;;;;;
+10178;GREEK THREE QUARTERS SIGN;No;0;ON;;;;3/4;N;;;;;
+10179;GREEK YEAR SIGN;So;0;ON;;;;;N;;;;;
+1017A;GREEK TALENT SIGN;So;0;ON;;;;;N;;;;;
+1017B;GREEK DRACHMA SIGN;So;0;ON;;;;;N;;;;;
+1017C;GREEK OBOL SIGN;So;0;ON;;;;;N;;;;;
+1017D;GREEK TWO OBOLS SIGN;So;0;ON;;;;;N;;;;;
+1017E;GREEK THREE OBOLS SIGN;So;0;ON;;;;;N;;;;;
+1017F;GREEK FOUR OBOLS SIGN;So;0;ON;;;;;N;;;;;
+10180;GREEK FIVE OBOLS SIGN;So;0;ON;;;;;N;;;;;
+10181;GREEK METRETES SIGN;So;0;ON;;;;;N;;;;;
+10182;GREEK KYATHOS BASE SIGN;So;0;ON;;;;;N;;;;;
+10183;GREEK LITRA SIGN;So;0;ON;;;;;N;;;;;
+10184;GREEK OUNKIA SIGN;So;0;ON;;;;;N;;;;;
+10185;GREEK XESTES SIGN;So;0;ON;;;;;N;;;;;
+10186;GREEK ARTABE SIGN;So;0;ON;;;;;N;;;;;
+10187;GREEK AROURA SIGN;So;0;ON;;;;;N;;;;;
+10188;GREEK GRAMMA SIGN;So;0;ON;;;;;N;;;;;
+10189;GREEK TRYBLION BASE SIGN;So;0;ON;;;;;N;;;;;
+1018A;GREEK ZERO SIGN;No;0;ON;;;;0;N;;;;;
+10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;;
+10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;;
+10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;;
+10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;;
+10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;;
+10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;;
+10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;;
+10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;;
+10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;;
+10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;;
+1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;;
+1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;;
+1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;;
+1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;;
+1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;;
+1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;Faliscan;;;
+10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;;
+10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;;
+10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;;
+10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;;
+10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;;
+10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;;
+10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;;
+10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;Faliscan;;;
+10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;;
+10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;;
+1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;;
+1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;Umbrian;;;
+1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;Umbrian;;;
+1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;Oscan;;;
+1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;Oscan;;;
+10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;;
+10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;;
+10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;;
+10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;;
+10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;;
+10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;;
+10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;;
+10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;;
+10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;;
+10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;;
+10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;;
+10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;;
+10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;;
+10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;;
+1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;;
+1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;;
+1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;;
+1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;;
+1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;;
+1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;;
+10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;;
+10341;GOTHIC LETTER NINETY;Lo;0;L;;;;;N;;;;;
+10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;;
+10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;;
+10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;;
+10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;;
+10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;;
+10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;;
+10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;;
+10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;;
+1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;900;N;;;;;
+10380;UGARITIC LETTER ALPA;Lo;0;L;;;;;N;;;;;
+10381;UGARITIC LETTER BETA;Lo;0;L;;;;;N;;;;;
+10382;UGARITIC LETTER GAMLA;Lo;0;L;;;;;N;;;;;
+10383;UGARITIC LETTER KHA;Lo;0;L;;;;;N;;;;;
+10384;UGARITIC LETTER DELTA;Lo;0;L;;;;;N;;;;;
+10385;UGARITIC LETTER HO;Lo;0;L;;;;;N;;;;;
+10386;UGARITIC LETTER WO;Lo;0;L;;;;;N;;;;;
+10387;UGARITIC LETTER ZETA;Lo;0;L;;;;;N;;;;;
+10388;UGARITIC LETTER HOTA;Lo;0;L;;;;;N;;;;;
+10389;UGARITIC LETTER TET;Lo;0;L;;;;;N;;;;;
+1038A;UGARITIC LETTER YOD;Lo;0;L;;;;;N;;;;;
+1038B;UGARITIC LETTER KAF;Lo;0;L;;;;;N;;;;;
+1038C;UGARITIC LETTER SHIN;Lo;0;L;;;;;N;;;;;
+1038D;UGARITIC LETTER LAMDA;Lo;0;L;;;;;N;;;;;
+1038E;UGARITIC LETTER MEM;Lo;0;L;;;;;N;;;;;
+1038F;UGARITIC LETTER DHAL;Lo;0;L;;;;;N;;;;;
+10390;UGARITIC LETTER NUN;Lo;0;L;;;;;N;;;;;
+10391;UGARITIC LETTER ZU;Lo;0;L;;;;;N;;;;;
+10392;UGARITIC LETTER SAMKA;Lo;0;L;;;;;N;;;;;
+10393;UGARITIC LETTER AIN;Lo;0;L;;;;;N;;;;;
+10394;UGARITIC LETTER PU;Lo;0;L;;;;;N;;;;;
+10395;UGARITIC LETTER SADE;Lo;0;L;;;;;N;;;;;
+10396;UGARITIC LETTER QOPA;Lo;0;L;;;;;N;;;;;
+10397;UGARITIC LETTER RASHA;Lo;0;L;;;;;N;;;;;
+10398;UGARITIC LETTER THANNA;Lo;0;L;;;;;N;;;;;
+10399;UGARITIC LETTER GHAIN;Lo;0;L;;;;;N;;;;;
+1039A;UGARITIC LETTER TO;Lo;0;L;;;;;N;;;;;
+1039B;UGARITIC LETTER I;Lo;0;L;;;;;N;;;;;
+1039C;UGARITIC LETTER U;Lo;0;L;;;;;N;;;;;
+1039D;UGARITIC LETTER SSU;Lo;0;L;;;;;N;;;;;
+1039F;UGARITIC WORD DIVIDER;Po;0;L;;;;;N;;;;;
+103A0;OLD PERSIAN SIGN A;Lo;0;L;;;;;N;;;;;
+103A1;OLD PERSIAN SIGN I;Lo;0;L;;;;;N;;;;;
+103A2;OLD PERSIAN SIGN U;Lo;0;L;;;;;N;;;;;
+103A3;OLD PERSIAN SIGN KA;Lo;0;L;;;;;N;;;;;
+103A4;OLD PERSIAN SIGN KU;Lo;0;L;;;;;N;;;;;
+103A5;OLD PERSIAN SIGN GA;Lo;0;L;;;;;N;;;;;
+103A6;OLD PERSIAN SIGN GU;Lo;0;L;;;;;N;;;;;
+103A7;OLD PERSIAN SIGN XA;Lo;0;L;;;;;N;;;;;
+103A8;OLD PERSIAN SIGN CA;Lo;0;L;;;;;N;;;;;
+103A9;OLD PERSIAN SIGN JA;Lo;0;L;;;;;N;;;;;
+103AA;OLD PERSIAN SIGN JI;Lo;0;L;;;;;N;;;;;
+103AB;OLD PERSIAN SIGN TA;Lo;0;L;;;;;N;;;;;
+103AC;OLD PERSIAN SIGN TU;Lo;0;L;;;;;N;;;;;
+103AD;OLD PERSIAN SIGN DA;Lo;0;L;;;;;N;;;;;
+103AE;OLD PERSIAN SIGN DI;Lo;0;L;;;;;N;;;;;
+103AF;OLD PERSIAN SIGN DU;Lo;0;L;;;;;N;;;;;
+103B0;OLD PERSIAN SIGN THA;Lo;0;L;;;;;N;;;;;
+103B1;OLD PERSIAN SIGN PA;Lo;0;L;;;;;N;;;;;
+103B2;OLD PERSIAN SIGN BA;Lo;0;L;;;;;N;;;;;
+103B3;OLD PERSIAN SIGN FA;Lo;0;L;;;;;N;;;;;
+103B4;OLD PERSIAN SIGN NA;Lo;0;L;;;;;N;;;;;
+103B5;OLD PERSIAN SIGN NU;Lo;0;L;;;;;N;;;;;
+103B6;OLD PERSIAN SIGN MA;Lo;0;L;;;;;N;;;;;
+103B7;OLD PERSIAN SIGN MI;Lo;0;L;;;;;N;;;;;
+103B8;OLD PERSIAN SIGN MU;Lo;0;L;;;;;N;;;;;
+103B9;OLD PERSIAN SIGN YA;Lo;0;L;;;;;N;;;;;
+103BA;OLD PERSIAN SIGN VA;Lo;0;L;;;;;N;;;;;
+103BB;OLD PERSIAN SIGN VI;Lo;0;L;;;;;N;;;;;
+103BC;OLD PERSIAN SIGN RA;Lo;0;L;;;;;N;;;;;
+103BD;OLD PERSIAN SIGN RU;Lo;0;L;;;;;N;;;;;
+103BE;OLD PERSIAN SIGN LA;Lo;0;L;;;;;N;;;;;
+103BF;OLD PERSIAN SIGN SA;Lo;0;L;;;;;N;;;;;
+103C0;OLD PERSIAN SIGN ZA;Lo;0;L;;;;;N;;;;;
+103C1;OLD PERSIAN SIGN SHA;Lo;0;L;;;;;N;;;;;
+103C2;OLD PERSIAN SIGN SSA;Lo;0;L;;;;;N;;;;;
+103C3;OLD PERSIAN SIGN HA;Lo;0;L;;;;;N;;;;;
+103C8;OLD PERSIAN SIGN AURAMAZDAA;Lo;0;L;;;;;N;;;;;
+103C9;OLD PERSIAN SIGN AURAMAZDAA-2;Lo;0;L;;;;;N;;;;;
+103CA;OLD PERSIAN SIGN AURAMAZDAAHA;Lo;0;L;;;;;N;;;;;
+103CB;OLD PERSIAN SIGN XSHAAYATHIYA;Lo;0;L;;;;;N;;;;;
+103CC;OLD PERSIAN SIGN DAHYAAUSH;Lo;0;L;;;;;N;;;;;
+103CD;OLD PERSIAN SIGN DAHYAAUSH-2;Lo;0;L;;;;;N;;;;;
+103CE;OLD PERSIAN SIGN BAGA;Lo;0;L;;;;;N;;;;;
+103CF;OLD PERSIAN SIGN BUUMISH;Lo;0;L;;;;;N;;;;;
+103D0;OLD PERSIAN WORD DIVIDER;So;0;L;;;;;N;;;;;
+103D1;OLD PERSIAN NUMBER ONE;Nl;0;ON;;;;1;N;;;;;
+103D2;OLD PERSIAN NUMBER TWO;Nl;0;ON;;;;2;N;;;;;
+103D3;OLD PERSIAN NUMBER TEN;Nl;0;ON;;;;10;N;;;;;
+103D4;OLD PERSIAN NUMBER TWENTY;Nl;0;ON;;;;20;N;;;;;
+103D5;OLD PERSIAN NUMBER HUNDRED;Nl;0;ON;;;;100;N;;;;;
+10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
+10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429;
+10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A;
+10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B;
+10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C;
+10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D;
+10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E;
+10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F;
+10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430;
+10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431;
+1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432;
+1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433;
+1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434;
+1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435;
+1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436;
+1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437;
+10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438;
+10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439;
+10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A;
+10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B;
+10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C;
+10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D;
+10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E;
+10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F;
+10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440;
+10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441;
+1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442;
+1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443;
+1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444;
+1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445;
+1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446;
+1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447;
+10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448;
+10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449;
+10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A;
+10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B;
+10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C;
+10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D;
+10426;DESERET CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;1044E;
+10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
+10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
+10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401
+1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402
+1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403
+1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404
+1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405
+1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406
+1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407
+10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408
+10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409
+10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A
+10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B
+10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C
+10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D
+10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E
+10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F
+10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410
+10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411
+1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412
+1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413
+1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414
+1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415
+1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416
+1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417
+10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418
+10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419
+10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A
+10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B
+10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C
+10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D
+10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E
+10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F
+10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420
+10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421
+1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422
+1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423
+1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424
+1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425
+1044E;DESERET SMALL LETTER OI;Ll;0;L;;;;;N;;;10426;;10426
+1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
+10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
+10451;SHAVIAN LETTER TOT;Lo;0;L;;;;;N;;;;;
+10452;SHAVIAN LETTER KICK;Lo;0;L;;;;;N;;;;;
+10453;SHAVIAN LETTER FEE;Lo;0;L;;;;;N;;;;;
+10454;SHAVIAN LETTER THIGH;Lo;0;L;;;;;N;;;;;
+10455;SHAVIAN LETTER SO;Lo;0;L;;;;;N;;;;;
+10456;SHAVIAN LETTER SURE;Lo;0;L;;;;;N;;;;;
+10457;SHAVIAN LETTER CHURCH;Lo;0;L;;;;;N;;;;;
+10458;SHAVIAN LETTER YEA;Lo;0;L;;;;;N;;;;;
+10459;SHAVIAN LETTER HUNG;Lo;0;L;;;;;N;;;;;
+1045A;SHAVIAN LETTER BIB;Lo;0;L;;;;;N;;;;;
+1045B;SHAVIAN LETTER DEAD;Lo;0;L;;;;;N;;;;;
+1045C;SHAVIAN LETTER GAG;Lo;0;L;;;;;N;;;;;
+1045D;SHAVIAN LETTER VOW;Lo;0;L;;;;;N;;;;;
+1045E;SHAVIAN LETTER THEY;Lo;0;L;;;;;N;;;;;
+1045F;SHAVIAN LETTER ZOO;Lo;0;L;;;;;N;;;;;
+10460;SHAVIAN LETTER MEASURE;Lo;0;L;;;;;N;;;;;
+10461;SHAVIAN LETTER JUDGE;Lo;0;L;;;;;N;;;;;
+10462;SHAVIAN LETTER WOE;Lo;0;L;;;;;N;;;;;
+10463;SHAVIAN LETTER HA-HA;Lo;0;L;;;;;N;;;;;
+10464;SHAVIAN LETTER LOLL;Lo;0;L;;;;;N;;;;;
+10465;SHAVIAN LETTER MIME;Lo;0;L;;;;;N;;;;;
+10466;SHAVIAN LETTER IF;Lo;0;L;;;;;N;;;;;
+10467;SHAVIAN LETTER EGG;Lo;0;L;;;;;N;;;;;
+10468;SHAVIAN LETTER ASH;Lo;0;L;;;;;N;;;;;
+10469;SHAVIAN LETTER ADO;Lo;0;L;;;;;N;;;;;
+1046A;SHAVIAN LETTER ON;Lo;0;L;;;;;N;;;;;
+1046B;SHAVIAN LETTER WOOL;Lo;0;L;;;;;N;;;;;
+1046C;SHAVIAN LETTER OUT;Lo;0;L;;;;;N;;;;;
+1046D;SHAVIAN LETTER AH;Lo;0;L;;;;;N;;;;;
+1046E;SHAVIAN LETTER ROAR;Lo;0;L;;;;;N;;;;;
+1046F;SHAVIAN LETTER NUN;Lo;0;L;;;;;N;;;;;
+10470;SHAVIAN LETTER EAT;Lo;0;L;;;;;N;;;;;
+10471;SHAVIAN LETTER AGE;Lo;0;L;;;;;N;;;;;
+10472;SHAVIAN LETTER ICE;Lo;0;L;;;;;N;;;;;
+10473;SHAVIAN LETTER UP;Lo;0;L;;;;;N;;;;;
+10474;SHAVIAN LETTER OAK;Lo;0;L;;;;;N;;;;;
+10475;SHAVIAN LETTER OOZE;Lo;0;L;;;;;N;;;;;
+10476;SHAVIAN LETTER OIL;Lo;0;L;;;;;N;;;;;
+10477;SHAVIAN LETTER AWE;Lo;0;L;;;;;N;;;;;
+10478;SHAVIAN LETTER ARE;Lo;0;L;;;;;N;;;;;
+10479;SHAVIAN LETTER OR;Lo;0;L;;;;;N;;;;;
+1047A;SHAVIAN LETTER AIR;Lo;0;L;;;;;N;;;;;
+1047B;SHAVIAN LETTER ERR;Lo;0;L;;;;;N;;;;;
+1047C;SHAVIAN LETTER ARRAY;Lo;0;L;;;;;N;;;;;
+1047D;SHAVIAN LETTER EAR;Lo;0;L;;;;;N;;;;;
+1047E;SHAVIAN LETTER IAN;Lo;0;L;;;;;N;;;;;
+1047F;SHAVIAN LETTER YEW;Lo;0;L;;;;;N;;;;;
+10480;OSMANYA LETTER ALEF;Lo;0;L;;;;;N;;;;;
+10481;OSMANYA LETTER BA;Lo;0;L;;;;;N;;;;;
+10482;OSMANYA LETTER TA;Lo;0;L;;;;;N;;;;;
+10483;OSMANYA LETTER JA;Lo;0;L;;;;;N;;;;;
+10484;OSMANYA LETTER XA;Lo;0;L;;;;;N;;;;;
+10485;OSMANYA LETTER KHA;Lo;0;L;;;;;N;;;;;
+10486;OSMANYA LETTER DEEL;Lo;0;L;;;;;N;;;;;
+10487;OSMANYA LETTER RA;Lo;0;L;;;;;N;;;;;
+10488;OSMANYA LETTER SA;Lo;0;L;;;;;N;;;;;
+10489;OSMANYA LETTER SHIIN;Lo;0;L;;;;;N;;;;;
+1048A;OSMANYA LETTER DHA;Lo;0;L;;;;;N;;;;;
+1048B;OSMANYA LETTER CAYN;Lo;0;L;;;;;N;;;;;
+1048C;OSMANYA LETTER GA;Lo;0;L;;;;;N;;;;;
+1048D;OSMANYA LETTER FA;Lo;0;L;;;;;N;;;;;
+1048E;OSMANYA LETTER QAAF;Lo;0;L;;;;;N;;;;;
+1048F;OSMANYA LETTER KAAF;Lo;0;L;;;;;N;;;;;
+10490;OSMANYA LETTER LAAN;Lo;0;L;;;;;N;;;;;
+10491;OSMANYA LETTER MIIN;Lo;0;L;;;;;N;;;;;
+10492;OSMANYA LETTER NUUN;Lo;0;L;;;;;N;;;;;
+10493;OSMANYA LETTER WAW;Lo;0;L;;;;;N;;;;;
+10494;OSMANYA LETTER HA;Lo;0;L;;;;;N;;;;;
+10495;OSMANYA LETTER YA;Lo;0;L;;;;;N;;;;;
+10496;OSMANYA LETTER A;Lo;0;L;;;;;N;;;;;
+10497;OSMANYA LETTER E;Lo;0;L;;;;;N;;;;;
+10498;OSMANYA LETTER I;Lo;0;L;;;;;N;;;;;
+10499;OSMANYA LETTER O;Lo;0;L;;;;;N;;;;;
+1049A;OSMANYA LETTER U;Lo;0;L;;;;;N;;;;;
+1049B;OSMANYA LETTER AA;Lo;0;L;;;;;N;;;;;
+1049C;OSMANYA LETTER EE;Lo;0;L;;;;;N;;;;;
+1049D;OSMANYA LETTER OO;Lo;0;L;;;;;N;;;;;
+104A0;OSMANYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+104A1;OSMANYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+104A2;OSMANYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+104A3;OSMANYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+104A4;OSMANYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+104A5;OSMANYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+104A6;OSMANYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+104A7;OSMANYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+104A8;OSMANYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+104A9;OSMANYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+10800;CYPRIOT SYLLABLE A;Lo;0;R;;;;;N;;;;;
+10801;CYPRIOT SYLLABLE E;Lo;0;R;;;;;N;;;;;
+10802;CYPRIOT SYLLABLE I;Lo;0;R;;;;;N;;;;;
+10803;CYPRIOT SYLLABLE O;Lo;0;R;;;;;N;;;;;
+10804;CYPRIOT SYLLABLE U;Lo;0;R;;;;;N;;;;;
+10805;CYPRIOT SYLLABLE JA;Lo;0;R;;;;;N;;;;;
+10808;CYPRIOT SYLLABLE JO;Lo;0;R;;;;;N;;;;;
+1080A;CYPRIOT SYLLABLE KA;Lo;0;R;;;;;N;;;;;
+1080B;CYPRIOT SYLLABLE KE;Lo;0;R;;;;;N;;;;;
+1080C;CYPRIOT SYLLABLE KI;Lo;0;R;;;;;N;;;;;
+1080D;CYPRIOT SYLLABLE KO;Lo;0;R;;;;;N;;;;;
+1080E;CYPRIOT SYLLABLE KU;Lo;0;R;;;;;N;;;;;
+1080F;CYPRIOT SYLLABLE LA;Lo;0;R;;;;;N;;;;;
+10810;CYPRIOT SYLLABLE LE;Lo;0;R;;;;;N;;;;;
+10811;CYPRIOT SYLLABLE LI;Lo;0;R;;;;;N;;;;;
+10812;CYPRIOT SYLLABLE LO;Lo;0;R;;;;;N;;;;;
+10813;CYPRIOT SYLLABLE LU;Lo;0;R;;;;;N;;;;;
+10814;CYPRIOT SYLLABLE MA;Lo;0;R;;;;;N;;;;;
+10815;CYPRIOT SYLLABLE ME;Lo;0;R;;;;;N;;;;;
+10816;CYPRIOT SYLLABLE MI;Lo;0;R;;;;;N;;;;;
+10817;CYPRIOT SYLLABLE MO;Lo;0;R;;;;;N;;;;;
+10818;CYPRIOT SYLLABLE MU;Lo;0;R;;;;;N;;;;;
+10819;CYPRIOT SYLLABLE NA;Lo;0;R;;;;;N;;;;;
+1081A;CYPRIOT SYLLABLE NE;Lo;0;R;;;;;N;;;;;
+1081B;CYPRIOT SYLLABLE NI;Lo;0;R;;;;;N;;;;;
+1081C;CYPRIOT SYLLABLE NO;Lo;0;R;;;;;N;;;;;
+1081D;CYPRIOT SYLLABLE NU;Lo;0;R;;;;;N;;;;;
+1081E;CYPRIOT SYLLABLE PA;Lo;0;R;;;;;N;;;;;
+1081F;CYPRIOT SYLLABLE PE;Lo;0;R;;;;;N;;;;;
+10820;CYPRIOT SYLLABLE PI;Lo;0;R;;;;;N;;;;;
+10821;CYPRIOT SYLLABLE PO;Lo;0;R;;;;;N;;;;;
+10822;CYPRIOT SYLLABLE PU;Lo;0;R;;;;;N;;;;;
+10823;CYPRIOT SYLLABLE RA;Lo;0;R;;;;;N;;;;;
+10824;CYPRIOT SYLLABLE RE;Lo;0;R;;;;;N;;;;;
+10825;CYPRIOT SYLLABLE RI;Lo;0;R;;;;;N;;;;;
+10826;CYPRIOT SYLLABLE RO;Lo;0;R;;;;;N;;;;;
+10827;CYPRIOT SYLLABLE RU;Lo;0;R;;;;;N;;;;;
+10828;CYPRIOT SYLLABLE SA;Lo;0;R;;;;;N;;;;;
+10829;CYPRIOT SYLLABLE SE;Lo;0;R;;;;;N;;;;;
+1082A;CYPRIOT SYLLABLE SI;Lo;0;R;;;;;N;;;;;
+1082B;CYPRIOT SYLLABLE SO;Lo;0;R;;;;;N;;;;;
+1082C;CYPRIOT SYLLABLE SU;Lo;0;R;;;;;N;;;;;
+1082D;CYPRIOT SYLLABLE TA;Lo;0;R;;;;;N;;;;;
+1082E;CYPRIOT SYLLABLE TE;Lo;0;R;;;;;N;;;;;
+1082F;CYPRIOT SYLLABLE TI;Lo;0;R;;;;;N;;;;;
+10830;CYPRIOT SYLLABLE TO;Lo;0;R;;;;;N;;;;;
+10831;CYPRIOT SYLLABLE TU;Lo;0;R;;;;;N;;;;;
+10832;CYPRIOT SYLLABLE WA;Lo;0;R;;;;;N;;;;;
+10833;CYPRIOT SYLLABLE WE;Lo;0;R;;;;;N;;;;;
+10834;CYPRIOT SYLLABLE WI;Lo;0;R;;;;;N;;;;;
+10835;CYPRIOT SYLLABLE WO;Lo;0;R;;;;;N;;;;;
+10837;CYPRIOT SYLLABLE XA;Lo;0;R;;;;;N;;;;;
+10838;CYPRIOT SYLLABLE XE;Lo;0;R;;;;;N;;;;;
+1083C;CYPRIOT SYLLABLE ZA;Lo;0;R;;;;;N;;;;;
+1083F;CYPRIOT SYLLABLE ZO;Lo;0;R;;;;;N;;;;;
+10A00;KHAROSHTHI LETTER A;Lo;0;R;;;;;N;;;;;
+10A01;KHAROSHTHI VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+10A02;KHAROSHTHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+10A03;KHAROSHTHI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+10A05;KHAROSHTHI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+10A06;KHAROSHTHI VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+10A0C;KHAROSHTHI VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+10A0D;KHAROSHTHI SIGN DOUBLE RING BELOW;Mn;220;NSM;;;;;N;;;;;
+10A0E;KHAROSHTHI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+10A0F;KHAROSHTHI SIGN VISARGA;Mn;230;NSM;;;;;N;;;;;
+10A10;KHAROSHTHI LETTER KA;Lo;0;R;;;;;N;;;;;
+10A11;KHAROSHTHI LETTER KHA;Lo;0;R;;;;;N;;;;;
+10A12;KHAROSHTHI LETTER GA;Lo;0;R;;;;;N;;;;;
+10A13;KHAROSHTHI LETTER GHA;Lo;0;R;;;;;N;;;;;
+10A15;KHAROSHTHI LETTER CA;Lo;0;R;;;;;N;;;;;
+10A16;KHAROSHTHI LETTER CHA;Lo;0;R;;;;;N;;;;;
+10A17;KHAROSHTHI LETTER JA;Lo;0;R;;;;;N;;;;;
+10A19;KHAROSHTHI LETTER NYA;Lo;0;R;;;;;N;;;;;
+10A1A;KHAROSHTHI LETTER TTA;Lo;0;R;;;;;N;;;;;
+10A1B;KHAROSHTHI LETTER TTHA;Lo;0;R;;;;;N;;;;;
+10A1C;KHAROSHTHI LETTER DDA;Lo;0;R;;;;;N;;;;;
+10A1D;KHAROSHTHI LETTER DDHA;Lo;0;R;;;;;N;;;;;
+10A1E;KHAROSHTHI LETTER NNA;Lo;0;R;;;;;N;;;;;
+10A1F;KHAROSHTHI LETTER TA;Lo;0;R;;;;;N;;;;;
+10A20;KHAROSHTHI LETTER THA;Lo;0;R;;;;;N;;;;;
+10A21;KHAROSHTHI LETTER DA;Lo;0;R;;;;;N;;;;;
+10A22;KHAROSHTHI LETTER DHA;Lo;0;R;;;;;N;;;;;
+10A23;KHAROSHTHI LETTER NA;Lo;0;R;;;;;N;;;;;
+10A24;KHAROSHTHI LETTER PA;Lo;0;R;;;;;N;;;;;
+10A25;KHAROSHTHI LETTER PHA;Lo;0;R;;;;;N;;;;;
+10A26;KHAROSHTHI LETTER BA;Lo;0;R;;;;;N;;;;;
+10A27;KHAROSHTHI LETTER BHA;Lo;0;R;;;;;N;;;;;
+10A28;KHAROSHTHI LETTER MA;Lo;0;R;;;;;N;;;;;
+10A29;KHAROSHTHI LETTER YA;Lo;0;R;;;;;N;;;;;
+10A2A;KHAROSHTHI LETTER RA;Lo;0;R;;;;;N;;;;;
+10A2B;KHAROSHTHI LETTER LA;Lo;0;R;;;;;N;;;;;
+10A2C;KHAROSHTHI LETTER VA;Lo;0;R;;;;;N;;;;;
+10A2D;KHAROSHTHI LETTER SHA;Lo;0;R;;;;;N;;;;;
+10A2E;KHAROSHTHI LETTER SSA;Lo;0;R;;;;;N;;;;;
+10A2F;KHAROSHTHI LETTER SA;Lo;0;R;;;;;N;;;;;
+10A30;KHAROSHTHI LETTER ZA;Lo;0;R;;;;;N;;;;;
+10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;;
+10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;;
+10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;;
+10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;;
+10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;;
+10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+10A3F;KHAROSHTHI VIRAMA;Mn;9;NSM;;;;;N;;;;;
+10A40;KHAROSHTHI DIGIT ONE;No;0;R;;;1;1;N;;;;;
+10A41;KHAROSHTHI DIGIT TWO;No;0;R;;;2;2;N;;;;;
+10A42;KHAROSHTHI DIGIT THREE;No;0;R;;;3;3;N;;;;;
+10A43;KHAROSHTHI DIGIT FOUR;No;0;R;;;4;4;N;;;;;
+10A44;KHAROSHTHI NUMBER TEN;No;0;R;;;;10;N;;;;;
+10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;;
+10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;;
+10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;;
+10A53;KHAROSHTHI PUNCTUATION CRESCENT BAR;Po;0;R;;;;;N;;;;;
+10A54;KHAROSHTHI PUNCTUATION MANGALAM;Po;0;R;;;;;N;;;;;
+10A55;KHAROSHTHI PUNCTUATION LOTUS;Po;0;R;;;;;N;;;;;
+10A56;KHAROSHTHI PUNCTUATION DANDA;Po;0;R;;;;;N;;;;;
+10A57;KHAROSHTHI PUNCTUATION DOUBLE DANDA;Po;0;R;;;;;N;;;;;
+10A58;KHAROSHTHI PUNCTUATION LINES;Po;0;R;;;;;N;;;;;
+1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;;
+1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;;
+1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;;
+1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;;
+1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;;
+1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;;
+1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;;
+1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;;
+1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;;
+1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;;
+1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;;
+1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;;
+1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;;
+1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;;
+1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;;
+1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;;
+1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;;
+1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;;
+1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;;
+1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;;
+1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;;
+1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;;
+1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;;
+1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;;
+1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;;
+1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;;
+1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;;
+1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;;
+1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;;
+1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;;
+1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;;
+1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;;
+1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;;
+1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;;
+1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;;
+1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;;
+1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;;
+1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;;
+1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;;
+1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;;
+1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;;
+1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;;
+1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;;
+1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;;
+1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;;
+1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;;
+1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;;
+1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;;
+1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;;
+1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;;
+1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;;
+1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;;
+1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;;
+1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;;
+1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;;
+1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;;
+1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;;
+1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;;
+1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;;
+1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;;
+1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;;
+1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;;
+1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;;
+1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;;
+1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;;
+1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;;
+1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;;
+1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;;
+1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;;
+1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;;
+1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;;
+1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;;
+1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;;
+1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;;
+1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;;
+1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;;
+1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;;
+1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;;
+1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;;
+1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;;
+1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;;
+1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;;
+1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;;
+1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;;
+1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;;
+1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;;
+1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;;
+1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;;
+1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;;
+1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;;
+1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;;
+1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;;
+1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;;
+1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;;
+1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;;
+1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;;
+1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;;
+1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;;
+1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;;
+1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;;
+1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;;
+1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;;
+1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;;
+1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;;
+1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;;
+1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;;
+1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;;
+1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;;
+1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;;
+1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;;
+1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;;
+1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;;
+1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;;
+1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;;
+1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;;
+1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;;
+1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;;
+1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;;
+1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;;
+1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;;
+1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;;
+1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;;
+1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;;
+1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;;
+1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;;
+1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;;
+1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;;
+1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;;
+1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;;
+1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;;
+1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;;
+1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;;
+1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;;
+1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;;
+1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;;
+1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;;
+1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;;
+1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;;
+1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;;
+1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;;
+1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;;
+1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;;
+1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;;
+1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;;
+1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;;
+1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;;
+1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;;
+1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;;
+1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;;
+1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;;
+1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;;
+1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;;
+1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;;
+1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;;
+1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;;
+1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;;
+1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;;
+1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;;
+1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;;
+1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;;
+1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;;
+1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;;
+1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;;
+1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;;
+1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;;
+1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;;
+1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;;
+1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;;
+1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;;
+1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;;
+1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;;
+1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;;
+1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;;
+1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;;
+1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;;
+1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;;
+1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;;
+1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;;
+1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;;
+1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;;
+1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;;
+1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;;
+1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;;
+1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;;
+1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;;
+1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;;
+1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;;
+1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;;
+1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;;
+1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;;
+1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;;
+1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;;
+1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;;
+1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;;
+1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;;
+1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;;
+1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;;
+1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;;
+1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;;
+1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;;
+1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;;
+1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;;
+1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;;
+1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;;
+1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;;
+1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;;
+1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;;
+1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;;
+1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;;
+1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;;
+1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;;
+1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;;
+1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;;
+1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;;
+1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;;
+1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;;
+1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;;
+1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;;
+1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;;
+1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;;
+1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;;
+1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;;
+1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;;
+1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;;
+1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;;
+1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;;
+1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;;
+1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;;
+1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;;
+1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;;
+1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;;
+1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;;
+1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;;
+1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;;
+1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;;
+1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;;
+1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;;
+1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;;
+1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;;
+1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;;
+1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;;
+1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;;
+1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;;
+1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;;
+1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;;
+1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;;
+1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;;
+1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;;
+1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;;
+1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;;
+1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;;
+1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;;
+1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;;
+1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;;
+1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;;
+1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;;
+1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;;
+1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;;
+1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;;
+1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;;
+1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;;
+1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;;
+1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;;
+1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;;
+1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;;
+1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;;
+1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;;
+1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;;
+1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;;
+1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;;
+1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;;
+1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;;
+1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;;
+1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;;
+1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;;
+1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;;
+1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;;
+1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;;
+1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;;
+1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;;
+1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;;
+1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;;
+1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;;
+1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;;
+1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;;
+1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;;
+1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;;
+1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;;
+1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;;
+1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;;
+1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;;
+1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;;
+1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;;
+1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;;
+1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;;
+1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;;
+1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;;
+1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;;
+1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;;
+1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;;
+1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;;
+1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;;
+1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;;
+1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;;
+1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;;
+1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;;
+1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;;
+1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;;
+1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;;
+1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;;
+1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;;
+1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;;
+1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;;
+1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;;
+1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;;
+1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;;
+1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;;
+1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;;
+1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;;
+1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;;
+1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;;
+1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;;
+1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;;
+1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;;
+1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;;
+1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;;
+1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;;
+1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;;
+1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;;
+1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;;
+1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;;
+1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;;
+1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;;
+1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;;
+1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;;
+1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;;
+1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;;
+1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;;
+1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;;
+1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;;
+1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;;
+1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;;
+1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;;
+1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;;
+1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;;
+1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;;
+1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;;
+1D200;GREEK VOCAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;
+1D201;GREEK VOCAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;
+1D202;GREEK VOCAL NOTATION SYMBOL-3;So;0;ON;;;;;N;;;;;
+1D203;GREEK VOCAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;
+1D204;GREEK VOCAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;
+1D205;GREEK VOCAL NOTATION SYMBOL-6;So;0;ON;;;;;N;;;;;
+1D206;GREEK VOCAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;
+1D207;GREEK VOCAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;
+1D208;GREEK VOCAL NOTATION SYMBOL-9;So;0;ON;;;;;N;;;;;
+1D209;GREEK VOCAL NOTATION SYMBOL-10;So;0;ON;;;;;N;;;;;
+1D20A;GREEK VOCAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;
+1D20B;GREEK VOCAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;
+1D20C;GREEK VOCAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;
+1D20D;GREEK VOCAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;
+1D20E;GREEK VOCAL NOTATION SYMBOL-15;So;0;ON;;;;;N;;;;;
+1D20F;GREEK VOCAL NOTATION SYMBOL-16;So;0;ON;;;;;N;;;;;
+1D210;GREEK VOCAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;
+1D211;GREEK VOCAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;
+1D212;GREEK VOCAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;
+1D213;GREEK VOCAL NOTATION SYMBOL-20;So;0;ON;;;;;N;;;;;
+1D214;GREEK VOCAL NOTATION SYMBOL-21;So;0;ON;;;;;N;;;;;
+1D215;GREEK VOCAL NOTATION SYMBOL-22;So;0;ON;;;;;N;;;;;
+1D216;GREEK VOCAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;
+1D217;GREEK VOCAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;
+1D218;GREEK VOCAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;
+1D219;GREEK VOCAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;
+1D21A;GREEK VOCAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;
+1D21B;GREEK VOCAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;
+1D21C;GREEK VOCAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;
+1D21D;GREEK INSTRUMENTAL NOTATION SYMBOL-1;So;0;ON;;;;;N;;;;;
+1D21E;GREEK INSTRUMENTAL NOTATION SYMBOL-2;So;0;ON;;;;;N;;;;;
+1D21F;GREEK INSTRUMENTAL NOTATION SYMBOL-4;So;0;ON;;;;;N;;;;;
+1D220;GREEK INSTRUMENTAL NOTATION SYMBOL-5;So;0;ON;;;;;N;;;;;
+1D221;GREEK INSTRUMENTAL NOTATION SYMBOL-7;So;0;ON;;;;;N;;;;;
+1D222;GREEK INSTRUMENTAL NOTATION SYMBOL-8;So;0;ON;;;;;N;;;;;
+1D223;GREEK INSTRUMENTAL NOTATION SYMBOL-11;So;0;ON;;;;;N;;;;;
+1D224;GREEK INSTRUMENTAL NOTATION SYMBOL-12;So;0;ON;;;;;N;;;;;
+1D225;GREEK INSTRUMENTAL NOTATION SYMBOL-13;So;0;ON;;;;;N;;;;;
+1D226;GREEK INSTRUMENTAL NOTATION SYMBOL-14;So;0;ON;;;;;N;;;;;
+1D227;GREEK INSTRUMENTAL NOTATION SYMBOL-17;So;0;ON;;;;;N;;;;;
+1D228;GREEK INSTRUMENTAL NOTATION SYMBOL-18;So;0;ON;;;;;N;;;;;
+1D229;GREEK INSTRUMENTAL NOTATION SYMBOL-19;So;0;ON;;;;;N;;;;;
+1D22A;GREEK INSTRUMENTAL NOTATION SYMBOL-23;So;0;ON;;;;;N;;;;;
+1D22B;GREEK INSTRUMENTAL NOTATION SYMBOL-24;So;0;ON;;;;;N;;;;;
+1D22C;GREEK INSTRUMENTAL NOTATION SYMBOL-25;So;0;ON;;;;;N;;;;;
+1D22D;GREEK INSTRUMENTAL NOTATION SYMBOL-26;So;0;ON;;;;;N;;;;;
+1D22E;GREEK INSTRUMENTAL NOTATION SYMBOL-27;So;0;ON;;;;;N;;;;;
+1D22F;GREEK INSTRUMENTAL NOTATION SYMBOL-29;So;0;ON;;;;;N;;;;;
+1D230;GREEK INSTRUMENTAL NOTATION SYMBOL-30;So;0;ON;;;;;N;;;;;
+1D231;GREEK INSTRUMENTAL NOTATION SYMBOL-32;So;0;ON;;;;;N;;;;;
+1D232;GREEK INSTRUMENTAL NOTATION SYMBOL-36;So;0;ON;;;;;N;;;;;
+1D233;GREEK INSTRUMENTAL NOTATION SYMBOL-37;So;0;ON;;;;;N;;;;;
+1D234;GREEK INSTRUMENTAL NOTATION SYMBOL-38;So;0;ON;;;;;N;;;;;
+1D235;GREEK INSTRUMENTAL NOTATION SYMBOL-39;So;0;ON;;;;;N;;;;;
+1D236;GREEK INSTRUMENTAL NOTATION SYMBOL-40;So;0;ON;;;;;N;;;;;
+1D237;GREEK INSTRUMENTAL NOTATION SYMBOL-42;So;0;ON;;;;;N;;;;;
+1D238;GREEK INSTRUMENTAL NOTATION SYMBOL-43;So;0;ON;;;;;N;;;;;
+1D239;GREEK INSTRUMENTAL NOTATION SYMBOL-45;So;0;ON;;;;;N;;;;;
+1D23A;GREEK INSTRUMENTAL NOTATION SYMBOL-47;So;0;ON;;;;;N;;;;;
+1D23B;GREEK INSTRUMENTAL NOTATION SYMBOL-48;So;0;ON;;;;;N;;;;;
+1D23C;GREEK INSTRUMENTAL NOTATION SYMBOL-49;So;0;ON;;;;;N;;;;;
+1D23D;GREEK INSTRUMENTAL NOTATION SYMBOL-50;So;0;ON;;;;;N;;;;;
+1D23E;GREEK INSTRUMENTAL NOTATION SYMBOL-51;So;0;ON;;;;;N;;;;;
+1D23F;GREEK INSTRUMENTAL NOTATION SYMBOL-52;So;0;ON;;;;;N;;;;;
+1D240;GREEK INSTRUMENTAL NOTATION SYMBOL-53;So;0;ON;;;;;N;;;;;
+1D241;GREEK INSTRUMENTAL NOTATION SYMBOL-54;So;0;ON;;;;;N;;;;;
+1D242;COMBINING GREEK MUSICAL TRISEME;Mn;230;NSM;;;;;N;;;;;
+1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;;
+1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;;
+1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;;
+1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;;
+1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;;
+1D303;DIGRAM FOR EARTHLY HEAVEN;So;0;ON;;;;;N;;;;;
+1D304;DIGRAM FOR EARTHLY HUMAN;So;0;ON;;;;;N;;;;;
+1D305;DIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+1D306;TETRAGRAM FOR CENTRE;So;0;ON;;;;;N;;;;;
+1D307;TETRAGRAM FOR FULL CIRCLE;So;0;ON;;;;;N;;;;;
+1D308;TETRAGRAM FOR MIRED;So;0;ON;;;;;N;;;;;
+1D309;TETRAGRAM FOR BARRIER;So;0;ON;;;;;N;;;;;
+1D30A;TETRAGRAM FOR KEEPING SMALL;So;0;ON;;;;;N;;;;;
+1D30B;TETRAGRAM FOR CONTRARIETY;So;0;ON;;;;;N;;;;;
+1D30C;TETRAGRAM FOR ASCENT;So;0;ON;;;;;N;;;;;
+1D30D;TETRAGRAM FOR OPPOSITION;So;0;ON;;;;;N;;;;;
+1D30E;TETRAGRAM FOR BRANCHING OUT;So;0;ON;;;;;N;;;;;
+1D30F;TETRAGRAM FOR DEFECTIVENESS OR DISTORTION;So;0;ON;;;;;N;;;;;
+1D310;TETRAGRAM FOR DIVERGENCE;So;0;ON;;;;;N;;;;;
+1D311;TETRAGRAM FOR YOUTHFULNESS;So;0;ON;;;;;N;;;;;
+1D312;TETRAGRAM FOR INCREASE;So;0;ON;;;;;N;;;;;
+1D313;TETRAGRAM FOR PENETRATION;So;0;ON;;;;;N;;;;;
+1D314;TETRAGRAM FOR REACH;So;0;ON;;;;;N;;;;;
+1D315;TETRAGRAM FOR CONTACT;So;0;ON;;;;;N;;;;;
+1D316;TETRAGRAM FOR HOLDING BACK;So;0;ON;;;;;N;;;;;
+1D317;TETRAGRAM FOR WAITING;So;0;ON;;;;;N;;;;;
+1D318;TETRAGRAM FOR FOLLOWING;So;0;ON;;;;;N;;;;;
+1D319;TETRAGRAM FOR ADVANCE;So;0;ON;;;;;N;;;;;
+1D31A;TETRAGRAM FOR RELEASE;So;0;ON;;;;;N;;;;;
+1D31B;TETRAGRAM FOR RESISTANCE;So;0;ON;;;;;N;;;;;
+1D31C;TETRAGRAM FOR EASE;So;0;ON;;;;;N;;;;;
+1D31D;TETRAGRAM FOR JOY;So;0;ON;;;;;N;;;;;
+1D31E;TETRAGRAM FOR CONTENTION;So;0;ON;;;;;N;;;;;
+1D31F;TETRAGRAM FOR ENDEAVOUR;So;0;ON;;;;;N;;;;;
+1D320;TETRAGRAM FOR DUTIES;So;0;ON;;;;;N;;;;;
+1D321;TETRAGRAM FOR CHANGE;So;0;ON;;;;;N;;;;;
+1D322;TETRAGRAM FOR DECISIVENESS;So;0;ON;;;;;N;;;;;
+1D323;TETRAGRAM FOR BOLD RESOLUTION;So;0;ON;;;;;N;;;;;
+1D324;TETRAGRAM FOR PACKING;So;0;ON;;;;;N;;;;;
+1D325;TETRAGRAM FOR LEGION;So;0;ON;;;;;N;;;;;
+1D326;TETRAGRAM FOR CLOSENESS;So;0;ON;;;;;N;;;;;
+1D327;TETRAGRAM FOR KINSHIP;So;0;ON;;;;;N;;;;;
+1D328;TETRAGRAM FOR GATHERING;So;0;ON;;;;;N;;;;;
+1D329;TETRAGRAM FOR STRENGTH;So;0;ON;;;;;N;;;;;
+1D32A;TETRAGRAM FOR PURITY;So;0;ON;;;;;N;;;;;
+1D32B;TETRAGRAM FOR FULLNESS;So;0;ON;;;;;N;;;;;
+1D32C;TETRAGRAM FOR RESIDENCE;So;0;ON;;;;;N;;;;;
+1D32D;TETRAGRAM FOR LAW OR MODEL;So;0;ON;;;;;N;;;;;
+1D32E;TETRAGRAM FOR RESPONSE;So;0;ON;;;;;N;;;;;
+1D32F;TETRAGRAM FOR GOING TO MEET;So;0;ON;;;;;N;;;;;
+1D330;TETRAGRAM FOR ENCOUNTERS;So;0;ON;;;;;N;;;;;
+1D331;TETRAGRAM FOR STOVE;So;0;ON;;;;;N;;;;;
+1D332;TETRAGRAM FOR GREATNESS;So;0;ON;;;;;N;;;;;
+1D333;TETRAGRAM FOR ENLARGEMENT;So;0;ON;;;;;N;;;;;
+1D334;TETRAGRAM FOR PATTERN;So;0;ON;;;;;N;;;;;
+1D335;TETRAGRAM FOR RITUAL;So;0;ON;;;;;N;;;;;
+1D336;TETRAGRAM FOR FLIGHT;So;0;ON;;;;;N;;;;;
+1D337;TETRAGRAM FOR VASTNESS OR WASTING;So;0;ON;;;;;N;;;;;
+1D338;TETRAGRAM FOR CONSTANCY;So;0;ON;;;;;N;;;;;
+1D339;TETRAGRAM FOR MEASURE;So;0;ON;;;;;N;;;;;
+1D33A;TETRAGRAM FOR ETERNITY;So;0;ON;;;;;N;;;;;
+1D33B;TETRAGRAM FOR UNITY;So;0;ON;;;;;N;;;;;
+1D33C;TETRAGRAM FOR DIMINISHMENT;So;0;ON;;;;;N;;;;;
+1D33D;TETRAGRAM FOR CLOSED MOUTH;So;0;ON;;;;;N;;;;;
+1D33E;TETRAGRAM FOR GUARDEDNESS;So;0;ON;;;;;N;;;;;
+1D33F;TETRAGRAM FOR GATHERING IN;So;0;ON;;;;;N;;;;;
+1D340;TETRAGRAM FOR MASSING;So;0;ON;;;;;N;;;;;
+1D341;TETRAGRAM FOR ACCUMULATION;So;0;ON;;;;;N;;;;;
+1D342;TETRAGRAM FOR EMBELLISHMENT;So;0;ON;;;;;N;;;;;
+1D343;TETRAGRAM FOR DOUBT;So;0;ON;;;;;N;;;;;
+1D344;TETRAGRAM FOR WATCH;So;0;ON;;;;;N;;;;;
+1D345;TETRAGRAM FOR SINKING;So;0;ON;;;;;N;;;;;
+1D346;TETRAGRAM FOR INNER;So;0;ON;;;;;N;;;;;
+1D347;TETRAGRAM FOR DEPARTURE;So;0;ON;;;;;N;;;;;
+1D348;TETRAGRAM FOR DARKENING;So;0;ON;;;;;N;;;;;
+1D349;TETRAGRAM FOR DIMMING;So;0;ON;;;;;N;;;;;
+1D34A;TETRAGRAM FOR EXHAUSTION;So;0;ON;;;;;N;;;;;
+1D34B;TETRAGRAM FOR SEVERANCE;So;0;ON;;;;;N;;;;;
+1D34C;TETRAGRAM FOR STOPPAGE;So;0;ON;;;;;N;;;;;
+1D34D;TETRAGRAM FOR HARDNESS;So;0;ON;;;;;N;;;;;
+1D34E;TETRAGRAM FOR COMPLETION;So;0;ON;;;;;N;;;;;
+1D34F;TETRAGRAM FOR CLOSURE;So;0;ON;;;;;N;;;;;
+1D350;TETRAGRAM FOR FAILURE;So;0;ON;;;;;N;;;;;
+1D351;TETRAGRAM FOR AGGRAVATION;So;0;ON;;;;;N;;;;;
+1D352;TETRAGRAM FOR COMPLIANCE;So;0;ON;;;;;N;;;;;
+1D353;TETRAGRAM FOR ON THE VERGE;So;0;ON;;;;;N;;;;;
+1D354;TETRAGRAM FOR DIFFICULTIES;So;0;ON;;;;;N;;;;;
+1D355;TETRAGRAM FOR LABOURING;So;0;ON;;;;;N;;;;;
+1D356;TETRAGRAM FOR FOSTERING;So;0;ON;;;;;N;;;;;
+1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4C1;MATHEMATICAL SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D6A4;MATHEMATICAL ITALIC SMALL DOTLESS I;Ll;0;L;<font> 0131;;;;N;;;;;
+1D6A5;MATHEMATICAL ITALIC SMALL DOTLESS J;Ll;0;L;<font> 0237;;;;N;;;;;
+1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
+2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
+2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;;
+2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;;
+2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;;
+2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;;
+2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;;
+2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;;
+2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;;
+2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;;
+2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;;
+2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;;
+2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;;
+2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;;
+2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;;
+2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;;
+2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;;
+2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;;
+2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;;
+2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;;
+2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;;
+2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;;
+2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;;
+2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;;
+2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;;
+2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;;
+2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;;
+2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;;
+2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;;
+2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;;
+2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;;
+2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;;
+2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;;
+2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;;
+2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;;
+2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;;
+2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;;
+2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;;
+2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;;
+2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;;
+2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;;
+2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;;
+2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;;
+2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;;
+2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;;
+2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;;
+2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;;
+2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;;
+2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;;
+2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;;
+2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;;
+2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;;
+2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;;
+2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;;
+2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;;
+2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;;
+2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;;
+2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;;
+2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;;
+2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;;
+2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;;
+2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;;
+2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;;
+2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;;
+2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;;
+2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;;
+2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;;
+2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;;
+2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;;
+2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;;
+2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;;
+2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;;
+2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;;
+2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;;
+2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;;
+2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;;
+2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;;
+2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;;
+2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;;
+2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;;
+2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;;
+2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;;
+2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;;
+2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;;
+2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;;
+2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;;
+2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;;
+2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;;
+2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;;
+2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;;
+2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;;
+2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;;
+2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;;
+2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;;
+2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;;
+2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;;
+2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;;
+2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;;
+2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;;
+2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;;
+2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;;
+2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;;
+2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;;
+2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;;
+2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;;
+2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;;
+2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;36FC;;;;N;;;;;
+2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;;
+2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;;
+2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;;
+2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;;
+2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;;
+2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;;
+2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;;
+2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;;
+2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;;
+2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;;
+2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;;
+2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F53;;;;N;;;;;
+2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;;
+2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;;
+2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;;
+2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;;
+2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;;
+2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;;
+2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;;
+2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;;
+2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;;
+2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;;
+2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;;
+2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;;
+2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;;
+2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;;
+2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;;
+2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;;
+2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;;
+2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;;
+2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;;
+2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;;
+2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;;
+2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;;
+2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;;
+2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;;
+2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;;
+2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;;
+2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;;
+2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;;N;;;;;
+2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;;
+2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;;
+2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;;
+2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;;
+2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;;
+2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;;
+2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;;
+2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;;
+2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;;
+2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;;
+2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;;
+2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;;
+2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;;
+2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;;
+2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;;
+2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;;
+2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;;
+2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;;
+2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;;
+2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;;
+2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;;
+2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;;
+2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;;
+2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;;
+2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;;
+2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;;
+2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;;
+2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;;
+2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;;
+2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;;
+2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;;
+2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;;
+2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;;
+2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;;
+2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;;
+2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;;
+2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;;
+2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;;
+2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;;
+2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;;
+2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;;
+2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;;
+2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;;
+2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;;
+2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;;
+2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;;
+2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;;
+2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;;
+2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;;
+2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;;
+2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;;
+2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;;
+2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;;
+2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;;
+2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;;
+2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;;
+2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;;
+2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;;
+2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;;
+2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;;
+2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;;
+2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;;
+2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;;
+2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;;
+2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;;
+2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;;
+2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;;
+2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;;
+2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;;
+2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;;
+2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;;
+2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;;
+2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;;
+2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;;
+2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;;
+2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;;
+2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;;
+2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;;
+2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;;
+2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;;
+2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;;
+2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;;
+2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;;
+2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;;
+2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;;
+2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;;
+2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;;
+2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;;
+2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;;
+2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;;
+2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;;
+2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;;
+2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;;
+2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;;
+2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;;
+2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;;
+2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;;
+2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;;
+2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;;
+2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;;
+2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;;
+2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;;
+2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;;
+2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;;
+2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;;
+2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;;
+2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;;
+2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;;
+2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;;
+2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;;
+2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;;
+2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;;
+2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;;
+2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;;
+2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;;
+2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;;
+2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;;
+2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;;
+2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;;
+2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;;
+2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;;
+2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;;
+2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;;
+2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;;
+2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;;
+2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;;
+2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;;
+2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;;
+2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;;
+2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;;
+2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;;
+2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;;
+2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;;
+2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;;
+2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;;
+2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;;
+2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;;
+2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;;
+2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;;
+2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;;
+2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;;
+2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;;
+2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;243AB;;;;N;;;;;
+2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;;
+2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;;
+2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;;
+2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;;
+2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;;
+2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;;
+2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;;
+2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;;
+2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;;
+2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;;
+2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;;
+2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;;
+2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;;
+2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;;
+2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;;
+2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;;
+2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;;
+2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;;
+2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;;
+2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;;
+2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;;
+2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;;
+2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;;
+2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;;
+2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;;
+2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;;
+2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;;
+2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;;
+2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;;
+2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;;
+2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;;
+2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;;
+2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;;
+2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;;
+2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;;
+2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;;
+2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;;
+2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;;
+2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;;
+2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;;
+2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;;
+2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;;
+2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;;
+2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;;
+2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;;
+2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;;
+2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;;
+2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;;
+2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;;
+2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;;
+2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;;
+2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;;
+2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;;
+2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;;
+2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;;
+2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;;
+2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;;
+2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;;
+2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;;
+2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;;
+2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;;
+2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;;
+2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;;
+2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AEE;;;;N;;;;;
+2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;;
+2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;;
+2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;;
+2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;;
+2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;;
+2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;;
+2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;;
+2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;;
+2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;;
+2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;;
+2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;;
+2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;;
+2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;;
+2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;;
+2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;;
+2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;;
+2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;;
+2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;;
+2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;;
+2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;;
+2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;;
+2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;;
+2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;;
+2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;;
+2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;;
+2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;;
+2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;;
+2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;;
+2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;;
+2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;;
+2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;;
+2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;;
+2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;;
+2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;;
+2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;;
+2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;;
+2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;;
+2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;;
+2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;;
+2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;;
+2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;;
+2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;;
+2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;;
+2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;;
+2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;;
+2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;;
+2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;;
+2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;;
+2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;;
+2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;;
+2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;;
+2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;;
+2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;;
+2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;;
+2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;;
+2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;;
+2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;;
+2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;;
+2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;;
+2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;;
+2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;;
+2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;;
+2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;;
+2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;;
+2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;;
+2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;;
+2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;;
+2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;;
+2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;;
+2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;;
+2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;;
+2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;;
+2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;;
+2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;;
+2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;;
+2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;;
+2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;;
+2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;;
+2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;;
+2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;;
+2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;;
+2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;;
+2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;;
+2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;;
+2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;;
+2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;;
+2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;;
+2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;;
+2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;;
+2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;;
+2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;;
+2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;;
+2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;;
+2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;;
+2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;;
+2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;45D7;;;;N;;;;;
+2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;;
+2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;;
+2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;;
+2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;;
+2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;;
+2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;;
+2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;;
+2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;;
+2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;;
+2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;;
+2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;;
+2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;;
+2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;;
+2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;;
+2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;;
+2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;;
+2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;;
+2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;;
+2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;;
+2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;;
+2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;;
+2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;;
+2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;;
+2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;;
+2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;;
+2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;;
+2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;;
+2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;;
+2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;;
+2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;;
+2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;;
+2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;;
+2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;;
+2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;;
+2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;;
+2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;;
+2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;;
+2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;;
+2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;;
+2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;;
+2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;;
+2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;;
+2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;;
+2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;;
+2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;;
+2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;;
+2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;;
+2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;;
+2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;;
+2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;;
+2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;;
+2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;;
+2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;;
+2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;;
+2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;;
+2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;;
+2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;;
+2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;;
+2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;;
+2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;;
+2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;;
+2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;;
+2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;;
+2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;;
+2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;;
+2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;;
+2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;;
+2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;;
+2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;;
+2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;;
+2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;;
+2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;;
+2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;;
+2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;;
+2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;;
+2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;;
+2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;;
+2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;;
+2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;;
+2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;;
+2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;;
+2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;;
+2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;;
+2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;;
+2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;;
+2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;;
+2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;;
+2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;;
+2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;;
+2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;;
+2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;;
+2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;;
+2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;;
+2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;;
+E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;;
+E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;;
+E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;;
+E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;;
+E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;;
+E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;;
+E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;;
+E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;;
+E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;;
+E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;;
+E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;;
+E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;;
+E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;;
+E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;;
+E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;;
+E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;;
+E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;;
+E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;;
+E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;;
+E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;;
+E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;;
+E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;;
+E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;;
+E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;;
+E003A;TAG COLON;Cf;0;BN;;;;;N;;;;;
+E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;;
+E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;;
+E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;;
+E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;;
+E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;;
+E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;;
+E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;;
+E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;;
+E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;;
+E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;;
+E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;;
+E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;;
+E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;;
+E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;;
+E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;;
+E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;;
+E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;;
+E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;;
+E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;;
+E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;;
+E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;;
+E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;;
+E0100;VARIATION SELECTOR-17;Mn;0;NSM;;;;;N;;;;;
+E0101;VARIATION SELECTOR-18;Mn;0;NSM;;;;;N;;;;;
+E0102;VARIATION SELECTOR-19;Mn;0;NSM;;;;;N;;;;;
+E0103;VARIATION SELECTOR-20;Mn;0;NSM;;;;;N;;;;;
+E0104;VARIATION SELECTOR-21;Mn;0;NSM;;;;;N;;;;;
+E0105;VARIATION SELECTOR-22;Mn;0;NSM;;;;;N;;;;;
+E0106;VARIATION SELECTOR-23;Mn;0;NSM;;;;;N;;;;;
+E0107;VARIATION SELECTOR-24;Mn;0;NSM;;;;;N;;;;;
+E0108;VARIATION SELECTOR-25;Mn;0;NSM;;;;;N;;;;;
+E0109;VARIATION SELECTOR-26;Mn;0;NSM;;;;;N;;;;;
+E010A;VARIATION SELECTOR-27;Mn;0;NSM;;;;;N;;;;;
+E010B;VARIATION SELECTOR-28;Mn;0;NSM;;;;;N;;;;;
+E010C;VARIATION SELECTOR-29;Mn;0;NSM;;;;;N;;;;;
+E010D;VARIATION SELECTOR-30;Mn;0;NSM;;;;;N;;;;;
+E010E;VARIATION SELECTOR-31;Mn;0;NSM;;;;;N;;;;;
+E010F;VARIATION SELECTOR-32;Mn;0;NSM;;;;;N;;;;;
+E0110;VARIATION SELECTOR-33;Mn;0;NSM;;;;;N;;;;;
+E0111;VARIATION SELECTOR-34;Mn;0;NSM;;;;;N;;;;;
+E0112;VARIATION SELECTOR-35;Mn;0;NSM;;;;;N;;;;;
+E0113;VARIATION SELECTOR-36;Mn;0;NSM;;;;;N;;;;;
+E0114;VARIATION SELECTOR-37;Mn;0;NSM;;;;;N;;;;;
+E0115;VARIATION SELECTOR-38;Mn;0;NSM;;;;;N;;;;;
+E0116;VARIATION SELECTOR-39;Mn;0;NSM;;;;;N;;;;;
+E0117;VARIATION SELECTOR-40;Mn;0;NSM;;;;;N;;;;;
+E0118;VARIATION SELECTOR-41;Mn;0;NSM;;;;;N;;;;;
+E0119;VARIATION SELECTOR-42;Mn;0;NSM;;;;;N;;;;;
+E011A;VARIATION SELECTOR-43;Mn;0;NSM;;;;;N;;;;;
+E011B;VARIATION SELECTOR-44;Mn;0;NSM;;;;;N;;;;;
+E011C;VARIATION SELECTOR-45;Mn;0;NSM;;;;;N;;;;;
+E011D;VARIATION SELECTOR-46;Mn;0;NSM;;;;;N;;;;;
+E011E;VARIATION SELECTOR-47;Mn;0;NSM;;;;;N;;;;;
+E011F;VARIATION SELECTOR-48;Mn;0;NSM;;;;;N;;;;;
+E0120;VARIATION SELECTOR-49;Mn;0;NSM;;;;;N;;;;;
+E0121;VARIATION SELECTOR-50;Mn;0;NSM;;;;;N;;;;;
+E0122;VARIATION SELECTOR-51;Mn;0;NSM;;;;;N;;;;;
+E0123;VARIATION SELECTOR-52;Mn;0;NSM;;;;;N;;;;;
+E0124;VARIATION SELECTOR-53;Mn;0;NSM;;;;;N;;;;;
+E0125;VARIATION SELECTOR-54;Mn;0;NSM;;;;;N;;;;;
+E0126;VARIATION SELECTOR-55;Mn;0;NSM;;;;;N;;;;;
+E0127;VARIATION SELECTOR-56;Mn;0;NSM;;;;;N;;;;;
+E0128;VARIATION SELECTOR-57;Mn;0;NSM;;;;;N;;;;;
+E0129;VARIATION SELECTOR-58;Mn;0;NSM;;;;;N;;;;;
+E012A;VARIATION SELECTOR-59;Mn;0;NSM;;;;;N;;;;;
+E012B;VARIATION SELECTOR-60;Mn;0;NSM;;;;;N;;;;;
+E012C;VARIATION SELECTOR-61;Mn;0;NSM;;;;;N;;;;;
+E012D;VARIATION SELECTOR-62;Mn;0;NSM;;;;;N;;;;;
+E012E;VARIATION SELECTOR-63;Mn;0;NSM;;;;;N;;;;;
+E012F;VARIATION SELECTOR-64;Mn;0;NSM;;;;;N;;;;;
+E0130;VARIATION SELECTOR-65;Mn;0;NSM;;;;;N;;;;;
+E0131;VARIATION SELECTOR-66;Mn;0;NSM;;;;;N;;;;;
+E0132;VARIATION SELECTOR-67;Mn;0;NSM;;;;;N;;;;;
+E0133;VARIATION SELECTOR-68;Mn;0;NSM;;;;;N;;;;;
+E0134;VARIATION SELECTOR-69;Mn;0;NSM;;;;;N;;;;;
+E0135;VARIATION SELECTOR-70;Mn;0;NSM;;;;;N;;;;;
+E0136;VARIATION SELECTOR-71;Mn;0;NSM;;;;;N;;;;;
+E0137;VARIATION SELECTOR-72;Mn;0;NSM;;;;;N;;;;;
+E0138;VARIATION SELECTOR-73;Mn;0;NSM;;;;;N;;;;;
+E0139;VARIATION SELECTOR-74;Mn;0;NSM;;;;;N;;;;;
+E013A;VARIATION SELECTOR-75;Mn;0;NSM;;;;;N;;;;;
+E013B;VARIATION SELECTOR-76;Mn;0;NSM;;;;;N;;;;;
+E013C;VARIATION SELECTOR-77;Mn;0;NSM;;;;;N;;;;;
+E013D;VARIATION SELECTOR-78;Mn;0;NSM;;;;;N;;;;;
+E013E;VARIATION SELECTOR-79;Mn;0;NSM;;;;;N;;;;;
+E013F;VARIATION SELECTOR-80;Mn;0;NSM;;;;;N;;;;;
+E0140;VARIATION SELECTOR-81;Mn;0;NSM;;;;;N;;;;;
+E0141;VARIATION SELECTOR-82;Mn;0;NSM;;;;;N;;;;;
+E0142;VARIATION SELECTOR-83;Mn;0;NSM;;;;;N;;;;;
+E0143;VARIATION SELECTOR-84;Mn;0;NSM;;;;;N;;;;;
+E0144;VARIATION SELECTOR-85;Mn;0;NSM;;;;;N;;;;;
+E0145;VARIATION SELECTOR-86;Mn;0;NSM;;;;;N;;;;;
+E0146;VARIATION SELECTOR-87;Mn;0;NSM;;;;;N;;;;;
+E0147;VARIATION SELECTOR-88;Mn;0;NSM;;;;;N;;;;;
+E0148;VARIATION SELECTOR-89;Mn;0;NSM;;;;;N;;;;;
+E0149;VARIATION SELECTOR-90;Mn;0;NSM;;;;;N;;;;;
+E014A;VARIATION SELECTOR-91;Mn;0;NSM;;;;;N;;;;;
+E014B;VARIATION SELECTOR-92;Mn;0;NSM;;;;;N;;;;;
+E014C;VARIATION SELECTOR-93;Mn;0;NSM;;;;;N;;;;;
+E014D;VARIATION SELECTOR-94;Mn;0;NSM;;;;;N;;;;;
+E014E;VARIATION SELECTOR-95;Mn;0;NSM;;;;;N;;;;;
+E014F;VARIATION SELECTOR-96;Mn;0;NSM;;;;;N;;;;;
+E0150;VARIATION SELECTOR-97;Mn;0;NSM;;;;;N;;;;;
+E0151;VARIATION SELECTOR-98;Mn;0;NSM;;;;;N;;;;;
+E0152;VARIATION SELECTOR-99;Mn;0;NSM;;;;;N;;;;;
+E0153;VARIATION SELECTOR-100;Mn;0;NSM;;;;;N;;;;;
+E0154;VARIATION SELECTOR-101;Mn;0;NSM;;;;;N;;;;;
+E0155;VARIATION SELECTOR-102;Mn;0;NSM;;;;;N;;;;;
+E0156;VARIATION SELECTOR-103;Mn;0;NSM;;;;;N;;;;;
+E0157;VARIATION SELECTOR-104;Mn;0;NSM;;;;;N;;;;;
+E0158;VARIATION SELECTOR-105;Mn;0;NSM;;;;;N;;;;;
+E0159;VARIATION SELECTOR-106;Mn;0;NSM;;;;;N;;;;;
+E015A;VARIATION SELECTOR-107;Mn;0;NSM;;;;;N;;;;;
+E015B;VARIATION SELECTOR-108;Mn;0;NSM;;;;;N;;;;;
+E015C;VARIATION SELECTOR-109;Mn;0;NSM;;;;;N;;;;;
+E015D;VARIATION SELECTOR-110;Mn;0;NSM;;;;;N;;;;;
+E015E;VARIATION SELECTOR-111;Mn;0;NSM;;;;;N;;;;;
+E015F;VARIATION SELECTOR-112;Mn;0;NSM;;;;;N;;;;;
+E0160;VARIATION SELECTOR-113;Mn;0;NSM;;;;;N;;;;;
+E0161;VARIATION SELECTOR-114;Mn;0;NSM;;;;;N;;;;;
+E0162;VARIATION SELECTOR-115;Mn;0;NSM;;;;;N;;;;;
+E0163;VARIATION SELECTOR-116;Mn;0;NSM;;;;;N;;;;;
+E0164;VARIATION SELECTOR-117;Mn;0;NSM;;;;;N;;;;;
+E0165;VARIATION SELECTOR-118;Mn;0;NSM;;;;;N;;;;;
+E0166;VARIATION SELECTOR-119;Mn;0;NSM;;;;;N;;;;;
+E0167;VARIATION SELECTOR-120;Mn;0;NSM;;;;;N;;;;;
+E0168;VARIATION SELECTOR-121;Mn;0;NSM;;;;;N;;;;;
+E0169;VARIATION SELECTOR-122;Mn;0;NSM;;;;;N;;;;;
+E016A;VARIATION SELECTOR-123;Mn;0;NSM;;;;;N;;;;;
+E016B;VARIATION SELECTOR-124;Mn;0;NSM;;;;;N;;;;;
+E016C;VARIATION SELECTOR-125;Mn;0;NSM;;;;;N;;;;;
+E016D;VARIATION SELECTOR-126;Mn;0;NSM;;;;;N;;;;;
+E016E;VARIATION SELECTOR-127;Mn;0;NSM;;;;;N;;;;;
+E016F;VARIATION SELECTOR-128;Mn;0;NSM;;;;;N;;;;;
+E0170;VARIATION SELECTOR-129;Mn;0;NSM;;;;;N;;;;;
+E0171;VARIATION SELECTOR-130;Mn;0;NSM;;;;;N;;;;;
+E0172;VARIATION SELECTOR-131;Mn;0;NSM;;;;;N;;;;;
+E0173;VARIATION SELECTOR-132;Mn;0;NSM;;;;;N;;;;;
+E0174;VARIATION SELECTOR-133;Mn;0;NSM;;;;;N;;;;;
+E0175;VARIATION SELECTOR-134;Mn;0;NSM;;;;;N;;;;;
+E0176;VARIATION SELECTOR-135;Mn;0;NSM;;;;;N;;;;;
+E0177;VARIATION SELECTOR-136;Mn;0;NSM;;;;;N;;;;;
+E0178;VARIATION SELECTOR-137;Mn;0;NSM;;;;;N;;;;;
+E0179;VARIATION SELECTOR-138;Mn;0;NSM;;;;;N;;;;;
+E017A;VARIATION SELECTOR-139;Mn;0;NSM;;;;;N;;;;;
+E017B;VARIATION SELECTOR-140;Mn;0;NSM;;;;;N;;;;;
+E017C;VARIATION SELECTOR-141;Mn;0;NSM;;;;;N;;;;;
+E017D;VARIATION SELECTOR-142;Mn;0;NSM;;;;;N;;;;;
+E017E;VARIATION SELECTOR-143;Mn;0;NSM;;;;;N;;;;;
+E017F;VARIATION SELECTOR-144;Mn;0;NSM;;;;;N;;;;;
+E0180;VARIATION SELECTOR-145;Mn;0;NSM;;;;;N;;;;;
+E0181;VARIATION SELECTOR-146;Mn;0;NSM;;;;;N;;;;;
+E0182;VARIATION SELECTOR-147;Mn;0;NSM;;;;;N;;;;;
+E0183;VARIATION SELECTOR-148;Mn;0;NSM;;;;;N;;;;;
+E0184;VARIATION SELECTOR-149;Mn;0;NSM;;;;;N;;;;;
+E0185;VARIATION SELECTOR-150;Mn;0;NSM;;;;;N;;;;;
+E0186;VARIATION SELECTOR-151;Mn;0;NSM;;;;;N;;;;;
+E0187;VARIATION SELECTOR-152;Mn;0;NSM;;;;;N;;;;;
+E0188;VARIATION SELECTOR-153;Mn;0;NSM;;;;;N;;;;;
+E0189;VARIATION SELECTOR-154;Mn;0;NSM;;;;;N;;;;;
+E018A;VARIATION SELECTOR-155;Mn;0;NSM;;;;;N;;;;;
+E018B;VARIATION SELECTOR-156;Mn;0;NSM;;;;;N;;;;;
+E018C;VARIATION SELECTOR-157;Mn;0;NSM;;;;;N;;;;;
+E018D;VARIATION SELECTOR-158;Mn;0;NSM;;;;;N;;;;;
+E018E;VARIATION SELECTOR-159;Mn;0;NSM;;;;;N;;;;;
+E018F;VARIATION SELECTOR-160;Mn;0;NSM;;;;;N;;;;;
+E0190;VARIATION SELECTOR-161;Mn;0;NSM;;;;;N;;;;;
+E0191;VARIATION SELECTOR-162;Mn;0;NSM;;;;;N;;;;;
+E0192;VARIATION SELECTOR-163;Mn;0;NSM;;;;;N;;;;;
+E0193;VARIATION SELECTOR-164;Mn;0;NSM;;;;;N;;;;;
+E0194;VARIATION SELECTOR-165;Mn;0;NSM;;;;;N;;;;;
+E0195;VARIATION SELECTOR-166;Mn;0;NSM;;;;;N;;;;;
+E0196;VARIATION SELECTOR-167;Mn;0;NSM;;;;;N;;;;;
+E0197;VARIATION SELECTOR-168;Mn;0;NSM;;;;;N;;;;;
+E0198;VARIATION SELECTOR-169;Mn;0;NSM;;;;;N;;;;;
+E0199;VARIATION SELECTOR-170;Mn;0;NSM;;;;;N;;;;;
+E019A;VARIATION SELECTOR-171;Mn;0;NSM;;;;;N;;;;;
+E019B;VARIATION SELECTOR-172;Mn;0;NSM;;;;;N;;;;;
+E019C;VARIATION SELECTOR-173;Mn;0;NSM;;;;;N;;;;;
+E019D;VARIATION SELECTOR-174;Mn;0;NSM;;;;;N;;;;;
+E019E;VARIATION SELECTOR-175;Mn;0;NSM;;;;;N;;;;;
+E019F;VARIATION SELECTOR-176;Mn;0;NSM;;;;;N;;;;;
+E01A0;VARIATION SELECTOR-177;Mn;0;NSM;;;;;N;;;;;
+E01A1;VARIATION SELECTOR-178;Mn;0;NSM;;;;;N;;;;;
+E01A2;VARIATION SELECTOR-179;Mn;0;NSM;;;;;N;;;;;
+E01A3;VARIATION SELECTOR-180;Mn;0;NSM;;;;;N;;;;;
+E01A4;VARIATION SELECTOR-181;Mn;0;NSM;;;;;N;;;;;
+E01A5;VARIATION SELECTOR-182;Mn;0;NSM;;;;;N;;;;;
+E01A6;VARIATION SELECTOR-183;Mn;0;NSM;;;;;N;;;;;
+E01A7;VARIATION SELECTOR-184;Mn;0;NSM;;;;;N;;;;;
+E01A8;VARIATION SELECTOR-185;Mn;0;NSM;;;;;N;;;;;
+E01A9;VARIATION SELECTOR-186;Mn;0;NSM;;;;;N;;;;;
+E01AA;VARIATION SELECTOR-187;Mn;0;NSM;;;;;N;;;;;
+E01AB;VARIATION SELECTOR-188;Mn;0;NSM;;;;;N;;;;;
+E01AC;VARIATION SELECTOR-189;Mn;0;NSM;;;;;N;;;;;
+E01AD;VARIATION SELECTOR-190;Mn;0;NSM;;;;;N;;;;;
+E01AE;VARIATION SELECTOR-191;Mn;0;NSM;;;;;N;;;;;
+E01AF;VARIATION SELECTOR-192;Mn;0;NSM;;;;;N;;;;;
+E01B0;VARIATION SELECTOR-193;Mn;0;NSM;;;;;N;;;;;
+E01B1;VARIATION SELECTOR-194;Mn;0;NSM;;;;;N;;;;;
+E01B2;VARIATION SELECTOR-195;Mn;0;NSM;;;;;N;;;;;
+E01B3;VARIATION SELECTOR-196;Mn;0;NSM;;;;;N;;;;;
+E01B4;VARIATION SELECTOR-197;Mn;0;NSM;;;;;N;;;;;
+E01B5;VARIATION SELECTOR-198;Mn;0;NSM;;;;;N;;;;;
+E01B6;VARIATION SELECTOR-199;Mn;0;NSM;;;;;N;;;;;
+E01B7;VARIATION SELECTOR-200;Mn;0;NSM;;;;;N;;;;;
+E01B8;VARIATION SELECTOR-201;Mn;0;NSM;;;;;N;;;;;
+E01B9;VARIATION SELECTOR-202;Mn;0;NSM;;;;;N;;;;;
+E01BA;VARIATION SELECTOR-203;Mn;0;NSM;;;;;N;;;;;
+E01BB;VARIATION SELECTOR-204;Mn;0;NSM;;;;;N;;;;;
+E01BC;VARIATION SELECTOR-205;Mn;0;NSM;;;;;N;;;;;
+E01BD;VARIATION SELECTOR-206;Mn;0;NSM;;;;;N;;;;;
+E01BE;VARIATION SELECTOR-207;Mn;0;NSM;;;;;N;;;;;
+E01BF;VARIATION SELECTOR-208;Mn;0;NSM;;;;;N;;;;;
+E01C0;VARIATION SELECTOR-209;Mn;0;NSM;;;;;N;;;;;
+E01C1;VARIATION SELECTOR-210;Mn;0;NSM;;;;;N;;;;;
+E01C2;VARIATION SELECTOR-211;Mn;0;NSM;;;;;N;;;;;
+E01C3;VARIATION SELECTOR-212;Mn;0;NSM;;;;;N;;;;;
+E01C4;VARIATION SELECTOR-213;Mn;0;NSM;;;;;N;;;;;
+E01C5;VARIATION SELECTOR-214;Mn;0;NSM;;;;;N;;;;;
+E01C6;VARIATION SELECTOR-215;Mn;0;NSM;;;;;N;;;;;
+E01C7;VARIATION SELECTOR-216;Mn;0;NSM;;;;;N;;;;;
+E01C8;VARIATION SELECTOR-217;Mn;0;NSM;;;;;N;;;;;
+E01C9;VARIATION SELECTOR-218;Mn;0;NSM;;;;;N;;;;;
+E01CA;VARIATION SELECTOR-219;Mn;0;NSM;;;;;N;;;;;
+E01CB;VARIATION SELECTOR-220;Mn;0;NSM;;;;;N;;;;;
+E01CC;VARIATION SELECTOR-221;Mn;0;NSM;;;;;N;;;;;
+E01CD;VARIATION SELECTOR-222;Mn;0;NSM;;;;;N;;;;;
+E01CE;VARIATION SELECTOR-223;Mn;0;NSM;;;;;N;;;;;
+E01CF;VARIATION SELECTOR-224;Mn;0;NSM;;;;;N;;;;;
+E01D0;VARIATION SELECTOR-225;Mn;0;NSM;;;;;N;;;;;
+E01D1;VARIATION SELECTOR-226;Mn;0;NSM;;;;;N;;;;;
+E01D2;VARIATION SELECTOR-227;Mn;0;NSM;;;;;N;;;;;
+E01D3;VARIATION SELECTOR-228;Mn;0;NSM;;;;;N;;;;;
+E01D4;VARIATION SELECTOR-229;Mn;0;NSM;;;;;N;;;;;
+E01D5;VARIATION SELECTOR-230;Mn;0;NSM;;;;;N;;;;;
+E01D6;VARIATION SELECTOR-231;Mn;0;NSM;;;;;N;;;;;
+E01D7;VARIATION SELECTOR-232;Mn;0;NSM;;;;;N;;;;;
+E01D8;VARIATION SELECTOR-233;Mn;0;NSM;;;;;N;;;;;
+E01D9;VARIATION SELECTOR-234;Mn;0;NSM;;;;;N;;;;;
+E01DA;VARIATION SELECTOR-235;Mn;0;NSM;;;;;N;;;;;
+E01DB;VARIATION SELECTOR-236;Mn;0;NSM;;;;;N;;;;;
+E01DC;VARIATION SELECTOR-237;Mn;0;NSM;;;;;N;;;;;
+E01DD;VARIATION SELECTOR-238;Mn;0;NSM;;;;;N;;;;;
+E01DE;VARIATION SELECTOR-239;Mn;0;NSM;;;;;N;;;;;
+E01DF;VARIATION SELECTOR-240;Mn;0;NSM;;;;;N;;;;;
+E01E0;VARIATION SELECTOR-241;Mn;0;NSM;;;;;N;;;;;
+E01E1;VARIATION SELECTOR-242;Mn;0;NSM;;;;;N;;;;;
+E01E2;VARIATION SELECTOR-243;Mn;0;NSM;;;;;N;;;;;
+E01E3;VARIATION SELECTOR-244;Mn;0;NSM;;;;;N;;;;;
+E01E4;VARIATION SELECTOR-245;Mn;0;NSM;;;;;N;;;;;
+E01E5;VARIATION SELECTOR-246;Mn;0;NSM;;;;;N;;;;;
+E01E6;VARIATION SELECTOR-247;Mn;0;NSM;;;;;N;;;;;
+E01E7;VARIATION SELECTOR-248;Mn;0;NSM;;;;;N;;;;;
+E01E8;VARIATION SELECTOR-249;Mn;0;NSM;;;;;N;;;;;
+E01E9;VARIATION SELECTOR-250;Mn;0;NSM;;;;;N;;;;;
+E01EA;VARIATION SELECTOR-251;Mn;0;NSM;;;;;N;;;;;
+E01EB;VARIATION SELECTOR-252;Mn;0;NSM;;;;;N;;;;;
+E01EC;VARIATION SELECTOR-253;Mn;0;NSM;;;;;N;;;;;
+E01ED;VARIATION SELECTOR-254;Mn;0;NSM;;;;;N;;;;;
+E01EE;VARIATION SELECTOR-255;Mn;0;NSM;;;;;N;;;;;
+E01EF;VARIATION SELECTOR-256;Mn;0;NSM;;;;;N;;;;;
+F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;N;;;;;
+FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N;;;;;
+100000;<Plane 16 Private Use, First>;Co;0;L;;;;;N;;;;;
+10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;N;;;;;
--- /dev/null
+++ b/lib/units
@@ -1,0 +1,597 @@
+/order of evaluation
+/ + -
+/ * /
+/ juxtaposition (meaning *)
+/ ¹ ² ³ ^
+/ | (meaning /)
+/ name number ()
+
+/dimensions
+m			#
+kg			#
+sec			#
+coul			#
+candela			#
+$			#
+radian			#
+bit			#
+erlang			#
+°K			#
+°C			#
+°F			#
+
+/constants
+
+π			3.14159265358979323846
+pi			π
+c			2.997925e+8 m/sec
+g			9.80665 m/sec²
+au			1.49597871e+11 m
+mole			6.022169e+23
+e			1.6021917e-19 coul
+energy			c²
+force			g
+mercury			1.33322e+5 kg/m²sec²
+hg			mercury
+h			6.62620e-34 m²kg/sec
+ℏ			h/2 π
+hbar			ℏ
+nonillion		1e30
+octillion		1e27
+septillion		1e24
+sextillion		1e21
+pentillion		1e18
+quadrillion		1e15
+trillion		1e12
+billion			1e9
+million			1e6
+thousand		1e3
+hundred			1e2
+
+/dimensionless
+
+°			1|180 π radian
+degree			°
+circle			2 π radian
+turn			2 π radian
+grad			.9 °
+arcdeg			1 °
+arcmin			1|60 °
+arcsec			1|3600 °
+ccs			1|36 erlang
+
+steradian		radian²
+sphere			4 π steradian
+sr			steradian
+giga		1024 1024 1024
+
+/Time
+
+second			sec
+s			sec
+minute			60 sec
+min			minute
+hour			60 min
+hr			hour
+day			24 hr
+da			day
+week			7 day
+year			365.24219879 day
+yr			year
+month			1|12 year
+ms			millisec
+us			microsec
+
+/Mass
+
+gram			millikg
+gm			gram
+mg			milligram
+metricton		kilokg
+
+/Avoirdupois
+
+lb			.45359237 kg
+lbf			lb g
+pound			lb
+ounce			1|16 lb
+oz			ounce
+dram			1|16 oz
+dr			dram
+grain			1|7000 lb
+gr			grain
+shortton		2000 lb
+ton			shortton
+longton			2240 lb
+
+/Apothecary
+
+scruple			20 grain
+apdram			60 grain
+apounce			480 grain
+troyounce		apounce
+appound			5760 grain
+troypound		appound
+
+/Length
+
+meter			m
+cm			centimeter
+mm			millimeter
+km			kilometer
+nm			nanometer
+micron			micrometer
+µ			micrometer
+Å			decinanometer
+angstrom		Å
+
+inch			2.54 cm
+"			inch
+in			inch
+inches		inch
+'			12"
+foot			12 in
+feet			foot
+ft			foot
+yard			3 ft
+yd			yard
+rod			5.5 yd
+rd			rod
+mile			5280 ft
+mi			mile
+
+british			1200|3937 m/ft
+nmile			1852 m
+
+acre			4840 yd²
+
+cc			cm³
+liter			kilocc
+ml			milliliter
+
+/US Liquid
+
+gallon			231 in³
+imperial		1.20095
+epa			0.8
+gal			gallon
+quart			1|4 gal
+qt			quart
+pint			1|2 qt
+pt			pint
+
+floz			1|16 pt
+fldr			1|8 floz
+
+/US Dry
+
+dry			268.8025 in³/gallon
+peck			8 dry quart
+pk			peck
+bushel			4 peck
+bu			bushel
+
+/British
+
+brgallon		277.420 in³
+brquart			1|4 brgallon
+brpint			1|2 brquart
+brfloz			1|20 brpint
+brpeck			554.84 in³
+brbushel		4 brpeck
+
+/Energy Work
+
+newton			kg m/sec²
+nt			newton
+joule			nt m
+cal			4.1868 joule
+
+/Electrical
+
+coulomb			coul
+ampere			coul/sec
+amp			ampere
+watt			joule/sec
+volt			watt/amp
+Ω			volt/amp
+ohm			Ω
+mho			1/Ω
+farad			coul/volt
+henry			sec²/farad
+weber			volt sec
+
+/Light
+
+cd			candela
+lumen			cd sr
+lux			cd sr/m²
+
+/ MONEY DATE
+/ Fri Oct 27 15:52:13 EDT 2000
+
+/ MONEY START
+argentpeso		1 | .9998 $
+australiadollar		1 | 1.9175 $
+brazilreal		1 | 1.9300 $
+britainpound		1 | .6972 $
+canadadollar		1 | 1.5237 $
+chilepeso		1 | 576.45 $
+chinayuan		1 | 8.2782 $
+colombiapeso		1 | 2165.00 $
+czechrepkoruna		1 | 42.11 $
+denmarkkrone		1 | 9.0134 $
+dominicanpeso		1 | 16.00 $
+egyptpound		1 | 3.6750 $
+euro			1 | 1.08863 $
+hongkongdollar		1 | 7.7991 $
+hungaryforint		1 | 317.59 $
+indiarupee		1 | 46.600 $
+indnsiarupiah		1 | 9025.00 $
+israelshekel		1 | 4.1450 $
+japanyen		1 | 108.34 $
+jordandinar		1 | .71098 $
+lebanonpound		1 | 1514.00 $
+malaysiaringgit		1 | 3.7996 $
+mexicopeso		1 | 9.6850 $
+newzealanddollar	1 | 2.4938 $
+norwaykrone		1 | 9.5940 $
+pakistanrupee		1 | 57.75 $
+perunewsol		1 | 3.510 $
+philpinspeso		1 | 50.10 $
+polandzloty		1 | 4.70 $
+russiaruble		1 | 27.9200 $
+sdr			1 | .7841 $
+saudiarabriyal		1 | 3.7508 $
+singaporedollar		1 | 1.7546 $
+slovakrepkoruna		1 | 52.65 $
+southafricarand		1 | 7.6725 $
+southkoreawon		1 | 1137.20 $
+swedenkrona		1 | 10.2621 $
+switzerlndfranc		1 | 1.8195 $
+taiwandollar		1 | 32.09 $
+thailandbaht		1 | 43.58 $
+turkeylira		1 | 687860 $
+uaedirham		1 | 3.6728 $
+uruguaynewpeso		1 | 12.4180 $
+venezuelabolivar	1 | 693.2500 $
+/ MONEY END
+
+€			euro
+£			britainpound
+¥			japanyen
+dollar			$
+
+bef			1 | 40.3399 €
+belgiumfranc	bef
+dem			1 | 1.95583 €
+germanymark	dem
+grd			1 | 340.750 €
+greecedrachma	grd
+esp			1 | 166.386 €
+spainpeseta		esp
+frf			1 | 6.55957 €
+francefranc	frf
+iep			1 | .787564 €
+irelandpunt	iep
+itl			1 | 1936.27 €
+italylira		itl
+luf			1 | 40.3399 €
+luxembourgfranc	luf
+nlg			1 | 2.20371 €
+netherlandsguilder	nlg
+ats			1 | 13.7603 €
+austriaschilling	ats
+pte			1 | 200.482 €
+portugalescudo	pte
+fim			1 | 5.94573 €
+finlandmark	fim
+
+baht			thailandbaht
+bolivar			venezuelabolivar
+brpound			britainpound
+dinar			jordandinar
+dirham			uaedirham
+drachma			greecedrachma
+escudo			portugalescudo
+forint			hungaryforint
+franc			francefranc
+guilder			netherlandsguilder
+krona			swedenkrona
+lira			italylira
+mark			germanymark
+peseta			spainpeseta
+peso			mexicopeso
+punt			irelandpunt
+rand			southafricarand
+real			brazilreal
+yuan			chinayuan
+ringgit			malaysiaringgit
+riyal			saudiarabriyal
+ruble			russiaruble
+rupee			indiarupee
+rupiah			indnsiarupiah
+shekel			israelshekel
+sol			perunewsol
+won			southkoreawon
+yen			japanyen
+zloty			polandzloty
+
+usdollar		dollar
+sterling		britainpound | pound
+poundsterling		britainpound
+
+/bits
+
+baud			bit/sec
+byte			8 bit
+short			2 byte
+long			4 byte
+vlong			8 bytes
+frame			2352 byte
+
+/Australian liquid measure
+
+pony			7 brfloz
+midie			10 brfloz
+pot			midie
+handle			midie
+schooner		15 brfloz
+jug			40 brfloz
+resch			midie
+alf			midie
+tinny			13 brfloz
+stubby			tinny
+twisty			250 ml
+longneck		2 tinny
+slab			24 tinny
+sixpack			6 tinny
+nip			brfloz
+
+/wine
+winebottle		750 ml
+balthazar		16 winebottle
+jeroboam		4 winebottle
+magnum			2 winebottle
+mathusalem		8 winebottle
+methuselah		8 winebottle
+nebuchadnezzar		20 winebottle
+rehoboam		6 winebottle
+salmanazar		12 winebottle
+split			0.25 winebottle
+jigger			1.5 floz
+
+/Trivia
+
+%			1|100
+admiraltyknot		6080 ft/hr
+ε₀			(1e-9/36π) farad/m
+α			(1/4π ε₀) e²/ℏ c
+alpha			α
+apostilb		cd/π m²
+are			1e+2 m²
+arpentcan		27.52 mi
+arpentlin		191.835 ft
+astronomicalunit	au
+atmosphere		1.01325e+5 nt/m²
+atm			atmosphere
+atomicmassunit		1.66044e-27 kg
+amu			atomicmassunit
+bag			94 lb
+bakersdozen		13
+bar			1e+5 nt/m²
+barie			1e-1 nt/m²
+barleycorn		1|3 in
+barn			1e-28 m²
+barrel			42 gal
+barye			1e-1 nt/m²
+bev			1e+9 e volt
+biot			10 amp
+blondel			cd/π m²
+boardfoot		144 in³
+bolt			40 yd
+bottommeasure		1|40 in
+britishthermalunit	1.05506e+3 joule
+btu			britishthermalunit
+quad			1.0e+15 btu
+refrigeration		12000 btu/ton hour
+buck			dollar
+cable			720 ft
+caliber			1e-2 in
+calorie			cal
+carat			205 mg
+cent			centidollar
+cental			100 lb
+centesimalminute	1e-2 grad
+centesimalsecond	1e-4 grad
+century			100 year
+cfs			ft³/sec
+chain			66 ft
+circularinch		1|4 π in²
+circularmil		1e-6|4 π in²
+clusec			1e-8 mm hg m³/s
+coomb			4 bu
+cord			128 ft³
+cordfoot		cord
+crith			9.06e-2 gm
+cubit			18 in
+cup			1|2 pt
+curie			3.7e+10/sec
+cusec			ft³/sec
+dalton			amu
+decade			10 yr
+degK			°K
+degC			°C
+degF			°F
+dipotre			1/m
+displacementton		35 ft³
+doppelzentner		100 kg
+dozen			12
+drop			.03 cm³
+dyne			cm gm/sec²
+electronvolt		e volt
+ell			45 in
+engineerschain		100 ft
+engineerslink		100|100 ft
+equivalentfootcandle	lumen/π ft²
+equivalentlux		lumen/π m²
+equivalentphot		cd/π cm²
+erg			cm²gm/sec²
+ev			e volt
+faraday			9.652e+4 coul
+fathom			6 ft
+fermi			1e-15 m
+fifth			4|5 qt
+fin			5 dollar
+finger			7|8 in
+firkin			9 gal
+footcandle		lumen/ft²
+footlambert		cd/π ft²
+fortnight		14 da
+franklin		3.33564e-10 coul
+frigorie		kilocal
+furlong			220 yd
+galileo			1e-2 m/sec²
+gamma			1e-9 weber/m²
+gauss			1e-4 weber/m²
+geodeticfoot		british ft
+geographicalmile	1852 m
+gilbert			7.95775e-1 amp
+gill			1|4 pt
+gross			144
+gunterschain		22 yd
+hand			4 in
+hectare			1e+4 m²
+hefnercandle		.92 cd
+hertz			1/sec
+hogshead		2 barrel
+hd			hogshead
+homestead		1|4 mi²
+horsepower		550 ft lb g/sec
+hp			horsepower
+hyl			gm force sec²/m
+hz			1/sec
+imaginarycubicfoot	1.4 ft³
+karat			1|24
+kcal			kilocal
+kcalorie		kilocal
+kev			1e+3 e volt
+key			kg
+khz			1e+3/sec
+kilderkin		18 gal
+knot			nmile/hr
+kwh			kilowatt hour
+lambert			cd/π cm²
+langley			cal/cm²
+last			80 bu
+league			3 mi
+lightyear		c yr
+ly			lightyear
+lightsecond		c sec
+line			1|12 in
+link			66|100 ft
+longhundredweight	112 lb
+longquarter		28 lb
+lusec			1e-6 mm hg m³/s
+mach			331.46 m/sec
+marineleague		3 nmile
+maxwell			1e-8 weber
+metriccarat		200 mg
+mev			1e+6 e volt
+mgd			megagal/day
+mh			millihenry
+mhz			1e+6/sec
+mil			1e-3 in
+millenium		1000 year
+minersinch		1.5 ft³/min
+minim			1|60 fldr
+mo			month
+mpg			mile/gal
+mph			mile/hr
+nail			1|16 yd
+nauticalmile		nmile
+nit			cd/m²
+noggin			1|8 qt
+nox			1e-3 lux
+ns			nanosec
+oersted			2.5e+2 amp/m π
+oe			oersted
+pace			36 in
+palm			3 in
+parasang		3.5 mi
+parsec			au radian/arcsec
+pascal			nt/m²
+pc			parsec
+pennyweight		1|20 oz
+percent			%
+perch			rd
+pf			picofarad
+phot			lumen/cm²
+pica			1|6 in
+pieze			1e+3 nt/m²
+pipe			4 barrel
+point			1|72 in
+poise			gm/cm sec
+pole			rd
+poundal			ft lb/sec²
+pdl			poundal
+proof			1/200
+psi			lb g/in²
+quarter			9 in
+quartersection		1|4 mi²
+quintal			100 kg
+quire			25
+rad			100 erg/gm
+ream			500
+registerton		100 ft³
+rhe			10 m²/nt sec
+rontgen			2.58e-4 curie/kg
+rood			1.21e+3 yd
+rope			20 ft
+rutherford		1e+6/sec
+rydberg			1.36054e+1 ev
+sabin			1 ft²
+sack			3 bu
+seam			8 bu
+section			mi²
+shippington		40 ft³
+shorthundredweight	100 lb
+shortquarter		25 lb
+siemens			1/Ω
+σ			5.66956e-5 erg/cm² °K^4 sec
+sigma			σ
+skein			120 yd
+skot			1e-3 apostilb
+slug			lb g sec²/ft
+span			9 in
+spat			4 π sr
+spindle			14400 yd
+square			100 ft²
+squidge			1|972 inch
+catsquidge		1|432 inch
+stere			m³
+sthene			1e+3 nt
+stilb			cd/cm²
+stoke			1e-4 m²/sec
+stone			14 lb
+strike			2 bu
+surveyfoot		british ft
+surveyorschain		66 ft
+surveyorslink		66|100 ft
+tablespoon		4 fldr
+teaspoon		4|3 fldr
+tesla			weber/m²
+therm			1e+5 btu
+thermie			1e+6 cal
+timberfoot		ft³
+tnt			4.6e+6 m²/sec²
+tonne			1e+6 gm
+torr			mm hg
+township		36 mi²
+tun			8 barrel
+water			.22491|2.54 kg/m²sec²
+wey			40 bu
+weymass			252 lb
+Xunit			1.00202e-13 m
+k			1.38047e-16 erg/°K
+foal			9223372036854775807
--- /dev/null
+++ b/lib/usbdb
@@ -1,0 +1,14 @@
+vendor 0x0711
+	product 0x0230
+		load /dis/lib/usb/usbmct.dis
+class 3
+	subclass 1
+		proto 1
+			load /dis/lib/usb/usbkbd.dis
+		proto 2
+			load /dis/lib/usb/usbmouse.dis
+
+class 8
+	subclass 6
+		proto 80
+			load /dis/lib/usb/usbmass.dis
--- /dev/null
+++ b/lib/wmcharon
@@ -1,0 +1,28 @@
+# /dis/sh script
+# wm defines "menu" and "delmenu" builtins
+load std
+prompt='% ' ''
+fn % {$*}
+autoload=std
+home=/usr/^"{cat /dev/user}
+
+if {! {~ wm ${loaded}}} {
+	echo wmsetup must run under wm >[1=2]
+	raise usage
+}
+
+fn wmrun {
+	args := $*
+	{
+		pctl newpgrp
+		fn wmrun
+		$args
+	} > /chan/wmstdout >[2] /chan/wmstderr &
+}
+
+fn cd {
+	builtin cd $*; echo cwd `{pwd} > /chan/shctl >[2] /dev/null
+}
+
+plumber >[2] /chan/wmstderr >/chan/wmstdout
+wmrun $*
--- /dev/null
+++ b/lib/wmsetup
@@ -1,0 +1,52 @@
+# /dis/sh script
+# wm defines "menu" and "delmenu" builtins
+load std
+prompt='% ' ''
+fn % {$*}
+autoload=std
+home=/usr/^"{cat /dev/user}
+
+if {! {~ wm ${loaded}}} {
+	echo wmsetup must run under wm >[1=2]
+	raise usage
+}
+
+fn wmrun {
+	args := $*
+	{
+		pctl newpgrp
+		fn wmrun
+		$args
+	} > /chan/wmstdout >[2] /chan/wmstderr &
+}
+
+fn cd {
+	builtin cd $*;
+	rescue 'bad redir' {} {
+		echo cwd `{pwd} > /chan/shctl
+	} >[2] /dev/null
+}
+
+plumber >/chan/wmstdout >[2=1]
+menu Shell			{wmrun wm/sh}
+menu Acme			{wmrun acme}
+menu Edit				{wmrun wm/edit}
+menu Charon			{wmrun charon}
+menu Manual			{wmrun wm/man}
+menu Files			{if {ftest -d $home} {wmrun wm/ftree $home} {wmrun wm/ftree /}}
+menu ''	''
+menu System			'Debugger'		{wmrun wm/deb}
+menu System			'Module manager'	{wmrun wm/rt}
+menu System			'Task manager'		{wmrun wm/task}
+menu System			'Memory monitor'	{wmrun wm/memory}
+menu System			'About'			{wmrun wm/about}
+menu Misc			'Coffee'			{wmrun wm/coffee}
+menu Misc			'Colours'			{wmrun wm/colors}
+#menu Misc			'Winctl'			{wmrun wm/winctl}
+menu Misc			'Clock'			{wmrun wm/date}
+menu Games			'Tetris'			{wmrun wm/tetris}
+menu Games			'Bounce'			{wmrun wm/bounce}
+#menu Games			'Game client'		{wmrun games/gameclient >/dev/null >[2=1]}
+#menu Games			'Game client (local)'	{wmrun games/gameclient -l > /dev/null >[2=1]}
+
+if {ftest -f $home/lib/wmsetup} {run $home/lib/wmsetup} {}
--- /dev/null
+++ b/lib/wmsetup.grid
@@ -1,0 +1,54 @@
+# /dis/sh script
+# wm defines "menu" and "delmenu" builtins
+load std
+prompt='% ' ''
+fn % {$*}
+autoload=std
+home=/usr/^"{cat /dev/user}
+
+if {! {~ wm ${loaded}}} {
+	echo wmsetup must run under wm >[1=2]
+	raise usage
+}
+
+fn wmrun {
+	args := $*
+	{
+		pctl newpgrp
+		fn wmrun
+		$args
+	} > /chan/wmstdout >[2] /chan/wmstderr &
+}
+
+fn cd {
+	builtin cd $*;
+	rescue 'bad redir' {} {
+		echo cwd `{pwd} > /chan/shctl
+	} >[2] /dev/null
+}
+autoload=std sexprs
+run /lib/sh/sched
+bind -a /grid/scripts/Inferno /dis
+if{! ftest -f /net/cs}{
+	ndb/cs
+}
+mount -a {mntgen} /n
+
+plumber >/chan/wmstdout >[2=1]
+menu Shell			{wmrun wm/sh}
+menu Acme			{wmrun acme}
+menu Charon			{wmrun charon}
+menu Manual			{wmrun wm/man}
+menu Files			{if {ftest -d $home} {wmrun wm/ftree $home} {wmrun wm/ftree /}}
+menu ''	''
+menu Grid			'Node monitor' {wmrun nodemonitor}
+menu Grid			'Job monitor' {wmrun jobmonitor}
+menu System			'Debugger'		{wmrun wm/deb}
+menu System			'Task manager'		{wmrun wm/task}
+menu System			'Memory monitor'	{wmrun wm/memory}
+menu System			'About'			{wmrun wm/about}
+menu Games			'Tetris'			{wmrun wm/tetris}
+menu Games			'Bounce'			{wmrun wm/bounce}
+
+# anything else
+if {ftest -f $home/lib/wmsetup} {run $home/lib/wmsetup} {}
--- /dev/null
+++ b/lib/words
@@ -1,0 +1,29758 @@
+AAA
+AAAS
+aardvark
+Aaron
+AARP
+AAU
+AAUP
+AAUW
+ABA
+Ababa
+aback
+abacus
+abaft
+abalone
+abandon
+abase
+abash
+abate
+abattoir
+abbe
+abbess
+abbey
+abbot
+Abbott
+abbreviate
+abc
+abcdefghijklmnopqrstuvwxyz
+abdicate
+abdomen
+abdominal
+abduct
+Abe
+abeam
+abed
+Abel
+Abelian
+Abelson
+Aberdeen
+Abernathy
+aberrant
+aberrate
+abet
+abettor
+abeyant
+abhor
+abhorrent
+abide
+Abidjan
+Abigail
+abject
+abjuration
+abjure
+ablate
+ablaut
+ablaze
+able
+abloom
+ablution
+ABM
+abnegate
+Abner
+abnormal
+aboard
+abode
+abolish
+abolition
+abolitionary
+abomasum
+abominable
+abominate
+aboriginal
+aborigine
+aborning
+abort
+abortifacient
+abound
+about
+above
+aboveboard
+aboveground
+abovementioned
+abracadabra
+abrade
+Abraham
+Abram
+Abramson
+abrasion
+abreact
+abreast
+abridge
+abridgment
+abroad
+abrogate
+abrupt
+Absalom
+abscess
+abscissa
+abscissae
+abscission
+abscond
+absent
+absentee
+absenteeism
+absentia
+absentminded
+absinthe
+absolute
+absolve
+absorb
+absorbent
+absorption
+abstain
+abstemious
+abstention
+abstinent
+abstract
+abstruse
+absurd
+absurdum
+abuilding
+abundant
+abuse
+abusive
+abut
+abysmal
+abyss
+abyssal
+Abyssinia
+AC
+acacia
+Acad.
+academe
+academia
+academic
+academician
+academy
+Acadia
+acanthus
+Acapulco
+accede
+accelerando
+accelerant
+accelerate
+accelerometer
+accent
+accentual
+accentuate
+accept
+acceptant
+acceptor
+access
+accessible
+accession
+accessorize
+accessory
+accident
+accidental
+accipiter
+acclaim
+acclamation
+acclimate
+acclimatize
+accolade
+accommodate
+accompaniment
+accompanist
+accompany
+accompli
+accomplice
+accomplish
+accord
+accordant
+accordion
+accost
+account
+accountant
+accouter
+Accra
+accredit
+accreditation
+accrete
+accretion
+accretionary
+accrual
+accrue
+acculturate
+accumulate
+accuracy
+accurate
+accursed
+accusation
+accusatory
+accuse
+accustom
+ace
+acentric
+acerb
+acerbic
+acetaldehyde
+acetate
+acetic
+acetify
+acetone
+acetyl
+acetylene
+ache
+achieve
+Achilles
+aching
+achondrite
+achromatic
+acid
+acidic
+acidify
+acidimeter
+acidulous
+Ackley
+acknowledge
+acknowledgeable
+acknowledgment
+ACLU
+ACM
+acme
+acne
+acolyte
+acorn
+acoustic
+acoustician
+acoustoelectric
+acoustooptic
+acquaint
+acquaintance
+acquiesce
+acquiescent
+acquire
+acquisition
+acquit
+acquittal
+acre
+acreage
+acrid
+acrimonious
+acrimony
+acrobat
+acrobatic
+acrolein
+acronym
+acrophobe
+acropolis
+across
+acrostic
+acrylate
+acrylic
+ACS
+act
+Actaeon
+actinic
+actinide
+actinium
+actinometer
+activate
+activism
+Acton
+actress
+actual
+actuarial
+actuary
+actuate
+acuity
+acumen
+acupuncture
+Acura
+acute
+acyclic
+acyl
+A.D.
+ad
+Ada
+adage
+adagio
+Adair
+Adam
+adamant
+adamantine
+Adams
+Adamson
+adapt
+adaptation
+adaptive
+adaptor
+add
+addend
+addenda
+addendum
+addict
+Addis
+Addison
+addition
+addle
+address
+addressee
+Addressograph
+adduce
+Adelaide
+Adele
+Adelia
+Adelphi
+Aden
+adenine
+adenoid
+adenoma
+adenosine
+adept
+adequacy
+adequate
+adhere
+adherent
+adhesion
+adiabatic
+Adidas
+adieu
+adipose
+Adirondack
+adjacent
+adjectival
+adjective
+adjoin
+adjoint
+adjourn
+adjudge
+adjudicate
+adjunct
+adjuration
+adjure
+adjust
+adjutant
+Adkins
+Adler
+administer
+administrable
+administrate
+administratrix
+admiral
+admiralty
+admiration
+admire
+admissible
+admission
+admit
+admittance
+admix
+admixture
+admonish
+admonition
+admonitory
+ado
+adobe
+adolescent
+Adolf
+Adolph
+Adolphus
+Adonis
+adopt
+adoration
+adore
+adorn
+adrenal
+adrenalin
+adrenaline
+Adrian
+Adriatic
+Adrienne
+adrift
+adroit
+adsorb
+adsorbate
+adsorbent
+adsorption
+adulate
+adult
+adulterant
+adulterate
+adulterer
+adulteress
+adulterous
+adultery
+adumbrate
+advance
+advantage
+advantageous
+advection
+advent
+adventitial
+adventitious
+adventure
+adventuresome
+adventuress
+adventurous
+adverb
+adverbial
+adversarial
+adversary
+adverse
+advert
+advertent
+advertise
+advice
+advise
+advisee
+advisor
+advisory
+advocacy
+advocate
+adz
+adze
+Aegean
+aegis
+Aeneas
+Aeneid
+aeolian
+Aeolus
+aerate
+aerial
+aerie
+Aerobacter
+aerobatic
+aerobic
+aerodynamic
+aeronautic
+aerosol
+aerospace
+Aeschylus
+Aesop
+afar
+affable
+affair
+affect
+affectation
+affectionate
+afferent
+affiance
+affidavit
+affiliate
+affine
+affinity
+affirm
+affirmation
+affix
+affixation
+afflatus
+afflict
+affluent
+afford
+afforest
+afforestation
+affray
+affright
+affront
+afghan
+Afghanistan
+aficionado
+afield
+afire
+AFL
+aflame
+afloat
+aflutter
+afoot
+aforementioned
+aforesaid
+aforethought
+afoul
+afraid
+afresh
+Africa
+Afrikaans
+Afrikaner
+afro
+aft
+afterbirth
+afterburner
+aftercare
+afterdeck
+aftereffect
+afterglow
+afterimage
+afterlife
+aftermarket
+aftermath
+aftermost
+afternoon
+aftershock
+aftertaste
+afterthought
+afterward
+afterworld
+again
+against
+Agamemnon
+agamic
+agape
+agar
+agaric
+agate
+Agatha
+agave
+age
+Agee
+agelong
+agenda
+agendum
+agent
+agglomerate
+agglutinate
+agglutinin
+aggrade
+aggrandize
+aggravate
+aggregate
+aggression
+aggressor
+aggrieve
+aghast
+agile
+agitate
+agitprop
+agleam
+agley
+aglitter
+aglow
+Agnes
+Agnew
+agnomen
+agnostic
+ago
+agog
+agon
+agone
+agony
+agora
+agoraphobe
+agouti
+agrarian
+agree
+agreeable
+agribusiness
+Agricola
+agricultural
+agriculture
+agrimony
+agronomist
+agronomy
+aground
+ague
+Aguilar
+Agway
+ah
+aha
+Ahab
+ahead
+ahem
+Ahmadabad
+ahoy
+aid
+Aida
+aide
+Aiken
+ail
+ailanthus
+Aileen
+aileron
+ailment
+aim
+ain't
+Ainu
+air
+airbag
+airborne
+airbrush
+Airbus
+aircraft
+airdrop
+Airedale
+Aires
+airfare
+airfield
+airflow
+airfoil
+airframe
+airhead
+airlift
+airline
+airlock
+airmail
+airmass
+airpark
+airplane
+airport
+airscrew
+airsick
+airspace
+airspeed
+airstream
+airstrip
+airtight
+airwave
+airway
+airworthy
+aisle
+Aitken
+ajar
+Ajax
+AK
+AK47
+Akers
+akido
+akimbo
+akin
+Akkadian
+Akron
+akvavit
+Al
+Alabama
+Alabamian
+alabaster
+alack
+alacrity
+Aladdin
+Alameda
+Alamo
+Alan
+alar
+alarm
+alas
+Alaska
+alb
+albacore
+Albania
+Albanian
+Albany
+albatross
+albedo
+albeit
+Alberich
+Albert
+Alberta
+Alberto
+albinism
+albino
+Albion
+Albrecht
+Albright
+album
+albumen
+albumin
+Albuquerque
+Alcestis
+alchemical
+alchemist
+alchemy
+Alcmena
+Alcoa
+alcohol
+alcoholic
+Alcott
+alcove
+Aldebaran
+aldehyde
+Alden
+alder
+Aldrich
+aldrin
+ale
+Alec
+Aleck
+alehouse
+alembic
+aleph
+alert
+Aleut
+Aleutian
+alewife
+Alex
+Alexander
+Alexandra
+Alexandria
+alexandrine
+Alexis
+alfalfa
+Alfonso
+Alfred
+Alfredo
+alfresco
+alga
+algae
+algal
+algebra
+algebraic
+Algenib
+Alger
+Algeria
+Algerian
+Algiers
+Algol
+Algonquin
+algorithm
+algorithmic
+Alhambra
+Ali
+alia
+alias
+alibi
+Alice
+Alicia
+alidade
+alien
+alienate
+alienee
+alienor
+alight
+align
+alike
+aliment
+alimentary
+alimentation
+alimony
+aliphatic
+aliquot
+Alison
+Alistair
+alive
+alizarin
+alkali
+alkaline
+alkaloid
+alkane
+alkene
+alkyd
+alkyl
+all
+Allah
+allay
+allegation
+allege
+Alleghenies
+Allegheny
+allegiant
+allegoric
+allegorist
+allegorize
+allegory
+Allegra
+allegretto
+allegro
+allele
+alleluia
+allemand
+Allen
+Allentown
+allergen
+allergenic
+allergic
+allergist
+allergy
+alleviate
+alley
+alleyway
+alliance
+alligator
+Allis
+Allison
+alliterate
+allocable
+allocate
+allophone
+allophonic
+allot
+allotrope
+allotropic
+allow
+allowance
+alloy
+allspice
+Allstate
+allude
+allure
+allusion
+alluvial
+alluvium
+ally
+allyl
+Allyn
+alma
+Almaden
+almagest
+almanac
+almighty
+almond
+almost
+alms
+almshouse
+alnico
+aloe
+aloft
+aloha
+alone
+along
+alongside
+Alonzo
+aloof
+aloud
+alp
+alpaca
+alpenstock
+Alpert
+alpha
+alphabet
+alphabetic
+alphameric
+alphanumeric
+Alpheratz
+Alphonse
+alphorn
+alpine
+already
+Alsace
+Alsatian
+also
+Alsop
+Altair
+altar
+altarpiece
+altazimuth
+alter
+alteration
+altercate
+altern
+alternate
+althea
+although
+altimeter
+altiplano
+altitude
+alto
+altocumulus
+altogether
+Alton
+altostratus
+altricial
+altruism
+altruist
+alum
+alumina
+aluminate
+aluminize
+aluminum
+alumna
+alumnae
+alumni
+alumnus
+alundum
+Alva
+Alvarez
+alveolar
+alveoli
+alveolus
+Alvin
+always
+alyssum
+Alzheimer
+A&M
+a.m.
+am
+AMA
+Amadeus
+amalgam
+amalgamate
+Amanda
+amanita
+amanuensis
+amaranth
+Amarillo
+amaryllis
+amass
+amateur
+amateurish
+amatory
+amaze
+amazon
+Amazonia
+Amazonian
+ambassador
+ambassadorial
+ambassadress
+amber
+ambergris
+ambiance
+ambidextrous
+ambient
+ambiguity
+ambiguous
+ambit
+ambition
+ambitious
+ambivalent
+amble
+ambrosia
+ambrosial
+ambulant
+ambulate
+ambuscade
+ambush
+ameer
+Amelia
+ameliorate
+amen
+amend
+amendatory
+Amerada
+America
+American
+Americana
+americanize
+americium
+Amerindian
+Ames
+Ameslan
+amethyst
+amethystine
+Amherst
+amiable
+amicable
+amicus
+amid
+amide
+amidships
+amidst
+amigo
+amine
+amino
+Amish
+amiss
+amity
+Amman
+Ammerman
+ammeter
+ammo
+ammonia
+ammonium
+ammunition
+amnesia
+amnesty
+amniocentesis
+amniotic
+Amoco
+amoeba
+amoebae
+amoebic
+amok
+among
+amongst
+amoral
+amorous
+amorphous
+amort
+Amos
+amount
+amour
+amperage
+ampere
+ampersand
+Ampex
+amphetamine
+amphibia
+amphibian
+amphibious
+amphibole
+amphibology
+amphitheater
+amphora
+ample
+amplify
+amplitude
+amply
+ampoule
+amputate
+amputee
+Amsterdam
+Amtrak
+amulet
+amuse
+Amy
+amygdaloid
+amyl
+amyloid
+an
+ana
+Anabaptist
+anabasis
+Anabel
+anabolic
+anachronism
+anachronistic
+anachronous
+anaconda
+anaerobic
+anaglyph
+anagram
+anagrammatic
+Anaheim
+anal
+analemma
+analeptic
+analgesia
+analgesic
+analog
+analogous
+analogue
+analogy
+analysand
+analyses
+analysis
+analyst
+analytic
+analyze
+anamorphic
+anapest
+anapestic
+anarch
+anarchic
+anarchs
+anarchy
+anastigmat
+anastigmatic
+anastomosis
+anastomotic
+anathema
+anathematize
+Anatole
+Anatolia
+Anatolian
+anatomic
+anatomist
+anatomize
+anatomy
+ancestor
+ancestral
+ancestress
+ancestry
+anchor
+anchorage
+anchorite
+anchovy
+ancient
+ancillary
+and
+andante
+andantino
+Andean
+Andersen
+Anderson
+Andes
+andesine
+andesite
+andiron
+Andorra
+Andover
+Andre
+Andrea
+Andrei
+Andrew
+Andrews
+Androcles
+androgen
+androgenic
+androgynous
+androgyny
+android
+Andromache
+Andromeda
+Andy
+anecdotal
+anecdote
+anechoic
+anemia
+anemic
+anemometer
+anemone
+anent
+aneroid
+anesthesia
+anesthesiology
+anesthetic
+anesthetist
+anesthetize
+aneurism
+aneurysm
+anew
+angel
+Angela
+Angeles
+angelfish
+angelic
+Angelica
+Angelina
+Angeline
+Angelo
+anger
+Angie
+angina
+angiogram
+angioplasty
+angiosperm
+angle
+angleworm
+Anglican
+anglicism
+anglicize
+Anglo
+anglophile
+anglophobe
+anglophobic
+anglophone
+Angola
+angora
+angry
+angst
+angstrom
+anguish
+angular
+angulate
+Angus
+anharmonic
+Anheuser
+anhydride
+anhydrite
+anhydrous
+ani
+aniline
+animadversion
+animadvert
+animal
+animate
+animism
+animist
+animosity
+animus
+anion
+anionic
+anise
+anisette
+anisotropic
+anisotropy
+Anita
+Ankara
+ankle
+anklebone
+anklet
+Ann
+Anna
+Annale
+Annalen
+annalist
+annals
+Annapolis
+Anne
+anneal
+Annette
+annex
+annexation
+Annie
+annihilate
+anniversary
+annotate
+announce
+annoy
+annoyance
+annual
+annuitant
+annuity
+annul
+annular
+annuli
+annulus
+annum
+annunciate
+anode
+anodic
+anodyne
+anoint
+anomalous
+anomaly
+anomie
+anon
+anonymity
+anonymous
+anopheles
+anorak
+anorexia
+anorexic
+anorthic
+anorthosite
+another
+anoxia
+anoxic
+Anselm
+Anselmo
+ANSI
+answer
+ant
+antacid
+Antaeus
+antagonism
+antagonist
+antagonistic
+antagonize
+antarctic
+Antarctica
+Antares
+ante
+anteater
+antebellum
+antecede
+antecedent
+antechamber
+antedate
+antediluvian
+anteing
+antelope
+antenna
+antennae
+antepenultimate
+anterior
+anteroom
+anthem
+anther
+anthill
+anthologize
+anthology
+Anthony
+anthracite
+anthracnose
+anthrax
+anthropic
+anthropocentric
+anthropogenic
+anthropoid
+anthropology
+anthropometric
+anthropomorphic
+anthropomorphism
+anthropomorphize
+anti
+antic
+antichrist
+anticipant
+anticipate
+anticline
+antidotal
+Antietam
+antigen
+antigenic
+Antigone
+Antigua
+antihistamine
+Antilles
+antimony
+antinomy
+Antioch
+antipasto
+antipathy
+antiperspirant
+antiphonal
+antipodal
+antipodean
+antipodes
+antiquarian
+antiquary
+antiquate
+antiquated
+antique
+antiquity
+antisemite
+antisemitic
+antisemitism
+antithetic
+antler
+Antoine
+Antoinette
+Anton
+Antonia
+Antonio
+Antony
+antonym
+antonymous
+antonymy
+Antwerp
+anus
+anvil
+anxiety
+anxious
+any
+anybody
+anybody'd
+anyhow
+anymore
+anyone
+anyplace
+anything
+anyway
+anywhere
+aorta
+aortic
+A&P
+AP
+apace
+apache
+apart
+apartheid
+apathetic
+apathy
+ape
+apercu
+aperiodic
+aperitif
+aperture
+apex
+aphasia
+aphasic
+aphelion
+aphid
+aphis
+aphorism
+aphorist
+aphrodisiac
+Aphrodite
+apiarist
+apiary
+apices
+apiculture
+apiece
+apish
+aplomb
+apnea
+apocalypse
+apocalyptic
+apocope
+apocrypha
+apocryphal
+apodictic
+apogee
+apolitical
+Apollo
+Apollonian
+apologetic
+apologia
+apologize
+apology
+apoplectic
+apoplexy
+apostasy
+apostate
+apostle
+apostolic
+apostrophe
+apostrophize
+apothecary
+apothegm
+apotheosis
+Appalachia
+appall
+appanage
+apparatchik
+apparatus
+apparel
+apparent
+apparition
+appeal
+appear
+appearance
+appease
+appellant
+appellate
+append
+appendage
+appendectomy
+appendices
+appendicitis
+appendix
+apperceive
+apperception
+appertain
+appetite
+appetize
+Appian
+applaud
+applause
+apple
+Appleby
+applejack
+Appleton
+appliance
+applicable
+applicant
+application
+applicator
+applique
+apply
+appoint
+appointee
+appointive
+apportion
+apposite
+apposition
+appraisal
+appraise
+appreciable
+appreciate
+apprehend
+apprehensible
+apprehension
+apprentice
+apprise
+approach
+approbation
+approbatory
+appropriable
+appropriate
+approval
+approve
+approximable
+approximant
+approximate
+appurtenant
+Apr
+Apr.
+apricot
+April
+apron
+apropos
+apse
+apsidal
+apsides
+apt
+aptitude
+aptly
+aptness
+aqua
+aquaculture
+aqualung
+aquamarine
+aquaplane
+aquarist
+aquarium
+Aquarius
+aquatic
+aqueduct
+aqueous
+aquifer
+Aquila
+aquiline
+Aquinas
+aquiver
+AR
+Arab
+arabesque
+Arabia
+Arabic
+arable
+Araby
+Arachne
+arachnid
+Aramaic
+Arapaho
+Arawak
+arbiter
+arbitrable
+arbitrage
+arbitrageur
+arbitrary
+arbitrate
+arbor
+arboreal
+arborescent
+arboretum
+arbutus
+arc
+arcade
+Arcadia
+arcana
+arcane
+arccos
+arccosine
+arch
+archaic
+archaism
+archangel
+archbishop
+archbishopric
+archdeacon
+archdiocese
+archduchess
+archduke
+archenemy
+archeology
+Archer
+archery
+archetypal
+archetype
+archetypical
+archfool
+Archibald
+Archie
+Archimedean
+Archimedes
+archipelago
+architect
+architectonic
+architectural
+architecture
+architrave
+archival
+archive
+archrival
+archway
+arcing
+arcsin
+arcsine
+arctan
+arctangent
+arctic
+Arcturus
+Arden
+ardent
+ardor
+arduous
+are
+area
+areal
+areaway
+areawide
+arena
+arenaceous
+aren't
+Arequipa
+Ares
+argent
+Argentina
+argentine
+Argentinian
+argillaceous
+Argive
+argon
+argonaut
+Argonne
+argosy
+argot
+argue
+argument
+argumentation
+argumentive
+Argus
+argyll
+Ariadne
+Arianism
+arid
+Ariel
+Aries
+arise
+arisen
+aristocracy
+aristocrat
+aristocratic
+Aristophanes
+Aristotelean
+Aristotelian
+Aristotle
+arithmetic
+arithmetician
+arithmeticize
+arithmetize
+Arizona
+ark
+Arkansan
+Arkansas
+Arlen
+Arlene
+Arlington
+Arlo
+arm
+armada
+armadillo
+Armageddon
+armament
+armamentaria
+armamentarium
+Armando
+Armata
+armature
+armchair
+Armco
+Armenia
+Armenian
+armhole
+armillaria
+armistice
+armlet
+armload
+armoire
+armor
+armorial
+armory
+Armour
+armpit
+armrest
+Armstrong
+army
+Arnold
+aroma
+aromatic
+arose
+around
+arousal
+arouse
+ARPA
+arpeggio
+arrack
+Arragon
+arraign
+arrange
+arrangeable
+arrant
+array
+arrear
+arrest
+Arrhenius
+arrhythmia
+arrival
+arrive
+arrogant
+arrogate
+arrow
+arrowhead
+arrowroot
+arroyo
+arsenal
+arsenate
+arsenic
+arsenide
+arsine
+arson
+art
+Artemis
+artemisia
+arterial
+arteriole
+arteriosclerosis
+arteriosclerotic
+artery
+artesian
+arthritic
+arthritis
+arthropod
+arthroscope
+Arthur
+Arthurian
+artichoke
+article
+articulate
+Artie
+artifact
+artifice
+artificial
+artillery
+artisan
+artistry
+Arturo
+artwork
+Aruba
+arugula
+arum
+Aryan
+aryl
+a's
+as
+ASA
+ASAP
+asbestos
+ascend
+ascendant
+ascendent
+ascension
+ascent
+ascertain
+ascetic
+asceticism
+ascorbic
+ascot
+ascribe
+ascription
+asepsis
+aseptic
+asexual
+ash
+ashamed
+Ashanti
+ashcan
+ashen
+Asher
+Asheville
+Ashland
+ashlar
+Ashley
+Ashmolean
+ashore
+ashram
+ashtray
+Asia
+Asiatic
+aside
+Asilomar
+Asimov
+asinine
+ask
+askance
+askew
+aslant
+asleep
+asocial
+asp
+asparagus
+aspect
+aspen
+asperity
+aspersion
+asphalt
+aspheric
+asphyxia
+asphyxiate
+aspic
+aspidistra
+aspirant
+aspirate
+aspire
+aspirin
+ass
+assai
+assail
+assailant
+Assam
+assassin
+assassinate
+assault
+assay
+assemblage
+assemble
+assembly
+assent
+assert
+assess
+assessor
+asset
+asseverate
+assiduity
+assiduous
+assign
+assignation
+assignee
+assimilable
+assimilate
+assist
+assistant
+associable
+associate
+assonant
+assort
+Asst.
+assuage
+assume
+assumption
+assurance
+assure
+assured
+Assyria
+Assyriology
+Astarte
+astatine
+aster
+asteria
+asterisk
+astern
+asteroid
+asthma
+asthmatic
+astigmat
+astigmatic
+astigmatism
+ASTM
+astonish
+Astor
+Astoria
+astound
+astraddle
+astral
+astray
+astride
+astringent
+astrodome
+astrolabe
+astrologer
+astrology
+astronaut
+astronautic
+astronomer
+astronomy
+astrophysical
+astrophysicist
+astrophysics
+Astroturf
+astute
+Asuncion
+asunder
+asylum
+asymmetry
+asymptomatic
+asymptote
+asymptotic
+asynchronism
+asynchronous
+asynchrony
+at
+Atalanta
+atavism
+atavistic
+Atchison
+ate
+atelier
+Athabascan
+atheism
+atheist
+Athena
+Athene
+Athenian
+Athens
+athirst
+athlete
+athletic
+athwart
+Atkins
+Atkinson
+Atlanta
+Atlantic
+Atlantica
+Atlantis
+atlas
+ATM
+atmosphere
+atmospheric
+atoll
+atom
+atomic
+atonal
+atone
+atop
+atremble
+Atreus
+atrium
+atrocious
+atrocity
+atrophic
+atrophy
+Atropos
+AT&T
+attach
+attache
+attack
+attain
+attainder
+attar
+attempt
+attend
+attendant
+attendee
+attention
+attenuate
+attest
+attestation
+attic
+Attica
+attire
+attitude
+attitudinal
+attitudinize
+Attn
+Attn.
+attorney
+attract
+attribute
+attrition
+attune
+Atwater
+Atwood
+atypic
+Auberge
+Aubrey
+auburn
+Auckland
+auction
+auctioneer
+audacious
+audacity
+audible
+audience
+audio
+audiology
+audiometer
+audiophile
+audiotape
+audiovisual
+audit
+audition
+auditor
+auditorium
+Audrey
+Audubon
+Auerbach
+Aug.
+Augean
+augend
+auger
+aught
+augment
+augmentation
+augur
+augury
+august
+Augusta
+Augustan
+Augustine
+Augustus
+auk
+aunt
+auntie
+aura
+aural
+aureomycin
+auric
+auricle
+auricular
+Auriga
+aurora
+auroral
+Auschwitz
+auspices
+auspicious
+Aussie
+austenite
+austere
+Austin
+austral
+Australasia
+Australia
+Australis
+Australopithecus
+Austria
+autarchy
+autarky
+authentic
+authenticate
+author
+authorial
+authoritarian
+authoritative
+autism
+autistic
+auto
+autobahn
+autochthonous
+autoclave
+autocracy
+autocrat
+autocratic
+autodidact
+autogen
+autogenic
+autogenous
+autogiro
+automata
+automate
+automatic
+automaton
+automorph
+automorphic
+autonomous
+autonomy
+autopsy
+autumn
+autumnal
+auxiliary
+auxin
+avail
+avalanche
+avalanching
+avarice
+avaricious
+avast
+avatar
+Ave.
+avenge
+avenue
+aver
+average
+averse
+aversion
+avert
+avertive
+Avery
+avian
+aviarist
+aviary
+aviate
+aviatrix
+aviculture
+avid
+avifauna
+avionic
+Avis
+Aviv
+avocado
+avocation
+avocet
+Avogadro
+avoid
+avoidance
+avoirdupois
+Avon
+avow
+avowal
+avuncular
+await
+awake
+awaken
+award
+awardee
+aware
+awash
+away
+awe
+aweigh
+awesome
+awestricken
+awestruck
+awful
+awhile
+awkward
+awl
+awn
+awoke
+awoken
+awry
+ax
+axe
+axial
+axil
+axillary
+axiology
+axiom
+axiomatic
+axiomatize
+axis
+axle
+axon
+ayatollah
+aye
+Ayers
+Aylesbury
+AZ
+azalea
+Azerbaijan
+azimuth
+azimuthal
+Azores
+Aztec
+Aztecan
+azure
+azurite
+babbitt
+babble
+Babcock
+babe
+Babel
+baboon
+babushka
+baby
+babyhood
+babyish
+Babylon
+Babylonian
+babysat
+babysit
+baccalaureate
+baccarat
+bacchanal
+bacchanalia
+bacchanalian
+Bacchus
+Bach
+bachelor
+bacilli
+bacillus
+back
+backache
+backbencher
+backbite
+backboard
+backbone
+backcross
+backdate
+backdrop
+backfield
+backfill
+backfire
+backgammon
+background
+backhand
+backhoe
+backlash
+backlog
+backorder
+backpack
+backplane
+backplate
+backrest
+backsaw
+backscatter
+backside
+backslap
+backslid
+backslide
+backspace
+backspin
+backstage
+backstay
+backstitch
+backstop
+backstretch
+backstroke
+backswept
+backtrack
+backup
+backward
+backwash
+backwater
+backwoods
+backyard
+bacon
+bacteria
+bacterial
+bacteriologic
+bacteriology
+bacteriophage
+bacterium
+bad
+bade
+Baden
+badge
+badinage
+badland
+badminton
+Baedeker
+Baffin
+baffle
+bag
+bagatelle
+bagel
+baggage
+baggy
+Baghdad
+Bagley
+bagpipe
+baguette
+bah
+Bahai
+Bahaism
+Bahama
+Bahrein
+bail
+Bailey
+bailiff
+bailiwick
+bailout
+Baird
+bait
+baize
+Baja
+bake
+Bakelite
+Bakersfield
+bakery
+Bakhtiari
+baklava
+baksheesh
+Baku
+balalaika
+balance
+Balboa
+balcony
+bald
+balderdash
+baldpate
+Baldwin
+baldy
+bale
+baleen
+baleful
+Balfour
+Bali
+Balinese
+balk
+Balkan
+balkanize
+ball
+ballad
+balladeer
+Ballard
+ballast
+ballerina
+ballet
+balletic
+balletomane
+ballfield
+balloon
+ballot
+ballpark
+ballroom
+ballyhoo
+balm
+baloney
+balsa
+balsam
+balsamic
+Baltic
+Baltimore
+Baltimorean
+baluster
+balustrade
+Balzac
+bam
+Bamako
+Bamberger
+Bambi
+bambino
+bamboo
+bamboozle
+ban
+banal
+banana
+Banbury
+band
+bandage
+bandanna
+bandgap
+bandicoot
+bandit
+banditry
+bandolier
+bandstand
+bandwagon
+bandwidth
+bandy
+bane
+bang
+bangkok
+Bangladesh
+bangle
+Bangor
+Bangui
+banish
+banister
+banjo
+bank
+bankroll
+bankrupt
+bankruptcy
+banns
+banquet
+banquette
+banshee
+bantam
+banter
+Bantu
+Bantus
+banyan
+banzai
+baobab
+baptism
+baptismal
+baptist
+Baptiste
+baptistery
+baptistry
+baptize
+bar
+barb
+Barbados
+Barbara
+barbarian
+barbaric
+barbarism
+barbarity
+barbarous
+barbecue
+barbell
+barber
+barberry
+Barbie
+barbital
+barbiturate
+Barbour
+Barcelona
+Barclay
+bard
+bare
+bareback
+barefaced
+barefoot
+bareheaded
+barfly
+bargain
+barge
+barhop
+baritone
+barium
+bark
+barkentine
+barley
+Barlow
+barmaid
+barn
+Barnabas
+barnacle
+Barnard
+Barnes
+Barnet
+Barnett
+Barney
+Barnhard
+barnstorm
+barnyard
+barograph
+barometer
+baron
+baroness
+baronet
+baronetage
+baronial
+barony
+baroque
+barque
+Barr
+barrack
+barracuda
+barrage
+barre
+barrel
+barren
+Barrett
+barrette
+barricade
+barrier
+Barrington
+barrio
+barrister
+Barron
+barroom
+barrow
+Barry
+Barrymore
+Barstow
+Bart
+bartend
+bartender
+barter
+Barth
+Bartholomew
+Bartlett
+Bartok
+Barton
+baryon
+basal
+basalt
+base
+baseball
+baseboard
+Basel
+baseline
+basement
+baseplate
+baserun
+bash
+bashaw
+basic
+basil
+basilar
+basilica
+basilisk
+basin
+basis
+bask
+basket
+basketball
+basketry
+basketwork
+basophilic
+Basque
+bass
+basset
+Bassett
+bassi
+bassinet
+basso
+bassoon
+basswood
+bastard
+bastardy
+baste
+bastille
+basting
+bastion
+bat
+Batavia
+batch
+Batchelder
+bate
+bateau
+Bateman
+bath
+bathe
+bathetic
+bathhouse
+bathos
+bathrobe
+bathroom
+bathtub
+Bathurst
+bathymetry
+batik
+Batman
+baton
+Bator
+batt
+battalion
+Battelle
+batten
+batterer
+battery
+battle
+battlefield
+battlefront
+battleground
+batwing
+bauble
+baud
+Baudelaire
+Bauer
+Bauhaus
+Bausch
+bauxite
+Bavaria
+bawd
+bawl
+Baxter
+bay
+bayberry
+Bayda
+Baylor
+bayonet
+Bayonne
+bayou
+Bayport
+Bayreuth
+bazaar
+bazooka
+BBC
+B.C.
+BC
+be
+beach
+beachcomb
+beachhead
+beacon
+bead
+beadle
+beadwork
+beagle
+beak
+beam
+bean
+beanbag
+beanie
+bear
+beard
+Beardsley
+bearish
+bearskin
+Beasley
+beast
+Beastie
+beat
+beaten
+beatific
+beatify
+beatitude
+beatnik
+Beatrice
+beau
+Beaujolais
+Beaumont
+Beauregard
+beauteous
+beautician
+beautify
+beauty
+beaux
+beaver
+bebop
+becalm
+became
+because
+Bechtel
+beck
+becket
+Beckman
+beckon
+Becky
+becloud
+become
+bed
+bedaub
+bedazzle
+bedbug
+bedclothes
+bedeck
+bedevil
+bedfast
+bedfellow
+Bedford
+bedim
+bedizen
+bedlam
+bedouin
+bedpan
+bedpost
+bedraggle
+bedridden
+bedrock
+bedroll
+bedroom
+bedside
+bedspread
+bedspring
+bedstead
+bedstraw
+bedtime
+bee
+Beebe
+beebread
+beech
+Beecham
+Beechcraft
+beechwood
+beef
+beefeater
+beefsteak
+beehive
+Beelzebub
+been
+beep
+beer
+beeswax
+beet
+Beethoven
+beetle
+befall
+befallen
+befell
+befit
+befog
+before
+beforehand
+beforetime
+befoul
+befriend
+befuddle
+beg
+began
+begat
+beget
+beggar
+beggary
+begin
+begone
+begonia
+begot
+begotten
+begrime
+begrudge
+beguile
+Begum
+begun
+behalf
+behave
+behavior
+behavioral
+behead
+beheld
+behemoth
+behest
+behind
+behindhand
+behold
+beholden
+behoove
+beige
+Beijing
+being
+Beirut
+bejeweled
+bel
+Bela
+belabor
+belated
+belay
+belch
+beleaguer
+Belfast
+belfry
+Belgian
+Belgium
+Belgrade
+belie
+belief
+belies
+believe
+belike
+Belinda
+belittle
+Belize
+bell
+Bella
+belladonna
+Bellamy
+Bellatrix
+bellboy
+belle
+bellflower
+bellhop
+bellicose
+belligerent
+Bellingham
+Bellini
+bellow
+bellum
+bellwether
+belly
+bellyache
+Belmont
+belong
+Belorussia
+beloved
+below
+Belshazzar
+belt
+Beltsville
+Beltway
+beluga
+belvedere
+belying
+bemadden
+bemoan
+bemuse
+Ben
+bench
+benchmark
+bend
+benday
+Bendix
+beneath
+Benedict
+Benedictine
+benediction
+benedictory
+benefaction
+benefactor
+benefactress
+benefice
+beneficent
+beneficial
+beneficiary
+benefit
+Benelux
+benevolent
+Bengal
+Bengali
+benight
+benign
+benignant
+benison
+Benjamin
+Bennett
+Bennie
+Bennington
+Benny
+Benson
+bent
+Bentham
+benthic
+Bentley
+Benton
+benumb
+Benz
+Benzedrine
+benzene
+benzoate
+benzoin
+benzyl
+Beowulf
+beplaster
+bequeath
+bequest
+berate
+Berea
+bereave
+bereft
+Berenices
+beret
+berg
+bergamot
+Bergen
+Berger
+Bergland
+Berglund
+Bergman
+Bergson
+Bergstrom
+beribbon
+beriberi
+Bering
+Berkeley
+berkelium
+Berkowitz
+Berkshire
+Berlin
+Berliner
+Berlioz
+Berlitz
+Berman
+Bermuda
+Bern
+Bernadette
+Bernadine
+Bernard
+Bernardino
+Bernardo
+berne
+Bernet
+Bernhard
+Bernice
+Bernie
+Berniece
+Bernini
+Bernoulli
+Bernstein
+berry
+berserk
+Bert
+berth
+Bertha
+Bertie
+Bertram
+Bertrand
+Berwick
+beryl
+beryllium
+beseech
+beseem
+beset
+beside
+besiege
+besmirch
+besot
+besought
+bespatter
+bespeak
+bespeckle
+bespectacled
+bespoke
+Bess
+Bessel
+Bessemer
+Bessie
+best
+bestial
+bestiary
+bestir
+bestow
+bestowal
+bestsell
+bestubble
+bet
+beta
+betake
+betaken
+betatron
+betel
+Betelgeuse
+Beth
+bethel
+Bethesda
+bethink
+Bethlehem
+bethought
+betide
+betimes
+betoken
+betony
+betook
+betray
+betrayal
+betrayer
+betroth
+betrothal
+Betsey
+Betsy
+Bette
+betterment
+bettor
+Betty
+between
+betwixt
+Beulah
+bevel
+beverage
+Beverly
+bevy
+bewail
+beware
+bewhisker
+bewilder
+bewitch
+bey
+beyond
+bezel
+Bhutan
+biannual
+bias
+biathlon
+biaxial
+bib
+bibb
+bible
+biblical
+bibliography
+bibliomania
+bibliophile
+bibulous
+bicameral
+bicarbonate
+bicentennial
+bicentric
+biceps
+bichromate
+bicker
+biconcave
+biconnected
+biconvex
+bicuspid
+bicycle
+bid
+biddable
+bidden
+biddy
+bide
+bidiagonal
+bidirectional
+biennial
+biennium
+bier
+bifacial
+bifocal
+bifold
+bifurcate
+big
+bigamist
+bigamous
+bigamy
+Bigelow
+biggie
+biggish
+Biggs
+bighead
+bighearted
+bighorn
+bight
+bigot
+bigotry
+bigwig
+biharmonic
+bijouterie
+bike
+bikini
+bilateral
+bilayer
+bile
+bilge
+bilharzia
+bilharziasis
+bilinear
+bilingual
+bilious
+bilk
+bill
+billabong
+billboard
+billet
+billfold
+billiard
+Billie
+Billiken
+billingsgate
+billion
+billionaire
+billionth
+billow
+billy
+Biltmore
+bimetal
+bimetallic
+bimetallism
+Bimini
+bimodal
+bimolecular
+bimonthly
+bin
+binary
+binaural
+bind
+bindery
+bindle
+binge
+Bingham
+Binghamton
+bingo
+binnacle
+binocular
+binomial
+binuclear
+biocide
+biography
+biology
+Biometrika
+biometry
+biopsy
+biota
+biotic
+bipartisan
+bipartite
+biped
+bipedal
+biphenyl
+biplane
+bipolar
+biquadratic
+biracial
+birch
+birchbark
+bird
+birdbath
+birdbrain
+birdhouse
+birdie
+birdseed
+birdshot
+birdwatch
+birefringent
+Birgit
+Birmingham
+birth
+birthday
+birthmark
+birthplace
+birthright
+birthstone
+biscuit
+bisect
+bisexual
+bishop
+bishopric
+Bismarck
+Bismark
+bismuth
+bison
+bisque
+Bissau
+bistable
+bistate
+bistro
+bit
+bitch
+bite
+bitt
+bitten
+bittern
+bitterroot
+bittersweet
+bitumen
+bituminous
+bitwise
+bivalent
+bivalve
+bivariate
+bivouac
+bivouacked
+bivouacking
+biweekly
+biz
+bizarre
+Bizet
+blab
+blabbermouth
+black
+blackamoor
+blackball
+blackberry
+blackbird
+blackboard
+blackbody
+Blackburn
+blacken
+blackface
+Blackfeet
+blackfly
+blackguard
+blackhead
+blackish
+blackjack
+blacklist
+blackmail
+Blackman
+blackout
+blacksmith
+blacksnake
+Blackstone
+blacktop
+Blackwell
+bladder
+bladdernut
+blade
+blah
+Blaine
+Blair
+Blake
+blame
+blameworthy
+blanc
+blanch
+Blanchard
+Blanche
+bland
+blandish
+blank
+Blankenship
+blanket
+blare
+blarney
+blaspheme
+blasphemous
+blasphemy
+blast
+blat
+blatant
+blather
+blatherskite
+Blatz
+blaze
+blazon
+bleach
+bleak
+bleary
+bleat
+bled
+bleed
+Bleeker
+blemish
+blench
+blend
+Blenheim
+bless
+blest
+Blevins
+blew
+blight
+blimp
+blimpish
+blind
+blindfold
+blink
+Blinn
+blintz
+blip
+bliss
+blister
+blithe
+blitz
+blitzkrieg
+blizzard
+bloat
+blob
+bloc
+Bloch
+block
+blockade
+blockage
+blockbust
+blockhead
+blockhouse
+bloke
+Blomberg
+Blomquist
+blond
+blonde
+blood
+bloodbath
+bloodhound
+bloodletting
+bloodroot
+bloodshed
+bloodshot
+bloodstain
+bloodstone
+bloodstream
+bloodsuck
+bloodthirsty
+bloody
+bloom
+Bloomfield
+Bloomington
+bloop
+blossom
+blot
+blotch
+blotchy
+blouse
+blow
+blowback
+blowfish
+blowgun
+blowhard
+blowhole
+blown
+blowout
+blowpipe
+blowsy
+blowtorch
+blowup
+blowzy
+blubber
+blubbery
+bludgeon
+blue
+blueback
+bluebeard
+bluebell
+blueberry
+bluebill
+bluebird
+bluebonnet
+bluebook
+bluebush
+bluefin
+bluefish
+bluegill
+bluegrass
+bluejacket
+bluepoint
+blueprint
+bluestocking
+bluet
+bluff
+bluish
+Blum
+Blumenthal
+blunder
+blunderbuss
+blunt
+blur
+blurb
+blurt
+blush
+bluster
+blustery
+blutwurst
+Blvd.
+Blythe
+BMW
+boa
+boar
+board
+boardinghouse
+boardroom
+boardwalk
+boast
+boat
+boathouse
+boatload
+boatswain
+boatyard
+bob
+Bobbie
+bobbin
+bobble
+bobby
+bobcat
+bobolink
+bobsled
+bobtail
+bobwhite
+Boca
+bocce
+boccie
+bock
+boddhisattva
+bode
+bodega
+bodhisattva
+bodice
+Bodleian
+body
+bodybuild
+bodyguard
+Boeing
+Boeotian
+bog
+bogey
+boggle
+Bogota
+bogus
+bogy
+Bohemia
+Bohr
+boil
+Bois
+Boise
+boisterous
+bola
+bold
+boldface
+bole
+bolero
+boletus
+bolivar
+Bolivia
+boll
+bollard
+bollix
+bolo
+Bologna
+bolometer
+Bolshevik
+Bolshevism
+Bolshevist
+Bolshoi
+bolster
+bolt
+Bolton
+Boltzmann
+bomb
+bombard
+bombardier
+bombast
+bombastic
+Bombay
+bombproof
+bombshell
+bombsight
+bon
+bona
+bonanza
+Bonaparte
+Bonaventure
+bonbon
+bond
+bondage
+bondholder
+bonds
+bone
+bonefish
+bonehead
+bonfire
+bong
+bongo
+Boniface
+bonito
+bonkers
+Bonn
+Bonner
+bonnet
+Bonneville
+Bonnie
+bonny
+bonsai
+bonus
+bonze
+boo
+boob
+boodle
+boogie
+book
+bookbind
+bookcase
+bookend
+bookie
+bookish
+booklet
+bookmark
+bookmobile
+bookplate
+booksell
+bookshelf
+bookshelves
+bookstore
+bookworm
+boolean
+boom
+boomerang
+boon
+boondock
+boondoggle
+Boone
+boor
+boorish
+boost
+boot
+bootblack
+Bootes
+booth
+bootie
+bootleg
+bootlick
+bootstrap
+booze
+bop
+borage
+borane
+borate
+borax
+Bordeaux
+bordello
+Borden
+border
+borderland
+borderline
+bore
+boreal
+borealis
+Boreas
+boredom
+Borg
+boric
+Boris
+born
+borne
+Borneo
+boron
+borosilicate
+borough
+Borroughs
+borrow
+borscht
+borzoi
+Bosch
+Bose
+bosh
+Bosnia
+bosom
+boson
+boss
+Boston
+bosun
+Boswell
+botanic
+botanist
+botanize
+botany
+botch
+botfly
+both
+botheration
+bothersome
+Botswana
+bottle
+bottleneck
+bottom
+bottommost
+botulin
+botulism
+Boucher
+boudoir
+bouffant
+bough
+bought
+bouillabaisse
+bouillon
+boulder
+bouldery
+boule
+boulevard
+boulevardier
+bounce
+bouncy
+bound
+boundary
+bounden
+bounteous
+bounty
+bouquet
+bourbon
+bourdon
+bourgeois
+bourgeoise
+bourgeoisie
+bourn
+bourse
+boustrophedon
+bout
+boutique
+boutonniere
+bovine
+bow
+Bowditch
+bowdlerize
+Bowdoin
+bowel
+Bowen
+bowery
+bowfin
+bowhead
+bowie
+bowl
+bowleg
+bowline
+bowsprit
+bowstring
+box
+boxcar
+boxwood
+boy
+boyar
+Boyce
+boycott
+Boyd
+Boyer
+boyfriend
+boyhood
+boyish
+Boyle
+Boylston
+boysenberry
+BP
+bra
+brace
+bracelet
+brachycephalic
+bracken
+bracket
+brackish
+bract
+brad
+Bradbury
+Bradford
+Bradley
+Bradshaw
+Brady
+brae
+brag
+Bragg
+braggart
+brahma
+Brahman
+Brahmaputra
+Brahmin
+Brahms
+Brahmsian
+braid
+braille
+brain
+Brainard
+brainchild
+brainchildren
+brainstorm
+brainwash
+braise
+brake
+bramble
+bran
+branch
+brand
+Brandeis
+Brandenburg
+brandish
+Brandon
+Brandt
+brandy
+brandywine
+Braniff
+brant
+brash
+Brasilia
+brass
+brassiere
+brat
+brattish
+bratwurst
+Braun
+bravado
+brave
+bravery
+bravo
+bravura
+brawl
+brawn
+bray
+braze
+brazen
+brazier
+Brazil
+Brazilian
+Brazzaville
+breach
+bread
+breadbasket
+breadboard
+breadfruit
+breadroot
+breadth
+breadwin
+break
+breakage
+breakaway
+breakdown
+breakfast
+breakneck
+breakout
+breakpoint
+breakthrough
+breakup
+breakwater
+bream
+breast
+breastplate
+breastwork
+breath
+breathalyzer
+breathe
+breathtaking
+breccia
+bred
+breech
+breechclout
+breeches
+breed
+breeze
+breezeway
+Bremen
+bremsstrahlung
+Brenda
+Brendan
+Brennan
+Brenner
+Brent
+Brest
+brethren
+Breton
+Brett
+breve
+brevet
+breviary
+brevity
+brew
+brewery
+Brewster
+Brian
+briar
+bribe
+bribery
+Brice
+brick
+brickbat
+bricklay
+brickwork
+brickyard
+bridal
+bride
+bridegroom
+bridesmaid
+bridge
+bridgeable
+bridgehead
+Bridgeport
+Bridget
+Bridgetown
+bridgework
+bridle
+Brie
+brief
+briefcase
+brier
+briery
+brig
+brigade
+brigadier
+brigand
+brigantine
+Briggs
+Brigham
+bright
+brighten
+Brighton
+brightwork
+Brigitte
+brilliant
+Brillouin
+brim
+brimstone
+Brindisi
+brindle
+brine
+bring
+brink
+brinkmanship
+brioche
+briquette
+Brisbane
+brisk
+brisket
+bristle
+bristly
+bristol
+Britain
+Britannic
+Britannica
+britches
+Briticism
+British
+Britisher
+Briton
+Britt
+Brittany
+Britten
+brittle
+broach
+broad
+broadcast
+broadcloth
+broaden
+broadloom
+broadsheet
+broadside
+Broadway
+brocade
+broccoli
+brochette
+brochure
+Brock
+Broglie
+brogue
+broil
+broke
+broken
+brokerage
+bromate
+bromeliad
+Bromfield
+bromide
+bromine
+Bromley
+bronchi
+bronchial
+bronchitis
+bronchus
+bronco
+brontosaurus
+Bronx
+bronze
+brooch
+brood
+brook
+Brooke
+Brookhaven
+Brookline
+Brooklyn
+brookside
+broom
+broomcorn
+broomstick
+broth
+brothel
+brother
+brougham
+brought
+brouhaha
+brow
+browbeat
+browbeaten
+brown
+Browne
+Brownell
+Brownian
+brownie
+brownish
+brownout
+brownstone
+browse
+Bruce
+brucellosis
+Bruckner
+Bruegel
+bruise
+bruit
+Brumidi
+brunch
+brunette
+Brunhilde
+Bruno
+Brunswick
+brunt
+brush
+brushfire
+brushwork
+brusque
+Brussels
+brutal
+brute
+brutish
+Bryan
+Bryant
+Bryce
+Bryn
+bryophyte
+b's
+BSA
+BTU
+bubble
+bubonic
+buccaneer
+Buchanan
+Bucharest
+Buchenwald
+Buchwald
+buck
+buckaroo
+buckboard
+bucket
+buckeye
+buckhorn
+Buckingham
+buckle
+Buckley
+Bucknell
+buckram
+buckshot
+buckskin
+buckthorn
+bucktooth
+buckwheat
+bucolic
+bud
+Budapest
+Budd
+Buddha
+Buddhism
+Buddhist
+buddy
+budge
+budget
+budgetary
+budgeteer
+budgie
+budgiregar
+Budweiser
+Buena
+Buenos
+buff
+buffalo
+buffet
+bufflehead
+buffoon
+buffoonery
+buffoonish
+bug
+bugaboo
+bugbear
+bugeyed
+buggery
+buggy
+bughouse
+bugle
+Buick
+build
+buildup
+built
+builtin
+Bujumbura
+bulb
+bulblet
+bulbous
+Bulgaria
+bulge
+bulimia
+bulimic
+bulk
+bulkhead
+bull
+bulldog
+bulldoze
+bullet
+bulletin
+bulletproof
+bullfight
+bullfinch
+bullfrog
+bullhead
+bullhide
+bullhorn
+bullion
+bullish
+bullock
+bullpen
+bullseye
+bullshit
+bullwhack
+bullwhip
+bully
+bullyboy
+bullyrag
+bulrush
+bulwark
+bum
+bumble
+bumblebee
+bump
+bumpkin
+bumptious
+bun
+bunch
+buncombe
+Bundestag
+bundle
+bung
+bungalow
+bungee
+bunghole
+bungle
+bunion
+bunk
+bunkhouse
+bunkmate
+bunkum
+bunny
+Bunsen
+bunt
+Bunyan
+buoy
+buoyant
+burble
+Burch
+burden
+burdensome
+burdock
+bureau
+bureaucracy
+bureaucrat
+bureaucratic
+buret
+burette
+burg
+burgee
+burgeon
+burgess
+burgher
+burglar
+burglarproof
+burglary
+burgle
+burgomaster
+Burgundian
+Burgundy
+burial
+buried
+burin
+Burke
+Burkina
+burl
+burlap
+burlesque
+burley
+Burlington
+burly
+Burma
+Burmese
+burn
+Burnett
+Burnham
+burnish
+burnoose
+burnout
+Burnside
+burnt
+burp
+burr
+burrito
+burro
+Burroughs
+burrow
+bursar
+bursitis
+burst
+Burt
+Burton
+Burtt
+Burundi
+bury
+bus
+busboy
+Busch
+buses
+bush
+bushel
+bushmaster
+Bushnell
+bushwhack
+business
+busload
+buss
+bust
+bustard
+bustle
+busy
+busybody
+busyness
+but
+butadiene
+butane
+butch
+butcher
+butchery
+butene
+buteo
+butler
+butt
+butte
+butterball
+buttercup
+butterfat
+Butterfield
+butterfinger
+butterfly
+buttermilk
+butternut
+butterscotch
+buttery
+buttock
+button
+buttonhole
+buttonhook
+buttonwood
+buttress
+Buttrick
+butyl
+butylene
+butyrate
+butyric
+buxom
+Buxtehude
+Buxton
+buy
+buyback
+buyer
+buyout
+buzz
+buzzard
+buzzer
+buzzing
+buzzsaw
+buzzword
+BWI
+by
+bye
+Byers
+bygone
+bylaw
+byline
+bypass
+bypath
+byplay
+byproduct
+Byrd
+Byrne
+byroad
+Byron
+Byronic
+bystander
+byte
+byway
+byword
+Byzantine
+Byzantium
+CA
+cab
+cabal
+cabala
+cabana
+cabaret
+cabbage
+cabby
+cabdriver
+cabin
+cabinet
+cabinetry
+cabinetwork
+cable
+cablegram
+caboodle
+caboose
+Cabot
+cabriole
+cabriolet
+cacao
+cacciatore
+cachalot
+cache
+cachet
+caching
+cacique
+cackle
+CACM
+cacophonist
+cacophonous
+cacophony
+cacti
+cactus
+cad
+cadastral
+cadaver
+cadaverous
+caddie
+caddish
+caddy
+cadent
+cadenza
+cadet
+cadge
+Cadillac
+cadmium
+cadre
+caduceus
+Cady
+Caesar
+caesura
+cafe
+cafeteria
+caffeinate
+caffeine
+caftan
+cage
+cagey
+Cahill
+cahoot
+caiman
+Cain
+Caine
+cairn
+Cairo
+caisson
+cajole
+cajolery
+Cajun
+cake
+cakewalk
+Cal
+calabash
+Calais
+calamine
+calamitous
+calamity
+calcareous
+calcify
+calcine
+calcite
+calcium
+calculable
+calculate
+calculi
+calculus
+Calcutta
+Calder
+caldera
+Caldwell
+Caleb
+calendar
+calendric
+calends
+calendula
+calf
+calfskin
+Calgary
+Calhoun
+caliber
+calibrate
+calico
+California
+californium
+caliper
+caliph
+caliphate
+calisthenic
+calk
+Calkins
+call
+calla
+Callaghan
+Callahan
+calligraph
+calligraphy
+calliope
+Callisto
+callous
+callow
+callus
+calm
+caloric
+calorie
+calorimeter
+Calumet
+calumniate
+calumny
+calvados
+calvary
+calve
+Calvert
+Calvin
+Calvinist
+calypso
+calyx
+cam
+camaraderie
+camber
+cambium
+Cambodia
+Cambrian
+cambric
+Cambridge
+camcorder
+Camden
+came
+camel
+camelback
+cameleer
+camellia
+camelopard
+Camelot
+Camembert
+cameo
+camera
+Cameron
+Cameroun
+Camilla
+Camille
+Camino
+camisole
+camouflage
+camp
+campaign
+campanile
+campanology
+Campbell
+campfire
+campground
+camphor
+campion
+camporee
+campsite
+campus
+camshaft
+can
+Canaan
+Canada
+Canadian
+canal
+canalize
+canape
+canard
+canary
+canasta
+Canaveral
+Canberra
+cancan
+cancel
+cancellate
+cancer
+cancerous
+Candace
+candela
+candelabra
+candid
+candidacy
+candidate
+Candide
+candle
+candlelight
+candlelit
+candlepower
+candlestick
+candor
+candy
+cane
+Canfield
+canine
+Canis
+canister
+canker
+cankerworm
+canna
+cannabis
+cannel
+cannery
+cannibal
+cannister
+cannon
+cannonade
+cannonball
+cannoneer
+cannot
+canoe
+canoeing
+canoeist
+Canoga
+canon
+canonic
+canopy
+canst
+can't
+cant
+cantabile
+Cantabrigian
+cantaloupe
+cantankerous
+cantata
+canteen
+Canterbury
+canticle
+cantilever
+cantle
+canto
+canton
+Cantonese
+cantor
+Cantrell
+canvas
+canvasback
+canvass
+canyon
+cap
+capacious
+capacitance
+capacitate
+capacitive
+capacitor
+capacity
+caparison
+cape
+capella
+caper
+Capetown
+capillarity
+capillary
+Capistrano
+capita
+capital
+capitate
+capitol
+Capitoline
+capitulate
+capo
+capon
+cappucino
+caprice
+capricious
+Capricorn
+capsize
+capstan
+capstone
+capsule
+captain
+captaincy
+caption
+captious
+captivate
+captor
+capture
+capuchin
+Caputo
+capybara
+car
+carabiner
+Caracas
+caracul
+carafe
+carageen
+caramel
+carapace
+carat
+caravan
+caravansary
+caravel
+caraway
+carbide
+carbine
+carbohydrate
+Carboloy
+carbon
+carbonaceous
+carbonate
+Carbondale
+Carbone
+carbonic
+carboniferous
+carbonyl
+carborundum
+carboxy
+carboxyl
+carboxylate
+carboy
+carbuncle
+carburet
+carburetion
+carburetor
+carcass
+carcinogen
+carcinogenic
+carcinoma
+card
+cardamom
+cardboard
+cardiac
+cardigan
+cardinal
+cardiograph
+cardiography
+cardioid
+cardiology
+cardiovascular
+care
+careen
+career
+carefree
+caress
+caret
+caretaker
+careworn
+Carey
+carfare
+Cargill
+cargo
+cargoes
+carhop
+Carib
+Caribbean
+caribou
+caricature
+caries
+carillon
+carioca
+Carl
+Carla
+Carleton
+Carlin
+Carlisle
+Carlo
+carload
+Carlson
+Carlton
+Carlyle
+Carmela
+Carmen
+Carmichael
+carmine
+carnage
+carnal
+carnation
+carne
+Carnegie
+carnelian
+carney
+carnival
+carnivore
+carnivorous
+carny
+carob
+carol
+Carole
+Carolina
+Caroline
+Carolingian
+Carolinian
+Carolyn
+carom
+carotene
+carotid
+carousal
+carouse
+carousel
+carp
+carpal
+Carpathia
+carpel
+carpenter
+carpentry
+carpet
+carpetbag
+carport
+Carr
+carrageen
+Carrara
+carrel
+carriage
+Carrie
+carrion
+Carroll
+carrot
+Carruthers
+carry
+carryall
+carryover
+carsick
+Carson
+cart
+cartage
+carte
+cartel
+Cartesian
+Carthage
+Carthaginian
+cartilage
+cartogram
+cartography
+carton
+cartoon
+cartouche
+cartridge
+cartwheel
+Caruso
+carve
+carven
+caryatid
+casaba
+Casanova
+casbah
+cascade
+cascara
+case
+casebook
+casein
+casework
+Casey
+cash
+cashew
+cashier
+cashmere
+casino
+cask
+casket
+Caspian
+Cassandra
+cassava
+casserole
+cassette
+Cassidy
+Cassiopeia
+Cassius
+cassock
+cassowary
+cast
+castanet
+castaway
+caste
+casteth
+castigate
+Castilian
+Castillo
+castle
+castoff
+castor
+castrate
+Castro
+casual
+casualty
+casuist
+casuistry
+cat
+catabolic
+catabolize
+cataclysm
+cataclysmic
+catacomb
+catafalque
+Catalan
+catalepsy
+cataleptic
+Catalina
+catalog
+catalogue
+catalpa
+catalysis
+catalyst
+catalytic
+catalyze
+catamaran
+catamount
+catapult
+cataract
+catarrh
+catastrophe
+catastrophic
+catatonia
+catatonic
+catbird
+catcall
+catch
+catchall
+catchup
+catchword
+catechism
+catechist
+catechize
+categoric
+categorize
+category
+catena
+catenary
+catenate
+cater
+caterpillar
+caterwaul
+catfish
+catgut
+catharsis
+cathartic
+cathedra
+cathedral
+Catherine
+Catherwood
+catheter
+cathode
+cathodic
+catholic
+Catholicism
+Cathy
+cation
+cationic
+catkin
+catnap
+catnip
+Catskill
+catsup
+cattail
+cattle
+catty
+CATV
+catwalk
+Caucasia
+Caucasus
+Cauchy
+caucus
+caudal
+caudillo
+caught
+cauldron
+cauliflower
+caulk
+causa
+causal
+causation
+cause
+causeway
+caustic
+cauterize
+caution
+cautionary
+cautious
+cavalcade
+cavalier
+cavalry
+cave
+caveat
+Cavendish
+cavern
+cavernous
+caviar
+cavil
+Caviness
+cavitate
+cavort
+caw
+cay
+cayenne
+Cayley
+cayman
+Cayuga
+CB
+CBC
+CBS
+CCC
+CCNY
+CD
+CDC
+cease
+Cecil
+Cecilia
+Cecily
+Cecropia
+cedar
+cede
+cedilla
+Cedric
+ceil
+celandine
+Celanese
+Celebes
+celebrant
+celebrate
+celebrity
+celeriac
+celerity
+celery
+celesta
+Celeste
+celestial
+Celia
+celibacy
+celibate
+cell
+cellar
+cello
+cellophane
+cellular
+celluloid
+cellulose
+Celsius
+Celt
+Celtic
+cement
+cemetery
+cenotaph
+cenote
+Cenozoic
+censer
+censor
+censorial
+censorious
+censure
+census
+cent
+centaur
+Centauri
+centenarian
+centenary
+centennial
+center
+centerboard
+centered
+centerfold
+centering
+centerline
+centerpiece
+centers
+centesimal
+centigrade
+centigram
+centiliter
+centime
+centimeter
+centipede
+central
+centrex
+centric
+centrifugal
+centrifugate
+centrifuge
+centripetal
+centrist
+centroid
+centum
+centurion
+century
+CEO
+cephalic
+cephalopod
+Cepheid
+Cepheus
+CEQ
+ceramic
+ceramist
+Cerberus
+cereal
+cerebellum
+cerebral
+cerebrate
+cerebrum
+ceremonial
+ceremonious
+ceremony
+Ceres
+cereus
+cerise
+cerium
+CERN
+certain
+certainty
+certificate
+certificatory
+certified
+certify
+certiorari
+certitude
+cerulean
+Cervantes
+cervical
+cervix
+cesarean
+cesium
+cessation
+cession
+Cessna
+cesspool
+cetacean
+cetera
+ceteris
+Cetus
+Ceylon
+Cezanne
+Chablis
+Chad
+chador
+Chadwick
+chafe
+chaff
+chaffer
+chaffinch
+chagrin
+chain
+chainsaw
+chair
+chairlady
+chaise
+chalcedony
+chalet
+chalice
+chalk
+chalkboard
+chalkline
+challenge
+Chalmers
+chamber
+chamberlain
+chambermaid
+chameleon
+chamfer
+chamois
+chamomile
+champ
+champagne
+champaign
+champion
+Champlain
+Chan
+chance
+chancel
+chancellery
+chancellor
+chancery
+chancy
+chandelier
+chandler
+chandlery
+Chaney
+Chang
+change
+changeable
+changeling
+changeover
+channel
+chanson
+chant
+chantey
+chanticleer
+Chantilly
+chantry
+chanty
+Chao
+chaos
+chaotic
+chap
+chaparral
+chapel
+chaperon
+chaperone
+chaplain
+chaplaincy
+Chaplin
+chapter
+char
+character
+characteristic
+charade
+charcoal
+chard
+charge
+chargeable
+charily
+chariot
+charioteer
+charisma
+charismatic
+charitable
+charity
+charlatan
+Charlene
+Charles
+Charleston
+Charley
+Charlie
+Charlotte
+Charlottesville
+charm
+charnel
+Charon
+chart
+Charta
+charter
+Chartres
+chartreuse
+chartroom
+chary
+Charybdis
+chase
+chasm
+chassis
+chaste
+chasten
+chastise
+chastity
+chasuble
+chat
+chateau
+chateaux
+Chatham
+Chattanooga
+chattel
+chatter
+Chaucer
+chauffer
+chauffeur
+Chauncey
+Chautauqua
+chauvinism
+chauvinist
+Chavez
+chaw
+cheap
+cheapen
+cheapskate
+cheat
+check
+checkbook
+checkerboard
+checklist
+checkmate
+checkout
+checkpoint
+checkroom
+checksum
+checkup
+cheddar
+cheek
+cheekbone
+cheer
+cheerlead
+cheery
+cheese
+cheeseburger
+cheesecake
+cheesecloth
+cheetah
+chef
+chelate
+Chelsea
+chemic
+chemise
+chemisorb
+chemisorption
+chemist
+chemistry
+chemoreception
+chemoreceptor
+chemotherapeutic
+chemotherapy
+chemurgy
+Chen
+Cheney
+chenille
+cherish
+Cherokee
+cheroot
+cherry
+chert
+cherub
+cherubic
+cherubim
+chervil
+Cheryl
+Chesapeake
+Cheshire
+chess
+chessboard
+chest
+Chester
+chesterfield
+Chesterton
+chestnut
+chevalier
+Chevrolet
+chevron
+Chevy
+chew
+Cheyenne
+chi
+Chiang
+chianti
+chiaroscuro
+chiasma
+chic
+Chicago
+Chicagoan
+chicanery
+Chicano
+chick
+chickadee
+chicken
+chicle
+chicory
+chide
+chief
+chiefdom
+chieftain
+chiffon
+chigger
+chignon
+Chihuahua
+chilblain
+child
+childbear
+childbirth
+Childers
+childish
+children
+Chile
+Chilean
+chili
+chilies
+chill
+chilly
+chime
+chimera
+chimeric
+Chimique
+chimney
+chimp
+chimpanzee
+chin
+china
+Chinaman
+Chinamen
+Chinatown
+chinch
+chinchilla
+chine
+Chinese
+Ching
+chink
+chino
+chinoiserie
+Chinook
+chintz
+chintzy
+chip
+chipboard
+chipmunk
+Chippendale
+Chippewa
+chiropodist
+chiropractic
+chiropractor
+chirp
+chisel
+Chisholm
+chit
+chitchat
+chitin
+chitinous
+chiton
+chivalric
+chivalrous
+chivalry
+chive
+chlorate
+chlordane
+chloric
+chloride
+chlorinate
+chlorine
+chloroform
+chlorophyl
+chlorophyll
+chock
+chocolate
+Choctaw
+choice
+choir
+choirboy
+choirmaster
+choke
+choler
+cholera
+choleric
+cholesterol
+cholinesterase
+chomp
+chondrite
+chondrule
+choose
+chop
+chophouse
+Chopin
+chopstick
+choral
+chorale
+chord
+chordal
+chordate
+chore
+choreograph
+choreography
+chorine
+chortle
+chorus
+chose
+chosen
+Chou
+chow
+chowder
+Chris
+Christ
+christen
+Christendom
+Christensen
+Christenson
+Christian
+Christiana
+Christianson
+Christie
+Christina
+Christine
+Christlike
+Christmas
+Christoffel
+Christophe
+Christopher
+Christy
+chromate
+chromatic
+chromatograph
+chromatography
+chrome
+chromic
+chromium
+chromosomal
+chromosome
+chromosphere
+chronic
+chronicle
+chronograph
+chronography
+chronology
+chronometer
+chrysalis
+chrysanthemum
+Chrysler
+chub
+chuck
+chuckle
+chuff
+chug
+chukker
+chum
+chump
+Chungking
+chunk
+church
+churchgo
+Churchill
+Churchillian
+churchyard
+churl
+churlish
+churn
+chute
+chutney
+CIA
+cicada
+Cicero
+Ciceronian
+cider
+cigar
+cigarette
+cilantro
+cilia
+ciliate
+cinch
+Cincinnati
+cinder
+Cinderella
+Cindy
+cinema
+cinematic
+cinematography
+Cinerama
+cinnabar
+cinnamon
+CIO
+cipher
+circa
+circadian
+Circe
+circle
+circlet
+circuit
+circuitous
+circuitry
+circulant
+circular
+circulate
+circumambient
+circumambulate
+circumcircle
+circumcise
+circumcision
+circumference
+circumferential
+circumflex
+circumfluent
+circumlocution
+circumlocutory
+circumnavigate
+circumpolar
+circumscribe
+circumscription
+circumspect
+circumsphere
+circumstance
+circumstantial
+circumvallate
+circumvent
+circus
+cirque
+cirrhosis
+cirrostratus
+cirrus
+CIS
+cistern
+cit.
+citadel
+citation
+cite
+Citicorp
+citify
+citizen
+citizeness
+citizenry
+citrate
+citric
+Citroen
+citron
+citrus
+city
+cityscape
+citywide
+civet
+civic
+civil
+civilian
+clack
+clad
+claim
+claimant
+Claire
+clairvoyant
+clam
+clambake
+clamber
+clamor
+clamorous
+clamp
+clamshell
+clan
+clandestine
+clang
+clangor
+clangorous
+clank
+clannish
+clans
+clap
+clapboard
+Clapeyron
+claptrap
+claque
+Clara
+Clare
+Claremont
+Clarence
+Clarendon
+claret
+clarify
+clarinet
+clarion
+clarity
+Clark
+Clarke
+clash
+clasp
+class
+classic
+classification
+classificatory
+classify
+classmate
+classroom
+clatter
+clattery
+Claude
+Claudia
+Claudio
+Claus
+clausal
+clause
+Clausen
+Clausius
+claustral
+claustrophobe
+clavichord
+clavicle
+clavier
+claw
+clay
+clayey
+claymore
+Clayton
+clean
+cleanse
+cleanup
+clear
+clearance
+clearheaded
+clearinghouse
+Clearwater
+cleat
+cleavage
+cleave
+clef
+cleft
+Clem
+clematis
+clement
+Clemson
+clench
+Cleo
+Cleopatra
+clepsydra
+clerestory
+clergy
+cleric
+clerisy
+clerk
+Cleveland
+clever
+cliche
+click
+client
+clientele
+cliff
+cliffhang
+Clifford
+Clifton
+climactic
+climate
+climatic
+climatology
+climax
+climb
+clime
+clinch
+cline
+cling
+clinic
+clinician
+clink
+Clint
+Clinton
+Clio
+clip
+clipboard
+clique
+clitoral
+clitoris
+Clive
+cloaca
+cloak
+cloakroom
+clobber
+clock
+clockwatcher
+clockwise
+clockwork
+clod
+cloddish
+clodhop
+clog
+cloisonne
+cloister
+clomp
+clonal
+clone
+clonic
+clop
+close
+closemouthed
+closet
+closeup
+closure
+clot
+cloth
+clothbound
+clothe
+clothes
+clotheshorse
+clothesline
+clothespin
+clothier
+Clotho
+cloture
+cloud
+cloudburst
+clout
+clove
+cloven
+cloverleaf
+clown
+clownish
+cloy
+club
+clubfoot
+clubhouse
+clubroom
+cluck
+clue
+clump
+clumsy
+clung
+clunk
+cluster
+clutch
+clutter
+Clyde
+Clytemnestra
+CNN
+Co.
+coach
+coachwork
+coact
+coadjutor
+coagulable
+coagulant
+coagulate
+coal
+coalesce
+coalescent
+coalition
+coaming
+coanchor
+coarse
+coarsen
+coarticulate
+coast
+coastal
+coastline
+coastwise
+coat
+Coates
+coati
+coattail
+coauthor
+coax
+coaxial
+cob
+cobalt
+Cobb
+cobble
+cobblestone
+Cobol
+cobra
+cobweb
+coca
+cocaine
+cocci
+coccidiosis
+coccus
+cochair
+cochineal
+cochlea
+cochlear
+Cochran
+Cochrane
+cock
+cockade
+cockamamie
+cockatiel
+cockatoo
+cockcrow
+cockerel
+cockeye
+cockfight
+cockle
+cocklebur
+cockleshell
+cockney
+cockpit
+cockroach
+cocksure
+cocktail
+coco
+cocoa
+cocoanut
+coconut
+cocoon
+cod
+coda
+Coddington
+coddle
+code
+codebreak
+codefendant
+codeine
+codeposit
+codetermine
+codeword
+codex
+codfish
+codger
+codices
+codicil
+codify
+codpiece
+Cody
+coed
+coeditor
+coeducation
+coefficient
+coelacanth
+coequal
+coerce
+coercible
+coercion
+coeval
+coexist
+coexistent
+coextensive
+cofactor
+coffee
+coffeecup
+coffeehouse
+coffeepot
+coffer
+cofferdam
+Coffey
+coffin
+Coffman
+cofound
+cog
+cogent
+cogitate
+cognac
+cognate
+cognition
+cognizable
+cognizant
+cognoscenti
+cohabit
+cohabitation
+Cohen
+cohere
+coherent
+cohesion
+Cohn
+cohort
+cohosh
+cohost
+coif
+coiffeur
+coiffure
+coil
+coin
+coinage
+coincide
+coincident
+coincidental
+coinsurance
+coinsure
+coinvent
+coinventor
+coital
+coitus
+coke
+col
+cola
+colander
+colatitude
+Colby
+cold
+cole
+Coleman
+coleoptera
+Coleridge
+coleslaw
+Colette
+coleus
+Colgate
+colic
+colicky
+coliform
+Colin
+coliseum
+colitis
+collaborate
+collage
+collagen
+collagenic
+collapse
+collapsible
+collar
+collarbone
+collard
+collate
+collateral
+colleague
+collect
+collectible
+colleen
+college
+collegial
+collegian
+collegiate
+collet
+collide
+collie
+colliery
+collimate
+collinear
+Collins
+collision
+collocate
+collodion
+colloid
+colloquia
+colloquial
+colloquium
+colloquy
+collude
+collusion
+cologne
+Colombia
+Colombo
+colon
+colonel
+colonial
+colonic
+colonist
+colonnade
+colony
+colophon
+color
+Colorado
+colorate
+coloratura
+colorcast
+colorfast
+colorimeter
+colossal
+Colosseum
+colossi
+Colossian
+Colossians
+colossus
+colostomy
+colostrum
+colt
+coltish
+coltsfoot
+Columbia
+columbine
+Columbus
+column
+columnar
+colza
+coma
+Comanche
+comatose
+comb
+combat
+combatant
+combative
+combination
+combinator
+combinatorial
+combinatoric
+combine
+combust
+combustible
+come
+comeback
+comedian
+comedic
+comedienne
+comedown
+comedy
+comestible
+comet
+cometary
+cometh
+comeuppance
+comfort
+comfrey
+comfy
+comic
+Cominform
+comma
+command
+commandant
+commandeer
+commando
+commemorate
+commend
+commendation
+commendatory
+commensurable
+commensurate
+comment
+commentary
+commentator
+commerce
+commercial
+commie
+commingle
+comminute
+commiserate
+commissar
+commissariat
+commissary
+commission
+commit
+committable
+committal
+committee
+commode
+commodious
+commodity
+commodore
+common
+commonality
+commonplace
+commonweal
+commonwealth
+commotion
+communal
+commune
+communicable
+communicant
+communicate
+communion
+communique
+communitarian
+commutate
+commute
+compact
+Compagnie
+companion
+companionway
+company
+comparative
+comparator
+compare
+comparison
+compartment
+compass
+compassion
+compassionate
+compatible
+compatriot
+compeer
+compel
+compellable
+compendia
+compendious
+compendium
+compensable
+compensate
+compete
+competent
+competition
+competitor
+compilation
+compile
+complacent
+complain
+complainant
+complaint
+complaisant
+compleat
+complement
+complementarity
+complementary
+complementation
+complete
+completion
+complex
+complexion
+compliant
+complicate
+complicity
+compliment
+complimentary
+compline
+comply
+component
+comport
+compose
+composit
+composite
+composition
+compositor
+compost
+composure
+compote
+compound
+comprehend
+comprehensible
+comprehension
+compress
+compressible
+compression
+compressor
+comprise
+compromise
+Compton
+comptroller
+compulsion
+compulsory
+compunction
+computation
+compute
+comrade
+Comstock
+con
+Conakry
+Conant
+concatenate
+concave
+conceal
+concede
+conceit
+conceive
+concentrate
+concentric
+concept
+conceptual
+concern
+concert
+concertgo
+concerti
+concertina
+concertino
+concertmaster
+concertmeister
+concerto
+concession
+concessionaire
+conch
+conchoidal
+conchology
+conchs
+concierge
+conciliate
+concise
+concision
+conclave
+conclude
+conclusion
+concoct
+concomitant
+concord
+concordant
+concordat
+Concorde
+concourse
+concrete
+concretion
+concubinage
+concubine
+concupiscent
+concur
+concurrent
+concussion
+condemn
+condemnate
+condensate
+condense
+condescend
+condescension
+condiment
+condition
+condo
+condolence
+condom
+condominium
+condone
+condor
+conduce
+conducive
+conduct
+conductance
+conduit
+cone
+coneflower
+conelrad
+Conestoga
+coney
+confab
+confabulate
+confect
+confectionary
+confectionery
+confederacy
+confederate
+confer
+conferee
+conference
+conferential
+conferral
+confess
+confession
+confessor
+confetti
+confidant
+confidante
+confide
+confident
+confidential
+configuration
+configure
+confine
+confirm
+confirmation
+confirmatory
+confiscable
+confiscate
+conflagration
+conflation
+conflict
+confluent
+confocal
+conform
+conformal
+conformant
+conformation
+confound
+confraternity
+confrere
+confront
+confrontation
+Confucian
+Confucianism
+Confucius
+confuse
+confusion
+confutation
+confute
+conga
+congeal
+congelation
+congener
+congeneric
+congenial
+congenital
+congeries
+congest
+congestion
+conglomerate
+Congo
+Congolese
+congratulate
+congregate
+congress
+congressional
+congruent
+congruential
+congruity
+congruous
+conic
+conifer
+coniferous
+conjectural
+conjecture
+conjoin
+conjoint
+conjugal
+conjugate
+conjunct
+conjunctivitis
+conjuncture
+conjure
+conk
+Conklin
+Conley
+conn
+connect
+Connecticut
+Conner
+Connie
+conniption
+connivance
+connive
+connoisseur
+Connolly
+Connor
+Connors
+connotation
+connote
+connubial
+conoid
+conquer
+conqueror
+conquest
+conquistador
+Conrad
+Conrail
+consanguine
+consanguineous
+conscience
+conscientious
+conscionable
+conscious
+conscript
+consecrate
+consecutive
+consensual
+consensus
+consent
+consequent
+consequential
+conservancy
+conservation
+conservatism
+conservator
+conserve
+consider
+considerate
+consign
+consignee
+consignor
+consist
+consistent
+consistory
+consolation
+console
+consolidate
+consomme
+consonant
+consonantal
+consort
+consortia
+consortium
+conspecific
+conspicuous
+conspiracy
+conspirator
+conspiratorial
+conspire
+constable
+constabulary
+Constance
+constant
+Constantine
+Constantinople
+constellate
+consternate
+constipate
+constituent
+constitute
+constrain
+constraint
+constrict
+construct
+constructible
+construe
+consul
+consular
+consulate
+consult
+consultant
+consultation
+consultive
+consume
+consummate
+consumption
+contact
+contagion
+contagious
+contain
+contaminant
+contaminate
+contemplate
+contemporaneity
+contemporaneous
+contemporary
+contempt
+contemptible
+contemptuous
+contend
+content
+contentious
+conterminous
+contest
+contestant
+context
+contextual
+contiguity
+contiguous
+continent
+continental
+contingent
+continua
+continual
+continuant
+continuation
+continue
+continuity
+continuo
+continuous
+continuum
+contort
+contour
+contraband
+contrabass
+contrabassoon
+contraception
+contract
+contractual
+contradict
+contradictor
+contradistinction
+contradistinguish
+contrail
+contraindicate
+contralateral
+contralto
+contraposition
+contrapositive
+contraption
+contrapuntal
+contrariety
+contrariwise
+contrary
+contrast
+contravariant
+contravene
+contravention
+contretemps
+contribute
+contributor
+contrite
+contrition
+contrivance
+contrive
+control
+controversial
+controversy
+controvert
+controvertible
+contumacious
+contumacy
+contumelious
+contumely
+contusion
+conundrum
+conurbation
+Convair
+convalesce
+convalescent
+convect
+convene
+convenient
+convent
+conventioneer
+converge
+convergent
+conversant
+conversation
+converse
+conversion
+convert
+convertible
+convex
+convey
+conveyance
+conveyor
+convict
+convince
+convivial
+convocation
+convoke
+convolute
+convolve
+convoy
+convulse
+convulsion
+Conway
+cony
+coo
+cook
+cookbook
+Cooke
+cookery
+cookie
+cookout
+cool
+coolant
+Cooley
+coolheaded
+Coolidge
+coolie
+coolish
+coon
+coonskin
+coop
+cooperage
+cooperate
+coordinate
+Coors
+coot
+cootie
+cop
+cope
+Copeland
+Copenhagen
+copepod
+Copernican
+Copernicus
+copilot
+copious
+coplanar
+copolymer
+copperas
+Copperfield
+copperhead
+coppery
+copra
+coprolite
+copse
+copter
+Coptic
+copula
+copulate
+copy
+copybook
+copycat
+copyreader
+copyright
+copywriter
+coquette
+coquettish
+Cora
+coracle
+coral
+coralline
+corbel
+Corbett
+Corcoran
+cord
+cordage
+cordial
+cordiform
+cordillera
+cordite
+cordon
+corduroy
+cordwood
+core
+coreligionist
+Corey
+coriander
+Corinne
+Corinth
+Corinthian
+Coriolanus
+Coriolis
+cork
+corkscrew
+cormorant
+corn
+cornbread
+cornea
+corneal
+Cornelia
+Cornelius
+Cornell
+cornerstone
+cornet
+cornfield
+cornflower
+cornice
+corniche
+Cornish
+cornmeal
+cornstalk
+cornstarch
+cornucopia
+Cornwall
+corolla
+corollary
+corona
+Coronado
+coronary
+coronate
+coroner
+coronet
+coroutine
+Corp.
+corpora
+corporal
+corporate
+corporeal
+corps
+corpse
+corpulent
+corpus
+corpuscle
+corpuscular
+corral
+correct
+correlate
+correspond
+correspondent
+corridor
+corrigenda
+corrigendum
+corrigible
+corroborate
+corroboree
+corrode
+corrodible
+corrosion
+corrugate
+corrupt
+corruptible
+corsage
+corsair
+corset
+Corsica
+cortege
+cortex
+cortical
+cortisone
+Cortland
+corundum
+coruscate
+corvette
+Corvus
+cos
+cosec
+cosecant
+coset
+Cosgrove
+cosh
+cosign
+cosignatory
+cosine
+cosmetic
+cosmetician
+cosmetology
+cosmic
+cosmography
+cosmology
+cosmonaut
+cosmopolitan
+cosmopolite
+cosmos
+cosponsor
+cossack
+cosset
+cost
+Costa
+costar
+Costello
+costume
+cosy
+cot
+cotangent
+coterie
+cotillion
+cotoneaster
+cotta
+cottage
+cotton
+cottonmouth
+cottonseed
+cottontail
+cottonwood
+Cottrell
+couch
+cougar
+cough
+could
+couldn't
+couloir
+coulomb
+Coulter
+council
+councillor
+counsel
+counselor
+count
+countdown
+countenance
+counterfeit
+countermand
+countervail
+countess
+countinghouse
+countrify
+country
+countryside
+countrywide
+county
+countywide
+coup
+coupe
+couple
+couplet
+coupon
+courage
+courageous
+courier
+course
+court
+courteous
+courtesan
+courtesy
+courthouse
+courtier
+Courtney
+courtroom
+courtyard
+couscous
+cousin
+couture
+couturier
+covalent
+covariant
+covary
+cove
+coven
+covenant
+cover
+coverage
+coverall
+coverlet
+covert
+coverup
+covet
+covetous
+cow
+Cowan
+coward
+cowardice
+cowbell
+cowbird
+cowboy
+cowcatcher
+cowgirl
+cowhand
+cowherd
+cowhide
+cowl
+cowlick
+coworker
+cowpea
+cowpoke
+cowpony
+cowpox
+cowpunch
+cowrie
+cowry
+cowslip
+cox
+coxcomb
+coxswain
+coy
+coyote
+coypu
+cozen
+cozy
+CPA
+CPI
+CPR
+crab
+crabapple
+crabgrass
+crabmeat
+crack
+crackbrain
+crackdown
+crackerjack
+crackle
+crackpot
+crackup
+cradle
+craft
+crafts
+craftspeople
+crag
+Craig
+cram
+Cramer
+cramp
+crampon
+cranberry
+Crandall
+crane
+cranelike
+Cranford
+crania
+cranial
+cranium
+crank
+crankcase
+crankshaft
+cranny
+Cranston
+crap
+crape
+crash
+crass
+crate
+cravat
+crave
+craven
+craw
+crawdad
+crawfish
+Crawford
+crawl
+crawlspace
+crayfish
+crayon
+craze
+creak
+cream
+creamery
+crease
+create
+creature
+creche
+credal
+credent
+credential
+credenza
+credible
+credit
+creditor
+credo
+credulity
+credulous
+creed
+creedal
+creek
+creekside
+creel
+creep
+creepage
+cremate
+crematorium
+crematory
+crenelate
+crenellate
+creole
+Creon
+creosote
+crepe
+crepitate
+crept
+crepuscular
+crescendo
+crescent
+cress
+Cressida
+crest
+crestfallen
+Crestview
+Cretaceous
+Cretan
+Crete
+cretin
+cretinous
+crevasse
+crevice
+crew
+crewcut
+crewel
+crib
+cribbage
+crick
+cricket
+cried
+crime
+Crimea
+criminal
+criminology
+crimp
+crimson
+cringe
+cringle
+crinkle
+crinkly
+crinoid
+crinoline
+cripple
+crises
+crisis
+crisp
+Crispin
+criss
+crisscross
+criteria
+criterion
+critic
+critique
+critter
+croak
+Croatia
+crochet
+crock
+crockery
+Crockett
+crocodile
+crocodilian
+crocus
+croft
+croissant
+Croix
+Cromwell
+crone
+crook
+crookneck
+croon
+crop
+cropland
+croquet
+croquette
+Crosby
+crosier
+cross
+crossarm
+crossbar
+crossbill
+crossbones
+crossbow
+crossbred
+crossbreed
+crosscurrent
+crosscut
+crosshatch
+crosslink
+crossover
+crosspatch
+crosspoint
+crossroad
+crossruff
+crosstalk
+crosstown
+crosstree
+crosswalk
+crossway
+crosswind
+crosswise
+crossword
+crotch
+crotchet
+crouch
+croup
+crouton
+crow
+crowbar
+crowd
+Crowe
+crowfoot
+Crowley
+crown
+crozier
+CRT
+crucial
+crucible
+crucifix
+crucifixion
+cruciform
+crucify
+crud
+crude
+cruel
+cruelty
+cruet
+Cruickshank
+cruise
+cruller
+crumb
+crumble
+crummy
+crump
+crumpet
+crumple
+crunch
+crupper
+crusade
+crush
+Crusoe
+crust
+crustacean
+crustal
+crutch
+crux
+Cruz
+cry
+cryogen
+cryogenic
+cryostat
+crypt
+cryptanalysis
+cryptanalyst
+cryptanalytic
+cryptanalyze
+cryptic
+crypto
+cryptograph
+cryptography
+cryptology
+crystal
+crystalline
+crystallite
+crystallize
+crystallography
+c's
+CSPAN
+CT
+cub
+Cuba
+cubbyhole
+cube
+cubic
+cubicle
+cubicly
+cubit
+cuboid
+cuckold
+cuckoldry
+cuckoo
+cucumber
+cud
+cuddle
+cuddlesome
+cuddly
+cudgel
+cue
+cuesta
+cuff
+cufflink
+cuirass
+cuisine
+Culbertson
+culex
+culinary
+cull
+cullet
+culm
+culminate
+culotte
+culpa
+culpable
+culprit
+cult
+cultivable
+cultivar
+cultivate
+cultural
+culture
+Culver
+culvert
+cumber
+Cumberland
+cumbersome
+cumin
+cummerbund
+Cummings
+Cummins
+cumquat
+cumulate
+cumulostratus
+cumulus
+Cunard
+cuneiform
+cunnilingus
+cunning
+Cunningham
+CUNY
+cup
+cupboard
+cupcake
+Cupid
+cupidity
+cupola
+cupric
+cuprous
+cur
+curacy
+curare
+curate
+curatorial
+curb
+curbside
+curbstone
+curd
+curdle
+cure
+curettage
+curette
+curfew
+curia
+curie
+curio
+curiosa
+curiosity
+curious
+curium
+curl
+curlew
+curlicue
+curmudgeon
+Curran
+currant
+current
+curricula
+curricular
+curriculum
+curry
+curse
+cursive
+cursor
+curt
+curtail
+curtain
+Curtis
+curtsey
+curtsy
+curvaceous
+curvacious
+curvature
+curve
+curvilinear
+Cushing
+cushion
+Cushman
+cushy
+cusp
+cuspidor
+cuss
+custard
+Custer
+custodial
+custodian
+custody
+custom
+customary
+customhouse
+cut
+cutaneous
+cutaway
+cutback
+cute
+cutesy
+cuticle
+cutlass
+cutler
+cutlery
+cutlet
+cutoff
+cutout
+cutpurse
+cutthroat
+cuttlebone
+cuttlefish
+cutup
+cutworm
+cyan
+Cyanamid
+cyanate
+cyanic
+cyanide
+cybernetic
+cybernetics
+cyberpunk
+cycad
+Cyclades
+cyclamen
+cycle
+cyclic
+cyclist
+cycloid
+cyclone
+cyclopean
+cyclops
+cyclorama
+cyclotron
+cygnet
+Cygnus
+cylinder
+cylindric
+cymbal
+cynic
+Cynthia
+cypress
+Cyprian
+Cypriot
+Cyprus
+Cyril
+Cyrillic
+Cyrus
+cyst
+cystic
+cytochemistry
+cytochrome
+cytogenetic
+cytology
+cytolysis
+cytoplasm
+cytoplasmic
+cytoplast
+cytosine
+czar
+czarina
+czarism
+czarist
+Czech
+Czechoslovakia
+Czechs
+dab
+dabble
+Dacca
+dacha
+dachshund
+Dacron
+dactyl
+dactylic
+dad
+dada
+Dadaism
+Dadaist
+daddy
+Dade
+dado
+dadoes
+Daedalus
+d'affaires
+daffodil
+daffy
+daft
+dageurreotype
+dagger
+daguerreotype
+Daguerrotype
+Dahl
+dahlia
+Dahomey
+Dailey
+daily
+Daimler
+dainty
+daiquiri
+dairy
+Dairylea
+dairymaid
+dais
+daisy
+Dakar
+Dakota
+dale
+Daley
+Dallas
+dalliance
+dally
+dalmatian
+Dalton
+Daly
+Dalzell
+dam
+damage
+Damascus
+damask
+dame
+damn
+damnation
+Damocles
+Damon
+damp
+dampen
+dampish
+damsel
+Dan
+Dana
+Danbury
+dance
+dandelion
+dander
+dandify
+dandle
+dandruff
+dandy
+Dane
+dang
+danger
+dangerous
+dangle
+Daniel
+Danielson
+Danish
+dank
+Danny
+danseuse
+Dante
+Danube
+Danubian
+Danzig
+Daphne
+dapper
+dapple
+Dar
+dare
+daredevil
+Darius
+Darjeeling
+dark
+darken
+darkish
+darkle
+darkroom
+Darlene
+darling
+darn
+Darrell
+Darren
+Darryl
+d'art
+dart
+Dartmouth
+Darwin
+Darwinian
+Daryl
+dash
+dashboard
+dastard
+data
+database
+date
+dateline
+Datsun
+datum
+daub
+Daugherty
+daughter
+daunt
+dauphin
+dauphine
+Dave
+davenport
+David
+Davidson
+Davies
+Davis
+Davison
+davit
+Davy
+dawdle
+dawn
+Dawson
+day
+daybed
+daybreak
+daydream
+daylight
+daytime
+Dayton
+Daytona
+daze
+dazzle
+DC
+DDT
+de
+deacon
+deaconess
+deactivate
+dead
+deadbeat
+deaden
+deadeye
+deadfall
+deadhead
+deadline
+deadlock
+deadpan
+deadweight
+deadwood
+deaf
+deafen
+deal
+deallocate
+dealt
+dean
+Deane
+deanery
+Deanna
+dear
+Dearborn
+dearie
+dearth
+deasil
+death
+deathbed
+deathward
+deathwatch
+debacle
+debar
+debark
+debarkation
+debase
+debate
+debauch
+debauchery
+Debbie
+Debby
+debenture
+debilitate
+debility
+debit
+deblur
+debonair
+Deborah
+Debra
+debrief
+debris
+debt
+debtor
+debug
+debunk
+Debussy
+debut
+debutant
+debutante
+Dec.
+decade
+decadent
+decaffeinate
+decagon
+decagonal
+decal
+decalcify
+decalogue
+decamp
+decant
+decapitate
+decapod
+decarbonate
+decarbonize
+decathlon
+Decatur
+decay
+Decca
+decease
+decedent
+deceit
+deceive
+decelerate
+December
+decennial
+decennium
+decent
+decentralize
+deception
+decertify
+decibel
+decide
+deciduous
+decile
+deciliter
+decimal
+decimate
+decimeter
+decipher
+decision
+decisional
+deck
+Decker
+deckhand
+deckhouse
+declaim
+declamation
+declamatory
+declaration
+declarator
+declare
+declassify
+declaw
+declension
+declinable
+declinate
+decline
+declivity
+decoct
+decode
+decollate
+decolletage
+decollimate
+decolonize
+decolorize
+decommission
+decommit
+decompile
+decompose
+decomposition
+decompress
+decompression
+decompressor
+decongestant
+deconstruct
+decontaminate
+decontrol
+deconvolution
+deconvolve
+decor
+decorate
+decorous
+decorticate
+decorum
+decouple
+decoy
+decrease
+decree
+decrement
+decrepit
+decrepitude
+decrescendo
+decriminalize
+decry
+decrypt
+dedicate
+dedifferentiate
+deduce
+deducible
+deduct
+deductible
+Dee
+deed
+deem
+deemphasize
+deep
+deepen
+deer
+Deere
+deerfly
+deerhound
+deerskin
+deerstalker
+deface
+defalcate
+defamation
+defamatory
+defame
+defang
+default
+defeat
+defecate
+defect
+defend
+defendant
+defenestrate
+defense
+defensible
+defensive
+defer
+deferent
+deferential
+deferral
+defiant
+deficient
+deficit
+defile
+define
+definiendum
+definiens
+definite
+definition
+deflate
+deflationary
+deflect
+deflower
+defocus
+defog
+defoliant
+defoliate
+deforest
+deforestation
+deform
+deformation
+defraud
+defray
+defrayal
+defrock
+defrost
+deft
+defunct
+defuse
+defy
+degas
+degauss
+degeneracy
+degenerate
+degradation
+degrade
+degrease
+degree
+degum
+dehiscent
+dehumanize
+dehumidify
+dehydrate
+dehydrogenate
+deice
+deify
+deign
+deinstitute
+deionize
+Deirdre
+deism
+deist
+deistic
+deity
+deja
+deject
+Del
+delaminate
+Delaney
+Delano
+Delaware
+delay
+Delbert
+Delco
+delectable
+delectate
+delegable
+delegacy
+delegate
+delete
+deleterious
+deletion
+delft
+Delgado
+Delhi
+deli
+Delia
+deliberate
+delicacy
+delicate
+delicatessen
+delicious
+delicti
+delight
+delightsome
+Delilah
+delimit
+delimitation
+delineament
+delineate
+delinquent
+deliquesce
+deliquescent
+delirious
+delirium
+delist
+deliver
+deliverance
+delivery
+dell
+Della
+Delmarva
+Delores
+delouse
+Delphi
+Delphic
+delphinium
+Delphinus
+delta
+deltoid
+delude
+deluge
+delusion
+delusory
+deluxe
+delve
+demagnetize
+demagnify
+demagogic
+demagogue
+demagoguery
+demagogy
+demand
+demarcate
+demark
+demarkation
+deme
+demean
+demeanor
+demented
+dementia
+demerit
+demigod
+demijohn
+demilitarize
+demimonde
+demineralize
+demiscible
+demise
+demission
+demit
+demitasse
+demiurge
+demo
+demobilize
+democracy
+democrat
+democratic
+demodulate
+demography
+demolish
+demolition
+demon
+demonetize
+demoniac
+demoniacal
+demonic
+demonology
+demonstrable
+demonstrate
+demoralize
+demote
+demotion
+demount
+demountable
+Dempsey
+demultiplex
+demur
+demure
+demurral
+demystify
+demythologize
+den
+denationalize
+denaturalize
+denature
+dendrite
+dendrochronology
+dendrology
+Deneb
+Denebola
+deniable
+denial
+denigrate
+denim
+Denise
+denitrify
+denizen
+Denmark
+Dennis
+Denny
+denominate
+denormalize
+denotation
+denote
+denouement
+denounce
+dense
+densitometer
+dent
+dental
+dentate
+dentistry
+dentition
+Denton
+dentrifice
+denture
+denuclearize
+denudation
+denude
+denumerable
+denunciation
+denunciatory
+Denver
+deny
+deodorant
+deodorize
+deoxidize
+deoxyribonucleic
+depart
+department
+departure
+depend
+dependent
+depersonalize
+depict
+depilate
+depilatory
+deplane
+deplete
+depletion
+deplore
+deploy
+depolarize
+depopulate
+deport
+deportation
+deportee
+depose
+deposit
+depositary
+deposition
+depositor
+depot
+deprave
+depravity
+deprecate
+depreciable
+depreciate
+depredate
+depress
+depressant
+depressible
+depression
+depressor
+depressurize
+deprivation
+deprive
+Dept.
+depth
+deputation
+depute
+deputy
+deracinate
+derail
+derange
+derate
+derby
+Derbyshire
+dereference
+deregulate
+Derek
+derelict
+deride
+derision
+derisory
+derivate
+derive
+dermatitis
+dermatology
+derogate
+derrick
+derriere
+dervish
+Des
+desalinate
+desalt
+descant
+Descartes
+descend
+descendant
+descendent
+descent
+describe
+description
+descriptor
+descry
+Desdemona
+desecrate
+desegregate
+desensitize
+desert
+desertify
+deserve
+desex
+deshabille
+desiccant
+desiccate
+desiderata
+desideratum
+design
+designate
+designee
+desire
+desirous
+desist
+desk
+desktop
+Desmond
+desolate
+desorption
+despair
+despatch
+desperado
+desperadoes
+desperate
+despicable
+despise
+despite
+despoil
+despoliation
+despond
+despondent
+despot
+despotic
+dessert
+destabilize
+desterilize
+destinate
+destine
+destiny
+destitute
+destroy
+destruct
+destructible
+desuetude
+desultory
+desynchronize
+detach
+detail
+detain
+detainee
+d'etat
+detect
+detent
+detente
+deter
+detergent
+deteriorate
+determinacy
+determinant
+determinate
+determine
+deterrent
+detest
+detestation
+dethrone
+detonable
+detonate
+detour
+detoxify
+detract
+d'etre
+detribalize
+detriment
+detrital
+detritus
+Detroit
+detune
+deuce
+deus
+deuterate
+deuterium
+deuteron
+Deuteronomy
+devaluate
+devalue
+devastate
+develop
+deviant
+deviate
+device
+devil
+devilish
+devilry
+deviltry
+devious
+devise
+devisee
+devitalize
+devitrify
+devoid
+devolution
+devolve
+Devon
+Devonshire
+devote
+devotee
+devotion
+devour
+devout
+dew
+dewar
+dewdrop
+Dewey
+Dewitt
+dewlap
+dexter
+dexterity
+dextral
+dextro
+dextrorotation
+dextrorotatory
+dextrose
+dextrous
+dey
+Dhabi
+dharma
+dhow
+diabase
+diabetes
+diabetic
+diabolic
+diabolism
+diabolist
+diachronic
+diacritical
+diadem
+diagnose
+diagnosis
+diagnostic
+diagnostician
+diagonal
+diagram
+diagrammatic
+dial
+dialect
+dialectic
+dialectician
+dialog
+dialogue
+dialyses
+dialysis
+dialytic
+dialyze
+diamagnetic
+diamagnetism
+diamegnetism
+diameter
+diametral
+diamine
+diamond
+diamondback
+Diana
+Diane
+diapason
+diaper
+diaphanous
+diaphoresis
+diaphragm
+diarist
+diarrhea
+diary
+diaspora
+diastolic
+diathermic
+diathermy
+diatom
+diatomaceous
+diatomic
+diatonic
+diatribe
+Diaz
+diazo
+dib
+dibasic
+dibble
+dibs
+dice
+dichloride
+dichotomize
+dichotomous
+dichotomy
+dick
+dickcissel
+dickens
+Dickensian
+Dickerson
+dickey
+Dickinson
+Dickson
+dicky
+dicot
+dicotyledon
+dicta
+dictate
+dictatorial
+diction
+dictionary
+dictum
+did
+didactic
+diddle
+didn't
+Dido
+didst
+die
+Diebold
+Diego
+diehard
+dieldrin
+dielectric
+diem
+dieresis
+diesel
+diet
+dietary
+dietetic
+diethylstilbestrol
+dietician
+dietitian
+Dietrich
+Dietz
+differ
+different
+differentiable
+differential
+differentiate
+difficult
+difficulty
+diffident
+diffract
+diffractometer
+diffuse
+diffusible
+diffusion
+difluoride
+dig
+digest
+digestible
+digestion
+digit
+digital
+digitalis
+digitate
+dignify
+dignitary
+dignity
+digram
+digraph
+digress
+digression
+dihedral
+dike
+dilapidate
+dilatant
+dilatation
+dilate
+dilemma
+dilettante
+dilettantish
+dilettantism
+diligent
+dill
+Dillon
+dilly
+dilogarithm
+diluent
+dilute
+dim
+dime
+dimension
+dimeric
+dimethyl
+diminish
+diminuendo
+diminution
+dimple
+dimply
+dimwit
+din
+Dinah
+dinar
+dine
+dinette
+ding
+dingbat
+dingdong
+dinghy
+dingo
+dingoes
+dinky
+dinnertime
+dinnerware
+dinosaur
+dinosaurian
+dint
+diocesan
+diocese
+diode
+Dionysiac
+Dionysian
+Dionysus
+Diophantine
+diopter
+diorama
+dioxide
+dioxin
+dip
+diphenyl
+diphtheria
+diphthong
+diploid
+diploidy
+diploma
+diplomacy
+diplomat
+diplomatic
+dipole
+dipsomania
+dipstick
+diptych
+Dirac
+dire
+direct
+directorate
+directorial
+directory
+directrices
+directrix
+dirge
+Dirichlet
+dirigible
+dirk
+dirt
+dirty
+Dis
+disambiguate
+disastrous
+disburse
+disc
+discern
+discernible
+disciple
+disciplinarian
+disciplinary
+discipline
+disco
+discography
+discoid
+discombobulate
+discomfit
+discomfiture
+discommode
+disconsolate
+discordant
+discotheque
+discovery
+discreet
+discrepant
+discrete
+discretion
+discretionary
+discriminable
+discriminant
+discriminate
+discus
+discuss
+discussant
+discussion
+disdain
+disembowel
+disgruntle
+dish
+dishcloth
+dishes
+dishevel
+dishrag
+dishwasher
+dishwater
+disinfectant
+disjunct
+disk
+dismal
+dismay
+dismissal
+Disney
+Disneyland
+disorganize
+disparage
+disparate
+disparity
+dispel
+dispensary
+dispensate
+dispense
+dispersal
+dispersant
+disperse
+dispersible
+dispersion
+dispirit
+disposal
+disputant
+disputation
+disputatious
+dispute
+disquietude
+disquisition
+disrupt
+dissemble
+disseminate
+dissension
+dissertation
+dissident
+dissipate
+dissociable
+dissociate
+dissonant
+dissuade
+dissuasion
+distaff
+distal
+distant
+distensible
+distention
+distill
+distillate
+distillery
+distills
+distinct
+distinguish
+distort
+distortion
+distraught
+distribution
+distributor
+district
+disturb
+disturbance
+disulfide
+disyllabic
+disyllable
+ditch
+dither
+ditto
+ditty
+Ditzel
+diuretic
+diurnal
+diva
+divalent
+divan
+dive
+diverge
+divergent
+diverse
+diversify
+diversion
+diversionary
+divert
+diverticulitis
+diverticulosis
+divertimento
+divertissement
+divest
+divestiture
+divide
+dividend
+divination
+divine
+divisible
+division
+divisional
+divisor
+divorce
+divorcee
+divot
+divulge
+divulgence
+divvy
+Dixie
+Dixieland
+Dixon
+dizzy
+DJ
+Djakarta
+djinn
+djinni
+Dmitry
+DNA
+Dnieper
+do
+DOA
+doable
+dobbin
+Dobbs
+dobson
+Doc
+docile
+dock
+docket
+dockhand
+dockside
+dockyard
+doctor
+doctoral
+doctorate
+doctrinaire
+doctrinal
+doctrine
+document
+documentary
+documentation
+DOD
+Dodd
+dodder
+dodecahedra
+dodecahedral
+dodecahedron
+dodge
+dodo
+dodoes
+Dodson
+doe
+doesn't
+doeth
+d'oeuvre
+doff
+dog
+dogcart
+dogcatcher
+doge
+dogface
+dogfight
+dogfish
+doggerel
+doggone
+doghouse
+dogleg
+dogma
+dogmatic
+dogmatism
+dogmatist
+dogmatize
+dogtooth
+dogtrot
+dogwood
+Doherty
+doily
+Dolan
+dolce
+doldrums
+dole
+dolichocephalic
+doll
+dollar
+dollop
+dolly
+dolomite
+dolor
+Dolores
+dolorous
+dolphin
+dolt
+doltish
+domain
+dome
+Domenico
+Domesday
+domestic
+domesticate
+domicile
+domiciliary
+dominant
+dominate
+domineer
+Domingo
+Dominic
+dominical
+Dominican
+Dominick
+dominion
+Dominique
+domino
+dominoes
+don
+Donahue
+Donald
+Donaldson
+donate
+done
+Doneck
+donkey
+Donna
+Donnelly
+Donner
+Donnie
+donnish
+donnybrook
+donor
+Donovan
+don't
+doodad
+doodle
+Dooley
+Doolittle
+doom
+doomsday
+door
+doorbell
+doorknob
+doormat
+doorstep
+doorway
+dooryard
+dopant
+dope
+dopester
+dopey
+dopier
+dopiest
+Doppler
+Dora
+Dorado
+Dorcas
+Dorchester
+Doreen
+Doria
+Doric
+Doris
+dorm
+dormant
+dormitory
+Dorothea
+Dorothy
+dorsal
+Dorset
+Dorsey
+dory
+dosage
+dose
+dosimeter
+dossier
+Dostoevsky
+dot
+dotage
+dotard
+dote
+doth
+Dottie
+double
+Doubleday
+doubleheader
+doublet
+doubleton
+doubloon
+doubt
+douce
+douche
+Doug
+dough
+doughboy
+Dougherty
+doughnut
+doughty
+Douglas
+Douglass
+dour
+douse
+dove
+dovecote
+dovekie
+dovetail
+dovish
+Dow
+dowager
+dowdy
+dowel
+dower
+dowitcher
+Dowling
+down
+downbeat
+downcast
+downdraft
+Downey
+downfall
+downfallen
+downgrade
+downhaul
+downhearted
+downhill
+Downing
+downplay
+downpour
+downrange
+downright
+downriver
+downside
+downsize
+downslope
+downspout
+downstage
+downstairs
+downstate
+downstream
+downstroke
+downswing
+downtime
+downtown
+downtrend
+downtrodden
+downturn
+downward
+downwind
+dowry
+dowse
+doxology
+doxy
+doyenne
+Doyle
+doze
+dozen
+dozenth
+Dr.
+drab
+drably
+drachma
+Draco
+draconian
+draft
+draftee
+drafts
+drag
+draggle
+draggly
+dragline
+dragnet
+dragon
+dragonfly
+dragonhead
+dragoon
+drain
+drainage
+drainpipe
+drake
+dram
+drama
+dramatic
+dramatist
+dramatize
+dramaturgic
+dramaturgy
+drank
+drape
+drapery
+drastic
+draw
+drawback
+drawbar
+drawbridge
+drawknife
+drawl
+drawn
+drawstring
+dray
+dread
+dreadnought
+dream
+dreamboat
+dreamland
+dreamlike
+dreamt
+dreamworld
+drear
+dreary
+dredge
+dreg
+drench
+dress
+dressage
+drew
+Drexel
+Dreyfuss
+drib
+dribble
+driblet
+dried
+drier
+drift
+driftwood
+drill
+drillmaster
+drink
+drip
+Driscoll
+drive
+drivel
+driven
+driveway
+drizzle
+drizzly
+drogue
+droll
+drollery
+drolly
+dromedary
+drone
+drool
+droop
+drop
+drophead
+dropkick
+droplet
+dropout
+dropsy
+drosophila
+dross
+drought
+drove
+drown
+drowse
+drub
+drudge
+drudgery
+drug
+druggist
+drugstore
+druid
+druidic
+drum
+drumbeat
+drumhead
+drumlin
+Drummond
+drumstick
+drunk
+drunkard
+drunken
+drunkometer
+Drury
+dry
+dryad
+Dryden
+drypoint
+drywall
+d's
+dual
+dualism
+Duane
+dub
+Dubhe
+dubiety
+dubious
+dubitable
+Dublin
+Dubliner
+ducal
+ducat
+duce
+duchess
+duchy
+duck
+duckbill
+duckling
+duckpin
+duckweed
+duct
+ductile
+ductwork
+dud
+dude
+dudgeon
+Dudley
+due
+duel
+dueness
+duenna
+duet
+duff
+duffel
+duffle
+Duffy
+dug
+Dugan
+dugong
+dugout
+duke
+dukedom
+dulcet
+dulcimer
+dull
+dullard
+dullish
+dully
+dulse
+Duluth
+duly
+Duma
+dumb
+dumbbell
+dumbfound
+dumbly
+dumbstruck
+dumbwaiter
+dumdum
+dumfound
+dummy
+dump
+dumpish
+dumpling
+dumpster
+Dumpty
+dun
+Dunbar
+Duncan
+dunce
+dunderhead
+dune
+Dunedin
+dung
+dungaree
+dungeon
+dunghill
+Dunham
+dunk
+Dunkirk
+Dunlap
+Dunlop
+Dunn
+dunnage
+duo
+duodecimal
+duodenal
+duodenum
+duopolist
+duopoly
+dupe
+duple
+duplex
+duplicable
+duplicate
+duplicity
+DuPont
+durable
+Durango
+duration
+Durer
+duress
+Durham
+during
+Durkee
+Durkin
+Durrell
+Durward
+Dusenberg
+Dusenbury
+dusk
+Dusseldorf
+dust
+dustbin
+dustpan
+dustup
+Dutch
+dutiable
+Dutton
+duty
+Dvorak
+dwarf
+dwarfish
+dwarves
+Dwayne
+dwell
+dwelt
+Dwight
+dwindle
+Dwyer
+dyad
+dyadic
+dye
+dyeing
+dyer
+dyestuff
+dying
+Dyke
+Dylan
+dynamic
+dynamism
+dynamite
+dynamo
+dynamometer
+dynast
+dynastic
+dynasty
+dyne
+Dynel
+dysentery
+dysfunction
+dysgenic
+dyslexia
+dyslexic
+dyspepsia
+dyspeptic
+dysplasia
+dysprosium
+dystrophy
+each
+Eagan
+eager
+eagle
+eaglet
+ear
+earache
+eardrum
+earl
+earlobe
+early
+earmark
+earmuff
+earn
+earnest
+earphone
+earring
+earshot
+earth
+earthbound
+earthen
+earthenware
+earthling
+earthmen
+earthmove
+earthquake
+earthshaking
+earthshine
+earthwork
+earthworm
+earwig
+ease
+easel
+east
+eastbound
+eastern
+easternmost
+Eastland
+Eastman
+eastmost
+eastward
+Eastwood
+easygoing
+eat
+eaten
+eatery
+Eaton
+eave
+eavesdrop
+ebb
+Eben
+ebony
+ebullient
+ebullition
+EC
+eccentric
+Eccles
+Ecclesiastes
+ecclesiastic
+ecdysiast
+ecdysis
+echelon
+echidna
+echinoderm
+echo
+echoes
+eclat
+eclectic
+eclipse
+ecliptic
+eclogue
+Ecole
+ecology
+econometric
+Econometrica
+economics
+economist
+economize
+economy
+ecosystem
+ecstasy
+ecstatic
+ectomorph
+ectomorphic
+ectoplasm
+ectothermic
+ecu
+Ecuador
+ecumenic
+ecumenical
+ecumenist
+eczema
+Ed
+Eddie
+eddy
+edelweiss
+edema
+edematous
+Eden
+edentate
+Edgar
+edge
+Edgerton
+edgeways
+edgewise
+edging
+edible
+edict
+edifice
+edify
+Edinburgh
+Edison
+edit
+Edith
+edition
+editor
+editorial
+Edmonds
+Edmondson
+Edmonton
+Edmund
+Edna
+EDT
+educable
+educate
+educe
+educible
+Edward
+Edwardian
+Edwards
+Edwin
+Edwina
+EEG
+eel
+eelgrass
+EEOC
+e'er
+eerie
+eerily
+eeriness
+efface
+effaceable
+effect
+effectual
+effectuate
+effeminacy
+effeminate
+effendi
+efferent
+effervesce
+effervescent
+effete
+efficacious
+efficacity
+efficacy
+efficient
+Effie
+effigy
+effloresce
+efflorescent
+effluent
+effluvia
+effluvium
+efflux
+effort
+effrontery
+effulgent
+effuse
+effusion
+eft
+EFTA
+e.g.
+egad
+egalitarian
+Egan
+egg
+egghead
+eggnog
+eggplant
+eggshell
+ego
+egocentric
+egomania
+egotism
+egotist
+egregious
+egress
+egret
+Egypt
+Egyptian
+Egyptology
+eh
+Ehrlich
+eider
+eiderdown
+eidetic
+Eiffel
+eigenfunction
+eigenstate
+eigenvalue
+eigenvector
+eight
+eighteen
+eighteenth
+eightfold
+eighth
+eightieth
+eighty
+Eileen
+Einstein
+Einsteinian
+einsteinium
+Eire
+Eisenhower
+Eisner
+either
+ejaculate
+eject
+ejecta
+eke
+Ekstrom
+Ektachrome
+elaborate
+Elaine
+elan
+elapse
+elastic
+elastomer
+elastomeric
+elate
+Elba
+Elbert
+elbow
+elder
+elderberry
+eldest
+Eldon
+Eleanor
+Eleazar
+elect
+electioneer
+electoral
+electorate
+Electra
+electress
+electret
+electric
+electrician
+electrify
+electro
+electrocute
+electrode
+electrography
+electrolysis
+electrolyte
+electrolytic
+electrolyze
+electron
+electronic
+electrophoresis
+electrophorus
+electrum
+eleemosynary
+elegant
+elegiac
+elegy
+element
+elementary
+Elena
+elephant
+elephantiasis
+elephantine
+elevate
+eleven
+eleventh
+elf
+elfin
+elfish
+Elgin
+Eli
+Elias
+elicit
+elide
+eligible
+Elijah
+eliminate
+Elinor
+Eliot
+Elisabeth
+Elisha
+elision
+elite
+elixir
+Elizabeth
+Elizabethan
+elk
+Elkhart
+elkhound
+Ella
+Ellen
+Elliott
+ellipse
+ellipsis
+ellipsoid
+ellipsometer
+elliptic
+Ellis
+Ellison
+Ellsworth
+Ellwood
+elm
+Elmer
+Elmhurst
+Elmira
+Elmsford
+elocution
+elocutionary
+Eloise
+elongate
+elope
+eloquent
+Elsa
+else
+Elsevier
+elsewhere
+Elsie
+Elsinore
+Elton
+eluate
+elucidate
+elude
+elusive
+elute
+elver
+elves
+Elvis
+elvish
+Ely
+Elysee
+elysian
+em
+emaciate
+emanate
+emancipate
+Emanuel
+emasculate
+embalm
+embank
+embarcadero
+embargo
+embargoes
+embark
+embarkation
+embarrass
+embassy
+embattle
+embayment
+embed
+embellish
+ember
+embezzle
+embitter
+emblazon
+emblem
+emblematic
+embodiment
+embody
+embolden
+embolism
+emboss
+embouchure
+embrace
+embraceable
+embrasure
+embrittle
+embrocate
+embroider
+embroidery
+embroil
+embryo
+embryology
+embryonic
+emcee
+emend
+emendable
+emendation
+emerald
+emerge
+emergent
+emeritus
+emersed
+emersion
+Emerson
+emery
+emetic
+emigrant
+emigrate
+emigre
+Emil
+Emile
+Emilio
+Emily
+eminent
+emir
+emirate
+emissary
+emission
+emissivity
+emit
+emittance
+Emma
+Emmanuel
+Emmett
+emollient
+emolument
+Emory
+emote
+emotion
+emotional
+empathetic
+empathic
+empathy
+emperor
+emphases
+emphasis
+emphasize
+emphatic
+emphysema
+emphysematous
+empire
+empiric
+emplace
+emplane
+employ
+employed
+employee
+employer
+employing
+emporia
+emporium
+empower
+empress
+emptor
+empty
+emu
+emulate
+emulsify
+emulsion
+en
+enable
+enact
+enamel
+enamelware
+enamor
+enantiomorph
+enantiomorphic
+encage
+encamp
+encapsulate
+encase
+encaustic
+encephalic
+encephalitis
+encephalograph
+encephalography
+enchain
+enchant
+enchantress
+enchilada
+encipher
+encircle
+enclave
+enclose
+enclosure
+encode
+encomia
+encomium
+encompass
+encore
+encounter
+encourage
+encroach
+encrust
+encrypt
+encumber
+encumbrance
+encyclical
+encyclopedia
+encyclopedic
+encyclopedist
+encyst
+end
+endanger
+endear
+endearment
+endeavor
+endemic
+endemism
+endgame
+Endicott
+endive
+endmost
+endocrine
+endogamous
+endogamy
+endogenous
+endomorph
+endomorphic
+endoplasm
+endorse
+endorsee
+endoskeleton
+endosperm
+endothelial
+endothermal
+endothermic
+endow
+endpaper
+endpoint
+endue
+endurance
+endure
+endways
+endwise
+ENE
+enema
+enemy
+energetic
+energize
+energy
+enervate
+enfant
+enfeeble
+Enfield
+enfilade
+enfold
+enforce
+enforceable
+enfranchise
+Eng.
+engage
+Engel
+engender
+engine
+engineer
+engirdle
+England
+Englander
+Engle
+Englewood
+English
+engorge
+engram
+engrave
+engross
+engulf
+enhance
+enharmonic
+Enid
+enigma
+enigmatic
+enjoin
+enjoinder
+enjoy
+enlarge
+enlargeable
+enlighten
+enlist
+enlistee
+enliven
+enmesh
+enmity
+ennoble
+ennui
+Enoch
+enormity
+enormous
+Enos
+enough
+enounce
+enplane
+enquire
+Enquirer
+enquiry
+enrage
+enrapt
+enrapture
+enrich
+Enrico
+enrobe
+enroll
+enrollee
+ensconce
+ensemble
+enshrine
+enshroud
+ensign
+ensilage
+enslave
+ensnare
+ensoul
+ensue
+ensuite
+ensure
+entablature
+entail
+entangle
+entendre
+entente
+enter
+enteric
+enterprise
+entertain
+enthalpy
+enthrall
+enthrone
+enthuse
+enthusiasm
+enthusiast
+enthusiastic
+entice
+entire
+entirety
+entitle
+entity
+entomb
+entomology
+entourage
+entrails
+entrain
+entrance
+entranceway
+entrant
+entrap
+entreat
+entreaty
+entree
+entrench
+entrepreneur
+entrepreneurial
+entropy
+entrust
+entry
+entryway
+entwine
+entwist
+enumerable
+enumerate
+enunciable
+enunciate
+envelop
+envelope
+enviable
+envious
+environ
+envisage
+envision
+envoi
+envoy
+envy
+enzymatic
+enzyme
+enzymology
+Eocene
+eohippus
+eon
+eosine
+EPA
+epaulet
+epaulette
+ephemera
+ephemeral
+ephemerides
+ephemeris
+Ephesian
+Ephesus
+Ephraim
+epic
+epicene
+epicenter
+epicure
+epicurean
+epicycle
+epicyclic
+epicycloid
+epidemic
+epidemiology
+epidermal
+epidermic
+epidermis
+epigenetic
+epiglottal
+epiglottis
+epigram
+epigrammatic
+epigraph
+epigraphy
+epilepsy
+epileptic
+epilogue
+epiphany
+epiphenomenal
+epiphenomenon
+epiphyseal
+epiphysis
+epiphyte
+epiphytic
+episcopacy
+episcopal
+Episcopalian
+episcopate
+episode
+episodic
+epistemic
+epistemology
+epistle
+epistolary
+epitaph
+epitaxial
+epitaxy
+epithelial
+epithelium
+epithet
+epitome
+epizootic
+epoch
+epochal
+epochs
+eponym
+eponymic
+eponymous
+eponymy
+epoxy
+epsilon
+Epsom
+Epstein
+equable
+equal
+equalitarian
+equanimity
+equate
+equatorial
+equerry
+equestrian
+equiangular
+equidistant
+equidistribute
+equilateral
+equilibrate
+equilibria
+equilibrium
+equine
+equinoctial
+equinox
+equip
+equipage
+equipoise
+equipotent
+equipotential
+equiprobable
+equitable
+equitation
+equity
+equivalent
+equivocal
+equivocate
+era
+eradicable
+eradicate
+erase
+Erasmus
+Erastus
+erasure
+Erato
+Eratosthenes
+erbium
+ERDA
+ere
+erect
+erectile
+eremite
+erg
+ergo
+ergodic
+ergonomic
+ergot
+Eric
+Erica
+Erich
+Erickson
+Ericsson
+Erie
+Erlenmeyer
+Erma
+ermine
+Ernest
+Ernestine
+Ernie
+Ernst
+erode
+erodible
+Eros
+erosible
+erosion
+erotic
+erotica
+err
+errancy
+errand
+errant
+errantry
+errata
+erratic
+erratum
+Errol
+erroneous
+error
+ersatz
+Erskine
+erstwhile
+erudite
+erudition
+erupt
+Ervin
+Erwin
+e's
+escadrille
+escalate
+escapade
+escape
+escapee
+escargot
+escarole
+escarpment
+eschatology
+escheat
+eschew
+escort
+escritoire
+escrow
+escudo
+escutcheon
+ESE
+esker
+Eskimo
+Esmark
+esophageal
+esophagi
+esophagus
+esoteric
+esoterica
+ESP
+espalier
+especial
+Esperanto
+espial
+espionage
+esplanade
+ESPN
+Esposito
+espousal
+espouse
+espresso
+esprit
+espy
+Esq.
+esquire
+essay
+Essen
+essence
+Essene
+essential
+Essex
+EST
+establish
+estate
+esteem
+Estella
+Estelle
+ester
+esterase
+Estes
+Esther
+esthete
+esthetic
+estimable
+estimate
+estival
+estivate
+Estonia
+estop
+estoppal
+estrange
+estrogen
+estrogenic
+estrus
+estuarine
+estuary
+et
+eta
+etc
+etcetera
+etch
+eternal
+eternity
+Ethan
+ethane
+ethanol
+Ethel
+ether
+ethereal
+ethic
+Ethiopia
+ethnic
+ethnocentric
+ethnography
+ethnology
+ethology
+ethos
+ethyl
+ethylene
+etiology
+etiquette
+Etruscan
+ETS
+etude
+etymology
+eucalypt
+eucalyptus
+Eucharist
+eucharistic
+Euclid
+euclidean
+Eugene
+Eugenia
+eugenic
+Euler
+Eulerian
+eulogize
+eulogy
+Eumenides
+Eunice
+eunuch
+eunuchs
+euphemism
+euphemist
+euphemize
+euphonic
+euphonious
+euphonium
+euphony
+euphoria
+euphoric
+Euphrates
+Eurasia
+eureka
+Euridyce
+Euripides
+Europa
+Europe
+European
+europium
+Eurydice
+eustatic
+eutectic
+Euterpe
+euthanasia
+eutrophic
+eutrophy
+Eva
+evacuate
+evacuee
+evade
+evaluable
+evaluate
+evanescent
+evangel
+evangelic
+Evans
+Evanston
+Evansville
+evaporate
+evasion
+eve
+Evelyn
+even
+evenhanded
+evensong
+event
+eventide
+eventual
+eventuate
+ever
+Eveready
+Everest
+Everett
+Everglades
+evergreen
+Everhart
+everlasting
+evermore
+evert
+every
+everybody
+everyday
+everyman
+everyone
+everything
+everywhere
+evict
+evictor
+evident
+evidential
+evidentiary
+evil
+evildoer
+evildoing
+evince
+eviscerate
+evocable
+evocation
+evoke
+evolute
+evolutionary
+evolve
+evzone
+ewe
+Ewing
+ex
+exacerbate
+exact
+exactitude
+exactor
+exaggerate
+exalt
+exaltation
+exam
+examination
+examine
+examinee
+example
+exarch
+exasperate
+excavate
+exceed
+excel
+excellent
+excelsior
+except
+excerpt
+excess
+excessive
+exchange
+exchangeable
+exchequer
+excise
+excision
+excitation
+excitatory
+excite
+exciton
+exclaim
+exclamation
+exclamatory
+exclude
+excludible
+exclusion
+exclusionary
+excommunicate
+excoriate
+excrement
+excrescent
+excreta
+excretal
+excrete
+excretion
+excretory
+excruciate
+exculpate
+excursion
+excursus
+excuse
+exec
+execrable
+execrate
+execute
+executor
+executrix
+exegesis
+exegete
+exegetic
+exemplar
+exemplify
+exempt
+exercise
+exert
+Exeter
+exeunt
+exfoliate
+exhalation
+exhale
+exhaust
+exhaustible
+exhaustion
+exhibit
+exhibition
+exhibitor
+exhilarate
+exhort
+exhortation
+exhortatory
+exhumation
+exhume
+exigent
+exiguous
+exile
+exist
+existent
+existential
+exit
+exodus
+exogamous
+exogamy
+exogenous
+exonerate
+exorable
+exorbitant
+exorcise
+exorcism
+exorcist
+exoskeletal
+exoskeleton
+exothermic
+exotic
+exotica
+expand
+expanse
+expansible
+expansion
+expansionary
+expatiate
+expatriate
+expect
+expectant
+expectation
+expectorant
+expectorate
+expedient
+expedite
+expedition
+expeditionary
+expeditious
+expeditor
+expel
+expend
+expenditure
+expense
+expensive
+experience
+experiential
+experiment
+experimentation
+expert
+expertise
+expiable
+expiate
+expiration
+expire
+expiry
+explain
+explanation
+explanatory
+expletive
+explicable
+explicate
+explicit
+explode
+exploit
+exploitation
+exploration
+exploratory
+explore
+explosion
+exponent
+exponential
+exponentiate
+export
+exportation
+expose
+exposit
+exposition
+expositor
+expostulate
+exposure
+expound
+express
+expressible
+expression
+expressway
+expropriate
+expulsion
+expunge
+expurgate
+exquisite
+exsert
+extant
+extemporaneous
+extempore
+extend
+extendible
+extensible
+extensile
+extension
+extensometer
+extensor
+extent
+extenuate
+exterior
+exterminate
+external
+extinct
+extinguish
+extirpate
+extol
+extoll
+extort
+extortionate
+extra
+extracellular
+extract
+extracurricular
+extraditable
+extradite
+extradition
+extralegal
+extralinguistic
+extramarital
+extramural
+extraneous
+extraordinary
+extrapolate
+extrasensory
+extraterrestrial
+extraterritorial
+extravagant
+extravaganza
+extrema
+extremal
+extreme
+extremis
+extremum
+extricable
+extricate
+extrinsic
+extroversion
+extrovert
+extrude
+extrusion
+exuberant
+exuberate
+exudation
+exude
+exult
+exultant
+exultation
+exurb
+exurbanite
+exurbia
+Exxon
+eye
+eyeball
+eyebolt
+eyebright
+eyebrow
+eyedrop
+eyeglass
+eyeing
+eyelash
+eyelet
+eyelid
+eyepiece
+eyeshade
+eyeshot
+eyesight
+eyesore
+eyestrain
+eyewash
+eyewitness
+eyrie
+Ezekiel
+Ezra
+FAA
+Faber
+Fabian
+fable
+fabric
+fabricate
+fabulist
+fabulous
+facade
+face
+facedown
+faceplate
+facet
+facetious
+facial
+facies
+facile
+facilitate
+facsimile
+fact
+factious
+factitious
+facto
+factoid
+factor
+factorial
+factory
+factotum
+factual
+facula
+facultative
+faculty
+fad
+faddish
+fade
+fadeaway
+fadeout
+faery
+Fafnir
+fag
+faggot
+Fahey
+Fahrenheit
+faience
+fail
+failsafe
+failsoft
+failure
+fain
+faint
+fainthearted
+fair
+Fairchild
+Fairfax
+Fairfield
+fairgoer
+fairground
+fairish
+fairlead
+Fairport
+fairway
+fairy
+fairyland
+faith
+fajita
+fake
+fakery
+fakir
+falcon
+falconry
+fall
+fallacious
+fallacy
+fallback
+fallen
+fallible
+falloff
+fallout
+fallow
+Falmouth
+false
+falsehood
+falsetto
+falsie
+falsify
+Falstaff
+falter
+fame
+familial
+familiar
+familiarly
+family
+famine
+famish
+famous
+fan
+fanatic
+fancy
+fandango
+fanfare
+fanfold
+fang
+fangled
+fanlight
+Fannie
+Fanny
+fanout
+fantail
+fantasia
+fantasist
+fantasize
+fantasm
+fantastic
+fantasy
+fantod
+far
+farad
+faraday
+faraway
+Farber
+farce
+farceur
+farcical
+fare
+farewell
+farfetched
+Fargo
+farina
+farinaceous
+Farkas
+Farley
+farm
+farmhand
+farmhouse
+Farmington
+farmland
+farmstead
+farmyard
+Farnsworth
+faro
+farrago
+Farrell
+farrier
+Farris
+farrow
+Farsi
+farsighted
+farther
+farthermost
+farthest
+farthing
+fascia
+fascicle
+fasciculate
+fascinate
+fascism
+fascist
+fashion
+Faso
+fast
+fasten
+fastidious
+fat
+fatal
+fate
+father
+fatherland
+fathom
+fatigue
+Fatima
+fatten
+fattish
+fatuity
+fatuous
+faucet
+Faulkner
+fault
+faultfind
+faun
+fauna
+faunal
+Faust
+Faustian
+Faustus
+favor
+favorable
+favorite
+fawn
+fax
+fay
+Faye
+Fayette
+Fayetteville
+faze
+FBI
+FCC
+FDA
+Fe
+fealty
+fear
+fearsome
+feasible
+feast
+feat
+feather
+featherbed
+featherbrain
+featherhead
+featherweight
+feathery
+feature
+Feb.
+febrile
+February
+fecal
+feces
+feckless
+fecund
+fed
+Fedders
+federal
+federate
+fedora
+fee
+feeble
+feebleminded
+feed
+feedback
+feedstock
+feel
+Feeney
+feet
+feign
+feint
+feisty
+Feldman
+feldspar
+feldspathic
+Felice
+Felicia
+felicitate
+felicitous
+felicity
+feline
+Felix
+fell
+fellah
+fellatio
+fellow
+felon
+felonious
+felony
+felt
+felucca
+female
+feminine
+feminism
+feminist
+feminize
+femur
+fen
+fence
+fencepost
+fend
+fenestrate
+fennel
+Fenton
+fenugreek
+feral
+Ferber
+Ferdinand
+Ferguson
+Fermat
+fermata
+ferment
+fermentation
+Fermi
+fermion
+fermium
+fern
+Fernando
+fernery
+ferocious
+ferocity
+Ferrell
+Ferrer
+ferret
+ferric
+ferris
+ferrite
+ferroelectric
+ferromagnet
+ferromagnetic
+ferromagnetism
+ferrous
+ferruginous
+ferrule
+ferry
+ferryboat
+fertile
+fervent
+fervid
+fervor
+fescue
+fest
+festal
+festival
+festive
+festoon
+festschrift
+feta
+fetal
+fetch
+fete
+fetid
+fetish
+fetlock
+fetter
+fettle
+fetus
+feud
+feudal
+feudatory
+fever
+feverish
+few
+fey
+fez
+fiance
+fiancee
+fiasco
+fiat
+fib
+fiber
+fiberboard
+Fiberglas
+Fibonacci
+fibrillar
+fibrillation
+fibrin
+fibrosis
+fibrous
+fibula
+FICA
+fiche
+fickle
+fiction
+fictioneer
+fictitious
+fid
+fiddle
+fiddlehead
+fiddlestick
+fide
+fidelity
+fidget
+fiducial
+fiduciary
+fie
+fief
+fiefdom
+field
+fieldstone
+fieldwork
+fiend
+fiendish
+fierce
+fiery
+fiesta
+fife
+FIFO
+fifteen
+fifteenth
+fifth
+fiftieth
+fifty
+fiftyish
+fig
+fight
+figural
+figurate
+figure
+figurehead
+figurine
+Fiji
+filament
+filamentary
+filamentous
+filar
+filbert
+filch
+file
+filet
+filial
+filibuster
+filigree
+Filipino
+fill
+fillet
+fillip
+filly
+film
+filmdom
+filmic
+filmstrip
+filter
+filth
+filtrate
+fin
+finagle
+final
+finale
+finance
+financial
+financier
+finch
+find
+fine
+finery
+finesse
+finessing
+finger
+fingerboard
+fingerling
+fingernail
+fingerprint
+fingertip
+finial
+finicky
+finis
+finish
+finitary
+finite
+finitude
+fink
+Finland
+Finley
+Finn
+Finnegan
+Finnish
+fir
+fire
+firearm
+fireball
+firebird
+fireboat
+firebox
+firebrand
+firebreak
+firebrick
+firebug
+fireclay
+firecracker
+firefight
+firefly
+fireguard
+firehouse
+firelight
+fireplace
+fireplug
+firepower
+fireproof
+fireside
+Firestone
+firetrap
+firewall
+firewood
+firework
+firm
+firmament
+first
+firstborn
+firsthand
+fiscal
+Fischbein
+Fischer
+fish
+fisher
+fishery
+fishhook
+fishmonger
+fishpond
+fishtail
+fishwife
+Fisk
+Fiske
+fissile
+fission
+fissure
+fist
+fisticuffs
+fit
+Fitch
+Fitchburg
+fitful
+fitment
+Fitzgerald
+Fitzpatrick
+Fitzroy
+five
+fivefold
+fix
+fixate
+fixture
+Fizeau
+fizz
+fizzle
+fjord
+FL
+flabbergast
+flabby
+flaccid
+flack
+flag
+flagella
+flagellant
+flagellar
+flagellate
+flagellum
+flageolet
+flagitious
+Flagler
+flagon
+flagpole
+flagrant
+flagstaff
+flagstone
+flail
+flair
+flak
+flake
+flam
+flambe
+flamboyant
+flame
+flamenco
+flameout
+flameproof
+flamethrower
+flamingo
+flammable
+Flanagan
+Flanders
+flange
+flank
+flannel
+flap
+flapjack
+flare
+flareup
+flash
+flashback
+flashbulb
+flashgun
+flashlight
+flashover
+flask
+flat
+flatbed
+flatcar
+flatfeet
+flatfish
+flatfoot
+flathead
+flatiron
+flatland
+flatten
+flatter
+flattery
+flatulent
+flatus
+flatware
+flatways
+flatwise
+flatwork
+flatworm
+flaunt
+flautist
+flavor
+flavorsome
+flaw
+flax
+flaxen
+flaxseed
+flay
+flea
+fleabane
+fleck
+flection
+fled
+fledge
+fledgling
+flee
+fleece
+fleet
+Fleming
+Flemish
+flense
+flesh
+fleshpot
+fleshy
+fletch
+Fletcher
+flew
+flex
+flexible
+flexural
+flexure
+flibbertigibbet
+flick
+flicker
+flier
+flight
+flimflam
+flimsy
+flinch
+fling
+flint
+flintlock
+flip
+flipflop
+flippant
+flirt
+flirtation
+flirtatious
+flit
+flitch
+flivver
+Flo
+float
+floc
+floccing
+flocculate
+flocculi
+flock
+floe
+flog
+flood
+floodgate
+floodlight
+floodlit
+floodplain
+floodwater
+floodway
+flooey
+floor
+floorboard
+floorwalker
+floozy
+flop
+flophouse
+floppy
+flora
+floral
+Florence
+Florentine
+Flores
+floret
+floriculture
+florid
+Florida
+Floridian
+florin
+florist
+floss
+flotation
+flotilla
+flotsam
+flounce
+flouncy
+flounder
+flour
+flourish
+flout
+flow
+flowchart
+flower
+flowerpot
+flowery
+flown
+flowstone
+Floyd
+flu
+flub
+fluctuant
+fluctuate
+flue
+fluency
+fluent
+fluff
+fluid
+fluke
+flume
+flummery
+flummox
+flung
+flunk
+fluoresce
+fluorescein
+fluorescent
+fluoridate
+fluoride
+fluorimeter
+fluorinate
+fluorine
+fluorite
+fluorocarbon
+fluorography
+fluoroscope
+fluoroscopic
+fluoroscopy
+fluorspar
+flurry
+flush
+fluster
+flute
+flutter
+fluttery
+fluvial
+flux
+fly
+flyby
+flycatcher
+flyer
+flyleaf
+Flynn
+flyover
+flypaper
+flyspeck
+flyway
+flyweight
+flywheel
+FM
+FMC
+foal
+foam
+fob
+focal
+foci
+focus
+fodder
+foe
+fog
+fogbound
+fogey
+foghorn
+fogy
+foible
+foil
+foist
+fold
+foldaway
+folderol
+foldout
+Foley
+foliage
+foliate
+folio
+folk
+folkish
+folklore
+folkloric
+folksong
+folksy
+folkway
+follicle
+follicular
+follow
+followeth
+folly
+Fomalhaut
+foment
+fond
+fondle
+fondue
+font
+Fontaine
+Fontainebleau
+food
+foodstuff
+foofaraw
+fool
+foolery
+foolhardy
+foolish
+foolproof
+foolscap
+foot
+footage
+football
+footboard
+footbridge
+footcandle
+Foote
+footfall
+footgear
+foothill
+foothold
+footlight
+footling
+footlocker
+footloose
+footnote
+footpad
+footpath
+footprint
+footrest
+footrope
+footsie
+footsore
+footstep
+footstool
+footway
+footwear
+footwork
+fop
+foppery
+foppish
+for
+forage
+foray
+forbade
+forbear
+forbearance
+Forbes
+forbid
+forbidden
+forbode
+forbore
+forborne
+force
+forceps
+forcible
+ford
+Fordham
+fore
+forearm
+forebears
+forebode
+forebrain
+forecast
+forecastle
+foreclose
+foreclosure
+foredeck
+foredoom
+foreface
+forefather
+forefeet
+forefinger
+forefoot
+forefront
+foregoing
+foregone
+foreground
+forehand
+forehead
+foreign
+forejudge
+foreknow
+foreknowledge
+foreknown
+forelady
+foreleg
+forelimb
+forelock
+foremast
+foremost
+foremother
+forename
+forenoon
+forensic
+foreordain
+foreordination
+forepart
+forepaw
+forepeak
+foreplay
+forequarter
+forerunner
+foresail
+foresaw
+foresee
+foreseeable
+foreseen
+foreseer
+foreshadow
+foreshore
+foreshorten
+foresight
+foreskin
+forest
+forestall
+forestation
+forestay
+forestry
+foreswear
+foresworn
+foretaste
+foretell
+forethought
+foretoken
+foretold
+foretop
+forever
+forevermore
+forewarn
+foreword
+forfeit
+forfeiture
+forfend
+forgather
+forgave
+forge
+forgeable
+forgery
+forget
+forgive
+forgiven
+forgo
+forgoes
+forgoing
+forgot
+forgotten
+fork
+forklift
+forlorn
+form
+formal
+formaldehyde
+formant
+format
+formate
+formfitting
+formic
+Formica
+formidable
+Formosa
+formula
+formulae
+formulaic
+formulary
+formulate
+fornicate
+Forrest
+forsake
+forsaken
+forsook
+forsooth
+forswear
+forsworn
+Forsythe
+forsythia
+fort
+forte
+Fortescue
+forth
+forthcome
+forthright
+forthwith
+fortieth
+fortify
+fortiori
+fortissimo
+fortitude
+fortnight
+Fortran
+fortress
+fortuitous
+fortuity
+fortunate
+fortune
+forty
+fortyish
+forum
+forward
+forwent
+Foss
+fossil
+fossiliferous
+foster
+Foucault
+fought
+foul
+foulard
+foulmouth
+found
+foundation
+foundling
+foundry
+fount
+fountain
+fountainhead
+four
+fourfold
+Fourier
+fourscore
+foursome
+foursquare
+fourteen
+fourteenth
+fourth
+fovea
+foveal
+fowl
+fox
+foxglove
+Foxhall
+foxhole
+foxhound
+foxtail
+foyer
+FPC
+fracas
+fractal
+fraction
+fractionate
+fractious
+fracture
+fragile
+fragment
+fragmentary
+fragmentation
+fragrant
+frail
+frailty
+frambesia
+frame
+framework
+Fran
+franc
+franca
+France
+Frances
+Francesca
+franchise
+Francine
+Francis
+Franciscan
+Francisco
+francium
+Franco
+Francois
+frangible
+frangipani
+frank
+Frankenstein
+Frankfort
+Frankfurt
+frankfurter
+Frankie
+franklin
+frantic
+Franz
+frappe
+Fraser
+fraternal
+fraternity
+fraternize
+fratricidal
+fratricide
+Frau
+fraud
+fraudulent
+fraught
+fray
+Frazier
+frazzle
+freak
+freakish
+freckle
+Fred
+Freda
+Freddie
+Freddy
+Frederic
+Frederick
+Fredericks
+Fredericksburg
+Fredericton
+Fredholm
+Fredrickson
+free
+freebase
+freebie
+freeboard
+freeboot
+freed
+freedom
+freehand
+freehearted
+freehold
+freeload
+Freemason
+freemasonry
+Freeport
+freestanding
+freestone
+freethink
+Freetown
+freeway
+freewheel
+freewill
+freeze
+freight
+French
+frenetic
+frenzy
+freon
+frequent
+fresco
+frescoes
+fresh
+freshen
+freshet
+freshwater
+Fresnel
+Fresno
+fret
+fretwork
+Freud
+Freudian
+Frey
+Fri.
+friable
+friar
+fricassee
+fricative
+Frick
+friction
+frictional
+Friday
+fridge
+fried
+Friedman
+Friedrich
+friend
+friendlily
+frieze
+frigate
+Frigga
+fright
+frighten
+frigid
+Frigidaire
+frijoles
+frill
+frilly
+fringe
+fringy
+frippery
+frisbee
+frisk
+fritillary
+fritter
+Fritz
+frivolity
+frivolous
+frizz
+frizzle
+frock
+frog
+frolic
+frolicked
+frolicking
+frolicsome
+from
+frond
+front
+frontage
+frontal
+frontier
+frontiers
+frontispiece
+frontlet
+frosh
+frost
+frostbite
+frostbitten
+froth
+froward
+frown
+frowsy
+frowzy
+froze
+frozen
+FRS
+fructify
+fructose
+Fruehauf
+frugal
+fruit
+fruitcake
+fruiterer
+fruition
+fruity
+frumpish
+frumpy
+frustrate
+frustum
+fry
+Frye
+f's
+FTC
+Fuchs
+fuchsia
+fuddle
+fudge
+fuel
+fugacity
+fugal
+fugitive
+fugue
+Fuji
+Fujitsu
+fulcrum
+fulfill
+fulgent
+full
+fullback
+Fullbright
+Fullerton
+fully
+fulminate
+fulsome
+Fulton
+fumarole
+fumble
+fume
+fumigant
+fumigate
+fun
+function
+functionary
+functor
+fund
+fundable
+fundamental
+fundraise
+funeral
+funerary
+funereal
+fungal
+fungi
+fungible
+fungicidal
+fungicide
+fungiform
+fungo
+fungoes
+fungoid
+fungus
+funicular
+funk
+funnel
+funny
+fur
+furbelow
+furbish
+furious
+furl
+furlong
+furlough
+Furman
+furnace
+furnish
+furniture
+furor
+furore
+furrier
+furrow
+further
+furtherance
+furthermore
+furthermost
+furthest
+furtive
+fury
+furze
+fuse
+fuselage
+fusible
+fusiform
+fusil
+fusileer
+fusillade
+fusion
+fuss
+fussbudget
+fustian
+fusty
+futile
+future
+fuze
+fuzz
+FY
+FYI
+GA
+gab
+gabardine
+gabble
+gabbro
+gaberdine
+Gaberones
+gabfest
+gabion
+gable
+Gabon
+Gabriel
+Gabrielle
+gad
+gadabout
+gadfly
+gadget
+gadgeteer
+gadgetry
+gadolinium
+gadwall
+Gaelic
+gaff
+gaffe
+gag
+gage
+gaggle
+gagster
+gagwriter
+gaiety
+Gail
+gaillardia
+gaily
+gain
+Gaines
+Gainesville
+gainsaid
+gainsay
+gait
+Gaithersburg
+gal
+gala
+galactic
+Galapagos
+Galatea
+Galatia
+galaxy
+Galbreath
+gale
+Galen
+galena
+Galilean
+Galilee
+Galileo
+gall
+Gallagher
+gallant
+gallantry
+galleon
+gallery
+galley
+Gallic
+gallinule
+gallium
+gallivant
+gallon
+gallonage
+gallop
+Galloway
+gallows
+gallstone
+Gallup
+gallus
+Galois
+galoot
+galore
+galosh
+Galt
+galumph
+galvanic
+galvanism
+galvanize
+galvanometer
+Galveston
+Galway
+gam
+gamba
+Gambia
+gambit
+gamble
+gambol
+gambrel
+game
+gamecock
+gamelan
+games
+gamete
+gamey
+gamin
+gamma
+gamut
+gander
+gang
+Ganges
+gangland
+ganglia
+gangling
+ganglion
+gangplank
+gangrene
+gangrenous
+gangster
+gangway
+gannet
+Gannett
+gantlet
+gantry
+Ganymede
+GAO
+gap
+gape
+gar
+garage
+garb
+garbage
+garble
+Garcia
+garden
+gardenia
+Gardner
+Garfield
+Gargantua
+gargantuan
+gargle
+gargoyle
+Garibaldi
+garish
+garland
+garlic
+garlicky
+garner
+garnet
+garnish
+garnishee
+garniture
+garret
+Garrett
+garrison
+Garrisonian
+garrulity
+garrulous
+Garry
+garter
+Garth
+Garvey
+Gary
+Garza
+gas
+gasbag
+Gascony
+gaseous
+gases
+gash
+gasholder
+gashouse
+gasify
+gasket
+gaslight
+gaslit
+gasohol
+gasoline
+gasp
+Gaspee
+Gaston
+gastric
+gastritis
+gastrointestinal
+gastronome
+gastronomy
+gastropod
+gasworks
+gat
+gate
+gatefold
+gatehouse
+gatepost
+gateway
+gather
+Gatlinburg
+gator
+Gatwick
+gauche
+gaucherie
+gaucho
+gaud
+gauge
+gaugeable
+Gauguin
+Gaul
+Gaulle
+gaunt
+gauntlet
+gaur
+gauss
+Gaussian
+gauze
+gave
+gavel
+Gavin
+gavotte
+gawk
+gawkish
+gay
+Gayle
+Gaylord
+gaze
+gazebo
+gazelle
+gazette
+gazetteer
+GDP
+GE
+gear
+gearbox
+gearshift
+gecko
+gedanken
+gee
+geese
+geest
+geezer
+gefilte
+Gegenschein
+Geiger
+Geigy
+geisha
+gel
+gelable
+gelatin
+gelatine
+gelatinous
+geld
+gelid
+gem
+Gemini
+Gemma
+gemology
+gemstone
+gendarme
+gender
+gene
+genealogy
+genera
+generable
+general
+generaled
+generalissimo
+generate
+generatrices
+generatrix
+generic
+generosity
+generous
+Genesco
+geneses
+genesis
+genetic
+Geneva
+Genevieve
+genial
+genie
+genii
+genital
+genitalia
+genitive
+genius
+Genoa
+genocidal
+genocide
+genome
+genomic
+genotype
+genotypical
+genre
+gent
+genteel
+gentian
+gentile
+gentility
+gentle
+gentlefolk
+gentleman
+gentrify
+gentry
+genuflect
+genuine
+genus
+geochronometry
+geode
+geodesic
+geodesy
+geodetic
+Geoffrey
+geography
+geoid
+geology
+geometrician
+geometrize
+geomorphology
+geophysicist
+George
+Georgetown
+Georgia
+geoscience
+geosynclinal
+geosyncline
+Gerald
+Geraldine
+geranium
+Gerard
+Gerber
+gerbil
+Gerhard
+Gerhardt
+geriatric
+germ
+German
+germane
+Germanic
+germanium
+Germantown
+Germany
+germicidal
+germicide
+germinal
+germinate
+gerontocracy
+gerontology
+Gerry
+gerrymander
+Gershwin
+Gertrude
+gerund
+gerundive
+gestalt
+gestapo
+gestation
+gesticulate
+gestural
+gesture
+gesundheit
+get
+getaway
+Gethsemane
+Getty
+Gettysburg
+getup
+gewgaw
+geyser
+Ghana
+ghastly
+Ghent
+gherkin
+ghetto
+ghost
+ghostwrite
+ghostwritten
+ghoul
+ghoulish
+GI
+Giacomo
+giant
+giantess
+gibber
+gibberish
+gibbet
+gibbon
+gibbous
+Gibbs
+gibe
+giblet
+Gibraltar
+Gibson
+giddap
+giddy
+Gideon
+Gifford
+gift
+gig
+gigantesque
+gigantic
+gigantism
+giggle
+giggly
+gigolo
+Gil
+gila
+gilbert
+Gilbertson
+Gilchrist
+gild
+Gilead
+Giles
+gill
+Gillespie
+Gillette
+Gilligan
+Gilmore
+gilt
+gimbal
+Gimbel
+gimcrack
+gimcrackery
+gimlet
+gimmick
+gimmickry
+gimpy
+gin
+Gina
+ginger
+gingerbread
+gingery
+gingham
+gingivitis
+gingko
+ginkgo
+ginmill
+Ginn
+Ginny
+Gino
+Ginsberg
+Ginsburg
+ginseng
+Giovanni
+Gipsy
+giraffe
+gird
+girdle
+girl
+girlfriend
+girlie
+girlish
+girly
+girth
+Gisela
+gist
+Giuliano
+Giuseppe
+give
+giveaway
+given
+giveth
+gizmo
+gizzard
+glace
+glacial
+glaciate
+glacier
+glaciology
+glacis
+glad
+gladden
+glade
+gladiator
+gladiatorial
+gladiolus
+gladsome
+Gladstone
+Gladys
+glamor
+glamorous
+glance
+gland
+glandular
+glare
+Glasgow
+glasnost
+glass
+glassblow
+glassine
+glassware
+glasswork
+Glaswegian
+glaucoma
+glaucous
+glaze
+glazier
+gleam
+glean
+Gleason
+glee
+glen
+Glenda
+Glendale
+Glenn
+glib
+glibly
+Glidden
+glide
+glimmer
+glimpse
+glint
+glissade
+glissando
+glisten
+glister
+glitch
+glitter
+glittery
+glitz
+gloaming
+gloat
+glob
+global
+globe
+globular
+globule
+globulin
+glockenspiel
+glom
+glomerular
+gloom
+Gloria
+Gloriana
+glorify
+glorious
+glory
+gloss
+glossary
+glossolalia
+glottal
+glottis
+Gloucester
+glove
+glow
+glowworm
+glucose
+glue
+gluey
+gluier
+glum
+glut
+glutamic
+gluten
+glutinous
+glutton
+gluttonous
+gluttony
+glyceride
+glycerin
+glycerinate
+glycerine
+glycerol
+glycol
+glycoprotein
+glyph
+GM
+GMT
+gnarl
+gnarly
+gnash
+gnat
+gnaw
+gneiss
+gnome
+gnomic
+gnomish
+gnomon
+gnomonic
+gnosis
+GNP
+gnu
+go
+Goa
+goad
+goal
+goalie
+goalpost
+goaltend
+goat
+goatee
+goatherd
+goatskin
+gob
+gobble
+gobbledegook
+gobbledygook
+goblet
+goblin
+god
+Goddard
+goddess
+godfather
+Godfrey
+godhead
+godmother
+godparent
+godsend
+godson
+Godwin
+godwit
+goer
+goes
+Goethe
+Goff
+goggle
+Gogh
+gogo
+going
+goiter
+gold
+Goldberg
+golden
+goldeneye
+goldenrod
+goldenseal
+goldfield
+goldfinch
+goldfish
+Goldman
+goldsmith
+Goldstein
+Goldstine
+Goldwater
+Goleta
+golf
+Goliath
+golly
+Gomez
+gonad
+gondola
+gondolier
+gone
+gong
+goniometer
+gonorrhea
+Gonzales
+Gonzalez
+goo
+goober
+good
+Goode
+Goodman
+Goodrich
+goodwill
+Goodwin
+goody
+Goodyear
+gooey
+goof
+googol
+googolplex
+gooier
+gooiest
+goon
+goose
+gooseberry
+gooseflesh
+gooseneck
+GOP
+gopher
+Gordian
+Gordon
+gore
+Goren
+gorge
+gorgeous
+gorgon
+Gorham
+gorilla
+Gorky
+Gorman
+gorse
+Gorton
+gosh
+goshawk
+gosling
+gospel
+gossamer
+gossip
+got
+Gotham
+Gothic
+gotta
+gotten
+Gottfried
+gouache
+gouge
+goulash
+Gould
+gourd
+gourmand
+gourmet
+gout
+govern
+governance
+governess
+governor
+gown
+goy
+goyim
+GPO
+GPS
+grab
+grace
+gracile
+gracious
+grackle
+grad
+gradate
+grade
+gradient
+gradual
+graduate
+Grady
+Graff
+graffiti
+graft
+graham
+grail
+grain
+gram
+grammar
+grammarian
+grammatic
+grampus
+granary
+grand
+grandam
+grandchild
+grandchildren
+granddaughter
+grandee
+grandeur
+grandfather
+grandiloquent
+grandiose
+grandma
+grandmother
+grandnephew
+grandniece
+grandpa
+grandparent
+grandsire
+grandson
+grandstand
+granduncle
+grange
+granite
+grannie
+granny
+granola
+grant
+grantee
+grantor
+grantsman
+granular
+granulate
+granule
+Granville
+grape
+grapefruit
+grapeshot
+grapevine
+graph
+grapheme
+graphic
+graphite
+graphology
+grapnel
+grapple
+grasp
+grass
+grasshopper
+grassland
+grata
+grate
+graticule
+gratify
+gratin
+gratis
+gratitude
+gratuitous
+gratuity
+grave
+gravel
+graven
+gravestone
+graveyard
+gravid
+gravimeter
+gravitate
+graviton
+gravure
+gravy
+gray
+graybeard
+grayish
+Grayson
+graywacke
+graze
+grease
+great
+greatcoat
+greathearted
+grebe
+Grecian
+Greece
+greed
+Greek
+green
+greenback
+greenbelt
+Greenberg
+Greenblatt
+Greenbriar
+greenbrier
+Greene
+greenery
+Greenfield
+greengrocer
+greengrocery
+greenhorn
+greenhouse
+greenie
+greenish
+Greenland
+greenmail
+greensand
+Greensboro
+greensward
+greenware
+Greenwich
+greenwood
+Greer
+greet
+Greg
+gregarious
+Gregg
+Gregorian
+Gregory
+gremlin
+grenade
+grenadier
+grenadine
+Grendel
+Grenoble
+Gresham
+Greta
+Gretchen
+grew
+grey
+greyhound
+greyish
+greylag
+grid
+griddle
+gridiron
+gridlock
+grief
+grievance
+grieve
+grievous
+griffin
+Griffith
+grill
+grille
+grillwork
+grim
+grimace
+Grimaldi
+grime
+Grimm
+grin
+grind
+grindstone
+gringo
+grip
+gripe
+grippe
+grisly
+grist
+gristle
+gristmill
+Griswold
+grit
+grizzle
+grizzly
+groan
+groat
+grocer
+grocery
+grog
+grogshop
+groin
+grommet
+groom
+groove
+groovy
+grope
+grosbeak
+gross
+Grosset
+Grosvenor
+grotesque
+Groton
+grotto
+grouch
+ground
+groundhog
+groundnut
+groundsel
+groundsheet
+groundskeeper
+groundskeeping
+groundwater
+groundwork
+group
+groupie
+grouse
+grout
+grove
+grovel
+Grover
+grow
+growl
+grown
+grownup
+growth
+grub
+grubstake
+grudge
+gruel
+gruesome
+gruff
+grumble
+Grumman
+grumpy
+grunge
+grunion
+grunt
+gryphon
+g's
+GSA
+GTE
+Guadalupe
+Guam
+guanaco
+guanidine
+guanine
+guano
+guarantee
+guarantor
+guaranty
+guard
+guardhouse
+Guardia
+guardian
+guardroom
+guards
+Guatemala
+guava
+gubernatorial
+gudgeon
+Guenther
+guerdon
+guerilla
+guernsey
+guerrilla
+guess
+guesstimate
+guesswork
+guest
+guff
+guffaw
+Guggenheim
+Guiana
+guidance
+guide
+guidebook
+guideline
+guidepost
+guignol
+guild
+guildhall
+guile
+Guilford
+guillemot
+guillotine
+guilt
+guinea
+Guinness
+guise
+guitar
+gulag
+gulch
+gulf
+gull
+Gullah
+gullet
+gullible
+Gulliver
+gully
+gulp
+gum
+gumbo
+gumdrop
+gumption
+gumshoe
+gun
+gunboat
+guncotton
+Gunderson
+gunfight
+gunfire
+gunflint
+gunk
+gunmetal
+gunnery
+gunny
+gunnysack
+gunplay
+gunpoint
+gunpowder
+gunrun
+gunshot
+gunsling
+gunsmith
+Gunther
+gunwale
+guppy
+gurdy
+gurgle
+Gurkha
+gurney
+guru
+Gus
+gush
+gusset
+gussy
+gust
+Gustafson
+gustatorial
+gustatory
+Gustav
+Gustave
+Gustavus
+gusto
+gut
+Gutenberg
+Guthrie
+Gutierrez
+gutsy
+guttersnipe
+guttural
+guy
+Guyana
+Guzman
+guzzle
+Gwen
+Gwendolyn
+Gwyn
+gybe
+gym
+gymnasium
+gymnast
+gymnastic
+gymnosperm
+gynecology
+gyp
+gypsum
+gypsy
+gyrate
+gyrfalcon
+gyro
+gyrocompass
+gyromagnetic
+gyroscope
+gyroscopic
+gyrostabilize
+ha
+Haag
+Haas
+Habakkuk
+habeas
+haberdasher
+haberdashery
+Haberman
+Habib
+habiliment
+habit
+habitant
+habitat
+habitation
+habitual
+habituate
+habitue
+hachure
+hacienda
+hack
+Hackett
+hackle
+hackmatack
+hackney
+hackneyed
+hacksaw
+hackwork
+had
+Hadamard
+Hadassah
+Haddad
+haddock
+Hades
+Hadley
+hadn't
+Hadrian
+hadron
+hafnium
+haft
+hag
+Hagen
+Hager
+Haggai
+haggard
+haggis
+haggle
+hagiography
+Hagstrom
+Hague
+Hahn
+Haifa
+haiku
+hail
+hailstone
+hailstorm
+Haines
+hair
+hairbreadth
+hairbrush
+haircut
+hairdo
+hairdress
+hairline
+hairpin
+hairsplit
+hairspring
+Haiti
+Haitian
+hajj
+hajji
+Hal
+halation
+halberd
+halcyon
+hale
+Haley
+half
+halfback
+halfhearted
+halfpenny
+halftone
+halfway
+halibut
+halide
+Halifax
+halite
+halitosis
+hall
+hallelujah
+Halley
+hallmark
+hallow
+Halloween
+hallucinate
+hallucinogen
+hallucinogenic
+hallway
+halo
+halocarbon
+halogen
+halogenate
+Halsey
+Halstead
+halt
+haltere
+halvah
+halve
+Halverson
+halyard
+ham
+Hamburg
+hamburger
+Hamilton
+hamlet
+Hamlin
+hammer
+hammerhead
+hammerlock
+hammock
+Hammond
+hamper
+Hampshire
+Hampshirite
+Hampton
+hamster
+hamstring
+Han
+Hancock
+hand
+handbag
+handball
+handbill
+handbook
+handcar
+handcart
+handclasp
+handcraft
+handcuff
+Handel
+handgrip
+handgun
+handhold
+handicap
+handicraft
+handicrafts
+handiwork
+handkerchief
+handle
+handleable
+handlebar
+handline
+handmade
+handmaiden
+handoff
+handout
+handpick
+handrail
+handsbreadth
+handset
+handshake
+handsome
+handspike
+handspring
+handstand
+handwork
+handwoven
+handwrite
+handwritten
+handy
+Haney
+Hanford
+hang
+hangable
+hangar
+hangdog
+hangnail
+hangout
+hangover
+hank
+Hankel
+hanker
+hanky
+Hanley
+Hanlon
+Hanna
+Hannah
+Hannibal
+Hanoi
+Hanover
+Hanoverian
+Hans
+Hansard
+Hansel
+Hansen
+hansom
+Hanson
+Hanukkah
+hap
+haphazard
+haploid
+happen
+happenstance
+happing
+Hapsburg
+harangue
+harass
+Harbin
+harbinger
+harbor
+Harcourt
+hard
+hardball
+hardboard
+hardboiled
+hardcover
+harden
+hardhat
+hardhead
+hardhearted
+Hardin
+Harding
+hardline
+hardpan
+hardscrabble
+hardship
+hardtack
+hardtop
+hardware
+hardwood
+hardworking
+hardy
+hare
+harebrained
+harelip
+harem
+haricot
+hark
+Harlan
+Harlem
+harlequin
+Harley
+harlot
+harlotry
+harm
+Harmon
+harmonic
+harmonica
+harmonious
+harmonist
+harmonium
+harmonize
+harmony
+harness
+Harold
+harp
+harpoon
+harpsichord
+harpy
+Harrell
+Harriet
+Harriman
+Harrington
+Harris
+Harrisburg
+Harrison
+harrow
+harry
+harsh
+harshen
+hart
+Hartford
+Hartley
+Hartman
+harum
+haruspex
+Harvard
+harvest
+Harvey
+hash
+Hashemite
+hashish
+hasn't
+hasp
+hassle
+hassock
+hast
+haste
+hasten
+Hastings
+hasty
+hat
+hatbox
+hatch
+hatchery
+hatchet
+hatchling
+hatchway
+hate
+Hatfield
+hath
+Hathaway
+hatred
+Hatteras
+Hattie
+haughty
+haul
+haulage
+haunch
+haunt
+hauteur
+Havana
+have
+haven
+haven't
+Havilland
+havoc
+haw
+Hawaii
+Hawaiian
+hawk
+Hawkins
+hawkish
+Hawley
+hawsehole
+hawser
+hawthorn
+Hawthorne
+hay
+haycock
+Hayden
+Haydn
+Hayes
+hayfield
+hayloft
+haymarket
+haymow
+Haynes
+hayrack
+hayride
+hayseed
+haystack
+Hayward
+haywire
+hazard
+hazardous
+haze
+hazel
+hazelnut
+HDTV
+he
+head
+headache
+headband
+headboard
+headcount
+headdress
+headfirst
+headgear
+headhunt
+headland
+headlight
+headline
+headlock
+headlong
+headmaster
+headmistress
+headmost
+headphone
+headpiece
+headquartered
+headquarters
+headrest
+headroom
+heads
+headsail
+headset
+headstand
+headstone
+headstrong
+headwaiter
+headwall
+headwater
+headway
+headwind
+headwork
+heal
+Healey
+health
+Healy
+heap
+hear
+heard
+hearken
+hearsay
+hearse
+Hearst
+heart
+heartache
+heartbeat
+heartbreak
+heartbroken
+heartburn
+hearten
+heartfelt
+hearth
+hearthstone
+heartland
+heartrending
+heartsick
+heartsore
+heartstring
+heartthrob
+heat
+heath
+heathen
+heathenish
+heather
+Heathkit
+Heathrow
+heatstroke
+heave
+heaven
+heavenward
+heavy
+heavyhearted
+heavyset
+heavyweight
+Hebe
+hebephrenic
+Hebert
+hebetude
+Hebraic
+Hebraism
+Hebraist
+Hebrew
+Hecate
+hecatomb
+heck
+heckle
+Heckman
+hectare
+hectic
+hectograph
+hector
+Hecuba
+he'd
+hedge
+hedgehog
+hedgehop
+hedgerow
+hedonism
+hedonist
+heebie
+heed
+heel
+heelpiece
+heft
+Hegelian
+hegemonic
+hegemony
+hegira
+Heidelberg
+Heidi
+heifer
+heigh
+height
+heighten
+Heine
+heinous
+Heinrich
+Heinz
+heir
+heiress
+heirloom
+Heisenberg
+heist
+held
+Helen
+Helena
+Helene
+Helga
+heliacal
+helical
+helices
+helicoid
+helicopter
+heliocentric
+heliograph
+heliostat
+heliotrope
+heliotropic
+heliport
+helium
+helix
+he'll
+hell
+hellbender
+hellcat
+hellebore
+Hellene
+Hellenic
+Hellenism
+Hellenist
+hellfire
+hellgrammite
+hellion
+hellish
+hello
+helm
+helmet
+Helmholtz
+helms
+Helmut
+helot
+helotry
+help
+helpmate
+helpmeet
+Helsinki
+helter
+helve
+hem
+hematite
+hematology
+hematoma
+heme
+hemicycle
+Hemingway
+hemiola
+hemiplegic
+hemisphere
+hemispheric
+hemline
+hemlock
+hemoglobin
+hemolysis
+hemolytic
+hemophilia
+hemophilic
+hemorrhage
+hemorrhagic
+hemorrhoid
+hemosiderin
+hemp
+Hempstead
+hen
+henbane
+hence
+henceforth
+henceforward
+henchman
+henchmen
+Henderson
+Hendrick
+Hendricks
+Hendrickson
+Hendrix
+henequen
+Henley
+henna
+hennery
+henpeck
+Henri
+Henrietta
+henry
+Hensley
+Henson
+hep
+hepatic
+hepatica
+hepatitis
+Hepburn
+heptagon
+heptagonal
+heptameter
+heptane
+her
+Hera
+Heraclitus
+herald
+heraldic
+heraldry
+herb
+herbaceous
+herbal
+herbarium
+Herbert
+herbicidal
+herbicide
+herbivore
+herbivorous
+Herculean
+Hercules
+herd
+herds
+here
+hereabout
+hereafter
+hereby
+hereditary
+heredity
+Hereford
+herein
+hereinabove
+hereinafter
+hereinbefore
+hereinbelow
+hereof
+hereon
+heresy
+heretic
+hereto
+heretofore
+hereunder
+hereunto
+hereupon
+herewith
+heritable
+heritage
+Herkimer
+Herman
+hermaphrodite
+hermeneutic
+Hermes
+hermetic
+hermit
+hermitage
+Hermite
+hermitian
+Hermosa
+Hernandez
+hernia
+hero
+Herodotus
+heroes
+heroic
+heroin
+heroine
+heroism
+heron
+heronry
+herpes
+herpetology
+Herr
+Herrera
+herringbone
+Herschel
+herself
+Hershel
+Hershey
+hertz
+Hertzog
+hesitant
+hesitate
+Hesperus
+Hess
+Hessian
+Hester
+heterocyclic
+heterodox
+heterodyne
+heterogamous
+heterogeneity
+heterogeneous
+heterologous
+heterology
+heteromorph
+heteromorphic
+heterosexual
+heterostructure
+heterotrophic
+heterozygous
+Hetman
+Hettie
+Hetty
+Heublein
+heuristic
+Heusen
+Heuser
+hew
+Hewett
+Hewitt
+Hewlett
+hewn
+hex
+hexad
+hexadecimal
+hexagon
+hexagonal
+hexagram
+hexameter
+hexane
+hey
+heyday
+hi
+Hiatt
+hiatus
+Hiawatha
+hibachi
+Hibbard
+hibernate
+Hibernia
+hibiscus
+hiccup
+hiccupped
+hiccupping
+hick
+Hickey
+Hickman
+hickory
+hid
+hidalgo
+hidden
+hide
+hideaway
+hidebound
+hideous
+hideout
+hie
+hierarch
+hierarchal
+hierarchic
+hierarchs
+hierarchy
+hieratic
+hieroglyph
+hieroglyphic
+Hieronymus
+hierophant
+hifalutin
+Higgins
+higgle
+higgledy
+high
+highball
+highboy
+highbrow
+highfalutin
+highhanded
+highland
+highlight
+highroad
+hightail
+highway
+hijack
+hijinks
+hike
+hilarious
+hilarity
+Hilbert
+Hilda
+Hildebrand
+Hildegard
+hill
+Hillary
+hillbilly
+Hillcrest
+Hillel
+hillock
+hillside
+hilltop
+hilly
+hilt
+Hilton
+hilum
+him
+Himalaya
+himself
+Hinayana
+hind
+hinder
+Hindi
+hindmost
+hindquarter
+hindrance
+hindsight
+Hindu
+Hinduism
+Hindustani
+Hines
+hinge
+Hinman
+hint
+hinterland
+Hinton
+hip
+hippie
+hippo
+hippocampus
+Hippocratic
+hippodrome
+hippopotamus
+hippy
+hipster
+Hiram
+hire
+hireling
+Hiroshi
+Hiroshima
+Hirsch
+hirsute
+his
+Hispanic
+hiss
+histamine
+histidine
+histochemistry
+histogram
+histology
+historian
+historic
+historiography
+history
+histrionic
+hit
+Hitachi
+hitch
+Hitchcock
+hitchhike
+hither
+hithermost
+hitherto
+hitherward
+Hitler
+Hitlerian
+Hittite
+HIV
+hive
+HMO
+ho
+hoagie
+Hoagland
+hoagy
+hoar
+hoard
+hoarfrost
+hoarse
+hoarsen
+hoax
+hob
+Hobart
+Hobbes
+Hobbesian
+hobble
+hobbledehoy
+Hobbs
+hobby
+hobbyhorse
+hobgoblin
+hobnail
+hobnob
+hobo
+hoboes
+Hoboken
+hoc
+hock
+hockey
+hocus
+hod
+Hodge
+hodgepodge
+Hodgkin
+hoe
+hoecake
+hoedown
+Hoff
+hog
+hogan
+hogback
+hoggish
+hogshead
+hogwash
+hoist
+Hokkaido
+hokum
+Holbrook
+Holcomb
+hold
+holden
+holdfast
+holdout
+holdover
+holdup
+hole
+holeable
+holey
+holiday
+Holland
+hollandaise
+holler
+Hollerith
+Hollingsworth
+Hollister
+hollow
+Holloway
+hollowware
+holly
+hollyhock
+Hollywood
+Holm
+Holman
+Holmdel
+Holmes
+holmium
+holocaust
+Holocene
+holograph
+holography
+holotype
+Holst
+Holstein
+holster
+Holt
+holy
+Holyoke
+holystone
+homage
+hombre
+homburg
+home
+homebody
+homebound
+homebred
+homebuild
+homecome
+homegrown
+homeland
+homemade
+homeomorph
+homeomorphic
+homeopath
+homeopathic
+homeopathy
+homeostasis
+homeostatic
+homeotypic
+homeown
+Homeric
+homeroom
+homesick
+homespun
+homestead
+homestretch
+hometown
+homeward
+homework
+homey
+homicidal
+homicide
+homier
+homiest
+homiletic
+homily
+hominess
+hominid
+hominoid
+hominy
+homo
+homoerotic
+homogenate
+homogeneity
+homogeneous
+homogenize
+homograph
+homolog
+homologize
+homologous
+homologue
+homology
+homomorph
+homomorphic
+homonym
+homonymic
+homonymous
+homonymy
+homophobe
+homophone
+homophonic
+homosexual
+homotopy
+homozygous
+homunculi
+homunculus
+honcho
+Honda
+Honduran
+Honduras
+hone
+honest
+honey
+honeybee
+honeycomb
+honeydew
+honeymoon
+honeysuckle
+Honeywell
+Hong
+honied
+honk
+honky
+Honolulu
+honor
+honoraria
+honorarium
+honorary
+honoree
+honorific
+honoris
+Honshu
+hooch
+hood
+hoodlum
+hoodoo
+hoodwink
+hooey
+hoof
+hoofmark
+hook
+hookah
+hookup
+hookworm
+hooligan
+hoop
+hoopla
+hooray
+hoosegow
+Hoosier
+hoot
+hootenanny
+Hoover
+hooves
+hop
+hope
+Hopi
+Hopkins
+Hopkinsian
+hopscotch
+Horace
+Horatio
+horde
+horehound
+horizon
+horizontal
+hormonal
+hormone
+horn
+hornbeam
+hornblende
+Hornblower
+hornbook
+Horne
+Horner
+hornet
+hornpipe
+hornswoggle
+horntail
+hornworm
+horology
+horoscope
+Horowitz
+horrendous
+horrible
+horrid
+horrific
+horrify
+horror
+hors
+horse
+horseback
+horsecar
+horsedom
+horseflesh
+horsefly
+horsehair
+horsehide
+horselaugh
+horseplay
+horsepower
+horseradish
+horseshoe
+horsetail
+horsewhip
+hortatory
+horticultural
+horticulture
+Horton
+Horus
+hosanna
+hose
+Hosea
+hosiery
+hospice
+hospitable
+hospital
+host
+hostage
+hostel
+hostelry
+hostess
+hostile
+hostler
+hot
+hotbed
+hotblood
+hotbox
+hotel
+hotelier
+hotfoot
+hothead
+hothouse
+hotline
+hotrod
+hotshot
+Houdaille
+Houdini
+hough
+Houghton
+hound
+hour
+hourglass
+house
+houseboat
+housebreak
+housebroken
+houseclean
+housecoat
+housefly
+household
+houselights
+housemaid
+housemother
+housetop
+houseware
+housewarming
+housewife
+housewives
+housework
+Houston
+Houyhnhnm
+hove
+hovel
+hover
+hovercraft
+how
+Howard
+howbeit
+how'd
+howdy
+Howe
+Howell
+however
+Howie
+howitzer
+howl
+how're
+howsoever
+howsomever
+hoy
+hoyden
+hoydenish
+hoyle
+Hoyt
+Hrothgar
+h's
+hub
+Hubbard
+Hubbell
+hubbub
+hubby
+hubcap
+Huber
+Hubert
+hubris
+huckleberry
+huckster
+huddle
+Hudson
+hue
+hued
+huff
+Huffman
+hug
+huge
+Huggins
+Hugh
+Hughes
+Hugo
+Huguenot
+huh
+hula
+hulk
+hull
+hullabaloo
+hum
+human
+humane
+humanitarian
+humankind
+humanoid
+humble
+Humboldt
+humbug
+humbuggery
+humdinger
+humdrum
+humerus
+humic
+humid
+humidify
+humidistat
+humidor
+humiliate
+humility
+Hummel
+hummingbird
+hummock
+humongous
+humor
+humoresque
+humorous
+hump
+humpback
+humph
+Humphrey
+humus
+Hun
+hunch
+hunchback
+hundred
+hundredfold
+hundredth
+hundredweight
+hung
+Hungarian
+Hungary
+hungry
+hunk
+hunt
+Huntington
+Huntley
+huntress
+hunts
+Huntsville
+Hurd
+hurdle
+hurdy
+hurl
+Hurley
+hurly
+Huron
+hurrah
+hurray
+hurricane
+hurry
+Hurst
+hurt
+hurtful
+hurtle
+Hurwitz
+husband
+husbandry
+hush
+husk
+hussar
+hussy
+hustings
+hustle
+Huston
+hut
+hutch
+Hutchins
+Hutchinson
+Hutchison
+Hutton
+Huxley
+Huxtable
+huzza
+huzzah
+hyacinth
+Hyades
+hyaline
+Hyannis
+Hyatt
+hybrid
+Hyde
+hydra
+hydrangea
+hydrant
+hydrate
+hydraulic
+hydrazine
+hydride
+hydro
+hydrocarbon
+hydrocarbonate
+hydrocephalic
+hydrochemistry
+hydrochloric
+hydrochloride
+hydrodynamic
+hydroelectric
+hydrofluoric
+hydrofoil
+hydroform
+hydrogen
+hydrogenate
+hydrography
+hydrology
+hydrolysis
+hydrolyze
+hydrometer
+hydrophilic
+hydrophobe
+hydrophone
+hydroplane
+hydroponic
+hydropower
+hydroscope
+hydrosphere
+hydrostatic
+hydrotherapy
+hydrothermal
+hydrous
+hydroxide
+hydroxy
+hydroxyl
+hydroxylate
+hyena
+hygiene
+hygienic
+hygrometer
+hygroscopic
+hying
+Hyman
+hymen
+hymeneal
+hymenoptera
+hymn
+hymnal
+hymnbook
+hype
+hyperbola
+hyperbolic
+hyperboloid
+hyperborean
+hypergolic
+hyperopia
+hyperopic
+hyphen
+hyphenate
+hypnosis
+hypnotic
+hypnotism
+hypnotist
+hypnotize
+hypoactive
+hypocaust
+hypocenter
+hypochondria
+hypocrisy
+hypocrite
+hypocritical
+hypocycloid
+hypodermic
+hypophyseal
+hypostatize
+hypotenuse
+hypothalamic
+hypothalamus
+hypothermia
+hypothermic
+hypotheses
+hypothesis
+hypothesize
+hypothetic
+hypothyroid
+hypoxia
+hypsometer
+hysterectomy
+hysteresis
+hysteria
+hysteric
+Hyundai
+IA
+iambic
+Ian
+iatrogenic
+Iberia
+ibex
+ibid.
+ibis
+IBM
+Ibn
+Icarus
+ICBM
+ICC
+ice
+iceberg
+iceboat
+icebox
+icebreaker
+icefall
+icehouse
+Iceland
+Icelandic
+ichneumon
+ichthyology
+ichthyosaur
+icicle
+icky
+icon
+iconic
+iconoclasm
+iconoclast
+iconoclastic
+iconography
+iconology
+iconoscope
+icosahedra
+icosahedral
+icosahedron
+I'd
+ID
+Ida
+Idaho
+idea
+ideal
+ideate
+idempotent
+identical
+identify
+identity
+ideograph
+ideography
+ideologue
+ideology
+ides
+idiocy
+idiom
+idiomatic
+idiosyncrasy
+idiosyncratic
+idiot
+idiotic
+idle
+idly
+idol
+idolater
+idolatrous
+idolatry
+idyll
+idyllic
+i.e.
+IEEE
+if
+Ifni
+igloo
+igneous
+ignite
+ignition
+ignoble
+ignominious
+ignominy
+ignoramus
+ignorant
+ignore
+iguana
+ii
+iii
+Ike
+IL
+ileitis
+ileum
+iliac
+Iliad
+ilk
+I'll
+ill
+illegal
+illegible
+illegitimacy
+illegitimate
+illiberal
+illicit
+illimitable
+Illinois
+illiquid
+illiteracy
+illiterate
+illness
+illogic
+illume
+illuminant
+illuminate
+illuminati
+illumine
+illusion
+illusionary
+illusory
+illustrate
+illustrious
+Ilona
+Ilyushin
+I'm
+image
+imagery
+imaginary
+imaginate
+imagine
+imbalance
+imbecile
+imbecilic
+imbibe
+Imbrium
+imbroglio
+imbrue
+imbue
+imitable
+imitate
+immanent
+immediacy
+immense
+immerse
+immersion
+imminent
+immolate
+immovable
+immune
+immunization
+immunology
+immure
+imp
+impact
+impair
+impartation
+impassable
+impasse
+impasto
+impatient
+impeach
+impecunious
+impedance
+impede
+impedimenta
+impel
+impend
+imperative
+imperial
+imperil
+imperious
+imperium
+impersonate
+impetigo
+impetuosity
+impetuous
+impetus
+impinge
+impish
+implement
+implementation
+implicant
+implicate
+implicit
+implode
+implore
+important
+importation
+importunate
+importune
+impost
+impoverish
+imprecate
+impregnable
+impregnate
+impresario
+impressible
+impression
+imprimatur
+imprint
+impromptu
+improvisation
+improvisatorial
+improvisatory
+improvise
+impudent
+impugn
+impulsion
+impulsive
+impunity
+imputation
+impute
+in
+inability
+inaction
+inadvisable
+inalienable
+inalterable
+inamorata
+inane
+inappeasable
+inapproachable
+inapt
+inarguable
+inartistic
+inasmuch
+inaugural
+inaugurate
+inboard
+inborn
+inbound
+inbred
+inbreed
+Inc.
+Inca
+incandescent
+incant
+incantation
+incapable
+incarcerate
+incarnate
+incendiary
+incense
+incentive
+inception
+inceptor
+incessant
+incest
+incestuous
+inch
+inchoate
+inchworm
+incident
+incidental
+incinerate
+incipient
+incise
+incision
+incisive
+incisor
+incivil
+inclination
+incline
+inclose
+include
+inclusion
+incognito
+income
+incommunicado
+incommutable
+incomparable
+incompetent
+incomplete
+incompletion
+incomprehension
+incomputable
+inconceivable
+inconclusive
+incondensable
+inconsiderable
+inconsolable
+incontestable
+incontrollable
+incorporable
+incorporate
+incorrect
+incorrigible
+increment
+incriminate
+incross
+incrustation
+incubate
+incubi
+incubus
+inculcate
+incumbent
+incunabula
+incur
+incursion
+indebted
+indecent
+indecipherable
+indecomposable
+indeed
+indefatigable
+indefeasible
+indefinable
+indelible
+indelicate
+indemnify
+indemnity
+indent
+indentation
+indenture
+indescribable
+indeterminable
+indeterminism
+index
+India
+Indian
+Indiana
+Indianapolis
+indicant
+indicate
+indices
+indicia
+indict
+Indies
+indigene
+indigenous
+indigent
+indigestible
+indignant
+indignation
+indigo
+indirect
+indiscoverable
+indispensable
+indispose
+indisposition
+indisputable
+indissoluble
+indistinct
+indistinguishable
+indium
+individual
+individualism
+individuate
+Indochina
+Indochinese
+indoctrinate
+indole
+indolent
+indomitable
+Indonesia
+indoor
+indrawn
+induce
+inducible
+inductance
+inductee
+indulge
+indulgent
+industrial
+industrialism
+industrious
+industry
+inebriate
+inebriety
+ineducable
+ineffable
+ineffective
+inelastic
+ineluctable
+inept
+ineptitude
+inequality
+inequivalent
+inerrant
+inert
+inertance
+inertia
+inertial
+inescapable
+inessential
+inevitable
+inexact
+inexcusable
+inexperience
+inexpert
+inexplainable
+inexpressible
+inextinguishable
+Inez
+infamy
+infancy
+infant
+infanta
+infanticide
+infantile
+infantry
+infarct
+infatuate
+infect
+infectible
+infectious
+infer
+inferable
+inference
+inferential
+inferior
+infernal
+inferno
+infest
+infestation
+infidel
+infield
+infight
+infima
+infimum
+infinitesimal
+infinitive
+infinitude
+infinitum
+infinity
+infirmary
+infix
+inflame
+inflammation
+inflammatory
+inflate
+inflationary
+inflect
+inflict
+inflorescent
+influential
+influenza
+influx
+info
+inform
+informatics
+information
+infra
+infract
+infrared
+infrasonic
+infrastructure
+infrequent
+infuriate
+ingenious
+ingenue
+ingenuity
+ingenuous
+Ingersoll
+ingest
+ingestible
+ingestion
+ingot
+Ingram
+ingrate
+ingratiate
+ingredient
+ingress
+Ingrid
+ingroup
+inhabit
+inhalant
+inhere
+inherent
+inherit
+inheritance
+inheritor
+inhibit
+inhibition
+inhibitor
+inholding
+inhomogeneity
+inhomogeneous
+inhuman
+inhume
+inimical
+iniquitous
+iniquity
+initial
+initiate
+inject
+Injun
+injure
+injurious
+injury
+ink
+inkblot
+inker
+inkling
+inkwell
+inland
+inlay
+inlet
+Inman
+inmate
+inmost
+inn
+innards
+innate
+inner
+innermost
+innersole
+innervate
+inning
+innocent
+innocuous
+innovate
+innuendo
+inoculant
+inoculate
+inoperative
+inordinate
+inpatient
+input
+inquire
+inquiry
+inquisition
+inquisitor
+inquisitorial
+inroad
+inrush
+inscription
+inseam
+insect
+insecticidal
+insecticide
+insectivore
+insecure
+inseminate
+insert
+inset
+inshore
+inside
+insidious
+insight
+insignia
+insincere
+insinuate
+insipid
+insist
+insistent
+insofar
+insolate
+insole
+insolent
+insolvable
+insomnia
+insomuch
+insouciant
+inspect
+inspiration
+inspirit
+instable
+installation
+instalment
+instant
+instantaneous
+instantiate
+instar
+instate
+instead
+instep
+instigate
+instill
+instinct
+instinctual
+institute
+instruct
+instructible
+instrument
+instrumentation
+insubordinate
+insufferable
+insulant
+insular
+insulate
+insulin
+insult
+insuperable
+insupportable
+insurance
+insure
+insurgent
+insurmountable
+insurrection
+intact
+intake
+integer
+integrable
+integral
+integrand
+integrate
+integrity
+intellect
+intellectual
+intelligent
+intelligentsia
+intelligible
+intend
+intendant
+intense
+intensify
+intensive
+intent
+intention
+inter
+intercalary
+intercalate
+intercept
+intercessor
+intercom
+interdict
+interest
+interfere
+interference
+interferometer
+interim
+interior
+interject
+interlude
+intermediacy
+intermediary
+intermit
+intermittent
+intermitting
+intern
+internal
+internecine
+Interpol
+interpolant
+interpolate
+interpret
+interpretation
+interpretive
+interpupillary
+interregnum
+interrogate
+interrogatory
+interrupt
+interruptible
+intersperse
+interspersion
+interstice
+interstitial
+interval
+intervale
+intervene
+intervenor
+intervention
+interviewee
+intestacy
+intestate
+intestinal
+intestine
+intimacy
+intimal
+intimate
+intimidate
+into
+intonate
+intoxicant
+intoxicate
+intractable
+intramolecular
+intransigent
+intransitive
+intrepid
+intricacy
+intricate
+intrigue
+intrinsic
+introduce
+introduction
+introductory
+introit
+introject
+intromission
+intromit
+introspect
+introversion
+introvert
+intrude
+intrusion
+intuit
+intuitable
+Inuit
+inundate
+inure
+invade
+invalid
+invasion
+invective
+inveigh
+inveigle
+invent
+inventor
+inventory
+Inverness
+inverse
+invert
+invertible
+invest
+investigate
+investiture
+investor
+inveterate
+inviable
+invidious
+invigorate
+inviolable
+inviolate
+invitation
+invite
+invitee
+invoice
+invoke
+involutionary
+involutory
+involve
+inward
+Io
+iodate
+iodic
+iodide
+iodine
+iodize
+iodoform
+iodous
+ion
+ionic
+ionize
+ionosphere
+ionospheric
+iota
+IOU
+Iowa
+ipecac
+ipsilateral
+ipso
+IQ
+IR
+Ira
+Iran
+Iranian
+Iraq
+Iraqi
+irascible
+irate
+ire
+Ireland
+Irene
+irenic
+irides
+iridescent
+iridium
+iris
+Irish
+irk
+irksome
+Irma
+iron
+ironbound
+ironclad
+ironic
+ironmaster
+ironmonger
+ironmongery
+ironside
+ironstone
+ironware
+ironwood
+ironwork
+irony
+Iroquois
+irrational
+Irrawaddy
+irreclaimable
+irrecoverable
+irredeemable
+irredentism
+irredentist
+irrefragable
+irremovable
+irreplaceable
+irreproducible
+irresolute
+irresolvable
+irrevocable
+irrigate
+irritable
+irritant
+irritate
+irrupt
+IRS
+Irvin
+Irvine
+Irving
+Irwin
+i's
+is
+Isaac
+Isaacson
+Isabel
+Isabella
+Isaiah
+ISBN
+isentropic
+Isfahan
+Ising
+isinglass
+Isis
+Islam
+Islamabad
+Islamic
+island
+isle
+islet
+ism
+isn't
+isochronal
+isochronism
+isochronous
+isoclinal
+isocline
+isogonic
+isolate
+Isolde
+isomer
+isomeric
+isomorph
+isomorphic
+isopleth
+isosceles
+isostasy
+isotherm
+isothermal
+isotope
+isotopic
+isotopy
+isotropic
+isotropy
+Israel
+Israeli
+Israelite
+ISSN
+issuant
+issue
+Istanbul
+isthmian
+isthmus
+it
+Italian
+italianate
+italic
+Italy
+itch
+it'd
+item
+iterate
+Ithaca
+itinerant
+itinerary
+it'll
+Ito
+itself
+IT&T
+ITT
+IUD
+iv
+Ivan
+Ivanhoe
+I've
+Iverson
+ivory
+ivy
+ix
+Izvestia
+jab
+jabber
+jabberwocky
+Jablonsky
+jacaranda
+jack
+jackal
+jackanapes
+jackass
+jackboot
+jackdaw
+jacket
+jackhammer
+Jackie
+jackknife
+jacklight
+Jackman
+jackpot
+jackrabbit
+Jackson
+Jacksonville
+jackstraw
+Jacky
+JACM
+Jacob
+Jacobean
+Jacobi
+Jacobian
+Jacobin
+Jacobs
+Jacobsen
+Jacobson
+Jacobus
+jacquard
+Jacqueline
+Jacques
+jacuzzi
+jade
+jaeger
+jag
+jaguar
+jail
+jailbird
+jailbreak
+jailhouse
+Jaime
+Jakarta
+Jake
+jalapeno
+jalopy
+jalousie
+jam
+Jamaica
+jamb
+jambalaya
+jamboree
+James
+Jamestown
+Jamie
+Jan
+Jane
+Janeiro
+Janet
+jangle
+Janice
+Janie
+Janis
+janissary
+janitor
+janitorial
+janizary
+Janos
+Jansenist
+January
+Janus
+Japan
+Japanese
+japanned
+jape
+japery
+jar
+jargon
+Jarvin
+Jarvis
+jasmine
+Jason
+jasper
+jaundice
+jaunt
+Java
+Javanese
+javelin
+jaw
+jawbone
+jawbreak
+jay
+jaybird
+Jaycee
+jaywalk
+jazz
+jealous
+jealousy
+jean
+Jeanette
+Jeanne
+Jeannie
+Jed
+jeebies
+jeep
+jeer
+Jeff
+Jefferson
+Jeffrey
+Jehovah
+jejune
+jejunum
+jelly
+jellyfish
+Jenkins
+Jennie
+Jennifer
+Jennings
+jenny
+Jensen
+jeopard
+jeopardy
+jerboa
+jeremiad
+Jeremiah
+Jeremy
+Jeres
+Jericho
+jerk
+jerkin
+jerkwater
+jeroboam
+Jerome
+jerry
+jersey
+Jerseyite
+Jerusalem
+jess
+Jesse
+Jessica
+Jessie
+jest
+Jesuit
+jesuitic
+jesuitism
+Jesus
+jet
+jetliner
+jetport
+jetsam
+jettison
+jetty
+jetway
+Jew
+jewel
+Jewell
+jewelry
+Jewess
+Jewett
+Jewish
+Jewry
+jezebel
+JFK
+jib
+jibe
+Jiddah
+jiffy
+jig
+jiggle
+jiggly
+jigsaw
+jihad
+Jill
+jilt
+Jim
+Jimenez
+Jimmie
+jimmy
+jingle
+jingly
+jingo
+jingoism
+jingoist
+jinks
+jinx
+jitney
+jitter
+jitterbug
+jittery
+jive
+J&J
+Jo
+Joan
+Joann
+Joanna
+Joanne
+Joaquin
+job
+jobholder
+Jocelyn
+jock
+jockey
+jockstrap
+jocose
+jocular
+jocund
+jodhpur
+Jodi
+Jody
+Joe
+Joel
+joey
+jog
+joggle
+Johann
+Johannes
+Johannesburg
+Johansen
+Johanson
+john
+Johnny
+johnnycake
+Johnson
+Johnston
+Johnstown
+join
+joinery
+joint
+joist
+joke
+Joliet
+Jolla
+jollity
+jolly
+jolt
+Jon
+Jonah
+Jonas
+Jonathan
+Jones
+jonquil
+Jordan
+Jordanian
+Jorge
+Jorgensen
+Jorgenson
+Jose
+Josef
+Joseph
+Josephine
+Josephson
+Josephus
+josh
+Joshua
+Josiah
+joss
+jostle
+jot
+joule
+jounce
+jouncy
+journal
+journalese
+journey
+joust
+Jovanovich
+Jove
+jovial
+Jovian
+jowl
+jowly
+joy
+Joyce
+joyous
+joyride
+joystick
+Jr.
+j's
+Juan
+Juanita
+jubilant
+jubilate
+jubilee
+Judah
+Judaic
+Judaism
+Judaist
+Judas
+Judd
+Jude
+judge
+judgment
+judicable
+judicatory
+judicature
+judicial
+judiciary
+judicious
+Judith
+judo
+Judson
+Judy
+jug
+jugate
+juggernaut
+juggle
+jugular
+juice
+Juilliard
+jujitsu
+juju
+jujube
+juke
+jukebox
+Jukes
+Jul.
+julep
+Jules
+Julia
+Julie
+julienne
+Juliet
+Julio
+Julius
+Julliard
+July
+jumble
+jumbo
+jump
+Jun.
+junco
+junction
+juncture
+June
+Juneau
+jungle
+jungly
+junior
+juniper
+junk
+junkerdom
+junket
+junketeer
+junkie
+Juno
+junta
+Jupiter
+Jura
+Jurassic
+jure
+juridic
+Juris
+jurisdiction
+jurisprudent
+jurisprudential
+jurist
+juror
+jury
+just
+justice
+justiciable
+justify
+Justine
+Justinian
+jut
+jute
+juvenal
+juvenile
+juxtapose
+juxtaposition
+Kaaba
+kabob
+Kabuki
+Kabul
+Kaddish
+kafir
+Kafka
+Kafkaesque
+Kahn
+kaiser
+Kajar
+Kalamazoo
+kale
+kaleidescope
+kaleidoscope
+kaleidoscopic
+kalends
+Kalmuk
+Kamchatka
+kamikaze
+Kampala
+kampong
+Kampuchea
+Kane
+kangaroo
+Kanji
+Kankakee
+Kansan
+Kansas
+Kant
+Kantian
+kaolin
+Kaplan
+kapok
+kappa
+kaput
+Karachi
+karakul
+Karamazov
+karate
+Karen
+Karl
+Karla
+karma
+Karol
+Karp
+karyotype
+Kashmir
+Kashmiri
+Kaskaskia
+Kate
+Katharine
+Katherine
+Kathleen
+Kathryn
+Kathy
+Katie
+Katmandu
+Katowice
+katydid
+Katz
+Kauffman
+Kaufman
+kava
+Kay
+kayak
+kayo
+Kazakhstan
+kazoo
+Keaton
+Keats
+kedge
+keel
+keelboat
+keelhaul
+keelson
+keen
+Keenan
+keep
+keepsake
+keg
+kegler
+Keith
+Keller
+Kelley
+Kellogg
+Kelly
+kelp
+Kelsey
+kelvin
+Kemp
+ken
+Kendall
+Kennan
+Kennecott
+Kennedy
+kennel
+Kenneth
+Kenney
+Kenny
+keno
+Kensington
+Kent
+Kenton
+Kentuckian
+Kentucky
+Kenya
+Kenyon
+kepi
+Kepler
+kept
+kerchief
+kerfuffle
+Kermit
+kern
+kernel
+kerosene
+Kerr
+kerry
+kerygma
+Kessler
+kestrel
+ketch
+ketchup
+ketone
+ketosis
+Kettering
+kettle
+kettledrum
+Kevin
+key
+keyboard
+keyed
+Keyes
+keyhole
+Keynes
+Keynesian
+keynote
+keypunch
+keystone
+keyway
+keyword
+khaki
+khan
+Khartoum
+khedive
+Khmer
+Khrushchev
+kibbutz
+kibbutzim
+kibitz
+kibitzing
+kibosh
+kick
+kickback
+kickoff
+kickshaw
+kid
+Kidd
+Kidde
+kiddie
+kidnap
+kidney
+Kieffer
+kielbasa
+Kiev
+Kiewit
+Kigali
+Kikuyu
+Kilgore
+kill
+killdeer
+killjoy
+kiln
+kilo
+kilohm
+kilt
+Kim
+Kimball
+Kimberly
+kimono
+kin
+kind
+kindergarten
+kindergartner
+kindhearted
+kindle
+kindred
+kine
+kinematic
+kinescope
+kinesic
+kinesthesis
+kinesthetic
+kinetic
+kinfolk
+king
+kingbird
+kingdom
+kingfish
+kingfisher
+kinglet
+kingpin
+Kingsbury
+Kingsley
+Kingston
+kink
+kinkajou
+Kinney
+kins
+Kinshasa
+Kinshasha
+kinship
+kiosk
+Kiowa
+Kipling
+kipper
+Kirby
+Kirchner
+Kirchoff
+Kirghiz
+Kirgizstan
+kirk
+Kirkland
+Kirkpatrick
+Kirov
+kirsch
+Kirsten
+kiss
+kissing
+kit
+Kitakyushu
+kitchen
+kitchenette
+kitchenware
+kite
+kith
+kitsch
+kitten
+kittenish
+kittiwake
+kittle
+kitty
+kiva
+Kiwanian
+Kiwanis
+kiwi
+Klan
+Klans
+klatch
+klatsch
+Klaus
+klaxon
+kleenex
+Klein
+kleptomania
+Kline
+Klux
+klystron
+km
+knack
+knap
+Knapp
+knapsack
+Knauer
+knave
+knavery
+knavish
+knead
+knee
+kneecap
+kneehole
+kneel
+knell
+knelt
+knew
+knick
+knickerbocker
+knickknack
+knife
+knifelike
+knight
+Knightsbridge
+knit
+knitwear
+knives
+knob
+knock
+knockdown
+knockout
+knoll
+knot
+knothole
+Knott
+knout
+know
+knoweth
+knowhow
+knowledge
+knowledgeable
+Knowles
+Knowlton
+known
+Knox
+Knoxville
+knuckle
+knuckleball
+knucklebone
+Knudsen
+Knudson
+knurl
+Knutsen
+Knutson
+koala
+Koch
+Kochab
+Kodachrome
+Kodak
+Kodiak
+Koenig
+Koenigsberg
+kohl
+kohlrabi
+kohlrabies
+kola
+kolkhoz
+Kong
+kook
+kooky
+kopeck
+Koppers
+Koran
+Korea
+kosher
+Kowalewski
+Kowalski
+kowtow
+kraal
+kraft
+Krakatoa
+Krakow
+Kramer
+krater
+Krause
+kraut
+Kremlin
+Kresge
+Krieger
+krill
+Kris
+Krishna
+Kristin
+Kristine
+krona
+Kronecker
+kroner
+Krueger
+Kruger
+Kruse
+krypton
+KS
+k's
+Ku
+kudos
+kudzu
+Kuhn
+kulak
+kumquat
+Kurd
+Kurdish
+Kurt
+kuru
+Kuwait
+Kuwaiti
+kvass
+kwashiorkor
+KY
+Kyle
+Kyoto
+kyrie
+Kyushu
+la
+lab
+Laban
+label
+labia
+labial
+labile
+lability
+labor
+laboratory
+laborious
+laborite
+Labour
+Labrador
+labyrinth
+labyrinthine
+lac
+laccolith
+lace
+lacerate
+Lacerta
+lacewing
+Lachesis
+lachrymal
+lachrymate
+lachrymose
+lack
+lackadaisic
+lackaday
+lackey
+lackluster
+laconic
+lacquer
+lacrosse
+lactase
+lactate
+lactic
+lactose
+lacuna
+lacunae
+lacustrine
+lad
+laddie
+laden
+ladle
+lady
+ladybird
+ladybug
+ladyfern
+ladyfinger
+Lafayette
+lag
+lager
+laggard
+lagniappe
+lagoon
+Lagos
+Lagrange
+Lagrangian
+Laguerre
+Lahore
+laic
+laid
+Laidlaw
+lain
+lair
+laird
+laissez
+laity
+lake
+lakefront
+Lakehurst
+lakeside
+Lally
+lam
+lama
+Lamar
+Lamarck
+Lamarckian
+lamasery
+lamb
+lambaste
+lambasting
+lambda
+lambert
+lame
+lamella
+lamellae
+lamellar
+lament
+lamentation
+lamina
+laminar
+laminate
+lamp
+lampblack
+lamplight
+lampoon
+lampoonery
+lamprey
+Lana
+Lancashire
+Lancaster
+lance
+lanceolate
+lancet
+land
+landau
+landfall
+landfill
+landform
+landhold
+Landis
+landlady
+landlocked
+landlord
+landlubber
+landmark
+landmass
+landowner
+Landry
+lands
+Landsat
+landscape
+landslide
+landward
+lane
+Lang
+Lange
+Langley
+Langmuir
+language
+languid
+languish
+languor
+languorous
+lank
+Lanka
+lanolin
+Lansing
+lantern
+lanthanide
+lanthanum
+lanyard
+Lao
+Laocoon
+Laos
+Laotian
+lap
+lapboard
+LAPD
+lapdog
+lapel
+lapidary
+Laplace
+Laplacian
+lappet
+lapse
+lapstrake
+lapwing
+Laramie
+larboard
+larcenist
+larcenous
+larceny
+larch
+lard
+Laredo
+lares
+large
+largemouth
+largess
+largesse
+larghetto
+largish
+largo
+lariat
+lark
+Larkin
+larkspur
+Larry
+Lars
+Larsen
+Larson
+larva
+larvae
+larval
+larvicide
+laryngeal
+larynges
+laryngitis
+laryngology
+laryngoscope
+laryngoscopic
+laryngoscopy
+larynx
+lasagna
+lascar
+lascivious
+lase
+lash
+lass
+lassie
+lassitude
+lasso
+last
+Laszlo
+latch
+latchkey
+latchstring
+late
+latecome
+lateen
+latent
+lateral
+Lateran
+laterite
+latex
+lath
+lathe
+lather
+Lathrop
+latifundium
+Latin
+Latinate
+latinize
+latish
+latitude
+latitudinal
+latitudinarian
+latitudinary
+latrine
+Latrobe
+latter
+lattice
+latticework
+latus
+Latvia
+laud
+laudanum
+laudatory
+Lauderdale
+Laue
+laugh
+laughingstock
+Laughlin
+laughter
+launch
+launder
+launderette
+laundress
+laundromat
+laundry
+Laura
+laureate
+laurel
+Lauren
+Laurence
+Laurent
+Laurentian
+Laurie
+Lausanne
+lava
+lavabo
+lavatory
+lave
+lavender
+Laverne
+lavish
+Lavoisier
+law
+lawbreak
+lawgive
+lawn
+Lawrence
+lawrencium
+Lawson
+lawsuit
+lawyer
+lax
+laxative
+lay
+layette
+layoff
+layout
+layover
+Layton
+layup
+Lazarus
+laze
+lazybones
+lea
+leach
+leachate
+lead
+leaden
+leadeth
+leadoff
+leads
+leaf
+leaflet
+league
+Leah
+leak
+leakage
+lean
+Leander
+Leanne
+leap
+leapfrog
+leapt
+Lear
+learn
+lease
+leasehold
+leash
+least
+leastwise
+leather
+leatherback
+leatherneck
+leatherwork
+leathery
+leave
+leaven
+Leavenworth
+Lebanese
+Lebanon
+lebensraum
+Lebesgue
+lecher
+lecherous
+lechery
+lecithin
+lectern
+lectionary
+lector
+lecture
+led
+lederhosen
+ledge
+lee
+leeboard
+leech
+leek
+leer
+leery
+leeward
+leeway
+left
+leftmost
+leftover
+leftward
+lefty
+leg
+legacy
+legal
+legalese
+legate
+legatee
+legato
+legend
+legendary
+Legendre
+legerdemain
+leghorn
+legible
+legion
+legionary
+legionnaire
+legislate
+legislature
+legit
+legitimacy
+legitimate
+legitimize
+Lego
+legume
+leguminous
+Lehigh
+Lehman
+Leigh
+Leighton
+Leila
+leisure
+leitmotif
+leitmotiv
+Leland
+lemma
+lemming
+lemon
+lemonade
+Lemuel
+lemur
+Len
+Lena
+lend
+lender
+length
+lengthen
+lengthways
+lengthwise
+lenient
+Lenin
+Leningrad
+Leninism
+Leninist
+lenity
+Lennox
+Lenny
+lens
+lent
+Lenten
+lenticular
+lentil
+lento
+Leo
+Leon
+Leona
+Leonard
+Leonardo
+Leone
+Leonid
+leonine
+leopard
+Leopold
+leotard
+leper
+lepidoptera
+leprechaun
+leprosy
+leprous
+lepton
+Leroy
+lesbian
+lesion
+Lesley
+Leslie
+Lesotho
+less
+lessee
+lessen
+lesson
+lessor
+lest
+Lester
+let
+letdown
+lethal
+lethargic
+lethargy
+Lethe
+Letitia
+letter
+letterhead
+letterpress
+Lettish
+lettuce
+letup
+leukemia
+leukemic
+leukocyte
+levee
+level
+levelheaded
+lever
+leverage
+Levi
+leviathan
+Levin
+Levine
+Levinson
+levitate
+Levite
+Leviticus
+Levitt
+levity
+levo
+levorotary
+levorotation
+levorotatory
+levy
+Lew
+lewd
+lewis
+lexical
+lexicography
+lexicon
+Lexington
+Leyden
+liable
+liaison
+liana
+liar
+lib
+libation
+Libby
+libel
+libelous
+liberal
+liberate
+Liberia
+libertarian
+libertine
+liberty
+libidinal
+libidinous
+libido
+librarian
+library
+librate
+librettist
+libretto
+Libreville
+Libya
+lice
+license
+licensee
+licensor
+licentious
+lichee
+lichen
+licit
+lick
+licorice
+lid
+lido
+lie
+Liechtenstein
+lied
+lief
+lien
+lieu
+lieutenant
+life
+lifeblood
+lifeboat
+lifeguard
+lifeline
+lifelong
+lifer
+lifesaver
+lifesaving
+lifespan
+lifestyle
+lifetime
+LIFO
+lift
+liftoff
+ligament
+ligamentary
+ligand
+ligate
+ligature
+Ligget
+Liggett
+light
+lighten
+lighterage
+lightface
+lightfast
+lighthearted
+lighthouse
+lightish
+lightning
+lightproof
+lightsome
+lightweight
+lignin
+lignite
+lignum
+like
+liken
+likewise
+Lila
+lilac
+Lilian
+Lilith
+Lillian
+Lillie
+lilliputian
+Lilly
+lilt
+lily
+Lima
+limb
+limbic
+limbo
+Limburger
+lime
+limelight
+limerick
+limestone
+limey
+limit
+limitation
+limn
+limnology
+limo
+limousine
+limp
+limpet
+limpid
+limpkin
+Lin
+linchpin
+Lincoln
+Lincolnesque
+Lind
+Linda
+lindane
+Lindberg
+Lindbergh
+linden
+Lindholm
+Lindquist
+Lindsay
+Lindsey
+Lindstrom
+line
+lineage
+lineal
+lineament
+linear
+lineation
+linebacker
+linen
+liner
+lineup
+linger
+lingerie
+lingo
+lingua
+lingual
+linguist
+liniment
+link
+linkage
+linkup
+Linnaean
+Linnean
+linoleum
+Linotype
+linseed
+lint
+lintel
+Linus
+lion
+Lionel
+lioness
+lionhearted
+lip
+lipid
+lipoma
+Lippincott
+lipread
+Lipschitz
+Lipscomb
+lipstick
+Lipton
+liquefaction
+liquefy
+liqueur
+liquid
+liquidate
+liquidus
+liquor
+lira
+Lisa
+Lisbon
+Lise
+lisle
+lisp
+Lissajous
+lissome
+list
+listen
+lit
+litany
+liter
+literacy
+literal
+literary
+literate
+literati
+literature
+lithe
+lithic
+lithium
+lithograph
+lithography
+lithology
+lithosphere
+lithospheric
+Lithuania
+litigant
+litigate
+litigious
+litmus
+litter
+litterbug
+little
+littleneck
+Littleton
+Litton
+littoral
+liturgic
+liturgy
+live
+livelong
+liven
+Livermore
+Liverpool
+liverwort
+liverwurst
+livery
+livestock
+liveth
+livid
+Livingston
+livre
+Liz
+lizard
+Lizzie
+llama
+Lloyd
+lo
+load
+loaf
+loam
+loan
+loath
+loathe
+loathsome
+loaves
+lob
+lobar
+lobate
+lobby
+lobe
+loblolly
+lobo
+lobotomize
+lobotomy
+lobscouse
+lobster
+lobular
+lobule
+local
+locale
+locate
+loci
+lock
+Locke
+locket
+Lockhart
+Lockheed
+Lockian
+lockjaw
+locknut
+lockout
+locksmith
+lockstep
+lockstitch
+lockup
+Lockwood
+loco
+locomotion
+locomotor
+locus
+locust
+locution
+locutor
+lode
+lodestone
+lodge
+lodgepole
+Lodowick
+Loeb
+l'oeil
+loess
+loft
+log
+Logan
+logarithm
+logarithmic
+logbook
+loge
+loggerhead
+loggia
+logic
+logician
+logistic
+logjam
+logo
+logorrhea
+logotype
+logroll
+logy
+Lohengrin
+loin
+loincloth
+Loire
+Lois
+loiter
+Loki
+Lola
+loll
+lollipop
+lolly
+lollygag
+lollypop
+Lomb
+London
+Londoner
+lone
+lonely
+lonesome
+long
+longboat
+longbow
+longevity
+Longfellow
+longhair
+longhand
+longhorn
+longhouse
+longish
+longitude
+longitudinal
+longleg
+longshoreman
+longshoremen
+longspur
+longstanding
+longtime
+longueur
+Lonnie
+look
+lookout
+lookup
+loom
+Loomis
+loon
+loop
+loophole
+loopy
+loose
+looseleaf
+loosen
+loosestrife
+loot
+lop
+lope
+Lopez
+lopsided
+loquacious
+loquacity
+loquat
+loran
+lord
+lordling
+lordosis
+lore
+Lorelei
+Loren
+Lorene
+Loretta
+lorgnette
+Lorinda
+loris
+Lorraine
+lorry
+Los
+lose
+loss
+lost
+lot
+lothario
+lotion
+Lotte
+lottery
+Lottie
+lotto
+lotus
+Lou
+loud
+loudmouth
+loudspeak
+Louis
+Louisa
+Louise
+Louisiana
+Louisville
+lounge
+Lounsbury
+loupe
+Lourdes
+louse
+lout
+loutish
+louver
+Louvre
+love
+lovebird
+Lovelace
+Loveland
+lovelorn
+lovely
+lovemaking
+lovesick
+loveth
+low
+lowborn
+lowboy
+lowbrow
+lowdown
+Lowe
+Lowell
+lower
+lowerclass
+lowermost
+Lowery
+lowland
+Lowry
+lox
+loxodrome
+loyal
+loyalty
+lozenge
+LP
+LPG
+l's
+LSI
+Ltd.
+LTV
+luau
+lubber
+Lubbock
+lube
+Lubell
+lubricant
+lubricate
+lubricious
+lubricity
+Lucas
+lucent
+Lucerne
+Lucia
+Lucian
+lucid
+Lucifer
+Lucille
+Lucinda
+Lucite
+Lucius
+luck
+lucrative
+lucre
+Lucretia
+Lucretius
+lucubrate
+Lucy
+Luddite
+ludicrous
+Ludlow
+Ludwig
+luff
+Lufthansa
+Luftwaffe
+lug
+luge
+luggage
+lugsail
+lugubrious
+Luis
+Luke
+lukewarm
+Lula
+lull
+lullaby
+lulu
+lumbago
+lumbar
+lumber
+lumberjack
+lumberyard
+lumen
+luminaire
+luminal
+luminance
+luminary
+luminesce
+luminescent
+luminiferous
+luminosity
+luminous
+lummox
+lump
+lumpen
+lumpish
+Lumpur
+luna
+lunacy
+lunar
+lunate
+lunatic
+lunch
+luncheon
+luncheonette
+lunchroom
+lunchtime
+Lund
+Lundberg
+Lundquist
+lune
+lunette
+lung
+lunge
+lungfish
+lunker
+lunkhead
+lupine
+Lura
+lurch
+lure
+lurid
+lurk
+Lusaka
+luscious
+lush
+lust
+luster
+lustrous
+lutanist
+lute
+luteal
+lutetium
+Luther
+Lutheran
+Lutz
+lux
+luxe
+Luxembourg
+luxuriant
+luxuriate
+luxurious
+luxury
+Luzon
+lyceum
+lycopodium
+Lydia
+lye
+lying
+Lykes
+Lyle
+Lyman
+Lyme
+lymph
+lymphatic
+lymphocyte
+lymphocytic
+lymphoma
+lynch
+Lynchburg
+Lynda
+Lynn
+Lynne
+lynx
+Lyon
+lyonnaise
+Lyons
+Lyra
+lyre
+lyrebird
+lyric
+lyricism
+lyse
+Lysenkoism
+lysergic
+lyses
+lysine
+lysis
+ma
+ma'am
+Mabel
+Mac
+macabre
+macadam
+macadamia
+macaque
+macaroni
+macaroon
+MacArthur
+Macassar
+macaw
+Macbeth
+MacDonald
+mace
+Macedon
+Macedonia
+macerate
+MacGregor
+Mach
+machete
+Machiavelli
+Machiavellian
+machicolate
+machination
+machine
+machinery
+machismo
+macho
+macintosh
+Mack
+MacKenzie
+mackerel
+Mackey
+Mackinac
+mackinaw
+mackintosh
+MacMillan
+Macon
+macrame
+macro
+macrocosm
+macroeconomic
+macromolecular
+macromolecule
+macron
+macrophage
+macroprocessor
+macroscopic
+macrostructure
+maculate
+Macy
+mad
+Madagascar
+madam
+Madame
+madcap
+madden
+maddish
+Maddox
+made
+Madeira
+Madeleine
+Madeline
+mademoiselle
+madhouse
+Madison
+Madonna
+madras
+Madrid
+madrigal
+Madsen
+Mae
+maelstrom
+maestoso
+maestro
+Mafia
+magazine
+magdalen
+Magdalene
+Magellan
+magenta
+Maggie
+maggot
+magi
+magic
+magician
+magisterial
+magistracy
+magistrate
+magma
+magmatic
+magna
+magnanimity
+magnanimous
+magnate
+magnesia
+magnesite
+magnesium
+magnet
+magnetic
+magnetite
+magneto
+magneton
+magnetron
+magnificat
+magnificent
+magnify
+magniloquent
+magnitude
+magnolia
+magnum
+Magnuson
+Magog
+magpie
+Magruder
+maguey
+Magyar
+maharaja
+maharajah
+maharani
+mahatma
+Mahayana
+Mahayanist
+mahogany
+Mahoney
+mahout
+maid
+maiden
+maidenhair
+maidenhead
+maidservant
+Maier
+mail
+mailbag
+mailbox
+maim
+main
+Maine
+mainland
+mainline
+mainmast
+mainsail
+mainsheet
+mainspring
+mainstay
+mainstream
+maintain
+maintenance
+maintop
+maitre
+maize
+majestic
+majesty
+major
+majorette
+majuscule
+make
+makeshift
+makeup
+Malabar
+Malachi
+malachite
+maladapt
+maladaptation
+maladaptive
+maladjust
+maladjustive
+maladminister
+maladministration
+maladroit
+malady
+Malagasy
+malaise
+malaprop
+malaria
+malarial
+malarkey
+malathion
+Malawi
+Malay
+Malaya
+Malaysia
+Malcolm
+malconduct
+malcontent
+Malden
+maldistribute
+Maldive
+male
+maledict
+maledictory
+malefaction
+malefactor
+maleficent
+malemute
+malevolent
+malfeasant
+malformation
+malformed
+malfunction
+malgre
+Mali
+malice
+malicious
+malign
+malignant
+malinger
+mall
+mallard
+malleable
+mallet
+Mallory
+mallow
+malnourished
+malnutrition
+malocclusion
+malodorous
+Malone
+Maloney
+malposed
+malpractice
+Malraux
+malt
+Malta
+Maltese
+Malthusian
+Malton
+maltose
+maltreat
+mama
+mamba
+mambo
+Mamie
+mamma
+mammal
+mammalian
+mammalogy
+mammary
+mammograph
+mammography
+mammon
+mammoth
+mammy
+man
+mana
+manacle
+manage
+manageable
+managerial
+Managua
+Manama
+manatee
+Manchester
+Manchu
+mandala
+mandamus
+mandarin
+mandate
+mandible
+mandolin
+mandrake
+mandrel
+mandrill
+Mandy
+mane
+maneuver
+Manfred
+manganese
+mange
+mangle
+mango
+mangrove
+manhandle
+Manhattan
+manhole
+manhunt
+mania
+maniacal
+manic
+manicotti
+manicure
+manifest
+manifestation
+manifesto
+manifold
+manikin
+manila
+manioc
+maniple
+manipulable
+manipulate
+Manitoba
+mankind
+Manley
+Mann
+manna
+mannequin
+mannerism
+mannikin
+mannish
+manometer
+manor
+manorial
+manpower
+manque
+manrope
+Mans
+mansard
+manse
+manservant
+Mansfield
+mansion
+manslaughter
+mantel
+mantic
+mantilla
+mantis
+mantissa
+mantle
+mantlepiece
+mantra
+mantrap
+manual
+Manuel
+manufactory
+manufacture
+manumission
+manumit
+manure
+manuscript
+Manville
+Manx
+many
+manzanita
+Mao
+Maori
+map
+maple
+mar
+marathon
+maraud
+maravedi
+marble
+Marc
+Marceau
+Marcel
+Marcella
+Marcello
+march
+marchioness
+Marcia
+Marco
+Marconi
+Marcus
+Marcy
+Mardi
+mare
+Margaret
+margarine
+margay
+marge
+Margery
+Margie
+margin
+marginal
+marginalia
+Margo
+Margot
+Marguerite
+maria
+mariachi
+Marian
+Marianne
+Marie
+Marietta
+marigold
+marijuana
+Marilyn
+marimba
+Marin
+marina
+marinade
+marinate
+marine
+Marino
+Mario
+Marion
+marionette
+marital
+maritime
+marjoram
+Marjorie
+Marjory
+mark
+markdown
+market
+marketeer
+marketplace
+Markham
+Markov
+Markovian
+marks
+markup
+marl
+Marlboro
+Marlborough
+Marlene
+marlin
+marline
+marlinspike
+Marlowe
+marly
+marmalade
+marmoset
+marmot
+maroon
+marque
+marquee
+marquess
+marquetry
+Marquette
+marquis
+marquise
+marriage
+marriageable
+married
+Marrietta
+Marriott
+marrow
+marrowbone
+marry
+Marseilles
+marsh
+Marsha
+marshal
+Marshall
+marshland
+marshmallow
+marsupial
+mart
+marten
+martensite
+Martha
+martial
+Martian
+martin
+martinet
+Martinez
+martingale
+martini
+Martinique
+Martinson
+Marty
+martyr
+martyrdom
+Marva
+marvel
+marvelous
+Marvin
+Marx
+Marxian
+Mary
+Maryann
+Maryland
+marzipan
+mascara
+mascot
+masculine
+maser
+Maseru
+mash
+mashie
+mask
+masochism
+masochist
+mason
+Masonic
+Masonite
+masonry
+masque
+masquerade
+mass
+Massachusetts
+massacre
+massacring
+massage
+masseur
+Massey
+massif
+massive
+mast
+mastectomy
+mastermind
+masterpiece
+masterwork
+mastery
+masthead
+mastic
+masticate
+mastiff
+mastitis
+mastodon
+mastoid
+mastoidectomy
+masturbate
+mat
+matador
+match
+matchbook
+matchbox
+matchlock
+matchstick
+mate
+Mateo
+mater
+material
+materiel
+maternal
+maternity
+matey
+math
+mathematic
+mathematician
+Mathematik
+Mathews
+Mathewson
+Mathias
+Mathieu
+Mathis
+Matilda
+matinal
+matinee
+matins
+Matisse
+matriarch
+matriarchal
+matriarchs
+matriarchy
+matrices
+matricide
+matriculate
+matrilineal
+matrimonial
+matrimony
+matrix
+matron
+Matson
+Matt
+matte
+Matthew
+Matthews
+Mattie
+mattock
+mattress
+Mattson
+maturate
+mature
+maudlin
+maul
+maunder
+Maureen
+Maurice
+Maurine
+Mauritania
+Mauritius
+mausoleum
+mauve
+maverick
+Mavis
+maw
+mawkish
+Mawr
+Max
+maxilla
+maxim
+maxima
+maximal
+Maximilian
+maximum
+Maxine
+maxwell
+Maxwellian
+may
+Maya
+mayapple
+maybe
+Mayer
+mayest
+Mayfair
+mayflower
+mayfly
+mayhap
+mayhem
+Maynard
+mayn't
+Mayo
+mayonnaise
+mayor
+mayoral
+mayoralty
+Mays
+mayst
+Mazda
+maze
+mazurka
+MBA
+Mbabane
+MC
+McAdams
+McAllister
+McBride
+McCabe
+McCall
+McCann
+McCarthy
+McCarty
+McCauley
+McClain
+McClellan
+McClure
+McCluskey
+McConnel
+McConnell
+McCormick
+McCoy
+McCracken
+McCullough
+McDaniel
+McDermott
+McDonald
+McDonnell
+McDougall
+McDowell
+McElroy
+McFadden
+McFarland
+McGee
+McGill
+McGinnis
+McGovern
+McGowan
+McGrath
+McGraw
+McGregor
+McGuire
+McHugh
+McIntosh
+McIntyre
+McKay
+McKee
+McKenna
+McKenzie
+McKeon
+McKesson
+McKinley
+McKinney
+McKnight
+McLaughlin
+McLean
+McLeod
+McMahon
+McMillan
+McMullen
+McNally
+McNamara
+McNaughton
+McNeil
+McPherson
+M.D.
+MD
+me
+mead
+Meade
+meadow
+meadowland
+meadowlark
+meadowsweet
+meager
+meal
+mealtime
+mealy
+mealybug
+mean
+meander
+meaning
+meant
+meantime
+meanwhile
+measle
+measly
+measure
+meat
+mecca
+mechanic
+mechanician
+mechanism
+mechanist
+mechanize
+mecum
+medal
+medallion
+meddle
+meddlesome
+Medea
+media
+medial
+median
+mediate
+mediatrix
+medic
+medicable
+Medicaid
+medicament
+Medicare
+medicate
+Medici
+medicinal
+medicine
+medico
+medieval
+mediocre
+mediocrity
+meditate
+Mediterranean
+medium
+medley
+medusa
+meek
+meet
+meetinghouse
+Meg
+megalith
+megalithic
+megalomania
+megalomanic
+megalopolis
+megalopolitan
+megohm
+Meier
+meiosis
+meiotic
+Meistersinger
+Mekong
+Mel
+melamine
+melancholia
+melancholic
+melancholy
+Melanesia
+melange
+melanic
+Melanie
+melanin
+melanism
+melanist
+melanoma
+Melbourne
+Melcher
+meld
+melee
+Melinda
+meliorate
+meliorism
+meliorist
+Melissa
+mellifluent
+mellifluous
+Mellon
+mellow
+melodeon
+melodic
+melodious
+melodrama
+melodramatic
+melody
+melon
+Melpomene
+melt
+meltdown
+meltwater
+Melville
+Melvin
+member
+membrane
+membranous
+memento
+memo
+memoir
+memorabilia
+memorable
+memoranda
+memorandum
+memorial
+memorium
+memorize
+memory
+Memphis
+men
+menace
+menage
+menagerie
+menarche
+mend
+mendacious
+mendacity
+mendelevium
+Mendelian
+Mendelssohn
+mendicant
+Menelaus
+menfolk
+menhaden
+menhir
+menial
+meningitis
+meniscus
+Menlo
+Mennonite
+menopause
+menorah
+Menshevik
+menstrual
+menstruate
+mensurable
+mensuration
+mental
+menthol
+mention
+mentor
+menu
+Menzies
+meow
+Mephistopheles
+mercantile
+mercaptan
+Mercator
+Mercedes
+mercenary
+mercer
+merchandise
+merchant
+mercilessly
+Merck
+mercurate
+mercurial
+mercuric
+mercurous
+mercury
+mercy
+mere
+Meredith
+meretricious
+merganser
+merge
+meridian
+meridional
+meringue
+merino
+merit
+meritorious
+Merle
+merlin
+mermaid
+merman
+Merriam
+Merrill
+Merrimack
+merriment
+Merritt
+merry
+merrymaker
+merrymaking
+Mervin
+mesa
+mescal
+mescaline
+mesdames
+mesenteric
+mesh
+mesmeric
+mesmerism
+mesmerize
+mesomorph
+mesomorphic
+meson
+Mesopotamia
+mesosphere
+Mesozoic
+mesquite
+mess
+message
+messenger
+messiah
+messianic
+messieurs
+Messrs.
+mestiza
+mestizo
+met
+metabolic
+metabolism
+metabolite
+metacarpal
+metal
+metallic
+metalliferous
+metallize
+metallography
+metalloid
+metallurgic
+metallurgist
+metallurgy
+metalware
+metalwork
+metamorphic
+metamorphism
+metamorphose
+metamorphosis
+metaphor
+metaphoric
+metastasize
+metatarsal
+Metcalf
+mete
+meteor
+meteoric
+meteorite
+meteoroid
+meteorology
+meter
+methacrylate
+methadone
+methane
+methanol
+methinks
+method
+methodic
+Methodism
+Methodist
+methodology
+methought
+Methuen
+Methuselah
+methyl
+methylate
+methylene
+meticulous
+metier
+metonymy
+metope
+metric
+metro
+metrology
+metronome
+metropolis
+metropolitan
+mettle
+mettlesome
+Metzler
+mew
+Mexican
+Mexico
+Meyer
+Meyers
+mezzanine
+mezzo
+MGM
+mho
+mi
+Miami
+miasma
+miasmal
+miasmic
+mica
+Micah
+mice
+Michael
+Michel
+Michelangelo
+Michele
+Michelin
+Michelle
+Michelson
+Michigan
+Mickelson
+mickey
+micro
+microbial
+microbic
+microcosm
+microfiche
+micrography
+micron
+Micronesia
+microscopy
+mid
+Midas
+middle
+middlebrow
+Middlebury
+Middlesex
+Middleton
+Middletown
+middleweight
+midge
+midriff
+midst
+midterm
+midwifery
+mien
+miff
+Mifflin
+might
+mightn't
+mignon
+migraine
+migrant
+migrate
+Miguel
+mikado
+mike
+mil
+milady
+Milan
+milch
+mild
+mildew
+Mildred
+mile
+mileage
+milepost
+milestone
+milieu
+militant
+militarism
+militarist
+militarize
+military
+militate
+militia
+milk
+milkmaid
+milkshake
+milksop
+milkweed
+mill
+Millard
+millenarian
+millenary
+millennia
+millennial
+millennium
+miller
+millet
+Millie
+Millikan
+milliner
+millinery
+million
+millionaire
+millions
+millionth
+millipede
+millpond
+millrace
+millstone
+millstream
+millwork
+millwright
+milo
+milord
+milt
+Milton
+Miltonic
+Milwaukee
+mime
+mimeo
+mimeograph
+mimesis
+mimetic
+Mimi
+mimic
+mimicked
+mimicking
+mimicry
+mimosa
+mina
+minaret
+minatory
+mince
+mincemeat
+mind
+Mindanao
+mindset
+mine
+minefield
+minelayer
+mineral
+mineralogy
+Minerva
+minestrone
+minesweep
+minesweeper
+Ming
+mingle
+mini
+miniature
+minim
+minima
+minimal
+minimax
+minimum
+minion
+minister
+ministerial
+ministration
+ministry
+miniver
+mink
+Minneapolis
+Minnesota
+Minnie
+minnow
+Minoan
+minor
+Minos
+Minotaur
+Minsky
+minstrel
+minstrelsy
+mint
+minuend
+minuet
+minus
+minuscule
+minute
+minutia
+minutiae
+minx
+Miocene
+Mira
+miracle
+miraculous
+mirage
+Miranda
+mire
+Mirfak
+Miriam
+mirror
+mirth
+MIRV
+miry
+misanthrope
+miscegenation
+miscellanea
+miscellaneous
+miscellany
+mischievous
+miscible
+miscreant
+miser
+miserable
+misericord
+misery
+mishmash
+misnomer
+misogamy
+misogynic
+misogynist
+misogynous
+misogyny
+misprision
+mispronunciation
+miss
+missal
+misshapen
+missile
+missileer
+missilery
+mission
+missionary
+Mississippi
+Mississippian
+Missoula
+Missouri
+Missy
+mist
+mistletoe
+mistral
+misutilize
+MIT
+Mitchell
+mite
+miter
+MITI
+miticide
+mitigate
+mitochondria
+mitosis
+mitral
+Mitsubishi
+mitt
+mitten
+mitzvah
+mix
+mixture
+mixup
+Mizar
+mizzen
+mizzenmast
+MN
+mnemonic
+MO
+moa
+moan
+moat
+mob
+Mobil
+mobile
+mobility
+mobocracy
+mobster
+moccasin
+mocha
+mock
+mockery
+mockingbird
+mockup
+modal
+mode
+model
+modem
+moderacy
+moderate
+moderato
+modern
+modest
+Modesto
+modesty
+modicum
+modify
+modish
+modular
+modulate
+module
+moduli
+modulo
+modulus
+modus
+Moe
+Moen
+Mogadiscio
+mogul
+mohair
+Mohammed
+Mohammedan
+Mohawk
+Mohican
+Mohr
+moiety
+Moines
+Moira
+moire
+Moiseyev
+moist
+moisten
+moisture
+Mojave
+mola
+molal
+molar
+molasses
+mold
+moldboard
+Moldova
+mole
+molecular
+molecule
+molehill
+moleskin
+molest
+molestation
+Moliere
+Moline
+moll
+mollify
+mollusc
+molluscan
+mollusk
+Molly
+mollycoddle
+Moloch
+molt
+molten
+molto
+Moluccas
+molybdate
+molybdenite
+molybdenum
+mom
+moment
+momenta
+momentary
+momentous
+momentum
+mommy
+Mon.
+Mona
+Monaco
+monad
+monadic
+monadnock
+monarch
+monarchial
+monarchic
+monarchs
+monarchy
+monasterial
+monastery
+monastic
+monatomic
+monaural
+Monday
+monel
+monetarism
+monetarist
+monetary
+money
+moneybags
+moneylender
+monger
+Mongol
+Mongolia
+mongolism
+Mongoloid
+mongoose
+mongrel
+Monica
+monicker
+monied
+monies
+moniker
+monism
+monist
+monitor
+monk
+monkey
+monkeyflower
+monkeyshine
+monkish
+Monmouth
+Monoceros
+monochromatic
+monochromator
+monocle
+monocotyledon
+monocular
+monogamous
+monogamy
+monogynous
+monogyny
+monolith
+monologist
+monologue
+monomer
+monomeric
+monomial
+Monongahela
+mononucleosis
+monophony
+monopoly
+monotheism
+monotheist
+monotonous
+monoxide
+Monroe
+Monrovia
+Mons
+Monsanto
+monsieur
+monsignor
+monsoon
+monster
+monstrosity
+monstrous
+Mont
+montage
+Montague
+Montana
+Montclair
+monte
+Montenegrin
+Monterey
+Monteverdi
+Montevideo
+Montgomery
+month
+Monticello
+Montmartre
+Montpelier
+Montrachet
+Montreal
+Monty
+monument
+moo
+mooch
+mood
+moon
+moonbeam
+Mooney
+moonlet
+moonlight
+moonlit
+moonrise
+moonscape
+moonset
+moonshine
+moonstone
+moonstruck
+moor
+moorage
+Moore
+Moorish
+moose
+moot
+mop
+mope
+moppet
+moraine
+moral
+morale
+Moran
+morass
+moratorium
+Moravia
+morbid
+mordant
+more
+morel
+Moreland
+moreover
+Moresby
+Morgan
+morganatic
+morgue
+Moriarty
+moribund
+Morley
+Mormon
+morn
+Moroccan
+morocco
+moron
+moronic
+morose
+morph
+morpheme
+morphemic
+morphine
+morphogenesis
+morphogenetic
+morphology
+morphophonemic
+Morrill
+morris
+Morrison
+Morrissey
+Morristown
+morrow
+Morse
+morsel
+mort
+mortal
+mortar
+mortarboard
+mortem
+mortgage
+mortgagee
+mortgagor
+mortician
+mortify
+Mortimer
+mortise
+Morton
+mortuary
+mosaic
+Moscow
+Moser
+Moses
+Moslem
+mosque
+mosquito
+mosquitoes
+moss
+mossback
+most
+mot
+mote
+motel
+motet
+moth
+mothball
+mother
+motherland
+motif
+motile
+motion
+motivate
+motley
+motoneuron
+motor
+motorboat
+motorcade
+motorcar
+motorcycle
+Motorola
+mottle
+motto
+mottoes
+Moulton
+mound
+mount
+mountain
+mountaineer
+mountainous
+mountainside
+mountaintop
+mountebank
+Mountie
+mourn
+mouse
+mousse
+moustache
+mouth
+mouthpiece
+mouthwash
+Mouton
+move
+movie
+mow
+mown
+moxie
+Moyer
+Mozambique
+Mozart
+mozzarella
+MPH
+Mr.
+Mrs.
+Ms.
+m's
+Mt.
+mu
+much
+mucilage
+mucilaginous
+muck
+muckrake
+mucosa
+mucous
+mucus
+mud
+Mudd
+muddle
+muddlehead
+muddy
+mudguard
+mudslide
+mudsling
+Mueller
+Muenster
+muezzin
+muff
+muffin
+muffle
+mufti
+mug
+mugwump
+Muir
+Mukden
+mukluk
+mulatto
+mulattoes
+mulberry
+mulch
+mulct
+mule
+mulish
+mull
+mullah
+mullein
+mullen
+mullet
+mulligan
+mulligatawny
+mullion
+multi
+multifarious
+multiformity
+multimedia
+multinomial
+multiphasic
+multiple
+multiplet
+multiplex
+multiplexor
+multipliable
+multiplicable
+multiplicand
+multiplication
+multiplicity
+multiply
+multitude
+multitudinous
+mum
+mumble
+mumbo
+Mumford
+mummify
+mummy
+mumps
+munch
+Muncie
+mundane
+mung
+Munich
+municipal
+munificent
+munition
+Munson
+muon
+Muong
+mural
+murder
+murderess
+murderous
+muriatic
+Muriel
+murine
+murk
+murmur
+murmurous
+Murphy
+Murray
+murre
+muscat
+muscatel
+muscle
+muscovite
+Muscovy
+muscular
+musculature
+muse
+musette
+museum
+mush
+mushroom
+music
+musicale
+musician
+musicology
+musk
+Muskegon
+muskellunge
+musket
+musketeer
+musketry
+muskmelon
+muskoxen
+muskrat
+Muslim
+muslin
+muss
+mussel
+must
+mustache
+mustachio
+mustang
+mustard
+mustn't
+mutagen
+mutagenic
+mutandis
+mutant
+mutate
+mutatis
+mute
+mutilate
+mutineer
+mutinous
+mutiny
+mutt
+mutter
+mutton
+mutual
+mutuel
+Muzak
+muzhik
+Muzo
+muzzle
+muzzy
+my
+Myanmar
+mycelium
+Mycenae
+Mycenaean
+mycology
+mycophagous
+myeline
+myeloid
+Myers
+mylar
+mynah
+Mynheer
+myocardial
+myocardium
+myoglobin
+myopia
+myopic
+myosin
+Myra
+myriad
+myrmidon
+Myrna
+Myron
+myrrh
+myrtle
+myself
+mysterious
+mystery
+mystic
+mystify
+mystique
+myth
+mythic
+mythologize
+mythology
+mythopoeic
+myxomatosis
+NAACP
+nab
+Nabisco
+nabla
+nabob
+nacelle
+nacho
+nacreous
+Nadia
+Nadine
+nadir
+nag
+Nagasaki
+Nagoya
+Nagy
+Nahum
+naiad
+nail
+Nair
+Nairobi
+naive
+naivete
+naked
+Nam
+name
+nameable
+nameplate
+namesake
+Namibia
+Nan
+Nancy
+Nanette
+Nanking
+nanny
+Nantucket
+Naomi
+nap
+napalm
+nape
+naphtha
+naphthalene
+napkin
+Naples
+napoleon
+Napoleonic
+Narbonne
+narcissism
+narcissist
+narcissus
+narcolepsy
+narcoleptic
+narcosis
+narcotic
+narcotize
+nares
+Narragansett
+narrate
+narrow
+narrowish
+narthex
+narwhal
+nary
+NASA
+nasal
+nascent
+Nash
+Nashua
+Nashville
+Nassau
+nasturtium
+nasty
+Nat
+natal
+Natalie
+natation
+natatorium
+natatory
+Natchez
+Nathan
+Nathaniel
+nation
+nationwide
+NATO
+natter
+natty
+natural
+nature
+naturopath
+naturopathy
+naught
+naughty
+nausea
+nauseate
+nauseous
+nauseum
+nautical
+nautilus
+Navajo
+naval
+nave
+navel
+navigable
+navigate
+navvy
+navy
+nay
+naysay
+Nazarene
+Nazareth
+nazi
+nazify
+Naziism
+Nazism
+N.B.
+NBA
+NBC
+NBS
+NC
+NCAA
+NCAR
+NCR
+ND
+Ndjamena
+NE
+Neal
+Neanderthal
+neap
+Neapolitan
+near
+nearby
+nearsighted
+neat
+neath
+Nebraska
+Nebuchadnezzar
+nebula
+nebulae
+nebular
+nebulize
+nebulosity
+nebulous
+necessary
+necessitate
+necessity
+neck
+neckerchief
+neckerchieves
+necklace
+neckline
+necktie
+necrology
+necromancer
+necromancy
+necromantic
+necrophagous
+necrophilia
+necropolis
+necropsy
+necrosis
+necrotic
+nectar
+nectarine
+Ned
+nee
+need
+Needham
+needle
+needlecraft
+needlepoint
+needlework
+needn't
+ne'er
+nefarious
+Neff
+negate
+neglect
+negligee
+negligent
+negligible
+negotiable
+negotiant
+negotiate
+Negress
+Negro
+Negroes
+negroid
+negrophile
+negrophobe
+Nehemiah
+Nehru
+neigh
+neighbor
+Neil
+neither
+Nell
+Nellie
+Nelsen
+nelson
+nematode
+nemeses
+nemesis
+Neocene
+neoclassic
+neoconservative
+neodymium
+neoliberal
+neolithic
+neologism
+neology
+neomycin
+neon
+neonatal
+neonate
+neonatology
+neoorthodox
+neoorthodoxy
+neophyte
+neoprene
+neotenic
+neoteny
+Nepal
+Nepali
+nepenthe
+nephew
+nepotism
+Neptune
+Neptunian
+neptunium
+nerd
+nereid
+Nero
+nerve
+nervous
+Ness
+nest
+nestle
+Nestor
+Nestorian
+net
+nether
+Netherlands
+netherworld
+nettle
+nettlesome
+network
+Neumann
+neural
+neuralgia
+neuralgic
+neurally
+neurasthenia
+neurasthenic
+neuritis
+neurology
+neuron
+neuronal
+neuroses
+neurosis
+neurotic
+neuter
+neutral
+neutrino
+neutron
+Neva
+Nevada
+never
+nevermore
+nevertheless
+Nevins
+new
+Newark
+Newbold
+newborn
+Newbury
+Newcastle
+newcomer
+newel
+Newell
+newfangled
+newfound
+Newfoundland
+newish
+newlywed
+Newman
+Newport
+news
+newsboy
+newsbreak
+newscast
+newsletter
+newsmonger
+newspaper
+newsprint
+newsreel
+newsroom
+newsstand
+Newsweek
+newsworthy
+newsy
+newt
+newton
+Newtonian
+next
+nexus
+NFL
+Nguyen
+NH
+NHL
+niacin
+Niagara
+Niamey
+nib
+nibble
+Nibelung
+niblick
+nibs
+Nicaragua
+nice
+Nicene
+nicety
+niche
+Nicholas
+Nicholls
+Nichols
+Nicholson
+nichrome
+nick
+nickel
+nickelodeon
+nickname
+Nicodemus
+Nicole
+Nicosia
+nicotine
+niece
+niello
+Nielsen
+Nielson
+Nietzsche
+nifty
+Niger
+Nigeria
+niggard
+niggardly
+nigger
+niggle
+nigh
+night
+nightcap
+nightclothes
+nightclub
+nightdress
+nightfall
+nightgown
+nighthawk
+nightingale
+nightjar
+nightlong
+nightmare
+nightmarish
+nightshade
+nightshirt
+nightstick
+nighttime
+nightwalker
+NIH
+nihilism
+nihilist
+Nike
+Nikkei
+Nikko
+Nikolai
+Nikon
+nil
+Nile
+nilpotent
+nim
+nimble
+nimbostratus
+nimbus
+NIMH
+Nimrod
+Nina
+nincompoop
+nine
+ninefold
+ninepence
+ninepin
+nineteen
+nineteenth
+ninetieth
+ninety
+Nineveh
+ninny
+ninth
+Niobe
+niobium
+nip
+nipple
+Nippon
+Nipponese
+nirvana
+nisei
+Nissan
+NIST
+nit
+nitpick
+nitrate
+nitric
+nitride
+nitrify
+nitrite
+nitrobenzene
+nitrocellulose
+nitrogen
+nitrogenous
+nitroglycerine
+nitrosamine
+nitrous
+nitty
+nitwit
+nix
+Nixon
+nizam
+NJ
+NM
+NNE
+NNW
+no
+NOAA
+Noah
+nob
+Nobel
+nobelium
+noble
+noblesse
+nobody
+nobody'd
+nocturnal
+nocturne
+nod
+nodal
+node
+nodular
+nodule
+Noel
+noetic
+nog
+noggin
+noise
+noisomely
+Nolan
+Noll
+nolo
+nomad
+nomadic
+nomenclature
+nomenklatura
+nominal
+nominate
+nominee
+nomograph
+nomography
+non
+nonagenarian
+nonagon
+nonce
+nonchalant
+noncom
+nondescript
+none
+nonesuch
+nonetheless
+nonfeasance
+nonpareil
+nonplus
+nonsensical
+noodle
+nook
+noon
+noonday
+noontide
+noontime
+noose
+nor
+Nora
+Norbert
+Nordhoff
+Nordic
+Nordstrom
+Noreen
+norepinephrine
+Norfolk
+noria
+norm
+Norma
+normal
+normalcy
+Norman
+Normandy
+normative
+Norris
+Norse
+north
+Northampton
+northbound
+northeast
+northeastern
+northeastward
+northerly
+northern
+northernmost
+northland
+northmost
+Northrop
+Northrup
+Northumberland
+northward
+northwest
+northwestern
+northwestward
+Norton
+Norwalk
+Norway
+Norwegian
+Norwich
+nose
+nosebag
+nosebleed
+nosedive
+nosegay
+nosepiece
+nosh
+nostalgia
+nostalgic
+Nostradamus
+Nostrand
+nostril
+nostrum
+not
+notarial
+notarize
+notary
+notate
+notch
+note
+notebook
+noteworthy
+nothing
+notice
+noticeable
+notify
+notion
+notoriety
+notorious
+Nottingham
+notwithstanding
+Nouakchott
+nougat
+noun
+nourish
+nouveau
+Nov.
+nova
+Novak
+novel
+novelette
+novella
+novelty
+November
+novena
+novice
+novitiate
+novo
+Novosibirsk
+now
+nowadays
+nowhere
+nowise
+noxious
+nozzle
+NRA
+NRC
+n's
+NSA
+NSF
+NTIS
+nu
+nuance
+nub
+nubbin
+nubble
+nubbly
+Nubia
+nubile
+nubility
+nucleant
+nuclear
+nucleate
+nuclei
+nucleic
+nucleoli
+nucleolus
+nucleon
+nucleonic
+nucleoplasm
+nucleoprotein
+nucleoside
+nucleotide
+nucleus
+nuclide
+nude
+nudge
+nugatory
+nugget
+nuisance
+nuisancy
+nuke
+null
+nullify
+numb
+number
+numbly
+numbskull
+numerable
+numeral
+numerate
+numeric
+Numerische
+numerology
+numerous
+numinous
+numismatic
+numismatist
+nun
+nuncio
+nunnery
+nuptial
+nurse
+nursemaid
+nursery
+nurserymaid
+nursling
+nurture
+nut
+nutant
+nutate
+nutcrack
+nuthatch
+nutmeg
+nutpick
+nutria
+nutrient
+nutriment
+nutrition
+nutritious
+nutshell
+nuzzle
+NV
+NW
+NWT
+NY
+N.Y.C.
+NYC
+nylon
+nymph
+nymphomania
+NYPD
+Nyquist
+NYSE
+NYU
+NZ
+oaf
+oafish
+Oahu
+oak
+oaken
+Oakland
+Oakley
+oakum
+oakwood
+oar
+oarlock
+oars
+oases
+oasis
+oat
+oath
+oatmeal
+Obadiah
+obbligato
+obduracy
+obdurate
+obedient
+obeisant
+obelisk
+Oberlin
+Oberon
+obese
+obey
+obfuscate
+obi
+obit
+obituary
+object
+objectify
+objectivity
+objet
+oblate
+obligate
+oblige
+obligee
+obligor
+oblique
+obliterate
+oblivion
+oblivious
+oblong
+obloquy
+obnoxious
+oboe
+oboist
+O'Brien
+obscene
+obscurant
+obscuration
+obscure
+obsequious
+obsequy
+observant
+observation
+observatory
+observe
+obsess
+obsession
+obsidian
+obsolesce
+obsolescent
+obsolete
+obstacle
+obstetric
+obstetrician
+obstinacy
+obstinate
+obstreperous
+obstruct
+obtain
+obtrude
+obtrusion
+obtuse
+obverse
+obviate
+obvious
+ocarina
+occasion
+occident
+occidental
+occipital
+occiput
+occlude
+occlusion
+occult
+occultation
+occupant
+occupation
+occupy
+occur
+occurrent
+ocean
+oceanarium
+oceangoing
+Oceania
+oceanic
+oceanography
+oceanside
+ocelli
+ocelot
+ocher
+o'clock
+O'Connell
+O'Connor
+Oct.
+octagon
+octagonal
+octahedra
+octahedral
+octahedron
+octal
+octameter
+octane
+octant
+octave
+Octavia
+octavo
+octennial
+octet
+octile
+octillion
+October
+octogenarian
+octopod
+octopus
+octoroon
+ocular
+oculist
+odd
+oddball
+oddment
+ode
+O'Dell
+Odessa
+odeum
+Odin
+odious
+odium
+Odom
+odometer
+O'Donnell
+odor
+odorant
+odoriferous
+odorous
+O'Dwyer
+Odysseus
+odyssey
+Oedipal
+Oedipus
+oenology
+o'er
+oersted
+oestrous
+oeuvre
+of
+off
+offal
+offbeat
+Offenbach
+offend
+offense
+offensive
+offer
+offertory
+offhand
+office
+officeholder
+officemate
+official
+officialdom
+officiate
+officio
+officious
+offload
+offprint
+offset
+offshoot
+offshore
+offspring
+offstage
+oft
+often
+oftentimes
+ofttimes
+Ogden
+ogee
+ogle
+ogre
+ogress
+oh
+O'Hare
+Ohio
+ohm
+ohmic
+ohmmeter
+oil
+oilcloth
+oilseed
+oilskin
+oilstone
+oily
+oink
+ointment
+OK
+okapi
+Okay
+OK'd
+Okinawa
+Oklahoma
+okra
+Olaf
+old
+olden
+Oldenburg
+oldie
+oldish
+Oldsmobile
+oldster
+oldy
+oleaginous
+oleander
+O'Leary
+olefin
+olefinic
+oleo
+oleomargarine
+olfaction
+olfactory
+Olga
+oligarch
+oligarchic
+oligarchs
+oligarchy
+Oligocene
+oligoclase
+oligopoly
+Olin
+olive
+Oliver
+Olivetti
+Olivia
+olivine
+Ollie
+Olsen
+Olson
+Olympia
+olympiad
+Olympic
+Olympus
+Omaha
+Oman
+omasum
+ombuds
+omega
+omelet
+omelette
+omen
+omicron
+ominous
+omission
+omit
+omnibus
+omnidirectional
+omnipotent
+omnipresent
+omnirange
+omniscient
+omnivore
+omnivorous
+on
+once
+oncology
+oncoming
+one
+Oneida
+O'Neil
+oneness
+onerous
+oneself
+onetime
+oneupmanship
+ongoing
+onion
+onionskin
+onlook
+only
+onomatopoeia
+onomatopoeic
+onomatopoetic
+Onondaga
+onrush
+onrushing
+onset
+onshore
+onslaught
+Ont.
+Ontario
+onto
+ontogenetic
+ontogeny
+ontology
+onus
+onward
+onyx
+oodles
+oolong
+oomph
+oops
+ooze
+op.
+opacity
+opal
+opalescent
+opaline
+opaque
+OPEC
+Opel
+open
+openhanded
+openhearted
+openmouthed
+openwork
+opera
+operable
+operago
+operand
+operant
+operate
+operatic
+operculum
+operetta
+Ophelia
+Ophiucus
+ophthalmic
+ophthalmology
+opiate
+opine
+opinion
+opinionated
+opium
+opossum
+Oppenheimer
+opponent
+opportune
+oppose
+opposite
+opposition
+oppress
+oppression
+oppressor
+opprobrious
+opprobrium
+opt
+optative
+optic
+optician
+optima
+optimal
+optimism
+optimist
+optimistic
+optimize
+optimum
+optoacoustic
+optoelectronic
+optoisolate
+optometrist
+optometry
+opulent
+opus
+opuscule
+or
+oracle
+oracular
+oral
+orange
+orangeade
+orangeroot
+orangery
+orangish
+orangutan
+orate
+oratorical
+oratorio
+oratory
+orb
+orbicular
+orbit
+orbital
+orchard
+orchestra
+orchestral
+orchestrate
+orchid
+orchis
+ordain
+ordeal
+order
+orderly
+ordinal
+ordinance
+ordinary
+ordinate
+ordnance
+Ordovician
+ordure
+ore
+oregano
+Oregon
+Oresteia
+Orestes
+organ
+organdy
+organic
+organismic
+organometallic
+orgasm
+orgiastic
+orgy
+orient
+oriental
+orientation
+orientations
+orienteer
+orifice
+origami
+origin
+original
+originate
+Orin
+Orinoco
+oriole
+Orion
+Orionid
+orison
+Orkney
+Orlando
+Orleans
+Orlon
+ormolu
+ornament
+ornamentation
+ornate
+ornately
+ornery
+ornithology
+orogenesis
+orogenic
+orogeny
+orography
+Orono
+orotund
+orphan
+orphanage
+Orpheus
+Orphic
+Orr
+orrery
+Ortega
+orthant
+orthicon
+ortho
+orthoclase
+orthodontic
+orthodontist
+orthodox
+orthodoxy
+orthogonal
+orthography
+orthonormal
+orthopedic
+orthophosphate
+orthorhombic
+orthotropic
+Ortiz
+Orville
+Orwell
+Orwellian
+oryx
+o's
+Osaka
+Osborn
+Osborne
+Oscar
+oscillate
+oscillograph
+oscillography
+oscilloscope
+osculate
+Osgood
+OSHA
+O'Shea
+Oshkosh
+osier
+Osiris
+Oslo
+osmium
+osmosis
+osmotic
+osprey
+osseous
+ossify
+ossuary
+ostensible
+ostensive
+ostentation
+ostentatious
+osteology
+osteomyelitis
+osteopath
+osteopathic
+osteoporosis
+ostracism
+ostracize
+ostracod
+Ostrander
+ostrich
+O'Sullivan
+Oswald
+Othello
+other
+otherness
+otherwise
+otherworld
+otherworldly
+otic
+otiose
+Otis
+Ott
+Ottawa
+otter
+Otto
+Ouagadougou
+ouch
+ought
+oughtn't
+Ouija
+ounce
+our
+ours
+ourselves
+oust
+out
+outermost
+outlandish
+outlaw
+outlawry
+outlier
+outpace
+outrageous
+outrance
+outshine
+outvote
+ouzel
+ouzo
+ova
+oval
+ovarian
+ovary
+ovate
+oven
+ovenbird
+over
+overhang
+overt
+overture
+Ovid
+oviduct
+oviform
+ovine
+oviparous
+ovipositor
+ovoid
+ovular
+ovulate
+ovum
+owe
+Owen
+Owens
+owing
+owl
+owlet
+owlish
+own
+ox
+oxalate
+oxalic
+oxbow
+Oxbridge
+oxcart
+oxen
+oxeye
+oxford
+oxidant
+oxidase
+oxidate
+oxide
+Oxnard
+oxtail
+oxygen
+oxygenate
+oxygenic
+oxymoron
+oxymoronic
+oyez
+oyster
+Ozark
+ozone
+pa
+Pablo
+Pabst
+PAC
+paca
+pace
+paceset
+pachyderm
+pachysandra
+pacific
+pacifism
+pacifist
+pacify
+pack
+package
+Packard
+packet
+packsack
+packsaddle
+pact
+pad
+paddle
+paddock
+paddy
+padlock
+padre
+paean
+pagan
+page
+pageant
+pageantry
+pageboy
+paginate
+pagoda
+paid
+pail
+pain
+Paine
+painstaking
+paint
+paintbrush
+pair
+pairwise
+paisley
+pajama
+Pakistan
+Pakistani
+pal
+palace
+paladin
+palanquin
+palatal
+palate
+palatial
+palatine
+palaver
+palazzi
+palazzo
+pale
+paleface
+paleobotany
+Paleocene
+paleography
+Paleolithic
+paleontology
+Paleozoic
+Palermo
+Palestine
+Palestinian
+palette
+palfrey
+palimpsest
+palindrome
+palindromic
+palisade
+pall
+palladia
+Palladian
+palladium
+Pallas
+pallbearer
+pallet
+palliate
+pallid
+pallor
+palm
+palmate
+palmetto
+palmistry
+Palmolive
+Palmyra
+Palo
+Palomar
+palomino
+palp
+palpable
+palpate
+palpitant
+palpitate
+palsy
+paltry
+Pam
+Pamela
+pampa
+pamper
+pamphlet
+pamphleteer
+pan
+panacea
+panache
+panama
+Panamanian
+panatela
+pancake
+Pancho
+panchromatic
+pancreas
+pancreatic
+panda
+Pandanus
+pandemic
+pandemonium
+pander
+Pandora
+pane
+panegyric
+panegyrist
+panel
+pang
+panhandle
+panic
+panicked
+panicking
+panicky
+panicle
+panjandrum
+panky
+pannier
+panoply
+panorama
+panoramic
+pansy
+pant
+pantaloon
+pantheism
+pantheist
+pantheon
+panther
+pantograph
+pantomime
+pantomimic
+pantry
+panty
+pantywaist
+panzer
+Paoli
+pap
+papa
+papacy
+papal
+papaw
+papaya
+paper
+paperback
+paperboard
+paperbound
+paperhang
+paperweight
+paperwork
+papery
+papillary
+papist
+papistry
+papoose
+Pappas
+pappy
+paprika
+Papua
+papyri
+papyrus
+par
+para
+parabola
+parabolic
+paraboloid
+parachute
+parade
+paradigm
+paradigmatic
+paradise
+paradisiac
+paradox
+paradoxic
+paraffin
+paragon
+Paraguay
+parakeet
+paralinguistic
+parallax
+parallel
+parallelepiped
+parallelism
+parallelogram
+paralytic
+paralyze
+Paramaribo
+paramecium
+parametrize
+paramour
+Paramus
+paranoia
+paranoid
+parapet
+paraphernalia
+paraplegia
+paraplegic
+parasite
+parasitology
+parasol
+parathion
+paraxial
+parboil
+parcel
+parch
+pardner
+pardon
+pare
+paregoric
+parent
+parentage
+parental
+parentheses
+parenthesis
+parenthesize
+parenthetic
+Pareto
+parfait
+pariah
+paribus
+parietal
+parimutuel
+Paris
+parish
+parishioner
+Parisian
+parity
+park
+parka
+Parke
+Parkinson
+parkinsonism
+parkland
+parkway
+parlance
+parlay
+parley
+parliament
+parliamentarian
+parliamentary
+parlor
+parlous
+Parmesan
+parochial
+parodist
+parody
+parole
+parolee
+paroxysm
+parquet
+Parr
+parricide
+Parrish
+parrot
+parry
+parse
+parsec
+Parsifal
+parsimonious
+parsimony
+parsley
+parsnip
+parson
+parsonage
+part
+partake
+parterre
+Parthenon
+partial
+participant
+participate
+participial
+participle
+particle
+particular
+particulate
+partisan
+partita
+partition
+partner
+partook
+partridge
+parturition
+party
+partygo
+parvenu
+Pasadena
+Pascal
+paseo
+pasha
+Paso
+pass
+passage
+passageway
+Passaic
+passbook
+passe
+passel
+passenger
+passerby
+passerine
+passeth
+passion
+passionate
+passivate
+passkey
+Passover
+passport
+password
+past
+pasta
+paste
+pasteboard
+pastel
+pasteup
+Pasteur
+pasteurize
+pastiche
+pastime
+pastor
+pastoral
+pastorale
+pastorate
+pastrami
+pastry
+pasturage
+pasture
+pat
+Patagonia
+patch
+patchwork
+pate
+Patel
+patent
+patentee
+paterfamilias
+paternal
+paternity
+paternoster
+Paterson
+path
+pathetic
+pathfind
+pathogen
+pathogenesis
+pathogenic
+pathology
+pathos
+pathway
+patient
+patina
+patio
+patois
+patriarch
+patriarchal
+patriarchate
+patriarchs
+patriarchy
+Patrice
+Patricia
+patrician
+patricidal
+patricide
+Patrick
+patrilineal
+patrimonial
+patrimony
+patriot
+patriotic
+patristic
+patrol
+patron
+patronage
+patroness
+patronymic
+patsy
+patter
+pattern
+Patterson
+Patti
+Patton
+patty
+paucity
+Paul
+Paula
+Paulette
+Pauli
+Pauline
+Paulo
+Paulsen
+Paulson
+Paulus
+paunch
+pauper
+pause
+pavane
+pave
+pavilion
+Pavlov
+Pavlovian
+paw
+pawl
+pawn
+pawnbroker
+pawnshop
+pawpaw
+Pawtucket
+pax
+pay
+payback
+paycheck
+payday
+payee
+payload
+paymaster
+Payne
+payoff
+payola
+payout
+payroll
+Paz
+PBS
+PDQ
+pea
+Peabody
+peace
+peaceable
+peacetime
+peach
+Peachtree
+peacock
+peafowl
+peahen
+peak
+peal
+Peale
+peanut
+pear
+Pearce
+pearl
+Pearson
+peasant
+peasantry
+Pease
+peashooter
+peat
+peavy
+pebble
+pecan
+peccable
+peccadillo
+peccadilloes
+peccary
+peck
+Pecos
+pectin
+pectoral
+peculate
+peculiar
+pecuniary
+pedagogic
+pedagogue
+pedagogy
+pedal
+pedant
+pedantic
+pedantry
+peddle
+pederast
+pedestal
+pedestrian
+pediatric
+pediatrician
+pedicab
+pedicure
+pedigree
+pediment
+pedlar
+pedometer
+Pedro
+pee
+peed
+peek
+peekaboo
+peel
+peen
+peep
+peephole
+peer
+peerage
+peeress
+peeve
+peevish
+peewee
+peg
+Pegasus
+pegboard
+Peggy
+pegmatite
+PEI
+pejorative
+Peking
+Pekingese
+pekoe
+pelagic
+Pelham
+pelican
+pellagra
+pellet
+pellucid
+pelt
+peltry
+pelvic
+pelvis
+Pembroke
+pemmican
+pen
+Pena
+penal
+penalty
+penance
+penates
+pence
+penchant
+pencil
+pendant
+pending
+pendulous
+pendulum
+Penelope
+peneplain
+peneplane
+penetrable
+penetrant
+penetrate
+penguin
+Penh
+penholder
+penicillin
+peninsula
+peninsular
+penis
+penitent
+penitential
+penitentiary
+penknife
+Penn
+penna
+pennant
+Pennington
+pennon
+Pennsylvania
+penny
+pennyroyal
+pennyweight
+penology
+Penrose
+Pensacola
+pension
+penstock
+pent
+pentad
+pentagon
+pentagonal
+pentagram
+pentameter
+pentane
+Pentateuch
+pentathlon
+Pentecost
+pentecostal
+penthouse
+penult
+penultimate
+penumbra
+penumbral
+penurious
+penury
+peon
+peonage
+peony
+people
+Peoria
+pep
+pepper
+peppercorn
+peppergrass
+peppermint
+pepperoni
+peppery
+Pepsi
+PepsiCo
+peptic
+peptide
+peptize
+per
+peradventure
+perambulate
+percale
+perceivable
+perceive
+percent
+percentage
+percentile
+percept
+perceptible
+perceptual
+perch
+perchance
+perchlorate
+Percival
+percolate
+percussion
+Percy
+perdition
+perdurable
+peregrinate
+peregrine
+peremptory
+perennial
+perestroika
+Perez
+perfect
+perfecta
+perfectible
+perfervid
+perfidious
+perfidy
+perforate
+perforce
+perform
+performance
+perfume
+perfumery
+perfunctory
+perfuse
+perfusion
+Pergamon
+pergola
+perhaps
+Periclean
+Pericles
+perigee
+perihelion
+peril
+Perilla
+perilous
+perimeter
+period
+periodic
+periodontic
+periodontist
+peripatetic
+peripheral
+periphery
+periphrastic
+periscope
+perish
+peristyle
+peritectic
+peritoneal
+periwig
+periwinkle
+perjure
+perjury
+perk
+Perkins
+Perle
+perlite
+permafrost
+permalloy
+permanent
+permeable
+permeance
+permeate
+Permian
+permissible
+permission
+permit
+permittivity
+permutation
+permute
+pernicious
+pernickety
+Pernod
+perorate
+peroxide
+perpendicular
+perpetrate
+perpetual
+perpetuate
+perpetuity
+perplex
+perquisite
+Perry
+persecute
+persecutor
+Perseid
+Persephone
+Perseus
+perseverance
+persevere
+Pershing
+Persia
+Persian
+persiflage
+persimmon
+persist
+persistent
+persnickety
+person
+persona
+personae
+personage
+personal
+personify
+personnel
+perspective
+perspicacious
+perspicacity
+perspicuity
+perspicuous
+perspiration
+perspire
+persuade
+persuasion
+pert
+pertain
+Perth
+pertinacious
+pertinacity
+pertinent
+perturb
+perturbation
+Peru
+perusal
+peruse
+Peruvian
+pervade
+pervasion
+perverse
+perversion
+pervert
+pervious
+peseta
+pesky
+peso
+pessimal
+pessimism
+pessimist
+pessimum
+pest
+pesticide
+pestiferous
+pestilent
+pestilential
+pestle
+pet
+petal
+petard
+Pete
+peter
+Petersburg
+Petersen
+Peterson
+petiole
+petit
+petite
+petition
+petrel
+petri
+petrifaction
+petrify
+petrochemical
+petroglyph
+petrography
+petrol
+petrolatum
+petroleum
+petrology
+petticoat
+pettifog
+pettifoggery
+pettish
+petulant
+petunia
+Peugeot
+pew
+pewter
+peyote
+pfennig
+Pfizer
+phaeton
+phage
+phagocyte
+phalange
+phalanx
+phalarope
+phallic
+phallus
+phantasm
+phantasy
+phantom
+pharaoh
+pharaonic
+pharisaic
+pharisee
+pharmaceutic
+pharmacist
+pharmacology
+pharmacopoeia
+pharmacy
+pharyngeal
+pharynx
+phase
+phasor
+PhD
+pheasant
+Phelps
+phenobarbital
+phenol
+phenolic
+phenomena
+phenomenal
+phenomenology
+phenomenon
+phenotype
+phenotypic
+phenyl
+pheromone
+phi
+phial
+Phil
+Philadelphia
+philander
+philanthropic
+philanthropist
+philanthropy
+philatelic
+philatelist
+philately
+Philemon
+philharmonic
+Philip
+Philippian
+philippic
+Philippine
+philistine
+Phillip
+Phillips
+philodendron
+philology
+Philomena
+philosopher
+philosophic
+philosophize
+philosophy
+philter
+Phipps
+phlebitis
+phlebotomist
+phlebotomy
+phlegm
+phlegmatic
+phloem
+phlogiston
+phlox
+phobia
+phobic
+phoebe
+Phoebus
+Phoenicia
+phoenix
+phon
+phone
+phoneme
+phonemic
+phonetic
+phonetician
+phonic
+phonograph
+phonology
+phonon
+phosgene
+phosphate
+phosphene
+phosphide
+phosphine
+phosphor
+phosphoresce
+phosphorescent
+phosphoric
+phosphorus
+phosphorylate
+photo
+photogenic
+photogrammetry
+photography
+photolysis
+photolytic
+photolyze
+photon
+photonic
+photostat
+photosynthesize
+phrasal
+phrase
+phraseology
+phrenology
+phthalate
+phthisis
+phyla
+phyletic
+Phyllis
+phyllotaxis
+phylogenetic
+phylogeny
+phylum
+physic
+physician
+Physik
+physiochemical
+physiognomy
+physiography
+physiology
+physiotherapist
+physiotherapy
+physique
+phytology
+phytoplankton
+phytotoxic
+phytotoxin
+pi
+pianissimo
+pianist
+piano
+pianoforte
+piaster
+piazza
+pica
+picador
+picalilli
+picaresque
+Picasso
+picayune
+Piccadilly
+piccolo
+pick
+pickaninny
+pickax
+pickaxe
+pickerel
+Pickering
+picket
+Pickett
+Pickford
+pickle
+Pickman
+pickoff
+pickpocket
+pickup
+picnic
+picnicked
+picnicker
+picnicking
+picogram
+Pict
+pictograph
+pictographic
+pictorial
+picture
+picturesque
+piddle
+pidgin
+pie
+piebald
+piece
+piecemeal
+piecewise
+piecework
+piedmont
+pier
+pierce
+Pierre
+Pierrot
+Pierson
+pieta
+pietism
+pietist
+pietistic
+piety
+piezoelectric
+piffle
+pig
+pigeon
+pigeonfoot
+pigeonhole
+piggish
+piggledy
+piggyback
+pigheaded
+piglet
+pigment
+pigmentary
+pigmentation
+pigmy
+pigpen
+pigroot
+pigskin
+pigstick
+pigsty
+pigtail
+pike
+pilaf
+pilaster
+Pilate
+pile
+pileate
+pileup
+pilfer
+pilferage
+pilgrim
+pilgrimage
+pill
+pillage
+pillar
+pillory
+pillow
+pillowcase
+Pillsbury
+pilot
+pimento
+pimiento
+pimp
+pimple
+pin
+pinafore
+pinata
+pinball
+pincer
+pinch
+pincushion
+pine
+pineal
+pineapple
+Pinehurst
+pinetum
+pinewood
+pinfeather
+ping
+pinhead
+pinhole
+pinion
+pink
+pinkeye
+pinkie
+pinkish
+pinko
+pinnace
+pinnacle
+pinnate
+pinochle
+pinpoint
+pinprick
+pinsetter
+Pinsky
+pinspotter
+pinstripe
+pint
+pintail
+pintle
+pinto
+pinup
+pinwheel
+pion
+pioneer
+pious
+pip
+pipe
+pipeline
+pipette
+pipsissewa
+piquant
+pique
+piracy
+Piraeus
+piranha
+pirate
+piratic
+pirogue
+pirouette
+pirouetted
+pirouetting
+Piscataway
+piscatory
+Pisces
+pisciculture
+piscine
+piss
+pissoir
+pistachio
+pistil
+pistol
+pistole
+pistoleer
+piston
+pit
+pita
+pitch
+pitchblende
+pitchfork
+pitchstone
+piteous
+pitfall
+pith
+pithead
+pithecanthropus
+pitiable
+pitilessly
+Pitney
+piton
+Pitt
+pittance
+Pittman
+Pitts
+Pittsburgh
+Pittsburgher
+Pittsfield
+Pittston
+pituitary
+pity
+Pius
+pivot
+pivotal
+pixel
+pixie
+pixilate
+pixy
+pizza
+pizzazz
+pizzeria
+pizzicato
+placable
+placard
+placate
+place
+placeable
+placebo
+placehold
+placenta
+placental
+placid
+placket
+plagiarism
+plagiarist
+plagiarize
+plagioclase
+plague
+plagued
+plaguey
+plaguily
+plaice
+plaid
+plain
+plainclothesman
+Plainfield
+plains
+plainsong
+plainspoken
+plaint
+plaintiff
+plaintive
+plait
+plan
+planar
+planarian
+Planck
+plane
+planeload
+planet
+planetaria
+planetarium
+planetary
+planetesimal
+planetoid
+plangent
+planimeter
+plank
+plankton
+planktonic
+planoconcave
+planoconvex
+plant
+plantain
+plantation
+plaque
+plasm
+plasma
+plasmon
+plaster
+plasterboard
+plasterwork
+plastic
+plastomer
+plastron
+plat
+plate
+plateau
+platelet
+platen
+platform
+platinic
+platinum
+platitude
+platitudinous
+Plato
+platonic
+Platonism
+Platonist
+platoon
+Platte
+platypus
+plaudit
+plausible
+play
+playa
+playact
+playback
+playbill
+playboy
+playgo
+playground
+playhouse
+playland
+playlet
+playmate
+playoff
+playpen
+playroom
+playsuit
+plaything
+playtime
+playwright
+playwriting
+plaza
+plea
+plead
+pleasant
+pleasantry
+please
+pleasure
+pleat
+plebe
+plebeian
+plebiscite
+plectrum
+pled
+pledge
+Pleiades
+Pleistocene
+plenary
+plenipotentiary
+plenish
+plenitude
+plenteous
+plenty
+plenum
+plesiosaur
+plethora
+pleura
+pleural
+pleurisy
+Plexiglas
+plexus
+pliable
+pliancy
+pliant
+pliers
+plight
+plimsoll
+plink
+plinth
+Pliny
+Pliocene
+plod
+plop
+plosion
+plot
+plover
+plow
+plowboy
+plowshare
+ploy
+pluck
+plug
+plugboard
+pluggable
+plum
+plumage
+plumb
+plumbago
+plumbate
+plumbic
+plume
+plummet
+plumose
+plump
+plumpish
+plunder
+plunge
+plunk
+pluperfect
+plural
+plus
+plush
+Plutarch
+Pluto
+plutocracy
+plutocrat
+plutocratic
+plutonian
+plutonic
+plutonium
+pluvial
+ply
+Plymouth
+plyscore
+plywood
+PM
+p.m.
+pneuma
+pneumatic
+pneumococcus
+pneumonia
+pneumonic
+Po
+poach
+pock
+pocket
+pocketbook
+pockmark
+Pocono
+pocus
+pod
+podia
+podiatrist
+podiatry
+podium
+Podunk
+podzol
+Poe
+poem
+poesy
+poet
+poetaster
+poetess
+poetic
+poetress
+poetry
+pogo
+pogrom
+poi
+poignant
+Poincare
+poinsettia
+point
+pointillism
+pointillist
+pointwise
+poise
+poison
+poisonous
+Poisson
+poke
+pokerface
+pokey
+pol
+Poland
+polar
+polarimeter
+Polaris
+polariscope
+polariscopic
+polariton
+polarograph
+polarography
+Polaroid
+polaron
+polder
+pole
+polecat
+polemic
+police
+policy
+policyholder
+polio
+poliomyelitis
+polis
+polish
+politburo
+polite
+politesse
+politic
+politician
+politicker
+politicking
+politico
+politics
+polity
+Polk
+polka
+poll
+pollack
+Pollard
+pollen
+pollinate
+polliwog
+pollock
+pollster
+pollutant
+pollute
+Pollux
+Pollyanna
+polo
+polonaise
+polonium
+polopony
+poltergeist
+poltroon
+poly
+polyandry
+polyethylene
+polygamist
+polygamous
+polygamy
+polyglot
+polygon
+polygonal
+polygynous
+polyhedra
+polyhedral
+polyhedron
+Polyhymnia
+polymathic
+polymer
+polymerase
+polymeric
+polymorph
+polymorphic
+polymorphous
+Polynesia
+Polynices
+polynomial
+polyp
+Polyphemus
+polyphonous
+polyphony
+polyploid
+polypropylene
+polytechnic
+polytheism
+polytheist
+polytope
+polytypy
+pomade
+pomegranate
+pommel
+pomology
+Pomona
+pomp
+pompadour
+pompano
+Pompeii
+pompon
+pomposity
+pompous
+Ponce
+Ponchartrain
+poncho
+pond
+ponder
+ponderous
+pong
+poniard
+Pontiac
+pontifex
+pontiff
+pontific
+pontificate
+pontoon
+pony
+ponytail
+Ponzi
+pooch
+poodle
+pooh
+pool
+Poole
+poolroom
+poop
+poor
+poorhouse
+poorish
+pop
+popcorn
+pope
+popery
+popeye
+popgun
+popinjay
+popish
+poplar
+poplin
+popover
+poppet
+poppy
+poppycock
+popsicle
+populace
+popular
+populate
+populism
+populist
+populous
+porcelain
+porch
+porcine
+porcupine
+pore
+porgy
+pork
+porn
+porno
+pornography
+porosity
+porous
+porphyry
+porpoise
+porridge
+porringer
+Porsche
+port
+portage
+portal
+portamenti
+portamento
+portation
+portcullis
+Porte
+portend
+portent
+portentous
+porter
+porterage
+porterhouse
+portfolio
+porthole
+Portia
+portico
+portiere
+Portland
+portmanteau
+Porto
+portrait
+portraiture
+portray
+portrayal
+Portsmouth
+Portugal
+Portuguese
+portulaca
+posada
+pose
+Poseidon
+poseur
+posh
+posit
+position
+positron
+posse
+possess
+possession
+possessor
+possible
+possum
+post
+postage
+postal
+postbellum
+postcard
+postclassic
+postcondition
+postdate
+postdoc
+postdoctoral
+posterior
+posteriori
+posterity
+postern
+postfix
+postglacial
+postgraduate
+posthaste
+posthumous
+posthypnotic
+postilion
+postimpression
+postlude
+postmark
+postmaster
+postmillenarian
+postmistress
+postmodern
+postmortem
+postmultiply
+postnasal
+postnuptial
+postoperative
+postorder
+postpaid
+postpartum
+postpone
+postprandial
+postprocess
+postprocessor
+postscript
+postulant
+postulate
+postural
+posture
+postwar
+posy
+pot
+potable
+potash
+potassium
+potation
+potato
+potatoes
+potbelly
+potboil
+potent
+potentate
+potential
+potentiate
+potentiometer
+pothole
+pothook
+pothunter
+potion
+potlatch
+potluck
+Potomac
+potpourri
+potsherd
+potshot
+pottage
+potter
+pottery
+Potts
+pouch
+Poughkeepsie
+poultice
+poultry
+pounce
+pound
+poundage
+poundal
+pour
+pout
+poverty
+pow
+powder
+powderpuff
+powdery
+Powell
+power
+powerhouse
+powwow
+pox
+Poynting
+ppm
+PR
+practicable
+practical
+practice
+practitioner
+Prado
+pragmatic
+pragmatism
+pragmatist
+Prague
+prairie
+praise
+praiseworthy
+praline
+pram
+prance
+prank
+prankish
+prankster
+praseodymium
+prate
+pratfall
+Pratt
+prattle
+Pravda
+prawn
+praxes
+praxis
+pray
+prayer
+preach
+preachy
+preamble
+Precambrian
+precarious
+precaution
+precautionary
+precede
+precedent
+precept
+preceptive
+precess
+precession
+precinct
+precious
+precipice
+precipitable
+precipitate
+precipitous
+precis
+precise
+precision
+preclude
+preclusion
+precocial
+precocious
+precocity
+precursor
+predaceous
+predacious
+predecessor
+predicament
+predicate
+predict
+predilect
+predispose
+predisposition
+predominant
+predominate
+preemie
+preeminent
+preempt
+preen
+prefab
+prefabricate
+preface
+prefatory
+prefect
+prefecture
+prefer
+preferable
+preference
+preferential
+prefix
+pregnant
+prehensile
+prehension
+prehistoric
+prehominid
+prejudice
+prejudicial
+prelim
+preliminary
+prelude
+premature
+premed
+premeditate
+premier
+premiere
+premise
+premium
+premonition
+Prentice
+preoccupy
+prep
+preparation
+preparator
+prepare
+preponderant
+preponderate
+preposition
+preposterous
+preppy
+preprogram
+prerequisite
+prerogative
+presage
+presbyter
+presbyterial
+Presbyterian
+presbytery
+prescient
+Prescott
+prescribe
+prescript
+present
+presentation
+preservation
+preserve
+preside
+president
+presidential
+presidium
+press
+pressboard
+pressroom
+pressure
+prestidigitate
+prestige
+prestigious
+presto
+Preston
+presume
+presumed
+presuming
+presumption
+presumptuous
+presuppose
+presupposition
+pretend
+pretense
+pretenses
+pretension
+pretentious
+preterite
+preternatural
+pretext
+Pretoria
+prettify
+pretty
+pretzel
+prevail
+prevalent
+prevaricate
+prevent
+preview
+previous
+prexy
+prey
+Priam
+price
+prick
+prickle
+pride
+priest
+priestess
+Priestley
+prig
+priggish
+prim
+prima
+primacy
+primal
+primary
+primate
+prime
+primeval
+primitive
+primitivism
+primo
+primogeniture
+primordial
+primp
+primrose
+primus
+prince
+princedom
+princeling
+princess
+Princeton
+principal
+principia
+principle
+print
+printery
+printout
+prior
+prioress
+priori
+prioritize
+priory
+Priscilla
+prism
+prismatic
+prismoid
+prison
+prissy
+pristine
+Pritchard
+prithee
+privacy
+private
+privateer
+privet
+privilege
+privity
+privy
+prix
+prize
+prizefight
+prizewin
+pro
+proactive
+probabilist
+probate
+probationary
+probe
+probity
+problem
+problematic
+proboscis
+procaine
+procedural
+procedure
+proceed
+process
+procession
+processor
+proclaim
+proclamation
+proclivity
+proconsul
+procrastinate
+procreate
+procrustean
+Procrustes
+Procter
+proctology
+proctor
+procurator
+procure
+procuress
+Procyon
+prod
+prodigal
+prodigious
+prodigy
+produce
+producible
+product
+productivity
+prof
+profanation
+profane
+profess
+profession
+professional
+professor
+professorial
+proffer
+proficient
+profile
+profit
+profiteer
+profligacy
+profligate
+profound
+profundity
+profuse
+profusion
+progenitor
+progeny
+progesterone
+prognosis
+prognosticate
+program
+programmatic
+progress
+progression
+prohibit
+prohibition
+prohibitory
+project
+projectile
+Prokofieff
+prolate
+prolegomena
+proletarian
+proletariat
+proliferate
+prolific
+prolix
+prologue
+prolong
+prolongate
+prolusion
+prom
+promenade
+Promethean
+Prometheus
+promethium
+prominent
+promiscuity
+promiscuous
+promise
+promissory
+promontory
+promote
+promotion
+prompt
+promptitude
+promulgate
+pronate
+prone
+prong
+pronghorn
+pronominal
+pronoun
+pronounce
+pronounceable
+pronto
+pronunciamento
+pronunciation
+proof
+proofread
+prop
+propagable
+propaganda
+propagandist
+propagandize
+propagate
+propane
+propel
+propellant
+propensity
+proper
+property
+propertyless
+prophecy
+prophesy
+prophet
+prophetess
+prophetic
+prophylactic
+prophylaxis
+propinquity
+propionate
+propitiable
+propitiate
+propitious
+proponent
+proportion
+proportionate
+propos
+proposal
+propose
+proposition
+propound
+proprietary
+proprietor
+proprietress
+propriety
+proprioception
+propulsion
+propyl
+propylene
+prorate
+prorogue
+prosaic
+proscenium
+prosciutto
+proscribe
+proscription
+prose
+prosecute
+prosecutor
+prosecutorial
+proselyte
+proselytize
+Proserpine
+prosodic
+prosodist
+prosody
+prosopopoeia
+prospect
+prospectus
+prosper
+prosperous
+prostate
+prostheses
+prosthesis
+prosthetic
+prostitute
+prostrate
+protactinium
+protagonist
+protean
+protease
+protect
+protectorate
+protectress
+protege
+protegee
+protein
+proteolysis
+proteolytic
+protest
+protestant
+protestation
+prothonotary
+protocol
+protolanguage
+proton
+protoplasm
+protoplasmic
+protoplast
+protoplastic
+prototype
+prototypic
+protozoa
+protozoan
+protozooic
+protozoon
+protract
+protractor
+protrude
+protrusion
+protuberant
+proud
+Proust
+prove
+proven
+provenance
+Provencal
+provender
+proverb
+proverbial
+provide
+provident
+providential
+province
+provincial
+provision
+provisional
+proviso
+provisory
+provocateur
+provocation
+provoke
+provolone
+provost
+prow
+prowess
+prowl
+proximal
+proximate
+proximity
+proxy
+prude
+prudent
+prudential
+prudery
+prudish
+Pruitt
+prune
+prurient
+Prussia
+pry
+P.S.
+p's
+psalm
+psalter
+psaltery
+pseudo
+pseudonym
+pseudonymous
+pshaw
+psi
+psoriasis
+psych
+psyche
+psychedelic
+psychiatric
+psychiatrist
+psychiatry
+psychic
+psycho
+psychoanalyze
+psychogenic
+psychokinesis
+psychology
+psychometry
+psychopath
+psychopathic
+psychoses
+psychosis
+psychotic
+PTA
+ptarmigan
+pterodactyl
+Ptolemaic
+Ptolemy
+ptomaine
+pub
+puberty
+pubescent
+pubic
+public
+publican
+publication
+publicly
+publish
+PUC
+Puccini
+puce
+puck
+puckish
+pudding
+puddle
+pudenda
+pudendum
+pudgy
+pueblo
+puerile
+Puerto
+puff
+puffball
+puffery
+puffin
+pug
+Pugh
+pugilism
+pugilist
+pugnacious
+pugnacity
+puissant
+puke
+pukka
+Pulaski
+pulchritude
+pule
+Pulitzer
+pull
+pullback
+pullet
+pulley
+Pullman
+pullout
+pullover
+pulmonary
+pulmonic
+pulp
+pulpit
+pulpwood
+pulsar
+pulsate
+pulsatile
+pulse
+pulverable
+pulverize
+puma
+pumice
+pummel
+pump
+pumpernickel
+pumpkin
+pumpkinseed
+pun
+punch
+punchboard
+puncheon
+punctate
+punctilio
+punctilious
+punctual
+punctuate
+puncture
+pundit
+punditry
+pungent
+Punic
+punish
+punitive
+punk
+punkah
+punster
+punt
+puny
+pup
+pupa
+pupae
+pupal
+pupate
+pupil
+pupillary
+puppet
+puppeteer
+puppetry
+puppy
+puppyish
+purblind
+Purcell
+purchase
+purdah
+Purdue
+pure
+purebred
+puree
+purgation
+purgatory
+purge
+purify
+Purina
+purine
+puritan
+puritanic
+purl
+purlieu
+purloin
+purple
+purplish
+purport
+purpose
+purposive
+purr
+purse
+purslane
+pursuant
+pursue
+pursuer
+pursuit
+pursuivant
+purulent
+purvey
+purveyance
+purveyor
+purview
+pus
+Pusan
+Pusey
+push
+pushball
+pushbutton
+pushcart
+pushover
+pushpin
+pusillanimity
+pusillanimous
+puss
+pussycat
+pussyfoot
+pustulant
+pustular
+pustulate
+pustule
+put
+putative
+Putnam
+putrefaction
+putrefy
+putrescent
+putrid
+putsch
+putt
+putter
+putty
+puzzle
+PVC
+Pygmalion
+pygmy
+Pyhrric
+Pyle
+pylon
+pyloric
+Pyongyang
+pyorrhea
+pyramid
+pyramidal
+pyre
+pyrethrin
+pyrethrum
+Pyrex
+pyridine
+pyrite
+pyroelectric
+pyrolysis
+pyrolytic
+pyrolyze
+pyromania
+pyrometer
+pyrophosphate
+pyrotechnic
+pyroxene
+pyrrhic
+Pythagoras
+Pythagorean
+Pythias
+python
+Q&A
+Qatar
+QED
+q's
+qua
+quack
+quackery
+quad
+quadrangle
+quadrangular
+quadrant
+quadratic
+quadrature
+quadrennial
+quadrennium
+quadric
+quadriceps
+quadrilateral
+quadrille
+quadrillion
+quadrillionth
+quadripartite
+quadriplegia
+quadriplegic
+quadrivium
+quadroon
+quadruped
+quadruple
+quadruplet
+quadruplicate
+quadrupole
+quaff
+quagmire
+quahog
+quail
+quaint
+quake
+Quakeress
+qualified
+qualify
+qualitative
+quality
+qualm
+qualmish
+quandary
+quanta
+Quantico
+quantify
+quantile
+quantitate
+quantitative
+quantity
+quantize
+quantum
+quarantine
+quark
+quarrel
+quarrelsome
+quarry
+quart
+quarterback
+quarterdeck
+quarterfinal
+quarterfinalist
+quartermaster
+quarternion
+quartet
+quartette
+quartic
+quartile
+quarto
+quartz
+quasar
+quash
+quasi
+quaternary
+quatrain
+quaver
+quay
+quayside
+Que.
+queasy
+queazy
+Quebec
+Quechua
+queen
+Queensland
+queer
+queerish
+quell
+quench
+Quentin
+querulous
+query
+quest
+question
+questionnaire
+quetzal
+queue
+Quezon
+quibble
+quiche
+quick
+quicken
+quickie
+quicklime
+quicksand
+quicksilver
+quickstep
+quid
+quiescent
+quiet
+quietude
+quietus
+quill
+quilt
+quince
+quinine
+Quinn
+quinquennial
+quint
+quintal
+quintessence
+quintessential
+quintet
+quintette
+quintic
+quintile
+quintillion
+quintuple
+quintuplet
+quintuplicate
+quip
+quire
+Quirinal
+quirk
+quirt
+quisling
+quit
+quite
+Quito
+quiver
+Quixote
+quixotic
+quiz
+quizzical
+quo
+quod
+quoin
+quoit
+quondam
+quonset
+quorum
+quota
+quotation
+quote
+quoth
+quotidian
+quotient
+Rabat
+rabbet
+rabbi
+rabbinate
+rabbinic
+rabbit
+rabbity
+rabble
+rabid
+rabies
+raccoon
+race
+racecourse
+racehorse
+racemic
+racetrack
+raceway
+Rachel
+Rachmaninoff
+racial
+rack
+racket
+racketeer
+raconteur
+racquet
+radar
+Radcliffe
+radial
+radian
+radiant
+radiate
+radical
+radices
+radii
+radio
+radiograph
+radiography
+radiolarian
+radiology
+radiosonde
+radish
+radium
+radius
+radix
+radome
+radon
+Rae
+Rafael
+Rafferty
+raffia
+raffish
+raffle
+raft
+rafts
+rag
+ragamuffin
+rage
+raggedy
+raglan
+ragout
+ragtag
+ragtime
+ragweed
+raid
+rail
+railbird
+railhead
+raillery
+railroad
+railway
+raiment
+rain
+rainbow
+raincoat
+raindrop
+rainfall
+rainproof
+rainspout
+rainstorm
+rainwear
+raise
+raisin
+raison
+raj
+rajah
+Rajiv
+rake
+rakehell
+rakish
+Raleigh
+rally
+Ralph
+Ralston
+ram
+Ramada
+Raman
+ramble
+rambunctious
+ramify
+Ramirez
+Ramo
+Ramon
+Ramona
+Ramos
+ramp
+rampage
+rampant
+rampart
+ramrod
+Ramsey
+ramshackle
+ran
+ranch
+rancho
+rancid
+rancor
+rancorous
+Rand
+Randall
+Randolph
+random
+randy
+rang
+range
+rangeland
+Rangoon
+Ranier
+rank
+Rankin
+Rankine
+rankle
+ransack
+ransom
+rant
+Rao
+Raoul
+rap
+rapacious
+rapacity
+rape
+Raphael
+rapid
+rapier
+rapine
+rappel
+rapport
+rapprochement
+rapscallion
+rapt
+raptor
+rapture
+rapturous
+rara
+rare
+rarebit
+rarefaction
+rarefy
+Raritan
+rasa
+rascal
+rash
+Rasmussen
+rasp
+raspberry
+raster
+Rastus
+rat
+rata
+ratatouille
+ratchet
+rate
+ratepayer
+rather
+rathskeller
+ratify
+ratio
+ratiocinate
+rationale
+rattail
+rattan
+rattle
+rattlesnake
+rattletrap
+rattly
+raucous
+Raul
+raunchy
+ravage
+rave
+ravel
+raven
+ravenous
+ravine
+ravioli
+ravish
+raw
+rawboned
+rawhide
+Rawlinson
+ray
+Rayleigh
+Raymond
+rayon
+Raytheon
+raze
+razor
+razorback
+razz
+razzle
+RBI
+RCA
+R&D
+re
+reach
+reactant
+reactionary
+read
+readout
+ready
+Reagan
+real
+realism
+realist
+reality
+realize
+realm
+realtor
+realty
+ream
+reap
+rear
+rearmost
+rearward
+reason
+reave
+reb
+rebarbative
+Rebecca
+rebel
+rebellion
+rebellious
+rebuke
+rebut
+rebuttal
+recalcitrant
+recantation
+recappable
+receipt
+receivable
+receive
+recension
+recent
+receptacle
+reception
+receptor
+recess
+recherche
+recidivism
+recidivist
+Recife
+recipe
+recipient
+reciprocal
+reciprocate
+reciprocity
+recital
+reck
+reckon
+reclamation
+recline
+recluse
+reclusive
+recognize
+recombinant
+recompense
+reconcile
+recondite
+reconnaissance
+reconnoiter
+recovery
+recreant
+recriminate
+recrudescent
+recruit
+rectal
+rectangle
+rectangular
+rectifier
+rectify
+rectilinear
+rectitude
+recto
+rector
+rectory
+rectum
+recumbent
+recuperate
+recur
+recurrent
+recursion
+recusant
+recuse
+red
+redact
+redbird
+redbud
+redcap
+redcoat
+redden
+reddish
+redemption
+redemptory
+redhead
+redivivus
+redleg
+Redmond
+redneck
+redolent
+redound
+redox
+redpoll
+redshank
+redskin
+redstart
+Redstone
+redtop
+reduce
+reducible
+redundant
+redwing
+redwood
+Reebok
+reed
+reedbuck
+reef
+reek
+reel
+reemit
+reenable
+Reese
+reeve
+ref
+refection
+refectory
+refer
+referable
+referee
+referenda
+referendum
+referent
+referential
+referral
+refinement
+refinery
+reflect
+reflectance
+reflectometer
+reflexive
+reformatory
+refract
+refractometer
+refractor
+refrain
+refrangible
+refrigerant
+refrigerate
+refuge
+refugee
+refulgent
+refusal
+refusenik
+refutation
+refute
+regalia
+regality
+regard
+regatta
+regelation
+regeneracy
+reggae
+regicide
+regime
+regimen
+regiment
+regimental
+regimentation
+Regina
+Reginald
+region
+regional
+Regis
+registrable
+registrant
+registrar
+registration
+registry
+regolith
+regress
+regression
+regressor
+regret
+regular
+regulate
+Regulus
+regurgitate
+rehabilitate
+rehearsal
+Reich
+Reid
+reify
+reign
+Reilly
+reimburse
+rein
+reindeer
+reinforce
+Reinhold
+reject
+rejoice
+rejoinder
+rejuvenate
+relatedly
+relaxant
+relaxation
+relayed
+relent
+relevant
+reliably
+reliant
+relic
+relict
+relief
+relies
+relieve
+religion
+religiosity
+religious
+relinquish
+reliquary
+relish
+reluctant
+remainder
+remand
+remanent
+Rembrandt
+remediable
+remedy
+remembrance
+Remington
+reminisce
+reminiscent
+remit
+remittal
+remittance
+remnant
+remonstrant
+remonstrate
+remorse
+remote
+removal
+remunerate
+Remus
+Rena
+renaissance
+renal
+Renault
+rend
+render
+rendezvous
+rendition
+Rene
+Renee
+renegade
+renege
+renewal
+rennet
+Renoir
+renounce
+renovate
+renown
+Rensselaer
+rent
+rental
+rentier
+renunciate
+rep
+repair
+reparable
+reparation
+repartee
+repatriate
+repeater
+repel
+repellent
+repentant
+repertoire
+repertory
+repetitious
+replete
+replica
+replicable
+replicate
+reportorial
+repository
+reprehensible
+repressable
+repressible
+repression
+repressor
+reprieve
+reprimand
+reprisal
+reprise
+reproach
+reptile
+reptilian
+republican
+repudiate
+repugnant
+repulsion
+reputation
+repute
+requiem
+require
+requisite
+requisition
+requital
+requite
+reredos
+rerouted
+rerouting
+rescind
+rescission
+rescue
+resemblant
+resemble
+resent
+reserpine
+reservation
+reservoir
+resident
+residential
+residua
+residual
+residuary
+residue
+residuum
+resignation
+resilient
+resinate
+resinous
+resist
+resistant
+resistible
+resistive
+resistor
+resonant
+resonate
+resorcinol
+respect
+respective
+respiration
+respirator
+resplendent
+respond
+respondent
+response
+responsible
+responsive
+rest
+restaurant
+restaurateur
+restitute
+restive
+restoration
+restraint
+restroom
+result
+resultant
+resume
+resumption
+resurgent
+resurrect
+resuscitate
+ret
+retain
+retaliate
+retard
+retardant
+retardation
+retch
+retention
+reticent
+reticle
+reticular
+reticulate
+reticule
+reticulum
+retina
+retinal
+retinue
+retiree
+retort
+retractile
+retribution
+retrieval
+retrieve
+retroaction
+retroactive
+retrofit
+retroflex
+retrograde
+retrogress
+retrogression
+retrorocket
+retrospect
+retrovirus
+retrovision
+Reub
+Reuben
+Reuters
+rev
+revanche
+revanchist
+reveille
+revel
+revelation
+revelatory
+revelry
+revenge
+revenue
+reverberant
+reverberate
+revere
+reverend
+reverent
+reverential
+reverie
+reversal
+reversible
+reversionary
+revert
+revertible
+revertive
+revile
+revilement
+revisal
+revise
+revival
+revive
+revoke
+revolt
+revolution
+revolutionary
+revolve
+revulsion
+Rex
+Reyes
+Reykjavik
+Reynolds
+RFP
+rhapsodic
+rhapsodize
+rhapsody
+Rhea
+Rhenish
+rhenium
+rheology
+rheostat
+rhesus
+rhetoric
+rhetorician
+rheum
+rheumatic
+rheumatism
+Rhine
+rhinestone
+rhino
+rhinoceros
+rhizome
+rho
+Rhoda
+Rhode
+Rhodes
+Rhodesia
+rhodium
+rhododendron
+rhomb
+rhombi
+rhombic
+rhombohedra
+rhombohedral
+rhombohedron
+rhomboid
+rhombus
+Rhonda
+rhubarb
+rhumb
+rhyme
+rhymester
+rhythm
+rhythmic
+RI
+rialto
+rib
+ribald
+ribaldry
+ribbon
+riboflavin
+ribonucleic
+ribosome
+Rica
+Ricardo
+Riccardo
+rice
+rich
+Richard
+Richards
+Richardson
+Richfield
+Richmond
+Richter
+rick
+rickets
+rickettsia
+rickettsiae
+rickety
+rickrack
+ricksha
+rickshaw
+Rico
+ricochet
+rid
+riddance
+ridden
+riddle
+ride
+ridge
+ridgepole
+Ridgway
+ridicule
+ridiculous
+Riemann
+Riesling
+rife
+riffle
+riffraff
+rifle
+riflery
+rift
+rig
+rigamarole
+Rigel
+Riggs
+right
+righteous
+rightmost
+rightward
+rigid
+rigidify
+rigor
+rigorous
+rile
+Riley
+rill
+rilly
+rim
+rime
+rimester
+rind
+Rinehart
+ring
+ringbolt
+ringleader
+ringlet
+ringmaster
+ringneck
+ringside
+ringtail
+ringtoss
+ringworm
+rink
+rinse
+Rio
+Riordan
+riot
+riotous
+rip
+riparian
+ripe
+ripen
+Ripley
+ripoff
+riposte
+ripple
+riprap
+ripsaw
+ripsnort
+riptide
+rise
+risen
+risible
+risk
+risque
+Rita
+ritardando
+Ritchie
+rite
+Ritter
+ritual
+Ritz
+ritzy
+rival
+rivalry
+riven
+river
+Rivera
+riverbank
+riverbed
+riverboat
+riverfront
+riverine
+riverside
+rivet
+Riviera
+rivulet
+Riyadh
+RNA
+roach
+road
+roadbed
+roadblock
+roadhouse
+roadrunner
+roadside
+roadstead
+roadster
+roadway
+roadwork
+roam
+roan
+roar
+roast
+rob
+robbery
+Robbins
+robe
+Roberson
+Robert
+Roberta
+Roberto
+Roberts
+Robertson
+robin
+Robinson
+robot
+robotic
+robust
+roc
+Rocco
+Rochester
+rock
+rockabye
+rockbound
+Rockefeller
+rocket
+rocketeer
+rocketry
+rockfish
+Rockford
+Rockies
+Rockland
+rockslide
+Rockwell
+rococo
+rod
+Rodale
+rode
+rodent
+rodeo
+Rodgers
+Rodney
+rodomontade
+Rodriguez
+roe
+roebuck
+roentgen
+roentgenography
+Roger
+Rogers
+Roget
+rogue
+roguish
+roil
+roily
+roister
+Roland
+role
+Rolf
+roll
+rollback
+rollick
+Rollins
+roly
+romaine
+roman
+romance
+Romanesque
+Romania
+romanize
+Romano
+romantic
+Rome
+Romeo
+Romero
+romp
+Romulus
+Ron
+Ronald
+rondeau
+rondo
+Ronnie
+rood
+roof
+rooftop
+rooftree
+rook
+rookery
+rookie
+room
+roomette
+roommate
+Roosevelt
+Rooseveltian
+roost
+root
+rootlet
+rootstock
+rope
+ropewalk
+Rorschach
+Rosa
+Rosalie
+rosary
+Roscoe
+rose
+roseate
+rosebud
+rosebush
+Roseland
+Rosemarie
+rosemary
+Rosen
+Rosenberg
+Rosenblum
+Rosenthal
+Rosenzweig
+roseola
+Rosetta
+rosette
+rosewater
+rosewood
+Rosicrucian
+Rosie
+rosin
+Ross
+roster
+rostrum
+rot
+Rotarian
+rotary
+rotate
+ROTC
+rote
+Roth
+rotifer
+rotisserie
+rotogravure
+rotor
+rototill
+rotten
+rottweiler
+rotund
+rotunda
+rouge
+rough
+roughage
+roughcast
+roughen
+roughhewn
+roughhouse
+roughish
+roughneck
+roughrider
+roughshod
+roulade
+roulette
+round
+roundabout
+roundhead
+roundhouse
+roundoff
+roundtable
+roundup
+roundworm
+rouse
+Rousseau
+roust
+roustabout
+rout
+route
+routine
+rove
+row
+rowboat
+rowdy
+Rowe
+rowel
+Rowena
+Rowland
+Rowley
+Roxanne
+Roy
+royal
+royalty
+Royce
+royster
+RPM
+RR
+r's
+RSVP
+Ruanda
+rub
+rubato
+rubberneck
+rubbery
+rubbish
+rubble
+rubdown
+rube
+rubella
+Ruben
+Rubicon
+rubicund
+rubidium
+ruble
+rubric
+ruby
+rucksack
+ruckus
+ruction
+rudder
+ruddy
+rude
+rudiment
+rudimentary
+Rudolf
+Rudolph
+Rudy
+Rudyard
+rue
+ruff
+ruffian
+ruffle
+rufous
+Rufus
+rug
+rugby
+ruggedize
+ruin
+ruination
+ruinous
+Ruiz
+rule
+rum
+rumble
+rumen
+Rumford
+ruminant
+ruminate
+rummage
+rummy
+rumor
+rumormonger
+rump
+rumple
+rumpus
+rumrun
+run
+runabout
+runaround
+runaway
+rundown
+rune
+rung
+Runge
+runic
+runneth
+Runnymede
+runoff
+runt
+runway
+Runyon
+rupee
+rupture
+rural
+ruse
+rush
+Rushmore
+rusk
+Russ
+Russell
+russet
+Russia
+russianize
+Russo
+rust
+rustic
+rusticate
+rustle
+rustproof
+rut
+rutabaga
+Rutgers
+Ruth
+ruthenium
+Rutherford
+ruthless
+rutile
+Rutland
+Rutledge
+RV
+Rwanda
+Ryan
+Rydberg
+Ryder
+rye
+Saab
+sabbath
+sabbatic
+Sabena
+saber
+Sabina
+Sabine
+sable
+sabotage
+saboteur
+sabra
+sac
+saccade
+saccadic
+saccharine
+sacerdotal
+sachem
+sachet
+sack
+sackcloth
+sacral
+sacrament
+Sacramento
+sacred
+sacrifice
+sacrificial
+sacrilege
+sacrilegious
+sacristan
+sacristy
+sacroiliac
+sacrosanct
+sacrum
+sad
+sadden
+saddle
+saddlebag
+saddlery
+sadhu
+Sadie
+sadism
+sadist
+Sadler
+sadomasochism
+sadomasochist
+safari
+safe
+safecrack
+safeguard
+safelight
+safety
+safflower
+saffron
+sag
+saga
+sagacious
+sagacity
+sage
+sagebrush
+Saginaw
+sagittal
+Sagittarius
+sago
+saguaro
+Sahara
+sahib
+said
+Saigon
+sail
+sailboard
+sailboat
+sailcloth
+sailfish
+sailor
+sailplane
+saint
+saith
+sake
+saki
+Sal
+salaam
+salacious
+salad
+salamander
+salami
+salaried
+salary
+Salazar
+sale
+Salem
+Salerno
+sales
+salesclerk
+salesgirl
+Salesian
+saleslady
+salespeople
+salesroom
+salient
+Salina
+saline
+Salisbury
+Salish
+saliva
+salivary
+salivate
+Salk
+Salle
+sallow
+sally
+salmon
+salmonella
+salon
+saloon
+salsify
+salt
+saltate
+saltbox
+saltbush
+saltcellar
+saltine
+saltpeter
+saltshaker
+saltwater
+saltworks
+salubrious
+salubrity
+salutary
+salutation
+salutatorian
+salutatory
+salute
+Salvador
+salvage
+salvageable
+salvation
+Salvatore
+salve
+salvo
+Sam
+Samantha
+Samaritan
+samarium
+samba
+same
+samizdat
+Sammy
+Samoa
+samovar
+sampan
+sample
+Sampson
+Samson
+Samuel
+Samuelson
+samurai
+San
+Sana
+sanatarium
+sanatoria
+sanatorium
+Sanborn
+Sanchez
+Sancho
+sanctify
+sanctimonious
+sanctimony
+sanction
+sanctity
+sanctuary
+sanctum
+sand
+sandal
+sandalwood
+sandbag
+sandbank
+sandbar
+sandblast
+sandbox
+Sandburg
+sanderling
+Sanderson
+sandglass
+sandhill
+Sandia
+sandlot
+sandpaper
+sandpile
+sandpiper
+Sandra
+sandstone
+sandstorm
+Sandusky
+sandwich
+sane
+Sanford
+sang
+sangaree
+sangfroid
+sanguinary
+sanguine
+sanguineous
+Sanhedrin
+sanitarian
+sanitarium
+sanitary
+sanitate
+sanitize
+sank
+sans
+Sanskrit
+Santa
+Santayana
+Santiago
+Santo
+Sao
+sap
+sapiens
+sapient
+sapling
+saponify
+sapphire
+saprophyte
+saprophytic
+sapsucker
+sapwood
+Sara
+Saracen
+Sarah
+Saran
+Sarasota
+Saratoga
+sarcasm
+sarcastic
+sarcoma
+sarcophagi
+sarcophagus
+sardine
+Sardinia
+sardonic
+sargasso
+sargassum
+sarge
+Sargent
+sari
+sarong
+sarsaparilla
+sartorial
+sash
+sashay
+Saskatchewan
+sass
+sassafras
+sassy
+sat
+satan
+satanic
+satchel
+sate
+satellite
+satiable
+satiate
+satiety
+satin
+satire
+satiric
+satisfaction
+satisfactory
+satisfy
+satrap
+saturable
+saturate
+Saturday
+Saturn
+saturnalia
+saturnalian
+saturnian
+saturnine
+satyr
+sauce
+saucepan
+Saud
+Saudi
+sauerbraten
+sauerkraut
+Saul
+Sault
+sauna
+Saunders
+saunter
+sauropod
+sausage
+saute
+sautee
+sauterne
+savage
+savagery
+savanna
+Savannah
+savant
+save
+savior
+Saviour
+Savonarola
+savor
+savory
+savoy
+Savoyard
+savvy
+saw
+sawbuck
+sawdust
+sawfish
+sawfly
+sawhorse
+sawmill
+sawtimber
+sawtooth
+sawyer
+sax
+saxifrage
+Saxon
+Saxony
+saxophone
+say
+SC
+scab
+scabbard
+scabious
+scabrous
+scads
+scaffold
+Scala
+scalar
+scalawag
+scald
+scale
+scalene
+scallion
+scallop
+scalp
+scalpel
+scaly
+scam
+scamp
+scan
+scandal
+scandalous
+Scandinavia
+scandium
+scansion
+scant
+scapegoat
+scapegrace
+scapula
+scapular
+scar
+scarab
+Scarborough
+scarce
+scare
+scarecrow
+scaremonger
+scarf
+scarface
+scarify
+scarless
+scarlet
+scarp
+Scarsdale
+scarum
+scarves
+scat
+scathe
+scathing
+scatology
+scatter
+scatterbrain
+scattergun
+scaup
+scavenge
+scenario
+scene
+scenery
+scenic
+scent
+scentless
+scepter
+Schaefer
+Schafer
+Schantz
+schedule
+schema
+schemata
+schematic
+schematize
+scheme
+Schenectady
+scherzo
+Schiller
+schism
+schismatic
+schist
+schistosomiasis
+schizoid
+schizophrenia
+schizophrenic
+schlemiel
+schlep
+Schlesinger
+schlieren
+Schlitz
+schlock
+Schloss
+schmaltz
+schmaltzy
+schmalz
+Schmidt
+Schmitt
+schmooze
+Schnabel
+schnapps
+schnauzer
+Schneider
+Schoenberg
+Schofield
+scholar
+scholastic
+scholium
+school
+schoolbag
+schoolbook
+schoolboy
+schoolchild
+schoolchildren
+schoolgirl
+schoolgirlish
+schoolhouse
+schoolmarm
+schoolmaster
+schoolmate
+schoolmistress
+schoolroom
+schoolteacher
+schoolwork
+schooner
+Schottky
+Schroeder
+Schroedinger
+Schubert
+Schultz
+Schulz
+Schumacher
+Schumann
+schuss
+Schuster
+Schuyler
+Schuylkill
+schwa
+Schwab
+Schwartz
+Schweitzer
+sciatic
+sciatica
+science
+scientific
+scientist
+scimitar
+scintilla
+scintillate
+scion
+scission
+scissor
+sclerosis
+sclerotic
+SCM
+scoff
+scofflaw
+scold
+scoliosis
+sconce
+scone
+scoop
+scoot
+scope
+scorch
+score
+scoreboard
+scorecard
+scoria
+scorn
+Scorpio
+scorpion
+scot
+scotch
+Scotia
+Scotland
+Scots
+Scott
+Scottish
+Scottsdale
+Scotty
+scoundrel
+scour
+scourge
+scout
+scoutmaster
+scow
+scowl
+scrabble
+scraggly
+scraggy
+scram
+scramble
+Scranton
+scrap
+scrapbook
+scrape
+scrapple
+scratch
+scrawl
+scrawly
+scrawny
+scream
+scree
+screech
+screed
+screen
+screenplay
+screenwriter
+screw
+screwball
+screwdriver
+screwworm
+scribble
+scribe
+Scribner
+scrim
+scrimmage
+scrimp
+scrimshaw
+scrip
+Scripps
+script
+scriptorium
+scriptural
+scripture
+scriptwriter
+scriven
+scrod
+scrofula
+scrofulous
+scrog
+scroll
+scrooge
+scrotum
+scrounge
+scrub
+scruff
+scrum
+scrumptious
+scrunch
+scruple
+scrupulosity
+scrupulous
+scrutable
+scrutinize
+scrutiny
+scuba
+scud
+scuff
+scuffle
+scull
+scullery
+scullion
+sculpin
+sculpt
+sculptor
+sculptress
+sculptural
+sculpture
+scum
+scurrility
+scurrilous
+scurry
+scurvy
+scuttle
+scuttlebutt
+scutum
+Scylla
+scythe
+Scythia
+SD
+SE
+sea
+seabag
+seabed
+seabird
+seaboard
+seaborne
+seacoast
+seafare
+seafood
+seafowl
+seafront
+seagoer
+seagoing
+Seagram
+seagull
+seahorse
+seal
+sealant
+sealskin
+seam
+seaman
+seamount
+seamstress
+Sean
+seance
+seaplane
+seaport
+seaquake
+sear
+search
+searchlight
+seascape
+seashell
+seashore
+seasick
+seaside
+season
+seasonal
+seat
+seatmate
+Seattle
+seawall
+seaward
+seaway
+seaweed
+seaworthy
+Sebastian
+sec
+secant
+secede
+secession
+seclude
+seclusion
+second
+secondary
+secondhand
+secondo
+secrecy
+secret
+secretarial
+secretariat
+secretary
+secrete
+secretion
+secretory
+sect
+sectarian
+sectary
+sector
+sectoral
+secular
+secure
+sedan
+sedate
+sedentary
+seder
+sedge
+sediment
+sedimentary
+sedimentation
+sedition
+seditious
+seduce
+seduction
+sedulous
+see
+seeable
+seed
+seedbed
+seedcake
+seedeat
+seedling
+seedpod
+seedsman
+seek
+seem
+seen
+seep
+seepage
+seer
+seersucker
+seesaw
+seethe
+seethed
+seething
+segment
+segmentary
+segmentation
+Segovia
+segregant
+segregate
+segue
+Segundo
+Seidel
+seigneur
+seigneurial
+seine
+seism
+seismic
+seismograph
+seismography
+seismology
+seismometer
+seize
+seizure
+seldom
+select
+Selectric
+Selena
+selenate
+selenite
+selenium
+selenography
+selenology
+self
+selfish
+Selfridge
+selfsame
+Selkirk
+sell
+sellout
+Selma
+selsyn
+seltzer
+selvage
+selves
+Selwyn
+semantic
+semaphore
+semblance
+semen
+semester
+semi
+seminal
+seminar
+seminarian
+seminary
+Seminole
+semiotic
+Semite
+semolina
+semper
+sempiternal
+senate
+senatorial
+send
+sender
+Seneca
+Senegal
+senescent
+senile
+senior
+senor
+senora
+senorita
+sensate
+sense
+sensible
+sensitive
+sensitize
+sensor
+sensorial
+sensorimotor
+sensual
+sensuous
+sent
+sentence
+sentential
+sententious
+sentient
+sentiment
+sentinel
+sentry
+Seoul
+sepal
+separable
+separate
+sepia
+Sepoy
+sepsis
+sept
+septa
+septate
+September
+septennial
+septet
+septic
+septillion
+septuagenarian
+septum
+septuplet
+sepulcher
+sepulchral
+sequel
+sequelae
+sequent
+sequential
+sequester
+sequestration
+sequin
+sequitur
+sequoia
+sera
+seraglio
+serape
+seraph
+seraphic
+seraphim
+Serb
+Serbia
+serenade
+serendipitous
+serendipity
+serene
+serf
+serfdom
+serge
+sergeant
+Sergei
+serial
+seriate
+seriatim
+series
+serif
+serigraph
+seriocomic
+serious
+sermon
+serology
+Serpens
+serpent
+serpentine
+serrate
+serried
+serum
+servant
+serve
+service
+serviceable
+serviette
+servile
+servitor
+servitude
+servo
+servomechanism
+servomotor
+sesame
+sesquicentennial
+sesquipedalian
+sessile
+session
+set
+setback
+Seth
+Seton
+setscrew
+settee
+settle
+setup
+seven
+sevenfold
+seventeen
+seventeenth
+seventh
+seventieth
+seventy
+sever
+severable
+several
+severalfold
+severalty
+severance
+severe
+Severn
+Seville
+sew
+sewage
+Seward
+sewerage
+sewn
+sex
+sexagesimal
+sexology
+Sextans
+sextant
+sextet
+sextillion
+sexton
+sextuple
+sextuplet
+sexual
+Seychelles
+Seymour
+sforzando
+shabby
+shack
+shackle
+shad
+shadbush
+shade
+shadow
+shadowbox
+Shafer
+Shaffer
+shaft
+shag
+shagbark
+shah
+shake
+shakeable
+shakedown
+shaken
+Shakespeare
+Shakespearean
+Shakespearian
+shako
+shaky
+shale
+shall
+shallot
+shallow
+shalom
+shalt
+sham
+shaman
+shamateur
+shamble
+shame
+shamefaced
+shampoo
+shamrock
+shamus
+Shane
+shanghai
+shanghaied
+shanghaier
+shanghaiing
+shank
+Shannon
+shan't
+Shantung
+shanty
+shantytown
+shape
+Shapiro
+shard
+share
+sharecrop
+sharehold
+shareholder
+shareown
+Shari
+shark
+sharkskin
+Sharon
+sharp
+Sharpe
+sharpen
+sharpshoot
+Shasta
+shatter
+shatterproof
+Shattuck
+shave
+shaven
+shaw
+shawl
+Shawn
+Shawnee
+shay
+she
+Shea
+sheaf
+shear
+Shearson
+sheath
+sheathe
+sheave
+shebang
+she'd
+shed
+Shedir
+Sheehan
+sheen
+sheep
+sheepfold
+sheepherding
+sheepish
+sheepshank
+sheepshead
+sheepshear
+sheepskin
+sheer
+sheet
+Sheffield
+sheik
+sheikdom
+sheikh
+Sheila
+shekel
+Shelby
+Sheldon
+shelf
+she'll
+shell
+shellac
+shellacked
+shellacking
+shellback
+Shelley
+shellfire
+shellfish
+shellproof
+Shelly
+shelter
+Shelton
+shelty
+shelve
+Shenandoah
+shenanigan
+Shepard
+shepherd
+Sheppard
+Sheraton
+sherbet
+Sheri
+Sheridan
+sheriff
+sherlock
+Sherman
+Sherri
+Sherrill
+sherry
+Sherwin
+Sherwood
+Sheryl
+Shetland
+Shia
+shibboleth
+shied
+shield
+shift
+shill
+shillelagh
+Shiloh
+shim
+shimmery
+shimmy
+shin
+shinbone
+shindig
+shine
+shingle
+shinny
+Shinto
+ship
+shipboard
+shipbuild
+shiplap
+Shipley
+shipmaster
+shipmate
+shipshape
+shipway
+shipworm
+shipwreck
+shipwright
+shipyard
+shire
+shirk
+Shirley
+shirr
+shirt
+shirttail
+shirtwaist
+shish
+shit
+shiv
+Shiva
+shivaree
+shiver
+shivery
+shoal
+shock
+Shockley
+shod
+shoddy
+shoe
+shoehorn
+shoelace
+shoestring
+shofar
+shogun
+shoji
+shone
+shoo
+shoofly
+shook
+shoot
+shootout
+shop
+shoplift
+shopown
+shoptalk
+shopworn
+shore
+shorebird
+shoreline
+shorn
+short
+shortage
+shortbread
+shortcake
+shortchange
+shortcoming
+shortcut
+shorten
+shortfall
+shorthand
+shortish
+shortsighted
+shortstop
+shot
+shotgun
+should
+shoulder
+shouldn't
+shouldst
+shout
+shove
+shovel
+show
+showboat
+showcase
+showdown
+showery
+shown
+showpiece
+showplace
+showroom
+shrank
+shrapnel
+shred
+Shreveport
+shrew
+shrewd
+shrewish
+shriek
+shrieve
+shrift
+shrike
+shrill
+shrilly
+shrimp
+shrine
+shrink
+shrinkage
+shrive
+shrivel
+shroud
+shrove
+shrub
+shrubbery
+shrug
+shrunk
+shrunken
+shtick
+Shu
+shuck
+shudder
+shuddery
+shuffle
+shuffleboard
+Shulman
+shun
+shunpike
+shunt
+shush
+shut
+shutdown
+shutoff
+shutout
+shutterbug
+shuttle
+shuttlecock
+shy
+Shylock
+shyly
+shyster
+sial
+SIAM
+Siamese
+Sian
+sib
+Siberia
+sibilant
+sibilate
+Sibley
+sibling
+sibyl
+sibylline
+sic
+Sicilian
+Sicily
+sick
+sickbed
+sicken
+sickish
+sickle
+sickroom
+side
+sidearm
+sideband
+sidebar
+sideboard
+sideburns
+sidecar
+sidehill
+sidekick
+sidelight
+sideline
+sidelobe
+sidelong
+sidereal
+sidesaddle
+sideshow
+sideslip
+sidesplitting
+sidestep
+sidestroke
+sideswipe
+sidetrack
+sidewalk
+sidewall
+sideway
+sidewinder
+sidewise
+sidle
+Sidney
+siege
+Siegel
+Siegfried
+Sieglinda
+Siegmund
+Siemens
+sienna
+sierra
+siesta
+sieve
+sift
+sigh
+sight
+sightsee
+sightseer
+sigma
+sigmoid
+Sigmund
+sign
+signal
+signatory
+signature
+signboard
+signet
+significant
+signify
+Signor
+Signora
+signpost
+Sikh
+Sikorsky
+silage
+silane
+Silas
+silent
+silhouette
+silhouetting
+silica
+silicate
+siliceous
+silicic
+silicide
+silicious
+silicon
+silicone
+silicosis
+silk
+silken
+silkworm
+sill
+silly
+silo
+silt
+siltation
+Silurian
+Silva
+silver
+silverfish
+Silverman
+silversmith
+silverware
+silvery
+silvicultural
+silviculture
+simian
+similar
+simile
+similitude
+simmer
+Simmons
+Simon
+simonize
+Simons
+Simonson
+simony
+simpatico
+simper
+simple
+simplectic
+simpleminded
+simpleton
+simplex
+simplicial
+simplicity
+simplify
+simplistic
+simply
+Simpson
+Sims
+simulacra
+simulacrum
+simulate
+simulcast
+simultaneity
+simultaneous
+sin
+Sinai
+since
+sincere
+Sinclair
+sine
+sinecure
+sinew
+sinfonia
+sing
+singable
+Singapore
+singe
+singeing
+Singh
+single
+singlehanded
+singlet
+singleton
+singletree
+singsong
+singular
+sinh
+sinister
+sinistral
+sink
+sinkhole
+sinter
+sinuous
+sinus
+sinusitis
+sinusoid
+Siobhan
+Sioux
+sip
+siphon
+sir
+sire
+siren
+Sirius
+sirloin
+sirocco
+Sis
+sisal
+siskin
+sissified
+sissy
+sister
+Sistine
+Sisyphean
+Sisyphian
+Sisyphus
+sit
+sitcom
+site
+situ
+situate
+situs
+six
+sixfold
+sixgun
+sixpence
+sixteen
+sixteenth
+sixth
+sixtieth
+sixty
+sixtyish
+size
+sizzle
+skat
+skate
+skateboard
+skedaddle
+skeet
+skein
+skeletal
+skeleton
+skelter
+skeptic
+sketch
+sketchbook
+sketchpad
+skew
+ski
+skid
+skied
+skiff
+skiing
+skill
+skillet
+skillful
+skim
+skimp
+skin
+skindive
+skinflint
+skinhead
+skink
+skip
+skipjack
+Skippy
+skirl
+skirmish
+skirt
+skit
+skittish
+skittle
+skivvy
+skoal
+skua
+skulduggery
+skulk
+skull
+skullcap
+skullduggery
+skunk
+sky
+skycap
+skydive
+Skye
+skyhook
+skyjack
+skylark
+skylight
+skyline
+skyrocket
+skysail
+skyscrape
+skyward
+skywave
+skyway
+skywrite
+S&L
+slab
+slack
+slacken
+slag
+slain
+slake
+slalom
+slam
+slander
+slanderous
+slang
+slant
+slantwise
+slap
+slapdash
+slaphappy
+slapstick
+slash
+slat
+slate
+slather
+slattern
+slaughter
+slaughterhouse
+Slav
+slave
+slavehold
+slavery
+Slavic
+slavish
+slaw
+slay
+sleaze
+sled
+sledge
+sledgehammer
+sleek
+sleep
+sleeplike
+sleepwalk
+sleepyhead
+sleet
+sleeve
+sleigh
+sleight
+slender
+slept
+sleuth
+slew
+slice
+slick
+slid
+slide
+slight
+slim
+slime
+sling
+slingshot
+slink
+slip
+slipcase
+slipcover
+slipknot
+slippage
+slippery
+slipshod
+slipstream
+slipup
+slit
+slither
+slithery
+sliver
+slivery
+slivovitz
+Sloan
+Sloane
+slob
+slobber
+Slocum
+sloe
+slog
+slogan
+sloganeer
+sloop
+slop
+slope
+slosh
+slot
+sloth
+slouch
+slough
+sloven
+slow
+slowdown
+slowish
+slowpoke
+sludge
+slug
+slugfest
+sluggard
+sluggish
+sluice
+sluiceway
+slum
+slumber
+slump
+slung
+slunk
+slur
+slurp
+slurry
+slush
+slushy
+slut
+sluttish
+sly
+smack
+small
+Smalley
+smallish
+smallpox
+smalltime
+smarmy
+smart
+smarten
+smash
+smashup
+smatter
+smear
+smell
+smelly
+smelt
+smidgen
+smile
+smirch
+smirk
+smite
+smith
+smithereens
+Smithfield
+Smithson
+Smithsonian
+smithy
+smitten
+smock
+smog
+smoke
+smokehouse
+smokeproof
+smokescreen
+smokestack
+smolder
+smooch
+smooth
+smoothbore
+smorgasbord
+smote
+smother
+Smucker
+smudge
+smug
+smuggle
+smut
+Smyrna
+Smythe
+snack
+snaffle
+snafu
+snag
+snail
+snake
+snakebird
+snakebite
+snakeroot
+snap
+snapback
+snapdragon
+snappish
+snapshot
+snare
+snark
+snarl
+snarly
+snatch
+snazzy
+sneak
+sneer
+sneeze
+snell
+snick
+snide
+sniff
+sniffle
+snifter
+snigger
+sniggle
+sniggly
+snip
+snipe
+sniperscope
+snippet
+snit
+snitch
+snivel
+snob
+snobbery
+snobbish
+snook
+snoop
+snoot
+snooze
+snore
+snorkel
+snort
+snotty
+snout
+snow
+snowball
+snowbird
+snowbound
+snowcapped
+snowdrift
+snowdrop
+snowfall
+snowfield
+snowflake
+snowmobile
+snowplow
+snowshed
+snowshoe
+snowslide
+snowstorm
+snowsuit
+snub
+snuff
+snuffbox
+snuffle
+snug
+snuggle
+snuggly
+Snyder
+so
+soak
+soap
+soapbox
+soapstone
+soapsud
+soar
+sob
+sober
+soberside
+sobriety
+sobriquet
+Soc.
+soccer
+sociable
+social
+socialite
+societal
+Societe
+society
+socioeconomic
+sociology
+sociometry
+sociopath
+sock
+socket
+sockeye
+Socrates
+Socratic
+sod
+soda
+sodden
+sodium
+Sodom
+sodomite
+sodomize
+sodomy
+sofa
+soffit
+Sofia
+soft
+softball
+soften
+softhead
+softhearted
+software
+softwood
+soggy
+soignee
+soil
+soilage
+soiree
+sojourn
+Sol
+solace
+solar
+solarium
+sold
+solder
+soldier
+soldiery
+sole
+solecism
+solemn
+solemnity
+solenoid
+solicit
+solicitation
+solicitor
+solicitous
+solicitude
+solid
+solidarity
+solidify
+solidus
+soliloquist
+soliloquize
+soliloquy
+solipsism
+solipsist
+solitaire
+solitary
+soliton
+solitude
+solo
+Solomon
+Solomonic
+Solon
+solstice
+soluble
+solute
+solvate
+solve
+solvent
+Somali
+Somalia
+somatic
+somber
+sombrero
+some
+somebody
+somebody'd
+someday
+somehow
+someone
+someplace
+Somers
+somersault
+Somerset
+Somerville
+something
+sometime
+somewhat
+somewhere
+sommelier
+Sommerfeld
+somnambulate
+somnambulist
+somnolent
+son
+sonar
+sonata
+sonatina
+song
+songbag
+songbird
+songbook
+songfest
+songwrite
+Sonia
+sonic
+sonnet
+sonneteer
+sonny
+sonogram
+Sonoma
+Sonora
+sonority
+sonorous
+Sony
+Sonya
+soon
+soot
+sooth
+soothe
+soothsay
+sop
+Sophia
+Sophie
+sophism
+sophist
+sophisticate
+sophistry
+Sophoclean
+Sophocles
+sophomore
+sophomoric
+soporific
+soprano
+sora
+sorb
+Sorbonne
+sorcerer
+sorceress
+sorcery
+sordid
+sore
+sorehead
+Sorensen
+Sorenson
+sorghum
+sorority
+sorption
+sorrel
+sorrow
+sorry
+sort
+sortie
+sostenuto
+sot
+Soto
+sottish
+sou
+souffle
+sought
+soul
+sound
+soundboard
+soundproof
+soup
+sour
+source
+sourdough
+sourpuss
+sourwood
+Sousa
+souse
+soutane
+south
+Southampton
+southbound
+southeast
+southeastern
+southeasternmost
+southeastward
+southern
+southernmost
+Southey
+southland
+southmost
+southpaw
+southward
+southwest
+southwestern
+southwesternmost
+southwestward
+souvenir
+sou'wester
+sovereign
+sovereignty
+soviet
+sovkhoz
+sow
+sowbelly
+sown
+sox
+soy
+soya
+soybean
+S&P
+spa
+space
+spacecraft
+spacesuit
+spacious
+spackle
+spade
+spadework
+spaghetti
+Spain
+spake
+spall
+spallation
+span
+spandrel
+spangle
+Spaniard
+spaniel
+Spanish
+spank
+spar
+spare
+spareribs
+sparge
+spark
+sparkle
+Sparkman
+sparkplug
+sparling
+sparrow
+sparse
+Sparta
+Spartan
+spasm
+spasmodic
+spastic
+spat
+spate
+spatial
+spatiotemporal
+spatterdock
+spatula
+Spaulding
+spavin
+spawn
+spay
+spayed
+speak
+speakeasy
+spear
+spearhead
+spearmint
+spec
+special
+specialty
+speciation
+specie
+species
+specific
+specify
+specimen
+specious
+speck
+speckle
+spectacle
+spectacular
+spectator
+specter
+spectra
+spectral
+spectrograph
+spectrography
+spectroheliograph
+spectrometer
+spectrophotometer
+spectroscope
+spectroscopy
+spectrum
+specular
+speculate
+speculum
+sped
+speech
+speechify
+speed
+speedboat
+speedometer
+speedster
+speedup
+speedway
+speedwell
+speleology
+spell
+spellbind
+spellbound
+spelunker
+spelunking
+Spence
+Spencer
+Spencerian
+spend
+spendthrift
+spent
+speramtozoon
+sperm
+spermatophyte
+spermatozoa
+spermicide
+Sperry
+spew
+sphagnum
+sphere
+spheric
+spheroid
+spherule
+sphincter
+sphinx
+sphygmometer
+Spica
+spice
+spicebush
+spicule
+spider
+spidery
+Spiegel
+spiel
+spiffy
+spigot
+spike
+spikenard
+spill
+spillage
+spillway
+spilt
+spin
+spinach
+spinal
+spindle
+spindly
+spine
+spinet
+spinnaker
+spinneret
+spinodal
+spinoff
+spinor
+spinster
+spiral
+spire
+spirit
+spiritual
+Spiro
+spirochete
+spit
+spitball
+spite
+spitfire
+spittle
+spittoon
+spitz
+splash
+splat
+splay
+splayed
+splayfoot
+spleen
+splendid
+splendiferous
+splendor
+splenetic
+splice
+spline
+splint
+splintery
+split
+splotch
+splurge
+splutter
+spoil
+spoilage
+spoilsman
+spoilsport
+Spokane
+spoke
+spoken
+spokes
+spokeshave
+spoliate
+spondaic
+sponge
+sponson
+sponsor
+spontaneity
+spontaneous
+spoof
+spook
+spool
+spoon
+spoonbill
+spoor
+sporadic
+spore
+sporran
+sport
+sportive
+sports
+sportscast
+sportsman
+sportswear
+sportswrite
+sportswriting
+spot
+spotlight
+spouse
+spout
+Sprague
+sprain
+sprang
+sprawl
+spray
+spread
+spree
+sprig
+sprightly
+spring
+springboard
+springe
+Springfield
+springhouse
+springtail
+springtime
+sprinkle
+sprint
+sprite
+sprocket
+Sproul
+sprout
+spruce
+sprue
+sprung
+spry
+spud
+spume
+spumoni
+spun
+spunk
+spur
+spurge
+spurious
+spurn
+spurt
+sputnik
+sputter
+sputum
+spy
+spyglass
+squab
+squabble
+squad
+squadron
+squalid
+squall
+squally
+squalor
+squamous
+squander
+square
+squarish
+squash
+squat
+squaw
+squawk
+squawroot
+squeak
+squeal
+squeamish
+squeegee
+squeeze
+squelch
+squib
+Squibb
+squid
+squiggle
+squiggly
+squill
+squint
+squire
+squirm
+squirrel
+squirt
+squish
+Sr.
+Sri
+s's
+SSE
+SST
+SSW
+St.
+stab
+stabile
+stable
+staccato
+Stacey
+stack
+Stacy
+stadia
+stadium
+staff
+Stafford
+stag
+stage
+stagecoach
+stagecraft
+stagehand
+stagestruck
+stagger
+stagnant
+stagnate
+Stahl
+staid
+stain
+stair
+staircase
+stairway
+stairwell
+stake
+stakehold
+stalactite
+stalag
+stalagmite
+stale
+stalemate
+Staley
+Stalin
+stalk
+stall
+stallion
+stalwart
+stamen
+Stamford
+stamina
+staminate
+stammer
+stamp
+stampede
+Stan
+stance
+stanch
+stanchion
+stand
+standard
+standby
+standbys
+standee
+standeth
+Standish
+standoff
+standoffish
+standout
+standpipe
+standpoint
+standstill
+standup
+Stanford
+Stanhope
+stank
+Stanley
+stannic
+stannous
+Stanton
+stanza
+staph
+staphylococcus
+staple
+Stapleton
+star
+starboard
+starch
+stardom
+stardust
+stare
+starfish
+stargaze
+stark
+Starkey
+starlet
+starlight
+starling
+starlit
+Starr
+start
+startle
+startup
+starvation
+starve
+starveling
+stash
+stasis
+state
+statecraft
+statehouse
+Staten
+stater
+stateroom
+states
+stateside
+statewide
+static
+stationarity
+stationary
+stationery
+stationmaster
+statistician
+Statler
+stator
+statuary
+statue
+statuesque
+statuette
+stature
+status
+statute
+statutory
+Stauffer
+staunch
+Staunton
+stave
+stay
+stayed
+staysail
+Ste.
+stead
+steadfast
+steady
+steak
+steal
+stealth
+steam
+steamboat
+steamroll
+stearate
+stearic
+Stearns
+steed
+steel
+Steele
+steelhead
+steelwork
+steely
+steelyard
+Steen
+steep
+steepen
+steeple
+steeplebush
+steeplechase
+steeplejack
+steer
+steerage
+steersman
+steeve
+Stefan
+stegosaurus
+stein
+Steinberg
+steinbok
+Steiner
+stela
+stele
+Stella
+stellar
+stellate
+stem
+stemware
+stench
+stencil
+steno
+stenography
+stenotype
+stentorian
+step
+stepbrother
+stepchild
+stepchildren
+stepdaughter
+stepfather
+Stephanie
+Stephen
+Stephens
+Stephenson
+stepladder
+stepmother
+steppe
+stepsister
+stepson
+stepwise
+steradian
+stere
+stereo
+stereography
+stereopsis
+stereopticon
+stereoscopy
+steric
+sterile
+sterling
+stern
+sternal
+sternmost
+Sterno
+sternpost
+sternum
+steroid
+stet
+stethoscope
+Stetson
+Steuben
+Steve
+stevedore
+Steven
+Stevens
+Stevenson
+stew
+steward
+stewardess
+Stewart
+stick
+stickle
+stickpin
+sticktight
+stickup
+stickwork
+sticky
+stiff
+stiffen
+stifle
+stigma
+stigmata
+stigmatic
+stigmatize
+stile
+stiletto
+still
+stillbirth
+stillborn
+stillwater
+stilt
+stimulant
+stimulate
+stimuli
+stimulus
+sting
+stink
+stinkbug
+stinkpot
+stint
+stipend
+stipple
+stipulate
+stir
+Stirling
+stirrup
+stitch
+stoat
+stochastic
+stock
+stockade
+stockbroker
+stockholder
+Stockholm
+stockpile
+stockpot
+stockroom
+Stockton
+stockyard
+stodgy
+stogy
+stoic
+stoichiometry
+stoke
+stole
+stolen
+stolid
+stolon
+stoma
+stomach
+stomachs
+stomp
+stone
+stonecrop
+stonecut
+Stonehenge
+stonemason
+stonewall
+stoneware
+stonework
+stood
+stooge
+stool
+stoolie
+stoop
+stop
+stopcock
+stopgap
+stoplight
+stopover
+stoppage
+stopwatch
+storage
+store
+storehouse
+storeown
+storeroom
+storewide
+Storey
+stork
+storm
+stormbound
+story
+storyboard
+storybook
+storytell
+stout
+stouthearted
+stove
+stovepipe
+stow
+stowage
+stowaway
+strabismic
+strabismus
+straddle
+strafe
+straggle
+straggly
+straight
+straightaway
+straightedge
+straighten
+straightforward
+straightway
+strain
+strait
+straiten
+straitjacket
+straitlaced
+strake
+strand
+strange
+strangle
+stranglehold
+strangulate
+strap
+straphanger
+strata
+stratagem
+strategic
+strategist
+strategy
+Stratford
+stratify
+stratigraphy
+stratocumulus
+stratosphere
+stratospheric
+Stratton
+stratum
+stratus
+Strauss
+straw
+strawberry
+strawflower
+stray
+streak
+stream
+streamlet
+streamline
+streamside
+street
+streetcar
+streetwalk
+strength
+strengthen
+strenuous
+strep
+streptococcus
+streptomycin
+stress
+stretch
+stretchy
+strew
+strewn
+striate
+stricken
+Strickland
+strict
+stricter
+stricture
+stride
+strident
+strife
+strike
+strikebound
+strikebreak
+strikeout
+string
+stringent
+strip
+stripe
+stripling
+striptease
+strive
+striven
+strobe
+stroboscope
+strode
+stroganoff
+stroke
+stroll
+Strom
+Stromberg
+strong
+strongbox
+stronghold
+strongish
+strongroom
+strontium
+strop
+strophe
+strove
+struck
+structural
+structure
+strudel
+struggle
+strum
+strumpet
+strung
+strut
+strychnine
+Stu
+Stuart
+stub
+stubble
+stubborn
+stucco
+stuck
+stud
+Studebaker
+student
+studio
+studious
+study
+stuff
+stultify
+stumble
+stumblebum
+stump
+stumpage
+stun
+stung
+stunk
+stunt
+stupefaction
+stupefy
+stupendous
+stupid
+stupor
+Sturbridge
+sturdy
+sturgeon
+Sturm
+stutter
+Stuttgart
+Stuyvesant
+sty
+stye
+Stygian
+style
+styli
+stylish
+stylites
+stylus
+stymie
+styptic
+styrene
+Styrofoam
+Styx
+suasion
+suave
+sub
+Subaru
+subdeb
+subdue
+subito
+subject
+subjectivity
+sublimate
+sublimer
+subliminal
+submersible
+submersion
+submit
+submittal
+suborn
+subpoena
+subpoenaed
+subrogation
+subservient
+subsidence
+subsidiary
+subsidy
+subsist
+subsistent
+substance
+substantial
+substantiate
+substantive
+substituent
+substitute
+substitutionary
+substrate
+subsume
+subsumed
+subsuming
+subsumption
+subterfuge
+subterranean
+subtext
+subtle
+subtlety
+subtly
+subtracter
+subtrahend
+suburb
+suburbia
+subvent
+subvert
+succeed
+success
+succession
+successor
+succinct
+succor
+succotash
+succubus
+succulent
+succumb
+such
+suck
+suckle
+suckling
+sucrose
+suction
+Sudan
+Sudanese
+sudden
+suds
+sudsy
+sue
+suede
+suet
+suey
+Suez
+suffer
+sufferance
+suffice
+sufficient
+suffix
+suffocate
+Suffolk
+suffragan
+suffrage
+suffragette
+suffuse
+suffusion
+sugar
+sugarcane
+sugarhouse
+sugarloaf
+sugarplum
+suggest
+suggestible
+suggestion
+suicidal
+suicide
+suit
+suitcase
+suite
+suitor
+sukiyaki
+sulfa
+sulfanilamide
+sulfate
+sulfide
+sulfite
+sulfonamide
+sulfur
+sulfuric
+sulfurous
+sulk
+sulky
+sullen
+Sullivan
+sully
+sultan
+sultanate
+sultry
+sum
+sumac
+Sumatra
+Sumerian
+summa
+summand
+summarily
+summarize
+summary
+summation
+summer
+summersault
+summertime
+summit
+summitry
+summon
+summons
+Sumner
+sump
+sumptuous
+Sumter
+sun
+sunbaked
+sunbath
+sunbathe
+sunbathing
+sunbeam
+sunbonnet
+sunbow
+sunburn
+sunburnt
+sunburst
+sundae
+Sunday
+sunder
+sundew
+sundial
+sundown
+sundry
+sunfish
+sunflower
+sung
+sunglasses
+sunk
+sunken
+sunlamp
+sunlight
+sunlit
+Sunni
+Sunnyvale
+sunrise
+sunscreen
+sunset
+sunshade
+sunshine
+sunspot
+sunstroke
+sunstruck
+sunsuit
+suntan
+sunup
+SUNY
+sup
+super
+superannuate
+superb
+superbly
+supercilious
+superficial
+superfluity
+superfluous
+superintendent
+superior
+superlunary
+supernatant
+supernovae
+supernumerary
+supersede
+superstar
+superstition
+superstitious
+supervene
+supervention
+supervise
+supervisory
+supine
+supplant
+supple
+supplely
+supplementary
+supplementation
+suppliant
+supplicant
+supplicate
+supply
+support
+supposal
+suppose
+supposition
+suppositious
+suppository
+suppress
+suppressant
+suppressible
+suppression
+suppressor
+suppurate
+supra
+supramolecular
+supranational
+suprema
+supremacist
+supremacy
+supreme
+supremum
+surcease
+surcharge
+surcoat
+surd
+sure
+surefire
+surefooted
+surety
+surf
+surface
+surfactant
+surfboard
+surfboat
+surfeit
+surge
+surgeon
+surgery
+surgical
+surly
+surmise
+surmount
+surname
+surpass
+surplice
+surplus
+surprint
+surprise
+surreal
+surrender
+surreptitious
+surrey
+surrogate
+surround
+surtax
+surtout
+surveillant
+survey
+surveyor
+survival
+survive
+survivor
+Sus
+Susan
+Susanna
+Susanne
+susceptance
+susceptible
+sushi
+Susie
+suspect
+suspend
+suspense
+suspension
+suspensor
+suspicion
+suspicious
+Sussex
+sustain
+sustenance
+Sutherland
+sutra
+Sutton
+suture
+Suzanne
+suzerain
+suzerainty
+Suzuki
+svelte
+Sven
+SW
+swab
+swaddle
+swag
+swage
+swagger
+Swahili
+swain
+swale
+swallow
+swallowtail
+swam
+swami
+swamp
+swampland
+swan
+swank
+swansdown
+Swanson
+swap
+sward
+swarm
+swart
+Swarthmore
+Swarthout
+swarthy
+swash
+swashbuckle
+swastika
+swat
+swatch
+swath
+swathe
+sway
+swayback
+Swaziland
+swear
+swearword
+sweat
+sweatband
+sweatshirt
+sweatshop
+Swede
+Sweden
+Swedish
+Sweeney
+sweep
+sweepstake
+sweet
+sweetbread
+sweeten
+sweetheart
+sweetie
+sweetish
+sweetmeat
+sweetshop
+swell
+swelter
+Swenson
+swept
+swerve
+swift
+swig
+swill
+swim
+swimsuit
+swindle
+swine
+swineherd
+swing
+swingable
+swinish
+swipe
+swirl
+swirly
+swish
+swiss
+switch
+switchback
+switchblade
+switchboard
+switchgear
+switchyard
+Switzer
+Switzerland
+swivel
+swizzle
+swollen
+swoon
+swoop
+swoosh
+sword
+swordfish
+swordplay
+swords
+swordtail
+swore
+sworn
+swum
+swung
+sybarite
+Sybil
+sycamore
+sycophant
+sycophantic
+Sydney
+Sykes
+syllabary
+syllabic
+syllabify
+syllable
+syllabus
+syllogism
+syllogistic
+sylph
+sylvan
+Sylvania
+Sylvester
+Sylvia
+sylviculture
+symbiont
+symbiosis
+symbiotic
+symbol
+symbolic
+symbology
+symmetrize
+symmetry
+sympathetic
+sympathize
+sympathy
+sympatric
+symphonic
+symphony
+symposia
+symposium
+symptom
+symptomatic
+synagogue
+synapse
+synaptic
+sync
+synch
+synchromesh
+synchronic
+synchronism
+synchronize
+synchronous
+synchrony
+synchrotron
+syncline
+syncopate
+syndic
+syndicate
+syndrome
+synecdoche
+synergetic
+synergism
+synergist
+synergistic
+synergy
+synod
+synodic
+synonym
+synonymous
+synonymy
+synopses
+synopsis
+synopsize
+synoptic
+syntactic
+syntax
+syntheses
+synthesis
+synthesize
+synthetic
+syphilis
+syphilitic
+Syracuse
+Syria
+syringa
+syringe
+syrinx
+syrup
+system
+systematic
+systematize
+systemic
+systemization
+systemwide
+systole
+systolic
+syzygy
+tab
+tabby
+tabernacle
+tablature
+table
+tableau
+tableaux
+tablecloth
+tableland
+tablespoon
+tablet
+tabletop
+tableware
+tabloid
+taboo
+tabu
+tabula
+tabular
+tabulate
+tachinid
+tachistoscope
+tachometer
+tacit
+taciturn
+Tacitus
+tack
+tackle
+taco
+Tacoma
+tact
+tactic
+tactician
+tactile
+taction
+tactual
+tad
+tadpole
+taffeta
+taffrail
+taffy
+Taft
+tag
+Tagalog
+tagalong
+Tahiti
+Tahitian
+Tahoe
+tail
+tailback
+tailcoat
+tailgate
+taillight
+tailor
+tailpiece
+tailpipe
+tailrace
+tailspin
+tailstock
+tailwind
+taint
+Taipei
+Taiwan
+Taiwanese
+Tajikistan
+take
+takedown
+taken
+takeoff
+takeout
+takeover
+taketh
+talc
+talcum
+tale
+talebear
+talent
+talisman
+talismanic
+talk
+talkative
+talkie
+tall
+Tallahassee
+tallish
+tallow
+tally
+tallyho
+Talmud
+talmudic
+talon
+talus
+tam
+tamale
+Tamara
+tamarack
+tamarind
+tamarisk
+tambour
+tambourine
+tame
+Tamil
+Tammany
+Tammy
+tamp
+Tampa
+tamper
+tampon
+tan
+tanager
+Tanaka
+Tananarive
+tanbark
+tandem
+tang
+tangelo
+tangent
+tangential
+tangerine
+tangible
+tangle
+tango
+tangy
+tanh
+tank
+tankard
+tannery
+tannest
+tannin
+tansy
+tantalize
+tantalum
+Tantalus
+tantamount
+tantrum
+Tanya
+Tanzania
+tao
+Taoist
+Taos
+tap
+tapa
+tape
+taper
+tapestry
+tapeworm
+tapioca
+tapir
+tapis
+tappet
+taproom
+taproot
+tapster
+tar
+tarantara
+tarantella
+tarantula
+Tarbell
+tardy
+target
+Tarheel
+tariff
+tarmac
+tarn
+tarnish
+tarp
+tarpaper
+tarpaulin
+tarpon
+tarragon
+tarry
+Tarrytown
+tart
+tartan
+tartar
+Tartary
+tartrate
+Tarzan
+task
+taskmaster
+taskmistress
+Tasmania
+Tass
+tassel
+taste
+tasting
+tasty
+tat
+Tate
+tater
+tattle
+tattler
+tattletale
+tattoo
+tau
+taught
+taunt
+Taurus
+taut
+tauten
+tautologous
+tautology
+tautonym
+tavern
+taverna
+tawdry
+tawny
+tax
+taxa
+taxation
+taxi
+taxicab
+taxidermic
+taxidermist
+taxidermy
+taxied
+taxiing
+taximeter
+taxiway
+taxon
+taxonomist
+taxonomy
+taxpay
+Taylor
+TB
+tea
+teacart
+teach
+teacup
+teahouse
+teak
+teakettle
+teakwood
+teal
+team
+teammate
+teamster
+teamwork
+teapot
+tear
+teardrop
+tearjerk
+tearoom
+tease
+teasel
+teaspoon
+teat
+teatime
+tech
+technetium
+technic
+technician
+technicolor
+technique
+technocracy
+technocrat
+technocratic
+technology
+tectonic
+tecum
+ted
+teddy
+tedious
+tedium
+tee
+teem
+teen
+teenage
+teensy
+teepee
+teeter
+teeterboard
+teeth
+teethe
+teetotal
+Teflon
+Tegucigalpa
+tegument
+Teheran
+Tehran
+tektite
+Tektronix
+telecom
+Teledyne
+Telefunken
+telegenic
+telegraphy
+telekinesis
+teleology
+telepathic
+telepathy
+telephone
+telephony
+telethon
+Telex
+tell
+telltale
+tellurium
+temblor
+temerity
+temper
+tempera
+temperance
+temperate
+temperature
+tempest
+tempestuous
+template
+temple
+Templeton
+tempo
+temporal
+temporary
+temporize
+tempt
+temptation
+temptress
+tempura
+ten
+tenable
+tenacious
+tenacity
+tenant
+tenantry
+tend
+tendency
+tendentious
+tender
+tenderfeet
+tenderfoot
+tenderhearted
+tenderloin
+tendinitis
+tendon
+tendril
+tenebrous
+tenement
+tenet
+tenfold
+Tenneco
+Tennessee
+Tenney
+tennis
+Tennyson
+tenon
+tenor
+tense
+tensile
+tension
+tensional
+tensor
+tenspot
+tent
+tentacle
+tentage
+tentative
+tenterhook
+tenth
+tenuous
+tenure
+tepee
+tepid
+tequila
+teratogen
+teratogenic
+teratology
+terbium
+tercel
+tercentenary
+teredo
+Terence
+Teresa
+tergiversate
+teriyaki
+term
+termagant
+terminable
+terminal
+terminate
+termini
+terminology
+terminus
+termite
+tern
+ternary
+terpene
+Terpsichore
+terpsichorean
+Terra
+terrace
+terrain
+terramycin
+terrapin
+terrarium
+terrazzo
+Terre
+Terrell
+Terrence
+terrestrial
+Terri
+terrible
+terrier
+terrific
+terrify
+territorial
+territory
+terror
+terry
+terse
+tertiary
+Tess
+tessellate
+tessera
+tesserae
+tessitura
+test
+testament
+testamentary
+testate
+testbed
+testes
+testicle
+testicular
+testify
+testimonial
+testimony
+testosterone
+tetanus
+tetched
+tetchy
+tete
+tether
+tetherball
+Teton
+tetrachloride
+tetracycline
+tetrad
+tetraethyl
+tetrafluoride
+tetrafluouride
+tetragonal
+tetragrammaton
+tetrahedra
+tetrahedral
+tetrahedron
+tetralogy
+tetraploid
+tetravalent
+tetrode
+Teutonic
+Texaco
+Texan
+Texas
+text
+textbook
+textile
+Textron
+textual
+textural
+texture
+TGV
+Thadeus
+Thai
+Thailand
+thalamus
+Thalia
+thallium
+thallophyte
+Thames
+than
+thane
+thank
+thanksgiving
+that
+thatch
+that'll
+thaumaturgic
+thaumaturgy
+thaw
+Thayer
+the
+Thea
+theater
+theatergoer
+theatergoing
+theatric
+Thebes
+thee
+theft
+their
+theirs
+theism
+theist
+Thelma
+them
+thematic
+theme
+themselves
+then
+thence
+thenceforth
+Theo
+theocracy
+theocratic
+theodolite
+Theodore
+theogony
+theologian
+theology
+theorem
+theoretic
+theoretician
+theorist
+theorize
+theory
+theosophy
+therapeutic
+therapist
+therapy
+there
+thereabouts
+thereafter
+thereat
+thereby
+there'd
+therefore
+therefrom
+therein
+there'll
+thereof
+thereon
+Theresa
+Therese
+thereto
+theretofore
+thereunder
+thereunto
+thereupon
+therewith
+therm
+thermal
+thermionic
+thermistor
+thermo
+Thermofax
+thermography
+thermophile
+thermophilic
+thermostat
+thesaurus
+these
+Theseus
+thesis
+thespian
+Thessalonian
+theta
+Thetis
+they
+they'd
+they'll
+they're
+they've
+thiamin
+thiamine
+thick
+thicken
+thicket
+thickheaded
+thickish
+thickset
+thief
+thieve
+thievery
+thievish
+thigh
+thimble
+Thimbu
+thin
+thine
+thing
+thingamajig
+think
+thinnish
+thiocyanate
+thiouracil
+third
+thirst
+thirteen
+thirteenth
+thirtieth
+thirty
+thirtyish
+this
+this'll
+thistle
+thistledown
+thither
+Thomas
+Thomistic
+Thompson
+Thomson
+thong
+Thor
+thorax
+Thoreau
+thorium
+thorn
+Thornton
+thorough
+thoroughbred
+thoroughfare
+thoroughgoing
+Thorpe
+Thorstein
+those
+thou
+though
+thought
+thousand
+thousandfold
+thousandth
+thraldom
+thrall
+thrash
+thread
+threadbare
+threat
+threaten
+three
+threefold
+threesome
+threnody
+thresh
+threshold
+threw
+thrice
+thrift
+thrill
+thrips
+thrive
+throat
+throb
+throes
+thrombosis
+thrombus
+throne
+throng
+throttle
+through
+throughout
+throughput
+throughway
+throve
+throw
+throwaway
+throwback
+thrown
+thrum
+thrush
+thrust
+Thruway
+Thu.
+Thuban
+thud
+thug
+thuggee
+thuggery
+thuggish
+Thule
+thulium
+thumb
+thumbnail
+thumbprint
+thumbscrew
+thumbtack
+thump
+thunder
+thunderbird
+thunderbolt
+thunderclap
+thundercloud
+thunderhead
+thunderous
+thundershower
+thunderstorm
+Thurman
+Thursday
+Thurston
+thus
+thwack
+thwart
+thy
+thyme
+thymine
+thyratron
+thyroid
+thyroidectomy
+thyroxine
+thyself
+ti
+tiara
+Tiber
+Tibet
+Tibetan
+tibia
+Tibor
+tic
+tick
+ticket
+tickle
+ticklish
+tidal
+tidbit
+tide
+tideland
+tidewater
+tidy
+tie
+tieback
+tiedown
+Tientsin
+tiff
+tiffany
+tiger
+tigerish
+tight
+tighten
+tightfisted
+tightrope
+tightwad
+tightwire
+tigress
+Tigris
+til
+tilde
+tile
+till
+tillage
+tilt
+tilth
+Tim
+timber
+timberland
+timberline
+timbre
+time
+timeout
+timepiece
+timesave
+timeserve
+timeshare
+timetable
+timeworn
+Timex
+timid
+Timon
+timorous
+timothy
+timpani
+timpanist
+tin
+Tina
+tincture
+tinder
+tinderbox
+tine
+tinfoil
+tinge
+tingle
+tinhorn
+tinker
+Tinkertoy
+tinkle
+tinkly
+tinplate
+tinsel
+tinsmith
+tint
+tintinnabulate
+tintype
+tinware
+Tioga
+tip
+tipoff
+Tipperary
+tipple
+tipster
+tipsy
+tiptoe
+tirade
+Tirana
+tire
+tiresome
+tissue
+tit
+titan
+titanate
+titanic
+titanium
+titer
+tithe
+tithing
+titian
+titillate
+title
+titmouse
+titrate
+tittle
+titular
+Titus
+TLC
+TN
+TNT
+to
+toad
+toadstool
+toady
+toast
+toastmaster
+toastmistress
+tobacco
+tobacconist
+Tobago
+Tobias
+toboggan
+Toby
+toccata
+tocsin
+today
+Todd
+toddle
+toddy
+toe
+toehold
+toeing
+toenail
+toffee
+tofu
+tog
+together
+toggery
+toggle
+Togo
+togs
+toil
+toilet
+toiletry
+toilette
+toilsome
+toilworn
+tokamak
+token
+Tokyo
+told
+Toledo
+tolerable
+tolerant
+tolerate
+toll
+tollbooth
+tollgate
+tollhouse
+Tolstoy
+toluene
+Tom
+tomahawk
+tomato
+tomatoes
+tomb
+tomboy
+tomboyish
+tombstone
+tomcat
+tome
+tomfoolery
+Tomlinson
+Tommie
+tommy
+tommyrot
+tomograph
+tomography
+tomorrow
+Tompkins
+ton
+tonal
+tone
+tong
+tongue
+Toni
+tonic
+tonight
+tonnage
+tonne
+tonneau
+tonsil
+tonsillectomy
+tonsillitis
+tonsorial
+tonsure
+Tonya
+too
+toodle
+took
+tool
+toolbox
+toolholder
+toolkit
+toolroom
+toolshed
+toolsmith
+toot
+tooth
+toothache
+toothbrush
+toothpaste
+toothpick
+toothsome
+tootle
+top
+topaz
+topcoat
+Topeka
+toper
+topflight
+topgallant
+topiary
+topic
+topkick
+topknot
+topmast
+topmost
+topnotch
+topo
+topocentric
+topography
+topology
+topple
+topsail
+topside
+topsoil
+topsy
+toque
+Torah
+torch
+torchbearer
+torchlight
+tore
+toreador
+tori
+torment
+torn
+tornado
+tornadoes
+toroid
+Toronto
+torpedo
+torpedoes
+torpid
+torpor
+torque
+torr
+Torrance
+torrent
+torrential
+Torres
+torrid
+torsion
+torso
+tort
+torte
+tortellini
+tortilla
+tortious
+tortoise
+tortoiseshell
+tortoni
+tortuous
+torture
+torus
+Tory
+Toshiba
+toss
+tot
+total
+totaled
+totaling
+totalitarian
+totalizator
+tote
+totem
+totemic
+toucan
+touch
+touchback
+touchdown
+touche
+touchhole
+touchstone
+tough
+toughen
+toughie
+toupee
+tour
+touristy
+tourmaline
+tournament
+tourney
+tourniquet
+tousle
+tout
+tow
+toward
+towboat
+towel
+towhead
+towhee
+towline
+town
+townhouse
+towns
+Townsend
+townsfolk
+townspeople
+towpath
+towrope
+toxic
+toxicology
+toxin
+toy
+Toyota
+trace
+traceable
+tracery
+Tracey
+trachea
+tracheal
+tracheotomy
+track
+trackage
+trackwalker
+tract
+Tracy
+trade
+trademark
+tradeoff
+trades
+tradespeople
+tradition
+traduce
+traffic
+trafficked
+trafficker
+trafficking
+tragedian
+tragedienne
+tragedy
+tragic
+tragicomedy
+tragicomic
+trail
+trailblaze
+trailside
+train
+trainee
+trainload
+traipse
+trait
+traitor
+traitorous
+trajectory
+tram
+tramcar
+trammel
+tramp
+trample
+trampoline
+tramway
+Tran
+trance
+tranquil
+tranquillity
+transact
+transalpine
+transatlantic
+transceiver
+transcend
+transcendent
+transcendental
+transconductance
+transcontinental
+transcribe
+transcript
+transducer
+transduction
+transect
+transept
+transfer
+transferable
+transferal
+transferee
+transference
+transferor
+transfiguration
+transfigure
+transfinite
+transfix
+transform
+transformation
+transfuse
+transfusion
+transgenic
+transgress
+transgression
+transgressor
+transient
+transistor
+transit
+Transite
+transition
+transitory
+translate
+transliterate
+translocate
+translucent
+transmigrate
+transmissible
+transmission
+transmit
+transmittable
+transmittal
+transmittance
+transmogrify
+transmutation
+transmute
+transoceanic
+transom
+transpacific
+transparent
+transpiration
+transpire
+transplant
+transplantation
+transpolar
+transpond
+transport
+transportation
+transpose
+transposition
+transship
+transubstantiate
+transuranium
+transversal
+transverse
+transvestite
+trap
+trapdoor
+trapeze
+trapezium
+trapezoid
+traprock
+trapshoot
+trash
+Trastevere
+trauma
+traumatic
+traumatize
+travail
+travel
+travelogue
+traversal
+traverse
+travertine
+travesty
+Travis
+travois
+trawl
+tray
+treacherous
+treachery
+treacle
+tread
+treadle
+treadmill
+treason
+treasonous
+treasure
+treasury
+treat
+treatise
+treaty
+treble
+tree
+treehopper
+treetop
+trefoil
+trek
+trellis
+tremble
+tremendous
+tremolo
+tremor
+tremulous
+trench
+trenchant
+trencherman
+trenchermen
+trend
+Trenton
+trepan
+trepidation
+trespass
+tress
+trestle
+Trevelyan
+Trevor
+triable
+triac
+triad
+trial
+triangle
+triangular
+triangulate
+Triangulum
+Trianon
+Triassic
+triathlon
+triatomic
+triaxial
+tribal
+tribe
+tribes
+tribulate
+tribunal
+tribune
+tributary
+tribute
+trice
+Trichinella
+trichloride
+trichloroethane
+trick
+trickery
+trickle
+trickster
+tricolor
+tricorn
+tricornered
+tricot
+tricycle
+trident
+tridiagonal
+tried
+triennial
+triennium
+trifecta
+trifle
+trifluouride
+trifocal
+trifurcate
+trig
+trigger
+trigonal
+trigonometric
+trigonometry
+trigram
+trigraph
+trihedral
+trilateral
+trilingual
+trill
+trillion
+trillionth
+trilobite
+trilogy
+trim
+trimer
+trimester
+trimotor
+Trinidad
+trinitarian
+trinity
+trinket
+trinomial
+trio
+triode
+trioxide
+trip
+tripartite
+tripe
+triplane
+triple
+triplet
+Triplett
+triplex
+triplicate
+triploid
+tripod
+tripoli
+triptych
+trireme
+trisect
+trisodium
+Tristan
+tristate
+trisyllable
+trite
+tritiate
+tritium
+triton
+tritone
+triumph
+triumphal
+triumphant
+triumvir
+triumvirate
+triune
+trivalent
+trivia
+trivial
+trivium
+trochaic
+trochee
+trod
+trodden
+troglodyte
+troglodytic
+trogon
+troika
+Trojan
+troll
+trolley
+trolleybus
+trollop
+trombone
+trompe
+troop
+trope
+trophic
+trophy
+tropic
+tropism
+tropopause
+troposphere
+tropospheric
+trot
+troth
+troubadour
+trouble
+troubleshoot
+troublesome
+trough
+trounce
+troupe
+trouser
+trousseau
+trout
+Troutman
+trove
+trowel
+troy
+truancy
+truant
+truantry
+truce
+truck
+truckle
+truckload
+truculent
+trudge
+Trudy
+true
+truffle
+truism
+truly
+Truman
+Trumbull
+trump
+trumpery
+trumpet
+truncate
+truncheon
+trundle
+trunk
+trunnion
+truss
+trust
+trustbust
+trustee
+trustworthy
+trusty
+truth
+TRW
+try
+tryout
+trypsin
+tsar
+tsarina
+tsetse
+tsunami
+TTL
+TTY
+tub
+tuba
+tubby
+tube
+tubercle
+tubercular
+tuberculin
+tuberculosis
+tuberculous
+tuberous
+tubular
+tubule
+tuck
+Tucson
+Tudor
+Tue.
+Tuesday
+tufa
+tuff
+tuffet
+tuft
+tug
+tugboat
+tuition
+Tulane
+tulip
+tulle
+Tulsa
+tum
+tumble
+tumbledown
+tumbleweed
+tumbrel
+tumbril
+tumescent
+tumid
+tummy
+tumor
+tumpline
+tumuli
+tumult
+tumultuous
+tumulus
+tun
+tuna
+tundra
+tune
+tung
+tungstate
+tungsten
+tunic
+Tunis
+Tunisia
+tunnel
+tuppence
+turban
+turbid
+turbinate
+turbine
+turbo
+turbocharge
+turbofan
+turbojet
+turboprop
+turbot
+turbulent
+tureen
+turf
+turgid
+Turin
+Turing
+turk
+turkey
+Turkish
+Turkmenistan
+turmeric
+turmoil
+turn
+turnabout
+turnaround
+turnbuckle
+turncoat
+turndown
+turnery
+turnip
+turnkey
+turnoff
+turnout
+turnover
+turnpike
+turnstile
+turnstone
+turntable
+turnup
+turpentine
+turpitude
+turquoise
+turret
+turtle
+turtleback
+turtledove
+turtleneck
+turvy
+Tuscaloosa
+Tuscan
+Tuscany
+Tuscarora
+tusk
+Tuskegee
+tussle
+tussock
+tut
+tutelage
+tutelary
+tutor
+tutorial
+tutti
+Tuttle
+tutu
+tux
+tuxedo
+tuyere
+TV
+TVA
+TWA
+twaddle
+twain
+twang
+tweak
+tweed
+tween
+tweet
+tweeze
+twelfth
+twelve
+twentieth
+twenty
+twentyish
+twerp
+twice
+twiddle
+twig
+twilight
+twill
+twin
+twine
+twinge
+twinkle
+twinkly
+twirl
+twirly
+twist
+twit
+twitch
+twitter
+twixt
+two
+twofold
+Twombly
+twopenny
+twosome
+TWX
+TX
+Tyburn
+tycoon
+tying
+Tyler
+tympanist
+tympanum
+Tyndall
+type
+typecast
+typeface
+typescript
+typeset
+typewrite
+typewritten
+typhoid
+Typhon
+typhoon
+typhus
+typic
+typify
+typo
+typography
+typology
+tyrannic
+tyrannicide
+tyrannize
+tyrannosaurus
+tyrannous
+tyranny
+tyrant
+tyro
+tyrosine
+tyrranize
+Tyson
+UAL
+ubiquitous
+ubiquity
+UCLA
+udder
+Uganda
+ugh
+uglify
+ugly
+UHF
+UJA
+U.K.
+UK
+ukase
+Ukraine
+Ukrainian
+ukulele
+Ulan
+ulcer
+ulcerate
+ulcerous
+Ullman
+ulna
+ulster
+ulterior
+ultimacy
+ultimate
+ultimatum
+ultra
+ululate
+Ulysses
+umber
+umbilical
+umbilici
+umbilicus
+umbra
+umbrage
+umbrageous
+umbrella
+umiak
+umlaut
+umpire
+umpteen
+umpteenth
+U.N.
+UN
+unaided
+unanimity
+unanimous
+unarticulated
+unary
+unbeknown
+unbeknownst
+unbidden
+unborn
+uncanny
+unchristian
+uncial
+uncle
+uncompleted
+uncouth
+unction
+unctuous
+under
+underclassman
+underclassmen
+underlie
+underling
+underlying
+undulant
+undulate
+unending
+UNESCO
+unfertilized
+uniaxial
+unicameral
+unicellular
+unicorn
+unicycle
+unidimensional
+unidirectional
+uniform
+uniformitarian
+unify
+unilateral
+unimodal
+unimodular
+uninominal
+union
+uniplex
+unipolar
+uniprocessor
+unique
+Uniroyal
+unisex
+unisexual
+unison
+unit
+unitarian
+unitary
+unite
+unity
+Univac
+univalent
+univariate
+universal
+universe
+univocal
+Unix
+unkempt
+unlucky
+unmediated
+unmet
+unmoderated
+unperturbed
+unpolitical
+unportable
+unprovable
+unproved
+unruly
+unscented
+untainted
+until
+untilled
+unto
+untouchable
+unused
+unvented
+unwary
+unwieldy
+up
+upbeat
+upbraid
+upbring
+upchuck
+upcome
+update
+updraft
+upend
+upgrade
+upheaval
+upheave
+upheld
+uphill
+uphold
+upholster
+upholstery
+UPI
+upkeep
+upland
+uplift
+upload
+upmost
+upon
+upperclass
+uppercut
+uppermost
+uppity
+upraise
+uprear
+upright
+uprise
+uprisen
+upriver
+uproar
+uproarious
+uproot
+uprose
+upscale
+upset
+upshot
+upside
+upsilon
+upslope
+upstage
+upstairs
+upstand
+upstart
+upstate
+upstater
+upstream
+upstroke
+upsurge
+upsweep
+upswept
+upswing
+uptake
+upthrust
+uptilt
+uptime
+Upton
+uptown
+uptrend
+upturn
+upward
+upwell
+upwind
+uranium
+Uranus
+uranyl
+urban
+Urbana
+urbane
+urbanite
+urchin
+urea
+urethane
+urethra
+urge
+urgency
+urgent
+uric
+urinal
+urinalysis
+urinary
+urinate
+urine
+Uris
+urn
+urology
+Ursa
+ursine
+Ursula
+Ursuline
+Uruguay
+U.S.
+u's
+us
+U.S.A.
+USA
+USAF
+usage
+USC
+USC&GS
+USDA
+use
+useful
+USGS
+usher
+usherette
+USIA
+USMA
+USMC
+USN
+USNA
+USNR
+USPS
+USSR
+usual
+usurer
+usurious
+usurp
+usurpation
+usury
+UT
+Utah
+utensil
+uterine
+utero
+uterus
+Utica
+utile
+utilitarian
+utmost
+utopia
+utopian
+utter
+utterance
+uttermost
+uvula
+uxorial
+uxorious
+Uzbekistan
+Uzi
+VA
+vacant
+vacate
+vacationland
+vaccinate
+vaccine
+vaccinia
+vacillate
+vacua
+vacuity
+vacuo
+vacuolate
+vacuole
+vacuous
+vacuum
+Vaduz
+vagabond
+vagarious
+vagary
+vagina
+vaginal
+vagrant
+vague
+Vail
+vain
+vainglorious
+vainglory
+Valdez
+vale
+valediction
+valedictorian
+valedictory
+valent
+valentine
+Valerie
+Valery
+valet
+Valhalla
+valiant
+valid
+validate
+valise
+Valkyrie
+Valletta
+valley
+Valois
+valor
+valorous
+valuable
+valuate
+value
+valve
+vamoose
+vamp
+vampire
+van
+vanadium
+Vance
+Vancouver
+vandal
+Vandenberg
+Vanderbilt
+Vanderpoel
+vane
+Vanessa
+vanguard
+vanilla
+vanish
+vanity
+vanload
+vanquish
+vantage
+vapid
+vapor
+vaporous
+Vargas
+variable
+variac
+Varian
+variant
+variate
+varicolored
+varicose
+variegate
+varietal
+variety
+variorum
+various
+varistor
+Varitype
+varlet
+varmint
+varnish
+varsity
+vary
+vascular
+vase
+vasectomy
+Vaseline
+vasoconstrict
+vasodilate
+vasomotor
+Vasquez
+vassal
+vassalage
+Vassar
+vast
+vasty
+vat
+Vatican
+vaudeville
+vaudevillian
+Vaudois
+Vaughan
+Vaughn
+vault
+vaunt
+VCR
+veal
+vector
+vectorial
+Veda
+vee
+veep
+veer
+veery
+Vega
+vegetable
+vegetal
+vegetarian
+vegetate
+veggie
+vehement
+vehicle
+vehicular
+veil
+vein
+velar
+Velasquez
+Velcro
+veld
+veldt
+Vella
+vellum
+Velma
+velocipede
+velocity
+velour
+velvet
+velveteen
+venal
+venation
+vend
+vendetta
+vendible
+vendor
+veneer
+venerable
+venerate
+venereal
+venery
+Venetian
+Veneto
+Venezuela
+vengeance
+vengeful
+venial
+Venice
+venin
+venire
+venison
+venom
+venomous
+venous
+vent
+ventilate
+ventral
+ventricle
+ventricular
+ventriloquism
+ventriloquist
+ventriloquy
+venture
+venturesome
+venturi
+venturous
+venue
+Venus
+Venusian
+Vera
+veracious
+veracity
+veranda
+verandah
+verb
+verbal
+verbatim
+verbena
+verbiage
+verbose
+verbosity
+verdant
+Verde
+Verdi
+verdict
+verdure
+verge
+veridic
+verify
+verisimilitude
+veritable
+verity
+Verlag
+vermeil
+vermicelli
+vermicide
+vermiculite
+vermilion
+vermin
+verminous
+Vermont
+vermouth
+Vern
+Verna
+vernacular
+vernal
+Verne
+vernier
+Vernon
+Verona
+Veronica
+versa
+Versailles
+versant
+versatile
+verse
+versify
+version
+verso
+verst
+versus
+vertebra
+vertebrae
+vertebral
+vertebrate
+vertex
+vertical
+vertices
+vertiginous
+vertigo
+vertigoes
+verve
+very
+vesicle
+vesicular
+vesper
+vessel
+vest
+vestal
+vestibular
+vestibule
+vestige
+vestigial
+vestry
+vet
+vetch
+veteran
+veterinarian
+veterinary
+veto
+vetoes
+vex
+vexation
+vexatious
+VHF
+VHS
+vi
+via
+viable
+viaduct
+vial
+viand
+vibrant
+vibraphone
+vibrate
+vibrato
+viburnum
+Vic
+vicar
+vicarage
+vicarious
+vice
+viceregal
+viceroy
+Vichy
+vichyssoise
+vicinal
+vicinity
+vicious
+vicissitude
+Vicki
+Vickie
+Vicksburg
+Vicky
+victim
+victor
+Victoria
+Victorian
+victorious
+victory
+victual
+vicuna
+Vida
+vide
+video
+videoconference
+videotape
+vidicon
+vie
+Vienna
+Viennese
+Vientiane
+Viet
+Vietnam
+Vietnamese
+view
+viewpoint
+vigil
+vigilant
+vigilante
+vigilantism
+vigintillion
+vignette
+vignetting
+vigor
+vigorous
+vii
+viii
+Viking
+vile
+vilify
+villa
+village
+villain
+villainous
+villainy
+villein
+vim
+Vincent
+vincible
+vinculum
+vindicate
+vindictive
+vine
+vinegar
+vineyard
+viniculture
+vinous
+Vinson
+vintage
+vintner
+vinyl
+viol
+viola
+violate
+violent
+violet
+violin
+violist
+VIP
+viper
+virago
+viral
+vireo
+Virgil
+virgin
+virginal
+Virginia
+Virginian
+Virgo
+virgule
+virile
+virology
+virtual
+virtue
+virtuosi
+virtuosity
+virtuoso
+virtuous
+virulent
+virus
+vis
+visa
+visage
+viscera
+visceral
+viscid
+viscoelastic
+viscometer
+viscosimeter
+viscosity
+viscount
+viscous
+vise
+Vishnu
+visible
+Visigoth
+Visigothic
+vision
+visionary
+visit
+visitation
+visitor
+visor
+vista
+visual
+vita
+vitae
+vital
+vitamin
+vitiate
+viticulture
+Vito
+vitreous
+vitrify
+vitriol
+vitriolic
+vitro
+vituperate
+viva
+vivace
+vivacious
+vivacity
+Vivaldi
+Vivian
+vivid
+vivify
+viviparous
+vivisect
+vivo
+vixen
+viz.
+vizier
+Vladimir
+Vladivostok
+vocable
+vocabulary
+vocal
+vocalic
+vocate
+vociferate
+vociferous
+vocoder
+vodka
+Vogel
+vogue
+voguish
+voice
+voiceband
+void
+volatile
+volcanic
+volcanism
+volcano
+Volga
+volition
+Volkswagen
+volley
+volleyball
+volocanology
+Volstead
+volt
+Volta
+voltage
+voltaic
+Voltaire
+Volterra
+voltmeter
+voluble
+volume
+volumetric
+voluminous
+voluntarism
+voluntary
+volunteer
+voluptuary
+voluptuous
+volute
+Volvo
+vomit
+von
+voodoo
+voracious
+voracity
+vortex
+vortices
+vorticity
+Voss
+votary
+vote
+votive
+vouch
+vouchsafe
+Vought
+vow
+vowel
+voyage
+voyageur
+voyeur
+V.P.
+VP
+Vreeland
+v's
+vs
+vs.
+VT
+Vulcan
+vulcanize
+vulgar
+vulgarian
+vulgate
+vulnerable
+vulpine
+vulture
+vulva
+VW
+vying
+WA
+Waals
+Wabash
+WAC
+wacky
+Waco
+wad
+waddle
+wade
+wader
+wadi
+Wadsworth
+wafer
+waffle
+waft
+wag
+wage
+wager
+waggish
+waggle
+Wagner
+Wagnerian
+wagon
+wagoneer
+wagonload
+wah
+Wahl
+wahoo
+waif
+wail
+wainscot
+Wainwright
+waist
+waistband
+waistcoat
+waistline
+wait
+Waite
+waitress
+waive
+wake
+Wakefield
+waken
+wakeup
+Walcott
+Walden
+Waldo
+Waldorf
+Waldron
+wale
+Walgreen
+walk
+walkie
+walkout
+walkover
+walkway
+wall
+wallaby
+Wallace
+wallboard
+Waller
+wallet
+walleye
+Wallis
+wallop
+wallow
+wallpaper
+walnut
+Walpole
+walrus
+Walsh
+Walt
+Walter
+Walters
+Waltham
+Walton
+waltz
+waltzing
+wampum
+wan
+wand
+Wanda
+wander
+wanderlust
+wane
+Wang
+wangle
+want
+wanton
+wapiti
+Wappinger
+war
+warble
+ward
+warden
+wardrobe
+wardroom
+ware
+warehouse
+warfare
+warfarin
+warhead
+warhorse
+Waring
+warlock
+warlord
+warm
+warmhearted
+warmish
+warmonger
+warmth
+warmup
+warn
+warp
+warpath
+warplane
+warrant
+warranty
+warren
+warrior
+Warsaw
+wart
+warthog
+wartime
+Warwick
+was
+wash
+washbasin
+washboard
+washbowl
+Washburn
+washcloth
+washer
+Washington
+washout
+washrag
+washroom
+washstand
+washtub
+wasn't
+wasp
+waspish
+wassail
+Wasserman
+wast
+wastage
+waste
+wastebasket
+wasteland
+wastepaper
+wastewater
+wasting
+wastrel
+watch
+watchband
+watchcase
+watchdog
+watchtower
+watchword
+water
+waterbed
+waterborne
+Waterbury
+watercolor
+watercourse
+watercraft
+watercress
+waterfall
+waterfowl
+waterfront
+Watergate
+Waterhouse
+waterlily
+waterline
+waterlog
+waterloo
+watermark
+watermelon
+waterproof
+watershed
+waterside
+waterspout
+watertight
+Watertown
+waterway
+waterworks
+watery
+Watkins
+Watson
+watt
+wattage
+wattle
+wattmeter
+wave
+waveform
+wavefront
+waveguide
+wavelength
+wavelet
+wavenumber
+waver
+wax
+waxen
+waxwing
+waxwork
+way
+waybill
+wayfare
+waylaid
+waylay
+Wayne
+wayside
+wayward
+we
+weak
+weaken
+weakish
+weakling
+weal
+wealth
+wean
+weapon
+weaponry
+wear
+wearied
+wearisome
+weary
+weasel
+weather
+weatherbeaten
+weathercock
+weatherglass
+weatherproof
+weatherstrip
+weathertight
+weave
+web
+Webb
+weber
+Webster
+WECo
+we'd
+wed
+wedge
+wedlock
+Wednesday
+wee
+weed
+week
+weekday
+weekend
+weeklong
+ween
+weep
+weevil
+Wehr
+Wei
+Weierstrass
+weigh
+weight
+Weinberg
+Weinstein
+weir
+weird
+Weiss
+Welch
+welcome
+weld
+Weldon
+welfare
+welkin
+we'll
+well
+wellbeing
+wellborn
+Weller
+Welles
+Wellesley
+wellhead
+Wellington
+wellingtons
+wellspring
+welsh
+welt
+wen
+wench
+wend
+Wendell
+Wendy
+went
+wept
+we're
+were
+weren't
+werewolf
+werewolves
+Werner
+wert
+Werther
+Wesley
+Wesleyan
+west
+westbound
+Westchester
+westerly
+western
+westernmost
+Westfield
+Westinghouse
+Westminster
+westmost
+Weston
+westward
+wet
+wetback
+wetland
+we've
+Weyerhauser
+whack
+whale
+whaleboat
+whalebone
+Whalen
+wham
+whammy
+wharf
+wharfinger
+Wharton
+wharves
+what
+what'd
+whatever
+Whatley
+whatnot
+what're
+whatsoever
+wheat
+Wheaties
+Wheatstone
+whee
+wheedle
+wheel
+wheelbarrow
+wheelbase
+wheelchair
+wheelhorse
+wheelhouse
+wheelwright
+wheeze
+Whelan
+whelk
+Wheller
+whelm
+whelp
+when
+whence
+whenever
+whensoever
+where
+whereabout
+whereas
+whereat
+whereby
+where'd
+wherefore
+wherefrom
+wherein
+whereof
+whereon
+where're
+wheresoever
+whereunto
+whereupon
+wherever
+wherewith
+wherewithal
+wherry
+whet
+whether
+whetstone
+whey
+wheyey
+which
+whichever
+whiff
+whiffle
+whiffletree
+whig
+while
+whilom
+whim
+whimper
+whimsical
+whimsy
+whine
+whinny
+whip
+whipcord
+whiplash
+whippersnapper
+whippet
+Whipple
+whippoorwill
+whipsaw
+whir
+whirl
+whirligig
+whirlpool
+whirlwind
+whirlybird
+whirr
+whish
+whisk
+whiskery
+whiskey
+whisper
+whist
+whistle
+whistleable
+whistleblow
+whit
+Whitaker
+Whitcomb
+white
+whitecap
+whiteface
+whitefish
+Whitehall
+whitehead
+Whitehorse
+whiten
+whiteout
+whitetail
+whitewall
+whitewash
+whitey
+whither
+whitish
+Whitlock
+Whitman
+Whitney
+Whittaker
+Whittier
+whittle
+whiz
+whizbang
+who
+whoa
+who'd
+whodunit
+whoever
+whole
+wholehearted
+wholesale
+wholesome
+who'll
+wholly
+whom
+whomever
+whomp
+whomsoever
+whoop
+whoopee
+whoosh
+whop
+whore
+whorehouse
+whorl
+whose
+whosoever
+who've
+whup
+why
+WI
+Wichita
+wick
+wickerwork
+wicket
+wide
+widen
+widespread
+widgeon
+widget
+widish
+widow
+width
+widthwise
+wield
+wiener
+Wier
+wife
+wig
+Wiggins
+wiggle
+wiggly
+wigwag
+wigwam
+Wilbert
+Wilbur
+Wilcox
+wild
+wildcat
+wildebeest
+wilderment
+wildfire
+wildfowl
+wildlife
+wildwood
+wile
+Wiley
+Wilfred
+Wilhelm
+Wilhelmina
+Wilkerson
+Wilkes
+Wilkins
+Wilkinson
+will
+Willa
+Willard
+William
+Williams
+Williamsburg
+Williamson
+Willie
+Willis
+Willoughby
+willow
+willpower
+willy
+Wilma
+Wilmington
+Wilshire
+Wilson
+wilt
+wily
+wimp
+win
+wince
+winch
+Winchester
+wind
+windage
+windbag
+windblown
+windbreak
+windburn
+windfall
+windjammer
+windlass
+windmill
+window
+windowpane
+windowsill
+windpipe
+windproof
+windrow
+windscreen
+windshield
+Windsor
+windstorm
+windsurf
+windswept
+windup
+windward
+wine
+wineglass
+winegrower
+winemaster
+winepress
+winery
+wineshop
+wineskin
+Winfield
+wing
+wingback
+winglet
+wingspan
+wingspread
+wingtip
+Winifred
+wink
+winkle
+Winnetka
+Winnie
+Winnipeg
+winnow
+wino
+Winslow
+winsome
+Winston
+winter
+wintergreen
+wintertime
+wintery
+Winthrop
+wintry
+winy
+wipe
+wirable
+wire
+wirehair
+wiretap
+Wisconsin
+wisdom
+wise
+wiseacre
+wisecrack
+wisenheimer
+wish
+wishbone
+wisp
+wisteria
+wistful
+wit
+witch
+witchcraft
+with
+withal
+withdraw
+withdrawal
+withdrawn
+withdrew
+withe
+withheld
+withhold
+within
+without
+withstand
+withstood
+witness
+Witt
+witticism
+wive
+wizard
+wizardry
+wizen
+WNW
+woad
+wobble
+woe
+woebegone
+wok
+woke
+Wolcott
+wolf
+Wolfe
+Wolff
+Wolfgang
+wolfhound
+wolfish
+wolverine
+wolves
+woman
+womanish
+womankind
+womb
+wombat
+women
+womenfolk
+won
+wonder
+wonderland
+wonderwork
+wondrous
+Wong
+wonk
+won't
+wont
+woo
+wood
+Woodard
+woodbine
+Woodbury
+woodcarver
+woodchopper
+woodchuck
+woodcock
+woodcraft
+woodcut
+wooden
+woodenhead
+woodgrain
+woodhen
+woodland
+Woodlawn
+woodlot
+woodpecker
+woodpile
+Woodrow
+woodruff
+woods
+woodshed
+woodside
+Woodstock
+woodsy
+woodturner
+Woodward
+woodwind
+woodwork
+woof
+wool
+woolen
+woolgather
+Woolworth
+Wooster
+woozy
+Worcester
+word
+wordmonger
+wordplay
+wordsmith
+Wordsworth
+wore
+work
+workable
+workaday
+workaholic
+workbag
+workbasket
+workbench
+workbook
+workday
+workforce
+workhorse
+workhouse
+working
+workload
+workman
+workout
+workpiece
+workplace
+workroom
+worksheet
+workshop
+workspace
+workstation
+worktable
+workweek
+world
+worldwide
+worm
+wormhole
+wormwood
+worn
+worrisome
+worry
+worse
+worsen
+worship
+worst
+worth
+Worthington
+worthwhile
+worthy
+Wotan
+would
+wouldn't
+wouldst
+wound
+wove
+woven
+wow
+WPA
+wrack
+wraith
+wrangle
+wrap
+wraparound
+wrapup
+wrasse
+wrath
+wreak
+wreath
+wreathe
+wreck
+wreckage
+wren
+wrench
+wrest
+wrestle
+wretch
+wriggle
+wriggly
+wright
+Wrigley
+wring
+wrinkle
+wrinkly
+wrist
+wristband
+wristlet
+wristwatch
+writ
+write
+writeup
+writhe
+writhing
+written
+wrong
+wrongdoer
+wrongdoing
+wrongheaded
+Wronskian
+wrote
+wrought
+wrung
+wry
+w's
+WSW
+Wu
+Wuhan
+wunderkind
+wurst
+WV
+WWI
+WWII
+WY
+Wyandotte
+Wyatt
+Wyeth
+Wylie
+Wyman
+Wyner
+Wyoming
+Xavier
+x'd
+xebec
+xenolith
+xenon
+xenophobe
+xenophobic
+xeric
+xeriscape
+xerography
+Xerox
+Xerxes
+xi
+Xiao
+x'ing
+Xmas
+Xosa
+x's
+xylem
+xylene
+xylophone
+yacht
+yachts
+yack
+yackety
+yagi
+yah
+yahoo
+Yahweh
+yak
+Yakima
+Yale
+Yalta
+yam
+Yamaha
+yammer
+yang
+Yangtze
+yank
+Yankee
+Yankton
+Yaounde
+yap
+yapping
+Yaqui
+yard
+yardage
+yardarm
+yardbird
+yardmaster
+yardstick
+Yarmouth
+yarmulke
+yarn
+yarrow
+Yates
+yaw
+yawl
+yawn
+yawp
+yclept
+ye
+yea
+Yeager
+yeah
+year
+yearbook
+yearling
+yearn
+yeast
+Yeats
+yegg
+yell
+yellow
+yellowish
+Yellowknife
+yellowlegs
+Yellowstone
+yelp
+Yemen
+yen
+yeoman
+yeomanry
+Yerkes
+yes
+yeshiva
+yesterday
+yesteryear
+yet
+yeti
+yew
+Yiddish
+yield
+yin
+yip
+yippee
+yipping
+YMCA
+yodel
+Yoder
+yoga
+yogi
+yogurt
+yoke
+yokel
+Yokohama
+Yokuts
+Yolanda
+yolk
+yon
+yond
+Yonkers
+yore
+York
+Yorker
+Yorktown
+Yosemite
+Yost
+you
+you'd
+you'll
+young
+youngish
+youngster
+Youngstown
+your
+you're
+yours
+yourself
+yourselves
+youth
+you've
+yowl
+Ypsilanti
+y's
+ytterbium
+yttrium
+Yucatan
+yucca
+Yugoslav
+Yugoslavia
+yuh
+Yuki
+Yukon
+yule
+yuletide
+yummy
+yuppie
+Yves
+Yvette
+Yvonne
+YWCA
+zabaglione
+Zachary
+zag
+zaibatsu
+Zaire
+Zambia
+Zan
+zany
+Zanzibar
+zap
+zarzuela
+zeal
+Zealand
+Zealander
+zealot
+zealotry
+zealous
+zebra
+zebu
+Zechariah
+zed
+Zeiss
+zeitgeist
+Zelda
+Zellerbach
+Zen
+zenith
+Zeno
+zeolite
+Zephaniah
+zephyr
+zeppelin
+zero
+zeroth
+zest
+zeta
+Zeus
+Ziegler
+zig
+ziggurat
+zigzag
+zilch
+zillion
+Zimbabwe
+Zimmerman
+zinc
+zing
+zinnia
+Zion
+zip
+zircon
+zirconium
+zither
+zloty
+zlotys
+zodiac
+zodiacal
+Zoe
+Zomba
+zombie
+zonal
+zonate
+zone
+zonk
+zoo
+zoogeography
+zoology
+zoom
+zoomorph
+zoomorphic
+zoophyte
+Zoroaster
+zounds
+z's
+zucchini
+Zulu
+Zurich
+zwieback
+zygote
+zygotic
+zymurgy
--- /dev/null
+++ b/lib/yaccpar
@@ -1,0 +1,211 @@
+
+YYSys: module
+{
+	FD: adt
+	{
+		fd:	int;
+	};
+	fildes:		fn(fd: int): ref FD;
+	fprint:		fn(fd: ref FD, s: string, *): int;
+};
+
+yysys: YYSys;
+yystderr: ref YYSys->FD;
+
+YYFLAG: con -1000;
+
+# parser for yacc output
+
+yytokname(yyc: int): string
+{
+	if(yyc > 0 && yyc <= len yytoknames && yytoknames[yyc-1] != nil)
+		return yytoknames[yyc-1];
+	return "<"+string yyc+">";
+}
+
+yystatname(yys: int): string
+{
+	if(yys >= 0 && yys < len yystates && yystates[yys] != nil)
+		return yystates[yys];
+	return "<"+string yys+">\n";
+}
+
+yylex1(yylex: ref YYLEX): int
+{
+	c : int;
+	yychar := yylex.lex();
+	if(yychar <= 0)
+		c = yytok1[0];
+	else if(yychar < len yytok1)
+		c = yytok1[yychar];
+	else if(yychar >= YYPRIVATE && yychar < YYPRIVATE+len yytok2)
+		c = yytok2[yychar-YYPRIVATE];
+	else{
+		n := len yytok3;
+		c = 0;
+		for(i := 0; i < n; i+=2) {
+			if(yytok3[i+0] == yychar) {
+				c = yytok3[i+1];
+				break;
+			}
+		}
+		if(c == 0)
+			c = yytok2[1];	# unknown char
+	}
+	if(yydebug >= 3)
+		yysys->fprint(yystderr, "lex %.4ux %s\n", yychar, yytokname(c));
+	return c;
+}
+
+YYS: adt
+{
+	yyv: YYSTYPE;
+	yys: int;
+};
+
+yyparse(yylex: ref YYLEX): int
+{
+	if(yydebug >= 1 && yysys == nil) {
+		yysys = load YYSys "$Sys";
+		yystderr = yysys->fildes(2);
+	}
+
+	yys := array[YYMAXDEPTH] of YYS;
+
+	yyval: YYSTYPE;
+	yystate := 0;
+	yychar := -1;
+	yynerrs := 0;		# number of errors
+	yyerrflag := 0;		# error recovery flag
+	yyp := -1;
+	yyn := 0;
+
+yystack:
+	for(;;){
+		# put a state and value onto the stack
+		if(yydebug >= 4)
+			yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate));
+
+		yyp++;
+		if(yyp >= len yys)
+			yys = (array[len yys * 2] of YYS)[0:] = yys;
+		yys[yyp].yys = yystate;
+		yys[yyp].yyv = yyval;
+
+		for(;;){
+			yyn = yypact[yystate];
+			if(yyn > YYFLAG) {	# simple state
+				if(yychar < 0)
+					yychar = yylex1(yylex);
+				yyn += yychar;
+				if(yyn >= 0 && yyn < YYLAST) {
+					yyn = yyact[yyn];
+					if(yychk[yyn] == yychar) { # valid shift
+						yychar = -1;
+						yyp++;
+						if(yyp >= len yys)
+							yys = (array[len yys * 2] of YYS)[0:] = yys;
+						yystate = yyn;
+						yys[yyp].yys = yystate;
+						yys[yyp].yyv = yylex.lval;
+						if(yyerrflag > 0)
+							yyerrflag--;
+						if(yydebug >= 4)
+							yysys->fprint(yystderr, "char %s in %s", yytokname(yychar), yystatname(yystate));
+						continue;
+					}
+				}
+			}
+		
+			# default state action
+			yyn = yydef[yystate];
+			if(yyn == -2) {
+				if(yychar < 0)
+					yychar = yylex1(yylex);
+		
+				# look through exception table
+				for(yyxi:=0;; yyxi+=2)
+					if(yyexca[yyxi] == -1 && yyexca[yyxi+1] == yystate)
+						break;
+				for(yyxi += 2;; yyxi += 2) {
+					yyn = yyexca[yyxi];
+					if(yyn < 0 || yyn == yychar)
+						break;
+				}
+				yyn = yyexca[yyxi+1];
+				if(yyn < 0){
+					yyn = 0;
+					break yystack;
+				}
+			}
+
+			if(yyn != 0)
+				break;
+
+			# error ... attempt to resume parsing
+			if(yyerrflag == 0) { # brand new error
+				yylex.error("syntax error");
+				yynerrs++;
+				if(yydebug >= 1) {
+					yysys->fprint(yystderr, "%s", yystatname(yystate));
+					yysys->fprint(yystderr, "saw %s\n", yytokname(yychar));
+				}
+			}
+
+			if(yyerrflag != 3) { # incompletely recovered error ... try again
+				yyerrflag = 3;
+	
+				# find a state where "error" is a legal shift action
+				while(yyp >= 0) {
+					yyn = yypact[yys[yyp].yys] + YYERRCODE;
+					if(yyn >= 0 && yyn < YYLAST) {
+						yystate = yyact[yyn];  # simulate a shift of "error"
+						if(yychk[yystate] == YYERRCODE)
+							continue yystack;
+					}
+	
+					# the current yyp has no shift onn "error", pop stack
+					if(yydebug >= 2)
+						yysys->fprint(yystderr, "error recovery pops state %d, uncovers %d\n",
+							yys[yyp].yys, yys[yyp-1].yys );
+					yyp--;
+				}
+				# there is no state on the stack with an error shift ... abort
+				yyn = 1;
+				break yystack;
+			}
+
+			# no shift yet; clobber input char
+			if(yydebug >= 2)
+				yysys->fprint(yystderr, "error recovery discards %s\n", yytokname(yychar));
+			if(yychar == YYEOFCODE) {
+				yyn = 1;
+				break yystack;
+			}
+			yychar = -1;
+			# try again in the same state
+		}
+	
+		# reduction by production yyn
+		if(yydebug >= 2)
+			yysys->fprint(yystderr, "reduce %d in:\n\t%s", yyn, yystatname(yystate));
+	
+		yypt := yyp;
+		yyp -= yyr2[yyn];
+#		yyval = yys[yyp+1].yyv;
+		yym := yyn;
+	
+		# consult goto table to find next state
+		yyn = yyr1[yyn];
+		yyg := yypgo[yyn];
+		yyj := yyg + yys[yyp].yys + 1;
+	
+		if(yyj >= YYLAST || yychk[yystate=yyact[yyj]] != -yyn)
+			yystate = yyact[yyg];
+		case yym {
+			$A
+		}
+	}
+
+	return yyn;
+}
--- /dev/null
+++ b/lib9/NOTICE
@@ -1,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/lib9/argv0.c
@@ -1,0 +1,1 @@
+char*	argv0 = 0;
--- /dev/null
+++ b/lib9/charstod.c
@@ -1,0 +1,80 @@
+#include "lib9.h"
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp).  The last call it makes to f terminates the
+ * scan, so is not a character in the number.  It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+#define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp)
+
+double
+charstod(int(*f)(void*), void *vp)
+{
+	char str[400], *s, *e, *start;
+	int c;
+
+	s = str;
+	e = str + sizeof str - 1;
+	c = (*f)(vp);
+	while(c == ' ' || c == '\t')
+		c = (*f)(vp);
+	if(c == '-' || c == '+'){
+		ADVANCE;
+	}
+	start = s;
+	while(c >= '0' && c <= '9'){
+		ADVANCE;
+	}
+	if(c == '.'){
+		ADVANCE;
+		while(c >= '0' && c <= '9'){
+			ADVANCE;
+		}
+	}
+	if(s > start && (c == 'e' || c == 'E')){
+		ADVANCE;
+		if(c == '-' || c == '+'){
+			ADVANCE;
+		}
+		while(c >= '0' && c <= '9'){
+			ADVANCE;
+		}
+	}else if(s == start && (c == 'i' || c == 'I')){
+		ADVANCE;
+		if(c != 'n' && c != 'N')
+			return NaN();
+		ADVANCE;
+		if(c != 'f' && c != 'F')
+			return NaN();
+		ADVANCE;
+		if(c != 'i' && c != 'I')
+			return NaN();
+		ADVANCE;
+		if(c != 'n' && c != 'N')
+			return NaN();
+		ADVANCE;
+		if(c != 'i' && c != 'I')
+			return NaN();
+		ADVANCE;
+		if(c != 't' && c != 'T')
+			return NaN();
+		ADVANCE;
+		if(c != 'y' && c != 'Y')
+			return NaN();
+		ADVANCE;  /* so caller can back up uniformly */
+		USED(c);
+	}else if(s == str && (c == 'n' || c == 'N')){
+		ADVANCE;
+		if(c != 'a' && c != 'A')
+			return NaN();
+		ADVANCE;
+		if(c != 'n' && c != 'N')
+			return NaN();
+		ADVANCE;  /* so caller can back up uniformly */
+		USED(c);
+	}
+	*s = 0;
+	return strtod(str, &s);
+}
--- /dev/null
+++ b/lib9/cistrcmp.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+int
+cistrcmp(char *s1, char *s2)
+{
+	int c1, c2;
+
+	while(*s1){
+		c1 = *(uchar*)s1++;
+		c2 = *(uchar*)s2++;
+
+		if(c1 == c2)
+			continue;
+
+		if(c1 >= 'A' && c1 <= 'Z')
+			c1 -= 'A' - 'a';
+
+		if(c2 >= 'A' && c2 <= 'Z')
+			c2 -= 'A' - 'a';
+
+		if(c1 != c2)
+			return c1 - c2;
+	}
+	return -*s2;
+}
--- /dev/null
+++ b/lib9/cistrncmp.c
@@ -1,0 +1,27 @@
+#include "lib9.h"
+
+int
+cistrncmp(char *s1, char *s2, int n)
+{
+	int c1, c2;
+
+	while(*s1 && n-- > 0){
+		c1 = *(uchar*)s1++;
+		c2 = *(uchar*)s2++;
+
+		if(c1 == c2)
+			continue;
+
+		if(c1 >= 'A' && c1 <= 'Z')
+			c1 -= 'A' - 'a';
+
+		if(c2 >= 'A' && c2 <= 'Z')
+			c2 -= 'A' - 'a';
+
+		if(c1 != c2)
+			return c1 - c2;
+	}
+	if(n <= 0)
+		return 0;
+	return -*s2;
+}
--- /dev/null
+++ b/lib9/cistrstr.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+
+char*
+cistrstr(char *s, char *sub)
+{
+	int c, csub, n;
+
+	csub = *sub;
+	if(csub == '\0')
+		return s;
+	if(csub >= 'A' && csub <= 'Z')
+		csub -= 'A' - 'a';
+	sub++;
+	n = strlen(sub);
+	for(; c = *s; s++){
+		if(c >= 'A' && c <= 'Z')
+			c -= 'A' - 'a';
+		if(c == csub && cistrncmp(s+1, sub, n) == 0)
+			return s;
+	}
+	return nil;
+}
--- /dev/null
+++ b/lib9/cleanname.c
@@ -1,0 +1,62 @@
+#include "lib9.h"
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x)	((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+	char *p, *q, *dotdot;
+	int rooted, erasedprefix;
+
+	rooted = name[0] == '/';
+	erasedprefix = 0;
+
+	/*
+	 * invariants:
+	 *	p points at beginning of path element we're considering.
+	 *	q points just past the last path element we wrote (no slash).
+	 *	dotdot points just past the point where .. cannot backtrack
+	 *		any further (no slash).
+	 */
+	p = q = dotdot = name+rooted;
+	while(*p) {
+		if(p[0] == '/')	/* null element */
+			p++;
+		else if(p[0] == '.' && SEP(p[1])) {
+			if(p == name)
+				erasedprefix = 1;
+			p += 1;	/* don't count the separator in case it is nul */
+		} else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+			p += 2;
+			if(q > dotdot) {	/* can backtrack */
+				while(--q > dotdot && *q != '/')
+					;
+			} else if(!rooted) {	/* /.. is / but ./../ is .. */
+				if(q != name)
+					*q++ = '/';
+				*q++ = '.';
+				*q++ = '.';
+				dotdot = q;
+			}
+			if(q == name)
+				erasedprefix = 1;	/* erased entire path via dotdot */
+		} else {	/* real path element */
+			if(q != name+rooted)
+				*q++ = '/';
+			while((*q = *p) != '/' && *q != 0)
+				p++, q++;
+		}
+	}
+	if(q == name)	/* empty string is really ``.'' */
+		*q++ = '.';
+	*q = '\0';
+	if(erasedprefix && name[0] == '#'){	
+		/* this was not a #x device path originally - make it not one now */
+		memmove(name+2, name, strlen(name)+1);
+		name[0] = '.';
+		name[1] = '/';
+	}
+	return name;
+}
--- /dev/null
+++ b/lib9/convD2M.c
@@ -1,0 +1,94 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+uint
+sizeD2M(Dir *d)
+{
+	char *sv[4];
+	int i, ns;
+
+	sv[0] = d->name;
+	sv[1] = d->uid;
+	sv[2] = d->gid;
+	sv[3] = d->muid;
+
+	ns = 0;
+	for(i = 0; i < 4; i++)
+		if(sv[i])
+			ns += strlen(sv[i]);
+
+	return STATFIXLEN + ns;
+}
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+	uchar *p, *ebuf;
+	char *sv[4];
+	int i, ns, nsv[4], ss;
+
+	if(nbuf < BIT16SZ)
+		return 0;
+
+	p = buf;
+	ebuf = buf + nbuf;
+
+	sv[0] = d->name;
+	sv[1] = d->uid;
+	sv[2] = d->gid;
+	sv[3] = d->muid;
+
+	ns = 0;
+	for(i = 0; i < 4; i++){
+		if(sv[i])
+			nsv[i] = strlen(sv[i]);
+		else
+			nsv[i] = 0;
+		ns += nsv[i];
+	}
+
+	ss = STATFIXLEN + ns;
+
+	/* set size befor erroring, so user can know how much is needed */
+	/* note that length excludes count field itself */
+	PBIT16(p, ss-BIT16SZ);
+	p += BIT16SZ;
+
+	if(ss > nbuf)
+		return BIT16SZ;
+
+	PBIT16(p, d->type);
+	p += BIT16SZ;
+	PBIT32(p, d->dev);
+	p += BIT32SZ;
+	PBIT8(p, d->qid.type);
+	p += BIT8SZ;
+	PBIT32(p, d->qid.vers);
+	p += BIT32SZ;
+	PBIT64(p, d->qid.path);
+	p += BIT64SZ;
+	PBIT32(p, d->mode);
+	p += BIT32SZ;
+	PBIT32(p, d->atime);
+	p += BIT32SZ;
+	PBIT32(p, d->mtime);
+	p += BIT32SZ;
+	PBIT64(p, d->length);
+	p += BIT64SZ;
+
+	for(i = 0; i < 4; i++){
+		ns = nsv[i];
+		if(p + ns + BIT16SZ > ebuf)
+			return 0;
+		PBIT16(p, ns);
+		p += BIT16SZ;
+		if(ns)
+			memmove(p, sv[i], ns);
+		p += ns;
+	}
+
+	if(ss != p - buf)
+		return 0;
+
+	return p - buf;
+}
--- /dev/null
+++ b/lib9/convM2D.c
@@ -1,0 +1,93 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+int
+statcheck(uchar *buf, uint nbuf)
+{
+	uchar *ebuf;
+	int i;
+
+	ebuf = buf + nbuf;
+
+	if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
+		return -1;
+
+	buf += STATFIXLEN - 4 * BIT16SZ;
+
+	for(i = 0; i < 4; i++){
+		if(buf + BIT16SZ > ebuf)
+			return -1;
+		buf += BIT16SZ + GBIT16(buf);
+	}
+
+	if(buf != ebuf)
+		return -1;
+
+	return 0;
+}
+
+static char nullstring[] = "";
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+	uchar *p, *ebuf;
+	char *sv[4];
+	int i, ns;
+
+	if(nbuf < STATFIXLEN)
+		return 0; 
+
+	p = buf;
+	ebuf = buf + nbuf;
+
+	p += BIT16SZ;	/* ignore size */
+	d->type = GBIT16(p);
+	p += BIT16SZ;
+	d->dev = GBIT32(p);
+	p += BIT32SZ;
+	d->qid.type = GBIT8(p);
+	p += BIT8SZ;
+	d->qid.vers = GBIT32(p);
+	p += BIT32SZ;
+	d->qid.path = GBIT64(p);
+	p += BIT64SZ;
+	d->mode = GBIT32(p);
+	p += BIT32SZ;
+	d->atime = GBIT32(p);
+	p += BIT32SZ;
+	d->mtime = GBIT32(p);
+	p += BIT32SZ;
+	d->length = GBIT64(p);
+	p += BIT64SZ;
+
+	for(i = 0; i < 4; i++){
+		if(p + BIT16SZ > ebuf)
+			return 0;
+		ns = GBIT16(p);
+		p += BIT16SZ;
+		if(p + ns > ebuf)
+			return 0;
+		if(strs){
+			sv[i] = strs;
+			memmove(strs, p, ns);
+			strs += ns;
+			*strs++ = '\0';
+		}
+		p += ns;
+	}
+
+	if(strs){
+		d->name = sv[0];
+		d->uid = sv[1];
+		d->gid = sv[2];
+		d->muid = sv[3];
+	}else{
+		d->name = nullstring;
+		d->uid = nullstring;
+		d->gid = nullstring;
+		d->muid = nullstring;
+	}
+	
+	return p - buf;
+}
--- /dev/null
+++ b/lib9/convM2S.c
@@ -1,0 +1,314 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+static
+uchar*
+gstring(uchar *p, uchar *ep, char **s)
+{
+	uint n;
+
+	if(p+BIT16SZ > ep)
+		return nil;
+	n = GBIT16(p);
+	p += BIT16SZ - 1;
+	if(p+n+1 > ep)
+		return nil;
+	/* move it down, on top of count, to make room for '\0' */
+	memmove(p, p + 1, n);
+	p[n] = '\0';
+	*s = (char*)p;
+	p += n+1;
+	return p;
+}
+
+static
+uchar*
+gqid(uchar *p, uchar *ep, Qid *q)
+{
+	if(p+QIDSZ > ep)
+		return nil;
+	q->type = GBIT8(p);
+	p += BIT8SZ;
+	q->vers = GBIT32(p);
+	p += BIT32SZ;
+	q->path = GBIT64(p);
+	p += BIT64SZ;
+	return p;
+}
+
+/*
+ * no syntactic checks.
+ * three causes for error:
+ *  1. message size field is incorrect
+ *  2. input buffer too short for its own data (counts too long, etc.)
+ *  3. too many names or qids
+ * gqid() and gstring() return nil if they would reach beyond buffer.
+ * main switch statement checks range and also can fall through
+ * to test at end of routine.
+ */
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+	uchar *p, *ep;
+	uint i, size;
+
+	p = ap;
+	ep = p + nap;
+
+	if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
+		return 0;
+	size = GBIT32(p);
+	p += BIT32SZ;
+
+	if(size < BIT32SZ+BIT8SZ+BIT16SZ)
+		return 0;
+
+	f->type = GBIT8(p);
+	p += BIT8SZ;
+	f->tag = GBIT16(p);
+	p += BIT16SZ;
+
+	switch(f->type)
+	{
+	default:
+		return 0;
+
+	case Tversion:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->msize = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->version);
+		break;
+
+	case Tflush:
+		if(p+BIT16SZ > ep)
+			return 0;
+		f->oldtag = GBIT16(p);
+		p += BIT16SZ;
+		break;
+
+	case Tauth:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->afid = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->uname);
+		if(p == nil)
+			break;
+		p = gstring(p, ep, &f->aname);
+		if(p == nil)
+			break;
+		break;
+
+	case Tattach:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->afid = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->uname);
+		if(p == nil)
+			break;
+		p = gstring(p, ep, &f->aname);
+		if(p == nil)
+			break;
+		break;
+
+	case Twalk:
+		if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->newfid = GBIT32(p);
+		p += BIT32SZ;
+		f->nwname = GBIT16(p);
+		p += BIT16SZ;
+		if(f->nwname > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwname; i++){
+			p = gstring(p, ep, &f->wname[i]);
+			if(p == nil)
+				break;
+		}
+		break;
+
+	case Topen:
+		if(p+BIT32SZ+BIT8SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->mode = GBIT8(p);
+		p += BIT8SZ;
+		break;
+
+	case Tcreate:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->name);
+		if(p == nil)
+			break;
+		if(p+BIT32SZ+BIT8SZ > ep)
+			return 0;
+		f->perm = GBIT32(p);
+		p += BIT32SZ;
+		f->mode = GBIT8(p);
+		p += BIT8SZ;
+		break;
+
+	case Tread:
+		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->offset = GBIT64(p);
+		p += BIT64SZ;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Twrite:
+		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->offset = GBIT64(p);
+		p += BIT64SZ;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		if(p+f->count > ep)
+			return 0;
+		f->data = (char*)p;
+		p += f->count;
+		break;
+
+	case Tclunk:
+	case Tremove:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Tstat:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Twstat:
+		if(p+BIT32SZ+BIT16SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->nstat = GBIT16(p);
+		p += BIT16SZ;
+		if(p+f->nstat > ep)
+			return 0;
+		f->stat = p;
+		p += f->nstat;
+		break;
+
+/*
+ */
+	case Rversion:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->msize = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->version);
+		break;
+
+	case Rerror:
+		p = gstring(p, ep, &f->ename);
+		break;
+
+	case Rflush:
+		break;
+
+	case Rauth:
+		p = gqid(p, ep, &f->aqid);
+		if(p == nil)
+			break;
+		break;
+
+	case Rattach:
+		p = gqid(p, ep, &f->qid);
+		if(p == nil)
+			break;
+		break;
+
+	case Rwalk:
+		if(p+BIT16SZ > ep)
+			return 0;
+		f->nwqid = GBIT16(p);
+		p += BIT16SZ;
+		if(f->nwqid > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwqid; i++){
+			p = gqid(p, ep, &f->wqid[i]);
+			if(p == nil)
+				break;
+		}
+		break;
+
+	case Ropen:
+	case Rcreate:
+		p = gqid(p, ep, &f->qid);
+		if(p == nil)
+			break;
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->iounit = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Rread:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		if(p+f->count > ep)
+			return 0;
+		f->data = (char*)p;
+		p += f->count;
+		break;
+
+	case Rwrite:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Rclunk:
+	case Rremove:
+		break;
+
+	case Rstat:
+		if(p+BIT16SZ > ep)
+			return 0;
+		f->nstat = GBIT16(p);
+		p += BIT16SZ;
+		if(p+f->nstat > ep)
+			return 0;
+		f->stat = p;
+		p += f->nstat;
+		break;
+
+	case Rwstat:
+		break;
+	}
+
+	if(p==nil || p>ep)
+		return 0;
+	if(ap+size == p)
+		return size;
+	return 0;
+}
--- /dev/null
+++ b/lib9/convS2M.c
@@ -1,0 +1,385 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+static
+uchar*
+pstring(uchar *p, char *s)
+{
+	uint n;
+
+	if(s == nil){
+		PBIT16(p, 0);
+		p += BIT16SZ;
+		return p;
+	}
+
+	n = strlen(s);
+	PBIT16(p, n);
+	p += BIT16SZ;
+	memmove(p, s, n);
+	p += n;
+	return p;
+}
+
+static
+uchar*
+pqid(uchar *p, Qid *q)
+{
+	PBIT8(p, q->type);
+	p += BIT8SZ;
+	PBIT32(p, q->vers);
+	p += BIT32SZ;
+	PBIT64(p, q->path);
+	p += BIT64SZ;
+	return p;
+}
+
+static
+uint
+stringsz(char *s)
+{
+	if(s == nil)
+		return BIT16SZ;
+
+	return BIT16SZ+strlen(s);
+}
+
+uint
+sizeS2M(Fcall *f)
+{
+	uint n;
+	int i;
+
+	n = 0;
+	n += BIT32SZ;	/* size */
+	n += BIT8SZ;	/* type */
+	n += BIT16SZ;	/* tag */
+
+	switch(f->type)
+	{
+	default:
+		return 0;
+
+	case Tversion:
+		n += BIT32SZ;
+		n += stringsz(f->version);
+		break;
+
+	case Tflush:
+		n += BIT16SZ;
+		break;
+
+	case Tauth:
+		n += BIT32SZ;
+		n += stringsz(f->uname);
+		n += stringsz(f->aname);
+		break;
+
+	case Tattach:
+		n += BIT32SZ;
+		n += BIT32SZ;
+		n += stringsz(f->uname);
+		n += stringsz(f->aname);
+		break;
+
+	case Twalk:
+		n += BIT32SZ;
+		n += BIT32SZ;
+		n += BIT16SZ;
+		for(i=0; i<f->nwname; i++)
+			n += stringsz(f->wname[i]);
+		break;
+
+	case Topen:
+		n += BIT32SZ;
+		n += BIT8SZ;
+		break;
+
+	case Tcreate:
+		n += BIT32SZ;
+		n += stringsz(f->name);
+		n += BIT32SZ;
+		n += BIT8SZ;
+		break;
+
+	case Tread:
+		n += BIT32SZ;
+		n += BIT64SZ;
+		n += BIT32SZ;
+		break;
+
+	case Twrite:
+		n += BIT32SZ;
+		n += BIT64SZ;
+		n += BIT32SZ;
+		n += f->count;
+		break;
+
+	case Tclunk:
+	case Tremove:
+		n += BIT32SZ;
+		break;
+
+	case Tstat:
+		n += BIT32SZ;
+		break;
+
+	case Twstat:
+		n += BIT32SZ;
+		n += BIT16SZ;
+		n += f->nstat;
+		break;
+/*
+ */
+
+	case Rversion:
+		n += BIT32SZ;
+		n += stringsz(f->version);
+		break;
+
+	case Rerror:
+		n += stringsz(f->ename);
+		break;
+
+	case Rflush:
+		break;
+
+	case Rauth:
+		n += QIDSZ;
+		break;
+
+	case Rattach:
+		n += QIDSZ;
+		break;
+
+	case Rwalk:
+		n += BIT16SZ;
+		n += f->nwqid*QIDSZ;
+		break;
+
+	case Ropen:
+	case Rcreate:
+		n += QIDSZ;
+		n += BIT32SZ;
+		break;
+
+	case Rread:
+		n += BIT32SZ;
+		n += f->count;
+		break;
+
+	case Rwrite:
+		n += BIT32SZ;
+		break;
+
+	case Rclunk:
+		break;
+
+	case Rremove:
+		break;
+
+	case Rstat:
+		n += BIT16SZ;
+		n += f->nstat;
+		break;
+
+	case Rwstat:
+		break;
+	}
+	return n;
+}
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+	uchar *p;
+	uint i, size;
+
+	size = sizeS2M(f);
+	if(size == 0)
+		return 0;
+	if(size > nap)
+		return 0;
+
+	p = (uchar*)ap;
+
+	PBIT32(p, size);
+	p += BIT32SZ;
+	PBIT8(p, f->type);
+	p += BIT8SZ;
+	PBIT16(p, f->tag);
+	p += BIT16SZ;
+
+	switch(f->type)
+	{
+	default:
+		return 0;
+
+	case Tversion:
+		PBIT32(p, f->msize);
+		p += BIT32SZ;
+		p = pstring(p, f->version);
+		break;
+
+	case Tflush:
+		PBIT16(p, f->oldtag);
+		p += BIT16SZ;
+		break;
+
+	case Tauth:
+		PBIT32(p, f->afid);
+		p += BIT32SZ;
+		p  = pstring(p, f->uname);
+		p  = pstring(p, f->aname);
+		break;
+
+	case Tattach:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT32(p, f->afid);
+		p += BIT32SZ;
+		p  = pstring(p, f->uname);
+		p  = pstring(p, f->aname);
+		break;
+
+	case Twalk:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT32(p, f->newfid);
+		p += BIT32SZ;
+		PBIT16(p, f->nwname);
+		p += BIT16SZ;
+		if(f->nwname > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwname; i++)
+			p = pstring(p, f->wname[i]);
+		break;
+
+	case Topen:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT8(p, f->mode);
+		p += BIT8SZ;
+		break;
+
+	case Tcreate:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		p = pstring(p, f->name);
+		PBIT32(p, f->perm);
+		p += BIT32SZ;
+		PBIT8(p, f->mode);
+		p += BIT8SZ;
+		break;
+
+	case Tread:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT64(p, f->offset);
+		p += BIT64SZ;
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		break;
+
+	case Twrite:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT64(p, f->offset);
+		p += BIT64SZ;
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		memmove(p, f->data, f->count);
+		p += f->count;
+		break;
+
+	case Tclunk:
+	case Tremove:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		break;
+
+	case Tstat:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		break;
+
+	case Twstat:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT16(p, f->nstat);
+		p += BIT16SZ;
+		memmove(p, f->stat, f->nstat);
+		p += f->nstat;
+		break;
+/*
+ */
+
+	case Rversion:
+		PBIT32(p, f->msize);
+		p += BIT32SZ;
+		p = pstring(p, f->version);
+		break;
+
+	case Rerror:
+		p = pstring(p, f->ename);
+		break;
+
+	case Rflush:
+		break;
+
+	case Rauth:
+		p = pqid(p, &f->aqid);
+		break;
+
+	case Rattach:
+		p = pqid(p, &f->qid);
+		break;
+
+	case Rwalk:
+		PBIT16(p, f->nwqid);
+		p += BIT16SZ;
+		if(f->nwqid > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwqid; i++)
+			p = pqid(p, &f->wqid[i]);
+		break;
+
+	case Ropen:
+	case Rcreate:
+		p = pqid(p, &f->qid);
+		PBIT32(p, f->iounit);
+		p += BIT32SZ;
+		break;
+
+	case Rread:
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		memmove(p, f->data, f->count);
+		p += f->count;
+		break;
+
+	case Rwrite:
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		break;
+
+	case Rclunk:
+		break;
+
+	case Rremove:
+		break;
+
+	case Rstat:
+		PBIT16(p, f->nstat);
+		p += BIT16SZ;
+		memmove(p, f->stat, f->nstat);
+		p += f->nstat;
+		break;
+
+	case Rwstat:
+		break;
+	}
+	if(size != p-ap)
+		return 0;
+	return size;
+}
--- /dev/null
+++ b/lib9/create.c
@@ -1,0 +1,32 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <fcntl.h>
+
+int
+create(char *f, int mode, int perm)
+{
+	int m;
+
+	m = 0;
+	switch(mode & 3){
+	case OREAD:
+	case OEXEC:
+		m = O_RDONLY;
+		break;
+	case OWRITE:
+		m = O_WRONLY;
+		break;
+	case ORDWR:
+		m = O_RDWR;
+		break;
+	}
+	m |= O_CREAT|O_TRUNC;
+
+	if(perm & DMDIR){
+		if(mkdir(f, perm&0777) < 0)
+			return -1;
+		perm &= ~DMDIR;
+		m &= 3;
+	}
+	return open(f, m, perm);
+}
--- /dev/null
+++ b/lib9/dirstat-Nt.c
@@ -1,0 +1,64 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define ISTYPE(s, t)	(((s)->st_mode&S_IFMT) == t)
+
+static char nullstring[] = "";
+static char Enovmem[] = "out of memory";
+
+static Dir*
+statconv(struct stat *s, char *name)
+{
+	Dir *dir;
+
+#ifdef NO
+	extern char* GetNameFromID(int);
+
+	uid = GetNameFromID(s->st_uid), NAMELEN);
+	gid = GetNameFromID(s->st_gid), NAMELEN);
+#endif
+	dir = malloc(sizeof(Dir));
+	if(dir == nil){
+		werrstr(Enovmem);
+		return nil;
+	}
+	dir->name = name;
+	dir->uid = dir->gid = dir->muid = nullstring;
+	dir->qid.type = ISTYPE(s, _S_IFDIR)? QTDIR: QTFILE;
+	dir->qid.path = s->st_ino;
+	dir->qid.vers = s->st_mtime;
+	dir->mode = (dir->qid.type<<24)|(s->st_mode&0777);
+	dir->atime = s->st_atime;
+	dir->mtime = s->st_mtime;
+	dir->length = s->st_size;
+	dir->dev = s->st_dev;
+	dir->type = ISTYPE(s, _S_IFIFO)? '|': 'M';
+	return dir;
+}
+
+Dir*
+dirfstat(int fd)
+{
+	struct stat sbuf;
+
+	if(fstat(fd, &sbuf) < 0)
+		return nil;
+	return statconv(&sbuf, nullstring);
+}
+
+Dir*
+dirstat(char *f)
+{
+	struct stat sbuf;
+	char *p;
+
+	if(stat(f, &sbuf) < 0)
+		return nil;
+	p = strrchr(f, '/');
+	if(p)
+		p++;
+	else
+		p = nullstring;
+	return statconv(&sbuf, p);
+}
--- /dev/null
+++ b/lib9/dirstat-posix.c
@@ -1,0 +1,79 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include <grp.h>
+
+static char nullstring[] = "";
+static char Enovmem[] = "out of memory";
+
+static Dir*
+statconv(struct stat *s, char *name)
+{
+	struct passwd *p;
+	struct group *g;
+	Dir *dir;
+	int str;
+	char *n;
+
+	str = 0;
+	p = getpwuid(s->st_uid);
+	if(p)
+		str += strlen(p->pw_name)+1;
+	g = getgrgid(s->st_gid);
+	if(g)
+		str += strlen(g->gr_name)+1;
+	dir = malloc(sizeof(Dir)+str);
+	if(dir == nil){
+		werrstr(Enovmem);
+		return nil;
+	}
+	n = (char*)dir+sizeof(Dir);
+	dir->name = name;
+	dir->uid = dir->gid = dir->muid = nullstring;
+	if(p){
+		dir->uid = n;
+		strcpy(n, p->pw_name);
+		n += strlen(p->pw_name)+1;
+	}
+	if(g){
+		dir->gid = n;
+		strcpy(n, g->gr_name);
+	}
+	dir->qid.type = S_ISDIR(s->st_mode)? QTDIR: QTFILE;
+	dir->qid.path = s->st_ino;
+	dir->qid.vers = s->st_mtime;
+	dir->mode = (dir->qid.type<<24)|(s->st_mode&0777);
+	dir->atime = s->st_atime;
+	dir->mtime = s->st_mtime;
+	dir->length = s->st_size;
+	dir->dev = s->st_dev;
+	dir->type = S_ISFIFO(s->st_mode)? '|': 'M';
+	return dir;
+}
+
+Dir*
+dirfstat(int fd)
+{
+	struct stat sbuf;
+
+	if(fstat(fd, &sbuf) < 0)
+		return nil;
+	return statconv(&sbuf, nullstring);
+}
+
+Dir*
+dirstat(char *f)
+{
+	struct stat sbuf;
+	char *p;
+
+	if(stat(f, &sbuf) < 0)
+		return nil;
+	p = strrchr(f, '/');
+	if(p)
+		p++;
+	else
+		p = nullstring;
+	return statconv(&sbuf, p);
+}
--- /dev/null
+++ b/lib9/dirwstat.c
@@ -1,0 +1,15 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int
+dirfwstat(int fd, Dir *d)
+{
+	return -1;
+}
+
+int
+dirwstat(char *name, Dir *d)
+{
+	return -1;
+}
--- /dev/null
+++ b/lib9/dofmt.c
@@ -1,0 +1,531 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted  */
+int
+dofmt(Fmt *f, char *fmt)
+{
+	Rune rune, *rt, *rs;
+	int r;
+	char *t, *s;
+	int n, nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = f->to;
+			rs = f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself)
+					fmt++;
+				else{
+					fmt += chartorune(&rune, fmt);
+					r = rune;
+				}
+				FMTRCHAR(f, rt, rs, r);
+			}
+			fmt++;
+			f->nfmt += rt - (Rune *)f->to;
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = f->to;
+			s = f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself){
+					FMTCHAR(f, t, s, r);
+					fmt++;
+				}else{
+					n = chartorune(&rune, fmt);
+					if(t + n > s){
+						t = _fmtflush(f, t, n);
+						if(t != nil)
+							s = f->stop;
+						else
+							return -1;
+					}
+					while(n--)
+						*t++ = *fmt++;
+				}
+			}
+			fmt++;
+			f->nfmt += t - (char *)f->to;
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = _fmtdispatch(f, fmt, 0);
+		if(fmt == nil)
+			return -1;
+	}
+}
+
+void *
+_fmtflush(Fmt *f, void *t, int len)
+{
+	if(f->runes)
+		f->nfmt += (Rune*)t - (Rune*)f->to;
+	else
+		f->nfmt += (char*)t - (char *)f->to;
+	f->to = t;
+	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+		f->stop = f->to;
+		return nil;
+	}
+	return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width charactes
+ */
+int
+_fmtpad(Fmt *f, int n)
+{
+	char *t, *s;
+	int i;
+
+	t = f->to;
+	s = f->stop;
+	for(i = 0; i < n; i++)
+		FMTCHAR(f, t, s, ' ');
+	f->nfmt += t - (char *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+_rfmtpad(Fmt *f, int n)
+{
+	Rune *t, *s;
+	int i;
+
+	t = f->to;
+	s = f->stop;
+	for(i = 0; i < n; i++)
+		FMTRCHAR(f, t, s, ' ');
+	f->nfmt += t - (Rune *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+_fmtcpy(Fmt *f, void *vm, int n, int sz)
+{
+	Rune *rt, *rs, r;
+	char *t, *s, *m, *me;
+	ulong fl;
+	int nc, w;
+
+	m = vm;
+	me = m + sz;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = f->to;
+		rs = f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRCHAR(f, rt, rs, r);
+		}
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(m < me)
+			return -1;
+		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+			return -1;
+		t = f->to;
+		s = f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+_fmtrcpy(Fmt *f, void *vm, int n)
+{
+	Rune r, *m, *me, *rt, *rs;
+	char *t, *s;
+	ulong fl;
+	int w;
+
+	m = vm;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = f->to;
+		rs = f->stop;
+		for(me = m + n; m < me; m++)
+			FMTRCHAR(f, rt, rs, *m);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+			return -1;
+		t = f->to;
+		s = f->stop;
+		for(me = m + n; m < me; m++){
+			r = *m;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+/* fmt out one character */
+int
+_charfmt(Fmt *f)
+{
+	char x[1];
+
+	x[0] = va_arg(f->args, int);
+	f->prec = 1;
+	return _fmtcpy(f, x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+_runefmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = va_arg(f->args, int);
+	return _fmtrcpy(f, x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+	int p, i;
+	if(!s)
+		return _fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(i = 0; i < p; i++)
+			if(s[i] == 0)
+				break;
+		return _fmtcpy(f, s, utfnlen(s, i), i);	/* BUG?: won't print a partial rune at end */
+	}
+
+	return _fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+_strfmt(Fmt *f)
+{
+	char *s;
+
+	s = va_arg(f->args, char *);
+	return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+	Rune *e;
+	int n, p;
+
+	if(!s)
+		return _fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(n = 0; n < p; n++)
+			if(s[n] == 0)
+				break;
+	}else{
+		for(e = s; *e; e++)
+			;
+		n = e - s;
+	}
+	return _fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+_runesfmt(Fmt *f)
+{
+	Rune *s;
+
+	s = va_arg(f->args, Rune *);
+	return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+_percentfmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = f->r;
+	f->prec = 1;
+	return _fmtrcpy(f, x, 1);
+}
+
+/* fmt an integer */
+int
+_ifmt(Fmt *f)
+{
+	char buf[70], *p, *conv;
+	uvlong vu;
+	ulong u;
+	int neg, base, i, n, fl, w, isv;
+
+	neg = 0;
+	fl = f->flags;
+	isv = 0;
+	vu = 0;
+	u = 0;
+	if(f->r == 'p'){
+		u = (ulong)va_arg(f->args, void*);
+		f->r = 'x';
+		fl |= FmtUnsigned;
+	}else if(fl & FmtVLong){
+		isv = 1;
+		if(fl & FmtUnsigned)
+			vu = va_arg(f->args, uvlong);
+		else
+			vu = va_arg(f->args, vlong);
+	}else if(fl & FmtLong){
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, ulong);
+		else
+			u = va_arg(f->args, long);
+	}else if(fl & FmtByte){
+		if(fl & FmtUnsigned)
+			u = (uchar)va_arg(f->args, int);
+		else
+			u = (char)va_arg(f->args, int);
+	}else if(fl & FmtShort){
+		if(fl & FmtUnsigned)
+			u = (ushort)va_arg(f->args, int);
+		else
+			u = (short)va_arg(f->args, int);
+	}else{
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, uint);
+		else
+			u = va_arg(f->args, int);
+	}
+	conv = "0123456789abcdef";
+	switch(f->r){
+	case 'd':
+		base = 10;
+		break;
+	case 'x':
+		base = 16;
+		break;
+	case 'X':
+		base = 16;
+		conv = "0123456789ABCDEF";
+		break;
+	case 'b':
+		base = 2;
+		break;
+	case 'o':
+		base = 8;
+		break;
+	default:
+		return -1;
+	}
+	if(!(fl & FmtUnsigned)){
+		if(isv && (vlong)vu < 0){
+			vu = -(vlong)vu;
+			neg = 1;
+		}else if(!isv && (long)u < 0){
+			u = -(long)u;
+			neg = 1;
+		}
+	}
+	p = buf + sizeof buf - 1;
+	n = 0;
+	if(isv){
+		while(vu){
+			i = vu % base;
+			vu /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}else{
+		while(u){
+			i = u % base;
+			u /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}
+	if(n == 0){
+		*p-- = '0';
+		n = 1;
+	}
+	for(w = f->prec; n < w && p > buf+3; n++)
+		*p-- = '0';
+	if(neg || (fl & (FmtSign|FmtSpace)))
+		n++;
+	if(fl & FmtSharp){
+		if(base == 16)
+			n += 2;
+		else if(base == 8){
+			if(p[1] == '0')
+				fl &= ~FmtSharp;
+			else
+				n++;
+		}
+	}
+	if((fl & FmtZero) && !(fl & FmtLeft)){
+		for(w = f->width; n < w && p > buf+3; n++)
+			*p-- = '0';
+		f->width = 0;
+	}
+	if(fl & FmtSharp){
+		if(base == 16)
+			*p-- = f->r;
+		if(base == 16 || base == 8)
+			*p-- = '0';
+	}
+	if(neg)
+		*p-- = '-';
+	else if(fl & FmtSign)
+		*p-- = '+';
+	else if(fl & FmtSpace)
+		*p-- = ' ';
+	f->flags &= ~FmtPrec;
+	return _fmtcpy(f, p + 1, n, n);
+}
+
+int
+_countfmt(Fmt *f)
+{
+	void *p;
+	ulong fl;
+
+	fl = f->flags;
+	p = va_arg(f->args, void*);
+	if(fl & FmtVLong){
+		*(vlong*)p = f->nfmt;
+	}else if(fl & FmtLong){
+		*(long*)p = f->nfmt;
+	}else if(fl & FmtByte){
+		*(char*)p = f->nfmt;
+	}else if(fl & FmtShort){
+		*(short*)p = f->nfmt;
+	}else{
+		*(int*)p = f->nfmt;
+	}
+	return 0;
+}
+
+int
+_flagfmt(Fmt *f)
+{
+	switch(f->r){
+	case ',':
+		f->flags |= FmtComma;
+		break;
+	case '-':
+		f->flags |= FmtLeft;
+		break;
+	case '+':
+		f->flags |= FmtSign;
+		break;
+	case '#':
+		f->flags |= FmtSharp;
+		break;
+	case ' ':
+		f->flags |= FmtSpace;
+		break;
+	case 'u':
+		f->flags |= FmtUnsigned;
+		break;
+	case 'h':
+		if(f->flags & FmtShort)
+			f->flags |= FmtByte;
+		f->flags |= FmtShort;
+		break;
+	case 'l':
+		if(f->flags & FmtLong)
+			f->flags |= FmtVLong;
+		f->flags |= FmtLong;
+		break;
+	}
+	return 1;
+}
+
+/* default error format */
+int
+_badfmt(Fmt *f)
+{
+	char x[3];
+
+	x[0] = '%';
+	x[1] = f->r;
+	x[2] = '%';
+	f->prec = 3;
+	_fmtcpy(f, x, 3, 3);
+	return 0;
+}
--- /dev/null
+++ b/lib9/dorfmt.c
@@ -1,0 +1,58 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted  */
+
+int
+dorfmt(Fmt *f, Rune *fmt)
+{
+	Rune *rt, *rs;
+	int r;
+	char *t, *s;
+	int nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = f->to;
+			rs = f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRCHAR(f, rt, rs, r);
+			}
+			f->nfmt += rt - (Rune *)f->to;
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = f->to;
+			s = f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRUNE(f, t, f->stop, r);
+			}
+			f->nfmt += t - (char *)f->to;
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = _fmtdispatch(f, fmt, 1);
+		if(fmt == nil)
+			return -1;
+	}
+	return 0;		/* not reached */
+}
--- /dev/null
+++ b/lib9/errfmt.c
@@ -1,0 +1,24 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+int
+errfmt(Fmt *f)
+{
+	char buf[ERRMAX];
+
+	rerrstr(buf, sizeof buf);
+	return _fmtcpy(f, buf, utflen(buf), strlen(buf));
+}
--- /dev/null
+++ b/lib9/errstr-Nt.c
@@ -1,0 +1,65 @@
+#include "lib9.h"
+#include <Windows.h>
+
+static char	errstring[ERRMAX];
+
+enum
+{
+	Magic = 0xffffff
+};
+
+static void
+winerror(int e, char *buf, uint nerr)
+{
+	int r;
+	char buf2[ERRMAX], *p, *q;
+	
+	r = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+		0, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+		buf2, sizeof(buf2), 0);
+
+	if(r == 0)
+		snprint(buf2, ERRMAX, "windows error %d", e);
+
+	q = buf2;
+	for(p = buf2; *p; p++) {
+		if(*p == '\r')
+			continue;
+		if(*p == '\n')
+			*q++ = ' ';
+		else
+			*q++ = *p;
+	}
+	*q = '\0';
+	utfecpy(buf, buf+nerr, buf2);
+}
+
+void
+werrstr(char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(errstring, errstring+sizeof(errstring), fmt, arg);
+	va_end(arg);
+	SetLastError(Magic);
+}
+
+int
+errstr(char *buf, uint nerr)
+{
+	DWORD le;
+
+	le = GetLastError();
+	if(le == Magic)
+		utfecpy(buf, buf+nerr, errstring);
+	else
+		winerror(le, buf, nerr);
+	return 1;
+}
+
+void
+oserrstr(char *buf, uint nerr)
+{
+	winerror(GetLastError(), buf, nerr);
+}
--- /dev/null
+++ b/lib9/errstr-Plan9.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+void
+oserrstr(char *buf, uint nerr)
+{
+	*buf = 0;
+	errstr(buf, nerr);
+}
--- /dev/null
+++ b/lib9/errstr-posix.c
@@ -1,0 +1,43 @@
+#include "lib9.h"
+
+#include <errno.h>
+
+static char errstring[ERRMAX];
+
+enum
+{
+	Magic = 0xffffff
+};
+
+void
+werrstr(char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(errstring, errstring+sizeof(errstring), fmt, arg);
+	va_end(arg);
+	errno = Magic;
+}
+
+void
+oserrstr(char *buf, uint nerr)
+{
+	char *s;
+
+	if(errno != EINTR)
+		s = strerror(errno);
+	else
+		s = "interrupted";
+	utfecpy(buf, buf+nerr, s);
+}
+
+int
+errstr(char *buf, uint nerr)
+{
+	if(errno == Magic)
+		utfecpy(buf, buf+nerr, errstring);
+	else
+		oserrstr(buf, nerr);
+	return 1;
+}
--- /dev/null
+++ b/lib9/exits.c
@@ -1,0 +1,17 @@
+#include "lib9.h"
+
+void
+exits(char *s)
+{
+	if(s == 0 || *s == 0)
+		exit(0);
+	exit(1);
+}
+
+void
+_exits(char *s)
+{
+	if(s == 0 || *s == 0)
+		_exit(0);
+	_exit(1);
+}
--- /dev/null
+++ b/lib9/fcallfmt.c
@@ -1,0 +1,246 @@
+/*
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <lib9.h>
+#include "fcall.h"
+
+static uint dumpsome(char*, char*, char*, long);
+static void fdirconv(char*, char*, Dir*);
+static char *qidtype(char*, uchar);
+
+#define	QIDFMT	"(%.16llux %lud %s)"
+
+int
+fcallfmt(Fmt *fmt)
+{
+	Fcall *f;
+	int fid, type, tag, i;
+	char buf[512], tmp[200];
+	char *p, *e;
+	Dir *d;
+	Qid *q;
+
+	e = buf+sizeof(buf);
+	f = va_arg(fmt->args, Fcall*);
+	type = f->type;
+	fid = f->fid;
+	tag = f->tag;
+	switch(type){
+	case Tversion:	/* 100 */
+		seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+		break;
+	case Rversion:
+		seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+		break;
+	case Tauth:	/* 102 */
+		seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
+			f->afid, f->uname, f->aname);
+		break;
+	case Rauth:
+		seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
+			f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
+		break;
+	case Tattach:	/* 104 */
+		seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
+			fid, f->afid, f->uname, f->aname);
+		break;
+	case Rattach:
+		seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
+			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
+		break;
+	case Rerror:	/* 107; 106 (Terror) illegal */
+		seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
+		break;
+	case Tflush:	/* 108 */
+		seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
+		break;
+	case Rflush:
+		seprint(buf, e, "Rflush tag %ud", tag);
+		break;
+	case Twalk:	/* 110 */
+		p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
+		if(f->nwname <= MAXWELEM)
+			for(i=0; i<f->nwname; i++)
+				p = seprint(p, e, "%d:%s ", i, f->wname[i]);
+		break;
+	case Rwalk:
+		p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
+		if(f->nwqid <= MAXWELEM)
+			for(i=0; i<f->nwqid; i++){
+				q = &f->wqid[i];
+				p = seprint(p, e, "%d:" QIDFMT " ", i,
+					q->path, q->vers, qidtype(tmp, q->type));
+			}
+		break;
+	case Topen:	/* 112 */
+		seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
+		break;
+	case Ropen:
+		seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag,
+			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+		break;
+	case Tcreate:	/* 114 */
+		seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode);
+		break;
+	case Rcreate:
+		seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
+			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+		break;
+	case Tread:	/* 116 */
+		seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
+			tag, fid, f->offset, f->count);
+		break;
+	case Rread:
+		p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
+			dumpsome(p, e, f->data, f->count);
+		break;
+	case Twrite:	/* 118 */
+		p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
+			tag, fid, f->offset, f->count);
+		dumpsome(p, e, f->data, f->count);
+		break;
+	case Rwrite:
+		seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
+		break;
+	case Tclunk:	/* 120 */
+		seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
+		break;
+	case Rclunk:
+		seprint(buf, e, "Rclunk tag %ud", tag);
+		break;
+	case Tremove:	/* 122 */
+		seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
+		break;
+	case Rremove:
+		seprint(buf, e, "Rremove tag %ud", tag);
+		break;
+	case Tstat:	/* 124 */
+		seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
+		break;
+	case Rstat:
+		p = seprint(buf, e, "Rstat tag %ud ", tag);
+		if(f->nstat > sizeof tmp)
+			seprint(p, e, " stat(%d bytes)", f->nstat);
+		else{
+			d = (Dir*)tmp;
+			convM2D(f->stat, f->nstat, d, (char*)(d+1));
+			seprint(p, e, " stat ");
+			fdirconv(p+6, e, d);
+		}
+		break;
+	case Twstat:	/* 126 */
+		p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
+		if(f->nstat > sizeof tmp)
+			seprint(p, e, " stat(%d bytes)", f->nstat);
+		else{
+			d = (Dir*)tmp;
+			convM2D(f->stat, f->nstat, d, (char*)(d+1));
+			seprint(p, e, " stat ");
+			fdirconv(p+6, e, d);
+		}
+		break;
+	case Rwstat:
+		seprint(buf, e, "Rwstat tag %ud", tag);
+		break;
+	default:
+		seprint(buf, e,  "unknown type %d", type);
+	}
+	return fmtstrcpy(fmt, buf);
+}
+
+static char*
+qidtype(char *s, uchar t)
+{
+	char *p;
+
+	p = s;
+	if(t & QTDIR)
+		*p++ = 'd';
+	if(t & QTAPPEND)
+		*p++ = 'a';
+	if(t & QTEXCL)
+		*p++ = 'l';
+	if(t & QTAUTH)
+		*p++ = 'A';
+	*p = '\0';
+	return s;
+}
+
+int
+dirfmt(Fmt *fmt)
+{
+	char buf[160];
+
+	fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
+	return fmtstrcpy(fmt, buf);
+}
+
+static void
+fdirconv(char *buf, char *e, Dir *d)
+{
+	char tmp[16];
+
+	seprint(buf, e, "'%s' '%s' '%s' '%s' "
+		"q " QIDFMT " m %#luo "
+		"at %ld mt %ld l %lld "
+		"t %d d %d",
+			d->name, d->uid, d->gid, d->muid,
+			d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
+			d->atime, d->mtime, d->length,
+			d->type, d->dev);
+}
+
+/*
+ * dump out count (or DUMPL, if count is bigger) bytes from
+ * buf to ans, as a string if they are all printable,
+ * else as a series of hex bytes
+ */
+#define DUMPL 64
+
+static uint
+dumpsome(char *ans, char *e, char *buf, long count)
+{
+	int i, printable;
+	char *p;
+
+	if(buf == nil){
+		seprint(ans, e, "<no data>");
+		return strlen(ans);
+	}
+	printable = 1;
+	if(count > DUMPL)
+		count = DUMPL;
+	for(i=0; i<count && printable; i++)
+		if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127)
+			printable = 0;
+	p = ans;
+	*p++ = '\'';
+	if(printable){
+		if(count > e-p-2)
+			count = e-p-2;
+		memmove(p, buf, count);
+		p += count;
+	}else{
+		if(2*count > e-p-2)
+			count = (e-p-2)/2;
+		for(i=0; i<count; i++){
+			if(i>0 && i%4==0)
+				*p++ = ' ';
+			sprint(p, "%2.2ux", buf[i]);
+			p += 2;
+		}
+	}
+	*p++ = '\'';
+	*p = 0;
+	return p - ans;
+}
--- /dev/null
+++ b/lib9/fltfmt.c
@@ -1,0 +1,324 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include <ctype.h>
+#include "fmtdef.h"
+
+enum
+{
+	FDIGIT	= 30,
+	FDEFLT	= 6,
+	NSIGNIF	= 17,
+};
+
+static int
+xadd(char *a, int n, int v)
+{
+	char *b;
+	int c;
+
+	if(n < 0 || n >= NSIGNIF)
+		return 0;
+	for(b = a+n; b >= a; b--) {
+		c = *b + v;
+		if(c <= '9') {
+			*b = c;
+			return 0;
+		}
+		*b = '0';
+		v = 1;
+	}
+	*a = '1';	// overflow adding
+	return 1;
+}
+
+static int
+xsub(char *a, int n, int v)
+{
+	char *b;
+	int c;
+
+	for(b = a+n; b >= a; b--) {
+		c = *b - v;
+		if(c >= '0') {
+			*b = c;
+			return 0;
+		}
+		*b = '9';
+		v = 1;
+	}
+	*a = '9';	// underflow subtracting
+	return 1;
+}
+
+static void
+xdtoa(Fmt *fmt, char *s2, double f)
+{
+	char s1[NSIGNIF+10];
+	double g, h;
+	int e, d, i, n;
+	int c1, c2, c3, c4, ucase, sign, chr, prec;
+
+	prec = FDEFLT;
+	if(fmt->flags & FmtPrec)
+		prec = fmt->prec;
+	if(prec > FDIGIT)
+		prec = FDIGIT;
+	if(isNaN(f)) {
+		strcpy(s2, "NaN");
+		return;
+	}
+	if(isInf(f, 1)) {
+		strcpy(s2, "+Inf");
+		return;
+	}
+	if(isInf(f, -1)) {
+		strcpy(s2, "-Inf");
+		return;
+	}
+	sign = 0;
+	if(f < 0) {
+		f = -f;
+		sign++;
+	}
+	ucase = 0;
+	chr = fmt->r;
+	if(isupper(chr)) {
+		ucase = 1;
+		chr = tolower(chr);
+	}
+
+	e = 0;
+	g = f;
+	if(g != 0) {
+		frexp(f, &e);
+		e = e * .301029995664;
+		if(e >= -150 && e <= +150) {
+			d = 0;
+			h = f;
+		} else {
+			d = e/2;
+			h = f * pow10(-d);
+		}
+		g = h * pow10(d-e);
+		while(g < 1) {
+			e--;
+			g = h * pow10(d-e);
+		}
+		while(g >= 10) {
+			e++;
+			g = h * pow10(d-e);
+		}
+	}
+
+	/*
+	 * convert NSIGNIF digits and convert
+	 * back to get accuracy.
+	 */
+	for(i=0; i<NSIGNIF; i++) {
+		d = g;
+		s1[i] = d + '0';
+		g = (g - d) * 10;
+	}
+	s1[i] = 0;
+
+	/*
+	 * try decimal rounding to eliminate 9s
+	 */
+	c2 = prec + 1;
+	if(chr == 'f')
+		c2 += e;
+	if(c2 >= NSIGNIF-2) {
+		strcpy(s2, s1);
+		d = e;
+		s1[NSIGNIF-2] = '0';
+		s1[NSIGNIF-1] = '0';
+		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
+		g = strtod(s1, nil);
+		if(g == f)
+			goto found;
+		if(xadd(s1, NSIGNIF-3, 1)) {
+			e++;
+			sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
+		}
+		g = strtod(s1, nil);
+		if(g == f)
+			goto found;
+		strcpy(s1, s2);
+		e = d;
+	}
+
+	/*
+	 * convert back so s1 gets exact answer
+	 */
+	for(;;) {
+		sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
+		g = strtod(s1, nil);
+		if(f > g) {
+			if(xadd(s1, NSIGNIF-1, 1))
+				e--;
+			continue;
+		}
+		if(f < g) {
+			if(xsub(s1, NSIGNIF-1, 1))
+				e++;
+			continue;
+		}
+		break;
+	}
+
+found:
+	/*
+	 * sign
+	 */
+	d = 0;
+	i = 0;
+	if(sign)
+		s2[d++] = '-';
+	else if(fmt->flags & FmtSign)
+		s2[d++] = '+';
+	else if(fmt->flags & FmtSpace)
+		s2[d++] = ' ';
+
+	/*
+	 * copy into final place
+	 * c1 digits of leading '0'
+	 * c2 digits from conversion
+	 * c3 digits of trailing '0'
+	 * c4 digits after '.'
+	 */
+	c1 = 0;
+	c2 = prec + 1;
+	c3 = 0;
+	c4 = prec;
+	switch(chr) {
+	default:
+		if(xadd(s1, c2, 5))
+			e++;
+		break;
+	case 'g':
+		/*
+		 * decide on 'e' of 'f' style convers
+		 */
+		if(xadd(s1, c2, 5))
+			e++;
+		if(e >= -5 && e <= prec) {
+			c1 = -e - 1;
+			c4 = prec - e;
+			chr = 'h';	// flag for 'f' style
+		}
+		break;
+	case 'f':
+		if(xadd(s1, c2+e, 5))
+			e++;
+		c1 = -e;
+		if(c1 > prec)
+			c1 = c2;
+		c2 += e;
+		break;
+	}
+
+	/*
+	 * clean up c1 c2 and c3
+	 */
+	if(c1 < 0)
+		c1 = 0;
+	if(c2 < 0)
+		c2 = 0;
+	if(c2 > NSIGNIF) {
+		c3 = c2-NSIGNIF;
+		c2 = NSIGNIF;
+	}
+
+	/*
+	 * copy digits
+	 */
+	while(c1 > 0) {
+		if(c1+c2+c3 == c4)
+			s2[d++] = '.';
+		s2[d++] = '0';
+		c1--;
+	}
+	while(c2 > 0) {
+		if(c2+c3 == c4)
+			s2[d++] = '.';
+		s2[d++] = s1[i++];
+		c2--;
+	}
+	while(c3 > 0) {
+		if(c3 == c4)
+			s2[d++] = '.';
+		s2[d++] = '0';
+		c3--;
+	}
+
+	/*
+	 * strip trailing '0' on g conv
+	 */
+	if(fmt->flags & FmtSharp) {
+		if(0 == c4)
+			s2[d++] = '.';
+	} else
+	if(chr == 'g' || chr == 'h') {
+		for(n=d-1; n>=0; n--)
+			if(s2[n] != '0')
+				break;
+		for(i=n; i>=0; i--)
+			if(s2[i] == '.') {
+				d = n;
+				if(i != n)
+					d++;
+				break;
+			}
+	}
+	if(chr == 'e' || chr == 'g') {
+		if(ucase)
+			s2[d++] = 'E';
+		else
+			s2[d++] = 'e';
+		c1 = e;
+		if(c1 < 0) {
+			s2[d++] = '-';
+			c1 = -c1;
+		} else
+			s2[d++] = '+';
+		if(c1 >= 100) {
+			s2[d++] = c1/100 + '0';
+			c1 = c1%100;
+		}
+		s2[d++] = c1/10 + '0';
+		s2[d++] = c1%10 + '0';
+	}
+	s2[d] = 0;
+}
+
+int
+_floatfmt(Fmt *fmt, double f)
+{
+	char s[FDIGIT+10];
+
+	xdtoa(fmt, s, f);
+	fmt->flags &= FmtWidth|FmtLeft;
+	_fmtcpy(fmt, s, strlen(s), strlen(s));
+	return 0;
+}
+
+int
+_efgfmt(Fmt *f)
+{
+	double d;
+
+	d = va_arg(f->args, double);
+	return _floatfmt(f, d);
+}
--- /dev/null
+++ b/lib9/fmt.c
@@ -1,0 +1,188 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+enum
+{
+	Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+	int	c;
+	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+struct
+{
+	/* lock by calling _fmtlock, _fmtunlock */
+	int	nfmt;
+	Convfmt	fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+	' ',	_flagfmt,
+	'#',	_flagfmt,
+	'%',	_percentfmt,
+	'+',	_flagfmt,
+	',',	_flagfmt,
+	'-',	_flagfmt,
+	'C',	_runefmt,
+	'S',	_runesfmt,
+	'X',	_ifmt,
+	'b',	_ifmt,
+	'c',	_charfmt,
+	'd',	_ifmt,
+	'h',	_flagfmt,
+	'l',	_flagfmt,
+	'n',	_countfmt,
+	'o',	_ifmt,
+	'p',	_ifmt,
+	'r',	errfmt,
+	's',	_strfmt,
+	'u',	_flagfmt,
+	'x',	_ifmt,
+	0,	nil,
+};
+
+int	(*doquote)(int);
+
+static Fmts
+fmtfmt(int c)
+{
+	Convfmt *p, *ep;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c)
+			return p->fmt;
+
+	/* is this a predefined format char? */
+	for(p=knownfmt; p->c; p++)
+		if(p->c == c){
+			/* no need to lock; fmtinstall is idempotent */
+			fmtinstall(p->c, p->fmt);
+			while(p->fmt == nil)	/* loop until value is updated */
+				;
+			return p->fmt;
+		}
+
+	return _badfmt;
+}
+
+int
+fmtinstall(int c, Fmts f)
+{
+	Convfmt *p, *ep;
+
+	if(c<=0 || c>=65536)
+		return -1;
+	if(!f)
+		f = _badfmt;
+
+	_fmtlock();
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c)
+			break;
+
+	if(p == &fmtalloc.fmt[Maxfmt]){
+		_fmtunlock();
+		return -1;
+	}
+
+	p->fmt = f;
+	if(p == ep){	/* installing a new format character */
+		fmtalloc.nfmt++;
+		p->c = c;
+	}
+
+	_fmtunlock();
+	return 0;
+}
+
+void*
+_fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+	Rune rune, r;
+	int i, n;
+
+	f->flags = 0;
+	f->width = f->prec = 0;
+
+	for(;;){
+		if(isrunes){
+			r = *(Rune*)fmt;
+			fmt = (Rune*)fmt + 1;
+		}else{
+			fmt = (char*)fmt + chartorune(&rune, fmt);
+			r = rune;
+		}
+		f->r = r;
+		switch(r){
+		case '\0':
+			return nil;
+		case '.':
+			f->flags |= FmtWidth|FmtPrec;
+			continue;
+		case '0':
+			if(!(f->flags & FmtWidth)){
+				f->flags |= FmtZero;
+				continue;
+			}
+			/* fall through */
+		case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			i = 0;
+			while(r >= '0' && r <= '9'){
+				i = i * 10 + r - '0';
+				if(isrunes){
+					r = *(Rune*)fmt;
+					fmt = (Rune*)fmt + 1;
+				}else{
+					r = *(char*)fmt;
+					fmt = (char*)fmt + 1;
+				}
+			}
+			if(isrunes)
+				fmt = (Rune*)fmt - 1;
+			else
+				fmt = (char*)fmt - 1;
+		numflag:
+			if(f->flags & FmtWidth){
+				f->flags |= FmtPrec;
+				f->prec = i;
+			}else{
+				f->flags |= FmtWidth;
+				f->width = i;
+			}
+			continue;
+		case '*':
+			i = va_arg(f->args, int);
+			if(i < 0){
+				i = -i;
+				f->flags |= FmtLeft;
+			}
+			goto numflag;
+		}
+		n = (*fmtfmt(r))(f);
+		if(n < 0)
+			return nil;
+		if(n == 0)
+			return fmt;
+	}
+}
--- /dev/null
+++ b/lib9/fmtdef.h
@@ -1,0 +1,102 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+	int	quoted;		/* if set, string must be quoted */
+	int	nrunesin;	/* number of input runes that can be accepted */
+	int	nbytesin;	/* number of input bytes that can be accepted */
+	int	nrunesout;	/* number of runes that will be generated */
+	int	nbytesout;	/* number of bytes that will be generated */
+};
+
+void	*_fmtflush(Fmt*, void*, int);
+void	*_fmtdispatch(Fmt*, void*, int);
+int	_floatfmt(Fmt*, double);
+int	_fmtpad(Fmt*, int);
+int	_rfmtpad(Fmt*, int);
+int	_fmtFdFlush(Fmt*);
+
+int	_efgfmt(Fmt*);
+int	_charfmt(Fmt*);
+int	_countfmt(Fmt*);
+int	_flagfmt(Fmt*);
+int	_percentfmt(Fmt*);
+int	_ifmt(Fmt*);
+int	_runefmt(Fmt*);
+int	_runesfmt(Fmt*);
+int	_strfmt(Fmt*);
+int	_badfmt(Fmt*);
+int	_fmtcpy(Fmt*, void*, int, int);
+int	_fmtrcpy(Fmt*, void*, int n);
+
+void	_fmtlock(void);
+void	_fmtunlock(void);
+
+#define FMTCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (char*)s){\
+		t = _fmtflush(f, t, 1);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (Rune*)s){\
+		t = _fmtflush(f, t, sizeof(Rune));\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRUNE(f, t, s, r)\
+	do{\
+	Rune _rune;\
+	int _runelen;\
+	if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+		t = _fmtflush(f, t, _runelen);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	if(r < Runeself)\
+		*t++ = r;\
+	else{\
+		_rune = r;\
+		t += runetochar(t, &_rune);\
+	}\
+	}while(0)
+
+#ifndef va_copy
+#define	va_copy(a, b) ((a) = (b))
+#endif
--- /dev/null
+++ b/lib9/fmtfd.c
@@ -1,0 +1,43 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/*
+ * public routine for final flush of a formatting buffer
+ * to a file descriptor; returns total char count.
+ */
+int
+fmtfdflush(Fmt *f)
+{
+	if(_fmtFdFlush(f) <= 0)
+		return -1;
+	return f->nfmt;
+}
+
+/*
+ * initialize an output buffer for buffered printing
+ */
+int
+fmtfdinit(Fmt *f, int fd, char *buf, int size)
+{
+	f->runes = 0;
+	f->start = buf;
+	f->to = buf;
+	f->stop = buf + size;
+	f->flush = _fmtFdFlush;
+	f->farg = (void*)fd;
+	f->nfmt = 0;
+	return 0;
+}
--- /dev/null
+++ b/lib9/fmtlock.c
@@ -1,0 +1,24 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+void
+_fmtlock(void)
+{
+}
+
+void
+_fmtunlock(void)
+{
+}
--- /dev/null
+++ b/lib9/fmtprint.c
@@ -1,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_copy(va, f->args);
+	va_end(f->args);
+	va_start(f->args, fmt);
+	n = dofmt(f, fmt);
+	va_end(f->args);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_copy(f->args, va);
+	va_end(va);
+	if(n >= 0)
+		return 0;
+	return n;
+}
+
--- /dev/null
+++ b/lib9/fmtquote.c
@@ -1,0 +1,259 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by _quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ *	NUL in input
+ *	count exceeded in input
+ *	count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+	int w;
+	Rune c;
+
+	q->quoted = 0;
+	q->nbytesout = 0;
+	q->nrunesout = 0;
+	q->nbytesin = 0;
+	q->nrunesin = 0;
+	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+		if(nout < 2)
+			return;
+		q->quoted = 1;
+		q->nbytesout = 2;
+		q->nrunesout = 2;
+	}
+	for(; nin!=0; nin-=w){
+		if(s)
+			w = chartorune(&c, s);
+		else{
+			c = *r;
+			w = runelen(c);
+		}
+
+		if(c == '\0')
+			break;
+		if(runesout){
+			if(q->nrunesout+1 > nout)
+				break;
+		}else{
+			if(q->nbytesout+w > nout)
+				break;
+		}
+
+		if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
+			if(!q->quoted){
+				if(runesout){
+					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
+						break;
+				}
+				q->nrunesout += 2;	/* include quotes */
+				q->nbytesout += 2;	/* include quotes */
+				q->quoted = 1;
+			}
+			if(c == '\'')	{
+				if(runesout){
+					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w > nout)	/* no room for quotes */
+						break;
+				}
+				q->nbytesout++;
+				q->nrunesout++;	/* quotes reproduce as two characters */
+			}
+		}
+
+		/* advance input */
+		if(s)
+			s += w;
+		else
+			r++;
+		q->nbytesin += w;
+		q->nrunesin++;
+
+		/* advance output */
+		q->nbytesout += w;
+		q->nrunesout++;
+	}
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+	Rune r, *rm, *rme;
+	char *t, *s, *m, *me;
+	Rune *rt, *rs;
+	ulong fl;
+	int nc, w;
+
+	m = sin;
+	me = m + q->nbytesin;
+	rm = rin;
+	rme = rm + q->nrunesin;
+
+	w = f->width;
+	fl = f->flags;
+	if(f->runes){
+		if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	t = f->to;
+	s = f->stop;
+	rt = f->to;
+	rs = f->stop;
+	if(f->runes)
+		FMTRCHAR(f, rt, rs, '\'');
+	else
+		FMTRUNE(f, t, s, '\'');
+	for(nc = q->nrunesin; nc > 0; nc--){
+		if(sin){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+		}else{
+			if(rm >= rme)
+				break;
+			r = *rm++;
+		}
+		if(f->runes){
+			FMTRCHAR(f, rt, rs, r);
+			if(r == '\'')
+				FMTRCHAR(f, rt, rs, r);
+		}else{
+			FMTRUNE(f, t, s, r);
+			if(r == '\'')
+				FMTRUNE(f, t, s, r);
+		}
+	}
+
+	if(f->runes){
+		FMTRCHAR(f, rt, rs, '\'');
+		USED(rs);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		FMTRUNE(f, t, s, '\'');
+		USED(s);
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+_quotestrfmt(int runesin, Fmt *f)
+{
+	int outlen;
+	Rune *r;
+	char *s;
+	Quoteinfo q;
+
+	f->flags &= ~FmtPrec;	/* ignored for %q %Q, so disable for %s %S in easy case */
+	if(runesin){
+		r = va_arg(f->args, Rune *);
+		s = nil;
+	}else{
+		s = va_arg(f->args, char *);
+		r = nil;
+	}
+	if(!s && !r)
+		return _fmtcpy(f, "<nil>", 5, 5);
+
+	if(f->flush)
+		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
+	else if(f->runes)
+		outlen = (Rune*)f->stop - (Rune*)f->to;
+	else
+		outlen = (char*)f->stop - (char*)f->to;
+
+	_quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
+//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+
+	if(runesin){
+		if(!q.quoted)
+			return _fmtrcpy(f, r, q.nrunesin);
+		return qstrfmt(nil, r, &q, f);
+	}
+
+	if(!q.quoted)
+		return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
+	return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+	return _quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+	return _quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+	fmtinstall('q', quotestrfmt);
+	fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+_needsquotes(char *s, int *quotelenp)
+{
+	Quoteinfo q;
+
+	_quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nbytesout;
+
+	return q.quoted;
+}
+
+int
+_runeneedsquotes(Rune *r, int *quotelenp)
+{
+	Quoteinfo q;
+
+	_quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nrunesout;
+
+	return q.quoted;
+}
--- /dev/null
+++ b/lib9/fmtrune.c
@@ -1,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+int
+fmtrune(Fmt *f, int r)
+{
+	Rune *rt;
+	char *t;
+	int n;
+
+	if(f->runes){
+		rt = f->to;
+		FMTRCHAR(f, rt, f->stop, r);
+		f->to = rt;
+		n = 1;
+	}else{
+		t = f->to;
+		FMTRUNE(f, t, f->stop, r);
+		n = t - (char*)f->to;
+		f->to = t;
+	}
+	f->nfmt += n;
+	return 0;
+}
--- /dev/null
+++ b/lib9/fmtstr.c
@@ -1,0 +1,23 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+fmtstrflush(Fmt *f)
+{
+	if(f->start == nil)
+		return nil;
+	*(char*)f->to = '\0';
+	return f->start;
+}
--- /dev/null
+++ b/lib9/fmtvprint.c
@@ -1,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_copy(va, f->args);
+	va_end(f->args);
+	va_copy(f->args, args);
+	n = dofmt(f, fmt);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_end(f->args);
+	va_copy(f->args, va);
+	va_end(va);
+	if(n >= 0)
+		return 0;
+	return n;
+}
+
--- /dev/null
+++ b/lib9/fprint.c
@@ -1,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include	"lib9.h"
+
+int
+fprint(int fd, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(fd, fmt, args);
+	va_end(args);
+	return n;
+}
--- /dev/null
+++ b/lib9/getcallerpc-DragonFly-386.S
@@ -1,0 +1,8 @@
+	.file	"getcallerpc-DragonFly-386.S"
+
+	.type	getcallerpc,@function
+	.global	getcallerpc
+getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret
--- /dev/null
+++ b/lib9/getcallerpc-FreeBSD-386.S
@@ -1,0 +1,8 @@
+	.file	"getcallerpc-FreeBSD-386.S"
+
+	.type	getcallerpc,@function
+	.global	getcallerpc
+getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret
--- /dev/null
+++ b/lib9/getcallerpc-Irix-mips.s
@@ -1,0 +1,9 @@
+#include <sys/regdef.h>
+#include <sys/asm.h>
+
+LEAF(getcallerpc)
+	.set	noreorder
+	lw	v0, 28(sp)
+	j	ra
+	.set reorder
+	END(getcallerpc)
--- /dev/null
+++ b/lib9/getcallerpc-Linux-386.S
@@ -1,0 +1,7 @@
+	.file	"getcallerpc-Linux-386.S"
+	.type	getcallerpc,@function
+	.global	getcallerpc
+getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret
--- /dev/null
+++ b/lib9/getcallerpc-Linux-arm.S
@@ -1,0 +1,1 @@
+/* getcallerpc for arm Linux is placed in lib9.h as inline function*/
--- /dev/null
+++ b/lib9/getcallerpc-Linux-power.c
@@ -1,0 +1,12 @@
+#include <lib9.h>
+
+ulong
+getcallerpc(void *x)
+{
+ulong *lp;
+
+	lp = x;
+
+	return lp[-1];
+}
+
--- /dev/null
+++ b/lib9/getcallerpc-Linux-spim.S
@@ -1,0 +1,10 @@
+#include <sys/regdef.h>
+#include <sys/asm.h>
+
+LEAF(getcallerpc)
+	.set	noreorder
+	addiu	t0,a0,-4
+	j	ra
+	lw	v0,0(t0)
+	.set reorder
+	END(getcallerpc)
--- /dev/null
+++ b/lib9/getcallerpc-MacOSX-386.s
@@ -1,0 +1,7 @@
+	.file	"getcallerpc-MacOSX-386.s"
+    .text
+.globl _getcallerpc
+_getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret
--- /dev/null
+++ b/lib9/getcallerpc-MacOSX-power.s
@@ -1,0 +1,19 @@
+/*
+ File: getcallerpc-Darwin-power.s
+
+ getcallerpc() is passed a pointer
+
+ Plan 9 asm:
+ 
+ TEXT	getcallerpc(SB), $-4
+	MOVW	0(R1), R3
+	RETURN
+ 
+ */
+
+#import <architecture/ppc/asm_help.h>
+
+.text
+LABEL(_getcallerpc)
+	mflr r3
+	blr
--- /dev/null
+++ b/lib9/getcallerpc-NetBSD-386.S
@@ -1,0 +1,8 @@
+	.file	"getcallerpc-NetBSD-386.S"
+
+	.type	getcallerpc,@function
+	.global	getcallerpc
+getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret
--- /dev/null
+++ b/lib9/getcallerpc-OpenBSD-386.S
@@ -1,0 +1,8 @@
+	.file	"getcallerpc-OpenBSD-386.S"
+
+	.type	getcallerpc,@function
+	.global	getcallerpc
+getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret
--- /dev/null
+++ b/lib9/getcallerpc-Solaris-386.s
@@ -1,0 +1,9 @@
+	.align	4
+	.globl	getcallerpc
+getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret	
+	.align	4
+	.type	getcallerpc,@function
+	.size	getcallerpc,.-getcallerpc
--- /dev/null
+++ b/lib9/getcallerpc-Solaris-sparc.s
@@ -1,0 +1,11 @@
+	.section	".text", #alloc, #execinstr
+	.align		8
+	.skip		16
+	.global getcallerpc
+	.type getcallerpc, #function
+getcallerpc:                  ! ignore argument
+	retl                    
+	add %i7,0,%o0
+
+	.size   getcallerpc,(.-getcallerpc)
+
--- /dev/null
+++ b/lib9/getcallerpc-Unixware-386.s
@@ -1,0 +1,9 @@
+	.align	4
+	.globl	getcallerpc
+getcallerpc:
+	movl	4(%esp), %eax
+	movl	-4(%eax), %eax
+	ret	
+	.align	4
+	.type	getcallerpc,@function
+	.size	getcallerpc,.-getcallerpc
--- /dev/null
+++ b/lib9/getfields.c
@@ -1,0 +1,35 @@
+#include	"lib9.h"
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+	Rune r;
+	int nr, intok, narg;
+
+	if(max <= 0)
+		return 0;
+
+	narg = 0;
+	args[narg] = str;
+	if(!mflag)
+		narg++;
+	intok = 0;
+	for(;; str += nr) {
+		nr = chartorune(&r, str);
+		if(r == 0)
+			break;
+		if(utfrune(set, r)) {
+			if(narg >= max)
+				break;
+			*str = 0;
+			intok = 0;
+			args[narg] = str + nr;
+			if(!mflag)
+				narg++;
+		} else {
+			if(!intok && mflag)
+				narg++;
+			intok = 1;
+		}
+	}
+	return narg;
+}
--- /dev/null
+++ b/lib9/getuser-Nt.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+char*
+getuser(void)
+{
+	/* could do better, but result isn't really used */
+	return "unknown";
+}
--- /dev/null
+++ b/lib9/getuser-posix.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include <pwd.h>
+
+char*
+getuser(void)
+{
+	struct passwd *p;
+
+	static char *user = 0;
+
+	if (!user) {
+		p = getpwuid(getuid());
+		if (p && p->pw_name) {
+			user = malloc(strlen(p->pw_name)+1);
+			if (user)
+				strcpy(user, p->pw_name);
+		}
+	}
+	if(!user)
+		user = "unknown";
+	return user;
+}
--- /dev/null
+++ b/lib9/getwd-Nt.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include <windows.h>
+
+
+char*
+getwd(char *buf, int size)
+{
+	int n;
+	char *p;
+
+	buf[0] = 0;
+
+	n = GetCurrentDirectory(size, buf);
+	if(n == 0) {
+		/*winerror();*/
+		return 0;
+	}
+
+	for(p=buf; *p; p++)
+		if(*p == '\\')
+			*p = '/';
+
+	return buf;
+}
--- /dev/null
+++ b/lib9/getwd-posix.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+#undef getwd
+#include <unistd.h>
+
+char *
+infgetwd(char *buf, int size)
+{
+	return getcwd(buf, size);
+}
--- /dev/null
+++ b/lib9/isnan-posix.c
@@ -1,0 +1,15 @@
+#include <lib9.h>
+
+int
+isNaN(double d)
+{
+	return isnan(d);
+}
+
+int
+isInf(double d, int sign)
+{
+	if(sign < 0)
+		return isinf(d) < 0;
+	return isinf(d);
+}
--- /dev/null
+++ b/lib9/lock-Irix-mips.s
@@ -1,0 +1,19 @@
+#include <sys/regdef.h>
+#include <sys/asm.h>
+
+/*
+ * lock from r4000 book
+ */
+LEAF(canlock)
+	.set 	noreorder
+1:
+	ll	t0,0(a0)		/* a0 is argument */
+	or	t1, t0, 1
+	sc	t1,0(a0)
+	beq	t1,zero,1b	
+	nop
+	j	$31			/* lock held */
+	xor	v0, t0, 1
+
+	.set 	reorder
+	END(canlock)
--- /dev/null
+++ b/lib9/lock-MacOSX-power.s
@@ -1,0 +1,16 @@
+#include <architecture/ppc/asm_help.h>
+
+LEAF(__tas)
+	sync
+	mr	r4,r3
+	addi    r5,0,0x1
+1:
+	lwarx	r3,0,r4
+	cmpwi   r3,0x0
+	bne-    2f
+	stwcx.	r5,0,r4
+	bne-    1b		/* Lost reservation, try again */
+2:
+	sync
+	blr
+END(__tas)
--- /dev/null
+++ b/lib9/lock-Nt-386.c
@@ -1,0 +1,15 @@
+#include "lib9.h"
+
+int
+_tas(int *la)
+{
+	int v;
+
+	_asm {
+		mov eax, la
+		mov ebx, 1
+		xchg	ebx, [eax]
+		mov	v, ebx
+	}
+	return v;
+}
--- /dev/null
+++ b/lib9/lock-Solaris-386.s
@@ -1,0 +1,56 @@
+	.section	.bss
+	.align	4
+.L4_.bss:
+	.align	4
+Solaris_Asm_IntP: / Offset 0
+	.type	Solaris_Asm_IntP,@object
+	.size	Solaris_Asm_IntP,4
+	.set	.,.+4
+Solaris_Asm_VoidP: / Offset 4
+	.type	Solaris_Asm_VoidP,@object
+	.size	Solaris_Asm_VoidP,4
+	.set	.,.+4
+	.section	.data
+	.align	4
+.L2_.data:
+	.align	4
+.L01:	.string	"canlock corrupted 0x%lux\n\000"
+	.set	.,.+0x2
+	.section	.text
+	.align	4
+.L1_.text:
+
+	.align	4
+	.align	4
+	.globl	canlock
+canlock:
+	pushl	%ebp
+	movl	%esp,%ebp
+	pushl	%esi
+	movl	8(%ebp),%eax
+	movl	%eax,Solaris_Asm_IntP
+	movl	$1, %ecx
+	xchg	(%eax), %ecx
+	andl	%ecx,%ecx
+	jne	.L1
+	movl	$1,%esi
+	jmp	.L2
+	.align	4
+.L3:
+	subl	%esi,%esi
+	jmp	.L2
+	.align	4
+.L1:
+	cmpl	$1,%ecx
+	je	.L3
+	pushl	%ecx
+	pushl	$.L01
+	call	print
+	addl	$8,%esp
+.L2:
+	movl	%esi,%eax
+	popl	%esi
+	leave	
+	ret	
+	.type	canlock,@function
+	.size	canlock,.-canlock
--- /dev/null
+++ b/lib9/lock-Solaris-sparc.s
@@ -1,0 +1,20 @@
+
+	.section	".text", #alloc, #execinstr
+	.align		8
+	.skip		16
+	.global canlock
+	.type	canlock,#function
+
+canlock:
+	or	%g0,1,%o1
+	swap	[%o0],%o1	! o0 points to lock; key is first word
+	cmp	%o1,1
+	bne	.gotit
+	nop
+	retl			! key was 1
+	or	%g0,0,%o0
+.gotit:
+	retl			! key was not 1
+	or	%g0,1,%o0
+
+	.size	canlock,(.-canlock)
--- /dev/null
+++ b/lib9/lock-Unixware-386.s
@@ -1,0 +1,56 @@
+	.section	.bss
+	.align	4
+.L4_.bss:
+	.align	4
+Unixware_Asm_IntP: / Offset 0
+	.type	Unixware_Asm_IntP,@object
+	.size	Unixware_Asm_IntP,4
+	.set	.,.+4
+Unixware_Asm_VoidP: / Offset 4
+	.type	Unixware_Asm_VoidP,@object
+	.size	Unixware_Asm_VoidP,4
+	.set	.,.+4
+	.section	.data
+	.align	4
+.L2_.data:
+	.align	4
+.L01:	.string	"canlock corrupted 0x%lux\n\000"
+	.set	.,.+0x2
+	.section	.text
+	.align	4
+.L1_.text:
+
+	.align	4
+	.align	4
+	.globl	canlock
+canlock:
+	pushl	%ebp
+	movl	%esp,%ebp
+	pushl	%esi
+	movl	8(%ebp),%eax
+	movl	%eax,Unixware_Asm_IntP
+	movl	$1, %ecx
+	xchg	(%eax), %ecx
+	andl	%ecx,%ecx
+	jne	.L1
+	movl	$1,%esi
+	jmp	.L2
+	.align	4
+.L3:
+	subl	%esi,%esi
+	jmp	.L2
+	.align	4
+.L1:
+	cmpl	$1,%ecx
+	je	.L3
+	pushl	%ecx
+	pushl	$.L01
+	call	print
+	addl	$8,%esp
+.L2:
+	movl	%esi,%eax
+	popl	%esi
+	leave	
+	ret	
+	.type	canlock,@function
+	.size	canlock,.-canlock
--- /dev/null
+++ b/lib9/lock.c
@@ -1,0 +1,141 @@
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+
+void
+lock(Lock *l)
+{
+	int i;
+
+	if(_tas(&l->val) == 0)
+		return;
+	for(i=0; i<100; i++){
+		if(_tas(&l->val) == 0)
+			return;
+		osyield();
+	}
+	for(i=1;; i++){
+		if(_tas(&l->val) == 0)
+			return;
+		osmillisleep(i*10);
+		if(i > 100){
+			osyield();
+			i = 1;
+		}
+	}
+}
+
+int
+canlock(Lock *l)
+{
+	return _tas(&l->val) == 0;
+}
+
+void
+unlock(Lock *l)
+{
+	l->val = 0;
+}
+
+void
+qlock(QLock *q)
+{
+	Proc *p;
+
+	lock(&q->use);
+	if(!q->locked) {
+		q->locked = 1;
+		unlock(&q->use);
+		return;
+	}
+	p = q->tail;
+	if(p == 0)
+		q->head = up;
+	else
+		p->qnext = up;
+	q->tail = up;
+	up->qnext = 0;
+	unlock(&q->use);
+	osblock();
+}
+
+int
+canqlock(QLock *q)
+{
+	if(!canlock(&q->use))
+		return 0;
+	if(q->locked){
+		unlock(&q->use);
+		return 0;
+	}
+	q->locked = 1;
+	unlock(&q->use);
+	return 1;
+}
+
+void
+qunlock(QLock *q)
+{
+	Proc *p;
+
+	lock(&q->use);
+	p = q->head;
+	if(p) {
+		q->head = p->qnext;
+		if(q->head == 0)
+			q->tail = 0;
+		unlock(&q->use);
+		osready(p);
+		return;
+	}
+	q->locked = 0;
+	unlock(&q->use);
+}
+
+void
+rlock(RWlock *l)
+{
+	qlock(&l->x);		/* wait here for writers and exclusion */
+	lock(&l->l);
+	l->readers++;
+	canqlock(&l->k);	/* block writers if we are the first reader */
+	unlock(&l->l);
+	qunlock(&l->x);
+}
+
+/* same as rlock but punts if there are any writers waiting */
+int
+canrlock(RWlock *l)
+{
+	if (!canqlock(&l->x))
+		return 0;
+	lock(&l->l);
+	l->readers++;
+	canqlock(&l->k);	/* block writers if we are the first reader */
+	unlock(&l->l);
+	qunlock(&l->x);
+	return 1;
+}
+
+void
+runlock(RWlock *l)
+{
+	lock(&l->l);
+	if(--l->readers == 0)	/* last reader out allows writers */
+		qunlock(&l->k);
+	unlock(&l->l);
+}
+
+void
+wlock(RWlock *l)
+{
+	qlock(&l->x);		/* wait here for writers and exclusion */
+	qlock(&l->k);		/* wait here for last reader */
+}
+
+void
+wunlock(RWlock *l)
+{
+	qunlock(&l->k);
+	qunlock(&l->x);
+}
--- /dev/null
+++ b/lib9/mkfile
@@ -1,0 +1,92 @@
+<../mkconfig
+
+LIB=lib9.a
+
+#
+# files used by all models
+#
+COMMONFILES=\
+	convD2M.$O\
+	convM2D.$O\
+	convM2S.$O\
+	convS2M.$O\
+	fcallfmt.$O\
+	runestrchr.$O\
+	runestrlen.$O\
+	runetype.$O\
+	strtoll.$O\
+	strtoull.$O\
+	rune.$O\
+#
+# files used by most models.  these are added to TARGFILES in some
+# model-specific mkfiles included below
+#
+IMPORTFILES=\
+	argv0.$O\
+	charstod.$O\
+	cistrcmp.$O\
+	cistrncmp.$O\
+	cistrstr.$O\
+	cleanname.$O\
+	create.$O\
+	dirwstat.$O\
+	dofmt.$O\
+	dorfmt.$O\
+	errfmt.$O\
+	exits.$O\
+	fmt.$O\
+	fmtfd.$O\
+	fmtlock.$O\
+	fmtprint.$O\
+	fmtquote.$O\
+	fmtrune.$O\
+	fmtstr.$O\
+	fmtvprint.$O\
+	fprint.$O\
+	getfields.$O\
+	nulldir.$O\
+	pow10.$O\
+	print.$O\
+	qsort.$O\
+	readn.$O\
+	rerrstr.$O\
+	runeseprint.$O\
+	runesmprint.$O\
+	runesnprint.$O\
+	runevseprint.$O\
+	seek.$O\
+	seprint.$O\
+	smprint.$O\
+	snprint.$O\
+	sprint.$O\
+	strdup.$O\
+	strecpy.$O\
+	sysfatal.$O\
+	tokenize.$O\
+	u16.$O\
+	u32.$O\
+	u64.$O\
+	utflen.$O\
+	utfnlen.$O\
+	utfrrune.$O\
+	utfrune.$O\
+	utfecpy.$O\
+	vfprint.$O\
+	vseprint.$O\
+	vsmprint.$O\
+	vsnprint.$O\
+
+<mkfile-$TARGMODEL
+
+OFILES=$COMMONFILES $TARGFILES
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/lib9.h\
+	fmtdef.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+convD2M.$O: $ROOT/include/fcall.h
+convM2D.$O: $ROOT/include/fcall.h
+convM2S.$O: $ROOT/include/fcall.h
+convS2M.$O: $ROOT/include/fcall.h
+fcallfmt.$O: $ROOT/include/fcall.h
--- /dev/null
+++ b/lib9/mkfile-Nt
@@ -1,0 +1,10 @@
+TARGFILES=\
+	$IMPORTFILES\
+	dirstat-Nt.$O\
+	errstr-Nt.$O\
+	getuser-Nt.$O\
+	getwd-Nt.$O\
+	setbinmode-Nt.$O\
+	lock-Nt-386.$O\
+	pread-Nt.$O\
+	isnan-posix.$O\
--- /dev/null
+++ b/lib9/mkfile-Plan9
@@ -1,0 +1,2 @@
+TARGFILES=errstr-Plan9.$O\
+
--- /dev/null
+++ b/lib9/mkfile-Posix
@@ -1,0 +1,10 @@
+TARGFILES=\
+	$IMPORTFILES\
+	dirstat-posix.$O\
+	errstr-posix.$O\
+	getuser-posix.$O\
+	getcallerpc-$SYSTARG-$OBJTYPE.$O\
+	setfcr-$SYSTARG-$OBJTYPE.$O\
+	getwd-posix.$O\
+	sbrk-posix.$O\
+	isnan-posix.$O\
--- /dev/null
+++ b/lib9/nulldir.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+
+void
+nulldir(Dir *d)
+{
+	memset(d, ~0, sizeof(Dir));
+	d->name = d->uid = d->gid = d->muid = "";
+}
--- /dev/null
+++ b/lib9/pow10.c
@@ -1,0 +1,51 @@
+#ifdef	LINUX_386
+#define	_MATH_H
+#endif
+#include	"lib9.h"
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+static
+double	tab[] =
+{
+	1.0e0,  1.0e1,  1.0e2,  1.0e3,  1.0e4,  1.0e5,  1.0e6,  1.0e7,  1.0e8,  1.0e9, 
+	1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, 
+	1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, 
+	1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, 
+	1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49, 
+	1.0e50, 1.0e51, 1.0e52, 1.0e53, 1.0e54, 1.0e55, 1.0e56, 1.0e57, 1.0e58, 1.0e59, 
+	1.0e60, 1.0e61, 1.0e62, 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, 
+	1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79, 
+	1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, 
+	1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99, 
+	1.0e100,1.0e101,1.0e102,1.0e103,1.0e104,1.0e105,1.0e106,1.0e107,1.0e108,1.0e109,
+	1.0e110,1.0e111,1.0e112,1.0e113,1.0e114,1.0e115,1.0e116,1.0e117,1.0e118,1.0e119,
+	1.0e120,1.0e121,1.0e122,1.0e123,1.0e124,1.0e125,1.0e126,1.0e127,1.0e128,1.0e129,
+	1.0e130,1.0e131,1.0e132,1.0e133,1.0e134,1.0e135,1.0e136,1.0e137,1.0e138,1.0e139,
+	1.0e140,1.0e141,1.0e142,1.0e143,1.0e144,1.0e145,1.0e146,1.0e147,1.0e148,1.0e149,
+	1.0e150,1.0e151,1.0e152,1.0e153,1.0e154,1.0e155,1.0e156,1.0e157,1.0e158,1.0e159,
+};
+
+double
+pow10(int n)
+{
+	int m;
+
+	if(n < 0) {
+		n = -n;
+		if(n < sizeof(tab)/sizeof(tab[0]))
+			return 1/tab[n];
+		m = n/2;
+		return 1/(pow10(m) * pow10(n-m));
+	}
+	if(n < sizeof(tab)/sizeof(tab[0]))
+		return tab[n];
+	m = n/2;
+	return pow10(m) * pow10(n-m);
+}
--- /dev/null
+++ b/lib9/pread-Nt.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+
+long
+pread(int fd, void *buf, long n, vlong offset)
+{
+	if(seek(fd, offset, 0) < 0)
+		return -1;
+	return read(fd, buf, n);
+}
--- /dev/null
+++ b/lib9/print.c
@@ -1,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include	"lib9.h"
+
+int
+print(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(1, fmt, args);
+	va_end(args);
+	return n;
+}
--- /dev/null
+++ b/lib9/qsort.c
@@ -1,0 +1,123 @@
+/*
+ * qsort -- simple quicksort
+ */
+
+#include "lib9.h"
+typedef
+struct
+{
+	int	(*cmp)(void*, void*);
+	void	(*swap)(char*, char*, long);
+	long	es;
+} Sort;
+
+static	void
+swapb(char *i, char *j, long es)
+{
+	char c;
+
+	do {
+		c = *i;
+		*i++ = *j;
+		*j++ = c;
+		es--;
+	} while(es != 0);
+
+}
+
+static	void
+swapi(char *ii, char *ij, long es)
+{
+	long *i, *j, c;
+
+	i = (long*)ii;
+	j = (long*)ij;
+	do {
+		c = *i;
+		*i++ = *j;
+		*j++ = c;
+		es -= sizeof(long);
+	} while(es != 0);
+}
+
+static	char*
+pivot(char *a, long n, Sort *p)
+{
+	long j;
+	char *pi, *pj, *pk;
+
+	j = n/6 * p->es;
+	pi = a + j;	/* 1/6 */
+	j += j;
+	pj = pi + j;	/* 1/2 */
+	pk = pj + j;	/* 5/6 */
+	if(p->cmp(pi, pj) < 0) {
+		if(p->cmp(pi, pk) < 0) {
+			if(p->cmp(pj, pk) < 0)
+				return pj;
+			return pk;
+		}
+		return pi;
+	}
+	if(p->cmp(pj, pk) < 0) {
+		if(p->cmp(pi, pk) < 0)
+			return pi;
+		return pk;
+	}
+	return pj;
+}
+
+static	void
+qsorts(char *a, long n, Sort *p)
+{
+	long j, es;
+	char *pi, *pj, *pn;
+
+	es = p->es;
+	while(n > 1) {
+		if(n > 10) {
+			pi = pivot(a, n, p);
+		} else
+			pi = a + (n>>1)*es;
+
+		p->swap(a, pi, es);
+		pi = a;
+		pn = a + n*es;
+		pj = pn;
+		for(;;) {
+			do
+				pi += es;
+			while(pi < pn && p->cmp(pi, a) < 0);
+			do
+				pj -= es;
+			while(pj > a && p->cmp(pj, a) > 0);
+			if(pj < pi)
+				break;
+			p->swap(pi, pj, es);
+		}
+		p->swap(a, pj, es);
+		j = (pj - a) / es;
+
+		n = n-j-1;
+		if(j >= n) {
+			qsorts(a, j, p);
+			a += (j+1)*es;
+		} else {
+			qsorts(a + (j+1)*es, n, p);
+			n = j;
+		}
+	}
+}
+
+void
+qsort(void *va, long n, long es, int (*cmp)(void*, void*))
+{
+	Sort s;
+
+	s.cmp = cmp;
+	s.es = es;
+	s.swap = swapi;
+	if(((uintptr)va | es) % sizeof(long))
+		s.swap = swapb;
+	qsorts((char*)va, n, &s);
+}
--- /dev/null
+++ b/lib9/readn.c
@@ -1,0 +1,21 @@
+#include "lib9.h"
+
+long
+readn(int f, void *av, long n)
+{
+	char *a;
+	long m, t;
+
+	a = av;
+	t = 0;
+	while(t < n){
+		m = read(f, a+t, n-t);
+		if(m <= 0){
+			if(t == 0)
+				return m;
+			break;
+		}
+		t += m;
+	}
+	return t;
+}
--- /dev/null
+++ b/lib9/rerrstr.c
@@ -1,0 +1,12 @@
+#include "lib9.h"
+
+void
+rerrstr(char *buf, uint nbuf)
+{
+	char tmp[ERRMAX];
+
+	tmp[0] = 0;
+	errstr(tmp, sizeof tmp);
+	utfecpy(buf, buf+nbuf, tmp);
+	errstr(tmp, sizeof tmp);
+}
--- /dev/null
+++ b/lib9/rune.c
@@ -1,0 +1,165 @@
+#include	"lib9.h"
+
+#define Bit(i) (7-(i))
+/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */
+#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF)
+/* 0000 0000 0000 0111 1111 1111 */
+#define	RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1)
+
+enum
+{
+	Bitx	= Bit(1),
+
+	Tx	= T(1),			/* 1000 0000 */
+	Rune1 = (1<<(Bit(0)+0*Bitx))-1,	/* 0000 0000 0000 0000 0111 1111 */
+
+	Maskx	= (1<<Bitx)-1,		/* 0011 1111 */
+	Testx	= Maskx ^ 0xFF,		/* 1100 0000 */
+
+	SurrogateMin	= 0xD800,
+	SurrogateMax	= 0xDFFF,
+
+	Bad	= Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+	int c[UTFmax], i;
+	Rune l;
+
+	/*
+	 * N character sequence
+	 *	00000-0007F => T1
+	 *	00080-007FF => T2 Tx
+	 *	00800-0FFFF => T3 Tx Tx
+	 *	10000-10FFFF => T4 Tx Tx Tx
+	 */
+
+	c[0] = *(uchar*)(str);
+	if(c[0] < Tx){
+		*rune = c[0];
+		return 1;
+	}
+	l = c[0];
+
+	for(i = 1; i < UTFmax; i++) {
+		c[i] = *(uchar*)(str+i);
+		c[i] ^= Tx;
+		if(c[i] & Testx)
+			goto bad;
+		l = (l << Bitx) | c[i];
+		if(c[0] < T(i + 2)) {
+			l &= RuneX(i + 1);
+			if(i == 1) {
+				if(c[0] < T(2) || l <= Rune1)
+					goto bad;
+			} else if(l <= RuneX(i) || l > Runemax)
+				goto bad;
+			if (i == 2 && SurrogateMin <= l && l <= SurrogateMax)
+				goto bad;
+			*rune = l;
+			return i + 1;
+		}
+	}
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	*rune = Bad;
+	return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+	int i, j;
+	Rune c;
+
+	c = *rune;
+	if(c <= Rune1) {
+		str[0] = c;
+		return 1;
+	}
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => 00-7F
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 * four character sequence (21-bit value)
+	 *     10000-1FFFFF => T4 Tx Tx Tx
+	 * If the Rune is out of range or a surrogate half,
+	 * convert it to the error rune.
+	 * Do this test when i==3 because the error rune encodes to three bytes.
+	 * Doing it earlier would duplicate work, since an out of range
+	 * Rune wouldn't have fit in one or two bytes.
+	 */
+	for(i = 2; i < UTFmax + 1; i++){
+		if(i == 3){
+			if(c > Runemax)
+				c = Runeerror;
+			if(SurrogateMin <= c && c <= SurrogateMax)
+				c = Runeerror;
+		}
+		if (c <= RuneX(i) || i == UTFmax ) {
+			str[0] = T(i) |  (c >> (i - 1)*Bitx);
+			for(j = 1; j < i; j++)
+				str[j] = Tx | ((c >> (i - j - 1)*Bitx) & Maskx);
+			return i;
+		}
+	}
+	return UTFmax;
+}
+
+int
+runelen(long c)
+{
+	Rune rune;
+	char str[10];
+
+	rune = c;
+	return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+	int nb, i;
+	Rune c;
+
+	nb = 0;
+	while(nrune--) {
+		c = *r++;
+		if(c <= Rune1){
+			nb++;
+		} else {
+			for(i = 2; i < UTFmax + 1; i++)
+				if(c <= RuneX(i) || i == UTFmax){
+					nb += i;
+					break;
+				}
+		}
+	}
+	return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+	int  i;
+	Rune c;
+
+	if(n <= 0)
+		return 0;
+	c = *(uchar*)str;
+	if(c < Tx)
+		return 1;
+	for(i = 3; i < UTFmax + 1; i++)
+		if(c < T(i))
+			return n >= i - 1;
+	return n >= UTFmax;
+}
--- /dev/null
+++ b/lib9/runeseprint.c
@@ -1,0 +1,13 @@
+#include "lib9.h"
+
+Rune*
+runeseprint(Rune *buf, Rune *e, char *fmt, ...)
+{
+	Rune *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = runevseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}
--- /dev/null
+++ b/lib9/runesmprint.c
@@ -1,0 +1,13 @@
+#include "lib9.h"
+
+Rune*
+runesmprint(char *fmt, ...)
+{
+	va_list args;
+	Rune *p;
+
+	va_start(args, fmt);
+	p = runevsmprint(fmt, args);
+	va_end(args);
+	return p;
+}
--- /dev/null
+++ b/lib9/runesnprint.c
@@ -1,0 +1,14 @@
+#include "lib9.h"
+
+int
+runesnprint(Rune *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = runevsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+
--- /dev/null
+++ b/lib9/runestrchr.c
@@ -1,0 +1,19 @@
+#include "lib9.h"
+
+Rune*
+runestrchr(Rune *s, Rune c)
+{
+	Rune c0 = c;
+	Rune c1;
+
+	if(c == 0) {
+		while(*s++)
+			;
+		return s-1;
+	}
+
+	while(c1 = *s++)
+		if(c1 == c0)
+			return s-1;
+	return 0;
+}
--- /dev/null
+++ b/lib9/runestrlen.c
@@ -1,0 +1,13 @@
+#include "lib9.h"
+
+
+long
+runestrlen(Rune *s)
+{
+	int i;
+
+	i = 0;
+	while(*s++)
+		i++;
+	return i;
+}
--- /dev/null
+++ b/lib9/runetype.c
@@ -1,0 +1,5 @@
+#include	"lib9.h"
+
+Rune*_runebsearch(Rune c, Rune *t, int n, int ne);
+
+#include "runetypebody-6.2.0.h"
--- /dev/null
+++ b/lib9/runetypebody-6.2.0.h
@@ -1,0 +1,1641 @@
+/* generated automatically by mkrunetype.c in Go from UnicodeData-6.2.0.txt
+ *  with s/rbsearch/_runebsearch/g
+ */
+
+static Rune __isspacer[] = {
+	0x0009, 0x000d,
+	0x0020, 0x0020,
+	0x0085, 0x0085,
+	0x00a0, 0x00a0,
+	0x1680, 0x1680,
+	0x180e, 0x180e,
+	0x2000, 0x200a,
+	0x2028, 0x2029,
+	0x202f, 0x202f,
+	0x205f, 0x205f,
+	0x3000, 0x3000,
+	0xfeff, 0xfeff,
+};
+
+int
+isspacerune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __isspacer, nelem(__isspacer)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	return 0;
+}
+
+static Rune __isdigitr[] = {
+	0x0030, 0x0039,
+	0x0660, 0x0669,
+	0x06f0, 0x06f9,
+	0x07c0, 0x07c9,
+	0x0966, 0x096f,
+	0x09e6, 0x09ef,
+	0x0a66, 0x0a6f,
+	0x0ae6, 0x0aef,
+	0x0b66, 0x0b6f,
+	0x0be6, 0x0bef,
+	0x0c66, 0x0c6f,
+	0x0ce6, 0x0cef,
+	0x0d66, 0x0d6f,
+	0x0e50, 0x0e59,
+	0x0ed0, 0x0ed9,
+	0x0f20, 0x0f29,
+	0x1040, 0x1049,
+	0x1090, 0x1099,
+	0x17e0, 0x17e9,
+	0x1810, 0x1819,
+	0x1946, 0x194f,
+	0x19d0, 0x19d9,
+	0x1a80, 0x1a89,
+	0x1a90, 0x1a99,
+	0x1b50, 0x1b59,
+	0x1bb0, 0x1bb9,
+	0x1c40, 0x1c49,
+	0x1c50, 0x1c59,
+	0xa620, 0xa629,
+	0xa8d0, 0xa8d9,
+	0xa900, 0xa909,
+	0xa9d0, 0xa9d9,
+	0xaa50, 0xaa59,
+	0xabf0, 0xabf9,
+	0xff10, 0xff19,
+	0x104a0, 0x104a9,
+	0x11066, 0x1106f,
+	0x110f0, 0x110f9,
+	0x11136, 0x1113f,
+	0x111d0, 0x111d9,
+	0x116c0, 0x116c9,
+	0x1d7ce, 0x1d7ff,
+};
+
+int
+isdigitrune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	return 0;
+}
+
+static Rune __isalphar[] = {
+	0x0041, 0x005a,
+	0x0061, 0x007a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00f6,
+	0x00f8, 0x02c1,
+	0x02c6, 0x02d1,
+	0x02e0, 0x02e4,
+	0x0370, 0x0374,
+	0x0376, 0x0377,
+	0x037a, 0x037d,
+	0x0388, 0x038a,
+	0x038e, 0x03a1,
+	0x03a3, 0x03f5,
+	0x03f7, 0x0481,
+	0x048a, 0x0527,
+	0x0531, 0x0556,
+	0x0561, 0x0587,
+	0x05d0, 0x05ea,
+	0x05f0, 0x05f2,
+	0x0620, 0x064a,
+	0x066e, 0x066f,
+	0x0671, 0x06d3,
+	0x06e5, 0x06e6,
+	0x06ee, 0x06ef,
+	0x06fa, 0x06fc,
+	0x0712, 0x072f,
+	0x074d, 0x07a5,
+	0x07ca, 0x07ea,
+	0x07f4, 0x07f5,
+	0x0800, 0x0815,
+	0x0840, 0x0858,
+	0x08a2, 0x08ac,
+	0x0904, 0x0939,
+	0x0958, 0x0961,
+	0x0971, 0x0977,
+	0x0979, 0x097f,
+	0x0985, 0x098c,
+	0x098f, 0x0990,
+	0x0993, 0x09a8,
+	0x09aa, 0x09b0,
+	0x09b6, 0x09b9,
+	0x09dc, 0x09dd,
+	0x09df, 0x09e1,
+	0x09f0, 0x09f1,
+	0x0a05, 0x0a0a,
+	0x0a0f, 0x0a10,
+	0x0a13, 0x0a28,
+	0x0a2a, 0x0a30,
+	0x0a32, 0x0a33,
+	0x0a35, 0x0a36,
+	0x0a38, 0x0a39,
+	0x0a59, 0x0a5c,
+	0x0a72, 0x0a74,
+	0x0a85, 0x0a8d,
+	0x0a8f, 0x0a91,
+	0x0a93, 0x0aa8,
+	0x0aaa, 0x0ab0,
+	0x0ab2, 0x0ab3,
+	0x0ab5, 0x0ab9,
+	0x0ae0, 0x0ae1,
+	0x0b05, 0x0b0c,
+	0x0b0f, 0x0b10,
+	0x0b13, 0x0b28,
+	0x0b2a, 0x0b30,
+	0x0b32, 0x0b33,
+	0x0b35, 0x0b39,
+	0x0b5c, 0x0b5d,
+	0x0b5f, 0x0b61,
+	0x0b85, 0x0b8a,
+	0x0b8e, 0x0b90,
+	0x0b92, 0x0b95,
+	0x0b99, 0x0b9a,
+	0x0b9e, 0x0b9f,
+	0x0ba3, 0x0ba4,
+	0x0ba8, 0x0baa,
+	0x0bae, 0x0bb9,
+	0x0c05, 0x0c0c,
+	0x0c0e, 0x0c10,
+	0x0c12, 0x0c28,
+	0x0c2a, 0x0c33,
+	0x0c35, 0x0c39,
+	0x0c58, 0x0c59,
+	0x0c60, 0x0c61,
+	0x0c85, 0x0c8c,
+	0x0c8e, 0x0c90,
+	0x0c92, 0x0ca8,
+	0x0caa, 0x0cb3,
+	0x0cb5, 0x0cb9,
+	0x0ce0, 0x0ce1,
+	0x0cf1, 0x0cf2,
+	0x0d05, 0x0d0c,
+	0x0d0e, 0x0d10,
+	0x0d12, 0x0d3a,
+	0x0d60, 0x0d61,
+	0x0d7a, 0x0d7f,
+	0x0d85, 0x0d96,
+	0x0d9a, 0x0db1,
+	0x0db3, 0x0dbb,
+	0x0dc0, 0x0dc6,
+	0x0e01, 0x0e30,
+	0x0e32, 0x0e33,
+	0x0e40, 0x0e46,
+	0x0e81, 0x0e82,
+	0x0e87, 0x0e88,
+	0x0e94, 0x0e97,
+	0x0e99, 0x0e9f,
+	0x0ea1, 0x0ea3,
+	0x0eaa, 0x0eab,
+	0x0ead, 0x0eb0,
+	0x0eb2, 0x0eb3,
+	0x0ec0, 0x0ec4,
+	0x0edc, 0x0edf,
+	0x0f40, 0x0f47,
+	0x0f49, 0x0f6c,
+	0x0f88, 0x0f8c,
+	0x1000, 0x102a,
+	0x1050, 0x1055,
+	0x105a, 0x105d,
+	0x1065, 0x1066,
+	0x106e, 0x1070,
+	0x1075, 0x1081,
+	0x10a0, 0x10c5,
+	0x10d0, 0x10fa,
+	0x10fc, 0x1248,
+	0x124a, 0x124d,
+	0x1250, 0x1256,
+	0x125a, 0x125d,
+	0x1260, 0x1288,
+	0x128a, 0x128d,
+	0x1290, 0x12b0,
+	0x12b2, 0x12b5,
+	0x12b8, 0x12be,
+	0x12c2, 0x12c5,
+	0x12c8, 0x12d6,
+	0x12d8, 0x1310,
+	0x1312, 0x1315,
+	0x1318, 0x135a,
+	0x1380, 0x138f,
+	0x13a0, 0x13f4,
+	0x1401, 0x166c,
+	0x166f, 0x167f,
+	0x1681, 0x169a,
+	0x16a0, 0x16ea,
+	0x1700, 0x170c,
+	0x170e, 0x1711,
+	0x1720, 0x1731,
+	0x1740, 0x1751,
+	0x1760, 0x176c,
+	0x176e, 0x1770,
+	0x1780, 0x17b3,
+	0x1820, 0x1877,
+	0x1880, 0x18a8,
+	0x18b0, 0x18f5,
+	0x1900, 0x191c,
+	0x1950, 0x196d,
+	0x1970, 0x1974,
+	0x1980, 0x19ab,
+	0x19c1, 0x19c7,
+	0x1a00, 0x1a16,
+	0x1a20, 0x1a54,
+	0x1b05, 0x1b33,
+	0x1b45, 0x1b4b,
+	0x1b83, 0x1ba0,
+	0x1bae, 0x1baf,
+	0x1bba, 0x1be5,
+	0x1c00, 0x1c23,
+	0x1c4d, 0x1c4f,
+	0x1c5a, 0x1c7d,
+	0x1ce9, 0x1cec,
+	0x1cee, 0x1cf1,
+	0x1cf5, 0x1cf6,
+	0x1d00, 0x1dbf,
+	0x1e00, 0x1f15,
+	0x1f18, 0x1f1d,
+	0x1f20, 0x1f45,
+	0x1f48, 0x1f4d,
+	0x1f50, 0x1f57,
+	0x1f5f, 0x1f7d,
+	0x1f80, 0x1fb4,
+	0x1fb6, 0x1fbc,
+	0x1fc2, 0x1fc4,
+	0x1fc6, 0x1fcc,
+	0x1fd0, 0x1fd3,
+	0x1fd6, 0x1fdb,
+	0x1fe0, 0x1fec,
+	0x1ff2, 0x1ff4,
+	0x1ff6, 0x1ffc,
+	0x2090, 0x209c,
+	0x210a, 0x2113,
+	0x2119, 0x211d,
+	0x212a, 0x212d,
+	0x212f, 0x2139,
+	0x213c, 0x213f,
+	0x2145, 0x2149,
+	0x2183, 0x2184,
+	0x2c00, 0x2c2e,
+	0x2c30, 0x2c5e,
+	0x2c60, 0x2ce4,
+	0x2ceb, 0x2cee,
+	0x2cf2, 0x2cf3,
+	0x2d00, 0x2d25,
+	0x2d30, 0x2d67,
+	0x2d80, 0x2d96,
+	0x2da0, 0x2da6,
+	0x2da8, 0x2dae,
+	0x2db0, 0x2db6,
+	0x2db8, 0x2dbe,
+	0x2dc0, 0x2dc6,
+	0x2dc8, 0x2dce,
+	0x2dd0, 0x2dd6,
+	0x2dd8, 0x2dde,
+	0x3005, 0x3006,
+	0x3031, 0x3035,
+	0x303b, 0x303c,
+	0x3041, 0x3096,
+	0x309d, 0x309f,
+	0x30a1, 0x30fa,
+	0x30fc, 0x30ff,
+	0x3105, 0x312d,
+	0x3131, 0x318e,
+	0x31a0, 0x31ba,
+	0x31f0, 0x31ff,
+	0x3400, 0x4db5,
+	0x4e00, 0x9fcc,
+	0xa000, 0xa48c,
+	0xa4d0, 0xa4fd,
+	0xa500, 0xa60c,
+	0xa610, 0xa61f,
+	0xa62a, 0xa62b,
+	0xa640, 0xa66e,
+	0xa67f, 0xa697,
+	0xa6a0, 0xa6e5,
+	0xa717, 0xa71f,
+	0xa722, 0xa788,
+	0xa78b, 0xa78e,
+	0xa790, 0xa793,
+	0xa7a0, 0xa7aa,
+	0xa7f8, 0xa801,
+	0xa803, 0xa805,
+	0xa807, 0xa80a,
+	0xa80c, 0xa822,
+	0xa840, 0xa873,
+	0xa882, 0xa8b3,
+	0xa8f2, 0xa8f7,
+	0xa90a, 0xa925,
+	0xa930, 0xa946,
+	0xa960, 0xa97c,
+	0xa984, 0xa9b2,
+	0xaa00, 0xaa28,
+	0xaa40, 0xaa42,
+	0xaa44, 0xaa4b,
+	0xaa60, 0xaa76,
+	0xaa80, 0xaaaf,
+	0xaab5, 0xaab6,
+	0xaab9, 0xaabd,
+	0xaadb, 0xaadd,
+	0xaae0, 0xaaea,
+	0xaaf2, 0xaaf4,
+	0xab01, 0xab06,
+	0xab09, 0xab0e,
+	0xab11, 0xab16,
+	0xab20, 0xab26,
+	0xab28, 0xab2e,
+	0xabc0, 0xabe2,
+	0xac00, 0xd7a3,
+	0xd7b0, 0xd7c6,
+	0xd7cb, 0xd7fb,
+	0xf900, 0xfa6d,
+	0xfa70, 0xfad9,
+	0xfb00, 0xfb06,
+	0xfb13, 0xfb17,
+	0xfb1f, 0xfb28,
+	0xfb2a, 0xfb36,
+	0xfb38, 0xfb3c,
+	0xfb40, 0xfb41,
+	0xfb43, 0xfb44,
+	0xfb46, 0xfbb1,
+	0xfbd3, 0xfd3d,
+	0xfd50, 0xfd8f,
+	0xfd92, 0xfdc7,
+	0xfdf0, 0xfdfb,
+	0xfe70, 0xfe74,
+	0xfe76, 0xfefc,
+	0xff21, 0xff3a,
+	0xff41, 0xff5a,
+	0xff66, 0xffbe,
+	0xffc2, 0xffc7,
+	0xffca, 0xffcf,
+	0xffd2, 0xffd7,
+	0xffda, 0xffdc,
+	0x10000, 0x1000b,
+	0x1000d, 0x10026,
+	0x10028, 0x1003a,
+	0x1003c, 0x1003d,
+	0x1003f, 0x1004d,
+	0x10050, 0x1005d,
+	0x10080, 0x100fa,
+	0x10280, 0x1029c,
+	0x102a0, 0x102d0,
+	0x10300, 0x1031e,
+	0x10330, 0x10340,
+	0x10342, 0x10349,
+	0x10380, 0x1039d,
+	0x103a0, 0x103c3,
+	0x103c8, 0x103cf,
+	0x10400, 0x1049d,
+	0x10800, 0x10805,
+	0x1080a, 0x10835,
+	0x10837, 0x10838,
+	0x1083f, 0x10855,
+	0x10900, 0x10915,
+	0x10920, 0x10939,
+	0x10980, 0x109b7,
+	0x109be, 0x109bf,
+	0x10a10, 0x10a13,
+	0x10a15, 0x10a17,
+	0x10a19, 0x10a33,
+	0x10a60, 0x10a7c,
+	0x10b00, 0x10b35,
+	0x10b40, 0x10b55,
+	0x10b60, 0x10b72,
+	0x10c00, 0x10c48,
+	0x11003, 0x11037,
+	0x11083, 0x110af,
+	0x110d0, 0x110e8,
+	0x11103, 0x11126,
+	0x11183, 0x111b2,
+	0x111c1, 0x111c4,
+	0x11680, 0x116aa,
+	0x12000, 0x1236e,
+	0x13000, 0x1342e,
+	0x16800, 0x16a38,
+	0x16f00, 0x16f44,
+	0x16f93, 0x16f9f,
+	0x1b000, 0x1b001,
+	0x1d400, 0x1d454,
+	0x1d456, 0x1d49c,
+	0x1d49e, 0x1d49f,
+	0x1d4a5, 0x1d4a6,
+	0x1d4a9, 0x1d4ac,
+	0x1d4ae, 0x1d4b9,
+	0x1d4bd, 0x1d4c3,
+	0x1d4c5, 0x1d505,
+	0x1d507, 0x1d50a,
+	0x1d50d, 0x1d514,
+	0x1d516, 0x1d51c,
+	0x1d51e, 0x1d539,
+	0x1d53b, 0x1d53e,
+	0x1d540, 0x1d544,
+	0x1d54a, 0x1d550,
+	0x1d552, 0x1d6a5,
+	0x1d6a8, 0x1d6c0,
+	0x1d6c2, 0x1d6da,
+	0x1d6dc, 0x1d6fa,
+	0x1d6fc, 0x1d714,
+	0x1d716, 0x1d734,
+	0x1d736, 0x1d74e,
+	0x1d750, 0x1d76e,
+	0x1d770, 0x1d788,
+	0x1d78a, 0x1d7a8,
+	0x1d7aa, 0x1d7c2,
+	0x1d7c4, 0x1d7cb,
+	0x1ee00, 0x1ee03,
+	0x1ee05, 0x1ee1f,
+	0x1ee21, 0x1ee22,
+	0x1ee29, 0x1ee32,
+	0x1ee34, 0x1ee37,
+	0x1ee4d, 0x1ee4f,
+	0x1ee51, 0x1ee52,
+	0x1ee61, 0x1ee62,
+	0x1ee67, 0x1ee6a,
+	0x1ee6c, 0x1ee72,
+	0x1ee74, 0x1ee77,
+	0x1ee79, 0x1ee7c,
+	0x1ee80, 0x1ee89,
+	0x1ee8b, 0x1ee9b,
+	0x1eea1, 0x1eea3,
+	0x1eea5, 0x1eea9,
+	0x1eeab, 0x1eebb,
+	0x20000, 0x2a6d6,
+	0x2a700, 0x2b734,
+	0x2b740, 0x2b81d,
+	0x2f800, 0x2fa1d,
+};
+
+static Rune __isalphas[] = {
+	0x00aa,
+	0x00b5,
+	0x00ba,
+	0x02ec,
+	0x02ee,
+	0x0386,
+	0x038c,
+	0x0559,
+	0x06d5,
+	0x06ff,
+	0x0710,
+	0x07b1,
+	0x07fa,
+	0x081a,
+	0x0824,
+	0x0828,
+	0x08a0,
+	0x093d,
+	0x0950,
+	0x09b2,
+	0x09bd,
+	0x09ce,
+	0x0a5e,
+	0x0abd,
+	0x0ad0,
+	0x0b3d,
+	0x0b71,
+	0x0b83,
+	0x0b9c,
+	0x0bd0,
+	0x0c3d,
+	0x0cbd,
+	0x0cde,
+	0x0d3d,
+	0x0d4e,
+	0x0dbd,
+	0x0e84,
+	0x0e8a,
+	0x0e8d,
+	0x0ea5,
+	0x0ea7,
+	0x0ebd,
+	0x0ec6,
+	0x0f00,
+	0x103f,
+	0x1061,
+	0x108e,
+	0x10c7,
+	0x10cd,
+	0x1258,
+	0x12c0,
+	0x17d7,
+	0x17dc,
+	0x18aa,
+	0x1aa7,
+	0x1f59,
+	0x1f5b,
+	0x1f5d,
+	0x1fbe,
+	0x2071,
+	0x207f,
+	0x2102,
+	0x2107,
+	0x2115,
+	0x2124,
+	0x2126,
+	0x2128,
+	0x214e,
+	0x2d27,
+	0x2d2d,
+	0x2d6f,
+	0x2e2f,
+	0xa8fb,
+	0xa9cf,
+	0xaa7a,
+	0xaab1,
+	0xaac0,
+	0xaac2,
+	0xfb1d,
+	0xfb3e,
+	0x10808,
+	0x1083c,
+	0x10a00,
+	0x16f50,
+	0x1d4a2,
+	0x1d4bb,
+	0x1d546,
+	0x1ee24,
+	0x1ee27,
+	0x1ee39,
+	0x1ee3b,
+	0x1ee42,
+	0x1ee47,
+	0x1ee49,
+	0x1ee4b,
+	0x1ee54,
+	0x1ee57,
+	0x1ee59,
+	0x1ee5b,
+	0x1ee5d,
+	0x1ee5f,
+	0x1ee64,
+	0x1ee7e,
+};
+
+int
+isalpharune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __isalphar, nelem(__isalphar)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = _runebsearch(c, __isalphas, nelem(__isalphas), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __isupperr[] = {
+	0x0041, 0x005a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00de,
+	0x0178, 0x0179,
+	0x0181, 0x0182,
+	0x0186, 0x0187,
+	0x0189, 0x018b,
+	0x018e, 0x0191,
+	0x0193, 0x0194,
+	0x0196, 0x0198,
+	0x019c, 0x019d,
+	0x019f, 0x01a0,
+	0x01a6, 0x01a7,
+	0x01ae, 0x01af,
+	0x01b1, 0x01b3,
+	0x01b7, 0x01b8,
+	0x01f6, 0x01f8,
+	0x023a, 0x023b,
+	0x023d, 0x023e,
+	0x0243, 0x0246,
+	0x0388, 0x038a,
+	0x038e, 0x038f,
+	0x0391, 0x03a1,
+	0x03a3, 0x03ab,
+	0x03d2, 0x03d4,
+	0x03f9, 0x03fa,
+	0x03fd, 0x042f,
+	0x04c0, 0x04c1,
+	0x0531, 0x0556,
+	0x10a0, 0x10c5,
+	0x1f08, 0x1f0f,
+	0x1f18, 0x1f1d,
+	0x1f28, 0x1f2f,
+	0x1f38, 0x1f3f,
+	0x1f48, 0x1f4d,
+	0x1f68, 0x1f6f,
+	0x1f88, 0x1f8f,
+	0x1f98, 0x1f9f,
+	0x1fa8, 0x1faf,
+	0x1fb8, 0x1fbc,
+	0x1fc8, 0x1fcc,
+	0x1fd8, 0x1fdb,
+	0x1fe8, 0x1fec,
+	0x1ff8, 0x1ffc,
+	0x210b, 0x210d,
+	0x2110, 0x2112,
+	0x2119, 0x211d,
+	0x212a, 0x212d,
+	0x2130, 0x2133,
+	0x213e, 0x213f,
+	0x2160, 0x216f,
+	0x24b6, 0x24cf,
+	0x2c00, 0x2c2e,
+	0x2c62, 0x2c64,
+	0x2c6d, 0x2c70,
+	0x2c7e, 0x2c80,
+	0xa77d, 0xa77e,
+	0xff21, 0xff3a,
+	0x10400, 0x10427,
+	0x1d400, 0x1d419,
+	0x1d434, 0x1d44d,
+	0x1d468, 0x1d481,
+	0x1d49e, 0x1d49f,
+	0x1d4a5, 0x1d4a6,
+	0x1d4a9, 0x1d4ac,
+	0x1d4ae, 0x1d4b5,
+	0x1d4d0, 0x1d4e9,
+	0x1d504, 0x1d505,
+	0x1d507, 0x1d50a,
+	0x1d50d, 0x1d514,
+	0x1d516, 0x1d51c,
+	0x1d538, 0x1d539,
+	0x1d53b, 0x1d53e,
+	0x1d540, 0x1d544,
+	0x1d54a, 0x1d550,
+	0x1d56c, 0x1d585,
+	0x1d5a0, 0x1d5b9,
+	0x1d5d4, 0x1d5ed,
+	0x1d608, 0x1d621,
+	0x1d63c, 0x1d655,
+	0x1d670, 0x1d689,
+	0x1d6a8, 0x1d6c0,
+	0x1d6e2, 0x1d6fa,
+	0x1d71c, 0x1d734,
+	0x1d756, 0x1d76e,
+	0x1d790, 0x1d7a8,
+};
+
+static Rune __isupperp[] = {
+	0x0100, 0x0136,
+	0x0139, 0x0147,
+	0x014a, 0x0176,
+	0x017b, 0x017d,
+	0x01a2, 0x01a4,
+	0x01cd, 0x01db,
+	0x01de, 0x01ee,
+	0x01fa, 0x0232,
+	0x0248, 0x024e,
+	0x0370, 0x0372,
+	0x03d8, 0x03ee,
+	0x0460, 0x0480,
+	0x048a, 0x04be,
+	0x04c3, 0x04cd,
+	0x04d0, 0x0526,
+	0x1e00, 0x1e94,
+	0x1e9e, 0x1efe,
+	0x1f59, 0x1f5f,
+	0x2124, 0x2128,
+	0x2c67, 0x2c6b,
+	0x2c82, 0x2ce2,
+	0x2ceb, 0x2ced,
+	0xa640, 0xa66c,
+	0xa680, 0xa696,
+	0xa722, 0xa72e,
+	0xa732, 0xa76e,
+	0xa779, 0xa77b,
+	0xa780, 0xa786,
+	0xa78b, 0xa78d,
+	0xa790, 0xa792,
+	0xa7a0, 0xa7aa,
+};
+
+static Rune __isuppers[] = {
+	0x0184,
+	0x01a9,
+	0x01ac,
+	0x01b5,
+	0x01bc,
+	0x01c4,
+	0x01c7,
+	0x01ca,
+	0x01f1,
+	0x01f4,
+	0x0241,
+	0x0376,
+	0x0386,
+	0x038c,
+	0x03cf,
+	0x03f4,
+	0x03f7,
+	0x10c7,
+	0x10cd,
+	0x2102,
+	0x2107,
+	0x2115,
+	0x2145,
+	0x2183,
+	0x2c60,
+	0x2c72,
+	0x2c75,
+	0x2cf2,
+	0x1d49c,
+	0x1d4a2,
+	0x1d546,
+	0x1d7ca,
+};
+
+int
+isupperrune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __isupperr, nelem(__isupperr)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = _runebsearch(c, __isupperp, nelem(__isupperp)/2, 2);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return 1;
+	p = _runebsearch(c, __isuppers, nelem(__isuppers), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __islowerr[] = {
+	0x0061, 0x007a,
+	0x00df, 0x00f6,
+	0x00f8, 0x00ff,
+	0x0137, 0x0138,
+	0x0148, 0x0149,
+	0x017e, 0x0180,
+	0x018c, 0x018d,
+	0x0199, 0x019b,
+	0x01aa, 0x01ab,
+	0x01b9, 0x01ba,
+	0x01bd, 0x01bf,
+	0x01dc, 0x01dd,
+	0x01ef, 0x01f0,
+	0x0233, 0x0239,
+	0x023f, 0x0240,
+	0x024f, 0x0293,
+	0x0295, 0x02af,
+	0x037b, 0x037d,
+	0x03ac, 0x03ce,
+	0x03d0, 0x03d1,
+	0x03d5, 0x03d7,
+	0x03ef, 0x03f3,
+	0x03fb, 0x03fc,
+	0x0430, 0x045f,
+	0x04ce, 0x04cf,
+	0x0561, 0x0587,
+	0x1d00, 0x1d2b,
+	0x1d6b, 0x1d77,
+	0x1d79, 0x1d9a,
+	0x1e95, 0x1e9d,
+	0x1eff, 0x1f07,
+	0x1f10, 0x1f15,
+	0x1f20, 0x1f27,
+	0x1f30, 0x1f37,
+	0x1f40, 0x1f45,
+	0x1f50, 0x1f57,
+	0x1f60, 0x1f67,
+	0x1f70, 0x1f7d,
+	0x1f80, 0x1f87,
+	0x1f90, 0x1f97,
+	0x1fa0, 0x1fa7,
+	0x1fb0, 0x1fb4,
+	0x1fb6, 0x1fb7,
+	0x1fc2, 0x1fc4,
+	0x1fc6, 0x1fc7,
+	0x1fd0, 0x1fd3,
+	0x1fd6, 0x1fd7,
+	0x1fe0, 0x1fe7,
+	0x1ff2, 0x1ff4,
+	0x1ff6, 0x1ff7,
+	0x210e, 0x210f,
+	0x213c, 0x213d,
+	0x2146, 0x2149,
+	0x2170, 0x217f,
+	0x24d0, 0x24e9,
+	0x2c30, 0x2c5e,
+	0x2c65, 0x2c66,
+	0x2c73, 0x2c74,
+	0x2c76, 0x2c7b,
+	0x2ce3, 0x2ce4,
+	0x2d00, 0x2d25,
+	0xa72f, 0xa731,
+	0xa771, 0xa778,
+	0xfb00, 0xfb06,
+	0xfb13, 0xfb17,
+	0xff41, 0xff5a,
+	0x10428, 0x1044f,
+	0x1d41a, 0x1d433,
+	0x1d44e, 0x1d454,
+	0x1d456, 0x1d467,
+	0x1d482, 0x1d49b,
+	0x1d4b6, 0x1d4b9,
+	0x1d4bd, 0x1d4c3,
+	0x1d4c5, 0x1d4cf,
+	0x1d4ea, 0x1d503,
+	0x1d51e, 0x1d537,
+	0x1d552, 0x1d56b,
+	0x1d586, 0x1d59f,
+	0x1d5ba, 0x1d5d3,
+	0x1d5ee, 0x1d607,
+	0x1d622, 0x1d63b,
+	0x1d656, 0x1d66f,
+	0x1d68a, 0x1d6a5,
+	0x1d6c2, 0x1d6da,
+	0x1d6dc, 0x1d6e1,
+	0x1d6fc, 0x1d714,
+	0x1d716, 0x1d71b,
+	0x1d736, 0x1d74e,
+	0x1d750, 0x1d755,
+	0x1d770, 0x1d788,
+	0x1d78a, 0x1d78f,
+	0x1d7aa, 0x1d7c2,
+	0x1d7c4, 0x1d7c9,
+};
+
+static Rune __islowerp[] = {
+	0x0101, 0x0135,
+	0x013a, 0x0146,
+	0x014b, 0x0177,
+	0x017a, 0x017c,
+	0x0183, 0x0185,
+	0x01a1, 0x01a5,
+	0x01b4, 0x01b6,
+	0x01cc, 0x01da,
+	0x01df, 0x01ed,
+	0x01f3, 0x01f5,
+	0x01f9, 0x0231,
+	0x0247, 0x024d,
+	0x0371, 0x0373,
+	0x03d9, 0x03ed,
+	0x0461, 0x0481,
+	0x048b, 0x04bf,
+	0x04c2, 0x04cc,
+	0x04d1, 0x0527,
+	0x1e01, 0x1e93,
+	0x1e9f, 0x1efd,
+	0x2c68, 0x2c6c,
+	0x2c81, 0x2ce1,
+	0x2cec, 0x2cee,
+	0xa641, 0xa66d,
+	0xa681, 0xa697,
+	0xa723, 0xa72d,
+	0xa733, 0xa76f,
+	0xa77a, 0xa77c,
+	0xa77f, 0xa787,
+	0xa78c, 0xa78e,
+	0xa791, 0xa793,
+	0xa7a1, 0xa7a9,
+};
+
+static Rune __islowers[] = {
+	0x00b5,
+	0x0188,
+	0x0192,
+	0x0195,
+	0x019e,
+	0x01a8,
+	0x01ad,
+	0x01b0,
+	0x01c6,
+	0x01c9,
+	0x023c,
+	0x0242,
+	0x0377,
+	0x0390,
+	0x03f5,
+	0x03f8,
+	0x1fbe,
+	0x210a,
+	0x2113,
+	0x212f,
+	0x2134,
+	0x2139,
+	0x214e,
+	0x2184,
+	0x2c61,
+	0x2c71,
+	0x2cf3,
+	0x2d27,
+	0x2d2d,
+	0xa7fa,
+	0x1d4bb,
+	0x1d7cb,
+};
+
+int
+islowerrune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __islowerr, nelem(__islowerr)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = _runebsearch(c, __islowerp, nelem(__islowerp)/2, 2);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return 1;
+	p = _runebsearch(c, __islowers, nelem(__islowers), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __istitler[] = {
+	0x0041, 0x005a,
+	0x00c0, 0x00d6,
+	0x00d8, 0x00de,
+	0x0178, 0x0179,
+	0x0181, 0x0182,
+	0x0186, 0x0187,
+	0x0189, 0x018b,
+	0x018e, 0x0191,
+	0x0193, 0x0194,
+	0x0196, 0x0198,
+	0x019c, 0x019d,
+	0x019f, 0x01a0,
+	0x01a6, 0x01a7,
+	0x01ae, 0x01af,
+	0x01b1, 0x01b3,
+	0x01b7, 0x01b8,
+	0x01f6, 0x01f8,
+	0x023a, 0x023b,
+	0x023d, 0x023e,
+	0x0243, 0x0246,
+	0x0388, 0x038a,
+	0x038e, 0x038f,
+	0x0391, 0x03a1,
+	0x03a3, 0x03ab,
+	0x03f9, 0x03fa,
+	0x03fd, 0x042f,
+	0x04c0, 0x04c1,
+	0x0531, 0x0556,
+	0x10a0, 0x10c5,
+	0x1f08, 0x1f0f,
+	0x1f18, 0x1f1d,
+	0x1f28, 0x1f2f,
+	0x1f38, 0x1f3f,
+	0x1f48, 0x1f4d,
+	0x1f68, 0x1f6f,
+	0x1f88, 0x1f8f,
+	0x1f98, 0x1f9f,
+	0x1fa8, 0x1faf,
+	0x1fb8, 0x1fbc,
+	0x1fc8, 0x1fcc,
+	0x1fd8, 0x1fdb,
+	0x1fe8, 0x1fec,
+	0x1ff8, 0x1ffc,
+	0x2160, 0x216f,
+	0x24b6, 0x24cf,
+	0x2c00, 0x2c2e,
+	0x2c62, 0x2c64,
+	0x2c6d, 0x2c70,
+	0x2c7e, 0x2c80,
+	0xa77d, 0xa77e,
+	0xff21, 0xff3a,
+	0x10400, 0x10427,
+};
+
+static Rune __istitlep[] = {
+	0x0100, 0x012e,
+	0x0132, 0x0136,
+	0x0139, 0x0147,
+	0x014a, 0x0176,
+	0x017b, 0x017d,
+	0x01a2, 0x01a4,
+	0x01cb, 0x01db,
+	0x01de, 0x01ee,
+	0x01f2, 0x01f4,
+	0x01fa, 0x0232,
+	0x0248, 0x024e,
+	0x0370, 0x0372,
+	0x03d8, 0x03ee,
+	0x0460, 0x0480,
+	0x048a, 0x04be,
+	0x04c3, 0x04cd,
+	0x04d0, 0x0526,
+	0x1e00, 0x1e94,
+	0x1ea0, 0x1efe,
+	0x1f59, 0x1f5f,
+	0x2c67, 0x2c6b,
+	0x2c82, 0x2ce2,
+	0x2ceb, 0x2ced,
+	0xa640, 0xa66c,
+	0xa680, 0xa696,
+	0xa722, 0xa72e,
+	0xa732, 0xa76e,
+	0xa779, 0xa77b,
+	0xa780, 0xa786,
+	0xa78b, 0xa78d,
+	0xa790, 0xa792,
+	0xa7a0, 0xa7aa,
+};
+
+static Rune __istitles[] = {
+	0x0184,
+	0x01a9,
+	0x01ac,
+	0x01b5,
+	0x01bc,
+	0x01c5,
+	0x01c8,
+	0x0241,
+	0x0376,
+	0x0386,
+	0x038c,
+	0x03cf,
+	0x03f7,
+	0x10c7,
+	0x10cd,
+	0x2132,
+	0x2183,
+	0x2c60,
+	0x2c72,
+	0x2c75,
+	0x2cf2,
+};
+
+int
+istitlerune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __istitler, nelem(__istitler)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = _runebsearch(c, __istitlep, nelem(__istitlep)/2, 2);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return 1;
+	p = _runebsearch(c, __istitles, nelem(__istitles), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+static Rune __toupperr[] = {
+	0x0061, 0x007a, 1048544,
+	0x00e0, 0x00f6, 1048544,
+	0x00f8, 0x00fe, 1048544,
+	0x023f, 0x0240, 1059391,
+	0x0256, 0x0257, 1048371,
+	0x028a, 0x028b, 1048359,
+	0x037b, 0x037d, 1048706,
+	0x03ad, 0x03af, 1048539,
+	0x03b1, 0x03c1, 1048544,
+	0x03c3, 0x03cb, 1048544,
+	0x03cd, 0x03ce, 1048513,
+	0x0430, 0x044f, 1048544,
+	0x0450, 0x045f, 1048496,
+	0x0561, 0x0586, 1048528,
+	0x1f00, 0x1f07, 1048584,
+	0x1f10, 0x1f15, 1048584,
+	0x1f20, 0x1f27, 1048584,
+	0x1f30, 0x1f37, 1048584,
+	0x1f40, 0x1f45, 1048584,
+	0x1f60, 0x1f67, 1048584,
+	0x1f70, 0x1f71, 1048650,
+	0x1f72, 0x1f75, 1048662,
+	0x1f76, 0x1f77, 1048676,
+	0x1f78, 0x1f79, 1048704,
+	0x1f7a, 0x1f7b, 1048688,
+	0x1f7c, 0x1f7d, 1048702,
+	0x1f80, 0x1f87, 1048584,
+	0x1f90, 0x1f97, 1048584,
+	0x1fa0, 0x1fa7, 1048584,
+	0x1fb0, 0x1fb1, 1048584,
+	0x1fd0, 0x1fd1, 1048584,
+	0x1fe0, 0x1fe1, 1048584,
+	0x2170, 0x217f, 1048560,
+	0x24d0, 0x24e9, 1048550,
+	0x2c30, 0x2c5e, 1048528,
+	0x2d00, 0x2d25, 1041312,
+	0xff41, 0xff5a, 1048544,
+	0x10428, 0x1044f, 1048536,
+};
+
+static Rune __toupperp[] = {
+	0x0101, 0x012f, 1048575,
+	0x0133, 0x0137, 1048575,
+	0x013a, 0x0148, 1048575,
+	0x014b, 0x0177, 1048575,
+	0x017a, 0x017e, 1048575,
+	0x0183, 0x0185, 1048575,
+	0x01a1, 0x01a5, 1048575,
+	0x01b4, 0x01b6, 1048575,
+	0x01ce, 0x01dc, 1048575,
+	0x01df, 0x01ef, 1048575,
+	0x01f9, 0x021f, 1048575,
+	0x0223, 0x0233, 1048575,
+	0x0247, 0x024f, 1048575,
+	0x0371, 0x0373, 1048575,
+	0x03d9, 0x03ef, 1048575,
+	0x0461, 0x0481, 1048575,
+	0x048b, 0x04bf, 1048575,
+	0x04c2, 0x04ce, 1048575,
+	0x04d1, 0x0527, 1048575,
+	0x1e01, 0x1e95, 1048575,
+	0x1ea1, 0x1eff, 1048575,
+	0x1f51, 0x1f57, 1048584,
+	0x2c68, 0x2c6c, 1048575,
+	0x2c81, 0x2ce3, 1048575,
+	0x2cec, 0x2cee, 1048575,
+	0xa641, 0xa66d, 1048575,
+	0xa681, 0xa697, 1048575,
+	0xa723, 0xa72f, 1048575,
+	0xa733, 0xa76f, 1048575,
+	0xa77a, 0xa77c, 1048575,
+	0xa77f, 0xa787, 1048575,
+	0xa791, 0xa793, 1048575,
+	0xa7a1, 0xa7a9, 1048575,
+};
+
+static Rune __touppers[] = {
+	0x00b5, 1049319,
+	0x00ff, 1048697,
+	0x0131, 1048344,
+	0x017f, 1048276,
+	0x0180, 1048771,
+	0x0188, 1048575,
+	0x018c, 1048575,
+	0x0192, 1048575,
+	0x0195, 1048673,
+	0x0199, 1048575,
+	0x019a, 1048739,
+	0x019e, 1048706,
+	0x01a8, 1048575,
+	0x01ad, 1048575,
+	0x01b0, 1048575,
+	0x01b9, 1048575,
+	0x01bd, 1048575,
+	0x01bf, 1048632,
+	0x01c5, 1048575,
+	0x01c6, 1048574,
+	0x01c8, 1048575,
+	0x01c9, 1048574,
+	0x01cb, 1048575,
+	0x01cc, 1048574,
+	0x01dd, 1048497,
+	0x01f2, 1048575,
+	0x01f3, 1048574,
+	0x01f5, 1048575,
+	0x023c, 1048575,
+	0x0242, 1048575,
+	0x0250, 1059359,
+	0x0251, 1059356,
+	0x0252, 1059358,
+	0x0253, 1048366,
+	0x0254, 1048370,
+	0x0259, 1048374,
+	0x025b, 1048373,
+	0x0260, 1048371,
+	0x0263, 1048369,
+	0x0265, 1090856,
+	0x0266, 1090884,
+	0x0268, 1048367,
+	0x0269, 1048365,
+	0x026b, 1059319,
+	0x026f, 1048365,
+	0x0271, 1059325,
+	0x0272, 1048363,
+	0x0275, 1048362,
+	0x027d, 1059303,
+	0x0280, 1048358,
+	0x0283, 1048358,
+	0x0288, 1048358,
+	0x0289, 1048507,
+	0x028c, 1048505,
+	0x0292, 1048357,
+	0x0345, 1048660,
+	0x0377, 1048575,
+	0x03ac, 1048538,
+	0x03c2, 1048545,
+	0x03cc, 1048512,
+	0x03d0, 1048514,
+	0x03d1, 1048519,
+	0x03d5, 1048529,
+	0x03d6, 1048522,
+	0x03d7, 1048568,
+	0x03f0, 1048490,
+	0x03f1, 1048496,
+	0x03f2, 1048583,
+	0x03f5, 1048480,
+	0x03f8, 1048575,
+	0x03fb, 1048575,
+	0x04cf, 1048561,
+	0x1d79, 1083908,
+	0x1d7d, 1052390,
+	0x1e9b, 1048517,
+	0x1fb3, 1048585,
+	0x1fbe, 1041371,
+	0x1fc3, 1048585,
+	0x1fe5, 1048583,
+	0x1ff3, 1048585,
+	0x214e, 1048548,
+	0x2184, 1048575,
+	0x2c61, 1048575,
+	0x2c65, 1037781,
+	0x2c66, 1037784,
+	0x2c73, 1048575,
+	0x2c76, 1048575,
+	0x2cf3, 1048575,
+	0x2d27, 1041312,
+	0x2d2d, 1041312,
+	0xa78c, 1048575,
+};
+
+Rune
+toupperrune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __toupperr, nelem(__toupperr)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+	p = _runebsearch(c, __toupperp, nelem(__toupperp)/3, 3);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return c + p[2] - 1048576;
+	p = _runebsearch(c, __touppers, nelem(__touppers)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 1048576;
+	return c;
+}
+
+static Rune __tolowerr[] = {
+	0x0041, 0x005a, 1048608,
+	0x00c0, 0x00d6, 1048608,
+	0x00d8, 0x00de, 1048608,
+	0x0189, 0x018a, 1048781,
+	0x01b1, 0x01b2, 1048793,
+	0x0388, 0x038a, 1048613,
+	0x038e, 0x038f, 1048639,
+	0x0391, 0x03a1, 1048608,
+	0x03a3, 0x03ab, 1048608,
+	0x03fd, 0x03ff, 1048446,
+	0x0400, 0x040f, 1048656,
+	0x0410, 0x042f, 1048608,
+	0x0531, 0x0556, 1048624,
+	0x10a0, 0x10c5, 1055840,
+	0x1f08, 0x1f0f, 1048568,
+	0x1f18, 0x1f1d, 1048568,
+	0x1f28, 0x1f2f, 1048568,
+	0x1f38, 0x1f3f, 1048568,
+	0x1f48, 0x1f4d, 1048568,
+	0x1f68, 0x1f6f, 1048568,
+	0x1f88, 0x1f8f, 1048568,
+	0x1f98, 0x1f9f, 1048568,
+	0x1fa8, 0x1faf, 1048568,
+	0x1fb8, 0x1fb9, 1048568,
+	0x1fba, 0x1fbb, 1048502,
+	0x1fc8, 0x1fcb, 1048490,
+	0x1fd8, 0x1fd9, 1048568,
+	0x1fda, 0x1fdb, 1048476,
+	0x1fe8, 0x1fe9, 1048568,
+	0x1fea, 0x1feb, 1048464,
+	0x1ff8, 0x1ff9, 1048448,
+	0x1ffa, 0x1ffb, 1048450,
+	0x2160, 0x216f, 1048592,
+	0x24b6, 0x24cf, 1048602,
+	0x2c00, 0x2c2e, 1048624,
+	0x2c7e, 0x2c7f, 1037761,
+	0xff21, 0xff3a, 1048608,
+	0x10400, 0x10427, 1048616,
+};
+
+static Rune __tolowerp[] = {
+	0x0100, 0x012e, 1048577,
+	0x0132, 0x0136, 1048577,
+	0x0139, 0x0147, 1048577,
+	0x014a, 0x0176, 1048577,
+	0x017b, 0x017d, 1048577,
+	0x01a2, 0x01a4, 1048577,
+	0x01b3, 0x01b5, 1048577,
+	0x01cd, 0x01db, 1048577,
+	0x01de, 0x01ee, 1048577,
+	0x01f8, 0x021e, 1048577,
+	0x0222, 0x0232, 1048577,
+	0x0248, 0x024e, 1048577,
+	0x0370, 0x0372, 1048577,
+	0x03d8, 0x03ee, 1048577,
+	0x0460, 0x0480, 1048577,
+	0x048a, 0x04be, 1048577,
+	0x04c3, 0x04cd, 1048577,
+	0x04d0, 0x0526, 1048577,
+	0x1e00, 0x1e94, 1048577,
+	0x1ea0, 0x1efe, 1048577,
+	0x1f59, 0x1f5f, 1048568,
+	0x2c67, 0x2c6b, 1048577,
+	0x2c80, 0x2ce2, 1048577,
+	0x2ceb, 0x2ced, 1048577,
+	0xa640, 0xa66c, 1048577,
+	0xa680, 0xa696, 1048577,
+	0xa722, 0xa72e, 1048577,
+	0xa732, 0xa76e, 1048577,
+	0xa779, 0xa77b, 1048577,
+	0xa780, 0xa786, 1048577,
+	0xa790, 0xa792, 1048577,
+	0xa7a0, 0xa7a8, 1048577,
+};
+
+static Rune __tolowers[] = {
+	0x0130, 1048377,
+	0x0178, 1048455,
+	0x0179, 1048577,
+	0x0181, 1048786,
+	0x0182, 1048577,
+	0x0184, 1048577,
+	0x0186, 1048782,
+	0x0187, 1048577,
+	0x018b, 1048577,
+	0x018e, 1048655,
+	0x018f, 1048778,
+	0x0190, 1048779,
+	0x0191, 1048577,
+	0x0193, 1048781,
+	0x0194, 1048783,
+	0x0196, 1048787,
+	0x0197, 1048785,
+	0x0198, 1048577,
+	0x019c, 1048787,
+	0x019d, 1048789,
+	0x019f, 1048790,
+	0x01a0, 1048577,
+	0x01a6, 1048794,
+	0x01a7, 1048577,
+	0x01a9, 1048794,
+	0x01ac, 1048577,
+	0x01ae, 1048794,
+	0x01af, 1048577,
+	0x01b7, 1048795,
+	0x01b8, 1048577,
+	0x01bc, 1048577,
+	0x01c4, 1048578,
+	0x01c5, 1048577,
+	0x01c7, 1048578,
+	0x01c8, 1048577,
+	0x01ca, 1048578,
+	0x01cb, 1048577,
+	0x01f1, 1048578,
+	0x01f2, 1048577,
+	0x01f4, 1048577,
+	0x01f6, 1048479,
+	0x01f7, 1048520,
+	0x0220, 1048446,
+	0x023a, 1059371,
+	0x023b, 1048577,
+	0x023d, 1048413,
+	0x023e, 1059368,
+	0x0241, 1048577,
+	0x0243, 1048381,
+	0x0244, 1048645,
+	0x0245, 1048647,
+	0x0246, 1048577,
+	0x0376, 1048577,
+	0x0386, 1048614,
+	0x038c, 1048640,
+	0x03cf, 1048584,
+	0x03f4, 1048516,
+	0x03f7, 1048577,
+	0x03f9, 1048569,
+	0x03fa, 1048577,
+	0x04c0, 1048591,
+	0x04c1, 1048577,
+	0x10c7, 1055840,
+	0x10cd, 1055840,
+	0x1e9e, 1040961,
+	0x1fbc, 1048567,
+	0x1fcc, 1048567,
+	0x1fec, 1048569,
+	0x1ffc, 1048567,
+	0x2126, 1041059,
+	0x212a, 1040193,
+	0x212b, 1040314,
+	0x2132, 1048604,
+	0x2183, 1048577,
+	0x2c60, 1048577,
+	0x2c62, 1037833,
+	0x2c63, 1044762,
+	0x2c64, 1037849,
+	0x2c6d, 1037796,
+	0x2c6e, 1037827,
+	0x2c6f, 1037793,
+	0x2c70, 1037794,
+	0x2c72, 1048577,
+	0x2c75, 1048577,
+	0x2cf2, 1048577,
+	0xa77d, 1013244,
+	0xa77e, 1048577,
+	0xa78b, 1048577,
+	0xa78d, 1006296,
+	0xa7aa, 1006268,
+};
+
+Rune
+tolowerrune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+	p = _runebsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return c + p[2] - 1048576;
+	p = _runebsearch(c, __tolowers, nelem(__tolowers)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 1048576;
+	return c;
+}
+
+static Rune __totitler[] = {
+	0x0061, 0x007a, 1048544,
+	0x00e0, 0x00f6, 1048544,
+	0x00f8, 0x00fe, 1048544,
+	0x023f, 0x0240, 1059391,
+	0x0256, 0x0257, 1048371,
+	0x028a, 0x028b, 1048359,
+	0x037b, 0x037d, 1048706,
+	0x03ad, 0x03af, 1048539,
+	0x03b1, 0x03c1, 1048544,
+	0x03c3, 0x03cb, 1048544,
+	0x03cd, 0x03ce, 1048513,
+	0x0430, 0x044f, 1048544,
+	0x0450, 0x045f, 1048496,
+	0x0561, 0x0586, 1048528,
+	0x1f00, 0x1f07, 1048584,
+	0x1f10, 0x1f15, 1048584,
+	0x1f20, 0x1f27, 1048584,
+	0x1f30, 0x1f37, 1048584,
+	0x1f40, 0x1f45, 1048584,
+	0x1f60, 0x1f67, 1048584,
+	0x1f70, 0x1f71, 1048650,
+	0x1f72, 0x1f75, 1048662,
+	0x1f76, 0x1f77, 1048676,
+	0x1f78, 0x1f79, 1048704,
+	0x1f7a, 0x1f7b, 1048688,
+	0x1f7c, 0x1f7d, 1048702,
+	0x1f80, 0x1f87, 1048584,
+	0x1f90, 0x1f97, 1048584,
+	0x1fa0, 0x1fa7, 1048584,
+	0x1fb0, 0x1fb1, 1048584,
+	0x1fd0, 0x1fd1, 1048584,
+	0x1fe0, 0x1fe1, 1048584,
+	0x2170, 0x217f, 1048560,
+	0x24d0, 0x24e9, 1048550,
+	0x2c30, 0x2c5e, 1048528,
+	0x2d00, 0x2d25, 1041312,
+	0xff41, 0xff5a, 1048544,
+	0x10428, 0x1044f, 1048536,
+};
+
+static Rune __totitlep[] = {
+	0x0101, 0x012f, 1048575,
+	0x0133, 0x0137, 1048575,
+	0x013a, 0x0148, 1048575,
+	0x014b, 0x0177, 1048575,
+	0x017a, 0x017e, 1048575,
+	0x0183, 0x0185, 1048575,
+	0x01a1, 0x01a5, 1048575,
+	0x01b4, 0x01b6, 1048575,
+	0x01cc, 0x01dc, 1048575,
+	0x01df, 0x01ef, 1048575,
+	0x01f3, 0x01f5, 1048575,
+	0x01f9, 0x021f, 1048575,
+	0x0223, 0x0233, 1048575,
+	0x0247, 0x024f, 1048575,
+	0x0371, 0x0373, 1048575,
+	0x03d9, 0x03ef, 1048575,
+	0x0461, 0x0481, 1048575,
+	0x048b, 0x04bf, 1048575,
+	0x04c2, 0x04ce, 1048575,
+	0x04d1, 0x0527, 1048575,
+	0x1e01, 0x1e95, 1048575,
+	0x1ea1, 0x1eff, 1048575,
+	0x1f51, 0x1f57, 1048584,
+	0x2c68, 0x2c6c, 1048575,
+	0x2c81, 0x2ce3, 1048575,
+	0x2cec, 0x2cee, 1048575,
+	0xa641, 0xa66d, 1048575,
+	0xa681, 0xa697, 1048575,
+	0xa723, 0xa72f, 1048575,
+	0xa733, 0xa76f, 1048575,
+	0xa77a, 0xa77c, 1048575,
+	0xa77f, 0xa787, 1048575,
+	0xa791, 0xa793, 1048575,
+	0xa7a1, 0xa7a9, 1048575,
+};
+
+static Rune __totitles[] = {
+	0x00b5, 1049319,
+	0x00ff, 1048697,
+	0x0131, 1048344,
+	0x017f, 1048276,
+	0x0180, 1048771,
+	0x0188, 1048575,
+	0x018c, 1048575,
+	0x0192, 1048575,
+	0x0195, 1048673,
+	0x0199, 1048575,
+	0x019a, 1048739,
+	0x019e, 1048706,
+	0x01a8, 1048575,
+	0x01ad, 1048575,
+	0x01b0, 1048575,
+	0x01b9, 1048575,
+	0x01bd, 1048575,
+	0x01bf, 1048632,
+	0x01c4, 1048577,
+	0x01c6, 1048575,
+	0x01c7, 1048577,
+	0x01c9, 1048575,
+	0x01ca, 1048577,
+	0x01dd, 1048497,
+	0x01f1, 1048577,
+	0x023c, 1048575,
+	0x0242, 1048575,
+	0x0250, 1059359,
+	0x0251, 1059356,
+	0x0252, 1059358,
+	0x0253, 1048366,
+	0x0254, 1048370,
+	0x0259, 1048374,
+	0x025b, 1048373,
+	0x0260, 1048371,
+	0x0263, 1048369,
+	0x0265, 1090856,
+	0x0266, 1090884,
+	0x0268, 1048367,
+	0x0269, 1048365,
+	0x026b, 1059319,
+	0x026f, 1048365,
+	0x0271, 1059325,
+	0x0272, 1048363,
+	0x0275, 1048362,
+	0x027d, 1059303,
+	0x0280, 1048358,
+	0x0283, 1048358,
+	0x0288, 1048358,
+	0x0289, 1048507,
+	0x028c, 1048505,
+	0x0292, 1048357,
+	0x0345, 1048660,
+	0x0377, 1048575,
+	0x03ac, 1048538,
+	0x03c2, 1048545,
+	0x03cc, 1048512,
+	0x03d0, 1048514,
+	0x03d1, 1048519,
+	0x03d5, 1048529,
+	0x03d6, 1048522,
+	0x03d7, 1048568,
+	0x03f0, 1048490,
+	0x03f1, 1048496,
+	0x03f2, 1048583,
+	0x03f5, 1048480,
+	0x03f8, 1048575,
+	0x03fb, 1048575,
+	0x04cf, 1048561,
+	0x1d79, 1083908,
+	0x1d7d, 1052390,
+	0x1e9b, 1048517,
+	0x1fb3, 1048585,
+	0x1fbe, 1041371,
+	0x1fc3, 1048585,
+	0x1fe5, 1048583,
+	0x1ff3, 1048585,
+	0x214e, 1048548,
+	0x2184, 1048575,
+	0x2c61, 1048575,
+	0x2c65, 1037781,
+	0x2c66, 1037784,
+	0x2c73, 1048575,
+	0x2c76, 1048575,
+	0x2cf3, 1048575,
+	0x2d27, 1041312,
+	0x2d2d, 1041312,
+	0xa78c, 1048575,
+};
+
+Rune
+totitlerune(Rune c)
+{
+	Rune *p;
+
+	p = _runebsearch(c, __totitler, nelem(__totitler)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 1048576;
+	p = _runebsearch(c, __totitlep, nelem(__totitlep)/3, 3);
+	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
+		return c + p[2] - 1048576;
+	p = _runebsearch(c, __totitles, nelem(__totitles)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 1048576;
+	return c;
+}
+
--- /dev/null
+++ b/lib9/runevseprint.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include "fmtdef.h"
+
+Rune*
+runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 1;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	va_copy(f.args, args);
+	dofmt(&f, fmt);
+	va_end(f.args);
+	*(Rune*)f.to = '\0';
+	return f.to;
+}
+
--- /dev/null
+++ b/lib9/sbrk-posix.c
@@ -1,0 +1,48 @@
+#ifdef __APPLE_CC__	/* look for a better way */
+#include "lib9.h"
+#undef _POSIX_C_SOURCE 
+#undef getwd
+
+#include	<unistd.h>
+#include        <pthread.h>
+#include	<time.h>
+#include	<termios.h>
+#include	<signal.h>
+#include	<pwd.h>
+#include	<sys/resource.h>
+#include	<sys/time.h>
+
+#include 	<sys/socket.h>
+#include	<sched.h>
+#include	<errno.h>
+#include        <sys/ucontext.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <mach/mach_init.h>
+
+#include <mach/task.h>
+
+#include <mach/vm_map.h>
+
+
+__typeof__(sbrk(0))
+sbrk(int size)
+{
+    void *brk;
+    kern_return_t   err;
+    
+    err = vm_allocate( (vm_map_t) mach_task_self(),
+                       (vm_address_t *)&brk,
+                       size,
+                       VM_FLAGS_ANYWHERE);
+    if (err != KERN_SUCCESS)
+        brk = (void*)-1;
+    
+    return brk;
+}
+#else
+/* dummy function for everyone else, in case its ar complains about empty files */
+void	__fakesbrk(void){}
+#endif
--- /dev/null
+++ b/lib9/seek.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+#include <sys/types.h>
+#include <fcntl.h>
+
+vlong
+seek(int fd, vlong where, int from)
+{
+	return lseek(fd, where, from);
+}
--- /dev/null
+++ b/lib9/seprint.c
@@ -1,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+	char *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = vseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}
--- /dev/null
+++ b/lib9/setbinmode-Nt.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+
+void
+setbinmode(void)
+{
+	_setmode(0, _O_BINARY);
+	_setmode(1, _O_BINARY);
+	_setmode(2, _O_BINARY);
+}
--- /dev/null
+++ b/lib9/setfcr-Linux-386.S
@@ -1,0 +1,34 @@
+
+#define	FN(x)	.type x,@function; .global x; x
+#define	ENT	subl $16, %esp
+#define	RET	addl $16, %esp; ret
+
+	.file	"setfcr-Linux-386.S"
+FN(setfcr):
+	ENT
+	xorb	$0x3f, %al
+	movl	%eax, (%esp)
+	fwait
+	fldcw	(%esp)
+	RET
+
+FN(getfcr):
+	ENT
+	fwait
+	fstcw	(%esp)
+	movw	(%esp), %ax
+	andl	$0xffff, %eax
+	xorb	$0x3f, %al
+	RET
+
+FN(getfsr):
+	ENT
+	fwait
+	fstsw	(%esp)
+	movw	(%esp), %ax
+	andl	$0xffff, %eax
+	RET
+
+FN(setfsr):
+	fclex
+	ret
--- /dev/null
+++ b/lib9/setfcr-Linux-arm.S
@@ -1,0 +1,33 @@
+#define	FN(x)	.type x,%function; .global x; x
+#define	ENT
+#define	RET	bx lr
+#ifdef USEVFP
+	.fpu	vfp
+#define	VMSR(f,r)	vmsr	f,r
+#define	VMRS(r,f)		vmrs	r,f
+#else
+	.fpu	softvfp
+#define	VMSR(f,r)
+#define	VMRS(r,f)
+#endif
+
+	.file	"setfcr-Linux-arm.S"
+FN(setfcr):
+	ENT
+	VMSR(fpscr,r0)
+	RET
+
+FN(getfcr):
+	ENT
+	VMRS(r0, fpscr)
+	RET
+
+FN(getfsr):
+	ENT
+	VMRS(r0, fpscr)
+	RET
+
+FN(setfsr):
+	ENT
+	VMSR(fpscr, r0)
+	RET
--- /dev/null
+++ b/lib9/setfcr-Linux-power.S
@@ -1,0 +1,30 @@
+
+#define	FN(x)	.type x,@function; .global x; x
+
+FN(getfcr):
+	mffs	%f0
+	stfdu	%f0,-16(%r1)
+	lw	%r3,-12(%r1)
+	blr
+
+FN(getfsr):
+	mffs	%f0
+	stfdu	%f0,-16(%r1)
+	lw	%r3,-12(%r1)
+	blr
+
+FN(setfsr):
+	sync
+	stw	%r3,-12(%r1)
+	lfd	%f0,-16(%r1)
+	mtfsf	0xff, %f0
+	isync
+	blr
+
+FN(setfcr):
+	sync
+	stw	%r3,-12(%r1)
+	lfd	%f0,-16(%r1)
+	mtfsf	0xff, %f0
+	isync
+	blr
--- /dev/null
+++ b/lib9/setfcr-MacOSX-386.c
@@ -1,0 +1,56 @@
+/*
+ * Linux 386 fpu support
+ * Mimic Plan9 floating point support
+ */
+
+#include "lib9.h"
+
+void
+setfcr(ulong fcr)
+{
+	__asm__(	"xorb	$0x3f, %%al\n\t"
+			"pushw	%%ax\n\t"
+			"fwait\n\t"
+			"fldcw	(%%esp)\n\t"
+			"popw	%%ax\n\t"
+			: /* no output */
+			: "al" (fcr)
+	);
+}
+
+ulong
+getfcr(void)
+{
+	ulong fcr = 0;
+
+	__asm__(	"pushl	%%eax\n\t"
+			"fwait\n\t"
+			"fstcw	(%%esp)\n\t"
+			"popl	%%eax\n\t"
+			"xorb	$0x3f, %%al\n\t"
+			: "=a"  (fcr)
+			: "eax"	(fcr)
+	);
+	return fcr; 
+}
+
+ulong
+getfsr(void)
+{
+	ulong fsr = -1;
+
+	__asm__(	"fwait\n\t"
+			"fstsw	(%%eax)\n\t"
+			"movl	(%%eax), %%eax\n\t"
+			"andl	$0xffff, %%eax\n\t"
+			: "=a"  (fsr)
+			: "eax" (&fsr)
+	);
+	return fsr;
+}
+
+void
+setfsr(ulong fsr)
+{
+	__asm__("fclex\n\t");
+}
--- /dev/null
+++ b/lib9/setfcr-MacOSX-power.c
@@ -1,0 +1,37 @@
+/*
+ * MacOSX/Darwin ppc fpu support
+ * Mimic Plan9 floating point support
+ */
+
+#include "lib9.h"
+#include <architecture/ppc/fp_regs.h>
+
+ulong
+getfcr(void)
+{
+	ppc_fp_scr_t fpscr = get_fp_scr();
+	return ((ulong*)&fpscr)[1];
+}
+
+ulong
+getfsr(void)
+{
+	ppc_fp_scr_t fpscr = get_fp_scr();
+	return ((ulong*)&fpscr)[1];
+}
+
+void
+setfsr(ulong fsr)
+{
+	ppc_fp_scr_t fpscr = get_fp_scr();
+	(((ulong*)&fpscr)[1]) = fsr;
+	set_fp_scr(fpscr);
+}
+
+void
+setfcr(ulong fcr)
+{
+	ppc_fp_scr_t fpscr = get_fp_scr();
+	(((ulong*)&fpscr)[1]) = fcr;
+	set_fp_scr(fpscr);
+}
--- /dev/null
+++ b/lib9/setfcr-NetBSD-386.S
@@ -1,0 +1,34 @@
+
+#define	FN(x)	.type x,@function; .global x; x
+#define	ENT	subl $16, %esp
+#define	RET	addl $16, %esp; ret
+
+	.file	"setfcr-Linux-386.S"
+FN(setfcr):
+	ENT
+	xorb	$0x3f, %al
+	movl	%eax, (%esp)
+	fwait
+	fldcw	(%esp)
+	RET
+
+FN(getfcr):
+	ENT
+	fwait
+	fstcw	(%esp)
+	movw	(%esp), %ax
+	andl	$0xffff, %eax
+	xorb	$0x3f, %al
+	RET
+
+FN(getfsr):
+	ENT
+	fwait
+	fstsw	(%esp)
+	movw	(%esp), %ax
+	andl	$0xffff, %eax
+	RET
+
+FN(setfsr):
+	fclex
+	ret
--- /dev/null
+++ b/lib9/setfcr-Solaris-sparc.c
@@ -1,0 +1,42 @@
+/* This code is a little awkward.  If somebody who understands Solaris
+   better would tell me an idiomatic way to invoke equivalent
+   behavior, I'd be grateful.    ehg@bell-labs.com  */
+
+#include "lib9.h"
+
+ulong
+getfcr(void)
+{
+	ulong v;
+
+	asm("	st	%fsr, [%fp-8]");
+	return v;
+}
+
+void
+setfcr(ulong v)
+{
+	ulong vv;
+
+	vv = (getfcr() & ~FPFCR) | (v & FPFCR);
+	asm("	ld	[%fp-4], %fsr");
+}
+
+ulong
+getfsr(void)
+{
+	ulong v;
+
+	asm("	st	%fsr, [%fp-8]");
+	return v;
+}
+
+void
+setfsr(ulong v)
+{
+	ulong vv;
+
+	vv = (getfsr() & ~FPFSR) | (v & FPFSR);
+	asm("	ld	[%fp-4], %fsr");
+}
+
--- /dev/null
+++ b/lib9/smprint.c
@@ -1,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+smprint(char *fmt, ...)
+{
+	va_list args;
+	char *p;
+
+	va_start(args, fmt);
+	p = vsmprint(fmt, args);
+	va_end(args);
+	return p;
+}
--- /dev/null
+++ b/lib9/snprint.c
@@ -1,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+
--- /dev/null
+++ b/lib9/sprint.c
@@ -1,0 +1,35 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+int
+sprint(char *buf, char *fmt, ...)
+{
+	int n;
+	uint len;
+	va_list args;
+
+	len = 1<<30;  /* big number, but sprint is deprecated anyway */
+	/*
+	 * the stack might be near the top of memory, so
+	 * we must be sure not to overflow a 32-bit pointer.
+	 */
+	if((uintptr)buf+len < (uintptr)buf)
+		len = -(uint)buf-1;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
--- /dev/null
+++ b/lib9/strdup.c
@@ -1,0 +1,12 @@
+#include "lib9.h"
+
+char*
+strdup(const char *s) 
+{  
+	char *os;
+
+	os = malloc(strlen(s) + 1);
+	if(os == 0)
+		return 0;
+	return strcpy(os, s);
+}
--- /dev/null
+++ b/lib9/strecpy.c
@@ -1,0 +1,16 @@
+#include "lib9.h"
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+	if(to >= e)
+		return to;
+	to = memccpy(to, from, '\0', e - to);
+	if(to == nil){
+		to = e - 1;
+		*to = '\0';
+	}else{
+		to--;
+	}
+	return to;
+}
--- /dev/null
+++ b/lib9/strtoll.c
@@ -1,0 +1,81 @@
+#include "lib9.h"
+
+vlong
+strtoll(const char *nptr, char **endptr, int base)
+{
+	const char *p;
+	vlong n;
+	int c, v, neg, ndig;
+
+	p = nptr;
+	neg = 0;
+	n = 0;
+	ndig = 0;
+
+	/*
+	 * White space
+	 */
+	for(;;p++){
+		switch(*p){
+		case ' ':
+		case '\t':
+		case '\n':
+		case '\f':
+		case '\r':
+		case '\v':
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * Sign
+	 */
+	if(*p=='-' || *p=='+')
+		if(*p++ == '-')
+			neg = 1;
+
+	/*
+	 * Base
+	 */
+	if(base==0){
+		if(*p != '0')
+			base = 10;
+		else{
+			base = 8;
+			if(p[1]=='x' || p[1]=='X'){
+				p += 2;
+				base = 16;
+			}
+		}
+	}else if(base==16 && *p=='0'){
+		if(p[1]=='x' || p[1]=='X')
+			p += 2;
+	}else if(base<0 || 36<base)
+		goto Return;
+
+	/*
+	 * Non-empty sequence of digits
+	 */
+	for(;; p++,ndig++){
+		c = *p;
+		v = base;
+		if('0'<=c && c<='9')
+			v = c - '0';
+		else if('a'<=c && c<='z')
+			v = c - 'a' + 10;
+		else if('A'<=c && c<='Z')
+			v = c - 'A' + 10;
+		if(v >= base)
+			break;
+		n = n*base + v;
+	}
+    Return:
+	if(ndig == 0)
+		p = nptr;
+	if(endptr)
+		*endptr = (char*) p;
+	if(neg)
+		return -n;
+	return n;
+}
--- /dev/null
+++ b/lib9/strtoull.c
@@ -1,0 +1,96 @@
+#include "lib9.h"
+
+#define UVLONG_MAX	((uvlong)1<<63)
+
+uvlong
+strtoull(const char *nptr, char **endptr, int base)
+{
+	const char *p;
+	uvlong n, nn, m;
+	int c, ovfl, v, neg, ndig;
+
+	p = nptr;
+	neg = 0;
+	n = 0;
+	ndig = 0;
+	ovfl = 0;
+
+	/*
+	 * White space
+	 */
+	for(;; p++) {
+		switch(*p) {
+		case ' ':
+		case '\t':
+		case '\n':
+		case '\f':
+		case '\r':
+		case '\v':
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * Sign
+	 */
+	if(*p == '-' || *p == '+')
+		if(*p++ == '-')
+			neg = 1;
+
+	/*
+	 * Base
+	 */
+	if(base == 0) {
+		base = 10;
+		if(*p == '0') {
+			base = 8;
+			if(p[1] == 'x' || p[1] == 'X'){
+				p += 2;
+				base = 16;
+			}
+		}
+	} else
+	if(base == 16 && *p == '0') {
+		if(p[1] == 'x' || p[1] == 'X')
+			p += 2;
+	} else
+	if(base < 0 || 36 < base)
+		goto Return;
+
+	/*
+	 * Non-empty sequence of digits
+	 */
+	m = UVLONG_MAX/base;
+	for(;; p++,ndig++) {
+		c = *p;
+		v = base;
+		if('0' <= c && c <= '9')
+			v = c - '0';
+		else
+		if('a' <= c && c <= 'z')
+			v = c - 'a' + 10;
+		else
+		if('A' <= c && c <= 'Z')
+			v = c - 'A' + 10;
+		if(v >= base)
+			break;
+		if(n > m)
+			ovfl = 1;
+		nn = n*base + v;
+		if(nn < n)
+			ovfl = 1;
+		n = nn;
+	}
+
+Return:
+	if(ndig == 0)
+		p = nptr;
+	if(endptr)
+		*endptr = (char*)p;
+	if(ovfl)
+		return UVLONG_MAX;
+	if(neg)
+		return -n;
+	return n;
+}
--- /dev/null
+++ b/lib9/sysfatal.c
@@ -1,0 +1,28 @@
+#include "lib9.h"
+
+
+
+static void
+_sysfatalimpl(char *fmt, va_list arg)
+{
+	char buf[1024];
+
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	if(argv0)
+		fprint(2, "%s: %s\n", argv0, buf);
+	else
+		fprint(2, "%s\n", buf);
+	exits(buf);
+}
+
+void (*_sysfatal)(char *fmt, va_list arg) = _sysfatalimpl;
+
+void
+sysfatal(char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	(*_sysfatal)(fmt, arg);
+	va_end(arg);
+}
--- /dev/null
+++ b/lib9/tokenize.c
@@ -1,0 +1,106 @@
+#include "lib9.h"
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+	int quoting;
+	char *t;
+
+	quoting = 0;
+	t = s;	/* s is output string, t is input string */
+	while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+		if(*t != '\''){
+			*s++ = *t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t++;
+		*s++ = *t++;
+	}
+	if(*s != '\0'){
+		*s = '\0';
+		if(t == s)
+			t++;
+	}
+	return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+	int quoting;
+
+	/* move to end of next token */
+	quoting = 0;
+	while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+		if(*t != '\''){
+			t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t += 2;
+	}
+	return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(sep, *s)!=nil)
+			*s++ = '\0';
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = etoken(s, sep);
+	}
+
+	return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(qsep, *s)!=nil)
+			s++;
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = qtoken(s, qsep);
+	}
+
+	return nargs;
+}
--- /dev/null
+++ b/lib9/u16.c
@@ -1,0 +1,52 @@
+#include <lib9.h>
+static char t16e[] = "0123456789ABCDEF";
+
+int
+dec16(uchar *out, int lim, char *in, int n)
+{
+	int c, w = 0, i = 0;
+	uchar *start = out;
+	uchar *eout = out + lim;
+
+	while(n-- > 0){
+		c = *in++;
+		if('0' <= c && c <= '9')
+			c = c - '0';
+		else if('a' <= c && c <= 'z')
+			c = c - 'a' + 10;
+		else if('A' <= c && c <= 'Z')
+			c = c - 'A' + 10;
+		else
+			continue;
+		w = (w<<4) + c;
+		i++;
+		if(i == 2){
+			if(out + 1 > eout)
+				goto exhausted;
+			*out++ = w;
+			w = 0;
+			i = 0;
+		}
+	}
+exhausted:
+	return out - start;
+}
+
+int
+enc16(char *out, int lim, uchar *in, int n)
+{
+	uint c;
+	char *eout = out + lim;
+	char *start = out;
+
+	while(n-- > 0){
+		c = *in++;
+		if(out + 2 >= eout)
+			goto exhausted;
+		*out++ = t16e[c>>4];
+		*out++ = t16e[c&0xf];
+	}
+exhausted:
+	*out = 0;
+	return out - start;
+}
--- /dev/null
+++ b/lib9/u32.c
@@ -1,0 +1,109 @@
+#include <lib9.h>
+
+int
+dec32(uchar *dest, int ndest, char *src, int nsrc)
+{
+	char *s, *tab;
+	uchar *start;
+	int i, u[8];
+
+	if(ndest+1 < (5*nsrc+7)/8)
+		return -1;
+	start = dest;
+	tab = "23456789abcdefghijkmnpqrstuvwxyz";
+	while(nsrc>=8){
+		for(i=0; i<8; i++){
+			s = strchr(tab,(int)src[i]);
+			u[i] = s ? s-tab : 0;
+		}
+		*dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+		*dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+		*dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+		*dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+		*dest++ = ((0x7 & u[6])<<5) | u[7];
+		src  += 8;
+		nsrc -= 8;
+	}
+	if(nsrc > 0){
+		if(nsrc == 1 || nsrc == 3 || nsrc == 6)
+			return -1;
+		for(i=0; i<nsrc; i++){
+			s = strchr(tab,(int)src[i]);
+			u[i] = s ? s-tab : 0;
+		}
+		*dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+		if(nsrc == 2)
+			goto out;
+		*dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+		if(nsrc == 4)
+			goto out;
+		*dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+		if(nsrc == 5)
+			goto out;
+		*dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+	}
+out:
+	return dest-start;
+}
+
+int
+enc32(char *dest, int ndest, uchar *src, int nsrc)
+{
+	char *tab, *start;
+	int j;
+
+	if(ndest <= (8*nsrc+4)/5 )
+		return -1;
+	start = dest;
+	tab = "23456789abcdefghijkmnpqrstuvwxyz";
+	while(nsrc>=5){
+		j = (0x1f & (src[0]>>3));
+		*dest++ = tab[j];
+		j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
+		*dest++ = tab[j];
+		j = (0x1f & (src[1]>>1));
+		*dest++ = tab[j];
+		j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
+		*dest++ = tab[j];
+		j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
+		*dest++ = tab[j];
+		j = (0x1f & (src[3]>>2));
+		*dest++ = tab[j];
+		j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
+		*dest++ = tab[j];
+		j = (0x1f & (src[4]));
+		*dest++ = tab[j];
+		src  += 5;
+		nsrc -= 5;
+	}
+	if(nsrc){
+		j = (0x1f & (src[0]>>3));
+		*dest++ = tab[j];
+		j = (0x1c & (src[0]<<2));
+		if(nsrc == 1)
+			goto out;
+		j |= (0x03 & (src[1]>>6));
+		*dest++ = tab[j];
+		j = (0x1f & (src[1]>>1));
+		if(nsrc == 2)
+			goto out;
+		*dest++ = tab[j];
+		j = (0x10 & (src[1]<<4));
+		if(nsrc == 3)
+			goto out;
+		j |= (0x0f & (src[2]>>4));
+		*dest++ = tab[j];
+		j = (0x1e & (src[2]<<1));
+		if(nsrc == 4)
+			goto out;
+		j |= (0x01 & (src[3]>>7));
+		*dest++ = tab[j];
+		j = (0x1f & (src[3]>>2));
+		*dest++ = tab[j];
+		j = (0x18 & (src[3]<<3));
+out:
+		*dest++ = tab[j];
+	}
+	*dest = 0;
+	return dest-start;
+}
--- /dev/null
+++ b/lib9/u64.c
@@ -1,0 +1,126 @@
+#include <lib9.h>
+
+enum {
+	INVAL=	255
+};
+
+static uchar t64d[256] = {
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,   62,INVAL,INVAL,INVAL,   63,
+      52,   53,   54,   55,   56,   57,   58,   59,   60,   61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,    0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,
+      15,   16,   17,   18,   19,   20,   21,   22,   23,   24,   25,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,   37,   38,   39,   40,
+      41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL
+};
+static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int
+dec64(uchar *out, int lim, char *in, int n)
+{
+	ulong b24;
+	uchar *start = out;
+	uchar *e = out + lim;
+	int i, c;
+
+	b24 = 0;
+	i = 0;
+	while(n-- > 0){
+ 
+		c = t64d[*(uchar*)in++];
+		if(c == INVAL)
+			continue;
+		switch(i){
+		case 0:
+			b24 = c<<18;
+			break;
+		case 1:
+			b24 |= c<<12;
+			break;
+		case 2:
+			b24 |= c<<6;
+			break;
+		case 3:
+			if(out + 3 > e)
+				goto exhausted;
+
+			b24 |= c;
+			*out++ = b24>>16;
+			*out++ = b24>>8;
+			*out++ = b24;
+			i = -1;
+			break;
+		}
+		i++;
+	}
+	switch(i){
+	case 2:
+		if(out + 1 > e)
+			goto exhausted;
+		*out++ = b24>>16;
+		break;
+	case 3:
+		if(out + 2 > e)
+			goto exhausted;
+		*out++ = b24>>16;
+		*out++ = b24>>8;
+		break;
+	}
+exhausted:
+	return out - start;
+}
+
+int
+enc64(char *out, int lim, uchar *in, int n)
+{
+	int i;
+	ulong b24;
+	char *start = out;
+	char *e = out + lim;
+
+	for(i = n/3; i > 0; i--){
+		b24 = (*in++)<<16;
+		b24 |= (*in++)<<8;
+		b24 |= *in++;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = t64e[(b24>>6)&0x3f];
+		*out++ = t64e[(b24)&0x3f];
+	}
+
+	switch(n%3){
+	case 2:
+		b24 = (*in++)<<16;
+		b24 |= (*in)<<8;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = t64e[(b24>>6)&0x3f];
+		*out++ = '=';
+		break;
+	case 1:
+		b24 = (*in)<<16;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = '=';
+		*out++ = '=';
+		break;
+	}
+exhausted:
+	*out = 0;
+	return out - start;
+}
--- /dev/null
+++ b/lib9/utfecpy.c
@@ -1,0 +1,20 @@
+#include "lib9.h"
+
+char*
+utfecpy(char *to, char *e, char *from)
+{
+	char *end;
+
+	if(to >= e)
+		return to;
+	end = memccpy(to, from, '\0', e - to);
+	if(end == nil){
+		end = e;
+		while(end>to && (*--end&0xC0)==0x80)
+			;
+		*end = '\0';
+	}else{
+		end--;
+	}
+	return end;
+}
--- /dev/null
+++ b/lib9/utflen.c
@@ -1,0 +1,21 @@
+#include "lib9.h"
+
+int
+utflen(char *s)
+{
+	int c;
+	long n;
+	Rune rune;
+
+	n = 0;
+	for(;;) {
+		c = *(uchar*)s;
+		if(c < Runeself) {
+			if(c == 0)
+				return n;
+			s++;
+		} else
+			s += chartorune(&rune, s);
+		n++;
+	}
+}
--- /dev/null
+++ b/lib9/utfnlen.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+int
+utfnlen(char *s, long m)
+{
+	int c;
+	long n;
+	Rune rune;
+	char *es;
+
+	es = s + m;
+	for(n = 0; s < es; n++) {
+		c = *(uchar*)s;
+		if(c < Runeself){
+			if(c == '\0')
+				break;
+			s++;
+			continue;
+		}
+		if(!fullrune(s, es-s))
+			break;
+		s += chartorune(&rune, s);
+	}
+	return n;
+}
--- /dev/null
+++ b/lib9/utfrrune.c
@@ -1,0 +1,29 @@
+#include "lib9.h"
+
+char*
+utfrrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	char *s1;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strrchr(s, c);
+
+	s1 = 0;
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return s1;
+			if(c1 == c)
+				s1 = s;
+			s++;
+			continue;
+		}
+		c1 = chartorune(&r, s);
+		if(r == c)
+			s1 = s;
+		s += c1;
+	}
+}
--- /dev/null
+++ b/lib9/utfrune.c
@@ -1,0 +1,28 @@
+#include "lib9.h"
+
+char*
+utfrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	int n;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strchr(s, c);
+
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return 0;
+			if(c1 == c)
+				return s;
+			s++;
+			continue;
+		}
+		n = chartorune(&r, s);
+		if(r == c)
+			return s;
+		s += n;
+	}
+}
--- /dev/null
+++ b/lib9/vfprint.c
@@ -1,0 +1,47 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/*
+ * generic routine for flushing a formatting buffer
+ * to a file descriptor
+ */
+int
+_fmtFdFlush(Fmt *f)
+{
+	int n;
+
+	n = (char*)f->to - (char*)f->start;
+	if(n && write((int)f->farg, f->start, n) != n)
+		return 0;
+	f->to = f->start;
+	return 1;
+}
+
+int
+vfprint(int fd, char *fmt, va_list args)
+{
+	Fmt f;
+	char buf[256];
+	int n;
+
+	fmtfdinit(&f, fd, buf, sizeof(buf));
+	va_copy(f.args, args);
+	n = dofmt(&f, fmt);
+	va_end(f.args);
+	if(n > 0 && _fmtFdFlush(&f) == 0)
+		return -1;
+	return n;
+}
--- /dev/null
+++ b/lib9/vseprint.c
@@ -1,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	va_copy(f.args, args);
+	dofmt(&f, fmt);
+	va_end(f.args);
+	*(char*)f.to = '\0';
+	return f.to;
+}
+
--- /dev/null
+++ b/lib9/vsmprint.c
@@ -1,0 +1,79 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+	char *s;
+	int n;
+
+	if(f->start == nil)
+		return 0;
+	n = (int)f->farg;
+	n += 256;
+	f->farg = (void*)n;
+	s = f->start;
+	f->start = realloc(s, n);
+	if(f->start == nil){
+		free(s);
+		f->to = nil;
+		f->stop = nil;
+		return 0;
+	}
+	f->to = (char*)f->start + ((char*)f->to - s);
+	f->stop = (char*)f->start + n - 1;
+	return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+	int n;
+
+	memset(f, 0, sizeof(*f));
+	n = 32;
+	f->start = malloc(n);
+	if(f->start == nil)
+		return -1;
+	f->to = f->start;
+	f->stop = (char*)f->start + n - 1;
+	f->flush = fmtStrFlush;
+	f->farg = (void*)n;
+	f->nfmt = 0;
+	return 0;
+}
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+	Fmt f;
+	int n;
+
+	if(fmtstrinit(&f) < 0)
+		return nil;
+	va_copy(f.args, args);
+	n = dofmt(&f, fmt);
+	va_end(f.args);
+	if(n < 0){
+		free(f.start);
+		f.start = nil;
+		return nil;
+	}
+	return fmtstrflush(&f);
+}
--- /dev/null
+++ b/lib9/vsnprint.c
@@ -1,0 +1,36 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+int
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(len <= 0)
+		return -1;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = buf + len - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	va_copy(f.args, args);
+	dofmt(&f, fmt);
+	va_end(f.args);
+	*(char*)f.to = '\0';
+	return (char*)f.to - buf;
+}
--- /dev/null
+++ b/libbio/NOTICE
@@ -1,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/libbio/bbuffered.c
@@ -1,0 +1,20 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bbuffered(Biobuf *bp)
+{
+	switch(bp->state) {
+	case Bracteof:
+	case Bractive:
+		return -bp->icount;
+
+	case Bwactive:
+		return bp->bsize + bp->ocount;
+
+	case Binactive:
+		return 0;
+	}
+	fprint(2, "Bbuffered: unknown state %d\n", bp->state);
+	return 0;
+}
--- /dev/null
+++ b/libbio/bfildes.c
@@ -1,0 +1,9 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bfildes(Biobuf *bp)
+{
+
+	return bp->fid;
+}
--- /dev/null
+++ b/libbio/bflush.c
@@ -1,0 +1,33 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bflush(Biobuf *bp)
+{
+	int n, c;
+
+	switch(bp->state) {
+	case Bwactive:
+		n = bp->bsize+bp->ocount;
+		if(n == 0)
+			return 0;
+		c = write(bp->fid, bp->bbuf, n);
+		if(n == c) {
+			bp->offset += n;
+			bp->ocount = -bp->bsize;
+			return 0;
+		}
+		bp->state = Binactive;
+		bp->ocount = 0;
+		break;
+
+	case Bracteof:
+		bp->state = Bractive;
+
+	case Bractive:
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+		return 0;
+	}
+	return Beof;
+}
--- /dev/null
+++ b/libbio/bgetc.c
@@ -1,0 +1,53 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bgetc(Biobuf *bp)
+{
+	int i;
+
+loop:
+	i = bp->icount;
+	if(i != 0) {
+		bp->icount = i+1;
+		return bp->ebuf[i];
+	}
+	if(bp->state != Bractive) {
+		if(bp->state == Bracteof)
+			bp->state = Bractive;
+		return Beof;
+	}
+	/*
+	 * get next buffer, try to keep Bungetsize
+	 * characters pre-catenated from the previous
+	 * buffer to allow that many ungets.
+	 */
+	memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
+	i = read(bp->fid, bp->bbuf, bp->bsize);
+	bp->gbuf = bp->bbuf;
+	if(i <= 0) {
+		bp->state = Bracteof;
+		if(i < 0)
+			bp->state = Binactive;
+		return Beof;
+	}
+	if(i < bp->bsize) {
+		memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
+		bp->gbuf = bp->ebuf-i;
+	}
+	bp->icount = -i;
+	bp->offset += i;
+	goto loop;
+}
+
+int
+Bungetc(Biobuf *bp)
+{
+
+	if(bp->state == Bracteof)
+		bp->state = Bractive;
+	if(bp->state != Bractive)
+		return Beof;
+	bp->icount--;
+	return 1;
+}
--- /dev/null
+++ b/libbio/bgetd.c
@@ -1,0 +1,36 @@
+#include "lib9.h"
+#include <bio.h>
+
+struct	bgetd
+{
+	Biobuf*	b;
+	int		eof;
+};
+
+static int
+Bgetdf(void *vp)
+{
+	int c;
+	struct bgetd *bg = vp;
+
+	c = Bgetc(bg->b);
+	if(c == Beof)
+		bg->eof = 1;
+	return c;
+}
+
+int
+Bgetd(Biobuf *bp, double *dp)
+{
+	double d;
+	struct bgetd b;
+
+	b.b = bp;
+	b.eof = 0;
+	d = charstod(Bgetdf, &b);
+	if(b.eof)
+		return -1;
+	Bungetc(bp);
+	*dp = d;
+	return 1;
+}
--- /dev/null
+++ b/libbio/bgetrune.c
@@ -1,0 +1,52 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+long
+Bgetrune(Biobuf *bp)
+{
+	int c, i;
+	Rune rune;
+	char str[UTFmax];
+
+	c = Bgetc(bp);
+	if(c < Runeself) {		/* one char */
+		bp->runesize = 1;
+		return c;
+	}
+	str[0] = c;
+	bp->runesize = 0;
+
+	for(i=1;;) {
+		c = Bgetc(bp);
+		if(c < 0)
+			return c;
+		if (i >= sizeof str)
+			return Runeerror;
+		str[i++] = c;
+
+		if(fullrune(str, i)) {
+			/* utf is long enough to be a rune, but could be bad. */
+			bp->runesize = chartorune(&rune, str);
+			if (rune == Runeerror)
+				bp->runesize = 0;	/* push back nothing */
+			else
+				/* push back bytes unconsumed by chartorune */
+				for(; i > bp->runesize; i--)
+					Bungetc(bp);
+			return rune;
+		}
+	}
+}
+
+int
+Bungetrune(Biobuf *bp)
+{
+
+	if(bp->state == Bracteof)
+		bp->state = Bractive;
+	if(bp->state != Bractive)
+		return Beof;
+	bp->icount -= bp->runesize;
+	bp->runesize = 0;
+	return 1;
+}
--- /dev/null
+++ b/libbio/binit.c
@@ -1,0 +1,144 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+enum
+{
+	MAXBUFS	= 20
+};
+
+static	Biobuf*	wbufs[MAXBUFS];
+static	int		atexitflag;
+
+static
+void
+batexit(void)
+{
+	Biobuf *bp;
+	int i;
+
+	for(i=0; i<nelem(wbufs); i++) {
+		bp = wbufs[i];
+		if(bp != 0) {
+			wbufs[i] = 0;
+			Bflush(bp);
+		}
+	}
+}
+
+static
+void
+deinstall(Biobuf *bp)
+{
+	int i;
+
+	for(i=0; i<nelem(wbufs); i++)
+		if(wbufs[i] == bp)
+			wbufs[i] = 0;
+}
+
+static
+void
+install(Biobuf *bp)
+{
+	int i;
+
+	deinstall(bp);
+	for(i=0; i<nelem(wbufs); i++)
+		if(wbufs[i] == 0) {
+			wbufs[i] = bp;
+			break;
+		}
+	if(atexitflag == 0) {
+		atexitflag = 1;
+		atexit(batexit);
+	}
+}
+
+int
+Binits(Biobuf *bp, int f, int mode, uchar *p, int size)
+{
+
+	p += Bungetsize;	/* make room for Bungets */
+	size -= Bungetsize;
+
+	switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
+	default:
+		fprint(2, "Bopen: unknown mode %d\n", mode);
+		return Beof;
+
+	case OREAD:
+		bp->state = Bractive;
+		bp->ocount = 0;
+		break;
+
+	case OWRITE:
+		install(bp);
+		bp->state = Bwactive;
+		bp->ocount = -size;
+		break;
+	}
+	bp->bbuf = p;
+	bp->ebuf = p+size;
+	bp->bsize = size;
+	bp->icount = 0;
+	bp->gbuf = bp->ebuf;
+	bp->fid = f;
+	bp->flag = 0;
+	bp->rdline = 0;
+	bp->offset = 0;
+	bp->runesize = 0;
+	return 0;
+}
+
+
+int
+Binit(Biobuf *bp, int f, int mode)
+{
+	return Binits(bp, f, mode, bp->b, sizeof(bp->b));
+}
+
+Biobuf*
+Bopen(char *name, int mode)
+{
+	Biobuf *bp;
+	int f;
+
+	switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
+	default:
+		fprint(2, "Bopen: unknown mode %d\n", mode);
+		return 0;
+
+	case OREAD:
+		f = open(name, OREAD);
+		break;
+
+	case OWRITE:
+		f = create(name, mode, 0666);
+		break;
+	}
+	if(f < 0)
+		return 0;
+	bp = malloc(sizeof(Biobuf));
+	if(bp == nil)
+		return 0;
+	Binits(bp, f, mode, bp->b, sizeof(bp->b));
+	bp->flag = Bmagic;
+	return bp;
+}
+
+int
+Bterm(Biobuf *bp)
+{
+	int r;
+
+	deinstall(bp);
+	r = Bflush(bp);
+	if(bp->flag == Bmagic) {
+		bp->flag = 0;
+		close(bp->fid);
+		bp->fid = -1;			/* prevent accidents */
+		free(bp);
+	}
+	/* otherwise opened with Binit(s) */
+	return r;
+}
--- /dev/null
+++ b/libbio/boffset.c
@@ -1,0 +1,25 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+vlong
+Boffset(Biobuf *bp)
+{
+	vlong n;
+
+	switch(bp->state) {
+	default:
+		fprint(2, "Boffset: unknown state %d\n", bp->state);
+		n = Beof;
+		break;
+
+	case Bracteof:
+	case Bractive:
+		n = bp->offset + bp->icount;
+		break;
+
+	case Bwactive:
+		n = bp->offset + (bp->bsize + bp->ocount);
+		break;
+	}
+	return n;
+}
--- /dev/null
+++ b/libbio/bprint.c
@@ -1,0 +1,14 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bprint(Biobuf *bp, char *fmt, ...)
+{
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	n = Bvprint(bp, fmt, arg);
+	va_end(arg);
+	return n;
+}
--- /dev/null
+++ b/libbio/bputc.c
@@ -1,0 +1,20 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bputc(Biobuf *bp, int c)
+{
+	int i;
+
+	for(;;) {
+		i = bp->ocount;
+		if(i) {
+			bp->ebuf[i++] = c;
+			bp->ocount = i;
+			return 0;
+		}
+		if(Bflush(bp) == Beof)
+			break;
+	}
+	return Beof;
+}
--- /dev/null
+++ b/libbio/bputrune.c
@@ -1,0 +1,22 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bputrune(Biobuf *bp, long c)
+{
+	Rune rune;
+	char str[UTFmax];
+	int n;
+
+	rune = c;
+	if(rune < Runeself) {
+		Bputc(bp, rune);
+		return 1;
+	}
+	n = runetochar(str, &rune);
+	if(n == 0)
+		return Bbad;
+	if(Bwrite(bp, str, n) != n)
+		return Beof;
+	return n;
+}
--- /dev/null
+++ b/libbio/brdline.c
@@ -1,0 +1,94 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+void*
+Brdline(Biobuf *bp, int delim)
+{
+	char *ip, *ep;
+	int i, j;
+
+	i = -bp->icount;
+	if(i == 0) {
+		/*
+		 * eof or other error
+		 */
+		if(bp->state != Bractive) {
+			if(bp->state == Bracteof)
+				bp->state = Bractive;
+			bp->rdline = 0;
+			bp->gbuf = bp->ebuf;
+			return 0;
+		}
+	}
+
+	/*
+	 * first try in remainder of buffer (gbuf doesn't change)
+	 */
+	ip = (char*)bp->ebuf - i;
+	ep = memchr(ip, delim, i);
+	if(ep) {
+		j = (ep - ip) + 1;
+		bp->rdline = j;
+		bp->icount += j;
+		return ip;
+	}
+
+	/*
+	 * copy data to beginning of buffer
+	 */
+	if(i < bp->bsize)
+		memmove(bp->bbuf, ip, i);
+	bp->gbuf = bp->bbuf;
+
+	/*
+	 * append to buffer looking for the delim
+	 */
+	ip = (char*)bp->bbuf + i;
+	while(i < bp->bsize) {
+		j = read(bp->fid, ip, bp->bsize-i);
+		if(j <= 0) {
+			/*
+			 * end of file with no delim
+			 */
+			memmove(bp->ebuf-i, bp->bbuf, i);
+			bp->rdline = i;
+			bp->icount = -i;
+			bp->gbuf = bp->ebuf-i;
+			return 0;
+		}
+		bp->offset += j;
+		i += j;
+		ep = memchr(ip, delim, j);
+		if(ep) {
+			/*
+			 * found in new piece
+			 * copy back up and reset everything
+			 */
+			ip = (char*)bp->ebuf - i;
+			if(i < bp->bsize){
+				memmove(ip, bp->bbuf, i);
+				bp->gbuf = (uchar*)ip;
+			}
+			j = (ep - (char*)bp->bbuf) + 1;
+			bp->rdline = j;
+			bp->icount = j - i;
+			return ip;
+		}
+		ip += j;
+	}
+
+	/*
+	 * full buffer without finding
+	 */
+	bp->rdline = bp->bsize;
+	bp->icount = -bp->bsize;
+	bp->gbuf = bp->bbuf;
+	return 0;
+}
+
+int
+Blinelen(Biobuf *bp)
+{
+
+	return bp->rdline;
+}
--- /dev/null
+++ b/libbio/brdstr.c
@@ -1,0 +1,111 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+static char*
+badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
+{
+	int n;
+
+	n = *np;
+	p = realloc(p, n+ndata+1);
+	if(p){
+		memmove(p+n, data, ndata);
+		n += ndata;
+		if(n>0 && nulldelim && p[n-1]==delim)
+			p[--n] = '\0';
+		else
+			p[n] = '\0';
+		*np = n;
+	}
+	return p;
+}
+
+char*
+Brdstr(Biobuf *bp, int delim, int nulldelim)
+{
+	char *ip, *ep, *p;
+	int i, j;
+
+	i = -bp->icount;
+	bp->rdline = 0;
+	if(i == 0) {
+		/*
+		 * eof or other error
+		 */
+		if(bp->state != Bractive) {
+			if(bp->state == Bracteof)
+				bp->state = Bractive;
+			bp->gbuf = bp->ebuf;
+			return nil;
+		}
+	}
+
+	/*
+	 * first try in remainder of buffer (gbuf doesn't change)
+	 */
+	ip = (char*)bp->ebuf - i;
+	ep = memchr(ip, delim, i);
+	if(ep) {
+		j = (ep - ip) + 1;
+		bp->icount += j;
+		return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
+	}
+
+	/*
+	 * copy data to beginning of buffer
+	 */
+	if(i < bp->bsize)
+		memmove(bp->bbuf, ip, i);
+	bp->gbuf = bp->bbuf;
+
+	/*
+	 * append to buffer looking for the delim
+	 */
+	p = nil;
+	for(;;){
+		ip = (char*)bp->bbuf + i;
+		while(i < bp->bsize) {
+			j = read(bp->fid, ip, bp->bsize-i);
+			if(j <= 0 && i == 0)
+				return p;
+			if(j <= 0 && i > 0){
+				/*
+				 * end of file but no delim. pretend we got a delim
+				 * by making the delim \0 and smashing it with nulldelim.
+				 */
+				j = 1;
+				ep = ip;
+				delim = '\0';
+				nulldelim = 1;
+				*ep = delim;	/* there will be room for this */
+			}else{
+				bp->offset += j;
+				ep = memchr(ip, delim, j);
+			}
+			i += j;
+			if(ep) {
+				/*
+				 * found in new piece
+				 * copy back up and reset everything
+				 */
+				ip = (char*)bp->ebuf - i;
+				if(i < bp->bsize){
+					memmove(ip, bp->bbuf, i);
+					bp->gbuf = (uchar*)ip;
+				}
+				j = (ep - (char*)bp->bbuf) + 1;
+				bp->icount = j - i;
+				return badd(p, &bp->rdline, ip, j, delim, nulldelim);
+			}
+			ip += j;
+		}
+	
+		/*
+		 * full buffer without finding; add to user string and continue
+		 */
+		p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
+		i = 0;
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+	}
+}
--- /dev/null
+++ b/libbio/bread.c
@@ -1,0 +1,47 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+long
+Bread(Biobuf *bp, void *ap, long count)
+{
+	long c;
+	uchar *p;
+	int i, n, ic;
+
+	p = ap;
+	c = count;
+	ic = bp->icount;
+
+	while(c > 0) {
+		n = -ic;
+		if(n > c)
+			n = c;
+		if(n == 0) {
+			if(bp->state != Bractive)
+				break;
+			i = read(bp->fid, bp->bbuf, bp->bsize);
+			if(i <= 0) {
+				bp->state = Bracteof;
+				if(i < 0)
+					bp->state = Binactive;
+				break;
+			}
+			bp->gbuf = bp->bbuf;
+			bp->offset += i;
+			if(i < bp->bsize) {
+				memmove(bp->ebuf-i, bp->bbuf, i);
+				bp->gbuf = bp->ebuf-i;
+			}
+			ic = -i;
+			continue;
+		}
+		memmove(p, bp->ebuf+ic, n);
+		c -= n;
+		ic += n;
+		p += n;
+	}
+	bp->icount = ic;
+	if(count == c && bp->state == Binactive)
+		return -1;
+	return count-c;
+}
--- /dev/null
+++ b/libbio/bseek.c
@@ -1,0 +1,57 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+vlong
+Bseek(Biobuf *bp, vlong offset, int base)
+{
+	vlong n, d;
+
+	switch(bp->state) {
+	default:
+		fprint(2, "Bseek: unknown state %d\n", bp->state);
+		return Beof;
+
+	case Bracteof:
+		bp->state = Bractive;
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+
+	case Bractive:
+		n = offset;
+		if(base == 1) {
+			n += Boffset(bp);
+			base = 0;
+		}
+
+		/*
+		 * try to seek within buffer
+		 */
+		if(base == 0) {
+			/*
+			 * if d is too large for an int, icount may wrap,
+			 * so we need to ensure that icount hasn't wrapped
+			 * and points within the buffer's valid data.
+			 */
+			d = n - Boffset(bp);
+			bp->icount += d;
+			if(d <= bp->bsize && bp->icount <= 0 &&
+			    bp->ebuf - bp->gbuf >= -bp->icount)
+				return n;
+		}
+
+		/*
+		 * reset the buffer
+		 */
+		n = seek(bp->fid, n, base);
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+		break;
+
+	case Bwactive:
+		Bflush(bp);
+		n = seek(bp->fid, offset, base);
+		break;
+	}
+	bp->offset = n;
+	return n;
+}
--- /dev/null
+++ b/libbio/bvprint.c
@@ -1,0 +1,43 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+static int
+fmtBflush(Fmt *f)
+{
+	Biobuf *bp;
+
+	bp = f->farg;
+	bp->ocount = (char*)f->to - (char*)f->stop;
+	if(Bflush(bp) < 0)
+		return 0;
+	f->stop = bp->ebuf;
+	f->to = (char*)f->stop + bp->ocount;
+	f->start = f->to;
+	return 1;
+}
+
+int
+Bvprint(Biobuf *bp, char *fmt, va_list arg)
+{
+	int n;
+	Fmt f;
+
+	f.runes = 0;
+	f.stop = bp->ebuf;
+	f.start = (char*)f.stop + bp->ocount;
+	f.to = f.start;
+	f.flush = fmtBflush;
+	f.farg = bp;
+	f.nfmt = 0;
+#ifdef va_copy
+	va_copy(f.args, arg);
+#else
+	f.args = arg;
+#endif
+	n = dofmt(&f, fmt);
+#ifdef va_copy
+	va_end(f.args);
+#endif
+	bp->ocount = (char*)f.to - (char*)f.stop;
+	return n;
+}
--- /dev/null
+++ b/libbio/bwrite.c
@@ -1,0 +1,42 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+long
+Bwrite(Biobuf *bp, void *ap, long count)
+{
+	long c;
+	uchar *p;
+	int i, n, oc;
+	char errbuf[ERRMAX];
+
+	p = ap;
+	c = count;
+	oc = bp->ocount;
+
+	while(c > 0) {
+		n = -oc;
+		if(n > c)
+			n = c;
+		if(n == 0) {
+			if(bp->state != Bwactive)
+				return Beof;
+			i = write(bp->fid, bp->bbuf, bp->bsize);
+			if(i != bp->bsize) {
+				errstr(errbuf, sizeof errbuf);
+				if(strstr(errbuf, "interrupt") == nil)
+					bp->state = Binactive;
+				errstr(errbuf, sizeof errbuf);
+				return Beof;
+			}
+			bp->offset += i;
+			oc = -bp->bsize;
+			continue;
+		}
+		memmove(bp->ebuf+oc, p, n);
+		oc += n;
+		c -= n;
+		p += n;
+	}
+	bp->ocount = oc;
+	return count-c;
+}
--- /dev/null
+++ b/libbio/mkfile
@@ -1,0 +1,25 @@
+<../mkconfig
+
+LIB=libbio.a
+OFILES=\
+	bbuffered.$O\
+	bfildes.$O\
+	bflush.$O\
+	bgetrune.$O\
+	bgetc.$O\
+	bgetd.$O\
+	binit.$O\
+	boffset.$O\
+	bprint.$O\
+	bputrune.$O\
+	bputc.$O\
+	brdline.$O\
+	brdstr.$O\
+	bread.$O\
+	bseek.$O\
+	bvprint.$O\
+	bwrite.$O\
+
+HFILES=	$ROOT/include/bio.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libdraw/NOTICE
@@ -1,0 +1,31 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Portions Copyright © 1997-1999 Vita Nuova Limited
+	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/libdraw/alloc.c
@@ -1,0 +1,237 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+Image*
+allocimage(Display *d, Rectangle r, ulong chan, int repl, ulong val)
+{
+	return _allocimage(nil, d, r, chan, repl, val, 0, 0);
+}
+
+Image*
+_allocimage(Image *ai, Display *d, Rectangle r, ulong chan, int repl, ulong val, int screenid, int refresh)
+{
+	uchar *a;
+	char *err;
+	Image *i;
+	Rectangle clipr;
+	int id;
+	int depth;
+
+	err = 0;
+	i = 0;
+
+	if(chan == 0){
+		kwerrstr("bad channel descriptor");
+		return nil;
+	}
+
+	depth = chantodepth(chan);
+	if(depth == 0){
+		err = "bad channel descriptor";
+    Error:
+		if(err)
+			kwerrstr("allocimage: %s", err);
+		else
+			kwerrstr("allocimage: %r");
+		free(i);
+		return 0;
+	}
+
+	/* flush pending data so we don't get error allocating the image */
+	flushimage(d, 0);
+	a = bufimage(d, 1+4+4+1+4+1+4*4+4*4+4);
+	if(a == 0)
+		goto Error;
+	d->imageid++;
+	id = d->imageid;
+	a[0] = 'b';
+	BPLONG(a+1, id);
+	BPLONG(a+5, screenid);
+	a[9] = refresh;
+	BPLONG(a+10, chan);
+	a[14] = repl;
+	BPLONG(a+15, r.min.x);
+	BPLONG(a+19, r.min.y);
+	BPLONG(a+23, r.max.x);
+	BPLONG(a+27, r.max.y);
+	if(repl)
+		/* huge but not infinite, so various offsets will leave it huge, not overflow */
+		clipr = Rect(-0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF);
+	else
+		clipr = r;
+	BPLONG(a+31, clipr.min.x);
+	BPLONG(a+35, clipr.min.y);
+	BPLONG(a+39, clipr.max.x);
+	BPLONG(a+43, clipr.max.y);
+	BPLONG(a+47, val);
+	if(flushimage(d, 0) < 0)
+		goto Error;
+
+	if(ai)
+		i = ai;
+	else{
+		i = malloc(sizeof(Image));
+		if(i == nil){
+			a = bufimage(d, 1+4);
+			if(a){
+				a[0] = 'f';
+				BPLONG(a+1, id);
+				flushimage(d, 0);
+			}
+			goto Error;
+		}
+	}
+	i->display = d;
+	i->id = id;
+	i->depth = depth;
+	i->chan = chan;
+	i->r = r;
+	i->clipr = clipr;
+	i->repl = repl;
+	i->screen = 0;
+	i->next = 0;
+	return i;
+}
+
+Image*
+namedimage(Display *d, char *name)
+{
+	uchar *a;
+	char *err, buf[12*12+1];
+	Image *i;
+	int id, n;
+	ulong chan;
+
+	err = 0;
+	i = 0;
+
+	n = strlen(name);
+	if(n >= 256){
+		err = "name too long";
+    Error:
+		if(err)
+			kwerrstr("namedimage: %s", err);
+		else
+			kwerrstr("namedimage: %r");
+		if(i)
+			free(i);
+		return 0;
+	}
+	/* flush pending data so we don't get error allocating the image */
+	flushimage(d, 0);
+	a = bufimage(d, 1+4+1+n);
+	if(a == 0)
+		goto Error;
+	d->imageid++;
+	id = d->imageid;
+	a[0] = 'n';
+	BPLONG(a+1, id);
+	a[5] = n;
+	memmove(a+6, name, n);
+	if(flushimage(d, 0) < 0)
+		goto Error;
+
+	if(kchanio(d->ctlchan, buf, sizeof buf, OREAD) < 12*12)
+		goto Error;
+	buf[12*12] = '\0';
+
+	i = malloc(sizeof(Image));
+	if(i == nil){
+	Error1:
+		a = bufimage(d, 1+4);
+		if(a){
+			a[0] = 'f';
+			BPLONG(a+1, id);
+			flushimage(d, 0);
+		}
+		goto Error;
+	}
+	i->display = d;
+	i->id = id;
+	if((chan=strtochan(buf+2*12))==0){
+		kwerrstr("bad channel from devdraw");
+		goto Error1;
+	}
+	i->chan = chan;
+	i->depth = chantodepth(chan);
+	i->repl = atoi(buf+3*12);
+	i->r.min.x = atoi(buf+4*12);
+	i->r.min.y = atoi(buf+5*12);
+	i->r.max.x = atoi(buf+6*12);
+	i->r.max.y = atoi(buf+7*12);
+	i->clipr.min.x = atoi(buf+8*12);
+	i->clipr.min.y = atoi(buf+9*12);
+	i->clipr.max.x = atoi(buf+10*12);
+	i->clipr.max.y = atoi(buf+11*12);
+	i->screen = 0;
+	i->next = 0;
+	return i;
+}
+
+int
+nameimage(Image *i, char *name, int in)
+{
+	uchar *a;
+	int n;
+
+	n = strlen(name);
+	a = bufimage(i->display, 1+4+1+1+n);
+	if(a == 0)
+		return 0;
+	a[0] = 'N';
+	BPLONG(a+1, i->id);
+	a[5] = in;
+	a[6] = n;
+	memmove(a+7, name, n);
+	if(flushimage(i->display, 0) < 0)
+		return 0;
+	return 1;
+}
+
+int
+_freeimage1(Image *i)
+{
+	uchar *a;
+	Display *d;
+	Image *w;
+
+	if(i == 0)
+		return 0;
+	/* make sure no refresh events occur on this if we block in the write */
+	d = i->display;
+	/* flush pending data so we don't get error deleting the image */
+	flushimage(d, 0);
+	a = bufimage(d, 1+4);
+	if(a == 0)
+		return -1;
+	a[0] = 'f';
+	BPLONG(a+1, i->id);
+	if(i->screen){
+		w = d->windows;
+		if(w == i)
+			d->windows = i->next;
+		else
+			while(w){
+				if(w->next == i){
+					w->next = i->next;
+					break;
+				}
+				w = w->next;
+			}
+	}
+	if(flushimage(d, i->screen!=0) < 0)
+		return -1;
+
+	return 0;
+}
+
+int
+freeimage(Image *i)
+{
+	int ret;
+
+	ret = _freeimage1(i);
+	free(i);
+	return ret;
+}
--- /dev/null
+++ b/libdraw/allocimagemix.c
@@ -1,0 +1,42 @@
+#include "lib9.h"
+#include "draw.h"
+
+Image*
+allocimagemix(Display *d, ulong color1, ulong color3)
+{
+	Image *t, *b;
+	static Image *qmask;
+
+	if(qmask == nil)
+		qmask = allocimage(d, Rect(0,0,1,1), GREY8, 1, 0x3F3F3FFF);
+		
+	if(d->depth <= 8){	/* create a 2×2 texture */
+		t = allocimage(d, Rect(0,0,1,1), d->chan, 0, color1);
+		if(t == nil)
+			return nil;
+
+		b = allocimage(d, Rect(0,0,2,2), d->chan, 1, color3);
+		if(b == nil){
+			freeimage(t);
+			return nil;
+		}
+
+		draw(b, Rect(0,0,1,1), t, nil, ZP);
+		freeimage(t);
+		return b;
+	}else{	/* use a solid color, blended using alpha */
+		t = allocimage(d, Rect(0,0,1,1), d->chan, 1, color1);
+		if(t == nil)
+			return nil;
+
+		b = allocimage(d, Rect(0,0,1,1), d->chan, 1, color3);
+		if(b == nil){
+			freeimage(t);
+			return nil;
+		}
+
+		draw(b, b->r, t, qmask, ZP);
+		freeimage(t);
+		return b;
+	}
+}
--- /dev/null
+++ b/libdraw/arith.c
@@ -1,0 +1,203 @@
+#include "lib9.h"
+#include "draw.h"
+
+Point
+Pt(int x, int y)
+{
+	Point p;
+
+	p.x = x;
+	p.y = y;
+	return p;
+}
+
+Rectangle
+Rect(int x, int y, int bx, int by)
+{
+	Rectangle r;
+
+	r.min.x = x;
+	r.min.y = y;
+	r.max.x = bx;
+	r.max.y = by;
+	return r;
+}
+
+Rectangle
+Rpt(Point min, Point max)
+{
+	Rectangle r;
+
+	r.min = min;
+	r.max = max;
+	return r;
+}
+
+Point
+addpt(Point a, Point b)
+{
+	a.x += b.x;
+	a.y += b.y;
+	return a;
+}
+
+Point
+subpt(Point a, Point b)
+{
+	a.x -= b.x;
+	a.y -= b.y;
+	return a;
+}
+
+Rectangle
+insetrect(Rectangle r, int n)
+{
+	r.min.x += n;
+	r.min.y += n;
+	r.max.x -= n;
+	r.max.y -= n;
+	return r;
+}
+
+Point
+divpt(Point a, int b)
+{
+	a.x /= b;
+	a.y /= b;
+	return a;
+}
+
+Point
+mulpt(Point a, int b)
+{
+	a.x *= b;
+	a.y *= b;
+	return a;
+}
+
+Rectangle
+rectsubpt(Rectangle r, Point p)
+{
+	r.min.x -= p.x;
+	r.min.y -= p.y;
+	r.max.x -= p.x;
+	r.max.y -= p.y;
+	return r;
+}
+
+Rectangle
+rectaddpt(Rectangle r, Point p)
+{
+	r.min.x += p.x;
+	r.min.y += p.y;
+	r.max.x += p.x;
+	r.max.y += p.y;
+	return r;
+}
+
+int
+eqpt(Point p, Point q)
+{
+	return p.x==q.x && p.y==q.y;
+}
+
+int
+eqrect(Rectangle r, Rectangle s)
+{
+	return r.min.x==s.min.x && r.max.x==s.max.x &&
+	       r.min.y==s.min.y && r.max.y==s.max.y;
+}
+
+int
+rectXrect(Rectangle r, Rectangle s)
+{
+	return r.min.x<s.max.x && s.min.x<r.max.x &&
+	       r.min.y<s.max.y && s.min.y<r.max.y;
+}
+
+int
+rectinrect(Rectangle r, Rectangle s)
+{
+	return s.min.x<=r.min.x && r.max.x<=s.max.x && s.min.y<=r.min.y && r.max.y<=s.max.y;
+}
+
+int
+ptinrect(Point p, Rectangle r)
+{
+	return p.x>=r.min.x && p.x<r.max.x &&
+	       p.y>=r.min.y && p.y<r.max.y;
+}
+
+Rectangle
+canonrect(Rectangle r)
+{
+	int t;
+	if (r.max.x < r.min.x) {
+		t = r.min.x;
+		r.min.x = r.max.x;
+		r.max.x = t;
+	}
+	if (r.max.y < r.min.y) {
+		t = r.min.y;
+		r.min.y = r.max.y;
+		r.max.y = t;
+	}
+	return r;
+}
+
+void
+combinerect(Rectangle *r1, Rectangle r2)
+{
+	if(r1->min.x > r2.min.x)
+		r1->min.x = r2.min.x;
+	if(r1->min.y > r2.min.y)
+		r1->min.y = r2.min.y;
+	if(r1->max.x < r2.max.x)
+		r1->max.x = r2.max.x;
+	if(r1->max.y < r2.max.y)
+		r1->max.y = r2.max.y;
+}
+
+ulong
+drawld2chan[] = {
+	GREY1,
+	GREY2,
+	GREY4,
+	CMAP8,
+};
+
+ulong
+setalpha(ulong color, uchar alpha)
+{
+	int red, green, blue;
+
+	red = (color >> 3*8) & 0xFF;
+	green = (color >> 2*8) & 0xFF;
+	blue = (color >> 1*8) & 0xFF;
+	/* ignore incoming alpha */
+	red = (red * alpha)/255;
+	green = (green * alpha)/255;
+	blue = (blue * alpha)/255;
+	return (red<<3*8) | (green<<2*8) | (blue<<1*8) | (alpha<<0*8);
+}
+
+Point	ZP;
+Rectangle ZR;
+int
+Rfmt(Fmt *f)
+{
+	Rectangle r;
+
+	r = va_arg(f->args, Rectangle);
+	return fmtprint(f, "%P %P", r.min, r.max);
+}
+
+int
+Pfmt(Fmt *f)
+{
+	Point p;
+
+	p = va_arg(f->args, Point);
+	return fmtprint(f, "[%d %d]", p.x, p.y);
+}
+
--- /dev/null
+++ b/libdraw/bezier.c
@@ -1,0 +1,243 @@
+#include "lib9.h"
+#include "draw.h"
+
+#define	PINC	32		/* realloc granularity */
+
+typedef struct Plist Plist;
+struct Plist
+{
+	Point *p;
+	int np;			/* -1 if malloc/realloc failed */
+};
+
+static void
+appendpt(Plist *l, Point p)
+{
+	if(l->np == -1)
+		return;
+	if(l->np == 0)
+		l->p = malloc(PINC*sizeof(Point));
+	else if(l->np%PINC == 0)
+		l->p = realloc(l->p, (l->np+PINC)*sizeof(Point));
+	if(l->p == 0){
+		l->np = -1;
+		return;
+	}
+	l->p[l->np++] = p;
+}
+
+static int
+normsq(Point p)
+{
+	return p.x*p.x+p.y*p.y;
+}
+
+static int
+psdist(Point p, Point a, Point b)
+{
+	int num, den;
+
+	p = subpt(p, a);
+	b = subpt(b, a);
+	num = p.x*b.x + p.y*b.y;
+	if(num <= 0)
+		return normsq(p);
+	den = normsq(b);
+	if(num >= den)
+		return normsq(subpt(b, p));
+	return normsq(subpt(divpt(mulpt(b, num), den), p));
+}
+
+/*
+ * Convert cubic Bezier curve control points to polyline
+ * vertices.  Leaves the last vertex off, so you can continue
+ * with another curve.
+ */
+static void
+bpts1(Plist *l, Point p0, Point p1, Point p2, Point p3, int scale)
+{
+	Point p01, p12, p23, p012, p123, p0123;
+	Point tp0, tp1, tp2, tp3;
+	tp0=divpt(p0, scale);
+	tp1=divpt(p1, scale);
+	tp2=divpt(p2, scale);
+	tp3=divpt(p3, scale);
+	if(psdist(tp1, tp0, tp3)<=1 && psdist(tp2, tp0, tp3)<=1){
+		appendpt(l, tp0);
+		appendpt(l, tp1);
+		appendpt(l, tp2);
+	}
+	else{
+		/*
+		 * if scale factor is getting too big for comfort,
+		 * rescale now & concede the rounding error
+		 */
+		if(scale>(1<<12)){
+			p0=tp0;
+			p1=tp1;
+			p2=tp2;
+			p3=tp3;
+			scale=1;
+		}
+		p01=addpt(p0, p1);
+		p12=addpt(p1, p2);
+		p23=addpt(p2, p3);
+		p012=addpt(p01, p12);
+		p123=addpt(p12, p23);
+		p0123=addpt(p012, p123);
+		bpts1(l, mulpt(p0, 8), mulpt(p01, 4), mulpt(p012, 2), p0123, scale*8);
+		bpts1(l, p0123, mulpt(p123, 2), mulpt(p23, 4), mulpt(p3, 8), scale*8);
+	}
+}
+
+static void
+bpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
+{
+	bpts1(l, p0, p1, p2, p3, 1);
+}
+
+static void
+bezierpts(Plist *l, Point p0, Point p1, Point p2, Point p3)
+{
+	bpts(l, p0, p1, p2, p3);
+	appendpt(l, p3);
+}
+
+static void
+bezsplinepts(Plist *l, Point *pt, int npt)
+{
+	Point *p, *ep;
+	Point a, b, c, d;
+	int periodic;
+
+	if(npt<3)
+		return;
+	ep = &pt[npt-3];
+	periodic = eqpt(pt[0], ep[2]);
+	if(periodic){
+		a = divpt(addpt(ep[1], pt[0]), 2);
+		b = divpt(addpt(ep[1], mulpt(pt[0], 5)), 6);
+		c = divpt(addpt(mulpt(pt[0], 5), pt[1]), 6);
+		d = divpt(addpt(pt[0], pt[1]), 2);
+		bpts(l, a, b, c, d);
+	}
+	for(p=pt; p<=ep; p++){
+		if(p==pt && !periodic){
+			a = p[0];
+			b = divpt(addpt(p[0], mulpt(p[1], 2)), 3);
+		}
+		else{
+			a = divpt(addpt(p[0], p[1]), 2);
+			b = divpt(addpt(p[0], mulpt(p[1], 5)), 6);
+		}
+		if(p==ep && !periodic){
+			c = divpt(addpt(mulpt(p[1], 2), p[2]), 3);
+			d = p[2];
+		}
+		else{
+			c = divpt(addpt(mulpt(p[1], 5), p[2]), 6);
+			d = divpt(addpt(p[1], p[2]), 2);
+		}
+		bpts(l, a, b, c, d);
+	}
+	appendpt(l, d);
+}
+
+int
+getbezsplinepts(Point *pt, int npt, Point **pp)
+{
+	Plist l;
+	l.np = 0;
+	l.p = nil;
+	bezsplinepts(&l, pt, npt);
+	*pp  = l.p;
+	return l.np;
+}
+
+int
+bezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp)
+{
+	return bezierop(dst, p0, p1, p2, p3, end0, end1, radius, src, sp, SoverD);
+}
+
+int
+bezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+	Plist l;
+
+	l.np = 0;
+	bezierpts(&l, p0, p1, p2, p3);
+	if(l.np == -1)
+		return 0;
+	if(l.np != 0){
+		polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, p0), l.p[0]), op);
+		free(l.p);
+	}
+	return 1;
+}
+
+int
+bezspline(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp)
+{
+	return bezsplineop(dst, pt, npt, end0, end1, radius, src, sp, SoverD);
+}
+
+int
+bezsplineop(Image *dst, Point *pt, int npt, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+	Plist l;
+
+	l.np = 0;
+	bezsplinepts(&l, pt, npt);
+	if(l.np==-1)
+		return 0;
+	if(l.np != 0){
+		polyop(dst, l.p, l.np, end0, end1, radius, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
+		free(l.p);
+	}
+	return 1;
+}
+
+int
+fillbezier(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp)
+{
+	return fillbezierop(dst, p0, p1, p2, p3, w, src, sp, SoverD);
+}
+
+int
+fillbezierop(Image *dst, Point p0, Point p1, Point p2, Point p3, int w, Image *src, Point sp, Drawop op)
+{
+	Plist l;
+
+	l.np = 0;
+	bezierpts(&l, p0, p1, p2, p3);
+	if(l.np == -1)
+		return 0;
+	if(l.np != 0){
+		fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, p0), l.p[0]), op);
+		free(l.p);
+	}
+	return 1;
+}
+
+int
+fillbezspline(Image *dst, Point *pt, int npt, int w, Image *src, Point sp)
+{
+	return fillbezsplineop(dst, pt, npt, w, src, sp, SoverD);
+}
+
+int
+fillbezsplineop(Image *dst, Point *pt, int npt, int w, Image *src, Point sp, Drawop op)
+{
+	Plist l;
+
+	l.np = 0;
+	bezsplinepts(&l, pt, npt);
+	if(l.np == -1)
+		return 0;
+	if(l.np > 0){
+		fillpolyop(dst, l.p, l.np, w, src, addpt(subpt(sp, pt[0]), l.p[0]), op);
+		free(l.p);
+	}
+	return 1;
+}
--- /dev/null
+++ b/libdraw/border.c
@@ -1,0 +1,26 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+borderop(Image *im, Rectangle r, int i, Image *color, Point sp, Drawop op)
+{
+	if(i < 0){
+		r = insetrect(r, i);
+		sp = addpt(sp, Pt(i,i));
+		i = -i;
+	}
+	drawop(im, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i),
+		color, nil, sp, op);
+	drawop(im, Rect(r.min.x, r.max.y-i, r.max.x, r.max.y),
+		color, nil, Pt(sp.x, sp.y+Dy(r)-i), op);
+	drawop(im, Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i),
+		color, nil, Pt(sp.x, sp.y+i), op);
+	drawop(im, Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i),
+		color, nil, Pt(sp.x+Dx(r)-i, sp.y+i), op);
+}
+
+void
+border(Image *im, Rectangle r, int i, Image *color, Point sp)
+{
+	borderop(im, r, i, color, sp, SoverD);
+}
--- /dev/null
+++ b/libdraw/buildfont.c
@@ -1,0 +1,142 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+static char*
+skip(char *s)
+{
+	while(*s==' ' || *s=='\n' || *s=='\t')
+		s++;
+	return s;
+}
+
+Font*
+buildfont(Display *d, char *buf, char *name)
+{
+	Font *fnt;
+	Cachefont *c;
+	char *s, *t;
+	ulong min, max;
+	int offset;
+	char badform[] = "bad font format: number expected (char position %d)";
+
+	s = buf;
+	fnt = malloc(sizeof(Font));
+	if(fnt == 0)
+		return 0;
+	memset(fnt, 0, sizeof(Font));
+	fnt->display = d;
+	fnt->name = strdup(name);
+	fnt->ncache = NFCACHE+NFLOOK;
+	fnt->nsubf = NFSUBF;
+	fnt->cache = malloc(fnt->ncache * sizeof(fnt->cache[0]));
+	fnt->subf = malloc(fnt->nsubf * sizeof(fnt->subf[0]));
+	if(fnt->name==0 || fnt->cache==0 || fnt->subf==0){
+    Err2:
+		free(fnt->name);
+		free(fnt->cache);
+		free(fnt->subf);
+		free(fnt->sub);
+		free(fnt);
+		return 0;
+	}
+	fnt->height = strtol(s, &s, 0);
+	s = skip(s);
+	fnt->ascent = strtol(s, &s, 0);
+	s = skip(s);
+	if(fnt->height<=0 || fnt->ascent<=0){
+		kwerrstr("bad height or ascent in font file");
+		goto Err2;
+	}
+	fnt->width = 0;
+	fnt->nsub = 0;
+	fnt->sub = 0;
+
+	memset(fnt->subf, 0, fnt->nsubf * sizeof(fnt->subf[0]));
+	memset(fnt->cache, 0, fnt->ncache*sizeof(fnt->cache[0]));
+	fnt->age = 1;
+	do{
+		/* must be looking at a number now */
+		if(*s<'0' || '9'<*s){
+			kwerrstr(badform, s-buf);
+			goto Err3;
+		}
+		min = strtol(s, &s, 0);
+		s = skip(s);
+		/* must be looking at a number now */
+		if(*s<'0' || '9'<*s){
+			kwerrstr(badform, s-buf);
+			goto Err3;
+		}
+		max = strtol(s, &s, 0);
+		s = skip(s);
+		if(*s==0 || min>=Runemax || max>=Runemax || min>max){
+			kwerrstr("illegal subfont range");
+    Err3:
+			freefont(fnt);
+			return 0;
+		}
+		t = s;
+		offset = strtol(s, &t, 0);
+		if(t>s && (*t==' ' || *t=='\t' || *t=='\n'))
+			s = skip(t);
+		else
+			offset = 0;
+		fnt->sub = realloc(fnt->sub, (fnt->nsub+1)*sizeof(Cachefont*));
+		if(fnt->sub == 0){
+			/* realloc manual says fnt->sub may have been destroyed */
+			fnt->nsub = 0;
+			goto Err3;
+		}
+		c = malloc(sizeof(Cachefont));
+		if(c == 0)
+			goto Err3;
+		fnt->sub[fnt->nsub] = c;
+		c->min = min;
+		c->max = max;
+		c->offset = offset;
+		t = s;
+		while(*s && *s!=' ' && *s!='\n' && *s!='\t')
+			s++;
+		*s++ = 0;
+		c->subfontname = 0;
+		c->name = strdup(t);
+		if(c->name == 0){
+			free(c);
+			goto Err3;
+		}
+		s = skip(s);
+		fnt->nsub++;
+	}while(*s);
+	return fnt;
+}
+
+void
+freefont(Font *f)
+{
+	int i;
+	Cachefont *c;
+	Subfont *s;
+
+	if(f == 0)
+		return;
+
+	for(i=0; i<f->nsub; i++){
+		c = f->sub[i];
+		free(c->subfontname);
+		free(c->name);
+		free(c);
+	}
+	for(i=0; i<f->nsubf; i++){
+		s = f->subf[i].f;
+/*		if(s && s!=display->defaultsubfont)*/	/* Plan 9 uses this */
+		if(s)
+			freesubfont(s);
+	}
+	freeimage(f->cacheimage);
+	free(f->name);
+	free(f->cache);
+	free(f->subf);
+	free(f->sub);
+	free(f);
+}
--- /dev/null
+++ b/libdraw/bytesperline.c
@@ -1,0 +1,30 @@
+#include "lib9.h"
+#include "draw.h"
+
+static
+int
+unitsperline(Rectangle r, int d, int bitsperunit)
+{
+	ulong l, t;
+
+	if(r.min.x >= 0){
+		l = (r.max.x*d+bitsperunit-1)/bitsperunit;
+		l -= (r.min.x*d)/bitsperunit;
+	}else{			/* make positive before divide */
+		t = (-r.min.x*d+bitsperunit-1)/bitsperunit;
+		l = t+(r.max.x*d+bitsperunit-1)/bitsperunit;
+	}
+	return l;
+}
+
+int
+wordsperline(Rectangle r, int d)
+{
+	return unitsperline(r, d, 8*sizeof(ulong));
+}
+
+int
+bytesperline(Rectangle r, int d)
+{
+	return unitsperline(r, d, 8);
+}
--- /dev/null
+++ b/libdraw/chan.c
@@ -1,0 +1,76 @@
+#include "lib9.h"
+#include "draw.h"
+
+static char channames[] = "rgbkamx";
+char*
+chantostr(char *buf, ulong cc)
+{
+	ulong c, rc;
+	char *p;
+
+	if(chantodepth(cc) == 0)
+		return nil;
+
+	/* reverse the channel descriptor so we can easily generate the string in the right order */
+	rc = 0;
+	for(c=cc; c; c>>=8){
+		rc <<= 8;
+		rc |= c&0xFF;
+	}
+
+	p = buf;
+	for(c=rc; c; c>>=8) {
+		*p++ = channames[TYPE(c)];
+		*p++ = '0'+NBITS(c);
+	}
+	*p = 0;
+
+	return buf;
+}
+
+/* avoid pulling in ctype when using with drawterm etc. */
+static int
+iswhitespace(char c)
+{
+	return c==' ' || c== '\t' || c=='\r' || c=='\n';
+}
+
+ulong
+strtochan(char *s)
+{
+	char *p, *q;
+	ulong c;
+	int t, n;
+
+	c = 0;
+	p=s;
+	while(*p && iswhitespace(*p))
+		p++;
+
+	while(*p && !iswhitespace(*p)){
+		if((q = strchr(channames, p[0])) == nil) 
+			return 0;
+		t = q-channames;
+		if(p[1] < '0' || p[1] > '9')
+			return 0;
+		n = p[1]-'0';
+		c = (c<<8) | __DC(t, n);
+		p += 2;
+	}
+	return c;
+}
+
+int
+chantodepth(ulong c)
+{
+	int n;
+
+	for(n=0; c; c>>=8){
+		if(TYPE(c) >= NChan || NBITS(c) > 8 || NBITS(c) <= 0)
+			return 0;
+		n += NBITS(c);
+	}
+	if(n==0 || (n>8 && n%8) || (n<8 && 8%n))
+		return 0;
+	return n;
+}
--- /dev/null
+++ b/libdraw/cloadimage.c
@@ -1,0 +1,49 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+int
+cloadimage(Image *i, Rectangle r, uchar *data, int ndata)
+{
+	int m, nb, miny, maxy, ncblock;
+	uchar *a;
+
+	if(!rectinrect(r, i->r)){
+		werrstr("cloadimage: bad rectangle");
+		return -1;
+	}
+
+	miny = r.min.y;
+	m = 0;
+	ncblock = _compblocksize(r, i->depth);
+	while(miny != r.max.y){
+		maxy = atoi((char*)data+0*12);
+		nb = atoi((char*)data+1*12);
+		if(maxy<=miny || r.max.y<maxy){
+			werrstr("creadimage: bad maxy %d", maxy);
+			return -1;
+		}
+		data += 2*12;
+		ndata -= 2*12;
+		m += 2*12;
+		if(nb<=0 || ncblock<nb || nb>ndata){
+			werrstr("creadimage: bad count %d", nb);
+			return -1;
+		}
+		a = bufimage(i->display, 21+nb);
+		if(a == nil)
+			return -1;
+		a[0] = 'Y';
+		BPLONG(a+1, i->id);
+		BPLONG(a+5, r.min.x);
+		BPLONG(a+9, miny);
+		BPLONG(a+13, r.max.x);
+		BPLONG(a+17, maxy);
+		memmove(a+21, data, nb);
+		miny = maxy;
+		data += nb;
+		ndata += nb;
+		m += nb;
+	}
+	return m;
+}
--- /dev/null
+++ b/libdraw/computil.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * compressed data are sequences of byte codes.  
+ * if the first byte b has the 0x80 bit set, the next (b^0x80)+1 bytes
+ * are data.  otherwise, it's two bytes specifying a previous string to repeat.
+ */
+void
+_twiddlecompressed(uchar *buf, int n)
+{
+	uchar *ebuf;
+	int j, k, c;
+
+	ebuf = buf+n;
+	while(buf < ebuf){
+		c = *buf++;
+		if(c >= 128){
+			k = c-128+1;
+			for(j=0; j<k; j++, buf++)
+				*buf ^= 0xFF;
+		}else
+			buf++;
+	}
+}
+
+int
+_compblocksize(Rectangle r, int depth)
+{
+	int bpl;
+
+	bpl = bytesperline(r, depth);
+	bpl = 2*bpl;	/* add plenty extra for blocking, etc. */
+	if(bpl < NCBLOCK)
+		return NCBLOCK;
+	return bpl;
+}
--- /dev/null
+++ b/libdraw/creadimage.c
@@ -1,0 +1,116 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+Image *
+creadimage(Display *d, int fd, int dolock)
+{
+	char hdr[5*12+1];
+	Rectangle r;
+	int m, nb, miny, maxy, new, ldepth, ncblock;
+	uchar *buf, *a;
+	Image *i;
+	ulong chan;
+	int font;
+
+	font = dolock&2;
+	dolock &= 1;
+	if(libreadn(fd, hdr, 5*12) != 5*12)
+		return nil;
+
+	/*
+	 * distinguish new channel descriptor from old ldepth.
+	 * channel descriptors have letters as well as numbers,
+	 * while ldepths are a single digit formatted as %-11d.
+	 */
+	new = 0;
+	for(m=0; m<10; m++){
+		if(hdr[m] != ' '){
+			new = 1;
+			break;
+		}
+	}
+	if(hdr[11] != ' '){
+		kwerrstr("creadimage: bad format");
+		return nil;
+	}
+	if(new){
+		hdr[11] = '\0';
+		if((chan = strtochan(hdr)) == 0){
+			kwerrstr("creadimage: bad channel string %s", hdr);
+			return nil;
+		}
+	}else{
+		ldepth = ((int)hdr[10])-'0';
+		if(ldepth<0 || ldepth>3){
+			kwerrstr("creadimage: bad ldepth %d", ldepth);
+			return nil;
+		}
+		chan = drawld2chan[ldepth];
+	}
+	r.min.x=atoi(hdr+1*12);
+	r.min.y=atoi(hdr+2*12);
+	r.max.x=atoi(hdr+3*12);
+	r.max.y=atoi(hdr+4*12);
+	if(r.min.x>r.max.x || r.min.y>r.max.y){
+		kwerrstr("creadimage: bad rectangle");
+		return nil;
+	}
+
+	if(dolock)
+		dolock = lockdisplay(d);
+	i = allocimage(d, r, chan, 0, 0);
+	if(dolock)
+		unlockdisplay(d);
+	if(i == nil)
+		return nil;
+	ncblock = _compblocksize(r, i->depth);
+	buf = malloc(ncblock);
+	if(buf == nil)
+		goto Errout;
+	miny = r.min.y;
+	while(miny != r.max.y){
+		if(libreadn(fd, hdr, 2*12) != 2*12){
+		Errout:
+			if(dolock)
+				lockdisplay(d);
+		Erroutlock:
+			freeimage(i);
+			if(dolock)
+				unlockdisplay(d);
+			free(buf);
+			return nil;
+		}
+		maxy = atoi(hdr+0*12);
+		nb = atoi(hdr+1*12);
+		if(maxy<=miny || r.max.y<maxy){
+			kwerrstr("creadimage: bad maxy %d", maxy);
+			goto Errout;
+		}
+		if(nb<=0 || ncblock<nb){
+			kwerrstr("creadimage: bad count %d", nb);
+			goto Errout;
+		}
+		if(libreadn(fd, buf, nb)!=nb)
+			goto Errout;
+		if(dolock)
+			lockdisplay(d);
+		a = bufimage(i->display, 21+nb);
+		if(a == nil)
+			goto Erroutlock;
+		a[0] = 'Y';
+		BPLONG(a+1, i->id);
+		BPLONG(a+5, r.min.x);
+		BPLONG(a+9, miny);
+		BPLONG(a+13, r.max.x);
+		BPLONG(a+17, maxy);
+		if(!font&&!new)	/* old image: flip the data bits */
+			_twiddlecompressed(buf, nb);
+		memmove(a+21, buf, nb);
+		if(dolock)
+			unlockdisplay(d);
+		miny = maxy;
+	}
+	free(buf);
+	return i;
+}
--- /dev/null
+++ b/libdraw/defont.c
@@ -1,0 +1,401 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * lucm/latin1.9, in uncompressed form
+ */
+uchar
+defontdata[] =
+{
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,0x30,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x32,0x33,0x30,0x34,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x35,0x20,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x30,0x06,0x06,0x03,0x42,0x40,0x00,0x00,0x00,0x18,0x03,0x03,
+0x02,0x43,0x00,0x60,0x60,0x48,0x00,0x0d,0x0c,0x01,0x81,0x80,0xd0,0x90,0x00,0x00,
+0x18,0x01,0x81,0x81,0x40,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x7f,0x9c,0x1c,
+0x0e,0x07,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x70,
+0x38,0x1c,0x0e,0x04,0x81,0xc1,0xc0,0x70,0x00,0x1c,0x1c,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xaa,0x80,0xc0,0x63,0xe3,
+0xf1,0xf8,0xfe,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f,0xff,0xff,0x1f,0x8f,
+0xc7,0xe3,0xf1,0xfb,0x7e,0x3e,0x3f,0x8f,0xff,0xe3,0xe3,0xff,0xff,0xff,0xff,0xff,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x0c,0x18,0x09,0x05,0x82,0x40,0xc0,0x00,0x00,0x06,0x0c,0x04,
+0x82,0x40,0xc1,0x80,0x90,0x48,0x00,0x16,0x03,0x06,0x02,0x41,0x60,0x90,0x00,0x00,
+0x06,0x06,0x02,0x41,0x41,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7f,0xa0,0x10,
+0x08,0x04,0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x48,
+0x24,0x12,0x09,0x06,0x82,0x01,0x00,0x90,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x04,0x80,0x00,0x40,0x00,0x00,0x38,0x06,0x18,0x00,0x00,0x00,0x00,0x00,
+0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x07,0xc6,0x01,0xf0,0x00,0x00,0x0c,0x00,0x18,0x00,0x00,0x30,0x00,0x3c,
+0x00,0x60,0x06,0x01,0x8c,0x07,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xe0,0xc3,0xc0,0x01,0x54,0x9c,0xc0,0x5f,0xef,
+0xf7,0xfb,0xfd,0xbf,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0x7f,0xff,0xff,0x6f,0xb7,
+0xdb,0xed,0xf6,0xf9,0x7d,0xfe,0xff,0x6f,0xff,0xdf,0xef,0xff,0xff,0xff,0xff,0xff,
+0xff,0x00,0x01,0x00,0x00,0x00,0x00,0x30,0x00,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x20,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x78,0x30,0x06,0x06,0x06,0x82,0x80,0xc0,0x00,
+0x00,0x18,0x03,0x03,0x02,0x41,0x80,0x30,0x30,0x24,0x76,0x0d,0x0c,0x00,0xc0,0xc0,
+0xd0,0x50,0x00,0x00,0x18,0x01,0x81,0x81,0x40,0x30,0x00,0x28,0x0f,0x7f,0xbc,0x1c,
+0x0e,0x07,0x03,0xc0,0x10,0x70,0x24,0x10,0x09,0x07,0x03,0x80,0xe0,0x70,0x90,0x48,
+0x24,0x12,0x09,0x05,0x81,0x81,0xc0,0x80,0x70,0x18,0x1c,0x07,0x01,0xc1,0xc0,0x90,
+0x00,0x0c,0x04,0x84,0x83,0xe1,0xc0,0xe0,0x38,0x0c,0x0c,0x02,0x00,0x00,0x00,0x00,
+0x00,0x06,0x1c,0x06,0x0f,0x87,0xc0,0x63,0xf8,0x78,0xfe,0x3e,0x0e,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7c,0x1c,0x0c,0x1f,0x03,0xc7,0xc3,0xf1,0xf8,0x3c,0x63,0x3f,0x0f,
+0x8c,0x66,0x06,0x19,0x84,0x78,0x7e,0x1e,0x1f,0x07,0xcf,0xf3,0x1b,0x0d,0x86,0x63,
+0x61,0x9f,0xc6,0x06,0x00,0x30,0x00,0x00,0x10,0x00,0x18,0x00,0x00,0x30,0x00,0x60,
+0x00,0x60,0x06,0x01,0x8c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,
+0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x00,0xaa,0xb6,0xc0,0x43,0xe3,
+0xf1,0xf8,0xfc,0x3f,0xef,0x8f,0xdb,0xef,0xf6,0xf8,0xfb,0xff,0x1f,0x8f,0x6f,0xb7,
+0xdb,0xed,0xf6,0xfa,0x7e,0x7e,0x3f,0x7f,0x8f,0xe7,0xe3,0xf8,0xfe,0x3e,0x3f,0x6f,
+0x00,0x00,0x01,0x01,0xc8,0x0b,0x0c,0x30,0x7c,0x14,0x0f,0x0f,0x00,0x00,0x00,0x00,
+0x78,0x00,0x1c,0x00,0x0f,0x07,0x81,0x80,0x00,0x7c,0x00,0x00,0x1c,0x0f,0x80,0x04,
+0x42,0x23,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x3c,0x3c,0x3f,0x1f,0x8f,
+0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x30,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0x3d,
+0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x0c,0x18,0x09,0x0b,0x02,0x81,0x20,0x00,
+0x00,0x06,0x0c,0x04,0x82,0x40,0x60,0xc0,0x48,0x24,0x18,0x16,0x03,0x03,0x01,0x21,
+0x60,0x50,0x00,0x00,0x06,0x06,0x02,0x41,0x40,0xc1,0x80,0x28,0x87,0x7f,0x84,0x10,
+0x08,0x04,0x02,0x40,0x38,0x48,0x24,0x10,0x09,0x04,0x04,0x81,0x00,0x80,0x90,0x48,
+0x24,0x12,0x09,0x04,0x80,0x41,0x00,0x80,0x40,0x04,0x10,0x04,0x02,0x01,0x20,0x90,
+0x00,0x0c,0x04,0x84,0x86,0x53,0x65,0xb0,0x08,0x18,0x06,0x0a,0x80,0x00,0x00,0x00,
+0x00,0x0c,0x36,0x0e,0x19,0xcc,0xe0,0xe3,0xf8,0xcc,0xfe,0x63,0x1b,0x00,0x00,0x00,
+0x00,0x00,0x00,0xc6,0x62,0x0c,0x19,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x01,
+0x8c,0xc6,0x06,0x19,0xc4,0xcc,0x63,0x33,0x19,0x8c,0x61,0x83,0x1b,0x0d,0x86,0x63,
+0x61,0x80,0xc6,0x03,0x00,0x30,0x30,0x00,0x1c,0x00,0x18,0x00,0x00,0x30,0x00,0x60,
+0x00,0x60,0x00,0x00,0x0c,0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,
+0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0xc0,0x60,0x01,0x54,0x86,0xc0,0x7b,0xef,
+0xf7,0xfb,0xfd,0xbf,0xc7,0xb7,0xdb,0xef,0xf6,0xfb,0xfb,0x7e,0xff,0x7f,0x6f,0xb7,
+0xdb,0xed,0xf6,0xfb,0x7f,0xbe,0xff,0x7f,0xbf,0xfb,0xef,0xfb,0xfd,0xfe,0xdf,0x6f,
+0xff,0x00,0x07,0x83,0x24,0x13,0x0c,0x30,0xc6,0x00,0x10,0x81,0x80,0x00,0x00,0x00,
+0x84,0x00,0x22,0x00,0x01,0x80,0xc0,0x00,0x00,0xf4,0x00,0x00,0x2c,0x18,0xc0,0x0c,
+0x46,0x20,0x90,0x00,0x18,0x0c,0x06,0x03,0x01,0x80,0xc0,0x70,0x66,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x38,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66,
+0x31,0x98,0xcc,0x66,0x36,0x19,0x80,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0xff,0x7f,0xb8,0x1c,
+0x0e,0x07,0x02,0x40,0x7c,0x70,0x3c,0x10,0x09,0x07,0x04,0x00,0xc0,0x60,0xe0,0x70,
+0x38,0x1c,0x0e,0x04,0x83,0x81,0xc0,0x70,0x70,0x38,0x1c,0x07,0x02,0xc1,0xc0,0x90,
+0x00,0x0c,0x00,0x04,0x86,0x43,0x69,0xb0,0x30,0x18,0x06,0x07,0x01,0x00,0x00,0x00,
+0x00,0x0c,0x63,0x16,0x00,0xc0,0x61,0x62,0x01,0x80,0x06,0x63,0x31,0x80,0x00,0x00,
+0x60,0x00,0xc0,0x06,0x43,0x16,0x19,0x8c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01,
+0x8c,0x86,0x07,0x39,0xc5,0x86,0x63,0x61,0x99,0x8c,0x01,0x83,0x1b,0x0d,0xb6,0x63,
+0x31,0x01,0x86,0x03,0x00,0x30,0x30,0x00,0x1c,0x3e,0x1b,0x03,0xc1,0xf0,0xf0,0x60,
+0x3e,0x6e,0x3e,0x0f,0x8c,0x60,0xc5,0xb1,0xb8,0x38,0x6c,0x0f,0x8c,0xc7,0xc1,0x83,
+0x19,0x8d,0x82,0x63,0x31,0x9f,0xc1,0x80,0xc0,0xc0,0x00,0xaa,0x86,0xc0,0x47,0xe3,
+0xf1,0xf8,0xfd,0xbf,0x83,0x8f,0xc3,0xef,0xf6,0xf8,0xfc,0xff,0x3f,0x9f,0x1f,0x8f,
+0xc7,0xe3,0xf1,0xfb,0x7c,0x7e,0x3f,0x8f,0x8f,0xc7,0xe3,0xf8,0xfd,0x3e,0x3f,0x6f,
+0x00,0x0c,0x0d,0x43,0x03,0xe1,0x88,0x30,0xc0,0x00,0x27,0x41,0x80,0x00,0x00,0x01,
+0x72,0x00,0x22,0x04,0x01,0x80,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xc0,0x04,
+0x82,0x43,0x20,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x38,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x00,0xc7,
+0x31,0x98,0xcc,0x66,0x33,0x11,0xf8,0xc8,0x7c,0x3e,0x1f,0x0f,0x87,0xc3,0xe1,0xd8,
+0x3c,0x1e,0x0f,0x07,0x83,0xc7,0xc3,0xe1,0xf0,0xf8,0x06,0x37,0x07,0x03,0x81,0xc0,
+0xe0,0x70,0x10,0x1d,0x31,0x98,0xcc,0x66,0x33,0x19,0xb0,0xc6,0x8f,0x7f,0x87,0x03,
+0x81,0x80,0x90,0x30,0x6c,0x48,0x24,0x10,0x06,0x04,0x04,0x80,0x20,0x10,0x10,0x0e,
+0x07,0x03,0x81,0xc0,0x60,0x88,0x38,0x0c,0x40,0x09,0x03,0x84,0x02,0x41,0x40,0x90,
+0x00,0x0c,0x00,0x1f,0xe7,0x41,0xd1,0xa0,0x00,0x30,0x03,0x0a,0x81,0x00,0x00,0x00,
+0x00,0x18,0x63,0x06,0x00,0xc0,0xc2,0x62,0x01,0xb0,0x0c,0x72,0x31,0x86,0x03,0x00,
+0xc0,0x00,0x60,0x06,0x8f,0x16,0x19,0x0c,0x06,0x33,0x01,0x80,0xc0,0x63,0x0c,0x01,
+0x8d,0x06,0x07,0x39,0x65,0x86,0x63,0x61,0x99,0x0e,0x01,0x83,0x19,0x89,0xb6,0x32,
+0x33,0x03,0x06,0x01,0x80,0x30,0x78,0x00,0x00,0x03,0x1d,0x86,0x23,0x31,0x99,0xfc,
+0x66,0x77,0x06,0x01,0x8c,0x40,0xc6,0xd9,0xdc,0x6c,0x76,0x19,0x8d,0xcc,0x27,0xf3,
+0x19,0x8d,0x82,0x63,0x31,0x80,0xc0,0x80,0xc0,0x80,0x01,0x54,0x8c,0xc0,0x78,0xfc,
+0x7e,0x7f,0x6f,0xcf,0x93,0xb7,0xdb,0xef,0xf9,0xfb,0xff,0xff,0xdf,0xef,0xef,0xf1,
+0xf8,0xfc,0x7e,0x3f,0x9f,0x77,0xc7,0xf3,0xbf,0xf6,0xfc,0x7b,0xfd,0xbe,0xbf,0x6f,
+0xff,0x0c,0x19,0x03,0x03,0x61,0x98,0x30,0x78,0x00,0x28,0x4f,0x83,0x30,0x00,0x01,
+0x4a,0x00,0x1c,0x04,0x03,0x03,0x80,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xd9,0x84,
+0x82,0x40,0xa0,0x18,0x2c,0x16,0x0b,0x05,0x82,0xc1,0x60,0xb0,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x64,0xcb,
+0x31,0x98,0xcc,0x66,0x33,0x31,0x8c,0xd8,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c,
+0x62,0x33,0x19,0x8c,0xc6,0x60,0xc0,0x60,0x30,0x18,0x1e,0x3b,0x8d,0x86,0xc3,0x61,
+0xb0,0xd8,0x10,0x36,0x31,0x98,0xcc,0x66,0x33,0x19,0xd8,0xc6,0x0f,0x7f,0x82,0x01,
+0x02,0x40,0xd0,0x40,0x6c,0x70,0x24,0x1c,0x06,0x04,0x03,0x01,0xc0,0xe0,0x10,0x12,
+0x09,0x04,0x82,0x40,0x90,0x50,0x10,0x12,0x70,0x09,0x04,0x04,0x01,0xc1,0x20,0x60,
+0x00,0x0c,0x00,0x04,0x83,0xc0,0x20,0xcc,0x00,0x30,0x03,0x02,0x01,0x00,0x00,0x00,
+0x00,0x18,0x63,0x06,0x01,0x83,0x84,0x63,0xf1,0xd8,0x18,0x3c,0x31,0x86,0x03,0x01,
+0x83,0xf8,0x30,0x1c,0x9b,0x33,0x1e,0x0c,0x06,0x33,0xe1,0x80,0xc0,0x7f,0x0c,0x01,
+0x8f,0x06,0x07,0x79,0x65,0x86,0x66,0x61,0x9e,0x07,0x81,0x83,0x19,0x89,0xb6,0x1c,
+0x1a,0x03,0x06,0x01,0x80,0x30,0x48,0x00,0x00,0x03,0x18,0xcc,0x06,0x33,0x18,0x60,
+0xc6,0x63,0x06,0x01,0x8c,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8e,0x4c,0x01,0x83,
+0x19,0x8d,0x92,0x32,0x31,0x81,0x87,0x00,0xc0,0x70,0xe4,0xaa,0x98,0xc0,0x7d,0xfe,
+0xfd,0xbf,0x2f,0xbf,0x93,0x8f,0xdb,0xe3,0xf9,0xfb,0xff,0x1e,0x3f,0x1f,0xef,0xed,
+0xf6,0xfb,0x7d,0xbf,0x6f,0xaf,0xef,0xed,0x8f,0xf6,0xfb,0xfb,0xfe,0x3e,0xdf,0x9f,
+0x00,0x00,0x19,0x0f,0xc6,0x30,0xd0,0x00,0xcc,0x00,0x28,0x59,0x86,0x67,0xf0,0x01,
+0x72,0x00,0x00,0x3f,0x86,0x00,0xc0,0x03,0x18,0xf4,0x00,0x00,0x0c,0x18,0xcc,0xc5,
+0x32,0x83,0x4c,0x00,0x66,0x33,0x19,0x8c,0xc6,0x63,0x31,0xbc,0xc0,0x3e,0x1f,0x0f,
+0x87,0xc1,0x80,0xc0,0x60,0x30,0xfb,0x2c,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xcb,
+0x31,0x98,0xcc,0x66,0x31,0xa1,0x8c,0xcc,0x06,0x03,0x01,0x80,0xc0,0x60,0x30,0x6c,
+0xc0,0x63,0x31,0x98,0xcc,0x60,0xc0,0x60,0x30,0x18,0x37,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0x00,0x67,0x31,0x98,0xcc,0x66,0x33,0x19,0x8c,0xc6,0x1f,0x7f,0x82,0x01,
+0x02,0x40,0xb0,0x40,0x6c,0x07,0x03,0x83,0x80,0xe0,0xe0,0x00,0x18,0x0e,0x10,0x10,
+0x08,0x04,0x02,0x00,0xf0,0x20,0x10,0x1e,0x08,0x89,0x03,0x00,0xe0,0x38,0x1c,0x0e,
+0x00,0x0c,0x00,0x04,0x81,0xe0,0x41,0x6c,0x00,0x30,0x03,0x00,0x0f,0xe0,0x03,0xf8,
+0x00,0x30,0x63,0x06,0x03,0x00,0xc7,0xf0,0x39,0x8c,0x30,0x3e,0x1b,0x80,0x00,0x03,
+0x00,0x00,0x18,0x30,0x9b,0x23,0x19,0x0c,0x06,0x33,0x01,0xf8,0xc6,0x63,0x0c,0x01,
+0x8d,0x86,0x05,0xd9,0x35,0x86,0x7c,0x61,0x9b,0x01,0xc1,0x83,0x19,0x99,0xb4,0x1c,
+0x0c,0x06,0x06,0x00,0xc0,0x30,0xcc,0x00,0x00,0x3f,0x18,0xcc,0x06,0x33,0xf8,0x60,
+0xc6,0x63,0x06,0x01,0x8f,0x00,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x0f,0x81,0x83,
+0x18,0xd9,0xba,0x1c,0x1b,0x03,0x00,0x80,0xc0,0x81,0x75,0x54,0x98,0xc0,0x7d,0xfe,
+0xfd,0xbf,0x4f,0xbf,0x93,0xf8,0xfc,0x7c,0x7f,0x1f,0x1f,0x6f,0xe7,0xf1,0xef,0xef,
+0xf7,0xfb,0xfd,0xff,0x0f,0xdf,0xef,0xe1,0xf7,0x76,0xfc,0xff,0x1f,0xc7,0xe3,0xf1,
+0xff,0x08,0x19,0x03,0x06,0x31,0xf8,0x00,0xc6,0x00,0x28,0x5b,0x8c,0xc0,0x11,0xf1,
+0x4a,0x00,0x00,0x04,0x0c,0x00,0xc0,0x03,0x18,0x74,0x38,0x00,0x0c,0x18,0xc6,0x65,
+0x52,0xb8,0x54,0x18,0x46,0x23,0x11,0x88,0xc4,0x62,0x31,0x30,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x10,0xd3,
+0x31,0x98,0xcc,0x66,0x30,0xc1,0x8c,0xc6,0x7e,0x3f,0x1f,0x8f,0xc7,0xe3,0xf1,0xfc,
+0xc0,0x7f,0x3f,0x9f,0xcf,0xe0,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0xfe,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x0e,0x7f,0x82,0x01,
+0x01,0x80,0x90,0x30,0xc6,0x08,0x01,0x02,0x00,0x40,0x80,0xe0,0x24,0x04,0x1c,0x10,
+0x08,0x04,0x02,0x00,0x90,0x20,0x10,0x12,0x0d,0x86,0x00,0x81,0x00,0x40,0x20,0x10,
+0x00,0x04,0x00,0x1f,0xe1,0x70,0xbb,0x28,0x00,0x30,0x03,0x00,0x01,0x00,0x00,0x00,
+0x00,0x30,0x63,0x06,0x06,0x00,0x67,0xf0,0x19,0x8c,0x30,0x67,0x0d,0x80,0x00,0x01,
+0x83,0xf8,0x30,0x30,0x9b,0x7f,0x19,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01,
+0x8c,0xc6,0x05,0xd9,0x35,0x86,0x60,0x61,0x99,0x80,0xe1,0x83,0x18,0xd0,0xdc,0x26,
+0x0c,0x0c,0x06,0x00,0xc0,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60,
+0xc6,0x63,0x06,0x01,0x8d,0x80,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x03,0xe1,0x83,
+0x18,0xd9,0xba,0x1c,0x1b,0x06,0x01,0x80,0xc0,0xc1,0x38,0xaa,0x80,0xc0,0x7d,0xfe,
+0xfe,0x7f,0x6f,0xcf,0x39,0xf7,0xfe,0xfd,0xff,0xbf,0x7f,0x0f,0xdb,0xfb,0xe3,0xef,
+0xf7,0xfb,0xfd,0xff,0x6f,0xdf,0xef,0xed,0xf2,0x79,0xff,0x7e,0xff,0xbf,0xdf,0xef,
+0x00,0x0c,0x19,0x03,0x03,0x60,0x60,0x30,0x66,0x00,0x28,0x4d,0xc6,0x60,0x10,0x00,
+0x84,0x00,0x00,0x04,0x0f,0x87,0x80,0x03,0x18,0x14,0x38,0x00,0x3f,0x0f,0x8c,0xc2,
+0x90,0x84,0xa4,0x18,0xfe,0x7f,0x3f,0x9f,0xcf,0xe7,0xf1,0xf0,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x26,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x38,0xd3,
+0x31,0x98,0xcc,0x66,0x30,0xc1,0x98,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60,
+0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0x00,0x6b,0x31,0x98,0xcc,0x66,0x31,0xb1,0x8c,0x6c,0x1c,0x7f,0x81,0x20,
+0x90,0x38,0x18,0x0b,0x83,0x06,0x01,0x03,0x80,0x40,0xe0,0x90,0x24,0x04,0x03,0x8e,
+0x86,0xc3,0x61,0x90,0x24,0x12,0x0e,0x04,0x8a,0x81,0xc7,0x70,0xc0,0x30,0x18,0x0c,
+0x00,0x00,0x00,0x04,0x81,0x31,0x6f,0x30,0x00,0x18,0x06,0x00,0x01,0x00,0x00,0x00,
+0x00,0x60,0x63,0x06,0x0c,0x00,0x60,0x60,0x19,0x8c,0x60,0x63,0x01,0x80,0x00,0x00,
+0xc0,0x00,0x60,0x00,0x4d,0xe1,0x99,0x8c,0x06,0x33,0x01,0x80,0xc6,0x63,0x0c,0x01,
+0x8c,0xc6,0x04,0x99,0x1d,0x86,0x60,0x61,0x99,0x80,0x61,0x83,0x18,0xd0,0xdc,0x63,
+0x0c,0x0c,0x06,0x00,0x60,0x30,0x84,0x00,0x00,0x63,0x18,0xcc,0x06,0x33,0x00,0x60,
+0x6e,0x63,0x06,0x01,0x8c,0xc0,0xc6,0xd9,0x8c,0xc6,0x63,0x31,0x8c,0x00,0x61,0x83,
+0x18,0xd0,0xcc,0x26,0x0e,0x0c,0x03,0x00,0xc0,0x60,0x01,0x54,0x98,0xc0,0x7e,0xdf,
+0x6f,0xc7,0xe7,0xf4,0x7c,0xf9,0xfe,0xfc,0x7f,0xbf,0x1f,0x5f,0xdb,0xfb,0xfc,0x71,
+0x79,0x3c,0x9e,0x6f,0xdb,0xed,0xf1,0xfb,0x75,0x7e,0x38,0x8f,0x3f,0xcf,0xe7,0xf3,
+0xff,0x0c,0x0d,0x03,0x03,0xe1,0xf8,0x30,0x3c,0x00,0x27,0x40,0x03,0x30,0x00,0x00,
+0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x18,0x14,0x00,0x00,0x00,0x00,0x19,0x82,
+0xf8,0x98,0xbe,0x70,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0xc0,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x63,0x23,0xb0,0xd8,0x6c,0x36,0x1b,0x0c,0x4c,0xe3,
+0x31,0x98,0xcc,0x66,0x30,0xc1,0xf0,0xc6,0xc6,0x63,0x31,0x98,0xcc,0x66,0x33,0x60,
+0xc0,0x60,0x30,0x18,0x0c,0x00,0xc0,0x60,0x30,0x18,0x63,0x31,0x98,0xcc,0x66,0x33,
+0x19,0x8c,0x10,0x73,0x31,0x98,0xcc,0x66,0x30,0xe1,0x8c,0x38,0x1c,0x7f,0x80,0xa0,
+0x50,0x10,0x24,0x0d,0xff,0x01,0x01,0x02,0x00,0x40,0x80,0xf0,0x24,0x04,0x02,0x01,
+0x81,0x20,0x10,0x30,0x28,0x1a,0x09,0x06,0x8a,0x81,0x20,0x90,0x20,0x08,0x04,0x02,
+0x00,0x0c,0x00,0x04,0x85,0x32,0x6f,0xb8,0x00,0x18,0x06,0x00,0x01,0x01,0xc0,0x00,
+0x70,0x60,0x36,0x06,0x1f,0xcc,0xe0,0x63,0x30,0xd8,0x60,0x63,0x33,0x06,0x03,0x00,
+0x60,0x00,0xc0,0x30,0x60,0x61,0x99,0x86,0x66,0x63,0x01,0x80,0x66,0x63,0x0c,0x03,
+0x0c,0x66,0x04,0x19,0x1c,0xcc,0x60,0x33,0x18,0xcc,0x61,0x81,0xb0,0x60,0xcc,0x63,
+0x0c,0x18,0x06,0x00,0x60,0x30,0x00,0x00,0x00,0x67,0x19,0x86,0x23,0x71,0x88,0x60,
+0x36,0x63,0x06,0x01,0x8c,0x60,0xc6,0xd9,0x8c,0x6c,0x66,0x1b,0x8c,0x08,0x61,0x83,
+0xb8,0x70,0xcc,0x63,0x0c,0x18,0x03,0x00,0xc0,0x60,0x00,0xaa,0x98,0xc0,0x7f,0x5f,
+0xaf,0xef,0xdb,0xf2,0x00,0xfe,0xfe,0xfd,0xff,0xbf,0x7f,0x6f,0xdb,0xfb,0xfd,0xfe,
+0x7e,0xdf,0xef,0xcf,0xd7,0xe5,0xf6,0xf9,0x75,0x7e,0xdf,0x6f,0xdf,0xf7,0xfb,0xfd,
+0x00,0x0c,0x07,0xc6,0x04,0x10,0x60,0x30,0x06,0x00,0x10,0x80,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x3f,0x80,0x00,0x00,0x03,0xb8,0x14,0x00,0x00,0x00,0x00,0x00,0x04,
+0x11,0x21,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x30,0x66,0x30,0x18,0x0c,
+0x06,0x01,0x80,0xc0,0x60,0x30,0x66,0x23,0x99,0x8c,0xc6,0x63,0x31,0x98,0x00,0x66,
+0x1b,0x0d,0x86,0xc3,0x60,0xc1,0x80,0xc6,0xce,0x67,0x33,0x99,0xcc,0xe6,0x73,0x74,
+0x62,0x31,0x18,0x8c,0x46,0x20,0xc0,0x60,0x30,0x18,0x36,0x31,0x8d,0x86,0xc3,0x61,
+0xb0,0xd8,0x10,0x36,0x3b,0x9d,0xce,0xe7,0x70,0xc1,0x98,0x30,0x00,0x7f,0x80,0xc0,
+0x60,0x10,0x24,0x0c,0x38,0x0e,0x01,0x02,0x00,0x40,0x80,0xa0,0x18,0x0e,0x03,0x00,
+0x80,0x40,0x60,0x50,0x30,0x16,0x0e,0x05,0x88,0x81,0xc0,0x81,0xc0,0x70,0x38,0x1c,
+0x00,0x0c,0x00,0x04,0x83,0xe0,0x39,0xcc,0x00,0x0c,0x0c,0x00,0x00,0x01,0xc0,0x00,
+0x70,0xc0,0x1c,0x06,0x1f,0xc7,0xc0,0x61,0xe0,0x70,0x60,0x3e,0x1e,0x06,0x03,0x00,
+0x00,0x00,0x00,0x30,0x1e,0x61,0x9f,0x03,0xc7,0xc3,0xf1,0x80,0x3e,0x63,0x3f,0x1e,
+0x0c,0x67,0xe4,0x19,0x0c,0x78,0x60,0x1e,0x18,0xc7,0xc1,0x80,0xe0,0x60,0xcc,0x63,
+0x0c,0x1f,0xc6,0x00,0x30,0x30,0x00,0x00,0x00,0x3b,0x9f,0x03,0xc1,0xb0,0xf0,0x60,
+0x06,0x63,0x06,0x01,0x8c,0x70,0xc6,0xd9,0x8c,0x38,0x7c,0x0d,0x8c,0x07,0xc0,0xf1,
+0xd8,0x60,0xcc,0x63,0x0c,0x1f,0xc3,0x00,0xc0,0x60,0x01,0x54,0x80,0xc0,0x7f,0x3f,
+0x9f,0xef,0xdb,0xf3,0xc7,0xf1,0xfe,0xfd,0xff,0xbf,0x7f,0xff,0xe7,0xf1,0xfc,0xff,
+0x7f,0xbf,0x9f,0xaf,0xcf,0xe9,0xf1,0xfa,0x77,0x7e,0x3f,0x7e,0x3f,0x8f,0xc7,0xe3,
+0xff,0x0c,0x01,0x0f,0xe8,0x08,0x60,0x30,0xc6,0x00,0x0f,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xd8,0x14,0x00,0x00,0x00,0x00,0x00,0x04,
+0x11,0x3d,0x04,0xc0,0xc3,0x61,0xb0,0xd8,0x6c,0x36,0x1b,0x3c,0x3c,0x3f,0x1f,0x8f,
+0xc7,0xe7,0xe3,0xf1,0xf8,0xfc,0x7c,0x21,0x8f,0x07,0x83,0xc1,0xe0,0xf0,0x00,0xbc,
+0x0e,0x07,0x03,0x81,0xc0,0xc1,0x80,0xcc,0x77,0x3b,0x9d,0xce,0xe7,0x73,0xb9,0x98,
+0x3c,0x1e,0x0f,0x07,0x83,0xc0,0xc0,0x60,0x30,0x18,0x1c,0x31,0x87,0x03,0x81,0xc0,
+0xe0,0x70,0x00,0x5c,0x1d,0x8e,0xc7,0x63,0xb0,0xc1,0xf0,0x30,0x00,0x7f,0x81,0x40,
+0xa0,0x10,0x28,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x90,0x00,0x00,0x02,0x00,
+0x80,0x80,0x10,0xf8,0x28,0x12,0x09,0x04,0x80,0x01,0x20,0x80,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x06,0x18,0x00,0x00,0x00,0x40,0x00,
+0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x07,0xc0,0x31,0xf0,0x01,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0xcc,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x00,0x01,0xe0,0xc3,0xc0,0x00,0x00,0xff,0xc0,0x7e,0xbf,
+0x5f,0xef,0xd7,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfd,0xff,
+0x7f,0x7f,0xef,0x07,0xd7,0xed,0xf6,0xfb,0x7f,0xfe,0xdf,0x7f,0xff,0xff,0xff,0xff,
+0x00,0x0c,0x01,0x00,0x00,0x00,0x00,0x30,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x14,0x00,0x08,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x00,0x7f,0x81,0x20,
+0x90,0x10,0x1c,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,
+0x81,0xe0,0x60,0x10,0x24,0x12,0x0e,0x04,0x80,0x01,0xc0,0x70,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x78,0x00,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x01,0x80,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0xfe,0xdf,
+0x6f,0xef,0xe3,0xf5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x7f,
+0x7e,0x1f,0x9f,0xef,0xdb,0xed,0xf1,0xfb,0x7f,0xfe,0x3f,0x8f,0xff,0xff,0xff,0xff,
+0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x81,0x80,0x60,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x32,0x35,0x36,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x31,0x35,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x31,0x33,0x20,
+0x00,0x00,0x01,0x0c,0x00,0x09,0x09,0x00,0x01,0x0f,0x00,0x09,0x12,0x00,0x01,0x0f,
+0x00,0x09,0x1b,0x00,0x01,0x0f,0x00,0x09,0x24,0x00,0x01,0x0f,0x00,0x09,0x2d,0x00,
+0x01,0x0f,0x00,0x09,0x36,0x00,0x01,0x0f,0x00,0x09,0x3f,0x00,0x03,0x0d,0x00,0x09,
+0x48,0x00,0x03,0x0d,0x00,0x09,0x51,0x00,0x03,0x0d,0x00,0x09,0x5a,0x00,0x03,0x0d,
+0x00,0x09,0x63,0x00,0x03,0x0d,0x00,0x09,0x6c,0x00,0x03,0x0d,0x00,0x09,0x75,0x00,
+0x03,0x0e,0x00,0x09,0x7e,0x00,0x03,0x0d,0x00,0x09,0x87,0x00,0x03,0x0d,0x00,0x09,
+0x90,0x00,0x01,0x0f,0x00,0x09,0x99,0x00,0x01,0x0f,0x00,0x09,0xa2,0x00,0x01,0x0f,
+0x00,0x09,0xab,0x00,0x01,0x0f,0x00,0x09,0xb4,0x00,0x01,0x0f,0x00,0x09,0xbd,0x00,
+0x01,0x0f,0x00,0x09,0xc6,0x00,0x01,0x0f,0x00,0x09,0xcf,0x00,0x01,0x0f,0x00,0x09,
+0xd8,0x00,0x01,0x0f,0x00,0x09,0xe1,0x00,0x03,0x0d,0x00,0x09,0xea,0x00,0x01,0x0f,
+0x00,0x09,0xf3,0x00,0x01,0x0f,0x00,0x09,0xfc,0x00,0x03,0x0d,0x00,0x09,0x05,0x01,
+0x03,0x0d,0x00,0x09,0x0e,0x01,0x03,0x0d,0x00,0x09,0x17,0x01,0x03,0x0d,0x00,0x09,
+0x20,0x01,0x00,0x00,0x00,0x09,0x29,0x01,0x03,0x0d,0x00,0x09,0x32,0x01,0x02,0x05,
+0x00,0x09,0x3b,0x01,0x03,0x0d,0x00,0x09,0x44,0x01,0x02,0x0e,0x00,0x09,0x4d,0x01,
+0x03,0x0d,0x00,0x09,0x56,0x01,0x03,0x0d,0x00,0x09,0x5f,0x01,0x02,0x06,0x00,0x09,
+0x68,0x01,0x02,0x0e,0x00,0x09,0x71,0x01,0x02,0x0e,0x00,0x09,0x7a,0x01,0x03,0x08,
+0x00,0x09,0x83,0x01,0x05,0x0c,0x00,0x09,0x8c,0x01,0x0b,0x0f,0x00,0x09,0x95,0x01,
+0x08,0x09,0x00,0x09,0x9e,0x01,0x0b,0x0d,0x00,0x09,0xa7,0x01,0x02,0x0e,0x00,0x09,
+0xb0,0x01,0x03,0x0d,0x00,0x09,0xb9,0x01,0x03,0x0d,0x00,0x09,0xc2,0x01,0x03,0x0d,
+0x00,0x09,0xcb,0x01,0x03,0x0d,0x00,0x09,0xd4,0x01,0x03,0x0d,0x00,0x09,0xdd,0x01,
+0x03,0x0d,0x00,0x09,0xe6,0x01,0x03,0x0d,0x00,0x09,0xef,0x01,0x03,0x0d,0x00,0x09,
+0xf8,0x01,0x03,0x0d,0x00,0x09,0x01,0x02,0x03,0x0d,0x00,0x09,0x0a,0x02,0x06,0x0d,
+0x00,0x09,0x13,0x02,0x06,0x0f,0x00,0x09,0x1c,0x02,0x05,0x0c,0x00,0x09,0x25,0x02,
+0x07,0x0a,0x00,0x09,0x2e,0x02,0x05,0x0c,0x00,0x09,0x37,0x02,0x03,0x0d,0x00,0x09,
+0x40,0x02,0x03,0x0d,0x00,0x09,0x49,0x02,0x03,0x0d,0x00,0x09,0x52,0x02,0x03,0x0d,
+0x00,0x09,0x5b,0x02,0x03,0x0d,0x00,0x09,0x64,0x02,0x03,0x0d,0x00,0x09,0x6d,0x02,
+0x03,0x0d,0x00,0x09,0x76,0x02,0x03,0x0d,0x00,0x09,0x7f,0x02,0x03,0x0d,0x00,0x09,
+0x88,0x02,0x03,0x0d,0x00,0x09,0x91,0x02,0x03,0x0d,0x00,0x09,0x9a,0x02,0x03,0x0d,
+0x00,0x09,0xa3,0x02,0x03,0x0d,0x00,0x09,0xac,0x02,0x03,0x0d,0x00,0x09,0xb5,0x02,
+0x03,0x0d,0x00,0x09,0xbe,0x02,0x03,0x0d,0x00,0x09,0xc7,0x02,0x03,0x0d,0x00,0x09,
+0xd0,0x02,0x03,0x0d,0x00,0x09,0xd9,0x02,0x03,0x0f,0x00,0x09,0xe2,0x02,0x03,0x0d,
+0x00,0x09,0xeb,0x02,0x03,0x0d,0x00,0x09,0xf4,0x02,0x03,0x0d,0x00,0x09,0xfd,0x02,
+0x03,0x0d,0x00,0x09,0x06,0x03,0x03,0x0d,0x00,0x09,0x0f,0x03,0x03,0x0d,0x00,0x09,
+0x18,0x03,0x03,0x0d,0x00,0x09,0x21,0x03,0x03,0x0d,0x00,0x09,0x2a,0x03,0x03,0x0d,
+0x00,0x09,0x33,0x03,0x02,0x0e,0x00,0x09,0x3c,0x03,0x02,0x0e,0x00,0x09,0x45,0x03,
+0x02,0x0e,0x00,0x09,0x4e,0x03,0x04,0x0b,0x00,0x09,0x57,0x03,0x0d,0x0e,0x00,0x09,
+0x60,0x03,0x02,0x06,0x00,0x09,0x69,0x03,0x05,0x0d,0x00,0x09,0x72,0x03,0x02,0x0d,
+0x00,0x09,0x7b,0x03,0x05,0x0d,0x00,0x09,0x84,0x03,0x02,0x0d,0x00,0x09,0x8d,0x03,
+0x05,0x0d,0x00,0x09,0x96,0x03,0x02,0x0d,0x00,0x09,0x9f,0x03,0x05,0x0f,0x00,0x09,
+0xa8,0x03,0x02,0x0d,0x00,0x09,0xb1,0x03,0x02,0x0d,0x00,0x09,0xba,0x03,0x02,0x0f,
+0x00,0x09,0xc3,0x03,0x02,0x0d,0x00,0x09,0xcc,0x03,0x02,0x0d,0x00,0x09,0xd5,0x03,
+0x05,0x0d,0x00,0x09,0xde,0x03,0x05,0x0d,0x00,0x09,0xe7,0x03,0x05,0x0d,0x00,0x09,
+0xf0,0x03,0x05,0x0f,0x00,0x09,0xf9,0x03,0x05,0x0f,0x00,0x09,0x02,0x04,0x05,0x0d,
+0x00,0x09,0x0b,0x04,0x05,0x0d,0x00,0x09,0x14,0x04,0x03,0x0d,0x00,0x09,0x1d,0x04,
+0x05,0x0d,0x00,0x09,0x26,0x04,0x05,0x0d,0x00,0x09,0x2f,0x04,0x05,0x0d,0x00,0x09,
+0x38,0x04,0x05,0x0d,0x00,0x09,0x41,0x04,0x05,0x0f,0x00,0x09,0x4a,0x04,0x05,0x0d,
+0x00,0x09,0x53,0x04,0x02,0x0e,0x00,0x09,0x5c,0x04,0x02,0x0e,0x00,0x09,0x65,0x04,
+0x02,0x0e,0x00,0x09,0x6e,0x04,0x07,0x0a,0x00,0x09,0x77,0x04,0x01,0x0d,0x00,0x09,
+0x80,0x04,0x00,0x0e,0x00,0x09,0x89,0x04,0x00,0x0f,0x00,0x09,0x92,0x04,0x00,0x0f,
+0x00,0x09,0x9b,0x04,0x00,0x0f,0x00,0x09,0xa4,0x04,0x00,0x0f,0x00,0x09,0xad,0x04,
+0x00,0x0f,0x00,0x09,0xb6,0x04,0x00,0x0f,0x00,0x09,0xbf,0x04,0x00,0x0f,0x00,0x09,
+0xc8,0x04,0x00,0x0f,0x00,0x09,0xd1,0x04,0x00,0x0f,0x00,0x09,0xda,0x04,0x00,0x0f,
+0x00,0x09,0xe3,0x04,0x00,0x0f,0x00,0x09,0xec,0x04,0x00,0x0f,0x00,0x09,0xf5,0x04,
+0x00,0x0f,0x00,0x09,0xfe,0x04,0x00,0x0f,0x00,0x09,0x07,0x05,0x00,0x0f,0x00,0x09,
+0x10,0x05,0x00,0x0f,0x00,0x09,0x19,0x05,0x00,0x0f,0x00,0x09,0x22,0x05,0x00,0x0f,
+0x00,0x09,0x2b,0x05,0x00,0x0f,0x00,0x09,0x34,0x05,0x00,0x0f,0x00,0x09,0x3d,0x05,
+0x00,0x0f,0x00,0x09,0x46,0x05,0x00,0x0f,0x00,0x09,0x4f,0x05,0x00,0x0f,0x00,0x09,
+0x58,0x05,0x00,0x0f,0x00,0x09,0x61,0x05,0x00,0x0f,0x00,0x09,0x6a,0x05,0x00,0x0f,
+0x00,0x09,0x73,0x05,0x00,0x0f,0x00,0x09,0x7c,0x05,0x00,0x0f,0x00,0x09,0x85,0x05,
+0x00,0x0f,0x00,0x09,0x8e,0x05,0x00,0x0f,0x00,0x09,0x97,0x05,0x00,0x0f,0x00,0x09,
+0xa0,0x05,0x00,0x0d,0x00,0x09,0xa9,0x05,0x05,0x0f,0x00,0x09,0xb2,0x05,0x02,0x0e,
+0x00,0x09,0xbb,0x05,0x03,0x0d,0x00,0x09,0xc4,0x05,0x03,0x0d,0x00,0x09,0xcd,0x05,
+0x03,0x0d,0x00,0x09,0xd6,0x05,0x02,0x0e,0x00,0x09,0xdf,0x05,0x03,0x0e,0x00,0x09,
+0xe8,0x05,0x02,0x04,0x00,0x09,0xf1,0x05,0x03,0x0d,0x00,0x09,0xfa,0x05,0x03,0x0a,
+0x00,0x09,0x03,0x06,0x06,0x0b,0x00,0x09,0x0c,0x06,0x07,0x0a,0x00,0x09,0x15,0x06,
+0x08,0x09,0x00,0x09,0x1e,0x06,0x03,0x0b,0x00,0x09,0x27,0x06,0x02,0x03,0x00,0x09,
+0x30,0x06,0x03,0x07,0x00,0x09,0x39,0x06,0x05,0x0c,0x00,0x09,0x42,0x06,0x03,0x0a,
+0x00,0x09,0x4b,0x06,0x03,0x0a,0x00,0x09,0x54,0x06,0x02,0x04,0x00,0x09,0x5d,0x06,
+0x05,0x0f,0x00,0x09,0x66,0x06,0x03,0x0e,0x00,0x09,0x6f,0x06,0x08,0x0a,0x00,0x09,
+0x78,0x06,0x0d,0x0f,0x00,0x09,0x81,0x06,0x03,0x0a,0x00,0x09,0x8a,0x06,0x03,0x0a,
+0x00,0x09,0x93,0x06,0x06,0x0b,0x00,0x09,0x9c,0x06,0x03,0x0d,0x00,0x09,0xa5,0x06,
+0x03,0x0d,0x00,0x09,0xae,0x06,0x03,0x0d,0x00,0x09,0xb7,0x06,0x05,0x0f,0x00,0x09,
+0xc0,0x06,0x00,0x0d,0x00,0x09,0xc9,0x06,0x00,0x0d,0x00,0x09,0xd2,0x06,0x00,0x0d,
+0x00,0x09,0xdb,0x06,0x00,0x0d,0x00,0x09,0xe4,0x06,0x00,0x0d,0x00,0x09,0xed,0x06,
+0x01,0x0d,0x00,0x09,0xf6,0x06,0x03,0x0d,0x00,0x09,0xff,0x06,0x03,0x0f,0x00,0x09,
+0x08,0x07,0x00,0x0d,0x00,0x09,0x11,0x07,0x00,0x0d,0x00,0x09,0x1a,0x07,0x00,0x0d,
+0x00,0x09,0x23,0x07,0x00,0x0d,0x00,0x09,0x2c,0x07,0x00,0x0d,0x00,0x09,0x35,0x07,
+0x00,0x0d,0x00,0x09,0x3e,0x07,0x00,0x0d,0x00,0x09,0x47,0x07,0x00,0x0d,0x00,0x09,
+0x50,0x07,0x03,0x0d,0x00,0x09,0x59,0x07,0x00,0x0d,0x00,0x09,0x62,0x07,0x00,0x0d,
+0x00,0x09,0x6b,0x07,0x00,0x0d,0x00,0x09,0x74,0x07,0x00,0x0d,0x00,0x09,0x7d,0x07,
+0x00,0x0d,0x00,0x09,0x86,0x07,0x00,0x0d,0x00,0x09,0x8f,0x07,0x06,0x0b,0x00,0x09,
+0x98,0x07,0x03,0x0d,0x00,0x09,0xa1,0x07,0x00,0x0d,0x00,0x09,0xaa,0x07,0x00,0x0d,
+0x00,0x09,0xb3,0x07,0x00,0x0d,0x00,0x09,0xbc,0x07,0x00,0x0d,0x00,0x09,0xc5,0x07,
+0x00,0x0d,0x00,0x09,0xce,0x07,0x03,0x0d,0x00,0x09,0xd7,0x07,0x02,0x0d,0x00,0x09,
+0xe0,0x07,0x02,0x0d,0x00,0x09,0xe9,0x07,0x02,0x0d,0x00,0x09,0xf2,0x07,0x02,0x0d,
+0x00,0x09,0xfb,0x07,0x02,0x0d,0x00,0x09,0x04,0x08,0x02,0x0d,0x00,0x09,0x0d,0x08,
+0x02,0x0d,0x00,0x09,0x16,0x08,0x05,0x0d,0x00,0x09,0x1f,0x08,0x05,0x0f,0x00,0x09,
+0x28,0x08,0x02,0x0d,0x00,0x09,0x31,0x08,0x02,0x0d,0x00,0x09,0x3a,0x08,0x02,0x0d,
+0x00,0x09,0x43,0x08,0x02,0x0d,0x00,0x09,0x4c,0x08,0x02,0x0d,0x00,0x09,0x55,0x08,
+0x02,0x0d,0x00,0x09,0x5e,0x08,0x02,0x0d,0x00,0x09,0x67,0x08,0x02,0x0d,0x00,0x09,
+0x70,0x08,0x02,0x0d,0x00,0x09,0x79,0x08,0x02,0x0d,0x00,0x09,0x82,0x08,0x02,0x0d,
+0x00,0x09,0x8b,0x08,0x02,0x0d,0x00,0x09,0x94,0x08,0x02,0x0d,0x00,0x09,0x9d,0x08,
+0x02,0x0d,0x00,0x09,0xa6,0x08,0x02,0x0d,0x00,0x09,0xaf,0x08,0x05,0x0c,0x00,0x09,
+0xb8,0x08,0x05,0x0d,0x00,0x09,0xc1,0x08,0x02,0x0d,0x00,0x09,0xca,0x08,0x02,0x0d,
+0x00,0x09,0xd3,0x08,0x02,0x0d,0x00,0x09,0xdc,0x08,0x02,0x0d,0x00,0x09,0xe5,0x08,
+0x02,0x0f,0x00,0x09,0xee,0x08,0x03,0x0f,0x00,0x09,0xf7,0x08,0x02,0x0f,0x00,0x09,
+0x00,0x09,0x00,0x00,0x00,0x00,
+};
+
+int	sizeofdefont = sizeof defontdata;
+
+void
+_unpackinfo(Fontchar *fc, uchar *p, int n)
+{
+	int j;
+
+	for(j=0;  j<=n;  j++){
+		fc->x = p[0]|(p[1]<<8);
+		fc->top = p[2];
+		fc->bottom = p[3];
+		fc->left = p[4];
+		fc->width = p[5];
+		fc++;
+		p += 6;
+	}
+}
--- /dev/null
+++ b/libdraw/draw.c
@@ -1,0 +1,68 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+_setdrawop(Display *d, Drawop op)
+{
+	uchar *a;
+
+	if(op != SoverD){
+		a = bufimage(d, 1+1);
+		if(a == 0)
+			return;
+		a[0] = 'O';
+		a[1] = op;
+	}
+}
+		
+static void
+draw1(Image *dst, Rectangle *r, Image *src, Point *p0, Image *mask, Point *p1, Drawop op)
+{
+	uchar *a;
+
+	_setdrawop(dst->display, op);
+
+	a = bufimage(dst->display, 1+4+4+4+4*4+2*4+2*4);
+	if(a == 0)
+		return;
+	if(src == nil)
+		src = dst->display->black;
+	if(mask == nil)
+		mask = dst->display->opaque;
+	a[0] = 'd';
+	BPLONG(a+1, dst->id);
+	BPLONG(a+5, src->id);
+	BPLONG(a+9, mask->id);
+	BPLONG(a+13, r->min.x);
+	BPLONG(a+17, r->min.y);
+	BPLONG(a+21, r->max.x);
+	BPLONG(a+25, r->max.y);
+	BPLONG(a+29, p0->x);
+	BPLONG(a+33, p0->y);
+	BPLONG(a+37, p1->x);
+	BPLONG(a+41, p1->y);
+}
+
+void
+draw(Image *dst, Rectangle r, Image *src, Image *mask, Point p1)
+{
+	draw1(dst, &r, src, &p1, mask, &p1, SoverD);
+}
+
+void
+drawop(Image *dst, Rectangle r, Image *src, Image *mask, Point p1, Drawop op)
+{
+	draw1(dst, &r, src, &p1, mask, &p1, op);
+}
+
+void
+gendraw(Image *dst, Rectangle r, Image *src, Point p0, Image *mask, Point p1)
+{
+	draw1(dst, &r, src, &p0, mask, &p1, SoverD);
+}
+
+void
+gendrawop(Image *dst, Rectangle r, Image *src, Point p0, Image *mask, Point p1, Drawop op)
+{
+	draw1(dst, &r, src, &p0, mask, &p1, op);
+}
--- /dev/null
+++ b/libdraw/drawrepl.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include "draw.h"
+
+int
+drawreplxy(int min, int max, int x)
+{
+	int sx;
+
+	sx = (x-min)%(max-min);
+	if(sx < 0)
+		sx += max-min;
+	return sx+min;
+}
+
+Point
+drawrepl(Rectangle r, Point p)
+{
+	p.x = drawreplxy(r.min.x, r.max.x, p.x);
+	p.y = drawreplxy(r.min.y, r.max.y, p.y);
+	return p;
+}
+
--- /dev/null
+++ b/libdraw/ellipse.c
@@ -1,0 +1,81 @@
+#include "lib9.h"
+#include "draw.h"
+
+static
+void
+doellipse(int cmd, Image *dst, Point *c, int xr, int yr, int thick, Image *src, Point *sp, int alpha, int phi, Drawop op)
+{
+	uchar *a;
+
+	_setdrawop(dst->display, op);
+
+	a = bufimage(dst->display, 1+4+4+2*4+4+4+4+2*4+2*4);
+	if(a == 0){
+		_drawprint(2, "image ellipse: %r\n");
+		return;
+	}
+	a[0] = cmd;
+	BPLONG(a+1, dst->id);
+	BPLONG(a+5, src->id);
+	BPLONG(a+9, c->x);
+	BPLONG(a+13, c->y);
+	BPLONG(a+17, xr);
+	BPLONG(a+21, yr);
+	BPLONG(a+25, thick);
+	BPLONG(a+29, sp->x);
+	BPLONG(a+33, sp->y);
+	BPLONG(a+37, alpha);
+	BPLONG(a+41, phi);
+}
+
+void
+ellipse(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp)
+{
+	doellipse('e', dst, &c, a, b, thick, src, &sp, 0, 0, SoverD);
+}
+
+void
+ellipseop(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, Drawop op)
+{
+	doellipse('e', dst, &c, a, b, thick, src, &sp, 0, 0, op);
+}
+
+void
+fillellipse(Image *dst, Point c, int a, int b, Image *src, Point sp)
+{
+	doellipse('E', dst, &c, a, b, 0, src, &sp, 0, 0, SoverD);
+}
+
+void
+fillellipseop(Image *dst, Point c, int a, int b, Image *src, Point sp, Drawop op)
+{
+	doellipse('E', dst, &c, a, b, 0, src, &sp, 0, 0, op);
+}
+
+void
+arc(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, int alpha, int phi)
+{
+	alpha |= 1<<31;
+	doellipse('e', dst, &c, a, b, thick, src, &sp, alpha, phi, SoverD);
+}
+
+void
+arcop(Image *dst, Point c, int a, int b, int thick, Image *src, Point sp, int alpha, int phi, Drawop op)
+{
+	alpha |= 1<<31;
+	doellipse('e', dst, &c, a, b, thick, src, &sp, alpha, phi, op);
+}
+
+void
+fillarc(Image *dst, Point c, int a, int b, Image *src, Point sp, int alpha, int phi)
+{
+	alpha |= 1<<31;
+	doellipse('E', dst, &c, a, b, 0, src, &sp, alpha, phi, SoverD);
+}
+
+void
+fillarcop(Image *dst, Point c, int a, int b, Image *src, Point sp, int alpha, int phi, Drawop op)
+{
+	alpha |= 1<<31;
+	doellipse('E', dst, &c, a, b, 0, src, &sp, alpha, phi, op);
+}
--- /dev/null
+++ b/libdraw/font.c
@@ -1,0 +1,398 @@
+#include "lib9.h"
+#include "draw.h"
+
+static int	fontresize(Font*, int, int, int);
+static int	freeup(Font*);
+
+#define	PJW	0	/* use NUL==pjw for invisible characters */
+
+int
+cachechars(Font *f, char **ss, Rune **rr, ushort *cp, int max, int *wp, char **subfontname)
+{
+	int i, th, sh, h, ld, w, rw, wid, nc;
+	char *sp;
+	Rune r, *rp, vr;
+	ulong a;
+	Cacheinfo *c, *tc, *ec;
+
+	if(ss){
+		sp = *ss;
+		rp = (Rune*) L"";
+	}else{
+		sp = "";
+		rp = *rr;
+	}
+	wid = 0;
+	*subfontname = 0;
+	for(i=0; (*sp || *rp) && i<max; sp+=w, rp+=rw){
+		if(ss){
+			r = *(uchar*)sp;
+			if(r < Runeself)
+				w = 1;
+			else{
+				w = chartorune(&vr, sp);
+				r = vr;
+			}
+			rw = 0;
+		}else{
+			r = *rp;
+			w = 0;
+			rw = 1;
+		}
+
+		sh = (17 * (uint)r) & (f->ncache-NFLOOK-1);
+		c = &f->cache[sh];
+		ec = c+NFLOOK;
+		h = sh;
+		while(c < ec){
+			if(c->value==r && c->age)
+				goto Found;
+			c++;
+			h++;
+		}
+	
+		/*
+		 * Not found; toss out oldest entry
+		 */
+		a = ~0;
+		th = sh;
+		tc = &f->cache[th];
+		while(tc < ec){
+			if(tc->age < a){
+				a = tc->age;
+				h = th;
+				c = tc;
+			}
+			tc++;
+			th++;
+		}
+
+		if(a && (f->age-a)<500){	/* kicking out too recent; resize */
+			nc = 2*(f->ncache-NFLOOK) + NFLOOK;
+			if(nc <= MAXFCACHE){
+				if(i == 0)
+					fontresize(f, f->width, nc, f->maxdepth);
+				/* else flush first; retry will resize */
+				break;
+			}
+		}
+
+		if(c->age == f->age)	/* flush pending string output */
+			break;
+
+		ld = loadchar(f, r, c, h, i, subfontname);
+		if(ld <= 0){
+			if(ld == 0)
+				continue;
+			break;
+		}
+		c = &f->cache[h];	/* may have reallocated f->cache */
+	
+	    Found:
+		wid += c->width;
+		c->age = f->age;
+		cp[i] = h;
+		i++;
+	}
+	if(ss)
+		*ss = sp;
+	else
+		*rr = rp;
+	*wp = wid;
+	return i;
+}
+
+void
+agefont(Font *f)
+{
+	Cacheinfo *c, *ec;
+	Cachesubf *s, *es;
+
+	f->age++;
+	if(f->age == 65536){
+		/*
+		 * Renormalize ages
+		 */
+		c = f->cache;
+		ec = c+f->ncache;
+		while(c < ec){
+			if(c->age){
+				c->age >>= 2;
+				c->age++;
+			}
+			c++;
+		}
+		s = f->subf;
+		es = s+f->nsubf;
+		while(s < es){
+			if(s->age){
+				if(s->age<SUBFAGE && s->cf->name != nil){
+					/* clean up */
+/*					if(s->f != display->defaultsubfont) */	/* plan 9 uses this */
+					if(s->f)
+						freesubfont(s->f);
+					s->cf = nil;
+					s->f = nil;
+					s->age = 0;
+				}else{
+					s->age >>= 2;
+					s->age++;
+				}
+			}
+			s++;
+		}
+		f->age = (65536>>2) + 1;
+	}
+}
+
+static Subfont*
+cf2subfont(Cachefont *cf, Font *f)
+{
+	char *name;
+	Subfont *sf;
+	int depth;
+
+	name = cf->subfontname;
+	if(name == nil){
+		depth = 0;
+		if(f->display){
+			if(f->display->image)
+				depth = f->display->image->depth;
+		}
+		name = subfontname(cf->name, f->name, depth);
+		if(name == nil)
+			return nil;
+		cf->subfontname = name;
+	}
+	sf = lookupsubfont(f->display, name);
+	return sf;
+}
+
+/* return 1 if load succeeded, 0 if failed, -1 if must retry */
+int
+loadchar(Font *f, Rune r, Cacheinfo *c, int h, int noflush, char **subfontname)
+{
+	int i, oi, wid, top, bottom;
+	Rune pic;
+	Fontchar *fi;
+	Cachefont *cf;
+	Cachesubf *subf, *of;
+	uchar *b;
+
+	pic = r;
+    Again:
+	for(i=0; i<f->nsub; i++){
+		cf = f->sub[i];
+		if(cf->min<=pic && pic<=cf->max)
+			goto Found;
+	}
+    TryPJW:
+	if(pic != PJW){
+		pic = PJW;
+		goto Again;
+	}
+	return 0;
+
+    Found:
+	/*
+	 * Choose exact or oldest
+	 */
+	oi = 0;
+	subf = &f->subf[0];
+	for(i=0; i<f->nsubf; i++){
+		if(cf == subf->cf)
+			goto Found2;
+		if(subf->age < f->subf[oi].age)
+			oi = i;
+		subf++;
+	}
+	subf = &f->subf[oi];
+
+	if(subf->f){
+		if(f->age-subf->age>SUBFAGE || f->nsubf>MAXSUBF){
+    Toss:
+			/* ancient data; toss */
+			freesubfont(subf->f);
+			subf->cf = nil;
+			subf->f = nil;
+			subf->age = 0;
+		}else{				/* too recent; grow instead */
+			of = f->subf;
+			f->subf = malloc((f->nsubf+DSUBF)*sizeof *subf);
+			if(f->subf == nil){
+				f->subf = of;
+				goto Toss;
+			}
+			memmove(f->subf, of, (f->nsubf+DSUBF)*sizeof *subf);
+			memset(f->subf+f->nsubf, 0, DSUBF*sizeof *subf);
+			subf = &f->subf[f->nsubf];
+			f->nsubf += DSUBF;
+			free(of);
+		}
+	}
+	subf->age = 0;
+	subf->cf = nil;
+	subf->f = cf2subfont(cf, f);
+	if(subf->f == nil){
+		if(cf->subfontname == nil)
+			goto TryPJW;
+		*subfontname = cf->subfontname;
+		return -1;
+	}
+
+	subf->cf = cf;
+	if(subf->f->ascent > f->ascent){
+		/* should print something? this is a mistake in the font file */
+		/* must prevent c->top from going negative when loading cache */
+		Image *b;
+		int d, t;
+		d = subf->f->ascent - f->ascent;
+		b = subf->f->bits;
+		draw(b, b->r, b, nil, addpt(b->r.min, Pt(0, d)));
+		draw(b, Rect(b->r.min.x, b->r.max.y-d, b->r.max.x, b->r.max.y), f->display->black, nil, b->r.min);
+		for(i=0; i<subf->f->n; i++){
+			t = subf->f->info[i].top-d;
+			if(t < 0)
+				t = 0;
+			subf->f->info[i].top = t;
+			t = subf->f->info[i].bottom-d;
+			if(t < 0)
+				t = 0;
+			subf->f->info[i].bottom = t;
+		}
+		subf->f->ascent = f->ascent;
+	}
+
+    Found2:
+	subf->age = f->age;
+
+	pic += cf->offset;
+	if(pic-cf->min >= subf->f->n)
+		goto TryPJW;
+	fi = &subf->f->info[pic - cf->min];
+	if(fi->width == 0)
+		goto TryPJW;
+	wid = (fi+1)->x - fi->x;
+	if(f->width < wid || f->width == 0 || f->maxdepth < subf->f->bits->depth){
+		/*
+		 * Flush, free, reload (easier than reformatting f->b)
+		 */
+		if(noflush)
+			return -1;
+		if(f->width < wid)
+			f->width = wid;
+		if(f->maxdepth < subf->f->bits->depth)
+			f->maxdepth = subf->f->bits->depth;
+		i = fontresize(f, f->width, f->ncache, f->maxdepth);
+		if(i <= 0)
+			return i;
+		/* c is still valid as didn't reallocate f->cache */
+	}
+	c->value = r;
+	top = fi->top + (f->ascent-subf->f->ascent);
+	bottom = fi->bottom + (f->ascent-subf->f->ascent);
+	c->width = fi->width;
+	c->x = h*f->width;
+	c->left = fi->left;
+	flushimage(f->display, 0);	/* flush any pending errors */
+	if (f->cacheimage == 0)
+		return 0;
+	b = bufimage(f->display, 37);
+	if(b == 0)
+		return 0;
+	b[0] = 'l';
+	BPLONG(b+1, f->cacheimage->id);
+	BPLONG(b+5, subf->f->bits->id);
+	BPSHORT(b+9, c-f->cache);
+	BPLONG(b+11, c->x);
+	BPLONG(b+15, top);
+	BPLONG(b+19, c->x+((fi+1)->x-fi->x));
+	BPLONG(b+23, bottom);
+	BPLONG(b+27, fi->x);
+	BPLONG(b+31, fi->top);
+	b[35] = fi->left;
+	b[36] = fi->width;
+	return 1;
+}
+
+/* release all subfonts, return number freed */
+static
+int
+freeup(Font *f)
+{
+	Cachesubf *s, *es;
+	int nf;
+
+	if(f->sub[0]->name == nil)	/* font from mkfont; don't free */
+		return 0;
+	s = f->subf;
+	es = s+f->nsubf;
+	nf = 0;
+	while(s < es){
+		if(s->age){
+			freesubfont(s->f);
+			s->cf = nil;
+			s->f = nil;
+			s->age = 0;
+			nf++;
+		}
+		s++;
+	}
+	return nf;
+}
+
+/* return whether resize succeeded && f->cache is unchanged */
+static int
+fontresize(Font *f, int wid, int ncache, int depth)
+{
+	Cacheinfo *i;
+	int ret;
+	Image *new;
+	uchar *b;
+	Display *d;
+
+	ret = 0;
+	d = f->display;
+	if(depth <= 0)
+		depth = 1;
+
+	new = allocimage(d, Rect(0, 0, ncache*wid, f->height), CHAN1(CGrey, depth), 0, 0);
+	if(new == nil){
+		_drawprint(2, "font cache resize failed: %r\n");
+/*		abort(); */
+		goto Return;
+	}
+	flushimage(d, 0);	/* flush any pending errors */
+	b = bufimage(d, 1+4+4+1);
+	if(b == 0){
+		freeimage(new);
+		goto Return;
+	}
+	b[0] = 'i';
+	BPLONG(b+1, new->id);
+	BPLONG(b+5, ncache);
+	b[9] = f->ascent;
+	if(flushimage(d, 0) < 0){
+		_drawprint(2, "resize: init failed: %r\n");
+		freeimage(new);
+		goto Return;
+	}
+	freeimage(f->cacheimage);
+	f->cacheimage = new;
+	f->width = wid;
+	f->maxdepth = depth;
+	ret = 1;
+	if(f->ncache != ncache){
+		i = malloc(ncache*sizeof f->cache[0]);
+		if(i != nil){
+			ret = 0;
+			free(f->cache);
+			f->ncache = ncache;
+			f->cache = i;
+		}
+		/* else just wipe the cache clean and things will be ok */
+	}
+    Return:
+	memset(f->cache, 0, f->ncache*sizeof f->cache[0]);
+	return ret;
+}
--- /dev/null
+++ b/libdraw/freesubfont.c
@@ -1,0 +1,16 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+freesubfont(Subfont *f)
+{
+	if(f == 0)
+		return;
+	f->ref--;
+	if(f->ref > 0)
+		return;
+	uninstallsubfont(f);
+	free(f->info);	/* note: f->info must have been malloc'ed! */
+	freeimage(f->bits);
+	free(f);
+}
--- /dev/null
+++ b/libdraw/getdefont.c
@@ -1,0 +1,59 @@
+#include "lib9.h"
+#include "draw.h"
+
+Subfont*
+getdefont(Display *d)
+{
+	char *hdr, *p;
+	int n;
+	Fontchar *fc;
+	Subfont *f;
+	int ld;
+	Rectangle r;
+	Image *i;
+
+	/*
+	 * make sure data is word-aligned.  this is true with Plan 9 compilers
+	 * but not in general.  the byte order is right because the data is
+	 * declared as char*, not ulong*.
+	 */
+	p = (char*)defontdata;
+	n = (ulong)p & 3;
+	if(n != 0){
+		memmove(p+(4-n), p, sizeofdefont-n);
+		p += 4-n;
+	}
+	ld = atoi(p+0*12);
+	r.min.x = atoi(p+1*12);
+	r.min.y = atoi(p+2*12);
+	r.max.x = atoi(p+3*12);
+	r.max.y = atoi(p+4*12);
+
+	i = allocimage(d, r, drawld2chan[ld], 0, 0);
+	if(i == 0)
+		return 0;
+
+	p += 5*12;
+	n = loadimage(i, r, (uchar*)p, (defontdata+sizeofdefont)-(uchar*)p);
+	if(n < 0){
+		freeimage(i);
+		return 0;
+	}
+
+	hdr = p+n;
+	n = atoi(hdr);
+	p = hdr+3*12;
+	fc = malloc(sizeof(Fontchar)*(n+1));
+	if(fc == 0){
+		freeimage(i);
+		return 0;
+	}
+	_unpackinfo(fc, (uchar*)p, n);
+	f = allocsubfont("*default*", n, atoi(hdr+12), atoi(hdr+24), fc, i);
+	if(f == 0){
+		freeimage(i);
+		free(fc);
+		return 0;
+	}
+	return f;
+}
--- /dev/null
+++ b/libdraw/getsubfont.c
@@ -1,0 +1,36 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+/*
+ * Default version: treat as file name
+ */
+
+Subfont*
+_getsubfont(Display *d, char *name)
+{
+	int fd;
+	Subfont *f;
+
+	fd = libopen(name, OREAD);
+		
+	if(fd < 0){
+		_drawprint(2, "getsubfont: can't open %s: %r\n", name);
+		return 0;
+	}
+	/*
+	 * unlock display so i/o happens with display released, unless
+	 * user is doing his own locking, in which case this could break things.
+	 * _getsubfont is called only from string.c and stringwidth.c,
+	 * which are known to be safe to have this done.
+	 */
+	if(d->local == 0)
+		unlockdisplay(d);
+	f = readsubfont(d, name, fd, d->local == 0);
+	if(d->local == 0)
+		lockdisplay(d);
+	if(f == 0)
+		_drawprint(2, "getsubfont: can't read %s: %r\n", name);
+	libclose(fd);
+	return f;
+}
--- /dev/null
+++ b/libdraw/init.c
@@ -1,0 +1,341 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+#include "interp.h"
+
+int	_drawdebug;
+
+enum {
+	CHECKLOCKING = 0
+};
+
+/*
+ * Attach, or possibly reattach, to window.
+ * If reattaching, maintain value of screen pointer.
+ */
+int
+gengetwindow(Display *d, char *winname, Image **winp, Screen **scrp, int ref)
+{
+	int n, fd;
+	char buf[64+1];
+	Image *image;
+
+	fd = libopen(winname, OREAD);
+	if(fd<0 || (n=libread(fd, buf, sizeof buf-1))<=0){
+		*winp = d->image;
+		assert(*winp && (*winp)->chan != 0);
+		return 1;
+	}
+	libclose(fd);
+	buf[n] = '\0';
+	if(*winp != nil){
+		_freeimage1(*winp);
+		freeimage((*scrp)->image);
+		freescreen(*scrp);
+		*scrp = nil;
+	}
+	image = namedimage(d, buf);
+	if(image == 0){
+		*winp = nil;
+		return -1;
+	}
+	assert(image->chan != 0);
+
+	*scrp = allocscreen(image, d->white, 0);
+	if(*scrp == nil){
+		*winp = nil;
+		return -1;
+	}
+
+	*winp = _allocwindow(*winp, *scrp, insetrect(image->r, Borderwidth), ref, DWhite);
+	if(*winp == nil)
+		return -1;
+	assert((*winp)->chan != 0);
+	return 1;
+}
+
+#define	NINFO	12*12
+
+Display*
+initdisplay(char *dev, char *win, void(*error)(Display*, char*))
+{
+	char buf[128], info[NINFO+1], *t;
+	int datafd, ctlfd, reffd;
+	Display *disp;
+	Image *image;
+	Dir *dir;
+	void *q;
+	ulong chan;
+
+	fmtinstall('P', Pfmt);
+	fmtinstall('R', Rfmt);
+	if(dev == 0)
+		dev = "/dev";
+	if(win == 0)
+		win = "/dev";
+	if(strlen(dev)>sizeof buf-25 || strlen(win)>sizeof buf-25){
+		kwerrstr("initdisplay: directory name too long");
+		return nil;
+	}
+	t = strdup(win);
+	if(t == nil)
+		return nil;
+
+	q = libqlalloc();
+	if(q == nil)
+		return nil;
+
+	sprint(buf, "%s/draw/new", dev);
+	ctlfd = libopen(buf, ORDWR);
+	if(ctlfd < 0){
+		if(libbind("#i", dev, MBEFORE) < 0){
+    Error1:
+			libqlfree(q);
+			free(t);
+			kwerrstr("initdisplay: %s: %r", buf);
+			return 0;
+		}
+		ctlfd = libopen(buf, ORDWR);
+	}
+	if(ctlfd < 0)
+		goto Error1;
+	if(libread(ctlfd, info, sizeof info) < NINFO){
+    Error2:
+		libclose(ctlfd);
+		goto Error1;
+	}
+
+	if((chan=strtochan(info+2*12)) == 0){
+		kwerrstr("bad channel in %s", buf);
+		goto Error2;
+	}
+
+	sprint(buf, "%s/draw/%d/data", dev, atoi(info+0*12));
+	datafd = libopen(buf, ORDWR);
+	if(datafd < 0)
+		goto Error2;
+	sprint(buf, "%s/draw/%d/refresh", dev, atoi(info+0*12));
+	reffd = libopen(buf, OREAD);
+	if(reffd < 0){
+    Error3:
+		libclose(datafd);
+		goto Error2;
+	}
+	strcpy(buf, "allocation failed");
+	disp = malloc(sizeof(Display));
+	if(disp == 0){
+    Error4:
+		libclose(reffd);
+		goto Error3;
+	}
+	image = malloc(sizeof(Image));
+	if(image == 0){
+    Error5:
+		free(disp);
+		goto Error4;
+	}
+	memset(image, 0, sizeof(Image));
+	memset(disp, 0, sizeof(Display));
+	image->display = disp;
+	image->id = 0;
+	image->chan = chan;
+	image->depth = chantodepth(chan);
+	image->repl = atoi(info+3*12);
+	image->r.min.x = atoi(info+4*12);
+	image->r.min.y = atoi(info+5*12);
+	image->r.max.x = atoi(info+6*12);
+	image->r.max.y = atoi(info+7*12);
+	image->clipr.min.x = atoi(info+8*12);
+	image->clipr.min.y = atoi(info+9*12);
+	image->clipr.max.x = atoi(info+10*12);
+	image->clipr.max.y = atoi(info+11*12);
+	disp->dirno = atoi(info+0*12);
+	disp->datachan = libfdtochan(datafd, ORDWR);
+	disp->refchan = libfdtochan(reffd, OREAD);
+	disp->ctlchan = libfdtochan(ctlfd, ORDWR);
+	if(disp->datachan == nil || disp->refchan == nil || disp->ctlchan == nil)
+		goto Error4;
+	disp->bufsize = Displaybufsize;	/* TO DO: iounit(datafd) */
+	if(disp->bufsize <= 0)
+		disp->bufsize = Displaybufsize;
+	if(disp->bufsize < 512){
+		kwerrstr("iounit %d too small", disp->bufsize);
+		goto Error5;
+	}
+	/* TO DO: allocate buffer */
+
+	libclose(datafd);
+	libclose(reffd);
+	disp->image = image;
+	disp->bufp = disp->buf;
+	disp->error = error;
+	disp->chan = image->chan;
+	disp->depth = image->depth;
+	disp->windir = t;
+	disp->devdir = strdup(dev);
+	disp->qlock = q;
+	libqlock(q);
+	disp->white = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
+	disp->black = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
+	disp->opaque = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DWhite);
+	disp->transparent = allocimage(disp, Rect(0, 0, 1, 1), GREY1, 1, DBlack);
+	if(disp->white == nil || disp->black == nil || disp->opaque == nil || disp->transparent == nil){
+		free(image);
+		free(disp->devdir);
+		free(disp->white);
+		free(disp->black);
+		libclose(ctlfd);
+		goto Error5;
+	}
+	if((dir = libdirfstat(ctlfd))!=nil && dir->type=='i'){
+		disp->local = 1;
+		disp->dataqid = dir->qid.path;
+	}
+	free(dir);
+	libclose(ctlfd);
+
+	if(CHECKLOCKING)
+		disp->local = 0;	/* force display locking even for local access */
+
+	assert(disp->chan != 0 && image->chan != 0);
+	return disp;
+}
+
+/*
+ * Call with d unlocked.
+ * Note that disp->defaultfont and defaultsubfont are not freed here.
+ */
+void
+closedisplay(Display *disp)
+{
+	int fd;
+	char buf[128];
+
+	if(disp == nil)
+		return;
+	libqlock(disp->qlock);
+	if(disp->oldlabel[0]){
+		snprint(buf, sizeof buf, "%s/label", disp->windir);
+		fd = libopen(buf, OWRITE);
+		if(fd >= 0){
+			libwrite(fd, disp->oldlabel, strlen(disp->oldlabel));
+			libclose(fd);
+		}
+	}
+
+	free(disp->devdir);
+	free(disp->windir);
+	freeimage(disp->white);
+	freeimage(disp->black);
+	freeimage(disp->opaque);
+	freeimage(disp->transparent);
+	free(disp->image);
+	libchanclose(disp->datachan);
+	libchanclose(disp->refchan);
+	libchanclose(disp->ctlchan);
+	/* should cause refresh slave to shut down */
+	libqunlock(disp->qlock);
+	libqlfree(disp->qlock);
+	free(disp);
+}
+
+int
+lockdisplay(Display *disp)
+{
+	if(disp->local)
+		return 0;
+	if(libqlowner(disp->qlock) != currun()){
+		libqlock(disp->qlock);
+		return 1;
+	}
+	return 0;
+}
+
+void
+unlockdisplay(Display *disp)
+{
+	if(disp->local)
+		return;
+	libqunlock(disp->qlock);
+}
+
+/* use static buffer to avoid stack bloat */
+int
+_drawprint(int fd, char *fmt, ...)
+{
+	int n;
+	va_list arg;
+	char buf[128];
+//	static QLock l;
+
+//	qlock(&l);
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof buf, fmt, arg);
+	va_end(arg);
+	n = libwrite(fd, buf, strlen(buf));
+//	qunlock(&l);
+	return n;
+}
+
+#ifdef YYY
+void
+drawerror(Display *d, char *s)
+{
+	char err[ERRMAX];
+
+	if(d->error)
+		d->error(d, s);
+	else{
+		err[0] = 0;
+		errstr(err, sizeof err);
+		_drawprint(2, "draw: %s: %s\n", s, err);
+		exits(s);
+	}
+}
+
+static
+int
+doflush(Display *d)
+{
+	int n;
+
+	n = d->bufp-d->buf;
+	if(n <= 0)
+		return 1;
+
+	if(kchanio(d->datachan, d->buf, n, OWRITE) != n){
+		if(_drawdebug)
+			_drawprint(2, "flushimage fail: d=%p: %r\n", d); /**/
+		d->bufp = d->buf;	/* might as well; chance of continuing */
+		return -1;
+	}
+	d->bufp = d->buf;
+	return 1;
+}
+
+int
+flushimage(Display *d, int visible)
+{
+	if(visible)
+		*d->bufp++ = 'v';	/* one byte always reserved for this */
+	return doflush(d);
+}
+
+uchar*
+bufimage(Display *d, int n)
+{
+	uchar *p;
+
+	if(n<0 || n>Displaybufsize){
+		kwerrstr("bad count in bufimage");
+		return 0;
+	}
+	if(d->bufp+n > d->buf+Displaybufsize)
+		if(doflush(d) < 0)
+			return 0;
+	p = d->bufp;
+	d->bufp += n;
+	return p;
+}
+
+#endif
--- /dev/null
+++ b/libdraw/line.c
@@ -1,0 +1,34 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+line(Image *dst, Point p0, Point p1, int end0, int end1, int radius, Image *src, Point sp)
+{
+	lineop(dst, p0, p1, end0, end1, radius, src, sp, SoverD);
+}
+
+void
+lineop(Image *dst, Point p0, Point p1, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+	uchar *a;
+
+	_setdrawop(dst->display, op);
+
+	a = bufimage(dst->display, 1+4+2*4+2*4+4+4+4+4+2*4);
+	if(a == 0){
+		_drawprint(2, "image line: %r\n");
+		return;
+	}
+	a[0] = 'L';
+	BPLONG(a+1, dst->id);
+	BPLONG(a+5, p0.x);
+	BPLONG(a+9, p0.y);
+	BPLONG(a+13, p1.x);
+	BPLONG(a+17, p1.y);
+	BPLONG(a+21, end0);
+	BPLONG(a+25, end1);
+	BPLONG(a+29, radius);
+	BPLONG(a+33, src->id);
+	BPLONG(a+37, sp.x);
+	BPLONG(a+41, sp.y);
+}
--- /dev/null
+++ b/libdraw/loadimage.c
@@ -1,0 +1,70 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+int
+loadimage(Image *i, Rectangle r, uchar *data, int ndata)
+{
+	long dy;
+	int n, bpl, roff, dstroff, lskip, llen, y;
+	uchar *a;
+	int chunk;
+	Rectangle dstr;
+
+	chunk = i->display->bufsize - 64;
+
+	bpl = bytesperline(r, i->depth);
+	n = bpl*Dy(r);
+	if(n > ndata){
+		kwerrstr("loadimage: insufficient data");
+		return -1;
+	}
+
+	dstr = r;
+	rectclip(&dstr, i->r);
+	rectclip(&dstr, i->clipr);
+
+	if (!rectinrect(dstr, i->r))
+		return 0;
+
+	roff = (r.min.x*i->depth)>>3;
+	dstroff = dstr.min.x * i->depth >> 3;
+	lskip = dstroff - roff;
+	llen = (dstr.max.x*i->depth + 7 >> 3) - dstroff;
+	data += (dstr.min.y - r.min.y) * bpl + lskip;
+
+	ndata = 0;
+	while(dstr.max.y > dstr.min.y){
+		dy = dstr.max.y - dstr.min.y;
+		if(dy*llen > chunk)
+			dy = chunk/llen;
+		if(dy <= 0){
+			kwerrstr("loadimage: image too wide for buffer");
+			return -1;
+		}
+		n = dy*llen;
+		a = bufimage(i->display, 21+n);
+		if(a == nil){
+			kwerrstr("bufimage failed");
+			return -1;
+		}
+		a[0] = 'y';
+		BPLONG(a+1, i->id);
+		BPLONG(a+5, dstr.min.x);
+		BPLONG(a+9, dstr.min.y);
+		BPLONG(a+13, dstr.max.x);
+		BPLONG(a+17, dstr.min.y+dy);
+		a += 21;
+		for (y = 0; y < dy; y++) {
+			memmove(a, data, llen);
+			a += llen;
+			ndata += llen;
+			data += bpl;
+		}
+		dstr.min.y += dy;
+	}
+	if(flushimage(i->display, 0) < 0)
+		return -1;
+	return ndata;
+}
+
--- /dev/null
+++ b/libdraw/mkfile
@@ -1,0 +1,54 @@
+<../mkconfig
+
+LIB=libdraw.a
+
+OFILES=	alloc.$O\
+	allocimagemix.$O\
+	arith.$O\
+	bezier.$O\
+	border.$O\
+	buildfont.$O\
+	bytesperline.$O\
+	chan.$O\
+	cloadimage.$O\
+	computil.$O\
+	creadimage.$O\
+	defont.$O\
+	draw.$O\
+	drawrepl.$O\
+	ellipse.$O\
+	font.$O\
+	freesubfont.$O\
+	getdefont.$O\
+	getsubfont.$O\
+	init.$O\
+	line.$O\
+	mkfont.$O\
+	openfont.$O\
+	poly.$O\
+	loadimage.$O\
+	readcolmap.$O\
+	readimage.$O\
+	readsubfont.$O\
+	rectclip.$O\
+	replclipr.$O\
+	rgb.$O\
+	string.$O\
+	stringbg.$O\
+	stringsubfont.$O\
+	stringwidth.$O\
+	subfont.$O\
+	subfontcache.$O\
+	subfontname.$O\
+	unloadimage.$O\
+	window.$O\
+	writecolmap.$O\
+	writeimage.$O\
+	writesubfont.$O\
+
+HFILES=\
+	$ROOT/include/draw.h \
+	$ROOT/include/interp.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
--- /dev/null
+++ b/libdraw/mkfont.c
@@ -1,0 +1,54 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Cobble fake font using existing subfont
+ */
+Font*
+mkfont(Subfont *subfont, Rune min)
+{
+	Font *font;
+	Cachefont *c;
+
+	font = malloc(sizeof(Font));
+	if(font == 0)
+		return 0;
+	memset(font, 0, sizeof(Font));
+	font->display = subfont->bits->display;
+	font->name = strdup("<synthetic>");
+	font->ncache = NFCACHE+NFLOOK;
+	font->nsubf = NFSUBF;
+	font->cache = malloc(font->ncache * sizeof(font->cache[0]));
+	font->subf = malloc(font->nsubf * sizeof(font->subf[0]));
+	if(font->name==0 || font->cache==0 || font->subf==0){
+    Err:
+		free(font->name);
+		free(font->cache);
+		free(font->subf);
+		free(font->sub);
+		free(font);
+		return 0;
+	}
+	memset(font->cache, 0, font->ncache*sizeof(font->cache[0]));
+	memset(font->subf, 0, font->nsubf*sizeof(font->subf[0]));
+	font->height = subfont->height;
+	font->ascent = subfont->ascent;
+	font->age = 1;
+	font->sub = malloc(sizeof(Cachefont*));
+	if(font->sub == 0)
+		goto Err;
+	c = malloc(sizeof(Cachefont));
+	if(c == 0)
+		goto Err;
+	font->nsub = 1;
+	font->sub[0] = c;
+	c->min = min;
+	c->max = min+subfont->n-1;
+	c->offset = 0;
+	c->name = 0;	/* noticed by freeup() and agefont() */
+	c->subfontname = 0;
+	font->subf[0].age = 0;
+	font->subf[0].cf = c;
+	font->subf[0].f = subfont;
+	return font;
+}
--- /dev/null
+++ b/libdraw/openfont.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+Font*
+openfont(Display *d, char *name)
+{
+	Font *fnt;
+	int fd, i, n;
+	char *buf;
+	Dir *dir;
+
+	fd = libopen(name, OREAD);
+	if(fd < 0)
+		return 0;
+
+	if((dir = libdirfstat(fd)) == nil){
+    Err0:
+		libclose(fd);
+		return 0;
+	}
+	n = dir->length;
+	free(dir);
+	buf = malloc(n+1);
+	if(buf == 0)
+		goto Err0;
+	buf[n] = 0;
+	i = libreadn(fd, buf, n);
+	libclose(fd);
+	if(i != n){
+		free(buf);
+		return 0;
+	}
+	fnt = buildfont(d, buf, name);
+	free(buf);
+	return fnt;
+}
--- /dev/null
+++ b/libdraw/poly.c
@@ -1,0 +1,86 @@
+#include "lib9.h"
+#include "draw.h"
+
+static
+uchar*
+addcoord(uchar *p, int oldx, int newx)
+{
+	int dx;
+
+	dx = newx-oldx;
+	/* does dx fit in 7 signed bits? */
+	if((unsigned)(dx - -0x40) <= 0x7F)
+		*p++ = dx&0x7F;
+	else{
+		*p++ = 0x80 | (newx&0x7F);
+		*p++ = newx>>7;
+		*p++ = newx>>15;
+	}
+	return p;
+}
+
+static
+void
+dopoly(int cmd, Image *dst, Point *pp, int np, int end0, int end1, int radius, Image *src, Point *sp, Drawop op)
+{
+	uchar *a, *t, *u;
+	int i, ox, oy;
+
+	if(np == 0)
+		return;
+	t = malloc(np*2*3);
+	if(t == nil)
+		return;
+	u = t;
+	ox = oy = 0;
+	for(i=0; i<np; i++){
+		u = addcoord(u, ox, pp[i].x);
+		ox = pp[i].x;
+		u = addcoord(u, oy, pp[i].y);
+		oy = pp[i].y;
+	}
+
+	_setdrawop(dst->display, op);
+
+	a = bufimage(dst->display, 1+4+2+4+4+4+4+2*4+(u-t));
+	if(a == 0){
+		free(t);
+		_drawprint(2, "image poly: %r\n");
+		return;
+	}
+	a[0] = cmd;
+	BPLONG(a+1, dst->id);
+	BPSHORT(a+5, np-1);
+	BPLONG(a+7, end0);
+	BPLONG(a+11, end1);
+	BPLONG(a+15, radius);
+	BPLONG(a+19, src->id);
+	BPLONG(a+23, sp->x);
+	BPLONG(a+27, sp->y);
+	memmove(a+31, t, u-t);
+	free(t);
+}
+
+void
+poly(Image *dst, Point *p, int np, int end0, int end1, int radius, Image *src, Point sp)
+{
+	dopoly('p', dst, p, np, end0, end1, radius, src, &sp, SoverD);
+}
+
+void
+polyop(Image *dst, Point *p, int np, int end0, int end1, int radius, Image *src, Point sp, Drawop op)
+{
+	dopoly('p', dst, p, np, end0, end1, radius, src, &sp, op);
+}
+
+void
+fillpoly(Image *dst, Point *p, int np, int wind, Image *src, Point sp)
+{
+	dopoly('P', dst, p, np, wind, 0, 0, src, &sp, SoverD);
+}
+
+void
+fillpolyop(Image *dst, Point *p, int np, int wind, Image *src, Point sp, Drawop op)
+{
+	dopoly('P', dst, p, np, wind, 0, 0, src, &sp, op);
+}
--- /dev/null
+++ b/libdraw/readcolmap.c
@@ -1,0 +1,46 @@
+#include "lib9.h"
+#include "draw.h"
+#include "bio.h"
+
+static ulong
+getval(char **p)
+{
+	ulong v;
+	char *q;
+
+	v = strtoul(*p, &q, 0);
+	v |= v<<8;
+	v |= v<<16;
+	*p = q;
+	return v;
+}
+
+void
+readcolmap(Display *d, RGB *colmap)
+{
+	int i;
+	char *p, *q;
+	Biobuf *b;
+	char buf[128];
+
+	sprint(buf, "/dev/draw/%d/colormap", d->dirno);
+	b = Bopen(buf, OREAD);
+	if(b == 0)
+		drawerror(d, "rdcolmap: can't open colormap device");
+
+	for(;;) {
+		p = Brdline(b, '\n');
+		if(p == 0)
+			break;
+		i = strtoul(p, &q, 0);
+		if(i < 0 || i > 255) {
+			_drawprint(2, "rdcolmap: bad index\n");
+			exits("bad");
+		}
+		p = q;
+		colmap[255-i].red = getval(&p);
+		colmap[255-i].green = getval(&p);
+		colmap[255-i].blue = getval(&p);
+	}
+	Bterm(b);
+}
--- /dev/null
+++ b/libdraw/readimage.c
@@ -1,0 +1,123 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+Image*
+readimage(Display *d, int fd, int dolock)
+{
+	char hdr[5*12+1];
+	int dy;
+	int new;
+	uint l, n;
+	int m, j, chunk;
+	int miny, maxy;
+	Rectangle r;
+	int ldepth;
+	ulong chan;
+	uchar *tmp;
+	Image *i;
+
+	if(libreadn(fd, hdr, 11) != 11) {
+		kwerrstr("readimage: short header");
+		return nil;
+	}
+	if(memcmp(hdr, "compressed\n", 11) == 0)
+		return creadimage(d, fd, dolock);
+	dolock &= 1;
+	if(libreadn(fd, hdr+11, 5*12-11) != 5*12-11) {
+		kwerrstr("readimage: short header");
+		return nil;
+	}
+	chunk = d->bufsize - 32;	/* a little room for header */
+
+	/*
+	 * distinguish new channel descriptor from old ldepth.
+	 * channel descriptors have letters as well as numbers,
+	 * while ldepths are a single digit formatted as %-11d.
+	 */
+	new = 0;
+	for(m=0; m<10; m++){
+		if(hdr[m] != ' '){
+			new = 1;
+			break;
+		}
+	}
+	if(hdr[11] != ' '){
+		kwerrstr("readimage: bad format");
+		return nil;
+	}
+	if(new){
+		hdr[11] = '\0';
+		if((chan = strtochan(hdr)) == 0){
+			kwerrstr("readimage: bad channel string %s", hdr);
+			return nil;
+		}
+	}else{
+		ldepth = ((int)hdr[10])-'0';
+		if(ldepth<0 || ldepth>3){
+			kwerrstr("readimage: bad ldepth %d", ldepth);
+			return nil;
+		}
+		chan = drawld2chan[ldepth];
+	}
+
+	r.min.x = atoi(hdr+1*12);
+	r.min.y = atoi(hdr+2*12);
+	r.max.x = atoi(hdr+3*12);
+	r.max.y = atoi(hdr+4*12);
+	if(r.min.x>r.max.x || r.min.y>r.max.y){
+		kwerrstr("readimage: bad rectangle");
+		return nil;
+	}
+
+	miny = r.min.y;
+	maxy = r.max.y;
+
+	l = bytesperline(r, chantodepth(chan));
+	if(dolock)
+		dolock = lockdisplay(d);
+	i = allocimage(d, r, chan, 0, -1);
+	if(dolock)
+		unlockdisplay(d);
+	if(i == nil)
+		return nil;
+	tmp = malloc(chunk);
+	if(tmp == nil)
+		goto Err;
+	while(maxy > miny){
+		dy = maxy - miny;
+		if(dy*l > chunk)
+			dy = chunk/l;
+		if(dy <= 0){
+			kwerrstr("readimage: image too wide for buffer");
+			goto Err;
+		}
+		n = dy*l;
+		m = libreadn(fd, tmp, n);
+		if(m != n){
+			kwerrstr("readimage: read count %d not %d: %r", m, n);
+   Err:
+			if(dolock)
+				lockdisplay(d);
+   Err1:
+ 			freeimage(i);
+			if(dolock)
+				unlockdisplay(d);
+			free(tmp);
+			return nil;
+		}
+		if(!new)	/* an old image: must flip all the bits */
+			for(j=0; j<chunk; j++)
+				tmp[j] ^= 0xFF;
+
+		if(dolock)
+			lockdisplay(d);
+		if(loadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
+			goto Err1;
+		if(dolock)
+			unlockdisplay(d);
+		miny += dy;
+	}
+	free(tmp);
+	return i;
+}
--- /dev/null
+++ b/libdraw/readsubfont.c
@@ -1,0 +1,58 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+
+Subfont*
+readsubfonti(Display*d, char *name, int fd, Image *ai, int dolock)
+{
+	char hdr[3*12+4+1];
+	int n;
+	uchar *p;
+	Fontchar *fc;
+	Subfont *f;
+	Image *i;
+
+	i = ai;
+	if(i == nil){
+		i = readimage(d, fd, dolock|2);
+		if(i == nil)
+			return nil;
+	}
+	if(libreadn(fd, hdr, 3*12) != 3*12){
+		if(ai == nil)
+			freeimage(i);
+		kwerrstr("rdsubfonfile: header read error: %r");
+		return nil;
+	}
+	n = atoi(hdr);
+	p = malloc(6*(n+1));
+	if(p == nil)
+		return nil;
+	if(libreadn(fd, p, 6*(n+1)) != 6*(n+1)){
+		kwerrstr("rdsubfonfile: fontchar read error: %r");
+    Err:
+		free(p);
+		return nil;
+	}
+	fc = malloc(sizeof(Fontchar)*(n+1));
+	if(fc == nil)
+		goto Err;
+	_unpackinfo(fc, p, n);
+	if(dolock)
+		lockdisplay(d);
+	f = allocsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i);
+	if(dolock)
+		unlockdisplay(d);
+	if(f == nil){
+		free(fc);
+		goto Err;
+	}
+	free(p);
+	return f;
+}
+
+Subfont*
+readsubfont(Display*d, char *name, int fd, int dolock)
+{
+	return readsubfonti(d, name, fd, nil, dolock);
+}
--- /dev/null
+++ b/libdraw/rectclip.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include "draw.h"
+
+int
+rectclip(Rectangle *rp, Rectangle b)		/* first by reference, second by value */
+{
+	Rectangle *bp = &b;
+	/*
+	 * Expand rectXrect() in line for speed
+	 */
+	if((rp->min.x<bp->max.x && bp->min.x<rp->max.x &&
+	    rp->min.y<bp->max.y && bp->min.y<rp->max.y)==0)
+		return 0;
+	/* They must overlap */
+	if(rp->min.x < bp->min.x)
+		rp->min.x = bp->min.x;
+	if(rp->min.y < bp->min.y)
+		rp->min.y = bp->min.y;
+	if(rp->max.x > bp->max.x)
+		rp->max.x = bp->max.x;
+	if(rp->max.y > bp->max.y)
+		rp->max.y = bp->max.y;
+	return 1;
+}
--- /dev/null
+++ b/libdraw/replclipr.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include "draw.h"
+
+void
+replclipr(Image *i, int repl, Rectangle clipr)
+{
+	uchar *b;
+
+	b = bufimage(i->display, 22);
+	if (b == 0) {
+		_drawprint(2, "replclipr: no bufimage\n");
+		return;
+	}
+	b[0] = 'c';
+	BPLONG(b+1, i->id);
+	repl = repl!=0;
+	b[5] = repl;
+	BPLONG(b+6, clipr.min.x);
+	BPLONG(b+10, clipr.min.y);
+	BPLONG(b+14, clipr.max.x);
+	BPLONG(b+18, clipr.max.y);
+	i->repl = repl;
+	i->clipr = clipr;
+}
--- /dev/null
+++ b/libdraw/rgb.c
@@ -1,0 +1,98 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * This original version, although fast and a true inverse of
+ * cmap2rgb, in the sense that rgb2cmap(cmap2rgb(c))
+ * returned the original color, does a terrible job for RGB
+ * triples that do not appear in the color map, so it has been
+ * replaced by the much slower version below, that loops
+ * over the color map looking for the nearest point in RGB
+ * space.  There is no visual psychology reason for that
+ * criterion, but it's easy to implement and the results are
+ * far more pleasing. 
+ *
+int
+rgb2cmap(int cr, int cg, int cb)
+{
+	int r, g, b, v, cv;
+
+	if(cr < 0)
+		cr = 0;
+	else if(cr > 255)
+		cr = 255;
+	if(cg < 0)
+		cg = 0;
+	else if(cg > 255)
+		cg = 255;
+	if(cb < 0)
+		cb = 0;
+	else if(cb > 255)
+		cb = 255;
+	r = cr>>6;
+	g = cg>>6;
+	b = cb>>6;
+	cv = cr;
+	if(cg > cv)
+		cv = cg;
+	if(cb > cv)
+		cv = cb;
+	v = (cv>>4)&3;
+	return ((((r<<2)+v)<<4)+(((g<<2)+b+v-r)&15));
+}
+*/
+
+int
+rgb2cmap(int cr, int cg, int cb)
+{
+	int i, r, g, b, sq;
+	ulong rgb;
+	int best, bestsq;
+
+	best = 0;
+	bestsq = 0x7FFFFFFF;
+	for(i=0; i<256; i++){
+		rgb = cmap2rgb(i);
+		r = (rgb>>16) & 0xFF;
+		g = (rgb>>8) & 0xFF;
+		b = (rgb>>0) & 0xFF;
+		sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb);
+		if(sq < bestsq){
+			bestsq = sq;
+			best = i;
+		}
+	}
+	return best;
+}
+
+int
+cmap2rgb(int c)
+{
+	int j, num, den, r, g, b, v, rgb;
+
+	r = c>>6;
+	v = (c>>4)&3;
+	j = (c-v+r)&15;
+	g = j>>2;
+	b = j&3;
+	den=r;
+	if(g>den)
+		den=g;
+	if(b>den)
+		den=b;
+	if(den==0) {
+		v *= 17;
+		rgb = (v<<16)|(v<<8)|v;
+	}
+	else{
+		num=17*(4*den+v);
+		rgb = ((r*num/den)<<16)|((g*num/den)<<8)|(b*num/den);
+	}
+	return rgb;
+}
+
+int
+cmap2rgba(int c)
+{
+	return (cmap2rgb(c)<<8)|0xFF;
+}
--- /dev/null
+++ b/libdraw/string.c
@@ -1,0 +1,136 @@
+#include "lib9.h"
+#include "draw.h"
+
+enum
+{
+	Max = 100
+};
+
+Point
+string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s)
+{
+	return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+stringop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, nil, ZP, op);
+}
+
+Point
+stringn(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len)
+{
+	return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+stringnop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, nil, ZP, op);
+}
+
+Point
+runestring(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r)
+{
+	return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+runestringop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, nil, ZP, op);
+}
+
+Point
+runestringn(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len)
+{
+	return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, nil, ZP, SoverD);
+}
+
+Point
+runestringnop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, nil, ZP, op);
+}
+
+Point
+_string(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Rune *r, int len, Rectangle clipr, Image *bg, Point bgp, Drawop op)
+{
+	int m, n, wid, max;
+	ushort cbuf[Max], *c, *ec;
+	uchar *b;
+	char *subfontname;
+	char **sptr;
+	Rune **rptr;
+	Font *def;
+
+	if(s == nil){
+		s = "";
+		sptr = nil;
+	}else
+		sptr = &s;
+	if(r == nil){
+		r = (Rune*) L"";
+		rptr = nil;
+	}else
+		rptr = &r;
+	while((*s || *r) && len){
+		max = Max;
+		if(len < max)
+			max = len;
+		n = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname);
+		if(n > 0){
+			_setdrawop(dst->display, op);
+
+			m = 47+2*n;
+			if(bg)
+				m += 4+2*4;
+			b = bufimage(dst->display, m);
+			if(b == 0){
+				_drawprint(2, "string: %r\n");
+				break;
+			}
+			if(bg)
+				b[0] = 'x';
+			else
+				b[0] = 's';
+			BPLONG(b+1, dst->id);
+			BPLONG(b+5, src->id);
+			BPLONG(b+9, f->cacheimage->id);
+			BPLONG(b+13, pt.x);
+			BPLONG(b+17, pt.y+f->ascent);
+			BPLONG(b+21, clipr.min.x);
+			BPLONG(b+25, clipr.min.y);
+			BPLONG(b+29, clipr.max.x);
+			BPLONG(b+33, clipr.max.y);
+			BPLONG(b+37, sp.x);
+			BPLONG(b+41, sp.y);
+			BPSHORT(b+45, n);
+			b += 47;
+			if(bg){
+				BPLONG(b, bg->id);
+				BPLONG(b+4, bgp.x);
+				BPLONG(b+8, bgp.y);
+				b += 12;
+			}
+			ec = &cbuf[n];
+			for(c=cbuf; c<ec; c++, b+=2)
+				BPSHORT(b, *c);
+			pt.x += wid;
+			bgp.x += wid;
+			agefont(f);
+			len -= n;
+		}
+		if(subfontname){
+			if(_getsubfont(f->display, subfontname) == 0){
+				def = f->display->defaultfont;
+				if(def && f!=def)
+					f = def;
+				else
+					break;
+			}
+		}
+	}
+	return pt;
+}
--- /dev/null
+++ b/libdraw/stringbg.c
@@ -1,0 +1,50 @@
+#include "lib9.h"
+#include "draw.h"
+
+Point
+stringbg(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Image *bg, Point bgp)
+{
+	return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+stringbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, Image *bg, Point bgp, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, s, nil, 1<<24, dst->clipr, bg, bgp, op);
+}
+
+Point
+stringnbg(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Image *bg, Point bgp)
+{
+	return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+stringnbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, char *s, int len, Image *bg, Point bgp, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, s, nil, len, dst->clipr, bg, bgp, op);
+}
+
+Point
+runestringbg(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Image *bg, Point bgp)
+{
+	return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+runestringbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, Image *bg, Point bgp, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, nil, r, 1<<24, dst->clipr, bg, bgp, op);
+}
+
+Point
+runestringnbg(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Image *bg, Point bgp)
+{
+	return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, bg, bgp, SoverD);
+}
+
+Point
+runestringnbgop(Image *dst, Point pt, Image *src, Point sp, Font *f, Rune *r, int len, Image *bg, Point bgp, Drawop op)
+{
+	return _string(dst, pt, src, sp, f, nil, r, len, dst->clipr, bg, bgp, op);
+}
--- /dev/null
+++ b/libdraw/stringsubfont.c
@@ -1,0 +1,64 @@
+#include "lib9.h"
+#include "draw.h"
+
+Point
+stringsubfont(Image *b, Point p, Image *color, Subfont *f, char *cs)
+{
+	int w, width;
+	uchar *s;
+	Rune c;
+	Fontchar *i;
+
+	s = (uchar*)cs;
+	for(; c=*s; p.x+=width){
+		width = 0;
+		if(c < Runeself)
+			s++;
+		else{
+			w = chartorune(&c, (char*)s);
+			if(w == 0){
+				s++;
+				continue;
+			}
+			s += w;
+		}
+		if(c >= f->n)
+			continue;
+		i = f->info+c;
+		width = i->width;
+		draw(b, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom),
+			color, f->bits, Pt(i->x, i->top));
+	}
+	return p;
+}
+
+Point
+strsubfontwidth(Subfont *f, char *cs)
+{
+	Rune c;
+	Point p;
+	uchar *s;
+	Fontchar *i;
+	int w, width;
+
+	p = Pt(0, f->height);
+	s = (uchar*)cs;
+	for(; c=*s; p.x+=width){
+		width = 0;
+		if(c < Runeself)
+			s++;
+		else{
+			w = chartorune(&c, (char*)s);
+			if(w == 0){
+				s++;
+				continue;
+			}
+			s += w;
+		}
+		if(c >= f->n)
+			continue;
+		i = f->info+c;
+		width = i->width;
+	}
+	return p;
+}
--- /dev/null
+++ b/libdraw/stringwidth.c
@@ -1,0 +1,96 @@
+#include "lib9.h"
+#include "draw.h"
+
+int
+_stringnwidth(Font *f, char *s, Rune *r, int len)
+{
+	int wid, twid, n, max, l;
+	char *name;
+	enum { Max = 64 };
+	ushort cbuf[Max];
+	Rune rune, **rptr;
+	char *subfontname, **sptr;
+	Font *def;
+	static Rune rnull;
+
+	if(s == nil){
+		s = "";
+		sptr = nil;
+	}else
+		sptr = &s;
+	if(r == nil){
+		r = &rnull;
+		rptr = nil;
+	}else
+		rptr = &r;
+	twid = 0;
+	while(len>0 && (*s || *r)){
+		max = Max;
+		if(len < max)
+			max = len;
+		n = 0;
+		while((l = cachechars(f, sptr, rptr, cbuf, max, &wid, &subfontname)) <= 0){
+			if(++n > 10){
+				if(*r)
+					rune = *r;
+				else
+					chartorune(&rune, s);
+				if(f->name != nil)
+					name = f->name;
+				else
+					name = "unnamed font";
+				_drawprint(2, "stringwidth: bad character set for rune 0x%.4ux in %s\n", rune, name);
+				return twid;
+			}
+			if(subfontname){
+				if(_getsubfont(f->display, subfontname) == 0){
+					def = f->display->defaultfont;
+					if(def && f!=def)
+						f = def;
+					else
+						break;
+				}
+			}
+		}
+		agefont(f);
+		twid += wid;
+		len -= l;
+	}
+	return twid;
+}
+
+int
+stringnwidth(Font *f, char *s, int len)
+{
+	return _stringnwidth(f, s, nil, len);
+}
+
+int
+stringwidth(Font *f, char *s)
+{
+	return _stringnwidth(f, s, nil, 1<<24);
+}
+
+Point
+stringsize(Font *f, char *s)
+{
+	return Pt(_stringnwidth(f, s, nil, 1<<24), f->height);
+}
+
+int
+runestringnwidth(Font *f, Rune *r, int len)
+{
+	return _stringnwidth(f, nil, r, len);
+}
+
+int
+runestringwidth(Font *f, Rune *r)
+{
+	return _stringnwidth(f, nil, r, 1<<24);
+}
+
+Point
+runestringsize(Font *f, Rune *r)
+{
+	return Pt(_stringnwidth(f, nil, r, 1<<24), f->height);
+}
--- /dev/null
+++ b/libdraw/subfont.c
@@ -1,0 +1,27 @@
+#include "lib9.h"
+#include "draw.h"
+
+Subfont*
+allocsubfont(char *name, int n, int height, int ascent, Fontchar *info, Image *i)
+{
+	Subfont *f;
+
+	assert(height != 0 /* allocsubfont */);
+
+	f = malloc(sizeof(Subfont));
+	if(f == 0)
+		return 0;
+	f->n = n;
+	f->height = height;
+	f->ascent = ascent;
+	f->info = info;
+	f->bits = i;
+	f->ref = 1;
+	if(name){
+		f->name = strdup(name);
+		if(lookupsubfont(i->display, name) == 0)
+			installsubfont(name, f);
+	}else
+		f->name = 0;
+	return f;
+}
--- /dev/null
+++ b/libdraw/subfontcache.c
@@ -1,0 +1,38 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Easy versions of the cache routines; may be substituted by fancier ones for other purposes
+ */
+
+static char	*lastname;
+Subfont	*lastsubfont;
+
+Subfont*
+lookupsubfont(Display *d, char *name)
+{
+	if(strcmp(name, "*default*") == 0)
+		return d->defaultsubfont;
+	if(lastname && strcmp(name, lastname)==0 && d==lastsubfont->bits->display){
+		lastsubfont->ref++;
+		return lastsubfont;
+	}
+	return 0;
+}
+
+void
+installsubfont(char *name, Subfont *subfont)
+{
+	free(lastname);
+	lastname = strdup(name);
+	lastsubfont = subfont;	/* notice we don't free the old one; that's your business */
+}
+
+void
+uninstallsubfont(Subfont *subfont)
+{
+	if(subfont == lastsubfont){
+		lastname = 0;
+		lastsubfont = 0;
+	}
+}
--- /dev/null
+++ b/libdraw/subfontname.c
@@ -1,0 +1,45 @@
+#include "lib9.h"
+#include "draw.h"
+
+/*
+ * Default version: convert to file name
+ */
+
+char*
+subfontname(char *cfname, char *fname, int maxdepth)
+{
+	char *t, *u, tmp1[128], tmp2[128];
+	int i;
+
+	if(strcmp(cfname, "*default*") == 0)
+		return strdup(cfname);
+	t = cfname;
+	if(t[0] != '/'){
+		snprint(tmp2, sizeof tmp2, "%s", fname);
+		u = utfrrune(tmp2, '/');
+		if(u)
+			u[0] = 0;
+		else
+			strcpy(tmp2, ".");
+		snprint(tmp1, sizeof tmp1, "%s/%s", tmp2, t);
+		t = tmp1;
+	}
+
+	if(maxdepth > 8)
+		maxdepth = 8;
+
+	for(i=3; i>=0; i--){
+		if((1<<i) > maxdepth)
+			continue;
+		/* try i-bit grey */
+		snprint(tmp2, sizeof tmp2, "%s.%d", t, i);
+		if(access(tmp2, AREAD) == 0)
+			return strdup(tmp2);
+	}
+
+	/* try default */
+	if(access(t, AREAD) == 0)
+		return strdup(t);
+
+	return nil;
+}
--- /dev/null
+++ b/libdraw/test.c
@@ -1,0 +1,9 @@
+#include "lib9.h"
+#include "draw.h"
+
+
+void
+main(int argc, char **argv)
+{
+		print("%dn", wordsperline(Rect(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4])), atoi(argv[5])));
+}
--- /dev/null
+++ b/libdraw/unloadimage.c
@@ -1,0 +1,58 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+#include "interp.h"
+
+int
+unloadimage(Image *i, Rectangle r, uchar *data, int ndata)
+{
+	int bpl, n, ntot, dy;
+	uchar *a;
+	Display *d;
+
+	if(!rectinrect(r, i->r)){
+		kwerrstr("unloadimage: bad rectangle");
+		return -1;
+	}
+	bpl = bytesperline(r, i->depth);
+	if(ndata < bpl*Dy(r)){
+		kwerrstr("unloadimage: buffer too small");
+		return -1;
+	}
+
+	d = i->display;
+	flushimage(d, 0);	/* make sure subsequent flush is for us only */
+	ntot = 0;
+	while(r.min.y < r.max.y){
+		a = bufimage(d, 1+4+4*4);
+		if(a == 0){
+			kwerrstr("unloadimage: %r");
+			return -1;
+		}
+		dy = 8000/bpl;
+		if(dy <= 0){
+			kwerrstr("unloadimage: image too wide");
+			return -1;
+		}
+		if(dy > Dy(r))
+			dy = Dy(r);
+		a[0] = 'r';
+		BPLONG(a+1, i->id);
+		BPLONG(a+5, r.min.x);
+		BPLONG(a+9, r.min.y);
+		BPLONG(a+13, r.max.x);
+		BPLONG(a+17, r.min.y+dy);
+		if(flushimage(d, 0) < 0)
+			return -1;
+		if(d->local == 0)
+			release();
+		n = kchanio(d->datachan, data+ntot, ndata-ntot, OREAD);
+		if(d->local == 0)
+			acquire();
+		if(n < 0)
+			return n;
+		ntot += n;
+		r.min.y += dy;
+	}
+	return ntot;
+}
--- /dev/null
+++ b/libdraw/window.c
@@ -1,0 +1,203 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+typedef struct Memimage Memimage;
+
+static int	screenid;
+
+Screen*
+allocscreen(Image *image, Image *fill, int public)
+{
+	uchar *a;
+	Screen *s;
+	int id, try;
+	Display *d;
+
+	d = image->display;
+	if(d != fill->display){
+		kwerrstr("allocscreen: image and fill on different displays");
+		return 0;
+	}
+	s = malloc(sizeof(Screen));
+	if(s == 0)
+		return 0;
+	SET(id);
+	for(try=0; try<25; try++){
+		/* loop until find a free id */
+		a = bufimage(d, 1+4+4+4+1);
+		if(a == 0){
+			free(s);
+			return 0;
+		}
+		id = ++screenid;
+		a[0] = 'A';
+		BPLONG(a+1, id);
+		BPLONG(a+5, image->id);
+		BPLONG(a+9, fill->id);
+		a[13] = public;
+		if(flushimage(d, 0) != -1)
+			break;
+	}
+	s->display = d;
+	s->id = id;
+	s->image = image;
+//	assert(s->image && s->image->chan != 0);
+
+	s->fill = fill;
+	return s;
+}
+
+Screen*
+publicscreen(Display *d, int id, ulong chan)
+{
+	uchar *a;
+	Screen *s;
+
+	s = malloc(sizeof(Screen));
+	if(s == 0)
+		return 0;
+	a = bufimage(d, 1+4+4);
+	if(a == 0){
+    Error:
+		free(s);
+		return 0;
+	}
+	a[0] = 'S';
+	BPLONG(a+1, id);
+	BPLONG(a+5, chan);
+	if(flushimage(d, 0) < 0)
+		goto Error;
+
+	s->display = d;
+	s->id = id;
+	s->image = 0;
+	s->fill = 0;
+	return s;
+}
+
+int
+freescreen(Screen *s)
+{
+	uchar *a;
+	Display *d;
+
+	if(s == 0)
+		return 0;
+	d = s->display;
+	a = bufimage(d, 1+4);
+	if(a == 0)
+		return -1;
+	a[0] = 'F';
+	BPLONG(a+1, s->id);
+	/*
+	 * flush(1) because screen is likely holding last reference to
+	 * window, and want it to disappear visually.
+	 */
+	if(flushimage(d, 1) < 0)
+		return -1;
+	free(s);
+	return 1;
+}
+
+Image*
+allocwindow(Screen *s, Rectangle r, int ref, ulong val)
+{
+	return _allocwindow(nil, s, r, ref, val);
+}
+
+Image*
+_allocwindow(Image *i, Screen *s, Rectangle r, int ref, ulong val)
+{
+	Display *d;
+
+	d = s->display;
+	i = _allocimage(i, d, r, s->image->chan, 0, val, s->id, ref);
+	if(i == 0)
+		return 0;
+	i->screen = s;
+	i->next = s->display->windows;
+	s->display->windows = i;
+	return i;
+}
+
+static
+void
+topbottom(Image **w, int n, int top)
+{
+	int i;
+	uchar *b;
+	Display *d;
+
+	if(n<0 || n>(Displaybufsize-100)/4){
+		_drawprint(2, "top/bottom: ridiculous number of windows\n");
+		return;
+	}
+	if(n==0)
+		return;
+	/* check that all images are on the same display; only it can check the screens */
+	d = w[0]->display;
+	for(i=1; i<n; i++)
+		if(w[i]->display != d){
+			_drawprint(2, "top/bottom: windows not on same display\n");
+			return;
+		}
+	b = bufimage(d, 1+1+2+4*n);
+	if (b == 0) {
+		_drawprint(2, "top/bottom: no bufimage\n");
+		return;
+	}
+	b[0] = 't';
+	b[1] = top;
+	BPSHORT(b+2, n);
+	for(i=0; i<n; i++)
+		BPLONG(b+4+4*i, w[i]->id);
+}
+
+void
+bottomwindow(Image *w)
+{
+	topbottom(&w, 1, 0);
+}
+
+void
+topwindow(Image *w)
+{
+	topbottom(&w, 1, 1);
+}
+
+void
+bottomnwindows(Image **w, int n)
+{
+	topbottom(w, n, 0);
+}
+
+void
+topnwindows(Image **w, int n)
+{
+	topbottom(w, n, 1);
+}
+
+int
+originwindow(Image *w, Point log, Point scr)
+{
+	uchar *b;
+	Point delta;
+
+	flushimage(w->display, 0);
+	b = bufimage(w->display, 1+4+2*4+2*4);
+	if(b == nil)
+		return 0;
+	b[0] = 'o';
+	BPLONG(b+1, w->id);
+	BPLONG(b+5, log.x);
+	BPLONG(b+9, log.y);
+	BPLONG(b+13, scr.x);
+	BPLONG(b+17, scr.y);
+	if(flushimage(w->display, 1) < 0)
+		return -1;
+	delta = subpt(log, w->r.min);
+	w->r = rectaddpt(w->r, delta);
+	w->clipr = rectaddpt(w->clipr, delta);
+	return 1;
+}
--- /dev/null
+++ b/libdraw/writecolmap.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+/*
+ * This code (and the devdraw interface) will have to change
+ * if we ever get bitmaps with ldepth > 3, because the
+ * colormap will have to be written in chunks
+ */
+
+void
+writecolmap(Display *d, RGB *m)
+{
+	int i, n, fd;
+	char buf[64], *t;
+	ulong r, g, b;
+
+	sprint(buf, "/dev/draw/%d/colormap", d->dirno);
+	fd = open(buf, OWRITE);
+	if(fd < 0)
+		drawerror(d, "wrcolmap: open colormap failed");
+	t = malloc(8192);
+	if(t == nil)
+		return;
+	n = 0;
+	for(i = 0; i < 256; i++) {
+		r = m[i].red>>24;
+		g = m[i].green>>24;
+		b = m[i].blue>>24;
+		n += sprint(t+n, "%d %lud %lud %lud\n", 255-i, r, g, b);
+	}
+	i = libwrite(fd, t, n);
+	free(t);
+	close(fd);
+	if(i != n)
+		drawerror(d, "wrcolmap: bad write");
+}
--- /dev/null
+++ b/libdraw/writeimage.c
@@ -1,0 +1,185 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+#define	HSHIFT	3	/* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
+#define	NHASH	(1<<(HSHIFT*NMATCH))
+#define	HMASK	(NHASH-1)
+#define	hupdate(h, c)	((((h)<<HSHIFT)^(c))&HMASK)
+typedef struct Hlist Hlist;
+struct Hlist{
+	uchar *s;
+	Hlist *next, *prev;
+};
+
+int
+writeimage(int fd, Image *i, int dolock)
+{
+	uchar *outbuf, *outp, *eout;		/* encoded data, pointer, end */
+	uchar *loutp;				/* start of encoded line */
+	Hlist *hash;				/* heads of hash chains of past strings */
+	Hlist *chain, *hp;			/* hash chain members, pointer */
+	Hlist *cp;				/* next Hlist to fall out of window */
+	int h;					/* hash value */
+	uchar *line, *eline;			/* input line, end pointer */
+	uchar *data, *edata;			/* input buffer, end pointer */
+	ulong n;				/* length of input buffer */
+	ulong nb;				/* # of bytes returned by unloadimage */
+	int bpl;				/* input line length */
+	int offs, runlen;			/* offset, length of consumed data */
+	uchar dumpbuf[NDUMP];			/* dump accumulator */
+	int ndump;				/* length of dump accumulator */
+	int miny, dy;				/* y values while unloading input */
+	int chunk, ncblock;
+	Rectangle r;
+	uchar *p, *q, *s, *es, *t;
+	char hdr[11+5*12+1];
+	char cbuf[20];
+
+	chunk = i->display->bufsize - 32;	/* a little room for header */
+	r = i->r;
+	bpl = bytesperline(r, i->depth);
+	n = Dy(r)*bpl;
+	data = malloc(n);
+	ncblock = _compblocksize(r, i->depth);
+	outbuf = malloc(ncblock);
+	hash = malloc(NHASH*sizeof(Hlist));
+	chain = malloc(NMEM*sizeof(Hlist));
+	if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
+	ErrOut:
+		free(data);
+		free(outbuf);
+		free(hash);
+		free(chain);
+		return -1;
+	}
+	for(miny = r.min.y; miny != r.max.y; miny += dy){
+		dy = r.max.y-miny;
+		if(dy*bpl > chunk)
+			dy = chunk/bpl;
+		if(dolock)
+			lockdisplay(i->display);
+		nb = unloadimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
+			data+(miny-r.min.y)*bpl, dy*bpl);
+		if(dolock)
+			unlockdisplay(i->display);
+		if(nb != dy*bpl)
+			goto ErrOut;
+	}
+	sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
+		chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
+	if(libwrite(fd, hdr, 11+5*12) != 11+5*12)
+		goto ErrOut;
+	edata = data+n;
+	eout = outbuf+ncblock;
+	line = data;
+	r.max.y = r.min.y;
+	while(line != edata){
+		memset(hash, 0, NHASH*sizeof(Hlist));
+		memset(chain, 0, NMEM*sizeof(Hlist));
+		cp = chain;
+		h = 0;
+		outp = outbuf;
+		for(n = 0; n != NMATCH; n++)
+			h = hupdate(h, line[n]);
+		loutp = outbuf;
+		while(line != edata){
+			ndump = 0;
+			eline = line+bpl;
+			for(p = line; p != eline; ){
+				if(eline-p < NRUN)
+					es = eline;
+				else
+					es = p+NRUN;
+				q = 0;
+				runlen = 0;
+				for(hp = hash[h].next; hp; hp = hp->next){
+					s = p + runlen;
+					if(s >= es)
+						continue;
+					t = hp->s + runlen;
+					for(; s >= p; s--)
+						if(*s != *t--)
+							goto matchloop;
+					t += runlen+2;
+					s += runlen+2;
+					for(; s < es; s++)
+						if(*s != *t++)
+							break;
+					n = s-p;
+					if(n > runlen){
+						runlen = n;
+						q = hp->s;
+						if(n == NRUN)
+							break;
+					}
+			matchloop: ;
+				}
+				if(runlen < NMATCH){
+					if(ndump == NDUMP){
+						if(eout-outp < ndump+1)
+							goto Bfull;
+						*outp++ = ndump-1+128;
+						memmove(outp, dumpbuf, ndump);
+						outp += ndump;
+						ndump = 0;
+					}
+					dumpbuf[ndump++] = *p;
+					runlen = 1;
+				}
+				else{
+					if(ndump != 0){
+						if(eout-outp < ndump+1)
+							goto Bfull;
+						*outp++ = ndump-1+128;
+						memmove(outp, dumpbuf, ndump);
+						outp += ndump;
+						ndump = 0;
+					}
+					offs = p-q-1;
+					if(eout-outp < 2)
+						goto Bfull;
+					*outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
+					*outp++ = offs&255;
+				}
+				for(q = p+runlen; p != q; p++){
+					if(cp->prev)
+						cp->prev->next = 0;
+					cp->next = hash[h].next;
+					cp->prev = &hash[h];
+					if(cp->next)
+						cp->next->prev = cp;
+					cp->prev->next = cp;
+					cp->s = p;
+					if(++cp == &chain[NMEM])
+						cp = chain;
+					if(edata-p > NMATCH)
+						h = hupdate(h, p[NMATCH]);
+				}
+			}
+			if(ndump != 0){
+				if(eout-outp < ndump+1)
+					goto Bfull;
+				*outp++ = ndump-1+128;
+				memmove(outp, dumpbuf, ndump);
+				outp += ndump;
+			}
+			line = eline;
+			loutp = outp;
+			r.max.y++;
+		}
+	Bfull:
+		if(loutp == outbuf)
+			goto ErrOut;
+		n = loutp-outbuf;
+		sprint(hdr, "%11d %11ld ", r.max.y, n);
+		libwrite(fd, hdr, 2*12);
+		libwrite(fd, outbuf, n);
+		r.min.y = r.max.y;
+	}
+	free(data);
+	free(outbuf);
+	free(hash);
+	free(chain);
+	return 0;
+}
--- /dev/null
+++ b/libdraw/writesubfont.c
@@ -1,0 +1,45 @@
+#include "lib9.h"
+#include "draw.h"
+#include "kernel.h"
+
+static
+void
+packinfo(Fontchar *fc, uchar *p, int n)
+{
+	int j;
+
+	for(j=0;  j<=n;  j++){
+		p[0] = fc->x;
+		p[1] = fc->x>>8;
+		p[2] = fc->top;
+		p[3] = fc->bottom;
+		p[4] = fc->left;
+		p[5] = fc->width;
+		fc++;
+		p += 6;
+	}
+}
+
+int
+writesubfont(int fd, Subfont *f)
+{
+	char hdr[3*12+1];
+	uchar *data;
+	int nb;
+
+	sprint(hdr, "%11d %11d %11d ", f->n, f->height, f->ascent);
+	if(libwrite(fd, hdr, 3*12) != 3*12){
+   Err:
+		kwerrstr("writesubfont: bad write: %r");
+		return -1;
+	}
+	nb = 6*(f->n+1);
+	data = malloc(nb);
+	if(data == nil)
+		return -1;
+	packinfo(f->info, data, f->n);
+	if(libwrite(fd, data, nb) != nb)
+		goto Err;
+	free(data);
+	return 0;
+}
--- /dev/null
+++ b/libdynld/NOTICE
@@ -1,0 +1,28 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 2004-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/libdynld/dynld-386.c
@@ -1,0 +1,42 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define	CHK(i,ntab)	if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+	return DYN_MAGIC | I_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+	int i;
+	ulong v, *pp;
+
+	p += (ulong)b;
+	pp = (ulong*)p;
+	v = *pp;
+	switch(m){
+	case 0:
+		v += (ulong)b;
+		break;
+	case 1:
+		i = v>>22;
+		v &= 0x3fffff;
+		CHK(i, ntab);
+		v += tab[i]->addr;
+		break;
+	case 2:
+		i = v>>22;
+		CHK(i, ntab);
+		v = tab[i]->addr -p-4;
+		break;
+	default:
+		return "bad relocation mode";
+	}
+	*pp = v;
+	return nil;
+}
--- /dev/null
+++ b/libdynld/dynld-arm.c
@@ -1,0 +1,44 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define	CHK(i,ntab)	if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+	return DYN_MAGIC | E_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+	int i;
+	ulong v, *pp;
+
+	p <<= 2;
+	p += (ulong)b;
+	pp = (ulong*)p;
+	v = *pp;
+	switch(m){
+	case 0:
+		v += (ulong)b;
+		break;
+	case 1:
+		i = v>>22;
+		v &= 0x3fffff;
+		CHK(i, ntab);
+		v += tab[i]->addr;
+		break;
+	case 2:
+		i = v&0x3ff;
+		v &= ~0x3ff;
+		CHK(i, ntab);
+		v |= ((tab[i]->addr-p-8)>>2)&0xffffff;
+		break;
+	default:
+		return "invalid relocation mode";
+	}
+	*pp = v;
+	return nil;
+}
--- /dev/null
+++ b/libdynld/dynld-mips.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define	CHK(i,ntab)	if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+	return DYN_MAGIC | V_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+	USED(b);
+	USED(p);
+	USED(m);
+	USED(tab);
+	USED(ntab);
+	return "mips unimplemented";
+}
--- /dev/null
+++ b/libdynld/dynld-power.c
@@ -1,0 +1,65 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define	CHK(i,ntab)	if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+	return DYN_MAGIC | Q_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+	int i;
+	ulong v, *pp0, *pp1;
+
+	p <<= 2;
+	p += (ulong)b;
+	pp0 = (ulong*)p;
+	v = *pp0;
+	switch(m){
+	case 0:
+		v += (ulong)b;
+		break;
+	case 1:
+		i = v>>22;
+		v &= 0x3fffff;
+		CHK(i, ntab);
+		v += tab[i]->addr;
+		break;
+	case 2:
+		i = (v&0xffc)>>2;
+		v &= ~0xffc;
+		CHK(i, ntab);
+		v |= (tab[i]->addr-p)&0x3fffffc;
+		break;
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		pp1 = (ulong*)(p+4);
+		v = (v<<16)|(*pp1&0xffff);
+		if(m&1)
+			v += (ulong)b;
+		else{
+			i = v>>22;
+			v &= 0x3fffff;
+			CHK(i, ntab);
+			v += tab[i]->addr;
+		}
+		if(m >= 5 && (v&0x8000))
+			v += 0x10000;
+		*pp0 &= ~0xffff;
+		*pp0 |= v>>16;
+		*pp1 &= ~0xffff;
+		*pp1 |= v&0xffff;
+		return nil;
+	default:
+		return "invalid relocation mode";
+	}
+	*pp0 = v;
+	return nil;
+}
--- /dev/null
+++ b/libdynld/dynld-sparc.c
@@ -1,0 +1,20 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+long
+dynmagic(void)
+{
+	return DYN_MAGIC | K_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+	USED(b);
+	USED(p);
+	USED(m);
+	USED(tab);
+	USED(ntab);
+	return "sparc unimplemented";
+}
--- /dev/null
+++ b/libdynld/dynld-spim.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+#define	CHK(i,ntab)	if((unsigned)(i)>=(ntab))return "bad relocation index"
+
+long
+dynmagic(void)
+{
+	return DYN_MAGIC | N_MAGIC;
+}
+
+char*
+dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
+{
+	USED(b);
+	USED(p);
+	USED(m);
+	USED(tab);
+	USED(ntab);
+	return "mips-le (spim) unimplemented";
+}
--- /dev/null
+++ b/libdynld/dynld.c
@@ -1,0 +1,258 @@
+#include	"lib9.h"
+#include	<a.out.h>
+#include	<dynld.h>
+
+static ulong
+get2(uchar *b)
+{
+	return (b[0] << 8) | b[1];
+}
+
+static ulong
+get4(uchar *b)
+{
+	return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+}
+
+static ulong
+lgetbe(ulong l)
+{
+	union {
+		ulong	 l;
+		uchar	c[4];
+	} u;
+	u.l = l;
+	return get4(u.c);
+}
+
+Dynsym*
+dynfindsym(char *s, Dynsym *tab, int ntab)
+{
+	int n, n2, d;
+	Dynsym *t, *m;
+
+	t = tab;
+	n = ntab;
+	while(n > 0){
+		n2 = n>>1;
+		m = t+n2;
+		d = strcmp(s, m->name);
+		if(d < 0){
+			n = n2;
+			continue;
+		}
+		if(d > 0){
+			t = m+1;
+			n -= n2+1;
+			continue;
+		}
+		return m;
+	}
+	return nil;
+}
+
+void*
+dynimport(Dynobj *o, char *name, ulong sig)
+{
+	Dynsym *t;
+
+	t = dynfindsym(name, o->export, o->nexport);
+	if(t == nil || sig != 0 && t->sig != 0 && t->sig != sig)
+		return nil;
+	return (void*)t->addr;
+}
+
+int
+dyntabsize(Dynsym *t)
+{
+	int n;
+
+	for(n = 0; t->name != nil; t++)
+		n++;
+	return n;
+}
+
+void
+dynobjfree(Dynobj *o)
+{
+	if(o != nil){
+		free(o->base);
+		free(o->import);
+		free(o);
+	}
+}
+
+void
+dynfreeimport(Dynobj *o)
+{
+	free(o->import);
+	o->import = nil;
+	o->nimport = 0;
+}
+
+static char Ereloc[] = "error reading object file";
+
+Dynobj*
+dynloadgen(void *file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int), void (*werr)(char*), Dynsym *tab, int ntab, ulong maxsize)
+{
+	int i, m, n, ni, nr, relsize;
+	ulong syms, entry, sig, p, a;
+	uchar *base;
+	Exec e;
+	Dynsym *t;
+	Dynobj *l;
+	char *s, *err, buf[64];
+	uchar *reldata, *rp, *ep;
+	vlong off;
+
+	err = Ereloc;	/* default */
+	off = (*sk)(file, 0, 1);
+	l = mallocz(sizeof(Dynobj), 1);
+	if(l == nil){
+		err = "can't allocate Dynobj";
+		goto Error;
+	}
+	if((*rd)(file, &e, sizeof(Exec)) != sizeof(Exec))
+		goto Error;
+	if(lgetbe(e.magic) != dynmagic()){
+		err = "not dynamic object file or wrong platform";
+		goto Error;
+	}
+	l->text = lgetbe(e.text);
+	l->data = lgetbe(e.data);
+	l->bss = lgetbe(e.bss);
+	syms = lgetbe(e.syms)+lgetbe(e.spsz)+lgetbe(e.pcsz);
+	entry = lgetbe(e.entry);
+	l->size = l->text + l->data + l->bss;
+	if(entry < 0 || entry >= l->size || entry & 3){
+		err = "invalid export table pointer (entry point)";
+		goto Error;
+	}
+	if(maxsize && l->size >= maxsize){
+		snprint(buf, sizeof(buf), "%lud: object too big", l->size);
+		err = buf;
+		goto Error;
+	}
+
+	l->base = base = malloc(l->size);
+	if(base == nil){
+		err = "out of memory: loading object file";
+		goto Error;
+	}
+	l->export = (Dynsym*)(base+entry);
+	if((*rd)(file, base, l->text+l->data) != l->text+l->data)
+		goto Error;
+	memset(base+l->text+l->data, 0, l->bss);
+	if((*sk)(file, syms, 1) < 0)
+		goto Error;
+	if((*rd)(file, buf, 4) != 4)
+		goto Error;
+	relsize = get4((uchar*)buf);	/* always contains at least an import count (might be zero) */
+	if(relsize < 4)
+		goto Error;
+	reldata = malloc(relsize);
+	if(reldata == nil){
+		err = "out of memory: relocation data";
+		goto Error;
+	}
+	if((*rd)(file, reldata, relsize) != relsize)
+		goto Error;
+	rp = reldata;
+	ep = reldata+relsize;
+	ni = get4(rp);
+	rp += 4;
+	if(ni < 0 || ni > 8000)
+		goto Error;	/* implausible size */
+	l->nimport = ni;
+	l->import = malloc(ni*sizeof(Dynsym*));
+	if(l->import == nil){
+		err = "out of memory: symbol table";
+		goto Error;
+	}
+	for(i = 0; i < ni; i++){
+		if(rp+5 > ep)
+			goto Error;
+		sig = get4(rp);
+		rp += 4;
+		s = (char*)rp;
+		while(*rp++)
+			if(rp >= ep)
+				goto Error;
+		t = dynfindsym(s, tab, ntab);
+		if(t == nil){
+			snprint(buf, sizeof(buf), "undefined symbol: %s", s);
+			err = buf;
+			goto Error;
+		}
+		if(sig != 0 && t->sig != 0 && t->sig != sig){
+			snprint(buf, sizeof(buf), "signature mismatch: %s (%lux != %lux)", s, sig, t->sig);
+			err = buf;
+			goto Error;
+		}
+		l->import[i] = t;
+	}
+
+	a = 0;
+	if(rp+4 > ep)
+		goto Error;
+	nr = get4(rp);
+	rp += 4;
+	for(i = 0; i < nr; i++){
+		if(rp >= ep)
+			goto Error;
+		m = *rp++;
+		n = m>>6;
+		if(rp+(1<<n) > ep)
+			goto Error;
+		switch(n){
+		case 0:
+			p = *rp++;
+			break;
+		case 1:
+			p = get2(rp);
+			rp += 2;
+			break;
+		case 2:
+			p = get4(rp);
+			rp += 4;
+			break;
+		default:
+			goto Error;
+		}
+		a += p;
+		err = dynreloc(base, a, m&0xf, l->import, ni);
+		if(err != nil){
+			snprint(buf, sizeof(buf), "dynamic object: %s", err);
+			err = buf;
+			goto Error;
+		}
+	}
+	free(reldata);
+
+	/* could check relocated export table here */
+	l->nexport = dyntabsize(l->export);
+
+	segflush(base, l->text);
+
+	return l;
+
+Error:
+	if(off >= 0)
+		(*sk)(file, off, 0);	/* restore original file offset */
+	(*werr)(err);
+	dynobjfree(l);
+	return nil;
+}
+
+int
+dynloadable(void* file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int))
+{
+	long magic;
+
+	if((*rd)(file, &magic, sizeof(magic)) != sizeof(magic)){
+		(*sk)(file, -(signed int)sizeof(magic), 1);
+		return 0;
+	}
+	(*sk)(file, -(signed int)sizeof(magic), 1);
+	return lgetbe(magic) == dynmagic();
+}
--- /dev/null
+++ b/libdynld/dynloadfd.c
@@ -1,0 +1,35 @@
+#include "lib9.h"
+#include <a.out.h>
+#include <dynld.h>
+
+typedef struct Fd Fd;
+struct Fd {
+	int	fd;
+};
+
+static long
+readfd(void *a, void *buf, long nbytes)
+{
+	return read(((Fd*)a)->fd, buf, nbytes);
+}
+
+static vlong
+seekfd(void *a, vlong off, int t)
+{
+	return seek(((Fd*)a)->fd, off, t);
+}
+
+static void
+errfd(char *s)
+{
+	werrstr("%s", s);
+}
+
+Dynobj*
+dynloadfd(int fd, Dynsym *sym, int nsym, ulong maxsize)
+{
+	Fd f;
+
+	f.fd = fd;
+	return dynloadgen(&f, readfd, seekfd, errfd, sym, nsym, maxsize);
+}
--- /dev/null
+++ b/libdynld/mkfile
@@ -1,0 +1,12 @@
+<../mkconfig
+
+LIB=libdynld.a
+
+OFILES=\
+	dynld-$OBJTYPE.$O\
+	dynloadfd.$O\
+	dynld.$O\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/lib9.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libfreetype/NOTICE/FTL.txt
@@ -1,0 +1,164 @@
+                    The FreeType Project LICENSE
+                    ----------------------------
+
+                            2000-Feb-08
+
+                       Copyright 1996-2000 by
+          David Turner, Robert Wilhelm, and Werner Lemberg
+
+
+
+Introduction
+============
+
+  The FreeType  Project is distributed in  several archive packages;
+  some of them may contain, in addition to the FreeType font engine,
+  various tools and  contributions which rely on, or  relate to, the
+  FreeType Project.
+
+  This  license applies  to all  files found  in such  packages, and
+  which do not  fall under their own explicit  license.  The license
+  affects  thus  the  FreeType   font  engine,  the  test  programs,
+  documentation and makefiles, at the very least.
+
+  This  license   was  inspired  by  the  BSD,   Artistic,  and  IJG
+  (Independent JPEG  Group) licenses, which  all encourage inclusion
+  and  use of  free  software in  commercial  and freeware  products
+  alike.  As a consequence, its main points are that:
+
+    o We don't promise that this software works. However, we will be
+      interested in any kind of bug reports. (`as is' distribution)
+
+    o You can  use this software for whatever you  want, in parts or
+      full form, without having to pay us. (`royalty-free' usage)
+
+    o You may not pretend that  you wrote this software.  If you use
+      it, or  only parts of it,  in a program,  you must acknowledge
+      somewhere  in  your  documentation  that  you  have  used  the
+      FreeType code. (`credits')
+
+  We  specifically  permit  and  encourage  the  inclusion  of  this
+  software, with  or without modifications,  in commercial products.
+  We  disclaim  all warranties  covering  The  FreeType Project  and
+  assume no liability related to The FreeType Project.
+
+
+Legal Terms
+===========
+
+0. Definitions
+--------------
+
+  Throughout this license,  the terms `package', `FreeType Project',
+  and  `FreeType  archive' refer  to  the  set  of files  originally
+  distributed  by the  authors  (David Turner,  Robert Wilhelm,  and
+  Werner Lemberg) as the `FreeType Project', be they named as alpha,
+  beta or final release.
+
+  `You' refers to  the licensee, or person using  the project, where
+  `using' is a generic term including compiling the project's source
+  code as  well as linking it  to form a  `program' or `executable'.
+  This  program is  referred to  as  `a program  using the  FreeType
+  engine'.
+
+  This  license applies  to all  files distributed  in  the original
+  FreeType  Project,   including  all  source   code,  binaries  and
+  documentation,  unless  otherwise  stated   in  the  file  in  its
+  original, unmodified form as  distributed in the original archive.
+  If you are  unsure whether or not a particular  file is covered by
+  this license, you must contact us to verify this.
+
+  The FreeType  Project is copyright (C) 1996-2000  by David Turner,
+  Robert Wilhelm, and Werner Lemberg.  All rights reserved except as
+  specified below.
+
+1. No Warranty
+--------------
+
+  THE FREETYPE PROJECT  IS PROVIDED `AS IS' WITHOUT  WARRANTY OF ANY
+  KIND, EITHER  EXPRESS OR IMPLIED,  INCLUDING, BUT NOT  LIMITED TO,
+  WARRANTIES  OF  MERCHANTABILITY   AND  FITNESS  FOR  A  PARTICULAR
+  PURPOSE.  IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE  FOR ANY DAMAGES CAUSED  BY THE USE OR  THE INABILITY TO
+  USE, OF THE FREETYPE PROJECT.
+
+2. Redistribution
+-----------------
+
+  This  license  grants  a  worldwide, royalty-free,  perpetual  and
+  irrevocable right  and license to use,  execute, perform, compile,
+  display,  copy,   create  derivative  works   of,  distribute  and
+  sublicense the  FreeType Project (in  both source and  object code
+  forms)  and  derivative works  thereof  for  any  purpose; and  to
+  authorize others  to exercise  some or all  of the  rights granted
+  herein, subject to the following conditions:
+
+    o Redistribution  of source code  must retain this  license file
+      (`LICENSE.TXT') unaltered; any additions, deletions or changes
+      to   the  original   files  must   be  clearly   indicated  in
+      accompanying  documentation.   The  copyright notices  of  the
+      unaltered, original  files must be preserved in  all copies of
+      source files.
+
+    o Redistribution in binary form must provide a  disclaimer  that
+      states  that  the software is based in part of the work of the
+      FreeType Team,  in  the  distribution  documentation.  We also
+      encourage you to put an URL to the FreeType web page  in  your
+      documentation, though this isn't mandatory.
+
+  These conditions  apply to any  software derived from or  based on
+  the FreeType Project,  not just the unmodified files.   If you use
+  our work, you  must acknowledge us.  However, no  fee need be paid
+  to us.
+
+3. Advertising
+--------------
+
+  Neither the  FreeType authors and  contributors nor you  shall use
+  the name of the  other for commercial, advertising, or promotional
+  purposes without specific prior written permission.
+
+  We suggest,  but do not require, that  you use one or  more of the
+  following phrases to refer  to this software in your documentation
+  or advertising  materials: `FreeType Project',  `FreeType Engine',
+  `FreeType library', or `FreeType Distribution'.
+
+  As  you have  not signed  this license,  you are  not  required to
+  accept  it.   However,  as  the FreeType  Project  is  copyrighted
+  material, only  this license, or  another one contracted  with the
+  authors, grants you  the right to use, distribute,  and modify it.
+  Therefore,  by  using,  distributing,  or modifying  the  FreeType
+  Project, you indicate that you understand and accept all the terms
+  of this license.
+
+4. Contacts
+-----------
+
+  There are two mailing lists related to FreeType:
+
+    o freetype@freetype.org
+
+      Discusses general use and applications of FreeType, as well as
+      future and  wanted additions to the  library and distribution.
+      If  you are looking  for support,  start in  this list  if you
+      haven't found anything to help you in the documentation.
+
+    o devel@freetype.org
+
+      Discusses bugs,  as well  as engine internals,  design issues,
+      specific licenses, porting, etc.
+
+    o http://www.freetype.org
+
+      Holds the current  FreeType web page, which will  allow you to
+      download  our  latest  development  version  and  read  online
+      documentation.
+
+  You can also contact us individually at:
+
+    David Turner      <david.turner@freetype.org>
+    Robert Wilhelm    <robert.wilhelm@freetype.org>
+    Werner Lemberg    <werner.lemberg@freetype.org>
+
+
+--- end of LICENSE.TXT ---
--- /dev/null
+++ b/libfreetype/NOTICE/GPL.txt
@@ -1,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+++ b/libfreetype/NOTICE/PATENTS
@@ -1,0 +1,27 @@
+
+                    FreeType Patents Disclaimer
+                            August 1999
+
+
+
+WE HAVE  DISCOVERED THAT APPLE  OWNS SEVERAL PATENTS RELATED  TO THE
+RENDERING OF TRUETYPE  FONTS.  THIS COULD MEAN THAT  THE FREE USE OF
+FREETYPE  MIGHT BE  ILLEGAL IN  THE USA,  JAPAN, AND  POSSIBLY OTHER
+COUNTRIES, BE IT IN COMMERCIAL OR OPEN SOURCE PRODUCTS.
+
+FOR  MORE DETAILS,  WE STRONGLY  ADVISE YOU  TO GO  TO  THE FREETYPE
+PATENTS PAGE AT THE FOLLOWING WEB ADDRESS:
+
+                http://www.freetype.org/patents.htm
+
+WE WILL NOT PLACE INFORMATION IN THIS FILE AS THE SITUATION IS STILL
+UNDETERMINED FOR NOW.  AT THE  TIME THESE LINES ARE WRITTEN, WE HAVE
+CONTACTED APPLE'S  LEGAL DEPARTMENT AND ARE STILL  WAITING FOR THEIR
+ANSWER ON THE SUBJECT.
+
+PLEASE READ  THE `INSTALL' FILE TO  SEE HOW TO  DISABLE THE ENGINE'S
+BYTECODE INTERPRETER IN ORDER TO  BUILD A PATENT-FREE ENGINE, AT THE
+COST OF RENDERING QUALITY.
+
+
+--- end of PATENTS ---
--- /dev/null
+++ b/libfreetype/NOTICE/license.txt
@@ -1,0 +1,10 @@
+
+FreeType comes with two licenses from which you can choose the one which
+fits your needs best:
+
+  . The FreeType License, in file `docs/FTL.txt'.
+
+  . The GNU General Public License, in file `docs/GPL.txt'.
+
+The contributed PCF driver comes with a license similar to that of X Windows
+which is compatible to the above two licenses (see file src/pcf/readme).
--- /dev/null
+++ b/libfreetype/adler32.c
@@ -1,0 +1,48 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: adler32.c,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#include "zlib.h"
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+ZEXTERNDEF uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
--- /dev/null
+++ b/libfreetype/ahangles.c
@@ -1,0 +1,147 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahangles.h                                                             */
+/*                                                                         */
+/*    A routine used to compute vector angles with limited accuracy        */
+/*    and very high speed (body).                                          */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahangles.h"
+
+
+  /* the following table has been automatically generated with */
+  /* the `mather.py' Python script                             */
+
+  const AH_Angle  ah_arctan[1L << AH_ATAN_BITS] =
+  {
+     0,  0,  1,  1,  1,  2,  2,  2,
+     3,  3,  3,  3,  4,  4,  4,  5,
+     5,  5,  6,  6,  6,  7,  7,  7,
+     8,  8,  8,  9,  9,  9, 10, 10,
+    10, 10, 11, 11, 11, 12, 12, 12,
+    13, 13, 13, 14, 14, 14, 14, 15,
+    15, 15, 16, 16, 16, 17, 17, 17,
+    18, 18, 18, 18, 19, 19, 19, 20,
+    20, 20, 21, 21, 21, 21, 22, 22,
+    22, 23, 23, 23, 24, 24, 24, 24,
+    25, 25, 25, 26, 26, 26, 26, 27,
+    27, 27, 28, 28, 28, 28, 29, 29,
+    29, 30, 30, 30, 30, 31, 31, 31,
+    31, 32, 32, 32, 33, 33, 33, 33,
+    34, 34, 34, 34, 35, 35, 35, 35,
+    36, 36, 36, 36, 37, 37, 37, 38,
+    38, 38, 38, 39, 39, 39, 39, 40,
+    40, 40, 40, 41, 41, 41, 41, 42,
+    42, 42, 42, 42, 43, 43, 43, 43,
+    44, 44, 44, 44, 45, 45, 45, 45,
+    46, 46, 46, 46, 46, 47, 47, 47,
+    47, 48, 48, 48, 48, 48, 49, 49,
+    49, 49, 50, 50, 50, 50, 50, 51,
+    51, 51, 51, 51, 52, 52, 52, 52,
+    52, 53, 53, 53, 53, 53, 54, 54,
+    54, 54, 54, 55, 55, 55, 55, 55,
+    56, 56, 56, 56, 56, 57, 57, 57,
+    57, 57, 57, 58, 58, 58, 58, 58,
+    59, 59, 59, 59, 59, 59, 60, 60,
+    60, 60, 60, 61, 61, 61, 61, 61,
+    61, 62, 62, 62, 62, 62, 62, 63,
+    63, 63, 63, 63, 63, 64, 64, 64
+  };
+
+
+  FT_LOCAL_DEF( AH_Angle )
+  ah_angle( FT_Vector*  v )
+  {
+    FT_Pos    dx, dy;
+    AH_Angle  angle;
+
+
+    dx = v->x;
+    dy = v->y;
+
+    /* check trivial cases */
+    if ( dy == 0 )
+    {
+      angle = 0;
+      if ( dx < 0 )
+        angle = AH_PI;
+      return angle;
+    }
+    else if ( dx == 0 )
+    {
+      angle = AH_HALF_PI;
+      if ( dy < 0 )
+        angle = -AH_HALF_PI;
+      return angle;
+    }
+
+    angle = 0;
+    if ( dx < 0 )
+    {
+      dx = -v->x;
+      dy = -v->y;
+      angle = AH_PI;
+    }
+
+    if ( dy < 0 )
+    {
+      FT_Pos  tmp;
+
+
+      tmp = dx;
+      dx  = -dy;
+      dy  = tmp;
+      angle -= AH_HALF_PI;
+    }
+
+    if ( dx == 0 && dy == 0 )
+      return 0;
+
+    if ( dx == dy )
+      angle += AH_PI / 4;
+    else if ( dx > dy )
+      angle += ah_arctan[FT_DivFix( dy, dx ) >> ( 16 - AH_ATAN_BITS )];
+    else
+      angle += AH_HALF_PI -
+               ah_arctan[FT_DivFix( dx, dy ) >> ( 16 - AH_ATAN_BITS )];
+
+    if ( angle > AH_PI )
+      angle -= AH_2PI;
+
+    return angle;
+  }
+
+
+  FT_LOCAL_DEF( AH_Angle )
+  ah_angle_diff( AH_Angle  angle1,
+                 AH_Angle  angle2 )
+  {
+    AH_Angle  delta;
+    
+
+    delta = ( angle2 - angle1 );
+    if ( delta < 0 )
+      delta += AH_2PI;
+    
+    if ( delta > AH_PI )
+      delta -= AH_2PI;
+    
+    return delta;
+  }                 
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahangles.h
@@ -1,0 +1,64 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahangles.h                                                             */
+/*                                                                         */
+/*    A routine used to compute vector angles with limited accuracy        */
+/*    and very high speed (specification).                                 */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AHANGLES_H__
+#define __AHANGLES_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+  /* PI expressed in ah_angles -- we don't really need an important */
+  /* precision, so 256 should be enough                             */
+#define AH_PI       256
+#define AH_2PI      ( AH_PI * 2 )
+#define AH_HALF_PI  ( AH_PI / 2 )
+#define AH_2PIMASK  ( AH_2PI - 1 )
+
+  /* the number of bits used to express an arc tangent; */
+  /* see the structure of the lookup table              */
+#define AH_ATAN_BITS  8
+
+  extern
+  const AH_Angle  ah_arctan[1L << AH_ATAN_BITS];
+
+
+  FT_LOCAL( AH_Angle )
+  ah_angle( FT_Vector*  v );
+
+
+  FT_LOCAL( AH_Angle )
+  ah_angle_diff( AH_Angle  angle1,
+                 AH_Angle  angle2 );
+
+
+FT_END_HEADER
+
+#endif /* __AHANGLES_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/aherrors.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  aherrors.h                                                             */
+/*                                                                         */
+/*    Autohinter error codes (specification only).                         */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the Autohinter error enumeration          */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __AHERRORS_H__
+#define __AHERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  AH_Err_
+#define FT_ERR_BASE    FT_Mod_Err_Autohint
+
+#include FT_ERRORS_H
+
+#endif /* __AHERRORS_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglobal.c
@@ -1,0 +1,395 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahglobal.c                                                             */
+/*                                                                         */
+/*    Routines used to compute global metrics automatically (body).        */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include "ahglobal.h"
+#include "ahglyph.h"
+
+
+#define MAX_TEST_CHARACTERS  12
+
+  static
+  const char*  blue_chars[AH_BLUE_MAX] =
+  {
+    "THEZOCQS",
+    "HEZLOCUS",
+    "xzroesc",
+    "xzroesc",
+    "pqgjy"
+  };
+
+
+  /* simple insertion sort */
+  static void
+  sort_values( FT_Int   count,
+               FT_Pos*  table )
+  {
+    FT_Int  i, j;
+    FT_Pos  swap;
+
+
+    for ( i = 1; i < count; i++ )
+    {
+      for ( j = i; j > 0; j-- )
+      {
+        if ( table[j] > table[j - 1] )
+          break;
+
+        swap         = table[j];
+        table[j]     = table[j - 1];
+        table[j - 1] = swap;
+      }
+    }
+  }
+
+
+  static FT_Error
+  ah_hinter_compute_blues( AH_Hinter  hinter )
+  {
+    AH_Blue       blue;
+    AH_Globals    globals = &hinter->globals->design;
+    FT_Pos        flats [MAX_TEST_CHARACTERS];
+    FT_Pos        rounds[MAX_TEST_CHARACTERS];
+    FT_Int        num_flats;
+    FT_Int        num_rounds;
+
+    FT_Face       face;
+    FT_GlyphSlot  glyph;
+    FT_Error      error;
+    FT_CharMap    charmap;
+
+
+    face  = hinter->face;
+    glyph = face->glyph;
+
+    /* save current charmap */
+    charmap = face->charmap;
+
+    /* do we have a Unicode charmap in there? */
+    error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
+    if ( error )
+      goto Exit;
+
+    /* we compute the blues simply by loading each character from the */
+    /* 'blue_chars[blues]' string, then compute its top-most and      */
+    /* bottom-most points                                             */
+
+    AH_LOG(( "blue zones computation\n" ));
+    AH_LOG(( "------------------------------------------------\n" ));
+
+    for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ )
+    {
+      const char*  p     = blue_chars[blue];
+      const char*  limit = p + MAX_TEST_CHARACTERS;
+      FT_Pos       *blue_ref, *blue_shoot;
+
+
+      AH_LOG(( "blue %3d: ", blue ));
+
+      num_flats  = 0;
+      num_rounds = 0;
+
+      for ( ; p < limit; p++ )
+      {
+        FT_UInt     glyph_index;
+        FT_Vector*  extremum;
+        FT_Vector*  points;
+        FT_Vector*  point_limit;
+        FT_Vector*  point;
+        FT_Bool     round;
+
+
+        /* exit if we reach the end of the string */
+        if ( !*p )
+          break;
+
+        AH_LOG(( "`%c'", *p ));
+
+        /* load the character in the face -- skip unknown or empty ones */
+        glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
+        if ( glyph_index == 0 )
+          continue;
+
+        error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+        if ( error || glyph->outline.n_points <= 0 )
+          continue;
+
+        /* now compute min or max point indices and coordinates */
+        points      = glyph->outline.points;
+        point_limit = points + glyph->outline.n_points;
+        point       = points;
+        extremum    = point;
+        point++;
+
+        if ( AH_IS_TOP_BLUE( blue ) )
+        {
+          for ( ; point < point_limit; point++ )
+            if ( point->y > extremum->y )
+              extremum = point;
+        }
+        else
+        {
+          for ( ; point < point_limit; point++ )
+            if ( point->y < extremum->y )
+              extremum = point;
+        }
+
+        AH_LOG(( "%5d", (int)extremum->y ));
+
+        /* now, check whether the point belongs to a straight or round  */
+        /* segment; we first need to find in which contour the extremum */
+        /* lies, then see its previous and next points                  */
+        {
+          FT_Int  idx = (FT_Int)( extremum - points );
+          FT_Int  n;
+          FT_Int  first, last, prev, next, end;
+          FT_Pos  dist;
+
+
+          last  = -1;
+          first = 0;
+
+          for ( n = 0; n < glyph->outline.n_contours; n++ )
+          {
+            end = glyph->outline.contours[n];
+            if ( end >= idx )
+            {
+              last = end;
+              break;
+            }
+            first = end + 1;
+          }
+
+          /* XXX: should never happen! */
+          if ( last < 0 )
+            continue;
+
+          /* now look for the previous and next points that are not on the */
+          /* same Y coordinate.  Threshold the `closeness'...              */
+
+          prev = idx;
+          next = prev;
+
+          do
+          {
+            if ( prev > first )
+              prev--;
+            else
+              prev = last;
+
+            dist = points[prev].y - extremum->y;
+            if ( dist < -5 || dist > 5 )
+              break;
+
+          } while ( prev != idx );
+
+          do
+          {
+            if ( next < last )
+              next++;
+            else
+              next = first;
+
+            dist = points[next].y - extremum->y;
+            if ( dist < -5 || dist > 5 )
+              break;
+
+          } while ( next != idx );
+
+          /* now, set the `round' flag depending on the segment's kind */
+          round = FT_BOOL(
+            FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
+            FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
+
+          AH_LOG(( "%c ", round ? 'r' : 'f' ));
+        }
+
+        if ( round )
+          rounds[num_rounds++] = extremum->y;
+        else
+          flats[num_flats++] = extremum->y;
+      }
+
+      AH_LOG(( "\n" ));
+
+      /* we have computed the contents of the `rounds' and `flats' tables, */
+      /* now determine the reference and overshoot position of the blue;   */
+      /* we simply take the median value after a simple short              */
+      sort_values( num_rounds, rounds );
+      sort_values( num_flats,  flats  );
+
+      blue_ref   = globals->blue_refs + blue;
+      blue_shoot = globals->blue_shoots + blue;
+      if ( num_flats == 0 && num_rounds == 0 )
+      {
+        *blue_ref   = -10000;
+        *blue_shoot = -10000;
+      }
+      else if ( num_flats == 0 )
+      {
+        *blue_ref   =
+        *blue_shoot = rounds[num_rounds / 2];
+      }
+      else if ( num_rounds == 0 )
+      {
+        *blue_ref   =
+        *blue_shoot = flats[num_flats / 2];
+      }
+      else
+      {
+        *blue_ref   = flats[num_flats / 2];
+        *blue_shoot = rounds[num_rounds / 2];
+      }
+
+      /* there are sometimes problems: if the overshoot position of top     */
+      /* zones is under its reference position, or the opposite for bottom  */
+      /* zones.  We must thus check everything there and correct the errors */
+      if ( *blue_shoot != *blue_ref )
+      {
+        FT_Pos   ref      = *blue_ref;
+        FT_Pos   shoot    = *blue_shoot;
+        FT_Bool  over_ref = FT_BOOL( shoot > ref );
+
+
+        if ( AH_IS_TOP_BLUE( blue ) ^ over_ref )
+          *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+      }
+
+      AH_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+    }
+
+    /* reset original face charmap */
+    FT_Set_Charmap( face, charmap );
+    error = 0;
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  ah_hinter_compute_widths( AH_Hinter  hinter )
+  {
+    /* scan the array of segments in each direction */
+    AH_Outline  outline = hinter->glyph;
+    AH_Segment  segments;
+    AH_Segment  limit;
+    AH_Globals  globals = &hinter->globals->design;
+    FT_Pos*     widths;
+    FT_Int      dimension;
+    FT_Int*     p_num_widths;
+    FT_Error    error = 0;
+    FT_Pos      edge_distance_threshold = 32000;
+
+
+    globals->num_widths  = 0;
+    globals->num_heights = 0;
+
+    /* For now, compute the standard width and height from the `o'       */
+    /* character.  I started computing the stem width of the `i' and the */
+    /* stem height of the "-", but it wasn't too good.  Moreover, we now */
+    /* have a single character that gives us standard width and height.  */
+    {
+      FT_UInt   glyph_index;
+
+
+      glyph_index = FT_Get_Char_Index( hinter->face, 'o' );
+      if ( glyph_index == 0 )
+        return 0;
+
+      error = FT_Load_Glyph( hinter->face, glyph_index, FT_LOAD_NO_SCALE );
+      if ( error )
+        goto Exit;
+
+      error = ah_outline_load( hinter->glyph, hinter->face );
+      if ( error )
+        goto Exit;
+
+      ah_outline_compute_segments( hinter->glyph );
+      ah_outline_link_segments( hinter->glyph );
+    }
+
+    segments     = outline->horz_segments;
+    limit        = segments + outline->num_hsegments;
+    widths       = globals->heights;
+    p_num_widths = &globals->num_heights;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Segment  seg = segments;
+      AH_Segment  link;
+      FT_Int      num_widths = 0;
+
+
+      for ( ; seg < limit; seg++ )
+      {
+        link = seg->link;
+        /* we only consider stem segments there! */
+        if ( link && link->link == seg && link > seg )
+        {
+          FT_Pos  dist;
+
+
+          dist = seg->pos - link->pos;
+          if ( dist < 0 )
+            dist = -dist;
+
+          if ( num_widths < AH_MAX_WIDTHS )
+            widths[num_widths++] = dist;
+        }
+      }
+
+      sort_values( num_widths, widths );
+      *p_num_widths = num_widths;
+
+      /* we will now try to find the smallest width */
+      if ( num_widths > 0 && widths[0] < edge_distance_threshold )
+        edge_distance_threshold = widths[0];
+
+      segments     = outline->vert_segments;
+      limit        = segments + outline->num_vsegments;
+      widths       = globals->widths;
+      p_num_widths = &globals->num_widths;
+    }
+
+    /* Now, compute the edge distance threshold as a fraction of the */
+    /* smallest width in the font. Set it in `hinter.glyph' too!     */
+    if ( edge_distance_threshold == 32000 )
+      edge_distance_threshold = 50;
+
+    /* let's try 20% */
+    hinter->glyph->edge_distance_threshold = edge_distance_threshold / 5;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  ah_hinter_compute_globals( AH_Hinter  hinter )
+  {
+    return ah_hinter_compute_widths( hinter ) ||
+           ah_hinter_compute_blues ( hinter );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglobal.h
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahglobal.h                                                             */
+/*                                                                         */
+/*    Routines used to compute global metrics automatically                */
+/*    (specification).                                                     */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AHGLOBAL_H__
+#define __AHGLOBAL_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+#define AH_IS_TOP_BLUE( b )  ( (b) == AH_BLUE_CAPITAL_TOP || \
+                               (b) == AH_BLUE_SMALL_TOP   )
+
+
+  /* compute global metrics automatically */
+  FT_LOCAL( FT_Error )
+  ah_hinter_compute_globals( AH_Hinter  hinter );
+
+
+FT_END_HEADER
+
+#endif /* __AHGLOBAL_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglyph.c
@@ -1,0 +1,1579 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahglyph.c                                                              */
+/*                                                                         */
+/*    Routines used to load and analyze a given glyph before hinting       */
+/*    (body).                                                              */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahglyph.h"
+#include "ahangles.h"
+#include "ahglobal.h"
+#include "aherrors.h"
+
+
+#ifdef AH_DEBUG
+
+#include <stdio.h>
+
+  void
+  ah_dump_edges( AH_Outline  outline )
+  {
+    AH_Edge     edges;
+    AH_Edge     edge_limit;
+    AH_Segment  segments;
+    FT_Int      dimension;
+
+
+    edges      = outline->horz_edges;
+    edge_limit = edges + outline->num_hedges;
+    segments   = outline->horz_segments;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Edge   edge;
+
+
+      printf ( "Table of %s edges:\n",
+               !dimension ? "vertical" : "horizontal" );
+      printf ( "  [ index |  pos |  dir  | link |"
+               " serif | blue | opos  |  pos  ]\n" );
+
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        printf ( "  [ %5d | %4d | %5s | %4d | %5d |  %c  | %5.2f | %5.2f ]\n",
+                 edge - edges,
+                 (int)edge->fpos,
+                 edge->dir == AH_DIR_UP
+                   ? "up"
+                   : ( edge->dir == AH_DIR_DOWN
+                         ? "down"
+                         : ( edge->dir == AH_DIR_LEFT
+                               ? "left"
+                               : ( edge->dir == AH_DIR_RIGHT
+                                     ? "right"
+                                     : "none" ) ) ),
+                 edge->link ? ( edge->link - edges ) : -1,
+                 edge->serif ? ( edge->serif - edges ) : -1,
+                 edge->blue_edge ? 'y' : 'n',
+                 edge->opos / 64.0,
+                 edge->pos / 64.0 );
+      }
+
+      edges      = outline->vert_edges;
+      edge_limit = edges + outline->num_vedges;
+      segments   = outline->vert_segments;
+    }
+  }
+
+
+  /* A function used to dump the array of linked segments */
+  void
+  ah_dump_segments( AH_Outline  outline )
+  {
+    AH_Segment  segments;
+    AH_Segment  segment_limit;
+    AH_Point    points;
+    FT_Int      dimension;
+
+
+    points        = outline->points;
+    segments      = outline->horz_segments;
+    segment_limit = segments + outline->num_hsegments;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Segment  seg;
+
+
+      printf ( "Table of %s segments:\n",
+               !dimension ? "vertical" : "horizontal" );
+      printf ( "  [ index |  pos |  dir  | link | serif |"
+               " numl | first | start ]\n" );
+
+      for ( seg = segments; seg < segment_limit; seg++ )
+      {
+        printf ( "  [ %5d | %4d | %5s | %4d | %5d | %4d | %5d | %5d ]\n",
+                 seg - segments,
+                 (int)seg->pos,
+                 seg->dir == AH_DIR_UP
+                   ? "up"
+                   : ( seg->dir == AH_DIR_DOWN
+                         ? "down"
+                         : ( seg->dir == AH_DIR_LEFT
+                               ? "left"
+                               : ( seg->dir == AH_DIR_RIGHT
+                                     ? "right"
+                                     : "none" ) ) ),
+                 seg->link ? (seg->link-segments) : -1,
+                 seg->serif ? (seg->serif-segments) : -1,
+                 (int)seg->num_linked,
+                 seg->first - points,
+                 seg->last - points );
+      }
+
+      segments      = outline->vert_segments;
+      segment_limit = segments + outline->num_vsegments;
+    }
+  }
+
+#endif /* AH_DEBUG */
+
+
+  /* compute the direction value of a given vector.. */
+  static AH_Direction
+  ah_compute_direction( FT_Pos  dx,
+                        FT_Pos  dy )
+  {
+    AH_Direction  dir;
+    FT_Pos        ax = ABS( dx );
+    FT_Pos        ay = ABS( dy );
+
+
+    dir = AH_DIR_NONE;
+
+    /* test for vertical direction */
+    if ( ax * 12 < ay )
+    {
+      dir = dy > 0 ? AH_DIR_UP : AH_DIR_DOWN;
+    }
+    /* test for horizontal direction */
+    else if ( ay * 12 < ax )
+    {
+      dir = dx > 0 ? AH_DIR_RIGHT : AH_DIR_LEFT;
+    }
+
+    return dir;
+  }
+
+
+  /* this function is used by ah_get_orientation (see below) to test */
+  /* the fill direction of a given bbox extrema                      */
+  static FT_Int
+  ah_test_extrema( FT_Outline*  outline,
+                   FT_Int       n )
+  {
+    FT_Vector  *prev, *cur, *next;
+    FT_Pos      product;
+    FT_Int      first, last, c;
+    FT_Int      retval;
+
+
+    /* we need to compute the `previous' and `next' point */
+    /* for these extrema                                  */
+    cur  = outline->points + n;
+    prev = cur - 1;
+    next = cur + 1;
+
+    first = 0;
+    for ( c = 0; c < outline->n_contours; c++ )
+    {
+      last  = outline->contours[c];
+
+      if ( n == first )
+        prev = outline->points + last;
+
+      if ( n == last )
+        next = outline->points + first;
+
+      first = last + 1;
+    }
+
+    product = FT_MulDiv( cur->x  - prev->x,  /* in.x  */
+                         next->y - cur->y,   /* out.y */
+                         0x40 )
+              -
+              FT_MulDiv( cur->y  - prev->y,  /* in.y  */
+                         next->x - cur->x,   /* out.x */
+                         0x40 );
+
+    retval = 0;
+    if ( product )
+      retval = product > 0 ? 2 : 1;
+
+    return retval;
+  }
+
+
+  /* Compute the orientation of path filling.  It differs between TrueType */
+  /* and Type1 formats.  We could use the `FT_OUTLINE_REVERSE_FILL' flag,  */
+  /* but it is better to re-compute it directly (it seems that this flag   */
+  /* isn't correctly set for some weird composite glyphs currently).       */
+  /*                                                                       */
+  /* We do this by computing bounding box points, and computing their      */
+  /* curvature.                                                            */
+  /*                                                                       */
+  /* The function returns either 1 or -1.                                  */
+  /*                                                                       */
+  static FT_Int
+  ah_get_orientation( FT_Outline*  outline )
+  {
+    FT_BBox  box;
+    FT_Int   indices_xMin, indices_yMin, indices_xMax, indices_yMax;
+    FT_Int   n, last;
+
+
+    indices_xMin = -1;
+    indices_yMin = -1;
+    indices_xMax = -1;
+    indices_yMax = -1;
+
+    box.xMin = box.yMin =  32767L;
+    box.xMax = box.yMax = -32768L;
+
+    /* is it empty? */
+    if ( outline->n_contours < 1 )
+      return 1;
+
+    last = outline->contours[outline->n_contours - 1];
+
+    for ( n = 0; n <= last; n++ )
+    {
+      FT_Pos  x, y;
+
+
+      x = outline->points[n].x;
+      if ( x < box.xMin )
+      {
+        box.xMin     = x;
+        indices_xMin = n;
+      }
+      if ( x > box.xMax )
+      {
+        box.xMax     = x;
+        indices_xMax = n;
+      }
+
+      y = outline->points[n].y;
+      if ( y < box.yMin )
+      {
+        box.yMin     = y;
+        indices_yMin = n;
+      }
+      if ( y > box.yMax )
+      {
+        box.yMax     = y;
+        indices_yMax = n;
+      }
+    }
+
+    /* test orientation of the xmin */
+    n = ah_test_extrema( outline, indices_xMin );
+    if ( n )
+      goto Exit;
+
+    n = ah_test_extrema( outline, indices_yMin );
+    if ( n )
+      goto Exit;
+
+    n = ah_test_extrema( outline, indices_xMax );
+    if ( n )
+      goto Exit;
+
+    n = ah_test_extrema( outline, indices_yMax );
+    if ( !n )
+      n = 1;
+
+  Exit:
+    return n;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ah_outline_new                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Creates a new and empty AH_OutlineRec object.                      */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  ah_outline_new( FT_Memory    memory,
+                  AH_Outline*  aoutline )
+  {
+    FT_Error     error;
+    AH_Outline   outline;
+
+
+    if ( !FT_NEW( outline ) )
+    {
+      outline->memory = memory;
+      *aoutline = outline;
+    }
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ah_outline_done                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Destroys a given AH_OutlineRec object.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  ah_outline_done( AH_Outline  outline )
+  {
+    FT_Memory memory = outline->memory;
+
+
+    FT_FREE( outline->horz_edges );
+    FT_FREE( outline->horz_segments );
+    FT_FREE( outline->contours );
+    FT_FREE( outline->points );
+
+    FT_FREE( outline );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ah_outline_save                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Saves the contents of a given AH_OutlineRec object into a face's   */
+  /*    glyph slot.                                                        */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  ah_outline_save( AH_Outline  outline,
+                   AH_Loader   gloader )
+  {
+    AH_Point    point       = outline->points;
+    AH_Point    point_limit = point + outline->num_points;
+    FT_Vector*  vec         = gloader->current.outline.points;
+    char*       tag         = gloader->current.outline.tags;
+
+
+    /* we assume that the glyph loader has already been checked for storage */
+    for ( ; point < point_limit; point++, vec++, tag++ )
+    {
+      vec->x = point->x;
+      vec->y = point->y;
+
+      if ( point->flags & AH_FLAG_CONIC )
+        tag[0] = FT_CURVE_TAG_CONIC;
+      else if ( point->flags & AH_FLAG_CUBIC )
+        tag[0] = FT_CURVE_TAG_CUBIC;
+      else
+        tag[0] = FT_CURVE_TAG_ON;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ah_outline_load                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads an unscaled outline from a glyph slot into an AH_OutlineRec  */
+  /*    object.                                                            */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  ah_outline_load( AH_Outline  outline,
+                   FT_Face     face )
+  {
+    FT_Memory    memory       = outline->memory;
+    FT_Error     error        = AH_Err_Ok;
+    FT_Outline*  source       = &face->glyph->outline;
+    FT_Int       num_points   = source->n_points;
+    FT_Int       num_contours = source->n_contours;
+    AH_Point     points;
+
+
+    /* check arguments */
+    if ( !face                                          ||
+         !face->size                                    ||
+         face->glyph->format != FT_GLYPH_FORMAT_OUTLINE )
+      return AH_Err_Invalid_Argument;
+
+    /* first of all, reallocate the contours array if necessary */
+    if ( num_contours > outline->max_contours )
+    {
+      FT_Int  new_contours = ( num_contours + 3 ) & -4;
+
+
+      if ( FT_RENEW_ARRAY( outline->contours,
+                           outline->max_contours,
+                           new_contours ) )
+        goto Exit;
+
+      outline->max_contours = new_contours;
+    }
+
+    /* then, reallocate the points, segments & edges arrays if needed -- */
+    /* note that we reserved two additional point positions, used to     */
+    /* hint metrics appropriately                                        */
+    /*                                                                   */
+    if ( num_points + 2 > outline->max_points )
+    {
+      FT_Int  news = ( num_points + 2 + 7 ) & -8;
+      FT_Int  max  = outline->max_points;
+
+
+      if ( FT_RENEW_ARRAY( outline->points,        max,     news     ) ||
+           FT_RENEW_ARRAY( outline->horz_edges,    max * 2, news * 2 ) ||
+           FT_RENEW_ARRAY( outline->horz_segments, max * 2, news * 2 ) )
+        goto Exit;
+
+      /* readjust some pointers */
+      outline->vert_edges    = outline->horz_edges    + news;
+      outline->vert_segments = outline->horz_segments + news;
+      outline->max_points    = news;
+    }
+
+    outline->num_points   = num_points;
+    outline->num_contours = num_contours;
+
+    outline->num_hedges    = 0;
+    outline->num_vedges    = 0;
+    outline->num_hsegments = 0;
+    outline->num_vsegments = 0;
+
+    /* We can't rely on the value of `FT_Outline.flags' to know the fill  */
+    /* direction used for a glyph, given that some fonts are broken (e.g. */
+    /* the Arphic ones). We thus recompute it each time we need to.       */
+    /*                                                                    */
+    outline->vert_major_dir = AH_DIR_UP;
+    outline->horz_major_dir = AH_DIR_LEFT;
+
+    if ( ah_get_orientation( source ) > 1 )
+    {
+      outline->vert_major_dir = AH_DIR_DOWN;
+      outline->horz_major_dir = AH_DIR_RIGHT;
+    }
+
+    outline->x_scale = face->size->metrics.x_scale;
+    outline->y_scale = face->size->metrics.y_scale;
+
+    points = outline->points;
+    if ( outline->num_points == 0 )
+      goto Exit;
+
+    {
+      /* do one thing at a time -- it is easier to understand, and */
+      /* the code is clearer                                       */
+      AH_Point  point;
+      AH_Point  point_limit = points + outline->num_points;
+
+
+      /* compute coordinates */
+      {
+        FT_Vector*  vec     = source->points;
+        FT_Fixed    x_scale = outline->x_scale;
+        FT_Fixed    y_scale = outline->y_scale;
+
+
+        for ( point = points; point < point_limit; vec++, point++ )
+        {
+          point->fx = vec->x;
+          point->fy = vec->y;
+          point->ox = point->x = FT_MulFix( vec->x, x_scale );
+          point->oy = point->y = FT_MulFix( vec->y, y_scale );
+
+          point->flags = 0;
+        }
+      }
+
+      /* compute Bezier flags */
+      {
+        char*  tag = source->tags;
+
+
+        for ( point = points; point < point_limit; point++, tag++ )
+        {
+          switch ( FT_CURVE_TAG( *tag ) )
+          {
+          case FT_CURVE_TAG_CONIC:
+            point->flags = AH_FLAG_CONIC; break;
+          case FT_CURVE_TAG_CUBIC:
+            point->flags = AH_FLAG_CUBIC; break;
+          default:
+            ;
+          }
+        }
+      }
+
+      /* compute `next' and `prev' */
+      {
+        FT_Int    contour_index;
+        AH_Point  prev;
+        AH_Point  first;
+        AH_Point  end;
+
+
+        contour_index = 0;
+
+        first = points;
+        end   = points + source->contours[0];
+        prev  = end;
+
+        for ( point = points; point < point_limit; point++ )
+        {
+          point->prev = prev;
+          if ( point < end )
+          {
+            point->next = point + 1;
+            prev        = point;
+          }
+          else
+          {
+            point->next = first;
+            contour_index++;
+            if ( point + 1 < point_limit )
+            {
+              end   = points + source->contours[contour_index];
+              first = point + 1;
+              prev  = end;
+            }
+          }
+        }
+      }
+
+      /* set-up the contours array */
+      {
+        AH_Point*  contour       = outline->contours;
+        AH_Point*  contour_limit = contour + outline->num_contours;
+        short*     end           = source->contours;
+        short      idx           = 0;
+
+
+        for ( ; contour < contour_limit; contour++, end++ )
+        {
+          contour[0] = points + idx;
+          idx        = (short)( end[0] + 1 );
+        }
+      }
+
+      /* compute directions of in & out vectors */
+      {
+        for ( point = points; point < point_limit; point++ )
+        {
+          AH_Point   prev;
+          AH_Point   next;
+          FT_Vector  ivec, ovec;
+
+
+          prev   = point->prev;
+          ivec.x = point->fx - prev->fx;
+          ivec.y = point->fy - prev->fy;
+
+          point->in_dir = ah_compute_direction( ivec.x, ivec.y );
+
+          next   = point->next;
+          ovec.x = next->fx - point->fx;
+          ovec.y = next->fy - point->fy;
+
+          point->out_dir = ah_compute_direction( ovec.x, ovec.y );
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+          if ( point->flags & (AH_FLAG_CONIC | AH_FLAG_CUBIC) )
+          {
+          Is_Weak_Point:
+            point->flags |= AH_FLAG_WEAK_INTERPOLATION;
+          }
+          else if ( point->out_dir == point->in_dir )
+          {
+            AH_Angle  angle_in, angle_out, delta;
+
+
+            if ( point->out_dir != AH_DIR_NONE )
+              goto Is_Weak_Point;
+
+            angle_in  = ah_angle( &ivec );
+            angle_out = ah_angle( &ovec );
+            delta     = angle_in - angle_out;
+
+            if ( delta > AH_PI )
+              delta = AH_2PI - delta;
+
+            if ( delta < 0 )
+              delta = -delta;
+
+            if ( delta < 2 )
+              goto Is_Weak_Point;
+          }
+          else if ( point->in_dir == -point->out_dir )
+            goto Is_Weak_Point;
+#endif
+        }
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ah_setup_uv( AH_Outline  outline,
+               AH_UV       source )
+  {
+    AH_Point  point       = outline->points;
+    AH_Point  point_limit = point + outline->num_points;
+
+
+    for ( ; point < point_limit; point++ )
+    {
+      FT_Pos  u, v;
+
+
+      switch ( source )
+      {
+      case AH_UV_FXY:
+        u = point->fx;
+        v = point->fy;
+        break;
+      case AH_UV_FYX:
+        u = point->fy;
+        v = point->fx;
+        break;
+      case AH_UV_OXY:
+        u = point->ox;
+        v = point->oy;
+        break;
+      case AH_UV_OYX:
+        u = point->oy;
+        v = point->ox;
+        break;
+      case AH_UV_YX:
+        u = point->y;
+        v = point->x;
+        break;
+      case AH_UV_OX:
+        u = point->x;
+        v = point->ox;
+        break;
+      case AH_UV_OY:
+        u = point->y;
+        v = point->oy;
+        break;
+      default:
+        u = point->x;
+        v = point->y;
+        break;
+      }
+      point->u = u;
+      point->v = v;
+    }
+  }
+
+
+  /* compute all inflex points in a given glyph */
+  static void
+  ah_outline_compute_inflections( AH_Outline  outline )
+  {
+    AH_Point*  contour       =  outline->contours;
+    AH_Point*  contour_limit =  contour + outline->num_contours;
+
+
+    /* load original coordinates in (u,v) */
+    ah_setup_uv( outline, AH_UV_FXY );
+
+    /* do each contour separately */
+    for ( ; contour < contour_limit; contour++ )
+    {
+      FT_Vector  vec;
+      AH_Point   point   = contour[0];
+      AH_Point   first   = point;
+      AH_Point   start   = point;
+      AH_Point   end     = point;
+      AH_Point   before;
+      AH_Point   after;
+      AH_Angle   angle_in, angle_seg, angle_out;
+      AH_Angle   diff_in, diff_out;
+      FT_Int     finished = 0;
+
+
+      /* compute first segment in contour */
+      first = point;
+
+      start = end = first;
+      do
+      {
+        end = end->next;
+        if ( end == first )
+          goto Skip;
+
+      } while ( end->u == first->u && end->v == first->v );
+
+      vec.x = end->u - start->u;
+      vec.y = end->v - start->v;
+      angle_seg = ah_angle( &vec );
+
+      /* extend the segment start whenever possible */
+      before = start;
+      do
+      {
+        do
+        {
+          start  = before;
+          before = before->prev;
+          if ( before == first )
+            goto Skip;
+
+        } while ( before->u == start->u && before->v == start->v );
+
+        vec.x    = start->u - before->u;
+        vec.y    = start->v - before->v;
+        angle_in = ah_angle( &vec );
+
+      } while ( angle_in == angle_seg );
+
+      first   = start;
+      diff_in = ah_angle_diff( angle_in, angle_seg );
+
+      /* now, process all segments in the contour */
+      do
+      {
+        /* first, extend current segment's end whenever possible */
+        after = end;
+        do
+        {
+          do
+          {
+            end   = after;
+            after = after->next;
+            if ( after == first )
+              finished = 1;
+
+          } while ( end->u == after->u && end->v == after->v );
+
+          vec.x     = after->u - end->u;
+          vec.y     = after->v - end->v;
+          angle_out = ah_angle( &vec );
+
+        } while ( angle_out == angle_seg );
+
+        diff_out = ah_angle_diff( angle_seg, angle_out );
+
+        if ( ( diff_in ^ diff_out ) < 0 )
+        {
+          /* diff_in and diff_out have different signs, we have */
+          /* inflection points here...                          */
+
+          do
+          {
+            start->flags |= AH_FLAG_INFLECTION;
+            start = start->next;
+
+          } while ( start != end );
+
+          start->flags |= AH_FLAG_INFLECTION;
+        }
+
+        start     = end;
+        end       = after;
+        angle_seg = angle_out;
+        diff_in   = diff_out;
+
+      } while ( !finished );
+
+    Skip:
+      ;
+    }
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ah_outline_compute_segments( AH_Outline  outline )
+  {
+    int           dimension;
+    AH_Segment    segments;
+    FT_Int*       p_num_segments;
+    AH_Direction  segment_dir;
+    AH_Direction  major_dir;
+
+
+    segments       = outline->horz_segments;
+    p_num_segments = &outline->num_hsegments;
+    major_dir      = AH_DIR_RIGHT;      /* This value must be positive! */
+    segment_dir    = major_dir;
+
+    /* set up (u,v) in each point */
+    ah_setup_uv( outline, AH_UV_FYX );
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Point*   contour       =  outline->contours;
+      AH_Point*   contour_limit =  contour + outline->num_contours;
+      AH_Segment  segment       =  segments;
+      FT_Int      num_segments  =  0;
+
+#ifdef AH_HINT_METRICS
+      AH_Point    min_point     =  0;
+      AH_Point    max_point     =  0;
+      FT_Pos      min_coord     =  32000;
+      FT_Pos      max_coord     = -32000;
+#endif
+
+
+      /* do each contour separately */
+      for ( ; contour < contour_limit; contour++ )
+      {
+        AH_Point  point   = contour[0];
+        AH_Point  last    = point->prev;
+        int       on_edge = 0;
+        FT_Pos    min_pos = +32000;  /* minimum segment pos != min_coord */
+        FT_Pos    max_pos = -32000;  /* maximum segment pos != max_coord */
+        FT_Bool   passed;
+
+
+#ifdef AH_HINT_METRICS
+        if ( point->u < min_coord )
+        {
+          min_coord = point->u;
+          min_point = point;
+        }
+        if ( point->u > max_coord )
+        {
+          max_coord = point->u;
+          max_point = point;
+        }
+#endif
+
+        if ( point == last )  /* skip singletons -- just in case? */
+          continue;
+
+        if ( ABS( last->out_dir )  == major_dir &&
+             ABS( point->out_dir ) == major_dir )
+        {
+          /* we are already on an edge, try to locate its start */
+          last = point;
+
+          for (;;)
+          {
+            point = point->prev;
+            if ( ABS( point->out_dir ) != major_dir )
+            {
+              point = point->next;
+              break;
+            }
+            if ( point == last )
+              break;
+          }
+        }
+
+        last   = point;
+        passed = 0;
+
+        for (;;)
+        {
+          FT_Pos  u, v;
+
+
+          if ( on_edge )
+          {
+            u = point->u;
+            if ( u < min_pos )
+              min_pos = u;
+            if ( u > max_pos )
+              max_pos = u;
+
+            if ( point->out_dir != segment_dir || point == last )
+            {
+              /* we are just leaving an edge; record a new segment! */
+              segment->last = point;
+              segment->pos  = ( min_pos + max_pos ) >> 1;
+
+              /* a segment is round if either its first or last point */
+              /* is a control point                                   */
+              if ( ( segment->first->flags | point->flags ) &
+                     AH_FLAG_CONTROL                        )
+                segment->flags |= AH_EDGE_ROUND;
+
+              /* compute segment size */
+              min_pos = max_pos = point->v;
+
+              v = segment->first->v;
+              if ( v < min_pos )
+                min_pos = v;
+              if ( v > max_pos )
+                max_pos = v;
+
+              segment->min_coord = min_pos;
+              segment->max_coord = max_pos;
+
+              on_edge = 0;
+              num_segments++;
+              segment++;
+              /* fallthrough */
+            }
+          }
+
+          /* now exit if we are at the start/end point */
+          if ( point == last )
+          {
+            if ( passed )
+              break;
+            passed = 1;
+          }
+
+          if ( !on_edge && ABS( point->out_dir ) == major_dir )
+          {
+            /* this is the start of a new segment! */
+            segment_dir = point->out_dir;
+
+            /* clear all segment fields */
+            FT_ZERO( segment );
+
+            segment->dir      = segment_dir;
+            segment->flags    = AH_EDGE_NORMAL;
+            min_pos = max_pos = point->u;
+            segment->first    = point;
+            segment->last     = point;
+            segment->contour  = contour;
+            on_edge           = 1;
+
+#ifdef AH_HINT_METRICS
+            if ( point == max_point )
+              max_point = 0;
+
+            if ( point == min_point )
+              min_point = 0;
+#endif
+          }
+
+          point = point->next;
+        }
+
+      } /* contours */
+
+#ifdef AH_HINT_METRICS
+      /* we need to ensure that there are edges on the left-most and  */
+      /* right-most points of the glyph in order to hint the metrics; */
+      /* we do this by inserting fake segments when needed            */
+      if ( dimension == 0 )
+      {
+        AH_Point  point       =  outline->points;
+        AH_Point  point_limit =  point + outline->num_points;
+
+        FT_Pos    min_pos     =  32000;
+        FT_Pos    max_pos     = -32000;
+
+
+        min_point = 0;
+        max_point = 0;
+
+        /* compute minimum and maximum points */
+        for ( ; point < point_limit; point++ )
+        {
+          FT_Pos  x = point->fx;
+
+
+          if ( x < min_pos )
+          {
+            min_pos   = x;
+            min_point = point;
+          }
+          if ( x > max_pos )
+          {
+            max_pos   = x;
+            max_point = point;
+          }
+        }
+
+        /* insert minimum segment */
+        if ( min_point )
+        {
+          /* clear all segment fields */
+          FT_ZERO( segment );
+
+          segment->dir   = segment_dir;
+          segment->flags = AH_EDGE_NORMAL;
+          segment->first = min_point;
+          segment->last  = min_point;
+          segment->pos   = min_pos;
+
+          num_segments++;
+          segment++;
+        }
+
+        /* insert maximum segment */
+        if ( max_point )
+        {
+          /* clear all segment fields */
+          FT_ZERO( segment );
+
+          segment->dir   = segment_dir;
+          segment->flags = AH_EDGE_NORMAL;
+          segment->first = max_point;
+          segment->last  = max_point;
+          segment->pos   = max_pos;
+
+          num_segments++;
+          segment++;
+        }
+      }
+#endif /* AH_HINT_METRICS */
+
+      *p_num_segments = num_segments;
+
+      segments       = outline->vert_segments;
+      major_dir      = AH_DIR_UP;
+      p_num_segments = &outline->num_vsegments;
+      ah_setup_uv( outline, AH_UV_FXY );
+    }
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ah_outline_link_segments( AH_Outline  outline )
+  {
+    AH_Segment  segments;
+    AH_Segment  segment_limit;
+    int         dimension;
+
+
+    ah_setup_uv( outline, AH_UV_FYX );
+
+    segments      = outline->horz_segments;
+    segment_limit = segments + outline->num_hsegments;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Segment  seg1;
+      AH_Segment  seg2;
+
+
+      /* now compare each segment to the others */
+      for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+      {
+        FT_Pos      best_score;
+        AH_Segment  best_segment;
+
+
+        /* the fake segments are introduced to hint the metrics -- */
+        /* we must never link them to anything                     */
+        if ( seg1->first == seg1->last )
+          continue;
+
+        best_segment = seg1->link;
+        if ( best_segment )
+          best_score = seg1->score;
+        else
+          best_score = 32000;
+
+        for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+          if ( seg1 != seg2 && seg1->dir + seg2->dir == 0 )
+          {
+            FT_Pos   pos1 = seg1->pos;
+            FT_Pos   pos2 = seg2->pos;
+            FT_Bool  is_dir;
+            FT_Bool  is_pos;
+
+
+            /* check that the segments are correctly oriented and */
+            /* positioned to form a black distance                */
+
+            is_dir = (FT_Bool)( seg1->dir == outline->horz_major_dir ||
+                                seg1->dir == outline->vert_major_dir );
+            is_pos = (FT_Bool)( pos1 > pos2 );
+
+            if ( pos1 == pos2 || !(is_dir ^ is_pos) )
+              continue;
+
+            {
+              FT_Pos  min = seg1->min_coord;
+              FT_Pos  max = seg1->max_coord;
+              FT_Pos  len, dist, score;
+
+
+              if ( min < seg2->min_coord )
+                min = seg2->min_coord;
+
+              if ( max > seg2->max_coord )
+                max = seg2->max_coord;
+
+              len = max - min;
+              if ( len >= 8 )
+              {
+                dist = seg2->pos - seg1->pos;
+                if ( dist < 0 )
+                  dist = -dist;
+
+                score = dist + 3000 / len;
+
+                if ( score < best_score )
+                {
+                  best_score   = score;
+                  best_segment = seg2;
+                }
+              }
+            }
+          }
+
+        if ( best_segment )
+        {
+          seg1->link  = best_segment;
+          seg1->score = best_score;
+
+          best_segment->num_linked++;
+        }
+
+      } /* edges 1 */
+
+      /* now, compute the `serif' segments */
+      for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+      {
+        seg2 = seg1->link;
+
+        if ( seg2 && seg2->link != seg1 )
+        {
+          seg1->link  = 0;
+          seg1->serif = seg2->link;
+        }
+      }
+
+      ah_setup_uv( outline, AH_UV_FXY );
+
+      segments      = outline->vert_segments;
+      segment_limit = segments + outline->num_vsegments;
+    }
+  }
+
+
+  static void
+  ah_outline_compute_edges( AH_Outline  outline )
+  {
+    AH_Edge       edges;
+    AH_Segment    segments;
+    AH_Segment    segment_limit;
+    AH_Direction  up_dir;
+    FT_Int*       p_num_edges;
+    FT_Int        dimension;
+    FT_Fixed      scale;
+    FT_Pos        edge_distance_threshold;
+
+
+    edges         = outline->horz_edges;
+    segments      = outline->horz_segments;
+    segment_limit = segments + outline->num_hsegments;
+    p_num_edges   = &outline->num_hedges;
+    up_dir        = AH_DIR_RIGHT;
+    scale         = outline->y_scale;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Edge     edge;
+      AH_Edge     edge_limit;  /* really == edge + num_edges */
+      AH_Segment  seg;
+
+
+      /*********************************************************************/
+      /*                                                                   */
+      /* We will begin by generating a sorted table of edges for the       */
+      /* current direction.  To do so, we simply scan each segment and try */
+      /* to find an edge in our table that corresponds to its position.    */
+      /*                                                                   */
+      /* If no edge is found, we create and insert a new edge in the       */
+      /* sorted table.  Otherwise, we simply add the segment to the edge's */
+      /* list which will be processed in the second step to compute the    */
+      /* edge's properties.                                                */
+      /*                                                                   */
+      /* Note that the edges table is sorted along the segment/edge        */
+      /* position.                                                         */
+      /*                                                                   */
+      /*********************************************************************/
+
+      edge_distance_threshold = FT_MulFix( outline->edge_distance_threshold,
+                                           scale );
+      if ( edge_distance_threshold > 64 / 4 )
+        edge_distance_threshold = 64 / 4;
+
+      edge_limit = edges;
+      for ( seg = segments; seg < segment_limit; seg++ )
+      {
+        AH_Edge  found = 0;
+
+
+        /* look for an edge corresponding to the segment */
+        for ( edge = edges; edge < edge_limit; edge++ )
+        {
+          FT_Pos  dist;
+
+
+          dist = seg->pos - edge->fpos;
+          if ( dist < 0 )
+            dist = -dist;
+
+          dist = FT_MulFix( dist, scale );
+          if ( dist < edge_distance_threshold )
+          {
+            found = edge;
+            break;
+          }
+        }
+
+        if ( !found )
+        {
+          /* insert a new edge in the list and */
+          /* sort according to the position    */
+          while ( edge > edges && edge[-1].fpos > seg->pos )
+          {
+            edge[0] = edge[-1];
+            edge--;
+          }
+          edge_limit++;
+
+          /* clear all edge fields */
+          FT_MEM_ZERO( edge, sizeof ( *edge ) );
+
+          /* add the segment to the new edge's list */
+          edge->first    = seg;
+          edge->last     = seg;
+          edge->fpos     = seg->pos;
+          edge->opos     = edge->pos = FT_MulFix( seg->pos, scale );
+          seg->edge_next = seg;
+        }
+        else
+        {
+          /* if an edge was found, simply add the segment to the edge's */
+          /* list                                                       */
+          seg->edge_next        = edge->first;
+          edge->last->edge_next = seg;
+          edge->last            = seg;
+        }
+      }
+
+      *p_num_edges = (FT_Int)( edge_limit - edges );
+
+
+      /*********************************************************************/
+      /*                                                                   */
+      /* Good, we will now compute each edge's properties according to     */
+      /* segments found on its position.  Basically, these are:            */
+      /*                                                                   */
+      /*  - edge's main direction                                          */
+      /*  - stem edge, serif edge or both (which defaults to stem then)    */
+      /*  - rounded edge, straigth or both (which defaults to straight)    */
+      /*  - link for edge                                                  */
+      /*                                                                   */
+      /*********************************************************************/
+
+      /* first of all, set the `edge' field in each segment -- this is */
+      /* required in order to compute edge links                       */
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        seg = edge->first;
+        if ( seg )
+          do
+          {
+            seg->edge = edge;
+            seg       = seg->edge_next;
+          }
+          while ( seg != edge->first );
+      }
+
+      /* now, compute each edge properties */
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        FT_Int  is_round    = 0;  /* does it contain round segments?    */
+        FT_Int  is_straight = 0;  /* does it contain straight segments? */
+        FT_Pos  ups         = 0;  /* number of upwards segments         */
+        FT_Pos  downs       = 0;  /* number of downwards segments       */
+
+
+        seg = edge->first;
+
+        do
+        {
+          FT_Bool  is_serif;
+
+
+          /* check for roundness of segment */
+          if ( seg->flags & AH_EDGE_ROUND )
+            is_round++;
+          else
+            is_straight++;
+
+          /* check for segment direction */
+          if ( seg->dir == up_dir )
+            ups   += seg->max_coord-seg->min_coord;
+          else
+            downs += seg->max_coord-seg->min_coord;
+
+          /* check for links -- if seg->serif is set, then seg->link must */
+          /* be ignored                                                   */
+          is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
+
+          if ( seg->link || is_serif )
+          {
+            AH_Edge     edge2;
+            AH_Segment  seg2;
+
+
+            edge2 = edge->link;
+            seg2  = seg->link;
+
+            if ( is_serif )
+            {
+              seg2  = seg->serif;
+              edge2 = edge->serif;
+            }
+
+            if ( edge2 )
+            {
+              FT_Pos  edge_delta;
+              FT_Pos  seg_delta;
+
+
+              edge_delta = edge->fpos - edge2->fpos;
+              if ( edge_delta < 0 )
+                edge_delta = -edge_delta;
+
+              seg_delta = seg->pos - seg2->pos;
+              if ( seg_delta < 0 )
+                seg_delta = -seg_delta;
+
+              if ( seg_delta < edge_delta )
+                edge2 = seg2->edge;
+            }
+            else
+              edge2 = seg2->edge;
+
+            if ( is_serif )
+              edge->serif = edge2;
+            else
+              edge->link  = edge2;
+          }
+
+          seg = seg->edge_next;
+
+        } while ( seg != edge->first );
+
+        /* set the round/straight flags */
+        edge->flags = AH_EDGE_NORMAL;
+
+        if ( is_round > 0 && is_round >= is_straight )
+          edge->flags |= AH_EDGE_ROUND;
+
+        /* set the edge's main direction */
+        edge->dir = AH_DIR_NONE;
+
+        if ( ups > downs )
+          edge->dir = up_dir;
+
+        else if ( ups < downs )
+          edge->dir = - up_dir;
+
+        else if ( ups == downs )
+          edge->dir = 0;  /* both up and down !! */
+
+        /* gets rid of serifs if link is set                */
+        /* XXX: This gets rid of many unpleasant artefacts! */
+        /*      Example: the `c' in cour.pfa at size 13     */
+
+        if ( edge->serif && edge->link )
+          edge->serif = 0;
+      }
+
+      edges         = outline->vert_edges;
+      segments      = outline->vert_segments;
+      segment_limit = segments + outline->num_vsegments;
+      p_num_edges   = &outline->num_vedges;
+      up_dir        = AH_DIR_UP;
+      scale         = outline->x_scale;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ah_outline_detect_features                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Performs feature detection on a given AH_OutlineRec object.        */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  ah_outline_detect_features( AH_Outline  outline )
+  {
+    ah_outline_compute_segments   ( outline );
+    ah_outline_link_segments      ( outline );
+    ah_outline_compute_edges      ( outline );
+    ah_outline_compute_inflections( outline );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ah_outline_compute_blue_edges                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the `blue edges' in a given outline (i.e. those that must */
+  /*    be snapped to a blue zone edge (top or bottom).                    */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  ah_outline_compute_blue_edges( AH_Outline       outline,
+                                 AH_Face_Globals  face_globals )
+  {
+    AH_Edge     edge       = outline->horz_edges;
+    AH_Edge     edge_limit = edge + outline->num_hedges;
+    AH_Globals  globals    = &face_globals->design;
+    FT_Fixed    y_scale    = outline->y_scale;
+
+    FT_Bool     blue_active[AH_BLUE_MAX];
+
+
+    /* compute which blue zones are active, i.e. have their scaled */
+    /* size < 3/4 pixels                                           */
+    {
+      AH_Blue  blue;
+      FT_Bool  check = 0;
+
+
+      for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ )
+      {
+        FT_Pos  ref, shoot, dist;
+
+
+        ref   = globals->blue_refs[blue];
+        shoot = globals->blue_shoots[blue];
+        dist  = ref-shoot;
+        if ( dist < 0 )
+          dist = -dist;
+
+        blue_active[blue] = 0;
+
+        if ( FT_MulFix( dist, y_scale ) < 48 )
+        {
+          blue_active[blue] = 1;
+          check = 1;
+        }
+      }
+
+      /* return immediately if no blue zone is active */
+      if ( !check )
+        return;
+    }
+
+    /* compute for each horizontal edge, which blue zone is closer */
+    for ( ; edge < edge_limit; edge++ )
+    {
+      AH_Blue  blue;
+      FT_Pos*  best_blue = 0;
+      FT_Pos   best_dist;  /* initial threshold */
+
+
+      /* compute the initial threshold as a fraction of the EM size */
+      best_dist = FT_MulFix( face_globals->face->units_per_EM / 40, y_scale );
+      if ( best_dist > 64 / 4 )
+        best_dist = 64 / 4;
+
+      for ( blue = AH_BLUE_CAPITAL_TOP; blue < AH_BLUE_MAX; blue++ )
+      {
+        /* if it is a top zone, check for right edges -- if it is a bottom */
+        /* zone, check for left edges                                      */
+        /*                                                                 */
+        /* of course, that's for TrueType XXX                              */
+        FT_Bool  is_top_blue  =
+                   FT_BOOL( AH_IS_TOP_BLUE( blue ) );
+        FT_Bool  is_major_dir =
+                   FT_BOOL( edge->dir == outline->horz_major_dir );
+
+        if ( !blue_active[blue] )
+          continue;
+
+        /* if it is a top zone, the edge must be against the major    */
+        /* direction; if it is a bottom zone, it must be in the major */
+        /* direction                                                  */
+        if ( is_top_blue ^ is_major_dir )
+        {
+          FT_Pos   dist;
+          FT_Pos*  blue_pos = globals->blue_refs + blue;
+
+
+          /* first of all, compare it to the reference position */
+          dist = edge->fpos - *blue_pos;
+          if ( dist < 0 )
+            dist = -dist;
+
+          dist = FT_MulFix( dist, y_scale );
+          if ( dist < best_dist )
+          {
+            best_dist = dist;
+            best_blue = blue_pos;
+          }
+
+          /* now, compare it to the overshoot position if the edge is     */
+          /* rounded, and if the edge is over the reference position of a */
+          /* top zone, or under the reference position of a bottom zone   */
+          if ( edge->flags & AH_EDGE_ROUND && dist != 0 )
+          {
+            FT_Bool  is_under_ref = FT_BOOL( edge->fpos < *blue_pos );
+
+
+            if ( is_top_blue ^ is_under_ref )
+            {
+              blue_pos = globals->blue_shoots + blue;
+              dist = edge->fpos - *blue_pos;
+              if ( dist < 0 )
+                dist = -dist;
+
+              dist = FT_MulFix( dist, y_scale );
+              if ( dist < best_dist )
+              {
+                best_dist = dist;
+                best_blue = blue_pos;
+              }
+            }
+          }
+        }
+      }
+
+      if ( best_blue )
+        edge->blue_edge = best_blue;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ah_outline_scale_blue_edges                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This functions must be called before hinting in order to re-adjust */
+  /*    the contents of the detected edges (basically change the `blue     */
+  /*    edge' pointer from `design units' to `scaled ones').               */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  ah_outline_scale_blue_edges( AH_Outline       outline,
+                               AH_Face_Globals  globals )
+  {
+    AH_Edge  edge       = outline->horz_edges;
+    AH_Edge  edge_limit = edge + outline->num_hedges;
+    FT_Pos   delta;
+
+
+    delta = globals->scaled.blue_refs - globals->design.blue_refs;
+
+    for ( ; edge < edge_limit; edge++ )
+    {
+      if ( edge->blue_edge )
+        edge->blue_edge += delta;
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahglyph.h
@@ -1,0 +1,93 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahglyph.h                                                              */
+/*                                                                         */
+/*    Routines used to load and analyze a given glyph before hinting       */
+/*    (specification).                                                     */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AHGLYPH_H__
+#define __AHGLYPH_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+  typedef enum  AH_UV_
+  {
+    AH_UV_FXY,
+    AH_UV_FYX,
+    AH_UV_OXY,
+    AH_UV_OYX,
+    AH_UV_OX,
+    AH_UV_OY,
+    AH_UV_YX,
+    AH_UV_XY  /* should always be last! */
+
+  } AH_UV;
+
+
+  FT_LOCAL( void )
+  ah_setup_uv( AH_Outline  outline,
+               AH_UV       source );
+
+
+  /* AH_OutlineRec functions - they should be typically called in this order */
+
+  FT_LOCAL( FT_Error )
+  ah_outline_new( FT_Memory    memory,
+                  AH_Outline*  aoutline );
+
+  FT_LOCAL( FT_Error )
+  ah_outline_load( AH_Outline  outline,
+                   FT_Face     face );
+
+  FT_LOCAL( void )
+  ah_outline_compute_segments( AH_Outline  outline );
+
+  FT_LOCAL( void )
+  ah_outline_link_segments( AH_Outline  outline );
+
+  FT_LOCAL( void )
+  ah_outline_detect_features( AH_Outline  outline );
+
+  FT_LOCAL( void )
+  ah_outline_compute_blue_edges( AH_Outline       outline,
+                                 AH_Face_Globals  globals );
+
+  FT_LOCAL( void )
+  ah_outline_scale_blue_edges( AH_Outline       outline,
+                               AH_Face_Globals  globals );
+
+  FT_LOCAL( void )
+  ah_outline_save( AH_Outline  outline,
+                   AH_Loader   loader );
+
+  FT_LOCAL( void )
+  ah_outline_done( AH_Outline  outline );
+
+
+FT_END_HEADER
+
+#endif /* __AHGLYPH_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahhint.c
@@ -1,0 +1,1493 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahhint.c                                                               */
+/*                                                                         */
+/*    Glyph hinter (body).                                                 */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "ahhint.h"
+#include "ahglyph.h"
+#include "ahangles.h"
+#include "aherrors.h"
+#include FT_OUTLINE_H
+
+
+#define FACE_GLOBALS( face )  ((AH_Face_Globals)(face)->autohint.data)
+
+#define AH_USE_IUP
+#define OPTIM_STEM_SNAP
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   Hinting routines                                              ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* snap a given width in scaled coordinates to one of the */
+  /* current standard widths                                */
+  static FT_Pos
+  ah_snap_width( FT_Pos*  widths,
+                 FT_Int   count,
+                 FT_Pos   width )
+  {
+    int     n;
+    FT_Pos  best      = 64 + 32 + 2;
+    FT_Pos  reference = width;
+    FT_Pos  scaled;
+
+
+    for ( n = 0; n < count; n++ )
+    {
+      FT_Pos  w;
+      FT_Pos  dist;
+
+
+      w = widths[n];
+      dist = width - w;
+      if ( dist < 0 )
+        dist = -dist;
+      if ( dist < best )
+      {
+        best      = dist;
+        reference = w;
+      }
+    }
+
+    scaled = (reference+32) & -64;
+
+    if ( width >= reference )
+    {
+      if ( width < scaled + 48 )
+        width = reference;
+    }
+    else
+    {
+      if ( width > scaled - 48 )
+        width = reference;
+    }
+
+    return width;
+  }
+
+
+  /* compute the snapped width of a given stem */
+  static FT_Pos
+  ah_compute_stem_width( AH_Hinter  hinter,
+                         int        vertical,
+                         FT_Pos     width )
+  {
+    AH_Globals  globals = &hinter->globals->scaled;
+    FT_Pos      dist    = width;
+    FT_Int      sign    = 0;
+
+
+    if ( dist < 0 )
+    {
+      dist = -width;
+      sign = 1;
+    }
+
+    if ( (  vertical && !hinter->do_vert_snapping ) ||
+         ( !vertical && !hinter->do_horz_snapping ) )
+    {
+      /* smooth hinting process, very lightly quantize the stem width */
+      /*                                                              */
+      if ( dist < 64 )
+        dist = 64;
+
+      {
+        FT_Pos  delta = dist - globals->stds[vertical];
+
+
+        if ( delta < 0 )
+          delta = -delta;
+
+        if ( delta < 40 )
+        {
+          dist = globals->stds[vertical];
+          if ( dist < 48 )
+            dist = 48;
+        }
+
+        if ( dist < 3 * 64 )
+        {
+          delta = ( dist & 63 );
+          dist &= -64;
+
+          if ( delta < 10 )
+            dist += delta;
+
+          else if ( delta < 32 )
+            dist += 10;
+
+          else if ( delta < 54 )
+            dist += 54;
+
+          else
+            dist += delta;
+        }
+        else
+          dist = ( dist + 32 ) & -64;
+      }
+    }
+    else
+    {
+      /* strong hinting process, snap the stem width to integer pixels */
+      /*                                                               */
+      if ( vertical )
+      {
+        dist = ah_snap_width( globals->heights, globals->num_heights, dist );
+
+        /* in the case of vertical hinting, always round */
+        /* the stem heights to integer pixels            */
+        if ( dist >= 64 )
+          dist = ( dist + 16 ) & -64;
+        else
+          dist = 64;
+      }
+      else
+      {
+        dist = ah_snap_width( globals->widths,  globals->num_widths, dist );
+
+        if ( hinter->flags & AH_HINTER_MONOCHROME )
+        {
+          /* monochrome horizontal hinting: snap widths to integer pixels */
+          /* with a different threshold                                   */
+          if ( dist < 64 )
+            dist = 64;
+          else
+            dist = ( dist + 32 ) & -64;
+        }
+        else
+        {
+          /* for horizontal anti-aliased hinting, we adopt a more subtle */
+          /* approach: we strengthen small stems, round stems whose size */
+          /* is between 1 and 2 pixels to an integer, otherwise nothing  */
+          if ( dist < 48 )
+            dist = ( dist + 64 ) >> 1;
+
+          else if ( dist < 128 )
+            dist = ( dist + 22 ) & -64;
+          else
+            /* XXX: round otherwise, prevent color fringes in LCD mode */
+            dist = ( dist + 32 ) & -64;
+        }
+      }
+    }
+
+    if ( sign )
+      dist = -dist;
+
+    return dist;
+  }
+
+
+  /* align one stem edge relative to the previous stem edge */
+  static void
+  ah_align_linked_edge( AH_Hinter  hinter,
+                        AH_Edge    base_edge,
+                        AH_Edge    stem_edge,
+                        int        vertical )
+  {
+    FT_Pos  dist = stem_edge->opos - base_edge->opos;
+
+
+    stem_edge->pos = base_edge->pos +
+                     ah_compute_stem_width( hinter, vertical, dist );
+  }
+
+
+  static void
+  ah_align_serif_edge( AH_Hinter  hinter,
+                       AH_Edge    base,
+                       AH_Edge    serif,
+                       int        vertical )
+  {
+    FT_Pos  dist;
+    FT_Pos  sign = 1;
+
+    FT_UNUSED( hinter );
+
+
+    dist = serif->opos - base->opos;
+    if ( dist < 0 )
+    {
+      dist = -dist;
+      sign = -1;
+    }
+
+    /* do not touch serifs widths !! */
+#if 0
+    if ( base->flags & AH_EDGE_DONE )
+    {
+      if ( dist >= 64 )
+        dist = (dist+8) & -64;
+
+      else if ( dist <= 32 && !vertical )
+        dist = ( dist + 33 ) >> 1;
+      else
+        dist = 0;
+    }
+#endif
+
+    serif->pos = base->pos + sign * dist;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****       E D G E   H I N T I N G                                   ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* Another alternative edge hinting algorithm */
+  static void
+  ah_hint_edges_3( AH_Hinter  hinter )
+  {
+    AH_Edge     edges;
+    AH_Edge     edge_limit;
+    AH_Outline  outline = hinter->glyph;
+    FT_Int      dimension;
+
+
+    edges      = outline->horz_edges;
+    edge_limit = edges + outline->num_hedges;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Edge  edge;
+      AH_Edge  anchor = 0;
+      int      has_serifs = 0;
+
+
+      if ( !hinter->do_horz_hints && !dimension )
+        goto Next_Dimension;
+
+      if ( !hinter->do_vert_hints && dimension )
+        goto Next_Dimension;
+
+      /* we begin by aligning all stems relative to the blue zone */
+      /* if needed -- that's only for horizontal edges            */
+      if ( dimension )
+      {
+        for ( edge = edges; edge < edge_limit; edge++ )
+        {
+          FT_Pos*      blue;
+          AH_EdgeRec  *edge1, *edge2;
+
+
+          if ( edge->flags & AH_EDGE_DONE )
+            continue;
+
+          blue  = edge->blue_edge;
+          edge1 = 0;
+          edge2 = edge->link;
+
+          if ( blue )
+          {
+            edge1 = edge;
+          }
+          else if (edge2 && edge2->blue_edge)
+          {
+            blue  = edge2->blue_edge;
+            edge1 = edge2;
+            edge2 = edge;
+          }
+
+          if ( !edge1 )
+            continue;
+
+          edge1->pos    = blue[0];
+          edge1->flags |= AH_EDGE_DONE;
+
+          if ( edge2 && !edge2->blue_edge )
+          {
+            ah_align_linked_edge( hinter, edge1, edge2, dimension );
+            edge2->flags |= AH_EDGE_DONE;
+          }
+
+          if ( !anchor )
+            anchor = edge;
+        }
+      }
+
+      /* now, we will align all stem edges, trying to maintain the */
+      /* relative order of stems in the glyph..                    */
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        AH_EdgeRec*  edge2;
+
+
+        if ( edge->flags & AH_EDGE_DONE )
+          continue;
+
+        /* skip all non-stem edges */
+        edge2 = edge->link;
+        if ( !edge2 )
+        {
+          has_serifs++;
+          continue;
+        }
+
+        /* now, align the stem */
+
+        /* this should not happen, but it's better to be safe. */
+        if ( edge2->blue_edge || edge2 < edge )
+        {
+
+          ah_align_linked_edge( hinter, edge2, edge, dimension );
+          edge->flags |= AH_EDGE_DONE;
+          continue;
+        }
+
+        if ( !anchor )
+        {
+          edge->pos = ( edge->opos + 32 ) & -64;
+          anchor    = edge;
+
+          edge->flags |= AH_EDGE_DONE;
+
+          ah_align_linked_edge( hinter, edge, edge2, dimension );
+        }
+        else
+        {
+          FT_Pos   org_pos, org_len, org_center, cur_len;
+          FT_Pos   cur_pos1, cur_pos2, delta1, delta2;
+
+
+          org_pos    = anchor->pos + (edge->opos - anchor->opos);
+          org_len    = edge2->opos - edge->opos;
+          org_center = org_pos + ( org_len >> 1 );
+
+          cur_len    = ah_compute_stem_width( hinter, dimension, org_len );
+
+          cur_pos1   = ( org_pos + 32 ) & -64;
+          delta1     = ( cur_pos1 + ( cur_len >> 1 ) - org_center );
+          if ( delta1 < 0 )
+            delta1 = -delta1;
+
+          cur_pos2   = ( ( org_pos + org_len + 32 ) & -64 ) - cur_len;
+          delta2     = ( cur_pos2 + ( cur_len >> 1 ) - org_center );
+          if ( delta2 < 0 )
+            delta2 = -delta2;
+
+          edge->pos  = ( delta1 <= delta2 ) ? cur_pos1 : cur_pos2;
+          edge2->pos = edge->pos + cur_len;
+
+          edge->flags  |= AH_EDGE_DONE;
+          edge2->flags |= AH_EDGE_DONE;
+
+          if ( edge > edges && edge->pos < edge[-1].pos )
+            edge->pos = edge[-1].pos;
+        }
+      }
+
+      if ( !has_serifs )
+        goto Next_Dimension;
+
+      /* now, hint the remaining edges (serifs and single) in order */
+      /* to complete our processing                                 */
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        if ( edge->flags & AH_EDGE_DONE )
+          continue;
+
+        if ( edge->serif )
+          ah_align_serif_edge( hinter, edge->serif, edge, dimension );
+        else if ( !anchor )
+        {
+          edge->pos = ( edge->opos + 32 ) & -64;
+          anchor    = edge;
+        }
+        else
+          edge->pos = anchor->pos +
+                      ( ( edge->opos-anchor->opos + 32 ) & -64 );
+
+        edge->flags |= AH_EDGE_DONE;
+
+        if ( edge > edges && edge->pos < edge[-1].pos )
+          edge->pos = edge[-1].pos;
+
+        if ( edge + 1 < edge_limit        &&
+             edge[1].flags & AH_EDGE_DONE &&
+             edge->pos > edge[1].pos      )
+          edge->pos = edge[1].pos;
+      }
+
+    Next_Dimension:
+      edges      = outline->vert_edges;
+      edge_limit = edges + outline->num_vedges;
+    }
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ah_hinter_hint_edges( AH_Hinter  hinter )
+  {
+    /* AH_Interpolate_Blue_Edges( hinter ); -- doesn't seem to help      */
+    /* reduce the problem of the disappearing eye in the `e' of Times... */
+    /* also, creates some artifacts near the blue zones?                 */
+    {
+      ah_hint_edges_3( hinter );
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****       P O I N T   H I N T I N G                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  ah_hinter_align_edge_points( AH_Hinter  hinter )
+  {
+    AH_Outline  outline = hinter->glyph;
+    AH_Edge     edges;
+    AH_Edge     edge_limit;
+    FT_Int      dimension;
+
+
+    edges      = outline->horz_edges;
+    edge_limit = edges + outline->num_hedges;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Edge  edge;
+
+
+      edge = edges;
+      for ( ; edge < edge_limit; edge++ )
+      {
+        /* move the points of each segment     */
+        /* in each edge to the edge's position */
+        AH_Segment  seg = edge->first;
+
+
+        do
+        {
+          AH_Point  point = seg->first;
+
+
+          for (;;)
+          {
+            if ( dimension )
+            {
+              point->y      = edge->pos;
+              point->flags |= AH_FLAG_TOUCH_Y;
+            }
+            else
+            {
+              point->x      = edge->pos;
+              point->flags |= AH_FLAG_TOUCH_X;
+            }
+
+            if ( point == seg->last )
+              break;
+
+            point = point->next;
+          }
+
+          seg = seg->edge_next;
+
+        } while ( seg != edge->first );
+      }
+
+      edges      = outline->vert_edges;
+      edge_limit = edges + outline->num_vedges;
+    }
+  }
+
+
+  /* hint the strong points -- this is equivalent to the TrueType `IP' */
+  static void
+  ah_hinter_align_strong_points( AH_Hinter  hinter )
+  {
+    AH_Outline  outline = hinter->glyph;
+    FT_Int      dimension;
+    AH_Edge     edges;
+    AH_Edge     edge_limit;
+    AH_Point    points;
+    AH_Point    point_limit;
+    AH_Flags    touch_flag;
+
+
+    points      = outline->points;
+    point_limit = points + outline->num_points;
+
+    edges       = outline->horz_edges;
+    edge_limit  = edges + outline->num_hedges;
+    touch_flag  = AH_FLAG_TOUCH_Y;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Point  point;
+      AH_Edge   edge;
+
+
+      if ( edges < edge_limit )
+        for ( point = points; point < point_limit; point++ )
+        {
+          FT_Pos  u, ou, fu;  /* point position */
+          FT_Pos  delta;
+
+
+          if ( point->flags & touch_flag )
+            continue;
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+          /* if this point is candidate to weak interpolation, we will  */
+          /* interpolate it after all strong points have been processed */
+          if (  ( point->flags & AH_FLAG_WEAK_INTERPOLATION ) &&
+               !( point->flags & AH_FLAG_INFLECTION )         )
+            continue;
+#endif
+
+          if ( dimension )
+          {
+            u  = point->fy;
+            ou = point->oy;
+          }
+          else
+          {
+            u  = point->fx;
+            ou = point->ox;
+          }
+
+          fu = u;
+
+          /* is the point before the first edge? */
+          edge  = edges;
+          delta = edge->fpos - u;
+          if ( delta >= 0 )
+          {
+            u = edge->pos - ( edge->opos - ou );
+            goto Store_Point;
+          }
+
+          /* is the point after the last edge ? */
+          edge  = edge_limit - 1;
+          delta = u - edge->fpos;
+          if ( delta >= 0 )
+          {
+            u = edge->pos + ( ou - edge->opos );
+            goto Store_Point;
+          }
+
+          /* otherwise, interpolate the point in between */
+          {
+            AH_Edge  before = 0;
+            AH_Edge  after  = 0;
+
+
+            for ( edge = edges; edge < edge_limit; edge++ )
+            {
+              if ( u == edge->fpos )
+              {
+                u = edge->pos;
+                goto Store_Point;
+              }
+              if ( u < edge->fpos )
+                break;
+              before = edge;
+            }
+
+            for ( edge = edge_limit - 1; edge >= edges; edge-- )
+            {
+              if ( u == edge->fpos )
+              {
+                u = edge->pos;
+                goto Store_Point;
+              }
+              if ( u > edge->fpos )
+                break;
+              after = edge;
+            }
+
+            /* assert( before && after && before != after ) */
+            u = before->pos + FT_MulDiv( fu - before->fpos,
+                                         after->pos - before->pos,
+                                         after->fpos - before->fpos );
+          }
+
+        Store_Point:
+
+          /* save the point position */
+          if ( dimension )
+            point->y = u;
+          else
+            point->x = u;
+
+          point->flags |= touch_flag;
+        }
+
+      edges      = outline->vert_edges;
+      edge_limit = edges + outline->num_vedges;
+      touch_flag = AH_FLAG_TOUCH_X;
+    }
+  }
+
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+
+  static void
+  ah_iup_shift( AH_Point  p1,
+                AH_Point  p2,
+                AH_Point  ref )
+  {
+    AH_Point  p;
+    FT_Pos    delta = ref->u - ref->v;
+
+
+    for ( p = p1; p < ref; p++ )
+      p->u = p->v + delta;
+
+    for ( p = ref + 1; p <= p2; p++ )
+      p->u = p->v + delta;
+  }
+
+
+  static void
+  ah_iup_interp( AH_Point  p1,
+                 AH_Point  p2,
+                 AH_Point  ref1,
+                 AH_Point  ref2 )
+  {
+    AH_Point  p;
+    FT_Pos    u;
+    FT_Pos    v1 = ref1->v;
+    FT_Pos    v2 = ref2->v;
+    FT_Pos    d1 = ref1->u - v1;
+    FT_Pos    d2 = ref2->u - v2;
+
+
+    if ( p1 > p2 )
+      return;
+
+    if ( v1 == v2 )
+    {
+      for ( p = p1; p <= p2; p++ )
+      {
+        u = p->v;
+
+        if ( u <= v1 )
+          u += d1;
+        else
+          u += d2;
+
+        p->u = u;
+      }
+      return;
+    }
+
+    if ( v1 < v2 )
+    {
+      for ( p = p1; p <= p2; p++ )
+      {
+        u = p->v;
+
+        if ( u <= v1 )
+          u += d1;
+        else if ( u >= v2 )
+          u += d2;
+        else
+          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+        p->u = u;
+      }
+    }
+    else
+    {
+      for ( p = p1; p <= p2; p++ )
+      {
+        u = p->v;
+
+        if ( u <= v2 )
+          u += d2;
+        else if ( u >= v1 )
+          u += d1;
+        else
+          u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+        p->u = u;
+      }
+    }
+  }
+
+
+  /* interpolate weak points -- this is equivalent to the TrueType `IUP' */
+  static void
+  ah_hinter_align_weak_points( AH_Hinter  hinter )
+  {
+    AH_Outline  outline = hinter->glyph;
+    FT_Int      dimension;
+    AH_Point    points;
+    AH_Point    point_limit;
+    AH_Point*   contour_limit;
+    AH_Flags    touch_flag;
+
+
+    points      = outline->points;
+    point_limit = points + outline->num_points;
+
+    /* PASS 1: Move segment points to edge positions */
+
+    touch_flag = AH_FLAG_TOUCH_Y;
+
+    contour_limit = outline->contours + outline->num_contours;
+
+    ah_setup_uv( outline, AH_UV_OY );
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Point   point;
+      AH_Point   end_point;
+      AH_Point   first_point;
+      AH_Point*  contour;
+
+
+      point   = points;
+      contour = outline->contours;
+
+      for ( ; contour < contour_limit; contour++ )
+      {
+        point       = *contour;
+        end_point   = point->prev;
+        first_point = point;
+
+        while ( point <= end_point && !( point->flags & touch_flag ) )
+          point++;
+
+        if ( point <= end_point )
+        {
+          AH_Point  first_touched = point;
+          AH_Point  cur_touched   = point;
+
+
+          point++;
+          while ( point <= end_point )
+          {
+            if ( point->flags & touch_flag )
+            {
+              /* we found two successive touched points; we interpolate */
+              /* all contour points between them                        */
+              ah_iup_interp( cur_touched + 1, point - 1,
+                             cur_touched, point );
+              cur_touched = point;
+            }
+            point++;
+          }
+
+          if ( cur_touched == first_touched )
+          {
+            /* this is a special case: only one point was touched in the */
+            /* contour; we thus simply shift the whole contour           */
+            ah_iup_shift( first_point, end_point, cur_touched );
+          }
+          else
+          {
+            /* now interpolate after the last touched point to the end */
+            /* of the contour                                          */
+            ah_iup_interp( cur_touched + 1, end_point,
+                           cur_touched, first_touched );
+
+            /* if the first contour point isn't touched, interpolate */
+            /* from the contour start to the first touched point     */
+            if ( first_touched > points )
+              ah_iup_interp( first_point, first_touched - 1,
+                             cur_touched, first_touched );
+          }
+        }
+      }
+
+      /* now save the interpolated values back to x/y */
+      if ( dimension )
+      {
+        for ( point = points; point < point_limit; point++ )
+          point->y = point->u;
+
+        touch_flag = AH_FLAG_TOUCH_X;
+        ah_setup_uv( outline, AH_UV_OX );
+      }
+      else
+      {
+        for ( point = points; point < point_limit; point++ )
+          point->x = point->u;
+
+        break;  /* exit loop */
+      }
+    }
+  }
+
+#endif /* !AH_OPTION_NO_WEAK_INTERPOLATION */
+
+
+  FT_LOCAL_DEF( void )
+  ah_hinter_align_points( AH_Hinter  hinter )
+  {
+    ah_hinter_align_edge_points( hinter );
+
+#ifndef AH_OPTION_NO_STRONG_INTERPOLATION
+    ah_hinter_align_strong_points( hinter );
+#endif
+
+#ifndef AH_OPTION_NO_WEAK_INTERPOLATION
+    ah_hinter_align_weak_points( hinter );
+#endif
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****       H I N T E R   O B J E C T   M E T H O D S                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* scale and fit the global metrics */
+  static void
+  ah_hinter_scale_globals( AH_Hinter  hinter,
+                           FT_Fixed   x_scale,
+                           FT_Fixed   y_scale )
+  {
+    FT_Int           n;
+    AH_Face_Globals  globals = hinter->globals;
+    AH_Globals       design = &globals->design;
+    AH_Globals       scaled = &globals->scaled;
+
+
+    /* copy content */
+    *scaled = *design;
+
+    /* scale the standard widths & heights */
+    for ( n = 0; n < design->num_widths; n++ )
+      scaled->widths[n] = FT_MulFix( design->widths[n], x_scale );
+
+    for ( n = 0; n < design->num_heights; n++ )
+      scaled->heights[n] = FT_MulFix( design->heights[n], y_scale );
+
+    scaled->stds[0] = ( design->num_widths  > 0 ) ? scaled->widths[0]  : 32000;
+    scaled->stds[1] = ( design->num_heights > 0 ) ? scaled->heights[0] : 32000;
+
+    /* scale the blue zones */
+    for ( n = 0; n < AH_BLUE_MAX; n++ )
+    {
+      FT_Pos  delta, delta2;
+
+
+      delta = design->blue_shoots[n] - design->blue_refs[n];
+      delta2 = delta;
+      if ( delta < 0 )
+        delta2 = -delta2;
+      delta2 = FT_MulFix( delta2, y_scale );
+
+      if ( delta2 < 32 )
+        delta2 = 0;
+      else if ( delta2 < 64 )
+        delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & -32 );
+      else
+        delta2 = ( delta2 + 32 ) & -64;
+
+      if ( delta < 0 )
+        delta2 = -delta2;
+
+      scaled->blue_refs[n] =
+        ( FT_MulFix( design->blue_refs[n], y_scale ) + 32 ) & -64;
+      scaled->blue_shoots[n] = scaled->blue_refs[n] + delta2;
+    }
+
+    globals->x_scale = x_scale;
+    globals->y_scale = y_scale;
+  }
+
+
+  static void
+  ah_hinter_align( AH_Hinter  hinter )
+  {
+    ah_hinter_align_edge_points( hinter );
+    ah_hinter_align_points( hinter );
+  }
+
+
+  /* finalize a hinter object */
+  FT_LOCAL_DEF( void )
+  ah_hinter_done( AH_Hinter  hinter )
+  {
+    if ( hinter )
+    {
+      FT_Memory  memory = hinter->memory;
+
+
+      ah_loader_done( hinter->loader );
+      ah_outline_done( hinter->glyph );
+
+      /* note: the `globals' pointer is _not_ owned by the hinter */
+      /*       but by the current face object, we don't need to   */
+      /*       release it                                         */
+      hinter->globals = 0;
+      hinter->face    = 0;
+
+      FT_FREE( hinter );
+    }
+  }
+
+
+  /* create a new empty hinter object */
+  FT_LOCAL_DEF( FT_Error )
+  ah_hinter_new( FT_Library  library,
+                 AH_Hinter  *ahinter )
+  {
+    AH_Hinter  hinter = 0;
+    FT_Memory  memory = library->memory;
+    FT_Error   error;
+
+
+    *ahinter = 0;
+
+    /* allocate object */
+    if ( FT_NEW( hinter ) )
+      goto Exit;
+
+    hinter->memory = memory;
+    hinter->flags  = 0;
+
+    /* allocate outline and loader */
+    error = ah_outline_new( memory, &hinter->glyph )  ||
+            ah_loader_new ( memory, &hinter->loader ) ||
+            ah_loader_create_extra( hinter->loader );
+    if ( error )
+      goto Exit;
+
+    *ahinter = hinter;
+
+  Exit:
+    if ( error )
+      ah_hinter_done( hinter );
+
+    return error;
+  }
+
+
+  /* create a face's autohint globals */
+  FT_LOCAL_DEF( FT_Error )
+  ah_hinter_new_face_globals( AH_Hinter   hinter,
+                              FT_Face     face,
+                              AH_Globals  globals )
+  {
+    FT_Error         error;
+    FT_Memory        memory = hinter->memory;
+    AH_Face_Globals  face_globals;
+
+
+    if ( FT_NEW( face_globals ) )
+      goto Exit;
+
+    hinter->face    = face;
+    hinter->globals = face_globals;
+
+    if ( globals )
+      face_globals->design = *globals;
+    else
+      ah_hinter_compute_globals( hinter );
+
+    face->autohint.data      = face_globals;
+    face->autohint.finalizer = (FT_Generic_Finalizer)
+                                 ah_hinter_done_face_globals;
+    face_globals->face       = face;
+
+  Exit:
+    return error;
+  }
+
+
+  /* discard a face's autohint globals */
+  FT_LOCAL_DEF( void )
+  ah_hinter_done_face_globals( AH_Face_Globals  globals )
+  {
+    FT_Face    face   = globals->face;
+    FT_Memory  memory = face->memory;
+
+
+    FT_FREE( globals );
+  }
+
+
+  static FT_Error
+  ah_hinter_load( AH_Hinter  hinter,
+                  FT_UInt    glyph_index,
+                  FT_Int32   load_flags,
+                  FT_UInt    depth )
+  {
+    FT_Face           face     = hinter->face;
+    FT_GlyphSlot      slot     = face->glyph;
+    FT_Slot_Internal  internal = slot->internal;
+    FT_Fixed          x_scale  = face->size->metrics.x_scale;
+    FT_Fixed          y_scale  = face->size->metrics.y_scale;
+    FT_Error          error;
+    AH_Outline        outline  = hinter->glyph;
+    AH_Loader         gloader  = hinter->loader;
+
+
+    /* load the glyph */
+    error = FT_Load_Glyph( face, glyph_index, load_flags );
+    if ( error )
+      goto Exit;
+
+    /* Set `hinter->transformed' after loading with FT_LOAD_NO_RECURSE. */
+    hinter->transformed = internal->glyph_transformed;
+
+    if ( hinter->transformed )
+    {
+      FT_Matrix  imatrix;
+
+
+      imatrix              = internal->glyph_matrix;
+      hinter->trans_delta  = internal->glyph_delta;
+      hinter->trans_matrix = imatrix;
+
+      FT_Matrix_Invert( &imatrix );
+      FT_Vector_Transform( &hinter->trans_delta, &imatrix );
+    }
+
+    /* set linear horizontal metrics */
+    slot->linearHoriAdvance = slot->metrics.horiAdvance;
+    slot->linearVertAdvance = slot->metrics.vertAdvance;
+
+    switch ( slot->format )
+    {
+    case FT_GLYPH_FORMAT_OUTLINE:
+
+      /* translate glyph outline if we need to */
+      if ( hinter->transformed )
+      {
+        FT_UInt     n     = slot->outline.n_points;
+        FT_Vector*  point = slot->outline.points;
+
+
+        for ( ; n > 0; point++, n-- )
+        {
+          point->x += hinter->trans_delta.x;
+          point->y += hinter->trans_delta.y;
+        }
+      }
+
+      /* copy the outline points in the loader's current                */
+      /* extra points, which is used to keep original glyph coordinates */
+      error = ah_loader_check_points( gloader, slot->outline.n_points + 2,
+                                      slot->outline.n_contours );
+      if ( error )
+        goto Exit;
+
+      FT_MEM_COPY( gloader->current.extra_points, slot->outline.points,
+                   slot->outline.n_points * sizeof ( FT_Vector ) );
+
+      FT_MEM_COPY( gloader->current.outline.contours, slot->outline.contours,
+                   slot->outline.n_contours * sizeof ( short ) );
+
+      FT_MEM_COPY( gloader->current.outline.tags, slot->outline.tags,
+                   slot->outline.n_points * sizeof ( char ) );
+
+      gloader->current.outline.n_points   = slot->outline.n_points;
+      gloader->current.outline.n_contours = slot->outline.n_contours;
+
+      /* compute original phantom points */
+      hinter->pp1.x = 0;
+      hinter->pp1.y = 0;
+      hinter->pp2.x = FT_MulFix( slot->metrics.horiAdvance, x_scale );
+      hinter->pp2.y = 0;
+
+      /* be sure to check for spacing glyphs */
+      if ( slot->outline.n_points == 0 )
+        goto Hint_Metrics;
+
+      /* now, load the slot image into the auto-outline, and run the */
+      /* automatic hinting process                                   */
+      error = ah_outline_load( outline, face );   /* XXX: change to slot */
+      if ( error )
+        goto Exit;
+
+      /* perform feature detection */
+      ah_outline_detect_features( outline );
+
+      if ( hinter->do_vert_hints )
+      {
+        ah_outline_compute_blue_edges( outline, hinter->globals );
+        ah_outline_scale_blue_edges( outline, hinter->globals );
+      }
+
+      /* perform alignment control */
+      ah_hinter_hint_edges( hinter );
+      ah_hinter_align( hinter );
+
+      /* now save the current outline into the loader's current table */
+      ah_outline_save( outline, gloader );
+
+      /* we now need to hint the metrics according to the change in */
+      /* width/positioning that occured during the hinting process  */
+      {
+        FT_Pos   old_advance, old_rsb, old_lsb, new_lsb;
+        AH_Edge  edge1 = outline->vert_edges;     /* leftmost edge  */
+        AH_Edge  edge2 = edge1 +
+                         outline->num_vedges - 1; /* rightmost edge */
+
+
+        old_advance = hinter->pp2.x;
+        old_rsb     = old_advance - edge2->opos;
+        old_lsb     = edge1->opos;
+        new_lsb     = edge1->pos;
+
+        hinter->pp1.x = ( ( new_lsb    - old_lsb ) + 32 ) & -64;
+        hinter->pp2.x = ( ( edge2->pos + old_rsb ) + 32 ) & -64;
+
+        /* try to fix certain bad advance computations */
+        if ( hinter->pp2.x + hinter->pp1.x == edge2->pos && old_rsb > 4 )
+          hinter->pp2.x += 64;
+      }
+
+      /* good, we simply add the glyph to our loader's base */
+      ah_loader_add( gloader );
+      break;
+
+    case FT_GLYPH_FORMAT_COMPOSITE:
+      {
+        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
+        FT_UInt      num_base_subgs, start_point;
+        FT_SubGlyph  subglyph;
+
+
+        start_point   = gloader->base.outline.n_points;
+
+        /* first of all, copy the subglyph descriptors in the glyph loader */
+        error = ah_loader_check_subglyphs( gloader, num_subglyphs );
+        if ( error )
+          goto Exit;
+
+        FT_MEM_COPY( gloader->current.subglyphs, slot->subglyphs,
+                     num_subglyphs * sizeof ( FT_SubGlyph ) );
+
+        gloader->current.num_subglyphs = num_subglyphs;
+        num_base_subgs = gloader->base.num_subglyphs;
+
+        /* now, read each subglyph independently */
+        for ( nn = 0; nn < num_subglyphs; nn++ )
+        {
+          FT_Vector  pp1, pp2;
+          FT_Pos     x, y;
+          FT_UInt    num_points, num_new_points, num_base_points;
+
+
+          /* gloader.current.subglyphs can change during glyph loading due */
+          /* to re-allocation -- we must recompute the current subglyph on */
+          /* each iteration                                                */
+          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+          pp1 = hinter->pp1;
+          pp2 = hinter->pp2;
+
+          num_base_points = gloader->base.outline.n_points;
+
+          error = ah_hinter_load( hinter, subglyph->index,
+                                  load_flags, depth + 1 );
+          if ( error )
+            goto Exit;
+
+          /* recompute subglyph pointer */
+          subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
+          {
+            pp1 = hinter->pp1;
+            pp2 = hinter->pp2;
+          }
+          else
+          {
+            hinter->pp1 = pp1;
+            hinter->pp2 = pp2;
+          }
+
+          num_points     = gloader->base.outline.n_points;
+          num_new_points = num_points - num_base_points;
+
+          /* now perform the transform required for this subglyph */
+
+          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
+                                   FT_SUBGLYPH_FLAG_XY_SCALE |
+                                   FT_SUBGLYPH_FLAG_2X2      ) )
+          {
+            FT_Vector*  cur   = gloader->base.outline.points +
+                                num_base_points;
+            FT_Vector*  org   = gloader->base.extra_points +
+                                num_base_points;
+            FT_Vector*  limit = cur + num_new_points;
+
+
+            for ( ; cur < limit; cur++, org++ )
+            {
+              FT_Vector_Transform( cur, &subglyph->transform );
+              FT_Vector_Transform( org, &subglyph->transform );
+            }
+          }
+
+          /* apply offset */
+
+          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
+          {
+            FT_Int      k = subglyph->arg1;
+            FT_UInt     l = subglyph->arg2;
+            FT_Vector*  p1;
+            FT_Vector*  p2;
+
+
+            if ( start_point + k >= num_base_points          ||
+                               l >= (FT_UInt)num_new_points  )
+            {
+              error = AH_Err_Invalid_Composite;
+              goto Exit;
+            }
+
+            l += num_base_points;
+
+            /* for now, only use the current point coordinates     */
+            /* we may consider another approach in the near future */
+            p1 = gloader->base.outline.points + start_point + k;
+            p2 = gloader->base.outline.points + start_point + l;
+
+            x = p1->x - p2->x;
+            y = p1->y - p2->y;
+          }
+          else
+          {
+            x = FT_MulFix( subglyph->arg1, x_scale );
+            y = FT_MulFix( subglyph->arg2, y_scale );
+
+            x = ( x + 32 ) & -64;
+            y = ( y + 32 ) & -64;
+          }
+
+          {
+            FT_Outline  dummy = gloader->base.outline;
+
+
+            dummy.points  += num_base_points;
+            dummy.n_points = (short)num_new_points;
+
+            FT_Outline_Translate( &dummy, x, y );
+          }
+        }
+      }
+      break;
+
+    default:
+      /* we don't support other formats (yet?) */
+      error = AH_Err_Unimplemented_Feature;
+    }
+
+  Hint_Metrics:
+    if ( depth == 0 )
+    {
+      FT_BBox  bbox;
+
+
+      /* transform the hinted outline if needed */
+      if ( hinter->transformed )
+        FT_Outline_Transform( &gloader->base.outline, &hinter->trans_matrix );
+
+      /* we must translate our final outline by -pp1.x, and compute */
+      /* the new metrics                                            */
+      if ( hinter->pp1.x )
+        FT_Outline_Translate( &gloader->base.outline, -hinter->pp1.x, 0 );
+
+      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
+      bbox.xMin &= -64;
+      bbox.yMin &= -64;
+      bbox.xMax  = ( bbox.xMax + 63 ) & -64;
+      bbox.yMax  = ( bbox.yMax + 63 ) & -64;
+
+      slot->metrics.width        = bbox.xMax - bbox.xMin;
+      slot->metrics.height       = bbox.yMax - bbox.yMin;
+      slot->metrics.horiBearingX = bbox.xMin;
+      slot->metrics.horiBearingY = bbox.yMax;
+
+      /* for mono-width fonts (like Andale, Courier, etc.), we need */
+      /* to keep the original rounded advance width                 */
+      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
+        slot->metrics.horiAdvance = hinter->pp2.x - hinter->pp1.x;
+      else
+        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
+                                               x_scale );
+
+      slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + 32 ) & -64;
+
+      /* now copy outline into glyph slot */
+      ah_loader_rewind( slot->internal->loader );
+      error = ah_loader_copy_points( slot->internal->loader, gloader );
+      if ( error )
+        goto Exit;
+
+      slot->outline = slot->internal->loader->base.outline;
+      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
+    }
+
+#ifdef DEBUG_HINTER
+    ah_debug_hinter = hinter;
+#endif
+
+  Exit:
+    return error;
+  }
+
+
+  /* load and hint a given glyph */
+  FT_LOCAL_DEF( FT_Error )
+  ah_hinter_load_glyph( AH_Hinter     hinter,
+                        FT_GlyphSlot  slot,
+                        FT_Size       size,
+                        FT_UInt       glyph_index,
+                        FT_Int32      load_flags )
+  {
+    FT_Face          face         = slot->face;
+    FT_Error         error;
+    FT_Fixed         x_scale      = size->metrics.x_scale;
+    FT_Fixed         y_scale      = size->metrics.y_scale;
+    AH_Face_Globals  face_globals = FACE_GLOBALS( face );
+    FT_Render_Mode   hint_mode    = FT_LOAD_TARGET_MODE(load_flags);
+
+
+    /* first of all, we need to check that we're using the correct face and */
+    /* global hints to load the glyph                                       */
+    if ( hinter->face != face || hinter->globals != face_globals )
+    {
+      hinter->face = face;
+      if ( !face_globals )
+      {
+        error = ah_hinter_new_face_globals( hinter, face, 0 );
+        if ( error )
+          goto Exit;
+
+      }
+      hinter->globals = FACE_GLOBALS( face );
+      face_globals    = FACE_GLOBALS( face );
+
+    }
+
+    /* now, we must check the current character pixel size to see if we */
+    /* need to rescale the global metrics                               */
+    if ( face_globals->x_scale != x_scale ||
+         face_globals->y_scale != y_scale )
+      ah_hinter_scale_globals( hinter, x_scale, y_scale );
+
+    ah_loader_rewind( hinter->loader );
+
+    /* reset hinting flags according to load flags and current render target */
+    hinter->do_horz_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
+    hinter->do_vert_hints = !FT_BOOL( load_flags & FT_LOAD_NO_AUTOHINT );
+
+#ifdef DEBUG_HINTER
+    hinter->do_horz_hints = !ah_debug_disable_vert;  /* not a bug, the meaning */
+    hinter->do_vert_hints = !ah_debug_disable_horz;  /* of h/v is inverted!    */
+#endif
+
+    /* we snap the width of vertical stems for the monochrome and         */
+    /* horizontal LCD rendering targets only.  Corresponds to X snapping. */
+    hinter->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+                                        hint_mode == FT_RENDER_MODE_LCD  );
+
+    /* we snap the width of horizontal stems for the monochrome and     */
+    /* vertical LCD rendering targets only.  Corresponds to Y snapping. */
+    hinter->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO   ||
+                                        hint_mode == FT_RENDER_MODE_LCD_V  );
+
+#if 1
+    load_flags  = FT_LOAD_NO_SCALE
+                | FT_LOAD_IGNORE_TRANSFORM ;
+#else
+    load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE;
+#endif
+
+    error = ah_hinter_load( hinter, glyph_index, load_flags, 0 );
+
+  Exit:
+    return error;
+  }
+
+
+  /* retrieve a face's autohint globals for client applications */
+  FT_LOCAL_DEF( void )
+  ah_hinter_get_global_hints( AH_Hinter  hinter,
+                              FT_Face    face,
+                              void**     global_hints,
+                              long*      global_len )
+  {
+    AH_Globals  globals = 0;
+    FT_Memory   memory  = hinter->memory;
+    FT_Error    error;
+
+
+    /* allocate new master globals */
+    if ( FT_NEW( globals ) )
+      goto Fail;
+
+    /* compute face globals if needed */
+    if ( !FACE_GLOBALS( face ) )
+    {
+      error = ah_hinter_new_face_globals( hinter, face, 0 );
+      if ( error )
+        goto Fail;
+    }
+
+    *globals      = FACE_GLOBALS( face )->design;
+    *global_hints = globals;
+    *global_len   = sizeof( *globals );
+
+    return;
+
+  Fail:
+    FT_FREE( globals );
+
+    *global_hints = 0;
+    *global_len   = 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ah_hinter_done_global_hints( AH_Hinter  hinter,
+                               void*      global_hints )
+  {
+    FT_Memory  memory = hinter->memory;
+
+
+    FT_FREE( global_hints );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahhint.h
@@ -1,0 +1,75 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahhint.h                                                               */
+/*                                                                         */
+/*    Glyph hinter (declaration).                                          */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AHHINT_H__
+#define __AHHINT_H__
+
+
+#include <ft2build.h>
+#include "ahglobal.h"
+
+
+FT_BEGIN_HEADER
+
+
+#define AH_HINT_DEFAULT        0
+#define AH_HINT_NO_ALIGNMENT   1
+#define AH_HINT_NO_HORZ_EDGES  0x200000L  /* temporary hack */
+#define AH_HINT_NO_VERT_EDGES  0x400000L  /* temporary hack */
+
+
+  /* create a new empty hinter object */
+  FT_LOCAL( FT_Error )
+  ah_hinter_new( FT_Library  library,
+                 AH_Hinter*  ahinter );
+
+  /* Load a hinted glyph in the hinter */
+  FT_LOCAL( FT_Error )
+  ah_hinter_load_glyph( AH_Hinter     hinter,
+                        FT_GlyphSlot  slot,
+                        FT_Size       size,
+                        FT_UInt       glyph_index,
+                        FT_Int32      load_flags );
+
+  /* finalize a hinter object */
+  FT_LOCAL( void )
+  ah_hinter_done( AH_Hinter  hinter );
+
+  FT_LOCAL( void )
+  ah_hinter_done_face_globals( AH_Face_Globals  globals );
+
+  FT_LOCAL( void )
+  ah_hinter_get_global_hints( AH_Hinter  hinter,
+                              FT_Face    face,
+                              void**     global_hints,
+                              long*      global_len );
+
+  FT_LOCAL( void )
+  ah_hinter_done_global_hints( AH_Hinter  hinter,
+                               void*      global_hints );
+
+
+FT_END_HEADER
+
+#endif /* __AHHINT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahloader.h
@@ -1,0 +1,61 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahloader.h                                                             */
+/*                                                                         */
+/*    Glyph loader for the auto-hinting module (declaration only).         */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This defines the AH_GlyphLoader type; it is simply a typedef to       */
+  /* FT_GlyphLoader.                                                       */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#ifndef __AHLOADER_H__
+#define __AHLOADER_H__
+
+
+#include <ft2build.h>
+
+
+FT_BEGIN_HEADER
+
+#include FT_INTERNAL_GLYPH_LOADER_H
+
+  #define AH_Load    FT_GlyphLoad
+  #define AH_Loader  FT_GlyphLoader
+
+  #define ah_loader_new              FT_GlyphLoader_New
+  #define ah_loader_done             FT_GlyphLoader_Done
+  #define ah_loader_reset            FT_GlyphLoader_Reset
+  #define ah_loader_rewind           FT_GlyphLoader_Rewind
+  #define ah_loader_create_extra     FT_GlyphLoader_CreateExtra
+  #define ah_loader_check_points     FT_GlyphLoader_CheckPoints
+  #define ah_loader_check_subglyphs  FT_GlyphLoader_CheckSubGlyphs
+  #define ah_loader_prepare          FT_GlyphLoader_Prepare
+  #define ah_loader_add              FT_GlyphLoader_Add
+  #define ah_loader_copy_points      FT_GlyphLoader_CopyPoints
+
+
+FT_END_HEADER
+
+#endif /* __AHLOADER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahmodule.c
@@ -1,0 +1,137 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahmodule.c                                                             */
+/*                                                                         */
+/*    Auto-hinting module implementation (declaration).                    */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+#include "ahhint.h"
+
+
+#ifdef  DEBUG_HINTER
+   AH_Hinter  ah_debug_hinter       = NULL;
+   FT_Bool    ah_debug_disable_horz = 0;
+   FT_Bool    ah_debug_disable_vert = 0;
+#endif
+
+  typedef struct  FT_AutoHinterRec_
+  {
+    FT_ModuleRec  root;
+    AH_Hinter     hinter;
+
+  } FT_AutoHinterRec;
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ft_autohinter_init( FT_AutoHinter  module )
+  {
+    FT_Error  error;
+
+
+    error = ah_hinter_new( module->root.library, &module->hinter );
+#ifdef DEBUG_HINTER
+    if ( !error )
+      ah_debug_hinter = module->hinter;
+#endif
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ft_autohinter_done( FT_AutoHinter  module )
+  {
+    ah_hinter_done( module->hinter );
+
+#ifdef DEBUG_HINTER
+    ah_debug_hinter = NULL;
+#endif
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ft_autohinter_load_glyph( FT_AutoHinter  module,
+                            FT_GlyphSlot   slot,
+                            FT_Size        size,
+                            FT_UInt        glyph_index,
+                            FT_Int32       load_flags )
+  {
+    return ah_hinter_load_glyph( module->hinter,
+                                 slot, size, glyph_index, load_flags );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ft_autohinter_reset_globals( FT_AutoHinter  module,
+                               FT_Face        face )
+  {
+    FT_UNUSED( module );
+
+    if ( face->autohint.data )
+      ah_hinter_done_face_globals( (AH_Face_Globals)(face->autohint.data) );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ft_autohinter_get_globals( FT_AutoHinter  module,
+                             FT_Face        face,
+                             void**         global_hints,
+                             long*          global_len )
+  {
+    ah_hinter_get_global_hints( module->hinter, face,
+                                global_hints, global_len );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ft_autohinter_done_globals( FT_AutoHinter  module,
+                              void*          global_hints )
+  {
+    ah_hinter_done_global_hints( module->hinter, global_hints );
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_AutoHinter_ServiceRec  ft_autohinter_service =
+  {
+    ft_autohinter_reset_globals,
+    ft_autohinter_get_globals,
+    ft_autohinter_done_globals,
+    ft_autohinter_load_glyph
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Module_Class  autohint_module_class =
+  {
+    ft_module_hinter,
+    sizeof ( FT_AutoHinterRec ),
+
+    "autohinter",
+    0x10000L,   /* version 1.0 of the autohinter  */
+    0x20000L,   /* requires FreeType 2.0 or above */
+
+    (const void*) &ft_autohinter_service,
+
+    (FT_Module_Constructor)ft_autohinter_init,
+    (FT_Module_Destructor) ft_autohinter_done,
+    (FT_Module_Requester)  0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahmodule.h
@@ -1,0 +1,42 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahmodule.h                                                             */
+/*                                                                         */
+/*    Auto-hinting module (declaration).                                   */
+/*                                                                         */
+/*  Copyright 2000-2001 Catharon Productions Inc.                          */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AHMODULE_H__
+#define __AHMODULE_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_CALLBACK_TABLE
+  const FT_Module_Class  autohint_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __AHMODULE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahoptim.c
@@ -1,0 +1,882 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahoptim.c                                                              */
+/*                                                                         */
+/*    FreeType auto hinting outline optimization (body).                   */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This module is in charge of optimising the outlines produced by the   */
+  /* auto-hinter in direct mode. This is required at small pixel sizes in  */
+  /* order to ensure coherent spacing, among other things..                */
+  /*                                                                       */
+  /* The technique used in this module is a simplified simulated           */
+  /* annealing.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H       /* for FT_ALLOC_ARRAY() and FT_FREE() */
+#include "ahoptim.h"
+
+
+  /* define this macro to use brute force optimization -- this is slow,  */
+  /* but a good way to perfect the distortion function `by hand' through */
+  /* tweaking                                                            */
+#define AH_BRUTE_FORCE
+
+
+#define xxxAH_DEBUG_OPTIM
+
+
+#undef LOG
+#ifdef AH_DEBUG_OPTIM
+
+#define LOG( x )  optim_log ## x
+
+#else
+
+#define LOG( x )
+
+#endif /* AH_DEBUG_OPTIM */
+
+
+#ifdef AH_DEBUG_OPTIM
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define FLOAT( x )  ( (float)( (x) / 64.0 ) )
+
+
+  static void
+  optim_log( const char*  fmt, ... )
+  {
+    va_list  ap;
+
+
+    va_start( ap, fmt );
+    vprintf( fmt, ap );
+    va_end( ap );
+  }
+
+
+  static void
+  AH_Dump_Stems( AH_Optimizer*  optimizer )
+  {
+    int       n;
+    AH_Stem*  stem;
+
+
+    stem = optimizer->stems;
+    for ( n = 0; n < optimizer->num_stems; n++, stem++ )
+    {
+      LOG(( " %c%2d [%.1f:%.1f]={%.1f:%.1f}="
+            "<%1.f..%1.f> force=%.1f speed=%.1f\n",
+            optimizer->vertical ? 'V' : 'H', n,
+            FLOAT( stem->edge1->opos ), FLOAT( stem->edge2->opos ),
+            FLOAT( stem->edge1->pos ),  FLOAT( stem->edge2->pos ),
+            FLOAT( stem->min_pos ),     FLOAT( stem->max_pos ),
+            FLOAT( stem->force ),       FLOAT( stem->velocity ) ));
+    }
+  }
+
+
+  static void
+  AH_Dump_Stems2( AH_Optimizer*  optimizer )
+  {
+    int       n;
+    AH_Stem*  stem;
+
+
+    stem = optimizer->stems;
+    for ( n = 0; n < optimizer->num_stems; n++, stem++ )
+    {
+      LOG(( " %c%2d [%.1f]=<%1.f..%1.f> force=%.1f speed=%.1f\n",
+            optimizer->vertical ? 'V' : 'H', n,
+            FLOAT( stem->pos ),
+            FLOAT( stem->min_pos ), FLOAT( stem->max_pos ),
+            FLOAT( stem->force ),   FLOAT( stem->velocity ) ));
+    }
+  }
+
+
+  static void
+  AH_Dump_Springs( AH_Optimizer*  optimizer )
+  {
+    int  n;
+    AH_Spring*  spring;
+    AH_Stem*    stems;
+
+
+    spring = optimizer->springs;
+    stems  = optimizer->stems;
+    LOG(( "%cSprings ", optimizer->vertical ? 'V' : 'H' ));
+
+    for ( n = 0; n < optimizer->num_springs; n++, spring++ )
+    {
+      LOG(( " [%d-%d:%.1f:%1.f:%.1f]",
+            spring->stem1 - stems, spring->stem2 - stems,
+            FLOAT( spring->owidth ),
+            FLOAT( spring->stem2->pos -
+                   ( spring->stem1->pos + spring->stem1->width ) ),
+            FLOAT( spring->tension ) ));
+    }
+
+    LOG(( "\n" ));
+  }
+
+#endif /* AH_DEBUG_OPTIM */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   COMPUTE STEMS AND SPRINGS IN AN OUTLINE                       ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static int
+  valid_stem_segments( AH_Segment  seg1,
+                       AH_Segment  seg2 )
+  {
+    return seg1->serif == 0                   &&
+           seg2                               &&
+           seg2->link == seg1                 &&
+           seg1->pos < seg2->pos              &&
+           seg1->min_coord <= seg2->max_coord &&
+           seg2->min_coord <= seg1->max_coord;
+  }
+
+
+  /* compute all stems in an outline */
+  static int
+  optim_compute_stems( AH_Optimizer*  optimizer )
+  {
+    AH_Outline  outline = optimizer->outline;
+    FT_Fixed    scale;
+    FT_Memory   memory  = optimizer->memory;
+    FT_Error    error   = 0;
+    FT_Int      dimension;
+    AH_Edge     edges;
+    AH_Edge     edge_limit;
+    AH_Stem**   p_stems;
+    FT_Int*     p_num_stems;
+
+
+    edges      = outline->horz_edges;
+    edge_limit = edges + outline->num_hedges;
+    scale      = outline->y_scale;
+
+    p_stems     = &optimizer->horz_stems;
+    p_num_stems = &optimizer->num_hstems;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      AH_Stem*  stems     = 0;
+      FT_Int    num_stems = 0;
+      AH_Edge   edge;
+
+
+      /* first of all, count the number of stems in this direction */
+      for ( edge = edges; edge < edge_limit; edge++ )
+      {
+        AH_Segment  seg = edge->first;
+
+
+        do
+        {
+          if (valid_stem_segments( seg, seg->link ) )
+            num_stems++;
+
+          seg = seg->edge_next;
+
+        } while ( seg != edge->first );
+      }
+
+      /* now allocate the stems and build their table */
+      if ( num_stems > 0 )
+      {
+        AH_Stem*  stem;
+
+
+        if ( FT_NEW_ARRAY( stems, num_stems ) )
+          goto Exit;
+
+        stem = stems;
+        for ( edge = edges; edge < edge_limit; edge++ )
+        {
+          AH_Segment  seg = edge->first;
+          AH_Segment  seg2;
+
+
+          do
+          {
+            seg2 = seg->link;
+            if ( valid_stem_segments( seg, seg2 ) )
+            {
+              AH_Edge  edge1 = seg->edge;
+              AH_Edge  edge2 = seg2->edge;
+
+
+              stem->edge1  = edge1;
+              stem->edge2  = edge2;
+              stem->opos   = edge1->opos;
+              stem->pos    = edge1->pos;
+              stem->owidth = edge2->opos - edge1->opos;
+              stem->width  = edge2->pos  - edge1->pos;
+
+              /* compute min_coord and max_coord */
+              {
+                FT_Pos  min_coord = seg->min_coord;
+                FT_Pos  max_coord = seg->max_coord;
+
+
+                if ( seg2->min_coord > min_coord )
+                  min_coord = seg2->min_coord;
+
+                if ( seg2->max_coord < max_coord )
+                  max_coord = seg2->max_coord;
+
+                stem->min_coord = min_coord;
+                stem->max_coord = max_coord;
+              }
+
+              /* compute minimum and maximum positions for stem --   */
+              /* note that the left-most/bottom-most stem has always */
+              /* a fixed position                                    */
+              if ( stem == stems || edge1->blue_edge || edge2->blue_edge )
+              {
+                /* this stem cannot move; it is snapped to a blue edge */
+                stem->min_pos = stem->pos;
+                stem->max_pos = stem->pos;
+              }
+              else
+              {
+                /* this edge can move; compute its min and max positions */
+                FT_Pos  pos1 = stem->opos;
+                FT_Pos  pos2 = pos1 + stem->owidth - stem->width;
+                FT_Pos  min1 = pos1 & -64;
+                FT_Pos  min2 = pos2 & -64;
+
+
+                stem->min_pos = min1;
+                stem->max_pos = min1 + 64;
+                if ( min2 < min1 )
+                  stem->min_pos = min2;
+                else
+                  stem->max_pos = min2 + 64;
+
+                /* XXX: just to see what it does */
+                stem->max_pos += 64;
+
+                /* just for the case where direct hinting did some */
+                /* incredible things (e.g. blue edge shifts)       */
+                if ( stem->min_pos > stem->pos )
+                  stem->min_pos = stem->pos;
+
+                if ( stem->max_pos < stem->pos )
+                  stem->max_pos = stem->pos;
+              }
+
+              stem->velocity = 0;
+              stem->force    = 0;
+
+              stem++;
+            }
+            seg = seg->edge_next;
+
+          } while ( seg != edge->first );
+        }
+      }
+
+      *p_stems     = stems;
+      *p_num_stems = num_stems;
+
+      edges      = outline->vert_edges;
+      edge_limit = edges + outline->num_vedges;
+      scale      = outline->x_scale;
+
+      p_stems     = &optimizer->vert_stems;
+      p_num_stems = &optimizer->num_vstems;
+    }
+
+  Exit:
+
+#ifdef AH_DEBUG_OPTIM
+    AH_Dump_Stems( optimizer );
+#endif
+
+    return error;
+  }
+
+
+  /* returns the spring area between two stems, 0 if none */
+  static FT_Pos
+  stem_spring_area( AH_Stem*  stem1,
+                    AH_Stem*  stem2 )
+  {
+    FT_Pos  area1 = stem1->max_coord - stem1->min_coord;
+    FT_Pos  area2 = stem2->max_coord - stem2->min_coord;
+    FT_Pos  min   = stem1->min_coord;
+    FT_Pos  max   = stem1->max_coord;
+    FT_Pos  area;
+
+
+    /* order stems */
+    if ( stem2->opos <= stem1->opos + stem1->owidth )
+      return 0;
+
+    if ( min < stem2->min_coord )
+      min = stem2->min_coord;
+
+    if ( max < stem2->max_coord )
+      max = stem2->max_coord;
+
+    area = ( max-min );
+    if ( 2 * area < area1 && 2 * area < area2 )
+      area = 0;
+
+    return area;
+  }
+
+
+  /* compute all springs in an outline */
+  static int
+  optim_compute_springs( AH_Optimizer*  optimizer )
+  {
+    /* basically, a spring exists between two stems if most of their */
+    /* surface is aligned                                            */
+    FT_Memory    memory  = optimizer->memory;
+
+    AH_Stem*     stems;
+    AH_Stem*     stem_limit;
+    AH_Stem*     stem;
+    int          dimension;
+    int          error = 0;
+
+    FT_Int*      p_num_springs;
+    AH_Spring**  p_springs;
+
+
+    stems      = optimizer->horz_stems;
+    stem_limit = stems + optimizer->num_hstems;
+
+    p_springs     = &optimizer->horz_springs;
+    p_num_springs = &optimizer->num_hsprings;
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      FT_Int      num_springs = 0;
+      AH_Spring*  springs     = 0;
+
+
+      /* first of all, count stem springs */
+      for ( stem = stems; stem + 1 < stem_limit; stem++ )
+      {
+        AH_Stem*  stem2;
+
+
+        for ( stem2 = stem+1; stem2 < stem_limit; stem2++ )
+          if ( stem_spring_area( stem, stem2 ) )
+            num_springs++;
+      }
+
+      /* then allocate and build the springs table */
+      if ( num_springs > 0 )
+      {
+        AH_Spring*  spring;
+
+
+        /* allocate table of springs */
+        if ( FT_NEW_ARRAY( springs, num_springs ) )
+          goto Exit;
+
+        /* fill the springs table */
+        spring = springs;
+        for ( stem = stems; stem+1 < stem_limit; stem++ )
+        {
+          AH_Stem*  stem2;
+          FT_Pos    area;
+
+
+          for ( stem2 = stem + 1; stem2 < stem_limit; stem2++ )
+          {
+            area = stem_spring_area( stem, stem2 );
+            if ( area )
+            {
+              /* add a new spring here */
+              spring->stem1   = stem;
+              spring->stem2   = stem2;
+              spring->owidth  = stem2->opos - ( stem->opos + stem->owidth );
+              spring->tension = 0;
+
+              spring++;
+            }
+          }
+        }
+      }
+      *p_num_springs = num_springs;
+      *p_springs     = springs;
+
+      stems      = optimizer->vert_stems;
+      stem_limit = stems + optimizer->num_vstems;
+
+      p_springs     = &optimizer->vert_springs;
+      p_num_springs = &optimizer->num_vsprings;
+    }
+
+  Exit:
+
+#ifdef AH_DEBUG_OPTIM
+    AH_Dump_Springs( optimizer );
+#endif
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   OPTIMIZE THROUGH MY STRANGE SIMULATED ANNEALING ALGO ;-)      ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#ifndef AH_BRUTE_FORCE
+
+  /* compute all spring tensions */
+  static void
+  optim_compute_tensions( AH_Optimizer*  optimizer )
+  {
+    AH_Spring*  spring = optimizer->springs;
+    AH_Spring*  limit  = spring + optimizer->num_springs;
+
+
+    for ( ; spring < limit; spring++ )
+    {
+      AH_Stem*  stem1 = spring->stem1;
+      AH_Stem*  stem2 = spring->stem2;
+      FT_Int    status;
+
+      FT_Pos  width;
+      FT_Pos  tension;
+      FT_Pos  sign;
+
+
+      /* compute the tension; it simply is -K*(new_width-old_width) */
+      width   = stem2->pos - ( stem1->pos + stem1->width );
+      tension = width - spring->owidth;
+
+      sign = 1;
+      if ( tension < 0 )
+      {
+        sign    = -1;
+        tension = -tension;
+      }
+
+      if ( width <= 0 )
+        tension = 32000;
+      else
+        tension = ( tension << 10 ) / width;
+
+      tension = -sign * FT_MulFix( tension, optimizer->tension_scale );
+      spring->tension = tension;
+
+      /* now, distribute tension among the englobing stems, if they */
+      /* are able to move                                           */
+      status = 0;
+      if ( stem1->pos <= stem1->min_pos )
+        status |= 1;
+      if ( stem2->pos >= stem2->max_pos )
+        status |= 2;
+
+      if ( !status )
+        tension /= 2;
+
+      if ( ( status & 1 ) == 0 )
+        stem1->force -= tension;
+
+      if ( ( status & 2 ) == 0 )
+        stem2->force += tension;
+    }
+  }
+
+
+  /* compute all stem movements -- returns 0 if nothing moved */
+  static int
+  optim_compute_stem_movements( AH_Optimizer*  optimizer )
+  {
+    AH_Stem*  stems = optimizer->stems;
+    AH_Stem*  limit = stems + optimizer->num_stems;
+    AH_Stem*  stem  = stems;
+    int       moved = 0;
+
+
+    /* set initial forces to velocity */
+    for ( stem = stems; stem < limit; stem++ )
+    {
+      stem->force     = stem->velocity;
+      stem->velocity /= 2;                  /* XXX: Heuristics */
+    }
+
+    /* compute the sum of forces applied on each stem */
+    optim_compute_tensions( optimizer );
+
+#ifdef AH_DEBUG_OPTIM
+    AH_Dump_Springs( optimizer );
+    AH_Dump_Stems2( optimizer );
+#endif
+
+    /* now, see whether something can move */
+    for ( stem = stems; stem < limit; stem++ )
+    {
+      if ( stem->force > optimizer->tension_threshold )
+      {
+        /* there is enough tension to move the stem to the right */
+        if ( stem->pos < stem->max_pos )
+        {
+          stem->pos     += 64;
+          stem->velocity = stem->force / 2;
+          moved          = 1;
+        }
+        else
+          stem->velocity = 0;
+      }
+      else if ( stem->force < optimizer->tension_threshold )
+      {
+        /* there is enough tension to move the stem to the left */
+        if ( stem->pos > stem->min_pos )
+        {
+          stem->pos     -= 64;
+          stem->velocity = stem->force / 2;
+          moved          = 1;
+        }
+        else
+          stem->velocity = 0;
+      }
+    }
+
+    /* return 0 if nothing moved */
+    return moved;
+  }
+
+#endif /* AH_BRUTE_FORCE */
+
+
+  /* compute current global distortion from springs */
+  static FT_Pos
+  optim_compute_distortion( AH_Optimizer*  optimizer )
+  {
+    AH_Spring*  spring = optimizer->springs;
+    AH_Spring*  limit  = spring + optimizer->num_springs;
+    FT_Pos      distortion = 0;
+
+
+    for ( ; spring < limit; spring++ )
+    {
+      AH_Stem*  stem1 = spring->stem1;
+      AH_Stem*  stem2 = spring->stem2;
+      FT_Pos  width;
+
+      width  = stem2->pos - ( stem1->pos + stem1->width );
+      width -= spring->owidth;
+      if ( width < 0 )
+        width = -width;
+
+      distortion += width;
+    }
+
+    return distortion;
+  }
+
+
+  /* record stems configuration in `best of' history */
+  static void
+  optim_record_configuration( AH_Optimizer*  optimizer )
+  {
+    FT_Pos             distortion;
+    AH_Configuration*  configs = optimizer->configs;
+    AH_Configuration*  limit   = configs + optimizer->num_configs;
+    AH_Configuration*  config;
+
+
+    distortion = optim_compute_distortion( optimizer );
+    LOG(( "config distortion = %.1f ", FLOAT( distortion * 64 ) ));
+
+    /* check that we really need to add this configuration to our */
+    /* sorted history                                             */
+    if ( limit > configs && limit[-1].distortion < distortion )
+    {
+      LOG(( "ejected\n" ));
+      return;
+    }
+
+    /* add new configuration at the end of the table */
+    {
+      int  n;
+
+
+      config = limit;
+      if ( optimizer->num_configs < AH_MAX_CONFIGS )
+        optimizer->num_configs++;
+      else
+        config--;
+
+      config->distortion = distortion;
+
+      for ( n = 0; n < optimizer->num_stems; n++ )
+        config->positions[n] = optimizer->stems[n].pos;
+    }
+
+    /* move the current configuration towards the front of the list */
+    /* when necessary -- yes this is slow bubble sort ;-)           */
+    while ( config > configs && config[0].distortion < config[-1].distortion )
+    {
+      AH_Configuration  temp;
+
+
+      config--;
+      temp      = config[0];
+      config[0] = config[1];
+      config[1] = temp;
+    }
+    LOG(( "recorded!\n" ));
+  }
+
+
+#ifdef AH_BRUTE_FORCE
+
+  /* optimize outline in a single direction */
+  static void
+  optim_compute( AH_Optimizer*  optimizer )
+  {
+    int       n;
+    FT_Bool   moved;
+
+    AH_Stem*  stem  = optimizer->stems;
+    AH_Stem*  limit = stem + optimizer->num_stems;
+
+
+    /* empty, exit */
+    if ( stem >= limit )
+      return;
+
+    optimizer->num_configs = 0;
+
+    stem = optimizer->stems;
+    for ( ; stem < limit; stem++ )
+      stem->pos = stem->min_pos;
+
+    do
+    {
+      /* record current configuration */
+      optim_record_configuration( optimizer );
+
+      /* now change configuration */
+      moved = 0;
+      for ( stem = optimizer->stems; stem < limit; stem++ )
+      {
+        if ( stem->pos < stem->max_pos )
+        {
+          stem->pos += 64;
+          moved      = 1;
+          break;
+        }
+
+        stem->pos = stem->min_pos;
+      }
+    } while ( moved );
+
+    /* now, set the best stem positions */
+    for ( n = 0; n < optimizer->num_stems; n++ )
+    {
+      AH_Stem*  stem = optimizer->stems + n;
+      FT_Pos    pos  = optimizer->configs[0].positions[n];
+
+
+      stem->edge1->pos = pos;
+      stem->edge2->pos = pos + stem->width;
+
+      stem->edge1->flags |= AH_EDGE_DONE;
+      stem->edge2->flags |= AH_EDGE_DONE;
+    }
+  }
+
+#else /* AH_BRUTE_FORCE */
+
+  /* optimize outline in a single direction */
+  static void
+  optim_compute( AH_Optimizer*  optimizer )
+  {
+    int  n, counter, counter2;
+
+
+    optimizer->num_configs       = 0;
+    optimizer->tension_scale     = 0x80000L;
+    optimizer->tension_threshold = 64;
+
+    /* record initial configuration threshold */
+    optim_record_configuration( optimizer );
+
+    counter = 0;
+    for ( counter2 = optimizer->num_stems*8; counter2 >= 0; counter2-- )
+    {
+      if ( counter == 0 )
+        counter = 2 * optimizer->num_stems;
+
+      if ( !optim_compute_stem_movements( optimizer ) )
+        break;
+
+      optim_record_configuration( optimizer );
+
+      counter--;
+      if ( counter == 0 )
+        optimizer->tension_scale /= 2;
+    }
+
+    /* now, set the best stem positions */
+    for ( n = 0; n < optimizer->num_stems; n++ )
+    {
+      AH_Stem*  stem = optimizer->stems + n;
+      FT_Pos    pos  = optimizer->configs[0].positions[n];
+
+
+      stem->edge1->pos = pos;
+      stem->edge2->pos = pos + stem->width;
+
+      stem->edge1->flags |= AH_EDGE_DONE;
+      stem->edge2->flags |= AH_EDGE_DONE;
+    }
+  }
+
+#endif /* AH_BRUTE_FORCE */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   HIGH-LEVEL OPTIMIZER API                                      ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* releases the optimization data */
+  void
+  AH_Optimizer_Done( AH_Optimizer*  optimizer )
+  {
+    if ( optimizer )
+    {
+      FT_Memory  memory = optimizer->memory;
+
+
+      FT_FREE( optimizer->horz_stems );
+      FT_FREE( optimizer->vert_stems );
+      FT_FREE( optimizer->horz_springs );
+      FT_FREE( optimizer->vert_springs );
+      FT_FREE( optimizer->positions );
+    }
+  }
+
+
+  /* loads the outline into the optimizer */
+  int
+  AH_Optimizer_Init( AH_Optimizer*  optimizer,
+                     AH_Outline     outline,
+                     FT_Memory      memory )
+  {
+    FT_Error  error;
+
+
+    FT_MEM_ZERO( optimizer, sizeof ( *optimizer ) );
+    optimizer->outline = outline;
+    optimizer->memory  = memory;
+
+    LOG(( "initializing new optimizer\n" ));
+    /* compute stems and springs */
+    error = optim_compute_stems  ( optimizer ) ||
+            optim_compute_springs( optimizer );
+    if ( error )
+      goto Fail;
+
+    /* allocate stem positions history and configurations */
+    {
+      int  n, max_stems;
+
+
+      max_stems = optimizer->num_hstems;
+      if ( max_stems < optimizer->num_vstems )
+        max_stems = optimizer->num_vstems;
+
+      if ( FT_NEW_ARRAY( optimizer->positions, max_stems * AH_MAX_CONFIGS ) )
+        goto Fail;
+
+      optimizer->num_configs = 0;
+      for ( n = 0; n < AH_MAX_CONFIGS; n++ )
+        optimizer->configs[n].positions = optimizer->positions +
+                                          n * max_stems;
+    }
+
+    return error;
+
+  Fail:
+    AH_Optimizer_Done( optimizer );
+    return error;
+  }
+
+
+  /* compute optimal outline */
+  void
+  AH_Optimizer_Compute( AH_Optimizer*  optimizer )
+  {
+    optimizer->num_stems   = optimizer->num_hstems;
+    optimizer->stems       = optimizer->horz_stems;
+    optimizer->num_springs = optimizer->num_hsprings;
+    optimizer->springs     = optimizer->horz_springs;
+
+    if ( optimizer->num_springs > 0 )
+    {
+      LOG(( "horizontal optimization ------------------------\n" ));
+      optim_compute( optimizer );
+    }
+
+    optimizer->num_stems   = optimizer->num_vstems;
+    optimizer->stems       = optimizer->vert_stems;
+    optimizer->num_springs = optimizer->num_vsprings;
+    optimizer->springs     = optimizer->vert_springs;
+
+    if ( optimizer->num_springs )
+    {
+      LOG(( "vertical optimization --------------------------\n" ));
+      optim_compute( optimizer );
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahoptim.h
@@ -1,0 +1,137 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahoptim.h                                                              */
+/*                                                                         */
+/*    FreeType auto hinting outline optimization (declaration).            */
+/*                                                                         */
+/*  Copyright 2000-2001 Catharon Productions Inc.                          */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AHOPTIM_H__
+#define __AHOPTIM_H__
+
+
+#include <ft2build.h>
+#include "ahtypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+  /* the maximal number of stem configurations to record */
+  /* during optimization                                 */
+#define AH_MAX_CONFIGS  8
+
+
+  typedef struct  AH_Stem_
+  {
+    FT_Pos   pos;       /* current position        */
+    FT_Pos   velocity;  /* current velocity        */
+    FT_Pos   force;     /* sum of current forces   */
+    FT_Pos   width;     /* normalized width        */
+
+    FT_Pos   min_pos;   /* minimum grid position */
+    FT_Pos   max_pos;   /* maximum grid position */
+
+    AH_Edge  edge1;     /* left/bottom edge */
+    AH_Edge  edge2;     /* right/top edge   */
+
+    FT_Pos   opos;      /* original position */
+    FT_Pos   owidth;    /* original width    */
+
+    FT_Pos   min_coord; /* minimum coordinate */
+    FT_Pos   max_coord; /* maximum coordinate */
+
+  } AH_Stem;
+
+
+  /* A spring between two stems */
+  typedef struct  AH_Spring_
+  {
+    AH_Stem*  stem1;
+    AH_Stem*  stem2;
+    FT_Pos    owidth;   /* original width  */
+    FT_Pos    tension;  /* current tension */
+
+  } AH_Spring;
+
+
+  /* A configuration records the position of each stem at a given time  */
+  /* as well as the associated distortion                               */
+  typedef struct AH_Configuration_
+  {
+    FT_Pos*  positions;
+    FT_Long  distortion;
+
+  } AH_Configuration;
+
+
+  typedef struct  AH_Optimizer_
+  {
+    FT_Memory         memory;
+    AH_Outline        outline;
+
+    FT_Int            num_hstems;
+    AH_Stem*          horz_stems;
+
+    FT_Int            num_vstems;
+    AH_Stem*          vert_stems;
+
+    FT_Int            num_hsprings;
+    FT_Int            num_vsprings;
+    AH_Spring*        horz_springs;
+    AH_Spring*        vert_springs;
+
+    FT_Int            num_configs;
+    AH_Configuration  configs[AH_MAX_CONFIGS];
+    FT_Pos*           positions;
+
+    /* during each pass, use these instead */
+    FT_Int            num_stems;
+    AH_Stem*          stems;
+
+    FT_Int            num_springs;
+    AH_Spring*        springs;
+    FT_Bool           vertical;
+
+    FT_Fixed          tension_scale;
+    FT_Pos            tension_threshold;
+
+  } AH_Optimizer;
+
+
+  /* loads the outline into the optimizer */
+  int
+  AH_Optimizer_Init( AH_Optimizer*  optimizer,
+                     AH_Outline     outline,
+                     FT_Memory      memory );
+
+
+  /* compute optimal outline */
+  void
+  AH_Optimizer_Compute( AH_Optimizer*  optimizer );
+
+
+  /* release the optimization data */
+  void
+  AH_Optimizer_Done( AH_Optimizer*  optimizer );
+
+
+FT_END_HEADER
+
+#endif /* __AHOPTIM_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ahtypes.h
@@ -1,0 +1,518 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ahtypes.h                                                              */
+/*                                                                         */
+/*    General types and definitions for the auto-hint module               */
+/*    (specification only).                                                */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 Catharon Productions Inc.                    */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __AHTYPES_H__
+#define __AHTYPES_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+
+#ifdef DEBUG_HINTER
+#include <../src/autohint/ahloader.h>
+#else
+#include "ahloader.h"
+#endif
+
+
+#define xxAH_DEBUG
+
+
+#ifdef AH_DEBUG
+
+#include <stdio.h>
+#define AH_LOG( x )  printf ## x
+
+#else
+
+#define AH_LOG( x )  do ; while ( 0 ) /* nothing */
+
+#endif /* AH_DEBUG */
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /**** COMPILE-TIME BUILD OPTIONS                                      ****/
+  /****                                                                 ****/
+  /**** Toggle these configuration macros to experiment with `features' ****/
+  /**** of the auto-hinter.                                             ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* If this option is defined, only strong interpolation will be used to  */
+  /* place the points between edges.  Otherwise, `smooth' points are       */
+  /* detected and later hinted through weak interpolation to correct some  */
+  /* unpleasant artefacts.                                                 */
+  /*                                                                       */
+#undef AH_OPTION_NO_WEAK_INTERPOLATION
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* If this option is defined, only weak interpolation will be used to    */
+  /* place the points between edges.  Otherwise, `strong' points are       */
+  /* detected and later hinted through strong interpolation to correct     */
+  /* some unpleasant artefacts.                                            */
+  /*                                                                       */
+#undef AH_OPTION_NO_STRONG_INTERPOLATION
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Undefine this macro if you don't want to hint the metrics.  There is  */
+  /* no reason to do this (at least for non-CJK scripts), except for       */
+  /* experimentation.                                                      */
+  /*                                                                       */
+#undef  AH_HINT_METRICS
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Define this macro if you do not want to insert extra edges at a       */
+  /* glyph's x and y extremum (if there isn't one already available).      */
+  /* This helps to reduce a number of artefacts and allows hinting of      */
+  /* metrics.                                                              */
+  /*                                                                       */
+#undef AH_OPTION_NO_EXTREMUM_EDGES
+
+
+  /* don't touch for now */
+#define AH_MAX_WIDTHS   12
+#define AH_MAX_HEIGHTS  12
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   TYPE DEFINITIONS                                              ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* see agangles.h */
+  typedef FT_Int  AH_Angle;
+
+
+  /* hint flags */
+#define AH_FLAG_NONE       0
+
+  /* bezier control points flags */
+#define AH_FLAG_CONIC                 1
+#define AH_FLAG_CUBIC                 2
+#define AH_FLAG_CONTROL               ( AH_FLAG_CONIC | AH_FLAG_CUBIC )
+
+  /* extrema flags */
+#define AH_FLAG_EXTREMA_X             4
+#define AH_FLAG_EXTREMA_Y             8
+
+  /* roundness */
+#define AH_FLAG_ROUND_X              16
+#define AH_FLAG_ROUND_Y              32
+
+  /* touched */
+#define AH_FLAG_TOUCH_X              64
+#define AH_FLAG_TOUCH_Y             128
+
+  /* weak interpolation */
+#define AH_FLAG_WEAK_INTERPOLATION  256
+#define AH_FLAG_INFLECTION          512
+
+  typedef FT_Int AH_Flags;
+
+
+  /* edge hint flags */
+#define AH_EDGE_NORMAL  0
+#define AH_EDGE_ROUND   1
+#define AH_EDGE_SERIF   2
+#define AH_EDGE_DONE    4
+
+  typedef FT_Int  AH_Edge_Flags;
+
+
+  /* hint directions -- the values are computed so that two vectors are */
+  /* in opposite directions iff `dir1+dir2 == 0'                        */
+#define AH_DIR_NONE    4
+#define AH_DIR_RIGHT   1
+#define AH_DIR_LEFT   -1
+#define AH_DIR_UP      2
+#define AH_DIR_DOWN   -2
+
+  typedef FT_Int  AH_Direction;
+
+
+  typedef struct AH_PointRec_*    AH_Point;
+  typedef struct AH_SegmentRec_*  AH_Segment;
+  typedef struct AH_EdgeRec_*     AH_Edge;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    AH_PointRec                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A structure used to model an outline point to the AH_OutlineRec    */
+  /*    type.                                                              */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    flags     :: The current point hint flags.                         */
+  /*                                                                       */
+  /*    ox, oy    :: The current original scaled coordinates.              */
+  /*                                                                       */
+  /*    fx, fy    :: The current coordinates in font units.                */
+  /*                                                                       */
+  /*    x,  y     :: The current hinted coordinates.                       */
+  /*                                                                       */
+  /*    u, v      :: Point coordinates -- meaning varies with context.     */
+  /*                                                                       */
+  /*    in_dir    :: The direction of the inwards vector (prev->point).    */
+  /*                                                                       */
+  /*    out_dir   :: The direction of the outwards vector (point->next).   */
+  /*                                                                       */
+  /*    in_angle  :: The angle of the inwards vector.                      */
+  /*                                                                       */
+  /*    out_angle :: The angle of the outwards vector.                     */
+  /*                                                                       */
+  /*    next      :: The next point in same contour.                       */
+  /*                                                                       */
+  /*    prev      :: The previous point in same contour.                   */
+  /*                                                                       */
+  typedef struct  AH_PointRec_
+  {
+    AH_Flags      flags;    /* point flags used by hinter */
+    FT_Pos        ox, oy;
+    FT_Pos        fx, fy;
+    FT_Pos        x,  y;
+    FT_Pos        u,  v;
+
+    AH_Direction  in_dir;   /* direction of inwards vector  */
+    AH_Direction  out_dir;  /* direction of outwards vector */
+
+    AH_Angle      in_angle;
+    AH_Angle      out_angle;
+
+    AH_Point      next;     /* next point in contour     */
+    AH_Point      prev;     /* previous point in contour */
+
+  } AH_PointRec;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    AH_SegmentRec                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A structure used to describe an edge segment to the auto-hinter.   */
+  /*    A segment is simply a sequence of successive points located on the */
+  /*    same horizontal or vertical `position', in a given direction.      */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    flags      :: The segment edge flags (straight, rounded, etc.).    */
+  /*                                                                       */
+  /*    dir        :: The segment direction.                               */
+  /*                                                                       */
+  /*    first      :: The first point in the segment.                      */
+  /*                                                                       */
+  /*    last       :: The last point in the segment.                       */
+  /*                                                                       */
+  /*    contour    :: A pointer to the first point of the segment's        */
+  /*                  contour.                                             */
+  /*                                                                       */
+  /*    pos        :: The segment position in font units.                  */
+  /*                                                                       */
+  /*    size       :: The segment size.                                    */
+  /*                                                                       */
+  /*    edge       :: The edge of the current segment.                     */
+  /*                                                                       */
+  /*    edge_next  :: The next segment on the same edge.                   */
+  /*                                                                       */
+  /*    link       :: The pairing segment for this edge.                   */
+  /*                                                                       */
+  /*    serif      :: The primary segment for serifs.                      */
+  /*                                                                       */
+  /*    num_linked :: The number of other segments that link to this one.  */
+  /*                                                                       */
+  /*    score      :: Used to score the segment when selecting them.       */
+  /*                                                                       */
+  typedef struct  AH_SegmentRec_
+  {
+    AH_Edge_Flags  flags;
+    AH_Direction   dir;
+
+    AH_Point       first;       /* first point in edge segment             */
+    AH_Point       last;        /* last point in edge segment              */
+    AH_Point*      contour;     /* ptr to first point of segment's contour */
+
+    FT_Pos         pos;         /* position of segment           */
+    FT_Pos         min_coord;   /* minimum coordinate of segment */
+    FT_Pos         max_coord;   /* maximum coordinate of segment */
+
+    AH_Edge        edge;
+    AH_Segment     edge_next;
+
+    AH_Segment     link;        /* link segment               */
+    AH_Segment     serif;       /* primary segment for serifs */
+    FT_Pos         num_linked;  /* number of linked segments  */
+    FT_Pos         score;
+
+  } AH_SegmentRec;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    AH_EdgeRec                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A structure used to describe an edge, which really is a horizontal */
+  /*    or vertical coordinate to be hinted depending on the segments      */
+  /*    located on it.                                                     */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    flags      :: The segment edge flags (straight, rounded, etc.).    */
+  /*                                                                       */
+  /*    dir        :: The main segment direction on this edge.             */
+  /*                                                                       */
+  /*    first      :: The first edge segment.                              */
+  /*                                                                       */
+  /*    last       :: The last edge segment.                               */
+  /*                                                                       */
+  /*    fpos       :: The original edge position in font units.            */
+  /*                                                                       */
+  /*    opos       :: The original scaled edge position.                   */
+  /*                                                                       */
+  /*    pos        :: The hinted edge position.                            */
+  /*                                                                       */
+  /*    link       :: The linked edge.                                     */
+  /*                                                                       */
+  /*    serif      :: The serif edge.                                      */
+  /*                                                                       */
+  /*    num_paired :: The number of other edges that pair to this one.     */
+  /*                                                                       */
+  /*    score      :: Used to score the edge when selecting them.          */
+  /*                                                                       */
+  /*    blue_edge  :: Indicate the blue zone edge this edge is related to. */
+  /*                  Only set for some of the horizontal edges in a Latin */
+  /*                  font.                                                */
+  /*                                                                       */
+  typedef struct  AH_EdgeRec_
+  {
+    AH_Edge_Flags  flags;
+    AH_Direction   dir;
+
+    AH_Segment     first;
+    AH_Segment     last;
+
+    FT_Pos         fpos;
+    FT_Pos         opos;
+    FT_Pos         pos;
+
+    AH_Edge        link;
+    AH_Edge        serif;
+    FT_Int         num_linked;
+
+    FT_Int         score;
+    FT_Pos*        blue_edge;
+
+  } AH_EdgeRec;
+
+
+  /* an outline as seen by the hinter */
+  typedef struct  AH_OutlineRec_
+  {
+    FT_Memory     memory;
+
+    AH_Direction  vert_major_dir;   /* vertical major direction   */
+    AH_Direction  horz_major_dir;   /* horizontal major direction */
+
+    FT_Fixed      x_scale;
+    FT_Fixed      y_scale;
+    FT_Pos        edge_distance_threshold;
+
+    FT_Int        max_points;
+    FT_Int        num_points;
+    AH_Point      points;
+
+    FT_Int        max_contours;
+    FT_Int        num_contours;
+    AH_Point *    contours;
+
+    FT_Int        num_hedges;
+    AH_Edge       horz_edges;
+
+    FT_Int        num_vedges;
+    AH_Edge       vert_edges;
+
+    FT_Int        num_hsegments;
+    AH_Segment    horz_segments;
+
+    FT_Int        num_vsegments;
+    AH_Segment    vert_segments;
+
+  } AH_OutlineRec, *AH_Outline;
+
+
+#define AH_BLUE_CAPITAL_TOP     0                              /* THEZOCQS */
+#define AH_BLUE_CAPITAL_BOTTOM  ( AH_BLUE_CAPITAL_TOP + 1 )    /* HEZLOCUS */
+#define AH_BLUE_SMALL_TOP       ( AH_BLUE_CAPITAL_BOTTOM + 1 ) /* xzroesc  */
+#define AH_BLUE_SMALL_BOTTOM    ( AH_BLUE_SMALL_TOP + 1 )      /* xzroesc  */
+#define AH_BLUE_SMALL_MINOR     ( AH_BLUE_SMALL_BOTTOM + 1 )   /* pqgjy    */
+#define AH_BLUE_MAX             ( AH_BLUE_SMALL_MINOR + 1 )
+
+  typedef FT_Int  AH_Blue;
+
+
+#define AH_HINTER_MONOCHROME  1
+#define AH_HINTER_OPTIMIZE    2
+
+  typedef FT_Int  AH_Hinter_Flags;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    AH_GlobalsRec                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Holds the global metrics for a given font face (be it in design    */
+  /*    units or scaled pixel values).                                     */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    num_widths  :: The number of widths.                               */
+  /*                                                                       */
+  /*    num_heights :: The number of heights.                              */
+  /*                                                                       */
+  /*    widths      :: Snap widths, including standard one.                */
+  /*                                                                       */
+  /*    heights     :: Snap height, including standard one.                */
+  /*                                                                       */
+  /*    blue_refs   :: The reference positions of blue zones.              */
+  /*                                                                       */
+  /*    blue_shoots :: The overshoot positions of blue zones.              */
+  /*                                                                       */
+  typedef struct  AH_GlobalsRec_
+  {
+    FT_Int  num_widths;
+    FT_Int  num_heights;
+
+    FT_Pos  stds[2];
+
+    FT_Pos  widths [AH_MAX_WIDTHS];
+    FT_Pos  heights[AH_MAX_HEIGHTS];
+
+    FT_Pos  blue_refs  [AH_BLUE_MAX];
+    FT_Pos  blue_shoots[AH_BLUE_MAX];
+
+  } AH_GlobalsRec, *AH_Globals;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    AH_Face_GlobalsRec                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Holds the complete global metrics for a given font face (i.e., the */
+  /*    design units version + a scaled version + the current scales       */
+  /*    used).                                                             */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    face    :: A handle to the source face object                      */
+  /*                                                                       */
+  /*    design  :: The globals in font design units.                       */
+  /*                                                                       */
+  /*    scaled  :: Scaled globals in sub-pixel values.                     */
+  /*                                                                       */
+  /*    x_scale :: The current horizontal scale.                           */
+  /*                                                                       */
+  /*    y_scale :: The current vertical scale.                             */
+  /*                                                                       */
+  typedef struct  AH_Face_GlobalsRec_
+  {
+    FT_Face     face;
+    AH_GlobalsRec  design;
+    AH_GlobalsRec  scaled;
+    FT_Fixed    x_scale;
+    FT_Fixed    y_scale;
+    FT_Bool     control_overshoot;
+
+  } AH_Face_GlobalsRec, *AH_Face_Globals;
+
+
+  typedef struct  AH_HinterRec
+  {
+    FT_Memory         memory;
+    AH_Hinter_Flags   flags;
+
+    FT_Int            algorithm;
+    FT_Face           face;
+
+    AH_Face_Globals   globals;
+
+    AH_Outline        glyph;
+
+    AH_Loader         loader;
+    FT_Vector         pp1;
+    FT_Vector         pp2;
+
+    FT_Bool           transformed;
+    FT_Vector         trans_delta;
+    FT_Matrix         trans_matrix;
+
+    FT_Bool           do_horz_hints;     /* disable X hinting            */
+    FT_Bool           do_vert_hints;     /* disable Y hinting            */
+    FT_Bool           do_horz_snapping;  /* disable X stem size snapping */
+    FT_Bool           do_vert_snapping;  /* disable Y stem size snapping */
+
+  } AH_HinterRec, *AH_Hinter;
+
+
+#ifdef  DEBUG_HINTER
+  extern AH_Hinter   ah_debug_hinter;
+  extern FT_Bool     ah_debug_disable_horz;
+  extern FT_Bool     ah_debug_disable_vert;
+#else
+#define ah_debug_disable_horz  0
+#define ah_debug_disable_vert  0
+#endif /* DEBUG_HINTER */
+
+
+FT_END_HEADER
+
+#endif /* __AHTYPES_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/autohint.c
@@ -1,0 +1,32 @@
+/***************************************************************************/
+/*                                                                         */
+/*  autohint.c                                                             */
+/*                                                                         */
+/*    Automatic Hinting wrapper (body only).                               */
+/*                                                                         */
+/*  Copyright 2000-2001 Catharon Productions Inc.                          */
+/*  Author: David Turner                                                   */
+/*                                                                         */
+/*  This file is part of the Catharon Typography Project and shall only    */
+/*  be used, modified, and distributed under the terms of the Catharon     */
+/*  Open Source License that should come with this file under the name     */
+/*  `CatharonLicense.txt'.  By continuing to use, modify, or distribute    */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/*  Note that this license is compatible with the FreeType license.        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ahangles.c"
+#include "ahglyph.c"
+#include "ahglobal.c"
+#include "ahhint.c"
+#include "ahmodule.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdf.c
@@ -1,0 +1,34 @@
+/*  bdf.c
+
+    FreeType font driver for bdf files
+
+    Copyright (C) 2001, 2002 by
+    Francesco Zappa Nardelli 
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "bdflib.c"
+#include "bdfdrivr.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdf.h
@@ -1,0 +1,295 @@
+/*
+ * Copyright 2000 Computing Research Labs, New Mexico State University
+ * Copyright 2001, 2002 Francesco Zappa Nardelli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef __BDF_H__
+#define __BDF_H__
+
+
+/*
+ * Based on bdf.h,v 1.16 2000/03/16 20:08:51 mleisher
+ */
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+
+/* Imported from bdfP.h */
+
+#define _bdf_glyph_modified( map, e )                 \
+          ( (map)[(e) >> 5] & ( 1 << ( (e) & 31 ) ) )
+#define _bdf_set_glyph_modified( map, e )              \
+          ( (map)[(e) >> 5] |= ( 1 << ( (e) & 31 ) ) )
+#define _bdf_clear_glyph_modified( map, e )             \
+          ( (map)[(e) >> 5] &= ~( 1 << ( (e) & 31 ) ) )
+
+/* end of bdfP.h */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* BDF font options macros and types.                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#define BDF_CORRECT_METRICS  0x01 /* Correct invalid metrics when loading. */
+#define BDF_KEEP_COMMENTS    0x02 /* Preserve the font comments.           */
+#define BDF_KEEP_UNENCODED   0x04 /* Keep the unencoded glyphs.            */
+#define BDF_PROPORTIONAL     0x08 /* Font has proportional spacing.        */
+#define BDF_MONOWIDTH        0x10 /* Font has mono width.                  */
+#define BDF_CHARCELL         0x20 /* Font has charcell spacing.            */
+
+#define BDF_ALL_SPACING  ( BDF_PROPORTIONAL | \
+                           BDF_MONOWIDTH    | \
+                           BDF_CHARCELL     )
+
+#define BDF_DEFAULT_LOAD_OPTIONS  ( BDF_CORRECT_METRICS | \
+                                    BDF_KEEP_COMMENTS   | \
+                                    BDF_KEEP_UNENCODED  | \
+                                    BDF_PROPORTIONAL    )
+
+
+  typedef struct  bdf_options_t_
+  {
+    int            correct_metrics;
+    int            keep_unencoded;
+    int            keep_comments;
+    int            font_spacing;
+
+  } bdf_options_t;
+
+
+  /* Callback function type for unknown configuration options. */
+  typedef int
+  (*bdf_options_callback_t)( bdf_options_t*  opts,
+                             char**          params,
+                             unsigned long   nparams,
+                             void*           client_data );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* BDF font property macros and types.                                   */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#define BDF_ATOM      1
+#define BDF_INTEGER   2
+#define BDF_CARDINAL  3
+
+
+  /* This structure represents a particular property of a font. */
+  /* There are a set of defaults and each font has their own.   */
+  typedef struct  bdf_property_t_
+  {
+    char*  name;         /* Name of the property.   */
+    int    format;       /* Format of the property. */
+    int    builtin;      /* A builtin property.     */
+    union
+    {
+      char*          atom;
+      long           int32;
+      unsigned long  card32;
+
+    } value;             /* Value of the property.  */
+
+  } bdf_property_t;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* BDF font metric and glyph types.                                      */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  typedef struct  bdf_bbx_t_
+  {
+    unsigned short  width;
+    unsigned short  height;
+
+    short           x_offset;
+    short           y_offset;
+
+    short           ascent;
+    short           descent;
+
+  } bdf_bbx_t;
+
+
+  typedef struct  bdf_glyph_t_
+  {
+    char*           name;        /* Glyph name.                          */
+    long            encoding;    /* Glyph encoding.                      */
+    unsigned short  swidth;      /* Scalable width.                      */
+    unsigned short  dwidth;      /* Device width.                        */
+    bdf_bbx_t       bbx;         /* Glyph bounding box.                  */
+    unsigned char*  bitmap;      /* Glyph bitmap.                        */
+    unsigned long   bpr;         /* Number of bytes used per row.        */
+    unsigned short  bytes;       /* Number of bytes used for the bitmap. */
+
+  } bdf_glyph_t;
+
+
+  typedef struct  _hashnode_
+  {
+    char*  key;
+    void*  data;
+  
+  } _hashnode, *hashnode;
+
+
+  typedef struct  hashtable_
+  {
+    int        limit;
+    int        size;
+    int        used;
+    hashnode*  table;
+
+  } hashtable;
+
+
+  typedef struct  bdf_glyphlist_t_
+  {
+    unsigned short  pad;          /* Pad to 4-byte boundary.              */
+    unsigned short  bpp;          /* Bits per pixel.                      */
+    long            start;        /* Beginning encoding value of glyphs.  */
+    long            end;          /* Ending encoding value of glyphs.     */
+    bdf_glyph_t*    glyphs;       /* Glyphs themselves.                   */
+    unsigned long   glyphs_size;  /* Glyph structures allocated.          */
+    unsigned long   glyphs_used;  /* Glyph structures used.               */
+    bdf_bbx_t       bbx;          /* Overall bounding box of glyphs.      */
+
+  } bdf_glyphlist_t;
+
+
+  typedef struct  bdf_font_t_
+  {
+    char*            name;           /* Name of the font.                   */
+    bdf_bbx_t        bbx;            /* Font bounding box.                  */
+
+    long             point_size;     /* Point size of the font.             */
+    unsigned long    resolution_x;   /* Font horizontal resolution.         */
+    unsigned long    resolution_y;   /* Font vertical resolution.           */
+
+    int              spacing;        /* Font spacing value.                 */
+
+    unsigned short   monowidth;      /* Logical width for monowidth font.   */
+
+    long             default_glyph;  /* Encoding of the default glyph.      */
+
+    long             font_ascent;    /* Font ascent.                        */
+    long             font_descent;   /* Font descent.                       */
+
+    unsigned long    glyphs_size;    /* Glyph structures allocated.         */
+    unsigned long    glyphs_used;    /* Glyph structures used.              */
+    bdf_glyph_t*     glyphs;         /* Glyphs themselves.                  */
+
+    unsigned long    unencoded_size; /* Unencoded glyph struct. allocated.  */
+    unsigned long    unencoded_used; /* Unencoded glyph struct. used.       */
+    bdf_glyph_t*     unencoded;      /* Unencoded glyphs themselves.        */
+
+    unsigned long    props_size;     /* Font properties allocated.          */
+    unsigned long    props_used;     /* Font properties used.               */
+    bdf_property_t*  props;          /* Font properties themselves.         */
+
+    char*            comments;       /* Font comments.                      */
+    unsigned long    comments_len;   /* Length of comment string.           */
+
+    bdf_glyphlist_t  overflow;       /* Storage used for glyph insertion.   */
+
+    void*            internal;       /* Internal data for the font.         */
+
+    unsigned long    nmod[2048];     /* Bitmap indicating modified glyphs.  */
+    unsigned long    umod[2048];     /* Bitmap indicating modified          */
+                                     /* unencoded glyphs.                   */
+    unsigned short   modified;       /* Boolean indicating font modified.   */
+    unsigned short   bpp;            /* Bits per pixel.                     */
+
+    FT_Memory        memory;
+
+    bdf_property_t*  user_props;
+    unsigned long    nuser_props;
+    hashtable        proptbl;
+
+  } bdf_font_t;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Types for load/save callbacks.                                        */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /* Error codes. */
+#define BDF_MISSING_START       -1
+#define BDF_MISSING_FONTNAME    -2
+#define BDF_MISSING_SIZE        -3
+#define BDF_MISSING_CHARS       -4
+#define BDF_MISSING_STARTCHAR   -5
+#define BDF_MISSING_ENCODING    -6
+#define BDF_MISSING_BBX         -7
+
+#define BDF_OUT_OF_MEMORY      -20
+
+#define BDF_INVALID_LINE      -100
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* BDF font API.                                                         */
+  /*                                                                       */
+  /*************************************************************************/
+
+  FT_LOCAL( FT_Error )
+  bdf_load_font( FT_Stream       stream,
+                 FT_Memory       memory,
+                 bdf_options_t*  opts,
+                 bdf_font_t*    *font );
+
+  FT_LOCAL( void )
+  bdf_free_font( bdf_font_t*  font );
+
+  FT_LOCAL( bdf_property_t * )
+  bdf_get_property( char*        name,
+                    bdf_font_t*  font );
+
+  FT_LOCAL( bdf_property_t * )
+  bdf_get_font_property( bdf_font_t*  font,
+                         char*        name );
+
+
+FT_END_HEADER
+
+
+#endif /* __BDF_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdfdrivr.c
@@ -1,0 +1,674 @@
+/*  bdfdrivr.c
+
+    FreeType font driver for bdf files
+
+    Copyright (C) 2001-2002 by
+    Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "bdf.h"
+#include "bdfdrivr.h"
+
+#include "bdferror.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_bdfdriver
+
+
+  typedef struct  BDF_CMapRec_
+  {
+    FT_CMapRec        cmap;
+    FT_UInt           num_encodings;
+    BDF_encoding_el*  encodings;
+
+  } BDF_CMapRec, *BDF_CMap;
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  bdf_cmap_init( BDF_CMap  cmap )
+  {
+    BDF_Face  face = (BDF_Face)FT_CMAP_FACE( cmap );
+
+
+    cmap->num_encodings = face->bdffont->glyphs_used;
+    cmap->encodings     = face->en_table;
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  bdf_cmap_done( BDF_CMap  cmap )
+  {
+    cmap->encodings     = NULL;
+    cmap->num_encodings = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  bdf_cmap_char_index( BDF_CMap   cmap,
+                       FT_UInt32  charcode )
+  {
+    BDF_encoding_el*  encodings = cmap->encodings;
+    FT_UInt           min, max, mid;
+    FT_UInt           result = 0;
+
+
+    min = 0;
+    max = cmap->num_encodings;
+
+    while ( min < max )
+    {
+      FT_UInt32  code;
+
+
+      mid  = ( min + max ) >> 1;
+      code = encodings[mid].enc;
+
+      if ( charcode == code )
+      {
+        result = encodings[mid].glyph + 1;
+        break;
+      }
+
+      if ( charcode < code )
+        max = mid;
+      else
+        min = mid + 1;
+    }
+
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  bdf_cmap_char_next( BDF_CMap    cmap,
+                      FT_UInt32  *acharcode )
+  {
+    BDF_encoding_el*  encodings = cmap->encodings;
+    FT_UInt           min, max, mid;
+    FT_UInt32         charcode = *acharcode + 1;
+    FT_UInt           result   = 0;
+
+
+    min = 0;
+    max = cmap->num_encodings;
+
+    while ( min < max )
+    {
+      FT_UInt32  code;
+
+
+      mid  = ( min + max ) >> 1;
+      code = encodings[mid].enc;
+
+      if ( charcode == code )
+      {
+        result = encodings[mid].glyph + 1;
+        goto Exit;
+      }
+
+      if ( charcode < code )
+        max = mid;
+      else
+        min = mid + 1;
+    }
+
+    charcode = 0;
+    if ( min < cmap->num_encodings )
+    {
+      charcode = encodings[min].enc;
+      result   = encodings[min].glyph + 1;
+    }
+
+  Exit:
+    *acharcode = charcode;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec  bdf_cmap_class =
+  {
+    sizeof( BDF_CMapRec ),
+    (FT_CMap_InitFunc)     bdf_cmap_init,
+    (FT_CMap_DoneFunc)     bdf_cmap_done,
+    (FT_CMap_CharIndexFunc)bdf_cmap_char_index,
+    (FT_CMap_CharNextFunc) bdf_cmap_char_next
+  };
+
+
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  BDF_Face_Done( BDF_Face  face )
+  {
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+    bdf_free_font( face->bdffont );
+
+    FT_FREE( face->en_table );
+
+    FT_FREE( face->charset_encoding );
+    FT_FREE( face->charset_registry );
+    FT_FREE( face->root.family_name );
+
+    FT_FREE( face->root.available_sizes );
+
+    FT_FREE( face->bdffont );
+
+    FT_TRACE4(( "BDF_Face_Done: done face\n" ));
+
+    return BDF_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  BDF_Face_Init( FT_Stream      stream,
+                 BDF_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params )
+  {
+    FT_Error       error  = BDF_Err_Ok;
+    FT_Memory      memory = FT_FACE_MEMORY( face );
+
+    bdf_font_t*    font;
+    bdf_options_t  options;
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+    FT_UNUSED( face_index );
+
+
+    if ( FT_STREAM_SEEK( 0 ) )
+      goto Exit;
+
+    options.correct_metrics = 1;   /* FZ XXX: options semantics */
+    options.keep_unencoded  = 1;
+    options.keep_comments   = 0;
+    options.font_spacing    = BDF_PROPORTIONAL;
+
+    error = bdf_load_font( stream, memory, &options, &font );
+    if ( error == BDF_Err_Missing_Startfont_Field )
+    {
+      FT_TRACE2(( "[not a valid BDF file]\n" ));
+      goto Fail;
+    }
+    else if ( error )
+      goto Exit;
+
+    /* we have a bdf font: let's construct the face object */
+    face->bdffont = font;
+    {
+      FT_Face          root = FT_FACE( face );
+      bdf_property_t*  prop = NULL;
+
+
+      FT_TRACE4(( "number of glyphs: %d (%d)\n",
+                  font->glyphs_size,
+                  font->glyphs_used ));
+      FT_TRACE4(( "number of unencoded glyphs: %d (%d)\n",
+                  font->unencoded_size,
+                  font->unencoded_used ));
+
+      root->num_faces  = 1;
+      root->face_index = 0;
+      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+                         FT_FACE_FLAG_HORIZONTAL  |
+                         FT_FACE_FLAG_FAST_GLYPHS;
+
+      prop = bdf_get_font_property( font, (char *)"SPACING" );
+      if ( prop != NULL )
+        if ( prop->format == BDF_ATOM )
+          if ( prop->value.atom != NULL )
+            if ( ( *(prop->value.atom) == 'M' ) ||
+                 ( *(prop->value.atom) == 'C' ) )
+              root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+      /* FZ XXX: TO DO: FT_FACE_FLAGS_VERTICAL   */
+      /* FZ XXX: I need a font to implement this */
+
+      root->style_flags = 0;
+      prop = bdf_get_font_property( font, (char *)"SLANT" );
+      if ( prop != NULL )
+        if ( prop->format == BDF_ATOM )
+          if ( prop->value.atom != NULL )
+            if ( ( *(prop->value.atom) == 'O' ) ||
+                 ( *(prop->value.atom) == 'I' ) )
+              root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+      prop = bdf_get_font_property( font, (char *)"WEIGHT_NAME" );
+      if ( prop != NULL )
+        if ( prop->format == BDF_ATOM )
+          if ( prop->value.atom != NULL )
+            if ( *(prop->value.atom) == 'B' )
+              root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+      prop = bdf_get_font_property( font, (char *)"FAMILY_NAME" );
+      if ( ( prop != NULL ) && ( prop->value.atom != NULL ) )
+      {
+        int  l = ft_strlen( prop->value.atom ) + 1;
+
+
+        if ( FT_NEW_ARRAY( root->family_name, l ) )
+          goto Exit;
+        ft_strcpy( root->family_name, prop->value.atom );
+      }
+      else
+        root->family_name = 0;
+
+      root->style_name = (char *)"Regular";
+      if ( root->style_flags & FT_STYLE_FLAG_BOLD )
+      {
+        if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+          root->style_name = (char *)"Bold Italic";
+        else
+          root->style_name = (char *)"Bold";
+      }
+      else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+        root->style_name = (char *)"Italic";
+
+      root->num_glyphs = font->glyphs_size;     /* unencoded included */
+
+      root->num_fixed_sizes = 1;
+      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
+        goto Exit;
+
+      prop = bdf_get_font_property( font, (char *)"AVERAGE_WIDTH" );
+      if ( ( prop != NULL ) && ( prop->value.int32 >= 10 ) )
+        root->available_sizes->width = (short)( prop->value.int32 / 10 );
+
+      prop = bdf_get_font_property( font, (char *)"PIXEL_SIZE" );
+      if ( prop != NULL )
+        root->available_sizes->height = (short) prop->value.int32;
+      else
+      {
+        prop = bdf_get_font_property( font, (char *)"POINT_SIZE" );
+        if ( prop != NULL )
+        {
+          bdf_property_t  *yres;
+
+
+          yres = bdf_get_font_property( font, (char *)"RESOLUTION_Y" );
+          if ( yres != NULL )
+          {
+            FT_TRACE4(( "POINT_SIZE: %d  RESOLUTION_Y: %d\n",
+                        prop->value.int32, yres->value.int32 ));
+            root->available_sizes->height =
+              (FT_Short)( prop->value.int32 * yres->value.int32 / 720 );
+          }
+        }
+      }
+
+      if ( root->available_sizes->width == 0 )
+      {
+        if ( root->available_sizes->height == 0 )
+        {
+          /* some fonts have broken SIZE declaration (jiskan24.bdf) */
+          FT_ERROR(( "BDF_Face_Init: reading size\n" ));
+          root->available_sizes->width = (FT_Short)font->point_size;
+        }
+        else
+          root->available_sizes->width = root->available_sizes->height;
+      }
+      if ( root->available_sizes->height == 0 )
+          root->available_sizes->height = root->available_sizes->width;
+
+      /* encoding table */
+      {
+        bdf_glyph_t*   cur = font->glyphs;
+        unsigned long  n;
+
+
+        if ( FT_NEW_ARRAY( face->en_table, font->glyphs_size ) )
+          goto Exit;
+
+        for ( n = 0; n < font->glyphs_size; n++ )
+        {
+          (face->en_table[n]).enc = cur[n].encoding;
+          FT_TRACE4(( "idx %d, val 0x%lX\n", n, cur[n].encoding ));
+          (face->en_table[n]).glyph = (FT_Short)n;
+        }
+      }
+
+      /* charmaps */
+      {
+        bdf_property_t  *charset_registry = 0, *charset_encoding = 0;
+        FT_Bool          unicode_charmap  = 0;
+
+
+        charset_registry =
+          bdf_get_font_property( font, (char *)"CHARSET_REGISTRY" );
+        charset_encoding =
+          bdf_get_font_property( font, (char *)"CHARSET_ENCODING" );
+        if ( ( charset_registry != NULL ) && ( charset_encoding != NULL ) )
+        {
+          if ( ( charset_registry->format == BDF_ATOM ) &&
+               ( charset_encoding->format == BDF_ATOM ) &&
+               ( charset_registry->value.atom != NULL ) &&
+               ( charset_encoding->value.atom != NULL ) )
+          {
+            if ( FT_NEW_ARRAY( face->charset_encoding,
+                               strlen( charset_encoding->value.atom ) + 1 ) )
+              goto Exit;
+            if ( FT_NEW_ARRAY( face->charset_registry,
+                               strlen( charset_registry->value.atom ) + 1 ) )
+              goto Exit;
+            ft_strcpy( face->charset_registry, charset_registry->value.atom );
+            ft_strcpy( face->charset_encoding, charset_encoding->value.atom );
+            if ( !ft_strcmp( face->charset_registry, "ISO10646" )     ||
+                 ( !ft_strcmp( face->charset_registry, "ISO8859" ) &&
+                   !ft_strcmp( face->charset_encoding, "1" )       )  )
+              unicode_charmap = 1;
+
+            {
+              FT_CharMapRec  charmap;
+
+
+              charmap.face        = FT_FACE( face );
+              charmap.encoding    = FT_ENCODING_NONE;
+              charmap.platform_id = 0;
+              charmap.encoding_id = 0;
+
+              if ( unicode_charmap )
+              {
+                charmap.encoding    = FT_ENCODING_UNICODE;
+                charmap.platform_id = 3;
+                charmap.encoding_id = 1;
+              }
+
+              error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
+
+#if 0
+              /* Select default charmap */
+              if (root->num_charmaps)
+                root->charmap = root->charmaps[0];
+#endif
+            }
+
+            goto Exit;
+          }
+        }
+
+        /* otherwise assume Adobe standard encoding */
+
+        {
+          FT_CharMapRec  charmap;
+
+
+          charmap.face        = FT_FACE( face );
+          charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
+          charmap.platform_id = 7;
+          charmap.encoding_id = 0;
+
+          error = FT_CMap_New( &bdf_cmap_class, NULL, &charmap, NULL );
+
+          /* Select default charmap */
+          if (root->num_charmaps)
+            root->charmap = root->charmaps[0];
+        }
+      }
+    }
+
+  Exit:
+    return error;
+
+  Fail:
+    BDF_Face_Done( face );
+    return BDF_Err_Unknown_File_Format;
+  }
+
+
+  static FT_Error
+  BDF_Set_Pixel_Size( FT_Size  size )
+  {
+    BDF_Face  face = (BDF_Face)FT_SIZE_FACE( size );
+    FT_Face   root = FT_FACE( face );
+
+
+    FT_TRACE4(( "rec %d - pres %d\n",
+                size->metrics.y_ppem, root->available_sizes->height ));
+
+    if ( size->metrics.y_ppem == root->available_sizes->height )
+    {
+      size->metrics.ascender  = face->bdffont->bbx.ascent << 6;
+      size->metrics.descender = face->bdffont->bbx.descent * ( -64 );
+      size->metrics.height    = face->bdffont->bbx.height << 6;
+
+      return BDF_Err_Ok;
+    }
+    else
+      return BDF_Err_Invalid_Pixel_Size;
+  }
+
+
+  static FT_Error
+  BDF_Glyph_Load( FT_GlyphSlot  slot,
+                  FT_Size       size,
+                  FT_UInt       glyph_index,
+                  FT_Int32      load_flags )
+  {
+    BDF_Face        face   = (BDF_Face)FT_SIZE_FACE( size );
+    FT_Error        error  = BDF_Err_Ok;
+    FT_Bitmap*      bitmap = &slot->bitmap;
+    bdf_glyph_t     glyph;
+    int             bpp    = face->bdffont->bpp;
+    int             i, j, count;
+    unsigned char   *p, *pp;
+
+    FT_Memory       memory = face->bdffont->memory;
+
+    FT_UNUSED( load_flags );
+
+
+    if ( !face )
+    {
+      error = BDF_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    if ( glyph_index > 0 )
+      glyph_index--;
+
+    /* slot, bitmap => freetype, glyph => bdflib */
+    glyph = face->bdffont->glyphs[glyph_index];
+
+    bitmap->rows  = glyph.bbx.height;
+    bitmap->width = glyph.bbx.width;
+
+    if ( bpp == 1 )
+    {
+      bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+      bitmap->pitch      = glyph.bpr;
+
+      if ( FT_NEW_ARRAY( bitmap->buffer, glyph.bytes ) )
+        goto Exit;
+      FT_MEM_COPY( bitmap->buffer, glyph.bitmap, glyph.bytes );
+    }
+    else
+    {
+      /* blow up pixmap to have 8 bits per pixel */
+      bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+      bitmap->pitch      = bitmap->width;
+
+      if ( FT_NEW_ARRAY( bitmap->buffer, bitmap->rows * bitmap->pitch ) )
+        goto Exit;
+
+      switch ( bpp )
+      {
+      case 2:
+        bitmap->num_grays = 4;
+
+        count = 0;
+        p     = glyph.bitmap;
+
+        for ( i = 0; i < bitmap->rows; i++ )
+        {
+          pp = p;
+
+          /* get the full bytes */
+          for ( j = 0; j < ( bitmap->width >> 2 ); j++ )
+          {
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xC0 ) >> 6 );
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x30 ) >> 4 );
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x0C ) >> 2 );
+            bitmap->buffer[count++] = (FT_Byte)(   *pp & 0x03 );
+
+            pp++;
+          }
+
+          /* get remaining pixels (if any) */
+          switch ( bitmap->width & 3 )
+          {
+          case 3:
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xC0 ) >> 6 );
+            /* fall through */
+          case 2:
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x30 ) >> 4 );
+            /* fall through */
+          case 1:
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0x0C ) >> 2 );
+            /* fall through */
+          case 0:
+            break;
+          }
+
+          p += glyph.bpr;
+        }
+        break;
+
+      case 4:
+        bitmap->num_grays = 16;
+
+        count = 0;
+        p     = glyph.bitmap;
+
+        for ( i = 0; i < bitmap->rows; i++ )
+        {
+          pp = p;
+
+          /* get the full bytes */
+          for ( j = 0; j < ( bitmap->width >> 1 ); j++ )
+          {
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xF0 ) >> 4 );
+            bitmap->buffer[count++] = (FT_Byte)(   *pp & 0x0F );
+
+            pp++;
+          }
+
+          /* get remaining pixel (if any) */
+          switch ( bitmap->width & 1 )
+          {
+          case 1:
+            bitmap->buffer[count++] = (FT_Byte)( ( *pp & 0xF0 ) >> 4 );
+            /* fall through */
+          case 0:
+            break;
+          }
+
+          p += glyph.bpr;
+        }
+        break;
+
+      case 8:
+        bitmap->num_grays = 256;
+
+        FT_MEM_COPY( bitmap->buffer, glyph.bitmap,
+                     bitmap->rows * bitmap->pitch );
+        break;
+      }
+    }
+
+    slot->bitmap_left = 0;
+    slot->bitmap_top  = glyph.bbx.ascent;
+
+    /* FZ XXX: TODO: vertical metrics */
+    slot->metrics.horiAdvance  = glyph.dwidth << 6;
+    slot->metrics.horiBearingX = glyph.bbx.x_offset << 6;
+    slot->metrics.horiBearingY = ( glyph.bbx.y_offset +
+                                   glyph.bbx.height ) << 6;
+    slot->metrics.width        = bitmap->width << 6;
+    slot->metrics.height       = bitmap->rows << 6;
+
+    slot->linearHoriAdvance = (FT_Fixed)glyph.dwidth << 16;
+    slot->format            = FT_GLYPH_FORMAT_BITMAP;
+    slot->flags             = FT_GLYPH_OWN_BITMAP;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  bdf_driver_class =
+  {
+    {
+      ft_module_font_driver,
+      sizeof ( FT_DriverRec ),
+
+      "bdf",
+      0x10000L,
+      0x20000L,
+
+      0,
+
+      (FT_Module_Constructor)0,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    sizeof ( BDF_FaceRec ),
+    sizeof ( FT_SizeRec ),
+    sizeof ( FT_GlyphSlotRec ),
+
+    (FT_Face_InitFunc)        BDF_Face_Init,
+    (FT_Face_DoneFunc)        BDF_Face_Done,
+    (FT_Size_InitFunc)        0,
+    (FT_Size_DoneFunc)        0,
+    (FT_Slot_InitFunc)        0,
+    (FT_Slot_DoneFunc)        0,
+
+    (FT_Size_ResetPointsFunc) BDF_Set_Pixel_Size,
+    (FT_Size_ResetPixelsFunc) BDF_Set_Pixel_Size,
+
+    (FT_Slot_LoadFunc)        BDF_Glyph_Load,
+
+    (FT_Face_GetKerningFunc)  0,
+    (FT_Face_AttachFunc)      0,
+    (FT_Face_GetAdvancesFunc) 0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdfdrivr.h
@@ -1,0 +1,74 @@
+/*  bdfdrivr.h
+
+    FreeType font driver for bdf fonts
+
+  Copyright (C) 2001, 2002 by
+  Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __BDFDRIVR_H__
+#define __BDFDRIVR_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+#include "bdf.h"
+
+
+FT_BEGIN_HEADER
+
+
+  typedef struct  BDF_encoding_el_
+  {
+    FT_ULong  enc;
+    FT_Short  glyph;
+
+  } BDF_encoding_el;
+
+
+  typedef struct  BDF_FaceRec_
+  {
+    FT_FaceRec        root;
+
+    char*             charset_encoding;
+    char*             charset_registry;
+
+    bdf_font_t*       bdffont;
+
+    BDF_encoding_el*  en_table;
+
+    FT_CharMap        charmap_handle;
+    FT_CharMapRec     charmap;  /* a single charmap per face */
+
+  } BDF_FaceRec, *BDF_Face;
+
+
+  FT_EXPORT_VAR( const FT_Driver_ClassRec )  bdf_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __BDFDRIVR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdferror.h
@@ -1,0 +1,44 @@
+/*
+ * Copyright 2001, 2002 Francesco Zappa Nardelli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the BDF error enumeration constants.      */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __BDFERROR_H__
+#define __BDFERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  BDF_Err_
+#define FT_ERR_BASE    FT_Mod_Err_BDF
+
+#include FT_ERRORS_H
+
+#endif /* __BDFERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/bdflib.c
@@ -1,0 +1,2436 @@
+/*
+ * Copyright 2000 Computing Research Labs, New Mexico State University
+ * Copyright 2001, 2002 Francesco Zappa Nardelli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  This file is based on bdf.c,v 1.22 2000/03/16 20:08:50               */
+  /*                                                                       */
+  /*  taken from Mark Leisher's xmbdfed package                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "bdf.h"
+#include "bdferror.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_bdflib
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Default BDF font options.                                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static const bdf_options_t  _bdf_opts =
+  {
+    1,                /* Correct metrics.               */
+    1,                /* Preserve unencoded glyphs.     */
+    0,                /* Preserve comments.             */
+    BDF_PROPORTIONAL  /* Default spacing.               */
+  };
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Builtin BDF font properties.                                          */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /* List of most properties that might appear in a font.  Doesn't include */
+  /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts.           */
+
+  static const bdf_property_t  _bdf_properties[] =
+  {
+    { (char *)"ADD_STYLE_NAME",          BDF_ATOM,     1, { 0 } },
+    { (char *)"AVERAGE_WIDTH",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1, { 0 } },
+    { (char *)"AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1, { 0 } },
+    { (char *)"CAP_HEIGHT",              BDF_INTEGER,  1, { 0 } },
+    { (char *)"CHARSET_COLLECTIONS",     BDF_ATOM,     1, { 0 } },
+    { (char *)"CHARSET_ENCODING",        BDF_ATOM,     1, { 0 } },
+    { (char *)"CHARSET_REGISTRY",        BDF_ATOM,     1, { 0 } },
+    { (char *)"COMMENT",                 BDF_ATOM,     1, { 0 } },
+    { (char *)"COPYRIGHT",               BDF_ATOM,     1, { 0 } },
+    { (char *)"DEFAULT_CHAR",            BDF_CARDINAL, 1, { 0 } },
+    { (char *)"DESTINATION",             BDF_CARDINAL, 1, { 0 } },
+    { (char *)"DEVICE_FONT_NAME",        BDF_ATOM,     1, { 0 } },
+    { (char *)"END_SPACE",               BDF_INTEGER,  1, { 0 } },
+    { (char *)"FACE_NAME",               BDF_ATOM,     1, { 0 } },
+    { (char *)"FAMILY_NAME",             BDF_ATOM,     1, { 0 } },
+    { (char *)"FIGURE_WIDTH",            BDF_INTEGER,  1, { 0 } },
+    { (char *)"FONT",                    BDF_ATOM,     1, { 0 } },
+    { (char *)"FONTNAME_REGISTRY",       BDF_ATOM,     1, { 0 } },
+    { (char *)"FONT_ASCENT",             BDF_INTEGER,  1, { 0 } },
+    { (char *)"FONT_DESCENT",            BDF_INTEGER,  1, { 0 } },
+    { (char *)"FOUNDRY",                 BDF_ATOM,     1, { 0 } },
+    { (char *)"FULL_NAME",               BDF_ATOM,     1, { 0 } },
+    { (char *)"ITALIC_ANGLE",            BDF_INTEGER,  1, { 0 } },
+    { (char *)"MAX_SPACE",               BDF_INTEGER,  1, { 0 } },
+    { (char *)"MIN_SPACE",               BDF_INTEGER,  1, { 0 } },
+    { (char *)"NORM_SPACE",              BDF_INTEGER,  1, { 0 } },
+    { (char *)"NOTICE",                  BDF_ATOM,     1, { 0 } },
+    { (char *)"PIXEL_SIZE",              BDF_INTEGER,  1, { 0 } },
+    { (char *)"POINT_SIZE",              BDF_INTEGER,  1, { 0 } },
+    { (char *)"QUAD_WIDTH",              BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_ASCENT",              BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_CAP_HEIGHT",          BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_DESCENT",             BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_END_SPACE",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_FIGURE_WIDTH",        BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_MAX_SPACE",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_MIN_SPACE",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_NORM_SPACE",          BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_PIXEL_SIZE",          BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_POINT_SIZE",          BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_PIXELSIZE",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_POINTSIZE",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_QUAD_WIDTH",          BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_SUBSCRIPT_X",         BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1, { 0 } },
+    { (char *)"RAW_X_HEIGHT",            BDF_INTEGER,  1, { 0 } },
+    { (char *)"RELATIVE_SETWIDTH",       BDF_CARDINAL, 1, { 0 } },
+    { (char *)"RELATIVE_WEIGHT",         BDF_CARDINAL, 1, { 0 } },
+    { (char *)"RESOLUTION",              BDF_INTEGER,  1, { 0 } },
+    { (char *)"RESOLUTION_X",            BDF_CARDINAL, 1, { 0 } },
+    { (char *)"RESOLUTION_Y",            BDF_CARDINAL, 1, { 0 } },
+    { (char *)"SETWIDTH_NAME",           BDF_ATOM,     1, { 0 } },
+    { (char *)"SLANT",                   BDF_ATOM,     1, { 0 } },
+    { (char *)"SMALL_CAP_SIZE",          BDF_INTEGER,  1, { 0 } },
+    { (char *)"SPACING",                 BDF_ATOM,     1, { 0 } },
+    { (char *)"STRIKEOUT_ASCENT",        BDF_INTEGER,  1, { 0 } },
+    { (char *)"STRIKEOUT_DESCENT",       BDF_INTEGER,  1, { 0 } },
+    { (char *)"SUBSCRIPT_SIZE",          BDF_INTEGER,  1, { 0 } },
+    { (char *)"SUBSCRIPT_X",             BDF_INTEGER,  1, { 0 } },
+    { (char *)"SUBSCRIPT_Y",             BDF_INTEGER,  1, { 0 } },
+    { (char *)"SUPERSCRIPT_SIZE",        BDF_INTEGER,  1, { 0 } },
+    { (char *)"SUPERSCRIPT_X",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"SUPERSCRIPT_Y",           BDF_INTEGER,  1, { 0 } },
+    { (char *)"UNDERLINE_POSITION",      BDF_INTEGER,  1, { 0 } },
+    { (char *)"UNDERLINE_THICKNESS",     BDF_INTEGER,  1, { 0 } },
+    { (char *)"WEIGHT",                  BDF_CARDINAL, 1, { 0 } },
+    { (char *)"WEIGHT_NAME",             BDF_ATOM,     1, { 0 } },
+    { (char *)"X_HEIGHT",                BDF_INTEGER,  1, { 0 } },
+    { (char *)"_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1, { 0 } },
+    { (char *)"_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1, { 0 } },
+  };
+
+  static unsigned long
+  _num_bdf_properties = sizeof ( _bdf_properties ) /
+                        sizeof ( _bdf_properties[0] );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Hash table utilities for the properties.                              */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /* XXX: Replace this with FreeType's hash functions */
+
+
+#define INITIAL_HT_SIZE  241
+
+  typedef void
+  (*hash_free_func)( hashnode  node );
+
+  static hashnode*
+  hash_bucket( char*       key,
+               hashtable*  ht )
+  {
+    char*          kp  = key;
+    unsigned long  res = 0;
+    hashnode*      bp  = ht->table, *ndp;
+
+
+    /* Mocklisp hash function. */
+    while ( *kp )
+      res = ( res << 5 ) - res + *kp++;
+
+    ndp = bp + ( res % ht->size );
+    while ( *ndp )
+    {
+      kp = (*ndp)->key;
+      if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
+        break;
+      ndp--;
+      if ( ndp < bp )
+        ndp = bp + ( ht->size - 1 );
+    }
+
+    return ndp;
+  }
+
+
+  static FT_Error
+  hash_rehash( hashtable*  ht,
+               FT_Memory   memory )
+  {
+    hashnode*  obp = ht->table, *bp, *nbp;
+    int        i, sz = ht->size;
+    FT_Error   error = BDF_Err_Ok;
+
+
+    ht->size <<= 1;
+    ht->limit  = ht->size / 3;
+
+    if ( FT_NEW_ARRAY( ht->table, ht->size ) )
+      goto Exit;
+    FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * ht->size );
+
+    for ( i = 0, bp = obp; i < sz; i++, bp++ )
+    {
+      if ( *bp )
+      {
+        nbp = hash_bucket( (*bp)->key, ht );
+        *nbp = *bp;
+      }
+    }
+    FT_FREE( obp );
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  hash_init( hashtable*  ht,
+             FT_Memory   memory )
+  {
+    int       sz = INITIAL_HT_SIZE;
+    FT_Error  error = BDF_Err_Ok;
+
+
+    ht->size  = sz;
+    ht->limit = sz / 3;
+    ht->used  = 0;
+
+    if ( FT_NEW_ARRAY( ht->table, sz ) )
+      goto Exit;
+    FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * sz );
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  hash_free( hashtable*  ht,
+             FT_Memory   memory )
+  {
+    if ( ht != 0 )
+    {
+      int        i, sz = ht->size;
+      hashnode*  bp = ht->table;
+
+
+      for ( i = 0; i < sz; i++, bp++ )
+        FT_FREE( *bp );
+
+      FT_FREE( ht->table );
+    }
+  }
+
+
+  static FT_Error
+  hash_insert( char*       key,
+               void*       data,
+               hashtable*  ht,
+               FT_Memory   memory )
+  {
+    hashnode  nn, *bp = hash_bucket( key, ht );
+    FT_Error  error = BDF_Err_Ok;
+
+
+    nn = *bp;
+    if ( !nn )
+    {
+      if ( FT_NEW( nn ) )
+        goto Exit;
+      *bp = nn;
+
+      nn->key  = key;
+      nn->data = data;
+
+      if ( ht->used >= ht->limit )
+      {
+        error = hash_rehash( ht, memory );
+        if ( error )
+          goto Exit;
+      }
+      ht->used++;
+    }
+    else
+      nn->data = data;
+
+  Exit:
+    return error;
+  }
+
+
+  static hashnode
+  hash_lookup( char*       key,
+               hashtable*  ht )
+  {
+    hashnode *np = hash_bucket( key, ht );
+
+
+    return *np;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Utility types and functions.                                          */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /* Function type for parsing lines of a BDF font. */
+
+  typedef FT_Error
+  (*_bdf_line_func_t)( char*          line,
+                       unsigned long  linelen,
+                       unsigned long  lineno,
+                       void*          call_data,
+                       void*          client_data );
+
+
+  /* List structure for splitting lines into fields. */
+
+  typedef struct  _bdf_list_t_
+  {
+    char**         field;
+    unsigned long  size;
+    unsigned long  used;
+
+  } _bdf_list_t;
+
+
+  /* Structure used while loading BDF fonts. */
+
+  typedef struct  _bdf_parse_t_
+  {
+    unsigned long   flags;
+    unsigned long   cnt;
+    unsigned long   row;
+
+    short           minlb;
+    short           maxlb;
+    short           maxrb;
+    short           maxas;
+    short           maxds;
+
+    short           rbearing;
+
+    char*           glyph_name;
+    long            glyph_enc;
+
+    bdf_font_t*     font;
+    bdf_options_t*  opts;
+
+    unsigned long   have[2048];
+    _bdf_list_t     list;
+
+    FT_Memory       memory;
+
+  } _bdf_parse_t;
+
+
+#define setsbit( m, cc )  ( m[(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
+#define sbitset( m, cc )  ( m[(cc) >> 3]  & ( 1 << ( (cc) & 7 ) ) )
+
+
+  /* An empty string for empty fields. */
+
+  static char  empty[1] = { 0 };   /* XXX eliminate this */
+
+
+  /* Assume the line is NULL-terminated and that the `list' parameter */
+  /* was initialized the first time it was used.                      */
+
+  static FT_Error
+  _bdf_split( char*          separators,
+              char*          line,
+              unsigned long  linelen,
+              _bdf_list_t*   list,
+              FT_Memory      memory )
+  {
+    int       mult, final_empty;
+    char      *sp, *ep, *end;
+    char      seps[32];
+    FT_Error  error = BDF_Err_Ok;
+
+
+    /* Initialize the list. */
+    list->used = 0;
+
+    /* If the line is empty, then simply return. */
+    if ( linelen == 0 || line[0] == 0 )
+      goto Exit;
+
+    /* In the original code, if the `separators' parameter is NULL or */
+    /* empty, the list is split into individual bytes.  We don't need */
+    /* this, so an error is signaled.                                 */
+    if ( separators == 0 || *separators == 0 )
+    {
+      error = BDF_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* Prepare the separator bitmap. */
+    FT_MEM_ZERO( seps, 32 );
+
+    /* If the very last character of the separator string is a plus, then */
+    /* set the `mult' flag to indicate that multiple separators should be */
+    /* collapsed into one.                                                */
+    for ( mult = 0, sp = separators; sp && *sp; sp++ )
+    {
+      if ( *sp == '+' && *( sp + 1 ) == 0 )
+        mult = 1;
+      else
+        setsbit( seps, *sp );
+    }
+
+    /* Break the line up into fields. */
+    for ( final_empty = 0, sp = ep = line, end = sp + linelen;
+          sp < end && *sp; )
+    {
+      /* Collect everything that is not a separator. */
+      for ( ; *ep && !sbitset( seps, *ep ); ep++ )
+        ;
+
+      /* Resize the list if necessary. */
+      if ( list->used == list->size )
+      {
+        if ( list->size == 0 )
+        {
+          if ( FT_NEW_ARRAY( list->field, 5 ) )
+            goto Exit;
+        }
+        else
+        {
+          if ( FT_RENEW_ARRAY ( list->field ,
+                                list->size,
+                                list->size + 5 ) )
+            goto Exit;
+        }
+
+        list->size += 5;
+      }
+
+      /* Assign the field appropriately. */
+      list->field[list->used++] = ( ep > sp ) ? sp : empty;
+
+      sp = ep;
+
+      if ( mult )
+      {
+        /* If multiple separators should be collapsed, do it now by */
+        /* setting all the separator characters to 0.               */
+        for ( ; *ep && sbitset( seps, *ep ); ep++ )
+          *ep = 0;
+      }
+      else if ( *ep != 0 )
+        /* Don't collapse multiple separators by making them 0, so just */
+        /* make the one encountered 0.                                  */
+        *ep++ = 0;
+
+      final_empty = ( ep > sp && *ep == 0 );
+      sp = ep;
+    }
+
+    /* Finally, NULL-terminate the list. */
+    if ( list->used + final_empty + 1 >= list->size )
+    {
+      if ( list->used == list->size )
+      {
+        if ( list->size == 0 )
+        {
+          if ( FT_NEW_ARRAY( list->field, 5 ) )
+            goto Exit;
+        }
+        else
+        {
+          if ( FT_RENEW_ARRAY( list->field,
+                               list->size,
+                               list->size + 5 ) )
+            goto Exit;
+        }
+
+        list->size += 5;
+      }
+    }
+
+    if ( final_empty )
+      list->field[list->used++] = empty;
+
+    if ( list->used == list->size )
+    {
+      if ( list->size == 0 )
+      {
+        if ( FT_NEW_ARRAY( list->field, 5 ) )
+          goto Exit;
+      }
+      else
+      {
+        if ( FT_RENEW_ARRAY( list->field,
+                             list->size,
+                             list->size + 5 ) )
+          goto Exit;
+      }
+
+      list->size += 5;
+    }
+
+    list->field[list->used] = 0;
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  _bdf_shift( unsigned long  n,
+              _bdf_list_t*   list )
+  {
+    unsigned long  i, u;
+
+
+    if ( list == 0 || list->used == 0 || n == 0 )
+      return;
+
+    if ( n >= list->used )
+    {
+      list->used = 0;
+      return;
+    }
+
+    for ( u = n, i = 0; u < list->used; i++, u++ )
+      list->field[i] = list->field[u];
+    list->used -= n;
+  }
+
+
+  static char *
+  _bdf_join( int             c,
+             unsigned long*  len,
+             _bdf_list_t*    list )
+  {
+    unsigned long  i, j;
+    char           *fp, *dp;
+
+
+    if ( list == 0 || list->used == 0 )
+      return 0;
+
+    *len = 0;
+
+    dp = list->field[0];
+    for ( i = j = 0; i < list->used; i++ )
+    {
+      fp = list->field[i];
+      while ( *fp )
+        dp[j++] = *fp++;
+
+      if ( i + 1 < list->used )
+        dp[j++] = (char)c;
+    }
+    dp[j] = 0;
+
+    *len = j;
+    return dp;
+  }
+
+
+  /* High speed file reader that passes each line to a callback. */
+  static FT_Error
+  bdf_internal_readstream( FT_Stream  stream,
+                           char*      buffer,
+                           int        count,
+                           int       *read_bytes )
+  {
+    int            rbytes;
+    unsigned long  pos   = stream->pos;
+    FT_Error       error = BDF_Err_Ok;
+
+
+    if ( pos > stream->size )
+    {
+      FT_ERROR(( "bdf_internal_readstream:" ));
+      FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+                 pos, stream->size ));
+      error = BDF_Err_Invalid_Stream_Operation;
+      goto Exit;
+    }
+
+    if ( stream->read )
+      rbytes = stream->read( stream, pos,
+                             (unsigned char *)buffer, count );
+    else
+    {
+      rbytes = stream->size - pos;
+      if ( rbytes > count )
+        rbytes = count;
+
+      FT_MEM_COPY( buffer, stream->base + pos, rbytes );
+    }
+
+    stream->pos = pos + rbytes;
+
+    *read_bytes = rbytes;
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  _bdf_readstream( FT_Stream         stream,
+                   _bdf_line_func_t  callback,
+                   void*             client_data,
+                   unsigned long    *lno )
+  {
+    _bdf_line_func_t  cb;
+    unsigned long     lineno;
+    int               n, res, done, refill, bytes, hold;
+    char              *ls, *le, *pp, *pe, *hp;
+    char              *buf = 0;
+    FT_Memory         memory = stream->memory;
+    FT_Error          error = BDF_Err_Ok;
+
+
+    if ( callback == 0 )
+    {
+      error = BDF_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    if ( FT_NEW_ARRAY( buf, 65536L ) )
+      goto Exit;
+
+    cb     = callback;
+    lineno = 1;
+    buf[0] = 0;
+
+    res = done = 0;
+    pp = ls = le = buf;
+
+    bytes = 65536L;
+
+    while ( !done )
+    {
+      error = bdf_internal_readstream( stream, pp, bytes, &n );
+      if ( error )
+        goto Exit;
+
+      if ( n == 0 )
+        break;
+
+      /* Determine the new end of the buffer pages. */
+      pe = pp + n;
+
+      for ( refill = 0; done == 0 && refill == 0; )
+      {
+        while ( le < pe && *le != '\n' && *le != '\r' )
+          le++;
+
+        if ( le == pe )
+        {
+          /* Hit the end of the last page in the buffer.  Need to find */
+          /* out how many pages to shift and how many pages need to be */
+          /* read in.  Adjust the line start and end pointers down to  */
+          /* point to the right places in the pages.                   */
+
+          pp  = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
+          n   = pp - buf;
+          ls -= n;
+          le -= n;
+          n   = pe - pp;
+
+          FT_MEM_COPY( buf, pp, n );
+
+          pp     = buf + n;
+          bytes  = 65536L - n;
+          refill = 1;
+        }
+        else
+        {
+          /* Temporarily NULL-terminate the line. */
+          hp   = le;
+          hold = *le;
+          *le  = 0;
+
+          /* XXX: Use encoding independent value for 0x1a */
+          if ( *ls != '#' && *ls != 0x1a                          &&
+               le > ls                                            &&
+               ( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
+                                client_data ) ) != BDF_Err_Ok     )
+            done = 1;
+          else
+          {
+            ls = ++le;
+            /* Handle the case of DOS crlf sequences. */
+            if ( le < pe && hold == '\n' && *le =='\r' )
+              ls = ++le;
+          }
+
+          /* Increment the line number. */
+          lineno++;
+
+          /* Restore the character at the end of the line. */
+          *hp = (char)hold;
+        }
+      }
+    }
+
+    *lno             = lineno;
+
+  Exit:
+    FT_FREE( buf );
+    return error;
+  }
+
+
+  /* XXX: make this work with EBCDIC also */
+
+  static const unsigned char  a2i[128] =
+  {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  };
+
+  static const unsigned char  odigits[32] =
+  {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  };
+
+  static const unsigned char  ddigits[32] =
+  {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  };
+
+  static const unsigned char  hdigits[32] =
+  {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+    0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  };
+
+
+#define isdigok( m, d )  (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
+
+
+  /* Routine to convert an ASCII string into an unsigned long integer. */
+  static unsigned long
+  _bdf_atoul( char*   s,
+              char**  end,
+              int     base )
+  {
+    unsigned long         v;
+    const unsigned char*  dmap;
+
+
+    if ( s == 0 || *s == 0 )
+      return 0;
+
+    /* Make sure the radix is something recognizable.  Default to 10. */
+    switch ( base )
+    {
+    case 8:
+      dmap = odigits;
+      break;
+    case 16:
+      dmap = hdigits;
+      break;
+    default:
+      base = 10;
+      dmap = ddigits;
+      break;
+    }
+
+    /* Check for the special hex prefix. */
+    if ( *s == '0'                                  &&
+         ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
+    {
+      base = 16;
+      dmap = hdigits;
+      s   += 2;
+    }
+
+    for ( v = 0; isdigok( dmap, *s ); s++ )
+      v = v * base + a2i[(int)*s];
+
+    if ( end != 0 )
+      *end = s;
+
+    return v;
+  }
+
+
+  /* Routine to convert an ASCII string into an signed long integer. */
+  static long
+  _bdf_atol( char*   s,
+             char**  end,
+             int     base )
+  {
+    long                  v, neg;
+    const unsigned char*  dmap;
+
+
+    if ( s == 0 || *s == 0 )
+      return 0;
+
+    /* Make sure the radix is something recognizable.  Default to 10. */
+    switch ( base )
+    {
+    case 8:
+      dmap = odigits;
+      break;
+    case 16:
+      dmap = hdigits;
+      break;
+    default:
+      base = 10;
+      dmap = ddigits;
+      break;
+    }
+
+    /* Check for a minus sign. */
+    neg = 0;
+    if ( *s == '-' )
+    {
+      s++;
+      neg = 1;
+    }
+
+    /* Check for the special hex prefix. */
+    if ( *s == '0'                                  &&
+         ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
+    {
+      base = 16;
+      dmap = hdigits;
+      s   += 2;
+    }
+
+    for ( v = 0; isdigok( dmap, *s ); s++ )
+      v = v * base + a2i[(int)*s];
+
+    if ( end != 0 )
+      *end = s;
+
+    return ( !neg ) ? v : -v;
+  }
+
+
+  /* Routine to convert an ASCII string into an signed short integer. */
+  static short
+  _bdf_atos( char*   s,
+             char**  end,
+             int     base )
+  {
+    short                 v, neg;
+    const unsigned char*  dmap;
+
+
+    if ( s == 0 || *s == 0 )
+      return 0;
+
+    /* Make sure the radix is something recognizable.  Default to 10. */
+    switch ( base )
+    {
+    case 8:
+      dmap = odigits;
+      break;
+    case 16:
+      dmap = hdigits;
+      break;
+    default:
+      base = 10;
+      dmap = ddigits;
+      break;
+    }
+
+    /* Check for a minus. */
+    neg = 0;
+    if ( *s == '-' )
+    {
+      s++;
+      neg = 1;
+    }
+
+    /* Check for the special hex prefix. */
+    if ( *s == '0'                                  &&
+         ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
+    {
+      base = 16;
+      dmap = hdigits;
+      s   += 2;
+    }
+
+    for ( v = 0; isdigok( dmap, *s ); s++ )
+      v = (short)( v * base + a2i[(int)*s] );
+
+    if ( end != 0 )
+      *end = s;
+
+    return (short)( ( !neg ) ? v : -v );
+  }
+
+
+  /* Routine to compare two glyphs by encoding so they can be sorted. */
+  static int
+  by_encoding( const void*  a,
+               const void*  b )
+  {
+    bdf_glyph_t  *c1, *c2;
+
+
+    c1 = (bdf_glyph_t *)a;
+    c2 = (bdf_glyph_t *)b;
+
+    if ( c1->encoding < c2->encoding )
+      return -1;
+    else if ( c1->encoding > c2->encoding )
+      return 1;
+
+    return 0;
+  }
+
+
+  static FT_Error
+  bdf_create_property( char*        name,
+                       int          format,
+                       bdf_font_t*  font )
+  {
+    unsigned long    n;
+    bdf_property_t*  p;
+    FT_Memory        memory = font->memory;
+    FT_Error         error = BDF_Err_Ok;
+
+
+    /* First check to see if the property has      */
+    /* already been added or not.  If it has, then */
+    /* simply ignore it.                           */
+    if ( hash_lookup( name, &(font->proptbl) ) )
+      goto Exit;
+
+    if ( font->nuser_props == 0 )
+    {
+      if ( FT_NEW_ARRAY( font->user_props, 1 ) )
+        goto Exit;
+    }
+    else
+    {
+      if ( FT_RENEW_ARRAY( font->user_props,
+                           font->nuser_props,
+                           font->nuser_props + 1 ) )
+        goto Exit;
+    }
+
+    p = font->user_props + font->nuser_props;
+    FT_MEM_ZERO( p, sizeof ( bdf_property_t ) );
+
+    n = (unsigned long)( ft_strlen( name ) + 1 );
+    if ( FT_NEW_ARRAY( p->name, n ) )
+      goto Exit;
+
+    FT_MEM_COPY( (char *)p->name, name, n );
+
+    p->format  = format;
+    p->builtin = 0;
+
+    n = _num_bdf_properties + font->nuser_props;
+
+    error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
+    if ( error )
+      goto Exit;
+
+    font->nuser_props++;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( bdf_property_t * )
+  bdf_get_property( char*        name,
+                    bdf_font_t*  font )
+  {
+    hashnode       hn;
+    unsigned long  propid;
+
+
+    if ( name == 0 || *name == 0 )
+      return 0;
+
+    if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
+      return 0;
+
+    propid = (unsigned long)hn->data;
+    if ( propid >= _num_bdf_properties )
+      return font->user_props + ( propid - _num_bdf_properties );
+
+    return (bdf_property_t*)_bdf_properties + propid;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* BDF font file parsing flags and functions.                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /* Parse flags. */
+
+#define _BDF_START      0x0001
+#define _BDF_FONT_NAME  0x0002
+#define _BDF_SIZE       0x0004
+#define _BDF_FONT_BBX   0x0008
+#define _BDF_PROPS      0x0010
+#define _BDF_GLYPHS     0x0020
+#define _BDF_GLYPH      0x0040
+#define _BDF_ENCODING   0x0080
+#define _BDF_SWIDTH     0x0100
+#define _BDF_DWIDTH     0x0200
+#define _BDF_BBX        0x0400
+#define _BDF_BITMAP     0x0800
+
+#define _BDF_SWIDTH_ADJ  0x1000
+
+#define _BDF_GLYPH_BITS ( _BDF_GLYPH    | \
+                          _BDF_ENCODING | \
+                          _BDF_SWIDTH   | \
+                          _BDF_DWIDTH   | \
+                          _BDF_BBX      | \
+                          _BDF_BITMAP   )
+
+#define _BDF_GLYPH_WIDTH_CHECK   0x40000000L
+#define _BDF_GLYPH_HEIGHT_CHECK  0x80000000L
+
+
+  /* Auto correction messages. */
+#define ACMSG1   "FONT_ASCENT property missing.  " \
+                 "Added \"FONT_ASCENT %hd\".\n"
+#define ACMSG2   "FONT_DESCENT property missing.  " \
+                 "Added \"FONT_DESCENT %hd\".\n"
+#define ACMSG3   "Font width != actual width.  Old: %hd New: %hd.\n"
+#define ACMSG4   "Font left bearing != actual left bearing.  " \
+                 "Old: %hd New: %hd.\n"
+#define ACMSG5   "Font ascent != actual ascent.  Old: %hd New: %hd.\n"
+#define ACMSG6   "Font descent != actual descent.  Old: %hd New: %hd.\n"
+#define ACMSG7   "Font height != actual height. Old: %hd New: %hd.\n"
+#define ACMSG8   "Glyph scalable width (SWIDTH) adjustments made.\n"
+#define ACMSG9   "SWIDTH field missing at line %ld.  Set automatically.\n"
+#define ACMSG10  "DWIDTH field missing at line %ld.  Set to glyph width.\n"
+#define ACMSG11  "SIZE bits per pixel field adjusted to %hd.\n"
+#define ACMSG12  "Duplicate encoding %ld (%s) changed to unencoded.\n"
+#define ACMSG13  "Glyph %ld extra rows removed.\n"
+#define ACMSG14  "Glyph %ld extra columns removed.\n"
+#define ACMSG15  "Incorrect glyph count: %ld indicated but %ld found.\n"
+
+  /* Error messages. */
+#define ERRMSG1  "[line %ld] Missing \"%s\" line.\n"
+#define ERRMSG2  "[line %ld] Font header corrupted or missing fields.\n"
+#define ERRMSG3  "[line %ld] Font glyphs corrupted or missing fields.\n"
+
+
+  static FT_Error
+  _bdf_add_comment( bdf_font_t*    font,
+                    char*          comment,
+                    unsigned long  len )
+  {
+    char*      cp;
+    FT_Memory  memory = font->memory;
+    FT_Error   error = BDF_Err_Ok;
+
+
+    if ( font->comments_len == 0 )
+    {
+      if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
+        goto Exit;
+    }
+    else
+    {
+      if ( FT_RENEW_ARRAY( font->comments,
+                           font->comments_len,
+                           font->comments_len + len + 1 ) )
+        goto Exit;
+    }
+
+    cp = font->comments + font->comments_len;
+    FT_MEM_COPY( cp, comment, len );
+    cp   += len;
+    *cp++ = '\n';
+    font->comments_len += len + 1;
+
+  Exit:
+    return error;
+  }
+
+
+  /* Set the spacing from the font name if it exists, or set it to the */
+  /* default specified in the options.                                 */
+  static FT_Error
+  _bdf_set_default_spacing( bdf_font_t*     font,
+                            bdf_options_t*  opts )
+  {
+    unsigned long  len;
+    char           name[128];
+    _bdf_list_t    list;
+    FT_Memory      memory;
+    FT_Error       error = BDF_Err_Ok;
+
+
+    if ( font == 0 || font->name == 0 || font->name[0] == 0 )
+    {
+      error = BDF_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    memory = font->memory;
+
+    font->spacing = opts->font_spacing;
+
+    len = (unsigned long)( ft_strlen( font->name ) + 1 );
+    FT_MEM_COPY( name, font->name, len );
+
+    list.size = list.used = 0;
+
+    error = _bdf_split( (char *)"-", name, len, &list, memory );
+    if ( error )
+      goto Exit;
+
+    if ( list.used == 15 )
+    {
+      switch ( list.field[11][0] )
+      {
+      case 'C':
+      case 'c':
+        font->spacing = BDF_CHARCELL;
+        break;
+      case 'M':
+      case 'm':
+        font->spacing = BDF_MONOWIDTH;
+        break;
+      case 'P':
+      case 'p':
+        font->spacing = BDF_PROPORTIONAL;
+        break;
+      }
+    }
+
+    FT_FREE( list.field );
+
+  Exit:
+    return error;
+  }
+
+
+  /* Determine whether the property is an atom or not.  If it is, then */
+  /* clean it up so the double quotes are removed if they exist.       */
+  static int
+  _bdf_is_atom( char*          line,
+                unsigned long  linelen,
+                char**         name,
+                char**         value,
+                bdf_font_t*    font )
+  {
+    int              hold;
+    char             *sp, *ep;
+    bdf_property_t*  p;
+
+
+    *name = sp = ep = line;
+
+    while ( *ep && *ep != ' ' && *ep != '\t' )
+      ep++;
+
+    hold = -1;
+    if ( *ep )
+    {
+      hold = *ep;
+      *ep  = 0;
+    }
+
+    p = bdf_get_property( sp, font );
+
+    /* Restore the character that was saved before any return can happen. */
+    if ( hold != -1 )
+      *ep = (char)hold;
+
+    /* If the property exists and is not an atom, just return here. */
+    if ( p && p->format != BDF_ATOM )
+      return 0;
+
+    /* The property is an atom.  Trim all leading and trailing whitespace */
+    /* and double quotes for the atom value.                              */
+    sp = ep;
+    ep = line + linelen;
+
+    /* Trim the leading whitespace if it exists. */
+    *sp++ = 0;
+    while ( *sp                           &&
+            ( *sp == ' ' || *sp == '\t' ) )
+      sp++;
+
+    /* Trim the leading double quote if it exists. */
+    if ( *sp == '"' )
+      sp++;
+    *value = sp;
+
+    /* Trim the trailing whitespace if it exists. */
+    while ( ep > sp                                       &&
+            ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
+      *--ep = 0;
+
+    /* Trim the trailing double quote if it exists. */
+    if ( ep > sp && *( ep - 1 ) == '"' )
+      *--ep = 0;
+
+    return 1;
+  }
+
+
+  static FT_Error
+  _bdf_add_property( bdf_font_t*  font,
+                     char*        name,
+                     char*        value )
+  {
+    unsigned long   propid;
+    hashnode        hn;
+    int             len;
+    bdf_property_t  *prop, *fp;
+    FT_Memory       memory = font->memory;
+    FT_Error        error = BDF_Err_Ok;
+
+
+    /* First, check to see if the property already exists in the font. */
+    if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
+    {
+      /* The property already exists in the font, so simply replace */
+      /* the value of the property with the current value.          */
+      fp = font->props + (unsigned long)hn->data;
+
+      switch ( fp->format )
+      {
+      case BDF_ATOM:
+        /* Delete the current atom if it exists. */
+        FT_FREE( fp->value.atom );
+
+        if ( value == 0 )
+          len = 1;
+        else
+          len = ft_strlen( value ) + 1;
+
+        if ( len > 1 )
+        {
+          if ( FT_NEW_ARRAY( fp->value.atom, len ) )
+            goto Exit;
+          FT_MEM_COPY( fp->value.atom, value, len );
+        }
+        else
+          fp->value.atom = 0;
+        break;
+
+      case BDF_INTEGER:
+        fp->value.int32 = _bdf_atol( value, 0, 10 );
+        break;
+
+      case BDF_CARDINAL:
+        fp->value.card32 = _bdf_atoul( value, 0, 10 );
+        break;
+
+      default:
+        ;
+      }
+
+      goto Exit;
+    }
+
+    /* See whether this property type exists yet or not. */
+    /* If not, create it.                                */
+    hn = hash_lookup( name, &(font->proptbl) );
+    if ( hn == 0 )
+    {
+      error = bdf_create_property( name, BDF_ATOM, font );
+      if ( error )
+        goto Exit;
+      hn = hash_lookup( name, &(font->proptbl) );
+    }
+
+    /* Allocate another property if this is overflow. */
+    if ( font->props_used == font->props_size )
+    {
+      if ( font->props_size == 0 )
+      {
+        if ( FT_NEW_ARRAY( font->props, 1 ) )
+          goto Exit;
+      }
+      else
+      {
+        if ( FT_RENEW_ARRAY( font->props,
+                             font->props_size,
+                             font->props_size + 1 ) )
+          goto Exit;
+      }
+
+      fp = font->props + font->props_size;
+      FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
+      font->props_size++;
+    }
+
+    propid = (unsigned long)hn->data;
+    if ( propid >= _num_bdf_properties )
+      prop = font->user_props + ( propid - _num_bdf_properties );
+    else
+      prop = (bdf_property_t*)_bdf_properties + propid;
+
+    fp = font->props + font->props_used;
+
+    fp->name    = prop->name;
+    fp->format  = prop->format;
+    fp->builtin = prop->builtin;
+
+    switch ( prop->format )
+    {
+    case BDF_ATOM:
+      if ( value == 0 )
+        len = 1;
+      else
+        len = ft_strlen( value ) + 1;
+
+      if ( len > 1 )
+      {
+        if ( FT_NEW_ARRAY( fp->value.atom, len ) )
+          goto Exit;
+        FT_MEM_COPY( fp->value.atom, value, len );
+      }
+      else
+        fp->value.atom = 0;
+      break;
+
+    case BDF_INTEGER:
+      fp->value.int32 = _bdf_atol( value, 0, 10 );
+      break;
+
+    case BDF_CARDINAL:
+      fp->value.card32 = _bdf_atoul( value, 0, 10 );
+      break;
+    }
+
+    /* If the property happens to be a comment, then it doesn't need */
+    /* to be added to the internal hash table.                       */
+    if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
+      /* Add the property to the font property table. */
+      error = hash_insert( fp->name,
+                           (void *)font->props_used,
+                           (hashtable *)font->internal,
+                           memory );
+      if ( error )
+        goto Exit;
+    }
+
+    font->props_used++;
+
+    /* Some special cases need to be handled here.  The DEFAULT_CHAR       */
+    /* property needs to be located if it exists in the property list, the */
+    /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are        */
+    /* present, and the SPACING property should override the default       */
+    /* spacing.                                                            */
+    if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
+      font->default_glyph = fp->value.int32;
+    else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
+      font->font_ascent = fp->value.int32;
+    else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
+      font->font_descent = fp->value.int32;
+    else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
+    {
+      if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
+        font->spacing = BDF_PROPORTIONAL;
+      else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
+        font->spacing = BDF_MONOWIDTH;
+      else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
+        font->spacing = BDF_CHARCELL;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static const unsigned char nibble_mask[8] =
+  {
+    0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
+  };
+
+
+  /* Actually parse the glyph info and bitmaps. */
+  static FT_Error
+  _bdf_parse_glyphs( char*          line,
+                     unsigned long  linelen,
+                     unsigned long  lineno,
+                     void*          call_data,
+                     void*          client_data )
+  {
+    int                c, mask_index;
+    char*              s;
+    unsigned char*     bp;
+    unsigned long      i, slen, nibbles;
+
+    _bdf_line_func_t*  next;
+    _bdf_parse_t*      p;
+    bdf_glyph_t*       glyph;
+    bdf_font_t*        font;
+
+    FT_Memory          memory;
+    FT_Error           error = BDF_Err_Ok;
+
+    FT_UNUSED( lineno );        /* only used in debug mode */
+
+
+    next = (_bdf_line_func_t *)call_data;
+    p    = (_bdf_parse_t *)    client_data;
+
+    font   = p->font;
+    memory = font->memory;
+
+    /* Check for a comment. */
+    if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
+    {
+      linelen -= 7;
+
+      s = line + 7;
+      if ( *s != 0 )
+      {
+        s++;
+        linelen--;
+      }
+      error = _bdf_add_comment( p->font, s, linelen );
+      goto Exit;
+    }
+
+    /* The very first thing expected is the number of glyphs. */
+    if ( !( p->flags & _BDF_GLYPHS ) )
+    {
+      if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
+      {
+        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
+        error = BDF_Err_Missing_Chars_Field;
+        goto Exit;
+      }
+
+      error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+      if ( error )
+        goto Exit;
+      p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
+
+      /* Make sure the number of glyphs is non-zero. */
+      if ( p->cnt == 0 )
+        font->glyphs_size = 64;
+
+      if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
+        goto Exit;
+
+      p->flags |= _BDF_GLYPHS;
+
+      goto Exit;
+    }
+
+    /* Check for the ENDFONT field. */
+    if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
+    {
+      /* Sort the glyphs by encoding. */
+      ft_qsort( (char *)font->glyphs,
+                font->glyphs_used,
+                sizeof ( bdf_glyph_t ),
+                by_encoding );
+
+      p->flags &= ~_BDF_START;
+
+      goto Exit;
+    }
+
+    /* Check for the ENDCHAR field. */
+    if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
+    {
+      p->glyph_enc = 0;
+      p->flags    &= ~_BDF_GLYPH_BITS;
+
+      goto Exit;
+    }
+
+    /* Check to see whether a glyph is being scanned but should be */
+    /* ignored because it is an unencoded glyph.                   */
+    if ( ( p->flags & _BDF_GLYPH )     &&
+         p->glyph_enc            == -1 &&
+         p->opts->keep_unencoded == 0  )
+      goto Exit;
+
+    /* Check for the STARTCHAR field. */
+    if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
+    {
+      /* Set the character name in the parse info first until the */
+      /* encoding can be checked for an unencoded character.      */
+      FT_FREE( p->glyph_name );
+
+      error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
+      if ( error )
+        goto Exit;
+      _bdf_shift( 1, &p->list );
+
+      s = _bdf_join( ' ', &slen, &p->list );
+
+      if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
+        goto Exit;
+      FT_MEM_COPY( p->glyph_name, s, slen + 1 );
+
+      p->flags |= _BDF_GLYPH;
+
+      goto Exit;
+    }
+
+    /* Check for the ENCODING field. */
+    if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
+    {
+      if ( !( p->flags & _BDF_GLYPH ) )
+      {
+        /* Missing STARTCHAR field. */
+        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
+        error = BDF_Err_Missing_Startchar_Field;
+        goto Exit;
+      }
+
+      error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+      if ( error )
+        goto Exit;
+      p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
+
+      /* Check to see whether this encoding has already been encountered. */
+      /* If it has then change it to unencoded so it gets added if        */
+      /* indicated.                                                       */
+      if ( p->glyph_enc >= 0 )
+      {
+        if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
+        {
+          /* Emit a message saying a glyph has been moved to the */
+          /* unencoded area.                                     */
+          FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
+                      p->glyph_enc, p->glyph_name ));
+          p->glyph_enc = -1;
+          font->modified = 1;
+        }
+        else
+          _bdf_set_glyph_modified( p->have, p->glyph_enc );
+      }
+
+      if ( p->glyph_enc >= 0 )
+      {
+        /* Make sure there are enough glyphs allocated in case the */
+        /* number of characters happen to be wrong.                */
+        if ( font->glyphs_used == font->glyphs_size )
+        {
+          if ( FT_RENEW_ARRAY( font->glyphs,
+                               font->glyphs_size,
+                               font->glyphs_size + 64 ) )
+            goto Exit;
+          FT_MEM_ZERO( font->glyphs + font->glyphs_size,
+                       sizeof ( bdf_glyph_t ) * 64 ); /* FZ inutile */
+          font->glyphs_size += 64;
+        }
+
+        glyph           = font->glyphs + font->glyphs_used++;
+        glyph->name     = p->glyph_name;
+        glyph->encoding = p->glyph_enc;
+
+        /* Reset the initial glyph info. */
+        p->glyph_name = 0;
+      }
+      else
+      {
+        /* Unencoded glyph.  Check to see whether it should */
+        /* be added or not.                                 */
+        if ( p->opts->keep_unencoded != 0 )
+        {
+          /* Allocate the next unencoded glyph. */
+          if ( font->unencoded_used == font->unencoded_size )
+          {
+            if ( font->unencoded_size == 0 )
+            {
+              if ( FT_NEW_ARRAY( font->unencoded, 4 ) )
+                goto Exit;
+            }
+            else
+            {
+              if ( FT_RENEW_ARRAY( font->unencoded ,
+                                   font->unencoded_size,
+                                   font->unencoded_size + 4 ) )
+                goto Exit;
+            }
+            font->unencoded_size += 4;
+          }
+
+          glyph           = font->unencoded + font->unencoded_used;
+          glyph->name     = p->glyph_name;
+          glyph->encoding = font->unencoded_used++;
+        }
+        else
+          /* Free up the glyph name if the unencoded shouldn't be */
+          /* kept.                                                */
+          FT_FREE( p->glyph_name );
+
+        p->glyph_name = 0;
+      }
+
+      /* Clear the flags that might be added when width and height are */
+      /* checked for consistency.                                      */
+      p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
+
+      p->flags |= _BDF_ENCODING;
+
+      goto Exit;
+    }
+
+    /* Point at the glyph being constructed. */
+    if ( p->glyph_enc == -1 )
+      glyph = font->unencoded + ( font->unencoded_used - 1 );
+    else
+      glyph = font->glyphs + ( font->glyphs_used - 1 );
+
+    /* Check to see whether a bitmap is being constructed. */
+    if ( p->flags & _BDF_BITMAP )
+    {
+      /* If there are more rows than are specified in the glyph metrics, */
+      /* ignore the remaining lines.                                     */
+      if ( p->row >= (unsigned long)glyph->bbx.height )
+      {
+        if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
+        {
+          FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
+          p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
+          font->modified = 1;
+        }
+
+        goto Exit;
+      }
+
+      /* Only collect the number of nibbles indicated by the glyph     */
+      /* metrics.  If there are more columns, they are simply ignored. */
+      nibbles = glyph->bpr << 1;
+      bp      = glyph->bitmap + p->row * glyph->bpr;
+
+      for ( i = 0, *bp = 0; i < nibbles; i++ )
+      {
+        c = line[i];
+        *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
+        if ( i + 1 < nibbles && ( i & 1 ) )
+          *++bp = 0;
+      }
+
+      /* Remove possible garbage at the right. */
+      mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
+      *bp &= nibble_mask[mask_index];
+
+      /* If any line has extra columns, indicate they have been removed. */
+      if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
+           !( p->flags & _BDF_GLYPH_WIDTH_CHECK )                   )
+      {
+        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
+        p->flags       |= _BDF_GLYPH_WIDTH_CHECK;
+        font->modified  = 1;
+      }
+
+      p->row++;
+      goto Exit;
+    }
+
+    /* Expect the SWIDTH (scalable width) field next. */
+    if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
+    {
+      if ( !( p->flags & _BDF_ENCODING ) )
+      {
+        /* Missing ENCODING field. */
+        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
+        error = BDF_Err_Missing_Encoding_Field;
+        goto Exit;
+      }
+
+      error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+      if ( error )
+        goto Exit;
+      glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
+      p->flags |= _BDF_SWIDTH;
+
+      goto Exit;
+    }
+
+    /* Expect the DWIDTH (scalable width) field next. */
+    if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
+    {
+      error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
+      if ( error )
+        goto Exit;
+      glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
+
+      if ( !( p->flags & _BDF_SWIDTH ) )
+      {
+        /* Missing SWIDTH field.  Emit an auto correction message and set */
+        /* the scalable width from the device width.                      */
+        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
+
+        glyph->swidth = (unsigned short)FT_MulDiv(
+                          glyph->dwidth, 72000L,
+                          (FT_Long)( font->point_size *
+                                     font->resolution_x ) );
+      }
+
+      p->flags |= _BDF_DWIDTH;
+      goto Exit;
+    }
+
+    /* Expect the BBX field next. */
+    if ( ft_memcmp( line, "BBX", 3 ) == 0 )
+    {
+      error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+      if ( error )
+        goto Exit;
+
+      glyph->bbx.width    = _bdf_atos( p->list.field[1], 0, 10 );
+      glyph->bbx.height   = _bdf_atos( p->list.field[2], 0, 10 );
+      glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
+      glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
+
+      /* Generate the ascent and descent of the character. */
+      glyph->bbx.ascent  = (short)( glyph->bbx.height + glyph->bbx.y_offset );
+      glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
+
+      /* Determine the overall font bounding box as the characters are */
+      /* loaded so corrections can be done later if indicated.         */
+      p->maxas    = (short)MAX( glyph->bbx.ascent, p->maxas );
+      p->maxds    = (short)MAX( glyph->bbx.descent, p->maxds );
+
+      p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
+
+      p->maxrb    = (short)MAX( p->rbearing, p->maxrb );
+      p->minlb    = (short)MIN( glyph->bbx.x_offset, p->minlb );
+      p->maxlb    = (short)MAX( glyph->bbx.x_offset, p->maxlb );
+
+      if ( !( p->flags & _BDF_DWIDTH ) )
+      {
+        /* Missing DWIDTH field.  Emit an auto correction message and set */
+        /* the device width to the glyph width.                           */
+        FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
+        glyph->dwidth = glyph->bbx.width;
+      }
+
+      /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
+      /* value if necessary.                                            */
+      if ( p->opts->correct_metrics != 0 )
+      {
+        /* Determine the point size of the glyph. */
+        unsigned short  sw = (unsigned short)FT_MulDiv(
+                               glyph->dwidth, 72000L,
+                               (FT_Long)( font->point_size *
+                                          font->resolution_x ) );
+
+
+        if ( sw != glyph->swidth )
+        {
+          glyph->swidth = sw;
+
+          if ( p->glyph_enc == -1 )
+            _bdf_set_glyph_modified( font->umod,
+                                     font->unencoded_used - 1 );
+          else
+            _bdf_set_glyph_modified( font->nmod, glyph->encoding );
+
+          p->flags       |= _BDF_SWIDTH_ADJ;
+          font->modified  = 1;
+        }
+      }
+
+      p->flags |= _BDF_BBX;
+      goto Exit;
+    }
+
+    /* And finally, gather up the bitmap. */
+    if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
+    {
+      if ( !( p->flags & _BDF_BBX ) )
+      {
+        /* Missing BBX field. */
+        FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
+        error = BDF_Err_Missing_Bbx_Field;
+        goto Exit;
+      }
+
+      /* Allocate enough space for the bitmap. */
+      glyph->bpr   = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
+      glyph->bytes = (unsigned short)( glyph->bpr * glyph->bbx.height );
+
+      if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
+        goto Exit;
+
+      p->row    = 0;
+      p->flags |= _BDF_BITMAP;
+
+      goto Exit;
+    }
+
+    error = BDF_Err_Invalid_File_Format;
+
+  Exit:
+    return error;
+  }
+
+
+  /* Load the font properties. */
+  static FT_Error
+  _bdf_parse_properties( char*          line,
+                         unsigned long  linelen,
+                         unsigned long  lineno,
+                         void*          call_data,
+                         void*          client_data )
+  {
+    unsigned long      vlen;
+    _bdf_line_func_t*  next;
+    _bdf_parse_t*      p;
+    char*              name;
+    char*              value;
+    char               nbuf[128];
+    FT_Memory          memory;
+    FT_Error           error = BDF_Err_Ok;
+
+    FT_UNUSED( lineno );
+
+
+    next = (_bdf_line_func_t *)call_data;
+    p    = (_bdf_parse_t *)    client_data;
+
+    memory = p->font->memory;
+
+    /* Check for the end of the properties. */
+    if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
+    {
+      /* If the FONT_ASCENT or FONT_DESCENT properties have not been      */
+      /* encountered yet, then make sure they are added as properties and */
+      /* make sure they are set from the font bounding box info.          */
+      /*                                                                  */
+      /* This is *always* done regardless of the options, because X11     */
+      /* requires these two fields to compile fonts.                      */
+      if ( bdf_get_font_property( p->font, (char *)"FONT_ASCENT" ) == 0 )
+      {
+        p->font->font_ascent = p->font->bbx.ascent;
+        ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
+        error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
+        if ( error )
+          goto Exit;
+
+        FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
+        p->font->modified = 1;
+      }
+
+      if ( bdf_get_font_property( p->font, (char *)"FONT_DESCENT" ) == 0 )
+      {
+        p->font->font_descent = p->font->bbx.descent;
+        ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
+        error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
+        if ( error )
+          goto Exit;
+
+        FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
+        p->font->modified = 1;
+      }
+
+      p->flags &= ~_BDF_PROPS;
+      *next     = _bdf_parse_glyphs;
+
+      goto Exit;
+    }
+
+    /* Ignore the _XFREE86_GLYPH_RANGES properties. */
+    if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
+      goto Exit;
+
+    /* Handle COMMENT fields and properties in a special way to preserve */
+    /* the spacing.                                                      */
+    if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
+    {
+      name = value = line;
+      value += 7;
+      if ( *value )
+        *value++ = 0;
+      error = _bdf_add_property( p->font, name, value );
+      if ( error )
+        goto Exit;
+    }
+    else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
+    {
+      error = _bdf_add_property( p->font, name, value );
+      if ( error )
+        goto Exit;
+    }
+    else
+    {
+      error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+      if ( error )
+        goto Exit;
+      name = p->list.field[0];
+
+      _bdf_shift( 1, &p->list );
+      value = _bdf_join( ' ', &vlen, &p->list );
+
+      error = _bdf_add_property( p->font, name, value );
+      if ( error )
+        goto Exit;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /* Load the font header. */
+  static FT_Error
+  _bdf_parse_start( char*          line,
+                    unsigned long  linelen,
+                    unsigned long  lineno,
+                    void*          call_data,
+                    void*          client_data )
+  {
+    unsigned long      slen;
+    _bdf_line_func_t*  next;
+    _bdf_parse_t*      p;
+    bdf_font_t*        font;
+    char               *s;
+
+    FT_Memory          memory = NULL;
+    FT_Error           error  = BDF_Err_Ok;
+
+    FT_UNUSED( lineno );            /* only used in debug mode */
+
+
+    next = (_bdf_line_func_t *)call_data;
+    p    = (_bdf_parse_t *)    client_data;
+
+    if ( p->font )
+      memory = p->font->memory;
+
+    /* Check for a comment.  This is done to handle those fonts that have */
+    /* comments before the STARTFONT line for some reason.                */
+    if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
+    {
+      if ( p->opts->keep_comments != 0 && p->font != 0 )
+      {
+        linelen -= 7;
+
+        s = line + 7;
+        if ( *s != 0 )
+        {
+          s++;
+          linelen--;
+        }
+
+        error = _bdf_add_comment( p->font, s, linelen );
+        if ( error )
+          goto Exit;
+        /* here font is not defined! */
+      }
+
+      goto Exit;
+    }
+
+    if ( !( p->flags & _BDF_START ) )
+    {
+      memory = p->memory;
+
+      if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
+      {
+        /* No STARTFONT field is a good indication of a problem. */
+        error = BDF_Err_Missing_Startfont_Field;
+        goto Exit;
+      }
+
+      p->flags = _BDF_START;
+      font = p->font = 0;
+
+      if ( FT_NEW( font ) )
+        goto Exit;
+      p->font = font;
+
+      font->memory = p->memory;
+      p->memory    = 0;
+
+      { /* setup */
+        unsigned long    i;
+        bdf_property_t*  prop;
+
+
+        error = hash_init( &(font->proptbl), memory );
+        if ( error )
+          goto Exit;
+        for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
+              i < _num_bdf_properties; i++, prop++ )
+        {
+          error = hash_insert( prop->name, (void *)i,
+                               &(font->proptbl), memory );
+          if ( error )
+            goto Exit;
+        }
+      }
+
+      if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
+        goto Exit;
+      error = hash_init( (hashtable *)p->font->internal,memory );
+      if ( error )
+        goto Exit;
+      p->font->spacing       = p->opts->font_spacing;
+      p->font->default_glyph = -1;
+
+      goto Exit;
+    }
+
+    /* Check for the start of the properties. */
+    if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
+    {
+      error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+      if ( error )
+        goto Exit;
+      p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
+
+      if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
+        goto Exit;
+
+      p->flags |= _BDF_PROPS;
+      *next     = _bdf_parse_properties;
+
+      goto Exit;
+    }
+
+    /* Check for the FONTBOUNDINGBOX field. */
+    if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
+    {
+      if ( !(p->flags & _BDF_SIZE ) )
+      {
+        /* Missing the SIZE field. */
+        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
+        error = BDF_Err_Missing_Size_Field;
+        goto Exit;
+      }
+
+      error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
+      if ( error )
+        goto Exit;
+
+      p->font->bbx.width  = _bdf_atos( p->list.field[1], 0, 10 );
+      p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
+
+      p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
+      p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
+
+      p->font->bbx.ascent  = (short)( p->font->bbx.height +
+                                      p->font->bbx.y_offset );
+
+      p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
+
+      p->flags |= _BDF_FONT_BBX;
+
+      goto Exit;
+    }
+
+    /* The next thing to check for is the FONT field. */
+    if ( ft_memcmp( line, "FONT", 4 ) == 0 )
+    {
+      error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
+      if ( error )
+        goto Exit;
+      _bdf_shift( 1, &p->list );
+
+      s = _bdf_join( ' ', &slen, &p->list );
+      if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
+        goto Exit;
+      FT_MEM_COPY( p->font->name, s, slen + 1 );
+
+      /* If the font name is an XLFD name, set the spacing to the one in  */
+      /* the font name.  If there is no spacing fall back on the default. */
+      error = _bdf_set_default_spacing( p->font, p->opts );
+      if ( error )
+        goto Exit;
+
+      p->flags |= _BDF_FONT_NAME;
+
+      goto Exit;
+    }
+
+    /* Check for the SIZE field. */
+    if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
+    {
+      if ( !( p->flags & _BDF_FONT_NAME ) )
+      {
+        /* Missing the FONT field. */
+        FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
+        error = BDF_Err_Missing_Font_Field;
+        goto Exit;
+      }
+
+      error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
+      if ( error )
+        goto Exit;
+
+      p->font->point_size   = _bdf_atoul( p->list.field[1], 0, 10 );
+      p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
+      p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
+
+      /* Check for the bits per pixel field. */
+      if ( p->list.used == 5 )
+      {
+        unsigned short bitcount, i, shift;
+
+
+        p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
+
+        /* Only values 1, 2, 4, 8 are allowed. */
+        shift = p->font->bpp;
+        bitcount = 0;
+        for ( i = 0; shift > 0; i++ )
+        {
+          if ( shift & 1 )
+            bitcount = i;
+          shift >>= 1;
+        }
+
+        shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
+
+        if ( p->font->bpp > shift || p->font->bpp != shift )
+        {
+          /* select next higher value */
+          p->font->bpp = (unsigned short)( shift << 1 );
+          FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
+        }
+      }
+      else
+        p->font->bpp = 1;
+
+      p->flags |= _BDF_SIZE;
+
+      goto Exit;
+    }
+
+    error = BDF_Err_Invalid_File_Format;
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* API.                                                                  */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  bdf_load_font( FT_Stream       stream,
+                 FT_Memory       extmemory,
+                 bdf_options_t*  opts,
+                 bdf_font_t*    *font )
+  {
+    unsigned long  lineno;
+    _bdf_parse_t   *p;
+
+    FT_Memory      memory = extmemory;
+    FT_Error       error  = BDF_Err_Ok;
+
+
+    if ( FT_ALLOC( p, sizeof ( _bdf_parse_t ) ) )
+      goto Exit;
+
+    memory    = NULL;
+    p->opts   = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
+    p->minlb  = 32767;
+    p->memory = extmemory;  /* only during font creation */
+
+    error = _bdf_readstream( stream, _bdf_parse_start,
+                             (void *)p, &lineno );
+    if ( error )
+      goto Exit;
+
+    if ( p->font != 0 )
+    {
+      /* If the font is not proportional, set the font's monowidth */
+      /* field to the width of the font bounding box.              */
+      memory = p->font->memory;
+
+      if ( p->font->spacing != BDF_PROPORTIONAL )
+        p->font->monowidth = p->font->bbx.width;
+
+      /* If the number of glyphs loaded is not that of the original count, */
+      /* indicate the difference.                                          */
+      if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
+      {
+        FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
+                    p->font->glyphs_used + p->font->unencoded_used ));
+        p->font->modified = 1;
+      }
+
+      /* Once the font has been loaded, adjust the overall font metrics if */
+      /* necessary.                                                        */
+      if ( p->opts->correct_metrics != 0 &&
+           ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
+      {
+        if ( p->maxrb - p->minlb != p->font->bbx.width )
+        {
+          FT_TRACE2(( "bdf_load_font: " ACMSG3,
+                      p->font->bbx.width, p->maxrb - p->minlb ));
+          p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
+          p->font->modified  = 1;
+        }
+
+        if ( p->font->bbx.x_offset != p->minlb )
+        {
+          FT_TRACE2(( "bdf_load_font: " ACMSG4,
+                      p->font->bbx.x_offset, p->minlb ));
+          p->font->bbx.x_offset = p->minlb;
+          p->font->modified     = 1;
+        }
+
+        if ( p->font->bbx.ascent != p->maxas )
+        {
+          FT_TRACE2(( "bdf_load_font: " ACMSG5,
+                      p->font->bbx.ascent, p->maxas ));
+          p->font->bbx.ascent = p->maxas;
+          p->font->modified   = 1;
+        }
+
+        if ( p->font->bbx.descent != p->maxds )
+        {
+          FT_TRACE2(( "bdf_load_font: " ACMSG6,
+                      p->font->bbx.descent, p->maxds ));
+          p->font->bbx.descent  = p->maxds;
+          p->font->bbx.y_offset = (short)( -p->maxds );
+          p->font->modified     = 1;
+        }
+
+        if ( p->maxas + p->maxds != p->font->bbx.height )
+        {
+          FT_TRACE2(( "bdf_load_font: " ACMSG7,
+                      p->font->bbx.height, p->maxas + p->maxds ));
+          p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
+        }
+
+        if ( p->flags & _BDF_SWIDTH_ADJ )
+          FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
+      }
+    }
+
+    if ( p->flags & _BDF_START )
+    {
+      {
+        /* The ENDFONT field was never reached or did not exist. */
+        if ( !( p->flags & _BDF_GLYPHS ) )
+          /* Error happened while parsing header. */
+          FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
+        else
+          /* Error happened when parsing glyphs. */
+          FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
+      }
+    }
+
+    /* Free up the list used during the parsing. */
+    if ( memory != NULL )
+      FT_FREE( p->list.field );
+
+    if ( p->font != 0 )
+    {
+      /* Make sure the comments are NULL terminated if they exist. */
+      memory = p->font->memory;
+
+      if ( p->font->comments_len > 0 ) {
+        if ( FT_RENEW_ARRAY( p->font->comments,
+                             p->font->comments_len,
+                             p->font->comments_len + 1 ) )
+          goto Exit;
+
+        p->font->comments[p->font->comments_len] = 0;
+      }
+    }
+    else if ( error == BDF_Err_Ok )
+      error = BDF_Err_Invalid_File_Format;
+
+    *font = p->font;
+
+  Exit:
+    if ( p )
+    {
+      memory = extmemory;
+      FT_FREE( p );
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  bdf_free_font( bdf_font_t*  font )
+  {
+    bdf_property_t*  prop;
+    unsigned long    i;
+    bdf_glyph_t*     glyphs;
+    FT_Memory        memory;
+
+
+    if ( font == 0 )
+      return;
+
+    memory = font->memory;
+
+    FT_FREE( font->name );
+
+    /* Free up the internal hash table of property names. */
+    if ( font->internal )
+    {
+      hash_free( (hashtable *)font->internal, memory );
+      FT_FREE( font->internal );
+    }
+
+    /* Free up the comment info. */
+    FT_FREE( font->comments );
+
+    /* Free up the properties. */
+    for ( i = 0; i < font->props_size; i++ )
+    {
+      if ( font->props[i].format == BDF_ATOM )
+        FT_FREE( font->props[i].value.atom );
+    }
+
+    FT_FREE( font->props );
+
+    /* Free up the character info. */
+    for ( i = 0, glyphs = font->glyphs;
+          i < font->glyphs_used; i++, glyphs++ )
+    {
+      FT_FREE( glyphs->name );
+      FT_FREE( glyphs->bitmap );
+    }
+
+    for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
+          i++, glyphs++ )
+    {
+      FT_FREE( glyphs->name );
+      FT_FREE( glyphs->bitmap );
+    }
+
+    FT_FREE( font->glyphs );
+    FT_FREE( font->unencoded );
+
+    /* Free up the overflow storage if it was used. */
+    for ( i = 0, glyphs = font->overflow.glyphs;
+          i < font->overflow.glyphs_used; i++, glyphs++ )
+    {
+      FT_FREE( glyphs->name );
+      FT_FREE( glyphs->bitmap );
+    }
+
+    FT_FREE( font->overflow.glyphs );
+
+    /* bdf_cleanup */
+    hash_free( &(font->proptbl), memory );
+
+    /* Free up the user defined properties. */
+    for (prop = font->user_props, i = 0;
+         i < font->nuser_props; i++, prop++ )
+    {
+      FT_FREE( prop->name );
+      if ( prop->format == BDF_ATOM )
+        FT_FREE( prop->value.atom );
+    }
+
+    FT_FREE( font->user_props );
+
+    /* FREE( font ); */ /* XXX Fixme */
+  }
+
+
+  FT_LOCAL_DEF( bdf_property_t * )
+  bdf_get_font_property( bdf_font_t*  font,
+                         char*        name )
+  {
+    hashnode  hn;
+
+
+    if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
+      return 0;
+
+    hn = hash_lookup( name, (hashtable *)font->internal );
+
+    return hn ? ( font->props + (unsigned long)hn->data ) : 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cff.c
@@ -1,0 +1,29 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cff.c                                                                  */
+/*                                                                         */
+/*    FreeType OpenType driver component (body only).                      */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "cffdrivr.c"
+#include "cffparse.c"
+#include "cffload.c"
+#include "cffobjs.c"
+#include "cffgload.c"
+#include "cffcmap.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffcmap.c
@@ -1,0 +1,326 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffcmap.c                                                              */
+/*                                                                         */
+/*    CFF character mapping table (cmap) support (body).                   */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "cffcmap.h"
+#include "cffload.h"
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****           CFF STANDARD (AND EXPERT) ENCODING CMAPS            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_CALLBACK_DEF( FT_Error )
+  cff_cmap_encoding_init( CFF_CMapStd  cmap )
+  {
+    TT_Face       face     = (TT_Face)FT_CMAP_FACE( cmap );
+    CFF_Font      cff      = (CFF_Font)face->extra.data;
+    CFF_Encoding  encoding = &cff->encoding;
+
+
+    cmap->count = encoding->count;
+    cmap->gids  = encoding->codes;
+    
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  cff_cmap_encoding_done( CFF_CMapStd  cmap )
+  {
+    cmap->count = 0;
+    cmap->gids  = NULL;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  cff_cmap_encoding_char_index( CFF_CMapStd  cmap,
+                                FT_UInt32    char_code )
+  {
+    FT_UInt  result = 0;
+
+
+    if ( char_code < cmap->count )
+      result = cmap->gids[char_code];
+    
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  cff_cmap_encoding_char_next( CFF_CMapStd   cmap,
+                               FT_UInt32    *pchar_code )
+  {
+    FT_UInt    result    = 0;
+    FT_UInt32  char_code = *pchar_code;
+    
+
+    *pchar_code = 0;
+
+    if ( char_code < cmap->count )
+    {
+      FT_UInt  code = (FT_UInt)(char_code + 1);
+      
+
+      for (;;)
+      {
+        if ( code >= cmap->count )
+          break;
+          
+        result = cmap->gids[code];
+        if ( result != 0 )
+        {
+          *pchar_code = code;
+          break;
+        }
+          
+        code++;
+      }
+    }
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+  cff_cmap_encoding_class_rec =
+  {
+    sizeof ( CFF_CMapStdRec ),
+
+    (FT_CMap_InitFunc)     cff_cmap_encoding_init,
+    (FT_CMap_DoneFunc)     cff_cmap_encoding_done,
+    (FT_CMap_CharIndexFunc)cff_cmap_encoding_char_index,
+    (FT_CMap_CharNextFunc) cff_cmap_encoding_char_next
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****              CFF SYNTHETIC UNICODE ENCODING CMAP              *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_CALLBACK_DEF( FT_Int )
+  cff_cmap_uni_pair_compare( const void*  pair1,
+                             const void*  pair2 )
+  {
+    FT_UInt32  u1 = ((CFF_CMapUniPair)pair1)->unicode;
+    FT_UInt32  u2 = ((CFF_CMapUniPair)pair2)->unicode;
+    
+
+    if ( u1 < u2 )
+      return -1;
+      
+    if ( u1 > u2 )
+      return +1;
+      
+    return 0;
+  }                            
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  cff_cmap_unicode_init( CFF_CMapUnicode  cmap )
+  {
+    FT_Error         error;
+    FT_UInt          count;
+    TT_Face          face    = (TT_Face)FT_CMAP_FACE( cmap );
+    FT_Memory        memory  = FT_FACE_MEMORY( face );
+    CFF_Font         cff     = (CFF_Font)face->extra.data;
+    CFF_Charset      charset = &cff->charset;
+    PSNames_Service  psnames = (PSNames_Service)cff->psnames;
+
+
+    cmap->num_pairs = 0;
+    cmap->pairs     = NULL;
+
+    count = (FT_UInt)face->root.num_glyphs;
+
+    if ( !FT_NEW_ARRAY( cmap->pairs, count ) )
+    {
+      FT_UInt          n, new_count;
+      CFF_CMapUniPair  pair;
+      FT_UInt32        uni_code;
+
+
+      pair = cmap->pairs;
+      for ( n = 0; n < count; n++ )
+      {
+        FT_UInt      sid   = charset->sids[n];
+        const char*  gname;
+
+
+        gname = cff_index_get_sid_string( &cff->string_index, sid, psnames );
+         
+        /* build unsorted pair table by matching glyph names */
+        if ( gname )
+        {
+          uni_code = psnames->unicode_value( gname );
+
+          if ( uni_code != 0 )
+          {
+            pair->unicode = uni_code;
+            pair->gindex  = n;
+            pair++;
+          }
+          
+          FT_FREE( gname );
+        }
+      }
+
+      new_count = (FT_UInt)( pair - cmap->pairs );
+      if ( new_count == 0 )
+      {
+        /* there are no unicode characters in here! */
+        FT_FREE( cmap->pairs );
+        error = FT_Err_Invalid_Argument;
+      }
+      else
+      {
+        /* re-allocate if the new array is much smaller than the original */
+        /* one                                                            */
+        if ( new_count != count && new_count < count / 2 )
+        {
+          (void)FT_RENEW_ARRAY( cmap->pairs, count, new_count );
+          error = 0;
+        }
+
+        /* sort the pairs table to allow efficient binary searches */
+        ft_qsort( cmap->pairs,
+                  new_count,
+                  sizeof ( CFF_CMapUniPairRec ),
+                  cff_cmap_uni_pair_compare );
+
+        cmap->num_pairs = new_count;
+      }
+    }
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  cff_cmap_unicode_done( CFF_CMapUnicode  cmap )
+  {
+    FT_Face    face   = FT_CMAP_FACE( cmap );
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
+ 
+    FT_FREE( cmap->pairs );
+    cmap->num_pairs = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  cff_cmap_unicode_char_index( CFF_CMapUnicode  cmap,
+                               FT_UInt32        char_code )
+  {
+    FT_UInt          min = 0;
+    FT_UInt          max = cmap->num_pairs;
+    FT_UInt          mid;
+    CFF_CMapUniPair  pair;
+
+
+    while ( min < max )
+    {
+      mid  = min + ( max - min ) / 2;
+      pair = cmap->pairs + mid;
+
+      if ( pair->unicode == char_code )
+        return pair->gindex;
+
+      if ( pair->unicode < char_code )
+        min = mid + 1;
+      else
+        max = mid;
+    }
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  cff_cmap_unicode_char_next( CFF_CMapUnicode  cmap,
+                              FT_UInt32       *pchar_code )
+  {
+    FT_UInt    result    = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+
+
+  Restart:
+    {
+      FT_UInt          min = 0;
+      FT_UInt          max = cmap->num_pairs;
+      FT_UInt          mid;
+      CFF_CMapUniPair  pair;
+
+
+      while ( min < max )
+      {
+        mid  = min + ( ( max - min ) >> 1 );
+        pair = cmap->pairs + mid;
+
+        if ( pair->unicode == char_code )
+        {
+          result = pair->gindex;
+          if ( result != 0 )
+            goto Exit;
+
+          char_code++;
+          goto Restart;
+        }
+
+        if ( pair->unicode < char_code )
+          min = mid+1;
+        else
+          max = mid;
+      }
+
+      /* we didn't find it, but we have a pair just above it */
+      char_code = 0;
+
+      if ( min < cmap->num_pairs )
+      {
+        pair   = cmap->pairs + min;
+        result = pair->gindex;
+        if ( result != 0 )
+          char_code = pair->unicode;
+      }
+    }
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+  cff_cmap_unicode_class_rec =
+  {
+    sizeof ( CFF_CMapUnicodeRec ),
+
+    (FT_CMap_InitFunc)     cff_cmap_unicode_init,
+    (FT_CMap_DoneFunc)     cff_cmap_unicode_done,
+    (FT_CMap_CharIndexFunc)cff_cmap_unicode_char_index,
+    (FT_CMap_CharNextFunc) cff_cmap_unicode_char_next
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffcmap.h
@@ -1,0 +1,88 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffcmap.h                                                              */
+/*                                                                         */
+/*    CFF character mapping table (cmap) support (specification).          */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CFFCMAP_H__
+#define __CFFCMAP_H__
+
+#include "cffobjs.h"
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****          TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* standard (and expert) encoding cmaps */
+  typedef struct CFF_CMapStdRec_*  CFF_CMapStd;
+
+  typedef struct  CFF_CMapStdRec_
+  {
+    FT_CMapRec  cmap;
+    FT_UInt     count;
+    FT_UShort*  gids;   /* up to 256 elements */
+    
+  } CFF_CMapStdRec;
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  cff_cmap_encoding_class_rec;
+
+  
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****               CFF SYNTHETIC UNICODE ENCODING CMAP             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* unicode (synthetic) cmaps */
+  typedef struct CFF_CMapUnicodeRec_*  CFF_CMapUnicode;
+
+  typedef struct  CFF_CMapUniPairRec_
+  {
+    FT_UInt32  unicode;
+    FT_UInt    gindex;
+  
+  } CFF_CMapUniPairRec, *CFF_CMapUniPair;
+
+
+  typedef struct  CFF_CMapUnicodeRec_
+  {
+    FT_CMapRec       cmap;
+    FT_UInt          num_pairs;
+    CFF_CMapUniPair  pairs;
+
+  } CFF_CMapUnicodeRec;
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  cff_cmap_unicode_class_rec;
+
+
+FT_END_HEADER
+
+#endif /* __CFFCMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffdrivr.c
@@ -1,0 +1,420 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffdrivr.c                                                             */
+/*                                                                         */
+/*    OpenType font driver implementation (body).                          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_IDS_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "cffdrivr.h"
+#include "cffgload.h"
+#include "cffload.h"
+
+#include "cfferrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cffdriver
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                          F A C E S                              ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+#undef  PAIR_TAG
+#define PAIR_TAG( left, right )  ( ( (FT_ULong)left << 16 ) | \
+                                     (FT_ULong)right        )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Get_Kerning                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A driver method used to return the kerning vector between two      */
+  /*    glyphs of the same face.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face        :: A handle to the source face object.                 */
+  /*                                                                       */
+  /*    left_glyph  :: The index of the left glyph in the kern pair.       */
+  /*                                                                       */
+  /*    right_glyph :: The index of the right glyph in the kern pair.      */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    kerning     :: The kerning vector.  This is in font units for      */
+  /*                   scalable formats, and in pixels for fixed-sizes     */
+  /*                   formats.                                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only horizontal layouts (left-to-right & right-to-left) are        */
+  /*    supported by this function.  Other layouts, or more sophisticated  */
+  /*    kernings, are out of scope of this method (the basic driver        */
+  /*    interface is meant to be simple).                                  */
+  /*                                                                       */
+  /*    They can be implemented by format-specific interfaces.             */
+  /*                                                                       */
+  static FT_Error
+  Get_Kerning( TT_Face     face,
+               FT_UInt     left_glyph,
+               FT_UInt     right_glyph,
+               FT_Vector*  kerning )
+  {
+    TT_Kern0_Pair  pair;
+
+
+    if ( !face )
+      return CFF_Err_Invalid_Face_Handle;
+
+    kerning->x = 0;
+    kerning->y = 0;
+
+    if ( face->kern_pairs )
+    {
+      /* there are some kerning pairs in this font file! */
+      FT_ULong  search_tag = PAIR_TAG( left_glyph, right_glyph );
+      FT_Long   left, right;
+
+
+      left  = 0;
+      right = face->num_kern_pairs - 1;
+
+      while ( left <= right )
+      {
+        FT_Long   middle = left + ( ( right - left ) >> 1 );
+        FT_ULong  cur_pair;
+
+
+        pair     = face->kern_pairs + middle;
+        cur_pair = PAIR_TAG( pair->left, pair->right );
+
+        if ( cur_pair == search_tag )
+          goto Found;
+
+        if ( cur_pair < search_tag )
+          left = middle + 1;
+        else
+          right = middle - 1;
+      }
+    }
+
+  Exit:
+    return CFF_Err_Ok;
+
+  Found:
+    kerning->x = pair->value;
+    goto Exit;
+  }
+
+
+#undef PAIR_TAG
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Load_Glyph                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A driver method used to load a glyph within a given glyph slot.    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    slot        :: A handle to the target slot object where the glyph  */
+  /*                   will be loaded.                                     */
+  /*                                                                       */
+  /*    size        :: A handle to the source face size at which the glyph */
+  /*                   must be scaled, loaded, etc.                        */
+  /*                                                                       */
+  /*    glyph_index :: The index of the glyph in the font file.            */
+  /*                                                                       */
+  /*    load_flags  :: A flag indicating what to load for this glyph.  The */
+  /*                   FTLOAD_??? constants can be used to control the     */
+  /*                   glyph loading process (e.g., whether the outline    */
+  /*                   should be scaled, whether to load bitmaps or not,   */
+  /*                   whether to hint the outline, etc).                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Load_Glyph( CFF_GlyphSlot  slot,
+              CFF_Size       size,
+              FT_UShort      glyph_index,
+              FT_Int32       load_flags )
+  {
+    FT_Error  error;
+
+
+    if ( !slot )
+      return CFF_Err_Invalid_Slot_Handle;
+
+    /* check whether we want a scaled outline or bitmap */
+    if ( !size )
+      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+    if ( load_flags & FT_LOAD_NO_SCALE )
+      size = NULL;
+
+    /* reset the size object if necessary */
+    if ( size )
+    {
+      /* these two object must have the same parent */
+      if ( size->face != slot->root.face )
+        return CFF_Err_Invalid_Face_Handle;
+    }
+
+    /* now load the glyph outline if necessary */
+    error = cff_slot_load( slot, size, glyph_index, load_flags );
+
+    /* force drop-out mode to 2 - irrelevant now */
+    /* slot->outline.dropout_mode = 2; */
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****             C H A R A C T E R   M A P P I N G S                 ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static FT_Error
+  cff_get_glyph_name( CFF_Face    face,
+                      FT_UInt     glyph_index,
+                      FT_Pointer  buffer,
+                      FT_UInt     buffer_max )
+  {
+    CFF_Font         font   = (CFF_Font)face->extra.data;
+    FT_Memory        memory = FT_FACE_MEMORY( face );
+    FT_String*       gname;
+    FT_UShort        sid;
+    PSNames_Service  psnames;
+    FT_Error         error;
+
+
+    psnames = (PSNames_Service)FT_Get_Module_Interface(
+                face->root.driver->root.library, "psnames" );
+
+    if ( !psnames )
+    {
+      FT_ERROR(( "cff_get_glyph_name:" ));
+      FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
+      FT_ERROR(( "                   " ));
+      FT_ERROR(( " without the `PSNames' module\n" ));
+      error = CFF_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* first, locate the sid in the charset table */
+    sid = font->charset.sids[glyph_index];
+
+    /* now, lookup the name itself */
+    gname = cff_index_get_sid_string( &font->string_index, sid, psnames );
+
+    if ( buffer_max > 0 )
+    {
+      FT_UInt  len = (FT_UInt)ft_strlen( gname );
+
+
+      if ( len >= buffer_max )
+        len = buffer_max - 1;
+
+      FT_MEM_COPY( buffer, gname, len );
+      ((FT_Byte*)buffer)[len] = 0;
+    }
+
+    FT_FREE ( gname );
+    error = CFF_Err_Ok;
+
+    Exit:
+      return error;
+  }
+
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cff_get_name_index                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Uses the psnames module and the CFF font's charset to to return a  */
+  /*    a given glyph name's glyph index.                                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face       :: A handle to the source face object.                  */
+  /*                                                                       */
+  /*    glyph_name :: The glyph name.                                      */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index.  0 means `undefined character code'.                  */
+  /*                                                                       */
+  static FT_UInt
+  cff_get_name_index( CFF_Face    face,
+                      FT_String*  glyph_name )
+  {
+    CFF_Font         cff;
+    CFF_Charset      charset;
+    PSNames_Service  psnames;
+    FT_Memory        memory = FT_FACE_MEMORY( face );
+    FT_String*       name;
+    FT_UShort        sid;
+    FT_UInt          i;
+    FT_Int           result;
+
+
+    cff     = (CFF_FontRec *)face->extra.data;
+    charset = &cff->charset;
+
+    psnames = (PSNames_Service)FT_Get_Module_Interface(
+                face->root.driver->root.library, "psnames" );
+
+    for ( i = 0; i < cff->num_glyphs; i++ )
+    {
+      sid = charset->sids[i];
+
+      if ( sid > 390 )
+        name = cff_index_get_name( &cff->string_index, sid - 391 );
+      else
+        name = (FT_String *)psnames->adobe_std_strings( sid );
+
+      result = ft_strcmp( glyph_name, name );
+
+      if ( sid > 390 )
+        FT_FREE( name );
+
+      if ( !result )
+        return i;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                D R I V E R  I N T E R F A C E                   ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static FT_Module_Interface
+  cff_get_interface( CFF_Driver   driver,
+                     const char*  module_interface )
+  {
+    FT_Module  sfnt;
+
+
+#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+
+    if ( ft_strcmp( (const char*)module_interface, "glyph_name" ) == 0 )
+      return (FT_Module_Interface)cff_get_glyph_name;
+
+    if ( ft_strcmp( (const char*)module_interface, "name_index" ) == 0 )
+      return (FT_Module_Interface)cff_get_name_index;
+
+#endif
+
+    /* we simply pass our request to the `sfnt' module */
+    sfnt = FT_Get_Module( driver->root.root.library, "sfnt" );
+
+    return sfnt ? sfnt->clazz->get_interface( sfnt, module_interface ) : 0;
+  }
+
+
+  /* The FT_DriverInterface structure is defined in ftdriver.h. */
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  cff_driver_class =
+  {
+    /* begin with the FT_Module_Class fields */
+    {
+      ft_module_font_driver       |
+      ft_module_driver_scalable   |
+      ft_module_driver_has_hinter,
+
+      sizeof( CFF_DriverRec ),
+      "cff",
+      0x10000L,
+      0x20000L,
+
+      0,   /* module-specific interface */
+
+      (FT_Module_Constructor)cff_driver_init,
+      (FT_Module_Destructor) cff_driver_done,
+      (FT_Module_Requester)  cff_get_interface,
+    },
+
+    /* now the specific driver fields */
+    sizeof( TT_FaceRec ),
+    sizeof( FT_SizeRec ),
+    sizeof( CFF_GlyphSlotRec ),
+
+    (FT_Face_InitFunc)       cff_face_init,
+    (FT_Face_DoneFunc)       cff_face_done,
+    (FT_Size_InitFunc)       cff_size_init,
+    (FT_Size_DoneFunc)       cff_size_done,
+    (FT_Slot_InitFunc)       cff_slot_init,
+    (FT_Slot_DoneFunc)       cff_slot_done,
+
+    (FT_Size_ResetPointsFunc)cff_size_reset,
+    (FT_Size_ResetPixelsFunc)cff_size_reset,
+
+    (FT_Slot_LoadFunc)       Load_Glyph,
+
+    (FT_Face_GetKerningFunc) Get_Kerning,
+    (FT_Face_AttachFunc)     0,
+    (FT_Face_GetAdvancesFunc)0,
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffdrivr.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffdrivr.h                                                             */
+/*                                                                         */
+/*    High-level OpenType driver interface (specification).                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CFFDRIVER_H__
+#define __CFFDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_CALLBACK_TABLE
+  const FT_Driver_ClassRec  cff_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __CFFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cfferrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cfferrs.h                                                              */
+/*                                                                         */
+/*    CFF error codes (specification only).                                */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the CFF error enumeration constants.      */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __CFFERRS_H__
+#define __CFFERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  CFF_Err_
+#define FT_ERR_BASE    FT_Mod_Err_CFF
+
+
+#include FT_ERRORS_H
+
+#endif /* __CFFERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffgload.c
@@ -1,0 +1,2481 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffgload.c                                                             */
+/*                                                                         */
+/*    OpenType Glyph Loader (body).                                        */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_OUTLINE_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+#include "cffobjs.h"
+#include "cffload.h"
+#include "cffgload.h"
+
+#include "cfferrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cffgload
+
+
+  typedef enum  CFF_Operator_
+  {
+    cff_op_unknown = 0,
+
+    cff_op_rmoveto,
+    cff_op_hmoveto,
+    cff_op_vmoveto,
+
+    cff_op_rlineto,
+    cff_op_hlineto,
+    cff_op_vlineto,
+
+    cff_op_rrcurveto,
+    cff_op_hhcurveto,
+    cff_op_hvcurveto,
+    cff_op_rcurveline,
+    cff_op_rlinecurve,
+    cff_op_vhcurveto,
+    cff_op_vvcurveto,
+
+    cff_op_flex,
+    cff_op_hflex,
+    cff_op_hflex1,
+    cff_op_flex1,
+
+    cff_op_endchar,
+
+    cff_op_hstem,
+    cff_op_vstem,
+    cff_op_hstemhm,
+    cff_op_vstemhm,
+
+    cff_op_hintmask,
+    cff_op_cntrmask,
+    cff_op_dotsection,  /* deprecated, acts as no-op */
+
+    cff_op_abs,
+    cff_op_add,
+    cff_op_sub,
+    cff_op_div,
+    cff_op_neg,
+    cff_op_random,
+    cff_op_mul,
+    cff_op_sqrt,
+
+    cff_op_blend,
+
+    cff_op_drop,
+    cff_op_exch,
+    cff_op_index,
+    cff_op_roll,
+    cff_op_dup,
+
+    cff_op_put,
+    cff_op_get,
+    cff_op_store,
+    cff_op_load,
+
+    cff_op_and,
+    cff_op_or,
+    cff_op_not,
+    cff_op_eq,
+    cff_op_ifelse,
+
+    cff_op_callsubr,
+    cff_op_callgsubr,
+    cff_op_return,
+
+    /* do not remove */
+    cff_op_max
+
+  } CFF_Operator;
+
+
+#define CFF_COUNT_CHECK_WIDTH  0x80
+#define CFF_COUNT_EXACT        0x40
+#define CFF_COUNT_CLEAR_STACK  0x20
+
+
+  static const FT_Byte  cff_argument_counts[] =
+  {
+    0,  /* unknown */
+
+    2 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT, /* rmoveto */
+    1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
+    1 | CFF_COUNT_CHECK_WIDTH | CFF_COUNT_EXACT,
+
+    0 | CFF_COUNT_CLEAR_STACK, /* rlineto */
+    0 | CFF_COUNT_CLEAR_STACK,
+    0 | CFF_COUNT_CLEAR_STACK,
+
+    0 | CFF_COUNT_CLEAR_STACK, /* rrcurveto */
+    0 | CFF_COUNT_CLEAR_STACK,
+    0 | CFF_COUNT_CLEAR_STACK,
+    0 | CFF_COUNT_CLEAR_STACK,
+    0 | CFF_COUNT_CLEAR_STACK,
+    0 | CFF_COUNT_CLEAR_STACK,
+    0 | CFF_COUNT_CLEAR_STACK,
+
+    13, /* flex */
+    7,
+    9,
+    11,
+
+    0 | CFF_COUNT_CHECK_WIDTH, /* endchar */
+
+    2 | CFF_COUNT_CHECK_WIDTH, /* hstem */
+    2 | CFF_COUNT_CHECK_WIDTH,
+    2 | CFF_COUNT_CHECK_WIDTH,
+    2 | CFF_COUNT_CHECK_WIDTH,
+
+    0 | CFF_COUNT_CHECK_WIDTH, /* hintmask */
+    0 | CFF_COUNT_CHECK_WIDTH, /* cntrmask */
+    0, /* dotsection */
+
+    1, /* abs */
+    2,
+    2,
+    2,
+    1,
+    0,
+    2,
+    1,
+
+    1, /* blend */
+
+    1, /* drop */
+    2,
+    1,
+    2,
+    1,
+
+    2, /* put */
+    1,
+    4,
+    3,
+
+    2, /* and */
+    2,
+    1,
+    2,
+    4,
+
+    1, /* callsubr */
+    1,
+    0
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /**********                                                      *********/
+  /**********                                                      *********/
+  /**********             GENERIC CHARSTRING PARSING               *********/
+  /**********                                                      *********/
+  /**********                                                      *********/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cff_builder_init                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given glyph builder.                                 */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    builder :: A pointer to the glyph builder to initialize.           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face    :: The current face object.                                */
+  /*                                                                       */
+  /*    size    :: The current size object.                                */
+  /*                                                                       */
+  /*    glyph   :: The current glyph object.                               */
+  /*                                                                       */
+  static void
+  cff_builder_init( CFF_Builder*   builder,
+                    TT_Face        face,
+                    CFF_Size       size,
+                    CFF_GlyphSlot  glyph,
+                    FT_Bool        hinting )
+  {
+    builder->path_begun  = 0;
+    builder->load_points = 1;
+
+    builder->face   = face;
+    builder->glyph  = glyph;
+    builder->memory = face->root.memory;
+
+    if ( glyph )
+    {
+      FT_GlyphLoader  loader = glyph->root.internal->loader;
+
+
+      builder->loader  = loader;
+      builder->base    = &loader->base.outline;
+      builder->current = &loader->current.outline;
+      FT_GlyphLoader_Rewind( loader );
+
+      builder->hint_flags    = FT_FACE(face)->internal->hint_flags;
+      builder->hints_globals = 0;
+      builder->hints_funcs   = 0;
+
+      if ( hinting && size )
+      {
+        builder->hints_globals = size->internal;
+        builder->hints_funcs   = glyph->root.internal->glyph_hints;
+      }
+    }
+
+    if ( size )
+    {
+      builder->scale_x = size->metrics.x_scale;
+      builder->scale_y = size->metrics.y_scale;
+    }
+
+    builder->pos_x = 0;
+    builder->pos_y = 0;
+
+    builder->left_bearing.x = 0;
+    builder->left_bearing.y = 0;
+    builder->advance.x      = 0;
+    builder->advance.y      = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cff_builder_done                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a given glyph builder.  Its contents can still be used   */
+  /*    after the call, but the function saves important information       */
+  /*    within the corresponding glyph slot.                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    builder :: A pointer to the glyph builder to finalize.             */
+  /*                                                                       */
+  static void
+  cff_builder_done( CFF_Builder*  builder )
+  {
+    CFF_GlyphSlot  glyph = builder->glyph;
+
+
+    if ( glyph )
+      glyph->root.outline = *builder->base;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cff_compute_bias                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the bias value in dependence of the number of glyph       */
+  /*    subroutines.                                                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    num_subrs :: The number of glyph subroutines.                      */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The bias value.                                                    */
+  static FT_Int
+  cff_compute_bias( FT_UInt  num_subrs )
+  {
+    FT_Int  result;
+
+
+    if ( num_subrs < 1240 )
+      result = 107;
+    else if ( num_subrs < 33900U )
+      result = 1131;
+    else
+      result = 32768U;
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cff_decoder_init                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given glyph decoder.                                 */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    decoder :: A pointer to the glyph builder to initialize.           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face    :: The current face object.                                */
+  /*                                                                       */
+  /*    size    :: The current size object.                                */
+  /*                                                                       */
+  /*    slot    :: The current glyph object.                               */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  cff_decoder_init( CFF_Decoder*    decoder,
+                    TT_Face         face,
+                    CFF_Size        size,
+                    CFF_GlyphSlot   slot,
+                    FT_Bool         hinting,
+                    FT_Render_Mode  hint_mode )
+  {
+    CFF_Font  cff = (CFF_Font)face->extra.data;
+
+
+    /* clear everything */
+    FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
+
+    /* initialize builder */
+    cff_builder_init( &decoder->builder, face, size, slot, hinting );
+
+    /* initialize Type2 decoder */
+    decoder->num_globals  = cff->num_global_subrs;
+    decoder->globals      = cff->global_subrs;
+    decoder->globals_bias = cff_compute_bias( decoder->num_globals );
+    
+    decoder->hint_mode    = hint_mode;
+  }
+
+
+  /* this function is used to select the locals subrs array */
+  FT_LOCAL_DEF( void )
+  cff_decoder_prepare( CFF_Decoder*  decoder,
+                       FT_UInt       glyph_index )
+  {
+    CFF_Font     cff = (CFF_Font)decoder->builder.face->extra.data;
+    CFF_SubFont  sub = &cff->top_font;
+
+
+    /* manage CID fonts */
+    if ( cff->num_subfonts >= 1 )
+    {
+      FT_Byte  fd_index = cff_fd_select_get( &cff->fd_select, glyph_index );
+
+
+      sub = cff->subfonts[fd_index];
+    }
+
+    decoder->num_locals    = sub->num_local_subrs;
+    decoder->locals        = sub->local_subrs;
+    decoder->locals_bias   = cff_compute_bias( decoder->num_locals );
+
+    decoder->glyph_width   = sub->private_dict.default_width;
+    decoder->nominal_width = sub->private_dict.nominal_width;
+  }
+
+
+  /* check that there is enough room for `count' more points */
+  static FT_Error
+  check_points( CFF_Builder*  builder,
+                FT_Int        count )
+  {
+    return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
+  }
+
+
+  /* add a new point, do not check space */
+  static void
+  cff_builder_add_point( CFF_Builder*  builder,
+                         FT_Pos        x,
+                         FT_Pos        y,
+                         FT_Byte       flag )
+  {
+    FT_Outline*  outline = builder->current;
+
+
+    if ( builder->load_points )
+    {
+      FT_Vector*  point   = outline->points + outline->n_points;
+      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
+
+
+      point->x = x >> 16;
+      point->y = y >> 16;
+      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
+
+      builder->last = *point;
+    }
+
+    outline->n_points++;
+  }
+
+
+  /* check space for a new on-curve point, then add it */
+  static FT_Error
+  cff_builder_add_point1( CFF_Builder*  builder,
+                          FT_Pos        x,
+                          FT_Pos        y )
+  {
+    FT_Error  error;
+
+
+    error = check_points( builder, 1 );
+    if ( !error )
+      cff_builder_add_point( builder, x, y, 1 );
+
+    return error;
+  }
+
+
+  /* check room for a new contour, then add it */
+  static FT_Error
+  cff_builder_add_contour( CFF_Builder*  builder )
+  {
+    FT_Outline*  outline = builder->current;
+    FT_Error     error;
+
+
+    if ( !builder->load_points )
+    {
+      outline->n_contours++;
+      return CFF_Err_Ok;
+    }
+
+    error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
+    if ( !error )
+    {
+      if ( outline->n_contours > 0 )
+        outline->contours[outline->n_contours - 1] =
+          (short)( outline->n_points - 1 );
+
+      outline->n_contours++;
+    }
+
+    return error;
+  }
+
+
+  /* if a path was begun, add its first on-curve point */
+  static FT_Error
+  cff_builder_start_point( CFF_Builder*  builder,
+                           FT_Pos        x,
+                           FT_Pos        y )
+  {
+    FT_Error  error = 0;
+
+
+    /* test whether we are building a new contour */
+    if ( !builder->path_begun )
+    {
+      builder->path_begun = 1;
+      error = cff_builder_add_contour( builder );
+      if ( !error )
+        error = cff_builder_add_point1( builder, x, y );
+    }
+
+    return error;
+  }
+
+
+  /* close the current contour */
+  static void
+  cff_builder_close_contour( CFF_Builder*  builder )
+  {
+    FT_Outline*  outline = builder->current;
+
+
+    /* XXXX: We must not include the last point in the path if it */
+    /*       is located on the first point.                       */
+    if ( outline->n_points > 1 )
+    {
+      FT_Int      first   = 0;
+      FT_Vector*  p1      = outline->points + first;
+      FT_Vector*  p2      = outline->points + outline->n_points - 1;
+      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
+
+
+      if ( outline->n_contours > 1 )
+      {
+        first = outline->contours[outline->n_contours - 2] + 1;
+        p1    = outline->points + first;
+      }
+
+      /* `delete' last point only if it coincides with the first    */
+      /* point and if it is not a control point (which can happen). */
+      if ( p1->x == p2->x && p1->y == p2->y )
+        if ( *control == FT_CURVE_TAG_ON )
+          outline->n_points--;
+    }
+
+    if ( outline->n_contours > 0 )
+      outline->contours[outline->n_contours - 1] =
+        (short)( outline->n_points - 1 );
+  }
+
+
+  static FT_Int
+  cff_lookup_glyph_by_stdcharcode( CFF_Font  cff,
+                                   FT_Int    charcode )
+  {
+    FT_UInt    n;
+    FT_UShort  glyph_sid;
+
+
+    /* check range of standard char code */
+    if ( charcode < 0 || charcode > 255 )
+      return -1;
+
+    /* Get code to SID mapping from `cff_standard_encoding'. */
+    glyph_sid = cff_get_standard_encoding( (FT_UInt)charcode );
+
+    for ( n = 0; n < cff->num_glyphs; n++ )
+    {
+      if ( cff->charset.sids[n] == glyph_sid )
+        return n;
+    }
+
+    return -1;
+  }
+
+
+  static FT_Error
+  cff_get_glyph_data( TT_Face    face,
+                      FT_UInt    glyph_index,
+                      FT_Byte**  pointer,
+                      FT_ULong*  length )
+  {
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    /* For incremental fonts get the character data using the */
+    /* callback function.                                     */
+    if ( face->root.internal->incremental_interface )
+    {
+      FT_Data   data;
+      FT_Error  error =
+                  face->root.internal->incremental_interface->funcs->get_glyph_data(
+                    face->root.internal->incremental_interface->object,
+                    glyph_index, &data );
+
+
+      *pointer = (FT_Byte*)data.pointer;
+      *length = data.length;
+
+      return error;
+    }
+    else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+    {
+      CFF_Font  cff  = (CFF_Font)(face->extra.data);
+
+
+      return cff_index_access_element( &cff->charstrings_index, glyph_index,
+                                       pointer, length );
+    }
+  }
+
+
+  static void
+  cff_free_glyph_data( TT_Face    face,
+                       FT_Byte**  pointer,
+                       FT_ULong   length )
+  {
+#ifndef FT_CONFIG_OPTION_INCREMENTAL
+    FT_UNUSED( length );
+#endif
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    /* For incremental fonts get the character data using the */
+    /* callback function.                                     */
+    if ( face->root.internal->incremental_interface )
+    {
+      FT_Data data;
+
+
+      data.pointer = *pointer;
+      data.length  = length;
+
+      face->root.internal->incremental_interface->funcs->free_glyph_data(
+        face->root.internal->incremental_interface->object,&data );
+    }
+    else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+    {
+      CFF_Font  cff = (CFF_Font)(face->extra.data);
+
+
+      cff_index_forget_element( &cff->charstrings_index, pointer );
+    }
+  }
+
+
+  static FT_Error
+  cff_operator_seac( CFF_Decoder*  decoder,
+                     FT_Pos        adx,
+                     FT_Pos        ady,
+                     FT_Int        bchar,
+                     FT_Int        achar )
+  {
+    FT_Error     error;
+    FT_Int       bchar_index, achar_index, n_base_points;
+    FT_Outline*  base = decoder->builder.base;
+    TT_Face      face = decoder->builder.face;
+    FT_Vector    left_bearing, advance;
+    FT_Byte*     charstring;
+    FT_ULong     charstring_len;
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    /* Incremental fonts don't necessarily have valid charsets.        */
+    /* They use the character code, not the glyph index, in this case. */
+    if ( face->root.internal->incremental_interface )
+    {
+      bchar_index = bchar;
+      achar_index = achar;
+    }
+    else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+    {
+      CFF_Font cff = (CFF_Font)(face->extra.data);
+
+
+      bchar_index = cff_lookup_glyph_by_stdcharcode( cff, bchar );
+      achar_index = cff_lookup_glyph_by_stdcharcode( cff, achar );
+    }
+
+    if ( bchar_index < 0 || achar_index < 0 )
+    {
+      FT_ERROR(( "cff_operator_seac:" ));
+      FT_ERROR(( " invalid seac character code arguments\n" ));
+      return CFF_Err_Syntax_Error;
+    }
+
+    /* If we are trying to load a composite glyph, do not load the */
+    /* accent character and return the array of subglyphs.         */
+    if ( decoder->builder.no_recurse )
+    {
+      FT_GlyphSlot    glyph  = (FT_GlyphSlot)decoder->builder.glyph;
+      FT_GlyphLoader  loader = glyph->internal->loader;
+      FT_SubGlyph     subg;
+
+
+      /* reallocate subglyph array if necessary */
+      error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
+      if ( error )
+        goto Exit;
+
+      subg = loader->current.subglyphs;
+
+      /* subglyph 0 = base character */
+      subg->index = bchar_index;
+      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
+                    FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+      subg->arg1  = 0;
+      subg->arg2  = 0;
+      subg++;
+
+      /* subglyph 1 = accent character */
+      subg->index = achar_index;
+      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+      subg->arg1  = (FT_Int)adx;
+      subg->arg2  = (FT_Int)ady;
+
+      /* set up remaining glyph fields */
+      glyph->num_subglyphs = 2;
+      glyph->subglyphs     = loader->base.subglyphs;
+      glyph->format        = FT_GLYPH_FORMAT_COMPOSITE;
+
+      loader->current.num_subglyphs = 2;
+    }
+
+    /* First load `bchar' in builder */
+    error = cff_get_glyph_data( face, bchar_index,
+                                &charstring, &charstring_len );
+    if ( !error )
+    {
+      error = cff_decoder_parse_charstrings( decoder, charstring,
+                                             charstring_len );
+
+      if ( error )
+        goto Exit;
+
+      cff_free_glyph_data( face, &charstring, charstring_len );
+    }
+
+    n_base_points = base->n_points;
+
+    /* Save the left bearing and width of the base character */
+    /* as they will be erased by the next load.              */
+
+    left_bearing = decoder->builder.left_bearing;
+    advance      = decoder->builder.advance;
+
+    decoder->builder.left_bearing.x = 0;
+    decoder->builder.left_bearing.y = 0;
+
+    /* Now load `achar' on top of the base outline. */
+    error = cff_get_glyph_data( face, achar_index,
+                                &charstring, &charstring_len );
+    if ( !error )
+    {
+      error = cff_decoder_parse_charstrings( decoder, charstring,
+                                             charstring_len );
+
+      if ( error )
+        goto Exit;
+
+      cff_free_glyph_data( face, &charstring, charstring_len );
+    }
+
+    /* Restore the left side bearing and advance width */
+    /* of the base character.                          */
+    decoder->builder.left_bearing = left_bearing;
+    decoder->builder.advance      = advance;
+
+    /* Finally, move the accent. */
+    if ( decoder->builder.load_points )
+    {
+      FT_Outline  dummy;
+
+
+      dummy.n_points = (short)( base->n_points - n_base_points );
+      dummy.points   = base->points   + n_base_points;
+
+      FT_Outline_Translate( &dummy, adx, ady );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cff_decoder_parse_charstrings                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Parses a given Type 2 charstrings program.                         */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    decoder         :: The current Type 1 decoder.                     */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charstring_base :: The base of the charstring stream.              */
+  /*                                                                       */
+  /*    charstring_len  :: The length in bytes of the charstring stream.   */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  cff_decoder_parse_charstrings( CFF_Decoder*  decoder,
+                                 FT_Byte*      charstring_base,
+                                 FT_ULong      charstring_len )
+  {
+    FT_Error           error;
+    CFF_Decoder_Zone*  zone;
+    FT_Byte*           ip;
+    FT_Byte*           limit;
+    CFF_Builder*       builder = &decoder->builder;
+    FT_Pos             x, y;
+    FT_Fixed           seed;
+    FT_Fixed*          stack;
+
+    T2_Hints_Funcs     hinter;
+
+
+    /* set default width */
+    decoder->num_hints  = 0;
+    decoder->read_width = 1;
+
+    /* compute random seed from stack address of parameter */
+    seed = (FT_Fixed)(char*)&seed           ^
+           (FT_Fixed)(char*)&decoder        ^
+           (FT_Fixed)(char*)&charstring_base;
+    seed = ( seed ^ ( seed >> 10 ) ^ ( seed >> 20 ) ) & 0xFFFF;
+    if ( seed == 0 )
+      seed = 0x7384;
+
+    /* initialize the decoder */
+    decoder->top  = decoder->stack;
+    decoder->zone = decoder->zones;
+    zone          = decoder->zones;
+    stack         = decoder->top;
+
+    hinter = (T2_Hints_Funcs) builder->hints_funcs;
+
+    builder->path_begun = 0;
+
+    zone->base           = charstring_base;
+    limit = zone->limit  = charstring_base + charstring_len;
+    ip    = zone->cursor = zone->base;
+
+    error = CFF_Err_Ok;
+
+    x = builder->pos_x;
+    y = builder->pos_y;
+
+    /* begin hints recording session, if any */
+    if ( hinter )
+      hinter->open( hinter->hints );
+
+    /* now, execute loop */
+    while ( ip < limit )
+    {
+      CFF_Operator  op;
+      FT_Byte       v;
+
+
+      /********************************************************************/
+      /*                                                                  */
+      /* Decode operator or operand                                       */
+      /*                                                                  */
+      v = *ip++;
+      if ( v >= 32 || v == 28 )
+      {
+        FT_Int    shift = 16;
+        FT_Int32  val;
+
+
+        /* this is an operand, push it on the stack */
+        if ( v == 28 )
+        {
+          if ( ip + 1 >= limit )
+            goto Syntax_Error;
+          val = (FT_Short)( ( (FT_Short)ip[0] << 8 ) | ip[1] );
+          ip += 2;
+        }
+        else if ( v < 247 )
+          val = (FT_Long)v - 139;
+        else if ( v < 251 )
+        {
+          if ( ip >= limit )
+            goto Syntax_Error;
+          val = ( (FT_Long)v - 247 ) * 256 + *ip++ + 108;
+        }
+        else if ( v < 255 )
+        {
+          if ( ip >= limit )
+            goto Syntax_Error;
+          val = -( (FT_Long)v - 251 ) * 256 - *ip++ - 108;
+        }
+        else
+        {
+          if ( ip + 3 >= limit )
+            goto Syntax_Error;
+          val = ( (FT_Int32)ip[0] << 24 ) |
+                ( (FT_Int32)ip[1] << 16 ) |
+                ( (FT_Int32)ip[2] <<  8 ) |
+                            ip[3];
+          ip    += 4;
+          shift  = 0;
+        }
+        if ( decoder->top - stack >= CFF_MAX_OPERANDS )
+          goto Stack_Overflow;
+
+        val           <<= shift;
+        *decoder->top++ = val;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+        if ( !( val & 0xFFFF ) )
+          FT_TRACE4(( " %d", (FT_Int32)( val >> 16 ) ));
+        else
+          FT_TRACE4(( " %.2f", val / 65536.0 ));
+#endif
+
+      }
+      else
+      {
+        FT_Fixed*  args     = decoder->top;
+        FT_Int     num_args = (FT_Int)( args - decoder->stack );
+        FT_Int     req_args;
+
+
+        /* find operator */
+        op = cff_op_unknown;
+
+        switch ( v )
+        {
+        case 1:
+          op = cff_op_hstem;
+          break;
+        case 3:
+          op = cff_op_vstem;
+          break;
+        case 4:
+          op = cff_op_vmoveto;
+          break;
+        case 5:
+          op = cff_op_rlineto;
+          break;
+        case 6:
+          op = cff_op_hlineto;
+          break;
+        case 7:
+          op = cff_op_vlineto;
+          break;
+        case 8:
+          op = cff_op_rrcurveto;
+          break;
+        case 10:
+          op = cff_op_callsubr;
+          break;
+        case 11:
+          op = cff_op_return;
+          break;
+        case 12:
+          {
+            if ( ip >= limit )
+              goto Syntax_Error;
+            v = *ip++;
+
+            switch ( v )
+            {
+            case 0:
+              op = cff_op_dotsection;
+              break;
+            case 3:
+              op = cff_op_and;
+              break;
+            case 4:
+              op = cff_op_or;
+              break;
+            case 5:
+              op = cff_op_not;
+              break;
+            case 8:
+              op = cff_op_store;
+              break;
+            case 9:
+              op = cff_op_abs;
+              break;
+            case 10:
+              op = cff_op_add;
+              break;
+            case 11:
+              op = cff_op_sub;
+              break;
+            case 12:
+              op = cff_op_div;
+              break;
+            case 13:
+              op = cff_op_load;
+              break;
+            case 14:
+              op = cff_op_neg;
+              break;
+            case 15:
+              op = cff_op_eq;
+              break;
+            case 18:
+              op = cff_op_drop;
+              break;
+            case 20:
+              op = cff_op_put;
+              break;
+            case 21:
+              op = cff_op_get;
+              break;
+            case 22:
+              op = cff_op_ifelse;
+              break;
+            case 23:
+              op = cff_op_random;
+              break;
+            case 24:
+              op = cff_op_mul;
+              break;
+            case 26:
+              op = cff_op_sqrt;
+              break;
+            case 27:
+              op = cff_op_dup;
+              break;
+            case 28:
+              op = cff_op_exch;
+              break;
+            case 29:
+              op = cff_op_index;
+              break;
+            case 30:
+              op = cff_op_roll;
+              break;
+            case 34:
+              op = cff_op_hflex;
+              break;
+            case 35:
+              op = cff_op_flex;
+              break;
+            case 36:
+              op = cff_op_hflex1;
+              break;
+            case 37:
+              op = cff_op_flex1;
+              break;
+            default:
+              /* decrement ip for syntax error message */
+              ip--;
+            }
+          }
+          break;
+        case 14:
+          op = cff_op_endchar;
+          break;
+        case 16:
+          op = cff_op_blend;
+          break;
+        case 18:
+          op = cff_op_hstemhm;
+          break;
+        case 19:
+          op = cff_op_hintmask;
+          break;
+        case 20:
+          op = cff_op_cntrmask;
+          break;
+        case 21:
+          op = cff_op_rmoveto;
+          break;
+        case 22:
+          op = cff_op_hmoveto;
+          break;
+        case 23:
+          op = cff_op_vstemhm;
+          break;
+        case 24:
+          op = cff_op_rcurveline;
+          break;
+        case 25:
+          op = cff_op_rlinecurve;
+          break;
+        case 26:
+          op = cff_op_vvcurveto;
+          break;
+        case 27:
+          op = cff_op_hhcurveto;
+          break;
+        case 29:
+          op = cff_op_callgsubr;
+          break;
+        case 30:
+          op = cff_op_vhcurveto;
+          break;
+        case 31:
+          op = cff_op_hvcurveto;
+          break;
+        default:
+          ;
+        }
+        if ( op == cff_op_unknown )
+          goto Syntax_Error;
+
+        /* check arguments */
+        req_args = cff_argument_counts[op];
+        if ( req_args & CFF_COUNT_CHECK_WIDTH )
+        {
+          args = stack;
+
+          if ( num_args > 0 && decoder->read_width )
+          {
+            /* If `nominal_width' is non-zero, the number is really a      */
+            /* difference against `nominal_width'.  Else, the number here  */
+            /* is truly a width, not a difference against `nominal_width'. */
+            /* If the font does not set `nominal_width', then              */
+            /* `nominal_width' defaults to zero, and so we can set         */
+            /* `glyph_width' to `nominal_width' plus number on the stack   */
+            /* -- for either case.                                         */
+
+            FT_Int set_width_ok;
+
+
+            switch ( op )
+            {
+            case cff_op_hmoveto:
+            case cff_op_vmoveto:
+              set_width_ok = num_args & 2;
+              break;
+
+            case cff_op_hstem:
+            case cff_op_vstem:
+            case cff_op_hstemhm:
+            case cff_op_vstemhm:
+            case cff_op_rmoveto:
+              set_width_ok = num_args & 1;
+              break;
+
+            case cff_op_endchar:
+              /* If there is a width specified for endchar, we either have */
+              /* 1 argument or 5 arguments.  We like to argue.             */
+              set_width_ok = ( ( num_args == 5 ) || ( num_args == 1 ) );
+              break;
+
+            default:
+              set_width_ok = 0;
+              break;
+            }
+
+            if ( set_width_ok )
+            {
+              decoder->glyph_width = decoder->nominal_width +
+                                       ( stack[0] >> 16 );
+
+              /* Consumed an argument. */
+              num_args--;
+              args++;
+            }
+          }
+
+          decoder->read_width = 0;
+          req_args            = 0;
+        }
+
+        req_args &= 15;
+        if ( num_args < req_args )
+          goto Stack_Underflow;
+        args     -= req_args;
+        num_args -= req_args;
+
+        switch ( op )
+        {
+        case cff_op_hstem:
+        case cff_op_vstem:
+        case cff_op_hstemhm:
+        case cff_op_vstemhm:
+          /* the number of arguments is always even here */
+          FT_TRACE4(( op == cff_op_hstem   ? " hstem"   :
+                    ( op == cff_op_vstem   ? " vstem"   :
+                    ( op == cff_op_hstemhm ? " hstemhm" : " vstemhm" ) ) ));
+
+          if ( hinter )
+            hinter->stems( hinter->hints,
+                           ( op == cff_op_hstem || op == cff_op_hstemhm ),
+                           num_args / 2,
+                           args );
+
+          decoder->num_hints += num_args / 2;
+          args = stack;
+          break;
+
+        case cff_op_hintmask:
+        case cff_op_cntrmask:
+          FT_TRACE4(( op == cff_op_hintmask ? " hintmask" : " cntrmask" ));
+
+          /* implement vstem when needed --                        */
+          /* the specification doesn't say it, but this also works */
+          /* with the 'cntrmask' operator                          */
+          /*                                                       */
+          if ( num_args > 0 )
+          {
+            if ( hinter )
+              hinter->stems( hinter->hints,
+                             0,
+                             num_args / 2,
+                             args );
+
+            decoder->num_hints += num_args / 2;
+          }
+
+          if ( hinter )
+          {
+            if ( op == cff_op_hintmask )
+              hinter->hintmask( hinter->hints,
+                                builder->current->n_points,
+                                decoder->num_hints,
+                                ip );
+            else
+              hinter->counter( hinter->hints,
+                               decoder->num_hints,
+                               ip );
+          }
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+          {
+            FT_UInt maskbyte;
+
+
+            FT_TRACE4(( " " ));
+
+            for ( maskbyte = 0;
+                  maskbyte < (FT_UInt)(( decoder->num_hints + 7 ) >> 3);
+                  maskbyte++, ip++ )
+              FT_TRACE4(( "%02X", *ip ));
+          }
+#else
+          ip += ( decoder->num_hints + 7 ) >> 3;
+#endif
+          if ( ip >= limit )
+            goto Syntax_Error;
+          args = stack;
+          break;
+
+        case cff_op_rmoveto:
+          FT_TRACE4(( " rmoveto" ));
+
+          cff_builder_close_contour( builder );
+          builder->path_begun = 0;
+          x   += args[0];
+          y   += args[1];
+          args = stack;
+          break;
+
+        case cff_op_vmoveto:
+          FT_TRACE4(( " vmoveto" ));
+
+          cff_builder_close_contour( builder );
+          builder->path_begun = 0;
+          y   += args[0];
+          args = stack;
+          break;
+
+        case cff_op_hmoveto:
+          FT_TRACE4(( " hmoveto" ));
+
+          cff_builder_close_contour( builder );
+          builder->path_begun = 0;
+          x   += args[0];
+          args = stack;
+          break;
+
+        case cff_op_rlineto:
+          FT_TRACE4(( " rlineto" ));
+
+          if ( cff_builder_start_point ( builder, x, y ) ||
+               check_points( builder, num_args / 2 )     )
+            goto Memory_Error;
+
+          if ( num_args < 2 || num_args & 1 )
+            goto Stack_Underflow;
+
+          args = stack;
+          while ( args < decoder->top )
+          {
+            x += args[0];
+            y += args[1];
+            cff_builder_add_point( builder, x, y, 1 );
+            args += 2;
+          }
+          args = stack;
+          break;
+
+        case cff_op_hlineto:
+        case cff_op_vlineto:
+          {
+            FT_Int  phase = ( op == cff_op_hlineto );
+
+
+            FT_TRACE4(( op == cff_op_hlineto ? " hlineto"
+                                             : " vlineto" ));
+
+            if ( cff_builder_start_point ( builder, x, y )     ||
+                 check_points( builder, num_args ) )
+              goto Memory_Error;
+
+            args = stack;
+            while (args < decoder->top )
+            {
+              if ( phase )
+                x += args[0];
+              else
+                y += args[0];
+
+              if ( cff_builder_add_point1( builder, x, y ) )
+                goto Memory_Error;
+
+              args++;
+              phase ^= 1;
+            }
+            args = stack;
+          }
+          break;
+
+        case cff_op_rrcurveto:
+          FT_TRACE4(( " rrcurveto" ));
+
+          /* check number of arguments; must be a multiple of 6 */
+          if ( num_args % 6 != 0 )
+            goto Stack_Underflow;
+
+          if ( cff_builder_start_point ( builder, x, y ) ||
+               check_points( builder, num_args / 2 )     )
+            goto Memory_Error;
+
+          args = stack;
+          while ( args < decoder->top )
+          {
+            x += args[0];
+            y += args[1];
+            cff_builder_add_point( builder, x, y, 0 );
+            x += args[2];
+            y += args[3];
+            cff_builder_add_point( builder, x, y, 0 );
+            x += args[4];
+            y += args[5];
+            cff_builder_add_point( builder, x, y, 1 );
+            args += 6;
+          }
+          args = stack;
+          break;
+
+        case cff_op_vvcurveto:
+          FT_TRACE4(( " vvcurveto" ));
+
+          if ( cff_builder_start_point ( builder, x, y ) )
+            goto Memory_Error;
+
+          args = stack;
+          if ( num_args & 1 )
+          {
+            x += args[0];
+            args++;
+            num_args--;
+          }
+
+          if ( num_args % 4 != 0 )
+            goto Stack_Underflow;
+
+          if ( check_points( builder, 3 * ( num_args / 4 ) ) )
+            goto Memory_Error;
+
+          while ( args < decoder->top )
+          {
+            y += args[0];
+            cff_builder_add_point( builder, x, y, 0 );
+            x += args[1];
+            y += args[2];
+            cff_builder_add_point( builder, x, y, 0 );
+            y += args[3];
+            cff_builder_add_point( builder, x, y, 1 );
+            args += 4;
+          }
+          args = stack;
+          break;
+
+        case cff_op_hhcurveto:
+          FT_TRACE4(( " hhcurveto" ));
+
+          if ( cff_builder_start_point ( builder, x, y ) )
+            goto Memory_Error;
+
+          args = stack;
+          if ( num_args & 1 )
+          {
+            y += args[0];
+            args++;
+            num_args--;
+          }
+
+          if ( num_args % 4 != 0 )
+            goto Stack_Underflow;
+
+          if ( check_points( builder, 3 * ( num_args / 4 ) ) )
+            goto Memory_Error;
+
+          while ( args < decoder->top )
+          {
+            x += args[0];
+            cff_builder_add_point( builder, x, y, 0 );
+            x += args[1];
+            y += args[2];
+            cff_builder_add_point( builder, x, y, 0 );
+            x += args[3];
+            cff_builder_add_point( builder, x, y, 1 );
+            args += 4;
+          }
+          args = stack;
+          break;
+
+        case cff_op_vhcurveto:
+        case cff_op_hvcurveto:
+          {
+            FT_Int  phase;
+
+
+            FT_TRACE4(( op == cff_op_vhcurveto ? " vhcurveto"
+                                               : " hvcurveto" ));
+
+            if ( cff_builder_start_point ( builder, x, y ) )
+              goto Memory_Error;
+
+            args = stack;
+            if (num_args < 4 || ( num_args % 4 ) > 1 )
+              goto Stack_Underflow;
+
+            if ( check_points( builder, ( num_args / 4 ) * 3 ) )
+              goto Stack_Underflow;
+
+            phase = ( op == cff_op_hvcurveto );
+
+            while ( num_args >= 4 )
+            {
+              num_args -= 4;
+              if ( phase )
+              {
+                x += args[0];
+                cff_builder_add_point( builder, x, y, 0 );
+                x += args[1];
+                y += args[2];
+                cff_builder_add_point( builder, x, y, 0 );
+                y += args[3];
+                if ( num_args == 1 )
+                  x += args[4];
+                cff_builder_add_point( builder, x, y, 1 );
+              }
+              else
+              {
+                y += args[0];
+                cff_builder_add_point( builder, x, y, 0 );
+                x += args[1];
+                y += args[2];
+                cff_builder_add_point( builder, x, y, 0 );
+                x += args[3];
+                if ( num_args == 1 )
+                  y += args[4];
+                cff_builder_add_point( builder, x, y, 1 );
+              }
+              args  += 4;
+              phase ^= 1;
+            }
+            args = stack;
+          }
+          break;
+
+        case cff_op_rlinecurve:
+          {
+            FT_Int  num_lines = ( num_args - 6 ) / 2;
+
+
+            FT_TRACE4(( " rlinecurve" ));
+
+            if ( num_args < 8 || ( num_args - 6 ) & 1 )
+              goto Stack_Underflow;
+
+            if ( cff_builder_start_point( builder, x, y ) ||
+                 check_points( builder, num_lines + 3 )   )
+              goto Memory_Error;
+
+            args = stack;
+
+            /* first, add the line segments */
+            while ( num_lines > 0 )
+            {
+              x += args[0];
+              y += args[1];
+              cff_builder_add_point( builder, x, y, 1 );
+              args += 2;
+              num_lines--;
+            }
+
+            /* then the curve */
+            x += args[0];
+            y += args[1];
+            cff_builder_add_point( builder, x, y, 0 );
+            x += args[2];
+            y += args[3];
+            cff_builder_add_point( builder, x, y, 0 );
+            x += args[4];
+            y += args[5];
+            cff_builder_add_point( builder, x, y, 1 );
+            args = stack;
+          }
+          break;
+
+        case cff_op_rcurveline:
+          {
+            FT_Int  num_curves = ( num_args - 2 ) / 6;
+
+
+            FT_TRACE4(( " rcurveline" ));
+
+            if ( num_args < 8 || ( num_args - 2 ) % 6 )
+              goto Stack_Underflow;
+
+            if ( cff_builder_start_point ( builder, x, y ) ||
+                 check_points( builder, num_curves*3 + 2 ) )
+              goto Memory_Error;
+
+            args = stack;
+
+            /* first, add the curves */
+            while ( num_curves > 0 )
+            {
+              x += args[0];
+              y += args[1];
+              cff_builder_add_point( builder, x, y, 0 );
+              x += args[2];
+              y += args[3];
+              cff_builder_add_point( builder, x, y, 0 );
+              x += args[4];
+              y += args[5];
+              cff_builder_add_point( builder, x, y, 1 );
+              args += 6;
+              num_curves--;
+            }
+
+            /* then the final line */
+            x += args[0];
+            y += args[1];
+            cff_builder_add_point( builder, x, y, 1 );
+            args = stack;
+          }
+          break;
+
+        case cff_op_hflex1:
+          {
+            FT_Pos start_y;
+
+
+            FT_TRACE4(( " hflex1" ));
+
+            args = stack;
+
+            /* adding five more points; 4 control points, 1 on-curve point */
+            /* make sure we have enough space for the start point if it    */
+            /* needs to be added..                                         */
+            if ( cff_builder_start_point( builder, x, y ) ||
+                 check_points( builder, 6 )               )
+              goto Memory_Error;
+
+            /* Record the starting point's y postion for later use */
+            start_y = y;
+
+            /* first control point */
+            x += args[0];
+            y += args[1];
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* second control point */
+            x += args[2];
+            y += args[3];
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* join point; on curve, with y-value the same as the last */
+            /* control point's y-value                                 */
+            x += args[4];
+            cff_builder_add_point( builder, x, y, 1 );
+
+            /* third control point, with y-value the same as the join */
+            /* point's y-value                                        */
+            x += args[5];
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* fourth control point */
+            x += args[6];
+            y += args[7];
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* ending point, with y-value the same as the start   */
+            x += args[8];
+            y  = start_y;
+            cff_builder_add_point( builder, x, y, 1 );
+
+            args = stack;
+            break;
+          }
+
+        case cff_op_hflex:
+          {
+            FT_Pos start_y;
+
+
+            FT_TRACE4(( " hflex" ));
+
+            args = stack;
+
+            /* adding six more points; 4 control points, 2 on-curve points */
+            if ( cff_builder_start_point( builder, x, y ) ||
+                 check_points ( builder, 6 )              )
+              goto Memory_Error;
+
+            /* record the starting point's y-position for later use */
+            start_y = y;
+
+            /* first control point */
+            x += args[0];
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* second control point */
+            x += args[1];
+            y += args[2];
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* join point; on curve, with y-value the same as the last */
+            /* control point's y-value                                 */
+            x += args[3];
+            cff_builder_add_point( builder, x, y, 1 );
+
+            /* third control point, with y-value the same as the join */
+            /* point's y-value                                        */
+            x += args[4];
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* fourth control point */
+            x += args[5];
+            y  = start_y;
+            cff_builder_add_point( builder, x, y, 0 );
+
+            /* ending point, with y-value the same as the start point's */
+            /* y-value -- we don't add this point, though               */
+            x += args[6];
+            cff_builder_add_point( builder, x, y, 1 );
+
+            args = stack;
+            break;
+          }
+
+        case cff_op_flex1:
+          {
+            FT_Pos  start_x, start_y; /* record start x, y values for alter */
+                                      /* use                                */
+            FT_Int  dx = 0, dy = 0;   /* used in horizontal/vertical        */
+                                      /* algorithm below                    */
+            FT_Int  horizontal, count;
+
+
+            FT_TRACE4(( " flex1" ));
+
+            /* adding six more points; 4 control points, 2 on-curve points */
+            if ( cff_builder_start_point( builder, x, y ) ||
+                 check_points( builder, 6 )               )
+               goto Memory_Error;
+
+            /* record the starting point's x, y postion for later use */
+            start_x = x;
+            start_y = y;
+
+            /* XXX: figure out whether this is supposed to be a horizontal */
+            /*      or vertical flex; the Type 2 specification is vague... */
+
+            args = stack;
+
+            /* grab up to the last argument */
+            for ( count = 5; count > 0; count-- )
+            {
+              dx += (FT_Int)args[0];
+              dy += (FT_Int)args[1];
+              args += 2;
+            }
+
+            /* rewind */
+            args = stack;
+
+            if ( dx < 0 ) dx = -dx;
+            if ( dy < 0 ) dy = -dy;
+
+            /* strange test, but here it is... */
+            horizontal = ( dx > dy );
+
+            for ( count = 5; count > 0; count-- )
+            {
+              x += args[0];
+              y += args[1];
+              cff_builder_add_point( builder, x, y, (FT_Bool)( count == 3 ) );
+              args += 2;
+            }
+
+            /* is last operand an x- or y-delta? */
+            if ( horizontal )
+            {
+              x += args[0];
+              y  = start_y;
+            }
+            else
+            {
+              x  = start_x;
+              y += args[0];
+            }
+
+            cff_builder_add_point( builder, x, y, 1 );
+
+            args = stack;
+            break;
+           }
+
+        case cff_op_flex:
+          {
+            FT_UInt  count;
+
+
+            FT_TRACE4(( " flex" ));
+
+            if ( cff_builder_start_point( builder, x, y ) ||
+                 check_points( builder, 6 )               )
+              goto Memory_Error;
+
+            args = stack;
+            for ( count = 6; count > 0; count-- )
+            {
+              x += args[0];
+              y += args[1];
+              cff_builder_add_point( builder, x, y,
+                                     (FT_Bool)( count == 3 || count == 0 ) );
+              args += 2;
+            }
+
+            args = stack;
+          }
+          break;
+
+        case cff_op_endchar:
+          FT_TRACE4(( " endchar" ));
+
+          /* We are going to emulate the seac operator. */
+          if ( num_args == 4 )
+          {
+            error = cff_operator_seac( decoder,
+                                       args[0] >> 16,
+                                       args[1] >> 16,
+                                       (FT_Int)( args[2] >> 16 ),
+                                       (FT_Int)( args[3] >> 16 ) );
+            args += 4;
+          }
+
+          if ( !error )
+            error = CFF_Err_Ok;
+
+          cff_builder_close_contour( builder );
+
+          /* close hints recording session */
+          if ( hinter )
+          {
+            if (hinter->close( hinter->hints, builder->current->n_points ) )
+              goto Syntax_Error;
+
+            /* apply hints to the loaded glyph outline now */
+            hinter->apply( hinter->hints,
+                           builder->current,
+                           (PSH_Globals)builder->hints_globals,
+                           builder->hint_flags );
+          }
+
+          /* add current outline to the glyph slot */
+          FT_GlyphLoader_Add( builder->loader );
+
+          /* return now! */
+          FT_TRACE4(( "\n\n" ));
+          return error;
+
+        case cff_op_abs:
+          FT_TRACE4(( " abs" ));
+
+          if ( args[0] < 0 )
+            args[0] = -args[0];
+          args++;
+          break;
+
+        case cff_op_add:
+          FT_TRACE4(( " add" ));
+
+          args[0] += args[1];
+          args++;
+          break;
+
+        case cff_op_sub:
+          FT_TRACE4(( " sub" ));
+
+          args[0] -= args[1];
+          args++;
+          break;
+
+        case cff_op_div:
+          FT_TRACE4(( " div" ));
+
+          args[0] = FT_DivFix( args[0], args[1] );
+          args++;
+          break;
+
+        case cff_op_neg:
+          FT_TRACE4(( " neg" ));
+
+          args[0] = -args[0];
+          args++;
+          break;
+
+        case cff_op_random:
+          {
+            FT_Fixed  Rand;
+
+
+            FT_TRACE4(( " rand" ));
+
+            Rand = seed;
+            if ( Rand >= 0x8000 )
+              Rand++;
+
+            args[0] = Rand;
+            seed    = FT_MulFix( seed, 0x10000L - seed );
+            if ( seed == 0 )
+              seed += 0x2873;
+            args++;
+          }
+          break;
+
+        case cff_op_mul:
+          FT_TRACE4(( " mul" ));
+
+          args[0] = FT_MulFix( args[0], args[1] );
+          args++;
+          break;
+
+        case cff_op_sqrt:
+          FT_TRACE4(( " sqrt" ));
+
+          if ( args[0] > 0 )
+          {
+            FT_Int    count = 9;
+            FT_Fixed  root  = args[0];
+            FT_Fixed  new_root;
+
+
+            for (;;)
+            {
+              new_root = ( root + FT_DivFix( args[0], root ) + 1 ) >> 1;
+              if ( new_root == root || count <= 0 )
+                break;
+              root = new_root;
+            }
+            args[0] = new_root;
+          }
+          else
+            args[0] = 0;
+          args++;
+          break;
+
+        case cff_op_drop:
+          /* nothing */
+          FT_TRACE4(( " drop" ));
+
+          break;
+
+        case cff_op_exch:
+          {
+            FT_Fixed  tmp;
+
+
+            FT_TRACE4(( " exch" ));
+
+            tmp     = args[0];
+            args[0] = args[1];
+            args[1] = tmp;
+            args   += 2;
+          }
+          break;
+
+        case cff_op_index:
+          {
+            FT_Int  idx = (FT_Int)( args[0] >> 16 );
+
+
+            FT_TRACE4(( " index" ));
+
+            if ( idx < 0 )
+              idx = 0;
+            else if ( idx > num_args - 2 )
+              idx = num_args - 2;
+            args[0] = args[-( idx + 1 )];
+            args++;
+          }
+          break;
+
+        case cff_op_roll:
+          {
+            FT_Int  count = (FT_Int)( args[0] >> 16 );
+            FT_Int  idx   = (FT_Int)( args[1] >> 16 );
+
+
+            FT_TRACE4(( " roll" ));
+
+            if ( count <= 0 )
+              count = 1;
+
+            args -= count;
+            if ( args < stack )
+              goto Stack_Underflow;
+
+            if ( idx >= 0 )
+            {
+              while ( idx > 0 )
+              {
+                FT_Fixed  tmp = args[count - 1];
+                FT_Int    i;
+
+
+                for ( i = count - 2; i >= 0; i-- )
+                  args[i + 1] = args[i];
+                args[0] = tmp;
+                idx--;
+              }
+            }
+            else
+            {
+              while ( idx < 0 )
+              {
+                FT_Fixed  tmp = args[0];
+                FT_Int    i;
+
+
+                for ( i = 0; i < count - 1; i++ )
+                  args[i] = args[i + 1];
+                args[count - 1] = tmp;
+                idx++;
+              }
+            }
+            args += count;
+          }
+          break;
+
+        case cff_op_dup:
+          FT_TRACE4(( " dup" ));
+
+          args[1] = args[0];
+          args++;
+          break;
+
+        case cff_op_put:
+          {
+            FT_Fixed  val = args[0];
+            FT_Int    idx = (FT_Int)( args[1] >> 16 );
+
+
+            FT_TRACE4(( " put" ));
+
+            if ( idx >= 0 && idx < decoder->len_buildchar )
+              decoder->buildchar[idx] = val;
+          }
+          break;
+
+        case cff_op_get:
+          {
+            FT_Int    idx = (FT_Int)( args[0] >> 16 );
+            FT_Fixed  val = 0;
+
+
+            FT_TRACE4(( " get" ));
+
+            if ( idx >= 0 && idx < decoder->len_buildchar )
+              val = decoder->buildchar[idx];
+
+            args[0] = val;
+            args++;
+          }
+          break;
+
+        case cff_op_store:
+          FT_TRACE4(( " store "));
+
+          goto Unimplemented;
+
+        case cff_op_load:
+          FT_TRACE4(( " load" ));
+
+          goto Unimplemented;
+
+        case cff_op_dotsection:
+          /* this operator is deprecated and ignored by the parser */
+          FT_TRACE4(( " dotsection" ));
+          break;
+
+        case cff_op_and:
+          {
+            FT_Fixed  cond = args[0] && args[1];
+
+
+            FT_TRACE4(( " and" ));
+
+            args[0] = cond ? 0x10000L : 0;
+            args++;
+          }
+          break;
+
+        case cff_op_or:
+          {
+            FT_Fixed  cond = args[0] || args[1];
+
+
+            FT_TRACE4(( " or" ));
+
+            args[0] = cond ? 0x10000L : 0;
+            args++;
+          }
+          break;
+
+        case cff_op_eq:
+          {
+            FT_Fixed  cond = !args[0];
+
+
+            FT_TRACE4(( " eq" ));
+
+            args[0] = cond ? 0x10000L : 0;
+            args++;
+          }
+          break;
+
+        case cff_op_ifelse:
+          {
+            FT_Fixed  cond = (args[2] <= args[3]);
+
+
+            FT_TRACE4(( " ifelse" ));
+
+            if ( !cond )
+              args[0] = args[1];
+            args++;
+          }
+          break;
+
+        case cff_op_callsubr:
+          {
+            FT_UInt  idx = (FT_UInt)( ( args[0] >> 16 ) +
+                                      decoder->locals_bias );
+
+
+            FT_TRACE4(( " callsubr(%d)", idx ));
+
+            if ( idx >= decoder->num_locals )
+            {
+              FT_ERROR(( "cff_decoder_parse_charstrings:" ));
+              FT_ERROR(( "  invalid local subr index\n" ));
+              goto Syntax_Error;
+            }
+
+            if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
+            {
+              FT_ERROR(( "cff_decoder_parse_charstrings:"
+                         " too many nested subrs\n" ));
+              goto Syntax_Error;
+            }
+
+            zone->cursor = ip;  /* save current instruction pointer */
+
+            zone++;
+            zone->base   = decoder->locals[idx];
+            zone->limit  = decoder->locals[idx + 1];
+            zone->cursor = zone->base;
+
+            if ( !zone->base )
+            {
+              FT_ERROR(( "cff_decoder_parse_charstrings:"
+                         " invoking empty subrs!\n" ));
+              goto Syntax_Error;
+            }
+
+            decoder->zone = zone;
+            ip            = zone->base;
+            limit         = zone->limit;
+          }
+          break;
+
+        case cff_op_callgsubr:
+          {
+            FT_UInt  idx = (FT_UInt)( ( args[0] >> 16 ) +
+                                      decoder->globals_bias );
+
+
+            FT_TRACE4(( " callgsubr(%d)", idx ));
+
+            if ( idx >= decoder->num_globals )
+            {
+              FT_ERROR(( "cff_decoder_parse_charstrings:" ));
+              FT_ERROR(( " invalid global subr index\n" ));
+              goto Syntax_Error;
+            }
+
+            if ( zone - decoder->zones >= CFF_MAX_SUBRS_CALLS )
+            {
+              FT_ERROR(( "cff_decoder_parse_charstrings:"
+                         " too many nested subrs\n" ));
+              goto Syntax_Error;
+            }
+
+            zone->cursor = ip;  /* save current instruction pointer */
+
+            zone++;
+            zone->base   = decoder->globals[idx];
+            zone->limit  = decoder->globals[idx + 1];
+            zone->cursor = zone->base;
+
+            if ( !zone->base )
+            {
+              FT_ERROR(( "cff_decoder_parse_charstrings:"
+                         " invoking empty subrs!\n" ));
+              goto Syntax_Error;
+            }
+
+            decoder->zone = zone;
+            ip            = zone->base;
+            limit         = zone->limit;
+          }
+          break;
+
+        case cff_op_return:
+          FT_TRACE4(( " return" ));
+
+          if ( decoder->zone <= decoder->zones )
+          {
+            FT_ERROR(( "cff_decoder_parse_charstrings:"
+                       " unexpected return\n" ));
+            goto Syntax_Error;
+          }
+
+          decoder->zone--;
+          zone  = decoder->zone;
+          ip    = zone->cursor;
+          limit = zone->limit;
+          break;
+
+        default:
+        Unimplemented:
+          FT_ERROR(( "Unimplemented opcode: %d", ip[-1] ));
+
+          if ( ip[-1] == 12 )
+            FT_ERROR(( " %d", ip[0] ));
+          FT_ERROR(( "\n" ));
+
+          return CFF_Err_Unimplemented_Feature;
+        }
+
+      decoder->top = args;
+
+      } /* general operator processing */
+
+    } /* while ip < limit */
+
+    FT_TRACE4(( "..end..\n\n" ));
+
+    return error;
+
+  Syntax_Error:
+    FT_TRACE4(( "cff_decoder_parse_charstrings: syntax error!" ));
+    return CFF_Err_Invalid_File_Format;
+
+  Stack_Underflow:
+    FT_TRACE4(( "cff_decoder_parse_charstrings: stack underflow!" ));
+    return CFF_Err_Too_Few_Arguments;
+
+  Stack_Overflow:
+    FT_TRACE4(( "cff_decoder_parse_charstrings: stack overflow!" ));
+    return CFF_Err_Stack_Overflow;
+
+  Memory_Error:
+    return builder->error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /**********                                                      *********/
+  /**********                                                      *********/
+  /**********            COMPUTE THE MAXIMUM ADVANCE WIDTH         *********/
+  /**********                                                      *********/
+  /**********    The following code is in charge of computing      *********/
+  /**********    the maximum advance width of the font.  It        *********/
+  /**********    quickly processes each glyph charstring to        *********/
+  /**********    extract the value from either a `sbw' or `seac'   *********/
+  /**********    operator.                                         *********/
+  /**********                                                      *********/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+#if 0 /* unused until we support pure CFF fonts */
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_compute_max_advance( TT_Face  face,
+                           FT_Int*  max_advance )
+  {
+    FT_Error     error = 0;
+    CFF_Decoder  decoder;
+    FT_Int       glyph_index;
+    CFF_Font     cff = (CFF_Font)face->other;
+
+
+    *max_advance = 0;
+
+    /* Initialize load decoder */
+    cff_decoder_init( &decoder, face, 0, 0, 0, 0 );
+
+    decoder.builder.metrics_only = 1;
+    decoder.builder.load_points  = 0;
+
+    /* For each glyph, parse the glyph charstring and extract */
+    /* the advance width.                                     */
+    for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
+          glyph_index++ )
+    {
+      FT_Byte*  charstring;
+      FT_ULong  charstring_len;
+
+
+      /* now get load the unscaled outline */
+      error = cff_get_glyph_data( face, glyph_index,
+                                  &charstring, &charstring_len );
+      if ( !error )
+      {
+        cff_decoder_prepare( &decoder, glyph_index );
+        error = cff_decoder_parse_charstrings( &decoder,
+                                               charstring, charstring_len );
+
+        cff_free_glyph_data( face, &charstring, &charstring_len );
+      }
+
+      /* ignore the error if one has occurred -- skip to next glyph */
+      error = 0;
+    }
+
+    *max_advance = decoder.builder.advance.x;
+
+    return CFF_Err_Ok;
+  }
+
+
+#endif /* 0 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /**********                                                      *********/
+  /**********                                                      *********/
+  /**********               UNHINTED GLYPH LOADER                  *********/
+  /**********                                                      *********/
+  /**********    The following code is in charge of loading a      *********/
+  /**********    single outline.  It completely ignores hinting    *********/
+  /**********    and is used when FT_LOAD_NO_HINTING is set.       *********/
+  /**********                                                      *********/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_slot_load( CFF_GlyphSlot  glyph,
+                 CFF_Size       size,
+                 FT_Int         glyph_index,
+                 FT_Int32       load_flags )
+  {
+    FT_Error     error;
+    CFF_Decoder  decoder;
+    TT_Face      face = (TT_Face)glyph->root.face;
+    FT_Bool      hinting;
+    CFF_Font     cff = (CFF_Font)face->extra.data;
+
+    FT_Matrix    font_matrix;
+    FT_Vector    font_offset;
+
+
+    if ( load_flags & FT_LOAD_NO_RECURSE )
+      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+    glyph->x_scale = 0x10000L;
+    glyph->y_scale = 0x10000L;
+    if ( size )
+    {
+      glyph->x_scale = size->metrics.x_scale;
+      glyph->y_scale = size->metrics.y_scale;
+    }
+
+    glyph->root.outline.n_points   = 0;
+    glyph->root.outline.n_contours = 0;
+
+    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 &&
+                       ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+    glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;  /* by default */
+
+    {
+      FT_Byte*  charstring;
+      FT_ULong  charstring_len;
+
+
+      cff_decoder_init( &decoder, face, size, glyph, hinting,
+                        FT_LOAD_TARGET_MODE(load_flags) );
+
+      decoder.builder.no_recurse =
+        (FT_Bool)( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
+
+      /* now load the unscaled outline */
+      error = cff_get_glyph_data( face, glyph_index,
+                                  &charstring, &charstring_len );
+      if ( !error )
+      {
+        cff_decoder_prepare( &decoder, glyph_index );
+        error = cff_decoder_parse_charstrings( &decoder,
+                                               charstring, charstring_len );
+
+        cff_free_glyph_data( face, &charstring, charstring_len );
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+        /* Control data and length may not be available for incremental   */
+        /* fonts.                                                         */
+        if ( face->root.internal->incremental_interface )
+        {
+          glyph->root.control_data = 0;
+          glyph->root.control_len = 0;
+        }
+        else
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+        /* We set control_data and control_len if charstrings is loaded.  */
+        /* See how charstring loads at cff_index_access_element() in      */
+        /* cffload.c.                                                     */
+        {
+          CFF_IndexRec csindex = cff->charstrings_index;
+
+
+          glyph->root.control_data =
+            csindex.bytes + csindex.offsets[glyph_index] - 1;
+          glyph->root.control_len =
+            charstring_len;
+        }
+      }
+
+      /* save new glyph tables */
+      cff_builder_done( &decoder.builder );
+    }
+
+    font_matrix = cff->top_font.font_dict.font_matrix;
+    font_offset = cff->top_font.font_dict.font_offset;
+
+    /* Now, set the metrics -- this is rather simple, as   */
+    /* the left side bearing is the xMin, and the top side */
+    /* bearing the yMax.                                   */
+    if ( !error )
+    {
+      /* For composite glyphs, return only left side bearing and */
+      /* advance width.                                          */
+      if ( load_flags & FT_LOAD_NO_RECURSE )
+      {
+        FT_Slot_Internal  internal = glyph->root.internal;
+
+
+        glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+        glyph->root.metrics.horiAdvance  = decoder.glyph_width;
+        internal->glyph_matrix           = font_matrix;
+        internal->glyph_delta            = font_offset;
+        internal->glyph_transformed      = 1;
+      }
+      else
+      {
+        FT_BBox            cbox;
+        FT_Glyph_Metrics*  metrics = &glyph->root.metrics;
+
+
+        /* copy the _unscaled_ advance width */
+        metrics->horiAdvance                    = decoder.glyph_width;
+        glyph->root.linearHoriAdvance           = decoder.glyph_width;
+        glyph->root.internal->glyph_transformed = 0;
+
+        /* make up vertical metrics */
+        metrics->vertBearingX = 0;
+        metrics->vertBearingY = 0;
+        metrics->vertAdvance  = 0;
+
+        glyph->root.linearVertAdvance = 0;
+
+        glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+        glyph->root.outline.flags = 0;
+        if ( size && size->metrics.y_ppem < 24 )
+          glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+        glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
+
+        /* apply the font matrix */
+        FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+        FT_Outline_Translate( &glyph->root.outline,
+                              font_offset.x,
+                              font_offset.y );
+
+        if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+        {
+          /* scale the outline and the metrics */
+          FT_Int       n;
+          FT_Outline*  cur     = &glyph->root.outline;
+          FT_Vector*   vec     = cur->points;
+          FT_Fixed     x_scale = glyph->x_scale;
+          FT_Fixed     y_scale = glyph->y_scale;
+
+
+          /* First of all, scale the points */
+          if ( !hinting )
+            for ( n = cur->n_points; n > 0; n--, vec++ )
+            {
+              vec->x = FT_MulFix( vec->x, x_scale );
+              vec->y = FT_MulFix( vec->y, y_scale );
+            }
+
+          FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+          /* Then scale the metrics */
+          metrics->horiAdvance  = FT_MulFix( metrics->horiAdvance,  x_scale );
+          metrics->vertAdvance  = FT_MulFix( metrics->vertAdvance,  y_scale );
+
+          metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+          metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+
+          if ( hinting )
+          {
+            metrics->horiAdvance  = ( metrics->horiAdvance + 32 ) & -64;
+            metrics->vertAdvance  = ( metrics->vertAdvance + 32 ) & -64;
+
+            metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
+            metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
+          }
+        }
+
+        /* compute the other metrics */
+        FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+        /* grid fit the bounding box if necessary */
+        if ( hinting )
+        {
+          cbox.xMin &= -64;
+          cbox.yMin &= -64;
+          cbox.xMax  = ( cbox.xMax + 63 ) & -64;
+          cbox.yMax  = ( cbox.yMax + 63 ) & -64;
+        }
+
+        metrics->width  = cbox.xMax - cbox.xMin;
+        metrics->height = cbox.yMax - cbox.yMin;
+
+        metrics->horiBearingX = cbox.xMin;
+        metrics->horiBearingY = cbox.yMax;
+      }
+    }
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffgload.h
@@ -1,0 +1,214 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffgload.h                                                             */
+/*                                                                         */
+/*    OpenType Glyph Loader (specification).                               */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CFFGLOAD_H__
+#define __CFFGLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "cffobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#define CFF_MAX_OPERANDS     48
+#define CFF_MAX_SUBRS_CALLS  32
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Structure>                                                           */
+  /*    CFF_Builder                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*     A structure used during glyph loading to store its outline.       */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    memory        :: The current memory object.                        */
+  /*                                                                       */
+  /*    face          :: The current face object.                          */
+  /*                                                                       */
+  /*    glyph         :: The current glyph slot.                           */
+  /*                                                                       */
+  /*    loader        :: The current glyph loader.                         */
+  /*                                                                       */
+  /*    base          :: The base glyph outline.                           */
+  /*                                                                       */
+  /*    current       :: The current glyph outline.                        */
+  /*                                                                       */
+  /*    last          :: The last point position.                          */
+  /*                                                                       */
+  /*    scale_x       :: The horizontal scale (FUnits to sub-pixels).      */
+  /*                                                                       */
+  /*    scale_y       :: The vertical scale (FUnits to sub-pixels).        */
+  /*                                                                       */
+  /*    pos_x         :: The horizontal translation (if composite glyph).  */
+  /*                                                                       */
+  /*    pos_y         :: The vertical translation (if composite glyph).    */
+  /*                                                                       */
+  /*    left_bearing  :: The left side bearing point.                      */
+  /*                                                                       */
+  /*    advance       :: The horizontal advance vector.                    */
+  /*                                                                       */
+  /*    bbox          :: Unused.                                           */
+  /*                                                                       */
+  /*    path_begun    :: A flag which indicates that a new path has begun. */
+  /*                                                                       */
+  /*    load_points   :: If this flag is not set, no points are loaded.    */
+  /*                                                                       */
+  /*    no_recurse    :: Set but not used.                                 */
+  /*                                                                       */
+  /*    error         :: An error code that is only used to report memory  */
+  /*                     allocation problems.                              */
+  /*                                                                       */
+  /*    metrics_only  :: A boolean indicating that we only want to compute */
+  /*                     the metrics of a given glyph, not load all of its */
+  /*                     points.                                           */
+  /*                                                                       */
+  /*    hints_funcs   :: Auxiliary pointer for hinting.                    */
+  /*                                                                       */
+  /*    hints_globals :: Auxiliary pointer for hinting.                    */
+  /*                                                                       */
+  typedef struct  CFF_Builder_
+  {
+    FT_Memory       memory;
+    TT_Face         face;
+    CFF_GlyphSlot   glyph;
+    FT_GlyphLoader  loader;
+    FT_Outline*     base;
+    FT_Outline*     current;
+
+    FT_Vector       last;
+
+    FT_Fixed        scale_x;
+    FT_Fixed        scale_y;
+
+    FT_Pos          pos_x;
+    FT_Pos          pos_y;
+
+    FT_Vector       left_bearing;
+    FT_Vector       advance;
+
+    FT_BBox         bbox;          /* bounding box */
+    FT_Bool         path_begun;
+    FT_Bool         load_points;
+    FT_Bool         no_recurse;
+
+    FT_Error        error;         /* only used for memory errors */
+    FT_Bool         metrics_only;
+
+    FT_UInt32       hint_flags;
+
+    void*           hints_funcs;    /* hinter-specific */
+    void*           hints_globals;  /* hinter-specific */
+
+  } CFF_Builder;
+
+
+  /* execution context charstring zone */
+
+  typedef struct  CFF_Decoder_Zone_
+  {
+    FT_Byte*  base;
+    FT_Byte*  limit;
+    FT_Byte*  cursor;
+
+  } CFF_Decoder_Zone;
+
+
+  typedef struct  CFF_Decoder_
+  {
+    CFF_Builder        builder;
+    CFF_Font           cff;
+
+    FT_Fixed           stack[CFF_MAX_OPERANDS + 1];
+    FT_Fixed*          top;
+
+    CFF_Decoder_Zone   zones[CFF_MAX_SUBRS_CALLS + 1];
+    CFF_Decoder_Zone*  zone;
+
+    FT_Int             flex_state;
+    FT_Int             num_flex_vectors;
+    FT_Vector          flex_vectors[7];
+
+    FT_Pos             glyph_width;
+    FT_Pos             nominal_width;
+
+    FT_Bool            read_width;
+    FT_Int             num_hints;
+    FT_Fixed*          buildchar;
+    FT_Int             len_buildchar;
+
+    FT_UInt            num_locals;
+    FT_UInt            num_globals;
+
+    FT_Int             locals_bias;
+    FT_Int             globals_bias;
+
+    FT_Byte**          locals;
+    FT_Byte**          globals;
+
+    FT_Byte**          glyph_names;   /* for pure CFF fonts only  */
+    FT_UInt            num_glyphs;    /* number of glyphs in font */
+
+    FT_Render_Mode     hint_mode;
+
+  } CFF_Decoder;
+
+
+  FT_LOCAL( void )
+  cff_decoder_init( CFF_Decoder*    decoder,
+                    TT_Face         face,
+                    CFF_Size        size,
+                    CFF_GlyphSlot   slot,
+                    FT_Bool         hinting,
+                    FT_Render_Mode  hint_mode );
+
+  FT_LOCAL( void )
+  cff_decoder_prepare( CFF_Decoder*  decoder,
+                       FT_UInt       glyph_index );
+
+#if 0  /* unused until we support pure CFF fonts */
+
+  /* Compute the maximum advance width of a font through quick parsing */
+  FT_LOCAL( FT_Error )
+  cff_compute_max_advance( TT_Face  face,
+                           FT_Int*  max_advance );
+
+#endif /* 0 */
+
+  FT_LOCAL( FT_Error )
+  cff_decoder_parse_charstrings( CFF_Decoder*  decoder,
+                                 FT_Byte*      charstring_base,
+                                 FT_ULong      charstring_len );
+
+  FT_LOCAL( FT_Error )
+  cff_slot_load( CFF_GlyphSlot  glyph,
+                 CFF_Size       size,
+                 FT_Int         glyph_index,
+                 FT_Int32       load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __CFFGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffload.c
@@ -1,0 +1,2247 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffload.c                                                              */
+/*                                                                         */
+/*    OpenType and CFF data/program tables loader (body).                  */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "cffload.h"
+#include "cffparse.h"
+
+#include "cfferrs.h"
+
+
+#if 1
+  static const FT_UShort  cff_isoadobe_charset[229] =
+  {
+    0,
+    1,
+    2,
+    3,
+    4,
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    12,
+    13,
+    14,
+    15,
+    16,
+    17,
+    18,
+    19,
+    20,
+    21,
+    22,
+    23,
+    24,
+    25,
+    26,
+    27,
+    28,
+    29,
+    30,
+    31,
+    32,
+    33,
+    34,
+    35,
+    36,
+    37,
+    38,
+    39,
+    40,
+    41,
+    42,
+    43,
+    44,
+    45,
+    46,
+    47,
+    48,
+    49,
+    50,
+    51,
+    52,
+    53,
+    54,
+    55,
+    56,
+    57,
+    58,
+    59,
+    60,
+    61,
+    62,
+    63,
+    64,
+    65,
+    66,
+    67,
+    68,
+    69,
+    70,
+    71,
+    72,
+    73,
+    74,
+    75,
+    76,
+    77,
+    78,
+    79,
+    80,
+    81,
+    82,
+    83,
+    84,
+    85,
+    86,
+    87,
+    88,
+    89,
+    90,
+    91,
+    92,
+    93,
+    94,
+    95,
+    96,
+    97,
+    98,
+    99,
+    100,
+    101,
+    102,
+    103,
+    104,
+    105,
+    106,
+    107,
+    108,
+    109,
+    110,
+    111,
+    112,
+    113,
+    114,
+    115,
+    116,
+    117,
+    118,
+    119,
+    120,
+    121,
+    122,
+    123,
+    124,
+    125,
+    126,
+    127,
+    128,
+    129,
+    130,
+    131,
+    132,
+    133,
+    134,
+    135,
+    136,
+    137,
+    138,
+    139,
+    140,
+    141,
+    142,
+    143,
+    144,
+    145,
+    146,
+    147,
+    148,
+    149,
+    150,
+    151,
+    152,
+    153,
+    154,
+    155,
+    156,
+    157,
+    158,
+    159,
+    160,
+    161,
+    162,
+    163,
+    164,
+    165,
+    166,
+    167,
+    168,
+    169,
+    170,
+    171,
+    172,
+    173,
+    174,
+    175,
+    176,
+    177,
+    178,
+    179,
+    180,
+    181,
+    182,
+    183,
+    184,
+    185,
+    186,
+    187,
+    188,
+    189,
+    190,
+    191,
+    192,
+    193,
+    194,
+    195,
+    196,
+    197,
+    198,
+    199,
+    200,
+    201,
+    202,
+    203,
+    204,
+    205,
+    206,
+    207,
+    208,
+    209,
+    210,
+    211,
+    212,
+    213,
+    214,
+    215,
+    216,
+    217,
+    218,
+    219,
+    220,
+    221,
+    222,
+    223,
+    224,
+    225,
+    226,
+    227,
+    228
+  };
+
+  static const FT_UShort  cff_expert_charset[166] =
+  {
+    0,
+    1,
+    229,
+    230,
+    231,
+    232,
+    233,
+    234,
+    235,
+    236,
+    237,
+    238,
+    13,
+    14,
+    15,
+    99,
+    239,
+    240,
+    241,
+    242,
+    243,
+    244,
+    245,
+    246,
+    247,
+    248,
+    27,
+    28,
+    249,
+    250,
+    251,
+    252,
+    253,
+    254,
+    255,
+    256,
+    257,
+    258,
+    259,
+    260,
+    261,
+    262,
+    263,
+    264,
+    265,
+    266,
+    109,
+    110,
+    267,
+    268,
+    269,
+    270,
+    271,
+    272,
+    273,
+    274,
+    275,
+    276,
+    277,
+    278,
+    279,
+    280,
+    281,
+    282,
+    283,
+    284,
+    285,
+    286,
+    287,
+    288,
+    289,
+    290,
+    291,
+    292,
+    293,
+    294,
+    295,
+    296,
+    297,
+    298,
+    299,
+    300,
+    301,
+    302,
+    303,
+    304,
+    305,
+    306,
+    307,
+    308,
+    309,
+    310,
+    311,
+    312,
+    313,
+    314,
+    315,
+    316,
+    317,
+    318,
+    158,
+    155,
+    163,
+    319,
+    320,
+    321,
+    322,
+    323,
+    324,
+    325,
+    326,
+    150,
+    164,
+    169,
+    327,
+    328,
+    329,
+    330,
+    331,
+    332,
+    333,
+    334,
+    335,
+    336,
+    337,
+    338,
+    339,
+    340,
+    341,
+    342,
+    343,
+    344,
+    345,
+    346,
+    347,
+    348,
+    349,
+    350,
+    351,
+    352,
+    353,
+    354,
+    355,
+    356,
+    357,
+    358,
+    359,
+    360,
+    361,
+    362,
+    363,
+    364,
+    365,
+    366,
+    367,
+    368,
+    369,
+    370,
+    371,
+    372,
+    373,
+    374,
+    375,
+    376,
+    377,
+    378
+  };
+
+  static const FT_UShort  cff_expertsubset_charset[87] =
+  {
+    0,
+    1,
+    231,
+    232,
+    235,
+    236,
+    237,
+    238,
+    13,
+    14,
+    15,
+    99,
+    239,
+    240,
+    241,
+    242,
+    243,
+    244,
+    245,
+    246,
+    247,
+    248,
+    27,
+    28,
+    249,
+    250,
+    251,
+    253,
+    254,
+    255,
+    256,
+    257,
+    258,
+    259,
+    260,
+    261,
+    262,
+    263,
+    264,
+    265,
+    266,
+    109,
+    110,
+    267,
+    268,
+    269,
+    270,
+    272,
+    300,
+    301,
+    302,
+    305,
+    314,
+    315,
+    158,
+    155,
+    163,
+    320,
+    321,
+    322,
+    323,
+    324,
+    325,
+    326,
+    150,
+    164,
+    169,
+    327,
+    328,
+    329,
+    330,
+    331,
+    332,
+    333,
+    334,
+    335,
+    336,
+    337,
+    338,
+    339,
+    340,
+    341,
+    342,
+    343,
+    344,
+    345,
+    346
+  };
+
+  static const FT_UShort  cff_standard_encoding[256] =
+  {
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    1,
+    2,
+    3,
+    4,
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    12,
+    13,
+    14,
+    15,
+    16,
+    17,
+    18,
+    19,
+    20,
+    21,
+    22,
+    23,
+    24,
+    25,
+    26,
+    27,
+    28,
+    29,
+    30,
+    31,
+    32,
+    33,
+    34,
+    35,
+    36,
+    37,
+    38,
+    39,
+    40,
+    41,
+    42,
+    43,
+    44,
+    45,
+    46,
+    47,
+    48,
+    49,
+    50,
+    51,
+    52,
+    53,
+    54,
+    55,
+    56,
+    57,
+    58,
+    59,
+    60,
+    61,
+    62,
+    63,
+    64,
+    65,
+    66,
+    67,
+    68,
+    69,
+    70,
+    71,
+    72,
+    73,
+    74,
+    75,
+    76,
+    77,
+    78,
+    79,
+    80,
+    81,
+    82,
+    83,
+    84,
+    85,
+    86,
+    87,
+    88,
+    89,
+    90,
+    91,
+    92,
+    93,
+    94,
+    95,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    96,
+    97,
+    98,
+    99,
+    100,
+    101,
+    102,
+    103,
+    104,
+    105,
+    106,
+    107,
+    108,
+    109,
+    110,
+    0,
+    111,
+    112,
+    113,
+    114,
+    0,
+    115,
+    116,
+    117,
+    118,
+    119,
+    120,
+    121,
+    122,
+    0,
+    123,
+    0,
+    124,
+    125,
+    126,
+    127,
+    128,
+    129,
+    130,
+    131,
+    0,
+    132,
+    133,
+    0,
+    134,
+    135,
+    136,
+    137,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    138,
+    0,
+    139,
+    0,
+    0,
+    0,
+    0,
+    140,
+    141,
+    142,
+    143,
+    0,
+    0,
+    0,
+    0,
+    0,
+    144,
+    0,
+    0,
+    0,
+    145,
+    0,
+    0,
+    146,
+    147,
+    148,
+    149,
+    0,
+    0,
+    0,
+    0
+  };
+
+  static const FT_UShort  cff_expert_encoding[256] =
+  {
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    1,
+    229,
+    230,
+    0,
+    231,
+    232,
+    233,
+    234,
+    235,
+    236,
+    237,
+    238,
+    13,
+    14,
+    15,
+    99,
+    239,
+    240,
+    241,
+    242,
+    243,
+    244,
+    245,
+    246,
+    247,
+    248,
+    27,
+    28,
+    249,
+    250,
+    251,
+    252,
+    0,
+    253,
+    254,
+    255,
+    256,
+    257,
+    0,
+    0,
+    0,
+    258,
+    0,
+    0,
+    259,
+    260,
+    261,
+    262,
+    0,
+    0,
+    263,
+    264,
+    265,
+    0,
+    266,
+    109,
+    110,
+    267,
+    268,
+    269,
+    0,
+    270,
+    271,
+    272,
+    273,
+    274,
+    275,
+    276,
+    277,
+    278,
+    279,
+    280,
+    281,
+    282,
+    283,
+    284,
+    285,
+    286,
+    287,
+    288,
+    289,
+    290,
+    291,
+    292,
+    293,
+    294,
+    295,
+    296,
+    297,
+    298,
+    299,
+    300,
+    301,
+    302,
+    303,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    304,
+    305,
+    306,
+    0,
+    0,
+    307,
+    308,
+    309,
+    310,
+    311,
+    0,
+    312,
+    0,
+    0,
+    312,
+    0,
+    0,
+    314,
+    315,
+    0,
+    0,
+    316,
+    317,
+    318,
+    0,
+    0,
+    0,
+    158,
+    155,
+    163,
+    319,
+    320,
+    321,
+    322,
+    323,
+    324,
+    325,
+    0,
+    0,
+    326,
+    150,
+    164,
+    169,
+    327,
+    328,
+    329,
+    330,
+    331,
+    332,
+    333,
+    334,
+    335,
+    336,
+    337,
+    338,
+    339,
+    340,
+    341,
+    342,
+    343,
+    344,
+    345,
+    346,
+    347,
+    348,
+    349,
+    350,
+    351,
+    352,
+    353,
+    354,
+    355,
+    356,
+    357,
+    358,
+    359,
+    360,
+    361,
+    362,
+    363,
+    364,
+    365,
+    366,
+    367,
+    368,
+    369,
+    370,
+    371,
+    372,
+    373,
+    374,
+    375,
+    376,
+    377,
+    378
+  };
+#endif
+
+
+  FT_LOCAL_DEF( FT_UShort )
+  cff_get_standard_encoding( FT_UInt  charcode )
+  {
+    return  (FT_UShort)(charcode < 256 ? cff_standard_encoding[charcode] : 0);
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cffload
+
+
+  /* read a CFF offset from memory */
+  static FT_ULong
+  cff_get_offset( FT_Byte*  p,
+                  FT_Byte   off_size )
+  {
+    FT_ULong  result;
+
+
+    for ( result = 0; off_size > 0; off_size-- )
+    {
+      result <<= 8;
+      result  |= *p++;
+    }
+
+    return result;
+  }
+
+
+  static FT_Error
+  cff_new_index( CFF_Index  idx,
+                 FT_Stream  stream,
+                 FT_Bool    load )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+    FT_UShort  count;
+
+
+    FT_MEM_ZERO( idx, sizeof ( *idx ) );
+
+    idx->stream = stream;
+    if ( !FT_READ_USHORT( count ) &&
+         count > 0             )
+    {
+      FT_Byte*   p;
+      FT_Byte    offsize;
+      FT_ULong   data_size;
+      FT_ULong*  poff;
+
+
+      /* there is at least one element; read the offset size,           */
+      /* then access the offset table to compute the index's total size */
+      if ( FT_READ_BYTE( offsize ) )
+        goto Exit;
+
+      idx->stream   = stream;
+      idx->count    = count;
+      idx->off_size = offsize;
+      data_size     = (FT_ULong)( count + 1 ) * offsize;
+
+      if ( FT_NEW_ARRAY( idx->offsets, count + 1 ) ||
+           FT_FRAME_ENTER( data_size )             )
+        goto Exit;
+
+      poff = idx->offsets;
+      p    = (FT_Byte*)stream->cursor;
+
+      for ( ; (FT_Short)count >= 0; count-- )
+      {
+        poff[0] = cff_get_offset( p, offsize );
+        poff++;
+        p += offsize;
+      }
+
+      FT_FRAME_EXIT();
+
+      idx->data_offset = FT_STREAM_POS();
+      data_size        = poff[-1] - 1;
+
+      if ( load )
+      {
+        /* load the data */
+        if ( FT_FRAME_EXTRACT( data_size, idx->bytes ) )
+          goto Exit;
+      }
+      else
+      {
+        /* skip the data */
+        if ( FT_STREAM_SKIP( data_size ) )
+          goto Exit;
+      }
+    }
+
+  Exit:
+    if ( error )
+      FT_FREE( idx->offsets );
+
+    return error;
+  }
+
+
+  static void
+  cff_done_index( CFF_Index  idx )
+  {
+    if ( idx->stream )
+    {
+      FT_Stream  stream = idx->stream;
+      FT_Memory  memory = stream->memory;
+
+
+      if ( idx->bytes )
+        FT_FRAME_RELEASE( idx->bytes );
+
+      FT_FREE( idx->offsets );
+      FT_MEM_ZERO( idx, sizeof ( *idx ) );
+    }
+  }
+
+
+ /* allocate a table containing pointers to an index's elements */
+  static FT_Error
+  cff_index_get_pointers( CFF_Index   idx,
+                          FT_Byte***  table )
+  {
+    FT_Error   error  = 0;
+    FT_Memory  memory = idx->stream->memory;
+    FT_ULong   n, offset, old_offset;
+    FT_Byte**  t;
+
+
+    *table = 0;
+
+    if ( idx->count > 0 && !FT_NEW_ARRAY( t, idx->count + 1 ) )
+    {
+      old_offset = 1;
+      for ( n = 0; n <= idx->count; n++ )
+      {
+        offset = idx->offsets[n];
+        if ( !offset )
+          offset = old_offset;
+
+        t[n] = idx->bytes + offset - 1;
+
+        old_offset = offset;
+      }
+      *table = t;
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_index_access_element( CFF_Index  idx,
+                            FT_UInt    element,
+                            FT_Byte**  pbytes,
+                            FT_ULong*  pbyte_len )
+  {
+    FT_Error  error = 0;
+
+
+    if ( idx && idx->count > element )
+    {
+      /* compute start and end offsets */
+      FT_ULong  off1, off2 = 0;
+
+
+      off1 = idx->offsets[element];
+      if ( off1 )
+      {
+        do
+        {
+          element++;
+          off2 = idx->offsets[element];
+
+        } while ( off2 == 0 && element < idx->count );
+
+        if ( !off2 )
+          off1 = 0;
+      }
+
+      /* access element */
+      if ( off1 )
+      {
+        *pbyte_len = off2 - off1;
+
+        if ( idx->bytes )
+        {
+          /* this index was completely loaded in memory, that's easy */
+          *pbytes = idx->bytes + off1 - 1;
+        }
+        else
+        {
+          /* this index is still on disk/file, access it through a frame */
+          FT_Stream  stream = idx->stream;
+
+
+          if ( FT_STREAM_SEEK( idx->data_offset + off1 - 1 ) ||
+               FT_FRAME_EXTRACT( off2 - off1, *pbytes )      )
+            goto Exit;
+        }
+      }
+      else
+      {
+        /* empty index element */
+        *pbytes    = 0;
+        *pbyte_len = 0;
+      }
+    }
+    else
+      error = CFF_Err_Invalid_Argument;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cff_index_forget_element( CFF_Index  idx,
+                            FT_Byte**  pbytes )
+  {
+    if ( idx->bytes == 0 )
+    {
+      FT_Stream  stream = idx->stream;
+
+
+      FT_FRAME_RELEASE( *pbytes );
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_String* )
+  cff_index_get_name( CFF_Index  idx,
+                      FT_UInt    element )
+  {
+    FT_Memory   memory = idx->stream->memory;
+    FT_Byte*    bytes;
+    FT_ULong    byte_len;
+    FT_Error    error;
+    FT_String*  name = 0;
+
+
+    error = cff_index_access_element( idx, element, &bytes, &byte_len );
+    if ( error )
+      goto Exit;
+
+    if ( !FT_ALLOC( name, byte_len + 1 ) )
+    {
+      FT_MEM_COPY( name, bytes, byte_len );
+      name[byte_len] = 0;
+    }
+    cff_index_forget_element( idx, &bytes );
+
+  Exit:
+    return name;
+  }
+
+
+  FT_LOCAL_DEF( FT_String* )
+  cff_index_get_sid_string( CFF_Index        idx,
+                            FT_UInt          sid,
+                            PSNames_Service  psnames_service )
+  {
+    /* if it is not a standard string, return it */
+    if ( sid > 390 )
+      return cff_index_get_name( idx, sid - 391 );
+
+    /* that's a standard string, fetch a copy from the PSName module */
+    {
+      FT_String*   name       = 0;
+      const char*  adobe_name = psnames_service->adobe_std_strings( sid );
+      FT_UInt      len;
+
+
+      if ( adobe_name )
+      {
+        FT_Memory  memory = idx->stream->memory;
+        FT_Error   error;
+
+
+        len = (FT_UInt)ft_strlen( adobe_name );
+        if ( !FT_ALLOC( name, len + 1 ) )
+        {
+          FT_MEM_COPY( name, adobe_name, len );
+          name[len] = 0;
+        }
+
+        FT_UNUSED( error );
+      }
+
+      return name;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /***                                                                   ***/
+  /***   FD Select table support                                         ***/
+  /***                                                                   ***/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static void
+  CFF_Done_FD_Select( CFF_FDSelect  fdselect,
+                      FT_Stream     stream )
+  {
+    if ( fdselect->data )
+      FT_FRAME_RELEASE( fdselect->data );
+
+    fdselect->data_size   = 0;
+    fdselect->format      = 0;
+    fdselect->range_count = 0;
+  }
+
+
+  static FT_Error
+  CFF_Load_FD_Select( CFF_FDSelect  fdselect,
+                      FT_UInt       num_glyphs,
+                      FT_Stream     stream,
+                      FT_ULong      offset )
+  {
+    FT_Error  error;
+    FT_Byte   format;
+    FT_UInt   num_ranges;
+
+
+    /* read format */
+    if ( FT_STREAM_SEEK( offset ) || FT_READ_BYTE( format ) )
+      goto Exit;
+
+    fdselect->format      = format;
+    fdselect->cache_count = 0;   /* clear cache */
+
+    switch ( format )
+    {
+    case 0:     /* format 0, that's simple */
+      fdselect->data_size = num_glyphs;
+      goto Load_Data;
+
+    case 3:     /* format 3, a tad more complex */
+      if ( FT_READ_USHORT( num_ranges ) )
+        goto Exit;
+
+      fdselect->data_size = num_ranges * 3 + 2;
+
+    Load_Data:
+      if ( FT_FRAME_EXTRACT( fdselect->data_size, fdselect->data ) )
+        goto Exit;
+      break;
+
+    default:    /* hmm... that's wrong */
+      error = CFF_Err_Invalid_File_Format;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Byte )
+  cff_fd_select_get( CFF_FDSelect  fdselect,
+                     FT_UInt       glyph_index )
+  {
+    FT_Byte  fd = 0;
+
+
+    switch ( fdselect->format )
+    {
+    case 0:
+      fd = fdselect->data[glyph_index];
+      break;
+
+    case 3:
+      /* first, compare to cache */
+      if ( (FT_UInt)( glyph_index - fdselect->cache_first ) <
+                        fdselect->cache_count )
+      {
+        fd = fdselect->cache_fd;
+        break;
+      }
+
+      /* then, lookup the ranges array */
+      {
+        FT_Byte*  p       = fdselect->data;
+        FT_Byte*  p_limit = p + fdselect->data_size;
+        FT_Byte   fd2;
+        FT_UInt   first, limit;
+
+
+        first = FT_NEXT_USHORT( p );
+        do
+        {
+          if ( glyph_index < first )
+            break;
+
+          fd2   = *p++;
+          limit = FT_NEXT_USHORT( p );
+
+          if ( glyph_index < limit )
+          {
+            fd = fd2;
+
+            /* update cache */
+            fdselect->cache_first = first;
+            fdselect->cache_count = limit-first;
+            fdselect->cache_fd    = fd2;
+            break;
+          }
+          first = limit;
+
+        } while ( p < p_limit );
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    return fd;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /***                                                                   ***/
+  /***   CFF font support                                                ***/
+  /***                                                                   ***/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  cff_charset_done( CFF_Charset  charset,
+                    FT_Stream    stream )
+  {
+    FT_Memory  memory = stream->memory;
+
+
+    FT_FREE( charset->sids );
+    charset->format = 0;
+    charset->offset = 0;
+  }
+
+
+  static FT_Error
+  cff_charset_load( CFF_Charset  charset,
+                    FT_UInt      num_glyphs,
+                    FT_Stream    stream,
+                    FT_ULong     base_offset,
+                    FT_ULong     offset )
+  {
+    FT_Memory  memory     = stream->memory;
+    FT_Error   error      = 0;
+    FT_UShort  glyph_sid;
+
+
+    /* If the the offset is greater than 2, we have to parse the */
+    /* charset table.                                            */
+    if ( offset > 2 )
+    {
+      FT_UInt  j;
+
+
+      charset->offset = base_offset + offset;
+
+      /* Get the format of the table. */
+      if ( FT_STREAM_SEEK( charset->offset ) ||
+           FT_READ_BYTE( charset->format )   )
+        goto Exit;
+
+      /* Allocate memory for sids. */
+      if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+        goto Exit;
+
+      /* assign the .notdef glyph */
+      charset->sids[0] = 0;
+
+      switch ( charset->format )
+      {
+      case 0:
+        if ( num_glyphs > 0 )
+        {
+          if ( FT_FRAME_ENTER( ( num_glyphs - 1 ) * 2 ) )
+            goto Exit;
+            
+          for ( j = 1; j < num_glyphs; j++ )
+            charset->sids[j] = FT_GET_USHORT();
+          
+          FT_FRAME_EXIT();
+        }
+        break;
+
+      case 1:
+      case 2:
+        {
+          FT_UInt  nleft;
+          FT_UInt  i;
+
+
+          j = 1;
+
+          while ( j < num_glyphs )
+          {
+
+            /* Read the first glyph sid of the range. */
+            if ( FT_READ_USHORT( glyph_sid ) )
+              goto Exit;
+
+            /* Read the number of glyphs in the range.  */
+            if ( charset->format == 2 )
+            {
+              if ( FT_READ_USHORT( nleft ) )
+                goto Exit;
+            }
+            else
+            {
+              if ( FT_READ_BYTE( nleft ) )
+                goto Exit;
+            }
+
+            /* Fill in the range of sids -- `nleft + 1' glyphs. */
+            for ( i = 0; j < num_glyphs && i <= nleft; i++, j++, glyph_sid++ )
+              charset->sids[j] = glyph_sid;
+          }
+        }
+        break;
+
+      default:
+        FT_ERROR(( "cff_charset_load: invalid table format!\n" ));
+        error = CFF_Err_Invalid_File_Format;
+        goto Exit;
+      }
+    }
+    else
+    {
+      /* Parse default tables corresponding to offset == 0, 1, or 2.  */
+      /* CFF specification intimates the following:                   */
+      /*                                                              */
+      /* In order to use a predefined charset, the following must be  */
+      /* true: The charset constructed for the glyphs in the font's   */
+      /* charstrings dictionary must match the predefined charset in  */
+      /* the first num_glyphs, and hence must match the predefined    */
+      /* charset *exactly*.                                           */
+
+      charset->offset = offset;  /* record charset type */
+
+      switch ( (FT_UInt)offset )
+      {
+      case 0:
+        if ( num_glyphs != 229 )
+        {
+          FT_ERROR(("cff_charset_load: implicit charset not equal to\n"
+                    "predefined charset (Adobe ISO-Latin)!\n" ));
+          error = CFF_Err_Invalid_File_Format;
+          goto Exit;
+        }
+
+        /* Allocate memory for sids. */
+        if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+          goto Exit;
+
+        /* Copy the predefined charset into the allocated memory. */
+        FT_MEM_COPY( charset->sids, cff_isoadobe_charset,
+                     num_glyphs * sizeof ( FT_UShort ) );
+
+        break;
+
+      case 1:
+        if ( num_glyphs != 166 )
+        {
+          FT_ERROR(( "cff_charset_load: implicit charset not equal to\n"
+                     "predefined charset (Adobe Expert)!\n" ));
+          error = CFF_Err_Invalid_File_Format;
+          goto Exit;
+        }
+
+        /* Allocate memory for sids. */
+        if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+          goto Exit;
+
+        /* Copy the predefined charset into the allocated memory.     */
+        FT_MEM_COPY( charset->sids, cff_expert_charset,
+                     num_glyphs * sizeof ( FT_UShort ) );
+
+        break;
+
+      case 2:
+        if ( num_glyphs != 87 )
+        {
+          FT_ERROR(( "cff_charset_load: implicit charset not equal to\n"
+                     "predefined charset (Adobe Expert Subset)!\n" ));
+          error = CFF_Err_Invalid_File_Format;
+          goto Exit;
+        }
+
+        /* Allocate memory for sids. */
+        if ( FT_NEW_ARRAY( charset->sids, num_glyphs ) )
+          goto Exit;
+
+        /* Copy the predefined charset into the allocated memory.     */
+        FT_MEM_COPY( charset->sids, cff_expertsubset_charset,
+                     num_glyphs * sizeof ( FT_UShort ) );
+
+        break;
+
+      default:
+        error = CFF_Err_Invalid_File_Format;
+        goto Exit;
+      }
+    }
+
+  Exit:
+
+    /* Clean up if there was an error. */
+    if ( error )
+      if ( charset->sids )
+      {
+        FT_FREE( charset->sids );
+        charset->format = 0;
+        charset->offset = 0;
+        charset->sids   = 0;
+      }
+
+    return error;
+  }
+
+
+
+  static void
+  cff_encoding_done( CFF_Encoding  encoding )
+  {
+    encoding->format = 0;
+    encoding->offset = 0;
+    encoding->count  = 0;
+  }
+
+
+
+  static FT_Error
+  cff_encoding_load( CFF_Encoding  encoding,
+                     CFF_Charset   charset,
+                     FT_UInt       num_glyphs,
+                     FT_Stream     stream,
+                     FT_ULong      base_offset,
+                     FT_ULong      offset )
+  {
+    FT_Error    error  = 0;
+    FT_UInt     count;
+    FT_UInt     j;
+    FT_UShort   glyph_sid;
+    FT_UInt     glyph_code;
+
+
+    /* Check for charset->sids.  If we do not have this, we fail. */
+    if ( !charset->sids )
+    {
+      error = CFF_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    /* Zero out the code to gid/sid mappings. */
+    for ( j = 0; j < 256; j++ )
+    {
+      encoding->sids [j] = 0;
+      encoding->codes[j] = 0;
+    }
+
+    /* Note: The encoding table in a CFF font is indexed by glyph index,  */
+    /* where the first encoded glyph index is 1.  Hence, we read the char */
+    /* code (`glyph_code') at index j and make the assignment:            */
+    /*                                                                    */
+    /*    encoding->codes[glyph_code] = j + 1                             */
+    /*                                                                    */
+    /* We also make the assignment:                                       */
+    /*                                                                    */
+    /*    encoding->sids[glyph_code] = charset->sids[j + 1]               */
+    /*                                                                    */
+    /* This gives us both a code to GID and a code to SID mapping.        */
+
+    if ( offset > 1 )
+    {
+
+      encoding->offset = base_offset + offset;
+
+      /* we need to parse the table to determine its size */
+      if ( FT_STREAM_SEEK( encoding->offset ) ||
+           FT_READ_BYTE( encoding->format )   ||
+           FT_READ_BYTE( count )              )
+        goto Exit;
+
+      encoding->count = count + 1;
+
+      switch ( encoding->format & 0x7F )
+      {
+      case 0:
+        {
+          FT_Byte*  p;
+          
+
+          if ( FT_FRAME_ENTER( count ) )
+            goto Exit;
+
+          p = (FT_Byte*)stream->cursor;
+          
+          for ( j = 1; j <= count; j++ )
+          {
+            glyph_code = *p++;
+
+            /* Make sure j is not too big. */
+            if ( (FT_UInt) glyph_code < num_glyphs )
+            {
+              /* Assign code to GID mapping. */
+              encoding->codes[glyph_code] = (FT_UShort)j;
+
+              /* Assign code to SID mapping. */
+              encoding->sids[glyph_code] = charset->sids[j];
+            }
+          }
+          
+          FT_FRAME_EXIT();
+        }
+        break;
+
+      case 1:
+        {
+          FT_Byte  nleft;
+          FT_UInt  i = 1;
+          FT_UInt  k;
+
+
+          /* Parse the Format1 ranges. */
+          for ( j = 0;  j < count; j++, i += nleft )
+          {
+            /* Read the first glyph code of the range. */
+            if ( FT_READ_BYTE( glyph_code ) )
+              goto Exit;
+
+            /* Read the number of codes in the range. */
+            if ( FT_READ_BYTE( nleft ) )
+              goto Exit;
+
+            /* Increment nleft, so we read `nleft + 1' codes/sids. */
+            nleft++;
+
+            /* Fill in the range of codes/sids. */
+            for ( k = i; k < nleft + i; k++, glyph_code++ )
+            {
+              /* Make sure k is not too big. */
+              if ( k < num_glyphs && glyph_code < 256 )
+              {
+                /* Assign code to GID mapping. */
+                encoding->codes[glyph_code] = (FT_UShort)k;
+
+                /* Assign code to SID mapping. */
+                encoding->sids[glyph_code] = charset->sids[k];
+              }
+            }
+          }
+        }
+        break;
+
+      default:
+        FT_ERROR(( "cff_encoding_load: invalid table format!\n" ));
+        error = CFF_Err_Invalid_File_Format;
+        goto Exit;
+      }
+
+      /* Parse supplemental encodings, if any. */
+      if ( encoding->format & 0x80 )
+      {
+        FT_UInt  gindex;
+
+
+        /* count supplements */
+        if ( FT_READ_BYTE( count ) )
+          goto Exit;
+
+        for ( j = 0; j < count; j++ )
+        {
+          /* Read supplemental glyph code. */
+          if ( FT_READ_BYTE( glyph_code ) )
+            goto Exit;
+
+          /* Read the SID associated with this glyph code. */
+          if ( FT_READ_USHORT( glyph_sid ) )
+            goto Exit;
+
+          /* Assign code to SID mapping. */
+          encoding->sids[glyph_code] = glyph_sid;
+
+          /* First, lookup GID which has been assigned to */
+          /* SID glyph_sid.                               */
+          for ( gindex = 0; gindex < num_glyphs; gindex++ )
+          {
+            if ( charset->sids[gindex] == glyph_sid )
+            {
+              encoding->codes[glyph_code] = (FT_UShort) gindex;
+              break;
+            }
+          }
+        }
+      }
+    }
+    else
+    {
+      FT_UInt i;
+
+
+      /* We take into account the fact a CFF font can use a predefined  */
+      /* encoding without containing all of the glyphs encoded by this  */
+      /* encoding (see the note at the end of section 12 in the CFF     */
+      /* specification).                                                */
+
+      encoding->count = 256;
+
+      switch ( (FT_UInt)offset )
+      {
+      case 0:
+        /* First, copy the code to SID mapping. */
+        FT_MEM_COPY( encoding->sids, cff_standard_encoding,
+                     256 * sizeof ( FT_UShort ) );
+
+        goto Populate;
+
+      case 1:
+        /* First, copy the code to SID mapping. */
+        FT_MEM_COPY( encoding->sids, cff_expert_encoding,
+                     256 * sizeof ( FT_UShort ) );
+
+      Populate:
+        /* Construct code to GID mapping from code to SID mapping */
+        /* and charset.                                           */
+        for ( j = 0; j < 256; j++ )
+        {
+          /* If j is encoded, find the GID for it. */
+          if ( encoding->sids[j] )
+          {
+            for ( i = 1; i < num_glyphs; i++ )
+              /* We matched, so break. */
+              if ( charset->sids[i] == encoding->sids[j] )
+                break;
+
+            /* i will be equal to num_glyphs if we exited the above */
+            /* loop without a match.  In this case, we also have to */
+            /* fix the code to SID mapping.                         */
+            if ( i == num_glyphs )
+            {
+              encoding->codes[j] = 0;
+              encoding->sids [j] = 0;
+            }
+            else
+              encoding->codes[j] = (FT_UShort)i;
+          }
+        }
+        break;
+
+      default:
+        FT_ERROR(( "cff_encoding_load: invalid table format!\n" ));
+        error = CFF_Err_Invalid_File_Format;
+        goto Exit;
+      }
+    }
+
+  Exit:
+
+    /* Clean up if there was an error. */
+    return error;
+  }
+
+
+  static FT_Error
+  cff_subfont_load( CFF_SubFont  font,
+                    CFF_Index    idx,
+                    FT_UInt      font_index,
+                    FT_Stream    stream,
+                    FT_ULong     base_offset )
+  {
+    FT_Error         error;
+    CFF_ParserRec    parser;
+    FT_Byte*         dict;
+    FT_ULong         dict_len;
+    CFF_FontRecDict  top  = &font->font_dict;
+    CFF_Private      priv = &font->private_dict;
+
+
+    cff_parser_init( &parser, CFF_CODE_TOPDICT, &font->font_dict );
+
+    /* set defaults */
+    FT_MEM_ZERO( top, sizeof ( *top ) );
+
+    top->underline_position  = -100;
+    top->underline_thickness = 50;
+    top->charstring_type     = 2;
+    top->font_matrix.xx      = 0x10000L;
+    top->font_matrix.yy      = 0x10000L;
+    top->cid_count           = 8720;
+
+    error = cff_index_access_element( idx, font_index, &dict, &dict_len ) ||
+            cff_parser_run( &parser, dict, dict + dict_len );
+
+    cff_index_forget_element( idx, &dict );
+
+    if ( error )
+      goto Exit;
+
+    /* if it is a CID font, we stop there */
+    if ( top->cid_registry )
+      goto Exit;
+
+    /* parse the private dictionary, if any */
+    if ( top->private_offset && top->private_size )
+    {
+      /* set defaults */
+      FT_MEM_ZERO( priv, sizeof ( *priv ) );
+
+      priv->blue_shift       = 7;
+      priv->blue_fuzz        = 1;
+      priv->lenIV            = -1;
+      priv->expansion_factor = (FT_Fixed)0.06 * 0x10000L;
+      priv->blue_scale       = (FT_Fixed)0.039625 * 0x10000L;
+
+      cff_parser_init( &parser, CFF_CODE_PRIVATE, priv );
+
+      if ( FT_STREAM_SEEK( base_offset + font->font_dict.private_offset ) ||
+           FT_FRAME_ENTER( font->font_dict.private_size )                 )
+        goto Exit;
+
+      error = cff_parser_run( &parser,
+                              (FT_Byte*)stream->cursor,
+                              (FT_Byte*)stream->limit );
+      FT_FRAME_EXIT();
+      if ( error )
+        goto Exit;
+    }
+
+    /* read the local subrs, if any */
+    if ( priv->local_subrs_offset )
+    {
+      if ( FT_STREAM_SEEK( base_offset + top->private_offset +
+                           priv->local_subrs_offset ) )
+        goto Exit;
+
+      error = cff_new_index( &font->local_subrs_index, stream, 1 );
+      if ( error )
+        goto Exit;
+
+      font->num_local_subrs = font->local_subrs_index.count;
+      error = cff_index_get_pointers( &font->local_subrs_index,
+                                      &font->local_subrs );
+      if ( error )
+        goto Exit;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  cff_subfont_done( FT_Memory    memory,
+                    CFF_SubFont  subfont )
+  {
+    if ( subfont )
+    {
+      cff_done_index( &subfont->local_subrs_index );
+      FT_FREE( subfont->local_subrs );
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_font_load( FT_Stream  stream,
+                 FT_Int     face_index,
+                 CFF_Font   font )
+  {
+    static const FT_Frame_Field  cff_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CFF_FontRec
+
+      FT_FRAME_START( 4 ),
+        FT_FRAME_BYTE( version_major ),
+        FT_FRAME_BYTE( version_minor ),
+        FT_FRAME_BYTE( header_size ),
+        FT_FRAME_BYTE( absolute_offsize ),
+      FT_FRAME_END
+    };
+
+    FT_Error         error;
+    FT_Memory        memory = stream->memory;
+    FT_ULong         base_offset;
+    CFF_FontRecDict  dict;
+
+    FT_ZERO( font );
+
+    font->stream = stream;
+    font->memory = memory;
+    dict         = &font->top_font.font_dict;
+    base_offset  = FT_STREAM_POS();
+
+    /* read CFF font header */
+    if ( FT_STREAM_READ_FIELDS( cff_header_fields, font ) )
+      goto Exit;
+
+    /* check format */
+    if ( font->version_major   != 1 ||
+         font->header_size      < 4 ||
+         font->absolute_offsize > 4 )
+    {
+      FT_TRACE2(( "[not a CFF font header!]\n" ));
+      error = CFF_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* skip the rest of the header */
+    if ( FT_STREAM_SKIP( font->header_size - 4 ) )
+      goto Exit;
+
+    /* read the name, top dict, string and global subrs index */
+    if ( FT_SET_ERROR( cff_new_index( &font->name_index,         stream, 0 )) ||
+         FT_SET_ERROR( cff_new_index( &font->font_dict_index,    stream, 0 )) ||
+         FT_SET_ERROR( cff_new_index( &font->string_index,       stream, 0 )) ||
+         FT_SET_ERROR( cff_new_index( &font->global_subrs_index, stream, 1 )) )
+      goto Exit;
+
+    /* well, we don't really forget the `disabled' fonts... */
+    font->num_faces = font->name_index.count;
+    if ( face_index >= (FT_Int)font->num_faces )
+    {
+      FT_ERROR(( "cff_font_load: incorrect face index = %d\n",
+                 face_index ));
+      error = CFF_Err_Invalid_Argument;
+    }
+
+    /* in case of a font format check, simply exit now */
+    if ( face_index < 0 )
+      goto Exit;
+
+    /* now, parse the top-level font dictionary */
+    error = cff_subfont_load( &font->top_font,
+                              &font->font_dict_index,
+                              face_index,
+                              stream,
+                              base_offset );
+    if ( error )
+      goto Exit;
+
+    /* now, check for a CID font */
+    if ( dict->cid_registry )
+    {
+      CFF_IndexRec  fd_index;
+      CFF_SubFont   sub;
+      FT_UInt       idx;
+
+
+      /* this is a CID-keyed font, we must now allocate a table of */
+      /* sub-fonts, then load each of them separately              */
+      if ( FT_STREAM_SEEK( base_offset + dict->cid_fd_array_offset ) )
+        goto Exit;
+
+      error = cff_new_index( &fd_index, stream, 0 );
+      if ( error )
+        goto Exit;
+
+      if ( fd_index.count > CFF_MAX_CID_FONTS )
+      {
+        FT_ERROR(( "cff_font_load: FD array too large in CID font\n" ));
+        goto Fail_CID;
+      }
+
+      /* allocate & read each font dict independently */
+      font->num_subfonts = fd_index.count;
+      if ( FT_NEW_ARRAY( sub, fd_index.count ) )
+        goto Fail_CID;
+
+      /* setup pointer table */
+      for ( idx = 0; idx < fd_index.count; idx++ )
+        font->subfonts[idx] = sub + idx;
+
+      /* now load each sub font independently */
+      for ( idx = 0; idx < fd_index.count; idx++ )
+      {
+        sub = font->subfonts[idx];
+        error = cff_subfont_load( sub, &fd_index, idx,
+                                  stream, base_offset );
+        if ( error )
+          goto Fail_CID;
+      }
+
+      /* now load the FD Select array */
+      error = CFF_Load_FD_Select( &font->fd_select,
+                                  (FT_UInt)dict->cid_count,
+                                  stream,
+                                  base_offset + dict->cid_fd_select_offset );
+
+    Fail_CID:
+      cff_done_index( &fd_index );
+
+      if ( error )
+        goto Exit;
+    }
+    else
+      font->num_subfonts = 0;
+
+    /* read the charstrings index now */
+    if ( dict->charstrings_offset == 0 )
+    {
+      FT_ERROR(( "cff_font_load: no charstrings offset!\n" ));
+      error = CFF_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    if ( FT_STREAM_SEEK( base_offset + dict->charstrings_offset ) )
+      goto Exit;
+
+    error = cff_new_index( &font->charstrings_index, stream, 0 );
+    if ( error )
+      goto Exit;
+
+    /* explicit the global subrs */
+    font->num_global_subrs = font->global_subrs_index.count;
+    font->num_glyphs       = font->charstrings_index.count;
+
+    error = cff_index_get_pointers( &font->global_subrs_index,
+                                    &font->global_subrs ) ;
+
+    if ( error )
+      goto Exit;
+
+    /* read the Charset and Encoding tables when available */
+    if ( font->num_glyphs > 0 )
+    {
+      error = cff_charset_load( &font->charset, font->num_glyphs, stream,
+                              base_offset, dict->charset_offset );
+      if ( error )
+        goto Exit;
+
+      error = cff_encoding_load( &font->encoding,
+                                 &font->charset,
+                                 font->num_glyphs,
+                                 stream,
+                                 base_offset,
+                                 dict->encoding_offset );
+      if ( error )
+        goto Exit;
+    }
+
+    /* get the font name */
+    font->font_name = cff_index_get_name( &font->name_index, face_index );
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cff_font_done( CFF_Font  font )
+  {
+    FT_Memory  memory = font->memory;
+    FT_UInt    idx;
+
+
+    cff_done_index( &font->global_subrs_index );
+    cff_done_index( &font->string_index );
+    cff_done_index( &font->font_dict_index );
+    cff_done_index( &font->name_index );
+    cff_done_index( &font->charstrings_index );
+
+    /* release font dictionaries, but only if working with */
+    /* a CID keyed CFF font                                */
+    if ( font->num_subfonts > 0 )
+    {
+      for ( idx = 0; idx < font->num_subfonts; idx++ )
+        cff_subfont_done( memory, font->subfonts[idx] );
+
+      FT_FREE( font->subfonts );
+    }
+
+    cff_encoding_done( &font->encoding );
+    cff_charset_done( &font->charset, font->stream );
+
+    cff_subfont_done( memory, &font->top_font );
+
+    CFF_Done_FD_Select( &font->fd_select, font->stream );
+
+    FT_FREE( font->global_subrs );
+    FT_FREE( font->font_name );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffload.h
@@ -1,0 +1,74 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffload.h                                                              */
+/*                                                                         */
+/*    OpenType & CFF data/program tables loader (specification).           */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CFFLOAD_H__
+#define __CFFLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+FT_BEGIN_HEADER
+
+  FT_LOCAL( FT_UShort )
+  cff_get_standard_encoding( FT_UInt  charcode );
+
+
+  FT_LOCAL( FT_String* )
+  cff_index_get_name( CFF_Index  idx,
+                      FT_UInt    element );
+
+  FT_LOCAL( FT_String* )
+  cff_index_get_sid_string( CFF_Index        idx,
+                            FT_UInt          sid,
+                            PSNames_Service  psnames_interface );
+
+
+  FT_LOCAL( FT_Error )
+  cff_index_access_element( CFF_Index  idx,
+                            FT_UInt    element,
+                            FT_Byte**  pbytes,
+                            FT_ULong*  pbyte_len );
+
+  FT_LOCAL( void )
+  cff_index_forget_element( CFF_Index  idx,
+                            FT_Byte**  pbytes );
+
+
+  FT_LOCAL( FT_Error )
+  cff_font_load( FT_Stream  stream,
+                 FT_Int     face_index,
+                 CFF_Font   font );
+
+  FT_LOCAL( void )
+  cff_font_done( CFF_Font  font );
+
+
+  FT_LOCAL( FT_Byte )
+  cff_fd_select_get( CFF_FDSelect  select,
+                     FT_UInt       glyph_index );
+
+
+FT_END_HEADER
+
+#endif /* __CFFLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffobjs.c
@@ -1,0 +1,575 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffobjs.c                                                              */
+/*                                                                         */
+/*    OpenType objects manager (body).                                     */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_ERRORS_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+#include "cffobjs.h"
+#include "cffload.h"
+#include "cffcmap.h"
+#include "cfferrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cffobjs
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                            SIZE FUNCTIONS                             */
+  /*                                                                       */
+  /*  Note that we store the global hints in the size's "internal" root    */
+  /*  field.                                                               */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static PSH_Globals_Funcs
+  cff_size_get_globals_funcs( CFF_Size  size )
+  {
+    CFF_Face          face     = (CFF_Face)size->face;
+    CFF_Font          font     = (CFF_FontRec *)face->extra.data;
+    PSHinter_Service  pshinter = (PSHinter_Service)font->pshinter;
+    FT_Module         module;
+
+
+    module = FT_Get_Module( size->face->driver->root.library,
+                            "pshinter" );
+    return ( module && pshinter && pshinter->get_globals_funcs )
+           ? pshinter->get_globals_funcs( module )
+           : 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cff_size_done( CFF_Size  size )
+  {
+    if ( size->internal )
+    {
+      PSH_Globals_Funcs  funcs;
+
+
+      funcs = cff_size_get_globals_funcs( size );
+      if ( funcs )
+        funcs->destroy( (PSH_Globals)size->internal );
+
+      size->internal = 0;
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_size_init( CFF_Size  size )
+  {
+    FT_Error           error = 0;
+    PSH_Globals_Funcs  funcs = cff_size_get_globals_funcs( size );
+
+
+    if ( funcs )
+    {
+      PSH_Globals    globals;
+      CFF_Face       face    = (CFF_Face)size->face;
+      CFF_Font       font    = (CFF_FontRec *)face->extra.data;
+      CFF_SubFont    subfont = &font->top_font;
+
+      CFF_Private    cpriv   = &subfont->private_dict;
+      PS_PrivateRec  priv;
+
+
+      /* IMPORTANT: The CFF and Type1 private dictionaries have    */
+      /*            slightly different structures; we need to      */
+      /*            synthetize a type1 dictionary on the fly here. */
+
+      {
+        FT_UInt  n, count;
+
+
+        FT_MEM_ZERO( &priv, sizeof ( priv ) );
+
+        count = priv.num_blue_values = cpriv->num_blue_values;
+        for ( n = 0; n < count; n++ )
+          priv.blue_values[n] = (FT_Short)cpriv->blue_values[n];
+
+        count = priv.num_other_blues = cpriv->num_other_blues;
+        for ( n = 0; n < count; n++ )
+          priv.other_blues[n] = (FT_Short)cpriv->other_blues[n];
+
+        count = priv.num_family_blues = cpriv->num_family_blues;
+        for ( n = 0; n < count; n++ )
+          priv.family_blues[n] = (FT_Short)cpriv->family_blues[n];
+
+        count = priv.num_family_other_blues = cpriv->num_family_other_blues;
+        for ( n = 0; n < count; n++ )
+          priv.family_other_blues[n] = (FT_Short)cpriv->family_other_blues[n];
+
+        priv.blue_scale = cpriv->blue_scale;
+        priv.blue_shift = (FT_Int)cpriv->blue_shift;
+        priv.blue_fuzz  = (FT_Int)cpriv->blue_fuzz;
+
+        priv.standard_width[0]  = (FT_UShort)cpriv->standard_width;
+        priv.standard_height[0] = (FT_UShort)cpriv->standard_height;
+
+        count = priv.num_snap_widths = cpriv->num_snap_widths;
+        for ( n = 0; n < count; n++ )
+          priv.snap_widths[n] = (FT_Short)cpriv->snap_widths[n];
+
+        count = priv.num_snap_heights = cpriv->num_snap_heights;
+        for ( n = 0; n < count; n++ )
+          priv.snap_heights[n] = (FT_Short)cpriv->snap_heights[n];
+
+        priv.force_bold     = cpriv->force_bold;
+        priv.language_group = cpriv->language_group;
+        priv.lenIV          = cpriv->lenIV;
+      }
+
+      error = funcs->create( size->face->memory, &priv, &globals );
+      if ( !error )
+        size->internal = (FT_Size_Internal)(void*)globals;
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_size_reset( CFF_Size  size )
+  {
+    PSH_Globals_Funcs  funcs = cff_size_get_globals_funcs( size );
+    FT_Error           error = 0;
+
+
+    if ( funcs )
+      error = funcs->set_scale( (PSH_Globals)size->internal,
+                                 size->metrics.x_scale,
+                                 size->metrics.y_scale,
+                                 0, 0 );
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                            SLOT  FUNCTIONS                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  cff_slot_done( CFF_GlyphSlot  slot )
+  {
+    slot->root.internal->glyph_hints = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_slot_init( CFF_GlyphSlot  slot )
+  {
+    CFF_Face          face     = (CFF_Face)slot->root.face;
+    CFF_Font          font     = (CFF_FontRec *)face->extra.data;
+    PSHinter_Service  pshinter = (PSHinter_Service)font->pshinter;
+
+
+    if ( pshinter )
+    {
+      FT_Module  module;
+
+
+      module = FT_Get_Module( slot->root.face->driver->root.library,
+                              "pshinter" );
+      if ( module )
+      {
+        T2_Hints_Funcs  funcs;
+
+
+        funcs = pshinter->get_t2_funcs( module );
+        slot->root.internal->glyph_hints = (void*)funcs;
+      }
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                           FACE  FUNCTIONS                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+  static FT_String*
+  cff_strcpy( FT_Memory         memory,
+              const FT_String*  source )
+  {
+    FT_Error    error;
+    FT_String*  result = 0;
+    FT_Int      len = (FT_Int)ft_strlen( source );
+
+
+    if ( !FT_ALLOC( result, len + 1 ) )
+    {
+      FT_MEM_COPY( result, source, len );
+      result[len] = 0;
+    }
+
+    FT_UNUSED( error );
+
+    return result;
+  }
+
+
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_face_init( FT_Stream      stream,
+                 CFF_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params )
+  {
+    FT_Error          error;
+    SFNT_Service      sfnt;
+    PSNames_Service   psnames;
+    PSHinter_Service  pshinter;
+    FT_Bool           pure_cff    = 1;
+    FT_Bool           sfnt_format = 0;
+
+
+    sfnt = (SFNT_Service)FT_Get_Module_Interface(
+             face->root.driver->root.library, "sfnt" );
+    if ( !sfnt )
+      goto Bad_Format;
+
+    psnames = (PSNames_Service)FT_Get_Module_Interface(
+                face->root.driver->root.library, "psnames" );
+
+    pshinter = (PSHinter_Service)FT_Get_Module_Interface(
+                 face->root.driver->root.library, "pshinter" );
+
+    /* create input stream from resource */
+    if ( FT_STREAM_SEEK( 0 ) )
+      goto Exit;
+
+    /* check that we have a valid OpenType file */
+    error = sfnt->init_face( stream, face, face_index, num_params, params );
+    if ( !error )
+    {
+      if ( face->format_tag != 0x4F54544FL )  /* `OTTO'; OpenType/CFF font */
+      {
+        FT_TRACE2(( "[not a valid OpenType/CFF font]\n" ));
+        goto Bad_Format;
+      }
+
+      /* if we are performing a simple font format check, exit immediately */
+      if ( face_index < 0 )
+        return CFF_Err_Ok;
+
+      sfnt_format = 1;
+
+      /* now, the font can be either an OpenType/CFF font, or an SVG CEF */
+      /* font in the later case; it doesn't have a `head' table          */
+      error = face->goto_table( face, TTAG_head, stream, 0 );
+      if ( !error )
+      {
+        pure_cff = 0;
+
+        /* load font directory */
+        error = sfnt->load_face( stream, face,
+                                 face_index, num_params, params );
+        if ( error )
+          goto Exit;
+      }
+      else
+      {
+        /* load the `cmap' table by hand */
+        error = sfnt->load_charmaps( face, stream );
+        if ( error )
+          goto Exit;
+
+        /* XXX: we don't load the GPOS table, as OpenType Layout     */
+        /* support will be added later to a layout library on top of */
+        /* FreeType 2                                                */
+      }
+
+      /* now, load the CFF part of the file */
+      error = face->goto_table( face, TTAG_CFF, stream, 0 );
+      if ( error )
+        goto Exit;
+    }
+    else
+    {
+      /* rewind to start of file; we are going to load a pure-CFF font */
+      if ( FT_STREAM_SEEK( 0 ) )
+        goto Exit;
+      error = CFF_Err_Ok;
+    }
+
+    /* now load and parse the CFF table in the file */
+    {
+      CFF_Font   cff;
+      FT_Memory  memory = face->root.memory;
+      FT_Face    root;
+      FT_Int32   flags;
+
+
+      if ( FT_NEW( cff ) )
+        goto Exit;
+
+      face->extra.data = cff;
+      error = cff_font_load( stream, face_index, cff );
+      if ( error )
+        goto Exit;
+
+      cff->pshinter = pshinter;
+      cff->psnames  = psnames;
+
+      /* Complement the root flags with some interesting information. */
+      /* Note that this is only necessary for pure CFF and CEF fonts. */
+
+      root             = &face->root;
+      root->num_glyphs = cff->num_glyphs;
+
+      if ( pure_cff )
+      {
+        CFF_FontRecDict  dict = &cff->top_font.font_dict;
+
+
+        /* we need the `PSNames' module for pure-CFF and CEF formats */
+        if ( !psnames )
+        {
+          FT_ERROR(( "cff_face_init:" ));
+          FT_ERROR(( " cannot open CFF & CEF fonts\n" ));
+          FT_ERROR(( "              " ));
+          FT_ERROR(( " without the `PSNames' module\n" ));
+          goto Bad_Format;
+        }
+
+        /* Set up num_faces. */
+        root->num_faces = cff->num_faces;
+
+        /* compute number of glyphs */
+        if ( dict->cid_registry )
+          root->num_glyphs = dict->cid_count;
+        else
+          root->num_glyphs = cff->charstrings_index.count;
+
+        /* set global bbox, as well as EM size */
+        root->bbox.xMin =   dict->font_bbox.xMin             >> 16;
+        root->bbox.yMin =   dict->font_bbox.yMin             >> 16;
+        root->bbox.xMax = ( dict->font_bbox.xMax + 0xFFFFU ) >> 16;
+        root->bbox.yMax = ( dict->font_bbox.yMax + 0xFFFFU ) >> 16;
+
+
+        root->ascender  = (FT_Short)( root->bbox.yMax );
+        root->descender = (FT_Short)( root->bbox.yMin );
+        root->height    = (FT_Short)(
+          ( ( root->ascender - root->descender ) * 12 ) / 10 );
+
+        if ( dict->units_per_em )
+          root->units_per_EM = dict->units_per_em;
+        else
+          root->units_per_EM = 1000;
+
+        /* retrieve font family & style name */
+        root->family_name  = cff_index_get_name( &cff->name_index, face_index );
+        if ( dict->cid_registry )
+          root->style_name = cff_strcpy( memory, "Regular" );  /* XXXX */
+        else
+          root->style_name = cff_index_get_sid_string( &cff->string_index,
+                                                       dict->weight,
+                                                       psnames );
+
+        /*******************************************************************/
+        /*                                                                 */
+        /* Compute face flags.                                             */
+        /*                                                                 */
+        flags = FT_FACE_FLAG_SCALABLE  |    /* scalable outlines */
+                FT_FACE_FLAG_HORIZONTAL;    /* horizontal data   */
+
+        if ( sfnt_format )
+          flags |= FT_FACE_FLAG_SFNT;
+
+        /* fixed width font? */
+        if ( dict->is_fixed_pitch )
+          flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+  /* XXX: WE DO NOT SUPPORT KERNING METRICS IN THE GPOS TABLE FOR NOW */
+#if 0
+        /* kerning available? */
+        if ( face->kern_pairs )
+          flags |= FT_FACE_FLAG_KERNING;
+#endif
+
+#ifndef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+        flags |= FT_FACE_FLAG_GLYPH_NAMES;
+#endif
+
+        root->face_flags = flags;
+
+        /*******************************************************************/
+        /*                                                                 */
+        /* Compute style flags.                                            */
+        /*                                                                 */
+        flags = 0;
+
+        if ( dict->italic_angle )
+          flags |= FT_STYLE_FLAG_ITALIC;
+
+        /* XXX: may not be correct */
+        if ( cff->top_font.private_dict.force_bold )
+          flags |= FT_STYLE_FLAG_BOLD;
+
+        root->style_flags = flags;
+      }
+
+      /*******************************************************************/
+      /*                                                                 */
+      /* Compute char maps.                                              */
+      /*                                                                 */
+
+      /* Try to synthetize a Unicode charmap if there is none available */
+      /* already.  If an OpenType font contains a Unicode "cmap", we    */
+      /* will use it, whatever be in the CFF part of the file.          */
+      {
+        FT_CharMapRec  cmaprec;
+        FT_CharMap     cmap;
+        FT_UInt        nn;
+        CFF_Encoding   encoding = &cff->encoding;
+
+
+        for ( nn = 0; nn < (FT_UInt) root->num_charmaps; nn++ )
+        {
+          cmap = root->charmaps[nn];
+
+          /* Windows Unicode (3,1)? */
+          if ( cmap->platform_id == 3 && cmap->encoding_id == 1 )
+            goto Skip_Unicode;
+
+          /* Deprecated Unicode platform id? */
+          if ( cmap->platform_id == 0 )
+            goto Skip_Unicode; /* Standard Unicode (deprecated) */
+        }
+
+        /* we didn't find a Unicode charmap, synthetize one */
+        cmaprec.face        = root;
+        cmaprec.platform_id = 3;
+        cmaprec.encoding_id = 1;
+        cmaprec.encoding    = FT_ENCODING_UNICODE;
+
+        nn = (FT_UInt) root->num_charmaps;
+
+        FT_CMap_New( &cff_cmap_unicode_class_rec, NULL, &cmaprec, NULL );
+
+        /* if no Unicode charmap was previously selected, select this one */
+        if ( root->charmap == NULL && nn != (FT_UInt) root->num_charmaps )
+          root->charmap = root->charmaps[nn];
+
+      Skip_Unicode:
+        if ( encoding->count > 0 )
+        {
+          FT_CMap_Class  clazz;
+
+
+          cmaprec.face        = root;
+          cmaprec.platform_id = 7;  /* Adobe platform id */
+
+          if ( encoding->offset == 0 )
+          {
+            cmaprec.encoding_id = 0;
+            cmaprec.encoding    = FT_ENCODING_ADOBE_STANDARD;
+            clazz               = &cff_cmap_encoding_class_rec;
+          }
+          else if ( encoding->offset == 1 )
+          {
+            cmaprec.encoding_id = 1;
+            cmaprec.encoding    = FT_ENCODING_ADOBE_EXPERT;
+            clazz               = &cff_cmap_encoding_class_rec;
+          }
+          else
+          {
+            cmaprec.encoding_id = 3;
+            cmaprec.encoding    = FT_ENCODING_ADOBE_CUSTOM;
+            clazz               = &cff_cmap_encoding_class_rec;
+          }
+
+          FT_CMap_New( clazz, NULL, &cmaprec, NULL );
+        }
+
+      }
+    }
+
+  Exit:
+    return error;
+
+  Bad_Format:
+    error = CFF_Err_Unknown_File_Format;
+    goto Exit;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cff_face_done( CFF_Face  face )
+  {
+    FT_Memory     memory = face->root.memory;
+    SFNT_Service  sfnt   = (SFNT_Service)face->sfnt;
+
+
+    if ( sfnt )
+      sfnt->done_face( face );
+
+    {
+      CFF_Font  cff = (CFF_Font)face->extra.data;
+
+
+      if ( cff )
+      {
+        cff_font_done( cff );
+        FT_FREE( face->extra.data );
+      }
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_driver_init( CFF_Driver  driver )
+  {
+    FT_UNUSED( driver );
+
+    return CFF_Err_Ok;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cff_driver_done( CFF_Driver  driver )
+  {
+    FT_UNUSED( driver );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffobjs.h
@@ -1,0 +1,160 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffobjs.h                                                              */
+/*                                                                         */
+/*    OpenType objects manager (specification).                            */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CFFOBJS_H__
+#define __CFFOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    CFF_Driver                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to an OpenType driver object.                             */
+  /*                                                                       */
+  typedef struct CFF_DriverRec_*  CFF_Driver;
+
+  typedef TT_Face  CFF_Face;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    CFF_Size                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to an OpenType size object.                               */
+  /*                                                                       */
+  typedef FT_Size  CFF_Size;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    CFF_GlyphSlot                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to an OpenType glyph slot object.                         */
+  /*                                                                       */
+  typedef struct  CFF_GlyphSlotRec_
+  {
+    FT_GlyphSlotRec  root;
+
+    FT_Bool          hint;
+    FT_Bool          scaled;
+
+    FT_Fixed         x_scale;
+    FT_Fixed         y_scale;
+
+  } CFF_GlyphSlotRec, *CFF_GlyphSlot;
+
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Subglyph transformation record.                                       */
+  /*                                                                       */
+  typedef struct  CFF_Transform_
+  {
+    FT_Fixed    xx, xy;     /* transformation matrix coefficients */
+    FT_Fixed    yx, yy;
+    FT_F26Dot6  ox, oy;     /* offsets        */
+
+  } CFF_Transform;
+
+
+  /* this is only used in the case of a pure CFF font with no charmap */
+  typedef struct  CFF_CharMapRec_
+  {
+    TT_CharMapRec  root;
+    PS_Unicodes    unicodes;
+
+  } CFF_CharMapRec, *CFF_CharMap;
+
+
+  /***********************************************************************/
+  /*                                                                     */
+  /* TrueType driver class.                                              */
+  /*                                                                     */
+  typedef struct  CFF_DriverRec_
+  {
+    FT_DriverRec  root;
+    void*         extension_component;
+
+  } CFF_DriverRec;
+
+
+  FT_LOCAL( FT_Error )
+  cff_size_init( CFF_Size  size );
+
+  FT_LOCAL( void )
+  cff_size_done( CFF_Size  size );
+
+  FT_LOCAL( FT_Error )
+  cff_size_reset( CFF_Size  size );
+
+  FT_LOCAL( void )
+  cff_slot_done( CFF_GlyphSlot  slot );
+
+  FT_LOCAL( FT_Error )
+  cff_slot_init( CFF_GlyphSlot   slot );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Face functions                                                        */
+  /*                                                                       */
+  FT_LOCAL( FT_Error )
+  cff_face_init( FT_Stream      stream,
+                 CFF_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params );
+
+  FT_LOCAL( void )
+  cff_face_done( CFF_Face  face );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Driver functions                                                      */
+  /*                                                                       */
+  FT_LOCAL( FT_Error )
+  cff_driver_init( CFF_Driver  driver );
+
+  FT_LOCAL( void )
+  cff_driver_done( CFF_Driver  driver );
+
+
+FT_END_HEADER
+
+#endif /* __CFFOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffparse.c
@@ -1,0 +1,681 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffparse.c                                                             */
+/*                                                                         */
+/*    CFF token stream parser (body)                                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cffparse.h"
+#include FT_INTERNAL_STREAM_H
+
+#include "cfferrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cffparse
+
+
+  enum
+  {
+    cff_kind_none = 0,
+    cff_kind_num,
+    cff_kind_fixed,
+    cff_kind_string,
+    cff_kind_bool,
+    cff_kind_delta,
+    cff_kind_callback,
+
+    cff_kind_max  /* do not remove */
+  };
+
+
+  /* now generate handlers for the most simple fields */
+  typedef FT_Error  (*CFF_Field_Reader)( CFF_Parser  parser );
+
+  typedef struct  CFF_Field_Handler_
+  {
+    int               kind;
+    int               code;
+    FT_UInt           offset;
+    FT_Byte           size;
+    CFF_Field_Reader  reader;
+    FT_UInt           array_max;
+    FT_UInt           count_offset;
+
+  } CFF_Field_Handler;
+
+
+  FT_LOCAL_DEF( void )
+  cff_parser_init( CFF_Parser  parser,
+                   FT_UInt     code,
+                   void*       object )
+  {
+    FT_MEM_ZERO( parser, sizeof ( *parser ) );
+
+    parser->top         = parser->stack;
+    parser->object_code = code;
+    parser->object      = object;
+  }
+
+
+  /* read an integer */
+  static FT_Long
+  cff_parse_integer( FT_Byte*  start,
+                     FT_Byte*  limit )
+  {
+    FT_Byte*  p   = start;
+    FT_Int    v   = *p++;
+    FT_Long   val = 0;
+
+
+    if ( v == 28 )
+    {
+      if ( p + 2 > limit )
+        goto Bad;
+
+      val = (FT_Short)( ( (FT_Int)p[0] << 8 ) | p[1] );
+      p  += 2;
+    }
+    else if ( v == 29 )
+    {
+      if ( p + 4 > limit )
+        goto Bad;
+
+      val = ( (FT_Long)p[0] << 24 ) |
+            ( (FT_Long)p[1] << 16 ) |
+            ( (FT_Long)p[2] <<  8 ) |
+                       p[3];
+      p += 4;
+    }
+    else if ( v < 247 )
+    {
+      val = v - 139;
+    }
+    else if ( v < 251 )
+    {
+      if ( p + 1 > limit )
+        goto Bad;
+
+      val = ( v - 247 ) * 256 + p[0] + 108;
+      p++;
+    }
+    else
+    {
+      if ( p + 1 > limit )
+        goto Bad;
+
+      val = -( v - 251 ) * 256 - p[0] - 108;
+      p++;
+    }
+
+  Exit:
+    return val;
+
+  Bad:
+    val = 0;
+    goto Exit;
+  }
+
+
+  /* read a real */
+  static FT_Fixed
+  cff_parse_real( FT_Byte*  start,
+                  FT_Byte*  limit,
+                  FT_Int    power_ten )
+  {
+    FT_Byte*  p    = start;
+    FT_Long   num, divider, result, exp;
+    FT_Int    sign = 0, exp_sign = 0;
+    FT_UInt   nib;
+    FT_UInt   phase;
+
+
+    result  = 0;
+    num     = 0;
+    divider = 1;
+
+    /* first of all, read the integer part */
+    phase = 4;
+
+    for (;;)
+    {
+      /* If we entered this iteration with phase == 4, we need to */
+      /* read a new byte.  This also skips past the intial 0x1E.  */
+      if ( phase )
+      {
+        p++;
+
+        /* Make sure we don't read past the end. */
+        if ( p >= limit )
+          goto Bad;
+      }
+
+      /* Get the nibble. */
+      nib   = ( p[0] >> phase ) & 0xF;
+      phase = 4 - phase;
+
+      if ( nib == 0xE )
+        sign = 1;
+      else if ( nib > 9 )
+        break;
+      else
+        result = result * 10 + nib;
+    }
+
+    /* read decimal part, if any */
+    if ( nib == 0xa )
+      for (;;)
+      {
+        /* If we entered this iteration with phase == 4, we need */
+        /* to read a new byte.                                   */
+        if ( phase )
+        {
+          p++;
+
+          /* Make sure we don't read past the end. */
+          if ( p >= limit )
+            goto Bad;
+        }
+
+        /* Get the nibble. */
+        nib   = ( p[0] >> phase ) & 0xF;
+        phase = 4 - phase;
+        if ( nib >= 10 )
+          break;
+
+        if ( divider < 10000000L )
+        {
+          num      = num * 10 + nib;
+          divider *= 10;
+        }
+      }
+
+    /* read exponent, if any */
+    if ( nib == 12 )
+    {
+      exp_sign = 1;
+      nib      = 11;
+    }
+
+    if ( nib == 11 )
+    {
+      exp = 0;
+
+      for (;;)
+      {
+        /* If we entered this iteration with phase == 4, we need */
+        /* to read a new byte.                                   */
+        if ( phase )
+        {
+          p++;
+
+          /* Make sure we don't read past the end. */
+          if ( p >= limit )
+            goto Bad;
+        }
+
+        /* Get the nibble. */
+        nib   = ( p[0] >> phase ) & 0xF;
+        phase = 4 - phase;
+        if ( nib >= 10 )
+          break;
+
+        exp = exp * 10 + nib;
+      }
+
+      if ( exp_sign )
+        exp = -exp;
+
+      power_ten += (FT_Int)exp;
+    }
+
+    /* raise to power of ten if needed */
+    while ( power_ten > 0 )
+    {
+      result = result * 10;
+      num    = num * 10;
+
+      power_ten--;
+    }
+
+    while ( power_ten < 0 )
+    {
+      result  = result / 10;
+      divider = divider * 10;
+
+      power_ten++;
+    }
+
+    /* Move the integer part into the high 16 bits. */
+    result <<= 16;
+
+    /* Place the decimal part into the low 16 bits. */
+    if ( num )
+      result |= FT_DivFix( num, divider );
+
+    if ( sign )
+      result = -result;
+
+  Exit:
+    return result;
+
+  Bad:
+    result = 0;
+    goto Exit;
+  }
+
+
+  /* read a number, either integer or real */
+  static FT_Long
+  cff_parse_num( FT_Byte**  d )
+  {
+    return ( **d == 30 ? ( cff_parse_real   ( d[0], d[1], 0 ) >> 16 )
+                       :   cff_parse_integer( d[0], d[1] ) );
+  }
+
+
+  /* read a floating point number, either integer or real */
+  static FT_Fixed
+  cff_parse_fixed( FT_Byte**  d )
+  {
+    return ( **d == 30 ? cff_parse_real   ( d[0], d[1], 0 )
+                       : cff_parse_integer( d[0], d[1] ) << 16 );
+  }
+
+  /* read a floating point number, either integer or real, */
+  /* but return 1000 times the number read in.             */
+  static FT_Fixed
+  cff_parse_fixed_thousand( FT_Byte**  d )
+  {
+    return **d ==
+      30 ? cff_parse_real     ( d[0], d[1], 3 )
+         : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 );
+  }
+
+  static FT_Error
+  cff_parse_font_matrix( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict   = (CFF_FontRecDict)parser->object;
+    FT_Matrix*       matrix = &dict->font_matrix;
+    FT_Vector*       offset = &dict->font_offset;
+    FT_UShort*       upm    = &dict->units_per_em;
+    FT_Byte**        data   = parser->stack;
+    FT_Error         error;
+    FT_Fixed         temp;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 6 )
+    {
+      matrix->xx = cff_parse_fixed_thousand( data++ );
+      matrix->yx = cff_parse_fixed_thousand( data++ );
+      matrix->xy = cff_parse_fixed_thousand( data++ );
+      matrix->yy = cff_parse_fixed_thousand( data++ );
+      offset->x  = cff_parse_fixed_thousand( data++ );
+      offset->y  = cff_parse_fixed_thousand( data   );
+
+      temp = ABS( matrix->yy );
+
+      *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) );
+
+      if ( temp != 0x10000L )
+      {
+        matrix->xx = FT_DivFix( matrix->xx, temp );
+        matrix->yx = FT_DivFix( matrix->yx, temp );
+        matrix->xy = FT_DivFix( matrix->xy, temp );
+        matrix->yy = FT_DivFix( matrix->yy, temp );
+        offset->x  = FT_DivFix( offset->x,  temp );
+        offset->y  = FT_DivFix( offset->y,  temp );
+      }
+
+      /* note that the offsets must be expressed in integer font units */
+      offset->x >>= 16;
+      offset->y >>= 16;
+
+      error = CFF_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  cff_parse_font_bbox( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
+    FT_BBox*         bbox = &dict->font_bbox;
+    FT_Byte**        data = parser->stack;
+    FT_Error         error;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 4 )
+    {
+      bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+      bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+      bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) );
+      bbox->yMax = FT_RoundFix( cff_parse_fixed( data   ) );
+      error = CFF_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  cff_parse_private_dict( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
+    FT_Byte**        data = parser->stack;
+    FT_Error         error;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 2 )
+    {
+      dict->private_size   = cff_parse_num( data++ );
+      dict->private_offset = cff_parse_num( data   );
+      error = CFF_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  cff_parse_cid_ros( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
+    FT_Byte**        data = parser->stack;
+    FT_Error         error;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 3 )
+    {
+      dict->cid_registry   = (FT_UInt)cff_parse_num ( data++ );
+      dict->cid_ordering   = (FT_UInt)cff_parse_num ( data++ );
+      dict->cid_supplement = (FT_ULong)cff_parse_num( data );
+      error = CFF_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+#define CFF_FIELD_NUM( code, name ) \
+          CFF_FIELD( code, name, cff_kind_num )
+#define CFF_FIELD_FIXED( code, name ) \
+          CFF_FIELD( code, name, cff_kind_fixed )
+#define CFF_FIELD_STRING( code, name ) \
+          CFF_FIELD( code, name, cff_kind_string )
+#define CFF_FIELD_BOOL( code, name ) \
+          CFF_FIELD( code, name, cff_kind_bool )
+#define CFF_FIELD_DELTA( code, name, max ) \
+          CFF_FIELD( code, name, cff_kind_delta )
+
+#define CFF_FIELD_CALLBACK( code, name ) \
+          {                              \
+            cff_kind_callback,           \
+            code | CFFCODE,              \
+            0, 0,                        \
+            cff_parse_ ## name,          \
+            0, 0                         \
+          },
+
+#undef  CFF_FIELD
+#define CFF_FIELD( code, name, kind ) \
+          {                          \
+            kind,                    \
+            code | CFFCODE,          \
+            FT_FIELD_OFFSET( name ), \
+            FT_FIELD_SIZE( name ),   \
+            0, 0, 0                  \
+          },
+
+#undef  CFF_FIELD_DELTA
+#define CFF_FIELD_DELTA( code, name, max ) \
+        {                                  \
+          cff_kind_delta,                  \
+          code | CFFCODE,                  \
+          FT_FIELD_OFFSET( name ),         \
+          FT_FIELD_SIZE_DELTA( name ),     \
+          0,                               \
+          max,                             \
+          FT_FIELD_OFFSET( num_ ## name )  \
+        },
+
+#define CFFCODE_TOPDICT  0x1000
+#define CFFCODE_PRIVATE  0x2000
+
+  static const CFF_Field_Handler  cff_field_handlers[] =
+  {
+
+#include "cfftoken.h"
+
+    { 0, 0, 0, 0, 0, 0, 0 }
+  };
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_parser_run( CFF_Parser  parser,
+                  FT_Byte*    start,
+                  FT_Byte*    limit )
+  {
+    FT_Byte*  p     = start;
+    FT_Error  error = CFF_Err_Ok;
+
+
+    parser->top    = parser->stack;
+    parser->start  = start;
+    parser->limit  = limit;
+    parser->cursor = start;
+
+    while ( p < limit )
+    {
+      FT_UInt  v = *p;
+
+
+      if ( v >= 27 && v != 31 )
+      {
+        /* it's a number; we will push its position on the stack */
+        if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
+          goto Stack_Overflow;
+
+        *parser->top ++ = p;
+
+        /* now, skip it */
+        if ( v == 30 )
+        {
+          /* skip real number */
+          p++;
+          for (;;)
+          {
+            if ( p >= limit )
+              goto Syntax_Error;
+            v = p[0] >> 4;
+            if ( v == 15 )
+              break;
+            v = p[0] & 0xF;
+            if ( v == 15 )
+              break;
+            p++;
+          }
+        }
+        else if ( v == 28 )
+          p += 2;
+        else if ( v == 29 )
+          p += 4;
+        else if ( v > 246 )
+          p += 1;
+      }
+      else
+      {
+        /* This is not a number, hence it's an operator.  Compute its code */
+        /* and look for it in our current list.                            */
+
+        FT_UInt                   code;
+        FT_UInt                   num_args = (FT_UInt)
+                                             ( parser->top - parser->stack );
+        const CFF_Field_Handler*  field;
+
+
+        *parser->top = p;
+        code = v;
+        if ( v == 12 )
+        {
+          /* two byte operator */
+          p++;
+          if ( p >= limit )
+            goto Syntax_Error;
+
+          code = 0x100 | p[0];
+        }
+        code = code | parser->object_code;
+
+        for ( field = cff_field_handlers; field->kind; field++ )
+        {
+          if ( field->code == (FT_Int)code )
+          {
+            /* we found our field's handler; read it */
+            FT_Long   val;
+            FT_Byte*  q = (FT_Byte*)parser->object + field->offset;
+
+
+            /* check that we have enough arguments -- except for */
+            /* delta encoded arrays, which can be empty          */
+            if ( field->kind != cff_kind_delta && num_args < 1 )
+              goto Stack_Underflow;
+
+            switch ( field->kind )
+            {
+            case cff_kind_bool:
+            case cff_kind_string:
+            case cff_kind_num:
+              val = cff_parse_num( parser->stack );
+              goto Store_Number;
+
+            case cff_kind_fixed:
+              val = cff_parse_fixed( parser->stack );
+
+            Store_Number:
+              switch ( field->size )
+              {
+              case 1:
+                *(FT_Byte*)q = (FT_Byte)val;
+                break;
+
+              case 2:
+                *(FT_Short*)q = (FT_Short)val;
+                break;
+
+              case 4:
+                *(FT_Int32*)q = (FT_Int)val;
+                break;
+
+              default:  /* for 64-bit systems where long is 8 bytes */
+                *(FT_Long*)q = val;
+              }
+              break;
+
+            case cff_kind_delta:
+              {
+                FT_Byte*   qcount = (FT_Byte*)parser->object +
+                                      field->count_offset;
+
+                FT_Byte**  data = parser->stack;
+
+
+                if ( num_args > field->array_max )
+                  num_args = field->array_max;
+
+                /* store count */
+                *qcount = (FT_Byte)num_args;
+
+                val = 0;
+                while ( num_args > 0 )
+                {
+                  val += cff_parse_num( data++ );
+                  switch ( field->size )
+                  {
+                  case 1:
+                    *(FT_Byte*)q = (FT_Byte)val;
+                    break;
+
+                  case 2:
+                    *(FT_Short*)q = (FT_Short)val;
+                    break;
+
+                  case 4:
+                    *(FT_Int32*)q = (FT_Int)val;
+                    break;
+
+                  default:  /* for 64-bit systems */
+                    *(FT_Long*)q = val;
+                  }
+
+                  q += field->size;
+                  num_args--;
+                }
+              }
+              break;
+
+            default:  /* callback */
+              error = field->reader( parser );
+              if ( error )
+                goto Exit;
+            }
+            goto Found;
+          }
+        }
+
+        /* this is an unknown operator, or it is unsupported; */
+        /* we will ignore it for now.                         */
+
+      Found:
+        /* clear stack */
+        parser->top = parser->stack;
+      }
+      p++;
+    }
+
+  Exit:
+    return error;
+
+  Stack_Overflow:
+    error = CFF_Err_Invalid_Argument;
+    goto Exit;
+
+  Stack_Underflow:
+    error = CFF_Err_Invalid_Argument;
+    goto Exit;
+
+  Syntax_Error:
+    error = CFF_Err_Invalid_Argument;
+    goto Exit;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cffparse.h
@@ -1,0 +1,69 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffparse.h                                                             */
+/*                                                                         */
+/*    CFF token stream parser (specification)                              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CFF_PARSE_H__
+#define __CFF_PARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CFF_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+#define CFF_MAX_STACK_DEPTH  96
+
+#define CFF_CODE_TOPDICT  0x1000
+#define CFF_CODE_PRIVATE  0x2000
+
+
+  typedef struct  CFF_ParserRec_
+  {
+    FT_Byte*   start;
+    FT_Byte*   limit;
+    FT_Byte*   cursor;
+
+    FT_Byte*   stack[CFF_MAX_STACK_DEPTH + 1];
+    FT_Byte**  top;
+
+    FT_UInt    object_code;
+    void*      object;
+
+  } CFF_ParserRec, *CFF_Parser;
+
+
+  FT_LOCAL( void )
+  cff_parser_init( CFF_Parser  parser,
+                   FT_UInt     code,
+                   void*       object );
+
+  FT_LOCAL( FT_Error )
+  cff_parser_run( CFF_Parser  parser,
+                  FT_Byte*    start,
+                  FT_Byte*    limit );
+
+
+FT_END_HEADER
+
+
+#endif /* __CFF_PARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cfftoken.h
@@ -1,0 +1,97 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cfftoken.h                                                             */
+/*                                                                         */
+/*    CFF token definitions (specification only).                          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CFF_FontRecDictRec
+
+#undef  CFFCODE
+#define CFFCODE       CFFCODE_TOPDICT
+
+  CFF_FIELD_STRING  ( 0,     version )
+  CFF_FIELD_STRING  ( 1,     notice )
+  CFF_FIELD_STRING  ( 0x100, copyright )
+  CFF_FIELD_STRING  ( 2,     full_name )
+  CFF_FIELD_STRING  ( 3,     family_name )
+  CFF_FIELD_STRING  ( 4,     weight )
+  CFF_FIELD_BOOL    ( 0x101, is_fixed_pitch )
+  CFF_FIELD_FIXED   ( 0x102, italic_angle )
+  CFF_FIELD_NUM     ( 0x103, underline_position )
+  CFF_FIELD_NUM     ( 0x104, underline_thickness )
+  CFF_FIELD_NUM     ( 0x105, paint_type )
+  CFF_FIELD_NUM     ( 0x106, charstring_type )
+  CFF_FIELD_CALLBACK( 0x107, font_matrix )
+  CFF_FIELD_NUM     ( 13,    unique_id )
+  CFF_FIELD_CALLBACK( 5,     font_bbox )
+  CFF_FIELD_NUM     ( 0x108, stroke_width )
+  CFF_FIELD_NUM     ( 15,    charset_offset )
+  CFF_FIELD_NUM     ( 16,    encoding_offset )
+  CFF_FIELD_NUM     ( 17,    charstrings_offset )
+  CFF_FIELD_CALLBACK( 18,    private_dict )
+  CFF_FIELD_NUM     ( 0x114, synthetic_base )
+  CFF_FIELD_STRING  ( 0x115, postscript )
+  CFF_FIELD_STRING  ( 0x116, base_font_name )
+
+#if 0
+  CFF_FIELD_DELTA   ( 0x117, base_font_blend, 16 )
+  CFF_FIELD_CALLBACK( 0x118, multiple_master )
+  CFF_FIELD_CALLBACK( 0x119, blend_axit_types )
+#endif
+
+  CFF_FIELD_CALLBACK( 0x11E, cid_ros )
+  CFF_FIELD_NUM     ( 0x11F, cid_font_version )
+  CFF_FIELD_NUM     ( 0x120, cid_font_revision )
+  CFF_FIELD_NUM     ( 0x121, cid_font_type )
+  CFF_FIELD_NUM     ( 0x122, cid_count )
+  CFF_FIELD_NUM     ( 0x123, cid_uid_base )
+  CFF_FIELD_NUM     ( 0x124, cid_fd_array_offset )
+  CFF_FIELD_NUM     ( 0x125, cid_fd_select_offset )
+  CFF_FIELD_STRING  ( 0x126, cid_font_name )
+
+#if 0
+  CFF_FIELD_NUM     ( 0x127, chameleon )
+#endif
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CFF_PrivateRec
+#undef  CFFCODE
+#define CFFCODE       CFFCODE_PRIVATE
+
+  CFF_FIELD_DELTA( 6,     blue_values, 14 )
+  CFF_FIELD_DELTA( 7,     other_blues, 10 )
+  CFF_FIELD_DELTA( 8,     family_blues, 14 )
+  CFF_FIELD_DELTA( 9,     family_other_blues, 10 )
+  CFF_FIELD_FIXED( 0x109, blue_scale )
+  CFF_FIELD_NUM  ( 0x10A, blue_shift )
+  CFF_FIELD_NUM  ( 0x10B, blue_fuzz )
+  CFF_FIELD_NUM  ( 10,    standard_width )
+  CFF_FIELD_NUM  ( 11,    standard_height )
+  CFF_FIELD_DELTA( 0x10C, snap_widths, 13 )
+  CFF_FIELD_DELTA( 0x10D, snap_heights, 13 )
+  CFF_FIELD_BOOL ( 0x10E, force_bold )
+  CFF_FIELD_FIXED( 0x10F, force_bold_threshold )
+  CFF_FIELD_NUM  ( 0x110, lenIV )
+  CFF_FIELD_NUM  ( 0x111, language_group )
+  CFF_FIELD_FIXED( 0x112, expansion_factor )
+  CFF_FIELD_NUM  ( 0x113, initial_random_seed )
+  CFF_FIELD_NUM  ( 19,    local_subrs_offset )
+  CFF_FIELD_NUM  ( 20,    default_width )
+  CFF_FIELD_NUM  ( 21,    nominal_width )
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ciderrs.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ciderrs.h                                                              */
+/*                                                                         */
+/*    CID error codes (specification only).                                */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the CID error enumeration constants.      */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __CIDERRS_H__
+#define __CIDERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  CID_Err_
+#define FT_ERR_BASE    FT_Mod_Err_CID
+
+#include FT_ERRORS_H
+
+#endif /* __CIDERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidgload.c
@@ -1,0 +1,437 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidgload.c                                                             */
+/*                                                                         */
+/*    CID-keyed Type1 Glyph Loader (body).                                 */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cidload.h"
+#include "cidgload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_OUTLINE_H
+
+#include "ciderrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cidgload
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  cid_load_glyph( T1_Decoder  decoder,
+                  FT_UInt     glyph_index )
+  {
+    CID_Face      face = (CID_Face)decoder->builder.face;
+    CID_FaceInfo  cid  = &face->cid;
+    FT_Byte*      p;
+    FT_UInt       fd_select;
+    FT_Stream     stream = face->root.stream;
+    FT_Error      error  = 0;
+    FT_Byte*      charstring = 0;
+    FT_Memory     memory = face->root.memory;
+    FT_UInt       glyph_length = 0;
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    /* For incremental fonts get the character data using */
+    /* the callback function.                             */
+    if ( face->root.internal->incremental_interface )
+    {
+      FT_Data  glyph_data;
+
+
+      error = face->root.internal->incremental_interface->funcs->get_glyph_data(
+                face->root.internal->incremental_interface->object,
+                glyph_index,
+                &glyph_data );
+      if ( error )
+        goto Exit;
+
+      p         = (FT_Byte*)glyph_data.pointer;
+      fd_select = (FT_UInt)cid_get_offset( &p, (FT_Byte)cid->fd_bytes );
+
+      if ( glyph_data.length != 0 )
+      {
+        glyph_length = glyph_data.length - cid->fd_bytes;
+        FT_ALLOC( charstring, glyph_length );
+        if ( !error )
+          ft_memcpy( charstring, glyph_data.pointer + cid->fd_bytes,
+                     glyph_length );
+      }
+
+      face->root.internal->incremental_interface->funcs->free_glyph_data(
+                face->root.internal->incremental_interface->object,
+                &glyph_data );
+
+      if ( error )
+        goto Exit;
+    }
+
+    else
+
+#endif
+
+    /* For ordinary fonts read the CID font dictionary index */
+    /* and charstring offset from the CIDMap.                */
+    {
+      FT_UInt   entry_len = cid->fd_bytes + cid->gd_bytes;
+      FT_ULong  off1;
+
+
+      if ( FT_STREAM_SEEK( cid->data_offset + cid->cidmap_offset +
+                           glyph_index * entry_len )               ||
+           FT_FRAME_ENTER( 2 * entry_len )                         )
+        goto Exit;
+
+      p            = (FT_Byte*)stream->cursor;
+      fd_select    = (FT_UInt) cid_get_offset( &p, (FT_Byte)cid->fd_bytes );
+      off1         = (FT_ULong)cid_get_offset( &p, (FT_Byte)cid->gd_bytes );
+      p           += cid->fd_bytes;
+      glyph_length = (FT_UInt) cid_get_offset(
+                                 &p, (FT_Byte)cid->gd_bytes ) - off1;
+      FT_FRAME_EXIT();
+
+      if ( glyph_length == 0 )
+        goto Exit;
+      if ( FT_ALLOC( charstring, glyph_length ) )
+        goto Exit;
+      if ( FT_STREAM_READ_AT( cid->data_offset + off1,
+                              charstring, glyph_length ) )
+        goto Exit;
+    }
+
+    /* Now set up the subrs array and parse the charstrings. */
+    {
+      CID_FaceDict  dict;
+      CID_Subrs     cid_subrs = face->subrs + fd_select;
+      FT_Int        cs_offset;
+
+
+      /* Set up subrs */
+      decoder->num_subrs = cid_subrs->num_subrs;
+      decoder->subrs     = cid_subrs->code;
+      decoder->subrs_len = 0;
+
+      /* Set up font matrix */
+      dict                 = cid->font_dicts + fd_select;
+
+      decoder->font_matrix = dict->font_matrix;
+      decoder->font_offset = dict->font_offset;
+      decoder->lenIV       = dict->private_dict.lenIV;
+
+      /* Decode the charstring. */
+
+      /* Adjustment for seed bytes. */
+      cs_offset = ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
+
+      /* Decrypt only if lenIV >= 0. */
+      if ( decoder->lenIV >= 0 )
+        cid_decrypt( charstring, glyph_length, 4330 );
+
+      error = decoder->funcs.parse_charstrings( decoder,
+                                                charstring + cs_offset,
+                                                glyph_length - cs_offset  );
+    }
+
+    FT_FREE( charstring );
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    /* Incremental fonts can optionally override the metrics. */
+    if ( !error                                       &&
+         face->root.internal->incremental_interface   &&
+         face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+    {
+      FT_Bool                    found = FALSE;
+      FT_Incremental_MetricsRec  metrics;
+
+
+      error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+                face->root.internal->incremental_interface->object,
+                glyph_index, FALSE, &metrics, &found );
+      if ( found )
+      {
+        decoder->builder.left_bearing.x = metrics.bearing_x;
+        decoder->builder.left_bearing.y = metrics.bearing_y;
+        decoder->builder.advance.x      = metrics.advance;
+        decoder->builder.advance.y      = 0;
+      }
+    }
+
+#endif
+
+  Exit:
+    return error;
+  }
+
+
+#if 0
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /**********                                                      *********/
+  /**********                                                      *********/
+  /**********            COMPUTE THE MAXIMUM ADVANCE WIDTH         *********/
+  /**********                                                      *********/
+  /**********    The following code is in charge of computing      *********/
+  /**********    the maximum advance width of the font.  It        *********/
+  /**********    quickly processes each glyph charstring to        *********/
+  /**********    extract the value from either a `sbw' or `seac'   *********/
+  /**********    operator.                                         *********/
+  /**********                                                      *********/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cid_face_compute_max_advance( CID_Face  face,
+                                FT_Int*   max_advance )
+  {
+    FT_Error       error;
+    T1_DecoderRec  decoder;
+    FT_Int         glyph_index;
+
+    PSAux_Service  psaux = (PSAux_Service)face->psaux;
+
+
+    *max_advance = 0;
+
+    /* Initialize load decoder */
+    error = psaux->t1_decoder_funcs->init( &decoder,
+                                           (FT_Face)face,
+                                           0, /* size       */
+                                           0, /* glyph slot */
+                                           0, /* glyph names! XXX */
+                                           0, /* blend == 0 */
+                                           0, /* hinting == 0 */
+                                           cid_load_glyph );
+    if ( error )
+      return error;
+
+    decoder.builder.metrics_only = 1;
+    decoder.builder.load_points  = 0;
+
+    /* for each glyph, parse the glyph charstring and extract */
+    /* the advance width                                      */
+    for ( glyph_index = 0; glyph_index < face->root.num_glyphs;
+          glyph_index++ )
+    {
+      /* now get load the unscaled outline */
+      error = cid_load_glyph( &decoder, glyph_index );
+      /* ignore the error if one occurred - skip to next glyph */
+    }
+
+    *max_advance = decoder.builder.advance.x;
+
+    return CID_Err_Ok;
+  }
+
+
+#endif /* 0 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /**********                                                      *********/
+  /**********                                                      *********/
+  /**********               UNHINTED GLYPH LOADER                  *********/
+  /**********                                                      *********/
+  /**********    The following code is in charge of loading a      *********/
+  /**********    single outline.  It completely ignores hinting    *********/
+  /**********    and is used when FT_LOAD_NO_HINTING is set.       *********/
+  /**********                                                      *********/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cid_slot_load_glyph( CID_GlyphSlot  glyph,
+                       CID_Size       size,
+                       FT_Int         glyph_index,
+                       FT_Int32       load_flags )
+  {
+    FT_Error       error;
+    T1_DecoderRec  decoder;
+    CID_Face       face = (CID_Face)glyph->root.face;
+    FT_Bool        hinting;
+
+    PSAux_Service  psaux = (PSAux_Service)face->psaux;
+    FT_Matrix      font_matrix;
+    FT_Vector      font_offset;
+
+
+    if ( load_flags & FT_LOAD_NO_RECURSE )
+      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+    glyph->x_scale = size->root.metrics.x_scale;
+    glyph->y_scale = size->root.metrics.y_scale;
+
+    glyph->root.outline.n_points   = 0;
+    glyph->root.outline.n_contours = 0;
+
+    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 &&
+                       ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+    glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+    {
+      error = psaux->t1_decoder_funcs->init( &decoder,
+                                             (FT_Face)face,
+                                             (FT_Size)size,
+                                             (FT_GlyphSlot)glyph,
+                                             0, /* glyph names -- XXX */
+                                             0, /* blend == 0 */
+                                             hinting,
+                                             FT_LOAD_TARGET_MODE(load_flags),
+                                             cid_load_glyph );
+
+      /* set up the decoder */
+      decoder.builder.no_recurse = FT_BOOL(
+        ( ( load_flags & FT_LOAD_NO_RECURSE ) != 0 ) );
+
+      error = cid_load_glyph( &decoder, glyph_index );
+
+      font_matrix = decoder.font_matrix;
+      font_offset = decoder.font_offset;
+
+      /* save new glyph tables */
+      psaux->t1_decoder_funcs->done( &decoder );
+    }
+
+    /* now, set the metrics -- this is rather simple, as   */
+    /* the left side bearing is the xMin, and the top side */
+    /* bearing the yMax                                    */
+    if ( !error )
+    {
+      glyph->root.outline.flags &= FT_OUTLINE_OWNER;
+      glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
+
+      /* for composite glyphs, return only left side bearing and */
+      /* advance width                                           */
+      if ( load_flags & FT_LOAD_NO_RECURSE )
+      {
+        FT_Slot_Internal  internal = glyph->root.internal;
+
+
+        glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+        glyph->root.metrics.horiAdvance  = decoder.builder.advance.x;
+
+        internal->glyph_matrix         = font_matrix;
+        internal->glyph_delta          = font_offset;
+        internal->glyph_transformed    = 1;
+      }
+      else
+      {
+        FT_BBox            cbox;
+        FT_Glyph_Metrics*  metrics = &glyph->root.metrics;
+
+
+        /* copy the _unscaled_ advance width */
+        metrics->horiAdvance          = decoder.builder.advance.x;
+        glyph->root.linearHoriAdvance = decoder.builder.advance.x;
+        glyph->root.internal->glyph_transformed = 0;
+
+        /* make up vertical metrics */
+        metrics->vertBearingX = 0;
+        metrics->vertBearingY = 0;
+        metrics->vertAdvance  = 0;
+
+        glyph->root.linearVertAdvance = 0;
+        glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+        if ( size && size->root.metrics.y_ppem < 24 )
+          glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+        /* apply the font matrix */
+        FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+        FT_Outline_Translate( &glyph->root.outline,
+                              font_offset.x,
+                              font_offset.y );
+
+        if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+        {
+          /* scale the outline and the metrics */
+          FT_Int       n;
+          FT_Outline*  cur = decoder.builder.base;
+          FT_Vector*   vec = cur->points;
+          FT_Fixed     x_scale = glyph->x_scale;
+          FT_Fixed     y_scale = glyph->y_scale;
+
+
+          /* First of all, scale the points */
+          if ( !hinting )
+            for ( n = cur->n_points; n > 0; n--, vec++ )
+            {
+              vec->x = FT_MulFix( vec->x, x_scale );
+              vec->y = FT_MulFix( vec->y, y_scale );
+            }
+
+          FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+          /* Then scale the metrics */
+          metrics->horiAdvance  = FT_MulFix( metrics->horiAdvance,  x_scale );
+          metrics->vertAdvance  = FT_MulFix( metrics->vertAdvance,  y_scale );
+
+          metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+          metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+
+          if ( hinting )
+          {
+            metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
+            metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
+
+            metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
+            metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
+          }
+        }
+
+        /* compute the other metrics */
+        FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+        /* grid fit the bounding box if necessary */
+        if ( hinting )
+        {
+          cbox.xMin &= -64;
+          cbox.yMin &= -64;
+          cbox.xMax  = ( cbox.xMax + 63 ) & -64;
+          cbox.yMax  = ( cbox.yMax + 63 ) & -64;
+        }
+
+        metrics->width  = cbox.xMax - cbox.xMin;
+        metrics->height = cbox.yMax - cbox.yMin;
+
+        metrics->horiBearingX = cbox.xMin;
+        metrics->horiBearingY = cbox.yMax;
+      }
+    }
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidgload.h
@@ -1,0 +1,51 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidgload.h                                                             */
+/*                                                                         */
+/*    OpenType Glyph Loader (specification).                               */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CIDGLOAD_H__
+#define __CIDGLOAD_H__
+
+
+#include <ft2build.h>
+#include "cidobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#if 0
+
+  /* Compute the maximum advance width of a font through quick parsing */
+  FT_LOCAL( FT_Error )
+  cid_face_compute_max_advance( CID_Face  face,
+                                FT_Int*   max_advance );
+
+#endif /* 0 */
+
+  FT_LOCAL( FT_Error )
+  cid_slot_load_glyph( CID_GlyphSlot  glyph,
+                       CID_Size       size,
+                       FT_Int         glyph_index,
+                       FT_Int32       load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __CIDGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidload.c
@@ -1,0 +1,546 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidload.c                                                              */
+/*                                                                         */
+/*    CID-keyed Type1 font loader (body).                                  */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_CONFIG_CONFIG_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+#include "cidload.h"
+
+#include "ciderrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cidload
+
+
+  /* read a single offset */
+  FT_LOCAL_DEF( FT_Long )
+  cid_get_offset( FT_Byte**  start,
+                  FT_Byte    offsize )
+  {
+    FT_Long   result;
+    FT_Byte*  p = *start;
+
+
+    for ( result = 0; offsize > 0; offsize-- )
+    {
+      result <<= 8;
+      result  |= *p++;
+    }
+
+    *start = p;
+    return result;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cid_decrypt( FT_Byte*   buffer,
+               FT_Offset  length,
+               FT_UShort  seed )
+  {
+    while ( length > 0 )
+    {
+      FT_Byte  plain;
+
+
+      plain     = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
+      seed      = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
+      *buffer++ = plain;
+      length--;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    TYPE 1 SYMBOL PARSING                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static FT_Error
+  cid_load_keyword( CID_Face        face,
+                    CID_Loader*     loader,
+                    const T1_Field  keyword )
+  {
+    FT_Error      error;
+    CID_Parser*   parser = &loader->parser;
+    FT_Byte*      object;
+    void*         dummy_object;
+    CID_FaceInfo  cid = &face->cid;
+
+
+    /* if the keyword has a dedicated callback, call it */
+    if ( keyword->type == T1_FIELD_TYPE_CALLBACK )
+    {
+      keyword->reader( (FT_Face)face, parser );
+      error = parser->root.error;
+      goto Exit;
+    }
+
+    /* we must now compute the address of our target object */
+    switch ( keyword->location )
+    {
+    case T1_FIELD_LOCATION_CID_INFO:
+      object = (FT_Byte*)cid;
+      break;
+
+    case T1_FIELD_LOCATION_FONT_INFO:
+      object = (FT_Byte*)&cid->font_info;
+      break;
+
+    default:
+      {
+        CID_FaceDict  dict;
+
+
+        if ( parser->num_dict < 0 )
+        {
+          FT_ERROR(( "cid_load_keyword: invalid use of `%s'!\n",
+                     keyword->ident ));
+          error = CID_Err_Syntax_Error;
+          goto Exit;
+        }
+
+        dict = cid->font_dicts + parser->num_dict;
+        switch ( keyword->location )
+        {
+        case T1_FIELD_LOCATION_PRIVATE:
+          object = (FT_Byte*)&dict->private_dict;
+          break;
+
+        default:
+          object = (FT_Byte*)dict;
+        }
+      }
+    }
+
+    dummy_object = object;
+
+    /* now, load the keyword data in the object's field(s) */
+    if ( keyword->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
+         keyword->type == T1_FIELD_TYPE_FIXED_ARRAY   )
+      error = cid_parser_load_field_table( &loader->parser, keyword,
+                                    &dummy_object );
+    else
+      error = cid_parser_load_field( &loader->parser, keyword, &dummy_object );
+  Exit:
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  parse_font_bbox( CID_Face     face,
+                   CID_Parser*  parser )
+  {
+    FT_Fixed  temp[4];
+    FT_BBox*  bbox = &face->cid.font_bbox;
+
+
+    (void)cid_parser_to_fixed_array( parser, 4, temp, 0 );
+    bbox->xMin = FT_RoundFix( temp[0] );
+    bbox->yMin = FT_RoundFix( temp[1] );
+    bbox->xMax = FT_RoundFix( temp[2] );
+    bbox->yMax = FT_RoundFix( temp[3] );
+
+    return CID_Err_Ok;       /* this is a callback function; */
+                            /* we must return an error code */
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  parse_font_matrix( CID_Face     face,
+                     CID_Parser*  parser )
+  {
+    FT_Matrix*    matrix;
+    FT_Vector*    offset;
+    CID_FaceDict  dict;
+    FT_Face       root = (FT_Face)&face->root;
+    FT_Fixed      temp[6];
+    FT_Fixed      temp_scale;
+
+
+    if ( parser->num_dict >= 0 )
+    {
+      dict   = face->cid.font_dicts + parser->num_dict;
+      matrix = &dict->font_matrix;
+      offset = &dict->font_offset;
+
+      (void)cid_parser_to_fixed_array( parser, 6, temp, 3 );
+
+      temp_scale = ABS( temp[3] );
+
+      /* Set Units per EM based on FontMatrix values.  We set the value to */
+      /* `1000/temp_scale', because temp_scale was already multiplied by   */
+      /* 1000 (in t1_tofixed(), from psobjs.c).                            */
+      root->units_per_EM = (FT_UShort)( FT_DivFix( 0x10000L,
+                                        FT_DivFix( temp_scale, 1000 ) ) );
+
+      /* we need to scale the values by 1.0/temp[3] */
+      if ( temp_scale != 0x10000L )
+      {
+        temp[0] = FT_DivFix( temp[0], temp_scale );
+        temp[1] = FT_DivFix( temp[1], temp_scale );
+        temp[2] = FT_DivFix( temp[2], temp_scale );
+        temp[4] = FT_DivFix( temp[4], temp_scale );
+        temp[5] = FT_DivFix( temp[5], temp_scale );
+        temp[3] = 0x10000L;
+      }
+
+      matrix->xx = temp[0];
+      matrix->yx = temp[1];
+      matrix->xy = temp[2];
+      matrix->yy = temp[3];
+
+      /* note that the font offsets are expressed in integer font units */
+      offset->x  = temp[4] >> 16;
+      offset->y  = temp[5] >> 16;
+    }
+
+    return CID_Err_Ok;       /* this is a callback function; */
+                            /* we must return an error code */
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  parse_fd_array( CID_Face     face,
+                  CID_Parser*  parser )
+  {
+    CID_FaceInfo  cid    = &face->cid;
+    FT_Memory     memory = face->root.memory;
+    FT_Error      error  = CID_Err_Ok;
+    FT_Long       num_dicts;
+
+
+    num_dicts = cid_parser_to_int( parser );
+
+    if ( !cid->font_dicts )
+    {
+      FT_Int  n;
+
+
+      if ( FT_NEW_ARRAY( cid->font_dicts, num_dicts ) )
+        goto Exit;
+
+      cid->num_dicts = (FT_UInt)num_dicts;
+
+      /* don't forget to set a few defaults */
+      for ( n = 0; n < cid->num_dicts; n++ )
+      {
+        CID_FaceDict  dict = cid->font_dicts + n;
+
+
+        /* default value for lenIV */
+        dict->private_dict.lenIV = 4;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static
+  const T1_FieldRec  cid_field_records[] =
+  {
+
+#include "cidtoken.h"
+
+    T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
+    T1_FIELD_CALLBACK( "FDArray", parse_fd_array )
+    T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
+    { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
+  };
+
+
+  static int
+  is_alpha( char  c )
+  {
+    return ( ft_isalnum( (int)c ) ||
+             c == '.'             ||
+             c == '_'             );
+  }
+
+
+  static FT_Error
+  cid_parse_dict( CID_Face     face,
+                  CID_Loader*  loader,
+                  FT_Byte*     base,
+                  FT_Long      size )
+  {
+    CID_Parser*  parser = &loader->parser;
+
+
+    parser->root.cursor = base;
+    parser->root.limit  = base + size;
+    parser->root.error  = 0;
+
+    {
+      FT_Byte*  cur   = base;
+      FT_Byte*  limit = cur + size;
+
+
+      for ( ;cur < limit; cur++ )
+      {
+        /* look for `%ADOBeginFontDict' */
+        if ( *cur == '%' && cur + 20 < limit &&
+             ft_strncmp( (char*)cur, "%ADOBeginFontDict", 17 ) == 0 )
+        {
+          cur += 17;
+
+          /* if /FDArray was found, then cid->num_dicts is > 0, and */
+          /* we can start increasing parser->num_dict               */
+          if ( face->cid.num_dicts > 0 )
+            parser->num_dict++;
+        }
+        /* look for immediates */
+        else if ( *cur == '/' && cur + 2 < limit )
+        {
+          FT_Byte*  cur2;
+          FT_Int    len;
+
+
+          cur++;
+
+          cur2 = cur;
+          while ( cur2 < limit && is_alpha( *cur2 ) )
+            cur2++;
+
+          len = (FT_Int)( cur2 - cur );
+          if ( len > 0 && len < 22 )
+          {
+            /* now compare the immediate name to the keyword table */
+            T1_Field  keyword = (T1_Field) cid_field_records;
+
+
+            for (;;)
+            {
+              FT_Byte*  name;
+
+
+              name = (FT_Byte*)keyword->ident;
+              if ( !name )
+                break;
+
+              if ( cur[0] == name[0]                          &&
+                   len == (FT_Int)ft_strlen( (const char*)name ) )
+              {
+                FT_Int  n;
+
+
+                for ( n = 1; n < len; n++ )
+                  if ( cur[n] != name[n] )
+                    break;
+
+                if ( n >= len )
+                {
+                  /* we found it - run the parsing callback */
+                  parser->root.cursor = cur2;
+                  cid_parser_skip_spaces( parser );
+                  parser->root.error = cid_load_keyword( face,
+                                                         loader,
+                                                         keyword );
+                  if ( parser->root.error )
+                    return parser->root.error;
+
+                  cur = parser->root.cursor;
+                  break;
+                }
+              }
+              keyword++;
+            }
+          }
+        }
+      }
+    }
+    return parser->root.error;
+  }
+
+
+  /* read the subrmap and the subrs of each font dict */
+  static FT_Error
+  cid_read_subrs( CID_Face  face )
+  {
+    CID_FaceInfo  cid    = &face->cid;
+    FT_Memory     memory = face->root.memory;
+    FT_Stream     stream = face->root.stream;
+    FT_Error      error;
+    FT_Int        n;
+    CID_Subrs     subr;
+    FT_UInt       max_offsets = 0;
+    FT_ULong*     offsets = 0;
+
+
+    if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) )
+      goto Exit;
+
+    subr = face->subrs;
+    for ( n = 0; n < cid->num_dicts; n++, subr++ )
+    {
+      CID_FaceDict  dict  = cid->font_dicts + n;
+      FT_Int        lenIV = dict->private_dict.lenIV;
+      FT_UInt       count, num_subrs = dict->num_subrs;
+      FT_ULong      data_len;
+      FT_Byte*      p;
+
+
+      /* reallocate offsets array if needed */
+      if ( num_subrs + 1 > max_offsets )
+      {
+        FT_UInt  new_max = ( num_subrs + 1 + 3 ) & -4;
+
+
+        if ( FT_RENEW_ARRAY( offsets, max_offsets, new_max ) )
+          goto Fail;
+
+        max_offsets = new_max;
+      }
+
+      /* read the subrmap's offsets */
+      if ( FT_STREAM_SEEK( cid->data_offset + dict->subrmap_offset ) ||
+           FT_FRAME_ENTER( ( num_subrs + 1 ) * dict->sd_bytes )   )
+        goto Fail;
+
+      p = (FT_Byte*)stream->cursor;
+      for ( count = 0; count <= num_subrs; count++ )
+        offsets[count] = cid_get_offset( &p, (FT_Byte)dict->sd_bytes );
+
+      FT_FRAME_EXIT();
+
+      /* now, compute the size of subrs charstrings, */
+      /* allocate, and read them                     */
+      data_len = offsets[num_subrs] - offsets[0];
+
+      if ( FT_NEW_ARRAY( subr->code, num_subrs + 1 ) ||
+               FT_ALLOC( subr->code[0], data_len )   )
+        goto Fail;
+
+      if ( FT_STREAM_SEEK( cid->data_offset + offsets[0] ) ||
+           FT_STREAM_READ( subr->code[0], data_len )  )
+        goto Fail;
+
+      /* set up pointers */
+      for ( count = 1; count <= num_subrs; count++ )
+      {
+        FT_ULong  len;
+
+
+        len               = offsets[count] - offsets[count - 1];
+        subr->code[count] = subr->code[count - 1] + len;
+      }
+
+      /* decrypt subroutines, but only if lenIV >= 0 */
+      if ( lenIV >= 0 )
+      {
+        for ( count = 0; count < num_subrs; count++ )
+        {
+          FT_ULong  len;
+
+
+          len = offsets[count + 1] - offsets[count];
+          cid_decrypt( subr->code[count], len, 4330 );
+        }
+      }
+
+      subr->num_subrs = num_subrs;
+    }
+
+  Exit:
+    FT_FREE( offsets );
+    return error;
+
+  Fail:
+    if ( face->subrs )
+    {
+      for ( n = 0; n < cid->num_dicts; n++ )
+      {
+        if ( face->subrs[n].code )
+          FT_FREE( face->subrs[n].code[0] );
+
+        FT_FREE( face->subrs[n].code );
+      }
+      FT_FREE( face->subrs );
+    }
+    goto Exit;
+  }
+
+
+  static void
+  t1_init_loader( CID_Loader*  loader,
+                  CID_Face     face )
+  {
+    FT_UNUSED( face );
+
+    FT_MEM_ZERO( loader, sizeof ( *loader ) );
+  }
+
+
+  static void
+  t1_done_loader( CID_Loader*  loader )
+  {
+    CID_Parser*  parser = &loader->parser;
+
+
+    /* finalize parser */
+    cid_parser_done( parser );
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cid_face_open( CID_Face  face )
+  {
+    CID_Loader   loader;
+    CID_Parser*  parser;
+    FT_Error     error;
+
+
+    t1_init_loader( &loader, face );
+
+    parser = &loader.parser;
+    error = cid_parser_new( parser, face->root.stream, face->root.memory,
+                            (PSAux_Service)face->psaux );
+    if ( error )
+      goto Exit;
+
+    error = cid_parse_dict( face, &loader,
+                            parser->postscript,
+                            parser->postscript_len );
+    if ( error )
+      goto Exit;
+
+    face->cid.data_offset = loader.parser.data_offset;
+    error = cid_read_subrs( face );
+
+  Exit:
+    t1_done_loader( &loader );
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidload.h
@@ -1,0 +1,57 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidload.h                                                              */
+/*                                                                         */
+/*    CID-keyed Type1 font loader (specification).                         */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CIDLOAD_H__
+#define __CIDLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include "cidparse.h"
+
+
+FT_BEGIN_HEADER
+
+
+  typedef struct  CID_Loader_
+  {
+    CID_Parser  parser;          /* parser used to read the stream */
+    FT_Int      num_chars;       /* number of characters in encoding */
+
+  } CID_Loader;
+
+
+  FT_LOCAL( FT_Long )
+  cid_get_offset( FT_Byte**  start,
+                  FT_Byte    offsize );
+
+  FT_LOCAL( void )
+  cid_decrypt( FT_Byte*   buffer,
+               FT_Offset  length,
+               FT_UShort  seed );
+
+  FT_LOCAL( FT_Error )
+  cid_face_open( CID_Face  face );
+
+
+FT_END_HEADER
+
+#endif /* __CIDLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidobjs.c
@@ -1,0 +1,448 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidobjs.c                                                              */
+/*                                                                         */
+/*    CID objects manager (body).                                          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include "cidgload.h"
+#include "cidload.h"
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+#include "ciderrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cidobjs
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                            SLOT  FUNCTIONS                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  cid_slot_done( CID_GlyphSlot  slot )
+  {
+    slot->root.internal->glyph_hints = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cid_slot_init( CID_GlyphSlot  slot )
+  {
+    CID_Face          face;
+    PSHinter_Service  pshinter;
+
+
+    face     = (CID_Face)slot->root.face;
+    pshinter = (PSHinter_Service)face->pshinter;
+
+    if ( pshinter )
+    {
+      FT_Module  module;
+
+
+      module = FT_Get_Module( slot->root.face->driver->root.library,
+                              "pshinter" );
+      if ( module )
+      {
+        T1_Hints_Funcs  funcs;
+
+
+        funcs = pshinter->get_t1_funcs( module );
+        slot->root.internal->glyph_hints = (void*)funcs;
+      }
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                           SIZE  FUNCTIONS                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static PSH_Globals_Funcs
+  cid_size_get_globals_funcs( CID_Size  size )
+  {
+    CID_Face          face     = (CID_Face)size->root.face;
+    PSHinter_Service  pshinter = (PSHinter_Service)face->pshinter;
+    FT_Module         module;
+
+
+    module = FT_Get_Module( size->root.face->driver->root.library,
+                            "pshinter" );
+    return ( module && pshinter && pshinter->get_globals_funcs )
+           ? pshinter->get_globals_funcs( module )
+           : 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cid_size_done( CID_Size  size )
+  {
+    if ( size->root.internal )
+    {
+      PSH_Globals_Funcs  funcs;
+
+
+      funcs = cid_size_get_globals_funcs( size );
+      if ( funcs )
+        funcs->destroy( (PSH_Globals)size->root.internal );
+
+      size->root.internal = 0;
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cid_size_init( CID_Size  size )
+  {
+    FT_Error           error = 0;
+    PSH_Globals_Funcs  funcs = cid_size_get_globals_funcs( size );
+
+
+    if ( funcs )
+    {
+      PSH_Globals   globals;
+      CID_Face      face = (CID_Face)size->root.face;
+      CID_FaceDict  dict = face->cid.font_dicts + face->root.face_index;
+      PS_Private    priv = &dict->private_dict;
+
+
+      error = funcs->create( size->root.face->memory, priv, &globals );
+      if ( !error )
+        size->root.internal = (FT_Size_Internal)(void*)globals;
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cid_size_reset( CID_Size  size )
+  {
+    PSH_Globals_Funcs  funcs = cid_size_get_globals_funcs( size );
+    FT_Error           error = 0;
+
+
+    if ( funcs )
+      error = funcs->set_scale( (PSH_Globals)size->root.internal,
+                                 size->root.metrics.x_scale,
+                                 size->root.metrics.y_scale,
+                                 0, 0 );
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                           FACE  FUNCTIONS                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cid_face_done                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a given face object.                                     */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A pointer to the face object to destroy.                   */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  cid_face_done( CID_Face  face )
+  {
+    FT_Memory  memory;
+
+
+    if ( face )
+    {
+      CID_FaceInfo  cid  = &face->cid;
+      PS_FontInfo   info = &cid->font_info;
+
+
+      memory = face->root.memory;
+
+      /* release subrs */
+      if ( face->subrs )
+      {
+        FT_Int  n;
+        
+
+        for ( n = 0; n < cid->num_dicts; n++ )
+        {
+          CID_Subrs  subr = face->subrs + n;
+          
+
+          if ( subr->code )
+          {
+            FT_FREE( subr->code[0] );
+            FT_FREE( subr->code );
+          }
+        }
+
+        FT_FREE( face->subrs );
+      }
+
+      /* release FontInfo strings */
+      FT_FREE( info->version );
+      FT_FREE( info->notice );
+      FT_FREE( info->full_name );
+      FT_FREE( info->family_name );
+      FT_FREE( info->weight );
+
+      /* release font dictionaries */
+      FT_FREE( cid->font_dicts );
+      cid->num_dicts = 0;
+
+      /* release other strings */
+      FT_FREE( cid->cid_font_name );
+      FT_FREE( cid->registry );
+      FT_FREE( cid->ordering );
+
+      face->root.family_name = 0;
+      face->root.style_name  = 0;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cid_face_init                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given CID face object.                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream     :: The source font stream.                              */
+  /*                                                                       */
+  /*    face_index :: The index of the font face in the resource.          */
+  /*                                                                       */
+  /*    num_params :: Number of additional generic parameters.  Ignored.   */
+  /*                                                                       */
+  /*    params     :: Additional generic parameters.  Ignored.             */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face       :: The newly built face object.                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  cid_face_init( FT_Stream      stream,
+                 CID_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params )
+  {
+    FT_Error          error;
+    PSNames_Service   psnames;
+    PSAux_Service     psaux;
+    PSHinter_Service  pshinter;
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+    FT_UNUSED( face_index );
+    FT_UNUSED( stream );
+
+
+    face->root.num_faces = 1;
+
+    psnames = (PSNames_Service)face->psnames;
+    if ( !psnames )
+    {
+      psnames = (PSNames_Service)FT_Get_Module_Interface(
+                  FT_FACE_LIBRARY( face ), "psnames" );
+
+      face->psnames = psnames;
+    }
+
+    psaux = (PSAux_Service)face->psaux;
+    if ( !psaux )
+    {
+      psaux = (PSAux_Service)FT_Get_Module_Interface(
+                FT_FACE_LIBRARY( face ), "psaux" );
+
+      face->psaux = psaux;
+    }
+
+    pshinter = (PSHinter_Service)face->pshinter;
+    if ( !pshinter )
+    {
+      pshinter = (PSHinter_Service)FT_Get_Module_Interface(
+                   FT_FACE_LIBRARY( face ), "pshinter" );
+
+      face->pshinter = pshinter;
+    }
+
+    /* open the tokenizer; this will also check the font format */
+    if ( FT_STREAM_SEEK( 0 ) )
+      goto Exit;
+
+    error = cid_face_open( face );
+    if ( error )
+      goto Exit;
+
+    /* if we just wanted to check the format, leave successfully now */
+    if ( face_index < 0 )
+      goto Exit;
+
+    /* check the face index */
+    if ( face_index != 0 )
+    {
+      FT_ERROR(( "cid_face_init: invalid face index\n" ));
+      error = CID_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* Now, load the font program into the face object */
+    {
+      /* Init the face object fields */
+      /* Now set up root face fields */
+      {
+        FT_Face  root = (FT_Face)&face->root;
+
+
+        root->num_glyphs   = face->cid.cid_count;
+        root->num_charmaps = 0;
+
+        root->face_index = face_index;
+        root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+        root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+        if ( face->cid.font_info.is_fixed_pitch )
+          root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+        /* XXX: TODO: add kerning with .afm support */
+
+        /* get style name -- be careful, some broken fonts only */
+        /* have a /FontName dictionary entry!                   */
+        root->family_name = face->cid.font_info.family_name;
+        if ( root->family_name )
+        {
+          char*  full   = face->cid.font_info.full_name;
+          char*  family = root->family_name;
+
+          while ( *family && *full == *family )
+          {
+            family++;
+            full++;
+          }
+
+          root->style_name = ( *full == ' ' ) ? full + 1
+                                              : (char *)"Regular";
+        }
+        else
+        {
+          /* do we have a `/FontName'? */
+          if ( face->cid.cid_font_name )
+          {
+            root->family_name = face->cid.cid_font_name;
+            root->style_name  = (char *)"Regular";
+          }
+        }
+
+        /* no embedded bitmap support */
+        root->num_fixed_sizes = 0;
+        root->available_sizes = 0;
+
+        root->bbox.xMin =   face->cid.font_bbox.xMin             >> 16;
+        root->bbox.yMin =   face->cid.font_bbox.yMin             >> 16;
+        root->bbox.xMax = ( face->cid.font_bbox.xMax + 0xFFFFU ) >> 16;
+        root->bbox.yMax = ( face->cid.font_bbox.yMax + 0xFFFFU ) >> 16;
+
+        if ( !root->units_per_EM )
+          root->units_per_EM  = 1000;
+
+        root->ascender  = (FT_Short)( root->bbox.yMax );
+        root->descender = (FT_Short)( root->bbox.yMin );
+        root->height    = (FT_Short)(
+          ( ( root->ascender + root->descender ) * 12 ) / 10 );
+
+        root->underline_position  = face->cid.font_info.underline_position;
+        root->underline_thickness = face->cid.font_info.underline_thickness;
+
+        root->internal->max_points   = 0;
+        root->internal->max_contours = 0;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cid_driver_init                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given CID driver object.                             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    driver :: A handle to the target driver object.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  cid_driver_init( CID_Driver  driver )
+  {
+    FT_UNUSED( driver );
+
+    return CID_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    cid_driver_done                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a given CID driver.                                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    driver :: A handle to the target CID driver.                       */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  cid_driver_done( CID_Driver  driver )
+  {
+    FT_UNUSED( driver );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidobjs.h
@@ -1,0 +1,158 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidobjs.h                                                              */
+/*                                                                         */
+/*    CID objects manager (specification).                                 */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CIDOBJS_H__
+#define __CIDOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  /* The following structures must be defined by the hinter */
+  typedef struct CID_Size_Hints_   CID_Size_Hints;
+  typedef struct CID_Glyph_Hints_  CID_Glyph_Hints;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    CID_Driver                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 driver object.                                */
+  /*                                                                       */
+  typedef struct CID_DriverRec_*  CID_Driver;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    CID_Size                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 size object.                                  */
+  /*                                                                       */
+  typedef struct CID_SizeRec_*  CID_Size;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    CID_GlyphSlot                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 glyph slot object.                            */
+  /*                                                                       */
+  typedef struct CID_GlyphSlotRec_*  CID_GlyphSlot;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    CID_CharMap                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 character mapping object.                     */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The Type 1 format doesn't use a charmap but an encoding table.     */
+  /*    The driver is responsible for making up charmap objects            */
+  /*    corresponding to these tables.                                     */
+  /*                                                                       */
+  typedef struct CID_CharMapRec_*  CID_CharMap;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* HERE BEGINS THE TYPE 1 SPECIFIC STUFF                                 */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  typedef struct  CID_SizeRec_
+  {
+    FT_SizeRec  root;
+    FT_Bool     valid;
+
+  } CID_SizeRec;
+
+
+  typedef struct  CID_GlyphSlotRec_
+  {
+    FT_GlyphSlotRec  root;
+
+    FT_Bool          hint;
+    FT_Bool          scaled;
+
+    FT_Fixed         x_scale;
+    FT_Fixed         y_scale;
+
+  } CID_GlyphSlotRec;
+
+
+  FT_LOCAL( void )
+  cid_slot_done( CID_GlyphSlot  slot );
+
+  FT_LOCAL( FT_Error )
+  cid_slot_init( CID_GlyphSlot   slot );
+
+
+  FT_LOCAL( void )
+  cid_size_done( CID_Size  size );
+
+
+  FT_LOCAL( FT_Error )
+  cid_size_init( CID_Size  size );
+
+
+  FT_LOCAL( FT_Error )
+  cid_size_reset( CID_Size  size );
+
+
+  FT_LOCAL( FT_Error )
+  cid_face_init( FT_Stream      stream,
+                 CID_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params );
+
+
+  FT_LOCAL( void )
+  cid_face_done( CID_Face  face );
+
+
+  FT_LOCAL( FT_Error )
+  cid_driver_init( CID_Driver  driver );
+
+
+  FT_LOCAL( void )
+  cid_driver_done( CID_Driver  driver );
+
+
+FT_END_HEADER
+
+#endif /* __CIDOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidparse.c
@@ -1,0 +1,155 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidparse.c                                                             */
+/*                                                                         */
+/*    CID-keyed Type1 parser (body).                                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+
+#include "cidparse.h"
+
+#include "ciderrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cidparse
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    INPUT STREAM PARSER                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cid_parser_new( CID_Parser*    parser,
+                  FT_Stream      stream,
+                  FT_Memory      memory,
+                  PSAux_Service  psaux )
+  {
+    FT_Error  error;
+    FT_ULong  base_offset, offset, ps_len;
+    FT_Byte   buffer[256 + 10];
+    FT_Int    buff_len;
+
+
+    FT_MEM_ZERO( parser, sizeof ( *parser ) );
+    psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
+
+    parser->stream = stream;
+
+    base_offset = FT_STREAM_POS();
+
+    /* first of all, check the font format in the  header */
+    if ( FT_FRAME_ENTER( 31 ) )
+      goto Exit;
+
+    if ( ft_strncmp( (char *)stream->cursor,
+                     "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) )
+    {
+      FT_TRACE2(( "[not a valid CID-keyed font]\n" ));
+      error = CID_Err_Unknown_File_Format;
+    }
+
+    FT_FRAME_EXIT();
+    if ( error )
+      goto Exit;
+
+    /* now, read the rest of the file, until we find a `StartData' */
+    buff_len = 256;
+    for (;;)
+    {
+      FT_Byte   *p, *limit = buffer + 256;
+      FT_ULong  top_position;
+
+
+      /* fill input buffer */
+      buff_len -= 256;
+      if ( buff_len > 0 )
+        FT_MEM_MOVE( buffer, limit, buff_len );
+
+      p = buffer + buff_len;
+
+      if ( FT_STREAM_READ( p, 256 + 10 - buff_len ) )
+        goto Exit;
+
+      top_position = FT_STREAM_POS() - buff_len;
+      buff_len = 256 + 10;
+
+      /* look for `StartData' */
+      for ( p = buffer; p < limit; p++ )
+      {
+        if ( p[0] == 'S' && ft_strncmp( (char*)p, "StartData", 9 ) == 0 )
+        {
+          /* save offset of binary data after `StartData' */
+          offset = (FT_ULong)( top_position - ( limit - p ) + 10 );
+          goto Found;
+        }
+      }
+    }
+
+  Found:
+    /* we have found the start of the binary data.  We will now        */
+    /* rewind and extract the frame of corresponding to the Postscript */
+    /* section                                                         */
+
+    ps_len = offset - base_offset;
+    if ( FT_STREAM_SEEK( base_offset )                    ||
+         FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
+      goto Exit;
+
+    parser->data_offset    = offset;
+    parser->postscript_len = ps_len;
+    parser->root.base      = parser->postscript;
+    parser->root.cursor    = parser->postscript;
+    parser->root.limit     = parser->root.cursor + ps_len;
+    parser->num_dict       = -1;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  cid_parser_done( CID_Parser*  parser )
+  {
+    /* always free the private dictionary */
+    if ( parser->postscript )
+    {
+      FT_Stream  stream = parser->stream;
+
+
+      FT_FRAME_RELEASE( parser->postscript );
+    }
+    parser->root.funcs.done( &parser->root );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidparse.h
@@ -1,0 +1,116 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidparse.h                                                             */
+/*                                                                         */
+/*    CID-keyed Type1 parser (specification).                              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CIDPARSE_H__
+#define __CIDPARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    CID_Parser                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A CID_Parser is an object used to parse a Type 1 fonts very        */
+  /*    quickly.                                                           */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    root           :: The root PS_ParserRec fields.                    */
+  /*                                                                       */
+  /*    stream         :: The current input stream.                        */
+  /*                                                                       */
+  /*    postscript     :: A pointer to the data to be parsed.              */
+  /*                                                                       */
+  /*    postscript_len :: The length of the data to be parsed.             */
+  /*                                                                       */
+  /*    data_offset    :: The start position of the binary data (i.e., the */
+  /*                      end of the data to be parsed.                    */
+  /*                                                                       */
+  /*    cid            :: A structure which holds the information about    */
+  /*                      the current font.                                */
+  /*                                                                       */
+  /*    num_dict       :: The number of font dictionaries.                 */
+  /*                                                                       */
+  typedef struct  CID_Parser_
+  {
+    PS_ParserRec  root;
+    FT_Stream     stream;
+
+    FT_Byte*      postscript;
+    FT_Long       postscript_len;
+
+    FT_ULong      data_offset;
+
+    CID_FaceInfo  cid;
+    FT_Int        num_dict;
+
+  } CID_Parser;
+
+
+  FT_LOCAL( FT_Error )
+  cid_parser_new( CID_Parser*    parser,
+                  FT_Stream      stream,
+                  FT_Memory      memory,
+                  PSAux_Service  psaux );
+
+  FT_LOCAL( void )
+  cid_parser_done( CID_Parser*  parser );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                            PARSING ROUTINES                           */
+  /*                                                                       */
+  /*************************************************************************/
+
+#define cid_parser_skip_spaces( p )  (p)->root.funcs.skip_spaces( &(p)->root )
+#define cid_parser_skip_alpha( p )   (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define cid_parser_to_int( p )        (p)->root.funcs.to_int( &(p)->root )
+#define cid_parser_to_fixed( p, t )   (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define cid_parser_to_coord_array( p, m, c )                          \
+          (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define cid_parser_to_fixed_array( p, m, f, t )                          \
+          (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define cid_parser_to_token( p, t )                         \
+          (p)->root.funcs.to_token( &(p)->root, t )
+#define cid_parser_to_token_array( p, t, m, c )                          \
+          (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define cid_parser_load_field( p, f, o )                              \
+          (p)->root.funcs.load_field( &(p)->root, f, o, 0, 0 )
+#define cid_parser_load_field_table( p, f, o )                              \
+          (p)->root.funcs.load_field_table( &(p)->root, f, o, 0, 0 )
+
+
+FT_END_HEADER
+
+#endif /* __CIDPARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidriver.c
@@ -1,0 +1,113 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidriver.c                                                             */
+/*                                                                         */
+/*    CID driver interface (body).                                         */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cidriver.h"
+#include "cidgload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "ciderrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ciddriver
+
+
+  static const char*
+  cid_get_postscript_name( CID_Face  face )
+  {
+    const char*  result = face->cid.cid_font_name;
+
+
+    if ( result && result[0] == '/' )
+      result++;
+
+    return result;
+  }
+
+
+  static FT_Module_Interface
+  cid_get_interface( FT_Driver         driver,
+                     const FT_String*  cid_interface )
+  {
+    FT_UNUSED( driver );
+    FT_UNUSED( cid_interface );
+
+    if ( ft_strcmp( (const char*)cid_interface, "postscript_name" ) == 0 )
+      return (FT_Module_Interface)cid_get_postscript_name;
+
+    return 0;
+  }
+
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  t1cid_driver_class =
+  {
+    /* first of all, the FT_Module_Class fields */
+    {
+      ft_module_font_driver       |
+      ft_module_driver_scalable   |
+      ft_module_driver_has_hinter ,
+
+      sizeof( FT_DriverRec ),
+      "t1cid",   /* module name           */
+      0x10000L,  /* version 1.0 of driver */
+      0x20000L,  /* requires FreeType 2.0 */
+
+      0,
+
+      (FT_Module_Constructor)cid_driver_init,
+      (FT_Module_Destructor) cid_driver_done,
+      (FT_Module_Requester)  cid_get_interface
+    },
+
+    /* then the other font drivers fields */
+    sizeof( CID_FaceRec ),
+    sizeof( CID_SizeRec ),
+    sizeof( CID_GlyphSlotRec ),
+
+    (FT_Face_InitFunc)       cid_face_init,
+    (FT_Face_DoneFunc)       cid_face_done,
+
+    (FT_Size_InitFunc)       cid_size_init,
+    (FT_Size_DoneFunc)       cid_size_done,
+    (FT_Slot_InitFunc)       cid_slot_init,
+    (FT_Slot_DoneFunc)       cid_slot_done,
+
+    (FT_Size_ResetPointsFunc)cid_size_reset,
+    (FT_Size_ResetPixelsFunc)cid_size_reset,
+
+    (FT_Slot_LoadFunc)       cid_slot_load_glyph,
+
+    (FT_Face_GetKerningFunc) 0,
+    (FT_Face_AttachFunc)     0,
+
+    (FT_Face_GetAdvancesFunc)0,
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidriver.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidriver.h                                                             */
+/*                                                                         */
+/*    High-level CID driver interface (specification).                     */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __CIDRIVER_H__
+#define __CIDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_CALLBACK_TABLE
+  const FT_Driver_ClassRec  t1cid_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __CIDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/cidtoken.h
@@ -1,0 +1,96 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cidtoken.h                                                             */
+/*                                                                         */
+/*    CID token definitions (specification only).                          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CID_FaceInfoRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_CID_INFO
+
+  T1_FIELD_STRING( "CIDFontName", cid_font_name )
+  T1_FIELD_NUM   ( "CIDFontVersion", cid_version )
+  T1_FIELD_NUM   ( "CIDFontType", cid_font_type )
+  T1_FIELD_STRING( "Registry", registry )
+  T1_FIELD_STRING( "Ordering", ordering )
+  T1_FIELD_NUM   ( "Supplement", supplement )
+  T1_FIELD_NUM   ( "UIDBase", uid_base )
+  T1_FIELD_NUM   ( "CIDMapOffset", cidmap_offset )
+  T1_FIELD_NUM   ( "FDBytes", fd_bytes )
+  T1_FIELD_NUM   ( "GDBytes", gd_bytes )
+  T1_FIELD_NUM   ( "CIDCount", cid_count )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PS_FontInfoRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FONT_INFO
+
+  T1_FIELD_STRING   ( "version", version )
+  T1_FIELD_STRING   ( "Notice", notice )
+  T1_FIELD_STRING   ( "FullName", full_name )
+  T1_FIELD_STRING   ( "FamilyName", family_name )
+  T1_FIELD_STRING   ( "Weight", weight )
+  T1_FIELD_FIXED    ( "ItalicAngle", italic_angle )
+  T1_FIELD_TYPE_BOOL( "isFixedPitch", is_fixed_pitch )
+  T1_FIELD_NUM      ( "UnderlinePosition", underline_position )
+  T1_FIELD_NUM      ( "UnderlineThickness", underline_thickness )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  CID_FaceDictRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FONT_DICT
+
+  T1_FIELD_NUM  ( "PaintType", paint_type )
+  T1_FIELD_NUM  ( "FontType", font_type )
+  T1_FIELD_NUM  ( "SubrMapOffset", subrmap_offset )
+  T1_FIELD_NUM  ( "SDBytes", sd_bytes )
+  T1_FIELD_NUM  ( "SubrCount", num_subrs )
+  T1_FIELD_NUM  ( "lenBuildCharArray", len_buildchar )
+  T1_FIELD_FIXED( "ForceBoldThreshold", forcebold_threshold )
+  T1_FIELD_FIXED( "ExpansionFactor", expansion_factor )
+  T1_FIELD_NUM  ( "StrokeWidth", stroke_width )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PS_PrivateRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_PRIVATE
+
+  T1_FIELD_NUM       ( "UniqueID", unique_id )
+  T1_FIELD_NUM       ( "lenIV", lenIV )
+  T1_FIELD_NUM       ( "LanguageGroup", language_group )
+  T1_FIELD_NUM       ( "password", password )
+
+  T1_FIELD_FIXED     ( "BlueScale", blue_scale )
+  T1_FIELD_NUM       ( "BlueShift", blue_shift )
+  T1_FIELD_NUM       ( "BlueFuzz",  blue_fuzz )
+
+  T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14 )
+  T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10 )
+  T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14 )
+  T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10 )
+
+  T1_FIELD_NUM_TABLE2( "StdHW", standard_width,  1 )
+  T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 )
+  T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 )
+
+  T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 )
+  T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 )
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/fnterrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/*                                                                         */
+/*  fnterrs.h                                                              */
+/*                                                                         */
+/*    Win FNT/FON error codes (specification only).                        */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the Windows FNT/FON error enumeration     */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __FNTERRS_H__
+#define __FNTERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  FNT_Err_
+#define FT_ERR_BASE    FT_Mod_Err_Winfonts
+
+#include FT_ERRORS_H
+
+#endif /* __FNTERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/freetype.c
@@ -1,0 +1,134 @@
+#include "freetype/freetype.h"
+#include "freetype.h"
+
+static char* fterrstr(int);
+
+char*
+ftnewface(char *path, int index, FTface *f, FTfaceinfo *finfo)
+{
+	FT_Library ft_lib;
+	FT_Face ft_face;
+	char *err;
+
+	err = fterrstr(FT_Init_FreeType(&ft_lib));
+	if (err != nil)
+		return err;
+
+	err = fterrstr(FT_New_Face(ft_lib, path, index, &ft_face));
+	if (err != nil) {
+		FT_Done_FreeType(ft_lib);
+		return err;
+	}
+
+	f->ft_lib = ft_lib;
+	f->ft_face = ft_face;
+	finfo->nfaces = ft_face->num_faces;
+	finfo->index = ft_face->face_index;
+	finfo->style = ft_face->style_flags;
+	finfo->height = (FT_MulFix(ft_face->height, ft_face->size->metrics.y_scale)+32)/64;
+	finfo->ascent = (FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale)+32)/64;
+	finfo->familyname = ft_face->family_name;
+	finfo->stylename = ft_face->style_name;
+	return nil;
+}
+
+char*
+ftloadmemface(void *buf, int nbytes, int index, FTface *f, FTfaceinfo *finfo)
+{
+	USED(buf);
+	USED(f);
+	USED(finfo);
+	return "not implemented";
+}
+
+char*
+ftsetcharsize(FTface f, int pt, int hdpi, int vdpi, FTfaceinfo *finfo)
+{
+	FT_Face ft_face = f.ft_face;
+	char *err;
+
+	err = fterrstr(FT_Set_Char_Size(ft_face, 0, pt, hdpi, vdpi));
+	if (err != nil)
+		return err;
+	finfo->height = (FT_MulFix(ft_face->height, ft_face->size->metrics.y_scale)+32)/64;
+	finfo->ascent = (FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale)+32)/64;
+	return nil;
+}
+
+void
+ftsettransform(FTface f, FTmatrix *m, FTvector *v)
+{
+	/* FTMatrix and FTVector are compatible with FT_Matrix and FT_Vector */
+	FT_Set_Transform(f.ft_face, (FT_Matrix*)m, (FT_Vector*)v);
+}
+
+int
+fthaschar(FTface f, int c)
+{
+	return FT_Get_Char_Index(f.ft_face, c) != 0;
+}
+
+char*
+ftloadglyph(FTface f, int ix, FTglyph *g)
+{
+	FT_Face ft_face = f.ft_face;
+	FT_GlyphSlot ft_glyph;
+	char *err;
+
+	ix = FT_Get_Char_Index(ft_face, ix);
+	err = fterrstr(FT_Load_Glyph(ft_face, ix, FT_LOAD_NO_BITMAP|FT_LOAD_RENDER|FT_LOAD_CROP_BITMAP));
+	if (err != nil)
+		return err;
+
+	ft_glyph = ft_face->glyph;
+	g->top = ft_glyph->bitmap_top;
+	g->left = ft_glyph->bitmap_left;
+	g->height = ft_glyph->bitmap.rows;
+	g->width = ft_glyph->bitmap.width;
+	g->advx = ft_glyph->advance.x;
+	g->advy = ft_glyph->advance.y;
+	g->bpr = ft_glyph->bitmap.pitch;
+	g->bitmap = ft_glyph->bitmap.buffer;
+	return nil;
+}
+
+void
+ftdoneface(FTface f)
+{
+	if (f.ft_face != nil)
+		FT_Done_Face(f.ft_face);
+	if (f.ft_lib != nil)
+		FT_Done_FreeType(f.ft_lib);
+}
+
+/*
+ * get the freetype error strings
+ */
+
+typedef struct FTerr FTerr;
+struct FTerr {
+	int		code;
+	char*	text;
+};
+
+#define FT_NOERRORDEF_(l,c,t)
+#define FT_ERRORDEF_(l,c,t)	c,t,
+
+static FTerr fterrs[] = {
+#include "freetype/fterrdef.h"
+	-1, "",
+};
+
+static char*
+fterrstr(int code)
+{
+	int i;
+	if (code == 0)
+		return nil;
+	for (i = 0; fterrs[i].code > 0; i++) {
+		if (fterrs[i].code == code)
+			return fterrs[i].text;
+	}
+	return "unknown FreeType error";
+}
+
--- /dev/null
+++ b/libfreetype/ftapi.c
@@ -1,0 +1,121 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftapi.c                                                                */
+/*                                                                         */
+/*    The FreeType compatibility functions (body).                         */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_OUTLINE_H
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                 C O M P A T I B I L I T Y                       ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* backwards compatibility API */
+
+  FT_BASE_DEF( void )
+  FT_New_Memory_Stream( FT_Library  library,
+                        FT_Byte*    base,
+                        FT_ULong    size,
+                        FT_Stream   stream )
+  {
+    FT_UNUSED( library );
+
+    FT_Stream_OpenMemory( stream, base, size );
+  }                        
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Seek_Stream( FT_Stream  stream,
+                  FT_ULong   pos )
+  {
+    return FT_Stream_Seek( stream, pos );
+  }                  
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Skip_Stream( FT_Stream  stream,
+                  FT_Long    distance )
+  {
+    return FT_Stream_Skip( stream, distance );
+  }                  
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Read_Stream( FT_Stream  stream,
+                  FT_Byte*   buffer,
+                  FT_ULong   count )
+  {
+    return FT_Stream_Read( stream, buffer, count );
+  }                  
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Read_Stream_At( FT_Stream  stream,
+                     FT_ULong   pos,
+                     FT_Byte*   buffer,
+                     FT_ULong   count )
+  {
+    return FT_Stream_ReadAt( stream, pos, buffer, count );
+  }                    
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Extract_Frame( FT_Stream  stream,
+                    FT_ULong   count,
+                    FT_Byte**  pbytes )
+  {
+    return FT_Stream_ExtractFrame( stream, count, pbytes );
+  }                    
+
+
+  FT_BASE_DEF( void )
+  FT_Release_Frame( FT_Stream  stream,
+                    FT_Byte**  pbytes )
+  {
+    FT_Stream_ReleaseFrame( stream, pbytes );
+  }                    
+
+  FT_BASE_DEF( FT_Error )
+  FT_Access_Frame( FT_Stream  stream,
+                   FT_ULong   count )
+  {
+    return FT_Stream_EnterFrame( stream, count );
+  }                   
+
+
+  FT_BASE_DEF( void )
+  FT_Forget_Frame( FT_Stream  stream )
+  {
+    FT_Stream_ExitFrame( stream );
+  }
+                   
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftbase.c
@@ -1,0 +1,34 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftbase.c                                                               */
+/*                                                                         */
+/*    Single object library component (body only).                         */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+
+#define  FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include "ftutil.c"
+#include "ftdbgmem.c"
+#include "ftstream.c"
+#include "ftcalc.c"
+#include "fttrigon.c"
+#include "ftoutln.c"
+#include "ftgloadr.c"
+#include "ftobjs.c"
+#include "ftnames.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftbbox.c
@@ -1,0 +1,653 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftbbox.c                                                               */
+/*                                                                         */
+/*    FreeType bbox computation (body).                                    */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used        */
+/*  modified and distributed under the terms of the FreeType project       */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This component has a _single_ role: to compute exact outline bounding */
+  /* boxes.                                                                */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_BBOX_H
+#include FT_IMAGE_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_CALC_H
+
+
+  typedef struct  TBBox_Rec_
+  {
+    FT_Vector  last;
+    FT_BBox    bbox;
+
+  } TBBox_Rec;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    BBox_Move_To                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function is used as a `move_to' and `line_to' emitter during  */
+  /*    FT_Outline_Decompose().  It simply records the destination point   */
+  /*    in `user->last'; no further computations are necessary since we    */
+  /*    the cbox as the starting bbox which must be refined.               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    to   :: A pointer to the destination vector.                       */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    user :: A pointer to the current walk context.                     */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Always 0.  Needed for the interface only.                          */
+  /*                                                                       */
+  static int
+  BBox_Move_To( FT_Vector*  to,
+                TBBox_Rec*  user )
+  {
+    user->last = *to;
+
+    return 0;
+  }
+
+
+#define CHECK_X( p, bbox )  \
+          ( p->x < bbox.xMin || p->x > bbox.xMax )
+
+#define CHECK_Y( p, bbox )  \
+          ( p->y < bbox.yMin || p->y > bbox.yMax )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    BBox_Conic_Check                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finds the extrema of a 1-dimensional conic Bezier curve and update */
+  /*    a bounding range.  This version uses direct computation, as it     */
+  /*    doesn't need square roots.                                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    y1  :: The start coordinate.                                       */
+  /*    y2  :: The coordinate of the control point.                        */
+  /*    y3  :: The end coordinate.                                         */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    min :: The address of the current minimum.                         */
+  /*    max :: The address of the current maximum.                         */
+  /*                                                                       */
+  static void
+  BBox_Conic_Check( FT_Pos   y1,
+                    FT_Pos   y2,
+                          FT_Pos   y3,
+                          FT_Pos*  min,
+                          FT_Pos*  max )
+  {
+    if ( y1 <= y3 )
+    {
+      if ( y2 == y1 )               /* Flat arc */
+        goto Suite;
+    }
+    else if ( y1 < y3 )
+    {
+      if ( y2 >= y1 && y2 <= y3 )   /* Ascending arc */
+        goto Suite;
+    }
+    else
+    {
+      if ( y2 >= y3 && y2 <= y1 )   /* Descending arc */
+      {
+        y2 = y1;
+        y1 = y3;
+        y3 = y2;
+        goto Suite;
+      }
+    }
+
+    y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 );
+
+  Suite:
+    if ( y1 < *min ) *min = y1;
+    if ( y3 > *max ) *max = y3;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    BBox_Conic_To                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function is used as a `conic_to' emitter during               */
+  /*    FT_Raster_Decompose().  It checks a conic Bezier curve with the    */
+  /*    current bounding box, and computes its extrema if necessary to     */
+  /*    update it.                                                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    control :: A pointer to a control point.                           */
+  /*    to      :: A pointer to the destination vector.                    */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    user    :: The address of the current walk context.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Always 0.  Needed for the interface only.                          */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    In the case of a non-monotonous arc, we compute directly the       */
+  /*    extremum coordinates, as it is sufficiently fast.                  */
+  /*                                                                       */
+  static int
+  BBox_Conic_To( FT_Vector*  control,
+                 FT_Vector*  to,
+                 TBBox_Rec*  user )
+  {
+    /* we don't need to check `to' since it is always an `on' point, thus */
+    /* within the bbox                                                    */
+
+    if ( CHECK_X( control, user->bbox ) )
+
+      BBox_Conic_Check( user->last.x,
+                        control->x,
+                        to->x,
+                        &user->bbox.xMin,
+                        &user->bbox.xMax );
+
+    if ( CHECK_Y( control, user->bbox ) )
+
+      BBox_Conic_Check( user->last.y,
+                        control->y,
+                        to->y,
+                        &user->bbox.yMin,
+                        &user->bbox.yMax );
+
+    user->last = *to;
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    BBox_Cubic_Check                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finds the extrema of a 1-dimensional cubic Bezier curve and        */
+  /*    updates a bounding range.  This version uses splitting because we  */
+  /*    don't want to use square roots and extra accuracies.               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    p1  :: The start coordinate.                                       */
+  /*    p2  :: The coordinate of the first control point.                  */
+  /*    p3  :: The coordinate of the second control point.                 */
+  /*    p4  :: The end coordinate.                                         */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    min :: The address of the current minimum.                         */
+  /*    max :: The address of the current maximum.                         */
+  /*                                                                       */
+#if 0
+  static void
+  BBox_Cubic_Check( FT_Pos   p1,
+                    FT_Pos   p2,
+                    FT_Pos   p3,
+                    FT_Pos   p4,
+                    FT_Pos*  min,
+                    FT_Pos*  max )
+  {
+    FT_Pos  stack[32*3 + 1], *arc;
+
+
+    arc = stack;
+
+    arc[0] = p1;
+    arc[1] = p2;
+    arc[2] = p3;
+    arc[3] = p4;
+
+    do
+    {
+      FT_Pos  y1 = arc[0];
+      FT_Pos  y2 = arc[1];
+      FT_Pos  y3 = arc[2];
+      FT_Pos  y4 = arc[3];
+
+
+      if ( y1 == y4 )
+      {
+        if ( y1 == y2 && y1 == y3 )                         /* Flat */
+          goto Test;
+      }
+      else if ( y1 < y4 )
+      {
+        if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 ) /* Ascending */
+          goto Test;
+      }
+      else
+      {
+        if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 ) /* Descending */
+        {
+          y2 = y1;
+          y1 = y4;
+          y4 = y2;
+          goto Test;
+        }
+      }
+
+      /* Unknown direction -- split the arc in two */
+      arc[6] = y4;
+      arc[1] = y1 = ( y1 + y2 ) / 2;
+      arc[5] = y4 = ( y4 + y3 ) / 2;
+      y2 = ( y2 + y3 ) / 2;
+      arc[2] = y1 = ( y1 + y2 ) / 2;
+      arc[4] = y4 = ( y4 + y2 ) / 2;
+      arc[3] = ( y1 + y4 ) / 2;
+
+      arc += 3;
+      goto Suite;
+
+   Test:
+      if ( y1 < *min ) *min = y1;
+      if ( y4 > *max ) *max = y4;
+      arc -= 3;
+
+    Suite:
+      ;
+    } while ( arc >= stack );
+  }
+#else
+
+  static void
+  test_cubic_extrema( FT_Pos    y1,
+                      FT_Pos    y2,
+                      FT_Pos    y3,
+                      FT_Pos    y4,
+                      FT_Fixed  u,
+                      FT_Pos*   min,
+                      FT_Pos*   max )
+  {
+ /* FT_Pos    a = y4 - 3*y3 + 3*y2 - y1; */
+    FT_Pos    b = y3 - 2*y2 + y1;
+    FT_Pos    c = y2 - y1;
+    FT_Pos    d = y1;
+    FT_Pos    y;
+    FT_Fixed  uu;
+
+    FT_UNUSED ( y4 );
+
+
+    /* The polynom is                       */
+    /*                                      */
+    /*   a*x^3 + 3b*x^2 + 3c*x + d      .   */
+    /*                                      */
+    /* However, we also have                */
+    /*                                      */
+    /*   dP/dx(u) = 0       ,               */
+    /*                                      */
+    /* which implies that                   */
+    /*                                      */
+    /*   P(u) = b*u^2 + 2c*u + d            */
+
+    if ( u > 0 && u < 0x10000L )
+    {
+      uu = FT_MulFix( u, u );
+      y  = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu );
+
+      if ( y < *min ) *min = y;
+      if ( y > *max ) *max = y;
+    }
+  }
+
+
+  static void
+  BBox_Cubic_Check( FT_Pos   y1,
+                    FT_Pos   y2,
+                    FT_Pos   y3,
+                    FT_Pos   y4,
+                    FT_Pos*  min,
+                    FT_Pos*  max )
+  {
+    /* always compare first and last points */
+    if      ( y1 < *min )  *min = y1;
+    else if ( y1 > *max )  *max = y1;
+
+    if      ( y4 < *min )  *min = y4;
+    else if ( y4 > *max )  *max = y4;
+
+    /* now, try to see if there are split points here */
+    if ( y1 <= y4 )
+    {
+      /* flat or ascending arc test */
+      if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
+        return;
+    }
+    else /* y1 > y4 */
+    {
+      /* descending arc test */
+      if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
+        return;
+    }
+
+    /* There are some split points.  Find them. */
+    {
+      FT_Pos    a = y4 - 3*y3 + 3*y2 - y1;
+      FT_Pos    b = y3 - 2*y2 + y1;
+      FT_Pos    c = y2 - y1;
+      FT_Pos    d;
+      FT_Fixed  t;
+
+
+      /* We need to solve "ax^2+2bx+c" here, without floating points!      */
+      /* The trick is to normalize to a different representation in order  */
+      /* to use our 16.16 fixed point routines.                            */
+      /*                                                                   */
+      /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after the            */
+      /* the normalization.  These values must fit into a single 16.16     */
+      /* value.                                                            */
+      /*                                                                   */
+      /* We normalize a, b, and c to "8.16" fixed float values to ensure   */
+      /* that their product is held in a "16.16" value.                    */
+      /*                                                                   */
+      {
+        FT_ULong  t1, t2;
+        int       shift = 0;
+
+
+        /* Technical explanation of what's happening there.            */
+        /*                                                             */
+        /*   The following computation is based on the fact that for   */
+        /*   any value "y", if "n" is the position of the most         */
+        /*   significant bit of "abs(y)" (starting from 0 for the      */
+        /*   least significant bit), then y is in the range            */
+        /*                                                             */
+        /*                  "-2^n..2^n-1"                              */
+        /*                                                             */
+        /*   We want to shift "a", "b" and "c" concurrently in order   */
+        /*   to ensure that they all fit in 8.16 values, which maps    */
+        /*   to the integer range "-2^23..2^23-1".                     */
+        /*                                                             */
+        /*   Necessarily, we need to shift "a", "b" and "c" so that    */
+        /*   the most significant bit of their absolute values is at   */
+        /*   _most_ at position 23.                                    */
+        /*                                                             */
+        /*   We begin by computing "t1" as the bitwise "or" of the     */
+        /*   absolute values of "a", "b", "c".                         */
+        /*                                                             */
+        t1  = (FT_ULong)((a >= 0) ? a : -a );
+        t2  = (FT_ULong)((b >= 0) ? b : -b );
+        t1 |= t2;
+        t2  = (FT_ULong)((c >= 0) ? c : -c );
+        t1 |= t2;
+
+        /*   Now, the most significant bit of "t1" is sure to be the   */
+        /*   msb of one of "a", "b", "c", depending on which one is    */
+        /*   expressed in the greatest integer range.                  */
+        /*                                                             */
+        /*   We now compute the "shift", by shifting "t1" as many      */
+        /*   times as necessary to move its msb to position 23.        */
+        /*                                                             */
+        /*   This corresponds to a value of t1 that is in the range    */
+        /*   0x40_0000..0x7F_FFFF.                                     */
+        /*                                                             */
+        /*   Finally, we shift "a", "b" and "c" by the same amount.    */
+        /*   This ensures that all values are now in the range         */
+        /*   -2^23..2^23, i.e. that they are now expressed as 8.16     */
+        /*   fixed float numbers.                                      */
+        /*                                                             */
+        /*   This also means that we are using 24 bits of precision    */
+        /*   to compute the zeros, independently of the range of       */
+        /*   the original polynom coefficients.                        */
+        /*                                                             */
+        /*   This should ensure reasonably accurate values for the     */
+        /*   zeros.  Note that the latter are only expressed with      */
+        /*   16 bits when computing the extrema (the zeros need to     */
+        /*   be in 0..1 exclusive to be considered part of the arc).   */
+        /*                                                             */
+        if ( t1 == 0 )  /* all coefficients are 0! */
+          return;
+
+        if ( t1 > 0x7FFFFFUL )
+        {
+          do
+          {
+            shift++;
+            t1 >>= 1;
+          } while ( t1 > 0x7FFFFFUL );
+
+          /* losing some bits of precision, but we use 24 of them */
+          /* for the computation anyway.                          */
+          a >>= shift;
+          b >>= shift;
+          c >>= shift;
+        }
+        else if ( t1 < 0x400000UL )
+        {
+          do
+          {
+            shift++;
+            t1 <<= 1;
+          } while ( t1 < 0x400000UL );
+
+          a <<= shift;
+          b <<= shift;
+          c <<= shift;
+        }
+      }
+
+      /* handle a == 0 */
+      if ( a == 0 )
+      {
+        if ( b != 0 )
+        {
+          t = - FT_DivFix( c, b ) / 2;
+          test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+        }
+      }
+      else
+      {
+        /* solve the equation now */
+        d = FT_MulFix( b, b ) - FT_MulFix( a, c );
+        if ( d < 0 )
+          return;
+
+        if ( d == 0 )
+        {
+          /* there is a single split point at -b/a */
+          t = - FT_DivFix( b, a );
+          test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+        }
+        else
+        {
+          /* there are two solutions; we need to filter them though */
+          d = FT_SqrtFixed( (FT_Int32)d );
+          t = - FT_DivFix( b - d, a );
+          test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+
+          t = - FT_DivFix( b + d, a );
+          test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+        }
+      }
+    }
+  }
+
+#endif
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    BBox_Cubic_To                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function is used as a `cubic_to' emitter during               */
+  /*    FT_Raster_Decompose().  It checks a cubic Bezier curve with the    */
+  /*    current bounding box, and computes its extrema if necessary to     */
+  /*    update it.                                                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    control1 :: A pointer to the first control point.                  */
+  /*    control2 :: A pointer to the second control point.                 */
+  /*    to       :: A pointer to the destination vector.                   */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    user     :: The address of the current walk context.               */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Always 0.  Needed for the interface only.                          */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    In the case of a non-monotonous arc, we don't compute directly     */
+  /*    extremum coordinates, we subdivise instead.                        */
+  /*                                                                       */
+  static int
+  BBox_Cubic_To( FT_Vector*  control1,
+                 FT_Vector*  control2,
+                 FT_Vector*  to,
+                 TBBox_Rec*  user )
+  {
+    /* we don't need to check `to' since it is always an `on' point, thus */
+    /* within the bbox                                                    */
+
+    if ( CHECK_X( control1, user->bbox ) ||
+         CHECK_X( control2, user->bbox ) )
+
+        BBox_Cubic_Check( user->last.x,
+                          control1->x,
+                          control2->x,
+                          to->x,
+                          &user->bbox.xMin,
+                          &user->bbox.xMax );
+
+    if ( CHECK_Y( control1, user->bbox ) ||
+         CHECK_Y( control2, user->bbox ) )
+
+        BBox_Cubic_Check( user->last.y,
+                          control1->y,
+                          control2->y,
+                          to->y,
+                          &user->bbox.yMin,
+                          &user->bbox.yMax );
+
+    user->last = *to;
+
+    return 0;
+  }
+
+
+  /* documentation is in ftbbox.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Get_BBox( FT_Outline*  outline,
+                       FT_BBox     *abbox )
+  {
+    FT_BBox     cbox;
+    FT_BBox     bbox;
+    FT_Vector*  vec;
+    FT_UShort   n;
+
+
+    if ( !abbox )
+      return FT_Err_Invalid_Argument;
+
+    if ( !outline )
+      return FT_Err_Invalid_Outline;
+
+    /* if outline is empty, return (0,0,0,0) */
+    if ( outline->n_points == 0 || outline->n_contours <= 0 )
+    {
+      abbox->xMin = abbox->xMax = 0;
+      abbox->yMin = abbox->yMax = 0;
+      return 0;
+    }
+
+    /* We compute the control box as well as the bounding box of  */
+    /* all `on' points in the outline.  Then, if the two boxes    */
+    /* coincide, we exit immediately.                             */
+
+    vec = outline->points;
+    bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x;
+    bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y;
+    vec++;
+
+    for ( n = 1; n < outline->n_points; n++ )
+    {
+      FT_Pos  x = vec->x;
+      FT_Pos  y = vec->y;
+
+
+      /* update control box */
+      if ( x < cbox.xMin ) cbox.xMin = x;
+      if ( x > cbox.xMax ) cbox.xMax = x;
+
+      if ( y < cbox.yMin ) cbox.yMin = y;
+      if ( y > cbox.yMax ) cbox.yMax = y;
+
+      if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON )
+      {
+        /* update bbox for `on' points only */
+        if ( x < bbox.xMin ) bbox.xMin = x;
+        if ( x > bbox.xMax ) bbox.xMax = x;
+
+        if ( y < bbox.yMin ) bbox.yMin = y;
+        if ( y > bbox.yMax ) bbox.yMax = y;
+      }
+
+      vec++;
+    }
+
+    /* test two boxes for equality */
+    if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
+         cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
+    {
+      /* the two boxes are different, now walk over the outline to */
+      /* get the Bezier arc extrema.                               */
+
+      static const FT_Outline_Funcs  bbox_interface =
+      {
+        (FT_Outline_MoveTo_Func) BBox_Move_To,
+        (FT_Outline_LineTo_Func) BBox_Move_To,
+        (FT_Outline_ConicTo_Func)BBox_Conic_To,
+        (FT_Outline_CubicTo_Func)BBox_Cubic_To,
+        0, 0
+      };
+
+      FT_Error   error;
+      TBBox_Rec  user;
+
+
+      user.bbox = bbox;
+
+      error = FT_Outline_Decompose( outline, &bbox_interface, &user );
+      if ( error )
+        return error;
+
+      *abbox = user.bbox;
+    }
+    else
+      *abbox = bbox;
+
+    return FT_Err_Ok;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftbdf.c
@@ -1,0 +1,63 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftbdf.c                                                                */
+/*                                                                         */
+/*    FreeType API for accessing BDF-specific strings (body).              */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_BDF_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_BDF_Charset_ID( FT_Face       face,
+                         const char*  *acharset_encoding,
+                         const char*  *acharset_registry )
+  {
+    FT_Error     error;
+    const char*  encoding = NULL;
+    const char*  registry = NULL;
+    
+
+    error = FT_Err_Invalid_Argument;
+    
+    if ( face != NULL && face->driver != NULL )
+    {
+      FT_Module  driver = (FT_Module) face->driver;
+      
+
+      if ( driver->clazz && driver->clazz->module_name         &&
+           ft_strcmp( driver->clazz->module_name, "bdf" ) == 0 )
+      {
+        BDF_Public_Face  bdf_face = (BDF_Public_Face)face;
+        
+
+        encoding = (const char*) bdf_face->charset_encoding;
+        registry = (const char*) bdf_face->charset_registry;
+        error    = 0;
+      }           
+    }
+  
+    if ( acharset_encoding )
+      *acharset_encoding = encoding;
+    
+    if ( acharset_registry )
+      *acharset_registry = registry;
+    
+    return error;
+  }                         
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcache.c
@@ -1,0 +1,31 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcache.c                                                              */
+/*                                                                         */
+/*    The FreeType Caching sub-system (body only).                         */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftlru.c"
+#include "ftcmanag.c"
+#include "ftccache.c"
+#include "ftcglyph.c"
+#include "ftcimage.c"
+#include "ftcsbits.c"
+#include "ftccmap.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcalc.c
@@ -1,0 +1,561 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcalc.c                                                               */
+/*                                                                         */
+/*    Arithmetic computations (body).                                      */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Support for 1-complement arithmetic has been totally dropped in this  */
+  /* release.  You can still write your own code if you need it.           */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Implementing basic computation routines.                              */
+  /*                                                                       */
+  /* FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(),   */
+  /* and FT_FloorFix() are declared in freetype.h.                         */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+/* we need to define a 64-bits data type here */
+
+#ifdef FT_LONG64
+
+  typedef FT_INT64  FT_Int64;
+
+#else
+
+  typedef struct  FT_Int64_
+  {
+    FT_UInt32  lo;
+    FT_UInt32  hi;
+
+  } FT_Int64;
+
+#endif /* FT_LONG64 */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_calc
+
+
+  /* The following three functions are available regardless of whether */
+  /* FT_LONG64 is defined.                                             */
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Fixed )
+  FT_RoundFix( FT_Fixed  a )
+  {
+    return ( a >= 0 ) ?   ( a + 0x8000L ) & -0x10000L
+                      : -((-a + 0x8000L ) & -0x10000L );
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Fixed )
+  FT_CeilFix( FT_Fixed  a )
+  {
+    return ( a >= 0 ) ?   ( a + 0xFFFFL ) & -0x10000L
+                      : -((-a + 0xFFFFL ) & -0x10000L );
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Fixed )
+  FT_FloorFix( FT_Fixed  a )
+  {
+    return ( a >= 0 ) ?   a & -0x10000L
+                      : -((-a) & -0x10000L );
+  }
+
+
+  /* documentation is in ftcalc.h */
+
+  FT_EXPORT_DEF( FT_Int32 )
+  FT_Sqrt32( FT_Int32  x )
+  {
+    FT_ULong  val, root, newroot, mask;
+
+
+    root = 0;
+    mask = 0x40000000L;
+    val  = (FT_ULong)x;
+
+    do
+    {
+      newroot = root + mask;
+      if ( newroot <= val )
+      {
+        val -= newroot;
+        root = newroot + mask;
+      }
+
+      root >>= 1;
+      mask >>= 2;
+
+    } while ( mask != 0 );
+
+    return root;
+  }
+
+
+#ifdef FT_LONG64
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Long )
+  FT_MulDiv( FT_Long  a,
+             FT_Long  b,
+             FT_Long  c )
+  {
+    FT_Int   s;
+    FT_Long  d;
+
+
+    s = 1;
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+    if ( c < 0 ) { c = -c; s = -s; }
+
+    d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c
+                         : 0x7FFFFFFFL );
+
+    return ( s > 0 ) ? d : -d;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Long )
+  FT_MulFix( FT_Long  a,
+             FT_Long  b )
+  {
+    FT_Int   s = 1;
+    FT_Long  c;
+
+
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+
+    c = (FT_Long)( ( (FT_Int64)a * b + 0x8000 ) >> 16 );
+    return ( s > 0 ) ? c : -c ;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Long )
+  FT_DivFix( FT_Long  a,
+             FT_Long  b )
+  {
+    FT_Int32   s;
+    FT_UInt32  q;
+
+    s = 1;
+    if ( a < 0 ) { a = -a; s = -1; }
+    if ( b < 0 ) { b = -b; s = -s; }
+
+    if ( b == 0 )
+      /* check for division by 0 */
+      q = 0x7FFFFFFFL;
+    else
+      /* compute result directly */
+      q = (FT_UInt32)( ( ( (FT_Int64)a << 16 ) + ( b >> 1 ) ) / b );
+
+    return ( s < 0 ? -(FT_Long)q : (FT_Long)q );
+  }
+
+
+#else /* FT_LONG64 */
+
+
+  static void
+  ft_multo64( FT_UInt32  x,
+              FT_UInt32  y,
+              FT_Int64  *z )
+  {
+    FT_UInt32  lo1, hi1, lo2, hi2, lo, hi, i1, i2;
+
+
+    lo1 = x & 0x0000FFFFU;  hi1 = x >> 16;
+    lo2 = y & 0x0000FFFFU;  hi2 = y >> 16;
+
+    lo = lo1 * lo2;
+    i1 = lo1 * hi2;
+    i2 = lo2 * hi1;
+    hi = hi1 * hi2;
+
+    /* Check carry overflow of i1 + i2 */
+    i1 += i2;
+    hi += (FT_UInt32)( i1 < i2 ) << 16;
+
+    hi += i1 >> 16;
+    i1  = i1 << 16;
+
+    /* Check carry overflow of i1 + lo */
+    lo += i1;
+    hi += ( lo < i1 );
+
+    z->lo = lo;
+    z->hi = hi;
+  }
+
+
+  static FT_UInt32
+  ft_div64by32( FT_UInt32  hi,
+                FT_UInt32  lo,
+                FT_UInt32  y )
+  {
+    FT_UInt32  r, q;
+    FT_Int     i;
+
+
+    q = 0;
+    r = hi;
+
+    if ( r >= y )
+      return (FT_UInt32)0x7FFFFFFFL;
+
+    i = 32;
+    do
+    {
+      r <<= 1;
+      q <<= 1;
+      r  |= lo >> 31;
+
+      if ( r >= (FT_UInt32)y )
+      {
+        r -= y;
+        q |= 1;
+      }
+      lo <<= 1;
+    } while ( --i );
+
+    return q;
+  }
+
+
+  /* documentation is in ftcalc.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Add64( FT_Int64*  x,
+            FT_Int64*  y,
+            FT_Int64  *z )
+  {
+    register FT_UInt32  lo, hi, max;
+
+
+    max = x->lo > y->lo ? x->lo : y->lo;
+    lo  = x->lo + y->lo;
+    hi  = x->hi + y->hi + ( lo < max );
+
+    z->lo = lo;
+    z->hi = hi;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Long )
+  FT_MulDiv( FT_Long  a,
+             FT_Long  b,
+             FT_Long  c )
+  {
+    long  s;
+
+
+    if ( a == 0 || b == c )
+      return a;
+
+    s  = a; a = ABS( a );
+    s ^= b; b = ABS( b );
+    s ^= c; c = ABS( c );
+
+    if ( a <= 46340L && b <= 46340L && c <= 176095L && c > 0 )
+    {
+      a = ( a * b + ( c >> 1 ) ) / c;
+    }
+    else if ( c > 0 )
+    {
+      FT_Int64  temp, temp2;
+
+
+      ft_multo64( a, b, &temp );
+
+      temp2.hi = 0;
+      temp2.lo = (FT_UInt32)(c >> 1);
+      FT_Add64( &temp, &temp2, &temp );
+      a = ft_div64by32( temp.hi, temp.lo, c );
+    }
+    else
+      a = 0x7FFFFFFFL;
+
+    return ( s < 0 ? -a : a );
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Long )
+  FT_MulFix( FT_Long  a,
+             FT_Long  b )
+  {
+    FT_Long   s;
+    FT_ULong  ua, ub;
+
+
+    if ( a == 0 || b == 0x10000L )
+      return a;
+
+    s  = a; a = ABS(a);
+    s ^= b; b = ABS(b);
+
+    ua = (FT_ULong)a;
+    ub = (FT_ULong)b;
+
+    if ( ua <= 2048 && ub <= 1048576L )
+    {
+      ua = ( ua * ub + 0x8000 ) >> 16;
+    }
+    else
+    {
+      FT_ULong  al = ua & 0xFFFF;
+
+
+      ua = ( ua >> 16 ) * ub +  al * ( ub >> 16 ) +
+           ( ( al * ( ub & 0xFFFF ) + 0x8000 ) >> 16 );
+    }
+
+    return ( s < 0 ? -(FT_Long)ua : (FT_Long)ua );
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Long )
+  FT_DivFix( FT_Long  a,
+             FT_Long  b )
+  {
+    FT_Int32   s;
+    FT_UInt32  q;
+
+
+    s  = a; a = ABS(a);
+    s ^= b; b = ABS(b);
+
+    if ( b == 0 )
+    {
+      /* check for division by 0 */
+      q = 0x7FFFFFFFL;
+    }
+    else if ( ( a >> 16 ) == 0 )
+    {
+      /* compute result directly */
+      q = (FT_UInt32)( (a << 16) + (b >> 1) ) / (FT_UInt32)b;
+    }
+    else
+    {
+      /* we need more bits; we have to do it by hand */
+      FT_Int64  temp, temp2;
+
+      temp.hi  = (FT_Int32) (a >> 16);
+      temp.lo  = (FT_UInt32)(a << 16);
+      temp2.hi = 0;
+      temp2.lo = (FT_UInt32)( b >> 1 );
+      FT_Add64( &temp, &temp2, &temp );
+      q = ft_div64by32( temp.hi, temp.lo, b );
+    }
+
+    return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+  }
+
+
+  /* documentation is in ftcalc.h */
+
+  FT_EXPORT_DEF( void )
+  FT_MulTo64( FT_Int32   x,
+              FT_Int32   y,
+              FT_Int64  *z )
+  {
+    FT_Int32  s;
+
+
+    s  = x; x = ABS( x );
+    s ^= y; y = ABS( y );
+
+    ft_multo64( x, y, z );
+
+    if ( s < 0 )
+    {
+      z->lo = (FT_UInt32)-(FT_Int32)z->lo;
+      z->hi = ~z->hi + !( z->lo );
+    }
+  }
+
+
+  /* documentation is in ftcalc.h */
+
+  /* apparently, the second version of this code is not compiled correctly */
+  /* on Mac machines with the MPW C compiler..  tsss, tsss, tss...         */
+
+#if 1
+
+  FT_EXPORT_DEF( FT_Int32 )
+  FT_Div64by32( FT_Int64*  x,
+                FT_Int32   y )
+  {
+    FT_Int32   s;
+    FT_UInt32  q, r, i, lo;
+
+
+    s  = x->hi;
+    if ( s < 0 )
+    {
+      x->lo = (FT_UInt32)-(FT_Int32)x->lo;
+      x->hi = ~x->hi + !x->lo;
+    }
+    s ^= y;  y = ABS( y );
+
+    /* Shortcut */
+    if ( x->hi == 0 )
+    {
+      if ( y > 0 )
+        q = x->lo / y;
+      else
+        q = 0x7FFFFFFFL;
+
+      return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+    }
+
+    r  = x->hi;
+    lo = x->lo;
+
+    if ( r >= (FT_UInt32)y ) /* we know y is to be treated as unsigned here */
+      return ( s < 0 ? 0x80000001UL : 0x7FFFFFFFUL );
+                             /* Return Max/Min Int32 if division overflow. */
+                             /* This includes division by zero! */
+    q = 0;
+    for ( i = 0; i < 32; i++ )
+    {
+      r <<= 1;
+      q <<= 1;
+      r  |= lo >> 31;
+
+      if ( r >= (FT_UInt32)y )
+      {
+        r -= y;
+        q |= 1;
+      }
+      lo <<= 1;
+    }
+
+    return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+  }
+
+#else /* 0 */
+
+  FT_EXPORT_DEF( FT_Int32 )
+  FT_Div64by32( FT_Int64*  x,
+                FT_Int32   y )
+  {
+    FT_Int32   s;
+    FT_UInt32  q;
+
+
+    s  = x->hi;
+    if ( s < 0 )
+    {
+      x->lo = (FT_UInt32)-(FT_Int32)x->lo;
+      x->hi = ~x->hi + !x->lo;
+    }
+    s ^= y;  y = ABS( y );
+
+    /* Shortcut */
+    if ( x->hi == 0 )
+    {
+      if ( y > 0 )
+        q = ( x->lo + ( y >> 1 ) ) / y;
+      else
+        q = 0x7FFFFFFFL;
+
+      return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+    }
+
+    q = ft_div64by32( x->hi, x->lo, y );
+
+    return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+  }
+
+#endif /* 0 */
+
+
+#endif /* FT_LONG64 */
+
+
+  /* a not-so-fast but working 16.16 fixed point square root function */
+
+  FT_EXPORT_DEF( FT_Int32 )
+  FT_SqrtFixed( FT_Int32  x )
+  {
+    FT_UInt32  root, rem_hi, rem_lo, test_div;
+    FT_Int     count;
+
+
+    root = 0;
+
+    if ( x > 0 )
+    {
+      rem_hi = 0;
+      rem_lo = x;
+      count  = 24;
+      do
+      {
+        rem_hi   = ( rem_hi << 2 ) | ( rem_lo >> 30 );
+        rem_lo <<= 2;
+        root   <<= 1;
+        test_div = ( root << 1 ) + 1;
+
+        if ( rem_hi >= test_div )
+        {
+          rem_hi -= test_div;
+          root   += 1;
+        }
+      } while ( --count );
+    }
+
+    return (FT_Int32)root;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftccache.c
@@ -1,0 +1,714 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftccache.c                                                             */
+/*                                                                         */
+/*    The FreeType internal cache interface (body).                        */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_MANAGER_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+#define FTC_HASH_MAX_LOAD  2
+#define FTC_HASH_MIN_LOAD  1
+#define FTC_HASH_SUB_LOAD  ( FTC_HASH_MAX_LOAD - FTC_HASH_MIN_LOAD )
+
+/* this one _must_ be a power of 2! */
+#define FTC_HASH_INITIAL_SIZE  8
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                   CACHE NODE DEFINITIONS                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_EXPORT_DEF( void )
+  ftc_node_done( FTC_Node   node,
+                 FTC_Cache  cache )
+  {
+    FTC_Family       family;
+    FTC_FamilyEntry  entry;
+
+
+    entry  = cache->manager->families.entries + node->fam_index;
+    family = entry->family;
+
+    /* remove from parent set table - eventually destroy the set */
+    if ( --family->num_nodes == 0 )
+      FT_LruList_Remove( cache->families, (FT_LruNode) family );
+  }
+
+
+  /* add a new node to the head of the manager's circular MRU list */
+  static void
+  ftc_node_mru_link( FTC_Node     node,
+                     FTC_Manager  manager )
+  {
+    FTC_Node  first = manager->nodes_list;
+
+
+    if ( first )
+    {
+      FTC_Node  last = first->mru_prev;
+
+
+      FT_ASSERT( last->mru_next == first );
+
+      node->mru_prev = last;
+      node->mru_next = first;
+
+      last->mru_next  = node;
+      first->mru_prev = node;
+    }
+    else
+    {
+      FT_ASSERT( manager->num_nodes == 0 );
+
+      node->mru_next = node;
+      node->mru_prev = node;
+    }
+
+    manager->nodes_list = node;
+    manager->num_nodes++;
+  }
+
+
+  /* remove a node from the manager's MRU list */
+  static void
+  ftc_node_mru_unlink( FTC_Node     node,
+                       FTC_Manager  manager )
+  {
+    FTC_Node  first = manager->nodes_list;
+    FTC_Node  prev  = node->mru_prev;
+    FTC_Node  next  = node->mru_next;
+
+
+    FT_ASSERT( first != NULL && manager->num_nodes > 0 );
+    FT_ASSERT( next->mru_prev == node );
+    FT_ASSERT( prev->mru_next == node );
+
+    next->mru_prev = prev;
+    prev->mru_next = next;
+
+    if ( node == first )
+    {
+      /* this is the last node in the list; update its head pointer */
+      if ( node == next )
+        manager->nodes_list = NULL;
+      else
+        manager->nodes_list = next;
+    }
+
+    node->mru_next = NULL;
+    node->mru_prev = NULL;
+    manager->num_nodes--;
+  }
+
+
+  /* move a node to the head of the manager's MRU list */
+  static void
+  ftc_node_mru_up( FTC_Node     node,
+                   FTC_Manager  manager )
+  {
+    FTC_Node  first = manager->nodes_list;
+
+
+    if ( node != first )
+    {
+      FTC_Node  prev = node->mru_prev;
+      FTC_Node  next = node->mru_next;
+      FTC_Node  last;
+
+
+      prev->mru_next = next;
+      next->mru_prev = prev;
+
+      last            = first->mru_prev;
+      node->mru_next  = first;
+      node->mru_prev  = last;
+      first->mru_prev = node;
+      last->mru_next  = node;
+
+      manager->nodes_list = node;
+    }
+  }
+
+
+  /* remove a node from its cache's hash table */
+  static FT_Error
+  ftc_node_hash_unlink( FTC_Node   node,
+                        FTC_Cache  cache )
+  {
+    FT_Error   error = 0;
+    FTC_Node  *pnode;
+    FT_UInt    idx, num_buckets;
+
+
+    idx = (FT_UInt)( node->hash & cache->mask );
+    if ( idx < cache->p )
+      idx = (FT_UInt)( node->hash & ( 2 * cache->mask + 1 ) );
+
+    pnode = cache->buckets + idx;
+
+    for (;;)
+    {
+      if ( *pnode == NULL )
+      {
+        FT_ERROR(( "ftc_node_hash_unlink: unknown node!\n" ));
+        return FT_Err_Ok;
+      }
+
+      if ( *pnode == node )
+      {
+        *pnode     = node->link;
+        node->link = NULL;
+        break;
+      }
+
+      pnode = &(*pnode)->link;
+    }
+
+    num_buckets = ( cache->p + cache->mask + 1 );
+
+    if ( ++cache->slack > (FT_Long)num_buckets * FTC_HASH_SUB_LOAD )
+    {
+      FT_UInt    p         = cache->p;
+      FT_UInt    mask      = cache->mask;
+      FT_UInt    old_index = p + mask;
+      FTC_Node*  pold;
+
+
+      FT_ASSERT( old_index >= FTC_HASH_INITIAL_SIZE );
+
+      if ( p == 0 )
+      {
+        FT_Memory  memory = cache->memory;
+
+
+        cache->mask >>= 1;
+        p             = cache->mask;
+
+        if ( FT_RENEW_ARRAY( cache->buckets, ( mask + 1 ) * 2, (mask+1) ) )
+        {
+          FT_ERROR(( "ftc_node_hash_unlink: couldn't shunk buckets!\n" ));
+          goto Exit;
+        }
+      }
+      else
+        p--;
+
+      pnode = cache->buckets + p;
+      while ( *pnode )
+        pnode = &(*pnode)->link;
+
+      pold   = cache->buckets + old_index;
+      *pnode = *pold;
+      *pold  = NULL;
+
+      cache->slack -= FTC_HASH_MAX_LOAD;
+      cache->p      = p;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+
+  /* add a node to the "top" of its cache's hash table */
+  static FT_Error
+  ftc_node_hash_link( FTC_Node   node,
+                      FTC_Cache  cache )
+  {
+    FTC_Node  *pnode;
+    FT_UInt    idx;
+    FT_Error   error = 0;
+
+
+    idx = (FT_UInt)( node->hash & cache->mask );
+    if ( idx < cache->p )
+      idx = (FT_UInt)( node->hash & (2 * cache->mask + 1 ) );
+
+    pnode = cache->buckets + idx;
+
+    node->link = *pnode;
+    *pnode     = node;
+
+    if ( --cache->slack < 0 )
+    {
+      FT_UInt    p     = cache->p;
+      FT_UInt    mask  = cache->mask;
+      FTC_Node   new_list;
+
+
+      /* split a single bucket */
+      new_list = NULL;
+      pnode    = cache->buckets + p;
+
+      for (;;)
+      {
+        node = *pnode;
+        if ( node == NULL )
+          break;
+
+        if ( node->hash & ( mask + 1 ) )
+        {
+          *pnode     = node->link;
+          node->link = new_list;
+          new_list   = node;
+        }
+        else
+          pnode = &node->link;
+      }
+
+      cache->buckets[p + mask + 1] = new_list;
+
+      cache->slack += FTC_HASH_MAX_LOAD;
+
+      if ( p >= mask )
+      {
+        FT_Memory  memory = cache->memory;
+
+
+        if ( FT_RENEW_ARRAY( cache->buckets,
+                             ( mask + 1 ) * 2, ( mask + 1 ) * 4 ) )
+        {
+          FT_ERROR(( "ftc_node_hash_link: couldn't expand buckets!\n" ));
+          goto Exit;
+        }
+
+        cache->mask = 2 * mask + 1;
+        cache->p    = 0;
+      }
+      else
+        cache->p = p + 1;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+
+
+  /* remove a node from the cache manager */
+  FT_EXPORT_DEF( void )
+  ftc_node_destroy( FTC_Node     node,
+                    FTC_Manager  manager )
+  {
+    FT_Memory        memory  = manager->library->memory;
+    FTC_Cache        cache;
+    FTC_FamilyEntry  entry;
+    FTC_Cache_Class  clazz;
+
+
+#ifdef FT_DEBUG_ERROR
+    /* find node's cache */
+    if ( node->fam_index >= manager->families.count )
+    {
+      FT_ERROR(( "ftc_node_destroy: invalid node handle\n" ));
+      return;
+    }
+#endif
+
+    entry = manager->families.entries + node->fam_index;
+    cache = entry->cache;
+
+#ifdef FT_DEBUG_ERROR
+    if ( cache == NULL )
+    {
+      FT_ERROR(( "ftc_node_destroy: invalid node handle\n" ));
+      return;
+    }
+#endif
+
+    clazz = cache->clazz;
+
+    manager->cur_weight -= clazz->node_weight( node, cache );
+
+    /* remove node from mru list */
+    ftc_node_mru_unlink( node, manager );
+
+    /* remove node from cache's hash table */
+    ftc_node_hash_unlink( node, cache );
+
+    /* now finalize it */
+    if ( clazz->node_done )
+      clazz->node_done( node, cache );
+
+    FT_FREE( node );
+
+    /* check, just in case of general corruption :-) */
+    if ( manager->num_nodes == 0 )
+      FT_ERROR(( "ftc_node_destroy: invalid cache node count! = %d\n",
+                  manager->num_nodes ));
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                   CACHE FAMILY DEFINITIONS                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_EXPORT_DEF( FT_Error )
+  ftc_family_init( FTC_Family  family,
+                   FTC_Query   query,
+                   FTC_Cache   cache )
+  {
+    FT_Error         error;
+    FTC_Manager      manager = cache->manager;
+    FT_Memory        memory  = manager->library->memory;
+    FTC_FamilyEntry  entry;
+
+
+    family->cache     = cache;
+    family->num_nodes = 0;
+
+    /* now add to manager's family table */
+    error = ftc_family_table_alloc( &manager->families, memory, &entry );
+    if ( !error )
+    {
+      entry->cache      = cache;
+      entry->family     = family;
+      family->fam_index = entry->index;
+
+      query->family = family;   /* save family in query */
+    }
+
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  ftc_family_done( FTC_Family  family )
+  {
+    FTC_Manager  manager = family->cache->manager;
+
+
+    /* remove from manager's family table */
+    ftc_family_table_free( &manager->families, family->fam_index );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    ABSTRACT CACHE CLASS                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+
+  FT_EXPORT_DEF( FT_Error )
+  ftc_cache_init( FTC_Cache  cache )
+  {
+    FT_Memory        memory = cache->memory;
+    FTC_Cache_Class  clazz  = cache->clazz;
+    FT_Error         error;
+
+
+    cache->p     = 0;
+    cache->mask  = FTC_HASH_INITIAL_SIZE - 1;
+    cache->slack = FTC_HASH_INITIAL_SIZE * FTC_HASH_MAX_LOAD;
+
+    if ( FT_NEW_ARRAY( cache->buckets, FTC_HASH_INITIAL_SIZE * 2 ) )
+      goto Exit;
+
+    /* now, initialize the lru list of families for this cache */
+    if ( clazz->family_size > 0 )
+    {
+      FT_LruList_ClassRec*  lru_class = &cache->family_class;
+
+
+      lru_class->list_size = sizeof( FT_LruListRec );
+      lru_class->list_init = NULL;
+      lru_class->list_done = NULL;
+
+      lru_class->node_size    = clazz->family_size;
+      lru_class->node_init    = (FT_LruNode_InitFunc)   clazz->family_init;
+      lru_class->node_done    = (FT_LruNode_DoneFunc)   clazz->family_done;
+      lru_class->node_flush   = (FT_LruNode_FlushFunc)  NULL;
+      lru_class->node_compare = (FT_LruNode_CompareFunc)clazz->family_compare;
+
+      error = FT_LruList_New( (FT_LruList_Class) lru_class,
+                              0,    /* max items == 0 => unbounded list */
+                              cache,
+                              memory,
+                              &cache->families );
+      if ( error )
+        FT_FREE( cache->buckets );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  ftc_cache_clear( FTC_Cache  cache )
+  {
+    if ( cache )
+    {
+      FT_Memory        memory  = cache->memory;
+      FTC_Cache_Class  clazz   = cache->clazz;
+      FTC_Manager      manager = cache->manager;
+      FT_UFast         i;
+      FT_UInt          count;
+
+      count = cache->p + cache->mask + 1;
+
+      for ( i = 0; i < count; i++ )
+      {
+        FTC_Node  *pnode = cache->buckets + i, next, node = *pnode;
+
+
+        while ( node )
+        {
+          next        = node->link;
+          node->link  = NULL;
+
+          /* remove node from mru list */
+          ftc_node_mru_unlink( node, manager );
+
+          /* now finalize it */
+          manager->cur_weight -= clazz->node_weight( node, cache );
+
+          if ( clazz->node_done )
+            clazz->node_done( node, cache );
+
+          FT_FREE( node );
+          node = next;
+        }
+        cache->buckets[i] = NULL;
+      }
+
+      cache->p = 0;
+
+      /* destroy the families */
+      if ( cache->families )
+        FT_LruList_Reset( cache->families );
+    }
+  }
+
+
+  FT_EXPORT_DEF( void )
+  ftc_cache_done( FTC_Cache  cache )
+  {
+    if ( cache )
+    {
+      FT_Memory  memory = cache->memory;
+
+
+      ftc_cache_clear( cache );
+
+      FT_FREE( cache->buckets );
+      cache->mask  = 0;
+      cache->slack = 0;
+
+      if ( cache->families )
+      {
+        FT_LruList_Destroy( cache->families );
+        cache->families = NULL;
+      }
+    }
+  }
+
+
+  /* Look up a node in "top" of its cache's hash table. */
+  /* If not found, create a new node.                   */
+  /*                                                    */
+  FT_EXPORT_DEF( FT_Error )
+  ftc_cache_lookup( FTC_Cache   cache,
+                    FTC_Query   query,
+                    FTC_Node   *anode )
+  {
+    FT_Error    error = FT_Err_Ok;
+    FT_LruNode  lru;
+
+
+    if ( !cache || !query || !anode )
+      return FTC_Err_Invalid_Argument;
+
+    *anode = NULL;
+
+    query->hash   = 0;
+    query->family = NULL;
+
+    /* XXX: we break encapsulation for the sake of speed! */
+    {
+      /* first of all, find the relevant family */
+      FT_LruList              list    = cache->families;
+      FT_LruNode              fam, *pfam;
+      FT_LruNode_CompareFunc  compare = list->clazz->node_compare;
+
+      pfam = &list->nodes;
+      for (;;)
+      {
+        fam = *pfam;
+        if ( fam == NULL )
+        {
+          error = FT_LruList_Lookup( list, query, &lru );
+          if ( error )
+            goto Exit;
+
+          goto Skip;
+        }
+
+        if ( compare( fam, query, list->data ) )
+          break;
+
+        pfam = &fam->next;
+      }
+
+      FT_ASSERT( fam != NULL );
+
+      /* move to top of list when needed */
+      if ( fam != list->nodes )
+      {
+        *pfam       = fam->next;
+        fam->next   = list->nodes;
+        list->nodes = fam;
+      }
+
+      lru = fam;
+
+    Skip:
+      ;
+    }
+
+    {
+      FTC_Family  family = (FTC_Family) lru;
+      FT_UFast    hash    = query->hash;
+      FTC_Node*   bucket;
+      FT_UInt     idx;
+
+
+      idx = hash & cache->mask;
+      if ( idx < cache->p )
+        idx = hash & ( cache->mask * 2 + 1 );
+
+      bucket  = cache->buckets + idx;
+
+
+      if ( query->family     != family                        ||
+           family->fam_index >= cache->manager->families.size )
+      {
+        FT_ERROR((
+          "ftc_cache_lookup: invalid query (bad 'family' field)\n" ));
+        return FTC_Err_Invalid_Argument;
+      }
+
+      if ( *bucket )
+      {
+        FTC_Node*             pnode   = bucket;
+        FTC_Node_CompareFunc  compare = cache->clazz->node_compare;
+
+
+        for ( ;; )
+        {
+          FTC_Node  node;
+
+
+          node = *pnode;
+          if ( node == NULL )
+            break;
+
+          if ( node->hash == hash                            &&
+               (FT_UInt)node->fam_index == family->fam_index &&
+               compare( node, query, cache ) )
+          {
+            /* move to head of bucket list */
+            if ( pnode != bucket )
+            {
+              *pnode     = node->link;
+              node->link = *bucket;
+              *bucket    = node;
+            }
+
+            /* move to head of MRU list */
+            if ( node != cache->manager->nodes_list )
+              ftc_node_mru_up( node, cache->manager );
+
+            *anode = node;
+            goto Exit;
+          }
+
+          pnode = &node->link;
+        }
+      }
+
+      /* didn't find a node, create a new one */
+      {
+        FTC_Cache_Class  clazz   = cache->clazz;
+        FTC_Manager      manager = cache->manager;
+        FT_Memory        memory  = cache->memory;
+        FTC_Node         node;
+
+
+        if ( FT_ALLOC( node, clazz->node_size ) )
+          goto Exit;
+
+        node->fam_index = (FT_UShort) family->fam_index;
+        node->hash      = query->hash;
+        node->ref_count = 0;
+
+        error = clazz->node_init( node, query, cache );
+        if ( error )
+        {
+          FT_FREE( node );
+          goto Exit;
+        }
+
+        error = ftc_node_hash_link( node, cache );
+        if ( error )
+        {
+          clazz->node_done( node, cache );
+          FT_FREE( node );
+          goto Exit;
+        }
+
+        ftc_node_mru_link( node, cache->manager );
+
+        cache->manager->cur_weight += clazz->node_weight( node, cache );
+
+        /* now try to compress the node pool when necessary */
+        if ( manager->cur_weight >= manager->max_weight )
+        {
+          node->ref_count++;
+          FTC_Manager_Compress( manager );
+          node->ref_count--;
+        }
+
+        *anode = node;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftccmap.c
@@ -1,0 +1,411 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftccmap.c                                                              */
+/*                                                                         */
+/*    FreeType CharMap cache (body)                                        */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_CACHE_H
+#include FT_CACHE_CHARMAP_H
+#include FT_CACHE_MANAGER_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Each FTC_CMapNode contains a simple array to map a range of character */
+  /* codes to equivalent glyph indices.                                    */
+  /*                                                                       */
+  /* For now, the implementation is very basic: Each node maps a range of  */
+  /* 128 consecutive character codes to their corresponding glyph indices. */
+  /*                                                                       */
+  /* We could do more complex things, but I don't think it is really very  */
+  /* useful.                                                               */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /* number of glyph indices / character code per node */
+#define FTC_CMAP_INDICES_MAX  128
+
+
+  typedef struct  FTC_CMapNodeRec_
+  {
+    FTC_NodeRec  node;
+    FT_UInt32    first;                         /* first character in node */
+    FT_UInt16    indices[FTC_CMAP_INDICES_MAX]; /* array of glyph indices  */
+
+  } FTC_CMapNodeRec, *FTC_CMapNode;
+
+
+#define FTC_CMAP_NODE( x ) ( (FTC_CMapNode)( x ) )
+
+
+  /* compute node hash value from cmap family and "requested" glyph index */
+#define FTC_CMAP_HASH( cfam, cquery )                                       \
+          ( (cfam)->hash + ( (cquery)->char_code / FTC_CMAP_INDICES_MAX ) )
+
+  /* if (indices[n] == FTC_CMAP_UNKNOWN), we assume that the corresponding */
+  /* glyph indices haven't been queried through FT_Get_Glyph_Index() yet   */
+#define FTC_CMAP_UNKNOWN  ( (FT_UInt16)-1 )
+
+
+  /* the charmap query */
+  typedef struct  FTC_CMapQueryRec_
+  {
+    FTC_QueryRec  query;
+    FTC_CMapDesc  desc;
+    FT_UInt32     char_code;
+
+  } FTC_CMapQueryRec, *FTC_CMapQuery;
+
+
+#define FTC_CMAP_QUERY( x )  ( (FTC_CMapQuery)( x ) )
+
+
+  /* the charmap family */
+  typedef struct FTC_CMapFamilyRec_
+  {
+    FTC_FamilyRec    family;
+    FT_UInt32        hash;
+    FTC_CMapDescRec  desc;
+    FT_UInt          index;
+
+  } FTC_CMapFamilyRec, *FTC_CMapFamily;
+
+
+#define FTC_CMAP_FAMILY( x )         ( (FTC_CMapFamily)( x ) )
+#define FTC_CMAP_FAMILY_MEMORY( x )  FTC_FAMILY( x )->memory
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        CHARMAP NODES                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* no need for specific finalizer; we use "ftc_node_done" directly */
+
+  /* initialize a new cmap node */
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_cmap_node_init( FTC_CMapNode   cnode,
+                      FTC_CMapQuery  cquery,
+                      FTC_Cache      cache )
+  {
+    FT_UInt32  first;
+    FT_UInt    n;
+    FT_UNUSED( cache );
+
+
+    first = ( cquery->char_code / FTC_CMAP_INDICES_MAX ) *
+            FTC_CMAP_INDICES_MAX;
+
+    cnode->first = first;
+    for ( n = 0; n < FTC_CMAP_INDICES_MAX; n++ )
+      cnode->indices[n] = FTC_CMAP_UNKNOWN;
+
+    return 0;
+  }
+
+
+  /* compute the weight of a given cmap node */
+  FT_CALLBACK_DEF( FT_ULong )
+  ftc_cmap_node_weight( FTC_CMapNode  cnode )
+  {
+    FT_UNUSED( cnode );
+    
+    return sizeof ( *cnode );
+  }
+
+
+  /* compare a cmap node to a given query */
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_cmap_node_compare( FTC_CMapNode   cnode,
+                         FTC_CMapQuery  cquery )
+  {
+    FT_UInt32  offset = (FT_UInt32)( cquery->char_code - cnode->first );
+
+
+    return FT_BOOL( offset < FTC_CMAP_INDICES_MAX );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    CHARMAP FAMILY                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_cmap_family_init( FTC_CMapFamily  cfam,
+                        FTC_CMapQuery   cquery,
+                        FTC_Cache       cache )
+  {
+    FTC_Manager   manager = cache->manager;
+    FTC_CMapDesc  desc = cquery->desc;
+    FT_UInt32     hash = 0;
+    FT_Error      error;
+    FT_Face       face;
+
+
+    /* setup charmap descriptor */
+    cfam->desc = *desc;
+
+    /* let's see whether the rest is correct too */
+    error = FTC_Manager_Lookup_Face( manager, desc->face_id, &face );
+    if ( !error )
+    {
+      FT_UInt      count = face->num_charmaps;
+      FT_UInt      idx   = count;
+      FT_CharMap*  cur   = face->charmaps;
+
+
+      switch ( desc->type )
+      {
+      case FTC_CMAP_BY_INDEX:
+        idx  = desc->u.index;
+        hash = idx * 33;
+        break;
+
+      case FTC_CMAP_BY_ENCODING:
+        for ( idx = 0; idx < count; idx++, cur++ )
+          if ( cur[0]->encoding == desc->u.encoding )
+            break;
+
+        hash = idx * 67;
+        break;
+
+      case FTC_CMAP_BY_ID:
+        for ( idx = 0; idx < count; idx++, cur++ )
+        {
+          if ( (FT_UInt)cur[0]->platform_id == desc->u.id.platform &&
+               (FT_UInt)cur[0]->encoding_id == desc->u.id.encoding )
+          {
+            hash = ( ( desc->u.id.platform << 8 ) | desc->u.id.encoding ) * 7;
+            break;
+          }
+        }
+        break;
+
+      default:
+        ;
+      }
+
+      if ( idx >= count )
+        goto Bad_Descriptor;
+
+      /* compute hash value, both in family and query */
+      cfam->index               = idx;
+      cfam->hash                = hash ^ FTC_FACE_ID_HASH( desc->face_id );
+      FTC_QUERY( cquery )->hash = FTC_CMAP_HASH( cfam, cquery );
+
+      error = ftc_family_init( FTC_FAMILY( cfam ),
+                               FTC_QUERY( cquery ), cache );
+    }
+
+    return error;
+
+  Bad_Descriptor:
+    FT_ERROR(( "ftp_cmap_family_init: invalid charmap descriptor\n" ));
+    return FTC_Err_Invalid_Argument;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_cmap_family_compare( FTC_CMapFamily  cfam,
+                           FTC_CMapQuery   cquery )
+  {
+    FT_Int  result = 0;
+
+
+    /* first, compare face id and type */
+    if ( cfam->desc.face_id != cquery->desc->face_id ||
+         cfam->desc.type    != cquery->desc->type    )
+      goto Exit;
+
+    switch ( cfam->desc.type )
+    {
+    case FTC_CMAP_BY_INDEX:
+      result = ( cfam->desc.u.index == cquery->desc->u.index );
+      break;
+
+    case FTC_CMAP_BY_ENCODING:
+      result = ( cfam->desc.u.encoding == cquery->desc->u.encoding );
+      break;
+
+    case FTC_CMAP_BY_ID:
+      result = ( cfam->desc.u.id.platform == cquery->desc->u.id.platform &&
+                 cfam->desc.u.id.encoding == cquery->desc->u.id.encoding );
+      break;
+
+    default:
+      ;
+    }
+
+    if ( result )
+    {
+      /* when found, update the 'family' and 'hash' field of the query */
+      FTC_QUERY( cquery )->family = FTC_FAMILY( cfam );
+      FTC_QUERY( cquery )->hash   = FTC_CMAP_HASH( cfam, cquery );
+    }
+
+  Exit:
+    return FT_BOOL( result );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GLYPH IMAGE CACHE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FTC_Cache_ClassRec  ftc_cmap_cache_class =
+  {
+    sizeof ( FTC_CacheRec ),
+    (FTC_Cache_InitFunc) ftc_cache_init,
+    (FTC_Cache_ClearFunc)ftc_cache_clear,
+    (FTC_Cache_DoneFunc) ftc_cache_done,
+
+    sizeof ( FTC_CMapFamilyRec ),
+    (FTC_Family_InitFunc)   ftc_cmap_family_init,
+    (FTC_Family_CompareFunc)ftc_cmap_family_compare,
+    (FTC_Family_DoneFunc)   ftc_family_done,
+
+    sizeof ( FTC_CMapNodeRec ),
+    (FTC_Node_InitFunc)   ftc_cmap_node_init,
+    (FTC_Node_WeightFunc) ftc_cmap_node_weight,
+    (FTC_Node_CompareFunc)ftc_cmap_node_compare,
+    (FTC_Node_DoneFunc)   ftc_node_done
+  };
+
+
+  /* documentation is in ftccmap.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_CMapCache_New( FTC_Manager     manager,
+                     FTC_CMapCache  *acache )
+  {
+    return FTC_Manager_Register_Cache(
+             manager,
+             (FTC_Cache_Class)&ftc_cmap_cache_class,
+             FTC_CACHE_P( acache ) );
+  }
+
+
+#ifdef FTC_CACHE_USE_INLINE
+
+#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
+          ftc_cmap_family_compare( (FTC_CMapFamily)(f), (FTC_CMapQuery)(q) )
+
+#define GEN_CACHE_NODE_COMPARE( n, q, c ) \
+          ftc_cmap_node_compare( (FTC_CMapNode)(n), (FTC_CMapQuery)(q) )
+
+#define GEN_CACHE_LOOKUP  ftc_cmap_cache_lookup
+
+#include "ftccache.i"
+
+#else  /* !FTC_CACHE_USE_INLINE */
+
+#define ftc_cmap_cache_lookup  ftc_cache_lookup
+
+#endif /* !FTC_CACHE_USE_INLINE */
+
+
+  /* documentation is in ftccmap.h */
+
+  FT_EXPORT_DEF( FT_UInt )
+  FTC_CMapCache_Lookup( FTC_CMapCache  cache,
+                        FTC_CMapDesc   desc,
+                        FT_UInt32      char_code )
+  {
+    FTC_CMapQueryRec  cquery;
+    FTC_CMapNode      node;
+    FT_Error          error;
+    FT_UInt           gindex = 0;
+
+
+    if ( !cache || !desc )
+    {
+      FT_ERROR(( "FTC_CMapCache_Lookup: bad arguments, returning 0!\n" ));
+      return 0;
+    }
+
+    cquery.desc      = desc;
+    cquery.char_code = char_code;
+
+    error = ftc_cmap_cache_lookup( FTC_CACHE( cache ),
+                                   FTC_QUERY( &cquery ),
+                                   (FTC_Node*)&node );
+    if ( !error )
+    {
+      FT_UInt  offset = (FT_UInt)( char_code - node->first );
+
+
+      FT_ASSERT( offset < FTC_CMAP_INDICES_MAX );
+
+      gindex = node->indices[offset];
+      if ( gindex == FTC_CMAP_UNKNOWN )
+      {
+        FT_Face  face;
+
+
+        /* we need to use FT_Get_Char_Index */
+        gindex = 0;
+
+        error = FTC_Manager_Lookup_Face( FTC_CACHE(cache)->manager,
+                                         desc->face_id,
+                                         &face );
+        if ( !error )
+        {
+          FT_CharMap  old, cmap  = NULL;
+          FT_UInt     cmap_index;
+
+
+          /* save old charmap, select new one */
+          old        = face->charmap;
+          cmap_index = FTC_CMAP_FAMILY( FTC_QUERY( &cquery )->family )->index;
+          cmap       = face->charmaps[cmap_index];
+
+          FT_Set_Charmap( face, cmap );
+
+          /* perform lookup */
+          gindex                = FT_Get_Char_Index( face, char_code );
+          node->indices[offset] = (FT_UInt16)gindex;
+
+          /* restore old charmap */
+          FT_Set_Charmap( face, old );
+        }
+      }
+    }
+
+    return gindex;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcerror.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcerror.h                                                             */
+/*                                                                         */
+/*    Caching sub-system error codes (specification only).                 */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the caching sub-system error enumeration  */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __FTCERROR_H__
+#define __FTCERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  FTC_Err_
+#define FT_ERR_BASE    FT_Mod_Err_Cache
+
+#include FT_ERRORS_H
+
+#endif /* __FTCERROR_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcglyph.c
@@ -1,0 +1,115 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcglyph.c                                                             */
+/*                                                                         */
+/*    FreeType Glyph Image (FT_Glyph) cache (body).                        */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_ERRORS_H
+#include FT_LIST_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "ftcerror.h"
+
+
+  /* create a new chunk node, setting its cache index and ref count */
+  FT_EXPORT_DEF( void )
+  ftc_glyph_node_init( FTC_GlyphNode     gnode,
+                       FT_UInt           gindex,
+                       FTC_GlyphFamily   gfam )
+  {
+    FT_UInt  len;
+    FT_UInt  start = FTC_GLYPH_FAMILY_START( gfam, gindex );
+
+
+    gnode->item_start = (FT_UShort)start;
+
+    len = gfam->item_total - start;
+    if ( len > gfam->item_count )
+      len = gfam->item_count;
+
+    gnode->item_count = (FT_UShort)len;
+    gfam->family.num_nodes++;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  ftc_glyph_node_done( FTC_GlyphNode  gnode,
+                       FTC_Cache      cache )
+  {
+    /* finalize the node */
+    gnode->item_count = 0;
+    gnode->item_start = 0;
+
+    ftc_node_done( FTC_NODE( gnode ), cache );
+  }
+
+
+  FT_EXPORT_DEF( FT_Bool )
+  ftc_glyph_node_compare( FTC_GlyphNode   gnode,
+                          FTC_GlyphQuery  gquery )
+  {
+    FT_UInt  start = (FT_UInt)gnode->item_start;
+    FT_UInt  count = (FT_UInt)gnode->item_count;
+
+    return FT_BOOL( (FT_UInt)( gquery->gindex - start ) < count );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      CHUNK SETS                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_EXPORT_DEF( FT_Error )
+  ftc_glyph_family_init( FTC_GlyphFamily  gfam,
+                         FT_UInt32        hash,
+                         FT_UInt          item_count,
+                         FT_UInt          item_total,
+                         FTC_GlyphQuery   gquery,
+                         FTC_Cache        cache )
+  {
+    FT_Error  error;
+
+
+    error = ftc_family_init( FTC_FAMILY( gfam ), FTC_QUERY( gquery ), cache );
+    if ( !error )
+    {
+      gfam->hash       = hash;
+      gfam->item_total = item_total;
+      gfam->item_count = item_count;
+      
+      FTC_GLYPH_FAMILY_FOUND( gfam, gquery );
+    }
+
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  ftc_glyph_family_done( FTC_GlyphFamily  gfam )
+  {
+    ftc_family_done( FTC_FAMILY( gfam ) );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcimage.c
@@ -1,0 +1,399 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcimage.c                                                             */
+/*                                                                         */
+/*    FreeType Image cache (body).                                         */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_IMAGE_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_INTERNAL_MEMORY_H
+
+#include "ftcerror.h"
+
+
+  /* the FT_Glyph image node type */
+  typedef struct  FTC_ImageNodeRec_
+  {
+    FTC_GlyphNodeRec  gnode;
+    FT_Glyph          glyph;
+
+  } FTC_ImageNodeRec, *FTC_ImageNode;
+
+
+#define FTC_IMAGE_NODE( x )         ( (FTC_ImageNode)( x ) )
+#define FTC_IMAGE_NODE_GINDEX( x )  FTC_GLYPH_NODE_GINDEX( x )
+
+
+  /* the glyph image query */
+  typedef struct  FTC_ImageQueryRec_
+  {
+    FTC_GlyphQueryRec  gquery;
+    FTC_ImageTypeRec   type;
+
+  } FTC_ImageQueryRec, *FTC_ImageQuery;
+
+
+#define FTC_IMAGE_QUERY( x )  ( (FTC_ImageQuery)( x ) )
+
+
+  /* the glyph image set type */
+  typedef struct  FTC_ImageFamilyRec_
+  {
+    FTC_GlyphFamilyRec  gfam;
+    FTC_ImageTypeRec    type;
+
+  } FTC_ImageFamilyRec, *FTC_ImageFamily;
+
+
+#define FTC_IMAGE_FAMILY( x )         ( (FTC_ImageFamily)( x ) )
+#define FTC_IMAGE_FAMILY_MEMORY( x )  FTC_GLYPH_FAMILY_MEMORY( &(x)->gfam )
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GLYPH IMAGE NODES                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* finalize a given glyph image node */
+  FT_CALLBACK_DEF( void )
+  ftc_image_node_done( FTC_ImageNode  inode,
+                       FTC_Cache      cache )
+  {
+    if ( inode->glyph )
+    {
+      FT_Done_Glyph( inode->glyph );
+      inode->glyph = NULL;
+    }
+
+    ftc_glyph_node_done( FTC_GLYPH_NODE( inode ), cache );
+  }
+
+
+  /* initialize a new glyph image node */
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_image_node_init( FTC_ImageNode   inode,
+                       FTC_GlyphQuery  gquery,
+                       FTC_Cache       cache )
+  {
+    FTC_ImageFamily  ifam = FTC_IMAGE_FAMILY( gquery->query.family );
+    FT_Error         error;
+    FT_Face          face;
+    FT_Size          size;
+
+
+    /* initialize its inner fields */
+    ftc_glyph_node_init( FTC_GLYPH_NODE( inode ),
+                         gquery->gindex,
+                         FTC_GLYPH_FAMILY( ifam ) );
+
+    /* we will now load the glyph image */
+    error = FTC_Manager_Lookup_Size( FTC_FAMILY( ifam )->cache->manager,
+                                     &ifam->type.font,
+                                     &face, &size );
+    if ( !error )
+    {
+      FT_UInt  gindex = FTC_GLYPH_NODE_GINDEX( inode );
+
+
+      error = FT_Load_Glyph( face, gindex, ifam->type.flags );
+      if ( !error )
+      {
+        if ( face->glyph->format == FT_GLYPH_FORMAT_BITMAP  ||
+             face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
+        {
+          /* ok, copy it */
+          FT_Glyph  glyph;
+
+
+          error = FT_Get_Glyph( face->glyph, &glyph );
+          if ( !error )
+          {
+            inode->glyph = glyph;
+            goto Exit;
+          }
+        }
+        else
+          error = FTC_Err_Invalid_Argument;
+      }
+    }
+
+    /* in case of error */
+    ftc_glyph_node_done( FTC_GLYPH_NODE(inode), cache );
+
+  Exit:
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_ULong )
+  ftc_image_node_weight( FTC_ImageNode  inode )
+  {
+    FT_ULong  size  = 0;
+    FT_Glyph  glyph = inode->glyph;
+
+
+    switch ( glyph->format )
+    {
+    case FT_GLYPH_FORMAT_BITMAP:
+      {
+        FT_BitmapGlyph  bitg;
+
+
+        bitg = (FT_BitmapGlyph)glyph;
+        size = bitg->bitmap.rows * labs( bitg->bitmap.pitch ) +
+               sizeof ( *bitg );
+      }
+      break;
+
+    case FT_GLYPH_FORMAT_OUTLINE:
+      {
+        FT_OutlineGlyph  outg;
+
+
+        outg = (FT_OutlineGlyph)glyph;
+        size = outg->outline.n_points *
+                 ( sizeof ( FT_Vector ) + sizeof ( FT_Byte ) ) +
+               outg->outline.n_contours * sizeof ( FT_Short ) +
+               sizeof ( *outg );
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    size += sizeof ( *inode );
+    return size;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GLYPH IMAGE SETS                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_image_family_init( FTC_ImageFamily  ifam,
+                         FTC_ImageQuery   iquery,
+                         FTC_Cache        cache )
+  {
+    FTC_Manager  manager = cache->manager;
+    FT_Error     error;
+    FT_Face      face;
+
+
+    ifam->type = iquery->type;
+
+    /* we need to compute "iquery.item_total" now */
+    error = FTC_Manager_Lookup_Face( manager,
+                                     iquery->type.font.face_id,
+                                     &face );
+    if ( !error )
+    {
+      error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( ifam ),
+                                     FTC_IMAGE_TYPE_HASH( &ifam->type ),
+                                     1,
+                                     face->num_glyphs,
+                                     FTC_GLYPH_QUERY( iquery ),
+                                     cache );
+    }
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_image_family_compare( FTC_ImageFamily  ifam,
+                            FTC_ImageQuery   iquery )
+  {
+    FT_Bool  result;
+
+
+    result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &ifam->type, &iquery->type ) );
+    if ( result )
+      FTC_GLYPH_FAMILY_FOUND( ifam, iquery );
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GLYPH IMAGE CACHE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FTC_Cache_ClassRec  ftc_image_cache_class =
+  {
+    sizeof ( FTC_CacheRec ),
+    (FTC_Cache_InitFunc) ftc_cache_init,
+    (FTC_Cache_ClearFunc)ftc_cache_clear,
+    (FTC_Cache_DoneFunc) ftc_cache_done,
+
+    sizeof ( FTC_ImageFamilyRec ),
+    (FTC_Family_InitFunc)   ftc_image_family_init,
+    (FTC_Family_CompareFunc)ftc_image_family_compare,
+    (FTC_Family_DoneFunc)   ftc_glyph_family_done,
+
+    sizeof ( FTC_ImageNodeRec ),
+    (FTC_Node_InitFunc)   ftc_image_node_init,
+    (FTC_Node_WeightFunc) ftc_image_node_weight,
+    (FTC_Node_CompareFunc)ftc_glyph_node_compare,
+    (FTC_Node_DoneFunc)   ftc_image_node_done
+  };
+
+
+  /* documentation is in ftcimage.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_ImageCache_New( FTC_Manager      manager,
+                      FTC_ImageCache  *acache )
+  {
+    return FTC_Manager_Register_Cache(
+             manager,
+             (FTC_Cache_Class)&ftc_image_cache_class,
+             FTC_CACHE_P( acache ) );
+  }
+
+
+  /* documentation is in ftcimage.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_ImageCache_Lookup( FTC_ImageCache  cache,
+                         FTC_ImageType   type,
+                         FT_UInt         gindex,
+                         FT_Glyph       *aglyph,
+                         FTC_Node       *anode )
+  {
+    FTC_ImageQueryRec  iquery;
+    FTC_ImageNode      node;
+    FT_Error           error;
+
+
+    /* some argument checks are delayed to ftc_cache_lookup */
+    if ( !aglyph )
+      return FTC_Err_Invalid_Argument;
+
+    if ( anode )
+      *anode  = NULL;
+
+    iquery.gquery.gindex = gindex;
+    iquery.type          = *type;
+
+    error = ftc_cache_lookup( FTC_CACHE( cache ),
+                              FTC_QUERY( &iquery ),
+                              (FTC_Node*)&node );
+    if ( !error )
+    {
+      *aglyph = node->glyph;
+
+      if ( anode )
+      {
+        *anode = (FTC_Node)node;
+        FTC_NODE( node )->ref_count++;
+      }
+    }
+
+    return error;
+  }
+
+
+  /* backwards-compatibility functions */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Image_Cache_New( FTC_Manager       manager,
+                       FTC_Image_Cache  *acache )
+  {
+    return FTC_ImageCache_New( manager, (FTC_ImageCache*)acache );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Image_Cache_Lookup( FTC_Image_Cache  icache,
+                          FTC_Image_Desc*  desc,
+                          FT_UInt          gindex,
+                          FT_Glyph        *aglyph )
+  {
+    FTC_ImageTypeRec  type0;
+
+
+    if ( !desc )
+      return FTC_Err_Invalid_Argument;
+
+    type0.font = desc->font;
+
+    /* convert image type flags to load flags */
+    {
+      FT_UInt  load_flags = FT_LOAD_DEFAULT;
+      FT_UInt  type       = desc->image_type;
+
+
+      /* determine load flags, depending on the font description's */
+      /* image type                                                */
+
+      if ( ftc_image_format( type ) == ftc_image_format_bitmap )
+      {
+        if ( type & ftc_image_flag_monochrome )
+          load_flags |= FT_LOAD_MONOCHROME;
+
+        /* disable embedded bitmaps loading if necessary */
+        if ( type & ftc_image_flag_no_sbits )
+          load_flags |= FT_LOAD_NO_BITMAP;
+      }
+      else
+      {
+        /* we want an outline, don't load embedded bitmaps */
+        load_flags |= FT_LOAD_NO_BITMAP;
+
+        if ( type & ftc_image_flag_unscaled )
+          load_flags |= FT_LOAD_NO_SCALE;
+      }
+
+      /* always render glyphs to bitmaps */
+      load_flags |= FT_LOAD_RENDER;
+
+      if ( type & ftc_image_flag_unhinted )
+        load_flags |= FT_LOAD_NO_HINTING;
+
+      if ( type & ftc_image_flag_autohinted )
+        load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+      type0.flags = load_flags;
+    }
+
+    return FTC_ImageCache_Lookup( (FTC_ImageCache)icache,
+                                   &type0,
+                                   gindex,
+                                   aglyph,
+                                   NULL );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcmanag.c
@@ -1,0 +1,765 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcmanag.c                                                             */
+/*                                                                         */
+/*    FreeType Cache Manager (body).                                       */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_MANAGER_H
+#include FT_CACHE_INTERNAL_LRU_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SIZES_H
+
+#include "ftcerror.h"
+
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cache
+
+#define FTC_LRU_GET_MANAGER( lru )  ( (FTC_Manager)(lru)->user_data )
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    FACE LRU IMPLEMENTATION                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct FTC_FaceNodeRec_*  FTC_FaceNode;
+  typedef struct FTC_SizeNodeRec_*  FTC_SizeNode;
+
+
+  typedef struct  FTC_FaceNodeRec_
+  {
+    FT_LruNodeRec  lru;
+    FT_Face        face;
+
+  } FTC_FaceNodeRec;
+
+
+  typedef struct  FTC_SizeNodeRec_
+  {
+    FT_LruNodeRec  lru;
+    FT_Size        size;
+
+  } FTC_SizeNodeRec;
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_face_node_init( FTC_FaceNode  node,
+                      FTC_FaceID    face_id,
+                      FTC_Manager   manager )
+  {
+    FT_Error  error;
+
+
+    error = manager->request_face( face_id,
+                                   manager->library,
+                                   manager->request_data,
+                                   &node->face );
+    if ( !error )
+    {
+      /* destroy initial size object; it will be re-created later */
+      if ( node->face->size )
+        FT_Done_Size( node->face->size );
+    }
+
+    return error;
+  }
+
+
+  /* helper function for ftc_face_node_done() */
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_size_node_select( FTC_SizeNode  node,
+                        FT_Face       face )
+  {
+    return FT_BOOL( node->size->face == face );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ftc_face_node_done( FTC_FaceNode  node,
+                      FTC_Manager   manager )
+  {
+    FT_Face  face    = node->face;
+
+
+    /* we must begin by removing all sizes for the target face */
+    /* from the manager's list                                 */
+    FT_LruList_Remove_Selection( manager->sizes_list,
+                                 (FT_LruNode_SelectFunc)ftc_size_node_select,
+                                 face );
+
+    /* all right, we can discard the face now */
+    FT_Done_Face( face );
+    node->face = NULL;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_LruList_ClassRec  ftc_face_list_class =
+  {
+    sizeof ( FT_LruListRec ),
+    (FT_LruList_InitFunc)0,
+    (FT_LruList_DoneFunc)0,
+
+    sizeof ( FTC_FaceNodeRec ),
+    (FT_LruNode_InitFunc)   ftc_face_node_init,
+    (FT_LruNode_DoneFunc)   ftc_face_node_done,
+    (FT_LruNode_FlushFunc)  0,  /* no flushing needed                      */
+    (FT_LruNode_CompareFunc)0,  /* direct comparison of FTC_FaceID handles */
+  };
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Manager_Lookup_Face( FTC_Manager  manager,
+                           FTC_FaceID   face_id,
+                           FT_Face     *aface )
+  {
+    FT_Error      error;
+    FTC_FaceNode  node;
+
+
+    if ( aface == NULL )
+      return FTC_Err_Bad_Argument;
+
+    *aface = NULL;
+
+    if ( !manager )
+      return FTC_Err_Invalid_Cache_Handle;
+
+    error = FT_LruList_Lookup( manager->faces_list,
+                               (FT_LruKey)face_id,
+                               (FT_LruNode*)&node );
+    if ( !error )
+      *aface = node->face;
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      SIZES LRU IMPLEMENTATION                 *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  typedef struct  FTC_SizeQueryRec_
+  {
+    FT_Face  face;
+    FT_UInt  width;
+    FT_UInt  height;
+
+  } FTC_SizeQueryRec, *FTC_SizeQuery;
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_size_node_init( FTC_SizeNode   node,
+                      FTC_SizeQuery  query )
+  {
+    FT_Face   face = query->face;
+    FT_Size   size;
+    FT_Error  error;
+
+
+    node->size = NULL;
+    error = FT_New_Size( face, &size );
+    if ( !error )
+    {
+      FT_Activate_Size( size );
+      error = FT_Set_Pixel_Sizes( query->face,
+                                  query->width,
+                                  query->height );
+      if ( error )
+        FT_Done_Size( size );
+      else
+        node->size = size;
+    }
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ftc_size_node_done( FTC_SizeNode  node )
+  {
+    if ( node->size )
+    {
+      FT_Done_Size( node->size );
+      node->size = NULL;
+    }
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_size_node_flush( FTC_SizeNode   node,
+                       FTC_SizeQuery  query )
+  {
+    FT_Size   size = node->size;
+    FT_Error  error;
+
+
+    if ( size->face == query->face )
+    {
+      FT_Activate_Size( size );
+      error = FT_Set_Pixel_Sizes( query->face, query->width, query->height );
+      if ( error )
+      {
+        FT_Done_Size( size );
+        node->size = NULL;
+      }
+    }
+    else
+    {
+      FT_Done_Size( size );
+      node->size = NULL;
+
+      error = ftc_size_node_init( node, query );
+    }
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_size_node_compare( FTC_SizeNode   node,
+                         FTC_SizeQuery  query )
+  {
+    FT_Size  size = node->size;
+
+
+    return FT_BOOL( size->face                    == query->face   &&
+                    (FT_UInt)size->metrics.x_ppem == query->width  &&
+                    (FT_UInt)size->metrics.y_ppem == query->height );
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_LruList_ClassRec  ftc_size_list_class =
+  {
+    sizeof ( FT_LruListRec ),
+    (FT_LruList_InitFunc)0,
+    (FT_LruList_DoneFunc)0,
+
+    sizeof ( FTC_SizeNodeRec ),
+    (FT_LruNode_InitFunc)   ftc_size_node_init,
+    (FT_LruNode_DoneFunc)   ftc_size_node_done,
+    (FT_LruNode_FlushFunc)  ftc_size_node_flush,
+    (FT_LruNode_CompareFunc)ftc_size_node_compare
+  };
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Manager_Lookup_Size( FTC_Manager  manager,
+                           FTC_Font     font,
+                           FT_Face     *aface,
+                           FT_Size     *asize )
+  {
+    FT_Error  error;
+
+
+    /* check for valid `manager' delayed to FTC_Manager_Lookup_Face() */
+    if ( aface )
+      *aface = 0;
+
+    if ( asize )
+      *asize = 0;
+
+    error = FTC_Manager_Lookup_Face( manager, font->face_id, aface );
+    if ( !error )
+    {
+      FTC_SizeQueryRec  query;
+      FTC_SizeNode      node;
+
+
+      query.face   = *aface;
+      query.width  = font->pix_width;
+      query.height = font->pix_height;
+
+      error = FT_LruList_Lookup( manager->sizes_list,
+                                 (FT_LruKey)&query,
+                                 (FT_LruNode*)&node );
+      if ( !error )
+      {
+        /* select the size as the current one for this face */
+        FT_Activate_Size( node->size );
+
+        if ( asize )
+          *asize = node->size;
+      }
+    }
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    SET TABLE MANAGEMENT                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  ftc_family_table_init( FTC_FamilyTable  table )
+  {
+    table->count   = 0;
+    table->size    = 0;
+    table->entries = NULL;
+    table->free    = FTC_FAMILY_ENTRY_NONE;
+  }
+
+
+  static void
+  ftc_family_table_done( FTC_FamilyTable  table,
+                         FT_Memory        memory )
+  {
+    FT_FREE( table->entries );
+    table->free  = 0;
+    table->count = 0;
+    table->size  = 0;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  ftc_family_table_alloc( FTC_FamilyTable   table,
+                          FT_Memory         memory,
+                          FTC_FamilyEntry  *aentry )
+  {
+    FTC_FamilyEntry  entry;
+    FT_Error         error = 0;
+
+
+    /* re-allocate table size when needed */
+    if ( table->free == FTC_FAMILY_ENTRY_NONE && table->count >= table->size )
+    {
+      FT_UInt  old_size = table->size;
+      FT_UInt  new_size, idx;
+
+
+      if ( old_size == 0 )
+        new_size = 8;
+      else
+      {
+        new_size = old_size * 2;
+
+        /* check for (unlikely) overflow */
+        if ( new_size < old_size )
+          new_size = 65534;
+      }
+
+      if ( FT_RENEW_ARRAY( table->entries, old_size, new_size ) )
+        return error;
+
+      table->size = new_size;
+
+      entry       = table->entries + old_size;
+      table->free = old_size;
+
+      for ( idx = old_size; idx + 1 < new_size; idx++, entry++ )
+      {
+        entry->link  = idx + 1;
+        entry->index = idx;
+      }
+
+      entry->link  = FTC_FAMILY_ENTRY_NONE;
+      entry->index = idx;
+    }
+
+    if ( table->free != FTC_FAMILY_ENTRY_NONE )
+    {
+      entry       = table->entries + table->free;
+      table->free = entry->link;
+    }
+    else if ( table->count < table->size )
+    {
+      entry = table->entries + table->count++;
+    }
+    else
+    {
+      FT_ERROR(( "ftc_family_table_alloc: internal bug!" ));
+      return FTC_Err_Invalid_Argument;
+    }
+
+    entry->link = FTC_FAMILY_ENTRY_NONE;
+    table->count++;
+
+    *aentry = entry;
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  ftc_family_table_free( FTC_FamilyTable  table,
+                         FT_UInt          idx )
+  {
+    /* simply add it to the linked list of free entries */
+    if ( idx < table->count )
+    {
+      FTC_FamilyEntry  entry = table->entries + idx;
+
+
+      if ( entry->link != FTC_FAMILY_ENTRY_NONE )
+        FT_ERROR(( "ftc_family_table_free: internal bug!\n" ));
+      else
+      {
+        entry->link = table->free;
+        table->free = entry->index;
+        table->count--;
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    CACHE MANAGER ROUTINES                     *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Manager_New( FT_Library          library,
+                   FT_UInt             max_faces,
+                   FT_UInt             max_sizes,
+                   FT_ULong            max_bytes,
+                   FTC_Face_Requester  requester,
+                   FT_Pointer          req_data,
+                   FTC_Manager        *amanager )
+  {
+    FT_Error     error;
+    FT_Memory    memory;
+    FTC_Manager  manager = 0;
+
+
+    if ( !library )
+      return FTC_Err_Invalid_Library_Handle;
+
+    memory = library->memory;
+
+    if ( FT_NEW( manager ) )
+      goto Exit;
+
+    if ( max_faces == 0 )
+      max_faces = FTC_MAX_FACES_DEFAULT;
+
+    if ( max_sizes == 0 )
+      max_sizes = FTC_MAX_SIZES_DEFAULT;
+
+    if ( max_bytes == 0 )
+      max_bytes = FTC_MAX_BYTES_DEFAULT;
+
+    error = FT_LruList_New( &ftc_face_list_class,
+                            max_faces,
+                            manager,
+                            memory,
+                            &manager->faces_list );
+    if ( error )
+      goto Exit;
+
+    error = FT_LruList_New( &ftc_size_list_class,
+                            max_sizes,
+                            manager,
+                            memory,
+                            &manager->sizes_list );
+    if ( error )
+      goto Exit;
+
+    manager->library      = library;
+    manager->max_weight   = max_bytes;
+    manager->cur_weight   = 0;
+
+    manager->request_face = requester;
+    manager->request_data = req_data;
+
+    ftc_family_table_init( &manager->families );
+
+    *amanager = manager;
+
+  Exit:
+    if ( error && manager )
+    {
+      FT_LruList_Destroy( manager->faces_list );
+      FT_LruList_Destroy( manager->sizes_list );
+      FT_FREE( manager );
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Manager_Done( FTC_Manager  manager )
+  {
+    FT_Memory  memory;
+    FT_UInt    idx;
+
+
+    if ( !manager || !manager->library )
+      return;
+
+    memory = manager->library->memory;
+
+    /* now discard all caches */
+    for (idx = 0; idx < FTC_MAX_CACHES; idx++ )
+    {
+      FTC_Cache  cache = manager->caches[idx];
+
+
+      if ( cache )
+      {
+        cache->clazz->cache_done( cache );
+        FT_FREE( cache );
+        manager->caches[idx] = 0;
+      }
+    }
+
+    /* discard families table */
+    ftc_family_table_done( &manager->families, memory );
+
+    /* discard faces and sizes */
+    FT_LruList_Destroy( manager->faces_list );
+    manager->faces_list = 0;
+
+    FT_LruList_Destroy( manager->sizes_list );
+    manager->sizes_list = 0;
+
+    FT_FREE( manager );
+  }
+
+
+  /* documentation is in ftcache.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Manager_Reset( FTC_Manager  manager )
+  {
+    if ( manager )
+    {
+      FT_LruList_Reset( manager->sizes_list );
+      FT_LruList_Reset( manager->faces_list );
+    }
+    /* XXX: FIXME: flush the caches? */
+  }
+
+
+#ifdef FT_DEBUG_ERROR
+
+  FT_EXPORT_DEF( void )
+  FTC_Manager_Check( FTC_Manager  manager )
+  {
+    FTC_Node  node, first;
+    
+
+    first = manager->nodes_list;
+
+    /* check node weights */
+    if ( first )
+    {
+      FT_ULong  weight = 0;
+      
+
+      node = first;
+
+      do
+      {
+        FTC_FamilyEntry  entry = manager->families.entries + node->fam_index;
+        FTC_Cache     cache;
+
+        if ( (FT_UInt)node->fam_index >= manager->families.count ||
+             entry->link              != FTC_FAMILY_ENTRY_NONE  )
+          FT_ERROR(( "FTC_Manager_Check: invalid node (family index = %ld\n",
+                     node->fam_index ));
+        else
+        {
+          cache   = entry->cache;
+          weight += cache->clazz->node_weight( node, cache );
+        }
+
+        node = node->mru_next;
+
+      } while ( node != first );
+
+      if ( weight != manager->cur_weight )
+        FT_ERROR(( "FTC_Manager_Check: invalid weight %ld instead of %ld\n",
+                   manager->cur_weight, weight ));
+    }
+
+    /* check circular list */
+    if ( first )
+    {
+      FT_UFast  count = 0;
+
+
+      node = first;
+      do
+      {
+        count++;
+        node = node->mru_next;
+
+      } while ( node != first );
+
+      if ( count != manager->num_nodes )
+        FT_ERROR((
+          "FTC_Manager_Check: invalid cache node count %d instead of %d\n",
+          manager->num_nodes, count ));
+    }
+  }
+
+#endif /* FT_DEBUG_ERROR */
+
+
+  /* `Compress' the manager's data, i.e., get rid of old cache nodes */
+  /* that are not referenced anymore in order to limit the total     */
+  /* memory used by the cache.                                       */
+
+  /* documentation is in ftcmanag.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Manager_Compress( FTC_Manager  manager )
+  {
+    FTC_Node   node, first;
+
+
+    if ( !manager )
+      return;
+
+    first = manager->nodes_list;
+
+#ifdef FT_DEBUG_ERROR
+    FTC_Manager_Check( manager );
+
+    FT_ERROR(( "compressing, weight = %ld, max = %ld, nodes = %d\n",
+               manager->cur_weight, manager->max_weight,
+               manager->num_nodes ));
+#endif
+
+    if ( manager->cur_weight < manager->max_weight || first == NULL )
+      return;
+
+    /* go to last node - it's a circular list */
+    node = first->mru_prev;
+    do
+    {
+      FTC_Node  prev = node->mru_prev;
+
+
+      prev = ( node == first ) ? NULL : node->mru_prev;
+
+      if ( node->ref_count <= 0 )
+        ftc_node_destroy( node, manager );
+
+      node = prev;
+
+    } while ( node && manager->cur_weight > manager->max_weight );
+  }
+
+
+  /* documentation is in ftcmanag.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_Manager_Register_Cache( FTC_Manager      manager,
+                              FTC_Cache_Class  clazz,
+                              FTC_Cache       *acache )
+  {
+    FT_Error   error = FTC_Err_Invalid_Argument;
+    FTC_Cache  cache = NULL;
+
+
+    if ( manager && clazz && acache )
+    {
+      FT_Memory  memory = manager->library->memory;
+      FT_UInt    idx  = 0;
+
+
+      /* check for an empty cache slot in the manager's table */
+      for ( idx = 0; idx < FTC_MAX_CACHES; idx++ )
+      {
+        if ( manager->caches[idx] == 0 )
+          break;
+      }
+
+      /* return an error if there are too many registered caches */
+      if ( idx >= FTC_MAX_CACHES )
+      {
+        error = FTC_Err_Too_Many_Caches;
+        FT_ERROR(( "FTC_Manager_Register_Cache:" ));
+        FT_ERROR(( " too many registered caches\n" ));
+        goto Exit;
+      }
+
+      if ( !FT_ALLOC( cache, clazz->cache_size ) )
+      {
+        cache->manager = manager;
+        cache->memory  = memory;
+        cache->clazz   = clazz;
+
+        /* THIS IS VERY IMPORTANT!  IT WILL WRETCH THE MANAGER */
+        /* IF IT IS NOT SET CORRECTLY                          */
+        cache->cache_index = idx;
+
+        if ( clazz->cache_init )
+        {
+          error = clazz->cache_init( cache );
+          if ( error )
+          {
+            if ( clazz->cache_done )
+              clazz->cache_done( cache );
+
+            FT_FREE( cache );
+            goto Exit;
+          }
+        }
+
+        manager->caches[idx] = cache;
+      }
+    }
+
+  Exit:
+    *acache = cache;
+    return error;
+  }
+
+
+  /* documentation is in ftcmanag.h */
+
+  FT_EXPORT_DEF( void )
+  FTC_Node_Unref( FTC_Node     node,
+                  FTC_Manager  manager )
+  {
+    if ( node && (FT_UInt)node->fam_index < manager->families.count &&
+         manager->families.entries[node->fam_index].cache )
+    {
+      node->ref_count--;
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftcsbits.c
@@ -1,0 +1,557 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftcsbits.c                                                             */
+/*                                                                         */
+/*    FreeType sbits manager (body).                                       */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_SMALL_BITMAPS_H
+#include FT_CACHE_INTERNAL_GLYPH_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_ERRORS_H
+
+#include "ftcerror.h"
+
+
+#define FTC_SBIT_ITEMS_PER_NODE  16
+
+
+  typedef struct FTC_SBitNodeRec_*  FTC_SBitNode;
+
+  typedef struct  FTC_SBitNodeRec_
+  {
+    FTC_GlyphNodeRec  gnode;
+    FTC_SBitRec       sbits[FTC_SBIT_ITEMS_PER_NODE];
+
+  } FTC_SBitNodeRec;
+
+
+#define FTC_SBIT_NODE( x )  ( (FTC_SBitNode)( x ) )
+
+
+  typedef struct  FTC_SBitQueryRec_
+  {
+    FTC_GlyphQueryRec  gquery;
+    FTC_ImageTypeRec   type;
+
+  } FTC_SBitQueryRec, *FTC_SBitQuery;
+
+
+#define FTC_SBIT_QUERY( x ) ( (FTC_SBitQuery)( x ) )
+
+
+  typedef struct FTC_SBitFamilyRec_*  FTC_SBitFamily;
+
+  /* sbit family structure */
+  typedef struct  FTC_SBitFamilyRec_
+  {
+    FTC_GlyphFamilyRec  gfam;
+    FTC_ImageTypeRec    type;
+
+  } FTC_SBitFamilyRec;
+
+
+#define FTC_SBIT_FAMILY( x )         ( (FTC_SBitFamily)( x ) )
+#define FTC_SBIT_FAMILY_MEMORY( x )  FTC_GLYPH_FAMILY_MEMORY( &( x )->cset )
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     SBIT CACHE NODES                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static FT_Error
+  ftc_sbit_copy_bitmap( FTC_SBit    sbit,
+                        FT_Bitmap*  bitmap,
+                        FT_Memory   memory )
+  {
+    FT_Error  error;
+    FT_Int    pitch = bitmap->pitch;
+    FT_ULong  size;
+
+
+    if ( pitch < 0 )
+      pitch = -pitch;
+
+    size = (FT_ULong)( pitch * bitmap->rows );
+
+    if ( !FT_ALLOC( sbit->buffer, size ) )
+      FT_MEM_COPY( sbit->buffer, bitmap->buffer, size );
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  ftc_sbit_node_done( FTC_SBitNode  snode,
+                      FTC_Cache     cache )
+  {
+    FTC_SBit   sbit   = snode->sbits;
+    FT_UInt    count  = FTC_GLYPH_NODE( snode )->item_count;
+    FT_Memory  memory = cache->memory;
+
+
+    for ( ; count > 0; sbit++, count-- )
+      FT_FREE( sbit->buffer );
+
+    ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
+  }
+
+
+  static FT_Error
+  ftc_sbit_node_load( FTC_SBitNode    snode,
+                      FTC_Manager     manager,
+                      FTC_SBitFamily  sfam,
+                      FT_UInt         gindex,
+                      FT_ULong       *asize )
+  {
+    FT_Error       error;
+    FTC_GlyphNode  gnode = FTC_GLYPH_NODE( snode );
+    FT_Memory      memory;
+    FT_Face        face;
+    FT_Size        size;
+    FTC_SBit       sbit;
+
+
+    if ( gindex <  (FT_UInt)gnode->item_start                     ||
+         gindex >= (FT_UInt)gnode->item_start + gnode->item_count )
+    {
+      FT_ERROR(( "ftc_sbit_node_load: invalid glyph index" ));
+      return FTC_Err_Invalid_Argument;
+    }
+
+    memory = manager->library->memory;
+
+    sbit = snode->sbits + ( gindex - gnode->item_start );
+
+    error = FTC_Manager_Lookup_Size( manager, &sfam->type.font,
+                                     &face, &size );
+    if ( !error )
+    {
+      /* by default, indicates a `missing' glyph */
+      sbit->buffer = 0;
+
+      error = FT_Load_Glyph( face, gindex, sfam->type.flags | FT_LOAD_RENDER );
+      if ( !error )
+      {
+        FT_Int        temp;
+        FT_GlyphSlot  slot   = face->glyph;
+        FT_Bitmap*    bitmap = &slot->bitmap;
+        FT_Int        xadvance, yadvance;
+
+
+        /* check that our values fit into 8-bit containers!       */
+        /* If this is not the case, our bitmap is too large       */
+        /* and we will leave it as `missing' with sbit.buffer = 0 */
+
+#define CHECK_CHAR( d )  ( temp = (FT_Char)d, temp == d )
+#define CHECK_BYTE( d )  ( temp = (FT_Byte)d, temp == d )
+
+        /* XXX: FIXME: add support for vertical layouts maybe */
+
+        /* horizontal advance in pixels */
+        xadvance = ( slot->metrics.horiAdvance + 32 ) >> 6;
+        yadvance = ( slot->metrics.vertAdvance + 32 ) >> 6;
+
+        if ( CHECK_BYTE( bitmap->rows  )     &&
+             CHECK_BYTE( bitmap->width )     &&
+             CHECK_CHAR( bitmap->pitch )     &&
+             CHECK_CHAR( slot->bitmap_left ) &&
+             CHECK_CHAR( slot->bitmap_top  ) &&
+             CHECK_CHAR( xadvance )          &&
+             CHECK_CHAR( yadvance )          )
+        {
+          sbit->width     = (FT_Byte)bitmap->width;
+          sbit->height    = (FT_Byte)bitmap->rows;
+          sbit->pitch     = (FT_Char)bitmap->pitch;
+          sbit->left      = (FT_Char)slot->bitmap_left;
+          sbit->top       = (FT_Char)slot->bitmap_top;
+          sbit->xadvance  = (FT_Char)xadvance;
+          sbit->yadvance  = (FT_Char)yadvance;
+          sbit->format    = (FT_Byte)bitmap->pixel_mode;
+          sbit->max_grays = (FT_Byte)(bitmap->num_grays - 1);
+
+#if 0 /* this doesn't work well with embedded bitmaps !! */
+
+          /* grab the bitmap when possible - this is a hack! */
+          if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+          {
+            slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+            sbit->buffer = bitmap->buffer;
+          }
+          else
+#endif
+          {
+            /* copy the bitmap into a new buffer -- ignore error */
+            error = ftc_sbit_copy_bitmap( sbit, bitmap, memory );
+          }
+
+          /* now, compute size */
+          if ( asize )
+            *asize = ABS( sbit->pitch ) * sbit->height;
+
+        }  /* glyph dimensions ok */
+
+      } /* glyph loading successful */
+
+      /* ignore the errors that might have occurred --   */
+      /* we mark unloaded glyphs with `sbit.buffer == 0' */
+      /* and 'width == 255', 'height == 0'               */
+      /*                                                 */
+      if ( error )
+      {
+        sbit->width = 255;
+        error       = 0;
+        /* sbit->buffer == NULL too! */
+      }
+    }
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_sbit_node_init( FTC_SBitNode    snode,
+                      FTC_GlyphQuery  gquery,
+                      FTC_Cache       cache )
+  {
+    FT_Error  error;
+
+
+    ftc_glyph_node_init( FTC_GLYPH_NODE( snode ),
+                         gquery->gindex,
+                         FTC_GLYPH_FAMILY( gquery->query.family ) );
+
+    error = ftc_sbit_node_load( snode,
+                                cache->manager,
+                                FTC_SBIT_FAMILY( FTC_QUERY( gquery )->family ),
+                                gquery->gindex,
+                                NULL );
+    if ( error )
+      ftc_glyph_node_done( FTC_GLYPH_NODE( snode ), cache );
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_ULong )
+  ftc_sbit_node_weight( FTC_SBitNode  snode )
+  {
+    FTC_GlyphNode  gnode = FTC_GLYPH_NODE( snode );
+    FT_UInt        count = gnode->item_count;
+    FTC_SBit       sbit  = snode->sbits;
+    FT_Int         pitch;
+    FT_ULong       size;
+
+
+    /* the node itself */
+    size = sizeof ( *snode );
+
+    /* the sbit records */
+    size += FTC_GLYPH_NODE( snode )->item_count * sizeof ( FTC_SBitRec );
+
+    for ( ; count > 0; count--, sbit++ )
+    {
+      if ( sbit->buffer )
+      {
+        pitch = sbit->pitch;
+        if ( pitch < 0 )
+          pitch = -pitch;
+
+        /* add the size of a given glyph image */
+        size += pitch * sbit->height;
+      }
+    }
+
+    return size;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_sbit_node_compare( FTC_SBitNode   snode,
+                         FTC_SBitQuery  squery,
+                         FTC_Cache      cache )
+  {
+    FTC_GlyphQuery  gquery = FTC_GLYPH_QUERY( squery );
+    FTC_GlyphNode   gnode  = FTC_GLYPH_NODE( snode );
+    FT_Bool         result;
+
+
+    result = ftc_glyph_node_compare( gnode, gquery );
+    if ( result )
+    {
+      /* check if we need to load the glyph bitmap now */
+      FT_UInt   gindex = gquery->gindex;
+      FTC_SBit  sbit   = snode->sbits + ( gindex - gnode->item_start );
+
+
+      if ( sbit->buffer == NULL && sbit->width != 255 )
+      {
+        FT_ULong  size;
+
+
+        /* yes, it's safe to ignore errors here */
+        ftc_sbit_node_load( snode,
+                            cache->manager,
+                            FTC_SBIT_FAMILY( FTC_QUERY( squery )->family ),
+                            gindex,
+                            &size );
+
+        cache->manager->cur_weight += size;
+      }
+    }
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     SBITS FAMILIES                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  ftc_sbit_family_init( FTC_SBitFamily  sfam,
+                        FTC_SBitQuery   squery,
+                        FTC_Cache       cache )
+  {
+    FTC_Manager  manager = cache->manager;
+    FT_Error     error;
+    FT_Face      face;
+
+
+    sfam->type = squery->type;
+
+    /* we need to compute "cquery.item_total" now */
+    error = FTC_Manager_Lookup_Face( manager,
+                                     squery->type.font.face_id,
+                                     &face );
+    if ( !error )
+    {
+      error = ftc_glyph_family_init( FTC_GLYPH_FAMILY( sfam ),
+                                     FTC_IMAGE_TYPE_HASH( &sfam->type ),
+                                     FTC_SBIT_ITEMS_PER_NODE,
+                                     face->num_glyphs,
+                                     FTC_GLYPH_QUERY( squery ),
+                                     cache );
+    }
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Bool )
+  ftc_sbit_family_compare( FTC_SBitFamily  sfam,
+                           FTC_SBitQuery   squery )
+  {
+    FT_Bool  result;
+
+
+    /* we need to set the "cquery.cset" field or our query for */
+    /* faster glyph comparisons in ftc_sbit_node_compare       */
+    /*                                                         */
+    result = FT_BOOL( FTC_IMAGE_TYPE_COMPARE( &sfam->type, &squery->type ) );
+    if ( result )
+      FTC_GLYPH_FAMILY_FOUND( sfam, squery );
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     SBITS CACHE                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FTC_Cache_ClassRec  ftc_sbit_cache_class =
+  {
+    sizeof ( FTC_CacheRec ),
+    (FTC_Cache_InitFunc) ftc_cache_init,
+    (FTC_Cache_ClearFunc)ftc_cache_clear,
+    (FTC_Cache_DoneFunc) ftc_cache_done,
+
+    sizeof ( FTC_SBitFamilyRec ),
+    (FTC_Family_InitFunc)   ftc_sbit_family_init,
+    (FTC_Family_CompareFunc)ftc_sbit_family_compare,
+    (FTC_Family_DoneFunc)   ftc_glyph_family_done,
+
+    sizeof ( FTC_SBitNodeRec ),
+    (FTC_Node_InitFunc)   ftc_sbit_node_init,
+    (FTC_Node_WeightFunc) ftc_sbit_node_weight,
+    (FTC_Node_CompareFunc)ftc_sbit_node_compare,
+    (FTC_Node_DoneFunc)   ftc_sbit_node_done
+  };
+
+
+  /* documentation is in ftcsbits.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_SBitCache_New( FTC_Manager     manager,
+                     FTC_SBitCache  *acache )
+  {
+    return FTC_Manager_Register_Cache( manager,
+                                       &ftc_sbit_cache_class,
+                                       (FTC_Cache*)acache );
+  }
+
+
+  /* documentation is in ftcsbits.h */
+
+#ifdef FTC_CACHE_USE_INLINE
+
+#define GEN_CACHE_FAMILY_COMPARE( f, q, c ) \
+          ftc_sbit_family_compare( (FTC_SBitFamily)(f), (FTC_SBitQuery)(q) )
+
+#define GEN_CACHE_NODE_COMPARE( n, q, c ) \
+          ftc_sbit_node_compare( (FTC_SBitNode)(n), (FTC_SBitQuery)(q), c )
+
+#define GEN_CACHE_LOOKUP  ftc_sbit_cache_lookup
+#include "ftccache.i"
+
+#else  /* !FTC_CACHE_USE_INLINE */
+
+#define ftc_sbit_cache_lookup  ftc_cache_lookup
+
+#endif /* !FTC_CACHE_USE_INLINE */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_SBitCache_Lookup( FTC_SBitCache   cache,
+                        FTC_ImageType   type,
+                        FT_UInt         gindex,
+                        FTC_SBit       *ansbit,
+                        FTC_Node       *anode )
+  {
+    FT_Error          error;
+    FTC_SBitQueryRec  squery;
+    FTC_SBitNode      node;
+
+
+    /* other argument checks delayed to ftc_cache_lookup */
+    if ( !ansbit )
+      return FTC_Err_Invalid_Argument;
+
+    *ansbit = NULL;
+
+    if ( anode )
+      *anode = NULL;
+
+    squery.gquery.gindex = gindex;
+    squery.type          = *type;
+
+    error = ftc_sbit_cache_lookup( FTC_CACHE( cache ),
+                                   FTC_QUERY( &squery ),
+                                   (FTC_Node*)&node );
+    if ( !error )
+    {
+      *ansbit = node->sbits + ( gindex - FTC_GLYPH_NODE( node )->item_start );
+
+      if ( anode )
+      {
+        *anode = FTC_NODE( node );
+        FTC_NODE( node )->ref_count++;
+      }
+    }
+    return error;
+  }
+
+
+  /* backwards-compatibility functions */
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_SBit_Cache_New( FTC_Manager      manager,
+                      FTC_SBit_Cache  *acache )
+  {
+    return FTC_SBitCache_New( manager, (FTC_SBitCache*)acache );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FTC_SBit_Cache_Lookup( FTC_SBit_Cache   cache,
+                         FTC_Image_Desc*  desc,
+                         FT_UInt          gindex,
+                         FTC_SBit        *ansbit )
+  {
+    FTC_ImageTypeRec  type0;
+
+
+    if ( !desc )
+      return FTC_Err_Invalid_Argument;
+
+    type0.font  = desc->font;
+    type0.flags = 0;
+
+    /* convert image type flags to load flags */
+    {
+      FT_UInt  load_flags = FT_LOAD_DEFAULT;
+      FT_UInt  type       = desc->image_type;
+
+
+      /* determine load flags, depending on the font description's */
+      /* image type                                                */
+
+      if ( ftc_image_format( type ) == ftc_image_format_bitmap )
+      {
+        if ( type & ftc_image_flag_monochrome )
+          load_flags |= FT_LOAD_MONOCHROME;
+
+        /* disable embedded bitmaps loading if necessary */
+        if ( type & ftc_image_flag_no_sbits )
+          load_flags |= FT_LOAD_NO_BITMAP;
+      }
+      else
+      {
+        /* we want an outline, don't load embedded bitmaps */
+        load_flags |= FT_LOAD_NO_BITMAP;
+
+        if ( type & ftc_image_flag_unscaled )
+          load_flags |= FT_LOAD_NO_SCALE;
+      }
+
+      /* always render glyphs to bitmaps */
+      load_flags |= FT_LOAD_RENDER;
+
+      if ( type & ftc_image_flag_unhinted )
+        load_flags |= FT_LOAD_NO_HINTING;
+
+      if ( type & ftc_image_flag_autohinted )
+        load_flags |= FT_LOAD_FORCE_AUTOHINT;
+
+      type0.flags = load_flags;
+    }
+
+    return FTC_SBitCache_Lookup( (FTC_SBitCache)cache,
+                                  &type0,
+                                  gindex,
+                                  ansbit,
+                                  NULL );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftdbgmem.c
@@ -1,0 +1,672 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftdbgmem.c                                                             */
+/*                                                                         */
+/*    Memory debugger (body).                                              */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+
+#ifdef FT_DEBUG_MEMORY
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+  typedef struct FT_MemNodeRec_*   FT_MemNode;
+  typedef struct FT_MemTableRec_*  FT_MemTable;
+
+#define FT_MEM_VAL( addr )  ((FT_ULong)(FT_Pointer)( addr ))
+
+  typedef struct  FT_MemNodeRec_
+  {
+    FT_Byte*     address;
+    FT_Long      size;     /* < 0 if the block was freed */
+
+    const char*  alloc_file_name;
+    FT_Long      alloc_line_no;
+
+    const char*  free_file_name;
+    FT_Long      free_line_no;
+
+    FT_MemNode   link;
+
+  } FT_MemNodeRec;
+
+
+  typedef struct  FT_MemTableRec_
+  {
+    FT_ULong         size;
+    FT_ULong         nodes;
+    FT_MemNode*      buckets;
+
+    FT_ULong         alloc_total;
+    FT_ULong         alloc_current;
+    FT_ULong         alloc_max;
+
+    const char*      file_name;
+    FT_Long          line_no;
+
+    FT_Memory        memory;
+    FT_Pointer       memory_user;
+    FT_Alloc_Func    alloc;
+    FT_Free_Func     free;
+    FT_Realloc_Func  realloc;
+
+  } FT_MemTableRec;
+
+
+#define FT_MEM_SIZE_MIN  7
+#define FT_MEM_SIZE_MAX  13845163
+
+#define FT_FILENAME( x )  ((x) ? (x) : "unknown file")
+
+
+  static const FT_UInt  ft_mem_primes[] =
+  {
+    7,
+    11,
+    19,
+    37,
+    73,
+    109,
+    163,
+    251,
+    367,
+    557,
+    823,
+    1237,
+    1861,
+    2777,
+    4177,
+    6247,
+    9371,
+    14057,
+    21089,
+    31627,
+    47431,
+    71143,
+    106721,
+    160073,
+    240101,
+    360163,
+    540217,
+    810343,
+    1215497,
+    1823231,
+    2734867,
+    4102283,
+    6153409,
+    9230113,
+    13845163,
+  };
+
+
+
+  extern void
+  ft_mem_debug_panic( const char*  fmt, ... )
+  {
+    va_list  ap;
+
+
+    printf( "FreeType.Debug: " );
+
+    va_start( ap, fmt );
+    vprintf( fmt, ap );
+    va_end( ap );
+
+    printf( "\n" );
+    exit( EXIT_FAILURE );
+  }
+
+
+  static FT_ULong
+  ft_mem_closest_prime( FT_ULong  num )
+  {
+    FT_UInt  i;
+
+
+    for ( i = 0;
+          i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
+      if ( ft_mem_primes[i] > num )
+        return ft_mem_primes[i];
+
+    return FT_MEM_SIZE_MAX;
+  }
+
+
+  static FT_Pointer
+  ft_mem_table_alloc( FT_MemTable  table,
+                      FT_Long      size )
+  {
+    FT_Memory   memory = table->memory;
+    FT_Pointer  block;
+
+
+    memory->user = table->memory_user;
+    block = table->alloc( memory, size );
+    memory->user = table;
+
+   return block;
+  }
+
+
+  static void
+  ft_mem_table_free( FT_MemTable  table,
+                     FT_Pointer   block )
+  {
+    FT_Memory  memory = table->memory;
+
+
+    memory->user = table->memory_user;
+    table->free( memory, block );
+    memory->user = table;
+  }
+
+
+  static void
+  ft_mem_table_resize( FT_MemTable  table )
+  {
+    FT_ULong  new_size;
+
+
+    new_size = ft_mem_closest_prime( table->nodes );
+    if ( new_size != table->size )
+    {
+      FT_MemNode*  new_buckets ;
+      FT_ULong     i;
+
+
+      new_buckets = (FT_MemNode *)
+                    ft_mem_table_alloc( table,
+                                        new_size * sizeof ( FT_MemNode ) );
+      if ( new_buckets == NULL )
+        return;
+
+      FT_MEM_ZERO( new_buckets, sizeof ( FT_MemNode ) * new_size );
+
+      for ( i = 0; i < table->size; i++ )
+      {
+        FT_MemNode  node, next, *pnode;
+        FT_ULong    hash;
+
+
+        node = table->buckets[i];
+        while ( node )
+        {
+          next  = node->link;
+          hash  = FT_MEM_VAL( node->address ) % new_size;
+          pnode = new_buckets + hash;
+
+          node->link = pnode[0];
+          pnode[0]   = node;
+
+          node = next;
+        }
+      }
+
+      if ( table->buckets )
+        ft_mem_table_free( table, table->buckets );
+
+      table->buckets = new_buckets;
+      table->size    = new_size;
+    }
+  }
+
+
+  static FT_MemTable
+  ft_mem_table_new( FT_Memory  memory )
+  {
+    FT_MemTable  table;
+
+
+    table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
+    if ( table == NULL )
+      goto Exit;
+
+    FT_MEM_ZERO( table, sizeof ( *table ) );
+
+    table->size  = FT_MEM_SIZE_MIN;
+    table->nodes = 0;
+
+    table->memory = memory;
+
+    table->memory_user = memory->user;
+
+    table->alloc   = memory->alloc;
+    table->realloc = memory->realloc;
+    table->free    = memory->free;
+
+    table->buckets = (FT_MemNode *)
+                     memory->alloc( memory,
+                                    table->size * sizeof ( FT_MemNode ) );
+    if ( table->buckets )
+      FT_MEM_ZERO( table->buckets, sizeof ( FT_MemNode ) * table->size );
+    else
+    {
+      memory->free( memory, table );
+      table = NULL;
+    }
+
+  Exit:
+    return table;
+  }
+
+
+  static void
+  ft_mem_table_destroy( FT_MemTable  table )
+  {
+    FT_ULong  i;
+
+
+    if ( table )
+    {
+      FT_Long    leak_count = 0;
+      FT_ULong   leaks = 0;
+
+
+      for ( i = 0; i < table->size; i++ )
+      {
+        FT_MemNode  *pnode = table->buckets + i, next, node = *pnode;
+
+
+        while ( node )
+        {
+          next       = node->link;
+          node->link = 0;
+
+          if ( node->size > 0 )
+          {
+            printf(
+              "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
+              node->address, node->size,
+              FT_FILENAME( node->alloc_file_name ),
+              node->alloc_line_no );
+
+            leak_count++;
+            leaks += node->size;
+
+            ft_mem_table_free( table, node->address );
+          }
+
+          node->address = NULL;
+          node->size    = 0;
+
+          free( node );
+          node = next;
+        }
+        table->buckets[i] = 0;
+      }
+      ft_mem_table_free( table, table->buckets );
+      table->buckets = NULL;
+
+      table->size   = 0;
+      table->nodes  = 0;
+
+      printf(
+        "FreeType: total memory allocations = %ld\n", table->alloc_total );
+      printf(
+        "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
+
+      free( table );
+
+      if ( leak_count > 0 )
+        ft_mem_debug_panic(
+          "FreeType: %ld bytes of memory leaked in %ld blocks\n",
+          leaks, leak_count );
+      printf( "FreeType: No memory leaks detected!\n" );
+    }
+  }
+
+
+  static FT_MemNode*
+  ft_mem_table_get_nodep( FT_MemTable  table,
+                          FT_Byte*     address )
+  {
+    FT_ULong     hash;
+    FT_MemNode  *pnode, node;
+
+
+    hash  = FT_MEM_VAL( address );
+    pnode = table->buckets + ( hash % table->size );
+
+    for (;;)
+    {
+      node = pnode[0];
+      if ( !node )
+        break;
+
+      if ( node->address == address )
+        break;
+
+      pnode = &node->link;
+    }
+    return pnode;
+  }
+
+
+  static void
+  ft_mem_table_set( FT_MemTable  table,
+                    FT_Byte*     address,
+                    FT_ULong     size )
+  {
+    FT_MemNode  *pnode, node;
+
+
+    if ( table )
+    {
+      pnode = ft_mem_table_get_nodep( table, address );
+      node  = *pnode;
+      if ( node )
+      {
+        if ( node->size < 0 )
+        {
+          /* this block was already freed.  This means that our memory is */
+          /* now completely corrupted!                                    */
+          ft_mem_debug_panic(
+            "memory heap corrupted (allocating freed block)" );
+        }
+        else
+        {
+          /* this block was already allocated.  This means that our memory */
+          /* is also corrupted!                                            */
+          ft_mem_debug_panic(
+            "memory heap corrupted (re-allocating allocated block)" );
+        }
+      }
+
+      /* we need to create a new node in this table */
+      node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
+      if ( node == NULL )
+        ft_mem_debug_panic( "not enough memory to run memory tests" );
+
+      node->address = address;
+      node->size    = size;
+
+      node->alloc_file_name = table->file_name;
+      node->alloc_line_no   = table->line_no;
+
+      node->free_file_name = NULL;
+      node->free_line_no   = 0;
+
+      node->link = pnode[0];
+
+      pnode[0] = node;
+      table->nodes++;
+
+      table->alloc_total   += size;
+      table->alloc_current += size;
+      if ( table->alloc_current > table->alloc_max )
+        table->alloc_max = table->alloc_current;
+
+      if ( table->nodes * 3 < table->size  ||
+           table->size  * 3 < table->nodes )
+        ft_mem_table_resize( table );
+    }
+  }
+
+
+  static void
+  ft_mem_table_remove( FT_MemTable  table,
+                       FT_Byte*     address )
+  {
+    if ( table )
+    {
+      FT_MemNode  *pnode, node;
+
+
+      pnode = ft_mem_table_get_nodep( table, address );
+      node  = *pnode;
+      if ( node )
+      {
+        if ( node->size < 0 )
+          ft_mem_debug_panic(
+            "freeing memory block at %p more than once at (%s:%ld)\n"
+            "block allocated at (%s:%ld) and released at (%s:%ld)",
+            address,
+            FT_FILENAME( table->file_name ), table->line_no,
+            FT_FILENAME( node->alloc_file_name ), node->alloc_line_no,
+            FT_FILENAME( node->free_file_name ), node->free_line_no );
+
+        /* we simply invert the node's size to indicate that the node */
+        /* was freed.  We also change its contents.                   */
+        FT_MEM_SET( address, 0xF3, node->size );
+
+        table->alloc_current -= node->size;
+        node->size            = -node->size;
+        node->free_file_name  = table->file_name;
+        node->free_line_no    = table->line_no;
+      }
+      else
+        ft_mem_debug_panic(
+          "trying to free unknown block at %p in (%s:%ld)\n",
+          address,
+          FT_FILENAME( table->file_name ), table->line_no );
+    }
+  }
+
+
+  extern FT_Pointer
+  ft_mem_debug_alloc( FT_Memory  memory,
+                      FT_Long    size )
+  {
+    FT_MemTable  table = (FT_MemTable)memory->user;
+    FT_Byte*     block;
+
+
+    if ( size <= 0 )
+      ft_mem_debug_panic( "negative block size allocation (%ld)", size );
+
+    block = (FT_Byte *)ft_mem_table_alloc( table, size );
+    if ( block )
+      ft_mem_table_set( table, block, (FT_ULong)size );
+
+    table->file_name = NULL;
+    table->line_no   = 0;
+
+    return (FT_Pointer) block;
+  }
+
+
+  extern void
+  ft_mem_debug_free( FT_Memory   memory,
+                     FT_Pointer  block )
+  {
+    FT_MemTable  table = (FT_MemTable)memory->user;
+
+
+    if ( block == NULL )
+      ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
+                          FT_FILENAME( table->file_name ),
+                          table->line_no );
+
+    ft_mem_table_remove( table, (FT_Byte*)block );
+
+    /* we never really free the block */
+    table->file_name = NULL;
+    table->line_no   = 0;
+  }
+
+
+  extern FT_Pointer
+  ft_mem_debug_realloc( FT_Memory   memory,
+                        FT_Long     cur_size,
+                        FT_Long     new_size,
+                        FT_Pointer  block )
+  {
+    FT_MemTable  table = (FT_MemTable)memory->user;
+    FT_MemNode   node, *pnode;
+    FT_Pointer   new_block;
+
+    const char*  file_name = FT_FILENAME( table->file_name );
+    FT_Long      line_no   = table->line_no;
+
+
+    if ( block == NULL || cur_size == 0 )
+      ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
+                           file_name, line_no );
+
+    if ( new_size <= 0 )
+      ft_mem_debug_panic(
+        "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
+        block, cur_size, file_name, line_no );
+
+    /* check 'cur_size' value */
+    pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
+    node  = *pnode;
+    if ( !node )
+      ft_mem_debug_panic(
+        "trying to reallocate unknown block at %p in (%s:%ld)",
+        block, file_name, line_no );
+
+    if ( node->size <= 0 )
+      ft_mem_debug_panic(
+        "trying to reallocate freed block at %p in (%s:%ld)",
+        block, file_name, line_no );
+
+    if ( node->size != cur_size )
+      ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
+                          "%ld instead of %ld in (%s:%ld)",
+                          block, cur_size, node->size, file_name, line_no );
+
+    new_block = ft_mem_debug_alloc( memory, new_size );
+    if ( new_block == NULL )
+      return NULL;
+
+    ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
+
+    table->file_name = file_name;
+    table->line_no   = line_no;
+
+    ft_mem_debug_free( memory, (FT_Byte*)block );
+
+    return new_block;
+  }
+
+
+  extern FT_Int
+  ft_mem_debug_init( FT_Memory  memory )
+  {
+    FT_MemTable  table;
+    FT_Int       result = 0;
+
+
+    if ( getenv( "FT_DEBUG_MEMORY" ) )
+    {
+      table = ft_mem_table_new( memory );
+      if ( table )
+      {
+        memory->user    = table;
+        memory->alloc   = ft_mem_debug_alloc;
+        memory->realloc = ft_mem_debug_realloc;
+        memory->free    = ft_mem_debug_free;
+        result = 1;
+      }
+    }
+    return result;
+  }
+
+
+  extern void
+  ft_mem_debug_done( FT_Memory  memory )
+  {
+    FT_MemTable  table = (FT_MemTable)memory->user;
+
+
+    if ( table )
+    {
+      memory->free    = table->free;
+      memory->realloc = table->realloc;
+      memory->alloc   = table->alloc;
+
+      ft_mem_table_destroy( table );
+      memory->user = NULL;
+    }
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Alloc_Debug( FT_Memory    memory,
+                  FT_Long      size,
+                  void*       *P,
+                  const char*  file_name,
+                  FT_Long      line_no )
+  {
+    FT_MemTable  table = (FT_MemTable)memory->user;
+
+
+    if ( table )
+    {
+      table->file_name = file_name;
+      table->line_no   = line_no;
+    }
+    return FT_Alloc( memory, size, P );
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Realloc_Debug( FT_Memory    memory,
+                    FT_Long      current,
+                    FT_Long      size,
+                    void*       *P,
+                    const char*  file_name,
+                    FT_Long      line_no )
+  {
+    FT_MemTable  table = (FT_MemTable)memory->user;
+
+
+    if ( table )
+    {
+      table->file_name = file_name;
+      table->line_no   = line_no;
+    }
+    return FT_Realloc( memory, current, size, P );
+  }
+
+
+  FT_BASE_DEF( void )
+  FT_Free_Debug( FT_Memory    memory,
+                 FT_Pointer   block,
+                 const char*  file_name,
+                 FT_Long      line_no )
+  {
+    FT_MemTable  table = (FT_MemTable)memory->user;
+
+
+    if ( table )
+    {
+      table->file_name = file_name;
+      table->line_no   = line_no;
+    }
+    FT_Free( memory, (void **)block );
+  }
+
+
+#else  /* !FT_DEBUG_MEMORY */
+
+  /* ANSI C doesn't like empty source files */
+  const FT_Byte  _debug_mem_dummy = 0;
+
+#endif /* !FT_DEBUG_MEMORY */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftdebug.c
@@ -1,0 +1,197 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftdebug.c                                                              */
+/*                                                                         */
+/*    Debugging and logging component (body).                              */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This component contains various macros and functions used to ease the */
+  /* debugging of the FreeType engine.  Its main purpose is in assertion   */
+  /* checking, tracing, and error detection.                               */
+  /*                                                                       */
+  /* There are now three debugging modes:                                  */
+  /*                                                                       */
+  /* - trace mode                                                          */
+  /*                                                                       */
+  /*   Error and trace messages are sent to the log file (which can be the */
+  /*   standard error output).                                             */
+  /*                                                                       */
+  /* - error mode                                                          */
+  /*                                                                       */
+  /*   Only error messages are generated.                                  */
+  /*                                                                       */
+  /* - release mode:                                                       */
+  /*                                                                       */
+  /*   No error message is sent or generated.  The code is free from any   */
+  /*   debugging parts.                                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+
+
+#if defined( FT_DEBUG_LEVEL_ERROR )
+
+  FT_EXPORT_DEF( void )
+  FT_Message( const char*  fmt, ... )
+  {
+    va_list  ap;
+
+
+    va_start( ap, fmt );
+    vprintf( fmt, ap );
+    va_end( ap );
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_Panic( const char*  fmt, ... )
+  {
+    va_list  ap;
+
+
+    va_start( ap, fmt );
+    vprintf( fmt, ap );
+    va_end( ap );
+
+    exit( EXIT_FAILURE );
+  }
+
+#endif /* FT_DEBUG_LEVEL_ERROR */
+
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+  /* array of trace levels, initialized to 0 */
+  int  ft_trace_levels[trace_count];
+
+  /* define array of trace toggle names */
+#define FT_TRACE_DEF(x)  #x ,
+
+  static const char*  ft_trace_toggles[trace_count + 1] =
+  {
+#include FT_INTERNAL_TRACE_H
+    NULL
+  };
+
+#undef FT_TRACE_DEF
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Initialize the tracing sub-system.  This is done by retrieving the    */
+  /* value of the "FT2_DEBUG" environment variable.  It must be a list of  */
+  /* toggles, separated by spaces, `;' or `,'.  Example:                   */
+  /*                                                                       */
+  /*    "any:3 memory:6 stream:5"                                          */
+  /*                                                                       */
+  /* This will request that all levels be set to 3, except the trace level */
+  /* for the memory and stream components which are set to 6 and 5,        */
+  /* respectively.                                                         */
+  /*                                                                       */
+  /* See the file <freetype/internal/fttrace.h> for details of the         */
+  /* available toggle names.                                               */
+  /*                                                                       */
+  /* The level must be between 0 and 6; 0 means quiet (except for serious  */
+  /* runtime errors), and 6 means _very_ verbose.                          */
+  /*                                                                       */
+  FT_BASE_DEF( void )
+  ft_debug_init( void )
+  {
+    const char*  ft2_debug = getenv( "FT2_DEBUG" );
+
+    if ( ft2_debug )
+    {
+      const char*  p = ft2_debug;
+      const char*  q;
+
+
+      for ( ; *p; p++ )
+      {
+        /* skip leading whitespace and separators */
+        if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
+          continue;
+
+        /* read toggle name, followed by ':' */
+        q = p;
+        while ( *p && *p != ':' )
+          p++;
+          
+        if ( *p == ':' && p > q )
+        {
+          FT_Int  n, i, len = (FT_Int)(p - q);
+          FT_Int  level = -1, found = -1;
+
+
+          for ( n = 0; n < trace_count; n++ )
+          {
+            const char*  toggle = ft_trace_toggles[n];
+
+
+            for ( i = 0; i < len; i++ )
+            {
+              if ( toggle[i] != q[i] )
+                break;
+            }
+
+            if ( i == len && toggle[i] == 0 )
+            {
+              found = n;
+              break;
+            }
+          }
+
+          /* read level */
+          p++;
+          if ( *p )
+          {
+            level = *p++ - '0';
+            if ( level < 0 || level > 6 )
+              level = -1;
+          }
+
+          if ( found >= 0 && level >= 0 )
+          {
+            if ( found == trace_any )
+            {
+              /* special case for "any" */
+              for ( n = 0; n < trace_count; n++ )
+                ft_trace_levels[n] = level;
+            }
+            else
+              ft_trace_levels[found] = level;
+          }
+        }
+      }
+    }
+  }
+
+#else  /* !FT_DEBUG_LEVEL_TRACE */
+
+  FT_BASE_DEF( void )
+  ft_debug_init( void )
+  {
+    /* nothing */
+  }
+
+#endif /* !FT_DEBUG_LEVEL_TRACE */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftexcept.c
@@ -1,0 +1,197 @@
+#include <ft2build.h>
+#include FT_EXCEPT_H
+
+
+  FT_BASE_DEF( void )
+  ft_cleanup_stack_init( FT_CleanupStack  stack,
+                         FT_Memory        memory )
+  {
+    stack->chunk = &stack->chunk_0;
+    stack->top   = stack->chunk->items;
+    stack->limit = stack->top + FT_CLEANUP_CHUNK_SIZE;
+    stack->chunk_0.link = NULL;
+
+    stack->memory = memory;
+  }
+
+
+
+  FT_BASE_DEF( void )
+  ft_cleanup_stack_done( FT_CleanupStack  stack )
+  {
+    FT_Memory        memory = stack->memory;
+    FT_CleanupChunk  chunk, next;
+
+    for (;;)
+    {
+      chunk = stack->chunk;
+      if ( chunk == &stack->chunk_0 )
+        break;
+
+      stack->chunk = chunk->link;
+
+      FT_Free( chunk, memory );
+    }
+
+    stack->memory = NULL;
+  }
+
+
+
+  FT_BASE_DEF( void )
+  ft_cleanup_stack_push( FT_CleanupStack  stack,
+                         FT_Pointer       item,
+                         FT_CleanupFunc   item_func,
+                         FT_Pointer       item_data )
+  {
+    FT_CleanupItem  top;
+
+
+    FT_ASSERT( stack && stack->chunk && stack->top );
+    FT_ASSERT( item  && item_func );
+
+    top = stack->top;
+
+    top->item      = item;
+    top->item_func = item_func;
+    top->item_data = item_data;
+
+    top ++;
+
+    if ( top == stack->limit )
+    {
+      FT_CleanupChunk  chunk;
+
+      chunk = FT_QAlloc( sizeof(*chunk), stack->memory );
+
+      chunk->link  = stack->chunk;
+      stack->chunk = chunk;
+      stack->limit = chunk->items + FT_CLEANUP_CHUNK_SIZE;
+      top          = chunk->items;
+    }
+
+    stack->top = top;
+  }
+
+
+
+  FT_BASE_DEF( void )
+  ft_cleanup_stack_pop( FT_CleanupStack   stack,
+                        FT_Int            destroy )
+  {
+    FT_CleanupItem  top;
+
+
+    FT_ASSERT( stack && stack->chunk && stack->top );
+    top = stack->top;
+
+    if ( top == stack->chunk->items )
+    {
+      FT_CleanupChunk  chunk;
+
+      chunk = stack->chunk;
+
+      if ( chunk == &stack->chunk_0 )
+      {
+        FT_ERROR(( "cleanup.pop: empty cleanup stack !!\n" ));
+        ft_cleanup_throw( stack, FT_Err_EmptyCleanupStack );
+      }
+
+      chunk = chunk->link;
+      FT_QFree( stack->chunk, stack->memory );
+
+      stack->chunk = chunk;
+      stack->limit = chunk->items + FT_CLEANUP_CHUNK_SIZE;
+      top          = stack->limit;
+    }
+
+    top --;
+
+    if ( destroy )
+      top->item_func( top->item, top->item_data );
+
+    top->item      = NULL;
+    top->item_func = NULL;
+    top->item_data = NULL;
+
+    stack->top = top;
+  }
+
+
+
+  FT_BASE_DEF( FT_CleanupItem )
+  ft_cleanup_stack_peek( FT_CleanupStack  stack )
+  {
+    FT_CleanupItem   top;
+    FT_CleanupChunk  chunk;
+
+
+    FT_ASSERT( stack && stack->chunk && stack->top );
+
+    top   = stack->top;
+    chunk = stack->chunk;
+
+    if ( top > chunk->items )
+      top--;
+    else
+    {
+      chunk = chunk->link;
+      top   = NULL;
+      if ( chunk != NULL )
+        top = chunk->items + FT_CLEANUP_CHUNK_SIZE - 1;
+    }
+    return top;
+  }
+
+
+
+  FT_BASE_DEF( void )
+  ft_xhandler_enter( FT_XHandler  xhandler,
+                     FT_Memory    memory )
+  {
+    FT_CleanupStack  stack = FT_MEMORY__CLEANUP(memory);
+
+    xhandler->previous = stack->xhandler;
+    xhandler->cleanup  = stack->top;
+    xhandler->error    = 0;
+    stack->xhandler    = xhandler;
+  }
+
+
+
+  FT_BASE_DEF( void )
+  ft_xhandler_exit( FT_XHandler  xhandler )
+  {
+    FT_CleanupStack  stack = FT_MEMORY__CLEANUP(memory);
+
+    stack->xhandler    = xhandler->previous;
+    xhandler->previous = NULL;
+    xhandler->error    = error;
+    xhandler->cleanup  = NULL;
+  }
+
+
+
+  FT_BASE_DEF( void )
+  ft_cleanup_throw( FT_CleanupStack  stack,
+                    FT_Error         error )
+  {
+    FT_XHandler  xhandler = stack->xhandler;
+
+    if ( xhandler == NULL )
+    {
+      /* no exception handler was registered. this  */
+      /* means that we have an un-handled exception */
+      /* the only thing we can do is _PANIC_ and    */
+      /* halt the current program..                 */
+      /*                                            */
+      FT_ERROR(( "FREETYPE PANIC: An un-handled exception occured. Program aborted" ));
+      ft_exit(1);
+    }
+
+    /* cleanup the stack until we reach the handler's */
+    /* starting stack location..                      */
+
+    xhandler->error = error;
+    longmp( xhandler->jump_buffer, 1 );
+  }                    
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/ftgloadr.c
@@ -1,0 +1,361 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgloadr.c                                                             */
+/*                                                                         */
+/*    The FreeType glyph loader (body).                                    */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg                       */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_GLYPH_LOADER_H
+#include FT_INTERNAL_MEMORY_H
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gloader
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                                                               *****/
+  /*****                    G L Y P H   L O A D E R                    *****/
+  /*****                                                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The glyph loader is a simple object which is used to load a set of    */
+  /* glyphs easily.  It is critical for the correct loading of composites. */
+  /*                                                                       */
+  /* Ideally, one can see it as a stack of abstract `glyph' objects.       */
+  /*                                                                       */
+  /*   loader.base     Is really the bottom of the stack.  It describes a  */
+  /*                   single glyph image made of the juxtaposition of     */
+  /*                   several glyphs (those `in the stack').              */
+  /*                                                                       */
+  /*   loader.current  Describes the top of the stack, on which a new      */
+  /*                   glyph can be loaded.                                */
+  /*                                                                       */
+  /*   Rewind          Clears the stack.                                   */
+  /*   Prepare         Set up `loader.current' for addition of a new glyph */
+  /*                   image.                                              */
+  /*   Add             Add the `current' glyph image to the `base' one,    */
+  /*                   and prepare for another one.                        */
+  /*                                                                       */
+  /* The glyph loader is now a base object.  Each driver used to           */
+  /* re-implement it in one way or the other, which wasted code and        */
+  /* energy.                                                               */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /* create a new glyph loader */
+  FT_BASE_DEF( FT_Error )
+  FT_GlyphLoader_New( FT_Memory        memory,
+                      FT_GlyphLoader  *aloader )
+  {
+    FT_GlyphLoader  loader;
+    FT_Error        error;
+
+
+    if ( !FT_NEW( loader ) )
+    {
+      loader->memory = memory;
+      *aloader       = loader;
+    }
+    return error;
+  }
+
+
+  /* rewind the glyph loader - reset counters to 0 */
+  FT_BASE_DEF( void )
+  FT_GlyphLoader_Rewind( FT_GlyphLoader  loader )
+  {
+    FT_GlyphLoad  base    = &loader->base;
+    FT_GlyphLoad  current = &loader->current;
+
+
+    base->outline.n_points   = 0;
+    base->outline.n_contours = 0;
+    base->num_subglyphs      = 0;
+
+    *current = *base;
+  }
+
+
+  /* reset the glyph loader, frees all allocated tables */
+  /* and starts from zero                               */
+  FT_BASE_DEF( void )
+  FT_GlyphLoader_Reset( FT_GlyphLoader  loader )
+  {
+    FT_Memory memory = loader->memory;
+
+
+    FT_FREE( loader->base.outline.points );
+    FT_FREE( loader->base.outline.tags );
+    FT_FREE( loader->base.outline.contours );
+    FT_FREE( loader->base.extra_points );
+    FT_FREE( loader->base.subglyphs );
+
+    loader->max_points    = 0;
+    loader->max_contours  = 0;
+    loader->max_subglyphs = 0;
+
+    FT_GlyphLoader_Rewind( loader );
+  }
+
+
+  /* delete a glyph loader */
+  FT_BASE_DEF( void )
+  FT_GlyphLoader_Done( FT_GlyphLoader  loader )
+  {
+    if ( loader )
+    {
+      FT_Memory memory = loader->memory;
+
+
+      FT_GlyphLoader_Reset( loader );
+      FT_FREE( loader );
+    }
+  }
+
+
+  /* re-adjust the `current' outline fields */
+  static void
+  FT_GlyphLoader_Adjust_Points( FT_GlyphLoader  loader )
+  {
+    FT_Outline*  base    = &loader->base.outline;
+    FT_Outline*  current = &loader->current.outline;
+
+
+    current->points   = base->points   + base->n_points;
+    current->tags     = base->tags     + base->n_points;
+    current->contours = base->contours + base->n_contours;
+
+    /* handle extra points table - if any */
+    if ( loader->use_extra )
+      loader->current.extra_points =
+        loader->base.extra_points + base->n_points;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_GlyphLoader_CreateExtra( FT_GlyphLoader  loader )
+  {
+    FT_Error   error;
+    FT_Memory  memory = loader->memory;
+
+
+    if ( !FT_NEW_ARRAY( loader->base.extra_points, loader->max_points ) )
+    {
+      loader->use_extra = 1;
+      FT_GlyphLoader_Adjust_Points( loader );
+    }
+    return error;
+  }
+
+
+  /* re-adjust the `current' subglyphs field */
+  static void
+  FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader  loader )
+  {
+    FT_GlyphLoad  base    = &loader->base;
+    FT_GlyphLoad  current = &loader->current;
+
+
+    current->subglyphs = base->subglyphs + base->num_subglyphs;
+  }
+
+
+  /* Ensure that we can add `n_points' and `n_contours' to our glyph. this */
+  /* function reallocates its outline tables if necessary.  Note that it   */
+  /* DOESN'T change the number of points within the loader!                */
+  /*                                                                       */
+  FT_BASE_DEF( FT_Error )
+  FT_GlyphLoader_CheckPoints( FT_GlyphLoader  loader,
+                               FT_UInt        n_points,
+                               FT_UInt        n_contours )
+  {
+    FT_Memory    memory  = loader->memory;
+    FT_Error     error   = FT_Err_Ok;
+    FT_Outline*  base    = &loader->base.outline;
+    FT_Outline*  current = &loader->current.outline;
+    FT_Bool      adjust  = 1;
+
+    FT_UInt      new_max, old_max;
+
+
+    /* check points & tags */
+    new_max = base->n_points + current->n_points + n_points;
+    old_max = loader->max_points;
+
+    if ( new_max > old_max )
+    {
+      new_max = ( new_max + 7 ) & -8;
+
+      if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) ||
+           FT_RENEW_ARRAY( base->tags,   old_max, new_max ) )
+        goto Exit;
+
+      if ( loader->use_extra &&
+           FT_RENEW_ARRAY( loader->base.extra_points, old_max, new_max ) )
+        goto Exit;
+
+      adjust = 1;
+      loader->max_points = new_max;
+    }
+
+    /* check contours */
+    old_max = loader->max_contours;
+    new_max = base->n_contours + current->n_contours +
+              n_contours;
+    if ( new_max > old_max )
+    {
+      new_max = ( new_max + 3 ) & -4;
+      if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) )
+        goto Exit;
+
+      adjust = 1;
+      loader->max_contours = new_max;
+    }
+
+    if ( adjust )
+      FT_GlyphLoader_Adjust_Points( loader );
+
+  Exit:
+    return error;
+  }
+
+
+  /* Ensure that we can add `n_subglyphs' to our glyph. this function */
+  /* reallocates its subglyphs table if necessary.  Note that it DOES */
+  /* NOT change the number of subglyphs within the loader!            */
+  /*                                                                  */
+  FT_BASE_DEF( FT_Error )
+  FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader  loader,
+                                 FT_UInt         n_subs )
+  {
+    FT_Memory     memory = loader->memory;
+    FT_Error      error  = FT_Err_Ok;
+    FT_UInt       new_max, old_max;
+
+    FT_GlyphLoad  base    = &loader->base;
+    FT_GlyphLoad  current = &loader->current;
+
+
+    new_max = base->num_subglyphs + current->num_subglyphs + n_subs;
+    old_max = loader->max_subglyphs;
+    if ( new_max > old_max )
+    {
+      new_max = ( new_max + 1 ) & -2;
+      if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) )
+        goto Exit;
+
+      loader->max_subglyphs = new_max;
+
+      FT_GlyphLoader_Adjust_Subglyphs( loader );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /* prepare loader for the addition of a new glyph on top of the base one */
+  FT_BASE_DEF( void )
+  FT_GlyphLoader_Prepare( FT_GlyphLoader  loader )
+  {
+    FT_GlyphLoad  current = &loader->current;
+
+
+    current->outline.n_points   = 0;
+    current->outline.n_contours = 0;
+    current->num_subglyphs      = 0;
+
+    FT_GlyphLoader_Adjust_Points   ( loader );
+    FT_GlyphLoader_Adjust_Subglyphs( loader );
+  }
+
+
+  /* add current glyph to the base image - and prepare for another */
+  FT_BASE_DEF( void )
+  FT_GlyphLoader_Add( FT_GlyphLoader  loader )
+  {
+    FT_GlyphLoad  base    = &loader->base;
+    FT_GlyphLoad  current = &loader->current;
+
+    FT_UInt       n_curr_contours = current->outline.n_contours;
+    FT_UInt       n_base_points   = base->outline.n_points;
+    FT_UInt       n;
+
+
+    base->outline.n_points =
+      (short)( base->outline.n_points + current->outline.n_points );
+    base->outline.n_contours =
+      (short)( base->outline.n_contours + current->outline.n_contours );
+
+    base->num_subglyphs += current->num_subglyphs;
+
+    /* adjust contours count in newest outline */
+    for ( n = 0; n < n_curr_contours; n++ )
+      current->outline.contours[n] =
+        (short)( current->outline.contours[n] + n_base_points );
+
+    /* prepare for another new glyph image */
+    FT_GlyphLoader_Prepare( loader );
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_GlyphLoader_CopyPoints( FT_GlyphLoader  target,
+                             FT_GlyphLoader  source )
+  {
+    FT_Error  error;
+    FT_UInt   num_points   = source->base.outline.n_points;
+    FT_UInt   num_contours = source->base.outline.n_contours;
+
+
+    error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours );
+    if ( !error )
+    {
+      FT_Outline*  out = &target->base.outline;
+      FT_Outline*  in  = &source->base.outline;
+
+
+      FT_MEM_COPY( out->points, in->points,
+                   num_points * sizeof ( FT_Vector ) );
+      FT_MEM_COPY( out->tags, in->tags,
+                   num_points * sizeof ( char ) );
+      FT_MEM_COPY( out->contours, in->contours,
+                   num_contours * sizeof ( short ) );
+
+      /* do we need to copy the extra points? */
+      if ( target->use_extra && source->use_extra )
+        FT_MEM_COPY( target->base.extra_points, source->base.extra_points,
+                     num_points * sizeof ( FT_Vector ) );
+
+      out->n_points   = (short)num_points;
+      out->n_contours = (short)num_contours;
+
+      FT_GlyphLoader_Adjust_Points( target );
+    }
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftglyph.c
@@ -1,0 +1,684 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftglyph.c                                                              */
+/*                                                                         */
+/*    FreeType convenience functions to handle glyphs (body).              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  This file contains the definition of several convenience functions   */
+  /*  that can be used by client applications to easily retrieve glyph     */
+  /*  bitmaps and outlines from a given face.                              */
+  /*                                                                       */
+  /*  These functions should be optional if you are writing a font server  */
+  /*  or text layout engine on top of FreeType.  However, they are pretty  */
+  /*  handy for many other simple uses of the library.                     */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_glyph
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   Convenience functions                                         ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Matrix_Multiply( FT_Matrix*  a,
+                      FT_Matrix*  b )
+  {
+    FT_Fixed  xx, xy, yx, yy;
+
+
+    if ( !a || !b )
+      return;
+
+    xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx );
+    xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy );
+    yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx );
+    yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy );
+
+    b->xx = xx;  b->xy = xy;
+    b->yx = yx;  b->yy = yy;
+  }
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Matrix_Invert( FT_Matrix*  matrix )
+  {
+    FT_Pos  delta, xx, yy;
+
+
+    if ( !matrix )
+      return FT_Err_Invalid_Argument;
+
+    /* compute discriminant */
+    delta = FT_MulFix( matrix->xx, matrix->yy ) -
+            FT_MulFix( matrix->xy, matrix->yx );
+
+    if ( !delta )
+      return FT_Err_Invalid_Argument;  /* matrix can't be inverted */
+
+    matrix->xy = - FT_DivFix( matrix->xy, delta );
+    matrix->yx = - FT_DivFix( matrix->yx, delta );
+
+    xx = matrix->xx;
+    yy = matrix->yy;
+
+    matrix->xx = FT_DivFix( yy, delta );
+    matrix->yy = FT_DivFix( xx, delta );
+
+    return FT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   FT_BitmapGlyph support                                        ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static FT_Error
+  ft_bitmap_copy( FT_Memory   memory,
+                  FT_Bitmap*  source,
+                  FT_Bitmap*  target )
+  {
+    FT_Error  error;
+    FT_Int    pitch = source->pitch;
+    FT_ULong  size;
+
+
+    *target = *source;
+
+    if ( pitch < 0 )
+      pitch = -pitch;
+
+    size = (FT_ULong)( pitch * source->rows );
+
+    if ( !FT_ALLOC( target->buffer, size ) )
+      FT_MEM_COPY( target->buffer, source->buffer, size );
+
+    return error;
+  }
+
+
+  static FT_Error
+  ft_bitmap_glyph_init( FT_BitmapGlyph  glyph,
+                        FT_GlyphSlot    slot )
+  {
+    FT_Error    error   = FT_Err_Ok;
+    FT_Library  library = FT_GLYPH(glyph)->library;
+    FT_Memory   memory  = library->memory;
+
+
+    if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
+    {
+      error = FT_Err_Invalid_Glyph_Format;
+      goto Exit;
+    }
+
+    /* grab the bitmap in the slot - do lazy copying whenever possible */
+    glyph->bitmap = slot->bitmap;
+    glyph->left   = slot->bitmap_left;
+    glyph->top    = slot->bitmap_top;
+
+    if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+      slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+    else
+    {
+      /* copy the bitmap into a new buffer */
+      error = ft_bitmap_copy( memory, &slot->bitmap, &glyph->bitmap );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  ft_bitmap_glyph_copy( FT_BitmapGlyph  source,
+                        FT_BitmapGlyph  target )
+  {
+    FT_Memory  memory = source->root.library->memory;
+
+
+    target->left = source->left;
+    target->top  = source->top;
+
+    return ft_bitmap_copy( memory, &source->bitmap, &target->bitmap );
+  }
+
+
+  static void
+  ft_bitmap_glyph_done( FT_BitmapGlyph  glyph )
+  {
+    FT_Memory  memory = FT_GLYPH(glyph)->library->memory;
+
+
+    FT_FREE( glyph->bitmap.buffer );
+  }
+
+
+  static void
+  ft_bitmap_glyph_bbox( FT_BitmapGlyph  glyph,
+                        FT_BBox*        cbox )
+  {
+    cbox->xMin = glyph->left << 6;
+    cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 );
+    cbox->yMax = glyph->top << 6;
+    cbox->yMin = cbox->yMax - ( glyph->bitmap.rows << 6 );
+  }
+
+
+  const FT_Glyph_Class  ft_bitmap_glyph_class =
+  {
+    sizeof( FT_BitmapGlyphRec ),
+    FT_GLYPH_FORMAT_BITMAP,
+
+    (FT_Glyph_InitFunc)     ft_bitmap_glyph_init,
+    (FT_Glyph_DoneFunc)     ft_bitmap_glyph_done,
+    (FT_Glyph_CopyFunc)     ft_bitmap_glyph_copy,
+    (FT_Glyph_TransformFunc)0,
+    (FT_Glyph_GetBBoxFunc)  ft_bitmap_glyph_bbox,
+    (FT_Glyph_PrepareFunc)  0
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   FT_OutlineGlyph support                                       ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static FT_Error
+  ft_outline_glyph_init( FT_OutlineGlyph  glyph,
+                         FT_GlyphSlot     slot )
+  {
+    FT_Error     error   = FT_Err_Ok;
+    FT_Library   library = FT_GLYPH(glyph)->library;
+    FT_Outline*  source  = &slot->outline;
+    FT_Outline*  target  = &glyph->outline;
+
+
+    /* check format in glyph slot */
+    if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+    {
+      error = FT_Err_Invalid_Glyph_Format;
+      goto Exit;
+    }
+
+    /* allocate new outline */
+    error = FT_Outline_New( library, source->n_points, source->n_contours,
+                            &glyph->outline );
+    if ( error )
+      goto Exit;
+
+    /* copy it */
+    FT_MEM_COPY( target->points, source->points,
+              source->n_points * sizeof ( FT_Vector ) );
+
+    FT_MEM_COPY( target->tags, source->tags,
+              source->n_points * sizeof ( FT_Byte ) );
+
+    FT_MEM_COPY( target->contours, source->contours,
+              source->n_contours * sizeof ( FT_Short ) );
+
+    /* copy all flags, except the `FT_OUTLINE_OWNER' one */
+    target->flags = source->flags | FT_OUTLINE_OWNER;
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  ft_outline_glyph_done( FT_OutlineGlyph  glyph )
+  {
+    FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
+  }
+
+
+  static FT_Error
+  ft_outline_glyph_copy( FT_OutlineGlyph  source,
+                         FT_OutlineGlyph  target )
+  {
+    FT_Error    error;
+    FT_Library  library = FT_GLYPH( source )->library;
+
+
+    error = FT_Outline_New( library, source->outline.n_points,
+                            source->outline.n_contours, &target->outline );
+    if ( !error )
+      FT_Outline_Copy( &source->outline, &target->outline );
+
+    return error;
+  }
+
+
+  static void
+  ft_outline_glyph_transform( FT_OutlineGlyph  glyph,
+                              FT_Matrix*       matrix,
+                              FT_Vector*       delta )
+  {
+    if ( matrix )
+      FT_Outline_Transform( &glyph->outline, matrix );
+
+    if ( delta )
+      FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
+  }
+
+
+  static void
+  ft_outline_glyph_bbox( FT_OutlineGlyph  glyph,
+                         FT_BBox*         bbox )
+  {
+    FT_Outline_Get_CBox( &glyph->outline, bbox );
+  }
+
+
+  static FT_Error
+  ft_outline_glyph_prepare( FT_OutlineGlyph  glyph,
+                            FT_GlyphSlot     slot )
+  {
+    slot->format         = FT_GLYPH_FORMAT_OUTLINE;
+    slot->outline        = glyph->outline;
+    slot->outline.flags &= ~FT_OUTLINE_OWNER;
+
+    return FT_Err_Ok;
+  }
+
+
+  const FT_Glyph_Class  ft_outline_glyph_class =
+  {
+    sizeof( FT_OutlineGlyphRec ),
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Glyph_InitFunc)     ft_outline_glyph_init,
+    (FT_Glyph_DoneFunc)     ft_outline_glyph_done,
+    (FT_Glyph_CopyFunc)     ft_outline_glyph_copy,
+    (FT_Glyph_TransformFunc)ft_outline_glyph_transform,
+    (FT_Glyph_GetBBoxFunc)  ft_outline_glyph_bbox,
+    (FT_Glyph_PrepareFunc)  ft_outline_glyph_prepare
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   FT_Glyph class and API                                        ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+   static FT_Error
+   ft_new_glyph( FT_Library             library,
+                 const FT_Glyph_Class*  clazz,
+                 FT_Glyph*              aglyph )
+   {
+     FT_Memory  memory = library->memory;
+     FT_Error   error;
+     FT_Glyph   glyph;
+
+
+     *aglyph = 0;
+
+     if ( !FT_ALLOC( glyph, clazz->glyph_size ) )
+     {
+       glyph->library = library;
+       glyph->clazz   = clazz;
+       glyph->format  = clazz->glyph_format;
+
+       *aglyph = glyph;
+     }
+
+     return error;
+   }
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Glyph_Copy( FT_Glyph   source,
+                 FT_Glyph  *target )
+  {
+    FT_Glyph               copy;
+    FT_Error               error;
+    const FT_Glyph_Class*  clazz;
+
+
+    /* check arguments */
+    if ( !target || !source || !source->clazz )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    *target = 0;
+
+    clazz = source->clazz;
+    error = ft_new_glyph( source->library, clazz, &copy );
+    if ( error )
+      goto Exit;
+
+    copy->advance = source->advance;
+    copy->format  = source->format;
+
+    if ( clazz->glyph_copy )
+      error = clazz->glyph_copy( source, copy );
+
+    if ( error )
+      FT_Done_Glyph( copy );
+    else
+      *target = copy;
+
+  Exit:
+    return error;
+  }
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_Glyph( FT_GlyphSlot  slot,
+                FT_Glyph     *aglyph )
+  {
+    FT_Library  library = slot->library;
+    FT_Error    error;
+    FT_Glyph    glyph;
+
+    const FT_Glyph_Class*  clazz = 0;
+
+
+    if ( !slot )
+      return FT_Err_Invalid_Slot_Handle;
+
+    if ( !aglyph )
+      return FT_Err_Invalid_Argument;
+
+    /* if it is a bitmap, that's easy :-) */
+    if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
+      clazz = &ft_bitmap_glyph_class;
+
+    /* it it is an outline too */
+    else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+      clazz = &ft_outline_glyph_class;
+
+    else
+    {
+      /* try to find a renderer that supports the glyph image format */
+      FT_Renderer  render = FT_Lookup_Renderer( library, slot->format, 0 );
+
+
+      if ( render )
+        clazz = &render->glyph_class;
+    }
+
+    if ( !clazz )
+    {
+      error = FT_Err_Invalid_Glyph_Format;
+      goto Exit;
+    }
+
+    /* create FT_Glyph object */
+    error = ft_new_glyph( library, clazz, &glyph );
+    if ( error )
+      goto Exit;
+
+    /* copy advance while converting it to 16.16 format */
+    glyph->advance.x = slot->advance.x << 10;
+    glyph->advance.y = slot->advance.y << 10;
+
+    /* now import the image from the glyph slot */
+    error = clazz->glyph_init( glyph, slot );
+
+    /* if an error occurred, destroy the glyph */
+    if ( error )
+      FT_Done_Glyph( glyph );
+    else
+      *aglyph = glyph;
+
+  Exit:
+    return error;
+  }
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Glyph_Transform( FT_Glyph    glyph,
+                      FT_Matrix*  matrix,
+                      FT_Vector*  delta )
+  {
+    const FT_Glyph_Class*  clazz;
+    FT_Error               error = FT_Err_Ok;
+
+
+    if ( !glyph || !glyph->clazz )
+      error = FT_Err_Invalid_Argument;
+    else
+    {
+      clazz = glyph->clazz;
+      if ( clazz->glyph_transform )
+      {
+        /* transform glyph image */
+        clazz->glyph_transform( glyph, matrix, delta );
+
+        /* transform advance vector */
+        if ( matrix )
+          FT_Vector_Transform( &glyph->advance, matrix );
+      }
+      else
+        error = FT_Err_Invalid_Glyph_Format;
+    }
+    return error;
+  }
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Glyph_Get_CBox( FT_Glyph  glyph,
+                     FT_UInt   bbox_mode,
+                     FT_BBox  *acbox )
+  {
+    const FT_Glyph_Class*  clazz;
+
+
+    if ( !acbox )
+      return;
+
+    acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;
+
+    if ( !glyph || !glyph->clazz )
+      return;
+    else
+    {
+      clazz = glyph->clazz;
+      if ( !clazz->glyph_bbox )
+        return;
+      else
+      {
+        /* retrieve bbox in 26.6 coordinates */
+        clazz->glyph_bbox( glyph, acbox );
+
+        /* perform grid fitting if needed */
+        if ( bbox_mode & ft_glyph_bbox_gridfit )
+        {
+          acbox->xMin &= -64;
+          acbox->yMin &= -64;
+          acbox->xMax  = ( acbox->xMax + 63 ) & -64;
+          acbox->yMax  = ( acbox->yMax + 63 ) & -64;
+        }
+
+        /* convert to integer pixels if needed */
+        if ( bbox_mode & ft_glyph_bbox_truncate )
+        {
+          acbox->xMin >>= 6;
+          acbox->yMin >>= 6;
+          acbox->xMax >>= 6;
+          acbox->yMax >>= 6;
+        }
+      }
+    }
+    return;
+  }
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Glyph_To_Bitmap( FT_Glyph*       the_glyph,
+                      FT_Render_Mode  render_mode,
+                      FT_Vector*      origin,
+                      FT_Bool         destroy )
+  {
+    FT_GlyphSlotRec  dummy;
+    FT_Error         error = FT_Err_Ok;
+    FT_Glyph         glyph;
+    FT_BitmapGlyph   bitmap = NULL;
+
+    const FT_Glyph_Class*  clazz;
+
+
+    /* check argument */
+    if ( !the_glyph )
+      goto Bad;
+
+    /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
+    /* then calling FT_Render_Glyph_Internal()                            */
+
+    glyph = *the_glyph;
+    if ( !glyph )
+      goto Bad;
+
+    clazz = glyph->clazz;
+
+    /* when called with a bitmap glyph, do nothing and return succesfully */
+    if ( clazz == &ft_bitmap_glyph_class )
+      goto Exit;
+
+    if ( !clazz || !clazz->glyph_prepare )
+      goto Bad;
+
+    FT_MEM_ZERO( &dummy, sizeof ( dummy ) );
+    dummy.library = glyph->library;
+    dummy.format  = clazz->glyph_format;
+
+    /* create result bitmap glyph */
+    error = ft_new_glyph( glyph->library, &ft_bitmap_glyph_class,
+                          (FT_Glyph*)&bitmap );
+    if ( error )
+      goto Exit;
+
+#if 0
+    /* if `origin' is set, translate the glyph image */
+    if ( origin )
+      FT_Glyph_Transform( glyph, 0, origin );
+#else
+    FT_UNUSED( origin );
+#endif
+
+    /* prepare dummy slot for rendering */
+    error = clazz->glyph_prepare( glyph, &dummy );
+    if ( !error )
+      error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
+
+#if 0
+    if ( !destroy && origin )
+    {
+      FT_Vector  v;
+
+
+      v.x = -origin->x;
+      v.y = -origin->y;
+      FT_Glyph_Transform( glyph, 0, &v );
+    }
+#endif
+
+    if ( error )
+      goto Exit;
+
+    /* in case of success, copy the bitmap to the glyph bitmap */
+    error = ft_bitmap_glyph_init( bitmap, &dummy );
+    if ( error )
+      goto Exit;
+
+    /* copy advance */
+    bitmap->root.advance = glyph->advance;
+
+    if ( destroy )
+      FT_Done_Glyph( glyph );
+
+    *the_glyph = FT_GLYPH( bitmap );
+
+  Exit:
+    if ( error && bitmap )
+      FT_Done_Glyph( FT_GLYPH( bitmap ) );
+
+    return error;
+
+  Bad:
+    error = FT_Err_Invalid_Argument;
+    goto Exit;
+  }
+
+
+  /* documentation is in ftglyph.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Done_Glyph( FT_Glyph  glyph )
+  {
+    if ( glyph )
+    {
+      FT_Memory              memory = glyph->library->memory;
+      const FT_Glyph_Class*  clazz  = glyph->clazz;
+
+
+      if ( clazz->glyph_done )
+        clazz->glyph_done( glyph );
+
+      FT_FREE( glyph );
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftgrays.c
@@ -1,0 +1,2159 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgrays.c                                                              */
+/*                                                                         */
+/*    A new `perfect' anti-aliasing renderer (body).                       */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file can be compiled without the rest of the FreeType engine, by */
+  /* defining the _STANDALONE_ macro when compiling it.  You also need to  */
+  /* put the files `ftgrays.h' and `ftimage.h' into the current            */
+  /* compilation directory.  Typically, you could do something like        */
+  /*                                                                       */
+  /* - copy `src/smooth/ftgrays.c' (this file) to your current directory   */
+  /*                                                                       */
+  /* - copy `include/freetype/ftimage.h' and `src/smooth/ftgrays.h' to the */
+  /*   same directory                                                      */
+  /*                                                                       */
+  /* - compile `ftgrays' with the _STANDALONE_ macro defined, as in        */
+  /*                                                                       */
+  /*     cc -c -D_STANDALONE_ ftgrays.c                                    */
+  /*                                                                       */
+  /* The renderer can be initialized with a call to                        */
+  /* `ft_gray_raster.raster_new'; an anti-aliased bitmap can be generated  */
+  /* with a call to `ft_gray_raster.raster_render'.                        */
+  /*                                                                       */
+  /* See the comments and documentation in the file `ftimage.h' for more   */
+  /* details on how the raster works.                                      */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This is a new anti-aliasing scan-converter for FreeType 2.  The       */
+  /* algorithm used here is _very_ different from the one in the standard  */
+  /* `ftraster' module.  Actually, `ftgrays' computes the _exact_          */
+  /* coverage of the outline on each pixel cell.                           */
+  /*                                                                       */
+  /* It is based on ideas that I initially found in Raph Levien's          */
+  /* excellent LibArt graphics library (see http://www.levien.com/libart   */
+  /* for more information, though the web pages do not tell anything       */
+  /* about the renderer; you'll have to dive into the source code to       */
+  /* understand how it works).                                             */
+  /*                                                                       */
+  /* Note, however, that this is a _very_ different implementation         */
+  /* compared to Raph's.  Coverage information is stored in a very         */
+  /* different way, and I don't use sorted vector paths.  Also, it doesn't */
+  /* use floating point values.                                            */
+  /*                                                                       */
+  /* This renderer has the following advantages:                           */
+  /*                                                                       */
+  /* - It doesn't need an intermediate bitmap.  Instead, one can supply a  */
+  /*   callback function that will be called by the renderer to draw gray  */
+  /*   spans on any target surface.  You can thus do direct composition on */
+  /*   any kind of bitmap, provided that you give the renderer the right   */
+  /*   callback.                                                           */
+  /*                                                                       */
+  /* - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on   */
+  /*   each pixel cell.                                                    */
+  /*                                                                       */
+  /* - It performs a single pass on the outline (the `standard' FT2        */
+  /*   renderer makes two passes).                                         */
+  /*                                                                       */
+  /* - It can easily be modified to render to _any_ number of gray levels  */
+  /*   cheaply.                                                            */
+  /*                                                                       */
+  /* - For small (< 20) pixel sizes, it is faster than the standard        */
+  /*   renderer.                                                           */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+
+/* experimental support for gamma correction within the rasterizer */
+#define xxxGRAYS_USE_GAMMA
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_smooth
+
+
+#define ErrRaster_MemoryOverflow   -4
+
+
+#ifdef _STANDALONE_
+
+#include <string.h>             /* for ft_memcpy() */
+#include <setjmp.h>
+#include <limits.h>
+#define FT_UINT_MAX  UINT_MAX
+
+#define ft_memset   memset
+
+#define ft_setjmp   setjmp
+#define ft_longjmp  longjmp
+#define ft_jmp_buf  jmp_buf
+
+
+#define ErrRaster_Invalid_Mode     -2
+#define ErrRaster_Invalid_Outline  -1
+
+#define FT_BEGIN_HEADER
+#define FT_END_HEADER
+
+#include "ftimage.h"
+#include "ftgrays.h"
+
+  /* This macro is used to indicate that a function parameter is unused. */
+  /* Its purpose is simply to reduce compiler warnings.  Note also that  */
+  /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+  /* ANSI compilers (e.g. LCC).                                          */
+#define FT_UNUSED( x )  (x) = (x)
+
+  /* Disable the tracing mechanism for simplicity -- developers can      */
+  /* activate it easily by redefining these two macros.                  */
+#ifndef FT_ERROR
+#define FT_ERROR( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+
+#else /* _STANDALONE_ */
+
+
+#include <ft2build.h>
+#include "ftgrays.h"
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_OUTLINE_H
+
+#include "ftsmerrs.h"
+
+#define ErrRaster_Invalid_Mode     Smooth_Err_Cannot_Render_Glyph
+#define ErrRaster_Invalid_Outline  Smooth_Err_Invalid_Outline
+
+
+#endif /* _STANDALONE_ */
+
+
+#ifndef FT_MEM_SET
+#define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
+#endif
+
+#ifndef FT_MEM_ZERO
+#define FT_MEM_ZERO( dest, count )  FT_MEM_SET( dest, 0, count )
+#endif
+
+  /* define this to dump debugging information */
+#define xxxDEBUG_GRAYS
+
+  /* as usual, for the speed hungry :-) */
+
+#ifndef FT_STATIC_RASTER
+
+
+#define RAS_ARG   PRaster  raster
+#define RAS_ARG_  PRaster  raster,
+
+#define RAS_VAR   raster
+#define RAS_VAR_  raster,
+
+#define ras       (*raster)
+
+
+#else /* FT_STATIC_RASTER */
+
+
+#define RAS_ARG   /* empty */
+#define RAS_ARG_  /* empty */
+#define RAS_VAR   /* empty */
+#define RAS_VAR_  /* empty */
+
+  static TRaster  ras;
+
+
+#endif /* FT_STATIC_RASTER */
+
+
+  /* must be at least 6 bits! */
+#define PIXEL_BITS  8
+
+#define ONE_PIXEL       ( 1L << PIXEL_BITS )
+#define PIXEL_MASK      ( -1L << PIXEL_BITS )
+#define TRUNC( x )      ( (TCoord)((x) >> PIXEL_BITS) )
+#define SUBPIXELS( x )  ( (TPos)(x) << PIXEL_BITS )
+#define FLOOR( x )      ( (x) & -ONE_PIXEL )
+#define CEILING( x )    ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL )
+#define ROUND( x )      ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL )
+
+#if PIXEL_BITS >= 6
+#define UPSCALE( x )    ( (x) << ( PIXEL_BITS - 6 ) )
+#define DOWNSCALE( x )  ( (x) >> ( PIXEL_BITS - 6 ) )
+#else
+#define UPSCALE( x )    ( (x) >> ( 6 - PIXEL_BITS ) )
+#define DOWNSCALE( x )  ( (x) << ( 6 - PIXEL_BITS ) )
+#endif
+
+  /* Define this if you want to use a more compact storage scheme.  This   */
+  /* increases the number of cells available in the render pool but slows  */
+  /* down the rendering a bit.  It is useful if you have a really tiny     */
+  /* render pool.                                                          */
+#undef GRAYS_COMPACT
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*   TYPE DEFINITIONS                                                    */
+  /*                                                                       */
+
+  /* don't change the following types to FT_Int or FT_Pos, since we might */
+  /* need to define them to "float" or "double" when experimenting with   */
+  /* new algorithms                                                       */
+
+  typedef int   TCoord;   /* integer scanline/pixel coordinate */
+  typedef long  TPos;     /* sub-pixel coordinate              */
+
+  /* determine the type used to store cell areas.  This normally takes at */
+  /* least PIXEL_BYTES*2 + 1.  On 16-bit systems, we need to use `long'   */
+  /* instead of `int', otherwise bad things happen                        */
+
+#if PIXEL_BITS <= 7
+
+  typedef int   TArea;
+
+#else /* PIXEL_BITS >= 8 */
+
+  /* approximately determine the size of integers using an ANSI-C header */
+#if FT_UINT_MAX == 0xFFFFU
+  typedef long  TArea;
+#else
+  typedef int  TArea;
+#endif
+
+#endif /* PIXEL_BITS >= 8 */
+
+
+  /* maximal number of gray spans in a call to the span callback */
+#define FT_MAX_GRAY_SPANS  32
+
+
+#ifdef GRAYS_COMPACT
+
+  typedef struct  TCell_
+  {
+    short  x     : 14;
+    short  y     : 14;
+    int    cover : PIXEL_BITS + 2;
+    int    area  : PIXEL_BITS * 2 + 2;
+
+  } TCell, *PCell;
+
+#else /* GRAYS_COMPACT */
+
+  typedef struct  TCell_
+  {
+    TCoord  x;
+    TCoord  y;
+    int     cover;
+    TArea   area;
+
+  } TCell, *PCell;
+
+#endif /* GRAYS_COMPACT */
+
+
+  typedef struct  TRaster_
+  {
+    PCell   cells;
+    int     max_cells;
+    int     num_cells;
+
+    TPos    min_ex, max_ex;
+    TPos    min_ey, max_ey;
+
+    TArea   area;
+    int     cover;
+    int     invalid;
+
+    TCoord  ex, ey;
+    TCoord  cx, cy;
+    TPos    x,  y;
+
+    TPos    last_ey;
+
+    FT_Vector   bez_stack[32 * 3 + 1];
+    int         lev_stack[32];
+
+    FT_Outline  outline;
+    FT_Bitmap   target;
+    FT_BBox     clip_box;
+
+    FT_Span     gray_spans[FT_MAX_GRAY_SPANS];
+    int         num_gray_spans;
+
+    FT_Raster_Span_Func  render_span;
+    void*                render_span_data;
+    int                  span_y;
+
+    int  band_size;
+    int  band_shoot;
+    int  conic_level;
+    int  cubic_level;
+
+    void*       memory;
+    ft_jmp_buf  jump_buffer;
+
+#ifdef GRAYS_USE_GAMMA
+    unsigned char  gamma[257];
+#endif
+
+  } TRaster, *PRaster;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Initialize the cells table.                                           */
+  /*                                                                       */
+  static void
+  gray_init_cells( RAS_ARG_ void*  buffer,
+                   long            byte_size )
+  {
+    ras.cells     = (PCell)buffer;
+    ras.max_cells = byte_size / sizeof ( TCell );
+    ras.num_cells = 0;
+    ras.area      = 0;
+    ras.cover     = 0;
+    ras.invalid   = 1;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Compute the outline bounding box.                                     */
+  /*                                                                       */
+  static void
+  gray_compute_cbox( RAS_ARG )
+  {
+    FT_Outline*  outline = &ras.outline;
+    FT_Vector*   vec     = outline->points;
+    FT_Vector*   limit   = vec + outline->n_points;
+
+
+    if ( outline->n_points <= 0 )
+    {
+      ras.min_ex = ras.max_ex = 0;
+      ras.min_ey = ras.max_ey = 0;
+      return;
+    }
+
+    ras.min_ex = ras.max_ex = vec->x;
+    ras.min_ey = ras.max_ey = vec->y;
+
+    vec++;
+
+    for ( ; vec < limit; vec++ )
+    {
+      TPos  x = vec->x;
+      TPos  y = vec->y;
+
+
+      if ( x < ras.min_ex ) ras.min_ex = x;
+      if ( x > ras.max_ex ) ras.max_ex = x;
+      if ( y < ras.min_ey ) ras.min_ey = y;
+      if ( y > ras.max_ey ) ras.max_ey = y;
+    }
+
+    /* truncate the bounding box to integer pixels */
+    ras.min_ex = ras.min_ex >> 6;
+    ras.min_ey = ras.min_ey >> 6;
+    ras.max_ex = ( ras.max_ex + 63 ) >> 6;
+    ras.max_ey = ( ras.max_ey + 63 ) >> 6;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Record the current cell in the table.                                 */
+  /*                                                                       */
+  static void
+  gray_record_cell( RAS_ARG )
+  {
+    PCell  cell;
+
+
+    if ( !ras.invalid && ( ras.area | ras.cover ) )
+    {
+      if ( ras.num_cells >= ras.max_cells )
+        ft_longjmp( ras.jump_buffer, 1 );
+
+      cell        = ras.cells + ras.num_cells++;
+      cell->x     = (TCoord)(ras.ex - ras.min_ex);
+      cell->y     = (TCoord)(ras.ey - ras.min_ey);
+      cell->area  = ras.area;
+      cell->cover = ras.cover;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Set the current cell to a new position.                               */
+  /*                                                                       */
+  static void
+  gray_set_cell( RAS_ARG_ TCoord  ex,
+                          TCoord  ey )
+  {
+    int  invalid, record, clean;
+
+
+    /* Move the cell pointer to a new position.  We set the `invalid'      */
+    /* flag to indicate that the cell isn't part of those we're interested */
+    /* in during the render phase.  This means that:                       */
+    /*                                                                     */
+    /* . the new vertical position must be within min_ey..max_ey-1.        */
+    /* . the new horizontal position must be strictly less than max_ex     */
+    /*                                                                     */
+    /* Note that if a cell is to the left of the clipping region, it is    */
+    /* actually set to the (min_ex-1) horizontal position.                 */
+
+    record  = 0;
+    clean   = 1;
+
+    invalid = ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex );
+    if ( !invalid )
+    {
+      /* All cells that are on the left of the clipping region go to the */
+      /* min_ex - 1 horizontal position.                                 */
+      if ( ex < ras.min_ex )
+        ex = (TCoord)(ras.min_ex - 1);
+
+      /* if our position is new, then record the previous cell */
+      if ( ex != ras.ex || ey != ras.ey )
+        record = 1;
+      else
+        clean = ras.invalid;  /* do not clean if we didn't move from */
+                              /* a valid cell                        */
+    }
+
+    /* record the previous cell if needed (i.e., if we changed the cell */
+    /* position, of changed the `invalid' flag)                         */
+    if ( ras.invalid != invalid || record )
+      gray_record_cell( RAS_VAR );
+
+    if ( clean )
+    {
+      ras.area  = 0;
+      ras.cover = 0;
+    }
+
+    ras.invalid = invalid;
+    ras.ex      = ex;
+    ras.ey      = ey;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Start a new contour at a given cell.                                  */
+  /*                                                                       */
+  static void
+  gray_start_cell( RAS_ARG_  TCoord  ex,
+                             TCoord  ey )
+  {
+    if ( ex < ras.min_ex )
+      ex = (TCoord)(ras.min_ex - 1);
+
+    ras.area    = 0;
+    ras.cover   = 0;
+    ras.ex      = ex;
+    ras.ey      = ey;
+    ras.last_ey = SUBPIXELS( ey );
+    ras.invalid = 0;
+
+    gray_set_cell( RAS_VAR_ ex, ey );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Render a scanline as one or more cells.                               */
+  /*                                                                       */
+  static void
+  gray_render_scanline( RAS_ARG_  TCoord  ey,
+                                  TPos    x1,
+                                  TCoord  y1,
+                                  TPos    x2,
+                                  TCoord  y2 )
+  {
+    TCoord  ex1, ex2, fx1, fx2, delta;
+    long    p, first, dx;
+    int     incr, lift, mod, rem;
+
+
+    dx = x2 - x1;
+
+    ex1 = TRUNC( x1 ); /* if (ex1 >= ras.max_ex) ex1 = ras.max_ex-1; */
+    ex2 = TRUNC( x2 ); /* if (ex2 >= ras.max_ex) ex2 = ras.max_ex-1; */
+    fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) );
+    fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) );
+
+    /* trivial case.  Happens often */
+    if ( y1 == y2 )
+    {
+      gray_set_cell( RAS_VAR_ ex2, ey );
+      return;
+    }
+
+    /* everything is located in a single cell.  That is easy! */
+    /*                                                        */
+    if ( ex1 == ex2 )
+    {
+      delta      = y2 - y1;
+      ras.area  += (TArea)( fx1 + fx2 ) * delta;
+      ras.cover += delta;
+      return;
+    }
+
+    /* ok, we'll have to render a run of adjacent cells on the same */
+    /* scanline...                                                  */
+    /*                                                              */
+    p     = ( ONE_PIXEL - fx1 ) * ( y2 - y1 );
+    first = ONE_PIXEL;
+    incr  = 1;
+
+    if ( dx < 0 )
+    {
+      p     = fx1 * ( y2 - y1 );
+      first = 0;
+      incr  = -1;
+      dx    = -dx;
+    }
+
+    delta = (TCoord)( p / dx );
+    mod   = (TCoord)( p % dx );
+    if ( mod < 0 )
+    {
+      delta--;
+      mod += (TCoord)dx;
+    }
+
+    ras.area  += (TArea)( fx1 + first ) * delta;
+    ras.cover += delta;
+
+    ex1 += incr;
+    gray_set_cell( RAS_VAR_ ex1, ey );
+    y1  += delta;
+
+    if ( ex1 != ex2 )
+    {
+      p     = ONE_PIXEL * ( y2 - y1 + delta );
+      lift  = (TCoord)( p / dx );
+      rem   = (TCoord)( p % dx );
+      if ( rem < 0 )
+      {
+        lift--;
+        rem += (TCoord)dx;
+      }
+
+      mod -= dx;
+
+      while ( ex1 != ex2 )
+      {
+        delta = lift;
+        mod  += rem;
+        if ( mod >= 0 )
+        {
+          mod -= (TCoord)dx;
+          delta++;
+        }
+
+        ras.area  += (TArea)ONE_PIXEL * delta;
+        ras.cover += delta;
+        y1        += delta;
+        ex1       += incr;
+        gray_set_cell( RAS_VAR_ ex1, ey );
+      }
+    }
+
+    delta      = y2 - y1;
+    ras.area  += (TArea)( fx2 + ONE_PIXEL - first ) * delta;
+    ras.cover += delta;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Render a given line as a series of scanlines.                         */
+  /*                                                                       */
+  static void
+  gray_render_line( RAS_ARG_ TPos  to_x,
+                             TPos  to_y )
+  {
+    TCoord  ey1, ey2, fy1, fy2;
+    TPos    dx, dy, x, x2;
+    long    p, first;
+    int     delta, rem, mod, lift, incr;
+
+
+    ey1 = TRUNC( ras.last_ey );
+    ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */
+    fy1 = (TCoord)( ras.y - ras.last_ey );
+    fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) );
+
+    dx = to_x - ras.x;
+    dy = to_y - ras.y;
+
+    /* XXX: we should do something about the trivial case where dx == 0, */
+    /*      as it happens very often!                                    */
+
+    /* perform vertical clipping */
+    {
+      TCoord  min, max;
+
+
+      min = ey1;
+      max = ey2;
+      if ( ey1 > ey2 )
+      {
+        min = ey2;
+        max = ey1;
+      }
+      if ( min >= ras.max_ey || max < ras.min_ey )
+        goto End;
+    }
+
+    /* everything is on a single scanline */
+    if ( ey1 == ey2 )
+    {
+      gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 );
+      goto End;
+    }
+
+    /* vertical line - avoid calling gray_render_scanline */
+    incr = 1;
+
+    if ( dx == 0 )
+    {
+      TCoord  ex     = TRUNC( ras.x );
+      TCoord  two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 );
+      TPos    area;
+
+
+      first = ONE_PIXEL;
+      if ( dy < 0 )
+      {
+        first = 0;
+        incr  = -1;
+      }
+
+      delta      = (int)( first - fy1 );
+      ras.area  += (TArea)two_fx * delta;
+      ras.cover += delta;
+      ey1       += incr;
+
+      gray_set_cell( raster, ex, ey1 );
+
+      delta = (int)( first + first - ONE_PIXEL );
+      area  = (TArea)two_fx * delta;
+      while ( ey1 != ey2 )
+      {
+        ras.area  += area;
+        ras.cover += delta;
+        ey1       += incr;
+        gray_set_cell( raster, ex, ey1 );
+      }
+
+      delta      = (int)( fy2 - ONE_PIXEL + first );
+      ras.area  += (TArea)two_fx * delta;
+      ras.cover += delta;
+      goto End;
+    }
+
+    /* ok, we have to render several scanlines */
+    p     = ( ONE_PIXEL - fy1 ) * dx;
+    first = ONE_PIXEL;
+    incr  = 1;
+
+    if ( dy < 0 )
+    {
+      p     = fy1 * dx;
+      first = 0;
+      incr  = -1;
+      dy    = -dy;
+    }
+
+    delta = (int)( p / dy );
+    mod   = (int)( p % dy );
+    if ( mod < 0 )
+    {
+      delta--;
+      mod += (TCoord)dy;
+    }
+
+    x = ras.x + delta;
+    gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first );
+
+    ey1 += incr;
+    gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
+
+    if ( ey1 != ey2 )
+    {
+      p     = ONE_PIXEL * dx;
+      lift  = (int)( p / dy );
+      rem   = (int)( p % dy );
+      if ( rem < 0 )
+      {
+        lift--;
+        rem += (int)dy;
+      }
+      mod -= (int)dy;
+
+      while ( ey1 != ey2 )
+      {
+        delta = lift;
+        mod  += rem;
+        if ( mod >= 0 )
+        {
+          mod -= (int)dy;
+          delta++;
+        }
+
+        x2 = x + delta;
+        gray_render_scanline( RAS_VAR_ ey1, x,
+                                       (TCoord)( ONE_PIXEL - first ), x2,
+                                       (TCoord)first );
+        x = x2;
+
+        ey1 += incr;
+        gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 );
+      }
+    }
+
+    gray_render_scanline( RAS_VAR_ ey1, x,
+                                   (TCoord)( ONE_PIXEL - first ), to_x,
+                                   fy2 );
+
+  End:
+    ras.x       = to_x;
+    ras.y       = to_y;
+    ras.last_ey = SUBPIXELS( ey2 );
+  }
+
+
+  static void
+  gray_split_conic( FT_Vector*  base )
+  {
+    TPos  a, b;
+
+
+    base[4].x = base[2].x;
+    b = base[1].x;
+    a = base[3].x = ( base[2].x + b ) / 2;
+    b = base[1].x = ( base[0].x + b ) / 2;
+    base[2].x = ( a + b ) / 2;
+
+    base[4].y = base[2].y;
+    b = base[1].y;
+    a = base[3].y = ( base[2].y + b ) / 2;
+    b = base[1].y = ( base[0].y + b ) / 2;
+    base[2].y = ( a + b ) / 2;
+  }
+
+
+  static void
+  gray_render_conic( RAS_ARG_ FT_Vector*  control,
+                              FT_Vector*  to )
+  {
+    TPos        dx, dy;
+    int         top, level;
+    int*        levels;
+    FT_Vector*  arc;
+
+
+    dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 );
+    if ( dx < 0 )
+      dx = -dx;
+    dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 );
+    if ( dy < 0 )
+      dy = -dy;
+    if ( dx < dy )
+      dx = dy;
+
+    level = 1;
+    dx = dx / ras.conic_level;
+    while ( dx > 0 )
+    {
+      dx >>= 2;
+      level++;
+    }
+
+    /* a shortcut to speed things up */
+    if ( level <= 1 )
+    {
+      /* we compute the mid-point directly in order to avoid */
+      /* calling gray_split_conic()                          */
+      TPos   to_x, to_y, mid_x, mid_y;
+
+
+      to_x  = UPSCALE( to->x );
+      to_y  = UPSCALE( to->y );
+      mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4;
+      mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4;
+
+      gray_render_line( RAS_VAR_ mid_x, mid_y );
+      gray_render_line( RAS_VAR_ to_x, to_y );
+      return;
+    }
+
+    arc       = ras.bez_stack;
+    levels    = ras.lev_stack;
+    top       = 0;
+    levels[0] = level;
+
+    arc[0].x = UPSCALE( to->x );
+    arc[0].y = UPSCALE( to->y );
+    arc[1].x = UPSCALE( control->x );
+    arc[1].y = UPSCALE( control->y );
+    arc[2].x = ras.x;
+    arc[2].y = ras.y;
+
+    while ( top >= 0 )
+    {
+      level = levels[top];
+      if ( level > 1 )
+      {
+        /* check that the arc crosses the current band */
+        TPos  min, max, y;
+
+
+        min = max = arc[0].y;
+
+        y = arc[1].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+
+        y = arc[2].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+
+        if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+          goto Draw;
+
+        gray_split_conic( arc );
+        arc += 2;
+        top++;
+        levels[top] = levels[top - 1] = level - 1;
+        continue;
+      }
+
+    Draw:
+      {
+        TPos  to_x, to_y, mid_x, mid_y;
+
+
+        to_x  = arc[0].x;
+        to_y  = arc[0].y;
+        mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4;
+        mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4;
+
+        gray_render_line( RAS_VAR_ mid_x, mid_y );
+        gray_render_line( RAS_VAR_ to_x, to_y );
+
+        top--;
+        arc -= 2;
+      }
+    }
+    return;
+  }
+
+
+  static void
+  gray_split_cubic( FT_Vector*  base )
+  {
+    TPos  a, b, c, d;
+
+
+    base[6].x = base[3].x;
+    c = base[1].x;
+    d = base[2].x;
+    base[1].x = a = ( base[0].x + c ) / 2;
+    base[5].x = b = ( base[3].x + d ) / 2;
+    c = ( c + d ) / 2;
+    base[2].x = a = ( a + c ) / 2;
+    base[4].x = b = ( b + c ) / 2;
+    base[3].x = ( a + b ) / 2;
+
+    base[6].y = base[3].y;
+    c = base[1].y;
+    d = base[2].y;
+    base[1].y = a = ( base[0].y + c ) / 2;
+    base[5].y = b = ( base[3].y + d ) / 2;
+    c = ( c + d ) / 2;
+    base[2].y = a = ( a + c ) / 2;
+    base[4].y = b = ( b + c ) / 2;
+    base[3].y = ( a + b ) / 2;
+  }
+
+
+  static void
+  gray_render_cubic( RAS_ARG_ FT_Vector*  control1,
+                              FT_Vector*  control2,
+                              FT_Vector*  to )
+  {
+    TPos        dx, dy, da, db;
+    int         top, level;
+    int*        levels;
+    FT_Vector*  arc;
+
+
+    dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 );
+    if ( dx < 0 )
+      dx = -dx;
+    dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 );
+    if ( dy < 0 )
+      dy = -dy;
+    if ( dx < dy )
+      dx = dy;
+    da = dx;
+
+    dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x );
+    if ( dx < 0 )
+      dx = -dx;
+    dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y );
+    if ( dy < 0 )
+      dy = -dy;
+    if ( dx < dy )
+      dx = dy;
+    db = dx;
+
+    level = 1;
+    da    = da / ras.cubic_level;
+    db    = db / ras.conic_level;
+    while ( da > 0 || db > 0 )
+    {
+      da >>= 2;
+      db >>= 3;
+      level++;
+    }
+
+    if ( level <= 1 )
+    {
+      TPos   to_x, to_y, mid_x, mid_y;
+
+
+      to_x  = UPSCALE( to->x );
+      to_y  = UPSCALE( to->y );
+      mid_x = ( ras.x + to_x +
+                3 * UPSCALE( control1->x + control2->x ) ) / 8;
+      mid_y = ( ras.y + to_y +
+                3 * UPSCALE( control1->y + control2->y ) ) / 8;
+
+      gray_render_line( RAS_VAR_ mid_x, mid_y );
+      gray_render_line( RAS_VAR_ to_x, to_y );
+      return;
+    }
+
+    arc      = ras.bez_stack;
+    arc[0].x = UPSCALE( to->x );
+    arc[0].y = UPSCALE( to->y );
+    arc[1].x = UPSCALE( control2->x );
+    arc[1].y = UPSCALE( control2->y );
+    arc[2].x = UPSCALE( control1->x );
+    arc[2].y = UPSCALE( control1->y );
+    arc[3].x = ras.x;
+    arc[3].y = ras.y;
+
+    levels    = ras.lev_stack;
+    top       = 0;
+    levels[0] = level;
+
+    while ( top >= 0 )
+    {
+      level = levels[top];
+      if ( level > 1 )
+      {
+        /* check that the arc crosses the current band */
+        TPos  min, max, y;
+
+
+        min = max = arc[0].y;
+        y = arc[1].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+        y = arc[2].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+        y = arc[3].y;
+        if ( y < min ) min = y;
+        if ( y > max ) max = y;
+        if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 )
+          goto Draw;
+        gray_split_cubic( arc );
+        arc += 3;
+        top ++;
+        levels[top] = levels[top - 1] = level - 1;
+        continue;
+      }
+
+    Draw:
+      {
+        TPos  to_x, to_y, mid_x, mid_y;
+
+
+        to_x  = arc[0].x;
+        to_y  = arc[0].y;
+        mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8;
+        mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8;
+
+        gray_render_line( RAS_VAR_ mid_x, mid_y );
+        gray_render_line( RAS_VAR_ to_x, to_y );
+        top --;
+        arc -= 3;
+      }
+    }
+    return;
+  }
+
+
+  /* a macro comparing two cell pointers.  Returns true if a <= b. */
+#if 1
+
+#define PACK( a )          ( ( (long)(a)->y << 16 ) + (a)->x )
+#define LESS_THAN( a, b )  ( PACK( a ) < PACK( b ) )
+
+#else /* 1 */
+
+#define LESS_THAN( a, b )  ( (a)->y < (b)->y || \
+                             ( (a)->y == (b)->y && (a)->x < (b)->x ) )
+
+#endif /* 1 */
+
+#define SWAP_CELLS( a, b, temp )  do             \
+                                  {              \
+                                    temp = *(a); \
+                                    *(a) = *(b); \
+                                    *(b) = temp; \
+                                  } while ( 0 )
+#define DEBUG_SORT
+#define QUICK_SORT
+
+#ifdef SHELL_SORT
+
+  /* a simple shell sort algorithm that works directly on our */
+  /* cells table                                              */
+  static void
+  gray_shell_sort ( PCell  cells,
+                    int    count )
+  {
+    PCell  i, j, limit = cells + count;
+    TCell  temp;
+    int    gap;
+
+
+    /* compute initial gap */
+    for ( gap = 0; ++gap < count; gap *= 3 )
+      ;
+
+    while ( gap /= 3 )
+    {
+      for ( i = cells + gap; i < limit; i++ )
+      {
+        for ( j = i - gap; ; j -= gap )
+        {
+          PCell  k = j + gap;
+
+
+          if ( LESS_THAN( j, k ) )
+            break;
+
+          SWAP_CELLS( j, k, temp );
+
+          if ( j < cells + gap )
+            break;
+        }
+      }
+    }
+  }
+
+#endif /* SHELL_SORT */
+
+
+#ifdef QUICK_SORT
+
+  /* This is a non-recursive quicksort that directly process our cells     */
+  /* array.  It should be faster than calling the stdlib qsort(), and we   */
+  /* can even tailor our insertion threshold...                            */
+
+#define QSORT_THRESHOLD  9  /* below this size, a sub-array will be sorted */
+                            /* through a normal insertion sort             */
+
+  static void
+  gray_quick_sort( PCell  cells,
+                   int    count )
+  {
+    PCell   stack[40];  /* should be enough ;-) */
+    PCell*  top;        /* top of stack */
+    PCell   base, limit;
+    TCell   temp;
+
+
+    limit = cells + count;
+    base  = cells;
+    top   = stack;
+
+    for (;;)
+    {
+      int    len = (int)( limit - base );
+      PCell  i, j, pivot;
+
+
+      if ( len > QSORT_THRESHOLD )
+      {
+        /* we use base + len/2 as the pivot */
+        pivot = base + len / 2;
+        SWAP_CELLS( base, pivot, temp );
+
+        i = base + 1;
+        j = limit - 1;
+
+        /* now ensure that *i <= *base <= *j */
+        if ( LESS_THAN( j, i ) )
+          SWAP_CELLS( i, j, temp );
+
+        if ( LESS_THAN( base, i ) )
+          SWAP_CELLS( base, i, temp );
+
+        if ( LESS_THAN( j, base ) )
+          SWAP_CELLS( base, j, temp );
+
+        for (;;)
+        {
+          do i++; while ( LESS_THAN( i, base ) );
+          do j--; while ( LESS_THAN( base, j ) );
+
+          if ( i > j )
+            break;
+
+          SWAP_CELLS( i, j, temp );
+        }
+
+        SWAP_CELLS( base, j, temp );
+
+        /* now, push the largest sub-array */
+        if ( j - base > limit - i )
+        {
+          top[0] = base;
+          top[1] = j;
+          base   = i;
+        }
+        else
+        {
+          top[0] = i;
+          top[1] = limit;
+          limit  = j;
+        }
+        top += 2;
+      }
+      else
+      {
+        /* the sub-array is small, perform insertion sort */
+        j = base;
+        i = j + 1;
+
+        for ( ; i < limit; j = i, i++ )
+        {
+          for ( ; LESS_THAN( j + 1, j ); j-- )
+          {
+            SWAP_CELLS( j + 1, j, temp );
+            if ( j == base )
+              break;
+          }
+        }
+        if ( top > stack )
+        {
+          top  -= 2;
+          base  = top[0];
+          limit = top[1];
+        }
+        else
+          break;
+      }
+    }
+  }
+
+#endif /* QUICK_SORT */
+
+
+#ifdef DEBUG_GRAYS
+#ifdef DEBUG_SORT
+
+  static int
+  gray_check_sort( PCell  cells,
+                   int    count )
+  {
+    PCell  p, q;
+
+
+    for ( p = cells + count - 2; p >= cells; p-- )
+    {
+      q = p + 1;
+      if ( !LESS_THAN( p, q ) )
+        return 0;
+    }
+    return 1;
+  }
+
+#endif /* DEBUG_SORT */
+#endif /* DEBUG_GRAYS */
+
+
+  static int
+  gray_move_to( FT_Vector*  to,
+                FT_Raster   raster )
+  {
+    TPos  x, y;
+
+
+    /* record current cell, if any */
+    gray_record_cell( (PRaster)raster );
+
+    /* start to a new position */
+    x = UPSCALE( to->x );
+    y = UPSCALE( to->y );
+
+    gray_start_cell( (PRaster)raster, TRUNC( x ), TRUNC( y ) );
+
+    ((PRaster)raster)->x = x;
+    ((PRaster)raster)->y = y;
+    return 0;
+  }
+
+
+  static int
+  gray_line_to( FT_Vector*  to,
+                FT_Raster   raster )
+  {
+    gray_render_line( (PRaster)raster,
+                      UPSCALE( to->x ), UPSCALE( to->y ) );
+    return 0;
+  }
+
+
+  static int
+  gray_conic_to( FT_Vector*  control,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    gray_render_conic( (PRaster)raster, control, to );
+    return 0;
+  }
+
+
+  static int
+  gray_cubic_to( FT_Vector*  control1,
+                 FT_Vector*  control2,
+                 FT_Vector*  to,
+                 FT_Raster   raster )
+  {
+    gray_render_cubic( (PRaster)raster, control1, control2, to );
+    return 0;
+  }
+
+
+  static void
+  gray_render_span( int       y,
+                    int       count,
+                    FT_Span*  spans,
+                    PRaster   raster )
+  {
+    unsigned char*  p;
+    FT_Bitmap*      map = &raster->target;
+
+
+    /* first of all, compute the scanline offset */
+    p = (unsigned char*)map->buffer - y * map->pitch;
+    if ( map->pitch >= 0 )
+      p += ( map->rows - 1 ) * map->pitch;
+
+    for ( ; count > 0; count--, spans++ )
+    {
+      unsigned char  coverage = spans->coverage;
+
+
+#ifdef GRAYS_USE_GAMMA
+      coverage = raster->gamma[coverage];
+#endif
+
+      if ( coverage )
+#if 1
+        FT_MEM_SET( p + spans->x, (unsigned char)coverage, spans->len );
+#else /* 1 */
+      {
+        q     = p + spans->x;
+        limit = q + spans->len;
+        for ( ; q < limit; q++ )
+          q[0] = (unsigned char)coverage;
+      }
+#endif /* 1 */
+    }
+  }
+
+
+#ifdef DEBUG_GRAYS
+
+#include <stdio.h>
+
+  static void
+  gray_dump_cells( RAS_ARG )
+  {
+    PCell  cell, limit;
+    int    y = -1;
+
+
+    cell  = ras.cells;
+    limit = cell + ras.num_cells;
+
+    for ( ; cell < limit; cell++ )
+    {
+      if ( cell->y != y )
+      {
+        fprintf( stderr, "\n%2d: ", cell->y );
+        y = cell->y;
+      }
+      fprintf( stderr, "[%d %d %d]",
+               cell->x, cell->area, cell->cover );
+    }
+    fprintf(stderr, "\n" );
+  }
+
+#endif /* DEBUG_GRAYS */
+
+
+  static void
+  gray_hline( RAS_ARG_ TCoord  x,
+                       TCoord  y,
+                       TPos    area,
+                       int     acount )
+  {
+    FT_Span*   span;
+    int        count;
+    int        coverage;
+
+
+    /* compute the coverage line's coverage, depending on the    */
+    /* outline fill rule                                         */
+    /*                                                           */
+    /* the coverage percentage is area/(PIXEL_BITS*PIXEL_BITS*2) */
+    /*                                                           */
+    coverage = (int)( area >> ( PIXEL_BITS * 2 + 1 - 8 ) );
+                                                    /* use range 0..256 */
+    if ( coverage < 0 )
+      coverage = -coverage;
+
+    if ( ras.outline.flags & FT_OUTLINE_EVEN_ODD_FILL )
+    {
+      coverage &= 511;
+
+      if ( coverage > 256 )
+        coverage = 512 - coverage;
+      else if ( coverage == 256 )
+        coverage = 255;
+    }
+    else
+    {
+      /* normal non-zero winding rule */
+      if ( coverage >= 256 )
+        coverage = 255;
+    }
+
+    y += (TCoord)ras.min_ey;
+    x += (TCoord)ras.min_ex;
+
+    if ( coverage )
+    {
+      /* see if we can add this span to the current list */
+      count = ras.num_gray_spans;
+      span  = ras.gray_spans + count - 1;
+      if ( count > 0                          &&
+           ras.span_y == y                    &&
+           (int)span->x + span->len == (int)x &&
+           span->coverage == coverage )
+      {
+        span->len = (unsigned short)( span->len + acount );
+        return;
+      }
+
+      if ( ras.span_y != y || count >= FT_MAX_GRAY_SPANS )
+      {
+        if ( ras.render_span && count > 0 )
+          ras.render_span( ras.span_y, count, ras.gray_spans,
+                           ras.render_span_data );
+        /* ras.render_span( span->y, ras.gray_spans, count ); */
+
+#ifdef DEBUG_GRAYS
+
+        if ( ras.span_y >= 0 )
+        {
+          int  n;
+
+
+          fprintf( stderr, "y=%3d ", ras.span_y );
+          span = ras.gray_spans;
+          for ( n = 0; n < count; n++, span++ )
+            fprintf( stderr, "[%d..%d]:%02x ",
+                     span->x, span->x + span->len - 1, span->coverage );
+          fprintf( stderr, "\n" );
+        }
+
+#endif /* DEBUG_GRAYS */
+
+        ras.num_gray_spans = 0;
+        ras.span_y         = y;
+
+        count = 0;
+        span  = ras.gray_spans;
+      }
+      else
+        span++;
+
+      /* add a gray span to the current list */
+      span->x        = (short)x;
+      span->len      = (unsigned short)acount;
+      span->coverage = (unsigned char)coverage;
+      ras.num_gray_spans++;
+    }
+  }
+
+
+  static void
+  gray_sweep( RAS_ARG_ FT_Bitmap*  target )
+  {
+    TCoord  x, y, cover;
+    TArea   area;
+    PCell   start, cur, limit;
+
+    FT_UNUSED( target );
+
+
+    if ( ras.num_cells == 0 )
+      return;
+
+    cur   = ras.cells;
+    limit = cur + ras.num_cells;
+
+    cover              = 0;
+    ras.span_y         = -1;
+    ras.num_gray_spans = 0;
+
+    for (;;)
+    {
+      start  = cur;
+      y      = start->y;
+      x      = start->x;
+
+      area   = start->area;
+      cover += start->cover;
+
+      /* accumulate all start cells */
+      for (;;)
+      {
+        ++cur;
+        if ( cur >= limit || cur->y != start->y || cur->x != start->x )
+          break;
+
+        area  += cur->area;
+        cover += cur->cover;
+      }
+
+      /* if the start cell has a non-null area, we must draw an */
+      /* individual gray pixel there                            */
+      if ( area && x >= 0 )
+      {
+        gray_hline( RAS_VAR_ x, y, cover * ( ONE_PIXEL * 2 ) - area, 1 );
+        x++;
+      }
+
+      if ( x < 0 )
+        x = 0;
+
+      if ( cur < limit && start->y == cur->y )
+      {
+        /* draw a gray span between the start cell and the current one */
+        if ( cur->x > x )
+          gray_hline( RAS_VAR_ x, y,
+                      cover * ( ONE_PIXEL * 2 ), cur->x - x );
+      }
+      else
+      {
+        /* draw a gray span until the end of the clipping region */
+        if ( cover && x < ras.max_ex - ras.min_ex )
+          gray_hline( RAS_VAR_ x, y,
+                      cover * ( ONE_PIXEL * 2 ),
+                      (int)( ras.max_ex - x - ras.min_ex ) );
+        cover = 0;
+      }
+
+      if ( cur >= limit )
+        break;
+    }
+
+    if ( ras.render_span && ras.num_gray_spans > 0 )
+      ras.render_span( ras.span_y, ras.num_gray_spans,
+                       ras.gray_spans, ras.render_span_data );
+
+#ifdef DEBUG_GRAYS
+
+    {
+      int       n;
+      FT_Span*  span;
+
+
+      fprintf( stderr, "y=%3d ", ras.span_y );
+      span = ras.gray_spans;
+      for ( n = 0; n < ras.num_gray_spans; n++, span++ )
+        fprintf( stderr, "[%d..%d]:%02x ",
+                 span->x, span->x + span->len - 1, span->coverage );
+      fprintf( stderr, "\n" );
+    }
+
+#endif /* DEBUG_GRAYS */
+
+  }
+
+
+#ifdef _STANDALONE_
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  The following function should only compile in stand_alone mode,      */
+  /*  i.e., when building this component without the rest of FreeType.     */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_Outline_Decompose                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Walks over an outline's structure to decompose it into individual  */
+  /*    segments and Bezier arcs.  This function is also able to emit      */
+  /*    `move to' and `close to' operations to indicate the start and end  */
+  /*    of new contours in the outline.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    outline        :: A pointer to the source target.                  */
+  /*                                                                       */
+  /*    func_interface :: A table of `emitters', i.e,. function pointers   */
+  /*                      called during decomposition to indicate path     */
+  /*                      operations.                                      */
+  /*                                                                       */
+  /*    user           :: A typeless pointer which is passed to each       */
+  /*                      emitter during the decomposition.  It can be     */
+  /*                      used to store the state during the               */
+  /*                      decomposition.                                   */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Error code.  0 means sucess.                                       */
+  /*                                                                       */
+  static
+  int  FT_Outline_Decompose( FT_Outline*              outline,
+                             const FT_Outline_Funcs*  func_interface,
+                             void*                    user )
+  {
+#undef SCALED
+#if 0
+#define SCALED( x )  ( ( (x) << shift ) - delta )
+#else
+#define SCALED( x )  (x)
+#endif
+
+    FT_Vector   v_last;
+    FT_Vector   v_control;
+    FT_Vector   v_start;
+
+    FT_Vector*  point;
+    FT_Vector*  limit;
+    char*       tags;
+
+    int   n;         /* index of contour in outline     */
+    int   first;     /* index of first point in contour */
+    int   error;
+    char  tag;       /* current point's state           */
+
+#if 0
+    int   shift = func_interface->shift;
+    TPos  delta = func_interface->delta;
+#endif
+
+
+    first = 0;
+
+    for ( n = 0; n < outline->n_contours; n++ )
+    {
+      int  last;  /* index of last point in contour */
+
+
+      last  = outline->contours[n];
+      limit = outline->points + last;
+
+      v_start = outline->points[first];
+      v_last  = outline->points[last];
+
+      v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
+      v_last.x  = SCALED( v_last.x );  v_last.y  = SCALED( v_last.y );
+
+      v_control = v_start;
+
+      point = outline->points + first;
+      tags  = outline->tags  + first;
+      tag   = FT_CURVE_TAG( tags[0] );
+
+      /* A contour cannot start with a cubic control point! */
+      if ( tag == FT_CURVE_TAG_CUBIC )
+        goto Invalid_Outline;
+
+      /* check first point to determine origin */
+      if ( tag == FT_CURVE_TAG_CONIC )
+      {
+        /* first point is conic control.  Yes, this happens. */
+        if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
+        {
+          /* start at last point if it is on the curve */
+          v_start = v_last;
+          limit--;
+        }
+        else
+        {
+          /* if both first and last points are conic,         */
+          /* start at their middle and record its position    */
+          /* for closure                                      */
+          v_start.x = ( v_start.x + v_last.x ) / 2;
+          v_start.y = ( v_start.y + v_last.y ) / 2;
+
+          v_last = v_start;
+        }
+        point--;
+        tags--;
+      }
+
+      error = func_interface->move_to( &v_start, user );
+      if ( error )
+        goto Exit;
+
+      while ( point < limit )
+      {
+        point++;
+        tags++;
+
+        tag = FT_CURVE_TAG( tags[0] );
+        switch ( tag )
+        {
+        case FT_CURVE_TAG_ON:  /* emit a single line_to */
+          {
+            FT_Vector  vec;
+
+
+            vec.x = SCALED( point->x );
+            vec.y = SCALED( point->y );
+
+            error = func_interface->line_to( &vec, user );
+            if ( error )
+              goto Exit;
+            continue;
+          }
+
+        case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
+          {
+            v_control.x = SCALED( point->x );
+            v_control.y = SCALED( point->y );
+
+          Do_Conic:
+            if ( point < limit )
+            {
+              FT_Vector  vec;
+              FT_Vector  v_middle;
+
+
+              point++;
+              tags++;
+              tag = FT_CURVE_TAG( tags[0] );
+
+              vec.x = SCALED( point->x );
+              vec.y = SCALED( point->y );
+
+              if ( tag == FT_CURVE_TAG_ON )
+              {
+                error = func_interface->conic_to( &v_control, &vec, user );
+                if ( error )
+                  goto Exit;
+                continue;
+              }
+
+              if ( tag != FT_CURVE_TAG_CONIC )
+                goto Invalid_Outline;
+
+              v_middle.x = ( v_control.x + vec.x ) / 2;
+              v_middle.y = ( v_control.y + vec.y ) / 2;
+
+              error = func_interface->conic_to( &v_control, &v_middle, user );
+              if ( error )
+                goto Exit;
+
+              v_control = vec;
+              goto Do_Conic;
+            }
+
+            error = func_interface->conic_to( &v_control, &v_start, user );
+            goto Close;
+          }
+
+        default:  /* FT_CURVE_TAG_CUBIC */
+          {
+            FT_Vector  vec1, vec2;
+
+
+            if ( point + 1 > limit                             ||
+                 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
+              goto Invalid_Outline;
+
+            point += 2;
+            tags  += 2;
+
+            vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
+            vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
+
+            if ( point <= limit )
+            {
+              FT_Vector  vec;
+
+
+              vec.x = SCALED( point->x );
+              vec.y = SCALED( point->y );
+
+              error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
+              if ( error )
+                goto Exit;
+              continue;
+            }
+
+            error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
+            goto Close;
+          }
+        }
+      }
+
+      /* close the contour with a line segment */
+      error = func_interface->line_to( &v_start, user );
+
+   Close:
+      if ( error )
+        goto Exit;
+
+      first = last + 1;
+    }
+
+    return 0;
+
+  Exit:
+    return error;
+
+  Invalid_Outline:
+    return ErrRaster_Invalid_Outline;
+  }
+
+#endif /* _STANDALONE_ */
+
+
+  typedef struct  TBand_
+  {
+    TPos  min, max;
+
+  } TBand;
+
+
+  static int
+  gray_convert_glyph_inner( RAS_ARG )
+  {
+    static
+    const FT_Outline_Funcs  func_interface =
+    {
+      (FT_Outline_MoveTo_Func) gray_move_to,
+      (FT_Outline_LineTo_Func) gray_line_to,
+      (FT_Outline_ConicTo_Func)gray_conic_to,
+      (FT_Outline_CubicTo_Func)gray_cubic_to,
+      0,
+      0
+    };
+
+    volatile int  error = 0;
+
+    if ( ft_setjmp( ras.jump_buffer ) == 0 )
+    {
+      error = FT_Outline_Decompose( &ras.outline, &func_interface, &ras );
+      gray_record_cell( RAS_VAR );
+    }
+    else
+    {
+      error = ErrRaster_MemoryOverflow;
+    }
+
+    return error;
+  }
+
+
+  static int
+  gray_convert_glyph( RAS_ARG )
+  {
+    TBand            bands[40];
+    volatile TBand*  band;
+    volatile int     n, num_bands;
+    volatile TPos    min, max, max_y;
+    FT_BBox*         clip;
+
+
+    /* Set up state in the raster object */
+    gray_compute_cbox( RAS_VAR );
+
+    /* clip to target bitmap, exit if nothing to do */
+    clip = &ras.clip_box;
+
+    if ( ras.max_ex <= clip->xMin || ras.min_ex >= clip->xMax ||
+         ras.max_ey <= clip->yMin || ras.min_ey >= clip->yMax )
+      return 0;
+
+    if ( ras.min_ex < clip->xMin ) ras.min_ex = clip->xMin;
+    if ( ras.min_ey < clip->yMin ) ras.min_ey = clip->yMin;
+
+    if ( ras.max_ex > clip->xMax ) ras.max_ex = clip->xMax;
+    if ( ras.max_ey > clip->yMax ) ras.max_ey = clip->yMax;
+
+    /* simple heuristic used to speed-up the bezier decomposition -- see */
+    /* the code in gray_render_conic() and gray_render_cubic() for more  */
+    /* details                                                           */
+    ras.conic_level = 32;
+    ras.cubic_level = 16;
+
+    {
+      int level = 0;
+
+
+      if ( ras.max_ex > 24 || ras.max_ey > 24 )
+        level++;
+      if ( ras.max_ex > 120 || ras.max_ey > 120 )
+        level++;
+
+      ras.conic_level <<= level;
+      ras.cubic_level <<= level;
+    }
+
+    /* setup vertical bands */
+    num_bands = (int)( ( ras.max_ey - ras.min_ey ) / ras.band_size );
+    if ( num_bands == 0 )  num_bands = 1;
+    if ( num_bands >= 39 ) num_bands = 39;
+
+    ras.band_shoot = 0;
+
+    min   = ras.min_ey;
+    max_y = ras.max_ey;
+
+    for ( n = 0; n < num_bands; n++, min = max )
+    {
+      max = min + ras.band_size;
+      if ( n == num_bands - 1 || max > max_y )
+        max = max_y;
+
+      bands[0].min = min;
+      bands[0].max = max;
+      band         = bands;
+
+      while ( band >= bands )
+      {
+        TPos  bottom, top, middle;
+        int   error;
+
+
+        ras.num_cells = 0;
+        ras.invalid   = 1;
+        ras.min_ey    = band->min;
+        ras.max_ey    = band->max;
+
+#if 1
+        error = gray_convert_glyph_inner( RAS_VAR );
+#else
+        error = FT_Outline_Decompose( outline, &func_interface, &ras ) ||
+                gray_record_cell( RAS_VAR );
+#endif
+
+        if ( !error )
+        {
+#ifdef SHELL_SORT
+          gray_shell_sort( ras.cells, ras.num_cells );
+#else
+          gray_quick_sort( ras.cells, ras.num_cells );
+#endif
+
+#ifdef DEBUG_GRAYS
+          gray_check_sort( ras.cells, ras.num_cells );
+          gray_dump_cells( RAS_VAR );
+#endif
+
+          gray_sweep( RAS_VAR_  &ras.target );
+          band--;
+          continue;
+        }
+        else if ( error != ErrRaster_MemoryOverflow )
+          return 1;
+
+        /* render pool overflow, we will reduce the render band by half */
+        bottom = band->min;
+        top    = band->max;
+        middle = bottom + ( ( top - bottom ) >> 1 );
+
+        /* waoow! This is too complex for a single scanline, something */
+        /* must be really rotten here!                                 */
+        if ( middle == bottom )
+        {
+#ifdef DEBUG_GRAYS
+          fprintf( stderr, "Rotten glyph!\n" );
+#endif
+          return 1;
+        }
+
+        if ( bottom-top >= ras.band_size )
+          ras.band_shoot++;
+
+        band[1].min = bottom;
+        band[1].max = middle;
+        band[0].min = middle;
+        band[0].max = top;
+        band++;
+      }
+    }
+
+    if ( ras.band_shoot > 8 && ras.band_size > 16 )
+      ras.band_size = ras.band_size / 2;
+
+    return 0;
+  }
+
+
+  extern int
+  gray_raster_render( PRaster            raster,
+                      FT_Raster_Params*  params )
+  {
+    FT_Outline*  outline = (FT_Outline*)params->source;
+    FT_Bitmap*   target_map = params->target;
+
+
+    if ( !raster || !raster->cells || !raster->max_cells )
+      return -1;
+
+    /* return immediately if the outline is empty */
+    if ( outline->n_points == 0 || outline->n_contours <= 0 )
+      return 0;
+
+    if ( !outline || !outline->contours || !outline->points )
+      return ErrRaster_Invalid_Outline;
+
+    if ( outline->n_points !=
+           outline->contours[outline->n_contours - 1] + 1 )
+      return ErrRaster_Invalid_Outline;
+
+    /* if direct mode is not set, we must have a target bitmap */
+    if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 &&
+         ( !target_map || !target_map->buffer )         )
+      return -1;
+
+    /* this version does not support monochrome rendering */
+    if ( !( params->flags & FT_RASTER_FLAG_AA ) )
+      return ErrRaster_Invalid_Mode;
+
+    /* compute clipping box */
+    if ( ( params->flags & FT_RASTER_FLAG_DIRECT ) == 0 )
+    {
+      /* compute clip box from target pixmap */
+      ras.clip_box.xMin = 0;
+      ras.clip_box.yMin = 0;
+      ras.clip_box.xMax = target_map->width;
+      ras.clip_box.yMax = target_map->rows;
+    }
+    else if ( params->flags & FT_RASTER_FLAG_CLIP )
+    {
+      ras.clip_box = params->clip_box;
+    }
+    else
+    {
+      ras.clip_box.xMin = -32768L;
+      ras.clip_box.yMin = -32768L;
+      ras.clip_box.xMax =  32767L;
+      ras.clip_box.yMax =  32767L;
+    }
+
+    ras.outline   = *outline;
+    ras.num_cells = 0;
+    ras.invalid   = 1;
+
+    if ( target_map )
+      ras.target = *target_map;
+
+    ras.render_span      = (FT_Raster_Span_Func)gray_render_span;
+    ras.render_span_data = &ras;
+
+    if ( params->flags & FT_RASTER_FLAG_DIRECT )
+    {
+      ras.render_span      = (FT_Raster_Span_Func)params->gray_spans;
+      ras.render_span_data = params->user;
+    }
+
+    return gray_convert_glyph( (PRaster)raster );
+  }
+
+
+  /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+  /****                         a static object.                  *****/
+
+#ifdef GRAYS_USE_GAMMA
+
+  /* initialize the "gamma" table. Yes, this is really a crummy function */
+  /* but the results look pretty good for something that simple.         */
+  /*                                                                     */
+#define M_MAX  255
+#define M_X    128
+#define M_Y    192
+
+  static void
+  grays_init_gamma( PRaster  raster )
+  {
+    unsigned int  x, a;
+
+
+    for ( x = 0; x < 256; x++ )
+    {
+      if ( x <= M_X )
+        a = ( x * M_Y + M_X / 2) / M_X;
+      else
+        a = M_Y + ( ( x - M_X ) * ( M_MAX - M_Y ) +
+            ( M_MAX - M_X ) / 2 ) / ( M_MAX - M_X );
+
+      raster->gamma[x] = (unsigned char)a;
+    }
+  }
+
+#endif /* GRAYS_USE_GAMMA */
+
+#ifdef _STANDALONE_
+
+  static int
+  gray_raster_new( void*       memory,
+                   FT_Raster*  araster )
+  {
+    static TRaster  the_raster;
+
+    FT_UNUSED( memory );
+
+
+    *araster = (FT_Raster)&the_raster;
+    FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
+
+#ifdef GRAYS_USE_GAMMA
+    grays_init_gamma( (PRaster)*araster );
+#endif
+
+    return 0;
+  }
+
+
+  static void
+  gray_raster_done( FT_Raster  raster )
+  {
+    /* nothing */
+    FT_UNUSED( raster );
+  }
+
+#else /* _STANDALONE_ */
+
+  static int
+  gray_raster_new( FT_Memory   memory,
+                   FT_Raster*  araster )
+  {
+    FT_Error  error;
+    PRaster   raster;
+
+
+    *araster = 0;
+    if ( !FT_ALLOC( raster, sizeof ( TRaster ) ) )
+    {
+      raster->memory = memory;
+      *araster = (FT_Raster)raster;
+
+#ifdef GRAYS_USE_GAMMA
+      grays_init_gamma( raster );
+#endif
+    }
+
+    return error;
+  }
+
+
+  static void
+  gray_raster_done( FT_Raster  raster )
+  {
+    FT_Memory  memory = (FT_Memory)((PRaster)raster)->memory;
+
+
+    FT_FREE( raster );
+  }
+
+#endif /* _STANDALONE_ */
+
+
+  static void
+  gray_raster_reset( FT_Raster    raster,
+                     const char*  pool_base,
+                     long         pool_size )
+  {
+    PRaster  rast = (PRaster)raster;
+
+
+    if ( raster && pool_base && pool_size >= 4096 )
+      gray_init_cells( rast, (char*)pool_base, pool_size );
+
+    rast->band_size  = (int)( ( pool_size / sizeof ( TCell ) ) / 8 );
+  }
+
+
+  const FT_Raster_Funcs  ft_grays_raster =
+  {
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Raster_New_Func)     gray_raster_new,
+    (FT_Raster_Reset_Func)   gray_raster_reset,
+    (FT_Raster_Set_Mode_Func)0,
+    (FT_Raster_Render_Func)  gray_raster_render,
+    (FT_Raster_Done_Func)    gray_raster_done
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftgrays.h
@@ -1,0 +1,57 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgrays.h                                                              */
+/*                                                                         */
+/*    FreeType smooth renderer declaration                                 */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __FTGRAYS_H__
+#define __FTGRAYS_H__
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+
+#ifdef _STANDALONE_
+#include "ftimage.h"
+#else
+#include <ft2build.h>
+#include FT_IMAGE_H
+#endif
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* To make ftgrays.h independent from configuration files we check       */
+  /* whether FT_EXPORT_VAR has been defined already.                       */
+  /*                                                                       */
+  /* On some systems and compilers (Win32 mostly), an extra keyword is     */
+  /* necessary to compile the library as a DLL.                            */
+  /*                                                                       */
+#ifndef FT_EXPORT_VAR
+#define FT_EXPORT_VAR( x )  extern  x
+#endif
+
+  FT_EXPORT_VAR( const FT_Raster_Funcs )  ft_grays_raster;
+
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif /* __FTGRAYS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftgzip.c
@@ -1,0 +1,561 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgzip.c                                                               */
+/*                                                                         */
+/*    FreeType support for .gz compressed fileds                           */
+/*                                                                         */
+/*  this optional component relies on zlib. It should mainly be used to    */
+/*  parse compressed PCF fonts, as found with many X11 server              */
+/*  distributions.                                                         */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+#include <string.h>
+
+#ifdef FT_CONFIG_OPTION_USE_ZLIB
+
+#ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB
+
+#  include "zlib.h"
+
+#else /* !SYSTEM_ZLIB */
+
+ /* in this case, we include our own modified sources of the ZLib   */
+ /* within the "ftgzip" component. The modifications were necessary */
+ /* to #include all files without conflicts, as well as preventing  */
+ /* the definition of "extern" functions that may cause linking     */
+ /* conflicts when a program is linked with both FreeType and the   */
+ /* original ZLib                                                   */
+
+#  define  NO_DUMMY_DECL
+#  define  BUILDFIXED    /* save code size */
+#  define  MY_ZCALLOC
+
+#  include "zlib.h"
+
+#    undef   SLOW
+#    define  SLOW  1  /* we can't use asm-optimized sources here !! */
+
+#    include "zutil.c"
+#    include "inftrees.c"
+#    include "infcodes.c"
+#    include "infutil.c"
+#    include "infblock.c"
+#    include "inflate.c"
+#    include "adler32.c"
+
+#endif /* !SYSTEM_ZLIB */
+
+
+/***************************************************************************/
+/***************************************************************************/
+/*****                                                                 *****/
+/*****            Z L I B   M E M O R Y   M A N A G E M E N T          *****/
+/*****                                                                 *****/
+/***************************************************************************/
+/***************************************************************************/
+
+ /* it's better to use FreeType memory routines instead of raw 'malloc/free' */
+
+
+ static voidpf
+ ft_gzip_alloc( FT_Memory  memory,
+                uInt       items,
+                uInt       size )
+ {
+   FT_ULong    sz = (FT_ULong)size * items;
+   FT_Pointer  p;
+
+   FT_MEM_ALLOC( p, sz );
+
+   return (voidpf) p;
+ }
+
+
+ static void
+ ft_gzip_free( FT_Memory  memory,
+               voidpf     address )
+ {
+   FT_MEM_FREE( address );
+ }
+
+
+#ifndef FT_CONFIG_OPTION_SYSTEM_ZLIB
+
+ local voidpf
+ zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+ {
+   return ft_gzip_alloc( opaque, items, size );
+ }
+
+ local void
+ zcfree( voidpf  opaque,
+         voidpf  ptr )
+ {
+   ft_gzip_free( opaque, ptr );
+ }
+
+#endif /* !SYSTEM_ZLIB */
+
+
+/***************************************************************************/
+/***************************************************************************/
+/*****                                                                 *****/
+/*****               Z L I B   F I L E   D E S C R I P T O R           *****/
+/*****                                                                 *****/
+/***************************************************************************/
+/***************************************************************************/
+
+#define  FT_GZIP_BUFFER_SIZE          4096
+
+  typedef struct FT_GZipFileRec_
+  {
+    FT_Stream    source;         /* parent/source stream        */
+    FT_Stream    stream;         /* embedding stream            */
+    FT_Memory    memory;         /* memory allocator            */
+    z_stream     zstream;        /* zlib input stream           */
+
+    FT_ULong     start;          /* starting position, after .gz header */
+    FT_Byte      input[ FT_GZIP_BUFFER_SIZE ];  /* input read buffer */
+
+    FT_Byte      buffer[ FT_GZIP_BUFFER_SIZE ];  /* output buffer      */
+    FT_ULong     pos;                            /* position in output */
+    FT_Byte*     cursor;
+    FT_Byte*     limit;
+
+  } FT_GZipFileRec, *FT_GZipFile;
+
+
+/* gzip flag byte */
+#define FT_GZIP_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define FT_GZIP_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define FT_GZIP_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define FT_GZIP_ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define FT_GZIP_COMMENT      0x10 /* bit 4 set: file comment present */
+#define FT_GZIP_RESERVED     0xE0 /* bits 5..7: reserved */
+
+
+ /* check and skip .gz header - we don't support "transparent" compression */
+  static FT_Error
+  ft_gzip_check_header( FT_Stream  stream )
+  {
+    FT_Error  error;
+    FT_Byte   head[4];
+
+    if ( FT_STREAM_SEEK( 0 )       ||
+         FT_STREAM_READ( head, 4 ) )
+      goto Exit;
+
+    /* head[0] && head[1] are the magic numbers     */
+    /* head[2] is the method, and head[3] the flags */
+    if ( head[0] != 0x1f              ||
+         head[1] != 0x8b              ||
+         head[2] != Z_DEFLATED        ||
+        (head[3] & FT_GZIP_RESERVED)  )
+    {
+      error = FT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    /* skip time, xflags and os code */
+    (void)FT_STREAM_SKIP( 6 );
+
+    /* skip the extra field */
+    if ( head[3] && FT_GZIP_EXTRA_FIELD )
+    {
+      FT_UInt  len;
+
+      if ( FT_READ_USHORT_LE( len ) ||
+           FT_STREAM_SKIP( len )    )
+        goto Exit;
+    }
+
+    /* skip original file name */
+    if ( head[3] && FT_GZIP_ORIG_NAME )
+      for (;;)
+      {
+        FT_UInt  c;
+
+        if ( FT_READ_BYTE( c) )
+          goto Exit;
+
+        if ( c == 0 )
+          break;
+      }
+
+    /* skip .gz comment */
+    if ( head[3] & FT_GZIP_COMMENT )
+      for (;;)
+      {
+        FT_UInt  c;
+
+        if ( FT_READ_BYTE( c) )
+          goto Exit;
+
+        if ( c == 0 )
+          break;
+      }
+
+    /* skip CRC */
+    if ( head[3] & FT_GZIP_HEAD_CRC )
+      if ( FT_STREAM_SKIP( 2 ) )
+        goto Exit;
+
+  Exit:
+    return error;
+  }
+
+
+
+  static FT_Error
+  ft_gzip_file_init( FT_GZipFile   zip,
+                     FT_Stream     stream,
+                     FT_Stream     source )
+  {
+    z_stream*  zstream = &zip->zstream;
+    FT_Error   error   = 0;
+
+    zip->stream = stream;
+    zip->source = source;
+    zip->memory = stream->memory;
+
+    zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
+    zip->cursor = zip->limit;
+    zip->pos    = 0;
+
+    /* check and skip .gz header */
+    {
+      stream = source;
+
+      error = ft_gzip_check_header( stream );
+      if (error)
+        goto Exit;
+
+      zip->start = FT_STREAM_POS();
+    }
+
+    /* initialize zlib - there is no zlib header in the compressed stream */
+    zstream->zalloc = (alloc_func) ft_gzip_alloc;
+    zstream->zfree  = (free_func)  ft_gzip_free;
+    zstream->opaque = stream->memory;
+
+    zstream->avail_in = 0;
+    zstream->next_in  = zip->buffer;
+
+    if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK ||
+         zstream->next_in == NULL                     )
+    {
+      error = FT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+
+  static void
+  ft_gzip_file_done( FT_GZipFile  zip )
+  {
+    z_stream*  zstream = &zip->zstream;
+
+    /* clear the rest */
+    zstream->zalloc    = NULL;
+    zstream->zfree     = NULL;
+    zstream->opaque    = NULL;
+    zstream->next_in   = NULL;
+    zstream->next_out  = NULL;
+    zstream->avail_in  = 0;
+    zstream->avail_out = 0;
+
+    zip->memory = NULL;
+    zip->source = NULL;
+    zip->stream = NULL;
+  }
+
+
+  static FT_Error
+  ft_gzip_file_reset( FT_GZipFile  zip )
+  {
+    FT_Stream  stream = zip->source;
+    FT_Error   error;
+
+    if ( !FT_STREAM_SEEK( zip->start ) )
+    {
+      z_stream*  zstream = &zip->zstream;
+
+      inflateReset( zstream );
+
+      zstream->avail_in  = 0;
+      zstream->next_in   = zip->input;
+      zstream->avail_out = 0;
+      zstream->next_out  = zip->buffer;
+
+      zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
+      zip->cursor = zip->limit;
+      zip->pos    = 0;
+    }
+    return  error;
+  }
+
+
+  static FT_Error
+  ft_gzip_file_fill_input( FT_GZipFile  zip )
+  {
+    z_stream*  zstream = &zip->zstream;
+    FT_Stream  stream  = zip->source;
+    FT_ULong   size;
+
+    if ( stream->read )
+    {
+      size = stream->read( stream, stream->pos, zip->input, FT_GZIP_BUFFER_SIZE );
+      if ( size == 0 )
+        return FT_Err_Invalid_Stream_Operation;
+    }
+    else
+    {
+      size = stream->size - stream->pos;
+      if ( size > FT_GZIP_BUFFER_SIZE )
+        size = FT_GZIP_BUFFER_SIZE;
+
+      if ( size == 0 )
+       return FT_Err_Invalid_Stream_Operation;
+
+      FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
+    }
+    stream->pos += size;
+
+    zstream->next_in  = zip->input;
+    zstream->avail_in = size;
+
+    return 0;
+  }
+
+
+
+  static FT_Error
+  ft_gzip_file_fill_output( FT_GZipFile  zip )
+  {
+    z_stream*  zstream = &zip->zstream;
+    FT_Error   error   = 0;
+
+    zip->cursor        = zip->buffer;
+    zstream->next_out  = zip->cursor;
+    zstream->avail_out = FT_GZIP_BUFFER_SIZE;
+
+    while ( zstream->avail_out > 0 )
+    {
+      int  err;
+
+      if ( zstream->avail_in == 0 )
+      {
+        error = ft_gzip_file_fill_input( zip );
+        if ( error )
+          break;
+      }
+
+      err = inflate( zstream, Z_NO_FLUSH );
+
+      if ( err == Z_STREAM_END )
+      {
+        zip->limit = zstream->next_out;
+        break;
+      }
+      else if ( err != Z_OK )
+      {
+        error = FT_Err_Invalid_Stream_Operation;
+        break;
+      }
+    }
+    return error;
+  }
+
+
+ /* fill output buffer, 'count' must be <= FT_GZIP_BUFFER_SIZE */
+  static FT_Error
+  ft_gzip_file_skip_output( FT_GZipFile  zip,
+                            FT_ULong     count )
+  {
+    FT_Error   error   = 0;
+    FT_ULong   delta;
+
+    for (;;)
+    {
+      delta = (FT_ULong)( zip->limit - zip->cursor );
+      if ( delta >= count )
+        delta = count;
+
+      zip->cursor += delta;
+      zip->pos    += delta;
+
+      count -= delta;
+      if ( count == 0 )
+        break;
+
+      error = ft_gzip_file_fill_output( zip );
+      if ( error )
+        break;
+    }
+
+    return error;
+  }
+
+
+  static FT_ULong
+  ft_gzip_file_io( FT_GZipFile   zip,
+                   FT_ULong      pos,
+                   FT_Byte*      buffer,
+                   FT_ULong      count )
+  {
+    FT_ULong   result = 0;
+    FT_Error   error;
+
+    /* reset inflate stream if we're seeking backwards        */
+    /* yes, that's not too efficient, but it saves memory :-) */
+    if ( pos < zip->pos )
+    {
+      error = ft_gzip_file_reset( zip );
+      if ( error ) goto Exit;
+    }
+
+    /* skip unwanted bytes */
+    if ( pos > zip->pos )
+    {
+      error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
+      if (error)
+        goto Exit;
+    }
+
+    if ( count == 0 )
+      goto Exit;
+
+    /* now read the data */
+    for (;;)
+    {
+      FT_ULong   delta;
+
+      delta = (FT_ULong)( zip->limit - zip->cursor );
+      if ( delta >= count )
+        delta = count;
+
+      FT_MEM_COPY( buffer, zip->cursor, delta );
+      buffer      += delta;
+      result      += delta;
+      zip->cursor += delta;
+      zip->pos    += delta;
+
+      count -= delta;
+      if ( count == 0 )
+        break;
+
+      error = ft_gzip_file_fill_output( zip );
+      if (error)
+        break;
+    }
+
+  Exit:
+    return result;
+  }
+
+
+/***************************************************************************/
+/***************************************************************************/
+/*****                                                                 *****/
+/*****               G Z   E M B E D D I N G   S T R E A M             *****/
+/*****                                                                 *****/
+/***************************************************************************/
+/***************************************************************************/
+
+  static void
+  ft_gzip_stream_close( FT_Stream  stream )
+  {
+    FT_GZipFile  zip    = stream->descriptor.pointer;
+    FT_Memory    memory = stream->memory;
+
+    if ( zip )
+    {
+      /* finalize gzip file descriptor */
+      ft_gzip_file_done( zip );
+
+      FT_FREE( zip );
+
+      stream->descriptor.pointer = NULL;
+    }
+  }
+
+
+  static FT_ULong
+  ft_gzip_stream_io( FT_Stream   stream,
+                     FT_ULong    pos,
+                     FT_Byte*    buffer,
+                     FT_ULong    count )
+  {
+    FT_GZipFile  zip = stream->descriptor.pointer;
+
+    return ft_gzip_file_io( zip, pos, buffer, count );
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stream_OpenGzip( FT_Stream    stream,
+                      FT_Stream    source )
+  {
+    FT_Error     error;
+    FT_Memory    memory = source->memory;
+    FT_GZipFile  zip;
+
+    FT_ZERO( stream );
+    stream->memory = memory;
+
+    if ( !FT_NEW( zip ) )
+    {
+      error = ft_gzip_file_init( zip, stream, source );
+      if ( error )
+      {
+        FT_FREE( zip );
+        goto Exit;
+      }
+
+      stream->descriptor.pointer = zip;
+    }
+
+     stream->size = 0x7FFFFFFF;  /* don't know the real size !! */
+    stream->pos   = 0;
+    stream->base  = 0;
+    stream->read  = ft_gzip_stream_io;
+    stream->close = ft_gzip_stream_close;
+
+  Exit:
+    return error;
+  }
+
+#else  /* !FT_CONFIG_OPTION_USE_ZLIB */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stream_OpenGzip( FT_Stream    stream,
+                      FT_Stream    source )
+  {
+    FT_UNUSED( stream );
+    FT_UNUSED( source );
+
+    return FT_Err_Unimplemented_Feature;
+  }
+
+#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
--- /dev/null
+++ b/libfreetype/fthash.c
@@ -1,0 +1,246 @@
+#include <ft2build.h>
+#include FT_TYPES_H
+#include FT_INTERNAL_HASH_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+#define  FT_HASH_MAX_LOAD  2
+#define  FT_HASH_MIN_LOAD  1
+#define  FT_HASH_SUB_LOAD  (FT_HASH_MAX_LOAD-FT_HASH_MIN_LOAD)
+
+/* this one _must_ be a power of 2 !! */
+#define  FT_HASH_INITIAL_SIZE  8
+
+
+  FT_BASE_DEF( void )
+  ft_hash_done( FT_Hash              table,
+                FT_Hash_ForeachFunc  node_func,
+                const FT_Pointer     node_data )
+  {
+    if ( table )
+    {
+      FT_Memory  memory = table->memory;
+
+      if ( node_func )
+        ft_hash_foreach( table, node_func, node_data );
+
+      FT_FREE( table->buckets );
+      table->p     = 0;
+      table->mask  = 0;
+      table->slack = 0;
+
+      table->node_equal = NULL;
+    }
+  }
+
+
+  FT_BASE_DEF( FT_UInt )
+  ft_hash_get_size( FT_Hash  table )
+  {
+    FT_UInt  result = 0;
+
+    if ( table )
+      result = (table->p + table->mask + 1)*FT_HASH_MAX_LOAD - table->slack;
+
+    return result;
+  }
+
+
+
+  FT_BASE_DEF( FT_Error )
+  ft_hash_init( FT_Hash            table,
+                FT_Hash_EqualFunc  equal,
+                FT_Memory          memory )
+  {
+    FT_Error  error;
+
+    table->memory     = memory;
+    table->p          = 0;
+    table->mask       = FT_HASH_INITIAL_SIZE-1;
+    table->slack      = FT_HASH_INITIAL_SIZE*FT_HASH_MAX_LOAD;
+    table->node_equal = equal;
+
+    (void)FT_NEW_ARRAY( table->buckets, FT_HASH_INITIAL_SIZE*2 );
+
+    return error;
+  }
+
+
+
+  FT_BASE_DEF( void )
+  ft_hash_foreach( FT_Hash              table,
+                   FT_Hash_ForeachFunc  foreach_func,
+                   const FT_Pointer     foreach_data )
+  {
+    FT_UInt       count = table->p + table->mask + 1;
+    FT_HashNode*  pnode = table->buckets;
+    FT_HashNode   node, next;
+
+    for ( ; count > 0; count--, pnode++ )
+    {
+      node = *pnode;
+      while ( node )
+      {
+        next = node->link;
+        foreach_func( node, foreach_data );
+        node = next;
+      }
+    }
+  }
+
+
+
+  FT_BASE_DEF( FT_HashLookup )
+  ft_hash_lookup( FT_Hash      table,
+                  FT_HashNode  keynode )
+  {
+    FT_UInt       index;
+    FT_UInt32     hash = keynode->hash;
+    FT_HashNode   node, *pnode;
+
+    index = (FT_UInt)(hash & table->mask);
+    if ( index < table->p )
+      index = (FT_UInt)(hash & (2*table->mask+1));
+
+    pnode = &table->buckets[index];
+    for (;;)
+    {
+      node = *pnode;
+      if ( node == NULL )
+        break;
+
+      if ( node->hash == hash && table->node_equal( node, keynode ) )
+        break;
+
+      pnode = &node->link;
+    }
+
+    return pnode;
+  }
+
+
+
+
+  FT_BASE_DEF( FT_Error )
+  ft_hash_add( FT_Hash        table,
+               FT_HashLookup  lookup,
+               FT_HashNode    new_node )
+  {
+    FT_Error     error = 0;
+
+    /* add it to the hash table */
+    new_node->link = *lookup;
+    *lookup        = new_node;
+
+    if ( --table->slack < 0 )
+    {
+      FT_UInt       p     = table->p;
+      FT_UInt       mask  = table->mask;
+      FT_HashNode   new_list, node, *pnode;
+
+      /* split a single bucket */
+      new_list = NULL;
+      pnode    = table->buckets + p;
+      for (;;)
+      {
+        node = *pnode;
+        if ( node == NULL )
+          break;
+
+        if ( node->hash & mask )
+        {
+          *pnode     = node->link;
+          node->link = new_list;
+          new_list   = node;
+        }
+        else
+          pnode = &node->link;
+      }
+
+      table->buckets[ p + mask + 1 ] = new_list;
+
+      table->slack += FT_HASH_MAX_LOAD;
+
+      if ( p >= mask )
+      {
+        FT_Memory  memory = table->memory;
+
+
+        if (FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1)*4 ))
+          goto Exit;
+
+        table->mask = 2*mask + 1;
+        table->p    = 0;
+      }
+      else
+        table->p = p + 1;
+    }
+  Exit:
+    return error;
+  }
+
+
+
+  FT_BASE_DEF( FT_Error )
+  ft_hash_remove( FT_Hash        table,
+                  FT_HashLookup  lookup )
+  {
+    FT_HashNode  node;
+    FT_UInt      num_buckets;
+    FT_Error     error = 0;
+
+    FT_ASSERT( pnode != NULL && node != NULL );
+
+    node       = *lookup;
+    *lookup    = node->link;
+    node->link = NULL;
+
+    num_buckets = ( table->p + table->mask + 1) ;
+
+    if ( ++ table->slack > (FT_Long)num_buckets*FT_HASH_SUB_LOAD )
+    {
+      FT_UInt       p         = table->p;
+      FT_UInt       mask      = table->mask;
+      FT_UInt       old_index = p + mask;
+      FT_HashNode*  pnode;
+      FT_HashNode*  pold;
+
+      if ( old_index < FT_HASH_INITIAL_SIZE )
+        goto Exit;
+
+      if ( p == 0 )
+      {
+        FT_Memory  memory = table->memory;
+
+        table->mask >>= 1;
+        p             = table->mask;
+
+        if ( FT_RENEW_ARRAY( table->buckets, (mask+1)*2, (mask+1) ) )
+        {
+          /* this should never happen normally, but who knows :-)   */
+          /* we need to re-inject the node in the hash table before */
+          /* returning there, since it's safer                      */
+          pnode      = table->buckets;
+          node->link = *pnode;
+          *pnode     = node;
+
+          goto Exit;
+        }
+      }
+      else
+        p--;
+
+      pnode = table->buckets + p;
+      while ( *pnode )
+        pnode = &(*pnode)->link;
+
+      pold   = table->buckets + old_index;
+      *pnode = *pold;
+      *pold  = NULL;
+
+      table->slack -= FT_HASH_MAX_LOAD;
+      table->p      = p;
+    }
+  Exit:
+    return error;
+  }
--- /dev/null
+++ b/libfreetype/ftinit.c
@@ -1,0 +1,161 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftinit.c                                                               */
+/*                                                                         */
+/*    FreeType initialization layer (body).                                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  The purpose of this file is to implement the following two           */
+  /*  functions:                                                           */
+  /*                                                                       */
+  /*  FT_Add_Default_Modules():                                            */
+  /*     This function is used to add the set of default modules to a      */
+  /*     fresh new library object.  The set is taken from the header file  */
+  /*     `freetype/config/ftmodule.h'.  See the document `FreeType 2.0     */
+  /*     Build System' for more information.                               */
+  /*                                                                       */
+  /*  FT_Init_FreeType():                                                  */
+  /*     This function creates a system object for the current platform,   */
+  /*     builds a library out of it, then calls FT_Default_Drivers().      */
+  /*                                                                       */
+  /*  Note that even if FT_Init_FreeType() uses the implementation of the  */
+  /*  system object defined at build time, client applications are still   */
+  /*  able to provide their own `ftsystem.c'.                              */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_MODULE_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_init
+
+#undef  FT_USE_MODULE
+#ifdef __cplusplus
+#define FT_USE_MODULE( x )  extern "C" const FT_Module_Class*  x;
+#else
+#define FT_USE_MODULE( x )  extern const FT_Module_Class*  x;
+#endif
+
+
+#include FT_CONFIG_MODULES_H
+
+
+#undef  FT_USE_MODULE
+#define FT_USE_MODULE( x )  (const FT_Module_Class*)&x,
+
+  static
+  const FT_Module_Class*  const ft_default_modules[] =
+  {
+#include FT_CONFIG_MODULES_H
+    0
+  };
+
+
+  /* documentation is in ftmodule.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Add_Default_Modules( FT_Library  library )
+  {
+    FT_Error                       error;
+    const FT_Module_Class* const*  cur;
+
+
+    /* test for valid `library' delayed to FT_Add_Module() */
+
+    cur = ft_default_modules;
+    while ( *cur )
+    {
+      error = FT_Add_Module( library, *cur );
+      /* notify errors, but don't stop */
+      if ( error )
+      {
+        FT_ERROR(( "FT_Add_Default_Module: Cannot install `%s', error = 0x%x\n",
+                   (*cur)->module_name, error ));
+      }
+      cur++;
+    }
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Init_FreeType( FT_Library  *alibrary )
+  {
+    FT_Error   error;
+    FT_Memory  memory;
+
+
+    /* First of all, allocate a new system object -- this function is part */
+    /* of the system-specific component, i.e. `ftsystem.c'.                */
+
+    memory = FT_New_Memory();
+    if ( !memory )
+    {
+      FT_ERROR(( "FT_Init_FreeType: cannot find memory manager\n" ));
+      return FT_Err_Unimplemented_Feature;
+    }
+
+    /* build a library out of it, then fill it with the set of */
+    /* default drivers.                                        */
+
+    error = FT_New_Library( memory, alibrary );
+    if ( !error )
+    {
+      (*alibrary)->version_major = FREETYPE_MAJOR;
+      (*alibrary)->version_minor = FREETYPE_MINOR;
+      (*alibrary)->version_patch = FREETYPE_PATCH;
+
+      FT_Add_Default_Modules( *alibrary );
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Done_FreeType( FT_Library  library )
+  {
+    if ( library )
+    {
+      FT_Memory  memory = library->memory;
+
+
+      /* Discard the library object */
+      FT_Done_Library( library );
+
+      /* discard memory manager */
+      FT_Done_Memory( memory );
+    }
+
+    return FT_Err_Ok;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftlist.c
@@ -1,0 +1,217 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftlist.c                                                               */
+/*                                                                         */
+/*    Generic list support for FreeType (body).                            */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  This file implements functions relative to list processing.  Its     */
+  /*  data structures are defined in `freetype/internal/ftlist.h'.         */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_list
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( FT_ListNode )
+  FT_List_Find( FT_List  list,
+                void*    data )
+  {
+    FT_ListNode  cur;
+
+
+    cur = list->head;
+    while ( cur )
+    {
+      if ( cur->data == data )
+        return cur;
+
+      cur = cur->next;
+    }
+
+    return (FT_ListNode)0;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Add( FT_List      list,
+               FT_ListNode  node )
+  {
+    FT_ListNode  before = list->tail;
+
+
+    node->next = 0;
+    node->prev = before;
+
+    if ( before )
+      before->next = node;
+    else
+      list->head = node;
+
+    list->tail = node;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Insert( FT_List      list,
+                  FT_ListNode  node )
+  {
+    FT_ListNode  after = list->head;
+
+
+    node->next = after;
+    node->prev = 0;
+
+    if ( !after )
+      list->tail = node;
+    else
+      after->prev = node;
+
+    list->head = node;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Remove( FT_List      list,
+                  FT_ListNode  node )
+  {
+    FT_ListNode  before, after;
+
+
+    before = node->prev;
+    after  = node->next;
+
+    if ( before )
+      before->next = after;
+    else
+      list->head = after;
+
+    if ( after )
+      after->prev = before;
+    else
+      list->tail = before;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Up( FT_List      list,
+              FT_ListNode  node )
+  {
+    FT_ListNode  before, after;
+
+
+    before = node->prev;
+    after  = node->next;
+
+    /* check whether we are already on top of the list */
+    if ( !before )
+      return;
+
+    before->next = after;
+
+    if ( after )
+      after->prev = before;
+    else
+      list->tail = before;
+
+    node->prev       = 0;
+    node->next       = list->head;
+    list->head->prev = node;
+    list->head       = node;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_List_Iterate( FT_List            list,
+                   FT_List_Iterator   iterator,
+                   void*              user )
+  {
+    FT_ListNode  cur   = list->head;
+    FT_Error     error = FT_Err_Ok;
+
+
+    while ( cur )
+    {
+      FT_ListNode  next = cur->next;
+
+
+      error = iterator( cur, user );
+      if ( error )
+        break;
+
+      cur = next;
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Finalize( FT_List             list,
+                    FT_List_Destructor  destroy,
+                    FT_Memory           memory,
+                    void*               user )
+  {
+    FT_ListNode  cur;
+
+
+    cur = list->head;
+    while ( cur )
+    {
+      FT_ListNode  next = cur->next;
+      void*        data = cur->data;
+
+
+      if ( destroy )
+        destroy( memory, data, user );
+
+      FT_FREE( cur );
+      cur = next;
+    }
+
+    list->head = 0;
+    list->tail = 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftlru.c
@@ -1,0 +1,338 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftlru.c                                                                */
+/*                                                                         */
+/*    Simple LRU list-cache (body).                                        */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CACHE_H
+#include FT_CACHE_INTERNAL_LRU_H
+#include FT_LIST_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "ftcerror.h"
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_LruList_New( FT_LruList_Class  clazz,
+                  FT_UInt           max_nodes,
+                  FT_Pointer        user_data,
+                  FT_Memory         memory,
+                  FT_LruList       *alist )
+  {
+    FT_Error    error;
+    FT_LruList  list;
+
+
+    if ( !alist || !clazz )
+      return FTC_Err_Invalid_Argument;
+
+    *alist = NULL;
+    if ( !FT_ALLOC( list, clazz->list_size ) )
+    {
+      /* initialize common fields */
+      list->clazz      = clazz;
+      list->memory     = memory;
+      list->max_nodes  = max_nodes;
+      list->data       = user_data;
+
+      if ( clazz->list_init )
+      {
+        error = clazz->list_init( list );
+        if ( error )
+        {
+          if ( clazz->list_done )
+            clazz->list_done( list );
+
+          FT_FREE( list );
+        }
+      }
+
+      *alist = list;
+    }
+
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_LruList_Destroy( FT_LruList  list )
+  {
+    FT_Memory         memory;
+    FT_LruList_Class  clazz;
+
+
+    if ( !list )
+      return;
+
+    memory = list->memory;
+    clazz  = list->clazz;
+
+    FT_LruList_Reset( list );
+
+    if ( clazz->list_done )
+      clazz->list_done( list );
+
+    FT_FREE( list );
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_LruList_Reset( FT_LruList  list )
+  {
+    FT_LruNode        node;
+    FT_LruList_Class  clazz;
+    FT_Memory         memory;
+
+
+    if ( !list )
+      return;
+
+    node   = list->nodes;
+    clazz  = list->clazz;
+    memory = list->memory;
+
+    while ( node )
+    {
+      FT_LruNode  next = node->next;
+
+
+      if ( clazz->node_done )
+        clazz->node_done( node, list->data );
+
+      FT_FREE( node );
+      node = next;
+    }
+
+    list->nodes     = NULL;
+    list->num_nodes = 0;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_LruList_Lookup( FT_LruList   list,
+                     FT_LruKey    key,
+                     FT_LruNode  *anode )
+  {
+    FT_Error          error = 0;
+    FT_LruNode        node, *pnode;
+    FT_LruList_Class  clazz;
+    FT_LruNode*       plast;
+    FT_LruNode        result = NULL;
+    FT_Memory         memory;
+
+
+    if ( !list || !key || !anode )
+      return FTC_Err_Invalid_Argument;
+
+    pnode  = &list->nodes;
+    plast  = pnode;
+    node   = NULL;
+    clazz  = list->clazz;
+    memory = list->memory;
+
+    if ( clazz->node_compare )
+    {
+      for (;;)
+      {
+        node = *pnode;
+        if ( node == NULL )
+          break;
+
+        if ( clazz->node_compare( node, key, list->data ) )
+          break;
+
+        plast = pnode;
+        pnode = &(*pnode)->next;
+      }
+    }
+    else
+    {
+      for (;;)
+      {
+        node = *pnode;
+        if ( node == NULL )
+          break;
+
+        if ( node->key == key )
+          break;
+
+        plast = pnode;
+        pnode = &(*pnode)->next;
+      }
+    }
+
+    if ( node )
+    {
+      /* move element to top of list */
+      if ( list->nodes != node )
+      {
+        *pnode      = node->next;
+        node->next  = list->nodes;
+        list->nodes = node;
+      }
+      result = node;
+      goto Exit;
+    }
+
+    /* we haven't found the relevant element.  We will now try */
+    /* to create a new one.                                    */
+    /*                                                         */
+
+    /* first, check if our list if full, when appropriate */
+    if ( list->max_nodes > 0 && list->num_nodes >= list->max_nodes )
+    {
+      /* this list list is full; we will now flush */
+      /* the oldest node, if there's one!          */
+      FT_LruNode  last = *plast;
+
+
+      if ( last )
+      {
+        if ( clazz->node_flush )
+        {
+          error = clazz->node_flush( last, key, list->data );
+        }
+        else
+        {
+          if ( clazz->node_done )
+            clazz->node_done( last, list->data );
+
+          last->key  = key;
+          error = clazz->node_init( last, key, list->data );
+        }
+
+        if ( !error )
+        {
+          /* move it to the top of the list */
+          *plast      = NULL;
+          last->next  = list->nodes;
+          list->nodes = last;
+
+          result = last;
+          goto Exit;
+        }
+
+        /* in case of error during the flush or done/init cycle, */
+        /* we need to discard the node                           */
+        if ( clazz->node_done )
+          clazz->node_done( last, list->data );
+
+        *plast = NULL;
+        list->num_nodes--;
+
+        FT_FREE( last );
+        goto Exit;
+      }
+    }
+
+    /* otherwise, simply allocate a new node */
+    if ( FT_ALLOC( node, clazz->node_size ) )
+      goto Exit;
+
+    node->key = key;
+    error = clazz->node_init( node, key, list->data );
+    if ( error )
+    {
+      FT_FREE( node );
+      goto Exit;
+    }
+
+    result      = node;
+    node->next  = list->nodes;
+    list->nodes = node;
+    list->num_nodes++;
+
+  Exit:
+    *anode = result;
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_LruList_Remove( FT_LruList  list,
+                     FT_LruNode  node )
+  {
+    FT_LruNode  *pnode;
+
+
+    if ( !list || !node )
+      return;
+
+    pnode = &list->nodes;
+    for (;;)
+    {
+      if ( *pnode == node )
+      {
+        FT_Memory         memory = list->memory;
+        FT_LruList_Class  clazz  = list->clazz;
+
+
+        *pnode     = node->next;
+        node->next = NULL;
+
+        if ( clazz->node_done )
+          clazz->node_done( node, list->data );
+
+        FT_FREE( node );
+        list->num_nodes--;
+        break;
+      }
+
+      pnode = &(*pnode)->next;
+    }
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_LruList_Remove_Selection( FT_LruList             list,
+                               FT_LruNode_SelectFunc  select_func,
+                               FT_Pointer             select_data )
+  {
+    FT_LruNode       *pnode, node;
+    FT_LruList_Class  clazz;
+    FT_Memory         memory;
+
+
+    if ( !list || !select_func )
+      return;
+
+    memory = list->memory;
+    clazz  = list->clazz;
+    pnode  = &list->nodes;
+
+    for (;;)
+    {
+      node = *pnode;
+      if ( node == NULL )
+        break;
+
+      if ( select_func( node, select_data, list->data ) )
+      {
+        *pnode     = node->next;
+        node->next = NULL;
+
+        if ( clazz->node_done )
+          clazz->node_done( node, list );
+
+        FT_FREE( node );
+      }
+      else
+        pnode = &(*pnode)->next;
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftmac.c
@@ -1,0 +1,919 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftmac.c                                                                */
+/*                                                                         */
+/*    Mac FOND support.  Written by just@letterror.com.                    */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  Just van Rossum, David Turner, Robert Wilhelm, and Werner Lemberg.     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*
+    Notes
+
+    Mac suitcase files can (and often do!) contain multiple fonts.  To
+    support this I use the face_index argument of FT_(Open|New)_Face()
+    functions, and pretend the suitcase file is a collection.
+
+    Warning: Although the FOND driver sets face->num_faces field to the
+    number of available fonts, but the Type 1 driver sets it to 1 anyway.
+    So this field is currently not reliable, and I don't see a clean way
+    to  resolve that.  The face_index argument translates to
+
+      Get1IndResource( 'FOND', face_index + 1 );
+
+    so clients should figure out the resource index of the FOND.
+    (I'll try to provide some example code for this at some point.)
+
+    The Mac FOND support works roughly like this:
+
+    - Check whether the offered stream points to a Mac suitcase file.
+      This is done by checking the file type: it has to be 'FFIL' or 'tfil'.
+      The stream that gets passed to our init_face() routine is a stdio
+      stream, which isn't usable for us, since the FOND resources live
+      in the resource fork.  So we just grab the stream->pathname field.
+
+    - Read the FOND resource into memory, then check whether there is
+      a TrueType font and/or(!) a Type 1 font available.
+
+    - If there is a Type 1 font available (as a separate 'LWFN' file),
+      read its data into memory, massage it slightly so it becomes
+      PFB data, wrap it into a memory stream, load the Type 1 driver
+      and delegate the rest of the work to it by calling FT_Open_Face().
+      (XXX TODO: after this has been done, the kerning data from the FOND
+      resource should be appended to the face: On the Mac there are usually
+      no AFM files available.  However, this is tricky since we need to map
+      Mac char codes to ps glyph names to glyph ID's...)
+
+    - If there is a TrueType font (an 'sfnt' resource), read it into
+      memory, wrap it into a memory stream, load the TrueType driver
+      and delegate the rest of the work to it, by calling FT_Open_Face().
+  */
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_STREAM_H
+#include "truetype/ttobjs.h"
+#include "type1/t1objs.h"
+
+#include <Resources.h>
+#include <Fonts.h>
+#include <Errors.h>
+#include <Files.h>
+#include <TextUtils.h>
+
+
+#include FT_MAC_H
+
+
+  /* Set PREFER_LWFN to 1 if LWFN (Type 1) is preferred over
+     TrueType in case *both* are available (this is not common,
+     but it *is* possible). */
+#ifndef PREFER_LWFN
+#define PREFER_LWFN 1
+#endif
+
+  /* Given a pathname, fill in a file spec. */
+  static int
+  file_spec_from_path( const char*  pathname,
+                       FSSpec*      spec )
+  {
+#if TARGET_API_MAC_CARBON
+
+    OSErr  e;
+    FSRef  ref;
+
+
+    e = FSPathMakeRef( (UInt8 *)pathname, &ref, false /* not a directory */ );
+    if ( e == noErr )
+      e = FSGetCatalogInfo( &ref, kFSCatInfoNone, NULL, NULL, spec, NULL );
+
+    return ( e == noErr ) ? 0 : (-1);
+
+#else
+
+    Str255    p_path;
+    FT_ULong  path_len;
+
+
+    /* convert path to a pascal string */
+    path_len = ft_strlen( pathname );
+    if ( path_len > 255 )
+      return -1;
+    p_path[0] = (unsigned char)path_len;
+    ft_strncpy( (char*)p_path + 1, pathname, path_len );
+
+    if ( FSMakeFSSpec( 0, 0, p_path, spec ) != noErr )
+      return -1;
+    else
+      return 0;
+
+#endif
+  }
+
+
+  /* Return the file type of the file specified by spec. */
+  static OSType
+  get_file_type( FSSpec*  spec )
+  {
+    FInfo  finfo;
+
+
+    if ( FSpGetFInfo( spec, &finfo ) != noErr )
+      return 0;  /* file might not exist */
+
+    return finfo.fdType;
+  }
+
+
+#if TARGET_API_MAC_CARBON
+
+  /* is this a Mac OS X .dfont file */
+  static Boolean
+  is_dfont( FSSpec*  spec )
+  {
+    int  nameLen = spec->name[0];
+
+
+    return nameLen >= 6                                   &&
+           !memcmp( spec->name + nameLen - 5, ".dfont", 6 );
+  }
+
+#endif
+
+
+  /* Given a PostScript font name, create the Macintosh LWFN file name. */
+  static void
+  create_lwfn_name( char*   ps_name,
+                    Str255  lwfn_file_name )
+  {
+    int       max = 5, count = 0;
+    FT_Byte*  p = lwfn_file_name;
+    FT_Byte*  q = (FT_Byte*)ps_name;
+
+
+    lwfn_file_name[0] = 0;
+
+    while ( *q )
+    {
+      if ( isupper( *q ) )
+      {
+        if ( count )
+          max = 3;
+        count = 0;
+      }
+      if ( count < max && ( ft_isalnum( *q ) || *q == '_' ) )
+      {
+        *++p = *q;
+        lwfn_file_name[0]++;
+        count++;
+      }
+      q++;
+    }
+  }
+
+
+  /* Given a file reference, answer its location as a vRefNum
+     and a dirID. */
+  static FT_Error
+  get_file_location( short           ref_num,
+                     short*          v_ref_num,
+                     long*           dir_id,
+                     unsigned char*  file_name )
+  {
+    FCBPBRec  pb;
+    OSErr     error;
+
+
+    pb.ioNamePtr = file_name;
+    pb.ioVRefNum = 0;
+    pb.ioRefNum  = ref_num;
+    pb.ioFCBIndx = 0;
+
+    error = PBGetFCBInfoSync( &pb );
+    if ( error == noErr )
+    {
+      *v_ref_num = pb.ioFCBVRefNum;
+      *dir_id    = pb.ioFCBParID;
+    }
+    return error;
+  }
+
+
+  /* Make a file spec for an LWFN file from a FOND resource and
+     a file name. */
+  static FT_Error
+  make_lwfn_spec( Handle          fond,
+                  unsigned char*  file_name,
+                  FSSpec*         spec )
+  {
+    FT_Error  error;
+    short     ref_num, v_ref_num;
+    long      dir_id;
+    Str255    fond_file_name;
+
+
+    ref_num = HomeResFile( fond );
+
+    error = ResError();
+    if ( !error )
+      error = get_file_location( ref_num, &v_ref_num,
+                                 &dir_id, fond_file_name );
+    if ( !error )
+      error = FSMakeFSSpec( v_ref_num, dir_id, file_name, spec );
+
+    return error;
+  }
+
+
+  /* Look inside the FOND data, answer whether there should be an SFNT
+     resource, and answer the name of a possible LWFN Type 1 file.
+
+     Thanks to Paul Miller (paulm@profoundeffects.com) for the fix
+     to load a face OTHER than the first one in the FOND!
+  */
+  static void
+  parse_fond( char*   fond_data,
+              short*  have_sfnt,
+              short*  sfnt_id,
+              Str255  lwfn_file_name,
+              short   face_index )
+  {
+    AsscEntry*  assoc;
+    AsscEntry*  base_assoc;
+    FamRec*     fond;
+
+
+    *sfnt_id          = 0;
+    *have_sfnt        = 0;
+    lwfn_file_name[0] = 0;
+
+    fond       = (FamRec*)fond_data;
+    assoc      = (AsscEntry*)( fond_data + sizeof ( FamRec ) + 2 );
+    base_assoc = assoc;
+    assoc     += face_index;        /* add on the face_index! */
+
+    /* if the face at this index is not scalable,
+       fall back to the first one (old behavior) */
+    if ( assoc->fontSize == 0 )
+    {
+      *have_sfnt = 1;
+      *sfnt_id   = assoc->fontID;
+    }
+    else if ( base_assoc->fontSize == 0 )
+    {
+      *have_sfnt = 1;
+      *sfnt_id   = base_assoc->fontID;
+    }
+
+    if ( fond->ffStylOff )
+    {
+      unsigned char*  p = (unsigned char*)fond_data;
+      StyleTable*     style;
+      unsigned short  string_count;
+      char            ps_name[256];
+      unsigned char*  names[64];
+      int             i;
+
+
+      p += fond->ffStylOff;
+      style = (StyleTable*)p;
+      p += sizeof ( StyleTable );
+      string_count = *(unsigned short*)(p);
+      p += sizeof ( short );
+
+      for ( i = 0 ; i < string_count && i < 64; i++ )
+      {
+        names[i] = p;
+        p += names[i][0];
+        p++;
+      }
+
+      {
+        size_t  ps_name_len = (size_t)names[0][0];
+
+
+        if ( ps_name_len != 0 )
+        {
+          memcpy(ps_name, names[0] + 1, ps_name_len);
+          ps_name[ps_name_len] = 0;
+        }
+        if ( style->indexes[0] > 1 )
+        {
+          unsigned char*  suffixes = names[style->indexes[0] - 1];
+
+
+          for ( i = 1; i < suffixes[0]; i++ )
+          {
+            unsigned char*  s;
+            size_t          j = suffixes[i] - 1;
+
+
+            if ( j < string_count && ( s = names[j] ) != NULL )
+            {
+              size_t  s_len = (size_t)s[0];
+
+
+              if ( s_len != 0 && ps_name_len + s_len < sizeof ( ps_name ) )
+              {
+                memcpy( ps_name + ps_name_len, s + 1, s_len );
+                ps_name_len += s_len;
+                ps_name[ps_name_len] = 0;
+              }
+            }
+          }
+        }
+      }
+
+      create_lwfn_name( ps_name, lwfn_file_name );
+    }
+  }
+
+
+  /* Read Type 1 data from the POST resources inside the LWFN file,
+     return a PFB buffer. This is somewhat convoluted because the FT2
+     PFB parser wants the ASCII header as one chunk, and the LWFN
+     chunks are often not organized that way, so we'll glue chunks
+     of the same type together. */
+  static FT_Error
+  read_lwfn( FT_Memory  memory,
+             FSSpec*    lwfn_spec,
+             FT_Byte**  pfb_data,
+             FT_ULong*  size )
+  {
+    FT_Error       error = FT_Err_Ok;
+    short          res_ref, res_id;
+    unsigned char  *buffer, *p, *size_p = NULL;
+    FT_ULong       total_size = 0;
+    FT_ULong       post_size, pfb_chunk_size;
+    Handle         post_data;
+    char           code, last_code;
+
+
+    res_ref = FSpOpenResFile( lwfn_spec, fsRdPerm );
+    if ( ResError() )
+      return FT_Err_Out_Of_Memory;
+    UseResFile( res_ref );
+
+    /* First pass: load all POST resources, and determine the size of
+       the output buffer. */
+    res_id    = 501;
+    last_code = -1;
+
+    for (;;)
+    {
+      post_data = Get1Resource( 'POST', res_id++ );
+      if ( post_data == NULL )
+        break;  /* we're done */
+
+      code = (*post_data)[0];
+
+      if ( code != last_code )
+      {
+        if ( code == 5 )
+          total_size += 2; /* just the end code */
+        else
+          total_size += 6; /* code + 4 bytes chunk length */
+      }
+
+      total_size += GetHandleSize( post_data ) - 2;
+      last_code = code;
+    }
+
+    if ( FT_ALLOC( buffer, (FT_Long)total_size ) )
+      goto Error;
+
+    /* Second pass: append all POST data to the buffer, add PFB fields.
+       Glue all consecutive chunks of the same type together. */
+    p              = buffer;
+    res_id         = 501;
+    last_code      = -1;
+    pfb_chunk_size = 0;
+
+    for (;;)
+    {
+      post_data = Get1Resource( 'POST', res_id++ );
+      if ( post_data == NULL )
+        break;  /* we're done */
+
+      post_size = (FT_ULong)GetHandleSize( post_data ) - 2;
+      code = (*post_data)[0];
+
+      if ( code != last_code )
+      {
+        if ( last_code != -1 )
+        {
+          /* we're done adding a chunk, fill in the size field */
+          if ( size_p != NULL )
+          {
+            *size_p++ = (FT_Byte)(   pfb_chunk_size         & 0xFF );
+            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 8  ) & 0xFF );
+            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 16 ) & 0xFF );
+            *size_p++ = (FT_Byte)( ( pfb_chunk_size >> 24 ) & 0xFF );
+          }
+          pfb_chunk_size = 0;
+        }
+
+        *p++ = 0x80;
+        if ( code == 5 )
+          *p++ = 0x03;  /* the end */
+        else if ( code == 2 )
+          *p++ = 0x02;  /* binary segment */
+        else
+          *p++ = 0x01;  /* ASCII segment */
+
+        if ( code != 5 )
+        {
+          size_p = p;   /* save for later */
+          p += 4;       /* make space for size field */
+        }
+      }
+
+      ft_memcpy( p, *post_data + 2, post_size );
+      pfb_chunk_size += post_size;
+      p += post_size;
+      last_code = code;
+    }
+
+    *pfb_data = buffer;
+    *size = total_size;
+
+  Error:
+    CloseResFile( res_ref );
+    return error;
+  }
+
+
+  /* Finalizer for a memory stream; gets called by FT_Done_Face().
+     It frees the memory it uses. */
+  static void
+  memory_stream_close( FT_Stream  stream )
+  {
+    FT_Memory  memory = stream->memory;
+
+
+    FT_FREE( stream->base );
+
+    stream->size  = 0;
+    stream->base  = 0;
+    stream->close = 0;
+  }
+
+
+  /* Create a new memory stream from a buffer and a size. */
+  static FT_Error
+  new_memory_stream( FT_Library           library,
+                     FT_Byte*             base,
+                     FT_ULong             size,
+                     FT_Stream_CloseFunc  close,
+                     FT_Stream           *astream )
+  {
+    FT_Error   error;
+    FT_Memory  memory;
+    FT_Stream  stream;
+
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    if ( !base )
+      return FT_Err_Invalid_Argument;
+
+    *astream = 0;
+    memory = library->memory;
+    if ( FT_NEW( stream ) )
+      goto Exit;
+
+    FT_Stream_OpenMemory( stream, base, size );
+
+    stream->close = close;
+
+    *astream = stream;
+
+  Exit:
+    return error;
+  }
+
+
+  /* Create a new FT_Face given a buffer and a driver name. */
+  static FT_Error
+  open_face_from_buffer( FT_Library  library,
+                         FT_Byte*    base,
+                         FT_ULong    size,
+                         FT_Long     face_index,
+                         char*       driver_name,
+                         FT_Face    *aface )
+  {
+    FT_Open_Args  args;
+    FT_Error      error;
+    FT_Stream     stream;
+    FT_Memory     memory = library->memory;
+
+
+    error = new_memory_stream( library,
+                               base,
+                               size,
+                               memory_stream_close,
+                               &stream );
+    if ( error )
+    {
+      FT_FREE( base );
+      return error;
+    }
+
+    args.flags = FT_OPEN_STREAM;
+    args.stream = stream;
+    if ( driver_name )
+    {
+      args.flags = args.flags | FT_OPEN_DRIVER;
+      args.driver = FT_Get_Module( library, driver_name );
+    }
+
+    error = FT_Open_Face( library, &args, face_index, aface );
+    if ( error == FT_Err_Ok )
+      (*aface)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
+    else
+    {
+      FT_Stream_CloseFunc( stream );
+      FT_FREE( stream );
+    }
+
+    return error;
+  }
+
+
+  /* Create a new FT_Face from a file spec to an LWFN file. */
+  static FT_Error
+  FT_New_Face_From_LWFN( FT_Library  library,
+                         FSSpec*     spec,
+                         FT_Long     face_index,
+                         FT_Face    *aface )
+  {
+    FT_Byte*  pfb_data;
+    FT_ULong  pfb_size;
+    FT_Error  error;
+
+
+    error = read_lwfn( library->memory, spec, &pfb_data, &pfb_size );
+    if ( error )
+      return error;
+
+    return open_face_from_buffer( library,
+                                  pfb_data,
+                                  pfb_size,
+                                  face_index,
+                                  "type1",
+                                  aface );
+  }
+
+
+  /* Create a new FT_Face from an SFNT resource, specified by res ID. */
+  static FT_Error
+  FT_New_Face_From_SFNT( FT_Library  library,
+                         short       sfnt_id,
+                         FT_Long     face_index,
+                         FT_Face    *aface )
+  {
+    Handle     sfnt = NULL;
+    FT_Byte*   sfnt_data;
+    size_t     sfnt_size;
+    FT_Error   error = 0;
+    FT_Memory  memory = library->memory;
+
+
+    sfnt = GetResource( 'sfnt', sfnt_id );
+    if ( ResError() )
+      return FT_Err_Invalid_Handle;
+
+    sfnt_size = (FT_ULong)GetHandleSize( sfnt );
+    if ( FT_ALLOC( sfnt_data, (FT_Long)sfnt_size ) )
+    {
+      ReleaseResource( sfnt );
+      return error;
+    }
+
+    HLock( sfnt );
+    ft_memcpy( sfnt_data, *sfnt, sfnt_size );
+    HUnlock( sfnt );
+    ReleaseResource( sfnt );
+
+    return open_face_from_buffer( library,
+                                  sfnt_data,
+                                  sfnt_size,
+                                  face_index,
+                                  "truetype",
+                                  aface );
+  }
+
+
+  /* Create a new FT_Face from a file spec to a suitcase file. */
+  static FT_Error
+  FT_New_Face_From_Suitcase( FT_Library  library,
+                             FSSpec*     spec,
+                             FT_Long     face_index,
+                             FT_Face    *aface )
+  {
+    FT_Error  error = FT_Err_Ok;
+    short     res_ref, res_index;
+    Handle    fond;
+
+
+    res_ref = FSpOpenResFile( spec, fsRdPerm );
+    if ( ResError() )
+      return FT_Err_Cannot_Open_Resource;
+    UseResFile( res_ref );
+
+    /* face_index may be -1, in which case we
+       just need to do a sanity check */
+    if ( face_index < 0 )
+      res_index = 1;
+    else
+    {
+      res_index = (short)( face_index + 1 );
+      face_index = 0;
+    }
+    fond = Get1IndResource( 'FOND', res_index );
+    if ( ResError() )
+    {
+      error = FT_Err_Cannot_Open_Resource;
+      goto Error;
+    }
+
+    error = FT_New_Face_From_FOND( library, fond, face_index, aface );
+
+  Error:
+    CloseResFile( res_ref );
+    return error;
+  }
+
+
+#if TARGET_API_MAC_CARBON
+
+  /* Create a new FT_Face from a file spec to a suitcase file. */
+  static FT_Error
+  FT_New_Face_From_dfont( FT_Library  library,
+                          FSSpec*     spec,
+                          FT_Long     face_index,
+                          FT_Face*    aface )
+  {
+    FT_Error  error = FT_Err_Ok;
+    short     res_ref, res_index;
+    Handle    fond;
+    FSRef     hostContainerRef;
+
+
+    error = FSpMakeFSRef( spec, &hostContainerRef );
+    if ( error == noErr )
+      error = FSOpenResourceFile( &hostContainerRef,
+                                  0, NULL, fsRdPerm, &res_ref );
+
+    if ( error != noErr )
+      return FT_Err_Cannot_Open_Resource;
+
+    UseResFile( res_ref );
+
+    /* face_index may be -1, in which case we
+       just need to do a sanity check */
+    if ( face_index < 0 )
+      res_index = 1;
+    else
+    {
+      res_index = (short)( face_index + 1 );
+      face_index = 0;
+    }
+    fond = Get1IndResource( 'FOND', res_index );
+    if ( ResError() )
+    {
+      error = FT_Err_Cannot_Open_Resource;
+      goto Error;
+    }
+
+    error = FT_New_Face_From_FOND( library, fond, face_index, aface );
+
+  Error:
+    CloseResFile( res_ref );
+    return error;
+  }
+
+#endif
+
+
+  /* documentation is in ftmac.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face_From_FOND( FT_Library  library,
+                         Handle      fond,
+                         FT_Long     face_index,
+                         FT_Face    *aface )
+  {
+    short   sfnt_id, have_sfnt, have_lwfn = 0;
+    Str255  lwfn_file_name;
+    short   fond_id;
+    OSType  fond_type;
+    Str255  fond_name;
+    FSSpec  lwfn_spec;
+
+
+    GetResInfo( fond, &fond_id, &fond_type, fond_name );
+    if ( ResError() != noErr || fond_type != 'FOND' )
+      return FT_Err_Invalid_File_Format;
+
+    HLock( fond );
+    parse_fond( *fond, &have_sfnt, &sfnt_id, lwfn_file_name, face_index );
+    HUnlock( fond );
+
+    if ( lwfn_file_name[0] )
+    {
+      if ( make_lwfn_spec( fond, lwfn_file_name, &lwfn_spec ) == FT_Err_Ok )
+        have_lwfn = 1;  /* yeah, we got one! */
+      else
+        have_lwfn = 0;  /* no LWFN file found */
+    }
+
+    if ( have_lwfn && ( !have_sfnt || PREFER_LWFN ) )
+      return FT_New_Face_From_LWFN( library,
+                                    &lwfn_spec,
+                                    face_index,
+                                    aface );
+    else if ( have_sfnt )
+      return FT_New_Face_From_SFNT( library,
+                                    sfnt_id,
+                                    face_index,
+                                    aface );
+
+    return FT_Err_Unknown_File_Format;
+  }
+
+
+  /* documentation is in ftmac.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_GetFile_From_Mac_Name( char*     fontName,
+                            FSSpec*   pathSpec,
+                            FT_Long*  face_index )
+  {
+    OptionBits            options = kFMUseGlobalScopeOption;
+
+    FMFontFamilyIterator  famIter;
+    OSStatus              status = FMCreateFontFamilyIterator( NULL, NULL,
+                                                               options,
+                                                               &famIter );
+    FMFont                the_font = NULL;
+    FMFontFamily          family   = NULL;
+
+
+    *face_index = 0;
+    while ( status == 0 && !the_font )
+    {
+      status = FMGetNextFontFamily( &famIter, &family );
+      if ( status == 0 )
+      {
+        int                           stat2;
+        FMFontFamilyInstanceIterator  instIter;
+        Str255                        famNameStr;
+        char                          famName[256];
+
+
+        /* get the family name */
+        FMGetFontFamilyName( family, famNameStr );
+        CopyPascalStringToC( famNameStr, famName );
+
+        /* iterate through the styles */
+        FMCreateFontFamilyInstanceIterator( family, &instIter );
+
+        *face_index = 0;
+        stat2 = 0;
+        while ( stat2 == 0 && !the_font )
+        {
+          FMFontStyle  style;
+          FMFontSize   size;
+          FMFont       font;
+
+
+          stat2 = FMGetNextFontFamilyInstance( &instIter, &font,
+                                               &style, &size );
+          if ( stat2 == 0 && size == 0 )
+          {
+            char  fullName[256];
+
+
+            /* build up a complete face name */
+            ft_strcpy( fullName, famName );
+            if ( style & bold )
+              strcat( fullName, " Bold" );
+            if ( style & italic )
+              strcat( fullName, " Italic" );
+
+            /* compare with the name we are looking for */
+            if ( ft_strcmp( fullName, fontName ) == 0 )
+            {
+              /* found it! */
+              the_font = font;
+            }
+            else
+               ++(*face_index);
+          }
+        }
+
+        FMDisposeFontFamilyInstanceIterator( &instIter );
+      }
+    }
+
+    FMDisposeFontFamilyIterator( &famIter );
+
+    if ( the_font )
+    {
+      FMGetFontContainer( the_font, pathSpec );
+      return FT_Err_Ok;
+    }
+    else
+      return FT_Err_Unknown_File_Format;
+  }
+
+
+  static long
+  ResourceForkSize(FSSpec*  spec)
+  {
+    long   len;
+    short  refNum;
+    OSErr  e;
+
+
+    e = FSpOpenRF( spec, fsRdPerm, &refNum ); /* I.M. Files 2-155 */
+    if ( e == noErr )
+    {
+      e = GetEOF( refNum, &len );
+      FSClose( refNum );
+    }
+
+    return ( e == noErr ) ? len : 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    FT_New_Face                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This is the Mac-specific implementation of FT_New_Face.  In        */
+  /*    addition to the standard FT_New_Face() functionality, it also      */
+  /*    accepts pathnames to Mac suitcase files.  For further              */
+  /*    documentation see the original FT_New_Face() in freetype.h.        */
+  /*                                                                       */
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face( FT_Library   library,
+               const char*  pathname,
+               FT_Long      face_index,
+               FT_Face     *aface )
+  {
+    FT_Open_Args  args;
+    FSSpec        spec;
+    OSType        file_type;
+
+
+    /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+    if ( !pathname )
+      return FT_Err_Invalid_Argument;
+
+    if ( file_spec_from_path( pathname, &spec ) )
+      return FT_Err_Invalid_Argument;
+
+    /* Regardless of type, don't try to use the resource fork if it is */
+    /* empty.  Some TTF fonts have type `FFIL', for example, but they  */
+    /* only have data forks.                                           */
+
+    if ( ResourceForkSize( &spec ) != 0 )
+    {
+      file_type = get_file_type( &spec );
+      if ( file_type == 'FFIL' || file_type == 'tfil' )
+        return FT_New_Face_From_Suitcase( library, &spec, face_index, aface );
+
+      if ( file_type == 'LWFN' )
+        return FT_New_Face_From_LWFN( library, &spec, face_index, aface );
+    }
+
+#if TARGET_API_MAC_CARBON
+
+    if ( is_dfont( &spec ) )
+      return FT_New_Face_From_dfont( library, &spec, face_index, aface );
+
+#endif
+
+    /* let it fall through to normal loader (.ttf, .otf, etc.) */
+    args.flags    = FT_OPEN_PATHNAME;
+    args.pathname = (char*)pathname;
+    return FT_Open_Face( library, &args, face_index, aface );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftmm.c
@@ -1,0 +1,126 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftmm.c                                                                 */
+/*                                                                         */
+/*    Multiple Master font support (body).                                 */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_mm
+
+
+  /* documentation is in ftmm.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_Multi_Master( FT_Face           face,
+                       FT_Multi_Master  *amaster )
+  {
+    FT_Error  error;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    error = FT_Err_Invalid_Argument;
+
+    if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+    {
+      FT_Driver       driver = face->driver;
+      FT_Get_MM_Func  func;
+
+
+      func = (FT_Get_MM_Func)driver->root.clazz->get_interface(
+                               FT_MODULE( driver ), "get_mm" );
+      if ( func )
+        error = func( face, amaster );
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in ftmm.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Set_MM_Design_Coordinates( FT_Face   face,
+                                FT_UInt   num_coords,
+                                FT_Long*  coords )
+  {
+    FT_Error  error;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    error = FT_Err_Invalid_Argument;
+
+    if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+    {
+      FT_Driver              driver = face->driver;
+      FT_Set_MM_Design_Func  func;
+
+
+      func = (FT_Set_MM_Design_Func)driver->root.clazz->get_interface(
+                                      FT_MODULE( driver ), "set_mm_design" );
+      if ( func )
+        error = func( face, num_coords, coords );
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in ftmm.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Set_MM_Blend_Coordinates( FT_Face    face,
+                               FT_UInt    num_coords,
+                               FT_Fixed*  coords )
+  {
+    FT_Error  error;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    error = FT_Err_Invalid_Argument;
+
+    if ( FT_HAS_MULTIPLE_MASTERS( face ) )
+    {
+      FT_Driver             driver = face->driver;
+      FT_Set_MM_Blend_Func  func;
+
+
+      func = (FT_Set_MM_Blend_Func)driver->root.clazz->get_interface(
+                                     FT_MODULE( driver ), "set_mm_blend" );
+      if ( func )
+        error = func( face, num_coords, coords );
+    }
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftnames.c
@@ -1,0 +1,94 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftnames.c                                                              */
+/*                                                                         */
+/*    Simple interface to access SFNT name tables (which are used          */
+/*    to hold font names, copyright info, notices, etc.) (body).           */
+/*                                                                         */
+/*    This is _not_ used to retrieve glyph names!                          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_SFNT_NAMES_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+#include FT_INTERNAL_STREAM_H
+
+
+#ifdef TT_CONFIG_OPTION_SFNT_NAMES
+
+
+  /* documentation is in ftnames.h */
+
+  FT_EXPORT_DEF( FT_UInt )
+  FT_Get_Sfnt_Name_Count( FT_Face  face )
+  {
+    return (face && FT_IS_SFNT( face )) ? ((TT_Face)face)->num_names : 0;
+  }
+
+
+  /* documentation is in ftnames.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_Sfnt_Name( FT_Face       face,
+                    FT_UInt       idx,
+                    FT_SfntName  *aname )
+  {
+    FT_Error  error = FT_Err_Invalid_Argument;
+
+
+    if ( aname && face && FT_IS_SFNT( face ) )
+    {
+      TT_Face  ttface = (TT_Face)face;
+
+
+      if ( idx < (FT_UInt)ttface->num_names )
+      {
+        TT_NameEntryRec*  entry = ttface->name_table.names + idx;
+
+
+        /* load name on demand */
+        if ( entry->stringLength > 0 && entry->string == NULL )
+        {
+          FT_Memory  memory = face->memory;
+          FT_Stream  stream = face->stream;
+
+
+          if ( FT_NEW_ARRAY  ( entry->string, entry->stringLength ) ||
+               FT_STREAM_SEEK( entry->stringOffset )                ||
+               FT_STREAM_READ( entry->string, entry->stringLength ) )
+          {
+            FT_FREE( entry->string );
+            entry->stringLength = 0;
+          }
+        }
+
+        aname->platform_id = entry->platformID;
+        aname->encoding_id = entry->encodingID;
+        aname->language_id = entry->languageID;
+        aname->name_id     = entry->nameID;
+        aname->string      = (FT_Byte*)entry->string;
+        aname->string_len  = entry->stringLength;
+
+        error = FT_Err_Ok;
+      }
+    }
+
+    return error;
+  }
+
+
+#endif /* TT_CONFIG_OPTION_SFNT_NAMES */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftobject.c
@@ -1,0 +1,396 @@
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECT_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+#define  FT_MAGIC_DEATH   0xDEADdead
+#define  FT_MAGIC_CLASS   0x12345678
+
+#define  FT_TYPE_HASH(x)  (( (FT_UInt32)(x) >> 2 )^( (FT_UInt32)(x) >> 10 ))
+
+#define  FT_OBJECT_CHECK(o)                                  \
+           ( FT_OBJECT(o)               != NULL           && \
+             FT_OBJECT(o)->clazz        != NULL           && \
+             FT_OBJECT(o)->ref_count    >= 1              && \
+             FT_OBJECT(o)->clazz->magic == FT_MAGIC_CLASS )
+
+#define  FT_CLASS_CHECK(c)  \
+           ( FT_CLASS(c) != NULL && FT_CLASS(c)->magic == FT_MAGIC_CLASS )
+
+#define  FT_ASSERT_IS_CLASS(c)  FT_ASSERT( FT_CLASS_CHECK(c) )
+
+ /*******************************************************************/
+ /*******************************************************************/
+ /*****                                                         *****/
+ /*****                                                         *****/
+ /*****                  M E T A - C L A S S                    *****/
+ /*****                                                         *****/
+ /*****                                                         *****/
+ /*******************************************************************/
+ /*******************************************************************/
+
+ /* forward declaration */
+  FT_BASE_DEF( FT_Error )
+  ft_metaclass_init( FT_MetaClass  meta,
+                     FT_Library    library );
+
+  /* forward declaration */
+  FT_BASE_DEF( void )
+  ft_metaclass_done( FT_MetaClass  meta );
+
+
+  /* class type for the meta-class itself */
+  static const FT_TypeRec  ft_meta_class_type =
+  {
+    "FT2.MetaClass",
+    NULL,
+
+    sizeof( FT_MetaClassRec ),
+    (FT_Object_InitFunc)  ft_metaclass_init,
+    (FT_Object_DoneFunc)  ft_metaclass_done,
+
+    sizeof( FT_ClassRec ),
+    (FT_Object_InitFunc)  NULL,
+    (FT_Object_DoneFunc)  NULL
+  };
+
+
+
+
+ /* destroy a given class */
+  static void
+  ft_class_hnode_destroy( FT_ClassHNode  node )
+  {
+    FT_Class   clazz  = node->clazz;
+    FT_Memory  memory = clazz->memory;
+
+    if ( clazz->class_done )
+      clazz->class_done( (FT_Object) clazz );
+
+    FT_FREE( clazz );
+
+    node->clazz = NULL;
+    node->type  = NULL;
+
+    FT_FREE( node );
+  }
+
+
+  static FT_Int
+  ft_type_equal( FT_Type  type1,
+                 FT_Type  type2 )
+  {
+    if ( type1 == type2 )
+      goto Ok;
+
+    if ( type1 == NULL || type2 == NULL )
+      goto Fail;
+
+    /* compare parent types */
+    if ( type1->super != type2->super )
+    {
+      if ( type1->super == NULL           ||
+           type2->super == NULL           ||
+           !ft_type_equal( type1, type2 ) )
+        goto Fail;
+    }
+
+    /* compare type names */
+    if ( type1->name != type2->name )
+    {
+      if ( type1->name == NULL                        ||
+           type2->name == NULL                        ||
+           ft_strcmp( type1->name, type2->name ) != 0 )
+        goto Fail;
+    }
+
+    /* compare the other type fields */
+    if ( type1->class_size != type2->class_size ||
+         type1->class_init != type2->class_init ||
+         type1->class_done != type2->class_done ||
+         type1->obj_size   != type2->obj_size   ||
+         type1->obj_init   != type2->obj_init   ||
+         type1->obj_done   != type2->obj_done   )
+      goto Fail;
+
+  Ok:
+    return 1;
+
+  Fail:
+    return 0;
+  }
+
+
+  static FT_Int
+  ft_class_hnode_equal( const FT_ClassHNode  node1,
+                        const FT_ClassHNode  node2 )
+  {
+    FT_Type  type1 = node1->type;
+    FT_Type  type2 = node2->type;
+
+    /* comparing the pointers should work in 99% of cases */
+    return ( type1 == type2 ) ? 1 : ft_type_equal( type1, type2 );
+  }
+
+
+  FT_BASE_DEF( void )
+  ft_metaclass_done( FT_MetaClass  meta )
+  {
+    /* clear all classes */
+    ft_hash_done( &meta->type_to_class,
+                  (FT_Hash_ForeachFunc) ft_class_hnode_destroy,
+                   NULL );
+
+    meta->clazz.object.clazz     = NULL;
+    meta->clazz.object.ref_count = 0;
+    meta->clazz.magic            = FT_MAGIC_DEATH;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  ft_metaclass_init( FT_MetaClass  meta,
+                     FT_Library    library )
+  {
+    FT_ClassRec*  clazz = (FT_ClassRec*) &meta->clazz;
+
+    /* the meta-class is its OWN class !! */
+    clazz->object.clazz     = (FT_Class) clazz;
+    clazz->object.ref_count = 1;
+    clazz->magic            = FT_MAGIC_CLASS;
+    clazz->library          = library;
+    clazz->memory           = library->memory;
+    clazz->type             = &ft_meta_class_type;
+    clazz->info             = NULL;
+
+    clazz->class_done       = (FT_Object_DoneFunc) ft_metaclass_done;
+
+    clazz->obj_size         = sizeof( FT_ClassRec );
+    clazz->obj_init         = NULL;
+    clazz->obj_done         = NULL;
+
+    return ft_hash_init( &meta->type_to_class,
+                        (FT_Hash_EqualFunc) ft_class_hnode_equal,
+                        library->memory );
+  }
+
+
+ /* find or create the class corresponding to a given type */
+ /* note that this function will retunr NULL in case of    */
+ /* memory overflow                                        */
+ /*                                                        */
+  static FT_Class
+  ft_metaclass_get_class( FT_MetaClass  meta,
+                          FT_Type       ctype )
+  {
+    FT_ClassHNodeRec   keynode, *node, **pnode;
+    FT_Memory          memory;
+    FT_ClassRec*       clazz;
+    FT_Class           parent;
+    FT_Error           error;
+
+    keynode.hnode.hash = FT_TYPE_HASH( ctype );
+    keynode.type       = ctype;
+
+    pnode = (FT_ClassHNode*) ft_hash_lookup( &meta->type_to_class,
+                                             (FT_HashNode) &keynode );
+    node  = *pnode;
+    if ( node != NULL )
+    {
+      clazz = (FT_ClassRec*) node->clazz;
+      goto Exit;
+    }
+
+    memory = FT_CLASS__MEMORY(meta);
+    clazz  = NULL;
+    parent = NULL;
+    if ( ctype->super != NULL )
+    {
+      FT_ASSERT( ctype->super->class_size <= ctype->class_size );
+      FT_ASSERT( ctype->super->obj_size   <= ctype->obj_size   );
+
+      parent = ft_metaclass_get_class( meta, ctype->super );
+    }
+
+    if ( !FT_NEW( node ) )
+    {
+      if ( !FT_ALLOC( clazz, ctype->class_size ) )
+      {
+        if ( parent )
+          FT_MEM_COPY( (FT_ClassRec*)clazz, parent, parent->type->class_size );
+
+        clazz->object.clazz     = (FT_Class) meta;
+        clazz->object.ref_count = 1;
+
+        clazz->memory  = memory;
+        clazz->library = FT_CLASS__LIBRARY(meta);
+        clazz->super   = parent;
+        clazz->type    = ctype;
+        clazz->info    = NULL;
+        clazz->magic   = FT_MAGIC_CLASS;
+
+        clazz->class_done = ctype->class_done;
+        clazz->obj_size   = ctype->obj_size;
+        clazz->obj_init   = ctype->obj_init;
+        clazz->obj_done   = ctype->obj_done;
+
+        if ( parent )
+        {
+          if ( clazz->class_done == NULL )
+            clazz->class_done = parent->class_done;
+
+          if ( clazz->obj_init == NULL )
+            clazz->obj_init = parent->obj_init;
+
+          if ( clazz->obj_done == NULL )
+            clazz->obj_done = parent->obj_done;
+        }
+
+        /* find class initializer, if any */
+        {
+          FT_Type             ztype = ctype;
+          FT_Object_InitFunc  cinit = NULL;
+
+          do
+          {
+            cinit = ztype->class_init;
+            if ( cinit != NULL )
+              break;
+
+            ztype = ztype->super;
+          }
+          while ( ztype != NULL );
+
+          /* then call it when needed */
+          if ( cinit != NULL )
+            error = cinit( (FT_Object) clazz, NULL );
+        }
+      }
+
+      if (error)
+      {
+        if ( clazz )
+        {
+          /* we always call the class destructor when    */
+          /* an error was detected in the constructor !! */
+          if ( clazz->class_done )
+            clazz->class_done( (FT_Object) clazz );
+
+          FT_FREE( clazz );
+        }
+        FT_FREE( node );
+      }
+    }
+
+  Exit:
+    return  (FT_Class) clazz;
+  }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  FT_BASE_DEF( FT_Int )
+  ft_object_check( FT_Pointer  obj )
+  {
+    return FT_OBJECT_CHECK(obj);
+  }
+
+
+  FT_BASE_DEF( FT_Int )
+  ft_object_is_a( FT_Pointer  obj,
+                  FT_Class    clazz )
+  {
+    if ( FT_OBJECT_CHECK(obj) )
+    {
+      FT_Class   c = FT_OBJECT__CLASS(obj);
+
+      do
+      {
+        if ( c == clazz )
+          return 1;
+
+        c = c->super;
+      }
+      while ( c == NULL );
+
+      return (clazz == NULL);
+    }
+    return 0;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  ft_object_create( FT_Object  *pobject,
+                    FT_Class    clazz,
+                    FT_Pointer  init_data )
+  {
+    FT_Memory  memory;
+    FT_Error   error;
+    FT_Object  obj;
+
+    FT_ASSERT_IS_CLASS(clazz);
+
+    memory = FT_CLASS__MEMORY(clazz);
+    if ( !FT_ALLOC( obj, clazz->obj_size ) )
+    {
+      obj->clazz     = clazz;
+      obj->ref_count = 1;
+
+      if ( clazz->obj_init )
+      {
+        error = clazz->obj_init( obj, init_data );
+        if ( error )
+        {
+          /* IMPORTANT: call the destructor when an error  */
+          /*            was detected in the constructor !! */
+          if ( clazz->obj_done )
+            clazz->obj_done( obj );
+
+          FT_FREE( obj );
+        }
+      }
+    }
+    *pobject = obj;
+    return error;
+  }
+
+
+  FT_BASE_DEF( FT_Class )
+  ft_class_find_by_type( FT_Type     type,
+                         FT_Library  library )
+  {
+    FT_MetaClass  meta = &library->meta_class;
+
+    return ft_metaclass_get_class( meta, type );
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  ft_object_create_from_type( FT_Object  *pobject,
+                              FT_Type     type,
+                              FT_Pointer  init_data,
+                              FT_Library  library )
+  {
+    FT_Class  clazz;
+    FT_Error  error;
+
+    clazz = ft_class_find_by_type( type, library );
+    if ( clazz )
+      error = ft_object_create( pobject, clazz, init_data );
+    else
+    {
+      *pobject = NULL;
+      error    = FT_Err_Out_Of_Memory;
+    }
+
+    return error;
+  }
--- /dev/null
+++ b/libfreetype/ftobjs.c
@@ -1,0 +1,2505 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftobjs.c                                                               */
+/*                                                                         */
+/*    The FreeType private base classes (body).                            */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_OUTLINE_H
+
+
+  FT_BASE_DEF( void )
+  ft_validator_init( FT_Validator        valid,
+                     const FT_Byte*      base,
+                     const FT_Byte*      limit,
+                     FT_ValidationLevel  level )
+  {
+    valid->base  = base;
+    valid->limit = limit;
+    valid->level = level;
+    valid->error = 0;
+  }
+
+
+  FT_BASE_DEF( FT_Int )
+  ft_validator_run( FT_Validator  valid )
+  {
+    int  result;
+
+
+    result = ft_setjmp( valid->jump_buffer );
+    return result;
+  }
+
+
+  FT_BASE_DEF( void )
+  ft_validator_error( FT_Validator  valid,
+                      FT_Error      error )
+  {
+    valid->error = error;
+    ft_longjmp( valid->jump_buffer, 1 );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                           S T R E A M                           ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* create a new input stream from a FT_Open_Args structure */
+  /*                                                         */
+  static FT_Error
+  ft_input_stream_new( FT_Library           library,
+                       const FT_Open_Args*  args,
+                       FT_Stream*           astream )
+  {
+    FT_Error   error;
+    FT_Memory  memory;
+    FT_Stream  stream;
+
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    if ( !args )
+      return FT_Err_Invalid_Argument;
+
+    *astream = 0;
+    memory   = library->memory;
+
+    if ( FT_NEW( stream ) )
+      goto Exit;
+
+    stream->memory = memory;
+
+    if ( args->flags & FT_OPEN_MEMORY )
+    {
+      /* create a memory-based stream */
+      FT_Stream_OpenMemory( stream,
+                            (const FT_Byte*)args->memory_base,
+                            args->memory_size );
+    }
+    else if ( args->flags & FT_OPEN_PATHNAME )
+    {
+      /* create a normal system stream */
+      error = FT_Stream_Open( stream, args->pathname );
+      stream->pathname.pointer = args->pathname;
+    }
+    else if ( ( args->flags & FT_OPEN_STREAM ) && args->stream )
+    {
+      /* use an existing, user-provided stream */
+
+      /* in this case, we do not need to allocate a new stream object */
+      /* since the caller is responsible for closing it himself       */
+      FT_FREE( stream );
+      stream = args->stream;
+    }
+    else
+      error = FT_Err_Invalid_Argument;
+
+    if ( error )
+      FT_FREE( stream );
+    else
+      stream->memory = memory;  /* just to be certain */
+
+    *astream = stream;
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  ft_input_stream_free( FT_Stream  stream,
+                        FT_Int     external )
+  {
+    if ( stream )
+    {
+      FT_Memory  memory = stream->memory;
+
+
+      FT_Stream_Close( stream );
+
+      if ( !external )
+        FT_FREE( stream );
+    }
+  }
+
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_objs
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****               FACE, SIZE & GLYPH SLOT OBJECTS                   ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static FT_Error
+  ft_glyphslot_init( FT_GlyphSlot  slot )
+  {
+    FT_Driver         driver = slot->face->driver;
+    FT_Driver_Class   clazz  = driver->clazz;
+    FT_Memory         memory = driver->root.memory;
+    FT_Error          error  = FT_Err_Ok;
+    FT_Slot_Internal  internal;
+
+
+    slot->library = driver->root.library;
+
+    if ( FT_NEW( internal ) )
+      goto Exit;
+
+    slot->internal = internal;
+
+    if ( FT_DRIVER_USES_OUTLINES( driver ) )
+      error = FT_GlyphLoader_New( memory, &internal->loader );
+
+    if ( !error && clazz->init_slot )
+      error = clazz->init_slot( slot );
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  ft_glyphslot_clear( FT_GlyphSlot  slot )
+  {
+    /* free bitmap if needed */
+    if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+    {
+      FT_Memory  memory = FT_FACE_MEMORY( slot->face );
+
+
+      FT_FREE( slot->bitmap.buffer );
+      slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+    }
+
+    /* clear all public fields in the glyph slot */
+    FT_ZERO( &slot->metrics );
+    FT_ZERO( &slot->outline );
+
+    slot->bitmap.width = 0;
+    slot->bitmap.rows  = 0;
+    slot->bitmap.pitch = 0;
+    slot->bitmap.pixel_mode = 0;
+    /* don't touch 'slot->bitmap.buffer' !! */
+
+    slot->bitmap_left   = 0;
+    slot->bitmap_top    = 0;
+    slot->num_subglyphs = 0;
+    slot->subglyphs     = 0;
+    slot->control_data  = 0;
+    slot->control_len   = 0;
+    slot->other         = 0;
+    slot->format        = FT_GLYPH_FORMAT_NONE;
+
+    slot->linearHoriAdvance = 0;
+    slot->linearVertAdvance = 0;
+  }
+
+
+  static void
+  ft_glyphslot_done( FT_GlyphSlot  slot )
+  {
+    FT_Driver         driver = slot->face->driver;
+    FT_Driver_Class   clazz  = driver->clazz;
+    FT_Memory         memory = driver->root.memory;
+
+
+    if ( clazz->done_slot )
+      clazz->done_slot( slot );
+
+    /* free bitmap buffer if needed */
+    if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+      FT_FREE( slot->bitmap.buffer );
+
+    /* free glyph loader */
+    if ( FT_DRIVER_USES_OUTLINES( driver ) )
+    {
+      FT_GlyphLoader_Done( slot->internal->loader );
+      slot->internal->loader = 0;
+    }
+
+    FT_FREE( slot->internal );
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_BASE_DEF( FT_Error )
+  FT_New_GlyphSlot( FT_Face        face,
+                    FT_GlyphSlot  *aslot )
+  {
+    FT_Error          error;
+    FT_Driver         driver;
+    FT_Driver_Class   clazz;
+    FT_Memory         memory;
+    FT_GlyphSlot      slot;
+
+
+    if ( !face || !aslot || !face->driver )
+      return FT_Err_Invalid_Argument;
+
+    *aslot = 0;
+
+    driver = face->driver;
+    clazz  = driver->clazz;
+    memory = driver->root.memory;
+
+    FT_TRACE4(( "FT_New_GlyphSlot: Creating new slot object\n" ));
+    if ( !FT_ALLOC( slot, clazz->slot_object_size ) )
+    {
+      slot->face = face;
+
+      error = ft_glyphslot_init( slot );
+      if ( error )
+      {
+        ft_glyphslot_done( slot );
+        FT_FREE( slot );
+        goto Exit;
+      }
+
+      *aslot = slot;
+    }
+
+  Exit:
+    FT_TRACE4(( "FT_New_GlyphSlot: Return %d\n", error ));
+    return error;
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_BASE_DEF( void )
+  FT_Done_GlyphSlot( FT_GlyphSlot  slot )
+  {
+    if ( slot )
+    {
+      FT_Driver      driver = slot->face->driver;
+      FT_Memory      memory = driver->root.memory;
+      FT_GlyphSlot*  parent;
+      FT_GlyphSlot   cur;
+
+
+      /* Remove slot from its parent face's list */
+      parent = &slot->face->glyph;
+      cur    = *parent;
+
+      while ( cur )
+      {
+        if ( cur == slot )
+        {
+          *parent = cur->next;
+          ft_glyphslot_done( slot );
+          FT_FREE( slot );
+          break;
+        }
+        cur = cur->next;
+      }
+    }
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Set_Transform( FT_Face     face,
+                    FT_Matrix*  matrix,
+                    FT_Vector*  delta )
+  {
+    FT_Face_Internal  internal;
+
+
+    if ( !face )
+      return;
+
+    internal = face->internal;
+
+    internal->transform_flags = 0;
+
+    if ( !matrix )
+    {
+      internal->transform_matrix.xx = 0x10000L;
+      internal->transform_matrix.xy = 0;
+      internal->transform_matrix.yx = 0;
+      internal->transform_matrix.yy = 0x10000L;
+      matrix = &internal->transform_matrix;
+    }
+    else
+      internal->transform_matrix = *matrix;
+
+    /* set transform_flags bit flag 0 if `matrix' isn't the identity */
+    if ( ( matrix->xy | matrix->yx ) ||
+         matrix->xx != 0x10000L      ||
+         matrix->yy != 0x10000L      )
+      internal->transform_flags |= 1;
+
+    if ( !delta )
+    {
+      internal->transform_delta.x = 0;
+      internal->transform_delta.y = 0;
+      delta = &internal->transform_delta;
+    }
+    else
+      internal->transform_delta = *delta;
+
+    /* set transform_flags bit flag 1 if `delta' isn't the null vector */
+    if ( delta->x | delta->y )
+      internal->transform_flags |= 2;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Set_Hint_Flags( FT_Face     face,
+                     FT_ULong    flags )
+  {
+    FT_Face_Internal  internal;
+
+    if ( !face )
+      return;
+
+    internal = face->internal;
+
+    internal->hint_flags = (FT_UInt)flags;
+  }
+
+
+  static FT_Renderer
+  ft_lookup_glyph_renderer( FT_GlyphSlot  slot );
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Load_Glyph( FT_Face   face,
+                 FT_UInt   glyph_index,
+                 FT_Int32  load_flags )
+  {
+    FT_Error      error;
+    FT_Driver     driver;
+    FT_GlyphSlot  slot;
+    FT_Library    library;
+    FT_Bool       autohint;
+    FT_Module     hinter;
+
+
+    if ( !face || !face->size || !face->glyph )
+      return FT_Err_Invalid_Face_Handle;
+
+    if ( glyph_index > (FT_UInt)face->num_glyphs )
+      return FT_Err_Invalid_Argument;
+
+    slot = face->glyph;
+    ft_glyphslot_clear( slot );
+
+    driver = face->driver;
+
+    /* if the flag NO_RECURSE is set, we disable hinting and scaling */
+    if ( load_flags & FT_LOAD_NO_RECURSE )
+    {
+      /* disable scaling, hinting, and transformation */
+      load_flags |= FT_LOAD_NO_SCALE         |
+                    FT_LOAD_NO_HINTING       |
+                    FT_LOAD_NO_BITMAP        |
+                    FT_LOAD_IGNORE_TRANSFORM;
+
+      /* disable bitmap rendering */
+      load_flags &= ~FT_LOAD_RENDER;
+    }
+
+    /* do we need to load the glyph through the auto-hinter? */
+    library  = driver->root.library;
+    hinter   = library->auto_hinter;
+    autohint =
+      FT_BOOL( hinter                                      &&
+               !( load_flags & ( FT_LOAD_NO_SCALE    |
+                                 FT_LOAD_NO_HINTING  |
+                                 FT_LOAD_NO_AUTOHINT ) )   &&
+               FT_DRIVER_IS_SCALABLE( driver )             &&
+               FT_DRIVER_USES_OUTLINES( driver )           );
+    if ( autohint )
+    {
+      if ( FT_DRIVER_HAS_HINTER( driver ) &&
+           !( load_flags & FT_LOAD_FORCE_AUTOHINT ) )
+        autohint = 0;
+    }
+
+    if ( autohint )
+    {
+      FT_AutoHinter_Service  hinting;
+
+
+      /* try to load embedded bitmaps first if available            */
+      /*                                                            */
+      /* XXX: This is really a temporary hack that should disappear */
+      /*      promptly with FreeType 2.1!                           */
+      /*                                                            */
+      if ( FT_HAS_FIXED_SIZES( face )             &&
+          ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
+      {
+        error = driver->clazz->load_glyph( slot, face->size,
+                                           glyph_index,
+                                           load_flags | FT_LOAD_SBITS_ONLY );
+
+        if ( !error && slot->format == FT_GLYPH_FORMAT_BITMAP )
+          goto Load_Ok;
+      }
+
+      /* load auto-hinted outline */
+      hinting = (FT_AutoHinter_Service)hinter->clazz->module_interface;
+
+      error   = hinting->load_glyph( (FT_AutoHinter)hinter,
+                                     slot, face->size,
+                                     glyph_index, load_flags );
+    }
+    else
+    {
+      error = driver->clazz->load_glyph( slot,
+                                         face->size,
+                                         glyph_index,
+                                         load_flags );
+      if ( error )
+        goto Exit;
+
+      /* check that the loaded outline is correct */
+      error = FT_Outline_Check( &slot->outline );
+      if ( error )
+        goto Exit;
+    }
+
+  Load_Ok:
+    /* compute the advance */
+    if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+    {
+      slot->advance.x = 0;
+      slot->advance.y = slot->metrics.vertAdvance;
+    }
+    else
+    {
+      slot->advance.x = slot->metrics.horiAdvance;
+      slot->advance.y = 0;
+    }
+
+    /* compute the linear advance in 16.16 pixels */
+    if ( ( load_flags & FT_LOAD_LINEAR_DESIGN ) == 0 )
+    {
+      FT_UInt           EM      = face->units_per_EM;
+      FT_Size_Metrics*  metrics = &face->size->metrics;
+
+
+      slot->linearHoriAdvance = FT_MulDiv( slot->linearHoriAdvance,
+                                           (FT_Long)metrics->x_ppem << 16, EM );
+
+      slot->linearVertAdvance = FT_MulDiv( slot->linearVertAdvance,
+                                           (FT_Long)metrics->y_ppem << 16, EM );
+    }
+
+    if ( ( load_flags & FT_LOAD_IGNORE_TRANSFORM ) == 0 )
+    {
+      FT_Face_Internal  internal = face->internal;
+
+
+      /* now, transform the glyph image if needed */
+      if ( internal->transform_flags )
+      {
+        /* get renderer */
+        FT_Renderer  renderer = ft_lookup_glyph_renderer( slot );
+
+
+        if ( renderer )
+          error = renderer->clazz->transform_glyph(
+                                     renderer, slot,
+                                     &internal->transform_matrix,
+                                     &internal->transform_delta );
+        /* transform advance */
+        FT_Vector_Transform( &slot->advance, &internal->transform_matrix );
+      }
+    }
+
+    /* do we need to render the image now? */
+    if ( !error                                    &&
+         slot->format != FT_GLYPH_FORMAT_BITMAP    &&
+         slot->format != FT_GLYPH_FORMAT_COMPOSITE &&
+         load_flags & FT_LOAD_RENDER )
+    {
+      FT_Render_Mode  mode = FT_LOAD_TARGET_MODE( load_flags );
+
+
+      if ( mode == FT_RENDER_MODE_NORMAL      &&
+           (load_flags & FT_LOAD_MONOCHROME ) )
+        mode = FT_RENDER_MODE_MONO;
+
+      error = FT_Render_Glyph( slot, mode );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Load_Char( FT_Face   face,
+                FT_ULong  char_code,
+                FT_Int32  load_flags )
+  {
+    FT_UInt  glyph_index;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    glyph_index = (FT_UInt)char_code;
+    if ( face->charmap )
+      glyph_index = FT_Get_Char_Index( face, char_code );
+
+    return FT_Load_Glyph( face, glyph_index, load_flags );
+  }
+
+
+  /* destructor for sizes list */
+  static void
+  destroy_size( FT_Memory  memory,
+                FT_Size    size,
+                FT_Driver  driver )
+  {
+    /* finalize client-specific data */
+    if ( size->generic.finalizer )
+      size->generic.finalizer( size );
+
+    /* finalize format-specific stuff */
+    if ( driver->clazz->done_size )
+      driver->clazz->done_size( size );
+
+    FT_FREE( size->internal );
+    FT_FREE( size );
+  }
+
+
+  /* destructor for faces list */
+  static void
+  destroy_face( FT_Memory  memory,
+                FT_Face    face,
+                FT_Driver  driver )
+  {
+    FT_Driver_Class  clazz = driver->clazz;
+
+
+    /* discard auto-hinting data */
+    if ( face->autohint.finalizer )
+      face->autohint.finalizer( face->autohint.data );
+
+    /* Discard glyph slots for this face.                           */
+    /* Beware!  FT_Done_GlyphSlot() changes the field `face->glyph' */
+    while ( face->glyph )
+      FT_Done_GlyphSlot( face->glyph );
+
+    /* discard all sizes for this face */
+    FT_List_Finalize( &face->sizes_list,
+                     (FT_List_Destructor)destroy_size,
+                     memory,
+                     driver );
+    face->size = 0;
+
+    /* now discard client data */
+    if ( face->generic.finalizer )
+      face->generic.finalizer( face );
+
+    /* discard charmaps */
+    {
+      FT_Int  n;
+
+
+      for ( n = 0; n < face->num_charmaps; n++ )
+      {
+        FT_CMap  cmap = FT_CMAP( face->charmaps[n] );
+
+
+        FT_CMap_Done( cmap );
+
+        face->charmaps[n] = NULL;
+      }
+
+      FT_FREE( face->charmaps );
+      face->num_charmaps = 0;
+    }
+
+
+    /* finalize format-specific stuff */
+    if ( clazz->done_face )
+      clazz->done_face( face );
+
+    /* close the stream for this face if needed */
+    ft_input_stream_free(
+      face->stream,
+      ( face->face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
+
+    face->stream = 0;
+
+    /* get rid of it */
+    if ( face->internal )
+    {
+      FT_FREE( face->internal->postscript_name );
+      FT_FREE( face->internal );
+    }
+    FT_FREE( face );
+  }
+
+
+  static void
+  Destroy_Driver( FT_Driver  driver )
+  {
+    FT_List_Finalize( &driver->faces_list,
+                      (FT_List_Destructor)destroy_face,
+                      driver->root.memory,
+                      driver );
+
+    /* check whether we need to drop the driver's glyph loader */
+    if ( FT_DRIVER_USES_OUTLINES( driver ) )
+      FT_GlyphLoader_Done( driver->glyph_loader );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    open_face                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function does some work for FT_Open_Face().                   */
+  /*                                                                       */
+  static FT_Error
+  open_face( FT_Driver      driver,
+             FT_Stream      stream,
+             FT_Long        face_index,
+             FT_Int         num_params,
+             FT_Parameter*  params,
+             FT_Face*       aface )
+  {
+    FT_Memory         memory;
+    FT_Driver_Class  clazz;
+    FT_Face           face = 0;
+    FT_Error          error;
+    FT_Face_Internal  internal;
+
+
+    clazz  = driver->clazz;
+    memory = driver->root.memory;
+
+    /* allocate the face object and perform basic initialization */
+    if ( FT_ALLOC( face, clazz->face_object_size ) )
+      goto Fail;
+
+    if ( FT_NEW( internal ) )
+      goto Fail;
+
+    face->internal = internal;
+
+    face->driver   = driver;
+    face->memory   = memory;
+    face->stream   = stream;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    {
+      int  i;
+
+
+      face->internal->incremental_interface = 0;
+      for ( i = 0; i < num_params && !face->internal->incremental_interface;
+            i++ )
+        if ( params[i].tag == FT_PARAM_TAG_INCREMENTAL )
+          face->internal->incremental_interface = params[i].data;
+	}
+#endif
+
+    error = clazz->init_face( stream,
+                              face,
+                              (FT_Int)face_index,
+                              num_params,
+                              params );
+    if ( error )
+      goto Fail;
+
+    /* select Unicode charmap by default */
+    {
+      FT_Int      nn;
+      FT_CharMap  unicmap = NULL, cmap;
+
+
+      for ( nn = 0; nn < face->num_charmaps; nn++ )
+      {
+        cmap = face->charmaps[nn];
+
+        if ( cmap->encoding == FT_ENCODING_UNICODE )
+        {
+          unicmap = cmap;
+          break;
+        }
+      }
+
+      if ( unicmap != NULL )
+        face->charmap = unicmap;
+    }
+
+    *aface = face;
+
+  Fail:
+    if ( error )
+    {
+      clazz->done_face( face );
+      FT_FREE( face->internal );
+      FT_FREE( face );
+      *aface = 0;
+    }
+
+    return error;
+  }
+
+
+  /* there's a Mac-specific extended implementation of FT_New_Face() */
+  /* in src/base/ftmac.c                                             */
+
+#ifndef FT_MACINTOSH
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Face( FT_Library   library,
+               const char*  pathname,
+               FT_Long      face_index,
+               FT_Face     *aface )
+  {
+    FT_Open_Args  args;
+
+
+    /* test for valid `library' and `aface' delayed to FT_Open_Face() */
+    if ( !pathname )
+      return FT_Err_Invalid_Argument;
+
+    args.flags    = FT_OPEN_PATHNAME;
+    args.pathname = (char*)pathname;
+
+    return FT_Open_Face( library, &args, face_index, aface );
+  }
+
+#endif  /* !FT_MACINTOSH */
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Memory_Face( FT_Library      library,
+                      const FT_Byte*  file_base,
+                      FT_Long         file_size,
+                      FT_Long         face_index,
+                      FT_Face        *aface )
+  {
+    FT_Open_Args  args;
+
+
+    /* test for valid `library' and `face' delayed to FT_Open_Face() */
+    if ( !file_base )
+      return FT_Err_Invalid_Argument;
+
+    args.flags       = FT_OPEN_MEMORY;
+    args.memory_base = file_base;
+    args.memory_size = file_size;
+
+    return FT_Open_Face( library, &args, face_index, aface );
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Open_Face( FT_Library           library,
+                const FT_Open_Args*  args,
+                FT_Long              face_index,
+                FT_Face             *aface )
+  {
+    FT_Error     error;
+    FT_Driver    driver;
+    FT_Memory    memory;
+    FT_Stream    stream;
+    FT_Face      face = 0;
+    FT_ListNode  node = 0;
+    FT_Bool      external_stream;
+
+
+    /* test for valid `library' delayed to */
+    /* ft_input_stream_new()               */
+
+    if ( !aface || !args )
+      return FT_Err_Invalid_Argument;
+
+    *aface = 0;
+
+    external_stream = FT_BOOL( ( args->flags & FT_OPEN_STREAM ) &&
+                               args->stream                     );
+
+    /* create input stream */
+    error = ft_input_stream_new( library, args, &stream );
+    if ( error )
+      goto Exit;
+
+    memory = library->memory;
+
+    /* If the font driver is specified in the `args' structure, use */
+    /* it.  Otherwise, we scan the list of registered drivers.      */
+    if ( ( args->flags & FT_OPEN_DRIVER ) && args->driver )
+    {
+      driver = FT_DRIVER( args->driver );
+
+      /* not all modules are drivers, so check... */
+      if ( FT_MODULE_IS_DRIVER( driver ) )
+      {
+        FT_Int         num_params = 0;
+        FT_Parameter*  params     = 0;
+
+
+        if ( args->flags & FT_OPEN_PARAMS )
+        {
+          num_params = args->num_params;
+          params     = args->params;
+        }
+
+        error = open_face( driver, stream, face_index,
+                           num_params, params, &face );
+        if ( !error )
+          goto Success;
+      }
+      else
+        error = FT_Err_Invalid_Handle;
+
+      ft_input_stream_free( stream, external_stream );
+      goto Fail;
+    }
+    else
+    {
+      /* check each font driver for an appropriate format */
+      FT_Module*  cur   = library->modules;
+      FT_Module*  limit = cur + library->num_modules;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        /* not all modules are font drivers, so check... */
+        if ( FT_MODULE_IS_DRIVER( cur[0] ) )
+        {
+          FT_Int         num_params = 0;
+          FT_Parameter*  params     = 0;
+
+
+          driver = FT_DRIVER( cur[0] );
+
+          if ( args->flags & FT_OPEN_PARAMS )
+          {
+            num_params = args->num_params;
+            params     = args->params;
+          }
+
+          error = open_face( driver, stream, face_index,
+                            num_params, params, &face );
+          if ( !error )
+            goto Success;
+
+          if ( FT_ERROR_BASE( error ) != FT_Err_Unknown_File_Format )
+            goto Fail2;
+        }
+      }
+
+      /* no driver is able to handle this format */
+      error = FT_Err_Unknown_File_Format;
+
+  Fail2:
+      ft_input_stream_free( stream, external_stream );
+      goto Fail;
+    }
+
+  Success:
+    FT_TRACE4(( "FT_Open_Face: New face object, adding to list\n" ));
+
+    /* set the FT_FACE_FLAG_EXTERNAL_STREAM bit for FT_Done_Face */
+    if ( external_stream )
+      face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
+
+    /* add the face object to its driver's list */
+    if ( FT_NEW( node ) )
+      goto Fail;
+
+    node->data = face;
+    /* don't assume driver is the same as face->driver, so use */
+    /* face->driver instead.                                   */
+    FT_List_Add( &face->driver->faces_list, node );
+
+    /* now allocate a glyph slot object for the face */
+    {
+      FT_GlyphSlot  slot;
+
+
+      FT_TRACE4(( "FT_Open_Face: Creating glyph slot\n" ));
+
+      error = FT_New_GlyphSlot( face, &slot );
+      if ( error )
+        goto Fail;
+
+      face->glyph = slot;
+    }
+
+    /* finally, allocate a size object for the face */
+    {
+      FT_Size  size;
+
+
+      FT_TRACE4(( "FT_Open_Face: Creating size object\n" ));
+
+      error = FT_New_Size( face, &size );
+      if ( error )
+        goto Fail;
+
+      face->size = size;
+    }
+
+    /* initialize internal face data */
+    {
+      FT_Face_Internal  internal = face->internal;
+
+
+      internal->transform_matrix.xx = 0x10000L;
+      internal->transform_matrix.xy = 0;
+      internal->transform_matrix.yx = 0;
+      internal->transform_matrix.yy = 0x10000L;
+
+      internal->transform_delta.x = 0;
+      internal->transform_delta.y = 0;
+    }
+
+    *aface = face;
+    goto Exit;
+
+  Fail:
+    FT_Done_Face( face );
+
+  Exit:
+    FT_TRACE4(( "FT_Open_Face: Return %d\n", error ));
+
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Attach_File( FT_Face      face,
+                  const char*  filepathname )
+  {
+    FT_Open_Args  open;
+
+
+    /* test for valid `face' delayed to FT_Attach_Stream() */
+
+    if ( !filepathname )
+      return FT_Err_Invalid_Argument;
+
+    open.flags    = FT_OPEN_PATHNAME;
+    open.pathname = (char*)filepathname;
+
+    return FT_Attach_Stream( face, &open );
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Attach_Stream( FT_Face        face,
+                    FT_Open_Args*  parameters )
+  {
+    FT_Stream  stream;
+    FT_Error   error;
+    FT_Driver  driver;
+
+    FT_Driver_Class  clazz;
+
+
+    /* test for valid `parameters' delayed to ft_input_stream_new() */
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    driver = face->driver;
+    if ( !driver )
+      return FT_Err_Invalid_Driver_Handle;
+
+    error = ft_input_stream_new( driver->root.library, parameters, &stream );
+    if ( error )
+      goto Exit;
+
+    /* we implement FT_Attach_Stream in each driver through the */
+    /* `attach_file' interface                                  */
+
+    error = FT_Err_Unimplemented_Feature;
+    clazz = driver->clazz;
+    if ( clazz->attach_file )
+      error = clazz->attach_file( face, stream );
+
+    /* close the attached stream */
+    ft_input_stream_free( stream,
+                    (FT_Bool)( parameters->stream &&
+                               ( parameters->flags & FT_OPEN_STREAM ) ) );
+
+  Exit:
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Done_Face( FT_Face  face )
+  {
+    FT_Error     error;
+    FT_Driver    driver;
+    FT_Memory    memory;
+    FT_ListNode  node;
+
+
+    error = FT_Err_Invalid_Face_Handle;
+    if ( face && face->driver )
+    {
+      driver = face->driver;
+      memory = driver->root.memory;
+
+      /* find face in driver's list */
+      node = FT_List_Find( &driver->faces_list, face );
+      if ( node )
+      {
+        /* remove face object from the driver's list */
+        FT_List_Remove( &driver->faces_list, node );
+        FT_FREE( node );
+
+        /* now destroy the object proper */
+        destroy_face( memory, face, driver );
+        error = FT_Err_Ok;
+      }
+    }
+    return error;
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Size( FT_Face   face,
+               FT_Size  *asize )
+  {
+    FT_Error         error;
+    FT_Memory        memory;
+    FT_Driver        driver;
+    FT_Driver_Class  clazz;
+
+    FT_Size          size = 0;
+    FT_ListNode      node = 0;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    if ( !asize )
+      return FT_Err_Invalid_Size_Handle;
+
+    if ( !face->driver )
+      return FT_Err_Invalid_Driver_Handle;
+
+    *asize = 0;
+
+    driver = face->driver;
+    clazz  = driver->clazz;
+    memory = face->memory;
+
+    /* Allocate new size object and perform basic initialisation */
+    if ( FT_ALLOC( size, clazz->size_object_size ) || FT_NEW( node ) )
+      goto Exit;
+
+    size->face = face;
+
+    /* for now, do not use any internal fields in size objects */
+    size->internal = 0;
+
+    if ( clazz->init_size )
+      error = clazz->init_size( size );
+
+    /* in case of success, add to the face's list */
+    if ( !error )
+    {
+      *asize     = size;
+      node->data = size;
+      FT_List_Add( &face->sizes_list, node );
+    }
+
+  Exit:
+    if ( error )
+    {
+      FT_FREE( node );
+      FT_FREE( size );
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Done_Size( FT_Size  size )
+  {
+    FT_Error     error;
+    FT_Driver    driver;
+    FT_Memory    memory;
+    FT_Face      face;
+    FT_ListNode  node;
+
+
+    if ( !size )
+      return FT_Err_Invalid_Size_Handle;
+
+    face = size->face;
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    driver = face->driver;
+    if ( !driver )
+      return FT_Err_Invalid_Driver_Handle;
+
+    memory = driver->root.memory;
+
+    error = FT_Err_Ok;
+    node  = FT_List_Find( &face->sizes_list, size );
+    if ( node )
+    {
+      FT_List_Remove( &face->sizes_list, node );
+      FT_FREE( node );
+
+      if ( face->size == size )
+      {
+        face->size = 0;
+        if ( face->sizes_list.head )
+          face->size = (FT_Size)(face->sizes_list.head->data);
+      }
+
+      destroy_size( memory, size, driver );
+    }
+    else
+      error = FT_Err_Invalid_Size_Handle;
+
+    return error;
+  }
+
+
+  static void
+  ft_recompute_scaled_metrics( FT_Face           face,
+                               FT_Size_Metrics*  metrics )
+  {
+    /* Compute root ascender, descender, test height, and max_advance */
+
+    metrics->ascender    = ( FT_MulFix( face->ascender,
+                                        metrics->y_scale ) + 32 ) & -64;
+
+    metrics->descender   = ( FT_MulFix( face->descender,
+                                        metrics->y_scale ) + 32 ) & -64;
+
+    metrics->height      = ( FT_MulFix( face->height,
+                                        metrics->y_scale ) + 32 ) & -64;
+
+    metrics->max_advance = ( FT_MulFix( face->max_advance_width,
+                                        metrics->x_scale ) + 32 ) & -64;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Set_Char_Size( FT_Face     face,
+                    FT_F26Dot6  char_width,
+                    FT_F26Dot6  char_height,
+                    FT_UInt     horz_resolution,
+                    FT_UInt     vert_resolution )
+  {
+    FT_Error          error = FT_Err_Ok;
+    FT_Driver         driver;
+    FT_Driver_Class   clazz;
+    FT_Size_Metrics*  metrics;
+    FT_Long           dim_x, dim_y;
+
+
+    if ( !face || !face->size || !face->driver )
+      return FT_Err_Invalid_Face_Handle;
+
+    driver  = face->driver;
+    metrics = &face->size->metrics;
+
+    if ( !char_width )
+      char_width = char_height;
+
+    else if ( !char_height )
+      char_height = char_width;
+
+    if ( !horz_resolution )
+      horz_resolution = 72;
+
+    if ( !vert_resolution )
+      vert_resolution = 72;
+
+    driver = face->driver;
+    clazz  = driver->clazz;
+
+    /* default processing -- this can be overridden by the driver */
+    if ( char_width  < 1 * 64 )
+      char_width  = 1 * 64;
+    if ( char_height < 1 * 64 )
+      char_height = 1 * 64;
+
+    /* Compute pixel sizes in 26.6 units */
+    dim_x = ( ( ( char_width  * horz_resolution ) / 72 ) + 32 ) & -64;
+    dim_y = ( ( ( char_height * vert_resolution ) / 72 ) + 32 ) & -64;
+
+    metrics->x_ppem  = (FT_UShort)( dim_x >> 6 );
+    metrics->y_ppem  = (FT_UShort)( dim_y >> 6 );
+
+    metrics->x_scale = 0x10000L;
+    metrics->y_scale = 0x10000L;
+
+    if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+    {
+      metrics->x_scale = FT_DivFix( dim_x, face->units_per_EM );
+      metrics->y_scale = FT_DivFix( dim_y, face->units_per_EM );
+
+      ft_recompute_scaled_metrics( face, metrics );
+    }
+
+    if ( clazz->set_char_sizes )
+      error = clazz->set_char_sizes( face->size,
+                                     char_width,
+                                     char_height,
+                                     horz_resolution,
+                                     vert_resolution );
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Set_Pixel_Sizes( FT_Face  face,
+                      FT_UInt  pixel_width,
+                      FT_UInt  pixel_height )
+  {
+    FT_Error          error = FT_Err_Ok;
+    FT_Driver         driver;
+    FT_Driver_Class   clazz;
+    FT_Size_Metrics*  metrics = &face->size->metrics;
+
+
+    if ( !face || !face->size || !face->driver )
+      return FT_Err_Invalid_Face_Handle;
+
+    driver = face->driver;
+    clazz  = driver->clazz;
+
+    /* default processing -- this can be overridden by the driver */
+    if ( pixel_width == 0 )
+      pixel_width = pixel_height;
+
+    else if ( pixel_height == 0 )
+      pixel_height = pixel_width;
+
+    if ( pixel_width  < 1 )
+      pixel_width  = 1;
+    if ( pixel_height < 1 )
+      pixel_height = 1;
+
+    metrics->x_ppem = (FT_UShort)pixel_width;
+    metrics->y_ppem = (FT_UShort)pixel_height;
+
+    if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+    {
+      metrics->x_scale = FT_DivFix( metrics->x_ppem << 6,
+                                    face->units_per_EM );
+
+      metrics->y_scale = FT_DivFix( metrics->y_ppem << 6,
+                                    face->units_per_EM );
+
+      ft_recompute_scaled_metrics( face, metrics );
+    }
+
+    if ( clazz->set_pixel_sizes )
+      error = clazz->set_pixel_sizes( face->size,
+                                      pixel_width,
+                                      pixel_height );
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_Kerning( FT_Face     face,
+                  FT_UInt     left_glyph,
+                  FT_UInt     right_glyph,
+                  FT_UInt     kern_mode,
+                  FT_Vector  *akerning )
+  {
+    FT_Error   error = FT_Err_Ok;
+    FT_Driver  driver;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    if ( !akerning )
+      return FT_Err_Invalid_Argument;
+
+    driver = face->driver;
+
+    akerning->x = 0;
+    akerning->y = 0;
+
+    if ( driver->clazz->get_kerning )
+    {
+      error = driver->clazz->get_kerning( face,
+                                          left_glyph,
+                                          right_glyph,
+                                          akerning );
+      if ( !error )
+      {
+        if ( kern_mode != FT_KERNING_UNSCALED )
+        {
+          akerning->x = FT_MulFix( akerning->x, face->size->metrics.x_scale );
+          akerning->y = FT_MulFix( akerning->y, face->size->metrics.y_scale );
+
+          if ( kern_mode != FT_KERNING_UNFITTED )
+          {
+            akerning->x = ( akerning->x + 32 ) & -64;
+            akerning->y = ( akerning->y + 32 ) & -64;
+          }
+        }
+      }
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Select_Charmap( FT_Face      face,
+                     FT_Encoding  encoding )
+  {
+    FT_CharMap*  cur;
+    FT_CharMap*  limit;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    cur = face->charmaps;
+    if ( !cur )
+      return FT_Err_Invalid_CharMap_Handle;
+
+    limit = cur + face->num_charmaps;
+
+    for ( ; cur < limit; cur++ )
+    {
+      if ( cur[0]->encoding == encoding )
+      {
+        face->charmap = cur[0];
+        return 0;
+      }
+    }
+
+    return FT_Err_Invalid_Argument;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Set_Charmap( FT_Face     face,
+                  FT_CharMap  charmap )
+  {
+    FT_CharMap*  cur;
+    FT_CharMap*  limit;
+
+
+    if ( !face )
+      return FT_Err_Invalid_Face_Handle;
+
+    cur = face->charmaps;
+    if ( !cur )
+      return FT_Err_Invalid_CharMap_Handle;
+
+    limit = cur + face->num_charmaps;
+
+    for ( ; cur < limit; cur++ )
+    {
+      if ( cur[0] == charmap )
+      {
+        face->charmap = cur[0];
+        return 0;
+      }
+    }
+    return FT_Err_Invalid_Argument;
+  }
+
+
+  FT_BASE_DEF( void )
+  FT_CMap_Done( FT_CMap  cmap )
+  {
+    if ( cmap )
+    {
+      FT_CMap_Class  clazz  = cmap->clazz;
+      FT_Face        face   = cmap->charmap.face;
+      FT_Memory      memory = FT_FACE_MEMORY(face);
+
+
+      if ( clazz->done )
+        clazz->done( cmap );
+
+      FT_FREE( cmap );
+    }
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_CMap_New( FT_CMap_Class   clazz,
+               FT_Pointer      init_data,
+               FT_CharMap      charmap,
+               FT_CMap        *acmap )
+  {
+    FT_Error   error = 0;
+    FT_Face    face;
+    FT_Memory  memory;
+    FT_CMap    cmap;
+
+
+    if ( clazz == NULL || charmap == NULL || charmap->face == NULL )
+      return FT_Err_Invalid_Argument;
+
+    face   = charmap->face;
+    memory = FT_FACE_MEMORY(face);
+
+    if ( !FT_ALLOC( cmap, clazz->size ) )
+    {
+      cmap->charmap = *charmap;
+      cmap->clazz   = clazz;
+
+      if ( clazz->init )
+      {
+        error = clazz->init( cmap, init_data );
+        if ( error )
+          goto Fail;
+      }
+
+      /* add it to our list of charmaps */
+      if ( FT_RENEW_ARRAY( face->charmaps,
+                           face->num_charmaps,
+                           face->num_charmaps+1 ) )
+        goto Fail;
+
+      face->charmaps[face->num_charmaps++] = (FT_CharMap)cmap;
+    }
+
+  Exit:
+    if ( acmap )
+      *acmap = cmap;
+
+    return error;
+
+  Fail:
+    FT_CMap_Done( cmap );
+    cmap = NULL;
+    goto Exit;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_UInt )
+  FT_Get_Char_Index( FT_Face   face,
+                     FT_ULong  charcode )
+  {
+    FT_UInt  result = 0;
+
+
+    if ( face && face->charmap )
+    {
+      FT_CMap  cmap = FT_CMAP( face->charmap );
+
+
+      result = cmap->clazz->char_index( cmap, charcode );
+    }
+    return  result;
+  }
+
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_ULong )
+  FT_Get_First_Char( FT_Face   face,
+                     FT_UInt  *agindex )
+  {
+    FT_ULong  result = 0;
+    FT_UInt   gindex = 0;
+
+
+    if ( face && face->charmap )
+    {
+      gindex = FT_Get_Char_Index( face, 0 );
+      if ( gindex == 0 )
+        result = FT_Get_Next_Char( face, 0, &gindex );
+    }
+
+    if ( agindex  )
+      *agindex = gindex;
+
+    return result;
+  }
+
+  /* documentation is in freetype.h */
+
+
+  FT_EXPORT_DEF( FT_ULong )
+  FT_Get_Next_Char( FT_Face   face,
+                    FT_ULong  charcode,
+                    FT_UInt  *agindex )
+  {
+    FT_ULong  result = 0;
+    FT_UInt   gindex = 0;
+
+
+    if ( face && face->charmap )
+    {
+      FT_UInt32  code = (FT_UInt32)charcode;
+      FT_CMap    cmap = FT_CMAP( face->charmap );
+
+
+      gindex = cmap->clazz->char_next( cmap, &code );
+      result = ( gindex == 0 ) ? 0 : code;
+    }
+
+    if ( agindex )
+      *agindex = gindex;
+
+    return result;
+  }
+
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_UInt )
+  FT_Get_Name_Index( FT_Face     face,
+                     FT_String*  glyph_name )
+  {
+    FT_UInt  result = 0;
+
+
+    if ( face && FT_HAS_GLYPH_NAMES( face ) )
+    {
+      /* now, lookup for glyph name */
+      FT_Driver         driver = face->driver;
+      FT_Module_Class*  clazz  = FT_MODULE_CLASS( driver );
+
+
+      if ( clazz->get_interface )
+      {
+        FT_Face_GetGlyphNameIndexFunc  requester;
+
+
+        requester = (FT_Face_GetGlyphNameIndexFunc)clazz->get_interface(
+                      FT_MODULE( driver ), "name_index" );
+        if ( requester )
+          result = requester( face, glyph_name );
+      }
+    }
+
+    return result;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_Glyph_Name( FT_Face     face,
+                     FT_UInt     glyph_index,
+                     FT_Pointer  buffer,
+                     FT_UInt     buffer_max )
+  {
+    FT_Error  error = FT_Err_Invalid_Argument;
+
+
+    /* clean up buffer */
+    if ( buffer && buffer_max > 0 )
+      ((FT_Byte*)buffer)[0] = 0;
+
+    if ( face                                     &&
+         glyph_index <= (FT_UInt)face->num_glyphs &&
+         FT_HAS_GLYPH_NAMES( face )               )
+    {
+      /* now, lookup for glyph name */
+      FT_Driver         driver = face->driver;
+      FT_Module_Class*  clazz  = FT_MODULE_CLASS( driver );
+
+
+      if ( clazz->get_interface )
+      {
+        FT_Face_GetGlyphNameFunc  requester;
+
+
+        requester = (FT_Face_GetGlyphNameFunc)clazz->get_interface(
+                      FT_MODULE( driver ), "glyph_name" );
+        if ( requester )
+          error = requester( face, glyph_index, buffer, buffer_max );
+      }
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( const char* )
+  FT_Get_Postscript_Name( FT_Face  face )
+  {
+    const char*  result = NULL;
+
+
+    if ( !face )
+      goto Exit;
+
+    result = face->internal->postscript_name;
+    if ( !result )
+    {
+      /* now, look up glyph name */
+      FT_Driver         driver = face->driver;
+      FT_Module_Class*  clazz  = FT_MODULE_CLASS( driver );
+
+
+      if ( clazz->get_interface )
+      {
+        FT_Face_GetPostscriptNameFunc  requester;
+
+
+        requester = (FT_Face_GetPostscriptNameFunc)clazz->get_interface(
+                      FT_MODULE( driver ), "postscript_name" );
+        if ( requester )
+          result = requester( face );
+      }
+    }
+  Exit:
+    return result;
+  }
+
+
+  /* documentation is in tttables.h */
+
+  FT_EXPORT_DEF( void* )
+  FT_Get_Sfnt_Table( FT_Face      face,
+                     FT_Sfnt_Tag  tag )
+  {
+    void*                   table = 0;
+    FT_Get_Sfnt_Table_Func  func;
+    FT_Driver               driver;
+
+
+    if ( !face || !FT_IS_SFNT( face ) )
+      goto Exit;
+
+    driver = face->driver;
+    func = (FT_Get_Sfnt_Table_Func)driver->root.clazz->get_interface(
+                                     FT_MODULE( driver ), "get_sfnt" );
+    if ( func )
+      table = func( face, tag );
+
+  Exit:
+    return table;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Activate_Size( FT_Size  size )
+  {
+    FT_Face  face;
+
+
+    if ( size == NULL )
+      return FT_Err_Bad_Argument;
+
+    face = size->face;
+    if ( face == NULL || face->driver == NULL )
+      return FT_Err_Bad_Argument;
+
+    /* we don't need anything more complex than that; all size objects */
+    /* are already listed by the face                                  */
+    face->size = size;
+
+    return FT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                        R E N D E R E R S                        ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* lookup a renderer by glyph format in the library's list */
+  FT_BASE_DEF( FT_Renderer )
+  FT_Lookup_Renderer( FT_Library       library,
+                      FT_Glyph_Format  format,
+                      FT_ListNode*     node )
+  {
+    FT_ListNode  cur;
+    FT_Renderer  result = 0;
+
+
+    if ( !library )
+      goto Exit;
+
+    cur = library->renderers.head;
+
+    if ( node )
+    {
+      if ( *node )
+        cur = (*node)->next;
+      *node = 0;
+    }
+
+    while ( cur )
+    {
+      FT_Renderer  renderer = FT_RENDERER( cur->data );
+
+
+      if ( renderer->glyph_format == format )
+      {
+        if ( node )
+          *node = cur;
+
+        result = renderer;
+        break;
+      }
+      cur = cur->next;
+    }
+
+  Exit:
+    return result;
+  }
+
+
+  static FT_Renderer
+  ft_lookup_glyph_renderer( FT_GlyphSlot  slot )
+  {
+    FT_Face      face    = slot->face;
+    FT_Library   library = FT_FACE_LIBRARY( face );
+    FT_Renderer  result  = library->cur_renderer;
+
+
+    if ( !result || result->glyph_format != slot->format )
+      result = FT_Lookup_Renderer( library, slot->format, 0 );
+
+    return result;
+  }
+
+
+  static void
+  ft_set_current_renderer( FT_Library  library )
+  {
+    FT_Renderer  renderer;
+
+
+    renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 0 );
+    library->cur_renderer = renderer;
+  }
+
+
+  static FT_Error
+  ft_add_renderer( FT_Module  module )
+  {
+    FT_Library   library = module->library;
+    FT_Memory    memory  = library->memory;
+    FT_Error     error;
+    FT_ListNode  node;
+
+
+    if ( FT_NEW( node ) )
+      goto Exit;
+
+    {
+      FT_Renderer         render = FT_RENDERER( module );
+      FT_Renderer_Class*  clazz  = (FT_Renderer_Class*)module->clazz;
+
+
+      render->clazz        = clazz;
+      render->glyph_format = clazz->glyph_format;
+
+      /* allocate raster object if needed */
+      if ( clazz->glyph_format == FT_GLYPH_FORMAT_OUTLINE &&
+           clazz->raster_class->raster_new )
+      {
+        error = clazz->raster_class->raster_new( memory, &render->raster );
+        if ( error )
+          goto Fail;
+
+        render->raster_render = clazz->raster_class->raster_render;
+        render->render        = clazz->render_glyph;
+      }
+
+      /* add to list */
+      node->data = module;
+      FT_List_Add( &library->renderers, node );
+
+      ft_set_current_renderer( library );
+    }
+
+  Fail:
+    if ( error )
+      FT_FREE( node );
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  ft_remove_renderer( FT_Module  module )
+  {
+    FT_Library   library = module->library;
+    FT_Memory    memory  = library->memory;
+    FT_ListNode  node;
+
+
+    node = FT_List_Find( &library->renderers, module );
+    if ( node )
+    {
+      FT_Renderer  render = FT_RENDERER( module );
+
+
+      /* release raster object, if any */
+      if ( render->raster )
+        render->clazz->raster_class->raster_done( render->raster );
+
+      /* remove from list */
+      FT_List_Remove( &library->renderers, node );
+      FT_FREE( node );
+
+      ft_set_current_renderer( library );
+    }
+  }
+
+
+  /* documentation is in ftrender.h */
+
+  FT_EXPORT_DEF( FT_Renderer )
+  FT_Get_Renderer( FT_Library       library,
+                   FT_Glyph_Format  format )
+  {
+    /* test for valid `library' delayed to FT_Lookup_Renderer() */
+
+    return FT_Lookup_Renderer( library, format, 0 );
+  }
+
+
+  /* documentation is in ftrender.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Set_Renderer( FT_Library     library,
+                   FT_Renderer    renderer,
+                   FT_UInt        num_params,
+                   FT_Parameter*  parameters )
+  {
+    FT_ListNode  node;
+    FT_Error     error = FT_Err_Ok;
+
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    if ( !renderer )
+      return FT_Err_Invalid_Argument;
+
+    node = FT_List_Find( &library->renderers, renderer );
+    if ( !node )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    FT_List_Up( &library->renderers, node );
+
+    if ( renderer->glyph_format == FT_GLYPH_FORMAT_OUTLINE )
+      library->cur_renderer = renderer;
+
+    if ( num_params > 0 )
+    {
+      FT_Renderer_SetModeFunc  set_mode = renderer->clazz->set_mode;
+
+
+      for ( ; num_params > 0; num_params-- )
+      {
+        error = set_mode( renderer, parameters->tag, parameters->data );
+        if ( error )
+          break;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Render_Glyph_Internal( FT_Library      library,
+                            FT_GlyphSlot    slot,
+                            FT_Render_Mode  render_mode )
+  {
+    FT_Error     error = FT_Err_Ok;
+    FT_Renderer  renderer;
+
+
+    /* if it is already a bitmap, no need to do anything */
+    switch ( slot->format )
+    {
+    case FT_GLYPH_FORMAT_BITMAP:   /* already a bitmap, don't do anything */
+      break;
+
+    default:
+      {
+        FT_ListNode  node   = 0;
+        FT_Bool      update = 0;
+
+
+        /* small shortcut for the very common case */
+        if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+        {
+          renderer = library->cur_renderer;
+          node     = library->renderers.head;
+        }
+        else
+          renderer = FT_Lookup_Renderer( library, slot->format, &node );
+
+        error = FT_Err_Unimplemented_Feature;
+        while ( renderer )
+        {
+          error = renderer->render( renderer, slot, render_mode, NULL );
+          if ( !error ||
+               FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
+            break;
+
+          /* FT_Err_Cannot_Render_Glyph is returned if the render mode   */
+          /* is unsupported by the current renderer for this glyph image */
+          /* format.                                                     */
+
+          /* now, look for another renderer that supports the same */
+          /* format.                                               */
+          renderer = FT_Lookup_Renderer( library, slot->format, &node );
+          update   = 1;
+        }
+
+        /* if we changed the current renderer for the glyph image format */
+        /* we need to select it as the next current one                  */
+        if ( !error && update && renderer )
+          FT_Set_Renderer( library, renderer, 0, 0 );
+      }
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Render_Glyph( FT_GlyphSlot    slot,
+                   FT_Render_Mode  render_mode )
+  {
+    FT_Library  library;
+
+
+    if ( !slot )
+      return FT_Err_Invalid_Argument;
+
+    library = FT_FACE_LIBRARY( slot->face );
+
+    return FT_Render_Glyph_Internal( library, slot, render_mode );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                         M O D U L E S                           ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Destroy_Module                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Destroys a given module object.  For drivers, this also destroys   */
+  /*    all child faces.                                                   */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*     module :: A handle to the target driver object.                   */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*     The driver _must_ be LOCKED!                                      */
+  /*                                                                       */
+  static void
+  Destroy_Module( FT_Module  module )
+  {
+    FT_Memory         memory  = module->memory;
+    FT_Module_Class*  clazz   = module->clazz;
+    FT_Library        library = module->library;
+
+
+    /* finalize client-data - before anything else */
+    if ( module->generic.finalizer )
+      module->generic.finalizer( module );
+
+    if ( library && library->auto_hinter == module )
+      library->auto_hinter = 0;
+
+    /* if the module is a renderer */
+    if ( FT_MODULE_IS_RENDERER( module ) )
+      ft_remove_renderer( module );
+
+    /* if the module is a font driver, add some steps */
+    if ( FT_MODULE_IS_DRIVER( module ) )
+      Destroy_Driver( FT_DRIVER( module ) );
+
+    /* finalize the module object */
+    if ( clazz->module_done )
+      clazz->module_done( module );
+
+    /* discard it */
+    FT_FREE( module );
+  }
+
+
+  /* documentation is in ftmodule.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Add_Module( FT_Library              library,
+                 const FT_Module_Class*  clazz )
+  {
+    FT_Error   error;
+    FT_Memory  memory;
+    FT_Module  module;
+    FT_UInt    nn;
+
+
+#define FREETYPE_VER_FIXED  ( ( (FT_Long)FREETYPE_MAJOR << 16 ) | \
+                                FREETYPE_MINOR                  )
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    if ( !clazz )
+      return FT_Err_Invalid_Argument;
+
+    /* check freetype version */
+    if ( clazz->module_requires > FREETYPE_VER_FIXED )
+      return FT_Err_Invalid_Version;
+
+    /* look for a module with the same name in the library's table */
+    for ( nn = 0; nn < library->num_modules; nn++ )
+    {
+      module = library->modules[nn];
+      if ( ft_strcmp( module->clazz->module_name, clazz->module_name ) == 0 )
+      {
+        /* this installed module has the same name, compare their versions */
+        if ( clazz->module_version <= module->clazz->module_version )
+          return FT_Err_Lower_Module_Version;
+
+        /* remove the module from our list, then exit the loop to replace */
+        /* it by our new version..                                        */
+        FT_Remove_Module( library, module );
+        break;
+      }
+    }
+
+    memory = library->memory;
+    error  = FT_Err_Ok;
+
+    if ( library->num_modules >= FT_MAX_MODULES )
+    {
+      error = FT_Err_Too_Many_Drivers;
+      goto Exit;
+    }
+
+    /* allocate module object */
+    if ( FT_ALLOC( module, clazz->module_size ) )
+      goto Exit;
+
+    /* base initialization */
+    module->library = library;
+    module->memory  = memory;
+    module->clazz   = (FT_Module_Class*)clazz;
+
+    /* check whether the module is a renderer - this must be performed */
+    /* before the normal module initialization                         */
+    if ( FT_MODULE_IS_RENDERER( module ) )
+    {
+      /* add to the renderers list */
+      error = ft_add_renderer( module );
+      if ( error )
+        goto Fail;
+    }
+
+    /* is the module a auto-hinter? */
+    if ( FT_MODULE_IS_HINTER( module ) )
+      library->auto_hinter = module;
+
+    /* if the module is a font driver */
+    if ( FT_MODULE_IS_DRIVER( module ) )
+    {
+      /* allocate glyph loader if needed */
+      FT_Driver  driver = FT_DRIVER( module );
+
+
+      driver->clazz = (FT_Driver_Class)module->clazz;
+      if ( FT_DRIVER_USES_OUTLINES( driver ) )
+      {
+        error = FT_GlyphLoader_New( memory, &driver->glyph_loader );
+        if ( error )
+          goto Fail;
+      }
+    }
+
+    if ( clazz->module_init )
+    {
+      error = clazz->module_init( module );
+      if ( error )
+        goto Fail;
+    }
+
+    /* add module to the library's table */
+    library->modules[library->num_modules++] = module;
+
+  Exit:
+    return error;
+
+  Fail:
+    if ( FT_MODULE_IS_DRIVER( module ) )
+    {
+      FT_Driver  driver = FT_DRIVER( module );
+
+
+      if ( FT_DRIVER_USES_OUTLINES( driver ) )
+        FT_GlyphLoader_Done( driver->glyph_loader );
+    }
+
+    if ( FT_MODULE_IS_RENDERER( module ) )
+    {
+      FT_Renderer  renderer = FT_RENDERER( module );
+
+
+      if ( renderer->raster )
+        renderer->clazz->raster_class->raster_done( renderer->raster );
+    }
+
+    FT_FREE( module );
+    goto Exit;
+  }
+
+
+  /* documentation is in ftmodule.h */
+
+  FT_EXPORT_DEF( FT_Module )
+  FT_Get_Module( FT_Library   library,
+                 const char*  module_name )
+  {
+    FT_Module   result = 0;
+    FT_Module*  cur;
+    FT_Module*  limit;
+
+
+    if ( !library || !module_name )
+      return result;
+
+    cur   = library->modules;
+    limit = cur + library->num_modules;
+
+    for ( ; cur < limit; cur++ )
+      if ( ft_strcmp( cur[0]->clazz->module_name, module_name ) == 0 )
+      {
+        result = cur[0];
+        break;
+      }
+
+    return result;
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_BASE_DEF( const void* )
+  FT_Get_Module_Interface( FT_Library   library,
+                           const char*  mod_name )
+  {
+    FT_Module  module;
+
+
+    /* test for valid `library' delayed to FT_Get_Module() */
+
+    module = FT_Get_Module( library, mod_name );
+
+    return module ? module->clazz->module_interface : 0;
+  }
+
+
+  /* documentation is in ftmodule.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Remove_Module( FT_Library  library,
+                    FT_Module   module )
+  {
+    /* try to find the module from the table, then remove it from there */
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    if ( module )
+    {
+      FT_Module*  cur   = library->modules;
+      FT_Module*  limit = cur + library->num_modules;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        if ( cur[0] == module )
+        {
+          /* remove it from the table */
+          library->num_modules--;
+          limit--;
+          while ( cur < limit )
+          {
+            cur[0] = cur[1];
+            cur++;
+          }
+          limit[0] = 0;
+
+          /* destroy the module */
+          Destroy_Module( module );
+
+          return FT_Err_Ok;
+        }
+      }
+    }
+    return FT_Err_Invalid_Driver_Handle;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                         L I B R A R Y                           ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* documentation is in ftmodule.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_New_Library( FT_Memory    memory,
+                  FT_Library  *alibrary )
+  {
+    FT_Library  library = 0;
+    FT_Error    error;
+
+
+    if ( !memory )
+      return FT_Err_Invalid_Argument;
+
+#ifdef FT_DEBUG_LEVEL_ERROR
+    /* init debugging support */
+    ft_debug_init();
+#endif
+
+    /* first of all, allocate the library object */
+    if ( FT_NEW( library ) )
+      return error;
+
+    library->memory = memory;
+
+    /* allocate the render pool */
+    library->raster_pool_size = FT_RENDER_POOL_SIZE;
+    if ( FT_ALLOC( library->raster_pool, FT_RENDER_POOL_SIZE ) )
+      goto Fail;
+
+    /* That's ok now */
+    *alibrary = library;
+
+    return FT_Err_Ok;
+
+  Fail:
+    FT_FREE( library );
+    return error;
+  }
+
+
+  /* documentation is in freetype.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Library_Version( FT_Library   library,
+                      FT_Int      *amajor,
+                      FT_Int      *aminor,
+                      FT_Int      *apatch )
+  {
+    FT_Int  major = 0;
+    FT_Int  minor = 0;
+    FT_Int  patch = 0;
+
+
+    if ( library )
+    {
+      major = library->version_major;
+      minor = library->version_minor;
+      patch = library->version_patch;
+    }
+
+    if ( amajor )
+      *amajor = major;
+
+    if ( aminor )
+      *aminor = minor;
+
+    if ( apatch )
+      *apatch = patch;
+  }
+
+
+  /* documentation is in ftmodule.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Done_Library( FT_Library  library )
+  {
+    FT_Memory  memory;
+
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    memory = library->memory;
+
+    /* Discard client-data */
+    if ( library->generic.finalizer )
+      library->generic.finalizer( library );
+
+    /* Close all modules in the library */
+#if 1
+    while ( library->num_modules > 0 )
+      FT_Remove_Module( library, library->modules[0] );
+#else
+    {
+      FT_UInt  n;
+
+
+      for ( n = 0; n < library->num_modules; n++ )
+      {
+        FT_Module  module = library->modules[n];
+
+
+        if ( module )
+        {
+          Destroy_Module( module );
+          library->modules[n] = 0;
+        }
+      }
+    }
+#endif
+
+    /* Destroy raster objects */
+    FT_FREE( library->raster_pool );
+    library->raster_pool_size = 0;
+
+    FT_FREE( library );
+    return FT_Err_Ok;
+  }
+
+
+  /* documentation is in ftmodule.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Set_Debug_Hook( FT_Library         library,
+                     FT_UInt            hook_index,
+                     FT_DebugHook_Func  debug_hook )
+  {
+    if ( library && debug_hook &&
+         hook_index <
+           ( sizeof ( library->debug_hooks ) / sizeof ( void* ) ) )
+      library->debug_hooks[hook_index] = debug_hook;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftoutln.c
@@ -1,0 +1,658 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftoutln.c                                                              */
+/*                                                                         */
+/*    FreeType outline management (body).                                  */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* All functions are declared in freetype.h.                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_outline
+
+
+  static
+  const FT_Outline  null_outline = { 0, 0, 0, 0, 0, 0 };
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Decompose( FT_Outline*              outline,
+                        const FT_Outline_Funcs*  func_interface,
+                        void*                    user )
+  {
+#undef SCALED
+#define SCALED( x )  ( ( (x) << shift ) - delta )
+
+    FT_Vector   v_last;
+    FT_Vector   v_control;
+    FT_Vector   v_start;
+
+    FT_Vector*  point;
+    FT_Vector*  limit;
+    char*       tags;
+
+    FT_Error    error;
+
+    FT_Int   n;         /* index of contour in outline     */
+    FT_UInt  first;     /* index of first point in contour */
+    FT_Int   tag;       /* current point's state           */
+
+    FT_Int   shift;
+    FT_Pos   delta;
+
+
+    if ( !outline || !func_interface )
+      return FT_Err_Invalid_Argument;
+
+    shift = func_interface->shift;
+    delta = func_interface->delta;
+    first = 0;
+
+    for ( n = 0; n < outline->n_contours; n++ )
+    {
+      FT_Int  last;  /* index of last point in contour */
+
+
+      last  = outline->contours[n];
+      limit = outline->points + last;
+
+      v_start = outline->points[first];
+      v_last  = outline->points[last];
+
+      v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y );
+      v_last.x  = SCALED( v_last.x );  v_last.y  = SCALED( v_last.y );
+
+      v_control = v_start;
+
+      point = outline->points + first;
+      tags  = outline->tags  + first;
+      tag   = FT_CURVE_TAG( tags[0] );
+
+      /* A contour cannot start with a cubic control point! */
+      if ( tag == FT_CURVE_TAG_CUBIC )
+        goto Invalid_Outline;
+
+      /* check first point to determine origin */
+      if ( tag == FT_CURVE_TAG_CONIC )
+      {
+        /* first point is conic control.  Yes, this happens. */
+        if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON )
+        {
+          /* start at last point if it is on the curve */
+          v_start = v_last;
+          limit--;
+        }
+        else
+        {
+          /* if both first and last points are conic,         */
+          /* start at their middle and record its position    */
+          /* for closure                                      */
+          v_start.x = ( v_start.x + v_last.x ) / 2;
+          v_start.y = ( v_start.y + v_last.y ) / 2;
+
+          v_last = v_start;
+        }
+        point--;
+        tags--;
+      }
+
+      error = func_interface->move_to( &v_start, user );
+      if ( error )
+        goto Exit;
+
+      while ( point < limit )
+      {
+        point++;
+        tags++;
+
+        tag = FT_CURVE_TAG( tags[0] );
+        switch ( tag )
+        {
+        case FT_CURVE_TAG_ON:  /* emit a single line_to */
+          {
+            FT_Vector  vec;
+
+
+            vec.x = SCALED( point->x );
+            vec.y = SCALED( point->y );
+
+            error = func_interface->line_to( &vec, user );
+            if ( error )
+              goto Exit;
+            continue;
+          }
+
+        case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
+          v_control.x = SCALED( point->x );
+          v_control.y = SCALED( point->y );
+
+        Do_Conic:
+          if ( point < limit )
+          {
+            FT_Vector  vec;
+            FT_Vector  v_middle;
+
+
+            point++;
+            tags++;
+            tag = FT_CURVE_TAG( tags[0] );
+
+            vec.x = SCALED( point->x );
+            vec.y = SCALED( point->y );
+
+            if ( tag == FT_CURVE_TAG_ON )
+            {
+              error = func_interface->conic_to( &v_control, &vec, user );
+              if ( error )
+                goto Exit;
+              continue;
+            }
+
+            if ( tag != FT_CURVE_TAG_CONIC )
+              goto Invalid_Outline;
+
+            v_middle.x = ( v_control.x + vec.x ) / 2;
+            v_middle.y = ( v_control.y + vec.y ) / 2;
+
+            error = func_interface->conic_to( &v_control, &v_middle, user );
+            if ( error )
+              goto Exit;
+
+            v_control = vec;
+            goto Do_Conic;
+          }
+
+          error = func_interface->conic_to( &v_control, &v_start, user );
+          goto Close;
+
+        default:  /* FT_CURVE_TAG_CUBIC */
+          {
+            FT_Vector  vec1, vec2;
+
+
+            if ( point + 1 > limit                             ||
+                 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
+              goto Invalid_Outline;
+
+            point += 2;
+            tags  += 2;
+
+            vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y );
+            vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y );
+
+            if ( point <= limit )
+            {
+              FT_Vector  vec;
+
+
+              vec.x = SCALED( point->x );
+              vec.y = SCALED( point->y );
+
+              error = func_interface->cubic_to( &vec1, &vec2, &vec, user );
+              if ( error )
+                goto Exit;
+              continue;
+            }
+
+            error = func_interface->cubic_to( &vec1, &vec2, &v_start, user );
+            goto Close;
+          }
+        }
+      }
+
+      /* close the contour with a line segment */
+      error = func_interface->line_to( &v_start, user );
+
+    Close:
+      if ( error )
+        goto Exit;
+
+      first = last + 1;
+    }
+
+    return 0;
+
+  Exit:
+    return error;
+
+  Invalid_Outline:
+    return FT_Err_Invalid_Outline;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_New_Internal( FT_Memory    memory,
+                           FT_UInt      numPoints,
+                           FT_Int       numContours,
+                           FT_Outline  *anoutline )
+  {
+    FT_Error  error;
+
+
+    if ( !anoutline || !memory )
+      return FT_Err_Invalid_Argument;
+
+    *anoutline = null_outline;
+
+    if ( FT_NEW_ARRAY( anoutline->points,   numPoints * 2L ) ||
+         FT_NEW_ARRAY( anoutline->tags,     numPoints      ) ||
+         FT_NEW_ARRAY( anoutline->contours, numContours    ) )
+      goto Fail;
+
+    anoutline->n_points    = (FT_UShort)numPoints;
+    anoutline->n_contours  = (FT_Short)numContours;
+    anoutline->flags      |= FT_OUTLINE_OWNER;
+
+    return FT_Err_Ok;
+
+  Fail:
+    anoutline->flags |= FT_OUTLINE_OWNER;
+    FT_Outline_Done_Internal( memory, anoutline );
+
+    return error;
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_New( FT_Library   library,
+                  FT_UInt      numPoints,
+                  FT_Int       numContours,
+                  FT_Outline  *anoutline )
+  {
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    return FT_Outline_New_Internal( library->memory, numPoints,
+                                    numContours, anoutline );
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Check( FT_Outline*  outline )
+  {
+    if ( outline )
+    {
+      FT_Int  n_points   = outline->n_points;
+      FT_Int  n_contours = outline->n_contours;
+      FT_Int  end0, end;
+      FT_Int  n;
+
+
+      /* empty glyph? */
+      if ( n_points == 0 && n_contours == 0 )
+        return 0;
+
+      /* check point and contour counts */
+      if ( n_points <= 0 || n_contours <= 0 )
+        goto Bad;
+
+      end0 = end = -1;
+      for ( n = 0; n < n_contours; n++ )
+      {
+        end = outline->contours[n];
+
+        /* note that we don't accept empty contours */
+        if ( end <= end0 || end >= n_points )
+          goto Bad;
+
+        end0 = end;
+      }
+
+      if ( end != n_points - 1 )
+        goto Bad;
+
+      /* XXX: check the tags array */
+      return 0;
+    }
+
+  Bad:
+    return FT_Err_Invalid_Argument;
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Copy( FT_Outline*  source,
+                   FT_Outline  *target )
+  {
+    FT_Int  is_owner;
+
+
+    if ( !source            || !target            ||
+         source->n_points   != target->n_points   ||
+         source->n_contours != target->n_contours )
+      return FT_Err_Invalid_Argument;
+
+    FT_MEM_COPY( target->points, source->points,
+                 source->n_points * sizeof ( FT_Vector ) );
+
+    FT_MEM_COPY( target->tags, source->tags,
+                 source->n_points * sizeof ( FT_Byte ) );
+
+    FT_MEM_COPY( target->contours, source->contours,
+                 source->n_contours * sizeof ( FT_Short ) );
+
+    /* copy all flags, except the `FT_OUTLINE_OWNER' one */
+    is_owner      = target->flags & FT_OUTLINE_OWNER;
+    target->flags = source->flags;
+
+    target->flags &= ~FT_OUTLINE_OWNER;
+    target->flags |= is_owner;
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Done_Internal( FT_Memory    memory,
+                            FT_Outline*  outline )
+  {
+    if ( outline )
+    {
+      if ( outline->flags & FT_OUTLINE_OWNER )
+      {
+        FT_FREE( outline->points   );
+        FT_FREE( outline->tags     );
+        FT_FREE( outline->contours );
+      }
+      *outline = null_outline;
+
+      return FT_Err_Ok;
+    }
+    else
+      return FT_Err_Invalid_Argument;
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Done( FT_Library   library,
+                   FT_Outline*  outline )
+  {
+    /* check for valid `outline' in FT_Outline_Done_Internal() */
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    return FT_Outline_Done_Internal( library->memory, outline );
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Outline_Get_CBox( FT_Outline*  outline,
+                       FT_BBox     *acbox )
+  {
+    FT_Pos  xMin, yMin, xMax, yMax;
+
+
+    if ( outline && acbox )
+    {
+      if ( outline->n_points == 0 )
+      {
+        xMin = 0;
+        yMin = 0;
+        xMax = 0;
+        yMax = 0;
+      }
+      else
+      {
+        FT_Vector*  vec   = outline->points;
+        FT_Vector*  limit = vec + outline->n_points;
+
+
+        xMin = xMax = vec->x;
+        yMin = yMax = vec->y;
+        vec++;
+
+        for ( ; vec < limit; vec++ )
+        {
+          FT_Pos  x, y;
+
+
+          x = vec->x;
+          if ( x < xMin ) xMin = x;
+          if ( x > xMax ) xMax = x;
+
+          y = vec->y;
+          if ( y < yMin ) yMin = y;
+          if ( y > yMax ) yMax = y;
+        }
+      }
+      acbox->xMin = xMin;
+      acbox->xMax = xMax;
+      acbox->yMin = yMin;
+      acbox->yMax = yMax;
+    }
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Outline_Translate( FT_Outline*  outline,
+                        FT_Pos       xOffset,
+                        FT_Pos       yOffset )
+  {
+    FT_UShort   n;
+    FT_Vector*  vec = outline->points;
+
+
+    for ( n = 0; n < outline->n_points; n++ )
+    {
+      vec->x += xOffset;
+      vec->y += yOffset;
+      vec++;
+    }
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Outline_Reverse( FT_Outline*  outline )
+  {
+    FT_UShort  n;
+    FT_Int     first, last;
+
+
+    first = 0;
+
+    for ( n = 0; n < outline->n_contours; n++ )
+    {
+      last  = outline->contours[n];
+
+      /* reverse point table */
+      {
+        FT_Vector*  p = outline->points + first;
+        FT_Vector*  q = outline->points + last;
+        FT_Vector   swap;
+
+
+        while ( p < q )
+        {
+          swap = *p;
+          *p   = *q;
+          *q   = swap;
+          p++;
+          q--;
+        }
+      }
+
+      /* reverse tags table */
+      {
+        char*  p = outline->tags + first;
+        char*  q = outline->tags + last;
+        char   swap;
+
+
+        while ( p < q )
+        {
+          swap = *p;
+          *p   = *q;
+          *q   = swap;
+          p++;
+          q--;
+        }
+      }
+
+      first = last + 1;
+    }
+
+    outline->flags ^= FT_OUTLINE_REVERSE_FILL;
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Render( FT_Library         library,
+                     FT_Outline*        outline,
+                     FT_Raster_Params*  params )
+  {
+    FT_Error     error;
+    FT_Bool      update = 0;
+    FT_Renderer  renderer;
+    FT_ListNode  node;
+
+
+    if ( !library )
+      return FT_Err_Invalid_Library_Handle;
+
+    if ( !params )
+      return FT_Err_Invalid_Argument;
+
+    renderer = library->cur_renderer;
+    node     = library->renderers.head;
+
+    params->source = (void*)outline;
+
+    error = FT_Err_Cannot_Render_Glyph;
+    while ( renderer )
+    {
+      error = renderer->raster_render( renderer->raster, params );
+      if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph )
+        break;
+
+      /* FT_Err_Cannot_Render_Glyph is returned if the render mode   */
+      /* is unsupported by the current renderer for this glyph image */
+      /* format                                                      */
+
+      /* now, look for another renderer that supports the same */
+      /* format                                                */
+      renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE,
+                                     &node );
+      update   = 1;
+    }
+
+    /* if we changed the current renderer for the glyph image format */
+    /* we need to select it as the next current one                  */
+    if ( !error && update && renderer )
+      FT_Set_Renderer( library, renderer, 0, 0 );
+
+    return error;
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Outline_Get_Bitmap( FT_Library   library,
+                         FT_Outline*  outline,
+                         FT_Bitmap   *abitmap )
+  {
+    FT_Raster_Params  params;
+
+
+    if ( !abitmap )
+      return FT_Err_Invalid_Argument;
+
+    /* other checks are delayed to FT_Outline_Render() */
+
+    params.target = abitmap;
+    params.flags  = 0;
+
+    if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY  ||
+         abitmap->pixel_mode == FT_PIXEL_MODE_LCD   ||
+         abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V )
+      params.flags |= FT_RASTER_FLAG_AA;
+
+    return FT_Outline_Render( library, outline, &params );
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Vector_Transform( FT_Vector*  vector,
+                       FT_Matrix*  matrix )
+  {
+    FT_Pos xz, yz;
+
+
+    if ( !vector || !matrix )
+      return;
+
+    xz = FT_MulFix( vector->x, matrix->xx ) +
+         FT_MulFix( vector->y, matrix->xy );
+
+    yz = FT_MulFix( vector->x, matrix->yx ) +
+         FT_MulFix( vector->y, matrix->yy );
+
+    vector->x = xz;
+    vector->y = yz;
+  }
+
+
+  /* documentation is in ftoutln.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Outline_Transform( FT_Outline*  outline,
+                        FT_Matrix*   matrix )
+  {
+    FT_Vector*  vec = outline->points;
+    FT_Vector*  limit = vec + outline->n_points;
+
+
+    for ( ; vec < limit; vec++ )
+      FT_Vector_Transform( vec, matrix );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftpfr.c
@@ -1,0 +1,105 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftpfr.c                                                                */
+/*                                                                         */
+/*    FreeType API for accessing PFR-specific data                         */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_PFR_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /* check the format */
+  static FT_Error
+  ft_pfr_check( FT_Face           face,
+                FT_PFR_Service   *aservice )
+  {
+    FT_Error  error = FT_Err_Bad_Argument;
+
+    if ( face && face->driver )
+    {
+      FT_Module    module = (FT_Module) face->driver;
+      const char*  name   = module->clazz->module_name;
+
+      if ( name[0] == 'p' &&
+           name[1] == 'f' &&
+           name[2] == 'r' &&
+           name[4] == 0   )
+      {
+        *aservice = (FT_PFR_Service) module->clazz->module_interface;
+        error = 0;
+      }
+    }
+    return error;
+  }
+
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_PFR_Metrics( FT_Face     face,
+                      FT_UInt    *aoutline_resolution,
+                      FT_UInt    *ametrics_resolution,
+                      FT_Fixed   *ametrics_x_scale,
+                      FT_Fixed   *ametrics_y_scale )
+  {
+    FT_Error        error;
+    FT_PFR_Service  service;
+
+    error = ft_pfr_check( face, &service );
+    if ( !error )
+    {
+      error = service->get_metrics( face,
+                                    aoutline_resolution,
+                                    ametrics_resolution,
+                                    ametrics_x_scale,
+                                    ametrics_y_scale );
+    }
+    return error;
+  }
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_PFR_Kerning( FT_Face     face,
+                      FT_UInt     left,
+                      FT_UInt     right,
+                      FT_Vector  *avector )
+  {
+    FT_Error        error;
+    FT_PFR_Service  service;
+
+    error = ft_pfr_check( face, &service );
+    if ( !error )
+    {
+      error = service->get_kerning( face, left, right, avector );
+    }
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_PFR_Advance( FT_Face    face,
+                      FT_UInt    gindex,
+                      FT_Pos    *aadvance )
+  {
+    FT_Error        error;
+    FT_PFR_Service  service;
+
+    error = ft_pfr_check( face, &service );
+    if ( !error )
+    {
+      error = service->get_advance( face, gindex, aadvance );
+    }
+    return error;
+  }
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftraster.c
@@ -1,0 +1,3288 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftraster.c                                                             */
+/*                                                                         */
+/*    The FreeType glyph rasterizer (body).                                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This is a rewrite of the FreeType 1.x scan-line converter             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include "ftraster.h"
+#include FT_INTERNAL_CALC_H   /* for FT_MulDiv only */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* A simple technical note on how the raster works                       */
+  /* -----------------------------------------------                       */
+  /*                                                                       */
+  /*   Converting an outline into a bitmap is achieved in several steps:   */
+  /*                                                                       */
+  /*   1 - Decomposing the outline into successive `profiles'.  Each       */
+  /*       profile is simply an array of scanline intersections on a given */
+  /*       dimension.  A profile's main attributes are                     */
+  /*                                                                       */
+  /*       o its scanline position boundaries, i.e. `Ymin' and `Ymax'.     */
+  /*                                                                       */
+  /*       o an array of intersection coordinates for each scanline        */
+  /*         between `Ymin' and `Ymax'.                                    */
+  /*                                                                       */
+  /*       o a direction, indicating whether it was built going `up' or    */
+  /*         `down', as this is very important for filling rules.          */
+  /*                                                                       */
+  /*   2 - Sweeping the target map's scanlines in order to compute segment */
+  /*       `spans' which are then filled.  Additionally, this pass         */
+  /*       performs drop-out control.                                      */
+  /*                                                                       */
+  /*   The outline data is parsed during step 1 only.  The profiles are    */
+  /*   built from the bottom of the render pool, used as a stack.  The     */
+  /*   following graphics shows the profile list under construction:       */
+  /*                                                                       */
+  /*     ____________________________________________________________ _ _  */
+  /*    |         |                   |         |                 |        */
+  /*    | profile | coordinates for   | profile | coordinates for |-->     */
+  /*    |    1    |  profile 1        |    2    |  profile 2      |-->     */
+  /*    |_________|___________________|_________|_________________|__ _ _  */
+  /*                                                                       */
+  /*    ^                                                         ^        */
+  /*    |                                                         |        */
+  /*  start of render pool                                       top       */
+  /*                                                                       */
+  /*   The top of the profile stack is kept in the `top' variable.         */
+  /*                                                                       */
+  /*   As you can see, a profile record is pushed on top of the render     */
+  /*   pool, which is then followed by its coordinates/intersections.  If  */
+  /*   a change of direction is detected in the outline, a new profile is  */
+  /*   generated until the end of the outline.                             */
+  /*                                                                       */
+  /*   Note that when all profiles have been generated, the function       */
+  /*   Finalize_Profile_Table() is used to record, for each profile, its   */
+  /*   bottom-most scanline as well as the scanline above its upmost       */
+  /*   boundary.  These positions are called `y-turns' because they (sort  */
+  /*   of) correspond to local extrema.  They are stored in a sorted list  */
+  /*   built from the top of the render pool as a downwards stack:         */
+  /*                                                                       */
+  /*      _ _ _______________________________________                      */
+  /*                            |                    |                     */
+  /*                         <--| sorted list of     |                     */
+  /*                         <--|  extrema scanlines |                     */
+  /*      _ _ __________________|____________________|                     */
+  /*                                                                       */
+  /*                            ^                    ^                     */
+  /*                            |                    |                     */
+  /*                         maxBuff           sizeBuff = end of pool      */
+  /*                                                                       */
+  /*   This list is later used during the sweep phase in order to          */
+  /*   optimize performance (see technical note on the sweep below).       */
+  /*                                                                       */
+  /*   Of course, the raster detects whether the two stacks collide and    */
+  /*   handles the situation propertly.                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  CONFIGURATION MACROS                                               **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* define DEBUG_RASTER if you want to compile a debugging version */
+#define xxxDEBUG_RASTER
+
+  /* The default render pool size in bytes */
+#define RASTER_RENDER_POOL  8192
+
+  /* undefine FT_RASTER_OPTION_ANTI_ALIASING if you do not want to support */
+  /* 5-levels anti-aliasing                                                */
+#ifdef FT_CONFIG_OPTION_5_GRAY_LEVELS
+#define FT_RASTER_OPTION_ANTI_ALIASING
+#endif
+
+  /* The size of the two-lines intermediate bitmap used */
+  /* for anti-aliasing, in bytes.                       */
+#define RASTER_GRAY_LINES  2048
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  OTHER MACROS (do not change)                                       **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_raster
+
+
+#ifdef _STANDALONE_
+
+
+  /* This macro is used to indicate that a function parameter is unused. */
+  /* Its purpose is simply to reduce compiler warnings.  Note also that  */
+  /* simply defining it as `(void)x' doesn't avoid warnings with certain */
+  /* ANSI compilers (e.g. LCC).                                          */
+#define FT_UNUSED( x )  (x) = (x)
+
+  /* Disable the tracing mechanism for simplicity -- developers can      */
+  /* activate it easily by redefining these two macros.                  */
+#ifndef FT_ERROR
+#define FT_ERROR( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+#ifndef FT_TRACE
+#define FT_TRACE( x )  do ; while ( 0 )     /* nothing */
+#endif
+
+#define Raster_Err_None          0
+#define Raster_Err_Not_Ini      -1
+#define Raster_Err_Overflow     -2
+#define Raster_Err_Neg_Height   -3
+#define Raster_Err_Invalid      -4
+#define Raster_Err_Unsupported  -5
+
+
+#else /* _STANDALONE_ */
+
+
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H        /* for FT_TRACE() and FT_ERROR() */
+
+#include "rasterrs.h"
+
+#define Raster_Err_None         Raster_Err_Ok
+#define Raster_Err_Not_Ini      Raster_Err_Raster_Uninitialized
+#define Raster_Err_Overflow     Raster_Err_Raster_Overflow
+#define Raster_Err_Neg_Height   Raster_Err_Raster_Negative_Height
+#define Raster_Err_Invalid      Raster_Err_Invalid_Outline
+#define Raster_Err_Unsupported  Raster_Err_Cannot_Render_Glyph
+
+
+#endif /* _STANDALONE_ */
+
+
+#ifndef FT_MEM_SET
+#define FT_MEM_SET( d, s, c )  ft_memset( d, s, c )
+#endif
+
+
+  /* FMulDiv means `Fast MulDiv'; it is used in case where `b' is       */
+  /* typically a small value and the result of a*b is known to fit into */
+  /* 32 bits.                                                           */
+#define FMulDiv( a, b, c )  ( (a) * (b) / (c) )
+
+  /* On the other hand, SMulDiv means `Slow MulDiv', and is used typically */
+  /* for clipping computations.  It simply uses the FT_MulDiv() function   */
+  /* defined in `ftcalc.h'.                                                */
+#define SMulDiv  FT_MulDiv
+
+  /* The rasterizer is a very general purpose component; please leave */
+  /* the following redefinitions there (you never know your target    */
+  /* environment).                                                    */
+
+#ifndef TRUE
+#define TRUE   1
+#endif
+
+#ifndef FALSE
+#define FALSE  0
+#endif
+
+#ifndef NULL
+#define NULL  (void*)0
+#endif
+
+#ifndef SUCCESS
+#define SUCCESS  0
+#endif
+
+#ifndef FAILURE
+#define FAILURE  1
+#endif
+
+
+#define MaxBezier  32   /* The maximum number of stacked Bezier curves. */
+                        /* Setting this constant to more than 32 is a   */
+                        /* pure waste of space.                         */
+
+#define Pixel_Bits  6   /* fractional bits of *input* coordinates */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  SIMPLE TYPE DECLARATIONS                                           **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef int             Int;
+  typedef unsigned int    UInt;
+  typedef short           Short;
+  typedef unsigned short  UShort, *PUShort;
+  typedef long            Long, *PLong;
+  typedef unsigned long   ULong;
+
+  typedef unsigned char   Byte, *PByte;
+  typedef char            Bool;
+
+  typedef struct  TPoint_
+  {
+    Long  x;
+    Long  y;
+
+  } TPoint;
+
+
+  typedef enum  TFlow_
+  {
+    Flow_None = 0,
+    Flow_Up   = 1,
+    Flow_Down = -1
+
+  } TFlow;
+
+
+  /* States of each line, arc, and profile */
+  typedef enum  TStates_
+  {
+    Unknown_State,
+    Ascending_State,
+    Descending_State,
+    Flat_State
+
+  } TStates;
+
+
+  typedef struct TProfile_  TProfile;
+  typedef TProfile*         PProfile;
+
+  struct  TProfile_
+  {
+    FT_F26Dot6  X;           /* current coordinate during sweep        */
+    PProfile    link;        /* link to next profile - various purpose */
+    PLong       offset;      /* start of profile's data in render pool */
+    int         flow;        /* Profile orientation: Asc/Descending    */
+    long        height;      /* profile's height in scanlines          */
+    long        start;       /* profile's starting scanline            */
+
+    unsigned    countL;      /* number of lines to step before this    */
+                             /* profile becomes drawable               */
+
+    PProfile    next;        /* next profile in same contour, used     */
+                             /* during drop-out control                */
+  };
+
+  typedef PProfile   TProfileList;
+  typedef PProfile*  PProfileList;
+
+
+  /* Simple record used to implement a stack of bands, required */
+  /* by the sub-banding mechanism                               */
+  typedef struct  TBand_
+  {
+    Short  y_min;   /* band's minimum */
+    Short  y_max;   /* band's maximum */
+
+  } TBand;
+
+
+#define AlignProfileSize \
+          ( ( sizeof ( TProfile ) + sizeof ( long ) - 1 ) / sizeof ( long ) )
+
+
+#ifdef TT_STATIC_RASTER
+
+
+#define RAS_ARGS       /* void */
+#define RAS_ARG        /* void */
+
+#define RAS_VARS       /* void */
+#define RAS_VAR        /* void */
+
+#define FT_UNUSED_RASTER  do ; while ( 0 )
+
+
+#else /* TT_STATIC_RASTER */
+
+
+#define RAS_ARGS       TRaster_Instance*  raster,
+#define RAS_ARG        TRaster_Instance*  raster
+
+#define RAS_VARS       raster,
+#define RAS_VAR        raster
+
+#define FT_UNUSED_RASTER  FT_UNUSED( raster )
+
+
+#endif /* TT_STATIC_RASTER */
+
+
+  typedef struct TRaster_Instance_  TRaster_Instance;
+
+
+  /* prototypes used for sweep function dispatch */
+  typedef void
+  Function_Sweep_Init( RAS_ARGS Short*  min,
+                                Short*  max );
+
+  typedef void
+  Function_Sweep_Span( RAS_ARGS Short       y,
+                                FT_F26Dot6  x1,
+                                FT_F26Dot6  x2,
+                                PProfile    left,
+                                PProfile    right );
+
+  typedef void
+  Function_Sweep_Step( RAS_ARG );
+
+
+  /* NOTE: These operations are only valid on 2's complement processors */
+
+#define FLOOR( x )    ( (x) & -ras.precision )
+#define CEILING( x )  ( ( (x) + ras.precision - 1 ) & -ras.precision )
+#define TRUNC( x )    ( (signed long)(x) >> ras.precision_bits )
+#define FRAC( x )     ( (x) & ( ras.precision - 1 ) )
+#define SCALED( x )   ( ( (x) << ras.scale_shift ) - ras.precision_half )
+
+  /* Note that I have moved the location of some fields in the */
+  /* structure to ensure that the most used variables are used */
+  /* at the top.  Thus, their offset can be coded with less    */
+  /* opcodes, and it results in a smaller executable.          */
+
+  struct  TRaster_Instance_
+  {
+    Int       precision_bits;       /* precision related variables         */
+    Int       precision;
+    Int       precision_half;
+    Long      precision_mask;
+    Int       precision_shift;
+    Int       precision_step;
+    Int       precision_jitter;
+
+    Int       scale_shift;          /* == precision_shift   for bitmaps    */
+                                    /* == precision_shift+1 for pixmaps    */
+
+    PLong     buff;                 /* The profiles buffer                 */
+    PLong     sizeBuff;             /* Render pool size                    */
+    PLong     maxBuff;              /* Profiles buffer size                */
+    PLong     top;                  /* Current cursor in buffer            */
+
+    FT_Error  error;
+
+    Int       numTurns;             /* number of Y-turns in outline        */
+
+    TPoint*   arc;                  /* current Bezier arc pointer          */
+
+    UShort    bWidth;               /* target bitmap width                 */
+    PByte     bTarget;              /* target bitmap buffer                */
+    PByte     gTarget;              /* target pixmap buffer                */
+
+    Long      lastX, lastY, minY, maxY;
+
+    UShort    num_Profs;            /* current number of profiles          */
+
+    Bool      fresh;                /* signals a fresh new profile which   */
+                                    /* 'start' field must be completed     */
+    Bool      joint;                /* signals that the last arc ended     */
+                                    /* exactly on a scanline.  Allows      */
+                                    /* removal of doublets                 */
+    PProfile  cProfile;             /* current profile                     */
+    PProfile  fProfile;             /* head of linked list of profiles     */
+    PProfile  gProfile;             /* contour's first profile in case     */
+                                    /* of impact                           */
+
+    TStates   state;                /* rendering state                     */
+
+    FT_Bitmap   target;             /* description of target bit/pixmap    */
+    FT_Outline  outline;
+
+    Long      traceOfs;             /* current offset in target bitmap     */
+    Long      traceG;               /* current offset in target pixmap     */
+
+    Short     traceIncr;            /* sweep's increment in target bitmap  */
+
+    Short     gray_min_x;           /* current min x during gray rendering */
+    Short     gray_max_x;           /* current max x during gray rendering */
+
+    /* dispatch variables */
+
+    Function_Sweep_Init*  Proc_Sweep_Init;
+    Function_Sweep_Span*  Proc_Sweep_Span;
+    Function_Sweep_Span*  Proc_Sweep_Drop;
+    Function_Sweep_Step*  Proc_Sweep_Step;
+
+    Byte      dropOutControl;       /* current drop_out control method     */
+
+    Bool      second_pass;          /* indicates wether a horizontal pass  */
+                                    /* should be performed to control      */
+                                    /* drop-out accurately when calling    */
+                                    /* Render_Glyph.  Note that there is   */
+                                    /* no horizontal pass during gray      */
+                                    /* rendering.                          */
+
+    TPoint    arcs[3 * MaxBezier + 1]; /* The Bezier stack                 */
+
+    TBand     band_stack[16];       /* band stack used for sub-banding     */
+    Int       band_top;             /* band stack top                      */
+
+    Int       count_table[256];     /* Look-up table used to quickly count */
+                                    /* set bits in a gray 2x2 cell         */
+
+    void*     memory;
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+    Byte      grays[5];             /* Palette of gray levels used for     */
+                                    /* render.                             */
+
+    Byte      gray_lines[RASTER_GRAY_LINES];
+                                /* Intermediate table used to render the   */
+                                /* graylevels pixmaps.                     */
+                                /* gray_lines is a buffer holding two      */
+                                /* monochrome scanlines                    */
+
+    Short     gray_width;       /* width in bytes of one monochrome        */
+                                /* intermediate scanline of gray_lines.    */
+                                /* Each gray pixel takes 2 bits long there */
+
+                       /* The gray_lines must hold 2 lines, thus with size */
+                       /* in bytes of at least `gray_width*2'.             */
+
+#endif /* FT_RASTER_ANTI_ALIASING */
+
+#if 0
+    PByte       flags;              /* current flags table                 */
+    PUShort     outs;               /* current outlines table              */
+    FT_Vector*  coords;
+
+    UShort      nPoints;            /* number of points in current glyph   */
+    Short       nContours;          /* number of contours in current glyph */
+#endif
+
+  };
+
+
+#ifdef FT_CONFIG_OPTION_STATIC_RASTER
+
+  static TRaster_Instance  cur_ras;
+#define ras  cur_ras
+
+#else
+
+#define ras  (*raster)
+
+#endif /* FT_CONFIG_OPTION_STATIC_RASTER */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  PROFILES COMPUTATION                                               **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Set_High_Precision                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Sets precision variables according to param flag.                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    High :: Set to True for high precision (typically for ppem < 18),  */
+  /*            false otherwise.                                           */
+  /*                                                                       */
+  static void
+  Set_High_Precision( RAS_ARGS Int  High )
+  {
+    if ( High )
+    {
+      ras.precision_bits   = 10;
+      ras.precision_step   = 128;
+      ras.precision_jitter = 24;
+    }
+    else
+    {
+      ras.precision_bits   = 6;
+      ras.precision_step   = 32;
+      ras.precision_jitter = 2;
+    }
+
+    FT_TRACE6(( "Set_High_Precision(%s)\n", High ? "true" : "false" ));
+
+    ras.precision       = 1 << ras.precision_bits;
+    ras.precision_half  = ras.precision / 2;
+    ras.precision_shift = ras.precision_bits - Pixel_Bits;
+    ras.precision_mask  = -ras.precision;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    New_Profile                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Creates a new profile in the render pool.                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    aState :: The state/orientation of the new profile.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success.  FAILURE in case of overflow or of incoherent   */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static Bool
+  New_Profile( RAS_ARGS TStates  aState )
+  {
+    if ( !ras.fProfile )
+    {
+      ras.cProfile  = (PProfile)ras.top;
+      ras.fProfile  = ras.cProfile;
+      ras.top      += AlignProfileSize;
+    }
+
+    if ( ras.top >= ras.maxBuff )
+    {
+      ras.error = Raster_Err_Overflow;
+      return FAILURE;
+    }
+
+    switch ( aState )
+    {
+    case Ascending_State:
+      ras.cProfile->flow = Flow_Up;
+      FT_TRACE6(( "New ascending profile = %lx\n", (long)ras.cProfile ));
+      break;
+
+    case Descending_State:
+      ras.cProfile->flow = Flow_Down;
+      FT_TRACE6(( "New descending profile = %lx\n", (long)ras.cProfile ));
+      break;
+
+    default:
+      FT_ERROR(( "New_Profile: invalid profile direction!\n" ));
+      ras.error = Raster_Err_Invalid;
+      return FAILURE;
+    }
+
+    ras.cProfile->start  = 0;
+    ras.cProfile->height = 0;
+    ras.cProfile->offset = ras.top;
+    ras.cProfile->link   = (PProfile)0;
+    ras.cProfile->next   = (PProfile)0;
+
+    if ( !ras.gProfile )
+      ras.gProfile = ras.cProfile;
+
+    ras.state = aState;
+    ras.fresh = TRUE;
+    ras.joint = FALSE;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    End_Profile                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes the current profile.                                     */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success.  FAILURE in case of overflow or incoherency.   */
+  /*                                                                       */
+  static Bool
+  End_Profile( RAS_ARG )
+  {
+    Long      h;
+    PProfile  oldProfile;
+
+
+    h = (Long)( ras.top - ras.cProfile->offset );
+
+    if ( h < 0 )
+    {
+      FT_ERROR(( "End_Profile: negative height encountered!\n" ));
+      ras.error = Raster_Err_Neg_Height;
+      return FAILURE;
+    }
+
+    if ( h > 0 )
+    {
+      FT_TRACE6(( "Ending profile %lx, start = %ld, height = %ld\n",
+                  (long)ras.cProfile, ras.cProfile->start, h ));
+
+      oldProfile           = ras.cProfile;
+      ras.cProfile->height = h;
+      ras.cProfile         = (PProfile)ras.top;
+
+      ras.top             += AlignProfileSize;
+
+      ras.cProfile->height = 0;
+      ras.cProfile->offset = ras.top;
+      oldProfile->next     = ras.cProfile;
+      ras.num_Profs++;
+    }
+
+    if ( ras.top >= ras.maxBuff )
+    {
+      FT_TRACE1(( "overflow in End_Profile\n" ));
+      ras.error = Raster_Err_Overflow;
+      return FAILURE;
+    }
+
+    ras.joint = FALSE;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Insert_Y_Turn                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Inserts a salient into the sorted list placed on top of the render */
+  /*    pool.                                                              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    New y scanline position.                                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success.  FAILURE in case of overflow.                  */
+  /*                                                                       */
+  static Bool
+  Insert_Y_Turn( RAS_ARGS Int  y )
+  {
+    PLong     y_turns;
+    Int       y2, n;
+
+
+    n       = ras.numTurns - 1;
+    y_turns = ras.sizeBuff - ras.numTurns;
+
+    /* look for first y value that is <= */
+    while ( n >= 0 && y < y_turns[n] )
+      n--;
+
+    /* if it is <, simply insert it, ignore if == */
+    if ( n >= 0 && y > y_turns[n] )
+      while ( n >= 0 )
+      {
+        y2 = (Int)y_turns[n];
+        y_turns[n] = y;
+        y = y2;
+        n--;
+      }
+
+    if ( n < 0 )
+    {
+      if ( ras.maxBuff <= ras.top )
+      {
+        ras.error = Raster_Err_Overflow;
+        return FAILURE;
+      }
+      ras.maxBuff--;
+      ras.numTurns++;
+      ras.sizeBuff[-ras.numTurns] = y;
+    }
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Finalize_Profile_Table                                             */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Adjusts all links in the profiles list.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success.  FAILURE in case of overflow.                  */
+  /*                                                                       */
+  static Bool
+  Finalize_Profile_Table( RAS_ARG )
+  {
+    Int       bottom, top;
+    UShort    n;
+    PProfile  p;
+
+
+    n = ras.num_Profs;
+
+    if ( n > 1 )
+    {
+      p = ras.fProfile;
+      while ( n > 0 )
+      {
+        if ( n > 1 )
+          p->link = (PProfile)( p->offset + p->height );
+        else
+          p->link = NULL;
+
+        switch ( p->flow )
+        {
+        case Flow_Down:
+          bottom     = (Int)( p->start - p->height + 1 );
+          top        = (Int)p->start;
+          p->start   = bottom;
+          p->offset += p->height - 1;
+          break;
+
+        case Flow_Up:
+        default:
+          bottom = (Int)p->start;
+          top    = (Int)( p->start + p->height - 1 );
+        }
+
+        if ( Insert_Y_Turn( RAS_VARS bottom )   ||
+             Insert_Y_Turn( RAS_VARS top + 1 )  )
+          return FAILURE;
+
+        p = p->link;
+        n--;
+      }
+    }
+    else
+      ras.fProfile = NULL;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Split_Conic                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Subdivides one conic Bezier into two joint sub-arcs in the Bezier  */
+  /*    stack.                                                             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    None (subdivided Bezier is taken from the top of the stack).       */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This routine is the `beef' of this component.  It is  _the_ inner  */
+  /*    loop that should be optimized to hell to get the best performance. */
+  /*                                                                       */
+  static void
+  Split_Conic( TPoint*  base )
+  {
+    Long  a, b;
+
+
+    base[4].x = base[2].x;
+    b = base[1].x;
+    a = base[3].x = ( base[2].x + b ) / 2;
+    b = base[1].x = ( base[0].x + b ) / 2;
+    base[2].x = ( a + b ) / 2;
+
+    base[4].y = base[2].y;
+    b = base[1].y;
+    a = base[3].y = ( base[2].y + b ) / 2;
+    b = base[1].y = ( base[0].y + b ) / 2;
+    base[2].y = ( a + b ) / 2;
+
+    /* hand optimized.  gcc doesn't seem to be too good at common      */
+    /* expression substitution and instruction scheduling ;-)          */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Split_Cubic                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Subdivides a third-order Bezier arc into two joint sub-arcs in the */
+  /*    Bezier stack.                                                      */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This routine is the `beef' of the component.  It is one of _the_   */
+  /*    inner loops that should be optimized like hell to get the best     */
+  /*    performance.                                                       */
+  /*                                                                       */
+  static void
+  Split_Cubic( TPoint*  base )
+  {
+    Long  a, b, c, d;
+
+
+    base[6].x = base[3].x;
+    c = base[1].x;
+    d = base[2].x;
+    base[1].x = a = ( base[0].x + c + 1 ) >> 1;
+    base[5].x = b = ( base[3].x + d + 1 ) >> 1;
+    c = ( c + d + 1 ) >> 1;
+    base[2].x = a = ( a + c + 1 ) >> 1;
+    base[4].x = b = ( b + c + 1 ) >> 1;
+    base[3].x = ( a + b + 1 ) >> 1;
+
+    base[6].y = base[3].y;
+    c = base[1].y;
+    d = base[2].y;
+    base[1].y = a = ( base[0].y + c + 1 ) >> 1;
+    base[5].y = b = ( base[3].y + d + 1 ) >> 1;
+    c = ( c + d + 1 ) >> 1;
+    base[2].y = a = ( a + c + 1 ) >> 1;
+    base[4].y = b = ( b + c + 1 ) >> 1;
+    base[3].y = ( a + b + 1 ) >> 1;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Line_Up                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an ascending line segment and stores */
+  /*    them in the render pool.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    x1   :: The x-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    y1   :: The y-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    x2   :: The x-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    y2   :: The y-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    miny :: A lower vertical clipping bound value.                     */
+  /*                                                                       */
+  /*    maxy :: An upper vertical clipping bound value.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static Bool
+  Line_Up( RAS_ARGS Long  x1,
+                    Long  y1,
+                    Long  x2,
+                    Long  y2,
+                    Long  miny,
+                    Long  maxy )
+  {
+    Long   Dx, Dy;
+    Int    e1, e2, f1, f2, size;     /* XXX: is `Short' sufficient? */
+    Long   Ix, Rx, Ax;
+
+    PLong  top;
+
+
+    Dx = x2 - x1;
+    Dy = y2 - y1;
+
+    if ( Dy <= 0 || y2 < miny || y1 > maxy )
+      return SUCCESS;
+
+    if ( y1 < miny )
+    {
+      /* Take care: miny-y1 can be a very large value; we use     */
+      /*            a slow MulDiv function to avoid clipping bugs */
+      x1 += SMulDiv( Dx, miny - y1, Dy );
+      e1  = TRUNC( miny );
+      f1  = 0;
+    }
+    else
+    {
+      e1 = (Int)TRUNC( y1 );
+      f1 = (Int)FRAC( y1 );
+    }
+
+    if ( y2 > maxy )
+    {
+      /* x2 += FMulDiv( Dx, maxy - y2, Dy );  UNNECESSARY */
+      e2  = (Int)TRUNC( maxy );
+      f2  = 0;
+    }
+    else
+    {
+      e2 = (Int)TRUNC( y2 );
+      f2 = (Int)FRAC( y2 );
+    }
+
+    if ( f1 > 0 )
+    {
+      if ( e1 == e2 )
+        return SUCCESS;
+      else
+      {
+        x1 += FMulDiv( Dx, ras.precision - f1, Dy );
+        e1 += 1;
+      }
+    }
+    else
+      if ( ras.joint )
+      {
+        ras.top--;
+        ras.joint = FALSE;
+      }
+
+    ras.joint = (char)( f2 == 0 );
+
+    if ( ras.fresh )
+    {
+      ras.cProfile->start = e1;
+      ras.fresh           = FALSE;
+    }
+
+    size = e2 - e1 + 1;
+    if ( ras.top + size >= ras.maxBuff )
+    {
+      ras.error = Raster_Err_Overflow;
+      return FAILURE;
+    }
+
+    if ( Dx > 0 )
+    {
+      Ix = ( ras.precision * Dx ) / Dy;
+      Rx = ( ras.precision * Dx ) % Dy;
+      Dx = 1;
+    }
+    else
+    {
+      Ix = -( ( ras.precision * -Dx ) / Dy );
+      Rx =    ( ras.precision * -Dx ) % Dy;
+      Dx = -1;
+    }
+
+    Ax  = -Dy;
+    top = ras.top;
+
+    while ( size > 0 )
+    {
+      *top++ = x1;
+
+      x1 += Ix;
+      Ax += Rx;
+      if ( Ax >= 0 )
+      {
+        Ax -= Dy;
+        x1 += Dx;
+      }
+      size--;
+    }
+
+    ras.top = top;
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Line_Down                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an descending line segment and       */
+  /*    stores them in the render pool.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    x1   :: The x-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    y1   :: The y-coordinate of the segment's start point.             */
+  /*                                                                       */
+  /*    x2   :: The x-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    y2   :: The y-coordinate of the segment's end point.               */
+  /*                                                                       */
+  /*    miny :: A lower vertical clipping bound value.                     */
+  /*                                                                       */
+  /*    maxy :: An upper vertical clipping bound value.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static Bool
+  Line_Down( RAS_ARGS Long  x1,
+                      Long  y1,
+                      Long  x2,
+                      Long  y2,
+                      Long  miny,
+                      Long  maxy )
+  {
+    Bool  result, fresh;
+
+
+    fresh  = ras.fresh;
+
+    result = Line_Up( RAS_VARS x1, -y1, x2, -y2, -maxy, -miny );
+
+    if ( fresh && !ras.fresh )
+      ras.cProfile->start = -ras.cProfile->start;
+
+    return result;
+  }
+
+
+  /* A function type describing the functions used to split Bezier arcs */
+  typedef void  (*TSplitter)( TPoint*  base );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Bezier_Up                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an ascending Bezier arc and stores   */
+  /*    them in the render pool.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
+  /*                                                                       */
+  /*    splitter :: The function to split Bezier arcs.                     */
+  /*                                                                       */
+  /*    miny     :: A lower vertical clipping bound value.                 */
+  /*                                                                       */
+  /*    maxy     :: An upper vertical clipping bound value.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static Bool
+  Bezier_Up( RAS_ARGS Int        degree,
+                      TSplitter  splitter,
+                      Long       miny,
+                      Long       maxy )
+  {
+    Long   y1, y2, e, e2, e0;
+    Short  f1;
+
+    TPoint*  arc;
+    TPoint*  start_arc;
+
+    PLong top;
+
+
+    arc = ras.arc;
+    y1  = arc[degree].y;
+    y2  = arc[0].y;
+    top = ras.top;
+
+    if ( y2 < miny || y1 > maxy )
+      goto Fin;
+
+    e2 = FLOOR( y2 );
+
+    if ( e2 > maxy )
+      e2 = maxy;
+
+    e0 = miny;
+
+    if ( y1 < miny )
+      e = miny;
+    else
+    {
+      e  = CEILING( y1 );
+      f1 = (Short)( FRAC( y1 ) );
+      e0 = e;
+
+      if ( f1 == 0 )
+      {
+        if ( ras.joint )
+        {
+          top--;
+          ras.joint = FALSE;
+        }
+
+        *top++ = arc[degree].x;
+
+        e += ras.precision;
+      }
+    }
+
+    if ( ras.fresh )
+    {
+      ras.cProfile->start = TRUNC( e0 );
+      ras.fresh = FALSE;
+    }
+
+    if ( e2 < e )
+      goto Fin;
+
+    if ( ( top + TRUNC( e2 - e ) + 1 ) >= ras.maxBuff )
+    {
+      ras.top   = top;
+      ras.error = Raster_Err_Overflow;
+      return FAILURE;
+    }
+
+    start_arc = arc;
+
+    while ( arc >= start_arc && e <= e2 )
+    {
+      ras.joint = FALSE;
+
+      y2 = arc[0].y;
+
+      if ( y2 > e )
+      {
+        y1 = arc[degree].y;
+        if ( y2 - y1 >= ras.precision_step )
+        {
+          splitter( arc );
+          arc += degree;
+        }
+        else
+        {
+          *top++ = arc[degree].x + FMulDiv( arc[0].x-arc[degree].x,
+                                            e - y1, y2 - y1 );
+          arc -= degree;
+          e   += ras.precision;
+        }
+      }
+      else
+      {
+        if ( y2 == e )
+        {
+          ras.joint  = TRUE;
+          *top++     = arc[0].x;
+
+          e += ras.precision;
+        }
+        arc -= degree;
+      }
+    }
+
+  Fin:
+    ras.top  = top;
+    ras.arc -= degree;
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Bezier_Down                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the x-coordinates of an descending Bezier arc and stores  */
+  /*    them in the render pool.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    degree   :: The degree of the Bezier arc (either 2 or 3).          */
+  /*                                                                       */
+  /*    splitter :: The function to split Bezier arcs.                     */
+  /*                                                                       */
+  /*    miny     :: A lower vertical clipping bound value.                 */
+  /*                                                                       */
+  /*    maxy     :: An upper vertical clipping bound value.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on render pool overflow.               */
+  /*                                                                       */
+  static Bool
+  Bezier_Down( RAS_ARGS Int        degree,
+                        TSplitter  splitter,
+                        Long       miny,
+                        Long       maxy )
+  {
+    TPoint*  arc = ras.arc;
+    Bool     result, fresh;
+
+
+    arc[0].y = -arc[0].y;
+    arc[1].y = -arc[1].y;
+    arc[2].y = -arc[2].y;
+    if ( degree > 2 )
+      arc[3].y = -arc[3].y;
+
+    fresh = ras.fresh;
+
+    result = Bezier_Up( RAS_VARS degree, splitter, -maxy, -miny );
+
+    if ( fresh && !ras.fresh )
+      ras.cProfile->start = -ras.cProfile->start;
+
+    arc[0].y = -arc[0].y;
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Line_To                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Injects a new line segment and adjusts Profiles list.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*   x :: The x-coordinate of the segment's end point (its start point   */
+  /*        is stored in `LastX').                                         */
+  /*                                                                       */
+  /*   y :: The y-coordinate of the segment's end point (its start point   */
+  /*        is stored in `LastY').                                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static Bool
+  Line_To( RAS_ARGS Long  x,
+                    Long  y )
+  {
+    /* First, detect a change of direction */
+
+    switch ( ras.state )
+    {
+    case Unknown_State:
+      if ( y > ras.lastY )
+      {
+        if ( New_Profile( RAS_VARS Ascending_State ) )
+          return FAILURE;
+      }
+      else
+      {
+        if ( y < ras.lastY )
+          if ( New_Profile( RAS_VARS Descending_State ) )
+            return FAILURE;
+      }
+      break;
+
+    case Ascending_State:
+      if ( y < ras.lastY )
+      {
+        if ( End_Profile( RAS_VAR )                   ||
+             New_Profile( RAS_VARS Descending_State ) )
+          return FAILURE;
+      }
+      break;
+
+    case Descending_State:
+      if ( y > ras.lastY )
+      {
+        if ( End_Profile( RAS_VAR )                  ||
+             New_Profile( RAS_VARS Ascending_State ) )
+          return FAILURE;
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    /* Then compute the lines */
+
+    switch ( ras.state )
+    {
+    case Ascending_State:
+      if ( Line_Up( RAS_VARS ras.lastX, ras.lastY,
+                    x, y, ras.minY, ras.maxY ) )
+        return FAILURE;
+      break;
+
+    case Descending_State:
+      if ( Line_Down( RAS_VARS ras.lastX, ras.lastY,
+                      x, y, ras.minY, ras.maxY ) )
+        return FAILURE;
+      break;
+
+    default:
+      ;
+    }
+
+    ras.lastX = x;
+    ras.lastY = y;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Conic_To                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Injects a new conic arc and adjusts the profile list.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*   cx :: The x-coordinate of the arc's new control point.              */
+  /*                                                                       */
+  /*   cy :: The y-coordinate of the arc's new control point.              */
+  /*                                                                       */
+  /*   x  :: The x-coordinate of the arc's end point (its start point is   */
+  /*         stored in `LastX').                                           */
+  /*                                                                       */
+  /*   y  :: The y-coordinate of the arc's end point (its start point is   */
+  /*         stored in `LastY').                                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static Bool
+  Conic_To( RAS_ARGS Long  cx,
+                     Long  cy,
+                     Long  x,
+                     Long  y )
+  {
+    Long     y1, y2, y3, x3, ymin, ymax;
+    TStates  state_bez;
+
+
+    ras.arc      = ras.arcs;
+    ras.arc[2].x = ras.lastX;
+    ras.arc[2].y = ras.lastY;
+    ras.arc[1].x = cx; ras.arc[1].y = cy;
+    ras.arc[0].x = x;  ras.arc[0].y = y;
+
+    do
+    {
+      y1 = ras.arc[2].y;
+      y2 = ras.arc[1].y;
+      y3 = ras.arc[0].y;
+      x3 = ras.arc[0].x;
+
+      /* first, categorize the Bezier arc */
+
+      if ( y1 <= y3 )
+      {
+        ymin = y1;
+        ymax = y3;
+      }
+      else
+      {
+        ymin = y3;
+        ymax = y1;
+      }
+
+      if ( y2 < ymin || y2 > ymax )
+      {
+        /* this arc has no given direction, split it! */
+        Split_Conic( ras.arc );
+        ras.arc += 2;
+      }
+      else if ( y1 == y3 )
+      {
+        /* this arc is flat, ignore it and pop it from the Bezier stack */
+        ras.arc -= 2;
+      }
+      else
+      {
+        /* the arc is y-monotonous, either ascending or descending */
+        /* detect a change of direction                            */
+        state_bez = y1 < y3 ? Ascending_State : Descending_State;
+        if ( ras.state != state_bez )
+        {
+          /* finalize current profile if any */
+          if ( ras.state != Unknown_State   &&
+               End_Profile( RAS_VAR ) )
+            goto Fail;
+
+          /* create a new profile */
+          if ( New_Profile( RAS_VARS state_bez ) )
+            goto Fail;
+        }
+
+        /* now call the appropriate routine */
+        if ( state_bez == Ascending_State )
+        {
+          if ( Bezier_Up( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+            goto Fail;
+        }
+        else
+          if ( Bezier_Down( RAS_VARS 2, Split_Conic, ras.minY, ras.maxY ) )
+            goto Fail;
+      }
+
+    } while ( ras.arc >= ras.arcs );
+
+    ras.lastX = x3;
+    ras.lastY = y3;
+
+    return SUCCESS;
+
+  Fail:
+    return FAILURE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Cubic_To                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Injects a new cubic arc and adjusts the profile list.              */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*   cx1 :: The x-coordinate of the arc's first new control point.       */
+  /*                                                                       */
+  /*   cy1 :: The y-coordinate of the arc's first new control point.       */
+  /*                                                                       */
+  /*   cx2 :: The x-coordinate of the arc's second new control point.      */
+  /*                                                                       */
+  /*   cy2 :: The y-coordinate of the arc's second new control point.      */
+  /*                                                                       */
+  /*   x   :: The x-coordinate of the arc's end point (its start point is  */
+  /*          stored in `LastX').                                          */
+  /*                                                                       */
+  /*   y   :: The y-coordinate of the arc's end point (its start point is  */
+  /*          stored in `LastY').                                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*   SUCCESS on success, FAILURE on render pool overflow or incorrect    */
+  /*   profile.                                                            */
+  /*                                                                       */
+  static Bool
+  Cubic_To( RAS_ARGS Long  cx1,
+                     Long  cy1,
+                     Long  cx2,
+                     Long  cy2,
+                     Long  x,
+                     Long  y )
+  {
+    Long     y1, y2, y3, y4, x4, ymin1, ymax1, ymin2, ymax2;
+    TStates  state_bez;
+
+
+    ras.arc      = ras.arcs;
+    ras.arc[3].x = ras.lastX;
+    ras.arc[3].y = ras.lastY;
+    ras.arc[2].x = cx1; ras.arc[2].y = cy1;
+    ras.arc[1].x = cx2; ras.arc[1].y = cy2;
+    ras.arc[0].x = x;   ras.arc[0].y = y;
+
+    do
+    {
+      y1 = ras.arc[3].y;
+      y2 = ras.arc[2].y;
+      y3 = ras.arc[1].y;
+      y4 = ras.arc[0].y;
+      x4 = ras.arc[0].x;
+
+      /* first, categorize the Bezier arc */
+
+      if ( y1 <= y4 )
+      {
+        ymin1 = y1;
+        ymax1 = y4;
+      }
+      else
+      {
+        ymin1 = y4;
+        ymax1 = y1;
+      }
+
+      if ( y2 <= y3 )
+      {
+        ymin2 = y2;
+        ymax2 = y3;
+      }
+      else
+      {
+        ymin2 = y3;
+        ymax2 = y2;
+      }
+
+      if ( ymin2 < ymin1 || ymax2 > ymax1 )
+      {
+        /* this arc has no given direction, split it! */
+        Split_Cubic( ras.arc );
+        ras.arc += 3;
+      }
+      else if ( y1 == y4 )
+      {
+        /* this arc is flat, ignore it and pop it from the Bezier stack */
+        ras.arc -= 3;
+      }
+      else
+      {
+        state_bez = ( y1 <= y4 ) ? Ascending_State : Descending_State;
+
+        /* detect a change of direction */
+        if ( ras.state != state_bez )
+        {
+          if ( ras.state != Unknown_State   &&
+               End_Profile( RAS_VAR ) )
+            goto Fail;
+
+          if ( New_Profile( RAS_VARS state_bez ) )
+            goto Fail;
+        }
+
+        /* compute intersections */
+        if ( state_bez == Ascending_State )
+        {
+          if ( Bezier_Up( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+            goto Fail;
+        }
+        else
+          if ( Bezier_Down( RAS_VARS 3, Split_Cubic, ras.minY, ras.maxY ) )
+            goto Fail;
+      }
+
+    } while ( ras.arc >= ras.arcs );
+
+    ras.lastX = x4;
+    ras.lastY = y4;
+
+    return SUCCESS;
+
+  Fail:
+    return FAILURE;
+  }
+
+
+#undef  SWAP_
+#define SWAP_( x, y )  do                \
+                       {                 \
+                         Long  swap = x; \
+                                         \
+                                         \
+                         x = y;          \
+                         y = swap;       \
+                       } while ( 0 )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Decompose_Curve                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Scans the outline arays in order to emit individual segments and   */
+  /*    Beziers by calling Line_To() and Bezier_To().  It handles all      */
+  /*    weird cases, like when the first point is off the curve, or when   */
+  /*    there are simply no `on' points in the contour!                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    first   :: The index of the first point in the contour.            */
+  /*                                                                       */
+  /*    last    :: The index of the last point in the contour.             */
+  /*                                                                       */
+  /*    flipped :: If set, flip the direction of the curve.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE on error.                              */
+  /*                                                                       */
+  static Bool
+  Decompose_Curve( RAS_ARGS UShort  first,
+                            UShort  last,
+                            int     flipped )
+  {
+    FT_Vector   v_last;
+    FT_Vector   v_control;
+    FT_Vector   v_start;
+
+    FT_Vector*  points;
+    FT_Vector*  point;
+    FT_Vector*  limit;
+    char*       tags;
+
+    unsigned    tag;       /* current point's state           */
+
+
+    points = ras.outline.points;
+    limit  = points + last;
+
+    v_start.x = SCALED( points[first].x );
+    v_start.y = SCALED( points[first].y );
+    v_last.x  = SCALED( points[last].x );
+    v_last.y  = SCALED( points[last].y );
+
+    if ( flipped )
+    {
+      SWAP_( v_start.x, v_start.y );
+      SWAP_( v_last.x, v_last.y );
+    }
+
+    v_control = v_start;
+
+    point = points + first;
+    tags  = ras.outline.tags  + first;
+    tag   = FT_CURVE_TAG( tags[0] );
+
+    /* A contour cannot start with a cubic control point! */
+    if ( tag == FT_CURVE_TAG_CUBIC )
+      goto Invalid_Outline;
+
+    /* check first point to determine origin */
+    if ( tag == FT_CURVE_TAG_CONIC )
+    {
+      /* first point is conic control.  Yes, this happens. */
+      if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON )
+      {
+        /* start at last point if it is on the curve */
+        v_start = v_last;
+        limit--;
+      }
+      else
+      {
+        /* if both first and last points are conic,         */
+        /* start at their middle and record its position    */
+        /* for closure                                      */
+        v_start.x = ( v_start.x + v_last.x ) / 2;
+        v_start.y = ( v_start.y + v_last.y ) / 2;
+
+        v_last = v_start;
+      }
+      point--;
+      tags--;
+    }
+
+    ras.lastX = v_start.x;
+    ras.lastY = v_start.y;
+
+    while ( point < limit )
+    {
+      point++;
+      tags++;
+
+      tag = FT_CURVE_TAG( tags[0] );
+
+      switch ( tag )
+      {
+      case FT_CURVE_TAG_ON:  /* emit a single line_to */
+        {
+          Long  x, y;
+
+
+          x = SCALED( point->x );
+          y = SCALED( point->y );
+          if ( flipped )
+            SWAP_( x, y );
+
+          if ( Line_To( RAS_VARS x, y ) )
+            goto Fail;
+          continue;
+        }
+
+      case FT_CURVE_TAG_CONIC:  /* consume conic arcs */
+        v_control.x = SCALED( point[0].x );
+        v_control.y = SCALED( point[0].y );
+
+        if ( flipped )
+          SWAP_( v_control.x, v_control.y );
+
+      Do_Conic:
+        if ( point < limit )
+        {
+          FT_Vector  v_middle;
+          Long       x, y;
+
+
+          point++;
+          tags++;
+          tag = FT_CURVE_TAG( tags[0] );
+
+          x = SCALED( point[0].x );
+          y = SCALED( point[0].y );
+
+          if ( flipped )
+            SWAP_( x, y );
+
+          if ( tag == FT_CURVE_TAG_ON )
+          {
+            if ( Conic_To( RAS_VARS v_control.x, v_control.y, x, y ) )
+              goto Fail;
+            continue;
+          }
+
+          if ( tag != FT_CURVE_TAG_CONIC )
+            goto Invalid_Outline;
+
+          v_middle.x = ( v_control.x + x ) / 2;
+          v_middle.y = ( v_control.y + y ) / 2;
+
+          if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+                                  v_middle.x,  v_middle.y ) )
+            goto Fail;
+
+          v_control.x = x;
+          v_control.y = y;
+
+          goto Do_Conic;
+        }
+
+        if ( Conic_To( RAS_VARS v_control.x, v_control.y,
+                                v_start.x,   v_start.y ) )
+          goto Fail;
+
+        goto Close;
+
+      default:  /* FT_CURVE_TAG_CUBIC */
+        {
+          Long  x1, y1, x2, y2, x3, y3;
+
+
+          if ( point + 1 > limit                             ||
+               FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC )
+            goto Invalid_Outline;
+
+          point += 2;
+          tags  += 2;
+
+          x1 = SCALED( point[-2].x );
+          y1 = SCALED( point[-2].y );
+          x2 = SCALED( point[-1].x );
+          y2 = SCALED( point[-1].y );
+          x3 = SCALED( point[ 0].x );
+          y3 = SCALED( point[ 0].y );
+
+          if ( flipped )
+          {
+            SWAP_( x1, y1 );
+            SWAP_( x2, y2 );
+            SWAP_( x3, y3 );
+          }
+
+          if ( point <= limit )
+          {
+            if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) )
+              goto Fail;
+            continue;
+          }
+
+          if ( Cubic_To( RAS_VARS x1, y1, x2, y2, v_start.x, v_start.y ) )
+            goto Fail;
+          goto Close;
+        }
+      }
+    }
+
+    /* close the contour with a line segment */
+    if ( Line_To( RAS_VARS v_start.x, v_start.y ) )
+      goto Fail;
+
+  Close:
+    return SUCCESS;
+
+  Invalid_Outline:
+    ras.error = Raster_Err_Invalid;
+
+  Fail:
+    return FAILURE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Convert_Glyph                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts a glyph into a series of segments and arcs and makes a    */
+  /*    profiles list with them.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    flipped :: If set, flip the direction of curve.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS on success, FAILURE if any error was encountered during    */
+  /*    rendering.                                                         */
+  /*                                                                       */
+  static Bool
+  Convert_Glyph( RAS_ARGS int  flipped )
+  {
+    int       i;
+    unsigned  start;
+
+    PProfile  lastProfile;
+
+
+    ras.fProfile = NULL;
+    ras.joint    = FALSE;
+    ras.fresh    = FALSE;
+
+    ras.maxBuff  = ras.sizeBuff - AlignProfileSize;
+
+    ras.numTurns = 0;
+
+    ras.cProfile         = (PProfile)ras.top;
+    ras.cProfile->offset = ras.top;
+    ras.num_Profs        = 0;
+
+    start = 0;
+
+    for ( i = 0; i < ras.outline.n_contours; i++ )
+    {
+      ras.state    = Unknown_State;
+      ras.gProfile = NULL;
+
+      if ( Decompose_Curve( RAS_VARS (unsigned short)start,
+                            ras.outline.contours[i],
+                            flipped ) )
+        return FAILURE;
+
+      start = ras.outline.contours[i] + 1;
+
+      /* We must now see whether the extreme arcs join or not */
+      if ( FRAC( ras.lastY ) == 0 &&
+           ras.lastY >= ras.minY  &&
+           ras.lastY <= ras.maxY  )
+        if ( ras.gProfile && ras.gProfile->flow == ras.cProfile->flow )
+          ras.top--;
+        /* Note that ras.gProfile can be nil if the contour was too small */
+        /* to be drawn.                                                   */
+
+      lastProfile = ras.cProfile;
+      if ( End_Profile( RAS_VAR ) )
+        return FAILURE;
+
+      /* close the `next profile in contour' linked list */
+      if ( ras.gProfile )
+        lastProfile->next = ras.gProfile;
+    }
+
+    if ( Finalize_Profile_Table( RAS_VAR ) )
+      return FAILURE;
+
+    return (Bool)( ras.top < ras.maxBuff ? SUCCESS : FAILURE );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /**                                                                     **/
+  /**  SCAN-LINE SWEEPS AND DRAWING                                       **/
+  /**                                                                     **/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Init_Linked                                                          */
+  /*                                                                       */
+  /*    Initializes an empty linked list.                                  */
+  /*                                                                       */
+  static void
+  Init_Linked( TProfileList*  l )
+  {
+    *l = NULL;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  InsNew                                                               */
+  /*                                                                       */
+  /*    Inserts a new profile in a linked list.                            */
+  /*                                                                       */
+  static void
+  InsNew( PProfileList  list,
+          PProfile      profile )
+  {
+    PProfile  *old, current;
+    Long       x;
+
+
+    old     = list;
+    current = *old;
+    x       = profile->X;
+
+    while ( current )
+    {
+      if ( x < current->X )
+        break;
+      old     = &current->link;
+      current = *old;
+    }
+
+    profile->link = current;
+    *old          = profile;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  DelOld                                                               */
+  /*                                                                       */
+  /*    Removes an old profile from a linked list.                         */
+  /*                                                                       */
+  static void
+  DelOld( PProfileList  list,
+          PProfile      profile )
+  {
+    PProfile  *old, current;
+
+
+    old     = list;
+    current = *old;
+
+    while ( current )
+    {
+      if ( current == profile )
+      {
+        *old = current->link;
+        return;
+      }
+
+      old     = &current->link;
+      current = *old;
+    }
+
+    /* we should never get there, unless the profile was not part of */
+    /* the list.                                                     */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Sort                                                                 */
+  /*                                                                       */
+  /*    Sorts a trace list.  In 95%, the list is already sorted.  We need  */
+  /*    an algorithm which is fast in this case.  Bubble sort is enough    */
+  /*    and simple.                                                        */
+  /*                                                                       */
+  static void
+  Sort( PProfileList  list )
+  {
+    PProfile  *old, current, next;
+
+
+    /* First, set the new X coordinate of each profile */
+    current = *list;
+    while ( current )
+    {
+      current->X       = *current->offset;
+      current->offset += current->flow;
+      current->height--;
+      current = current->link;
+    }
+
+    /* Then sort them */
+    old     = list;
+    current = *old;
+
+    if ( !current )
+      return;
+
+    next = current->link;
+
+    while ( next )
+    {
+      if ( current->X <= next->X )
+      {
+        old     = &current->link;
+        current = *old;
+
+        if ( !current )
+          return;
+      }
+      else
+      {
+        *old          = next;
+        current->link = next->link;
+        next->link    = current;
+
+        old     = list;
+        current = *old;
+      }
+
+      next = current->link;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Vertical Sweep Procedure Set                                         */
+  /*                                                                       */
+  /*  These four routines are used during the vertical black/white sweep   */
+  /*  phase by the generic Draw_Sweep() function.                          */
+  /*                                                                       */
+  /*************************************************************************/
+
+  static void
+  Vertical_Sweep_Init( RAS_ARGS Short*  min,
+                                Short*  max )
+  {
+    Long  pitch = ras.target.pitch;
+
+    FT_UNUSED( max );
+
+
+    ras.traceIncr = (Short)-pitch;
+    ras.traceOfs  = -*min * pitch;
+    if ( pitch > 0 )
+      ras.traceOfs += ( ras.target.rows - 1 ) * pitch;
+
+    ras.gray_min_x = 0;
+    ras.gray_max_x = 0;
+  }
+
+
+  static void
+  Vertical_Sweep_Span( RAS_ARGS Short       y,
+                                FT_F26Dot6  x1,
+                                FT_F26Dot6  x2,
+                                PProfile    left,
+                                PProfile    right )
+  {
+    Long   e1, e2;
+    int    c1, c2;
+    Byte   f1, f2;
+    Byte*  target;
+
+    FT_UNUSED( y );
+    FT_UNUSED( left );
+    FT_UNUSED( right );
+
+
+    /* Drop-out control */
+
+    e1 = TRUNC( CEILING( x1 ) );
+
+    if ( x2 - x1 - ras.precision <= ras.precision_jitter )
+      e2 = e1;
+    else
+      e2 = TRUNC( FLOOR( x2 ) );
+
+    if ( e2 >= 0 && e1 < ras.bWidth )
+    {
+      if ( e1 < 0 )
+        e1 = 0;
+      if ( e2 >= ras.bWidth )
+        e2 = ras.bWidth - 1;
+
+      c1 = (Short)( e1 >> 3 );
+      c2 = (Short)( e2 >> 3 );
+
+      f1 = (Byte)  ( 0xFF >> ( e1 & 7 ) );
+      f2 = (Byte) ~( 0x7F >> ( e2 & 7 ) );
+
+      if ( ras.gray_min_x > c1 ) ras.gray_min_x = (short)c1;
+      if ( ras.gray_max_x < c2 ) ras.gray_max_x = (short)c2;
+
+      target = ras.bTarget + ras.traceOfs + c1;
+      c2 -= c1;
+
+      if ( c2 > 0 )
+      {
+        target[0] |= f1;
+
+        /* memset() is slower than the following code on many platforms. */
+        /* This is due to the fact that, in the vast majority of cases,  */
+        /* the span length in bytes is relatively small.                 */
+        c2--;
+        while ( c2 > 0 )
+        {
+          *(++target) = 0xFF;
+          c2--;
+        }
+        target[1] |= f2;
+      }
+      else
+        *target |= ( f1 & f2 );
+    }
+  }
+
+
+  static void
+  Vertical_Sweep_Drop( RAS_ARGS Short       y,
+                                FT_F26Dot6  x1,
+                                FT_F26Dot6  x2,
+                                PProfile    left,
+                                PProfile    right )
+  {
+    Long   e1, e2;
+    Short  c1, f1;
+
+
+    /* Drop-out control */
+
+    e1 = CEILING( x1 );
+    e2 = FLOOR  ( x2 );
+
+    if ( e1 > e2 )
+    {
+      if ( e1 == e2 + ras.precision )
+      {
+        switch ( ras.dropOutControl )
+        {
+        case 1:
+          e1 = e2;
+          break;
+
+        case 4:
+          e1 = CEILING( (x1 + x2 + 1) / 2 );
+          break;
+
+        case 2:
+        case 5:
+          /* Drop-out Control Rule #4 */
+
+          /* The spec is not very clear regarding rule #4.  It      */
+          /* presents a method that is way too costly to implement  */
+          /* while the general idea seems to get rid of `stubs'.    */
+          /*                                                        */
+          /* Here, we only get rid of stubs recognized if:          */
+          /*                                                        */
+          /*  upper stub:                                           */
+          /*                                                        */
+          /*   - P_Left and P_Right are in the same contour         */
+          /*   - P_Right is the successor of P_Left in that contour */
+          /*   - y is the top of P_Left and P_Right                 */
+          /*                                                        */
+          /*  lower stub:                                           */
+          /*                                                        */
+          /*   - P_Left and P_Right are in the same contour         */
+          /*   - P_Left is the successor of P_Right in that contour */
+          /*   - y is the bottom of P_Left                          */
+          /*                                                        */
+
+          /* FIXXXME: uncommenting this line solves the disappearing */
+          /*          bit problem in the `7' of verdana 10pts, but   */
+          /*          makes a new one in the `C' of arial 14pts      */
+
+#if 0
+          if ( x2 - x1 < ras.precision_half )
+#endif
+          {
+            /* upper stub test */
+            if ( left->next == right && left->height <= 0 )
+              return;
+
+            /* lower stub test */
+            if ( right->next == left && left->start == y )
+              return;
+          }
+
+          /* check that the rightmost pixel isn't set */
+
+          e1 = TRUNC( e1 );
+
+          c1 = (Short)( e1 >> 3 );
+          f1 = (Short)( e1 &  7 );
+
+          if ( e1 >= 0 && e1 < ras.bWidth                      &&
+               ras.bTarget[ras.traceOfs + c1] & ( 0x80 >> f1 ) )
+            return;
+
+          if ( ras.dropOutControl == 2 )
+            e1 = e2;
+          else
+            e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+          break;
+
+        default:
+          return;  /* unsupported mode */
+        }
+      }
+      else
+        return;
+    }
+
+    e1 = TRUNC( e1 );
+
+    if ( e1 >= 0 && e1 < ras.bWidth )
+    {
+      c1 = (Short)( e1 >> 3 );
+      f1 = (Short)( e1 & 7 );
+
+      if ( ras.gray_min_x > c1 ) ras.gray_min_x = c1;
+      if ( ras.gray_max_x < c1 ) ras.gray_max_x = c1;
+
+      ras.bTarget[ras.traceOfs + c1] |= (char)( 0x80 >> f1 );
+    }
+  }
+
+
+  static void
+  Vertical_Sweep_Step( RAS_ARG )
+  {
+    ras.traceOfs += ras.traceIncr;
+  }
+
+
+  /***********************************************************************/
+  /*                                                                     */
+  /*  Horizontal Sweep Procedure Set                                     */
+  /*                                                                     */
+  /*  These four routines are used during the horizontal black/white     */
+  /*  sweep phase by the generic Draw_Sweep() function.                  */
+  /*                                                                     */
+  /***********************************************************************/
+
+  static void
+  Horizontal_Sweep_Init( RAS_ARGS Short*  min,
+                                  Short*  max )
+  {
+    /* nothing, really */
+    FT_UNUSED( raster );
+    FT_UNUSED( min );
+    FT_UNUSED( max );
+  }
+
+
+  static void
+  Horizontal_Sweep_Span( RAS_ARGS Short       y,
+                                  FT_F26Dot6  x1,
+                                  FT_F26Dot6  x2,
+                                  PProfile    left,
+                                  PProfile    right )
+  {
+    Long   e1, e2;
+    PByte  bits;
+    Byte   f1;
+
+    FT_UNUSED( left );
+    FT_UNUSED( right );
+
+
+    if ( x2 - x1 < ras.precision )
+    {
+      e1 = CEILING( x1 );
+      e2 = FLOOR  ( x2 );
+
+      if ( e1 == e2 )
+      {
+        bits = ras.bTarget + ( y >> 3 );
+        f1   = (Byte)( 0x80 >> ( y & 7 ) );
+
+        e1 = TRUNC( e1 );
+
+        if ( e1 >= 0 && e1 < ras.target.rows )
+        {
+          PByte  p;
+
+
+          p = bits - e1*ras.target.pitch;
+          if ( ras.target.pitch > 0 )
+            p += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+          p[0] |= f1;
+        }
+      }
+    }
+  }
+
+
+  static void
+  Horizontal_Sweep_Drop( RAS_ARGS Short       y,
+                                  FT_F26Dot6  x1,
+                                  FT_F26Dot6  x2,
+                                  PProfile    left,
+                                  PProfile    right )
+  {
+    Long   e1, e2;
+    PByte  bits;
+    Byte   f1;
+
+
+    /* During the horizontal sweep, we only take care of drop-outs */
+
+    e1 = CEILING( x1 );
+    e2 = FLOOR  ( x2 );
+
+    if ( e1 > e2 )
+    {
+      if ( e1 == e2 + ras.precision )
+      {
+        switch ( ras.dropOutControl )
+        {
+        case 1:
+          e1 = e2;
+          break;
+
+        case 4:
+          e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+          break;
+
+        case 2:
+        case 5:
+
+          /* Drop-out Control Rule #4 */
+
+          /* The spec is not very clear regarding rule #4.  It      */
+          /* presents a method that is way too costly to implement  */
+          /* while the general idea seems to get rid of `stubs'.    */
+          /*                                                        */
+
+          /* rightmost stub test */
+          if ( left->next == right && left->height <= 0 )
+            return;
+
+          /* leftmost stub test */
+          if ( right->next == left && left->start == y )
+            return;
+
+          /* check that the rightmost pixel isn't set */
+
+          e1 = TRUNC( e1 );
+
+          bits = ras.bTarget + ( y >> 3 );
+          f1   = (Byte)( 0x80 >> ( y & 7 ) );
+
+          bits -= e1 * ras.target.pitch;
+          if ( ras.target.pitch > 0 )
+            bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+          if ( e1 >= 0              &&
+               e1 < ras.target.rows &&
+               *bits & f1 )
+            return;
+
+          if ( ras.dropOutControl == 2 )
+            e1 = e2;
+          else
+            e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+          break;
+
+        default:
+          return;  /* unsupported mode */
+        }
+      }
+      else
+        return;
+    }
+
+    bits = ras.bTarget + ( y >> 3 );
+    f1   = (Byte)( 0x80 >> ( y & 7 ) );
+
+    e1 = TRUNC( e1 );
+
+    if ( e1 >= 0 && e1 < ras.target.rows )
+    {
+      bits -= e1 * ras.target.pitch;
+      if ( ras.target.pitch > 0 )
+        bits += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+      bits[0] |= f1;
+    }
+  }
+
+
+  static void
+  Horizontal_Sweep_Step( RAS_ARG )
+  {
+    /* Nothing, really */
+    FT_UNUSED( raster );
+  }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Vertical Gray Sweep Procedure Set                                    */
+  /*                                                                       */
+  /*  These two routines are used during the vertical gray-levels sweep    */
+  /*  phase by the generic Draw_Sweep() function.                          */
+  /*                                                                       */
+  /*  NOTES                                                                */
+  /*                                                                       */
+  /*  - The target pixmap's width *must* be a multiple of 4.               */
+  /*                                                                       */
+  /*  - You have to use the function Vertical_Sweep_Span() for the gray    */
+  /*    span call.                                                         */
+  /*                                                                       */
+  /*************************************************************************/
+
+  static void
+  Vertical_Gray_Sweep_Init( RAS_ARGS Short*  min,
+                                     Short*  max )
+  {
+    Long  pitch, byte_len;
+
+
+    *min = *min & -2;
+    *max = ( *max + 3 ) & -2;
+
+    ras.traceOfs  = 0;
+    pitch         = ras.target.pitch;
+    byte_len      = -pitch;
+    ras.traceIncr = (Short)byte_len;
+    ras.traceG    = ( *min / 2 ) * byte_len;
+
+    if ( pitch > 0 )
+    {
+      ras.traceG += ( ras.target.rows - 1 ) * pitch;
+      byte_len    = -byte_len;
+    }
+
+    ras.gray_min_x =  (Short)byte_len;
+    ras.gray_max_x = -(Short)byte_len;
+  }
+
+
+  static void
+  Vertical_Gray_Sweep_Step( RAS_ARG )
+  {
+    Int    c1, c2;
+    PByte  pix, bit, bit2;
+    Int*   count = ras.count_table;
+    Byte*  grays;
+
+
+    ras.traceOfs += ras.gray_width;
+
+    if ( ras.traceOfs > ras.gray_width )
+    {
+      pix   = ras.gTarget + ras.traceG + ras.gray_min_x * 4;
+      grays = ras.grays;
+
+      if ( ras.gray_max_x >= 0 )
+      {
+        Long   last_pixel = ras.target.width - 1;
+        Int    last_cell  = last_pixel >> 2;
+        Int    last_bit   = last_pixel & 3;
+        Bool   over       = 0;
+
+
+        if ( ras.gray_max_x >= last_cell && last_bit != 3 )
+        {
+          ras.gray_max_x = last_cell - 1;
+          over = 1;
+        }
+
+        if ( ras.gray_min_x < 0 )
+          ras.gray_min_x = 0;
+
+        bit   = ras.bTarget + ras.gray_min_x;
+        bit2  = bit + ras.gray_width;
+
+        c1 = ras.gray_max_x - ras.gray_min_x;
+
+        while ( c1 >= 0 )
+        {
+          c2 = count[*bit] + count[*bit2];
+
+          if ( c2 )
+          {
+            pix[0] = grays[(c2 >> 12) & 0x000F];
+            pix[1] = grays[(c2 >> 8 ) & 0x000F];
+            pix[2] = grays[(c2 >> 4 ) & 0x000F];
+            pix[3] = grays[ c2        & 0x000F];
+
+            *bit  = 0;
+            *bit2 = 0;
+          }
+
+          bit++;
+          bit2++;
+          pix += 4;
+          c1--;
+        }
+
+        if ( over )
+        {
+          c2 = count[*bit] + count[*bit2];
+          if ( c2 )
+          {
+            switch ( last_bit )
+            {
+            case 2:
+              pix[2] = grays[(c2 >> 4 ) & 0x000F];
+            case 1:
+              pix[1] = grays[(c2 >> 8 ) & 0x000F];
+            default:
+              pix[0] = grays[(c2 >> 12) & 0x000F];
+            }
+
+            *bit  = 0;
+            *bit2 = 0;
+          }
+        }
+      }
+
+      ras.traceOfs = 0;
+      ras.traceG  += ras.traceIncr;
+
+      ras.gray_min_x =  32000;
+      ras.gray_max_x = -32000;
+    }
+  }
+
+
+  static void
+  Horizontal_Gray_Sweep_Span( RAS_ARGS Short       y,
+                                       FT_F26Dot6  x1,
+                                       FT_F26Dot6  x2,
+                                       PProfile    left,
+                                       PProfile    right )
+  {
+    /* nothing, really */
+    FT_UNUSED( raster );
+    FT_UNUSED( y );
+    FT_UNUSED( x1 );
+    FT_UNUSED( x2 );
+    FT_UNUSED( left );
+    FT_UNUSED( right );
+  }
+
+
+  static void
+  Horizontal_Gray_Sweep_Drop( RAS_ARGS Short       y,
+                                       FT_F26Dot6  x1,
+                                       FT_F26Dot6  x2,
+                                       PProfile    left,
+                                       PProfile    right )
+  {
+    Long   e1, e2;
+    PByte  pixel;
+    Byte   color;
+
+
+    /* During the horizontal sweep, we only take care of drop-outs */
+    e1 = CEILING( x1 );
+    e2 = FLOOR  ( x2 );
+
+    if ( e1 > e2 )
+    {
+      if ( e1 == e2 + ras.precision )
+      {
+        switch ( ras.dropOutControl )
+        {
+        case 1:
+          e1 = e2;
+          break;
+
+        case 4:
+          e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+          break;
+
+        case 2:
+        case 5:
+
+          /* Drop-out Control Rule #4 */
+
+          /* The spec is not very clear regarding rule #4.  It      */
+          /* presents a method that is way too costly to implement  */
+          /* while the general idea seems to get rid of `stubs'.    */
+          /*                                                        */
+
+          /* rightmost stub test */
+          if ( left->next == right && left->height <= 0 )
+            return;
+
+          /* leftmost stub test */
+          if ( right->next == left && left->start == y )
+            return;
+
+          if ( ras.dropOutControl == 2 )
+            e1 = e2;
+          else
+            e1 = CEILING( ( x1 + x2 + 1 ) / 2 );
+
+          break;
+
+        default:
+          return;  /* unsupported mode */
+        }
+      }
+      else
+        return;
+    }
+
+    if ( e1 >= 0 )
+    {
+      if ( x2 - x1 >= ras.precision_half )
+        color = ras.grays[2];
+      else
+        color = ras.grays[1];
+
+      e1 = TRUNC( e1 ) / 2;
+      if ( e1 < ras.target.rows )
+      {
+        pixel = ras.gTarget - e1 * ras.target.pitch + y / 2;
+        if ( ras.target.pitch > 0 )
+          pixel += ( ras.target.rows - 1 ) * ras.target.pitch;
+
+        if ( pixel[0] == ras.grays[0] )
+          pixel[0] = color;
+      }
+    }
+  }
+
+
+#endif /* FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  Generic Sweep Drawing routine                                        */
+  /*                                                                       */
+  /*************************************************************************/
+
+  static Bool
+  Draw_Sweep( RAS_ARG )
+  {
+    Short         y, y_change, y_height;
+
+    PProfile      P, Q, P_Left, P_Right;
+
+    Short         min_Y, max_Y, top, bottom, dropouts;
+
+    Long          x1, x2, xs, e1, e2;
+
+    TProfileList  waiting;
+    TProfileList  draw_left, draw_right;
+
+
+    /* Init empty linked lists */
+
+    Init_Linked( &waiting );
+
+    Init_Linked( &draw_left  );
+    Init_Linked( &draw_right );
+
+    /* first, compute min and max Y */
+
+    P     = ras.fProfile;
+    max_Y = (Short)TRUNC( ras.minY );
+    min_Y = (Short)TRUNC( ras.maxY );
+
+    while ( P )
+    {
+      Q = P->link;
+
+      bottom = (Short)P->start;
+      top    = (Short)( P->start + P->height - 1 );
+
+      if ( min_Y > bottom ) min_Y = bottom;
+      if ( max_Y < top    ) max_Y = top;
+
+      P->X = 0;
+      InsNew( &waiting, P );
+
+      P = Q;
+    }
+
+    /* Check the Y-turns */
+    if ( ras.numTurns == 0 )
+    {
+      ras.error = Raster_Err_Invalid;
+      return FAILURE;
+    }
+
+    /* Now inits the sweep */
+
+    ras.Proc_Sweep_Init( RAS_VARS &min_Y, &max_Y );
+
+    /* Then compute the distance of each profile from min_Y */
+
+    P = waiting;
+
+    while ( P )
+    {
+      P->countL = (UShort)( P->start - min_Y );
+      P = P->link;
+    }
+
+    /* Let's go */
+
+    y        = min_Y;
+    y_height = 0;
+
+    if ( ras.numTurns > 0 &&
+         ras.sizeBuff[-ras.numTurns] == min_Y )
+      ras.numTurns--;
+
+    while ( ras.numTurns > 0 )
+    {
+      /* look in the waiting list for new activations */
+
+      P = waiting;
+
+      while ( P )
+      {
+        Q = P->link;
+        P->countL -= y_height;
+        if ( P->countL == 0 )
+        {
+          DelOld( &waiting, P );
+
+          switch ( P->flow )
+          {
+          case Flow_Up:
+            InsNew( &draw_left,  P );
+            break;
+
+          case Flow_Down:
+            InsNew( &draw_right, P );
+            break;
+          }
+        }
+
+        P = Q;
+      }
+
+      /* Sort the drawing lists */
+
+      Sort( &draw_left );
+      Sort( &draw_right );
+
+      y_change = (Short)ras.sizeBuff[-ras.numTurns--];
+      y_height = (Short)( y_change - y );
+
+      while ( y < y_change )
+      {
+        /* Let's trace */
+
+        dropouts = 0;
+
+        P_Left  = draw_left;
+        P_Right = draw_right;
+
+        while ( P_Left )
+        {
+          x1 = P_Left ->X;
+          x2 = P_Right->X;
+
+          if ( x1 > x2 )
+          {
+            xs = x1;
+            x1 = x2;
+            x2 = xs;
+          }
+
+          if ( x2 - x1 <= ras.precision )
+          {
+            e1 = FLOOR( x1 );
+            e2 = CEILING( x2 );
+
+            if ( ras.dropOutControl != 0                 &&
+                 ( e1 > e2 || e2 == e1 + ras.precision ) )
+            {
+              /* a drop out was detected */
+
+              P_Left ->X = x1;
+              P_Right->X = x2;
+
+              /* mark profile for drop-out processing */
+              P_Left->countL = 1;
+              dropouts++;
+
+              goto Skip_To_Next;
+            }
+          }
+
+          ras.Proc_Sweep_Span( RAS_VARS y, x1, x2, P_Left, P_Right );
+
+        Skip_To_Next:
+
+          P_Left  = P_Left->link;
+          P_Right = P_Right->link;
+        }
+
+        /* now perform the dropouts _after_ the span drawing -- */
+        /* drop-outs processing has been moved out of the loop  */
+        /* for performance tuning                               */
+        if ( dropouts > 0 )
+          goto Scan_DropOuts;
+
+      Next_Line:
+
+        ras.Proc_Sweep_Step( RAS_VAR );
+
+        y++;
+
+        if ( y < y_change )
+        {
+          Sort( &draw_left  );
+          Sort( &draw_right );
+        }
+      }
+
+      /* Now finalize the profiles that needs it */
+
+      P = draw_left;
+      while ( P )
+      {
+        Q = P->link;
+        if ( P->height == 0 )
+          DelOld( &draw_left, P );
+        P = Q;
+      }
+
+      P = draw_right;
+      while ( P )
+      {
+        Q = P->link;
+        if ( P->height == 0 )
+          DelOld( &draw_right, P );
+        P = Q;
+      }
+    }
+
+    /* for gray-scaling, flushes the bitmap scanline cache */
+    while ( y <= max_Y )
+    {
+      ras.Proc_Sweep_Step( RAS_VAR );
+      y++;
+    }
+
+    return SUCCESS;
+
+  Scan_DropOuts:
+
+    P_Left  = draw_left;
+    P_Right = draw_right;
+
+    while ( P_Left )
+    {
+      if ( P_Left->countL )
+      {
+        P_Left->countL = 0;
+#if 0
+        dropouts--;  /* -- this is useful when debugging only */
+#endif
+        ras.Proc_Sweep_Drop( RAS_VARS y,
+                                      P_Left->X,
+                                      P_Right->X,
+                                      P_Left,
+                                      P_Right );
+      }
+
+      P_Left  = P_Left->link;
+      P_Right = P_Right->link;
+    }
+
+    goto Next_Line;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Render_Single_Pass                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Performs one sweep with sub-banding.                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    flipped :: If set, flip the direction of the outline.              */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Renderer error code.                                               */
+  /*                                                                       */
+  static int
+  Render_Single_Pass( RAS_ARGS Bool  flipped )
+  {
+    Short  i, j, k;
+
+
+    while ( ras.band_top >= 0 )
+    {
+      ras.maxY = (Long)ras.band_stack[ras.band_top].y_max * ras.precision;
+      ras.minY = (Long)ras.band_stack[ras.band_top].y_min * ras.precision;
+
+      ras.top = ras.buff;
+
+      ras.error = Raster_Err_None;
+
+      if ( Convert_Glyph( RAS_VARS flipped ) )
+      {
+        if ( ras.error != Raster_Err_Overflow )
+          return FAILURE;
+
+        ras.error = Raster_Err_None;
+
+        /* sub-banding */
+
+#ifdef DEBUG_RASTER
+        ClearBand( RAS_VARS TRUNC( ras.minY ), TRUNC( ras.maxY ) );
+#endif
+
+        i = ras.band_stack[ras.band_top].y_min;
+        j = ras.band_stack[ras.band_top].y_max;
+
+        k = (Short)( ( i + j ) / 2 );
+
+        if ( ras.band_top >= 7 || k < i )
+        {
+          ras.band_top = 0;
+          ras.error    = Raster_Err_Invalid;
+
+          return ras.error;
+        }
+
+        ras.band_stack[ras.band_top + 1].y_min = k;
+        ras.band_stack[ras.band_top + 1].y_max = j;
+
+        ras.band_stack[ras.band_top].y_max = (Short)( k - 1 );
+
+        ras.band_top++;
+      }
+      else
+      {
+        if ( ras.fProfile )
+          if ( Draw_Sweep( RAS_VAR ) )
+             return ras.error;
+        ras.band_top--;
+      }
+    }
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Render_Glyph                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Renders a glyph in a bitmap.  Sub-banding if needed.               */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  Render_Glyph( RAS_ARG )
+  {
+    FT_Error  error;
+
+
+    Set_High_Precision( RAS_VARS ras.outline.flags &
+                        FT_OUTLINE_HIGH_PRECISION );
+    ras.scale_shift    = ras.precision_shift;
+    ras.dropOutControl = 2;
+    ras.second_pass    = (FT_Byte)( !( ras.outline.flags &
+                                       FT_OUTLINE_SINGLE_PASS ) );
+
+    /* Vertical Sweep */
+    ras.Proc_Sweep_Init = Vertical_Sweep_Init;
+    ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+    ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+    ras.Proc_Sweep_Step = Vertical_Sweep_Step;
+
+    ras.band_top            = 0;
+    ras.band_stack[0].y_min = 0;
+    ras.band_stack[0].y_max = (short)( ras.target.rows - 1 );
+
+    ras.bWidth  = (unsigned short)ras.target.width;
+    ras.bTarget = (Byte*)ras.target.buffer;
+
+    if ( ( error = Render_Single_Pass( RAS_VARS 0 ) ) != 0 )
+      return error;
+
+    /* Horizontal Sweep */
+    if ( ras.second_pass && ras.dropOutControl != 0 )
+    {
+      ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+      ras.Proc_Sweep_Span = Horizontal_Sweep_Span;
+      ras.Proc_Sweep_Drop = Horizontal_Sweep_Drop;
+      ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+      ras.band_top            = 0;
+      ras.band_stack[0].y_min = 0;
+      ras.band_stack[0].y_max = (short)( ras.target.width - 1 );
+
+      if ( ( error = Render_Single_Pass( RAS_VARS 1 ) ) != 0 )
+        return error;
+    }
+
+    return Raster_Err_Ok;
+  }
+
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Render_Gray_Glyph                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Renders a glyph with grayscaling.  Sub-banding if needed.          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  Render_Gray_Glyph( RAS_ARG )
+  {
+    Long      pixel_width;
+    FT_Error  error;
+
+
+    Set_High_Precision( RAS_VARS ras.outline.flags &
+                        FT_OUTLINE_HIGH_PRECISION );
+    ras.scale_shift    = ras.precision_shift + 1;
+    ras.dropOutControl = 2;
+    ras.second_pass    = !( ras.outline.flags & FT_OUTLINE_SINGLE_PASS );
+
+    /* Vertical Sweep */
+
+    ras.band_top            = 0;
+    ras.band_stack[0].y_min = 0;
+    ras.band_stack[0].y_max = 2 * ras.target.rows - 1;
+
+    ras.bWidth  = ras.gray_width;
+    pixel_width = 2 * ( ( ras.target.width + 3 ) >> 2 );
+
+    if ( ras.bWidth > pixel_width )
+      ras.bWidth = pixel_width;
+
+    ras.bWidth  = ras.bWidth * 8;
+    ras.bTarget = (Byte*)ras.gray_lines;
+    ras.gTarget = (Byte*)ras.target.buffer;
+
+    ras.Proc_Sweep_Init = Vertical_Gray_Sweep_Init;
+    ras.Proc_Sweep_Span = Vertical_Sweep_Span;
+    ras.Proc_Sweep_Drop = Vertical_Sweep_Drop;
+    ras.Proc_Sweep_Step = Vertical_Gray_Sweep_Step;
+
+    error = Render_Single_Pass( RAS_VARS 0 );
+    if ( error )
+      return error;
+
+    /* Horizontal Sweep */
+    if ( ras.second_pass && ras.dropOutControl != 0 )
+    {
+      ras.Proc_Sweep_Init = Horizontal_Sweep_Init;
+      ras.Proc_Sweep_Span = Horizontal_Gray_Sweep_Span;
+      ras.Proc_Sweep_Drop = Horizontal_Gray_Sweep_Drop;
+      ras.Proc_Sweep_Step = Horizontal_Sweep_Step;
+
+      ras.band_top            = 0;
+      ras.band_stack[0].y_min = 0;
+      ras.band_stack[0].y_max = ras.target.width * 2 - 1;
+
+      error = Render_Single_Pass( RAS_VARS 1 );
+      if ( error )
+        return error;
+    }
+
+    return Raster_Err_Ok;
+  }
+
+#else /* !FT_RASTER_OPTION_ANTI_ALIASING */
+
+  FT_LOCAL_DEF( FT_Error )
+  Render_Gray_Glyph( RAS_ARG )
+  {
+    FT_UNUSED_RASTER;
+
+    return Raster_Err_Cannot_Render_Glyph;
+  }
+
+#endif /* !FT_RASTER_OPTION_ANTI_ALIASING */
+
+
+  static void
+  ft_black_init( TRaster_Instance*  raster )
+  {
+    FT_UInt  n;
+    FT_ULong c;
+
+
+    /* setup count table */
+    for ( n = 0; n < 256; n++ )
+    {
+      c = ( n & 0x55 ) + ( ( n & 0xAA ) >> 1 );
+
+      c = ( ( c << 6 ) & 0x3000 ) |
+          ( ( c << 4 ) & 0x0300 ) |
+          ( ( c << 2 ) & 0x0030 ) |
+                   (c  & 0x0003 );
+
+      raster->count_table[n] = (UInt)c;
+    }
+
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+    /* set default 5-levels gray palette */
+    for ( n = 0; n < 5; n++ )
+      raster->grays[n] = n * 255 / 4;
+
+    raster->gray_width = RASTER_GRAY_LINES / 2;
+
+#endif
+  }
+
+
+  /**** RASTER OBJECT CREATION: In standalone mode, we simply use *****/
+  /****                         a static object.                  *****/
+
+
+#ifdef _STANDALONE_
+
+
+  static int
+  ft_black_new( void*      memory,
+                FT_Raster  *araster )
+  {
+     static FT_RasterRec_  the_raster;
+
+
+     *araster = &the_raster;
+     FT_MEM_ZERO( &the_raster, sizeof ( the_raster ) );
+     ft_black_init( &the_raster );
+
+     return 0;
+  }
+
+
+  static void
+  ft_black_done( FT_Raster  raster )
+  {
+    /* nothing */
+    raster->init = 0;
+  }
+
+
+#else /* _STANDALONE_ */
+
+
+  static int
+  ft_black_new( FT_Memory           memory,
+                TRaster_Instance**  araster )
+  {
+    FT_Error           error;
+    TRaster_Instance*  raster;
+
+
+    *araster = 0;
+    if ( !FT_NEW( raster ) )
+    {
+      raster->memory = memory;
+      ft_black_init( raster );
+
+      *araster = raster;
+    }
+
+    return error;
+  }
+
+
+  static void
+  ft_black_done( TRaster_Instance*  raster )
+  {
+    FT_Memory  memory = (FT_Memory)raster->memory;
+    FT_FREE( raster );
+  }
+
+
+#endif /* _STANDALONE_ */
+
+
+  static void
+  ft_black_reset( TRaster_Instance*  raster,
+                  const char*        pool_base,
+                  long               pool_size )
+  {
+    if ( raster && pool_base && pool_size >= 4096 )
+    {
+      /* save the pool */
+      raster->buff     = (PLong)pool_base;
+      raster->sizeBuff = raster->buff + pool_size / sizeof ( Long );
+    }
+  }
+
+
+  static void
+  ft_black_set_mode( TRaster_Instance*  raster,
+                     unsigned long      mode,
+                     const char*        palette )
+  {
+#ifdef FT_RASTER_OPTION_ANTI_ALIASING
+
+    if ( mode == FT_MAKE_TAG( 'p', 'a', 'l', '5' ) )
+    {
+      /* set 5-levels gray palette */
+      raster->grays[0] = palette[0];
+      raster->grays[1] = palette[1];
+      raster->grays[2] = palette[2];
+      raster->grays[3] = palette[3];
+      raster->grays[4] = palette[4];
+    }
+
+#else
+
+    FT_UNUSED( raster );
+    FT_UNUSED( mode );
+    FT_UNUSED( palette );
+
+#endif
+  }
+
+
+  static int
+  ft_black_render( TRaster_Instance*  raster,
+                   FT_Raster_Params*  params )
+  {
+    FT_Outline*  outline    = (FT_Outline*)params->source;
+    FT_Bitmap*   target_map = params->target;
+
+
+    if ( !raster || !raster->buff || !raster->sizeBuff )
+      return Raster_Err_Not_Ini;
+
+    /* return immediately if the outline is empty */
+    if ( outline->n_points == 0 || outline->n_contours <= 0 )
+      return Raster_Err_None;
+
+    if ( !outline || !outline->contours || !outline->points )
+      return Raster_Err_Invalid;
+
+    if ( outline->n_points != outline->contours[outline->n_contours - 1] + 1 )
+      return Raster_Err_Invalid;
+
+    /* this version of the raster does not support direct rendering, sorry */
+    if ( params->flags & FT_RASTER_FLAG_DIRECT )
+      return Raster_Err_Unsupported;
+
+    if ( !target_map || !target_map->buffer )
+      return Raster_Err_Invalid;
+
+    ras.outline  = *outline;
+    ras.target   = *target_map;
+
+    return ( ( params->flags & FT_RASTER_FLAG_AA )
+               ? Render_Gray_Glyph( raster )
+               : Render_Glyph( raster ) );
+  }
+
+
+  const FT_Raster_Funcs  ft_standard_raster =
+  {
+    FT_GLYPH_FORMAT_OUTLINE,
+    (FT_Raster_New_Func)     ft_black_new,
+    (FT_Raster_Reset_Func)   ft_black_reset,
+    (FT_Raster_Set_Mode_Func)ft_black_set_mode,
+    (FT_Raster_Render_Func)  ft_black_render,
+    (FT_Raster_Done_Func)    ft_black_done
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftraster.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftraster.h                                                             */
+/*                                                                         */
+/*    The FreeType glyph rasterizer (specification).                       */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used        */
+/*  modified and distributed under the terms of the FreeType project       */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __FTRASTER_H__
+#define __FTRASTER_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_IMAGE_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Uncomment the following line if you are using ftraster.c as a         */
+  /* standalone module, fully independent of FreeType.                     */
+  /*                                                                       */
+/* #define _STANDALONE_ */
+
+  FT_EXPORT_VAR( const FT_Raster_Funcs )  ft_standard_raster;
+
+
+FT_END_HEADER
+
+#endif /* __FTRASTER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftrend1.c
@@ -1,0 +1,273 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftrend1.c                                                              */
+/*                                                                         */
+/*    The FreeType glyph rasterizer interface (body).                      */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_OUTLINE_H
+#include "ftrend1.h"
+#include "ftraster.h"
+
+#include "rasterrs.h"
+
+
+  /* initialize renderer -- init its raster */
+  static FT_Error
+  ft_raster1_init( FT_Renderer  render )
+  {
+    FT_Library  library = FT_MODULE_LIBRARY( render );
+
+
+    render->clazz->raster_class->raster_reset( render->raster,
+                                               library->raster_pool,
+                                               library->raster_pool_size );
+
+    return Raster_Err_Ok;
+  }
+
+
+  /* set render-specific mode */
+  static FT_Error
+  ft_raster1_set_mode( FT_Renderer  render,
+                       FT_ULong     mode_tag,
+                       FT_Pointer   data )
+  {
+    /* we simply pass it to the raster */
+    return render->clazz->raster_class->raster_set_mode( render->raster,
+                                                         mode_tag,
+                                                         data );
+  }
+
+
+  /* transform a given glyph image */
+  static FT_Error
+  ft_raster1_transform( FT_Renderer   render,
+                        FT_GlyphSlot  slot,
+                        FT_Matrix*    matrix,
+                        FT_Vector*    delta )
+  {
+    FT_Error error = Raster_Err_Ok;
+
+
+    if ( slot->format != render->glyph_format )
+    {
+      error = Raster_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    if ( matrix )
+      FT_Outline_Transform( &slot->outline, matrix );
+
+    if ( delta )
+      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+  Exit:
+    return error;
+  }
+
+
+  /* return the glyph's control box */
+  static void
+  ft_raster1_get_cbox( FT_Renderer   render,
+                       FT_GlyphSlot  slot,
+                       FT_BBox*      cbox )
+  {
+    FT_MEM_ZERO( cbox, sizeof ( *cbox ) );
+
+    if ( slot->format == render->glyph_format )
+      FT_Outline_Get_CBox( &slot->outline, cbox );
+  }
+
+
+  /* convert a slot's glyph image into a bitmap */
+  static FT_Error
+  ft_raster1_render( FT_Renderer     render,
+                     FT_GlyphSlot    slot,
+                     FT_Render_Mode  mode,
+                     FT_Vector*      origin )
+  {
+    FT_Error     error;
+    FT_Outline*  outline;
+    FT_BBox      cbox;
+    FT_UInt      width, height, pitch;
+    FT_Bitmap*   bitmap;
+    FT_Memory    memory;
+
+    FT_Raster_Params  params;
+
+
+    /* check glyph image format */
+    if ( slot->format != render->glyph_format )
+    {
+      error = Raster_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* check rendering mode */
+    if ( mode != FT_RENDER_MODE_MONO )
+    {
+      /* raster1 is only capable of producing monochrome bitmaps */
+      if ( render->clazz == &ft_raster1_renderer_class )
+        return Raster_Err_Cannot_Render_Glyph;
+    }
+    else
+    {
+      /* raster5 is only capable of producing 5-gray-levels bitmaps */
+      if ( render->clazz == &ft_raster5_renderer_class )
+        return Raster_Err_Cannot_Render_Glyph;
+    }
+
+    outline = &slot->outline;
+
+    /* translate the outline to the new origin if needed */
+    if ( origin )
+      FT_Outline_Translate( outline, origin->x, origin->y );
+
+    /* compute the control box, and grid fit it */
+    FT_Outline_Get_CBox( outline, &cbox );
+
+    cbox.xMin &= -64;
+    cbox.yMin &= -64;
+    cbox.xMax  = ( cbox.xMax + 63 ) & -64;
+    cbox.yMax  = ( cbox.yMax + 63 ) & -64;
+
+    width  = (FT_UInt)( ( cbox.xMax - cbox.xMin ) >> 6 );
+    height = (FT_UInt)( ( cbox.yMax - cbox.yMin ) >> 6 );
+    bitmap = &slot->bitmap;
+    memory = render->root.memory;
+
+    /* release old bitmap buffer */
+    if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+    {
+      FT_FREE( bitmap->buffer );
+      slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+    }
+
+    /* allocate new one, depends on pixel format */
+    if ( !( mode & FT_RENDER_MODE_MONO ) )
+    {
+      /* we pad to 32 bits, only for backwards compatibility with FT 1.x */
+      pitch = ( width + 3 ) & -4;
+      bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+      bitmap->num_grays  = 256;
+    }
+    else
+    {
+      pitch = ( ( width + 15 ) >> 4 ) << 1;
+      bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+    }
+
+    bitmap->width = width;
+    bitmap->rows  = height;
+    bitmap->pitch = pitch;
+
+    if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+      goto Exit;
+
+    slot->flags |= FT_GLYPH_OWN_BITMAP;
+
+    /* translate outline to render it into the bitmap */
+    FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+    /* set up parameters */
+    params.target = bitmap;
+    params.source = outline;
+    params.flags  = 0;
+
+    if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY )
+      params.flags |= FT_RASTER_FLAG_AA;
+
+    /* render outline into the bitmap */
+    error = render->raster_render( render->raster, &params );
+    
+    FT_Outline_Translate( outline, cbox.xMin, cbox.yMin );
+    
+    if ( error )
+      goto Exit;
+
+    slot->format      = FT_GLYPH_FORMAT_BITMAP;
+    slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 );
+    slot->bitmap_top  = (FT_Int)( cbox.yMax >> 6 );
+
+  Exit:
+    return error;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Renderer_Class  ft_raster1_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+
+      "raster1",
+      0x10000L,
+      0x20000L,
+
+      0,    /* module specific interface */
+
+      (FT_Module_Constructor)ft_raster1_init,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Renderer_RenderFunc)   ft_raster1_render,
+    (FT_Renderer_TransformFunc)ft_raster1_transform,
+    (FT_Renderer_GetCBoxFunc)  ft_raster1_get_cbox,
+    (FT_Renderer_SetModeFunc)  ft_raster1_set_mode,
+
+    (FT_Raster_Funcs*)    &ft_standard_raster
+  };
+
+
+  /* This renderer is _NOT_ part of the default modules; you will need */
+  /* to register it by hand in your application.  It should only be    */
+  /* used for backwards-compatibility with FT 1.x anyway.              */
+  /*                                                                   */
+  FT_CALLBACK_TABLE_DEF
+  const FT_Renderer_Class  ft_raster5_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+
+      "raster5",
+      0x10000L,
+      0x20000L,
+
+      0,    /* module specific interface */
+
+      (FT_Module_Constructor)ft_raster1_init,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Renderer_RenderFunc)   ft_raster1_render,
+    (FT_Renderer_TransformFunc)ft_raster1_transform,
+    (FT_Renderer_GetCBoxFunc)  ft_raster1_get_cbox,
+    (FT_Renderer_SetModeFunc)  ft_raster1_set_mode,
+
+    (FT_Raster_Funcs*)    &ft_standard_raster
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftrend1.h
@@ -1,0 +1,44 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftrend1.h                                                              */
+/*                                                                         */
+/*    The FreeType glyph rasterizer interface (specification).             */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __FTREND1_H__
+#define __FTREND1_H__
+
+
+#include <ft2build.h>
+#include FT_RENDER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Renderer_Class )  ft_raster1_renderer_class;
+
+  /* this renderer is _NOT_ part of the default modules, you'll need */
+  /* to register it by hand in your application.  It should only be  */
+  /* used for backwards-compatibility with FT 1.x anyway.            */
+  /*                                                                 */
+  FT_EXPORT_VAR( const FT_Renderer_Class )  ft_raster5_renderer_class;
+
+
+FT_END_HEADER
+
+#endif /* __FTREND1_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsmerrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftsmerrs.h                                                             */
+/*                                                                         */
+/*    smooth renderer error codes (specification only).                    */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the smooth renderer error enumeration     */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __FTSMERRS_H__
+#define __FTSMERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  Smooth_Err_
+#define FT_ERR_BASE    FT_Mod_Err_Smooth
+
+#include FT_ERRORS_H
+
+#endif /* __FTSMERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsmooth.c
@@ -1,0 +1,371 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftsmooth.c                                                             */
+/*                                                                         */
+/*    Anti-aliasing renderer interface (body).                             */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_OUTLINE_H
+#include "ftsmooth.h"
+#include "ftgrays.h"
+
+#include "ftsmerrs.h"
+
+
+  /* initialize renderer -- init its raster */
+  static FT_Error
+  ft_smooth_init( FT_Renderer  render )
+  {
+    FT_Library  library = FT_MODULE_LIBRARY( render );
+
+
+    render->clazz->raster_class->raster_reset( render->raster,
+                                               library->raster_pool,
+                                               library->raster_pool_size );
+
+    return 0;
+  }
+
+
+  /* sets render-specific mode */
+  static FT_Error
+  ft_smooth_set_mode( FT_Renderer  render,
+                      FT_ULong     mode_tag,
+                      FT_Pointer   data )
+  {
+    /* we simply pass it to the raster */
+    return render->clazz->raster_class->raster_set_mode( render->raster,
+                                                         mode_tag,
+                                                         data );
+  }
+
+  /* transform a given glyph image */
+  static FT_Error
+  ft_smooth_transform( FT_Renderer   render,
+                       FT_GlyphSlot  slot,
+                       FT_Matrix*    matrix,
+                       FT_Vector*    delta )
+  {
+    FT_Error  error = Smooth_Err_Ok;
+
+
+    if ( slot->format != render->glyph_format )
+    {
+      error = Smooth_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    if ( matrix )
+      FT_Outline_Transform( &slot->outline, matrix );
+
+    if ( delta )
+      FT_Outline_Translate( &slot->outline, delta->x, delta->y );
+
+  Exit:
+    return error;
+  }
+
+
+  /* return the glyph's control box */
+  static void
+  ft_smooth_get_cbox( FT_Renderer   render,
+                      FT_GlyphSlot  slot,
+                      FT_BBox*      cbox )
+  {
+    FT_MEM_ZERO( cbox, sizeof ( *cbox ) );
+
+    if ( slot->format == render->glyph_format )
+      FT_Outline_Get_CBox( &slot->outline, cbox );
+  }
+
+
+  /* convert a slot's glyph image into a bitmap */
+  static FT_Error
+  ft_smooth_render_generic( FT_Renderer     render,
+                            FT_GlyphSlot    slot,
+                            FT_Render_Mode  mode,
+                            FT_Vector*      origin,
+                            FT_Render_Mode  required_mode,
+                            FT_Int          hmul,
+                            FT_Int          vmul )
+  {
+    FT_Error     error;
+    FT_Outline*  outline = NULL;
+    FT_BBox      cbox;
+    FT_UInt      width, height, pitch;
+    FT_Bitmap*   bitmap;
+    FT_Memory    memory;
+
+    FT_Raster_Params  params;
+
+
+    /* check glyph image format */
+    if ( slot->format != render->glyph_format )
+    {
+      error = Smooth_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* check mode */
+    if ( mode != required_mode )
+      return Smooth_Err_Cannot_Render_Glyph;
+
+    outline = &slot->outline;
+
+    /* translate the outline to the new origin if needed */
+    if ( origin )
+      FT_Outline_Translate( outline, origin->x, origin->y );
+
+    /* compute the control box, and grid fit it */
+    FT_Outline_Get_CBox( outline, &cbox );
+
+    cbox.xMin &= -64;
+    cbox.yMin &= -64;
+    cbox.xMax  = ( cbox.xMax + 63 ) & -64;
+    cbox.yMax  = ( cbox.yMax + 63 ) & -64;
+
+    width  = ( cbox.xMax - cbox.xMin ) >> 6;
+    height = ( cbox.yMax - cbox.yMin ) >> 6;
+    bitmap = &slot->bitmap;
+    memory = render->root.memory;
+
+    /* release old bitmap buffer */
+    if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+    {
+      FT_FREE( bitmap->buffer );
+      slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+    }
+
+    /* allocate new one, depends on pixel format */
+    pitch = width;
+    if ( hmul )
+    {
+      width = width * hmul;
+      pitch = ( width + 3 ) & -4;
+    }
+
+    if ( vmul )
+      height *= vmul;
+
+    bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+    bitmap->num_grays  = 256;
+    bitmap->width      = width;
+    bitmap->rows       = height;
+    bitmap->pitch      = pitch;
+
+    if ( FT_ALLOC( bitmap->buffer, (FT_ULong)pitch * height ) )
+      goto Exit;
+
+    slot->flags |= FT_GLYPH_OWN_BITMAP;
+
+    /* translate outline to render it into the bitmap */
+    FT_Outline_Translate( outline, -cbox.xMin, -cbox.yMin );
+
+    /* set up parameters */
+    params.target = bitmap;
+    params.source = outline;
+    params.flags  = FT_RASTER_FLAG_AA;
+
+    /* implode outline if needed */
+    {
+      FT_Int      n;
+      FT_Vector*  vec;
+
+
+      if ( hmul )
+        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+          vec->x *= hmul;
+
+      if ( vmul )
+        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+          vec->y *= vmul;
+    }
+
+    /* render outline into the bitmap */
+    error = render->raster_render( render->raster, &params );
+
+    /* deflate outline if needed */
+    {
+      FT_Int      n;
+      FT_Vector*  vec;
+
+
+      if ( hmul )
+        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+          vec->x /= hmul;
+
+      if ( vmul )
+        for ( vec = outline->points, n = 0; n < outline->n_points; n++, vec++ )
+          vec->y /= vmul;
+    }
+
+    FT_Outline_Translate( outline, cbox.xMin, cbox.yMin );
+
+    if ( error )
+      goto Exit;
+
+    slot->format      = FT_GLYPH_FORMAT_BITMAP;
+    slot->bitmap_left = (FT_Int)( cbox.xMin >> 6 );
+    slot->bitmap_top  = (FT_Int)( cbox.yMax >> 6 );
+
+  Exit:
+    if ( outline && origin )
+      FT_Outline_Translate( outline, -origin->x, -origin->y );
+
+    return error;
+  }
+
+
+  /* convert a slot's glyph image into a bitmap */
+  static FT_Error
+  ft_smooth_render( FT_Renderer     render,
+                    FT_GlyphSlot    slot,
+                    FT_Render_Mode  mode,
+                    FT_Vector*      origin )
+  {
+    return ft_smooth_render_generic( render, slot, mode, origin,
+                                     FT_RENDER_MODE_NORMAL,
+                                     0, 0 );
+  }
+
+
+  /* convert a slot's glyph image into a horizontal LCD bitmap */
+  static FT_Error
+  ft_smooth_render_lcd( FT_Renderer     render,
+                        FT_GlyphSlot    slot,
+                        FT_Render_Mode  mode,
+                        FT_Vector*      origin )
+  {
+    FT_Error  error;
+
+    error = ft_smooth_render_generic( render, slot, mode, origin,
+                                      FT_RENDER_MODE_LCD,
+                                      3, 0 );
+    if ( !error )
+      slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD;
+
+    return error;
+  }
+
+
+  /* convert a slot's glyph image into a vertical LCD bitmap */
+  static FT_Error
+  ft_smooth_render_lcd_v( FT_Renderer     render,
+                          FT_GlyphSlot    slot,
+                          FT_Render_Mode  mode,
+                          FT_Vector*      origin )
+  {
+    FT_Error  error;
+
+    error = ft_smooth_render_generic( render, slot, mode, origin,
+                                      FT_RENDER_MODE_LCD_V,
+                                      0, 3 );
+    if ( !error )
+      slot->bitmap.pixel_mode = FT_PIXEL_MODE_LCD_V;
+
+    return error;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Renderer_Class  ft_smooth_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+
+      "smooth",
+      0x10000L,
+      0x20000L,
+
+      0,    /* module specific interface */
+
+      (FT_Module_Constructor)ft_smooth_init,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Renderer_RenderFunc)   ft_smooth_render,
+    (FT_Renderer_TransformFunc)ft_smooth_transform,
+    (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,
+    (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,
+
+    (FT_Raster_Funcs*)    &ft_grays_raster
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Renderer_Class  ft_smooth_lcd_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+
+      "smooth-lcd",
+      0x10000L,
+      0x20000L,
+
+      0,    /* module specific interface */
+
+      (FT_Module_Constructor)ft_smooth_init,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Renderer_RenderFunc)   ft_smooth_render_lcd,
+    (FT_Renderer_TransformFunc)ft_smooth_transform,
+    (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,
+    (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,
+
+    (FT_Raster_Funcs*)    &ft_grays_raster
+  };
+
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Renderer_Class  ft_smooth_lcdv_renderer_class =
+  {
+    {
+      ft_module_renderer,
+      sizeof( FT_RendererRec ),
+
+      "smooth-lcdv",
+      0x10000L,
+      0x20000L,
+
+      0,    /* module specific interface */
+
+      (FT_Module_Constructor)ft_smooth_init,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    FT_GLYPH_FORMAT_OUTLINE,
+
+    (FT_Renderer_RenderFunc)   ft_smooth_render_lcd_v,
+    (FT_Renderer_TransformFunc)ft_smooth_transform,
+    (FT_Renderer_GetCBoxFunc)  ft_smooth_get_cbox,
+    (FT_Renderer_SetModeFunc)  ft_smooth_set_mode,
+
+    (FT_Raster_Funcs*)    &ft_grays_raster
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsmooth.h
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftsmooth.h                                                             */
+/*                                                                         */
+/*    Anti-aliasing renderer interface (specification).                    */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __FTSMOOTH_H__
+#define __FTSMOOTH_H__
+
+
+#include <ft2build.h>
+#include FT_RENDER_H
+
+
+FT_BEGIN_HEADER
+
+
+#ifndef FT_CONFIG_OPTION_NO_STD_RASTER
+  FT_EXPORT_VAR( const FT_Renderer_Class )  ft_std_renderer_class;
+#endif
+
+#ifndef FT_CONFIG_OPTION_NO_SMOOTH_RASTER
+  FT_EXPORT_VAR( const FT_Renderer_Class )  ft_smooth_renderer_class;
+
+  FT_EXPORT_VAR( const FT_Renderer_Class )  ft_smooth_lcd_renderer_class;
+
+  FT_EXPORT_VAR( const FT_Renderer_Class )  ft_smooth_lcd_v_renderer_class;
+#endif
+
+
+
+FT_END_HEADER
+
+#endif /* __FTSMOOTH_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftstream.c
@@ -1,0 +1,803 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftstream.c                                                             */
+/*                                                                         */
+/*    I/O stream support (body).                                           */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_stream
+
+
+  FT_BASE_DEF( void )
+  FT_Stream_OpenMemory( FT_Stream       stream,
+                        const FT_Byte*  base,
+                        FT_ULong        size )
+  {
+    stream->base   = (FT_Byte*) base;
+    stream->size   = size;
+    stream->pos    = 0;
+    stream->cursor = 0;
+    stream->read   = 0;
+    stream->close  = 0;
+  }
+
+
+  FT_BASE_DEF( void )
+  FT_Stream_Close( FT_Stream  stream )
+  {
+    if ( stream && stream->close )
+    {
+      stream->close( stream );
+      stream->close = NULL;
+    }
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Stream_Seek( FT_Stream  stream,
+                  FT_ULong   pos )
+  {
+    FT_Error  error = FT_Err_Ok;
+
+
+    stream->pos = pos;
+
+    if ( stream->read )
+    {
+      if ( stream->read( stream, pos, 0, 0 ) )
+      {
+        FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+                   pos, stream->size ));
+
+        error = FT_Err_Invalid_Stream_Operation;
+      }
+    }
+    /* note that seeking to the first position after the file is valid */
+    else if ( pos > stream->size )
+    {
+      FT_ERROR(( "FT_Stream_Seek: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+                 pos, stream->size ));
+
+      error = FT_Err_Invalid_Stream_Operation;
+    }
+
+    return error;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Stream_Skip( FT_Stream  stream,
+                  FT_Long    distance )
+  {
+    return FT_Stream_Seek( stream, (FT_ULong)( stream->pos + distance ) );
+  }
+
+
+  FT_BASE_DEF( FT_Long )
+  FT_Stream_Pos( FT_Stream  stream )
+  {
+    return stream->pos;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Stream_Read( FT_Stream  stream,
+                  FT_Byte*   buffer,
+                  FT_ULong   count )
+  {
+    return FT_Stream_ReadAt( stream, stream->pos, buffer, count );
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Stream_ReadAt( FT_Stream  stream,
+                    FT_ULong   pos,
+                    FT_Byte*   buffer,
+                    FT_ULong   count )
+  {
+    FT_Error  error = FT_Err_Ok;
+    FT_ULong  read_bytes;
+
+
+    if ( pos >= stream->size )
+    {
+      FT_ERROR(( "FT_Stream_ReadAt: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+                 pos, stream->size ));
+
+      return FT_Err_Invalid_Stream_Operation;
+    }
+
+    if ( stream->read )
+      read_bytes = stream->read( stream, pos, buffer, count );
+    else
+    {
+      read_bytes = stream->size - pos;
+      if ( read_bytes > count )
+        read_bytes = count;
+
+      FT_MEM_COPY( buffer, stream->base + pos, read_bytes );
+    }
+
+    stream->pos = pos + read_bytes;
+
+    if ( read_bytes < count )
+    {
+      FT_ERROR(( "FT_Stream_ReadAt:" ));
+      FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n",
+                 count, read_bytes ));
+
+      error = FT_Err_Invalid_Stream_Operation;
+    }
+
+    return error;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Stream_ExtractFrame( FT_Stream  stream,
+                          FT_ULong   count,
+                          FT_Byte**  pbytes )
+  {
+    FT_Error  error;
+
+
+    error = FT_Stream_EnterFrame( stream, count );
+    if ( !error )
+    {
+      *pbytes = (FT_Byte*)stream->cursor;
+
+      /* equivalent to FT_Stream_ExitFrame(), with no memory block release */
+      stream->cursor = 0;
+      stream->limit  = 0;
+    }
+
+    return error;
+  }
+
+
+  FT_BASE_DEF( void )
+  FT_Stream_ReleaseFrame( FT_Stream  stream,
+                          FT_Byte**  pbytes )
+  {
+    if ( stream->read )
+    {
+      FT_Memory  memory = stream->memory;
+
+
+      FT_FREE( *pbytes );
+    }
+    *pbytes = 0;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Stream_EnterFrame( FT_Stream  stream,
+                        FT_ULong   count )
+  {
+    FT_Error  error = FT_Err_Ok;
+    FT_ULong  read_bytes;
+
+
+    /* check for nested frame access */
+    FT_ASSERT( stream && stream->cursor == 0 );
+
+    if ( stream->read )
+    {
+      /* allocate the frame in memory */
+      FT_Memory  memory = stream->memory;
+
+
+      if ( FT_ALLOC( stream->base, count ) )
+        goto Exit;
+
+      /* read it */
+      read_bytes = stream->read( stream, stream->pos,
+                                 stream->base, count );
+      if ( read_bytes < count )
+      {
+        FT_ERROR(( "FT_Stream_EnterFrame:" ));
+        FT_ERROR(( " invalid read; expected %lu bytes, got %lu\n",
+                   count, read_bytes ));
+
+        FT_FREE( stream->base );
+        error = FT_Err_Invalid_Stream_Operation;
+      }
+      stream->cursor = stream->base;
+      stream->limit  = stream->cursor + count;
+      stream->pos   += read_bytes;
+    }
+    else
+    {
+      /* check current and new position */
+      if ( stream->pos >= stream->size        ||
+           stream->pos + count > stream->size )
+      {
+        FT_ERROR(( "FT_Stream_EnterFrame:" ));
+        FT_ERROR(( " invalid i/o; pos = 0x%lx, count = %lu, size = 0x%lx\n",
+                   stream->pos, count, stream->size ));
+
+        error = FT_Err_Invalid_Stream_Operation;
+        goto Exit;
+      }
+
+      /* set cursor */
+      stream->cursor = stream->base + stream->pos;
+      stream->limit  = stream->cursor + count;
+      stream->pos   += count;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  FT_BASE_DEF( void )
+  FT_Stream_ExitFrame( FT_Stream  stream )
+  {
+    /* IMPORTANT: The assertion stream->cursor != 0 was removed, given    */
+    /*            that it is possible to access a frame of length 0 in    */
+    /*            some weird fonts (usually, when accessing an array of   */
+    /*            0 records, like in some strange kern tables).           */
+    /*                                                                    */
+    /*  In this case, the loader code handles the 0-length table          */
+    /*  gracefully; however, stream.cursor is really set to 0 by the      */
+    /*  FT_Stream_EnterFrame() call, and this is not an error.            */
+    /*                                                                    */
+    FT_ASSERT( stream );
+
+    if ( stream->read )
+    {
+      FT_Memory  memory = stream->memory;
+
+
+      FT_FREE( stream->base );
+    }
+    stream->cursor = 0;
+    stream->limit  = 0;
+  }
+
+
+  FT_BASE_DEF( FT_Char )
+  FT_Stream_GetChar( FT_Stream  stream )
+  {
+    FT_Char  result;
+
+
+    FT_ASSERT( stream && stream->cursor );
+
+    result = 0;
+    if ( stream->cursor < stream->limit )
+      result = *stream->cursor++;
+
+    return result;
+  }
+
+
+  FT_BASE_DEF( FT_Short )
+  FT_Stream_GetShort( FT_Stream  stream )
+  {
+    FT_Byte*  p;
+    FT_Short  result;
+
+
+    FT_ASSERT( stream && stream->cursor );
+
+    result         = 0;
+    p              = stream->cursor;
+    if ( p + 1 < stream->limit )
+      result       = FT_NEXT_SHORT( p );
+    stream->cursor = p;
+
+    return result;
+  }
+
+
+  FT_BASE_DEF( FT_Short )
+  FT_Stream_GetShortLE( FT_Stream  stream )
+  {
+    FT_Byte*  p;
+    FT_Short  result;
+
+
+    FT_ASSERT( stream && stream->cursor );
+
+    result         = 0;
+    p              = stream->cursor;
+    if ( p + 1 < stream->limit )
+      result       = FT_NEXT_SHORT_LE( p );
+    stream->cursor = p;
+
+    return result;
+  }
+
+
+  FT_BASE_DEF( FT_Long )
+  FT_Stream_GetOffset( FT_Stream  stream )
+  {
+    FT_Byte*  p;
+    FT_Long   result;
+
+
+    FT_ASSERT( stream && stream->cursor );
+
+    result         = 0;
+    p              = stream->cursor;
+    if ( p + 2 < stream->limit )
+      result       = FT_NEXT_OFF3( p );
+    stream->cursor = p;
+    return result;
+  }
+
+
+  FT_BASE_DEF( FT_Long )
+  FT_Stream_GetLong( FT_Stream  stream )
+  {
+    FT_Byte*  p;
+    FT_Long   result;
+
+
+    FT_ASSERT( stream && stream->cursor );
+
+    result         = 0;
+    p              = stream->cursor;
+    if ( p + 3 < stream->limit )
+      result       = FT_NEXT_LONG( p );
+    stream->cursor = p;
+    return result;
+  }
+
+
+  FT_BASE_DEF( FT_Long )
+  FT_Stream_GetLongLE( FT_Stream  stream )
+  {
+    FT_Byte*  p;
+    FT_Long   result;
+
+
+    FT_ASSERT( stream && stream->cursor );
+
+    result         = 0;
+    p              = stream->cursor;
+    if ( p + 3 < stream->limit )
+      result       = FT_NEXT_LONG_LE( p );
+    stream->cursor = p;
+    return result;
+  }
+
+
+  FT_BASE_DEF( FT_Char )
+  FT_Stream_ReadChar( FT_Stream  stream,
+                      FT_Error*  error )
+  {
+    FT_Byte  result = 0;
+
+
+    FT_ASSERT( stream );
+
+    *error = FT_Err_Ok;
+
+    if ( stream->read )
+    {
+      if ( stream->read( stream, stream->pos, &result, 1L ) != 1L )
+        goto Fail;
+    }
+    else
+    {
+      if ( stream->pos < stream->size )
+        result = stream->base[stream->pos];
+      else
+        goto Fail;
+    }
+    stream->pos++;
+
+    return result;
+
+  Fail:
+    *error = FT_Err_Invalid_Stream_Operation;
+    FT_ERROR(( "FT_Stream_ReadChar: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+               stream->pos, stream->size ));
+
+    return 0;
+  }
+
+
+  FT_BASE_DEF( FT_Short )
+  FT_Stream_ReadShort( FT_Stream  stream,
+                       FT_Error*  error )
+  {
+    FT_Byte   reads[2];
+    FT_Byte*  p = 0;
+    FT_Short  result = 0;
+
+
+    FT_ASSERT( stream );
+
+    *error = FT_Err_Ok;
+
+    if ( stream->pos + 1 < stream->size )
+    {
+      if ( stream->read )
+      {
+        if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+          goto Fail;
+
+        p = reads;
+      }
+      else
+      {
+        p = stream->base + stream->pos;
+      }
+
+      if ( p )
+        result = FT_NEXT_SHORT( p );
+    }
+    else
+      goto Fail;
+
+    stream->pos += 2;
+
+    return result;
+
+  Fail:
+    *error = FT_Err_Invalid_Stream_Operation;
+    FT_ERROR(( "FT_Stream_ReadShort:" ));
+    FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+               stream->pos, stream->size ));
+
+    return 0;
+  }
+
+
+  FT_BASE_DEF( FT_Short )
+  FT_Stream_ReadShortLE( FT_Stream  stream,
+                         FT_Error*  error )
+  {
+    FT_Byte   reads[2];
+    FT_Byte*  p = 0;
+    FT_Short  result = 0;
+
+
+    FT_ASSERT( stream );
+
+    *error = FT_Err_Ok;
+
+    if ( stream->pos + 1 < stream->size )
+    {
+      if ( stream->read )
+      {
+        if ( stream->read( stream, stream->pos, reads, 2L ) != 2L )
+          goto Fail;
+
+        p = reads;
+      }
+      else
+      {
+        p = stream->base + stream->pos;
+      }
+
+      if ( p )
+        result = FT_NEXT_SHORT_LE( p );
+    }
+    else
+      goto Fail;
+
+    stream->pos += 2;
+
+    return result;
+
+  Fail:
+    *error = FT_Err_Invalid_Stream_Operation;
+    FT_ERROR(( "FT_Stream_ReadShortLE:" ));
+    FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+               stream->pos, stream->size ));
+
+    return 0;
+  }
+
+
+  FT_BASE_DEF( FT_Long )
+  FT_Stream_ReadOffset( FT_Stream  stream,
+                        FT_Error*  error )
+  {
+    FT_Byte   reads[3];
+    FT_Byte*  p = 0;
+    FT_Long   result = 0;
+
+
+    FT_ASSERT( stream );
+
+    *error = FT_Err_Ok;
+
+    if ( stream->pos + 2 < stream->size )
+    {
+      if ( stream->read )
+      {
+        if (stream->read( stream, stream->pos, reads, 3L ) != 3L )
+          goto Fail;
+
+        p = reads;
+      }
+      else
+      {
+        p = stream->base + stream->pos;
+      }
+
+      if ( p )
+        result = FT_NEXT_OFF3( p );
+    }
+    else
+      goto Fail;
+
+    stream->pos += 3;
+
+    return result;
+
+  Fail:
+    *error = FT_Err_Invalid_Stream_Operation;
+    FT_ERROR(( "FT_Stream_ReadOffset:" ));
+    FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+               stream->pos, stream->size ));
+
+    return 0;
+  }
+
+
+  FT_BASE_DEF( FT_Long )
+  FT_Stream_ReadLong( FT_Stream  stream,
+                      FT_Error*  error )
+  {
+    FT_Byte   reads[4];
+    FT_Byte*  p = 0;
+    FT_Long   result = 0;
+
+
+    FT_ASSERT( stream );
+
+    *error = FT_Err_Ok;
+
+    if ( stream->pos + 3 < stream->size )
+    {
+      if ( stream->read )
+      {
+        if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+          goto Fail;
+
+        p = reads;
+      }
+      else
+      {
+        p = stream->base + stream->pos;
+      }
+
+      if ( p )
+        result = FT_NEXT_LONG( p );
+    }
+    else
+      goto Fail;
+
+    stream->pos += 4;
+
+    return result;
+
+  Fail:
+    FT_ERROR(( "FT_Stream_ReadLong: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+               stream->pos, stream->size ));
+    *error = FT_Err_Invalid_Stream_Operation;
+
+    return 0;
+  }
+
+
+  FT_BASE_DEF( FT_Long )
+  FT_Stream_ReadLongLE( FT_Stream  stream,
+                        FT_Error*  error )
+  {
+    FT_Byte   reads[4];
+    FT_Byte*  p = 0;
+    FT_Long   result = 0;
+
+
+    FT_ASSERT( stream );
+
+    *error = FT_Err_Ok;
+
+    if ( stream->pos + 3 < stream->size )
+    {
+      if ( stream->read )
+      {
+        if ( stream->read( stream, stream->pos, reads, 4L ) != 4L )
+          goto Fail;
+
+        p = reads;
+      }
+      else
+      {
+        p = stream->base + stream->pos;
+      }
+
+      if ( p )
+        result = FT_NEXT_LONG_LE( p );
+    }
+    else
+      goto Fail;
+
+    stream->pos += 4;
+
+    return result;
+
+  Fail:
+    FT_ERROR(( "FT_Stream_ReadLongLE:" ));
+    FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+               stream->pos, stream->size ));
+    *error = FT_Err_Invalid_Stream_Operation;
+
+    return 0;
+  }
+
+
+  FT_BASE_DEF( FT_Error )
+  FT_Stream_ReadFields( FT_Stream              stream,
+                        const FT_Frame_Field*  fields,
+                        void*                  structure )
+  {
+    FT_Error  error;
+    FT_Bool   frame_accessed = 0;
+    FT_Byte*  cursor = stream->cursor;
+
+
+    if ( !fields || !stream )
+      return FT_Err_Invalid_Argument;
+
+    error = FT_Err_Ok;
+    do
+    {
+      FT_ULong  value;
+      FT_Int    sign_shift;
+      FT_Byte*  p;
+
+
+      switch ( fields->value )
+      {
+      case ft_frame_start:  /* access a new frame */
+        error = FT_Stream_EnterFrame( stream, fields->offset );
+        if ( error )
+          goto Exit;
+
+        frame_accessed = 1;
+        cursor         = stream->cursor;
+        fields++;
+        continue;  /* loop! */
+
+      case ft_frame_bytes:  /* read a byte sequence */
+      case ft_frame_skip:   /* skip some bytes      */
+        {
+          FT_UInt  len = fields->size;
+
+
+          if ( cursor + len > stream->limit )
+          {
+            error = FT_Err_Invalid_Stream_Operation;
+            goto Exit;
+          }
+
+          if ( fields->value == ft_frame_bytes )
+          {
+            p = (FT_Byte*)structure + fields->offset;
+            FT_MEM_COPY( p, cursor, len );
+          }
+          cursor += len;
+          fields++;
+          continue;
+        }
+
+      case ft_frame_byte:
+      case ft_frame_schar:  /* read a single byte */
+        value = FT_NEXT_BYTE(cursor);
+        sign_shift = 24;
+        break;
+
+      case ft_frame_short_be:
+      case ft_frame_ushort_be:  /* read a 2-byte big-endian short */
+        value = FT_NEXT_USHORT(cursor);
+        sign_shift = 16;
+        break;
+
+      case ft_frame_short_le:
+      case ft_frame_ushort_le:  /* read a 2-byte little-endian short */
+        value = FT_NEXT_USHORT_LE(cursor);
+        sign_shift = 16;
+        break;
+
+      case ft_frame_long_be:
+      case ft_frame_ulong_be:  /* read a 4-byte big-endian long */
+        value = FT_NEXT_ULONG(cursor);
+        sign_shift = 0;
+        break;
+
+      case ft_frame_long_le:
+      case ft_frame_ulong_le:  /* read a 4-byte little-endian long */
+        value = FT_NEXT_ULONG_LE(cursor);
+        sign_shift = 0;
+        break;
+
+      case ft_frame_off3_be:
+      case ft_frame_uoff3_be:  /* read a 3-byte big-endian long */
+        value = FT_NEXT_UOFF3(cursor);
+        sign_shift = 8;
+        break;
+
+      case ft_frame_off3_le:
+      case ft_frame_uoff3_le:  /* read a 3-byte little-endian long */
+        value = FT_NEXT_UOFF3_LE(cursor);
+        sign_shift = 8;
+        break;
+
+      default:
+        /* otherwise, exit the loop */
+        stream->cursor = cursor;
+        goto Exit;
+      }
+
+      /* now, compute the signed value is necessary */
+      if ( fields->value & FT_FRAME_OP_SIGNED )
+        value = (FT_ULong)( (FT_Int32)( value << sign_shift ) >> sign_shift );
+
+      /* finally, store the value in the object */
+
+      p = (FT_Byte*)structure + fields->offset;
+      switch ( fields->size )
+      {
+      case 1:
+        *(FT_Byte*)p = (FT_Byte)value;
+        break;
+
+      case 2:
+        *(FT_UShort*)p = (FT_UShort)value;
+        break;
+
+      case 4:
+        *(FT_UInt32*)p = (FT_UInt32)value;
+        break;
+
+      default:  /* for 64-bit systems */
+        *(FT_ULong*)p = (FT_ULong)value;
+      }
+
+      /* go to next field */
+      fields++;
+    }
+    while ( 1 );
+
+  Exit:
+    /* close the frame if it was opened by this read */
+    if ( frame_accessed )
+      FT_Stream_ExitFrame( stream );
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftstroker.c
@@ -1,0 +1,1364 @@
+#include <ft2build.h>
+#include FT_STROKER_H
+#include FT_TRIGONOMETRY_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_DEBUG_H
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****                       BEZIER COMPUTATIONS                       *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+#define FT_SMALL_CONIC_THRESHOLD   (FT_ANGLE_PI/6)
+#define FT_SMALL_CUBIC_THRESHOLD   (FT_ANGLE_PI/6)
+#define FT_EPSILON  2
+
+#define FT_IS_SMALL(x)  ((x) > -FT_EPSILON && (x) < FT_EPSILON)
+
+  static FT_Pos
+  ft_pos_abs( FT_Pos  x )
+  {
+    return  x >= 0 ? x : -x ;
+  }
+
+  static void
+  ft_conic_split( FT_Vector*  base )
+  {
+    FT_Pos  a, b;
+
+
+    base[4].x = base[2].x;
+    b = base[1].x;
+    a = base[3].x = ( base[2].x + b )/2;
+    b = base[1].x = ( base[0].x + b )/2;
+    base[2].x = ( a + b )/2;
+
+    base[4].y = base[2].y;
+    b = base[1].y;
+    a = base[3].y = ( base[2].y + b )/2;
+    b = base[1].y = ( base[0].y + b )/2;
+    base[2].y = ( a + b )/2;
+  }
+
+
+  static FT_Bool
+  ft_conic_is_small_enough( FT_Vector*  base,
+                            FT_Angle   *angle_in,
+                            FT_Angle   *angle_out )
+  {
+    FT_Vector  d1, d2;
+    FT_Angle   theta;
+    FT_Int     close1, close2;
+
+    d1.x = base[1].x - base[2].x;
+    d1.y = base[1].y - base[2].y;
+    d2.x = base[0].x - base[1].x;
+    d2.y = base[0].y - base[1].y;
+
+    close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);
+    close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);
+
+    if (close1)
+    {
+      if (close2)
+        *angle_in = *angle_out = 0;
+      else
+        *angle_in = *angle_out = FT_Atan2( d2.x, d2.y );
+    }
+    else if (close2)
+    {
+      *angle_in = *angle_out = FT_Atan2( d1.x, d1.y );
+    }
+    else
+    {
+      *angle_in  = FT_Atan2( d1.x, d1.y );
+      *angle_out = FT_Atan2( d2.x, d2.y );
+    }
+
+    theta = ft_pos_abs( FT_Angle_Diff( *angle_in, *angle_out ) );
+
+    return FT_BOOL( theta < FT_SMALL_CONIC_THRESHOLD );
+  }
+
+
+  static void
+  ft_cubic_split( FT_Vector*  base )
+  {
+    FT_Pos  a, b, c, d;
+
+
+    base[6].x = base[3].x;
+    c = base[1].x;
+    d = base[2].x;
+    base[1].x = a = ( base[0].x + c )/2;
+    base[5].x = b = ( base[3].x + d )/2;
+    c = ( c + d )/2;
+    base[2].x = a = ( a + c )/2;
+    base[4].x = b = ( b + c )/2;
+    base[3].x = ( a + b )/2;
+
+    base[6].y = base[3].y;
+    c = base[1].y;
+    d = base[2].y;
+    base[1].y = a = ( base[0].y + c )/2;
+    base[5].y = b = ( base[3].y + d )/2;
+    c = ( c + d )/2;
+    base[2].y = a = ( a + c )/2;
+    base[4].y = b = ( b + c )/2;
+    base[3].y = ( a + b )/2;
+  }
+
+
+  static FT_Bool
+  ft_cubic_is_small_enough( FT_Vector*  base,
+                            FT_Angle   *angle_in,
+                            FT_Angle   *angle_mid,
+                            FT_Angle   *angle_out )
+  {
+    FT_Vector  d1, d2, d3;
+    FT_Angle   theta1, theta2;
+    FT_Int     close1, close2, close3;
+
+    d1.x = base[2].x - base[3].x;
+    d1.y = base[2].y - base[3].y;
+    d2.x = base[1].x - base[2].x;
+    d2.y = base[1].y - base[2].y;
+    d3.x = base[0].x - base[1].x;
+    d3.y = base[0].y - base[1].y;
+
+    close1 = FT_IS_SMALL(d1.x) && FT_IS_SMALL(d1.y);
+    close2 = FT_IS_SMALL(d2.x) && FT_IS_SMALL(d2.y);
+    close3 = FT_IS_SMALL(d3.x) && FT_IS_SMALL(d3.y);
+
+    if (close1 || close3)
+    {
+      if (close2)
+      {
+        /* basically a point */
+        *angle_in = *angle_out = *angle_mid = 0;
+      }
+      else if (close1)
+      {
+        *angle_in  = *angle_mid = FT_Atan2( d2.x, d2.y );
+        *angle_out = FT_Atan2( d3.x, d3.y );
+      }
+      else  /* close2 */
+      {
+        *angle_in  = FT_Atan2( d1.x, d1.y );
+        *angle_mid = *angle_out = FT_Atan2( d2.x, d2.y );
+      }
+    }
+    else if (close2)
+    {
+      *angle_in  = *angle_mid = FT_Atan2( d1.x, d1.y );
+      *angle_out = FT_Atan2( d3.x, d3.y );
+    }
+    else
+    {
+      *angle_in  = FT_Atan2( d1.x, d1.y );
+      *angle_mid = FT_Atan2( d2.x, d2.y );
+      *angle_out = FT_Atan2( d3.x, d3.y );
+    }
+    theta1 = ft_pos_abs( FT_Angle_Diff( *angle_in,  *angle_mid ) );
+    theta2 = ft_pos_abs( FT_Angle_Diff( *angle_mid, *angle_out ) );
+
+    return FT_BOOL( theta1 < FT_SMALL_CUBIC_THRESHOLD &&
+                    theta2 < FT_SMALL_CUBIC_THRESHOLD );
+  }
+
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****                       STROKE BORDERS                            *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  typedef enum
+  {
+    FT_STROKE_TAG_ON    = 1,   /* on-curve point  */
+    FT_STROKE_TAG_CUBIC = 2,   /* cubic off-point */
+    FT_STROKE_TAG_BEGIN = 4,   /* sub-path start  */
+    FT_STROKE_TAG_END   = 8    /* sub-path end    */
+
+  } FT_StrokeTags;
+
+
+  typedef struct FT_StrokeBorderRec_
+  {
+    FT_UInt     num_points;
+    FT_UInt     max_points;
+    FT_Vector*  points;
+    FT_Byte*    tags;
+    FT_Bool     movable;
+    FT_Int      start;    /* index of current sub-path start point */
+    FT_Memory   memory;
+
+  } FT_StrokeBorderRec, *FT_StrokeBorder;
+
+
+  static FT_Error
+  ft_stroke_border_grow( FT_StrokeBorder  border,
+                         FT_UInt          new_points )
+  {
+    FT_UInt   old_max = border->max_points;
+    FT_UInt   new_max = border->num_points + new_points;
+    FT_Error  error   = 0;
+
+    if ( new_max > old_max )
+    {
+      FT_UInt    cur_max = old_max;
+      FT_Memory  memory  = border->memory;
+
+      while ( cur_max < new_max )
+        cur_max += (cur_max >> 1) + 16;
+
+      if ( FT_RENEW_ARRAY( border->points, old_max, cur_max ) ||
+           FT_RENEW_ARRAY( border->tags,   old_max, cur_max ) )
+        goto Exit;
+
+      border->max_points = cur_max;
+    }
+  Exit:
+    return error;
+  }
+
+  static void
+  ft_stroke_border_close( FT_StrokeBorder  border )
+  {
+    FT_ASSERT( border->start >= 0 );
+
+    border->tags[ border->start        ] |= FT_STROKE_TAG_BEGIN;
+    border->tags[ border->num_points-1 ] |= FT_STROKE_TAG_END;
+
+    border->start   = -1;
+    border->movable = 0;
+  }
+
+
+  static FT_Error
+  ft_stroke_border_lineto( FT_StrokeBorder  border,
+                           FT_Vector*       to,
+                           FT_Bool          movable )
+  {
+    FT_Error  error = 0;
+
+    FT_ASSERT( border->start >= 0 );
+
+    if ( border->movable )
+    {
+      /* move last point */
+      border->points[ border->num_points-1 ] = *to;
+    }
+    else
+    {
+      /* add one point */
+      error = ft_stroke_border_grow( border, 1 );
+      if (!error)
+      {
+        FT_Vector*  vec = border->points + border->num_points;
+        FT_Byte*    tag = border->tags   + border->num_points;
+
+        vec[0] = *to;
+        tag[0] = FT_STROKE_TAG_ON;
+
+        border->num_points += 1;
+      }
+    }
+    border->movable = movable;
+    return error;
+  }
+
+
+  static FT_Error
+  ft_stroke_border_conicto( FT_StrokeBorder  border,
+                            FT_Vector*       control,
+                            FT_Vector*       to )
+  {
+    FT_Error  error;
+
+    FT_ASSERT( border->start >= 0 );
+
+    error = ft_stroke_border_grow( border, 2 );
+    if (!error)
+    {
+      FT_Vector*  vec = border->points + border->num_points;
+      FT_Byte*    tag = border->tags   + border->num_points;
+
+      vec[0] = *control;
+      vec[1] = *to;
+
+      tag[0] = 0;
+      tag[1] = FT_STROKE_TAG_ON;
+
+      border->num_points += 2;
+    }
+    border->movable = 0;
+    return error;
+  }
+
+
+  static FT_Error
+  ft_stroke_border_cubicto( FT_StrokeBorder  border,
+                            FT_Vector*       control1,
+                            FT_Vector*       control2,
+                            FT_Vector*       to )
+  {
+    FT_Error  error;
+
+    FT_ASSERT( border->start >= 0 );
+
+    error = ft_stroke_border_grow( border, 3 );
+    if (!error)
+    {
+      FT_Vector*  vec = border->points + border->num_points;
+      FT_Byte*    tag = border->tags   + border->num_points;
+
+      vec[0] = *control1;
+      vec[1] = *control2;
+      vec[2] = *to;
+
+      tag[0] = FT_STROKE_TAG_CUBIC;
+      tag[1] = FT_STROKE_TAG_CUBIC;
+      tag[2] = FT_STROKE_TAG_ON;
+
+      border->num_points += 3;
+    }
+    border->movable = 0;
+    return error;
+  }
+
+
+#define  FT_ARC_CUBIC_ANGLE  (FT_ANGLE_PI/2)
+
+
+  static FT_Error
+  ft_stroke_border_arcto( FT_StrokeBorder  border,
+                          FT_Vector*       center,
+                          FT_Fixed         radius,
+                          FT_Angle         angle_start,
+                          FT_Angle         angle_diff )
+  {
+    FT_Angle   total, angle, step, rotate, next, theta;
+    FT_Vector  a, b, a2, b2;
+    FT_Fixed   length;
+    FT_Error   error = 0;
+
+    /* compute start point */
+    FT_Vector_From_Polar( &a, radius, angle_start );
+    a.x += center->x;
+    a.y += center->y;
+
+    total  = angle_diff;
+    angle  = angle_start;
+    rotate = ( angle_diff >= 0 ) ? FT_ANGLE_PI2 : -FT_ANGLE_PI2;
+
+    while (total != 0)
+    {
+      step = total;
+      if ( step > FT_ARC_CUBIC_ANGLE )
+        step   = FT_ARC_CUBIC_ANGLE;
+
+      else if ( step < -FT_ARC_CUBIC_ANGLE )
+        step = -FT_ARC_CUBIC_ANGLE;
+
+      next  = angle + step;
+      theta = step;
+      if ( theta < 0 )
+        theta = -theta;
+
+      theta >>= 1;
+
+      /* compute end point */
+      FT_Vector_From_Polar( &b, radius, next );
+      b.x += center->x;
+      b.y += center->y;
+
+      /* compute first and second control points */
+      length = FT_MulDiv( radius, FT_Sin(theta)*4,
+                          (0x10000L + FT_Cos(theta))*3 );
+
+      FT_Vector_From_Polar( &a2, length, angle + rotate );
+      a2.x += a.x;
+      a2.y += a.y;
+
+      FT_Vector_From_Polar( &b2, length, next - rotate );
+      b2.x += b.x;
+      b2.y += b.y;
+
+      /* add cubic arc */
+      error = ft_stroke_border_cubicto( border, &a2, &b2, &b );
+      if (error) break;
+
+      /* process the rest of the arc ?? */
+      a      = b;
+      total -= step;
+      angle  = next;
+    }
+    return error;
+  }
+
+
+  static FT_Error
+  ft_stroke_border_moveto( FT_StrokeBorder  border,
+                           FT_Vector*       to )
+  {
+    /* close current open path if any ? */
+    if ( border->start >= 0 )
+      ft_stroke_border_close( border );
+
+    border->start   = border->num_points;
+    border->movable = 0;
+
+    return ft_stroke_border_lineto( border, to, 0 );
+  }
+
+
+ static void
+ ft_stroke_border_init( FT_StrokeBorder  border,
+                        FT_Memory        memory )
+ {
+   border->memory = memory;
+   border->points = NULL;
+   border->tags   = NULL;
+
+   border->num_points = 0;
+   border->max_points = 0;
+   border->start      = -1;
+ }
+
+
+ static void
+ ft_stroke_border_reset( FT_StrokeBorder  border )
+ {
+   border->num_points = 0;
+   border->start      = -1;
+ }
+
+
+ static void
+ ft_stroke_border_done( FT_StrokeBorder  border )
+ {
+   FT_Memory  memory = border->memory;
+
+   FT_FREE( border->points );
+   FT_FREE( border->tags );
+
+   border->num_points = 0;
+   border->max_points = 0;
+   border->start      = -1;
+ }
+
+
+ static FT_Error
+ ft_stroke_border_get_counts( FT_StrokeBorder  border,
+                              FT_UInt         *anum_points,
+                              FT_UInt         *anum_contours )
+ {
+   FT_Error  error        = 0;
+   FT_UInt   num_points   = 0;
+   FT_UInt   num_contours = 0;
+
+   FT_UInt     count      = border->num_points;
+   FT_Vector*  point      = border->points;
+   FT_Byte*    tags       = border->tags;
+   FT_Int      in_contour = 0;
+
+   for ( ; count > 0; count--, point++, tags++ )
+   {
+     if ( tags[0] & FT_STROKE_TAG_BEGIN )
+     {
+       if ( in_contour != 0 )
+         goto Fail;
+
+       in_contour = 1;
+     }
+     else if ( in_contour == 0 )
+       goto Fail;
+
+     if ( tags[0] & FT_STROKE_TAG_END )
+     {
+       if ( in_contour == 0 )
+         goto Fail;
+
+       in_contour = 0;
+       num_contours++;
+     }
+   }
+   if ( in_contour != 0 )
+     goto Fail;
+
+ Exit:
+   *anum_points   = num_points;
+   *anum_contours = num_contours;
+   return error;
+
+ Fail:
+   num_points   = 0;
+   num_contours = 0;
+   goto Exit;
+ }
+
+
+ static void
+ ft_stroke_border_export( FT_StrokeBorder  border,
+                          FT_Outline*      outline )
+ {
+   /* copy point locations */
+   FT_MEM_COPY( outline->points + outline->n_points,
+                border->points,
+                border->num_points * sizeof(FT_Vector) );
+
+   /* copy tags */
+   {
+     FT_UInt   count = border->num_points;
+     FT_Byte*  read  = border->tags;
+     FT_Byte*  write = (FT_Byte*) outline->tags + outline->n_points;
+
+     for ( ; count > 0; count--, read++, write++ )
+     {
+       if ( *read & FT_STROKE_TAG_ON )
+         *write = FT_CURVE_TAG_ON;
+       else if ( *read & FT_STROKE_TAG_CUBIC )
+         *write = FT_CURVE_TAG_CUBIC;
+       else
+         *write = FT_CURVE_TAG_CONIC;
+     }
+   }
+
+   /* copy contours */
+   {
+     FT_UInt    count = border->num_points;
+     FT_Byte*   tags  = border->tags;
+     FT_Short*  write = outline->contours + outline->n_contours;
+     FT_Short   index = (FT_Short) outline->n_points;
+
+     for ( ; count > 0; count--, tags++, write++, index++ )
+     {
+       if ( *tags & FT_STROKE_TAG_END )
+       {
+         *write++ = index;
+         outline->n_contours++;
+       }
+     }
+   }
+
+   outline->n_points  = (short)( outline->n_points + border->num_points );
+
+   FT_ASSERT( FT_Outline_Check( outline ) == 0 );
+ }
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****                           STROKER                               *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+#define  FT_SIDE_TO_ROTATE(s)   (FT_ANGLE_PI2 - (s)*FT_ANGLE_PI)
+
+  typedef struct FT_StrokerRec_
+  {
+    FT_Angle             angle_in;
+    FT_Angle             angle_out;
+    FT_Vector            center;
+    FT_Bool              first_point;
+    FT_Bool              subpath_open;
+    FT_Angle             subpath_angle;
+    FT_Vector            subpath_start;
+
+    FT_Stroker_LineCap   line_cap;
+    FT_Stroker_LineJoin  line_join;
+    FT_Fixed             miter_limit;
+    FT_Fixed             radius;
+
+    FT_Bool              valid;
+    FT_StrokeBorderRec   borders[2];
+    FT_Memory            memory;
+
+  } FT_StrokerRec;
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_New( FT_Memory    memory,
+                  FT_Stroker  *astroker )
+  {
+    FT_Error    error;
+    FT_Stroker  stroker;
+
+    if ( !FT_NEW( stroker ) )
+    {
+      stroker->memory = memory;
+
+      ft_stroke_border_init( &stroker->borders[0], memory );
+      ft_stroke_border_init( &stroker->borders[1], memory );
+    }
+    *astroker = stroker;
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_Stroker_Set( FT_Stroker           stroker,
+                  FT_Fixed             radius,
+                  FT_Stroker_LineCap   line_cap,
+                  FT_Stroker_LineJoin  line_join,
+                  FT_Fixed             miter_limit )
+  {
+    stroker->radius      = radius;
+    stroker->line_cap    = line_cap;
+    stroker->line_join   = line_join;
+    stroker->miter_limit = miter_limit;
+
+    stroker->valid = 0;
+
+    ft_stroke_border_reset( &stroker->borders[0] );
+    ft_stroke_border_reset( &stroker->borders[1] );
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_Stroker_Done( FT_Stroker  stroker )
+  {
+    if ( stroker )
+    {
+      FT_Memory  memory = stroker->memory;
+
+      ft_stroke_border_done( &stroker->borders[0] );
+      ft_stroke_border_done( &stroker->borders[1] );
+
+      stroker->memory = NULL;
+      FT_FREE( stroker );
+    }
+  }
+
+
+
+ /* creates a circular arc at a corner or cap */
+  static FT_Error
+  ft_stroker_arcto( FT_Stroker  stroker,
+                    FT_Int      side )
+  {
+    FT_Angle          total, rotate;
+    FT_Fixed          radius = stroker->radius;
+    FT_Error          error  = 0;
+    FT_StrokeBorder   border = stroker->borders + side;
+
+    rotate = FT_SIDE_TO_ROTATE(side);
+
+    total = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+    if (total == FT_ANGLE_PI)
+      total = -rotate*2;
+
+    error = ft_stroke_border_arcto( border,
+                                    &stroker->center,
+                                    radius,
+                                    stroker->angle_in + rotate,
+                                    total );
+    border->movable = 0;
+    return error;
+  }
+
+
+  /* adds a cap at the end of an opened path */
+  static FT_Error
+  ft_stroker_cap( FT_Stroker  stroker,
+                  FT_Angle    angle,
+                  FT_Int      side )
+  {
+    FT_Error  error  = 0;
+
+    if ( stroker->line_cap == FT_STROKER_LINECAP_ROUND )
+    {
+      /* add a round cap */
+      stroker->angle_in  = angle;
+      stroker->angle_out = angle + FT_ANGLE_PI;
+      error = ft_stroker_arcto( stroker, side );
+    }
+    else if ( stroker->line_cap == FT_STROKER_LINECAP_SQUARE )
+    {
+      /* add a square cap */
+      FT_Vector         delta, delta2;
+      FT_Angle          rotate = FT_SIDE_TO_ROTATE(side);
+      FT_Fixed          radius = stroker->radius;
+      FT_StrokeBorder   border = stroker->borders + side;
+
+      FT_Vector_From_Polar( &delta2, radius, angle+rotate );
+      FT_Vector_From_Polar( &delta,  radius, angle );
+
+      delta.x += stroker->center.x + delta2.x;
+      delta.y += stroker->center.y + delta2.y;
+
+      error = ft_stroke_border_lineto( border, &delta, 0 );
+      if (error) goto Exit;
+
+      FT_Vector_From_Polar( &delta2, radius, angle-rotate );
+      FT_Vector_From_Polar( &delta,  radius, angle );
+
+      delta.x += delta2.x + stroker->center.x;
+      delta.y += delta2.y + stroker->center.y;
+
+      error = ft_stroke_border_lineto( border, &delta, 0 );
+    }
+  Exit:
+    return error;
+  }
+
+
+
+ /* process an inside corner, i.e. compute intersection */
+  static FT_Error
+  ft_stroker_inside( FT_Stroker  stroker,
+                     FT_Int      side)
+  {
+    FT_StrokeBorder  border = stroker->borders + side;
+    FT_Angle         phi, theta, rotate;
+    FT_Fixed         length, thcos, sigma;
+    FT_Vector        delta;
+    FT_Error         error = 0;
+
+
+    rotate = FT_SIDE_TO_ROTATE(side);
+
+    /* compute median angle */
+    theta = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+    if ( theta == FT_ANGLE_PI )
+      theta = rotate;
+    else
+      theta = theta/2;
+
+    phi = stroker->angle_in + theta;
+
+    thcos  = FT_Cos( theta );
+    sigma  = FT_MulFix( stroker->miter_limit, thcos );
+
+    if ( sigma < 0x10000L )
+    {
+      FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate );
+      delta.x += stroker->center.x;
+      delta.y += stroker->center.y;
+      border->movable = 0;
+    }
+    else
+    {
+      length = FT_DivFix( stroker->radius, thcos );
+
+      FT_Vector_From_Polar( &delta, length, phi + rotate );
+      delta.x += stroker->center.x;
+      delta.y += stroker->center.y;
+    }
+
+    error = ft_stroke_border_lineto( border, &delta, 0 );
+
+    return error;
+  }
+
+
+ /* process an outside corner, i.e. compute bevel/miter/round */
+  static FT_Error
+  ft_stroker_outside( FT_Stroker  stroker,
+                      FT_Int      side )
+  {
+    FT_StrokeBorder  border = stroker->borders + side;
+    FT_Error         error;
+    FT_Angle         rotate;
+
+    if ( stroker->line_join == FT_STROKER_LINEJOIN_ROUND )
+    {
+      error = ft_stroker_arcto( stroker, side );
+    }
+    else
+    {
+      /* this is a mitered or beveled corner */
+      FT_Fixed   sigma, radius = stroker->radius;
+      FT_Angle   theta, phi;
+      FT_Fixed   thcos;
+      FT_Bool    miter;
+
+      rotate = FT_SIDE_TO_ROTATE(side);
+      miter  = FT_BOOL( stroker->line_join == FT_STROKER_LINEJOIN_MITER );
+
+      theta  = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+      if (theta == FT_ANGLE_PI)
+        theta = rotate;
+      else
+        theta = theta/2;
+
+      thcos  = FT_Cos( theta );
+      sigma  = FT_MulFix( stroker->miter_limit, thcos );
+
+      if ( sigma >= 0x10000L )
+        miter = 0;
+
+      phi = stroker->angle_in + theta + rotate;
+
+      if (miter)  /* this is a miter (broken angle) */
+      {
+        FT_Vector  middle, delta;
+        FT_Fixed  length;
+
+        /* compute middle point */
+        FT_Vector_From_Polar( &middle, FT_MulFix( radius, stroker->miter_limit ),
+                              phi );
+        middle.x += stroker->center.x;
+        middle.y += stroker->center.y;
+
+        /* compute first angle point */
+        length = FT_MulFix( radius, FT_DivFix( 0x10000L - sigma,
+                                    ft_pos_abs( FT_Sin( theta ) ) ) );
+
+        FT_Vector_From_Polar( &delta, length, phi + rotate );
+        delta.x += middle.x;
+        delta.y += middle.y;
+
+        error = ft_stroke_border_lineto( border, &delta, 0 );
+        if (error) goto Exit;
+
+        /* compute second angle point */
+        FT_Vector_From_Polar( &delta, length, phi - rotate );
+        delta.x += middle.x;
+        delta.y += middle.y;
+
+        error = ft_stroke_border_lineto( border, &delta, 0 );
+        if (error) goto Exit;
+
+        /* finally, add a movable end point */
+        FT_Vector_From_Polar( &delta, radius, stroker->angle_out + rotate );
+        delta.x += stroker->center.x;
+        delta.y += stroker->center.y;
+
+        error = ft_stroke_border_lineto( border, &delta, 1 );
+      }
+      else /* this is a bevel (intersection) */
+      {
+        FT_Fixed  length;
+        FT_Vector  delta;
+
+        length = FT_DivFix( stroker->radius, thcos );
+
+        FT_Vector_From_Polar( &delta, length, phi );
+        delta.x += stroker->center.x;
+        delta.y += stroker->center.y;
+
+        error = ft_stroke_border_lineto( border, &delta, 0 );
+        if (error) goto Exit;
+
+        /* now add end point */
+        FT_Vector_From_Polar( &delta, stroker->radius, stroker->angle_out + rotate );
+        delta.x += stroker->center.x;
+        delta.y += stroker->center.y;
+
+        error = ft_stroke_border_lineto( border, &delta, 1 );
+      }
+    }
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  ft_stroker_process_corner( FT_Stroker  stroker )
+  {
+    FT_Error  error = 0;
+    FT_Angle  turn;
+    FT_Int    inside_side;
+
+    turn = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+
+    /* no specific corner processing is required if the turn is 0 */
+    if (turn == 0)
+      goto Exit;
+
+    /* when we turn to the right, the inside side is 0 */
+    inside_side = 0;
+
+    /* otherwise, the inside side is 1 */
+    if (turn < 0)
+      inside_side = 1;
+
+    /* process the inside side */
+    error = ft_stroker_inside( stroker, inside_side );
+    if (error) goto Exit;
+
+    /* process the outside side */
+    error = ft_stroker_outside( stroker, 1-inside_side );
+
+  Exit:
+    return error;
+  }
+
+
+ /* add two points to the left and right borders corresponding to the */
+ /* start of the subpath..                                            */
+  static FT_Error
+  ft_stroker_subpath_start( FT_Stroker  stroker,
+                            FT_Angle    start_angle )
+  {
+    FT_Vector        delta;
+    FT_Vector        point;
+    FT_Error         error;
+    FT_StrokeBorder  border;
+
+    FT_Vector_From_Polar( &delta, stroker->radius, start_angle + FT_ANGLE_PI2 );
+
+    point.x = stroker->center.x + delta.x;
+    point.y = stroker->center.y + delta.y;
+
+    border = stroker->borders;
+    error = ft_stroke_border_moveto( border, &point );
+    if (error) goto Exit;
+
+    point.x = stroker->center.x - delta.x;
+    point.y = stroker->center.y - delta.y;
+
+    border++;
+    error = ft_stroke_border_moveto( border, &point );
+
+    /* save angle for last cap */
+    stroker->subpath_angle = start_angle;
+    stroker->first_point   = 0;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_LineTo( FT_Stroker  stroker,
+                     FT_Vector*  to )
+  {
+    FT_Error         error = 0;
+    FT_StrokeBorder  border;
+    FT_Vector        delta;
+    FT_Angle         angle;
+    FT_Int           side;
+
+    delta.x = to->x - stroker->center.x;
+    delta.y = to->y - stroker->center.y;
+
+    angle = FT_Atan2( delta.x, delta.y );
+    FT_Vector_From_Polar( &delta, stroker->radius, angle + FT_ANGLE_PI2 );
+
+    /* process corner if necessary */
+    if ( stroker->first_point )
+    {
+      /* this is the first segment of a subpath. We need to      */
+      /* add a point to each border at their respective starting */
+      /* point locations..                                       */
+      error = ft_stroker_subpath_start( stroker, angle );
+      if (error) goto Exit;
+    }
+    else
+    {
+      /* process the current corner */
+      stroker->angle_out = angle;
+      error = ft_stroker_process_corner( stroker );
+      if (error) goto Exit;
+    }
+
+    /* now add a line segment to both the "inside" and "outside" paths */
+
+    for ( border = stroker->borders, side = 1; side >= 0; side--, border++ )
+    {
+      FT_Vector  point;
+
+      point.x = to->x + delta.x;
+      point.y = to->y + delta.y;
+
+      error = ft_stroke_border_lineto( border, &point, 1 );
+      if (error) goto Exit;
+
+      delta.x = -delta.x;
+      delta.y = -delta.y;
+    }
+
+    stroker->angle_in  = angle;
+    stroker->center    = *to;
+
+  Exit:
+    return error;
+  }
+
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_ConicTo( FT_Stroker  stroker,
+                      FT_Vector*  control,
+                      FT_Vector*  to )
+  {
+    FT_Error    error = 0;
+    FT_Vector   bez_stack[34];
+    FT_Vector*  arc;
+    FT_Vector*  limit = bez_stack + 30;
+    FT_Angle    start_angle;
+    FT_Bool     first_arc = 1;
+
+    arc    = bez_stack;
+    arc[0] = *to;
+    arc[1] = *control;
+    arc[2] = stroker->center;
+
+    while ( arc >= bez_stack )
+    {
+      FT_Angle  angle_in, angle_out;
+
+      angle_in = angle_out = 0;  /* remove compiler warnings */
+
+      if ( arc < limit &&
+           !ft_conic_is_small_enough( arc, &angle_in, &angle_out ) )
+      {
+        ft_conic_split( arc );
+        arc += 2;
+        continue;
+      }
+
+      if ( first_arc )
+      {
+        first_arc = 0;
+
+        start_angle = angle_in;
+
+        /* process corner if necessary */
+        if ( stroker->first_point )
+          error = ft_stroker_subpath_start( stroker, start_angle );
+        else
+        {
+          stroker->angle_out = start_angle;
+          error = ft_stroker_process_corner( stroker );
+        }
+      }
+
+      /* the arc's angle is small enough, we can add it directly to each */
+      /* border..                                                        */
+      {
+        FT_Vector  ctrl, end;
+        FT_Angle   theta, phi, rotate;
+        FT_Fixed  length;
+        FT_Int     side;
+
+        theta  = FT_Angle_Diff( angle_in, angle_out )/2;
+        phi    = angle_in + theta;
+        length = FT_DivFix( stroker->radius, FT_Cos(theta) );
+
+        for ( side = 0; side <= 1; side++ )
+        {
+          rotate = FT_SIDE_TO_ROTATE(side);
+
+          /* compute control point */
+          FT_Vector_From_Polar( &ctrl, length, phi + rotate );
+          ctrl.x += arc[1].x;
+          ctrl.y += arc[1].y;
+
+          /* compute end point */
+          FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
+          end.x += arc[0].x;
+          end.y += arc[0].y;
+
+          error = ft_stroke_border_conicto( stroker->borders + side, &ctrl, &end );
+          if (error) goto Exit;
+        }
+      }
+
+      arc -= 2;
+
+      if (arc < bez_stack)
+        stroker->angle_in = angle_out;
+    }
+
+    stroker->center = *to;
+
+  Exit:
+    return error;
+  }
+
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_CubicTo( FT_Stroker  stroker,
+                      FT_Vector*      control1,
+                      FT_Vector*      control2,
+                      FT_Vector*      to )
+  {
+    FT_Error    error = 0;
+    FT_Vector   bez_stack[37];
+    FT_Vector*  arc;
+    FT_Vector*  limit = bez_stack + 32;
+    FT_Angle    start_angle;
+    FT_Bool     first_arc = 1;
+
+    arc    = bez_stack;
+    arc[0] = *to;
+    arc[1] = *control2;
+    arc[2] = *control1;
+    arc[3] = stroker->center;
+
+    while ( arc >= bez_stack )
+    {
+      FT_Angle  angle_in, angle_mid, angle_out;
+
+      /* remove compiler warnings */
+      angle_in = angle_out = angle_mid = 0;
+
+      if ( arc < limit &&
+           !ft_cubic_is_small_enough( arc, &angle_in, &angle_mid, &angle_out ) )
+      {
+        ft_cubic_split( arc );
+        arc += 3;
+        continue;
+      }
+
+      if ( first_arc )
+      {
+        first_arc = 0;
+
+        /* process corner if necessary */
+        start_angle = angle_in;
+
+        if ( stroker->first_point )
+          error = ft_stroker_subpath_start( stroker, start_angle );
+        else
+            {
+              stroker->angle_out = start_angle;
+              error = ft_stroker_process_corner( stroker );
+            }
+        if (error) goto Exit;
+      }
+
+      /* the arc's angle is small enough, we can add it directly to each */
+      /* border..                                                        */
+      {
+        FT_Vector  ctrl1, ctrl2, end;
+        FT_Angle   theta1, phi1, theta2, phi2, rotate;
+        FT_Fixed   length1, length2;
+        FT_Int     side;
+
+        theta1  = ft_pos_abs( angle_mid - angle_in )/2;
+        theta2  = ft_pos_abs( angle_out - angle_mid )/2;
+        phi1    = (angle_mid+angle_in)/2;
+        phi2    = (angle_mid+angle_out)/2;
+        length1 = FT_DivFix( stroker->radius, FT_Cos(theta1) );
+        length2 = FT_DivFix( stroker->radius, FT_Cos(theta2) );
+
+        for ( side = 0; side <= 1; side++ )
+        {
+          rotate = FT_SIDE_TO_ROTATE(side);
+
+          /* compute control points */
+          FT_Vector_From_Polar( &ctrl1, length1, phi1 + rotate );
+          ctrl1.x += arc[2].x;
+          ctrl1.y += arc[2].y;
+
+          FT_Vector_From_Polar( &ctrl2, length2, phi2 + rotate );
+          ctrl2.x += arc[1].x;
+          ctrl2.y += arc[1].y;
+
+          /* compute end point */
+          FT_Vector_From_Polar( &end, stroker->radius, angle_out + rotate );
+          end.x += arc[0].x;
+          end.y += arc[0].y;
+
+          error = ft_stroke_border_cubicto( stroker->borders + side, &ctrl1, &ctrl2, &end );
+          if (error) goto Exit;
+        }
+      }
+
+      arc -= 3;
+      if (arc < bez_stack)
+        stroker->angle_in = angle_out;
+    }
+
+    stroker->center = *to;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_BeginSubPath( FT_Stroker  stroker,
+                           FT_Vector*  to,
+                           FT_Bool     open )
+  {
+    /* we cannot process the first point, because there is not enough     */
+    /* information regarding its corner/cap. The latter will be processed */
+    /* in the "end_subpath" routine                                       */
+    /*                                                                    */
+    stroker->first_point   = 1;
+    stroker->center        = *to;
+    stroker->subpath_open  = open;
+
+    /* record the subpath start point index for each border */
+    stroker->subpath_start = *to;
+    return 0;
+  }
+
+
+  static
+  FT_Error  ft_stroker_add_reverse_left( FT_Stroker  stroker,
+                                         FT_Bool     open )
+  {
+    FT_StrokeBorder  right  = stroker->borders + 0;
+    FT_StrokeBorder  left   = stroker->borders + 1;
+    FT_Int           new_points;
+    FT_Error         error  = 0;
+
+    FT_ASSERT( left->start >= 0 );
+
+    new_points = left->num_points - left->start;
+    if ( new_points > 0 )
+    {
+      error = ft_stroke_border_grow( right, (FT_UInt)new_points );
+      if (error) goto Exit;
+      {
+        FT_Vector*    dst_point = right->points + right->num_points;
+        FT_Byte*      dst_tag   = right->tags   + right->num_points;
+        FT_Vector*    src_point = left->points  + left->num_points - 1;
+        FT_Byte*      src_tag   = left->tags    + left->num_points - 1;
+
+        while ( src_point >= left->points + left->start )
+        {
+          *dst_point = *src_point;
+          *dst_tag   = *src_tag;
+
+          if (open)
+            dst_tag[0] &= ~(FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END);
+          else
+          {
+            /* switch begin/end tags if necessary.. */
+            if (dst_tag[0] & (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END))
+              dst_tag[0] ^= (FT_STROKE_TAG_BEGIN | FT_STROKE_TAG_END);
+          }
+
+          src_point--;
+          src_tag--;
+          dst_point++;
+          dst_tag++;
+        }
+      }
+      left->num_points   = left->start;
+      right->num_points += new_points;
+
+      right->movable = 0;
+      left->movable  = 0;
+    }
+  Exit:
+    return error;
+  }
+
+
+ /* there's a lot of magic in this function !! */
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_EndSubPath( FT_Stroker  stroker )
+  {
+    FT_Error  error  = 0;
+
+    if ( stroker->subpath_open )
+    {
+      FT_StrokeBorder  right = stroker->borders;
+
+      /* all right, this is an opened path, we need to add a cap between     */
+      /* right & left, add the reverse of left, then add a final cap between */
+      /* left & right..                                                      */
+      error = ft_stroker_cap( stroker, stroker->angle_in, 0 );
+      if (error) goto Exit;
+
+      /* add reversed points from "left" to "right" */
+      error = ft_stroker_add_reverse_left( stroker, 1 );
+      if (error) goto Exit;
+
+      /* now add the final cap */
+      stroker->center = stroker->subpath_start;
+      error = ft_stroker_cap( stroker, stroker->subpath_angle+FT_ANGLE_PI, 0 );
+      if (error) goto Exit;
+
+      /* now, end the right subpath accordingly. the left one is */
+      /* rewind and doesn't need further processing..            */
+      ft_stroke_border_close( right );
+    }
+    else
+    {
+      FT_Angle           turn;
+      FT_Int             inside_side;
+
+      /* process the corner ... */
+      stroker->angle_out = stroker->subpath_angle;
+      turn               = FT_Angle_Diff( stroker->angle_in, stroker->angle_out );
+
+      /* no specific corner processing is required if the turn is 0 */
+      if (turn != 0)
+      {
+        /* when we turn to the right, the inside side is 0 */
+        inside_side = 0;
+
+        /* otherwise, the inside side is 1 */
+        if (turn < 0)
+          inside_side = 1;
+
+        /* IMPORTANT: WE DO NOT PROCESS THE INSIDE BORDER HERE !! */
+        /* process the inside side */
+        /* error = ft_stroker_inside( stroker, inside_side );
+             if (error) goto Exit; */
+
+        /* process the outside side */
+        error = ft_stroker_outside( stroker, 1-inside_side );
+        if (error) goto Exit;
+      }
+
+      /* we will first end our two subpaths */
+      ft_stroke_border_close( stroker->borders + 0 );
+      ft_stroke_border_close( stroker->borders + 1 );
+
+      /* now, add the reversed left subpath to "right" */
+      error = ft_stroker_add_reverse_left( stroker, 0 );
+      if (error) goto Exit;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stroker_GetCounts( FT_Stroker  stroker,
+                        FT_UInt    *anum_points,
+                        FT_UInt    *anum_contours )
+  {
+    FT_UInt   count1, count2, num_points   = 0;
+    FT_UInt   count3, count4, num_contours = 0;
+    FT_Error  error;
+
+    error = ft_stroke_border_get_counts( stroker->borders+0, &count1, &count2 );
+    if (error) goto Exit;
+
+    error = ft_stroke_border_get_counts( stroker->borders+1, &count3, &count4 );
+    if (error) goto Exit;
+
+    num_points   = count1 + count3;
+    num_contours = count2 + count4;
+
+    stroker->valid = 1;
+
+  Exit:
+    *anum_points   = num_points;
+    *anum_contours = num_contours;
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_Stroker_Export( FT_Stroker   stroker,
+                     FT_Outline*  outline )
+  {
+    if ( stroker->valid )
+    {
+      ft_stroke_border_export( stroker->borders+0, outline );
+      ft_stroke_border_export( stroker->borders+1, outline );
+    }
+  }
--- /dev/null
+++ b/libfreetype/ftsynth.c
@@ -1,0 +1,286 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftsynth.c                                                              */
+/*                                                                         */
+/*    FreeType synthesizing code for emboldening and slanting (body).      */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_CALC_H
+#include FT_OUTLINE_H
+#include FT_TRIGONOMETRY_H
+#include FT_SYNTHESIS_H
+
+
+#define FT_BOLD_THRESHOLD  0x0100
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   EXPERIMENTAL OBLIQUING SUPPORT                                ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_EXPORT_DEF( void )
+  FT_GlyphSlot_Oblique( FT_GlyphSlot  slot )
+  {
+    FT_Matrix    transform;
+    FT_Outline*  outline = &slot->outline;
+
+
+    /* only oblique outline glyphs */
+    if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+      return;
+
+    /* we don't touch the advance width */
+
+    /* For italic, simply apply a shear transform, with an angle */
+    /* of about 12 degrees.                                      */
+
+    transform.xx = 0x10000L;
+    transform.yx = 0x00000L;
+
+    transform.xy = 0x06000L;
+    transform.yy = 0x10000L;
+
+    FT_Outline_Transform( outline, &transform );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****   EXPERIMENTAL EMBOLDENING/OUTLINING SUPPORT                    ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+
+  static int
+  ft_test_extrema( FT_Outline*  outline,
+                   int          n )
+  {
+    FT_Vector  *prev, *cur, *next;
+    FT_Pos      product;
+    FT_Int      c, first, last;
+
+
+    /* we need to compute the `previous' and `next' point */
+    /* for these extrema.                                 */
+    cur   = outline->points + n;
+    prev  = cur - 1;
+    next  = cur + 1;
+
+    first = 0;
+    for ( c = 0; c < outline->n_contours; c++ )
+    {
+      last  = outline->contours[c];
+
+      if ( n == first )
+        prev = outline->points + last;
+
+      if ( n == last )
+        next = outline->points + first;
+
+      first = last + 1;
+    }
+
+    product = FT_MulDiv( cur->x - prev->x,   /* in.x  */
+                         next->y - cur->y,   /* out.y */
+                         0x40 )
+              -
+              FT_MulDiv( cur->y - prev->y,   /* in.y  */
+                         next->x - cur->x,   /* out.x */
+                         0x40 );
+
+    if ( product )
+      product = product > 0 ? 1 : -1;
+
+    return product;
+  }
+
+
+  /* Compute the orientation of path filling.  It differs between TrueType */
+  /* and Type1 formats.  We could use the `FT_OUTLINE_REVERSE_FILL' flag,  */
+  /* but it is better to re-compute it directly (it seems that this flag   */
+  /* isn't correctly set for some weird composite glyphs currently).       */
+  /*                                                                       */
+  /* We do this by computing bounding box points, and computing their      */
+  /* curvature.                                                            */
+  /*                                                                       */
+  /* The function returns either 1 or -1.                                  */
+  /*                                                                       */
+  static int
+  ft_get_orientation( FT_Outline*  outline )
+  {
+    FT_BBox  box;
+    FT_BBox  indices;
+    int      n, last;
+
+
+    indices.xMin = -1;
+    indices.yMin = -1;
+    indices.xMax = -1;
+    indices.yMax = -1;
+
+    box.xMin = box.yMin =  32767;
+    box.xMax = box.yMax = -32768;
+
+    /* is it empty ? */
+    if ( outline->n_contours < 1 )
+      return 1;
+
+    last = outline->contours[outline->n_contours - 1];
+
+    for ( n = 0; n <= last; n++ )
+    {
+      FT_Pos  x, y;
+
+
+      x = outline->points[n].x;
+      if ( x < box.xMin )
+      {
+        box.xMin     = x;
+        indices.xMin = n;
+      }
+      if ( x > box.xMax )
+      {
+        box.xMax     = x;
+        indices.xMax = n;
+      }
+
+      y = outline->points[n].y;
+      if ( y < box.yMin )
+      {
+        box.yMin     = y;
+        indices.yMin = n;
+      }
+      if ( y > box.yMax )
+      {
+        box.yMax     = y;
+        indices.yMax = n;
+      }
+    }
+
+    /* test orientation of the xmin */
+    n = ft_test_extrema( outline, indices.xMin );
+    if ( n )
+      goto Exit;
+
+    n = ft_test_extrema( outline, indices.yMin );
+    if ( n )
+      goto Exit;
+
+    n = ft_test_extrema( outline, indices.xMax );
+    if ( n )
+      goto Exit;
+
+    n = ft_test_extrema( outline, indices.yMax );
+    if ( !n )
+      n = 1;
+
+  Exit:
+    return n;
+  }
+
+
+  FT_EXPORT_DEF( void )
+  FT_GlyphSlot_Embolden( FT_GlyphSlot  slot )
+  {
+    FT_Vector*   points;
+    FT_Vector    v_prev, v_first, v_next, v_cur;
+    FT_Pos       distance;
+    FT_Outline*  outline = &slot->outline;
+    FT_Face      face = FT_SLOT_FACE( slot );
+    FT_Angle     rotate, angle_in, angle_out;
+    FT_Int       c, n, first, orientation;
+
+
+    /* only embolden outline glyph images */
+    if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+      return;
+
+    /* compute control distance */
+    distance = FT_MulFix( face->units_per_EM / 60,
+                          face->size->metrics.y_scale );
+
+    orientation = ft_get_orientation( outline );
+    rotate      = FT_ANGLE_PI2*orientation;
+
+    points = outline->points;
+
+    first = 0;
+    for ( c = 0; c < outline->n_contours; c++ )
+    {
+      int  last = outline->contours[c];
+
+
+      v_first = points[first];
+      v_prev  = points[last];
+      v_cur   = v_first;
+
+      for ( n = first; n <= last; n++ )
+      {
+        FT_Pos     d;
+        FT_Vector  in, out;
+        FT_Fixed   scale;
+        FT_Angle   angle_diff;
+
+
+        if ( n < last ) v_next = points[n + 1];
+        else            v_next = v_first;
+
+        /* compute the in and out vectors */
+        in.x  = v_cur.x - v_prev.x;
+        in.y  = v_cur.y - v_prev.y;
+
+        out.x = v_next.x - v_cur.x;
+        out.y = v_next.y - v_cur.y;
+
+        angle_in   = FT_Atan2( in.x, in.y );
+        angle_out  = FT_Atan2( out.x, out.y );
+        angle_diff = FT_Angle_Diff( angle_in, angle_out );
+        scale      = FT_Cos( angle_diff/2 );
+
+        if ( scale < 0x400L && scale > -0x400L )
+        {
+          if ( scale >= 0 )
+            scale = 0x400L;
+          else
+            scale = -0x400L;
+        }
+
+        d = FT_DivFix( distance, scale );
+
+        FT_Vector_From_Polar( &in, d, angle_in + angle_diff/2 - rotate );
+
+        outline->points[n].x = v_cur.x + distance + in.x;
+        outline->points[n].y = v_cur.y + distance + in.y;
+
+        v_prev = v_cur;
+        v_cur  = v_next;
+      }
+
+      first = last + 1;
+    }
+
+    slot->metrics.horiAdvance = ( slot->metrics.horiAdvance + distance*4 ) & -64;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsysio.c
@@ -1,0 +1,131 @@
+#include <ft2build.h>
+#include FT_SYSTEM_STREAM_H
+
+#include <stdio.h>
+
+ /* the ISO/ANSI standard stream object */
+  typedef struct FT_StdStreamRec_
+  {
+    FT_StreamRec  stream;
+    FILE*         file;
+    const char*   pathname;
+  
+  } FT_StdStreamRec, *FT_StdStream;
+
+
+
+ /* read bytes from a standard stream */
+  static FT_ULong
+  ft_std_stream_read( FT_StdStream   stream,
+                      FT_Byte*       buffer,
+                      FT_ULong       size )
+  {
+    long   read_bytes;
+    
+    read_bytes = fread( buffer, 1, size, stream->file );
+    if ( read_bytes < 0 )
+      read_bytes = 0;
+      
+    return (FT_ULong) read_bytes;
+  }
+
+
+ /* seek the standard stream to a new position */
+  static FT_Error
+  ft_std_stream_seek( FT_StdStream   stream,
+                      FT_ULong       pos )
+  {
+    return ( fseek( stream->file, pos, SEEK_SET ) < 0 )
+         ? FT_Err_Stream_Seek
+         : FT_Err_Ok;
+  }
+  
+  
+ /* close a standard stream */  
+  static void
+  ft_std_stream_done( FT_StdStream  stream )
+  {
+    fclose( stream->file );
+    stream->file     = NULL;
+    stream->pathname = NULL;
+  }
+
+
+ /* open a standard stream from a given pathname */
+  static void
+  ft_std_stream_init( FT_StdStream  stream,
+                      const char*   pathname )
+  {
+    FT_ASSERT( pathname != NULL );
+
+    stream->file = fopen( pathname, "rb" );
+    if ( stream->file == NULL )
+    {
+      FT_ERROR(( "iso.stream.init: could not open '%s'\n", pathname ));
+      FT_XTHROW( FT_Err_Stream_Open );
+    }
+    
+    /* compute total size in bytes */
+    fseek( file, 0, SEEK_END );
+    FT_STREAM__SIZE(stream) = ftell( file );
+    fseek( file, 0, SEEK_SET );
+    
+    stream->pathname = pathname;
+    stream->pos      = 0;
+    
+    FT_TRACE1(( "iso.stream.init: opened '%s' (%ld bytes) succesfully\n",
+                 pathname, FT_STREAM__SIZE(stream) ));
+  }                 
+
+
+  static void
+  ft_std_stream_class_init( FT_ClassRec*  _clazz )
+  {
+    FT_StreamClassRec*  clazz = FT_STREAM_CLASS(_clazz);
+    
+    clazz->stream_read = (FT_Stream_ReadFunc) ft_std_stream_read;
+    clazz->stream_seek = (FT_Stream_SeekFunc) ft_std_stream_seek;
+  }
+
+
+  static const FT_TypeRec  ft_std_stream_type;
+  {
+    "StreamClass",
+    NULL,
+    
+    sizeof( FT_ClassRec ),
+    ft_stream_class_init,
+    NULL,
+    
+    sizeof( FT_StdStreamRec ),
+    ft_std_stream_init,
+    ft_std_stream_done,
+    NULL,
+  };
+  
+
+
+  FT_EXPORT_DEF( FT_Stream )
+  ft_std_stream_new( FT_Memory    memory,
+                     const char*  pathname )
+  {
+    FT_Class  clazz;
+    
+    clazz = ft_class_from_type( memory, &ft_std_stream_type );
+    
+    return (FT_Stream) ft_object_new( clazz, pathname );
+  }                     
+
+
+  FT_EXPORT_DEF( void )
+  ft_std_stream_create( FT_Memory    memory,
+                        const char*  pathname,
+                        FT_Stream*   astream )
+  {
+    FT_Class  clazz;
+    
+    clazz = ft_class_from_type( memory, &ft_std_stream_type );
+    
+    ft_object_create( clazz, pathname, FT_OBJECT_P(astream) );
+  }                        
+
--- /dev/null
+++ b/libfreetype/ftsysmem.c
@@ -1,0 +1,30 @@
+#include <ft2build.h>
+#include FT_SYSTEM_MEMORY_H
+
+  static FT_Memory
+  ft_memory_new_default( FT_ULong  size )
+  {
+    return (FT_Memory) ft_malloc( size );
+  }
+  
+  static void
+  ft_memory_destroy_default( FT_Memory  memory )
+  {
+    ft_free( memory );
+  }
+
+  
+ /* notice that in normal builds, we use the ISO C library functions */
+ /* 'malloc', 'free' and 'realloc' directly..                        */
+ /*                                                                  */
+  static const FT_Memory_FuncsRec  ft_memory_funcs_default_rec = 
+  {
+    (FT_Memory_CreateFunc)  ft_memory_new_iso,
+    (FT_Memory_DestroyFunc) ft_memory_destroy_iso,
+    (FT_Memory_AllocFunc)   ft_malloc,
+    (FT_Memory_FreeFunc)    ft_free,
+    (FT_Memory_ReallocFunc) ft_realloc
+  };
+  
+  FT_APIVAR_DEF( const FT_Memory_Funcs )
+  ft_memory_funcs_default = &ft_memory_funcs_defaults_rec;
--- /dev/null
+++ b/libfreetype/ftsystem.c
@@ -1,0 +1,303 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftsystem.c                                                             */
+/*                                                                         */
+/*    ANSI-specific FreeType low-level system interface (body).            */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file contains the default interface used by FreeType to access   */
+  /* low-level, i.e. memory management, i/o access as well as thread       */
+  /* synchronisation.  It can be replaced by user-specific routines if     */
+  /* necessary.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                       MEMORY MANAGEMENT INTERFACE                     */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* It is not necessary to do any error checking for the                  */
+  /* allocation-related functions.  This will be done by the higher level  */
+  /* routines like FT_Alloc() or FT_Realloc().                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_alloc                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The memory allocation function.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory :: A pointer to the memory object.                          */
+  /*                                                                       */
+  /*    size   :: The requested size in bytes.                             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The address of newly allocated block.                              */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void* )
+  ft_alloc( FT_Memory  memory,
+            long       size )
+  {
+    FT_UNUSED( memory );
+
+    return malloc( size );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_realloc                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The memory reallocation function.                                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory   :: A pointer to the memory object.                        */
+  /*                                                                       */
+  /*    cur_size :: The current size of the allocated memory block.        */
+  /*                                                                       */
+  /*    new_size :: The newly requested size in bytes.                     */
+  /*                                                                       */
+  /*    block    :: The current address of the block in memory.            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The address of the reallocated memory block.                       */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void* )
+  ft_realloc( FT_Memory  memory,
+              long       cur_size,
+              long       new_size,
+              void*      block )
+  {
+    FT_UNUSED( memory );
+    FT_UNUSED( cur_size );
+
+    return realloc( block, new_size );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_free                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The memory release function.                                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory  :: A pointer to the memory object.                         */
+  /*                                                                       */
+  /*    block   :: The address of block in memory to be freed.             */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void )
+  ft_free( FT_Memory  memory,
+           void*      block )
+  {
+    FT_UNUSED( memory );
+
+    free( block );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                     RESOURCE MANAGEMENT INTERFACE                     */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_io
+
+  /* We use the macro STREAM_FILE for convenience to extract the       */
+  /* system-specific stream handle from a given FreeType stream object */
+#define STREAM_FILE( stream )  ( (FILE*)stream->descriptor.pointer )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_ansi_stream_close                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The function to close a stream.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: A pointer to the stream object.                          */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void )
+  ft_ansi_stream_close( FT_Stream  stream )
+  {
+    fclose( STREAM_FILE( stream ) );
+
+    stream->descriptor.pointer = NULL;
+    stream->size               = 0;
+    stream->base               = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_ansi_stream_io                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The function to open a stream.                                     */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: A pointer to the stream object.                          */
+  /*                                                                       */
+  /*    offset :: The position in the data stream to start reading.        */
+  /*                                                                       */
+  /*    buffer :: The address of buffer to store the read data.            */
+  /*                                                                       */
+  /*    count  :: The number of bytes to read from the stream.             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The number of bytes actually read.                                 */
+  /*                                                                       */
+  FT_CALLBACK_DEF( unsigned long )
+  ft_ansi_stream_io( FT_Stream       stream,
+                     unsigned long   offset,
+                     unsigned char*  buffer,
+                     unsigned long   count )
+  {
+    FILE*  file;
+
+
+    file = STREAM_FILE( stream );
+
+    fseek( file, offset, SEEK_SET );
+
+    return (unsigned long)fread( buffer, 1, count, file );
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Stream_Open( FT_Stream    stream,
+                  const char*  filepathname )
+  {
+    FILE*  file;
+
+
+    if ( !stream )
+      return FT_Err_Invalid_Stream_Handle;
+
+    file = fopen( filepathname, "rb" );
+    if ( !file )
+    {
+      FT_ERROR(( "FT_Stream_Open:" ));
+      FT_ERROR(( " could not open `%s'\n", filepathname ));
+
+      return FT_Err_Cannot_Open_Resource;
+    }
+
+    fseek( file, 0, SEEK_END );
+    stream->size = ftell( file );
+    fseek( file, 0, SEEK_SET );
+
+    stream->descriptor.pointer = file;
+    stream->pathname.pointer   = (char*)filepathname;
+    stream->pos                = 0;
+
+    stream->read  = ft_ansi_stream_io;
+    stream->close = ft_ansi_stream_close;
+
+    FT_TRACE1(( "FT_Stream_Open:" ));
+    FT_TRACE1(( " opened `%s' (%d bytes) successfully\n",
+                filepathname, stream->size ));
+
+    return FT_Err_Ok;
+  }
+
+
+#ifdef FT_DEBUG_MEMORY
+
+  extern FT_Int
+  ft_mem_debug_init( FT_Memory  memory );
+
+  extern void
+  ft_mem_debug_done( FT_Memory  memory );
+
+#endif
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_EXPORT_DEF( FT_Memory )
+  FT_New_Memory( void )
+  {
+    FT_Memory  memory;
+
+
+    memory = (FT_Memory)malloc( sizeof ( *memory ) );
+    if ( memory )
+    {
+      memory->user    = 0;
+      memory->alloc   = ft_alloc;
+      memory->realloc = ft_realloc;
+      memory->free    = ft_free;
+#ifdef FT_DEBUG_MEMORY
+      ft_mem_debug_init( memory );
+#endif
+    }
+
+    return memory;
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Done_Memory( FT_Memory  memory )
+  {
+#ifdef FT_DEBUG_MEMORY
+    ft_mem_debug_done( memory );
+#endif
+    memory->free( memory, memory );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftsystem_inf.c
@@ -1,0 +1,308 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftsystem.c                                                             */
+/*                                                                         */
+/*    ANSI-specific FreeType low-level system interface (body).            */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file contains the default interface used by FreeType to access   */
+  /* low-level, i.e. memory management, i/o access as well as thread       */
+  /* synchronisation.  It can be replaced by user-specific routines if     */
+  /* necessary.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+/* This is the Inferno version */
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+#include "kernel.h"
+
+/*#include <stdio.h>*/
+/*#include <stdlib.h>*/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                       MEMORY MANAGEMENT INTERFACE                     */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* It is not necessary to do any error checking for the                  */
+  /* allocation-related functions.  This will be done by the higher level  */
+  /* routines like FT_Alloc() or FT_Realloc().                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_alloc                                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The memory allocation function.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory :: A pointer to the memory object.                          */
+  /*                                                                       */
+  /*    size   :: The requested size in bytes.                             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The address of newly allocated block.                              */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void* )
+  ft_alloc( FT_Memory  memory,
+            long       size )
+  {
+    FT_UNUSED( memory );
+
+    return malloc( size );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_realloc                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The memory reallocation function.                                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory   :: A pointer to the memory object.                        */
+  /*                                                                       */
+  /*    cur_size :: The current size of the allocated memory block.        */
+  /*                                                                       */
+  /*    new_size :: The newly requested size in bytes.                     */
+  /*                                                                       */
+  /*    block    :: The current address of the block in memory.            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The address of the reallocated memory block.                       */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void* )
+  ft_realloc( FT_Memory  memory,
+              long       cur_size,
+              long       new_size,
+              void*      block )
+  {
+    FT_UNUSED( memory );
+    FT_UNUSED( cur_size );
+
+    return realloc( block, new_size );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_free                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The memory release function.                                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory  :: A pointer to the memory object.                         */
+  /*                                                                       */
+  /*    block   :: The address of block in memory to be freed.             */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void )
+  ft_free( FT_Memory  memory,
+           void*      block )
+  {
+    FT_UNUSED( memory );
+
+    free( block );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                     RESOURCE MANAGEMENT INTERFACE                     */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_io
+
+  /* We use the macro STREAM_FD for convenience to extract the       */
+  /* fd from a given FreeType stream object */
+#define STREAM_FD( stream )  ( (int)stream->descriptor.pointer )
+#define CLOSED_FD	(void*)-1
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_ansi_stream_close                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The function to close a stream.                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: A pointer to the stream object.                          */
+  /*                                                                       */
+  FT_CALLBACK_DEF( void )
+  ft_ansi_stream_close( FT_Stream  stream )
+  {
+    kclose( STREAM_FD( stream ) );
+
+    stream->descriptor.pointer = CLOSED_FD;
+    stream->size               = 0;
+    stream->base               = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ft_ansi_stream_io                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The function to open a stream.                                     */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: A pointer to the stream object.                          */
+  /*                                                                       */
+  /*    offset :: The position in the data stream to start reading.        */
+  /*                                                                       */
+  /*    buffer :: The address of buffer to store the read data.            */
+  /*                                                                       */
+  /*    count  :: The number of bytes to read from the stream.             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The number of bytes actually read.                                 */
+  /*                                                                       */
+  FT_CALLBACK_DEF( unsigned long )
+  ft_ansi_stream_io( FT_Stream       stream,
+                     unsigned long   offset,
+                     unsigned char*  buffer,
+                     unsigned long   count )
+  {
+	int fd;
+
+	fd = STREAM_FD( stream );
+	kseek( fd, offset, SEEK_SET );
+	if(count == 0)
+		return 0;
+	return (unsigned long)kread( fd, buffer, count);
+}
+
+
+  /* documentation is in ftobjs.h */
+
+FT_EXPORT_DEF( FT_Error )
+FT_Stream_Open( FT_Stream stream, const char*  filepathname)
+{
+	Dir *dir;
+	int  file;
+
+	if ( !stream )
+		return FT_Err_Invalid_Stream_Handle;
+	file = kopen( (char*)filepathname, OREAD);
+	if ( file < 0) {
+		FT_ERROR(( "FT_Stream_Open:" ));
+		FT_ERROR(( " could not open `%s'\n", filepathname ));
+		return FT_Err_Cannot_Open_Resource;
+	}
+	dir = kdirfstat(file);
+	if (dir == nil) {
+		kclose(file);
+		FT_ERROR(( "FT_Stream_Open:" ));
+		FT_ERROR(( " could not stat `%s'\n", filepathname ));
+		return FT_Err_Cannot_Open_Resource;
+	}
+	stream->size = dir->length;
+	free(dir);
+
+	stream->descriptor.pointer = (void*)file;
+	stream->pathname.pointer = (char*)filepathname;
+	stream->pos = 0;
+
+	stream->read  = ft_ansi_stream_io;
+	stream->close = ft_ansi_stream_close;
+
+	FT_TRACE1(( "FT_Stream_Open:" ));
+	FT_TRACE1(( " opened `%s' (%d bytes) successfully\n",
+		filepathname, stream->size ));
+
+	return FT_Err_Ok;
+}
+
+
+#ifdef FT_DEBUG_MEMORY
+
+  extern FT_Int
+  ft_mem_debug_init( FT_Memory  memory );
+
+  extern void
+  ft_mem_debug_done( FT_Memory  memory );
+
+#endif
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_EXPORT_DEF( FT_Memory )
+  FT_New_Memory( void )
+  {
+    FT_Memory  memory;
+
+
+    memory = (FT_Memory)malloc( sizeof ( *memory ) );
+    if ( memory )
+    {
+      memory->user    = 0;
+      memory->alloc   = ft_alloc;
+      memory->realloc = ft_realloc;
+      memory->free    = ft_free;
+#ifdef FT_DEBUG_MEMORY
+      ft_mem_debug_init( memory );
+#endif
+    }
+
+    return memory;
+  }
+
+
+  /* documentation is in ftobjs.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Done_Memory( FT_Memory  memory )
+  {
+#ifdef FT_DEBUG_MEMORY
+    ft_mem_debug_done( memory );
+#endif
+    memory->free( memory, memory );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/fttrigon.c
@@ -1,0 +1,485 @@
+/***************************************************************************/
+/*                                                                         */
+/*  fttrigon.c                                                             */
+/*                                                                         */
+/*    FreeType trigonometric functions (body).                             */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_TRIGONOMETRY_H
+
+
+  /* the following is 0.2715717684432231 * 2^30 */
+#define FT_TRIG_COSCALE  0x11616E8EUL
+
+  /* this table was generated for FT_PI = 180L << 16, i.e. degrees */
+#define FT_TRIG_MAX_ITERS  23
+
+  static const FT_Fixed
+  ft_trig_arctan_table[24] =
+  {
+    4157273L, 2949120L, 1740967L, 919879L, 466945L, 234379L, 117304L,
+    58666L, 29335L, 14668L, 7334L, 3667L, 1833L, 917L, 458L, 229L, 115L,
+    57L, 29L, 14L, 7L, 4L, 2L, 1L
+  };
+
+  /* the Cordic shrink factor, multiplied by 2^32 */
+#define FT_TRIG_SCALE    1166391785UL  /* 0x4585BA38UL */
+
+
+#ifdef FT_CONFIG_HAS_INT64
+
+  /* multiply a given value by the CORDIC shrink factor */
+  static FT_Fixed
+  ft_trig_downscale( FT_Fixed  val )
+  {
+    FT_Fixed  s;
+    FT_Int64  v;
+
+
+    s   = val;
+    val = ( val >= 0 ) ? val : -val;
+
+    v   = ( val * (FT_Int64)FT_TRIG_SCALE ) + 0x100000000UL;
+    val = (FT_Fixed)( v >> 32 );
+
+    return ( s >= 0 ) ? val : -val;
+  }
+
+#else /* !FT_CONFIG_HAS_INT64 */
+
+  /* multiply a given value by the CORDIC shrink factor */
+  static FT_Fixed
+  ft_trig_downscale( FT_Fixed  val )
+  {
+    FT_Fixed   s;
+    FT_UInt32  v1, v2, k1, k2, hi, lo1, lo2, lo3;
+
+
+    s   = val;
+    val = ( val >= 0 ) ? val : -val;
+
+    v1 = (FT_UInt32)val >> 16;
+    v2 = (FT_UInt32)val & 0xFFFF;
+
+    k1 = FT_TRIG_SCALE >> 16;       /* constant */
+    k2 = FT_TRIG_SCALE & 0xFFFF;    /* constant */
+
+    hi   = k1 * v1;
+    lo1  = k1 * v2 + k2 * v1;       /* can't overflow */
+
+    lo2  = ( k2 * v2 ) >> 16;
+    lo3  = ( lo1 >= lo2 ) ? lo1 : lo2;
+    lo1 += lo2;
+
+    hi  += lo1 >> 16;
+    if ( lo1 < lo3 )
+      hi += 0x10000UL;
+
+    val  = (FT_Fixed)hi;
+
+    return ( s >= 0 ) ? val : -val;
+  }
+
+#endif /* !FT_CONFIG_HAS_INT64 */
+
+
+  static FT_Int
+  ft_trig_prenorm( FT_Vector*  vec )
+  {
+    FT_Fixed  x, y, z;
+    FT_Int    shift;
+
+
+    x = vec->x;
+    y = vec->y;
+
+    z     = ( ( x >= 0 ) ? x : - x ) | ( (y >= 0) ? y : -y );
+    shift = 0;
+
+    if ( z < ( 1L << 27 ) )
+    {
+      do
+      {
+        shift++;
+        z <<= 1;
+      } while ( z < ( 1L << 27 ) );
+
+      vec->x = x << shift;
+      vec->y = y << shift;
+    }
+    else if ( z > ( 1L << 28 ) )
+    {
+      do
+      {
+        shift++;
+        z >>= 1;
+      } while ( z > ( 1L << 28 ) );
+
+      vec->x = x >> shift;
+      vec->y = y >> shift;
+      shift  = -shift;
+    }
+    return shift;
+  }
+
+
+  static void
+  ft_trig_pseudo_rotate( FT_Vector*  vec,
+                         FT_Angle    theta )
+  {
+    FT_Int           i;
+    FT_Fixed         x, y, xtemp;
+    const FT_Fixed  *arctanptr;
+
+
+    x = vec->x;
+    y = vec->y;
+
+    /* Get angle between -90 and 90 degrees */
+    while ( theta <= -FT_ANGLE_PI2 )
+    {
+      x = -x;
+      y = -y;
+      theta += FT_ANGLE_PI;
+    }
+
+    while ( theta > FT_ANGLE_PI2 )
+    {
+      x = -x;
+      y = -y;
+      theta -= FT_ANGLE_PI;
+    }
+
+    /* Initial pseudorotation, with left shift */
+    arctanptr = ft_trig_arctan_table;
+
+    if ( theta < 0 )
+    {
+      xtemp  = x + ( y << 1 );
+      y      = y - ( x << 1 );
+      x      = xtemp;
+      theta += *arctanptr++;
+    }
+    else
+    {
+      xtemp  = x - ( y << 1 );
+      y      = y + ( x << 1 );
+      x      = xtemp;
+      theta -= *arctanptr++;
+    }
+
+    /* Subsequent pseudorotations, with right shifts */
+    i = 0;
+    do
+    {
+      if ( theta < 0 )
+      {
+        xtemp  = x + ( y >> i );
+        y      = y - ( x >> i );
+        x      = xtemp;
+        theta += *arctanptr++;
+      }
+      else
+      {
+        xtemp  = x - ( y >> i );
+        y      = y + ( x >> i );
+        x      = xtemp;
+        theta -= *arctanptr++;
+      }
+    } while ( ++i < FT_TRIG_MAX_ITERS );
+
+    vec->x = x;
+    vec->y = y;
+  }
+
+
+  static void
+  ft_trig_pseudo_polarize( FT_Vector*  vec )
+  {
+    FT_Fixed         theta;
+    FT_Fixed         yi, i;
+    FT_Fixed         x, y;
+    const FT_Fixed  *arctanptr;
+
+
+    x = vec->x;
+    y = vec->y;
+
+    /* Get the vector into the right half plane */
+    theta = 0;
+    if ( x < 0 )
+    {
+      x = -x;
+      y = -y;
+      theta = 2 * FT_ANGLE_PI2;
+    }
+
+    if ( y > 0 )
+      theta = - theta;
+
+    arctanptr = ft_trig_arctan_table;
+
+    if ( y < 0 )
+    {
+      /* Rotate positive */
+      yi     = y + ( x << 1 );
+      x      = x - ( y << 1 );
+      y      = yi;
+      theta -= *arctanptr++;  /* Subtract angle */
+    }
+    else
+    {
+      /* Rotate negative */
+      yi     = y - ( x << 1 );
+      x      = x + ( y << 1 );
+      y      = yi;
+      theta += *arctanptr++;  /* Add angle */
+    }
+
+    i = 0;
+    do
+    {
+      if ( y < 0 )
+      {
+        /* Rotate positive */
+        yi     = y + ( x >> i );
+        x      = x - ( y >> i );
+        y      = yi;
+        theta -= *arctanptr++;
+      }
+      else
+      {
+        /* Rotate negative */
+        yi     = y - ( x >> i );
+        x      = x + ( y >> i );
+        y      = yi;
+        theta += *arctanptr++;
+      }
+    } while ( ++i < FT_TRIG_MAX_ITERS );
+
+    /* round theta */
+    if ( theta >= 0 )
+      theta = ( theta + 16 ) & -32;
+    else
+      theta = - (( -theta + 16 ) & -32);
+
+    vec->x = x;
+    vec->y = theta;
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( FT_Fixed )
+  FT_Cos( FT_Angle  angle )
+  {
+    FT_Vector  v;
+
+
+    v.x = FT_TRIG_COSCALE >> 2;
+    v.y = 0;
+    ft_trig_pseudo_rotate( &v, angle );
+
+    return v.x / ( 1 << 12 );
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( FT_Fixed )
+  FT_Sin( FT_Angle  angle )
+  {
+    return FT_Cos( FT_ANGLE_PI2 - angle );
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( FT_Fixed )
+  FT_Tan( FT_Angle  angle )
+  {
+    FT_Vector  v;
+
+
+    v.x = FT_TRIG_COSCALE >> 2;
+    v.y = 0;
+    ft_trig_pseudo_rotate( &v, angle );
+
+    return FT_DivFix( v.y, v.x );
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( FT_Angle )
+  FT_Atan2( FT_Fixed  dx,
+            FT_Fixed  dy )
+  {
+    FT_Vector  v;
+
+
+    if ( dx == 0 && dy == 0 )
+      return 0;
+
+    v.x = dx;
+    v.y = dy;
+    ft_trig_prenorm( &v );
+    ft_trig_pseudo_polarize( &v );
+
+    return v.y;
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Vector_Unit( FT_Vector*  vec,
+                  FT_Angle    angle )
+  {
+    vec->x = FT_TRIG_COSCALE >> 2;
+    vec->y = 0;
+    ft_trig_pseudo_rotate( vec, angle );
+    vec->x >>= 12;
+    vec->y >>= 12;
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Vector_Rotate( FT_Vector*  vec,
+                    FT_Angle    angle )
+  {
+    FT_Int     shift;
+    FT_Vector  v;
+
+
+    v.x   = vec->x;
+    v.y   = vec->y;
+
+    if ( angle && ( v.x != 0 || v.y != 0 ) )
+    {
+      shift = ft_trig_prenorm( &v );
+      ft_trig_pseudo_rotate( &v, angle );
+      v.x = ft_trig_downscale( v.x );
+      v.y = ft_trig_downscale( v.y );
+
+      if ( shift >= 0 )
+      {
+        vec->x = v.x >> shift;
+        vec->y = v.y >> shift;
+      }
+      else
+      {
+        shift  = -shift;
+        vec->x = v.x << shift;
+        vec->y = v.y << shift;
+      }
+    }
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( FT_Fixed )
+  FT_Vector_Length( FT_Vector*  vec )
+  {
+    FT_Int     shift;
+    FT_Vector  v;
+
+
+    v = *vec;
+
+    /* handle trivial cases */
+    if ( v.x == 0 )
+    {
+      return ( v.y >= 0 ) ? v.y : -v.y;
+    }
+    else if ( v.y == 0 )
+    {
+      return ( v.x >= 0 ) ? v.x : -v.x;
+    }
+
+    /* general case */
+    shift = ft_trig_prenorm( &v );
+    ft_trig_pseudo_polarize( &v );
+
+    v.x = ft_trig_downscale( v.x );
+
+    if ( shift > 0 )
+      return ( v.x + ( 1 << ( shift - 1 ) ) ) >> shift;
+
+    return v.x << -shift;
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Vector_Polarize( FT_Vector*  vec,
+                      FT_Fixed   *length,
+                      FT_Angle   *angle )
+  {
+    FT_Int     shift;
+    FT_Vector  v;
+
+
+    v = *vec;
+
+    if ( v.x == 0 && v.y == 0 )
+      return;
+
+    shift = ft_trig_prenorm( &v );
+    ft_trig_pseudo_polarize( &v );
+
+    v.x = ft_trig_downscale( v.x );
+
+    *length = ( shift >= 0 ) ? ( v.x >> shift ) : ( v.x << -shift );
+    *angle  = v.y;
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( void )
+  FT_Vector_From_Polar( FT_Vector*  vec,
+                        FT_Fixed    length,
+                        FT_Angle    angle )
+  {
+    vec->x = length;
+    vec->y = 0;
+
+    FT_Vector_Rotate( vec, angle );
+  }
+
+
+  /* documentation is in fttrigon.h */
+
+  FT_EXPORT_DEF( FT_Angle )
+  FT_Angle_Diff( FT_Angle  angle1,
+                 FT_Angle  angle2 )
+  {
+    FT_Angle  delta = angle2 - angle1;
+
+    delta %= FT_ANGLE_2PI;
+
+    if ( delta > FT_ANGLE_PI )
+      delta -= FT_ANGLE_2PI;
+
+    return delta;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/fttype1.c
@@ -1,0 +1,87 @@
+/***************************************************************************/
+/*                                                                         */
+/*  fttype1.c                                                              */
+/*                                                                         */
+/*    FreeType utility file for PS names support (body).                   */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_TYPE42_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+  /* documentation is in t1tables.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_Get_PS_Font_Info( FT_Face          face,
+                       PS_FontInfoRec*  afont_info )
+  {
+    PS_FontInfo  font_info = NULL;
+    FT_Error     error     = FT_Err_Invalid_Argument;
+    const char*  driver_name;
+
+
+    if ( face && face->driver && face->driver->root.clazz )
+    {
+      driver_name = face->driver->root.clazz->module_name;
+      if ( ft_strcmp( driver_name, "type1" ) == 0 )
+        font_info = &((T1_Face)face)->type1.font_info;
+      else if ( ft_strcmp( driver_name, "t1cid" ) == 0 )
+        font_info = &((CID_Face)face)->cid.font_info;
+      else if ( ft_strcmp( driver_name, "type42" ) == 0 )
+        font_info = &((T42_Face)face)->type1.font_info;
+    }
+    if ( font_info != NULL )
+    {
+      *afont_info = *font_info;
+      error = FT_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+  /* XXX: Bad hack, but I didn't want to change several drivers here. */
+
+  /* documentation is in t1tables.h */
+
+  FT_EXPORT_DEF( FT_Int )
+  FT_Has_PS_Glyph_Names( FT_Face  face )
+  {
+    FT_Int       result = 0;
+    const char*  driver_name;
+
+
+    if ( face && face->driver && face->driver->root.clazz )
+    {
+      /* Currently, only the type1, type42, and cff drivers provide */
+      /* reliable glyph names...                                    */
+
+      /* We could probably hack the TrueType driver to recognize    */
+      /* certain cases where the glyph names are most certainly     */
+      /* correct (e.g. using a 20 or 22 format `post' table), but   */
+      /* this will probably happen later...                         */
+
+      driver_name = face->driver->root.clazz->module_name;
+      result      = ( ft_strcmp( driver_name, "type1"  ) == 0 ||
+                      ft_strcmp( driver_name, "type42" ) == 0 ||
+                      ft_strcmp( driver_name, "cff"    ) == 0 );
+    }
+
+    return result;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftutil.c
@@ -1,0 +1,330 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftutil.c                                                               */
+/*                                                                         */
+/*    FreeType utility file for memory and list management (body).         */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_LIST_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_memory
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                                                               *****/
+  /*****               M E M O R Y   M A N A G E M E N T               *****/
+  /*****                                                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* documentation is in ftmemory.h */
+
+  FT_BASE_DEF( FT_Error )
+  FT_Alloc( FT_Memory  memory,
+            FT_Long    size,
+            void*     *P )
+  {
+    FT_ASSERT( P != 0 );
+
+    if ( size > 0 )
+    {
+      *P = memory->alloc( memory, size );
+      if ( !*P )
+      {
+        FT_ERROR(( "FT_Alloc:" ));
+        FT_ERROR(( " Out of memory? (%ld requested)\n",
+                   size ));
+
+        return FT_Err_Out_Of_Memory;
+      }
+      FT_MEM_ZERO( *P, size );
+    }
+    else
+      *P = NULL;
+
+    FT_TRACE7(( "FT_Alloc:" ));
+    FT_TRACE7(( " size = %ld, block = 0x%08p, ref = 0x%08p\n",
+                size, *P, P ));
+
+    return FT_Err_Ok;
+  }
+
+
+  /* documentation is in ftmemory.h */
+
+  FT_BASE_DEF( FT_Error )
+  FT_Realloc( FT_Memory  memory,
+              FT_Long    current,
+              FT_Long    size,
+              void**     P )
+  {
+    void*  Q;
+
+
+    FT_ASSERT( P != 0 );
+
+    /* if the original pointer is NULL, call FT_Alloc() */
+    if ( !*P )
+      return FT_Alloc( memory, size, P );
+
+    /* if the new block if zero-sized, clear the current one */
+    if ( size <= 0 )
+    {
+      FT_Free( memory, P );
+      return FT_Err_Ok;
+    }
+
+    Q = memory->realloc( memory, current, size, *P );
+    if ( !Q )
+      goto Fail;
+
+    if ( size > current )
+      FT_MEM_ZERO( (char*)Q + current, size - current );
+
+    *P = Q;
+    return FT_Err_Ok;
+
+  Fail:
+    FT_ERROR(( "FT_Realloc:" ));
+    FT_ERROR(( " Failed (current %ld, requested %ld)\n",
+               current, size ));
+    return FT_Err_Out_Of_Memory;
+  }
+
+
+  /* documentation is in ftmemory.h */
+
+  FT_BASE_DEF( void )
+  FT_Free( FT_Memory  memory,
+           void**     P )
+  {
+    FT_TRACE7(( "FT_Free:" ));
+    FT_TRACE7(( " Freeing block 0x%08p, ref 0x%08p\n",
+                P, P ? *P : (void*)0 ));
+
+    if ( P && *P )
+    {
+      memory->free( memory, *P );
+      *P = 0;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                                                               *****/
+  /*****            D O U B L Y   L I N K E D   L I S T S              *****/
+  /*****                                                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_list
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( FT_ListNode )
+  FT_List_Find( FT_List  list,
+                void*    data )
+  {
+    FT_ListNode  cur;
+
+
+    cur = list->head;
+    while ( cur )
+    {
+      if ( cur->data == data )
+        return cur;
+
+      cur = cur->next;
+    }
+
+    return (FT_ListNode)0;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Add( FT_List      list,
+               FT_ListNode  node )
+  {
+    FT_ListNode  before = list->tail;
+
+
+    node->next = 0;
+    node->prev = before;
+
+    if ( before )
+      before->next = node;
+    else
+      list->head = node;
+
+    list->tail = node;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Insert( FT_List      list,
+                  FT_ListNode  node )
+  {
+    FT_ListNode  after = list->head;
+
+
+    node->next = after;
+    node->prev = 0;
+
+    if ( !after )
+      list->tail = node;
+    else
+      after->prev = node;
+
+    list->head = node;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Remove( FT_List      list,
+                  FT_ListNode  node )
+  {
+    FT_ListNode  before, after;
+
+
+    before = node->prev;
+    after  = node->next;
+
+    if ( before )
+      before->next = after;
+    else
+      list->head = after;
+
+    if ( after )
+      after->prev = before;
+    else
+      list->tail = before;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Up( FT_List      list,
+              FT_ListNode  node )
+  {
+    FT_ListNode  before, after;
+
+
+    before = node->prev;
+    after  = node->next;
+
+    /* check whether we are already on top of the list */
+    if ( !before )
+      return;
+
+    before->next = after;
+
+    if ( after )
+      after->prev = before;
+    else
+      list->tail = before;
+
+    node->prev       = 0;
+    node->next       = list->head;
+    list->head->prev = node;
+    list->head       = node;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_List_Iterate( FT_List            list,
+                   FT_List_Iterator   iterator,
+                   void*              user )
+  {
+    FT_ListNode  cur   = list->head;
+    FT_Error     error = FT_Err_Ok;
+
+
+    while ( cur )
+    {
+      FT_ListNode  next = cur->next;
+
+
+      error = iterator( cur, user );
+      if ( error )
+        break;
+
+      cur = next;
+    }
+
+    return error;
+  }
+
+
+  /* documentation is in ftlist.h */
+
+  FT_EXPORT_DEF( void )
+  FT_List_Finalize( FT_List             list,
+                    FT_List_Destructor  destroy,
+                    FT_Memory           memory,
+                    void*               user )
+  {
+    FT_ListNode  cur;
+
+
+    cur = list->head;
+    while ( cur )
+    {
+      FT_ListNode  next = cur->next;
+      void*        data = cur->data;
+
+
+      if ( destroy )
+        destroy( memory, data, user );
+
+      FT_FREE( cur );
+      cur = next;
+    }
+
+    list->head = 0;
+    list->tail = 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ftxf86.c
@@ -1,0 +1,80 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftxf86.c                                                               */
+/*                                                                         */
+/*    FreeType utility file for X11 support (body).                        */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_XFREE86_H
+#include FT_INTERNAL_OBJECTS_H
+
+  /* XXX: This really is a sad hack, but I didn't want to change every     */
+  /*      driver just to support this at the moment, since other important */
+  /*      changes are coming anyway.                                       */
+
+  typedef struct  FT_FontFormatRec_
+  {
+    const char*  driver_name;
+    const char*  format_name;
+
+  } FT_FontFormatRec;
+
+
+  FT_EXPORT_DEF( const char* )
+  FT_Get_X11_Font_Format( FT_Face  face )
+  {
+    static const FT_FontFormatRec  font_formats[] =
+    {
+      { "type1",    "Type 1" },
+      { "truetype", "TrueType" },
+      { "bdf",      "BDF" },
+      { "pcf",      "PCF" },
+      { "type42",   "Type 42" },
+      { "cidtype1", "CID Type 1" },
+      { "cff",      "CFF" },
+      { "pfr",      "PFR" },
+      { "winfonts",   "Windows FNT" }
+    };
+
+    const char*  result = NULL;
+
+
+    if ( face && face->driver )
+    {
+      FT_Module  driver = (FT_Module)face->driver;
+
+
+      if ( driver->clazz && driver->clazz->module_name )
+      {
+        FT_Int  n;
+        FT_Int  count = sizeof( font_formats ) / sizeof ( font_formats[0] );
+
+
+        result = driver->clazz->module_name;
+
+        for ( n = 0; n < count; n++ )
+          if ( ft_strcmp( result, font_formats[n].driver_name ) == 0 )
+          {
+            result = font_formats[n].format_name;
+            break;
+          }
+      }
+    }
+
+    return result;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/infblock.c
@@ -1,0 +1,383 @@
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+local void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (c != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens);
+  if (s->mode == CODES)
+    inflate_codes_free(s->sub.decode.codes, z);
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0);
+  Tracev((stderr, "inflate:   blocks reset\n"));
+}
+
+
+local inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->hufts =
+       (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL)
+  {
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s->hufts);
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Tracev((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, Z_NULL);
+  return s;
+}
+
+
+local int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Tracev((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Tracev((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td, z);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BAD;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = BAD;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BAD;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, s->hufts, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR)
+        {
+          ZFREE(z, s->sub.trees.blens);
+          s->mode = BAD;
+        }
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->bits;
+        c = h->base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BAD;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td,
+                                  s->hufts, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR)
+          {
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BAD;
+          }
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok\n"));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+        s->sub.decode.codes = c;
+      }
+      ZFREE(z, s->sub.trees.blens);
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONE;
+    case DONE:
+      r = Z_STREAM_END;
+      LEAVE
+    case BAD:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+local int inflate_blocks_free(s, z)
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_blocks_reset(s, z, Z_NULL);
+  ZFREE(z, s->window);
+  ZFREE(z, s->hufts);
+  ZFREE(z, s);
+  Tracev((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+
--- /dev/null
+++ b/libfreetype/infblock.h
@@ -1,0 +1,36 @@
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFBLOCK_H
+#define _INFBLOCK_H
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+local  inflate_blocks_statef * inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+local  int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+local  void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+local  int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+#endif /* _INFBLOCK_H */
--- /dev/null
+++ b/libfreetype/infcodes.c
@@ -1,0 +1,250 @@
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "infblock.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+typedef enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+inflate_codes_mode;
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  inflate_codes_mode mode;      /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+local int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t + t->base;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+      f = q - c->sub.copy.dist;
+      while (f < s->window)             /* modulo window size-"while" instead */
+        f += s->end - s->window;        /* of "if" handles invalid distances */
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      if (k > 7)        /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;            /* can always return one */
+      }
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
+
+local void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+  ZFREE(z, c);
+  Tracev((stderr, "inflate:       codes free\n"));
+}
--- /dev/null
+++ b/libfreetype/infcodes.h
@@ -1,0 +1,31 @@
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFCODES_H
+#define _INFCODES_H
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+local inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+local int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+local void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
+#endif /* _INFCODES_H */
--- /dev/null
+++ b/libfreetype/inffixed.h
@@ -1,0 +1,151 @@
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by the maketree.c program
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+local uInt fixed_bl = 9;
+local uInt fixed_bd = 5;
+local inflate_huft fixed_tl[] = {
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254},
+    {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115},
+    {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193},
+    {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161},
+    {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225},
+    {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145},
+    {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209},
+    {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177},
+    {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241},
+    {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227},
+    {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201},
+    {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169},
+    {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233},
+    {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153},
+    {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217},
+    {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185},
+    {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249},
+    {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163},
+    {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197},
+    {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165},
+    {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229},
+    {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149},
+    {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213},
+    {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181},
+    {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245},
+    {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205},
+    {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173},
+    {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237},
+    {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157},
+    {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221},
+    {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189},
+    {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253},
+    {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131},
+    {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195},
+    {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163},
+    {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227},
+    {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147},
+    {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211},
+    {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179},
+    {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243},
+    {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258},
+    {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203},
+    {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171},
+    {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235},
+    {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155},
+    {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219},
+    {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187},
+    {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251},
+    {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195},
+    {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199},
+    {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167},
+    {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231},
+    {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151},
+    {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215},
+    {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183},
+    {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247},
+    {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0},
+    {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207},
+    {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175},
+    {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239},
+    {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159},
+    {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223},
+    {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191},
+    {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255}
+  };
+local inflate_huft fixed_td[] = {
+    {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097},
+    {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385},
+    {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193},
+    {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577},
+    {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145},
+    {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577},
+    {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289},
+    {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577}
+  };
--- /dev/null
+++ b/libfreetype/inflate.c
@@ -1,0 +1,273 @@
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+
+#define  DONE  INFLATE_DONE
+#define  BAD   INFLATE_BAD
+
+typedef enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+inflate_mode;
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  inflate_mode  mode;   /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int ZEXPORT inflateReset(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, Z_NULL);
+  Tracev((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateEnd(z)
+z_streamp z;
+{
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z);
+  ZFREE(z, z->state);
+  z->state = Z_NULL;
+  Tracev((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int ZEXPORT inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream))
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+  if (z->zalloc == Z_NULL)
+  {
+    z->zalloc = zcalloc;
+    z->opaque = (voidpf)0;
+  }
+  if (z->zfree == Z_NULL) z->zfree = zcfree;
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Tracev((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+
+#undef  NEEDBYTE
+#define NEEDBYTE {if(z->avail_in==0)return r;r=f;}
+
+#undef  NEXTBYTE
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+
+int ZEXPORT inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL)
+    return Z_STREAM_ERROR;
+  f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib header ok\n"));
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+        break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r == Z_OK)
+        r = f;
+      if (r != Z_STREAM_END)
+        return r;
+      r = f;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Tracev((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+#ifdef NEED_DUMMY_RETURN
+  return Z_STREAM_ERROR;  /* Some dumb compilers complain without this */
+#endif
+}
+
--- /dev/null
+++ b/libfreetype/inftrees.c
@@ -1,0 +1,453 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#if !defined(BUILDFIXED) && !defined(STDC)
+#  define BUILDFIXED   /* non ANSI compilers may not accept inffixed.h */
+#endif
+
+local const char inflate_copyright[] =
+   " inflate 1.1.4 Copyright 1995-2002 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    inflate_huft *,     /* space for trees */
+    uInt *,             /* hufts used in space */
+    uIntf * ));         /* space for values */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+
+local int huft_build(b, n, s, d, e, t, m, hp, hn, v)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= 288) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+inflate_huft *hp;       /* space for trees */
+uInt *hn;               /* hufts used in space */
+uIntf *v;               /* working area: values in order of bit length */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), or Z_DATA_ERROR if the input is invalid. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  uInt mask;                    /* (1 << w) - 1, to avoid cc -O bug on HP */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                     /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? (uInt)l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate new table */
+        if (*hn + z > MANY)     /* (note: doesn't matter for fixed) */
+          return Z_DATA_ERROR;  /* overflow of MANY */
+        u[h] = q = hp + *hn;
+        *hn += z;
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          j = i >> (w - l);
+          r.base = (uInt)(q - u[h-1] - j);   /* offset to this table */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+        else
+          *t = q;               /* first table is returned result */
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      mask = (1 << w) - 1;      /* needed on HP, cc -O bug */
+      while ((i & mask) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+        mask = (1 << w) - 1;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+local int inflate_trees_bits(c, bb, tb, hp, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  if ((v = (uIntf*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL)
+    return Z_MEM_ERROR;
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL,
+                 tb, bb, hp, &hn, v);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  ZFREE(z, v);
+  return r;
+}
+
+
+local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+inflate_huft *hp;       /* space for trees */
+z_streamp z;            /* for messages */
+{
+  int r;
+  uInt hn = 0;          /* hufts used in space */
+  uIntf *v;             /* work area for huft_build */
+
+  /* allocate work area */
+  if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+    return Z_MEM_ERROR;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    ZFREE(z, v);
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    ZFREE(z, v);
+    return r;
+#endif
+  }
+
+  /* done */
+  ZFREE(z, v);
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+#ifdef BUILDFIXED
+local int fixed_built = 0;
+#define FIXEDH 544      /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+#else
+#include "inffixed.h"
+#endif
+
+
+local int inflate_trees_fixed(bl, bd, tl, td, z)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+z_streamp z;             /* for memory allocation */
+{
+#ifdef BUILDFIXED
+  /* build fixed tables if not already */
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    uInt f = 0;         /* number of hufts used in fixed_mem */
+    uIntf *c;           /* length list for huft_build */
+    uIntf *v;           /* work area for huft_build */
+
+    /* allocate memory */
+    if ((c = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+      return Z_MEM_ERROR;
+    if ((v = (uIntf*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL)
+    {
+      ZFREE(z, c);
+      return Z_MEM_ERROR;
+    }
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 9;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl,
+               fixed_mem, &f, v);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd,
+               fixed_mem, &f, v);
+
+    /* done */
+    ZFREE(z, v);
+    ZFREE(z, c);
+    fixed_built = 1;
+  }
+#endif
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
--- /dev/null
+++ b/libfreetype/inftrees.h
@@ -1,0 +1,63 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+#ifndef _INFTREES_H
+#define _INFTREES_H
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    uInt pad;           /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit int's) */
+  uInt base;            /* literal, length base, distance base,
+                           or table offset */
+};
+
+/* Maximum size of dynamic tree.  The maximum found in a long but non-
+   exhaustive search was 1004 huft structures (850 for length/literals
+   and 154 for distances, the latter actually the result of an
+   exhaustive search).  The actual maximum is not known, but the
+   value below is more than safe. */
+#define MANY 1440
+
+local  int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+local  int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    inflate_huft *,             /* space for trees */
+    z_streamp));                /* for messages */
+
+local  int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp));                /* for memory allocation */
+
+#endif /* _INFTREES_H */
--- /dev/null
+++ b/libfreetype/infutil.c
@@ -1,0 +1,86 @@
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infblock.h"
+#include "inftrees.h"
+#include "infcodes.h"
+#include "infutil.h"
+
+
+/* And'ing with mask[n] masks the lower n bits */
+local uInt inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  zmemcpy(p, q, n);
+  p += n;
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    zmemcpy(p, q, n);
+    p += n;
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
--- /dev/null
+++ b/libfreetype/infutil.h
@@ -1,0 +1,96 @@
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-2002 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONE,     /* finished last block, done */
+      BAD}      /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_codes_statef
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  inflate_huft *hufts;  /* single malloc for tree space */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+local uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+local int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+#endif
--- /dev/null
+++ b/libfreetype/mkfile
@@ -1,0 +1,49 @@
+<../mkconfig
+
+LIB=libfreetype.a
+
+OFILES=\
+	freetype.$O\
+	autohint.$O\
+	ftbase.$O\
+	ftglyph.$O\
+	cff.$O\
+	psaux.$O\
+	psnames.$O\
+	raster.$O\
+	sfnt.$O\
+	smooth.$O\
+	truetype.$O\
+	type1.$O\
+	type42.$O\
+	ftsystem_inf.$O\
+	ftinit.$O\
+	pshinter.$O\
+	pfr.$O\
+
+# optional modules - see include/freetype/config/ftmodule.h
+#	type1cid.$O\
+#	winfnt.$O\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+CFLAGS= $ANSICPP $CFLAGS -I$ROOT/include/freetype -I.
+
+freetype.$O:	$ROOT/include/freetype.h
+
+# FreeType is organised by #include of .c files
+# here are the necessary depenencies
+
+autohint.$O:	ahangles.c ahglyph.c ahglobal.c ahhint.c ahmodule.c
+ftbase.$O:	ftutil.c ftdbgmem.c ftstream.c ftcalc.c fttrigon.c ftoutln.c ftgloadr.c ftobjs.c ftnames.c
+cff.$O:	cffdrivr.c cffparse.c cffload.c cffobjs.c cffgload.c cffcmap.c
+psaux.$O:	psobjs.c psauxmod.c t1decode.c t1cmap.c
+psnames.$O:	psmodule.c
+raster.$O:	ftraster.c ftrend1.c
+sfnt.$O:	ttload.c ttcmap.c ttcmap0.c sfobjs.c sfdriver.c
+smooth.$O:	ftgrays.c ftsmooth.c
+truetype.$O:	ttdriver.c ttpload.c ttgload.c ttobjs.c
+type1.$O:	t1parse.c t1load.c t1objs.c t1driver.c t1gload.c
+type42.$O:	t42objs.c t42parse.c t42drivr.c
+pshinter.$O:	pshrec.c pshglob.c pshalgo1.c pshalgo2.c pshalgo3.c pshmod.c
+pfr.$O:	pfrload.c pfrgload.c pfrcmap.c pfrobjs.c pfrdrivr.c pfrsbit.c
--- /dev/null
+++ b/libfreetype/otlayout.h
@@ -1,0 +1,205 @@
+#ifndef __OT_LAYOUT_H__
+#define __OT_LAYOUT_H__
+
+
+#include "otlconf.h"
+
+OTL_BEGIN_HEADER
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                       BASE DATA TYPES                        *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  typedef unsigned char     OTL_Byte;
+  typedef const OTL_Byte*   OTL_Bytes;
+
+  typedef int               OTL_Error;
+
+  typedef void*             OTL_Pointer;
+
+  typedef int               OTL_Int;
+  typedef unsigned int      OTL_UInt;
+
+  typedef long              OTL_Long;
+  typedef unsigned long     OTL_ULong;
+
+  typedef short             OTL_Int16;
+  typedef unsigned short    OTL_UInt16;
+
+
+#if OTL_SIZEOF_INT == 4
+
+  typedef int               OTL_Int32;
+  typedef unsigned int      OTL_UInt32;
+
+#elif OTL_SIZEOF_LONG == 4
+
+  typedef long              OTL_Int32;
+  typedef unsigned long     OTL_UInt32;
+
+#else
+#  error "no 32-bits type found"
+#endif
+
+  typedef OTL_UInt32        OTL_Tag;
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                       ERROR CODES                            *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  typedef enum
+  {
+    OTL_Err_Ok = 0,
+    OTL_Err_InvalidArgument,
+    OTL_Err_InvalidFormat,
+    OTL_Err_InvalidOffset,
+
+    OTL_Err_Max
+
+  } OTL_Error;
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                     MEMORY MANAGEMENT                        *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  typedef OTL_Pointer  (*OTL_AllocFunc)( OTL_ULong    size,
+                                         OTL_Pointer  data );
+
+  typedef OTL_Pointer  (*OTL_ReallocFunc)( OTL_Pointer   block,
+                                           OTL_ULong     size,
+                                           OTL_Pointer   data );
+
+  typedef void         (*OTL_FreeFunc)( OTL_Pointer  block,
+                                        OTL_Pointer  data );
+
+  typedef struct OTL_MemoryRec_
+  {
+    OTL_Pointer      mem_data;
+    OTL_AllocFunc    mem_alloc;
+    OTL_ReallocFunc  mem_realloc;
+    OTL_FreeFunc     mem_free;
+
+  } OTL_MemoryRec, *OTL_Memory;
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                        ENUMERATIONS                          *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+/* re-define OTL_MAKE_TAG to something different if you're not */
+/* using an ASCII-based character set (Vaxes anyone ?)         */
+#ifndef  OTL_MAKE_TAG
+#define  OTL_MAKE_TAG(c1,c2,c3,c4)         \
+           ( ( (OTL_UInt32)(c1) << 24 ) |  \
+               (OTL_UInt32)(c2) << 16 ) |  \
+               (OTL_UInt32)(c3) <<  8 ) |  \
+               (OTL_UInt32)(c4)         )
+#endif
+
+  typedef enum OTL_ScriptTag_
+  {
+    OTL_SCRIPT_NONE = 0,
+
+#define OTL_SCRIPT_TAG(c1,c2,c3,c4,s,n)  OTL_SCRIPT_TAG_ ## n = OTL_MAKE_TAG(c1,c2,c3,c4),
+#include "otltags.h"
+
+    OTL_SCRIPT_MAX
+
+  } OTL_ScriptTag;
+
+
+  typedef enum OTL_LangTag_
+  {
+    OTL_LANG_DEFAULT = 0,
+
+#define OTL_LANG_TAG(c1,c2,c3,c4,s,n)  OTL_LANG_TAG_ ## n = OTL_MAKE_TAG(c1,c2,c3,c4),
+#include "otltags.h"
+
+    OTL_LANG_MAX
+
+  } OTL_LangTag;
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                       MEMORY READS                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#define  OTL_PEEK_USHORT(p)  ( ((OTL_UInt)((p)[0]) << 8) |  \
+                               ((OTL_UInt)((p)[1])     ) )
+
+#define  OTL_PEEK_ULONG(p)   ( ((OTL_UInt32)((p)[0]) << 24) |  \
+                               ((OTL_UInt32)((p)[1]) << 16) |  \
+                               ((OTL_UInt32)((p)[2]) <<  8) |  \
+                               ((OTL_UInt32)((p)[3])      ) )
+
+#define  OTL_PEEK_SHORT(p)     ((OTL_Int16)OTL_PEEK_USHORT(p))
+
+#define  OTL_PEEK_LONG(p)      ((OTL_Int32)OTL_PEEK_ULONG(p))
+
+#define  OTL_NEXT_USHORT(p)  ( (p) += 2, OTL_PEEK_USHORT((p)-2) )
+#define  OTL_NEXT_ULONG(p)   ( (p) += 4, OTL_PEEK_ULONG((p)-4) )
+
+#define  OTL_NEXT_SHORT(p)   ((OTL_Int16)OTL_NEXT_USHORT(p))
+#define  OTL_NEXT_LONG(p)    ((OTL_Int32)OTL_NEXT_ULONG(p))
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                        VALIDATION                            *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  typedef struct OTL_ValidatorRec_*  OTL_Validator;
+
+  typedef struct OTL_ValidatorRec_
+  {
+    OTL_Bytes    limit;
+    OTL_Bytes    base;
+    OTL_Error    error;
+    OTL_jmp_buf  jump_buffer;
+
+  } OTL_ValidatorRec;
+
+  typedef void  (*OTL_ValidateFunc)( OTL_Bytes  table,
+                                     OTL_Valid  valid );
+
+  OTL_API( void )
+  otl_validator_error( OTL_Validator  validator,
+                       OTL_Error      error );
+
+#define  OTL_INVALID(e)  otl_validator_error( valid, e )
+
+#define  OTL_INVALID_TOO_SHORT  OTL_INVALID( OTL_Err_InvalidOffset )
+#define  OTL_INVALID_DATA       OTL_INVALID( OTL_Err_InvalidFormat )
+
+#define  OTL_CHECK(_count)   OTL_BEGIN_STMNT                       \
+                               if ( p + (_count) > valid->limit )  \
+                                 OTL_INVALID_TOO_SHORT;            \
+                             OTL_END_STMNT
+
+ /* */
+
+OTL_END_HEADER
+
+#endif /* __OPENTYPE_LAYOUT_H__ */
--- /dev/null
+++ b/libfreetype/otlbase.c
@@ -1,0 +1,181 @@
+#include "otlbase.h"
+#include "otlcommn.h"
+
+  static void
+  otl_base_coord_validate( OTL_Bytes      table,
+                           OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 4 );
+
+    format = OTL_NEXT_USHORT( p );
+    p += 2;
+
+    switch ( format )
+    {
+      case 1:
+        break;
+
+      case 2:
+        OTL_CHECK( 4 );
+        break;
+
+      case 3:
+        OTL_CHECK( 2 );
+        otl_device_table_validate( table + OTL_PEEK_USHORT( p ) );
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+  static void
+  otl_base_tag_list_validate( OTL_Bytes      table,
+                              OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK(2);
+
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( count*4 );
+  }
+
+
+
+  static void
+  otl_base_values_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 4 );
+
+    p    += 2;  /* skip default index */
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*2 );
+
+    for ( ; count > 0; count-- )
+      otl_base_coord_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_base_minmax_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   min_coord, max_coord, count;
+
+    OTL_CHECK(6);
+    min_coord = OTL_NEXT_USHORT( p );
+    max_coord = OTL_NEXT_USHORT( p );
+    count     = OTL_NEXT_USHORT( p );
+
+    if ( min_coord )
+      otl_base_coord_validate( table + min_coord, valid );
+
+    if ( max_coord )
+      otl_base_coord_validate( table + max_coord, valid );
+
+    OTL_CHECK( count*8 );
+    for ( ; count > 0; count-- )
+    {
+      p += 4;  /* ignore tag */
+      min_coord = OTL_NEXT_USHORT( p );
+      max_coord = OTL_NEXT_USHORT( p );
+
+      if ( min_coord )
+        otl_base_coord_validate( table + min_coord, valid );
+
+      if ( max_coord )
+        otl_base_coord_validate( table + max_coord, valid );
+    }
+  }
+
+
+  static void
+  otl_base_script_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   values, default_minmax;
+
+    OTL_CHECK(6);
+
+    values         = OTL_NEXT_USHORT( p );
+    default_minmax = OTL_NEXT_USHORT( p );
+    count          = OTL_NEXT_USHORT( p );
+
+    if ( values )
+      otl_base_values_validate( table + values, valid );
+
+    if ( default_minmax )
+      otl_base_minmax_validate( table + default_minmax, valid );
+
+    OTL_CHECK( count*6 );
+    for ( ; count > 0; count-- )
+    {
+      p += 4;  /* ignore tag */
+      otl_base_minmax_validate( table + OTL_NEXT_USHORT( p ), valid );
+    }
+  }
+
+
+  static void
+  otl_base_script_list_validate( OTL_Bytes      table,
+                                 OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK(2);
+
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK(count*6);
+
+    for ( ; count > 0; count-- )
+    {
+      p += 4;  /* ignore script tag */
+      otl_base_script_validate( table + OTL_NEXT_USHORT( p ) );
+    }
+  }
+
+  static void
+  otl_axis_table_validate( OTL_Bytes      table,
+                           OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   tags;
+
+    OTL_CHECK(4);
+
+    tags = OTL_NEXT_USHORT( p );
+    if ( tags )
+      otl_base_tag_list_validate   ( table + tags );
+
+    otl_base_script_list_validate( table + OTL_NEXT_USHORT( p ) );
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_base_validate( OTL_Bytes      table,
+                     OTL_Validator  valid )
+  {
+    OTL_Bytes p = table;
+
+    OTL_CHECK(6);
+
+    if ( OTL_NEXT_ULONG( p ) != 0x10000UL )
+      OTL_INVALID_DATA;
+
+    otl_axis_table_validate( table + OTL_NEXT_USHORT( p ) );
+    otl_axis_table_validate( table + OTL_NEXT_USHORT( p ) );
+  }
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otlbase.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_BASE_H__
+#define __OTL_BASE_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+  OTL_LOCAL( void )
+  otl_base_validate( OTL_Bytes      table,
+                     OTL_Validator  valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_BASE_H__ */
--- /dev/null
+++ b/libfreetype/otlcommn.c
@@ -1,0 +1,940 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otlcommn.c                                                             */
+/*                                                                         */
+/*    OpenType layout support, common tables (body).                       */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "otlayout.h"
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                       COVERAGE TABLE                          *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_coverage_validate( OTL_Bytes      table,
+                         OTL_Validator  valid )
+  {
+    OTL_Bytes  p;
+    OTL_UInt   format;
+
+
+    if ( table + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+    case 1:
+      {
+        OTL_UInt  count = OTL_NEXT_USHORT( p );
+
+
+        if ( p + count * 2 >= valid->limit )
+          OTL_INVALID_TOO_SHORT;
+
+        /* XXX: check glyph indices */
+      }
+      break;
+
+    case 2:
+      {
+        OTL_UInt  n, num_ranges = OTL_NEXT_USHORT( p );
+        OTL_UInt  start, end, start_cover, total = 0, last = 0;
+
+
+        if ( p + num_ranges * 6 >= valid->limit )
+          OTL_INVALID_TOO_SHORT;
+
+        for ( n = 0; n < num_ranges; n++ )
+        {
+          start       = OTL_NEXT_USHORT( p );
+          end         = OTL_NEXT_USHORT( p );
+          start_cover = OTL_NEXT_USHORT( p );
+
+          if ( start > end || start_cover != total )
+            OTL_INVALID_DATA;
+
+          if ( n > 0 && start <= last )
+            OTL_INVALID_DATA;
+
+          total += end - start + 1;
+          last   = end;
+        }
+      }
+      break;
+
+    default:
+      OTL_INVALID_FORMAT;
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_coverage_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p      = table;
+    OTL_UInt   format = OTL_NEXT_USHORT( p );
+    OTL_UInt   count  = OTL_NEXT_USHORT( p );
+    OTL_UInt   result = 0;
+
+
+    switch ( format )
+    {
+    case 1:
+      return count;
+
+    case 2:
+      {
+        OTL_UInt  start, end;
+
+
+        for ( ; count > 0; count-- )
+        {
+          start = OTL_NEXT_USHORT( p );
+          end   = OTL_NEXT_USHORT( p );
+          p    += 2;                    /* skip start_index */
+
+          result += end - start + 1;
+        }
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    return result;
+  }
+
+
+  OTL_LOCALDEF( OTL_Int )
+  otl_coverage_get_index( OTL_Bytes  table,
+                          OTL_UInt   glyph_index )
+  {
+    OTL_Bytes  p      = table;
+    OTL_UInt   format = OTL_NEXT_USHORT( p );
+    OTL_UInt   count  = OTL_NEXT_USHORT( p );
+
+
+    switch ( format )
+    {
+    case 1:
+      {
+        OTL_UInt  min = 0, max = count, mid, gindex;
+
+
+        table += 4;
+        while ( min < max )
+        {
+          mid    = ( min + max ) >> 1;
+          p      = table + 2 * mid;
+          gindex = OTL_PEEK_USHORT( p );
+
+          if ( glyph_index == gindex )
+            return (OTL_Int)mid;
+
+          if ( glyph_index < gindex )
+            max = mid;
+          else
+            min = mid + 1;
+        }
+      }
+      break;
+
+    case 2:
+      {
+        OTL_UInt  min = 0, max = count, mid;
+        OTL_UInt  start, end, delta, start_cover;
+
+
+        table += 4;
+        while ( min < max )
+        {
+          mid    = ( min + max ) >> 1;
+          p      = table + 6 * mid;
+          start  = OTL_NEXT_USHORT( p );
+          end    = OTL_NEXT_USHORT( p );
+
+          if ( glyph_index < start )
+            max = mid;
+          else if ( glyph_index > end )
+            min = mid + 1;
+          else
+            return (OTL_Int)( glyph_index + OTL_NEXT_USHORT( p ) - start );
+        }
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    return -1;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  CLASS DEFINITION TABLE                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_class_definition_validate( OTL_Bytes      table,
+                                 OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+
+    if ( p + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+    case 1:
+      {
+        OTL_UInt  count, start = OTL_NEXT_USHORT( p );
+
+
+        if ( p + 2 > valid->limit )
+          OTL_INVALID_TOO_SHORT;
+
+        count = OTL_NEXT_USHORT( p );
+
+        if ( p + count * 2 > valid->limit )
+          OTL_INVALID_TOO_SHORT;
+
+        /* XXX: check glyph indices */
+      }
+      break;
+
+    case 2:
+      {
+        OTL_UInt  n, num_ranges = OTL_NEXT_USHORT( p );
+        OTL_UInt  start, end, value, last = 0;
+
+
+        if ( p + num_ranges * 6 > valid->limit )
+          OTL_INVALID_TOO_SHORT;
+
+        for ( n = 0; n < num_ranges; n++ )
+        {
+          start = OTL_NEXT_USHORT( p );
+          end   = OTL_NEXT_USHORT( p );
+          value = OTL_NEXT_USHORT( p );  /* ignored */
+
+          if ( start > end || ( n > 0 && start <= last ) )
+            OTL_INVALID_DATA;
+
+          last = end;
+        }
+      }
+      break;
+
+    default:
+      OTL_INVALID_FORMAT;
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_class_definition_get_value( OTL_Bytes  table,
+                                  OTL_UInt   glyph_index )
+  {
+    OTL_Bytes  p      = table;
+    OTL_UInt   format = OTL_NEXT_USHORT( p );
+
+
+    switch ( format )
+    {
+    case 1:
+      {
+        OTL_UInt  start = OTL_NEXT_USHORT( p );
+        OTL_UInt  count = OTL_NEXT_USHORT( p );
+        OTL_UInt  idx   = (OTL_UInt)( glyph_index - start );
+
+
+        if ( idx < count )
+        {
+          p += 2 * idx;
+          return OTL_PEEK_USHORT( p );
+        }
+      }
+      break;
+
+    case 2:
+      {
+        OTL_UInt  count = OTL_NEXT_USHORT( p );
+        OTL_UInt  min = 0, max = count, mid, gindex;
+
+
+        table += 4;
+        while ( min < max )
+        {
+          mid   = ( min + max ) >> 1;
+          p     = table + 6 * mid;
+          start = OTL_NEXT_USHORT( p );
+          end   = OTL_NEXT_USHORT( p );
+
+          if ( glyph_index < start )
+            max = mid;
+          else if ( glyph_index > end )
+            min = mid + 1;
+          else
+            return OTL_PEEK_USHORT( p );
+        }
+      }
+      break;
+
+    default:
+      ;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      DEVICE TABLE                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_device_table_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   start, end, count, format, count;
+
+
+    if ( p + 8 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    start  = OTL_NEXT_USHORT( p );
+    end    = OTL_NEXT_USHORT( p );
+    format = OTL_NEXT_USHORT( p );
+
+    if ( format < 1 || format > 3 || end < start )
+      OTL_INVALID_DATA;
+
+    count = (OTL_UInt)( end - start + 1 );
+
+    if ( p + ( ( 1 << format ) * count ) / 8 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_start( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_end( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table + 2;
+
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_Int )
+  otl_device_table_get_delta( OTL_Bytes  table,
+                              OTL_UInt   size )
+  {
+    OTL_Bytes  p = table;
+    OTL_Int    result = 0;
+    OTL_UInt   start, end, format, idx, value;
+
+
+    start  = OTL_NEXT_USHORT( p );
+    end    = OTL_NEXT_USHORT( p );
+    format = OTL_NEXT_USHORT( p );
+
+    if ( size >= start && size <= end )
+    {
+      /* we could do that with clever bit operations, but a switch is */
+      /* much simpler to understand and maintain                      */
+      /*                                                              */
+      switch ( format )
+      {
+      case 1:
+        idx    = (OTL_UInt)( ( size - start ) * 2 );
+        p     += idx / 16;
+        value  = OTL_PEEK_USHORT( p );
+        shift  = idx & 15;
+        result = (OTL_Short)( value << shift ) >> ( 14 - shift );
+
+        break;
+
+      case 2:
+        idx    = (OTL_UInt)( ( size - start ) * 4 );
+        p     += idx / 16;
+        value  = OTL_PEEK_USHORT( p );
+        shift  = idx & 15;
+        result = (OTL_Short)( value << shift ) >> ( 12 - shift );
+
+        break;
+
+      case 3:
+        idx    = (OTL_UInt)( ( size - start ) * 8 );
+        p     += idx / 16;
+        value  = OTL_PEEK_USHORT( p );
+        shift  = idx & 15;
+        result = (OTL_Short)( value << shift ) >> ( 8 - shift );
+
+        break;
+
+      default:
+        ;
+      }
+    }
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      LOOKUP LISTS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_lookup_validate( OTL_Bytes      table,
+                       OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   num_tables;
+
+
+    if ( table + 6 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    p += 4;
+    num_tables = OTL_NEXT_USHORT( p );
+
+    if ( p + num_tables * 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_tables > 0; num_tables-- )
+    {
+      offset = OTL_NEXT_USHORT( p );
+
+      if ( table + offset >= valid->limit )
+        OTL_INVALID_OFFSET;
+    }
+
+    /* XXX: check sub-tables? */
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table + 4;
+
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_get_table( OTL_Bytes  table,
+                        OTL_UInt   idx )
+  {
+    OTL_Bytes  p, result = NULL;
+    OTL_UInt   count;
+
+
+    p     = table + 4;
+    count = OTL_NEXT_USHORT( p );
+    if ( idx < count )
+    {
+      p     += idx * 2;
+      result = table + OTL_PEEK_USHORT( p );
+    }
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      LOOKUP LISTS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_lookup_list_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table, q;
+    OTL_UInt   num_lookups, offset;
+
+
+    if ( p + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    num_lookups = OTL_NEXT_USHORT( p );
+
+    if ( p + num_lookups * 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_lookups > 0; num_lookups-- )
+    {
+      offset = OTL_NEXT_USHORT( p );
+
+      otl_lookup_validate( table + offset, valid );
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_list_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_lookup( OTL_Bytes  table,
+                              OTL_UInt   idx )
+  {
+    OTL_Bytes  p, result = 0;
+    OTL_UInt   count;
+
+
+    p     = table;
+    count = OTL_NEXT_USHORT( p );
+    if ( idx < count )
+    {
+      p     += idx * 2;
+      result = table + OTL_PEEK_USHORT( p );
+    }
+
+    return result;
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_table( OTL_Bytes  table,
+                             OTL_UInt   lookup_index,
+                             OTL_UInt   table_index )
+  {
+    OTL_Bytes  result = NULL;
+
+
+    result = otl_lookup_list_get_lookup( table, lookup_index );
+    if ( result )
+      result = otl_lookup_get_table( result, table_index );
+
+    return result;
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_lookup_list_foreach( OTL_Bytes        table,
+                           OTL_ForeachFunc  func,
+                           OTL_Pointer      func_data )
+  {
+    OTL_Bytes  p     = table;
+    OTL_UInt   count = OTL_NEXT_USHORT( p );
+
+
+    for ( ; count > 0; count-- )
+      func( table + OTL_NEXT_USHORT( p ), func_data );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        FEATURES                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_feature_validate( OTL_Bytes      table,
+                        OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   feat_params, num_lookups;
+
+
+    if ( p + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    feat_params = OTL_NEXT_USHORT( p );  /* ignored */
+    num_lookups = OTL_NEXT_USHORT( p );
+
+    if ( p + num_lookups * 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    /* XXX: check lookup indices */
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table + 4;
+
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_lookups( OTL_Bytes  table,
+                           OTL_UInt   start,
+                           OTL_UInt   count,
+                           OTL_UInt  *lookups )
+  {
+    OTL_Bytes  p;
+    OTL_UInt   num_features, result = 0;
+
+
+    p            = table + 4;
+    num_features = OTL_NEXT_USHORT( p );
+
+    p += start * 2;
+
+    for ( ; count > 0 && start < num_features; count--, start++ )
+    {
+      lookups[0] = OTL_NEXT_USHORT(p);
+      lookups++;
+      result++;
+    }
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        FEATURE LIST                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_feature_list_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   num_features, offset;
+
+
+    if ( table + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    num_features = OTL_NEXT_USHORT( p );
+
+    if ( p + num_features * 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_features > 0; num_features-- )
+    {
+      p     += 4;                       /* skip tag */
+      offset = OTL_NEXT_USHORT( p );
+
+      otl_feature_table_validate( table + offset, valid );
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_list_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_feature_list_get_feature( OTL_Bytes  table,
+                                OTL_UInt   idx )
+  {
+    OTL_Bytes  p, result = NULL;
+    OTL_UInt   count;
+
+
+    p     = table;
+    count = OTL_NEXT_USHORT( p );
+
+    if ( idx < count )
+    {
+      p     += idx * 2;
+      result = table + OTL_PEEK_USHORT( p );
+    }
+
+    return result;
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_feature_list_foreach( OTL_Bytes        table,
+                            OTL_ForeachFunc  func,
+                            OTL_Pointer      func_data )
+  {
+    OTL_Bytes  p;
+    OTL_UInt   count;
+
+
+    p = table;
+    count = OTL_NEXT_USHORT( p );
+
+    for ( ; count > 0; count-- )
+      func( table + OTL_NEXT_USHORT( p ), func_data );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       LANGUAGE SYSTEM                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  OTL_LOCALDEF( void )
+  otl_lang_validate( OTL_Bytes      table,
+                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   lookup_order;
+    OTL_UInt   req_feature;
+    OTL_UInt   num_features;
+
+
+    if ( table + 6 >= valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    lookup_order = OTL_NEXT_USHORT( p );
+    req_feature  = OTL_NEXT_USHORT( p );
+    num_features = OTL_NEXT_USHORT( p );
+
+    /* XXX: check req_feature if not 0xFFFFU */
+
+    if ( p + 2 * num_features >= valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    /* XXX: check features indices! */
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lang_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table + 4;
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lang_get_req_feature( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table + 2;
+
+
+    return OTL_PEEK_USHORT( p );
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lang_get_features( OTL_Bytes  table,
+                         OTL_UInt   start,
+                         OTL_UInt   count,
+                         OTL_UInt  *features )
+  {
+    OTL_Bytes  p            = table + 4;
+    OTL_UInt   num_features = OTL_NEXT_USHORT( p );
+    OTL_UInt   result       = 0;
+
+
+    p += start * 2;
+
+    for ( ; count > 0 && start < num_features; start++, count-- )
+    {
+      features[0] = OTL_NEXT_USHORT( p );
+      features++;
+      result++;
+    }
+
+    return result;
+  }
+
+
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           SCRIPTS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  OTL_LOCALDEF( void )
+  otl_script_validate( OTL_Bytes      table,
+                       OTL_Validator  valid )
+  {
+    OTL_UInt   default_lang;
+    OTL_Bytes  p = table;
+
+
+    if ( table + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    default_lang = OTL_NEXT_USHORT( p );
+    num_langs    = OTL_NEXT_USHORT( p );
+
+    if ( default_lang != 0 )
+    {
+      if ( table + default_lang >= valid->limit )
+        OTL_INVALID_OFFSET;
+    }
+
+    if ( p + num_langs * 6 >= valid->limit )
+      OTL_INVALID_OFFSET;
+
+    for ( ; num_langs > 0; num_langs-- )
+    {
+      OTL_UInt  offset;
+
+
+      p     += 4;  /* skip tag */
+      offset = OTL_NEXT_USHORT( p );
+
+      otl_lang_validate( table + offset, valid );
+    }
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_script_list_validate( OTL_Bytes      list,
+                            OTL_Validator  valid )
+  {
+    OTL_UInt   num_scripts;
+    OTL_Bytes  p = list;
+
+
+    if ( list + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    num_scripts = OTL_NEXT_USHORT( p );
+
+    if ( p + num_scripts * 6 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_scripts > 0; num_scripts-- )
+    {
+      OTL_UInt  offset;
+
+
+      p     += 4;                       /* skip tag */
+      offset = OTL_NEXT_USHORT( p );
+
+      otl_script_table_validate( list + offset, valid );
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         LOOKUP LISTS                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  otl_lookup_table_validate( OTL_Bytes          table,
+                             OTL_UInt           type_count,
+                             OTL_ValidateFunc*  type_funcs,
+                             OTL_Validator      valid )
+  {
+    OTL_Bytes         p = table;
+    OTL_UInt          lookup_type, lookup_flag, count;
+    OTL_ValidateFunc  validate;
+
+    OTL_CHECK( 6 );
+    lookup_type = OTL_NEXT_USHORT( p );
+    lookup_flag = OTL_NEXT_USHORT( p );
+    count       = OTL_NEXT_USHORT( p );
+
+    if ( lookup_type == 0 || lookup_type >= type_count )
+      OTL_INVALID_DATA;
+
+    validate = type_funcs[ lookup_type - 1 ];
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_lookup_list_validate( OTL_Bytes          table,
+                            OTL_UInt           type_count,
+                            OTL_ValidateFunc*  type_funcs,
+                            OTL_Validator      valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_lookup_table_validate( table + OTL_NEXT_USHORT( p ),
+                                 type_count, type_funcs, valid );
+  }
+
+/* END */
--- /dev/null
+++ b/libfreetype/otlcommn.h
@@ -1,0 +1,277 @@
+/***************************************************************************/
+/*                                                                         */
+/*  otlcommn.h                                                             */
+/*                                                                         */
+/*    OpenType layout support, common tables (specification).              */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __OTLCOMMN_H__
+#define __OTLCOMMN_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       COVERAGE TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* validate coverage table */
+  OTL_LOCALDEF( void )
+  otl_coverage_validate( OTL_Bytes      base,
+                         OTL_Validator  valid );
+
+  /* return number of covered glyphs */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_coverage_get_count( OTL_Bytes  base );
+
+  /* Return the coverage index corresponding to a glyph glyph index. */
+  /* Return -1 if the glyph isn't covered.                           */
+  OTL_LOCALDEF( OTL_Int )
+  otl_coverage_get_index( OTL_Bytes  base,
+                          OTL_UInt   glyph_index );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  CLASS DEFINITION TABLE                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* validate class definition table */
+  OTL_LOCALDEF( void )
+  otl_class_definition_validate( OTL_Bytes      table,
+                                 OTL_Validator  valid );
+
+  /* return class value for a given glyph index */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_class_definition_get_value( OTL_Bytes  table,
+                                  OTL_UInt   glyph_index );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      DEVICE TABLE                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* validate a device table */
+  OTL_LOCALDEF( void )
+  otl_device_table_validate( OTL_Bytes      table,
+                             OTL_Validator  valid );
+
+  /* return a device table's first size */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_start( OTL_Bytes  table );
+
+  /* return a device table's last size */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_end( OTL_Bytes  table );
+
+  /* return pixel adjustment for a given size */
+  OTL_LOCALDEF( OTL_Int )
+  otl_device_table_get_delta( OTL_Bytes  table,
+                              OTL_UInt   size );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           LOOKUPS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* validate lookup table */
+  OTL_LOCALDEF( void )
+  otl_lookup_validate( OTL_Bytes      table,
+                       OTL_Validator  valid );
+
+  /* return number of sub-tables in a lookup */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_get_count( OTL_Bytes  table );
+
+
+  /* return lookup sub-table */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_get_table( OTL_Bytes  table,
+                        OTL_UInt   idx );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      LOOKUP LISTS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* validate lookup list */
+  OTL_LOCALDEF( void )
+  otl_lookup_list_validate( OTL_Bytes      table,
+                            OTL_Validator  valid );
+
+  /* return number of lookups in list */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_list_get_count( OTL_Bytes  table );
+
+  /* return a given lookup from a list */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_lookup( OTL_Bytes  table,
+                              OTL_UInt   idx );
+
+  /* return lookup sub-table from a list */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_table( OTL_Bytes  table,
+                             OTL_UInt   lookup_index,
+                             OTL_UInt   table_index );
+
+  /* iterate over lookup list */
+  OTL_LOCALDEF( void )
+  otl_lookup_list_foreach( OTL_Bytes        table,
+                           OTL_ForeachFunc  func,
+                           OTL_Pointer      func_data );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        FEATURES                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* validate feature table */
+  OTL_LOCALDEF( void )
+  otl_feature_validate( OTL_Bytes      table,
+                        OTL_Validator  valid );
+
+  /* return feature's lookup count */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_count( OTL_Bytes  table );
+
+  /* get several lookups indices from a feature. returns the number of */
+  /* lookups grabbed                                                   */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_lookups( OTL_Bytes  table,
+                           OTL_UInt   start,
+                           OTL_UInt   count,
+                           OTL_UInt  *lookups );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        FEATURE LIST                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* validate a feature list */
+  OTL_LOCALDEF( void )
+  otl_feature_list_validate( OTL_Bytes      table,
+                             OTL_Validator  valid );
+
+  /* return number of features in list */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_list_get_count( OTL_Bytes  table );
+
+
+  /* return a given feature from a list */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_feature_list_get_feature( OTL_Bytes  table,
+                                OTL_UInt   idx );
+
+  /* iterate over all features in a list */
+  OTL_LOCALDEF( void )
+  otl_feature_list_foreach( OTL_Bytes        table,
+                            OTL_ForeachFunc  func,
+                            OTL_Pointer      func_data );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       LANGUAGE SYSTEM                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCAL( void )
+  otl_lang_validate( OTL_Bytes      table,
+                     OTL_Validator  valid );
+
+
+  OTL_LOCAL( OTL_UInt )
+  otl_lang_get_req_feature( OTL_Bytes  table );
+
+
+  OTL_LOCAL( OTL_UInt )
+  otl_lang_get_count( OTL_Bytes  table );
+
+
+  OTL_LOCAL( OTL_UInt )
+  otl_lang_get_features( OTL_Bytes  table,
+                         OTL_UInt   start,
+                         OTL_UInt   count,
+                         OTL_UInt  *features );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           SCRIPTS                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCAL( void )
+  otl_script_list_validate( OTL_Bytes          list,
+                            OTL_Validator      valid );
+
+  OTL_LOCAL( OTL_Bytes )
+  otl_script_list_get_script( OTL_Bytes  table );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         LOOKUP LISTS                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  OTL_LOCAL( void )
+  otl_lookup_list_validate( OTL_Bytes          list,
+                            OTL_UInt           type_count,
+                            OTL_ValidateFunc*  type_funcs,
+                            OTL_Validator      valid );
+
+ /* */
+
+OTL_END_HEADER
+
+#endif /* __OTLCOMMN_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/otlconf.h
@@ -1,0 +1,78 @@
+#ifndef __OT_LAYOUT_CONFIG_H__
+#define __OT_LAYOUT_CONFIG_H__
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                    CONFIGURATION MACROS                      *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifdef __cplusplus
+#  define OTL_BEGIN_HEADER  extern "C" {
+#else
+#  define OTL_BEGIN_HEADER  /* nothing */
+#endif
+
+#ifdef __cplusplus
+#  define OTL_END_HEADER   }
+#else
+#  define OTL_END_HEADER   /* nothing */
+#endif
+
+#ifndef OTL_API
+#  ifdef __cplusplus
+#    define  OTL_API( x )   extern "C"
+#  else
+#    define  OTL_API( x )   extern x
+#  endif
+#endif
+
+#ifndef OTL_APIDEF
+#  define  OTL_APIDEF( x )  x
+#endif
+
+#ifndef OTL_LOCAL
+#  define OTL_LOCAL( x )   extern x
+#endif
+
+#ifndef OTL_LOCALDEF
+#  define OTL_LOCALDEF( x )  x
+#endif
+
+#define  OTL_BEGIN_STMNT  do {
+#define  OTL_END_STMNT    } while (0)
+#define  OTL_DUMMY_STMNT  OTL_BEGIN_STMNT OTL_END_STMNT
+
+#define  OTL_UNUSED( x )       (x)=(x)
+#define  OTL_UNUSED_CONST(x)   (void)(x)
+
+
+#include <limits.h>
+#if UINT_MAX == 0xFFFFU
+#  define OTL_SIZEOF_INT  2
+#elif UINT_MAX == 0xFFFFFFFFU
+#  define OTL_SIZEOF_INT  4
+#elif UINT_MAX > 0xFFFFFFFFU && UINT_MAX == 0xFFFFFFFFFFFFFFFFU
+#  define OTL_SIZEOF_INT  8
+#else
+#  error  "unsupported number of bytes in 'int' type!"
+#endif
+
+#if ULONG_MAX == 0xFFFFFFFFU
+#  define  OTL_SIZEOF_LONG  4
+#elif ULONG_MAX > 0xFFFFFFFFU && ULONG_MAX == 0xFFFFFFFFFFFFFFFFU
+#  define  OTL_SIZEOF_LONG  8
+#else
+#  error  "unsupported number of bytes in 'long' type!"
+#endif
+
+#include <setjmp.h>
+#define  OTL_jmp_buf   jmp_buf
+#define  otl_setjmp    setjmp
+#define  otl_longjmp   longjmp
+
+/* */
+
+#endif /* __OT_LAYOUT_CONFIG_H__ */
--- /dev/null
+++ b/libfreetype/otlgdef.c
@@ -1,0 +1,175 @@
+#include "otlgdef.h"
+#include "otlcommn.h"
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                      ATTACHMENTS LIST                        *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_attach_point_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    if ( p + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    count = OTL_NEXT_USHORT( p );
+    if ( table + count*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+  }
+
+
+  static void
+  otl_attach_list_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_Bytes  coverage;
+    OTL_UInt   count;
+
+    if ( p + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    coverage = table + OTL_NEXT_USHORT( p );
+    count    = OTL_NEXT_USHORT( p );
+
+    otl_coverage_validate( coverage, valid );
+    if ( count != otl_coverage_get_count( coverage ) )
+      OTL_INVALID_DATA;
+
+    if ( p + count*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; count > 0; count-- )
+      otl_attach_point_validate( table + OTL_NEXT_USHORT( p ) );
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                      LIGATURE CARETS                         *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_caret_value_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+
+    if ( p + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+      case 2:
+        break;
+
+      case 3:
+        {
+          OTL_Bytes  device;
+
+          p += 2;
+          if ( p + 2 > valid->limit )
+            OTL_INVALID_TOO_SHORT;
+
+          otl_device_table_validate( table + OTL_PEEK_USHORT( p ) );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+  static void
+  otl_ligature_glyph_validate( OTL_Bytes      table,
+                               OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    if ( p + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    count = OTL_NEXT_USHORT( p );
+
+    if ( p + count*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; count > 0; count-- )
+      otl_caret_value_validate( table + OTL_NEXT_USHORT( p ) );
+  }
+
+
+  static void
+  otl_ligature_caret_list_validate( OTL_Bytes      table,
+                                    OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_Bytes  coverage;
+    OTL_UInt   count;
+
+    if ( p + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    coverage = table + OTL_NEXT_USHORT( p );
+    count    = OTL_NEXT_USHORT( p );
+
+    otl_coverage_validate( coverage, valid );
+    if ( count != otl_coverage_get_count( coverage ) )
+      OTL_INVALID_DATA;
+
+    if ( p + count*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; count > 0; count-- )
+      otl_ligature_glyph_validate( table + OTL_NEXT_USHORT( p ) );
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                         GDEF TABLE                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  OTL_APIDEF( void )
+  otl_gdef_validate( OTL_Bytes      table,
+                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+
+    if ( p + 12 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    /* check format */
+    if ( OTL_NEXT_ULONG( p ) != 0x00010000UL )
+      OTL_INVALID_FORMAT;
+
+    /* validate class definition table */
+    otl_class_definition_validate( table + OTL_NEXT_USHORT( p ) );
+
+    /* validate attachment point list */
+    otl_attach_list_validate( table + OTL_NEXT_USHORT( p ) );
+
+    /* validate ligature caret list */
+    otl_ligature_caret_list_validate( table + OTL_NEXT_USHORT( p ) );
+
+    /* validate mark attach class */
+    otl_class_definition_validate( table + OTL_NEXT_USHORT( p ) );
+  }
+
--- /dev/null
+++ b/libfreetype/otlgdef.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_GDEF_H__
+#define __OTL_GDEF_H__
+
+#include "otltable.h"
+
+OTL_BEGIN_HEADER
+
+  OTL_API( void )
+  otl_gdef_validate( OTL_Bytes  table,
+                     OTL_Valid  valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GDEF_H__ */
--- /dev/null
+++ b/libfreetype/otlgpos.c
@@ -1,0 +1,980 @@
+#include "otlgpos.h"
+#include "otlcommn.h"
+
+ /* forward declaration */
+  static OTL_ValidateFunc  otl_gpos_validate_funcs[];
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                         VALUE RECORDS                        *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static OTL_UInt
+  otl_value_length( OTL_UInt  format )
+  {
+    FT_UInt  count;
+
+    count = (( format & 0xAA ) >> 1) + ( format & 0x55 );
+    count = (( count  & 0xCC ) >> 2) + ( count  & 0x33 );
+    count = (( count  & 0xF0 ) >> 4) + ( count  & 0x0F );
+
+    return count;
+  }
+
+
+  static void
+  otl_value_validate( OTL_Bytes      table,
+                      OTL_Bytes      pos_table,
+                      OTL_UInt       format,
+                      OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count, device;
+
+    if ( format >= 0x100U )
+      OTL_INVALID_DATA;
+
+    for ( count = 4; count > 0; count-- )
+    {
+      if ( format & 1 )
+      {
+        OTL_CHECK( 2 );
+        p += 2;
+      }
+
+      format >>= 1;
+    }
+
+    for ( count = 4; count > 0; count-- )
+    {
+      if ( format & 1 )
+      {
+        OTL_CHECK( 2 );
+        device = OTL_NEXT_USHORT( p );
+        if ( device )
+          otl_device_table_validate( pos_table + device, valid );
+      }
+      format >>= 1;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                          ANCHORS                             *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_anchor_validate( OTL_Bytes      table,
+                       OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 6 );
+    format = OTL_NEXT_USHORT( p );
+    p += 4;
+
+    switch ( format )
+    {
+      case 1:
+        break;
+
+      case 2:
+        OTL_CHECK( 2 );  /* anchor point */
+        break;
+
+      case 3:
+        {
+          OTL_UInt  x_device, y_device;
+
+          OTL_CHECK( 4 );
+          x_device = OTL_NEXT_USHORT( p );
+          y_device = OTL_NEXT_USHORT( p );
+
+          if ( x_device )
+            otl_device_table_validate( table + x_device, valid );
+
+          if ( y_device )
+            otl_device_table_validate( table + y_device, valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                           MARK ARRAY                         *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_mark_array_validate( OTL_Bytes      table,
+                           OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( count * 4 );
+    for ( ; count > 0; count-- )
+    {
+      p += 2;  /* ignore class index */
+      otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 1                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_gpos_lookup1_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          FT_UInt  coverage, value_format;
+
+          OTL_CHECK( 4 );
+          coverage     = OTL_NEXT_USHORT( p );
+          value_format = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+          otl_value_validate( p, table, value_format, valid );
+        }
+        break;
+
+      case 2:
+        {
+          FT_UInt  coverage, value_format, count, len;
+
+          OTL_CHECK( 6 );
+          coverage     = OTL_NEXT_USHORT( p );
+          value_format = OTL_NEXT_USHORT( p );
+          count        = OTL_NEXT_USHORT( p );
+          len          = otl_value_length( value_format );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( count * len );
+          for ( ; count > 0; count-- )
+          {
+            otl_value_validate( p, table, value_format, valid );
+            p += len;
+          }
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 2                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static otl_gpos_pairset_validate( OTL_Bytes      table,
+                                    OTL_Bytes      pos_table,
+                                    OTL_UInt       format1,
+                                    OTL_UInt       format2,
+                                    OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   len1, len2, count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+    len1  = otl_value_length( format1 );
+    len2  = otl_value_length( format2 );
+
+    OTL_CHECK( count * (len1+len2+2) );
+    for ( ; count > 0; count-- )
+    {
+      p += 2;  /* ignore glyph id */
+      otl_value_validate( p, pos_table, format1, valid );
+      p += len1;
+
+      otl_value_validate( p, pos_table, format2, valid );
+      p += len2;
+    }
+  }
+
+  static void
+  otl_gpos_lookup2_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, value1, value2, count;
+
+          OTL_CHECK( 8 );
+          coverage = OTL_NEXT_USHORT( p );
+          value1   = OTL_NEXT_USHORT( p );
+          value2   = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( count*2 );
+          for ( ; count > 0; count-- )
+          {
+            otl_gpos_pairset_validate( table + OTL_NEXT_USHORT( p ),
+                                       table, value1, value2, valid );
+          }
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  coverage, value1, value2, class1, class2, count1, count2;
+          OTL_UInt  len1, len2;
+
+          OTL_CHECK( 14 );
+          coverage = OTL_NEXT_USHORT( p );
+          value1   = OTL_NEXT_USHORT( p );
+          value2   = OTL_NEXT_USHORT( p );
+          class1   = OTL_NEXT_USHORT( p );
+          class2   = OTL_NEXT_USHORT( p );
+          count1   = OTL_NEXT_USHORT( p );
+          count2   = OTL_NEXT_USHORT( p );
+
+          len1 = otl_value_length( value1 );
+          len2 = otl_value_length( value2 );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( count1*count2*(len1+len2) );
+          for ( ; count1 > 0; count1-- )
+          {
+            for ( ; count2 > 0; count2-- )
+            {
+              otl_value_validate( p, table, value1, valid );
+              p += len1;
+
+              otl_value_validate( p, table, value2, valid );
+              p += len2;
+            }
+          }
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 3                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_gpos_lookup3_validate( OTL_Bytes  table,
+                             OTL_Valid  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, count, anchor1, anchor2;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( count*4 );
+          for ( ; count > 0; count-- )
+          {
+            anchor1 = OTL_NEXT_USHORT( p );
+            anchor2 = OTL_NEXT_USHORT( p );
+
+            if ( anchor1 )
+              otl_anchor_validate( table + anchor1, valid );
+
+            if ( anchor2 )
+              otl_anchor_validate( table + anchor2, valid );
+          }
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 4                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_base_array_validate( OTL_Bytes      table,
+                           OTL_UInt       class_count,
+                           OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count, count2;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*class_count*2 );
+    for ( ; count > 0; count-- )
+      for ( count2 = class_count; count2 > 0; count2-- )
+        otl_anchor_validate( table + OTL_NEXT_USHORT( p ) );
+  }
+
+
+  static void
+  otl_gpos_lookup4_validate( OTL_Bytes  table,
+                             OTL_Valid  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  mark_coverage, base_coverage, class_count;
+          OTL_UInt  mark_array, base_array;
+
+          OTL_CHECK( 10 );
+          mark_coverage = OTL_NEXT_USHORT( p );
+          base_coverage = OTL_NEXT_USHORT( p );
+          class_count   = OTL_NEXT_USHORT( p );
+          mark_array    = OTL_NEXT_USHORT( p );
+          base_array    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + mark_coverage, valid );
+          otl_coverage_validate( table + base_coverage, valid );
+
+          otl_mark_array_validate( table + mark_array, valid );
+          otl_base_array_validate( table, class_count, valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 5                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_liga_attach_validate( OTL_Bytes      table,
+                            OTL_UInt       class_count,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count, count2;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*class_count*2 );
+    for ( ; count > 0; count-- )
+      for ( count2 = class_count; class_count > 0; class_count-- )
+        otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_liga_array_validate( OTL_Bytes      table,
+                           OTL_UInt       class_count,
+                           OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count, count2;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*2 );
+    for ( ; count > 0; count-- )
+      otl_liga_attach_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_gpos_lookup5_validate( OTL_Bytes  table,
+                             OTL_Valid  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  mark_coverage, lig_coverage, class_count;
+          OTL_UInt  mar_array, lig_array;
+
+          OTL_CHECK( 10 );
+          mark_coverage = OTL_NEXT_USHORT( p );
+          liga_coverage = OTL_NEXT_USHORT( p );
+          class_count   = OTL_NEXT_USHORT( p );
+          mark_array    = OTL_NEXT_USHORT( p );
+          liga_array    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + mark_coverage, valid );
+          otl_coverage_validate( table + liga_coverage, valid );
+
+          otl_mark_array_validate( table + mark_array, valid );
+          otl_liga_array_validate( table + liga_array, class_count, valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 6                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+  static void
+  otl_mark2_array_validate( OTL_Bytes      table,
+                            OTL_UInt       class_count,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count, count2;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*class_count*2 );
+    for ( ; count > 0; count-- )
+      for ( count2 = class_count; class_count > 0; class_count-- )
+        otl_anchor_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_gpos_lookup6_validate( OTL_Bytes  table,
+                             OTL_Valid  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  coverage1, coverage2, class_count, array1, array2;
+
+          OTL_CHECK( 10 );
+          coverage1   = OTL_NEXT_USHORT( p );
+          coverage2   = OTL_NEXT_USHORT( p );
+          class_count = OTL_NEXT_USHORT( p );
+          array1      = OTL_NEXT_USHORT( p );
+          array2      = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage1, valid );
+          otl_coverage_validate( table + coverage2, valid );
+
+          otl_mark_array_validate( table + array1, valid );
+          otl_mark2_array_validate( table + array2, valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 7                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_pos_rule_validate( OTL_Bytes      table,
+                         OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   glyph_count, pos_count;
+
+    OTL_CHECK( 4 );
+    glyph_count = OTL_NEXT_USHORT( p );
+    pos_count   = OTL_NEXT_USHORT( p );
+
+    if ( glyph_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( (glyph_count-1)*2 + pos_count*4 );
+
+    /* XXX: check glyph indices and pos lookups */
+  }
+
+
+  static void
+  otl_pos_rule_set_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*2 );
+    for ( ; count > 0; count-- )
+      otl_pos_rule_validate( table + OTL_NEXT_USHORT(p), valid );
+  }
+
+
+
+  static void
+  otl_pos_class_rule_validate( OTL_Bytes      table,
+                               OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   glyph_count, pos_count;
+
+    OTL_CHECK( 4 );
+    glyph_count = OTL_NEXT_USHORT( p );
+    pos_count   = OTL_NEXT_USHORT( p );
+
+    if ( glyph_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( (glyph_count-1)*2 + pos_count*4 );
+
+    /* XXX: check glyph indices and pos lookups */
+  }
+
+
+  static void
+  otl_pos_class_set_validate( OTL_Bytes      table,
+                              OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*2 );
+    for ( ; count > 0; count-- )
+      otl_pos_rule_validate( table + OTL_NEXT_USHORT(p), valid );
+  }
+
+
+  static void
+  otl_gpos_lookup7_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, count;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( count*2 );
+          for ( ; count > 0; count-- )
+            otl_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  coverage, class_def, count;
+
+          OTL_CHECK( 6 );
+          coverage  = OTL_NEXT_USHORT( p );
+          class_def = OTL_NEXT_USHORT( p );
+          count     = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate        ( table + coverage, valid );
+          otl_class_definition_validate( table + class_def, valid );
+
+          OTL_CHECK( count*2 );
+          for ( ; count > 0; count-- )
+            otl_
+        }
+        break;
+
+      case 3:
+        {
+          OTL_UInt  glyph_count, pos_count;
+
+          OTL_CHECK( 4 );
+          glyph_count = OTL_NEXT_USHORT( p );
+          pos_count   = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( glyph_count*2 + pos_count*4 );
+          for ( ; glyph_count > 0; glyph_count )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+          /* XXX: check pos lookups */
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 8                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_chain_pos_rule_validate( OTL_Bytes      table,
+                               OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   back_count, input_count, ahead_count, pos_count;
+
+    OTL_CHECK( 2 );
+    back_count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( back_count*2 + 2 );
+    p += back_count*2;
+
+    input_count = OTL_NEXT_USHORT( p );
+    if ( input_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( input_count*2 );
+    p += (input_count-1)*2;
+
+    ahead_count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( ahead_count*2 + 2 );
+    p += ahead_count*2;
+
+    pos_count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( pos_count*4 );
+  }
+
+
+  static void
+  otl_chain_pos_rule_set_validate( OTL_Bytes      table,
+                                   OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_chain_pos_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+
+  static void
+  otl_chain_pos_class_rule_validate( OTL_Bytes      table,
+                                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   back_count, input_count, ahead_count, pos_count;
+
+    OTL_CHECK( 2 );
+    back_count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( back_count*2 + 2 );
+    p += back_count*2;
+
+    input_count = OTL_NEXT_USHORT( p );
+    if ( input_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( input_count*2 );
+    p += (input_count-1)*2;
+
+    ahead_count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( ahead_count*2 + 2 );
+    p += ahead_count*2;
+
+    pos_count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( pos_count*4 );
+  }
+
+
+  static void
+  otl_chain_pos_class_set_validate( OTL_Bytes      table,
+                                   OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_chain_pos_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_gpos_lookup8_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, count;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( count*2 );
+          for ( ; count > 0; count-- )
+            otl_chain_pos_rule_set_validate( table + OTL_NEXT_USHORT( p ),
+                                             valid );
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  coverage, back_class, input_class, ahead_class, count;
+
+          OTL_CHECK( 10 );
+          coverage    = OTL_NEXT_USHORT( p );
+          back_class  = OTL_NEXT_USHORT( p );
+          input_class = OTL_NEXT_USHORT( p );
+          ahead_class = OTL_NEXT_USHORT( p );
+          count       = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          otl_class_definition_validate( table + back_class,  valid );
+          otl_class_definition_validate( table + input_class, valid );
+          otl_class_definition_validate( table + ahead_class, valid );
+
+          OTL_CHECK( count*2 );
+          for ( ; count > 0; count-- )
+            otl_chain_pos_class_set_validate( table + OTL_NEXT_USHORT( p ),
+                                              valid );
+        }
+        break;
+
+      case 3:
+        {
+          OTL_UInt  back_count, input_count, ahead_count, pos_count, count;
+
+          OTL_CHECK( 2 );
+          back_count = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( 2*back_count+2 );
+          for ( count = back_count; count > 0; count-- )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+          input_count = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( 2*input_count+2 );
+          for ( count = input_count; count > 0; count-- )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+          ahead_count = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( 2*ahead_count+2 );
+          for ( count = ahead_count; count > 0; count-- )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+          pos_count = OTL_NEXT_USHORT( p );
+          OTL_CHECK( pos_count*4 );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GPOS LOOKUP TYPE 9                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_gpos_lookup9_validate( OTL_Bytes  table,
+                             OTL_Valid  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt          lookup_type, lookup_offset;
+          OTL_ValidateFunc  validate;
+
+          OTL_CHECK( 6 );
+          lookup_type   = OTL_NEXT_USHORT( p );
+          lookup_offset = OTL_NEXT_ULONG( p );
+
+          if ( lookup_type == 0 || lookup_type >= 9 )
+            OTL_INVALID_DATA;
+
+          validate = otl_gpos_validate_funcs[ lookup_type-1 ];
+          validate( table + lookup_offset, valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+  static OTL_ValidateFunc  otl_gpos_validate_funcs[ 9 ] =
+  {
+    otl_gpos_lookup1_validate,
+    otl_gpos_lookup2_validate,
+    otl_gpos_lookup3_validate,
+    otl_gpos_lookup4_validate,
+    otl_gpos_lookup5_validate,
+    otl_gpos_lookup6_validate,
+    otl_gpos_lookup7_validate,
+    otl_gpos_lookup8_validate,
+    otl_gpos_lookup9_validate,
+  };
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                         GPOS TABLE                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+  OTL_LOCALDEF( void )
+  otl_gpos_validate( OTL_Bytes      table,
+                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   scripts, features, lookups;
+
+    OTL_CHECK( 10 );
+
+    if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
+      OTL_INVALID_DATA;
+
+    scripts  = OTL_NEXT_USHORT( p );
+    features = OTL_NEXT_USHORT( p );
+    lookups  = OTL_NEXT_USHORT( p );
+
+    otl_script_list_validate ( table + scripts, valid );
+    otl_feature_list_validate( table + features, valid );
+
+    otl_lookup_list_validate( table + lookups, 9, otl_gpos_validate_funcs,
+                              valid );
+  }
+  
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otlgpos.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_GPOS_H__
+#define __OTL_GPOS_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+  OTL_LOCAL( void )
+  otl_gpos_validate( OTL_Bytes      table,
+                     OTL_Validator  valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GPOS_H__ */
--- /dev/null
+++ b/libfreetype/otlgsub.c
@@ -1,0 +1,867 @@
+#include "otlgsub.h"
+#include "otlcommn.h"
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GSUB LOOKUP TYPE 1                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /*
+  *  1: Single Substitution - Table format(s)
+  *
+  *  This table is used to substiture individual glyph indices
+  *  with another one. There are only two sub-formats:
+  *
+  *   Name         Offset    Size       Description
+  *   ------------------------------------------
+  *   format       0         2          sub-table format (1)
+  *   offset       2         2          offset to coverage table
+  *   delta        4         2          16-bit delta to apply on all
+  *                                     covered glyph indices
+  *
+  *   Name         Offset    Size       Description
+  *   ------------------------------------------
+  *   format       0         2          sub-table format (2)
+  *   offset       2         2          offset to coverage table
+  *   count        4         2          coverage table count
+  *   substs[]     6         2*count    substituted glyph indices,
+  *
+  */
+
+  static void
+  otl_gsub_lookup1_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  coverage;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  coverage, count;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( 2*count );
+
+          /* NB: we don't check that there are at most 'count'   */
+          /*     elements in the coverage table. This is delayed */
+          /*     to the lookup function...                       */
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+  static OTL_Bool
+  otl_gsub_lookup1_apply( OTL_Bytes   table,
+                          OTL_Parser  parser )
+  {
+    OTL_Bytes  p = table;
+    OTL_Bytes  coverage;
+    OTL_UInt   format, gindex, property;
+    OTL_Int    index;
+    OTL_Bool   subst = 0;
+
+    if ( parser->context_len != 0xFFFF && parser->context_len < 1 )
+      goto Exit;
+
+    gindex = otl_parser_get_gindex( parser );
+
+    if ( !otl_parser_check_property( parser, gindex, &property ) )
+      goto Exit;
+
+    format   = OTL_NEXT_USHORT(p);
+    coverage = table + OTL_NEXT_USHORT(p);
+    index    = otl_coverage_lookup( coverage, gindex );
+
+    if ( index >= 0 )
+    {
+      switch ( format )
+      {
+        case 1:
+          {
+            OTL_Int  delta = OTL_NEXT_SHORT(p);
+
+            gindex = ( gindex + delta ) & 0xFFFF;
+            otl_parser_replace_1( parser, gindex );
+            subst = 1;
+          }
+          break;
+
+        case 2:
+          {
+            OTL_UInt  count = OTL_NEXT_USHORT(p);
+
+            if ( (OTL_UInt) index < count )
+            {
+              p += index*2;
+              otl_parser_replace_1( parser, OTL_PEEK_USHORT(p) );
+              subst = 1;
+            }
+          }
+          break;
+
+        default:
+          ;
+      }
+    }
+  Exit:
+    return subst;
+  }
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GSUB LOOKUP TYPE 2                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /*
+  *  2: Multiple Substitution - Table format(s)
+  *
+  *  Replaces a single glyph with one or more glyphs.
+  *
+  *   Name         Offset    Size       Description
+  *   -----------------------------------------------------------
+  *   format       0         2          sub-table format (1)
+  *   offset       2         2          offset to coverage table
+  *   count        4         2          coverage table count
+  *   sequencess[] 6         2*count    offsets to sequence items
+  *
+  *   each sequence item has the following format:
+  *
+  *   Name         Offset    Size       Description
+  *   -----------------------------------------------------------
+  *   count        0         2          number of replacement glyphs
+  *   gindices[]   2         2*count    string of glyph indices
+  */
+
+  static void
+  otl_seq_validate( OTL_Bytes      table,
+                    OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    /* XXX: according to the spec, 'count' should be > 0     */
+    /*      we can deal with these cases pretty well however */
+
+    OTL_CHECK( 2*count );
+    /* check glyph indices */
+  }
+
+
+  static void
+  otl_gsub_lookup2_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format, coverage;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, seq_count;
+
+          OTL_CHECK( 4 );
+          coverage  = OTL_NEXT_USHORT( p );
+          seq_count = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( seq_count*2 );
+          for ( ; seq_count > 0; seq_count-- )
+            otl_seq_validate( table + OTL_NEXT_USHORT( p ), valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+  static OTL_Bool
+  otl_gsub_lookup2_apply( OTL_Bytes    table,
+                          OTL_Parser   parser )
+  {
+    OTL_Bytes  p = table;
+    OTL_Bytes  coverage, sequence;
+    OTL_UInt   format, gindex, index, property;
+    OTL_Int    index;
+    OTL_Bool   subst = 0;
+
+    if ( context_len != 0xFFFF && context_len < 1 )
+      goto Exit;
+
+    gindex = otl_parser_get_gindex( parser );
+
+    if ( !otl_parser_check_property( parser, gindex, &property ) )
+      goto Exit;
+
+    p        += 2;  /* skip format */
+    coverage  = table + OTL_NEXT_USHORT(p);
+    seq_count = OTL_NEXT_USHORT(p);
+    index     = otl_coverage_lookup( coverage, gindex );
+
+    if ( (OTL_UInt) index >= seq_count )
+      goto Exit;
+
+    p       += index*2;
+    sequence = table + OTL_PEEK_USHORT(p);
+    p        = sequence;
+    count    = OTL_NEXT_USHORT(p);
+
+    otl_parser_replace_n( parser, count, p );
+    subst = 1;
+
+   Exit:
+    return subst;
+  }
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GSUB LOOKUP TYPE 3                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+ /*
+  *  3: Alternate Substitution - Table format(s)
+  *
+  *  Replaces a single glyph by another one taken liberally
+  *  in a list of alternatives
+  *
+  *   Name         Offset    Size       Description
+  *   -----------------------------------------------------------
+  *   format       0         2          sub-table format (1)
+  *   offset       2         2          offset to coverage table
+  *   count        4         2          coverage table count
+  *   alternates[] 6         2*count    offsets to alternate items
+  *
+  *   each alternate item has the following format:
+  *
+  *   Name         Offset    Size       Description
+  *   -----------------------------------------------------------
+  *   count        0         2          number of replacement glyphs
+  *   gindices[]   2         2*count    string of glyph indices, each one
+  *                                     is a valid alternative
+  */
+
+  static void
+  otl_alternate_set_validate( OTL_Bytes      table,
+                              OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    /* XXX: check glyph indices */
+  }
+
+
+  static void
+  otl_gsub_lookup3_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format, coverage;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, count;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( 2*count );
+          for ( ; count > 0; count-- )
+            otl_alternate_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+  static OTL_Bool
+  otl_gsub_lookup3_apply( OTL_Bytes    table,
+                          OTL_Parser   parser )
+  {
+    OTL_Bytes  p = table;
+    OTL_Bytes  coverage, alternates;
+    OTL_UInt   format, gindex, index, property;
+    OTL_Int    index;
+    OTL_Bool   subst = 0;
+
+    OTL_GSUB_Alternate  alternate = parser->alternate;
+
+    if ( context_len != 0xFFFF && context_len < 1 )
+      goto Exit;
+
+    if ( alternate == NULL )
+      goto Exit;
+
+    gindex = otl_parser_get_gindex( parser );
+
+    if ( !otl_parser_check_property( parser, gindex, &property ) )
+      goto Exit;
+
+    p        += 2;  /* skip format */
+    coverage  = table + OTL_NEXT_USHORT(p);
+    seq_count = OTL_NEXT_USHORT(p);
+    index     = otl_coverage_lookup( coverage, gindex );
+
+    if ( (OTL_UInt) index >= seq_count )
+      goto Exit;
+
+    p         += index*2;
+    alternates = table + OTL_PEEK_USHORT(p);
+    p          = alternates;
+    count      = OTL_NEXT_USHORT(p);
+
+    gindex = alternate->handler_func(
+                 gindex, count, p, alternate->handler_data );
+
+    otl_parser_replace_1( parser, gindex );
+    subst = 1;
+
+   Exit:
+    return subst;
+  }
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GSUB LOOKUP TYPE 4                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_ligature_validate( OTL_Bytes      table,
+                         OTL_Validator  valid )
+  {
+    OTL_UInt  glyph_id, count;
+
+    OTL_CHECK( 4 );
+    glyph_id = OTL_NEXT_USHORT( p );
+    count    = OTL_NEXT_USHORT( p );
+
+    if ( count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( 2*(count-1) );
+    /* XXX: check glyph indices */
+  }
+
+
+  static void
+  otl_ligature_set_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_ligature_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_gsub_lookup4_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format, coverage;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, count;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( 2*count );
+          for ( ; count > 0; count-- )
+            otl_ligature_set_validate( table + OTL_NEXT_USHORT( p ), valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GSUB LOOKUP TYPE 5                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+  static void
+  otl_sub_rule_validate( OTL_Bytes      table,
+                         OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   glyph_count, subst_count;
+
+    OTL_CHECK( 4 );
+    glyph_count = OTL_NEXT_USHORT( p );
+    subst_count = OTL_NEXT_USHORT( p );
+
+    if ( glyph_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
+
+    /* XXX: check glyph indices and subst lookups */
+  }
+
+
+  static void
+  otl_sub_rule_set_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_sub_class_rule_validate( OTL_Bytes      table,
+                               OTL_Validator  valid )
+  {
+    OTL_UInt  glyph_count, subst_count;
+
+    OTL_CHECK( 4 );
+    glyph_count = OTL_NEXT_USHORT( p );
+    subst_count = OTL_NEXT_USHORT( p );
+
+    if ( glyph_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( (glyph_count-1)*2 + substcount*4 );
+
+    /* XXX: check glyph indices and subst lookups */
+  }
+
+
+  static void
+  otl_sub_class_rule_set_validate( OTL_Bytes      table,
+                                   OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_sub_class_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_gsub_lookup5_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format, coverage;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, count;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( 2*count );
+          for ( ; count > 0; count-- )
+            otl_sub_rule_set_validate( table + coverage, valid );
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  coverage, class_def, count;
+
+          OTL_CHECK( 6 );
+          coverage  = OTL_NEXT_USHORT( p );
+          class_def = OTL_NEXT_USHORT( p );
+          count     = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate        ( table + coverage, valid );
+          otl_class_definition_validate( table + class_def, valid );
+
+          OTL_CHECK( 2*count );
+          for ( ; count > 0; count-- )
+            otl_sub_class_rule_set_validate( table + coveragen valid );
+        }
+        break;
+
+      case 3:
+        {
+          OTL_UInt  glyph_count, subst_count, count;
+
+          OTL_CHECK( 4 );
+          glyph_count = OTL_NEXT_USHORT( p );
+          subst_count = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( 2*glyph_count + 4*subst_count );
+          for ( count = glyph_count; count > 0; count-- )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GSUB LOOKUP TYPE 6                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+  static void
+  otl_chain_sub_rule_validate( OTL_Bytes      table,
+                               OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   back_count, input_count, ahead_count, subst_count, count;
+
+    OTL_CHECK( 2 );
+    back_count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*back_count+2 );
+    p += 2*back_count;
+
+    input_count = OTL_NEXT_USHORT( p );
+    if ( input_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( 2*input_count );
+    p += 2*(input_count-1);
+
+    ahead_count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( 2*ahead_count + 2 );
+    p += 2*ahead_count;
+
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( 4*count );
+
+    /* XXX: check glyph indices and subst lookups */
+  }
+
+
+  static void
+  otl_chain_sub_rule_set_validate( OTL_Bytes      table,
+                                   OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_chain_sub_class_rule_validate( OTL_Bytes      table,
+                                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   back_count, input_count, ahead_count, subst_count, count;
+
+    OTL_CHECK( 2 );
+    back_count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*back_count+2 );
+    p += 2*back_count;
+
+    input_count = OTL_NEXT_USHORT( p );
+    if ( input_count == 0 )
+      OTL_INVALID_DATA;
+
+    OTL_CHECK( 2*input_count );
+    p += 2*(input_count-1);
+
+    ahead_count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( 2*ahead_count + 2 );
+    p += 2*ahead_count;
+
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( 4*count );
+
+    /* XXX: check class indices and subst lookups */
+  }
+
+
+
+  static void
+  otl_chain_sub_class_set_validate( OTL_Bytes      table,
+                                    OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( 2*count );
+    for ( ; count > 0; count-- )
+      otl_chain_sub_rule_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_gsub_lookup6_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format, coverage;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  coverage, count;
+
+          OTL_CHECK( 4 );
+          coverage = OTL_NEXT_USHORT( p );
+          count    = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          OTL_CHECK( 2*count );
+          for ( ; count > 0; count-- )
+            otl_chain_sub_rule_set_validate( table + coverage, valid );
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  coverage, back_class, input_class, ahead_class, count;
+
+          OTL_CHECK( 10 );
+          coverage    = OTL_NEXT_USHORT( p );
+          back_class  = OTL_NEXT_USHORT( p );
+          input_class = OTL_NEXT_USHORT( p );
+          ahead_class = OTL_NEXT_USHORT( p );
+          count       = OTL_NEXT_USHORT( p );
+
+          otl_coverage_validate( table + coverage, valid );
+
+          otl_class_definition_validate( table + back_class,  valid );
+          otl_class_definition_validate( table + input_class, valid );
+          otl_class_definition_validate( table + ahead_class, valid );
+
+          OTL_CHECK( 2*count );
+          for ( ; count > 0; count-- )
+            otl_chain_sub_class_set( table + OTL_NEXT_USHORT( p ), valid );
+        }
+        break;
+
+      case 3:
+        {
+          OTL_UInt  back_count, input_count, ahead_count, subst_count, count;
+
+          OTL_CHECK( 2 );
+          back_count = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( 2*back_count+2 );
+          for ( count = back_count; count > 0; count-- )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+          input_count = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( 2*input_count+2 );
+          for ( count = input_count; count > 0; count-- )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+          ahead_count = OTL_NEXT_USHORT( p );
+
+          OTL_CHECK( 2*ahead_count+2 );
+          for ( count = ahead_count; count > 0; count-- )
+            otl_coverage_validate( table + OTL_NEXT_USHORT( p ), valid );
+
+          subst_count = OTL_NEXT_USHORT( p );
+          OTL_CHECK( subst_count*4 );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 GSUB LOOKUP TYPE 6                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  static void
+  otl_gsub_lookup7_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format, coverage;
+
+    OTL_CHECK( 2 );
+    format = OTL_NEXT_USHORT( p );
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt          lookup_type, lookup_offset;
+          OTL_ValidateFunc  validate;
+
+          OTL_CHECK( 6 );
+          lookup_type   = OTL_NEXT_USHORT( p );
+          lookup_offset = OTL_NEXT_ULONG( p );
+
+          if ( lookup_type == 0 || lookup_type >= 7 )
+            OTL_INVALID_DATA;
+
+          validate = otl_gsub_validate_funcs[ lookup_type-1 ];
+          validate( table + lookup_offset, valid );
+        }
+        break;
+
+      default:
+        OTL_INVALID_DATA;
+    }
+  }
+
+
+  static const OTL_ValidateFunc  otl_gsub_validate_funcs[ 7 ] =
+  {
+    otl_gsub_lookup1_validate,
+    otl_gsub_lookup2_validate,
+    otl_gsub_lookup3_validate,
+    otl_gsub_lookup4_validate,
+    otl_gsub_lookup5_validate,
+    otl_gsub_lookup6_validate
+  };
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                         GSUB TABLE                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+  OTL_LOCALDEF( void )
+  otl_gsub_validate( OTL_Bytes      table,
+                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   scripts, features, lookups;
+
+    OTL_CHECK( 10 );
+
+    if ( OTL_NEXT_USHORT( p ) != 0x10000UL )
+      OTL_INVALID_DATA;
+
+    scripts  = OTL_NEXT_USHORT( p );
+    features = OTL_NEXT_USHORT( p );
+    lookups  = OTL_NEXT_USHORT( p );
+
+    otl_script_list_validate ( table + scripts, valid );
+    otl_feature_list_validate( table + features, valid );
+
+    otl_lookup_list_validate( table + lookups, 7, otl_gsub_validate_funcs,
+                              valid );
+  }
--- /dev/null
+++ b/libfreetype/otlgsub.h
@@ -1,0 +1,26 @@
+#ifndef __OTL_GSUB_H__
+#define __OTL_GSUB_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+  typedef OTL_UInt  (*OTL_GSUB_AlternateFunc)( OTL_UInt     gindex,
+                                               OTL_UInt     count,
+                                               OTL_Bytes    alternates,
+                                               OTL_Pointer  data );
+
+  typedef struct OTL_GSUB_AlternateRec_
+  {
+    OTL_GSUB_AlternateFunc  handler_func;
+    OTL_Pointer             handler_data;
+
+  } OTL_GSUB_AlternateRec, *OTL_GSUB_Alternate;
+
+  OTL_LOCAL( void )
+  otl_gsub_validate( OTL_Bytes      table,
+                     OTL_Validator  valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_GSUB_H__ */
--- /dev/null
+++ b/libfreetype/otljstf.c
@@ -1,0 +1,189 @@
+#include "otljstf.h"
+#include "otlcommn.h"
+#include "otlgpos.h"
+
+  static void
+  otl_jstf_extender_validate( OTL_Bytes      table,
+                              OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*2 );
+  }
+
+
+  static void
+  otl_jstf_gsub_mods_validate( OTL_Bytes      table,
+                               OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( count*2 );
+
+    /* XXX: check GSUB lookup indices */
+  }
+
+
+  static void
+  otl_jstf_gpos_mods_validate( OTL_Bytes      table,
+                               OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( count*2 );
+
+    /* XXX: check GPOS lookup indices */
+  }
+
+
+  static void
+  otl_jstf_max_validate( OTL_Bytes      table,
+                         OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*2 );
+    for ( ; count > 0; count-- )
+      otl_gpos_subtable_check( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_jstf_priority_validate( OTL_Bytes      table,
+                              OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   offset;
+
+    OTL_CHECK( 20 );
+
+    /* shrinkage GSUB enable/disable */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gsub_mods_validate( table + val, valid );
+
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gsub_mods_validate( table + val, valid );
+
+    /* shrinkage GPOS enable/disable */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gpos_mods_validate( table + val, valid );
+
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gpos_mods_validate( table + val, valid );
+
+    /* shrinkage JSTF max */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_max_validate( table + val, valid );
+
+    /* extension GSUB enable/disable */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gsub_mods_validate( table + val, valid );
+
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gsub_mods_validate( table + val, valid );
+
+    /* extension GPOS enable/disable */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gpos_mods_validate( table + val, valid );
+
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_gpos_mods_validate( table + val, valid );
+
+    /* extension JSTF max */
+    val = OTL_NEXT_USHORT( p );
+    if ( val )
+      otl_jstf_max_validate( table + val, valid );
+  }
+
+  static void
+  otl_jstf_lang_validate( OTL_Bytes      table,
+                          OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 2 );
+
+    count = OTL_NEXT_USHORT( p );
+
+    OTL_CHECK( count*2 );
+    for ( ; count > 0; count-- )
+      otl_jstf_priority_validate( table + OTL_NEXT_USHORT( p ), valid );
+  }
+
+
+  static void
+  otl_jstf_script_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count, extender, default_lang;
+
+    OTL_CHECK( 6 );
+    extender     = OTL_NEXT_USHORT( p );
+    default_lang = OTL_NEXT_USHORT( p );
+    count        = OTL_NEXT_USHORT( p );
+
+    if ( extender )
+      otl_jstf_extender_validate( table + extender, valid );
+
+    if ( default_lang )
+      otl_jstf_lang_validate( table + default_lang, valid );
+
+    OTL_CHECK( 6*count );
+
+    for ( ; count > 0; count-- )
+    {
+      p += 4;  /* ignore tag */
+      otl_jstf_lang_validate( table + OTL_NEXT_USHORT( p ), valid );
+    }
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_jstf_validate( OTL_Bytes      table,
+                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   count;
+
+    OTL_CHECK( 4 );
+
+    if ( OTL_NEXT_ULONG( p ) != 0x10000UL )
+      OTL_INVALID_DATA;
+
+    count = OTL_NEXT_USHORT( p );
+    OTL_CHECK( count*6 );
+
+    for ( ; count > 0; count++ )
+    {
+      p += 4;  /* ignore tag */
+      otl_jstf_script_validate( table + OTL_NEXT_USHORT( p ), valid );
+    }
+  }
+  
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otljstf.h
@@ -1,0 +1,14 @@
+#ifndef __OTL_JSTF_H__
+#define __OTL_JSTF_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+  OTL_LOCAL( void )
+  otl_jstf_validate( OTL_Bytes      table,
+                     OTL_Validator  valid );
+
+OTL_END_HEADER
+
+#endif /* __OTL_JSTF_H__ */
\ No newline at end of file
--- /dev/null
+++ b/libfreetype/otlparse.c
@@ -1,0 +1,142 @@
+#include "otlparse.h"
+#include "otlutils.h"
+
+  static void
+  otl_string_ensure( OTL_String  string,
+                     OTL_UInt    count,
+                     OTL_Parser  parser )
+  {
+    count += string->length;
+
+    if ( count > string->capacity )
+    {
+      OTL_UInt    old_count = string->capacity;
+      OTL_UInt    new_count = old_count;
+      OTL_Memory  memory    = parser->memory;
+
+      while ( new_count < count )
+        new_count += (new_count >> 1) + 16;
+
+      if ( OTL_MEM_RENEW_ARRAY( string->glyphs, old_count, new_count ) )
+        otl_parser_error( parser, OTL_Parse_Err_Memory );
+
+      string->capacity = new_count;
+    }
+  }
+
+#define  OTL_STRING_ENSURE(str,count,parser)                   \
+           OTL_BEGIN_STMNT                                     \
+             if ( (str)->length + (count) > (str)>capacity )   \
+               otl_string_ensure( str, count, parser );        \
+           OTL_END_STMNT
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_parser_get_gindex( OTL_Parser  parser )
+  {
+    OTL_String  in = parser->str_in;
+
+    if ( in->cursor >= in->num_glyphs )
+      otl_parser_error( parser, OTL_Err_Parser_Internal );
+
+    return in->str[ in->cursor ].gindex;
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_parser_error( OTL_Parser      parser,
+                    OTL_ParseError  error; )
+  {
+    parser->error = error;
+    otl_longjmp( parser->jump_buffer, 1 );
+  }
+
+#define  OTL_PARSER_UNCOVERED(x)  otl_parser_error( x, OTL_Parse_Err_UncoveredGlyph );
+
+  OTL_LOCAL( void )
+  otl_parser_check_property( OTL_Parser  parser,
+                             OTL_UInt    gindex,
+                             OTL_UInt    flags,
+                             OTL_UInt   *aproperty );
+
+  OTL_LOCALDEF( void )
+  otl_parser_replace_1( OTL_Parser  parser,
+                        OTL_UInt    gindex )
+  {
+    OTL_String       in  = parser->str_in;
+    OTL_String       out = parser->str_out;
+    OTL_StringGlyph  glyph, in_glyph;
+
+    /* sanity check */
+    if ( in == NULL               ||
+         out == NULL              ||
+         in->length == 0          ||
+         in->cursor >= in->length )
+    {
+      /* report as internal error, since these should */
+      /* never happen !!                              */
+      otl_parser_error( parser, OTL_Err_Parse_Internal );
+    }
+
+    OTL_STRING_ENSURE( out, 1, parser );
+    glyph    = out->glyphs + out->length;
+    in_glyph = in->glyphs  + in->cursor;
+
+    glyph->gindex        = gindex;
+    glyph->property      = in_glyph->property;
+    glyph->lig_component = in_glyph->lig_component;
+    glyph->lig_id        = in_glyph->lig_id;
+
+    out->length += 1;
+    out->cursor  = out->length;
+    in->cursor  += 1;
+  }
+
+  OTL_LOCALDEF( void )
+  otl_parser_replace_n( OTL_Parser  parser,
+                        OTL_UInt    count,
+                        OTL_Bytes   indices )
+  {
+    OTL_UInt         lig_component, lig_id, property;
+    OTL_String       in  = parser->str_in;
+    OTL_String       out = parser->str_out;
+    OTL_StringGlyph  glyph, in_glyph;
+    OTL_Bytes        p = indices;
+
+    /* sanity check */
+    if ( in == NULL               ||
+         out == NULL              ||
+         in->length == 0          ||
+         in->cursor >= in->length )
+    {
+      /* report as internal error, since these should */
+      /* never happen !!                              */
+      otl_parser_error( parser, OTL_Err_Parse_Internal );
+    }
+
+    OTL_STRING_ENSURE( out, count, parser );
+    glyph    = out->glyphs + out->length;
+    in_glyph = in->glyphs  + in->cursor;
+
+    glyph->gindex = gindex;
+
+    lig_component = in_glyph->lig_component;
+    lig_id        = in_glyph->lid_id;
+    property      = in_glyph->property;
+
+    for ( ; count > 0; count-- )
+    {
+      glyph->gindex        = OTL_NEXT_USHORT(p);
+      glyph->property      = property;
+      glyph->lig_component = lig_component;
+      glyph->lig_id        = lig_id;
+
+      out->length ++;
+    }
+
+    out->cursor  = out->length;
+    in->cursor  += 1;
+  }
+
+
+
--- /dev/null
+++ b/libfreetype/otlparse.h
@@ -1,0 +1,99 @@
+#ifndef __OTL_PARSER_H__
+#define __OTL_PARSER_H__
+
+#include "otlayout.h"
+#include "otlgdef.h"
+#include "otlgsub.h"
+#include "otlgpos.h"
+
+OTL_BEGIN_HEADER
+
+  typedef struct OTL_ParserRec_*   OTL_Parser;
+
+  typedef struct OTL_StringRec_*   OTL_String;
+
+  typedef struct OTL_StringGlyphRec_
+  {
+    OTL_UInt  gindex;
+    OTL_UInt  properties;
+    OTL_UInt  lig_component;
+    OTL_UInt  lig_id;
+
+  } OTL_StringGlyphRec, *OTL_StringGlyph;
+
+  typedef struct OTL_StringRec_
+  {
+    OTL_StringGlyph  glyphs;
+    OTL_UInt         cursor;
+    OTL_UInt         length;
+    OTL_UInt         capacity;
+
+  } OTL_StringRec;
+
+  typedef struct OTL_ParserRec_
+  {
+    OTL_Bytes      tab_gdef;
+    OTL_Bytes      tab_gsub;
+    OTL_Bytes      tab_gpos;
+    OTL_Bytes      tab_base;
+    OTL_Bytes      tab_jstf;
+
+    OTL_Alternate  alternate;  /* external alternate handler */
+
+    OTL_UInt       context_len;
+    OTL_UInt       markup_flags;
+
+    OTL_jmp_buf    jump_buffer;
+    OTL_Memory     memory;
+    OTL_Error      error;
+
+    OTL_StringRec  strings[2];
+    OTL_String     str_in;
+    OTL_String     str_out;
+
+  } OTL_ParserRec;
+
+  typedef enum
+  {
+    OTL_Err_Parser_Ok = 0,
+    OTL_Err_Parser_InvalidData,
+    OTL_Err_Parser_UncoveredGlyph
+
+  } OTL_ParseError;
+
+  OTL_LOCAL( OTL_UInt )
+  otl_parser_get_gindex( OTL_Parser  parser );
+
+
+  OTL_LOCAL( void )
+  otl_parser_error( OTL_Parser  parser, OTL_ParserError  error );
+
+#define  OTL_PARSER_UNCOVERED(x)  \
+           otl_parser_error( x, OTL_Err_Parser_UncoveredGlyph )
+
+  OTL_LOCAL( void )
+  otl_parser_check_property( OTL_Parser  parser,
+                             OTL_UInt    gindex,
+                             OTL_UInt    flags,
+                             OTL_UInt   *aproperty );
+
+ /* copy current input glyph to output */
+  OTL_LOCAL( void )
+  otl_parser_copy_1( OTL_Parser  parser );
+
+ /* copy current input glyph to output, replacing its index */
+  OTL_LOCAL( void )
+  otl_parser_replace_1( OTL_Parser  parser,
+                        OTL_UInt    gindex );
+
+ /* copy current input glyph to output, replacing it by several indices */
+ /* read directly from the table                                        */
+  OTL_LOCAL( void )
+  otl_parser_replace_n( OTL_Parser  parser,
+                        OTL_UInt    count,
+                        OTL_Bytes   indices );
+
+OTL_END_HEADER
+
+#endif /* __OTL_PARSER_H__ */
+
--- /dev/null
+++ b/libfreetype/otltable.h
@@ -1,0 +1,60 @@
+#ifndef __OTL_TABLE_H__
+#define __OTL_TABLE_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+  typedef struct OTL_TableRec_*    OTL_Table;
+
+  typedef enum
+  {
+    OTL_TABLE_TYPE_GDEF = 1,
+    OTL_TABLE_TYPE_GSUB,
+    OTL_TABLE_TYPE_GPOS,
+    OTL_TABLE_TYPE_BASE,
+    OTL_TABLE_TYPE_JSTF
+
+  } OTL_TableType;
+
+
+ /* this may become a private structure later */
+  typedef struct OTL_TableRec_
+  {
+    OTL_TableType  type;
+    OTL_Bytes      base;
+    OTL_Bytes      limit;
+
+    OTL_Tag        script_tag;
+    OTL_Tag        lang_tag;
+
+    OTL_UInt       lookup_count;
+    OTL_Byte*      lookup_flags;
+
+    OTL_UInt       feature_count;
+    OTL_Tag        feature_tags;
+    OTL_Byte*      feature_flags;
+
+  } OTL_TableRec;
+
+
+  OTL_API( OTL_Error )
+  otl_table_validate( OTL_Bytes      table,
+                      OTL_Size       size,
+                      OTL_TableType  type,
+                      OTL_Size      *abyte_size );
+
+  OTL_API( void )
+  otl_table_init( OTL_Table      table,
+                  OTL_TableType  type,
+                  OTL_Bytes      base,
+                  OTL_Size       size );
+
+  OTL_API( void )
+  otl_table_set_script( OTL_Table      table,
+                        OTL_ScriptTag  script,
+                        OTL_LangTag    language );
+
+OTL_END_HEADER
+
+#endif /* __OTL_TABLE_H__ */
--- /dev/null
+++ b/libfreetype/otltags.h
@@ -1,0 +1,86 @@
+/* this file may be included several times by other parts of */
+/* the OpenType Layout library.. don't add #ifdef .. #endif  */
+/* delimiters to it...                                       */
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                       SCRIPT TAGS                            *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_SCRIPT_TAG
+#define OTL_SCRIPT_TAG(c1,c2,c3,c4,s,n)  /* void */
+#endif
+
+OTL_SCRIPT_TAG( 'a','r','a','b', "Arabic", ARABIC )
+OTL_SCRIPT_TAG( 'a','r','m','n', "Armenian", ARMENIAN )
+OTL_SCRIPT_TAG( 'b','e','n','g', "Bengali", BENGALI )
+OTL_SCRIPT_TAG( 'b','o','p','o', "Bopomofo", BOPOMOFO )
+OTL_SCRIPT_TAG( 'b','r','a','i', "Braille", BRAILLE )
+OTL_SCRIPT_TAG( 'c','a','n','s', "Canadian Syllabic", CANADIAN )
+OTL_SCRIPT_TAG( 'c','h','e','r', "Cherokee", CHEROKEE )
+OTL_SCRIPT_TAG( 'h','a','n','i', "CJK Ideographic", CJK )
+OTL_SCRIPT_TAG( 'c','y','r','l', "Cyrillic", CYRILLIC )
+OTL_SCRIPT_TAG( 'd','e','v','a', "Devanagari", DEVANAGARI )
+OTL_SCRIPT_TAG( 'e','t','h','i', "Ethiopic", ETHIOPIC )
+OTL_SCRIPT_TAG( 'g','e','o','r', "Georgian", GEORGIAN )
+OTL_SCRIPT_TAG( 'g','r','e','k', "Greek", GREEK )
+OTL_SCRIPT_TAG( 'g','u','j','r', "Gujarati", GUJARATI )
+OTL_SCRIPT_TAG( 'g','u','r','u', "Gurmukhi", GURMUKHI )
+OTL_SCRIPT_TAG( 'j','a','m','o', "Hangul Jamo", JAMO )
+OTL_SCRIPT_TAG( 'h','a','n','g', "Hangul", HANGUL )
+OTL_SCRIPT_TAG( 'h','e','b','r', "Hebrew", HEBREW )
+OTL_SCRIPT_TAG( 'h','i','r','a', "Hiragana", HIRAGANA )
+OTL_SCRIPT_TAG( 'k','n','d','a', "Kannada", KANNADA )
+OTL_SCRIPT_TAG( 'k','a','n','a', "Katakana", KATAKANA )
+OTL_SCRIPT_TAG( 'k','h','m','r', "Khmer", KHMER )
+OTL_SCRIPT_TAG( 'l','a','o',' ', "Lao", LAO )
+OTL_SCRIPT_TAG( 'l','a','t','n', "Latin", LATIN )
+OTL_SCRIPT_TAG( 'm','l','y','m', "Malayalam", MALAYALAM )
+OTL_SCRIPT_TAG( 'm','o','n','g', "Mongolian", MONGOLIAN )
+OTL_SCRIPT_TAG( 'm','y','m','r', "Myanmar", MYANMAR )
+OTL_SCRIPT_TAG( 'o','g','a','m', "Ogham", OGHAM )
+OTL_SCRIPT_TAG( 'o','r','y','a', "Oriya", ORIYA )
+OTL_SCRIPT_TAG( 'r','u','n','r', "Runic", RUNIC )
+OTL_SCRIPT_TAG( 's','i','n','h', "Sinhala", SINHALA )
+OTL_SCRIPT_TAG( 's','y','r','c', "Syriac", SYRIAC )
+OTL_SCRIPT_TAG( 't','a','m','l', "Tamil", TAMIL )
+OTL_SCRIPT_TAG( 't','e','l','u', "Telugu", TELUGU )
+OTL_SCRIPT_TAG( 't','h','a','a', "Thaana", THAANA )
+OTL_SCRIPT_TAG( 't','h','a','i', "Thai", THAI )
+OTL_SCRIPT_TAG( 't','i','b','t', "Tibetan", TIBETAN )
+OTL_SCRIPT_TAG( 'y','i',' ',' ', "Yi", YI )
+
+#undef OTL_SCRIPT_TAG
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                       LANGUAGE TAGS                          *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_LANG_TAG
+#define OTL_LANG_TAG(c1,c2,c3,c4,s,n)  /* void */
+#endif
+
+#undef OTL_LANG_TAG
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                       FEATURE TAGS                           *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+#ifndef OTL_FEATURE_TAG
+#define OTL_FEATURE_TAG(c1,c2,c3,c4,s,n)  /* void */
+#endif
+
+#undef OTL_FEATURE_TAG
+
--- /dev/null
+++ b/libfreetype/otlutils.h
@@ -1,0 +1,33 @@
+#ifndef __OTLAYOUT_UTILS_H__
+#define __OTLAYOUT_UTILS_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+  OTL_LOCAL( OTL_Error )
+  otl_mem_alloc( OTL_Pointer*  pblock,
+                 OTL_ULong     size,
+                 OTL_Memory    memory );
+
+  OTL_LOCAL( void )
+  otl_mem_free( OTL_Pointer*  pblock,
+                OTL_Memory    memory );
+
+  OTL_LOCAL( OTL_Error )
+  otl_mem_realloc( OTL_Pointer  *pblock,
+                   OTL_ULong     cur_size,
+                   OTL_ULong     new_size,
+                   OTL_Memory    memory );
+
+#define  OTL_MEM_ALLOC(p,s)       otl_mem_alloc( (void**)&(p), (s), memory )
+#define  OTL_MEM_FREE(p)          otl_mem_free( (void**)&(p), memory )
+#define  OTL_MEM_REALLOC(p,c,n)   otl_mem_realloc( (void**)&(p), (c), (s), memory )
+
+#define  OTL_MEM_NEW(p)   OTL_MEM_ALLOC(p,sizeof(*(p)))
+#define  OTL_MEM_NEW_ARRAY(p,c)  OTL_MEM_ALLOC(p,(c)*sizeof(*(p)))
+#define  OTL_MEM_RENEW_ARRAY(p,c,n)  OTL_MEM_REALLOC(p,(c)*sizeof(*(p)),(n)*sizeof(*(p)))
+
+OTL_END_HEADER
+
+#endif /* __OTLAYOUT_UTILS_H__ */
--- /dev/null
+++ b/libfreetype/pcf.c
@@ -1,0 +1,36 @@
+/*  pcf.c
+
+    FreeType font driver for pcf fonts
+
+  Copyright 2000-2001 by
+  Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+
+#include <ft2build.h>
+#include "pcfutil.c"
+#include "pcfread.c"
+#include "pcfdriver.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcf.h
@@ -1,0 +1,238 @@
+/*  pcf.h
+
+  FreeType font driver for pcf fonts
+
+  Copyright (C) 2000-2001, 2002 by
+  Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCF_H__
+#define __PCF_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+  typedef struct  PCF_TableRec_
+  {
+    FT_ULong  type;
+    FT_ULong  format;
+    FT_ULong  size;
+    FT_ULong  offset;
+
+  } PCF_TableRec, *PCF_Table;
+
+
+  typedef struct  PCF_TocRec_
+  {
+    FT_ULong   version;
+    FT_ULong   count;
+    PCF_Table  tables;
+
+  } PCF_TocRec, *PCF_Toc;
+
+
+  typedef struct  PCF_ParsePropertyRec_
+  {
+    FT_Long  name;
+    FT_Byte  isString;
+    FT_Long  value;
+
+  } PCF_ParsePropertyRec, *PCF_ParseProperty;
+
+
+  typedef struct  PCF_PropertyRec_
+  {
+    FT_String*  name;
+    FT_Byte     isString;
+
+    union
+    {
+      FT_String*  atom;
+      FT_Long     integer;
+      FT_ULong    cardinal;
+
+    } value;
+
+  } PCF_PropertyRec, *PCF_Property;
+
+
+  typedef struct  PCF_Compressed_MetricRec_
+  {
+    FT_Byte  leftSideBearing;
+    FT_Byte  rightSideBearing;
+    FT_Byte  characterWidth;
+    FT_Byte  ascent;
+    FT_Byte  descent;
+
+  } PCF_Compressed_MetricRec, *PCF_Compressed_Metric;
+
+
+  typedef struct  PCF_MetricRec_
+  {
+    FT_Short  leftSideBearing;
+    FT_Short  rightSideBearing;
+    FT_Short  characterWidth;
+    FT_Short  ascent;
+    FT_Short  descent;
+    FT_Short  attributes;
+    FT_ULong  bits;
+
+  } PCF_MetricRec, *PCF_Metric;
+
+
+  typedef struct  PCF_AccelRec_
+  {
+    FT_Byte        noOverlap;
+    FT_Byte        constantMetrics;
+    FT_Byte        terminalFont;
+    FT_Byte        constantWidth;
+    FT_Byte        inkInside;
+    FT_Byte        inkMetrics;
+    FT_Byte        drawDirection;
+    FT_Long        fontAscent;
+    FT_Long        fontDescent;
+    FT_Long        maxOverlap;
+    PCF_MetricRec  minbounds;
+    PCF_MetricRec  maxbounds;
+    PCF_MetricRec  ink_minbounds;
+    PCF_MetricRec  ink_maxbounds;
+
+  } PCF_AccelRec, *PCF_Accel;
+
+
+  typedef struct  PCD_EncodingRec_
+  {
+    FT_Long   enc;
+    FT_Short  glyph;
+
+  } PCF_EncodingRec, *PCF_Encoding;
+
+
+  typedef struct  PCF_FaceRec_
+  {
+    FT_FaceRec     root;
+
+    FT_StreamRec   gzip_stream;
+    FT_Stream      gzip_source;
+
+    char*          charset_encoding;
+    char*          charset_registry;
+
+    PCF_TocRec     toc;
+    PCF_AccelRec   accel;
+
+    int            nprops;
+    PCF_Property   properties;
+
+    FT_Long        nmetrics;
+    PCF_Metric     metrics;
+    FT_Long        nencodings;
+    PCF_Encoding   encodings;
+
+    FT_Short       defaultChar;
+
+    FT_ULong       bitmapsFormat;
+
+    FT_CharMap     charmap_handle;
+    FT_CharMapRec  charmap;  /* a single charmap per face */
+
+  } PCF_FaceRec, *PCF_Face;
+
+
+  /* macros for pcf font format */
+
+#define LSBFirst  0
+#define MSBFirst  1
+
+#define PCF_FILE_VERSION        ( ( 'p' << 24 ) | \
+                                  ( 'c' << 16 ) | \
+                                  ( 'f' <<  8 ) | 1 )
+#define PCF_FORMAT_MASK         0xFFFFFF00L
+
+#define PCF_DEFAULT_FORMAT      0x00000000L
+#define PCF_INKBOUNDS           0x00000200L
+#define PCF_ACCEL_W_INKBOUNDS   0x00000100L
+#define PCF_COMPRESSED_METRICS  0x00000100L
+
+#define PCF_FORMAT_MATCH( a, b ) \
+          ( ( (a) & PCF_FORMAT_MASK ) == ( (b) & PCF_FORMAT_MASK ) )
+
+#define PCF_GLYPH_PAD_MASK  ( 3 << 0 )
+#define PCF_BYTE_MASK       ( 1 << 2 )
+#define PCF_BIT_MASK        ( 1 << 3 )
+#define PCF_SCAN_UNIT_MASK  ( 3 << 4 )
+
+#define PCF_BYTE_ORDER( f ) \
+          ( ( (f) & PCF_BYTE_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_BIT_ORDER( f ) \
+          ( ( (f) & PCF_BIT_MASK ) ? MSBFirst : LSBFirst )
+#define PCF_GLYPH_PAD_INDEX( f ) \
+          ( (f) & PCF_GLYPH_PAD_MASK )
+#define PCF_GLYPH_PAD( f ) \
+          ( 1 << PCF_GLYPH_PAD_INDEX( f ) )
+#define PCF_SCAN_UNIT_INDEX( f ) \
+          ( ( (f) & PCF_SCAN_UNIT_MASK ) >> 4 )
+#define PCF_SCAN_UNIT( f ) \
+          ( 1 << PCF_SCAN_UNIT_INDEX( f ) )
+#define PCF_FORMAT_BITS( f )             \
+          ( (f) & ( PCF_GLYPH_PAD_MASK | \
+                    PCF_BYTE_MASK      | \
+                    PCF_BIT_MASK       | \
+                    PCF_SCAN_UNIT_MASK ) )
+
+#define PCF_SIZE_TO_INDEX( s )  ( (s) == 4 ? 2 : (s) == 2 ? 1 : 0 )
+#define PCF_INDEX_TO_SIZE( b )  ( 1 << b )
+
+#define PCF_FORMAT( bit, byte, glyph, scan )          \
+          ( ( PCF_SIZE_TO_INDEX( scan )      << 4 ) | \
+            ( ( (bit)  == MSBFirst ? 1 : 0 ) << 3 ) | \
+            ( ( (byte) == MSBFirst ? 1 : 0 ) << 2 ) | \
+            ( PCF_SIZE_TO_INDEX( glyph )     << 0 ) )
+
+#define PCF_PROPERTIES        ( 1 << 0 )
+#define PCF_ACCELERATORS      ( 1 << 1 )
+#define PCF_METRICS           ( 1 << 2 )
+#define PCF_BITMAPS           ( 1 << 3 )
+#define PCF_INK_METRICS       ( 1 << 4 )
+#define PCF_BDF_ENCODINGS     ( 1 << 5 )
+#define PCF_SWIDTHS           ( 1 << 6 )
+#define PCF_GLYPH_NAMES       ( 1 << 7 )
+#define PCF_BDF_ACCELERATORS  ( 1 << 8 )
+
+#define GLYPHPADOPTIONS  4 /* I'm not sure about this */
+
+  FT_LOCAL( FT_Error )
+  pcf_load_font( FT_Stream,
+                 PCF_Face );
+
+
+FT_END_HEADER
+
+#endif /* __PCF_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfdriver.c
@@ -1,0 +1,501 @@
+/*  pcfdriver.c
+
+    FreeType font driver for pcf files
+
+    Copyright (C) 2000-2001, 2002 by
+    Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_GZIP_H
+#include FT_ERRORS_H
+
+#include "pcf.h"
+#include "pcfdriver.h"
+#include "pcfutil.h"
+
+#include "pcferror.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pcfread
+
+
+  typedef struct  PCF_CMapRec_
+  {
+    FT_CMapRec    cmap;
+    FT_UInt       num_encodings;
+    PCF_Encoding  encodings;
+
+  } PCF_CMapRec, *PCF_CMap;
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  pcf_cmap_init( PCF_CMap  cmap )
+  {
+    PCF_Face  face = (PCF_Face)FT_CMAP_FACE( cmap );
+
+
+    cmap->num_encodings = (FT_UInt)face->nencodings;
+    cmap->encodings     = face->encodings;
+
+    return FT_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  pcf_cmap_done( PCF_CMap  cmap )
+  {
+    cmap->encodings     = NULL;
+    cmap->num_encodings = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  pcf_cmap_char_index( PCF_CMap   cmap,
+                       FT_UInt32  charcode )
+  {
+    PCF_Encoding  encodings = cmap->encodings;
+    FT_UInt       min, max, mid;
+    FT_UInt       result = 0;
+
+
+    min = 0;
+    max = cmap->num_encodings;
+
+    while ( min < max )
+    {
+      FT_UInt32  code;
+
+
+      mid  = ( min + max ) >> 1;
+      code = encodings[mid].enc;
+
+      if ( charcode == code )
+      {
+        result = encodings[mid].glyph + 1;
+        break;
+      }
+
+      if ( charcode < code )
+        max = mid;
+      else
+        min = mid + 1;
+    }
+
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  pcf_cmap_char_next( PCF_CMap    cmap,
+                      FT_UInt32  *acharcode )
+  {
+    PCF_Encoding  encodings = cmap->encodings;
+    FT_UInt       min, max, mid;
+    FT_UInt32     charcode = *acharcode + 1;
+    FT_UInt       result   = 0;
+
+
+    min = 0;
+    max = cmap->num_encodings;
+
+    while ( min < max )
+    {
+      FT_UInt32  code;
+
+
+      mid  = ( min + max ) >> 1;
+      code = encodings[mid].enc;
+
+      if ( charcode == code )
+      {
+        result = encodings[mid].glyph + 1;
+        goto Exit;
+      }
+
+      if ( charcode < code )
+        max = mid;
+      else
+        min = mid + 1;
+    }
+
+    charcode = 0;
+    if ( min < cmap->num_encodings )
+    {
+      charcode = encodings[min].enc;
+      result   = encodings[min].glyph + 1;
+    }
+
+  Exit:
+    *acharcode = charcode;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec  pcf_cmap_class =
+  {
+    sizeof( PCF_CMapRec ),
+    (FT_CMap_InitFunc)     pcf_cmap_init,
+    (FT_CMap_DoneFunc)     pcf_cmap_done,
+    (FT_CMap_CharIndexFunc)pcf_cmap_char_index,
+    (FT_CMap_CharNextFunc) pcf_cmap_char_next
+  };
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pcfdriver
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  PCF_Face_Done( PCF_Face  face )
+  {
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+    FT_FREE( face->encodings );
+    FT_FREE( face->metrics );
+
+    /* free properties */
+    {
+      PCF_Property  prop = face->properties;
+      FT_Int        i;
+
+
+      for ( i = 0; i < face->nprops; i++ )
+      {
+        prop = &face->properties[i];
+
+        FT_FREE( prop->name );
+        if ( prop->isString )
+          FT_FREE( prop->value );
+      }
+
+      FT_FREE( face->properties );
+    }
+
+    FT_FREE( face->toc.tables );
+    FT_FREE( face->root.family_name );
+    FT_FREE( face->root.available_sizes );
+    FT_FREE( face->charset_encoding );
+    FT_FREE( face->charset_registry );
+
+    FT_TRACE4(( "PCF_Face_Done: done face\n" ));
+
+    /* close gzip stream if any */
+    if ( face->root.stream == &face->gzip_stream )
+    {
+      FT_Stream_Close( &face->gzip_stream );
+      face->root.stream = face->gzip_source;
+    }
+
+    return PCF_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  PCF_Face_Init( FT_Stream      stream,
+                 PCF_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params )
+  {
+    FT_Error  error = PCF_Err_Ok;
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+    FT_UNUSED( face_index );
+
+
+    error = pcf_load_font( stream, face );
+    if ( error )
+    {
+      FT_Error  error2;
+
+      /* this didn't work, try gzip support !! */
+      error2 = FT_Stream_OpenGzip( &face->gzip_stream, stream );
+      if ( error2 == FT_Err_Unimplemented_Feature )
+        goto Fail;
+
+      error = error2;
+      if ( error )
+        goto Fail;
+
+      face->gzip_source = stream;
+      face->root.stream = &face->gzip_stream;
+
+      stream = face->root.stream;
+
+      error = pcf_load_font( stream, face );
+      if ( error )
+        goto Fail;
+    }
+
+    /* set-up charmap */
+    {
+      FT_String  *charset_registry, *charset_encoding;
+      FT_Bool     unicode_charmap  = 0;
+
+
+      charset_registry = face->charset_registry;
+      charset_encoding = face->charset_encoding;
+
+      if ( ( charset_registry != NULL ) &&
+           ( charset_encoding != NULL ) )
+      {
+        if ( !ft_strcmp( face->charset_registry, "ISO10646" )     ||
+             ( !ft_strcmp( face->charset_registry, "ISO8859" ) &&
+               !ft_strcmp( face->charset_encoding, "1" )       )  )
+          unicode_charmap = 1;
+      }
+
+      {
+        FT_CharMapRec  charmap;
+
+
+        charmap.face        = FT_FACE( face );
+        charmap.encoding    = FT_ENCODING_NONE;
+        charmap.platform_id = 0;
+        charmap.encoding_id = 0;
+
+        if ( unicode_charmap )
+        {
+          charmap.encoding    = FT_ENCODING_UNICODE;
+          charmap.platform_id = 3;
+          charmap.encoding_id = 1;
+        }
+
+        error = FT_CMap_New( &pcf_cmap_class, NULL, &charmap, NULL );
+
+#if 0
+        /* Select default charmap */
+        if (face->root.num_charmaps)
+          face->root.charmap = face->root.charmaps[0];
+#endif
+      }
+    }
+
+  Exit:
+    return error;
+
+  Fail:
+    FT_TRACE2(( "[not a valid PCF file]\n" ));
+    error = PCF_Err_Unknown_File_Format;  /* error */
+    goto Exit;
+  }
+
+
+  static FT_Error
+  PCF_Set_Pixel_Size( FT_Size  size )
+  {
+    PCF_Face face = (PCF_Face)FT_SIZE_FACE( size );
+
+
+    FT_TRACE4(( "rec %d - pres %d\n", size->metrics.y_ppem,
+                                      face->root.available_sizes->height ));
+
+    if ( size->metrics.y_ppem == face->root.available_sizes->height )
+    {
+      size->metrics.ascender    = face->accel.fontAscent << 6;
+      size->metrics.descender   = face->accel.fontDescent * (-64);
+#if 0
+      size->metrics.height      = face->accel.maxbounds.ascent << 6;
+#endif
+      size->metrics.height      = size->metrics.ascender -
+                                  size->metrics.descender;
+
+      size->metrics.max_advance = face->accel.maxbounds.characterWidth << 6;
+
+      return PCF_Err_Ok;
+    }
+    else
+    {
+      FT_TRACE4(( "size WRONG\n" ));
+      return PCF_Err_Invalid_Pixel_Size;
+    }
+  }
+
+
+  static FT_Error
+  PCF_Glyph_Load( FT_GlyphSlot  slot,
+                  FT_Size       size,
+                  FT_UInt       glyph_index,
+                  FT_Int32      load_flags )
+  {
+    PCF_Face    face   = (PCF_Face)FT_SIZE_FACE( size );
+    FT_Stream   stream = face->root.stream;
+    FT_Error    error  = PCF_Err_Ok;
+    FT_Memory   memory = FT_FACE( face )->memory;
+    FT_Bitmap*  bitmap = &slot->bitmap;
+    PCF_Metric  metric;
+    int         bytes;
+
+    FT_UNUSED( load_flags );
+
+
+    FT_TRACE4(( "load_glyph %d ---", glyph_index ));
+
+    if ( !face )
+    {
+      error = PCF_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    if ( glyph_index > 0 )
+      glyph_index--;
+
+    metric = face->metrics + glyph_index;
+
+    bitmap->rows       = metric->ascent + metric->descent;
+    bitmap->width      = metric->rightSideBearing - metric->leftSideBearing;
+    bitmap->num_grays  = 1;
+    bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+
+    FT_TRACE6(( "BIT_ORDER %d ; BYTE_ORDER %d ; GLYPH_PAD %d\n",
+                  PCF_BIT_ORDER( face->bitmapsFormat ),
+                  PCF_BYTE_ORDER( face->bitmapsFormat ),
+                  PCF_GLYPH_PAD( face->bitmapsFormat ) ));
+
+    switch ( PCF_GLYPH_PAD( face->bitmapsFormat ) )
+    {
+    case 1:
+      bitmap->pitch = ( bitmap->width + 7 ) >> 3;
+      break;
+
+    case 2:
+      bitmap->pitch = ( ( bitmap->width + 15 ) >> 4 ) << 1;
+      break;
+
+    case 4:
+      bitmap->pitch = ( ( bitmap->width + 31 ) >> 5 ) << 2;
+      break;
+
+    case 8:
+      bitmap->pitch = ( ( bitmap->width + 63 ) >> 6 ) << 3;
+      break;
+
+    default:
+      return PCF_Err_Invalid_File_Format;
+    }
+
+    /* XXX: to do: are there cases that need repadding the bitmap? */
+    bytes = bitmap->pitch * bitmap->rows;
+
+    if ( FT_ALLOC( bitmap->buffer, bytes ) )
+      goto Exit;
+
+    if ( FT_STREAM_SEEK( metric->bits )          ||
+         FT_STREAM_READ( bitmap->buffer, bytes ) )
+      goto Exit;
+
+    if ( PCF_BIT_ORDER( face->bitmapsFormat ) != MSBFirst )
+      BitOrderInvert( bitmap->buffer, bytes );
+
+    if ( ( PCF_BYTE_ORDER( face->bitmapsFormat ) !=
+           PCF_BIT_ORDER( face->bitmapsFormat )  ) )
+    {
+      switch ( PCF_SCAN_UNIT( face->bitmapsFormat ) )
+      {
+      case 1:
+        break;
+
+      case 2:
+        TwoByteSwap( bitmap->buffer, bytes );
+        break;
+
+      case 4:
+        FourByteSwap( bitmap->buffer, bytes );
+        break;
+      }
+    }
+
+    slot->bitmap_left = metric->leftSideBearing;
+    slot->bitmap_top  = metric->ascent;
+
+    slot->metrics.horiAdvance  = metric->characterWidth << 6 ;
+    slot->metrics.horiBearingX = metric->leftSideBearing << 6 ;
+    slot->metrics.horiBearingY = metric->ascent << 6 ;
+    slot->metrics.width        = ( metric->rightSideBearing -
+                                   metric->leftSideBearing ) << 6;
+    slot->metrics.height       = bitmap->rows << 6;
+
+    slot->linearHoriAdvance = (FT_Fixed)bitmap->width << 16;
+    slot->format            = FT_GLYPH_FORMAT_BITMAP;
+    slot->flags             = FT_GLYPH_OWN_BITMAP;
+
+    FT_TRACE4(( " --- ok\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  pcf_driver_class =
+  {
+    {
+      ft_module_font_driver,
+      sizeof ( FT_DriverRec ),
+
+      "pcf",
+      0x10000L,
+      0x20000L,
+
+      0,
+
+      (FT_Module_Constructor)0,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    sizeof( PCF_FaceRec ),
+    sizeof( FT_SizeRec ),
+    sizeof( FT_GlyphSlotRec ),
+
+    (FT_Face_InitFunc)        PCF_Face_Init,
+    (FT_Face_DoneFunc)        PCF_Face_Done,
+    (FT_Size_InitFunc)        0,
+    (FT_Size_DoneFunc)        0,
+    (FT_Slot_InitFunc)        0,
+    (FT_Slot_DoneFunc)        0,
+
+    (FT_Size_ResetPointsFunc) PCF_Set_Pixel_Size,
+    (FT_Size_ResetPixelsFunc) PCF_Set_Pixel_Size,
+
+    (FT_Slot_LoadFunc)        PCF_Glyph_Load,
+
+    (FT_Face_GetKerningFunc)  0,
+    (FT_Face_AttachFunc)      0,
+    (FT_Face_GetAdvancesFunc) 0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfdriver.h
@@ -1,0 +1,44 @@
+/*  pcfdriver.h
+
+    FreeType font driver for pcf fonts
+
+  Copyright 2000-2001, 2002 by
+  Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCFDRIVER_H__
+#define __PCFDRIVER_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+FT_BEGIN_HEADER
+
+  FT_EXPORT_VAR( const FT_Driver_ClassRec )  pcf_driver_class;
+
+FT_END_HEADER
+
+
+#endif /* __PCFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcferror.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pcferror.h                                                             */
+/*                                                                         */
+/*    PCF error codes (specification only).                                */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the PCF error enumeration constants.      */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __PCFERROR_H__
+#define __PCFERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  PCF_Err_
+#define FT_ERR_BASE    FT_Mod_Err_PCF
+
+#include FT_ERRORS_H
+
+#endif /* __PCFERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfread.c
@@ -1,0 +1,1057 @@
+/*  pcfread.c
+
+    FreeType font driver for pcf fonts
+
+  Copyright 2000-2001, 2002 by
+  Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "pcf.h"
+#include "pcfdriver.h"
+
+#include "pcferror.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pcfread
+
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+  static const char*  tableNames[] =
+  {
+    "prop", "accl", "mtrcs", "bmps", "imtrcs",
+    "enc", "swidth", "names", "accel"
+  };
+#endif
+
+
+  static
+  const FT_Frame_Field  pcf_toc_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_TocRec
+
+    FT_FRAME_START( 8 ),
+      FT_FRAME_ULONG_LE( version ),
+      FT_FRAME_ULONG_LE( count ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_table_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_TableRec
+
+    FT_FRAME_START( 16  ),
+      FT_FRAME_ULONG_LE( type ),
+      FT_FRAME_ULONG_LE( format ),
+      FT_FRAME_ULONG_LE( size ),
+      FT_FRAME_ULONG_LE( offset ),
+    FT_FRAME_END
+  };
+
+
+  static FT_Error
+  pcf_read_TOC( FT_Stream  stream,
+                PCF_Face   face )
+  {
+    FT_Error   error;
+    PCF_Toc    toc = &face->toc;
+    PCF_Table  tables;
+
+    FT_Memory  memory = FT_FACE(face)->memory;
+    FT_UInt    n;
+
+
+    if ( FT_STREAM_SEEK ( 0 )                          ||
+         FT_STREAM_READ_FIELDS ( pcf_toc_header, toc ) )
+      return PCF_Err_Cannot_Open_Resource;
+
+    if ( toc->version != PCF_FILE_VERSION )
+      return PCF_Err_Invalid_File_Format;
+
+    if ( FT_NEW_ARRAY( face->toc.tables, toc->count ) )
+      return PCF_Err_Out_Of_Memory;
+
+    tables = face->toc.tables;
+    for ( n = 0; n < toc->count; n++ )
+    {
+      if ( FT_STREAM_READ_FIELDS( pcf_table_header, tables ) )
+        goto Exit;
+      tables++;
+    }
+
+#if defined( FT_DEBUG_LEVEL_TRACE )
+
+    {
+      FT_UInt      i, j;
+      const char*  name = "?";
+
+
+      FT_TRACE4(( "Tables count: %ld\n", face->toc.count ));
+      tables = face->toc.tables;
+      for ( i = 0; i < toc->count; i++ )
+      {
+        for( j = 0; j < sizeof ( tableNames ) / sizeof ( tableNames[0] ); j++ )
+          if ( tables[i].type == (FT_UInt)( 1 << j ) )
+            name = tableNames[j];
+
+        FT_TRACE4(( "Table %d: type=%-6s format=0x%04lX "
+                    "size=0x%06lX (%8ld) offset=0x%04lX\n",
+                    i, name,
+                    tables[i].format,
+                    tables[i].size, tables[i].size,
+                    tables[i].offset ));
+      }
+    }
+
+#endif
+
+    return PCF_Err_Ok;
+
+  Exit:
+    FT_FREE( face->toc.tables );
+    return error;
+  }
+
+
+  static
+  const FT_Frame_Field  pcf_metric_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_MetricRec
+
+    FT_FRAME_START( 12 ),
+      FT_FRAME_SHORT_LE( leftSideBearing ),
+      FT_FRAME_SHORT_LE( rightSideBearing ),
+      FT_FRAME_SHORT_LE( characterWidth ),
+      FT_FRAME_SHORT_LE( ascent ),
+      FT_FRAME_SHORT_LE( descent ),
+      FT_FRAME_SHORT_LE( attributes ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_metric_msb_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_MetricRec
+
+    FT_FRAME_START( 12 ),
+      FT_FRAME_SHORT( leftSideBearing ),
+      FT_FRAME_SHORT( rightSideBearing ),
+      FT_FRAME_SHORT( characterWidth ),
+      FT_FRAME_SHORT( ascent ),
+      FT_FRAME_SHORT( descent ),
+      FT_FRAME_SHORT( attributes ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_compressed_metric_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_Compressed_MetricRec
+
+    FT_FRAME_START( 5 ),
+      FT_FRAME_BYTE( leftSideBearing ),
+      FT_FRAME_BYTE( rightSideBearing ),
+      FT_FRAME_BYTE( characterWidth ),
+      FT_FRAME_BYTE( ascent ),
+      FT_FRAME_BYTE( descent ),
+    FT_FRAME_END
+  };
+
+
+  static FT_Error
+  pcf_get_metric( FT_Stream   stream,
+                  FT_ULong    format,
+                  PCF_Metric  metric )
+  {
+    FT_Error  error = PCF_Err_Ok;
+
+
+    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+    {
+      const FT_Frame_Field*  fields;
+
+
+      /* parsing normal metrics */
+      fields = PCF_BYTE_ORDER( format ) == MSBFirst
+               ? pcf_metric_msb_header
+               : pcf_metric_header;
+
+      /* the following sets 'error' but doesn't return in case of failure */
+      (void)FT_STREAM_READ_FIELDS( fields, metric );
+    }
+    else
+    {
+      PCF_Compressed_MetricRec  compr;
+
+
+      /* parsing compressed metrics */
+      if ( FT_STREAM_READ_FIELDS( pcf_compressed_metric_header, &compr ) )
+        goto Exit;
+
+      metric->leftSideBearing  = (FT_Short)( compr.leftSideBearing  - 0x80 );
+      metric->rightSideBearing = (FT_Short)( compr.rightSideBearing - 0x80 );
+      metric->characterWidth   = (FT_Short)( compr.characterWidth   - 0x80 );
+      metric->ascent           = (FT_Short)( compr.ascent           - 0x80 );
+      metric->descent          = (FT_Short)( compr.descent          - 0x80 );
+      metric->attributes       = 0;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_seek_to_table_type( FT_Stream  stream,
+                          PCF_Table  tables,
+                          FT_Int     ntables,
+                          FT_ULong   type,
+                          FT_ULong  *aformat,
+                          FT_ULong  *asize )
+  {
+    FT_Error  error = 0;
+    FT_Int    i;
+
+
+    for ( i = 0; i < ntables; i++ )
+      if ( tables[i].type == type )
+      {
+        if ( stream->pos > tables[i].offset )
+          return PCF_Err_Invalid_Stream_Skip;
+
+        if ( FT_STREAM_SKIP( tables[i].offset - stream->pos ) )
+          return PCF_Err_Invalid_Stream_Skip;
+
+        *asize   = tables[i].size;  /* unused - to be removed */
+        *aformat = tables[i].format;
+
+        return PCF_Err_Ok;
+      }
+
+    return PCF_Err_Invalid_File_Format;
+  }
+
+
+  static FT_Bool
+  pcf_has_table_type( PCF_Table  tables,
+                      FT_Int     ntables,
+                      FT_ULong   type )
+  {
+    FT_Int  i;
+
+
+    for ( i = 0; i < ntables; i++ )
+      if ( tables[i].type == type )
+        return TRUE;
+
+    return FALSE;
+  }
+
+
+  static
+  const FT_Frame_Field  pcf_property_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_ParsePropertyRec
+
+    FT_FRAME_START( 9 ),
+      FT_FRAME_LONG_LE( name ),
+      FT_FRAME_BYTE   ( isString ),
+      FT_FRAME_LONG_LE( value ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_property_msb_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_ParsePropertyRec
+
+    FT_FRAME_START( 9 ),
+      FT_FRAME_LONG( name ),
+      FT_FRAME_BYTE( isString ),
+      FT_FRAME_LONG( value ),
+    FT_FRAME_END
+  };
+
+
+  static PCF_Property
+  pcf_find_property( PCF_Face          face,
+                     const FT_String*  prop )
+  {
+    PCF_Property  properties = face->properties;
+    FT_Bool       found      = 0;
+    int           i;
+
+
+    for ( i = 0 ; i < face->nprops && !found; i++ )
+    {
+      if ( !ft_strcmp( properties[i].name, prop ) )
+        found = 1;
+    }
+
+    if ( found )
+      return properties + i - 1;
+    else
+      return NULL;
+  }
+
+
+  static FT_Error
+  pcf_get_properties( FT_Stream  stream,
+                      PCF_Face   face )
+  {
+    PCF_ParseProperty  props      = 0;
+    PCF_Property       properties = 0;
+    FT_Int             nprops, i;
+    FT_ULong           format, size;
+    FT_Error           error;
+    FT_Memory          memory     = FT_FACE(face)->memory;
+    FT_ULong           string_size;
+    FT_String*         strings    = 0;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_PROPERTIES,
+                                    &format,
+                                    &size );
+    if ( error )
+      goto Bail;
+
+    if ( FT_READ_ULONG_LE( format ) )
+      goto Bail;
+
+    FT_TRACE4(( "get_prop: format = %ld\n", format ));
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+      goto Bail;
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      (void)FT_READ_ULONG( nprops );
+    else
+      (void)FT_READ_ULONG_LE( nprops );
+    if ( error )
+      goto Bail;
+
+    FT_TRACE4(( "get_prop: nprop = %d\n", nprops ));
+
+    if ( FT_NEW_ARRAY( props, nprops ) )
+      goto Bail;
+
+    for ( i = 0; i < nprops; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      {
+        if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) )
+          goto Bail;
+      }
+      else
+      {
+        if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) )
+          goto Bail;
+      }
+    }
+
+    /* pad the property array                                            */
+    /*                                                                   */
+    /* clever here - nprops is the same as the number of odd-units read, */
+    /* as only isStringProp are odd length   (Keith Packard)             */
+    /*                                                                   */
+    if ( nprops & 3 )
+    {
+      i = 4 - ( nprops & 3 );
+      FT_Stream_Skip( stream, i );
+    }
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      (void)FT_READ_ULONG( string_size );
+    else
+      (void)FT_READ_ULONG_LE( string_size );
+    if ( error )
+      goto Bail;
+
+    FT_TRACE4(( "get_prop: string_size = %ld\n", string_size ));
+
+    if ( FT_NEW_ARRAY( strings, string_size ) )
+      goto Bail;
+
+    error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size );
+    if ( error )
+      goto Bail;
+
+    if ( FT_NEW_ARRAY( properties, nprops ) )
+      goto Bail;
+
+    for ( i = 0; i < nprops; i++ )
+    {
+      /* XXX: make atom */
+      if ( FT_NEW_ARRAY( properties[i].name,
+                         ft_strlen( strings + props[i].name ) + 1 ) )
+        goto Bail;
+      ft_strcpy( properties[i].name,strings + props[i].name );
+
+      properties[i].isString = props[i].isString;
+
+      if ( props[i].isString )
+      {
+        if ( FT_NEW_ARRAY( properties[i].value.atom,
+                           ft_strlen( strings + props[i].value ) + 1 ) )
+          goto Bail;
+        ft_strcpy( properties[i].value.atom, strings + props[i].value );
+      }
+      else
+        properties[i].value.integer = props[i].value;
+    }
+
+    face->properties = properties;
+    face->nprops = nprops;
+
+    FT_FREE( props );
+    FT_FREE( strings );
+
+    return PCF_Err_Ok;
+
+  Bail:
+    FT_FREE( props );
+    FT_FREE( strings );
+
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_get_metrics( FT_Stream  stream,
+                   PCF_Face   face )
+  {
+    FT_Error    error    = PCF_Err_Ok;
+    FT_Memory   memory   = FT_FACE(face)->memory;
+    FT_ULong    format   = 0;
+    FT_ULong    size     = 0;
+    PCF_Metric  metrics  = 0;
+    int         i;
+    int         nmetrics = -1;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_METRICS,
+                                    &format,
+                                    &size );
+    if ( error )
+      return error;
+
+    error = FT_READ_ULONG_LE( format );
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )     &&
+         !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) )
+      return PCF_Err_Invalid_File_Format;
+
+    if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_ULONG( nmetrics );
+      else
+        (void)FT_READ_ULONG_LE( nmetrics );
+    }
+    else
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_USHORT( nmetrics );
+      else
+        (void)FT_READ_USHORT_LE( nmetrics );
+    }
+    if ( error || nmetrics == -1 )
+      return PCF_Err_Invalid_File_Format;
+
+    face->nmetrics = nmetrics;
+
+    if ( FT_NEW_ARRAY( face->metrics, nmetrics ) )
+      return PCF_Err_Out_Of_Memory;
+
+    metrics = face->metrics;
+    for ( i = 0; i < nmetrics; i++ )
+    {
+      pcf_get_metric( stream, format, metrics + i );
+
+      metrics[i].bits = 0;
+
+      FT_TRACE4(( "%d : width=%d, "
+                  "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n",
+                  i,
+                  ( metrics + i )->characterWidth,
+                  ( metrics + i )->leftSideBearing,
+                  ( metrics + i )->rightSideBearing,
+                  ( metrics + i )->ascent,
+                  ( metrics + i )->descent,
+                  ( metrics + i )->attributes ));
+
+      if ( error )
+        break;
+    }
+
+    if ( error )
+      FT_FREE( face->metrics );
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_get_bitmaps( FT_Stream  stream,
+                   PCF_Face   face )
+  {
+    FT_Error   error  = PCF_Err_Ok;
+    FT_Memory  memory = FT_FACE(face)->memory;
+    FT_Long*   offsets;
+    FT_Long    bitmapSizes[GLYPHPADOPTIONS];
+    FT_ULong   format, size;
+    int        nbitmaps, i, sizebitmaps = 0;
+    char*      bitmaps;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_BITMAPS,
+                                    &format,
+                                    &size );
+    if ( error )
+      return error;
+
+    error = FT_Stream_EnterFrame( stream, 8 );
+    if ( error )
+      return error;
+
+    format = FT_GET_ULONG_LE();
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+      nbitmaps  = FT_GET_ULONG();
+    else
+      nbitmaps  = FT_GET_ULONG_LE();
+
+    FT_Stream_ExitFrame( stream );
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+      return PCF_Err_Invalid_File_Format;
+
+    if ( nbitmaps != face->nmetrics )
+      return PCF_Err_Invalid_File_Format;
+
+    if ( FT_NEW_ARRAY( offsets, nbitmaps ) )
+      return error;
+
+    for ( i = 0; i < nbitmaps; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_LONG( offsets[i] );
+      else
+        (void)FT_READ_LONG_LE( offsets[i] );
+
+      FT_TRACE4(( "bitmap %d is at offset %ld\n", i, offsets[i] ));
+    }
+    if ( error )
+      goto Bail;
+
+    for ( i = 0; i < GLYPHPADOPTIONS; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        (void)FT_READ_LONG( bitmapSizes[i] );
+      else
+        (void)FT_READ_LONG_LE( bitmapSizes[i] );
+      if ( error )
+        goto Bail;
+
+      sizebitmaps = bitmapSizes[PCF_GLYPH_PAD_INDEX( format )];
+
+      FT_TRACE4(( "padding %d implies a size of %ld\n", i, bitmapSizes[i] ));
+    }
+
+    FT_TRACE4(( "  %d bitmaps, padding index %ld\n",
+                nbitmaps,
+                PCF_GLYPH_PAD_INDEX( format ) ));
+    FT_TRACE4(( "bitmap size = %d\n", sizebitmaps ));
+
+    FT_UNUSED( sizebitmaps );       /* only used for debugging */
+
+    for ( i = 0; i < nbitmaps; i++ )
+      face->metrics[i].bits = stream->pos + offsets[i];
+
+    face->bitmapsFormat = format;
+
+    FT_FREE ( offsets );
+    return error;
+
+  Bail:
+    FT_FREE ( offsets );
+    FT_FREE ( bitmaps );
+    return error;
+  }
+
+
+  static FT_Error
+  pcf_get_encodings( FT_Stream  stream,
+                     PCF_Face   face )
+  {
+    FT_Error      error   = PCF_Err_Ok;
+    FT_Memory     memory  = FT_FACE(face)->memory;
+    FT_ULong      format, size;
+    int           firstCol, lastCol;
+    int           firstRow, lastRow;
+    int           nencoding, encodingOffset;
+    int           i, j;
+    PCF_Encoding  tmpEncoding, encoding = 0;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    PCF_BDF_ENCODINGS,
+                                    &format,
+                                    &size );
+    if ( error )
+      return error;
+
+    error = FT_Stream_EnterFrame( stream, 14 );
+    if ( error )
+      return error;
+
+    format = FT_GET_ULONG_LE();
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+    {
+      firstCol          = FT_GET_SHORT();
+      lastCol           = FT_GET_SHORT();
+      firstRow          = FT_GET_SHORT();
+      lastRow           = FT_GET_SHORT();
+      face->defaultChar = FT_GET_SHORT();
+    }
+    else
+    {
+      firstCol          = FT_GET_SHORT_LE();
+      lastCol           = FT_GET_SHORT_LE();
+      firstRow          = FT_GET_SHORT_LE();
+      lastRow           = FT_GET_SHORT_LE();
+      face->defaultChar = FT_GET_SHORT_LE();
+    }
+
+    FT_Stream_ExitFrame( stream );
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) )
+      return PCF_Err_Invalid_File_Format;
+
+    FT_TRACE4(( "enc: firstCol %d, lastCol %d, firstRow %d, lastRow %d\n",
+                firstCol, lastCol, firstRow, lastRow ));
+
+    nencoding = ( lastCol - firstCol + 1 ) * ( lastRow - firstRow + 1 );
+
+    if ( FT_NEW_ARRAY( tmpEncoding, nencoding ) )
+      return PCF_Err_Out_Of_Memory;
+
+    error = FT_Stream_EnterFrame( stream, 2 * nencoding );
+    if ( error )
+      goto Bail;
+
+    for ( i = 0, j = 0 ; i < nencoding; i++ )
+    {
+      if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+        encodingOffset = FT_GET_SHORT();
+      else
+        encodingOffset = FT_GET_SHORT_LE();
+
+      if ( encodingOffset != -1 )
+      {
+        tmpEncoding[j].enc = ( ( ( i / ( lastCol - firstCol + 1 ) ) +
+                                 firstRow ) * 256 ) +
+                               ( ( i % ( lastCol - firstCol + 1 ) ) +
+                                 firstCol );
+
+        tmpEncoding[j].glyph = (FT_Short)encodingOffset;
+        j++;
+      }
+
+      FT_TRACE4(( "enc n. %d ; Uni %ld ; Glyph %d\n",
+                  i, tmpEncoding[j - 1].enc, encodingOffset ));
+    }
+    FT_Stream_ExitFrame( stream );
+
+    if ( FT_NEW_ARRAY( encoding, j ) )
+      goto Bail;
+
+    for ( i = 0; i < j; i++ )
+    {
+      encoding[i].enc   = tmpEncoding[i].enc;
+      encoding[i].glyph = tmpEncoding[i].glyph;
+    }
+
+    face->nencodings = j;
+    face->encodings  = encoding;
+    FT_FREE( tmpEncoding );
+
+    return error;
+
+  Bail:
+    FT_FREE( encoding );
+    FT_FREE( tmpEncoding );
+    return error;
+  }
+
+
+  static
+  const FT_Frame_Field  pcf_accel_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_AccelRec
+
+    FT_FRAME_START( 20 ),
+      FT_FRAME_BYTE      ( noOverlap ),
+      FT_FRAME_BYTE      ( constantMetrics ),
+      FT_FRAME_BYTE      ( terminalFont ),
+      FT_FRAME_BYTE      ( constantWidth ),
+      FT_FRAME_BYTE      ( inkInside ),
+      FT_FRAME_BYTE      ( inkMetrics ),
+      FT_FRAME_BYTE      ( drawDirection ),
+      FT_FRAME_SKIP_BYTES( 1 ),
+      FT_FRAME_LONG_LE   ( fontAscent ),
+      FT_FRAME_LONG_LE   ( fontDescent ),
+      FT_FRAME_LONG_LE   ( maxOverlap ),
+    FT_FRAME_END
+  };
+
+
+  static
+  const FT_Frame_Field  pcf_accel_msb_header[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PCF_AccelRec
+
+    FT_FRAME_START( 20 ),
+      FT_FRAME_BYTE      ( noOverlap ),
+      FT_FRAME_BYTE      ( constantMetrics ),
+      FT_FRAME_BYTE      ( terminalFont ),
+      FT_FRAME_BYTE      ( constantWidth ),
+      FT_FRAME_BYTE      ( inkInside ),
+      FT_FRAME_BYTE      ( inkMetrics ),
+      FT_FRAME_BYTE      ( drawDirection ),
+      FT_FRAME_SKIP_BYTES( 1 ),
+      FT_FRAME_LONG      ( fontAscent ),
+      FT_FRAME_LONG      ( fontDescent ),
+      FT_FRAME_LONG      ( maxOverlap ),
+    FT_FRAME_END
+  };
+
+
+  static FT_Error
+  pcf_get_accel( FT_Stream  stream,
+                 PCF_Face   face,
+                 FT_ULong   type )
+  {
+    FT_ULong   format, size;
+    FT_Error   error = PCF_Err_Ok;
+    PCF_Accel  accel = &face->accel;
+
+
+    error = pcf_seek_to_table_type( stream,
+                                    face->toc.tables,
+                                    face->toc.count,
+                                    type,
+                                    &format,
+                                    &size );
+    if ( error )
+      goto Bail;
+
+    error = FT_READ_ULONG_LE( format );
+
+    if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT )    &&
+         !PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+      goto Bail;
+
+    if ( PCF_BYTE_ORDER( format ) == MSBFirst )
+    {
+      if ( FT_STREAM_READ_FIELDS( pcf_accel_msb_header, accel ) )
+        goto Bail;
+    }
+    else
+    {
+      if ( FT_STREAM_READ_FIELDS( pcf_accel_header, accel ) )
+        goto Bail;
+    }
+
+    error = pcf_get_metric( stream,
+                            format & ( ~PCF_FORMAT_MASK ),
+                            &(accel->minbounds) );
+    if ( error )
+      goto Bail;
+
+    error = pcf_get_metric( stream,
+                            format & ( ~PCF_FORMAT_MASK ),
+                            &(accel->maxbounds) );
+    if ( error )
+      goto Bail;
+
+    if ( PCF_FORMAT_MATCH( format, PCF_ACCEL_W_INKBOUNDS ) )
+    {
+      error = pcf_get_metric( stream,
+                              format & ( ~PCF_FORMAT_MASK ),
+                              &(accel->ink_minbounds) );
+      if ( error )
+        goto Bail;
+
+      error = pcf_get_metric( stream,
+                              format & ( ~PCF_FORMAT_MASK ),
+                              &(accel->ink_maxbounds) );
+      if ( error )
+        goto Bail;
+    }
+    else
+    {
+      accel->ink_minbounds = accel->minbounds; /* I'm not sure about this */
+      accel->ink_maxbounds = accel->maxbounds;
+    }
+    return error;
+
+  Bail:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pcf_load_font( FT_Stream  stream,
+                 PCF_Face   face )
+  {
+    FT_Error   error  = PCF_Err_Ok;
+    FT_Memory  memory = FT_FACE(face)->memory;
+    FT_Bool    hasBDFAccelerators;
+
+
+    error = pcf_read_TOC( stream, face );
+    if ( error )
+      goto Exit;
+
+    error = pcf_get_properties( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* Use the old accelerators if no BDF accelerators are in the file. */
+    hasBDFAccelerators = pcf_has_table_type( face->toc.tables,
+                                             face->toc.count,
+                                             PCF_BDF_ACCELERATORS );
+    if ( !hasBDFAccelerators )
+    {
+      error = pcf_get_accel( stream, face, PCF_ACCELERATORS );
+      if ( error )
+        goto Exit;
+    }
+
+    /* metrics */
+    error = pcf_get_metrics( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* bitmaps */
+    error = pcf_get_bitmaps( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* encodings */
+    error = pcf_get_encodings( stream, face );
+    if ( error )
+      goto Exit;
+
+    /* BDF style accelerators (i.e. bounds based on encoded glyphs) */
+    if ( hasBDFAccelerators )
+    {
+      error = pcf_get_accel( stream, face, PCF_BDF_ACCELERATORS );
+      if ( error )
+        goto Exit;
+    }
+
+    /* XXX: TO DO: inkmetrics and glyph_names are missing */
+
+    /* now construct the face object */
+    {
+      FT_Face       root = FT_FACE( face );
+      PCF_Property  prop;
+      int           size_set = 0;
+
+
+      root->num_faces = 1;
+      root->face_index = 0;
+      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+                         FT_FACE_FLAG_HORIZONTAL  |
+                         FT_FACE_FLAG_FAST_GLYPHS;
+
+      if ( face->accel.constantWidth )
+        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+      root->style_flags = 0;
+      prop = pcf_find_property( face, "SLANT" );
+      if ( prop != NULL )
+        if ( prop->isString )
+          if ( ( *(prop->value.atom) == 'O' ) ||
+               ( *(prop->value.atom) == 'I' ) )
+            root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+      prop = pcf_find_property( face, "WEIGHT_NAME" );
+      if ( prop != NULL )
+        if ( prop->isString )
+          if ( *(prop->value.atom) == 'B' )
+            root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+      root->style_name = (char *)"Regular";
+
+      if ( root->style_flags & FT_STYLE_FLAG_BOLD ) {
+        if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+          root->style_name = (char *)"Bold Italic";
+        else
+          root->style_name = (char *)"Bold";
+      }
+      else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+        root->style_name = (char *)"Italic";
+
+      prop = pcf_find_property( face, "FAMILY_NAME" );
+      if ( prop != NULL )
+      {
+        if ( prop->isString )
+        {
+          int  l = ft_strlen( prop->value.atom ) + 1;
+
+
+          if ( FT_NEW_ARRAY( root->family_name, l ) )
+            goto Exit;
+          ft_strcpy( root->family_name, prop->value.atom );
+        }
+      }
+      else
+        root->family_name = 0;
+
+      root->num_glyphs = face->nmetrics;
+
+      root->num_fixed_sizes = 1;
+      if ( FT_NEW_ARRAY( root->available_sizes, 1 ) )
+        goto Exit;
+
+      prop = pcf_find_property( face, "PIXEL_SIZE" );
+      if ( prop != NULL )
+      {
+        root->available_sizes->height =
+        root->available_sizes->width  = (FT_Short)( prop->value.integer );
+
+        size_set = 1;
+      }
+      else
+      {
+        prop = pcf_find_property( face, "POINT_SIZE" );
+        if ( prop != NULL )
+        {
+          PCF_Property  xres, yres, avgw;
+
+
+          xres = pcf_find_property( face, "RESOLUTION_X" );
+          yres = pcf_find_property( face, "RESOLUTION_Y" );
+          avgw = pcf_find_property( face, "AVERAGE_WIDTH" );
+
+          if ( ( yres != NULL ) && ( xres != NULL ) )
+          {
+            root->available_sizes->height =
+              (FT_Short)( prop->value.integer *
+                          yres->value.integer / 720 );
+
+              root->available_sizes->width =
+                (FT_Short)( prop->value.integer *
+                            xres->value.integer / 720 );
+
+            size_set = 1;
+          }
+        }
+      }
+
+      if (size_set == 0 )
+      {
+        root->available_sizes->width  = 12;
+        root->available_sizes->height = 12;
+      }
+
+      /* set-up charset */
+      {
+        PCF_Property  charset_registry = 0, charset_encoding = 0;
+
+
+        charset_registry = pcf_find_property( face, "CHARSET_REGISTRY" );
+        charset_encoding = pcf_find_property( face, "CHARSET_ENCODING" );
+
+        if ( ( charset_registry != NULL ) &&
+             ( charset_encoding != NULL ) )
+        {
+          if ( ( charset_registry->isString ) &&
+               ( charset_encoding->isString ) )
+          {
+            if ( FT_NEW_ARRAY( face->charset_encoding,
+                               ft_strlen( charset_encoding->value.atom ) + 1 ) )
+              goto Exit;
+
+            if ( FT_NEW_ARRAY( face->charset_registry,
+                               ft_strlen( charset_registry->value.atom ) + 1 ) )
+              goto Exit;
+
+            ft_strcpy( face->charset_registry, charset_registry->value.atom );
+            ft_strcpy( face->charset_encoding, charset_encoding->value.atom );
+          }
+        }
+      }
+    }
+
+  Exit:
+    if ( error )
+    {
+      /* this is done to respect the behaviour of the original */
+      /* PCF font driver.                                      */
+      error = PCF_Err_Invalid_File_Format;
+    }
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfutil.c
@@ -1,0 +1,215 @@
+/*
+
+Copyright 1990, 1994, 1998  The Open Group
+
+All Rights Reserved.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+/* $XFree86: xc/lib/font/util/utilbitmap.c,v 1.3 1999/08/22 08:58:58 dawes Exp $ */
+
+/*
+ * Author:  Keith Packard, MIT X Consortium
+ */
+
+
+#include <ft2build.h>
+#include "pcfutil.h"
+
+
+  /* Utility functions for reformatting font bitmaps */
+
+  static const unsigned char  _reverse_byte[0x100] =
+  {
+    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+  };
+
+  /*
+   *  Invert bit order within each BYTE of an array.
+   */
+
+  void
+  BitOrderInvert( unsigned char*  buf,
+                  int             nbytes )
+  {
+    const unsigned char*  rev = _reverse_byte;
+
+
+    for ( ; --nbytes >= 0; buf++ )
+      *buf = rev[*buf];
+  }
+
+
+  /*
+   *  Invert byte order within each 16-bits of an array.
+   */
+
+  void
+  TwoByteSwap( unsigned char*  buf,
+               int             nbytes )
+  {
+    unsigned char  c;
+
+
+    for ( ; nbytes > 0; nbytes -= 2, buf += 2 )
+    {
+      c      = buf[0];
+      buf[0] = buf[1];
+      buf[1] = c;
+    }
+  }
+
+  /*
+   *  Invert byte order within each 32-bits of an array.
+   */
+
+  void
+  FourByteSwap( unsigned char*  buf,
+                int             nbytes )
+  {
+    unsigned char  c;
+
+
+    for ( ; nbytes > 0; nbytes -= 4, buf += 4 )
+    {
+      c      = buf[0];
+      buf[0] = buf[3];
+      buf[3] = c;
+
+      c      = buf[1];
+      buf[1] = buf[2];
+      buf[2] = c;
+    }
+  }
+
+
+  /*
+   *  Repad a bitmap.
+   */
+
+  int
+  RepadBitmap( char*         pSrc,
+               char*         pDst,
+               unsigned int  srcPad,
+               unsigned int  dstPad,
+               int           width,
+               int           height )
+  {
+    int   srcWidthBytes, dstWidthBytes;
+    int   row, col;
+    char  *pTmpSrc, *pTmpDst;
+
+
+    switch ( srcPad )
+    {
+    case 1:
+      srcWidthBytes = ( width + 7 ) >> 3;
+      break;
+
+    case 2:
+      srcWidthBytes = ( ( width + 15 ) >> 4 ) << 1;
+      break;
+
+    case 4:
+      srcWidthBytes = ( ( width + 31 ) >> 5 ) << 2;
+      break;
+
+    case 8:
+      srcWidthBytes = ( ( width + 63 ) >> 6 ) << 3;
+      break;
+
+    default:
+      return 0;
+    }
+
+    switch ( dstPad )
+    {
+    case 1:
+      dstWidthBytes = ( width + 7 ) >> 3;
+      break;
+
+    case 2:
+      dstWidthBytes = ( ( width + 15 ) >> 4 ) << 1;
+      break;
+
+    case 4:
+      dstWidthBytes = ( ( width + 31 ) >> 5 ) << 2;
+      break;
+
+    case 8:
+      dstWidthBytes = ( ( width + 63 ) >> 6 ) << 3;
+      break;
+
+    default:
+      return 0;
+    }
+
+    width = srcWidthBytes;
+    if ( width > dstWidthBytes )
+      width = dstWidthBytes;
+
+    pTmpSrc= pSrc;
+    pTmpDst= pDst;
+
+    for ( row = 0; row < height; row++ )
+    {
+      for ( col = 0; col < width; col++ )
+        *pTmpDst++ = *pTmpSrc++;
+
+      while ( col < dstWidthBytes )
+      {
+        *pTmpDst++ = '\0';
+        col++;
+      }
+      pTmpSrc += srcWidthBytes - width;
+    }
+
+    return dstWidthBytes * height;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pcfutil.h
@@ -1,0 +1,58 @@
+/*  pcfutil.h
+
+    FreeType font driver for pcf fonts
+
+  Copyright 2000-2001 by
+  Francesco Zappa Nardelli
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __PCFUTIL_H__
+#define __PCFUTIL_H__
+
+
+#include <ft2build.h>
+
+
+  void
+  BitOrderInvert( unsigned char*  buf,
+                  int             nbytes);
+
+  void
+  TwoByteSwap( unsigned char*  buf,
+               int             nbytes);
+
+  void
+  FourByteSwap( unsigned char*  buf,
+                int             nbytes);
+
+  int
+  RepadBitmap( char*           pSrc,
+               char*           pDst,
+               unsigned int    srcPad,
+               unsigned int    dstPad,
+               int             width,
+               int             height);
+
+#endif /* __PCFUTIL_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfr.c
@@ -1,0 +1,29 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfr.c                                                                  */
+/*                                                                         */
+/*    FreeType PFR driver component.                                       */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+
+#include "pfrload.c"
+#include "pfrgload.c"
+#include "pfrcmap.c"
+#include "pfrobjs.c"
+#include "pfrdrivr.c"
+#include "pfrsbit.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrcmap.c
@@ -1,0 +1,158 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrcmap.c                                                              */
+/*                                                                         */
+/*    FreeType PFR cmap handling (body).                                   */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "pfrcmap.h" 
+#include "pfrobjs.h"
+#include FT_INTERNAL_DEBUG_H
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  pfr_cmap_init( PFR_CMap  cmap )
+  {
+    PFR_Face  face = (PFR_Face)FT_CMAP_FACE( cmap );
+
+
+    cmap->num_chars = face->phy_font.num_chars;
+    cmap->chars     = face->phy_font.chars;
+    
+    /* just for safety, check that the character entries are correctly */
+    /* sorted in increasing character code order                       */
+    {
+      FT_UInt  n;
+      
+
+      for ( n = 1; n < cmap->num_chars; n++ )
+      {
+        if ( cmap->chars[n - 1].char_code >= cmap->chars[n].char_code )
+          FT_ASSERT( 0 );
+      }
+    }
+    
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  pfr_cmap_done( PFR_CMap  cmap )
+  {
+    cmap->chars     = NULL;
+    cmap->num_chars = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  pfr_cmap_char_index( PFR_CMap   cmap,
+                       FT_UInt32  char_code )
+  {
+    FT_UInt   min = 0;
+    FT_UInt   max = cmap->num_chars;
+    FT_UInt   mid;
+    PFR_Char  gchar;
+
+
+    while ( min < max )
+    {
+      mid   = min + ( max - min ) / 2;
+      gchar = cmap->chars + mid;
+
+      if ( gchar->char_code == char_code )
+        return mid + 1;
+
+      if ( gchar->char_code < char_code )
+        min = mid + 1;
+      else
+        max = mid;
+    }
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  pfr_cmap_char_next( PFR_CMap    cmap,
+                      FT_UInt32  *pchar_code )
+  {
+    FT_UInt    result    = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+
+
+  Restart:
+    {
+      FT_UInt   min = 0;
+      FT_UInt   max = cmap->num_chars;
+      FT_UInt   mid;
+      PFR_Char  gchar;
+
+
+      while ( min < max )
+      {
+        mid   = min + ( ( max - min ) >> 1 );
+        gchar = cmap->chars + mid;
+
+        if ( gchar->char_code == char_code )
+        {
+          result = mid;
+          if ( result != 0 )
+          {
+            result++;
+            goto Exit;
+          }
+
+          char_code++;
+          goto Restart;
+        }
+
+        if ( gchar->char_code < char_code )
+          min = mid+1;
+        else
+          max = mid;
+      }
+
+      /* we didn't find it, but we have a pair just above it */
+      char_code = 0;
+
+      if ( min < cmap->num_chars )
+      {
+        gchar  = cmap->chars + min;
+        result = min;
+        if ( result != 0 )
+        {
+          result++;
+          char_code = gchar->char_code;
+        }
+      }
+    }
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+  pfr_cmap_class_rec =
+  {
+    sizeof ( PFR_CMapRec ),
+
+    (FT_CMap_InitFunc)     pfr_cmap_init,
+    (FT_CMap_DoneFunc)     pfr_cmap_done,
+    (FT_CMap_CharIndexFunc)pfr_cmap_char_index,
+    (FT_CMap_CharNextFunc) pfr_cmap_char_next
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrcmap.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrcmap.h                                                              */
+/*                                                                         */
+/*    FreeType PFR cmap handling (specification).                          */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PFRCMAP_H__
+#define __PFRCMAP_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "pfrtypes.h"
+
+
+FT_BEGIN_HEADER
+
+  typedef struct  PFR_CMapRec_
+  {
+    FT_CMapRec  cmap;
+    FT_UInt     num_chars;
+    PFR_Char    chars;
+  
+  } PFR_CMapRec, *PFR_CMap;
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec  pfr_cmap_class_rec;
+
+FT_END_HEADER
+
+
+#endif /* __PFRCMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrdrivr.c
@@ -1,0 +1,168 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrdrivr.c                                                             */
+/*                                                                         */
+/*    FreeType PFR driver interface (body).                                */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_PFR_H
+#include "pfrdrivr.h"
+#include "pfrobjs.h"
+
+
+  static FT_Error
+  pfr_get_kerning( PFR_Face    face,
+                   FT_UInt     left,
+                   FT_UInt     right,
+                   FT_Vector  *avector )
+  {
+    FT_Error  error;
+
+    error = pfr_face_get_kerning( face, left, right, avector );
+    if ( !error )
+    {
+      PFR_PhyFont  phys = &face->phy_font;
+
+      /* convert from metrics to outline units when necessary */
+      if ( phys->outline_resolution != phys->metrics_resolution )
+      {
+        if ( avector->x != 0 )
+          avector->x = FT_MulDiv( avector->x, phys->outline_resolution,
+                                              phys->metrics_resolution );
+
+        if ( avector->y != 0 )
+          avector->y = FT_MulDiv( avector->x, phys->outline_resolution,
+                                              phys->metrics_resolution );
+      }
+    }
+    return error;
+  }
+
+
+  static FT_Error
+  pfr_get_advance( PFR_Face   face,
+                   FT_UInt    gindex,
+                   FT_Pos    *aadvance )
+  {
+    FT_Error     error = FT_Err_Bad_Argument;
+
+    *aadvance = 0;
+    if ( face )
+    {
+      PFR_PhyFont  phys  = &face->phy_font;
+
+      if ( gindex < phys->num_chars )
+      {
+        *aadvance = phys->chars[ gindex ].advance;
+        error = 0;
+      }
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  pfr_get_metrics( PFR_Face   face,
+                   FT_UInt   *aoutline_resolution,
+                   FT_UInt   *ametrics_resolution,
+                   FT_Fixed  *ametrics_x_scale,
+                   FT_Fixed  *ametrics_y_scale )
+  {
+    PFR_PhyFont  phys  = &face->phy_font;
+    FT_Fixed     x_scale, y_scale;
+    FT_Size      size = face->root.size;
+
+    if ( aoutline_resolution )
+      *aoutline_resolution = phys->outline_resolution;
+
+    if ( ametrics_resolution )
+      *ametrics_resolution = phys->metrics_resolution;
+
+    x_scale = 0x10000L;
+    y_scale = 0x10000L;
+
+    if ( size )
+    {
+      x_scale = FT_DivFix( size->metrics.x_ppem << 6,
+                           phys->metrics_resolution );
+
+      y_scale = FT_DivFix( size->metrics.y_ppem << 6,
+                           phys->metrics_resolution );
+    }
+
+    if ( ametrics_x_scale )
+      *ametrics_x_scale = x_scale;
+
+    if ( ametrics_y_scale )
+      *ametrics_y_scale = y_scale;
+
+    return 0;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_PFR_ServiceRec  pfr_service_rec =
+  {
+    (FT_PFR_GetMetricsFunc)  pfr_get_metrics,
+    (FT_PFR_GetKerningFunc)  pfr_get_kerning,
+    (FT_PFR_GetAdvanceFunc)  pfr_get_advance
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  pfr_driver_class =
+  {
+    {
+      ft_module_font_driver      |
+      ft_module_driver_scalable,
+
+      sizeof( FT_DriverRec ),
+
+      "pfr",
+      0x10000L,
+      0x20000L,
+
+      (FT_PFR_Service)  &pfr_service_rec,   /* format interface */
+
+      (FT_Module_Constructor)NULL,
+      (FT_Module_Destructor) NULL,
+      (FT_Module_Requester)  NULL
+    },
+
+    sizeof( PFR_FaceRec ),
+    sizeof( PFR_SizeRec ),
+    sizeof( PFR_SlotRec ),
+
+    (FT_Face_InitFunc)        pfr_face_init,
+    (FT_Face_DoneFunc)        pfr_face_done,
+    (FT_Size_InitFunc)        NULL,
+    (FT_Size_DoneFunc)        NULL,
+    (FT_Slot_InitFunc)        pfr_slot_init,
+    (FT_Slot_DoneFunc)        pfr_slot_done,
+
+    (FT_Size_ResetPointsFunc) NULL,
+    (FT_Size_ResetPixelsFunc) NULL,
+    (FT_Slot_LoadFunc)        pfr_slot_load,
+
+    (FT_Face_GetKerningFunc)  pfr_get_kerning,
+    (FT_Face_AttachFunc)      0,
+    (FT_Face_GetAdvancesFunc) 0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrdrivr.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrdrivr.h                                                             */
+/*                                                                         */
+/*    High-level Type PFR driver interface (specification).                */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PFRDRIVR_H__
+#define __PFRDRIVR_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Driver_ClassRec )  pfr_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __PFRDRIVR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrerror.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrerror.h                                                             */
+/*                                                                         */
+/*    PFR error codes (specification only).                                */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the PFR error enumeration constants.      */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __PFRERROR_H__
+#define __PFRERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  PFR_Err_
+#define FT_ERR_BASE    FT_Mod_Err_PFR
+
+#include FT_ERRORS_H
+
+#endif /* __PFRERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrgload.c
@@ -1,0 +1,801 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrgload.c                                                             */
+/*                                                                         */
+/*    FreeType PFR glyph loader (body).                                    */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "pfrgload.h"
+#include "pfrsbit.h"
+#include "pfrload.h"            /* for macro definitions */
+#include FT_INTERNAL_DEBUG_H
+
+#include "pfrerror.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pfr
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      PFR GLYPH BUILDER                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( void )
+  pfr_glyph_init( PFR_Glyph       glyph,
+                  FT_GlyphLoader  loader )
+  {
+    FT_ZERO( glyph );
+
+    glyph->loader     = loader;
+    glyph->path_begun = 0;
+
+    FT_GlyphLoader_Rewind( loader );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  pfr_glyph_done( PFR_Glyph  glyph )
+  {
+    FT_Memory  memory = glyph->loader->memory;
+
+
+    FT_FREE( glyph->x_control );
+    glyph->y_control = NULL;
+
+    glyph->max_xy_control = 0;
+    glyph->num_x_control  = 0;
+    glyph->num_y_control  = 0;
+
+    FT_FREE( glyph->subs );
+
+    glyph->max_subs = 0;
+    glyph->num_subs = 0;
+
+    glyph->loader     = NULL;
+    glyph->path_begun = 0;
+  }
+
+
+  /* close current contour, if any */
+  static void
+  pfr_glyph_close_contour( PFR_Glyph  glyph )
+  {
+    FT_GlyphLoader  loader  = glyph->loader;
+    FT_Outline*     outline = &loader->current.outline;
+    FT_Int          last, first;
+
+
+    if ( !glyph->path_begun )
+      return;
+
+    /* compute first and last point indices in current glyph outline */
+    last  = outline->n_points - 1;
+    first = 0;
+    if ( outline->n_contours > 0 )
+      first = outline->contours[outline->n_contours - 1];
+
+    /* if the last point falls on the same location than the first one */
+    /* we need to delete it                                            */
+    if ( last > first )
+    {
+      FT_Vector*  p1 = outline->points + first;
+      FT_Vector*  p2 = outline->points + last;
+
+
+      if ( p1->x == p2->x && p1->y == p2->y )
+      {
+        outline->n_points--;
+        last--;
+      }
+    }
+
+    /* don't add empty contours */
+    if ( last >= first )
+      outline->contours[outline->n_contours++] = (short)last;
+
+    glyph->path_begun = 0;
+  }
+
+
+  /* reset glyph to start the loading of a new glyph */
+  static void
+  pfr_glyph_start( PFR_Glyph  glyph )
+  {
+    glyph->path_begun = 0;
+  }
+
+
+  static FT_Error
+  pfr_glyph_line_to( PFR_Glyph   glyph,
+                     FT_Vector*  to )
+  {
+    FT_GlyphLoader  loader  = glyph->loader;
+    FT_Outline*     outline = &loader->current.outline;
+    FT_Error        error;
+
+
+    /* check that we have begun a new path */
+    FT_ASSERT( glyph->path_begun != 0 );
+
+    error = FT_GlyphLoader_CheckPoints( loader, 1, 0 );
+    if ( !error )
+    {
+      FT_UInt  n = outline->n_points;
+
+
+      outline->points[n] = *to;
+      outline->tags  [n] = FT_CURVE_TAG_ON;
+
+      outline->n_points++;
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  pfr_glyph_curve_to( PFR_Glyph   glyph,
+                      FT_Vector*  control1,
+                      FT_Vector*  control2,
+                      FT_Vector*  to )
+  {
+    FT_GlyphLoader  loader  = glyph->loader;
+    FT_Outline*     outline = &loader->current.outline;
+    FT_Error        error;
+
+
+    /* check that we have begun a new path */
+    FT_ASSERT( glyph->path_begun != 0 );
+
+    error = FT_GlyphLoader_CheckPoints( loader, 3, 0 );
+    if ( !error )
+    {
+      FT_Vector*  vec = outline->points         + outline->n_points;
+      FT_Byte*    tag = (FT_Byte*)outline->tags + outline->n_points;
+
+
+      vec[0] = *control1;
+      vec[1] = *control2;
+      vec[2] = *to;
+      tag[0] = FT_CURVE_TAG_CUBIC;
+      tag[1] = FT_CURVE_TAG_CUBIC;
+      tag[2] = FT_CURVE_TAG_ON;
+
+      outline->n_points = (FT_Short)( outline->n_points + 3 );
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  pfr_glyph_move_to( PFR_Glyph   glyph,
+                     FT_Vector*  to )
+  {
+    FT_GlyphLoader  loader  = glyph->loader;
+    FT_Error        error;
+
+
+    /* close current contour if any */
+    pfr_glyph_close_contour( glyph );
+
+    /* indicate that a new contour has started */
+    glyph->path_begun = 1;
+
+    /* check that there is room for a new contour and a new point */
+    error = FT_GlyphLoader_CheckPoints( loader, 1, 1 );
+    if ( !error )
+      /* add new start point */
+      error = pfr_glyph_line_to( glyph, to );
+
+    return error;
+  }
+
+
+  static void
+  pfr_glyph_end( PFR_Glyph  glyph )
+  {
+    /* close current contour if any */
+    pfr_glyph_close_contour( glyph );
+
+    /* merge the current glyph into the stack */
+    FT_GlyphLoader_Add( glyph->loader );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      PFR GLYPH LOADER                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* load a simple glyph */
+  static FT_Error
+  pfr_glyph_load_simple( PFR_Glyph  glyph,
+                         FT_Byte*   p,
+                         FT_Byte*   limit )
+  {
+    FT_Error   error  = 0;
+    FT_Memory  memory = glyph->loader->memory;
+    FT_UInt    flags, x_count, y_count, i, count, mask;
+    FT_Int     x;
+
+
+    PFR_CHECK( 1 );
+    flags = PFR_NEXT_BYTE( p );
+
+    /* test for composite glyphs */
+    FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) == 0 );
+
+    x_count = 0;
+    y_count = 0;
+
+    if ( flags & PFR_GLYPH_1BYTE_XYCOUNT )
+    {
+      PFR_CHECK( 1 );
+      count   = PFR_NEXT_BYTE( p );
+      x_count = ( count & 15 );
+      y_count = ( count >> 4 );
+    }
+    else
+    {
+      if ( flags & PFR_GLYPH_XCOUNT )
+      {
+        PFR_CHECK( 1 );
+        x_count = PFR_NEXT_BYTE( p );
+      }
+
+      if ( flags & PFR_GLYPH_YCOUNT )
+      {
+        PFR_CHECK( 1 );
+        y_count = PFR_NEXT_BYTE( p );
+      }
+    }
+
+    count = x_count + y_count;
+
+    /* re-allocate array when necessary */
+    if ( count > glyph->max_xy_control )
+    {
+      FT_UInt  new_max = ( count + 7 ) & -8;
+
+
+      if ( FT_RENEW_ARRAY( glyph->x_control,
+                           glyph->max_xy_control,
+                           new_max ) )
+        goto Exit;
+
+      glyph->max_xy_control = new_max;
+    }
+
+    glyph->y_control = glyph->x_control + x_count;
+
+    mask  = 0;
+    x     = 0;
+
+    for ( i = 0; i < count; i++ )
+    {
+      if ( ( i & 7 ) == 0 )
+      {
+        PFR_CHECK( 1 );
+        mask = PFR_NEXT_BYTE( p );
+      }
+
+      if ( mask & 1 )
+      {
+        PFR_CHECK( 2 );
+        x = PFR_NEXT_SHORT( p );
+      }
+      else
+      {
+        PFR_CHECK( 1 );
+        x += PFR_NEXT_BYTE( p );
+      }
+
+      glyph->x_control[i] = x;
+
+      mask >>= 1;
+    }
+
+    /* XXX: for now we ignore the secondary stroke and edge definitions */
+    /*      since we don't want to support native PFR hinting           */
+    /*                                                                  */
+    if ( flags & PFR_GLYPH_EXTRA_ITEMS )
+    {
+      error = pfr_extra_items_skip( &p, limit );
+      if ( error )
+        goto Exit;
+    }
+
+    pfr_glyph_start( glyph );
+
+    /* now load a simple glyph */
+    {
+      FT_Vector   pos[4];
+      FT_Vector*  cur;
+
+
+      pos[0].x = pos[0].y = 0;
+      pos[3]   = pos[0];
+
+      for (;;)
+      {
+        FT_Int  format, args_format = 0, args_count, n;
+
+
+        /***************************************************************/
+        /*  read instruction                                           */
+        /*                                                             */
+        PFR_CHECK( 1 );
+        format = PFR_NEXT_BYTE( p );
+
+        switch ( format >> 4 )
+        {
+        case 0:                             /* end glyph */
+          FT_TRACE6(( "- end glyph" ));
+          args_count = 0;
+          break;
+
+        case 1:                             /* general line operation */
+          FT_TRACE6(( "- general line" ));
+          goto Line1;
+
+        case 4:                             /* move to inside contour  */
+          FT_TRACE6(( "- move to inside" ));
+          goto Line1;
+
+        case 5:                             /* move to outside contour */
+          FT_TRACE6(( "- move to outside" ));
+        Line1:
+          args_format = format & 15;
+          args_count  = 1;
+          break;
+
+        case 2:                             /* horizontal line to */
+          FT_TRACE6(( "- horizontal line to cx.%d", format & 15 ));
+          pos[0].y   = pos[3].y;
+          pos[0].x   = glyph->x_control[format & 15];
+          pos[3]     = pos[0];
+          args_count = 0;
+          break;
+
+        case 3:                             /* vertical line to */
+          FT_TRACE6(( "- vertical line to cy.%d", format & 15 ));
+          pos[0].x   = pos[3].x;
+          pos[0].y   = glyph->y_control[format & 15];
+          pos[3] = pos[0];
+          args_count = 0;
+          break;
+
+        case 6:                             /* horizontal to vertical curve */
+          FT_TRACE6(( "- hv curve " ));
+          args_format  = 0xB8E;
+          args_count   = 3;
+          break;
+
+        case 7:                             /* vertical to horizontal curve */
+          FT_TRACE6(( "- vh curve" ));
+          args_format = 0xE2B;
+          args_count  = 3;
+          break;
+
+        default:                            /* general curve to */
+          FT_TRACE6(( "- general curve" ));
+          args_count  = 4;
+          args_format = format & 15;
+        }
+
+        /***********************************************************/
+        /*  now read arguments                                     */
+        /*                                                         */
+        cur = pos;
+        for ( n = 0; n < args_count; n++ )
+        {
+          FT_Int  idx, delta;
+
+
+          /* read the X argument */
+          switch ( args_format & 3 )
+          {
+          case 0:                           /* 8-bit index */
+            PFR_CHECK( 1 );
+            idx  = PFR_NEXT_BYTE( p );
+            cur->x = glyph->x_control[idx];
+            FT_TRACE7(( " cx#%d", idx ));
+            break;
+
+          case 1:                           /* 16-bit value */
+            PFR_CHECK( 2 );
+            cur->x = PFR_NEXT_SHORT( p );
+            FT_TRACE7(( " x.%d", cur->x ));
+            break;
+
+          case 2:                           /* 8-bit delta */
+            PFR_CHECK( 1 );
+            delta  = PFR_NEXT_INT8( p );
+            cur->x = pos[3].x + delta;
+            FT_TRACE7(( " dx.%d", delta ));
+            break;
+
+          default:
+            FT_TRACE7(( " |" ));
+            cur->x = pos[3].x;
+          }
+
+          /* read the Y argument */
+          switch ( ( args_format >> 2 ) & 3 )
+          {
+          case 0:                           /* 8-bit index */
+            PFR_CHECK( 1 );
+            idx  = PFR_NEXT_BYTE( p );
+            cur->y = glyph->y_control[idx];
+            FT_TRACE7(( " cy#%d", idx ));
+            break;
+
+          case 1:                           /* 16-bit absolute value */
+            PFR_CHECK( 2 );
+            cur->y = PFR_NEXT_SHORT( p );
+            FT_TRACE7(( " y.%d", cur->y ));
+            break;
+
+          case 2:                           /* 8-bit delta */
+            PFR_CHECK( 1 );
+            delta  = PFR_NEXT_INT8( p );
+            cur->y = pos[3].y + delta;
+            FT_TRACE7(( " dy.%d", delta ));
+            break;
+
+          default:
+            FT_TRACE7(( " -" ));
+            cur->y = pos[3].y;
+          }
+
+          /* read the additional format flag for the general curve */
+          if ( n == 0 && args_count == 4 )
+          {
+            PFR_CHECK( 1 );
+            args_format = PFR_NEXT_BYTE( p );
+            args_count--;
+          }
+          else
+            args_format >>= 4;
+
+          /* save the previous point */
+          pos[3] = cur[0];
+          cur++;
+        }
+
+        FT_TRACE7(( "\n" ));
+
+        /***********************************************************/
+        /*  finally, execute instruction                           */
+        /*                                                         */
+        switch ( format >> 4 )
+        {
+        case 0:                             /* end glyph => EXIT */
+          pfr_glyph_end( glyph );
+          goto Exit;
+
+        case 1:                             /* line operations */
+        case 2:
+        case 3:
+          error = pfr_glyph_line_to( glyph, pos );
+          goto Test_Error;
+
+        case 4:                             /* move to inside contour  */
+        case 5:                             /* move to outside contour */
+          error = pfr_glyph_move_to( glyph, pos );
+          goto Test_Error;
+
+        default:                            /* curve operations */
+          error = pfr_glyph_curve_to( glyph, pos, pos + 1, pos + 2 );
+
+        Test_Error:  /* test error condition */
+          if ( error )
+            goto Exit;
+        }
+      } /* for (;;) */
+    }
+
+  Exit:
+    return error;
+
+  Too_Short:
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_glyph_load_simple: invalid glyph data\n" ));
+    goto Exit;
+  }
+
+
+  /* load a composite/compound glyph */
+  static FT_Error
+  pfr_glyph_load_compound( PFR_Glyph  glyph,
+                           FT_Byte*   p,
+                           FT_Byte*   limit )
+  {
+    FT_Error        error  = 0;
+    FT_GlyphLoader  loader = glyph->loader;
+    FT_Memory       memory = loader->memory;
+    PFR_SubGlyph    subglyph;
+    FT_UInt         flags, i, count, org_count;
+    FT_Int          x_pos, y_pos;
+
+
+    PFR_CHECK( 1 );
+    flags = PFR_NEXT_BYTE( p );
+
+    /* test for composite glyphs */
+    FT_ASSERT( ( flags & PFR_GLYPH_IS_COMPOUND ) != 0 );
+
+    count = flags & 0x3F;
+
+    /* ignore extra items when present */
+    /*                                 */
+    if ( flags & PFR_GLYPH_EXTRA_ITEMS )
+    {
+      error = pfr_extra_items_skip( &p, limit );
+      if (error) goto Exit;
+    }
+
+    /* we can't rely on the FT_GlyphLoader to load sub-glyphs, because   */
+    /* the PFR format is dumb, using direct file offsets to point to the */
+    /* sub-glyphs (instead of glyph indices).  Sigh.                     */
+    /*                                                                   */
+    /* For now, we load the list of sub-glyphs into a different array    */
+    /* but this will prevent us from using the auto-hinter at its best   */
+    /* quality.                                                          */
+    /*                                                                   */
+    org_count = glyph->num_subs;
+
+    if ( org_count + count > glyph->max_subs )
+    {
+      FT_UInt  new_max = ( org_count + count + 3 ) & -4;
+
+
+      if ( FT_RENEW_ARRAY( glyph->subs, glyph->max_subs, new_max ) )
+        goto Exit;
+
+      glyph->max_subs = new_max;
+    }
+
+    subglyph = glyph->subs + org_count;
+
+    for ( i = 0; i < count; i++, subglyph++ )
+    {
+      FT_UInt  format;
+
+
+      x_pos = 0;
+      y_pos = 0;
+
+      PFR_CHECK( 1 );
+      format = PFR_NEXT_BYTE( p );
+
+      /* read scale when available */
+      subglyph->x_scale = 0x10000L;
+      if ( format & PFR_SUBGLYPH_XSCALE )
+      {
+        PFR_CHECK( 2 );
+        subglyph->x_scale = PFR_NEXT_SHORT( p ) << 4;
+      }
+
+      subglyph->y_scale = 0x10000L;
+      if ( format & PFR_SUBGLYPH_YSCALE )
+      {
+        PFR_CHECK( 2 );
+        subglyph->y_scale = PFR_NEXT_SHORT( p ) << 4;
+      }
+
+      /* read offset */
+      switch ( format & 3 )
+      {
+      case 1:
+        PFR_CHECK( 2 );
+        x_pos = PFR_NEXT_SHORT( p );
+        break;
+
+      case 2:
+        PFR_CHECK( 1 );
+        x_pos += PFR_NEXT_INT8( p );
+        break;
+
+      default:
+        ;
+      }
+
+      switch ( ( format >> 2 ) & 3 )
+      {
+      case 1:
+        PFR_CHECK( 2 );
+        y_pos = PFR_NEXT_SHORT( p );
+        break;
+
+      case 2:
+        PFR_CHECK( 1 );
+        y_pos += PFR_NEXT_INT8( p );
+        break;
+
+      default:
+        ;
+      }
+
+      subglyph->x_delta = x_pos;
+      subglyph->y_delta = y_pos;
+
+      /* read glyph position and size now */
+      if ( format & PFR_SUBGLYPH_2BYTE_SIZE )
+      {
+        PFR_CHECK( 2 );
+        subglyph->gps_size = PFR_NEXT_USHORT( p );
+      }
+      else
+      {
+        PFR_CHECK( 1 );
+        subglyph->gps_size = PFR_NEXT_BYTE( p );
+      }
+
+      if ( format & PFR_SUBGLYPH_3BYTE_OFFSET )
+      {
+        PFR_CHECK( 3 );
+        subglyph->gps_offset = PFR_NEXT_LONG( p );
+      }
+      else
+      {
+        PFR_CHECK( 2 );
+        subglyph->gps_offset = PFR_NEXT_USHORT( p );
+      }
+
+      glyph->num_subs++;
+    }
+
+  Exit:
+    return error;
+
+  Too_Short:
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_glyph_load_compound: invalid glyph data\n" ));
+    goto Exit;
+  }
+
+
+
+
+
+  static FT_Error
+  pfr_glyph_load_rec( PFR_Glyph  glyph,
+                      FT_Stream  stream,
+                      FT_ULong   gps_offset,
+                      FT_ULong   offset,
+                      FT_ULong   size )
+  {
+    FT_Error  error;
+    FT_Byte*  p;
+    FT_Byte*  limit;
+
+
+    if ( FT_STREAM_SEEK( gps_offset + offset ) ||
+         FT_FRAME_ENTER( size )                )
+      goto Exit;
+
+    p     = (FT_Byte*)stream->cursor;
+    limit = p + size;
+
+    if ( size > 0 && *p & PFR_GLYPH_IS_COMPOUND )
+    {
+      FT_Int          n, old_count, count;
+      FT_GlyphLoader  loader = glyph->loader;
+      FT_Outline*     base   = &loader->base.outline;
+
+
+      old_count = glyph->num_subs;
+
+      /* this is a compound glyph - load it */
+      error = pfr_glyph_load_compound( glyph, p, limit );
+
+      FT_FRAME_EXIT();
+
+      if ( error )
+        goto Exit;
+
+      count = glyph->num_subs - old_count;
+
+      /* now, load each individual glyph */
+      for ( n = 0; n < count; n++ )
+      {
+        FT_Int        i, old_points, num_points;
+        PFR_SubGlyph  subglyph;
+
+
+        subglyph   = glyph->subs + old_count + n;
+        old_points = base->n_points;
+
+        error = pfr_glyph_load_rec( glyph, stream, gps_offset,
+                                    subglyph->gps_offset,
+                                    subglyph->gps_size );
+        if ( error )
+          goto Exit;
+
+        /* note that `glyph->subs' might have been re-allocated */
+        subglyph   = glyph->subs + old_count + n;
+        num_points = base->n_points - old_points;
+
+        /* translate and eventually scale the new glyph points */
+        if ( subglyph->x_scale != 0x10000L || subglyph->y_scale != 0x10000L )
+        {
+          FT_Vector*  vec = base->points + old_points;
+
+
+          for ( i = 0; i < num_points; i++, vec++ )
+          {
+            vec->x = FT_MulFix( vec->x, subglyph->x_scale ) +
+                       subglyph->x_delta;
+            vec->y = FT_MulFix( vec->y, subglyph->y_scale ) +
+                       subglyph->y_delta;
+          }
+        }
+        else
+        {
+          FT_Vector*  vec = loader->base.outline.points + old_points;
+
+
+          for ( i = 0; i < num_points; i++, vec++ )
+          {
+            vec->x += subglyph->x_delta;
+            vec->y += subglyph->y_delta;
+          }
+        }
+
+        /* proceed to next sub-glyph */
+      }
+    }
+    else
+    {
+      /* load a simple glyph */
+      error = pfr_glyph_load_simple( glyph, p, limit );
+
+      FT_FRAME_EXIT();
+    }
+
+  Exit:
+    return error;
+  }
+
+
+
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_glyph_load( PFR_Glyph  glyph,
+                  FT_Stream  stream,
+                  FT_ULong   gps_offset,
+                  FT_ULong   offset,
+                  FT_ULong   size )
+  {
+    /* initialize glyph loader */
+    FT_GlyphLoader_Rewind( glyph->loader );
+
+    /* load the glyph, recursively when needed */
+    return pfr_glyph_load_rec( glyph, stream, gps_offset, offset, size );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrgload.h
@@ -1,0 +1,49 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrgload.h                                                             */
+/*                                                                         */
+/*    FreeType PFR glyph loader (specification).                           */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PFRGLOAD_H__
+#define __PFRGLOAD_H__
+
+#include "pfrtypes.h"
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( void )
+  pfr_glyph_init( PFR_Glyph       glyph,
+                  FT_GlyphLoader  loader );
+
+  FT_LOCAL( void )
+  pfr_glyph_done( PFR_Glyph  glyph );
+
+
+  FT_LOCAL( FT_Error )
+  pfr_glyph_load( PFR_Glyph  glyph,
+                  FT_Stream  stream,
+                  FT_ULong   gps_offset,
+                  FT_ULong   offset,
+                  FT_ULong   size );
+
+
+FT_END_HEADER
+
+
+#endif /* __PFRGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrload.c
@@ -1,0 +1,901 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrload.c                                                              */
+/*                                                                         */
+/*    FreeType PFR loader (body).                                          */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "pfrload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+#include "pfrerror.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pfr
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          EXTRA ITEMS                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_extra_items_skip( FT_Byte*  *pp,
+                        FT_Byte*   limit )
+  {
+    return pfr_extra_items_parse( pp, limit, NULL, NULL );
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_extra_items_parse( FT_Byte*       *pp,
+                         FT_Byte*        limit,
+                         PFR_ExtraItem   item_list,
+                         FT_Pointer      item_data )
+  {
+    FT_Error  error = 0;
+    FT_Byte*  p     = *pp;
+    FT_UInt   num_items, item_type, item_size;
+
+
+    PFR_CHECK( 1 );
+    num_items = PFR_NEXT_BYTE( p );
+
+    for ( ; num_items > 0; num_items-- )
+    {
+      PFR_CHECK( 2 );
+      item_size = PFR_NEXT_BYTE( p );
+      item_type = PFR_NEXT_BYTE( p );
+
+      PFR_CHECK( item_size );
+
+      if ( item_list )
+      {
+        PFR_ExtraItem  extra = item_list;
+
+
+        for ( extra = item_list; extra->parser != NULL; extra++ )
+        {
+          if ( extra->type == item_type )
+          {
+            error = extra->parser( p, p + item_size, item_data );
+            if ( error ) goto Exit;
+
+            break;
+          }
+        }
+      }
+
+      p += item_size;
+    }
+
+  Exit:
+    *pp = p;
+    return error;
+
+  Too_Short:
+    FT_ERROR(( "pfr_extra_items_parse: invalid extra items table\n" ));
+    error = PFR_Err_Invalid_Table;
+    goto Exit;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          PFR HEADER                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+   static const FT_Frame_Field  pfr_header_fields[] =
+   {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PFR_HeaderRec
+
+     FT_FRAME_START( 58 ),
+       FT_FRAME_ULONG ( signature ),
+       FT_FRAME_USHORT( version ),
+       FT_FRAME_USHORT( signature2 ),
+       FT_FRAME_USHORT( header_size ),
+
+       FT_FRAME_USHORT( log_dir_size ),
+       FT_FRAME_USHORT( log_dir_offset ),
+
+       FT_FRAME_USHORT( log_font_max_size ),
+       FT_FRAME_UOFF3 ( log_font_section_size ),
+       FT_FRAME_UOFF3 ( log_font_section_offset ),
+
+       FT_FRAME_USHORT( phy_font_max_size ),
+       FT_FRAME_UOFF3 ( phy_font_section_size ),
+       FT_FRAME_UOFF3 ( phy_font_section_offset ),
+
+       FT_FRAME_USHORT( gps_max_size ),
+       FT_FRAME_UOFF3 ( gps_section_size ),
+       FT_FRAME_UOFF3 ( gps_section_offset ),
+
+       FT_FRAME_BYTE  ( max_blue_values ),
+       FT_FRAME_BYTE  ( max_x_orus ),
+       FT_FRAME_BYTE  ( max_y_orus ),
+
+       FT_FRAME_BYTE  ( phy_font_max_size_high ),
+       FT_FRAME_BYTE  ( color_flags ),
+
+       FT_FRAME_UOFF3 ( bct_max_size ),
+       FT_FRAME_UOFF3 ( bct_set_max_size ),
+       FT_FRAME_UOFF3 ( phy_bct_set_max_size ),
+
+       FT_FRAME_USHORT( num_phy_fonts ),
+       FT_FRAME_BYTE  ( max_vert_stem_snap ),
+       FT_FRAME_BYTE  ( max_horz_stem_snap ),
+       FT_FRAME_USHORT( max_chars ),
+     FT_FRAME_END
+   };
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_header_load( PFR_Header  header,
+                   FT_Stream   stream )
+  {
+    FT_Error   error;
+
+
+    /* read header directly */
+    if ( !FT_STREAM_SEEK( 0 )                                &&
+         !FT_STREAM_READ_FIELDS( pfr_header_fields, header ) )
+    {
+      /* make a few adjustments to the header */
+      header->phy_font_max_size +=
+        (FT_UInt32)header->phy_font_max_size_high << 16;
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  pfr_header_check( PFR_Header  header )
+  {
+    FT_Bool  result = 1;
+
+
+    /* check signature and header size */
+    if ( header->signature  != 0x50465230L ||   /* "PFR0" */
+         header->version     > 4           ||
+         header->header_size < 58          ||
+         header->signature2 != 0x0d0a      )    /* CR/LF  */
+    {
+      result = 0;
+    }
+    return  result;
+  }
+
+
+  /***********************************************************************/
+  /***********************************************************************/
+  /*****                                                             *****/
+  /*****                    PFR LOGICAL FONTS                        *****/
+  /*****                                                             *****/
+  /***********************************************************************/
+  /***********************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_log_font_count( FT_Stream  stream,
+                      FT_UInt32  section_offset,
+                      FT_UInt   *acount )
+  {
+    FT_Error   error;
+    FT_UInt    count;
+    FT_UInt    result = 0;
+
+
+    if ( FT_STREAM_SEEK( section_offset ) || FT_READ_USHORT( count ) )
+      goto Exit;
+
+    result = count;
+
+  Exit:
+    *acount = result;
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_log_font_load( PFR_LogFont  log_font,
+                     FT_Stream    stream,
+                     FT_UInt      idx,
+                     FT_UInt32    section_offset,
+                     FT_Bool      size_increment )
+  {
+    FT_UInt    num_log_fonts;
+    FT_UInt    flags;
+    FT_UInt32  offset;
+    FT_UInt32  size;
+    FT_Error   error;
+
+
+    if ( FT_STREAM_SEEK( section_offset ) ||
+         FT_READ_USHORT( num_log_fonts )  )
+      goto Exit;
+
+    if ( idx >= num_log_fonts )
+      return PFR_Err_Invalid_Argument;
+
+    if ( FT_STREAM_SKIP( idx * 5 ) ||
+         FT_READ_USHORT( size )      ||
+         FT_READ_UOFF3 ( offset )    )
+      goto Exit;
+
+    /* save logical font size and offset */
+    log_font->size   = size;
+    log_font->offset = offset;
+
+    /* now, check the rest of the table before loading it */
+    {
+      FT_Byte*  p;
+      FT_Byte*  limit;
+      FT_UInt   local;
+
+
+      if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) )
+        goto Exit;
+
+      p     = stream->cursor;
+      limit = p + size;
+
+      PFR_CHECK(13);
+
+      log_font->matrix[0] = PFR_NEXT_LONG( p );
+      log_font->matrix[1] = PFR_NEXT_LONG( p );
+      log_font->matrix[2] = PFR_NEXT_LONG( p );
+      log_font->matrix[3] = PFR_NEXT_LONG( p );
+
+      flags = PFR_NEXT_BYTE( p );
+
+      local = 0;
+      if ( flags & PFR_LOG_STROKE )
+      {
+        local++;
+        if ( flags & PFR_LOG_2BYTE_STROKE )
+          local++;
+
+        if ( (flags & PFR_LINE_JOIN_MASK) == PFR_LINE_JOIN_MITER )
+          local += 3;
+      }
+      if ( flags & PFR_LOG_BOLD )
+      {
+        local++;
+        if ( flags & PFR_LOG_2BYTE_BOLD )
+          local++;
+      }
+
+      PFR_CHECK( local );
+
+      if ( flags & PFR_LOG_STROKE )
+      {
+        log_font->stroke_thickness = ( flags & PFR_LOG_2BYTE_STROKE )
+                                     ? PFR_NEXT_SHORT( p )
+                                     : PFR_NEXT_BYTE( p );
+
+        if ( ( flags & PFR_LINE_JOIN_MASK ) == PFR_LINE_JOIN_MITER )
+          log_font->miter_limit = PFR_NEXT_LONG( p );
+      }
+
+      if ( flags & PFR_LOG_BOLD )
+      {
+        log_font->bold_thickness = ( flags & PFR_LOG_2BYTE_BOLD )
+                                   ? PFR_NEXT_SHORT( p )
+                                   : PFR_NEXT_BYTE( p );
+      }
+
+      if ( flags & PFR_LOG_EXTRA_ITEMS )
+      {
+        error = pfr_extra_items_skip( &p, limit );
+        if (error) goto Fail;
+      }
+
+      PFR_CHECK(5);
+      log_font->phys_size   = PFR_NEXT_USHORT( p );
+      log_font->phys_offset = PFR_NEXT_ULONG( p );
+      if ( size_increment )
+      {
+        PFR_CHECK( 1 );
+        log_font->phys_size += (FT_UInt32)PFR_NEXT_BYTE( p ) << 16;
+      }
+    }
+
+  Fail:
+    FT_FRAME_EXIT();
+
+  Exit:
+    return error;
+
+  Too_Short:
+    FT_ERROR(( "pfr_log_font_load: invalid logical font table\n" ));
+    error = PFR_Err_Invalid_Table;
+    goto Fail;
+  }
+
+
+  /***********************************************************************/
+  /***********************************************************************/
+  /*****                                                             *****/
+  /*****                    PFR PHYSICAL FONTS                       *****/
+  /*****                                                             *****/
+  /***********************************************************************/
+  /***********************************************************************/
+
+
+  /* load bitmap strikes lists */
+  FT_CALLBACK_DEF( FT_Error )
+  pfr_extra_item_load_bitmap_info( FT_Byte*     p,
+                                   FT_Byte*     limit,
+                                   PFR_PhyFont  phy_font )
+  {
+    FT_Memory   memory = phy_font->memory;
+    PFR_Strike  strike;
+    FT_UInt     flags0;
+    FT_UInt     n, count, size1;
+    FT_Error    error = 0;
+
+
+    PFR_CHECK( 5 );
+
+    p += 3;  /* skip bctSize */
+    flags0 = PFR_NEXT_BYTE( p );
+    count  = PFR_NEXT_BYTE( p );
+
+    /* re-allocate when needed */
+    if ( phy_font->num_strikes + count > phy_font->max_strikes )
+    {
+      FT_UInt  new_max = (phy_font->num_strikes + count + 3) & -4;
+
+      if ( FT_RENEW_ARRAY( phy_font->strikes,
+                           phy_font->num_strikes,
+                           new_max ) )
+        goto Exit;
+
+      phy_font->max_strikes = new_max;
+    }
+
+    size1 = 1 + 1 + 1 + 2 + 2 + 1;
+    if ( flags0 & PFR_STRIKE_2BYTE_XPPM )
+      size1++;
+
+    if ( flags0 & PFR_STRIKE_2BYTE_YPPM )
+      size1++;
+
+    if ( flags0 & PFR_STRIKE_3BYTE_SIZE )
+      size1++;
+
+    if ( flags0 & PFR_STRIKE_3BYTE_OFFSET )
+      size1++;
+
+    if ( flags0 & PFR_STRIKE_2BYTE_COUNT )
+      size1++;
+
+    strike = phy_font->strikes + phy_font->num_strikes;
+
+    PFR_CHECK( count * size1 );
+
+    for ( n = 0; n < count; n++, strike++ )
+    {
+      strike->x_ppm       = ( flags0 & PFR_STRIKE_2BYTE_XPPM )
+                            ? PFR_NEXT_USHORT( p )
+                            : PFR_NEXT_BYTE( p );
+
+      strike->y_ppm       = ( flags0 & PFR_STRIKE_2BYTE_YPPM )
+                            ? PFR_NEXT_USHORT( p )
+                            : PFR_NEXT_BYTE( p );
+
+      strike->flags       = PFR_NEXT_BYTE( p );
+
+      strike->bct_size    = ( flags0 & PFR_STRIKE_3BYTE_SIZE )
+                            ? PFR_NEXT_ULONG( p )
+                            : PFR_NEXT_USHORT( p );
+
+      strike->bct_offset  = ( flags0 & PFR_STRIKE_3BYTE_OFFSET )
+                            ? PFR_NEXT_ULONG( p )
+                            : PFR_NEXT_USHORT( p );
+
+      strike->num_bitmaps = ( flags0 & PFR_STRIKE_2BYTE_COUNT )
+                            ? PFR_NEXT_USHORT( p )
+                            : PFR_NEXT_BYTE( p );
+    }
+
+    phy_font->num_strikes += count;
+
+  Exit:
+    return error;
+
+  Too_Short:
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_extra_item_load_bitmap_info: invalid bitmap info table\n" ));
+    goto Exit;
+  }
+
+
+  /* load font ID, i.e. name */
+  FT_CALLBACK_DEF( FT_Error )
+  pfr_extra_item_load_font_id( FT_Byte*     p,
+                               FT_Byte*     limit,
+                               PFR_PhyFont  phy_font )
+  {
+    FT_Error   error  = 0;
+    FT_Memory  memory = phy_font->memory;
+    FT_UInt    len    = (FT_UInt)( limit - p );
+
+
+    if ( phy_font->font_id != NULL )
+      goto Exit;
+
+    if ( FT_ALLOC( phy_font->font_id, len+1 ) )
+      goto Exit;
+
+    /* copy font ID name, and terminate it for safety */
+    FT_MEM_COPY( phy_font->font_id, p, len );
+    phy_font->font_id[len] = 0;
+
+  Exit:
+    return error;
+  }
+
+
+  /* load stem snap tables */
+  FT_CALLBACK_DEF( FT_Error )
+  pfr_extra_item_load_stem_snaps( FT_Byte*     p,
+                                  FT_Byte*     limit,
+                                  PFR_PhyFont  phy_font )
+  {
+    FT_UInt    count, num_vert, num_horz;
+    FT_Int*    snaps;
+    FT_Error   error  = 0;
+    FT_Memory  memory = phy_font->memory;
+
+
+    if ( phy_font->vertical.stem_snaps != NULL )
+      goto Exit;
+
+    PFR_CHECK( 1 );
+    count = PFR_NEXT_BYTE( p );
+
+    num_vert = count & 15;
+    num_horz = count >> 4;
+    count    = num_vert + num_horz;
+
+    PFR_CHECK( count * 2 );
+
+    if ( FT_NEW_ARRAY( snaps, count ) )
+      goto Exit;
+
+    phy_font->vertical.stem_snaps = snaps;
+    phy_font->horizontal.stem_snaps = snaps + num_vert;
+
+    for ( ; count > 0; count--, snaps++ )
+      *snaps = FT_NEXT_SHORT( p );
+
+  Exit:
+    return error;
+
+  Too_Short:
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_exta_item_load_stem_snaps: invalid stem snaps table\n" ));
+    goto Exit;
+  }
+
+
+#if 0
+
+  /* load kerning pair data */
+  FT_CALLBACK_DEF( FT_Error )
+  pfr_extra_item_load_kerning_pairs( FT_Byte*     p,
+                                     FT_Byte*     limit,
+                                     PFR_PhyFont  phy_font )
+  {
+    FT_Int        count;
+    FT_UShort     base_adj;
+    FT_UInt       flags;
+    FT_UInt       num_pairs;
+    PFR_KernPair  pairs;
+    FT_Error      error  = 0;
+    FT_Memory     memory = phy_font->memory;
+
+
+    /* allocate a new kerning item */
+    /* XXX: there may be multiple extra items for kerning */
+    if ( phy_font->kern_pairs != NULL )
+      goto Exit;
+
+    FT_TRACE2(( "pfr_extra_item_load_kerning_pairs()\n" ));
+
+    PFR_CHECK( 4 );
+
+    num_pairs = PFR_NEXT_BYTE( p );
+    base_adj  = PFR_NEXT_SHORT( p );
+    flags     = PFR_NEXT_BYTE( p );
+
+#ifndef PFR_CONFIG_NO_CHECKS
+    count = 3;
+
+    if ( flags & PFR_KERN_2BYTE_CHAR )
+      count += 2;
+
+    if ( flags & PFR_KERN_2BYTE_ADJ )
+      count += 1;
+
+    PFR_CHECK( num_pairs * count );
+#endif
+
+    if ( FT_NEW_ARRAY( pairs, num_pairs ) )
+      goto Exit;
+
+    phy_font->num_kern_pairs = num_pairs;
+    phy_font->kern_pairs     = pairs;
+
+    for (count = num_pairs ; count > 0; count--, pairs++ )
+    {
+      if ( flags & PFR_KERN_2BYTE_CHAR )
+      {
+        pairs->glyph1 = PFR_NEXT_USHORT( p );
+        pairs->glyph2 = PFR_NEXT_USHORT( p );
+      }
+      else
+      {
+        pairs->glyph1 = PFR_NEXT_BYTE( p );
+        pairs->glyph2 = PFR_NEXT_BYTE( p );
+      }
+
+      if ( flags & PFR_KERN_2BYTE_ADJ )
+        pairs->kerning.x = base_adj + PFR_NEXT_SHORT( p );
+      else
+        pairs->kerning.x = base_adj + PFR_NEXT_INT8( p );
+
+      pairs->kerning.y = 0;
+
+      FT_TRACE2(( "kerning %d <-> %d : %ld\n",
+                   pairs->glyph1, pairs->glyph2, pairs->kerning.x ));
+    }
+
+  Exit:
+    return error;
+
+  Too_Short:
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_extra_item_load_kerning_pairs: "
+               "invalid kerning pairs table\n" ));
+    goto Exit;
+  }
+
+#else /* 0 */
+
+  /* load kerning pair data */
+  FT_CALLBACK_DEF( FT_Error )
+  pfr_extra_item_load_kerning_pairs( FT_Byte*     p,
+                                     FT_Byte*     limit,
+                                     PFR_PhyFont  phy_font )
+  {
+    PFR_KernItem  item;
+    FT_Error      error  = 0;
+    FT_Memory     memory = phy_font->memory;
+
+
+    FT_TRACE2(( "pfr_extra_item_load_kerning_pairs()\n" ));
+
+    if ( FT_NEW( item ) )
+      goto Exit;
+
+    PFR_CHECK( 4 );
+
+    item->pair_count = PFR_NEXT_BYTE( p );
+    item->base_adj   = PFR_NEXT_SHORT( p );
+    item->flags      = PFR_NEXT_BYTE( p );
+    item->offset     = phy_font->offset + ( p - phy_font->cursor );
+
+#ifndef PFR_CONFIG_NO_CHECKS
+    item->pair_size = 3;
+
+    if ( item->flags & PFR_KERN_2BYTE_CHAR )
+      item->pair_size += 2;
+
+    if ( item->flags & PFR_KERN_2BYTE_ADJ )
+      item->pair_size += 1;
+
+    PFR_CHECK( item->pair_count * item->pair_size );
+#endif
+
+    /* load first and last pairs into the item to speed up */
+    /* lookup later...                                     */
+    if ( item->pair_count > 0 )
+    {
+      FT_UInt   char1, char2;
+      FT_Byte*  q;
+
+
+      if ( item->flags & PFR_KERN_2BYTE_CHAR )
+      {
+        q     = p;
+        char1 = PFR_NEXT_USHORT( q );
+        char2 = PFR_NEXT_USHORT( q );
+
+        item->pair1 = PFR_KERN_INDEX( char1, char2 );
+
+        q = p + item->pair_size * ( item->pair_count - 1 );
+        char1 = PFR_NEXT_USHORT( q );
+        char2 = PFR_NEXT_USHORT( q );
+
+        item->pair2 = PFR_KERN_INDEX( char1, char2 );
+      }
+      else
+      {
+        q     = p;
+        char1 = PFR_NEXT_BYTE( q );
+        char2 = PFR_NEXT_BYTE( q );
+
+        item->pair1 = PFR_KERN_INDEX( char1, char2 );
+
+        q = p + item->pair_size * ( item->pair_count - 1 );
+        char1 = PFR_NEXT_BYTE( q );
+        char2 = PFR_NEXT_BYTE( q );
+
+        item->pair2 = PFR_KERN_INDEX( char1, char2 );
+      }
+
+      /* add new item to the current list */
+      item->next                 = NULL;
+      *phy_font->kern_items_tail = item;
+      phy_font->kern_items_tail  = &item->next;
+      phy_font->num_kern_pairs  += item->pair_count;
+    }
+    else
+    {
+      /* empty item! */
+      FT_FREE( item );
+    }
+
+  Exit:
+    return error;
+
+  Too_Short:
+    FT_FREE( item );
+
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_extra_item_load_kerning_pairs: "
+               "invalid kerning pairs table\n" ));
+    goto Exit;
+  }
+#endif /* 0 */
+
+
+  static const PFR_ExtraItemRec  pfr_phy_font_extra_items[] =
+  {
+    { 1, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_bitmap_info },
+    { 2, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_font_id },
+    { 3, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_stem_snaps },
+    { 4, (PFR_ExtraItem_ParseFunc) pfr_extra_item_load_kerning_pairs },
+    { 0, NULL }
+  };
+
+
+  FT_LOCAL_DEF( void )
+  pfr_phy_font_done( PFR_PhyFont  phy_font,
+                     FT_Memory    memory )
+  {
+    if ( phy_font->font_id )
+      FT_FREE( phy_font->font_id );
+
+    FT_FREE( phy_font->vertical.stem_snaps );
+    phy_font->vertical.num_stem_snaps = 0;
+
+    phy_font->horizontal.stem_snaps     = NULL;
+    phy_font->horizontal.num_stem_snaps = 0;
+
+    FT_FREE( phy_font->strikes );
+    phy_font->num_strikes = 0;
+    phy_font->max_strikes = 0;
+
+    FT_FREE( phy_font->chars );
+    phy_font->num_chars    = 0;
+    phy_font->chars_offset = 0;
+
+    FT_FREE( phy_font->blue_values );
+    phy_font->num_blue_values = 0;
+
+    {
+      PFR_KernItem  item, next;
+
+
+      item = phy_font->kern_items;
+      while ( item )
+      {
+        next = item->next;
+        FT_FREE( item );
+        item = next;
+      }
+      phy_font->kern_items      = NULL;
+      phy_font->kern_items_tail = NULL;
+    }
+
+    phy_font->num_kern_pairs = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_phy_font_load( PFR_PhyFont  phy_font,
+                     FT_Stream    stream,
+                     FT_UInt32    offset,
+                     FT_UInt32    size )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+    FT_UInt    flags, num_aux;
+    FT_Byte*   p;
+    FT_Byte*   limit;
+
+
+    phy_font->memory = memory;
+    phy_font->offset = offset;
+
+    phy_font->kern_items      = NULL;
+    phy_font->kern_items_tail = &phy_font->kern_items;
+
+    if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( size ) )
+      goto Exit;
+
+    phy_font->cursor = stream->cursor;
+
+    p     = stream->cursor;
+    limit = p + size;
+
+    PFR_CHECK( 15 );
+    phy_font->font_ref_number    = PFR_NEXT_USHORT( p );
+    phy_font->outline_resolution = PFR_NEXT_USHORT( p );
+    phy_font->metrics_resolution = PFR_NEXT_USHORT( p );
+    phy_font->bbox.xMin          = PFR_NEXT_SHORT( p );
+    phy_font->bbox.yMin          = PFR_NEXT_SHORT( p );
+    phy_font->bbox.xMax          = PFR_NEXT_SHORT( p );
+    phy_font->bbox.yMax          = PFR_NEXT_SHORT( p );
+    phy_font->flags      = flags = PFR_NEXT_BYTE( p );
+
+    /* get the standard advance for non-proprotional fonts */
+    if ( !(flags & PFR_PHY_PROPORTIONAL) )
+    {
+      PFR_CHECK( 2 );
+      phy_font->standard_advance = PFR_NEXT_SHORT( p );
+    }
+
+    /* load the extra items when present */
+    if ( flags & PFR_PHY_EXTRA_ITEMS )
+    {
+      error =  pfr_extra_items_parse( &p, limit,
+                                      pfr_phy_font_extra_items, phy_font );
+
+      if ( error )
+        goto Fail;
+    }
+
+    /* skip the aux bytes */
+    PFR_CHECK( 3 );
+    num_aux = PFR_NEXT_ULONG( p );
+
+    PFR_CHECK( num_aux );
+    p += num_aux;
+
+    /* read the blue values */
+    {
+      FT_UInt  n, count;
+
+      PFR_CHECK( 1 );
+      phy_font->num_blue_values = count = PFR_NEXT_BYTE( p );
+
+      PFR_CHECK( count * 2 );
+
+      if ( FT_NEW_ARRAY( phy_font->blue_values, count ) )
+        goto Fail;
+
+      for ( n = 0; n < count; n++ )
+        phy_font->blue_values[n] = PFR_NEXT_SHORT( p );
+    }
+
+    PFR_CHECK( 8 );
+    phy_font->blue_fuzz  = PFR_NEXT_BYTE( p );
+    phy_font->blue_scale = PFR_NEXT_BYTE( p );
+
+    phy_font->vertical.standard   = PFR_NEXT_USHORT( p );
+    phy_font->horizontal.standard = PFR_NEXT_USHORT( p );
+
+    /* read the character descriptors */
+    {
+      FT_UInt  n, count, Size;
+
+
+      phy_font->num_chars    = count = PFR_NEXT_USHORT( p );
+      phy_font->chars_offset = offset + ( p - stream->cursor );
+
+      if ( FT_NEW_ARRAY( phy_font->chars, count ) )
+        goto Fail;
+
+      Size = 1 + 1 + 2;
+      if ( flags & PFR_PHY_2BYTE_CHARCODE )
+        Size += 1;
+
+      if ( flags & PFR_PHY_PROPORTIONAL )
+        Size += 2;
+
+      if ( flags & PFR_PHY_ASCII_CODE )
+        Size += 1;
+
+      if ( flags & PFR_PHY_2BYTE_GPS_SIZE )
+        Size += 1;
+
+      if ( flags & PFR_PHY_3BYTE_GPS_OFFSET )
+        Size += 1;
+
+      PFR_CHECK( count * Size );
+
+      for ( n = 0; n < count; n++ )
+      {
+        PFR_Char  cur = &phy_font->chars[n];
+
+
+        cur->char_code = ( flags & PFR_PHY_2BYTE_CHARCODE )
+                         ? PFR_NEXT_USHORT( p )
+                         : PFR_NEXT_BYTE( p );
+
+        cur->advance   = ( flags & PFR_PHY_PROPORTIONAL )
+                         ? PFR_NEXT_SHORT( p )
+                         : (FT_Int) phy_font->standard_advance;
+
+#if 0
+        cur->ascii     = ( flags & PFR_PHY_ASCII_CODE )
+                         ? PFR_NEXT_BYTE( p )
+                         : 0;
+#else
+        if ( flags & PFR_PHY_ASCII_CODE )
+          p += 1;
+#endif
+        cur->gps_size  = ( flags & PFR_PHY_2BYTE_GPS_SIZE )
+                         ? PFR_NEXT_USHORT( p )
+                         : PFR_NEXT_BYTE( p );
+
+        cur->gps_offset = ( flags & PFR_PHY_3BYTE_GPS_OFFSET )
+                          ? PFR_NEXT_ULONG( p )
+                          : PFR_NEXT_USHORT( p );
+      }
+    }
+
+    /* that's it !! */
+  Fail:
+    FT_FRAME_EXIT();
+
+    /* save position of bitmap info */
+    phy_font->bct_offset = FT_STREAM_POS();
+    phy_font->cursor     = NULL;
+
+  Exit:
+    return error;
+
+  Too_Short:
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_phy_font_load: invalid physical font table\n" ));
+    goto Fail;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrload.h
@@ -1,0 +1,118 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrload.h                                                              */
+/*                                                                         */
+/*    FreeType PFR loader (specification).                                 */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PFRLOAD_H__
+#define __PFRLOAD_H__
+
+#include "pfrobjs.h"
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+#ifdef PFR_CONFIG_NO_CHECKS
+#define PFR_CHECK( x )  do { } while ( 0 )
+#else
+#define PFR_CHECK( x )  do                       \
+                        {                        \
+                          if ( p + (x) > limit ) \
+                            goto Too_Short;      \
+                        } while ( 0 )
+#endif
+
+#define PFR_NEXT_BYTE( p )    FT_NEXT_BYTE( p )
+#define PFR_NEXT_INT8( p )    FT_NEXT_CHAR( p )
+#define PFR_NEXT_SHORT( p )   FT_NEXT_SHORT( p )
+#define PFR_NEXT_USHORT( p )  FT_NEXT_USHORT( p )
+#define PFR_NEXT_LONG( p )    FT_NEXT_OFF3( p )
+#define PFR_NEXT_ULONG( p )   FT_NEXT_UOFF3( p )
+
+
+ /* handling extra items */
+
+  typedef FT_Error
+  (*PFR_ExtraItem_ParseFunc)( FT_Byte*    p,
+                              FT_Byte*    limit,
+                              FT_Pointer  data );
+
+  typedef struct  PFR_ExtraItemRec_
+  {
+    FT_UInt                  type;
+    PFR_ExtraItem_ParseFunc  parser;
+  
+  } PFR_ExtraItemRec;
+  
+  typedef const struct PFR_ExtraItemRec_*  PFR_ExtraItem;
+ 
+
+  FT_LOCAL( FT_Error )
+  pfr_extra_items_skip( FT_Byte*  *pp,
+                        FT_Byte*  limit );
+
+  FT_LOCAL( FT_Error )
+  pfr_extra_items_parse( FT_Byte*      *pp,
+                         FT_Byte*       limit,
+                         PFR_ExtraItem  item_list,
+                         FT_Pointer     item_data );
+
+
+  /* load a PFR header */
+  FT_LOCAL( FT_Error )
+  pfr_header_load( PFR_Header  header,
+                   FT_Stream   stream );
+
+  /* check a PFR header */
+  FT_LOCAL( FT_Bool )
+  pfr_header_check( PFR_Header  header );
+
+
+  /* return number of logical fonts in this file */
+  FT_LOCAL( FT_Error )
+  pfr_log_font_count( FT_Stream   stream,
+                      FT_UInt32   log_section_offset,
+                      FT_UInt    *acount );
+
+  /* load a pfr logical font entry */
+  FT_LOCAL( FT_Error )
+  pfr_log_font_load( PFR_LogFont  log_font,
+                     FT_Stream    stream,
+                     FT_UInt      face_index,
+                     FT_UInt32    section_offset,
+                     FT_Bool      size_increment );
+
+
+  /* load a physical font entry */
+  FT_LOCAL( FT_Error )
+  pfr_phy_font_load( PFR_PhyFont  phy_font,
+                     FT_Stream    stream,
+                     FT_UInt32    offset,
+                     FT_UInt32    size );
+
+  /* finalize a physical font */
+  FT_LOCAL( void )
+  pfr_phy_font_done( PFR_PhyFont  phy_font,
+                     FT_Memory    memory );
+
+  /* */
+ 
+FT_END_HEADER
+
+#endif /* __PFRLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrobjs.c
@@ -1,0 +1,437 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrobjs.c                                                              */
+/*                                                                         */
+/*    FreeType PFR object methods (body).                                  */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "pfrobjs.h"
+#include "pfrload.h"
+#include "pfrgload.h"
+#include "pfrcmap.h"
+#include "pfrsbit.h"
+#include FT_OUTLINE_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "pfrerror.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pfr
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     FACE OBJECT METHODS                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  pfr_face_done( PFR_Face  face )
+  {
+    /* finalize the physical font record */
+    pfr_phy_font_done( &face->phy_font, FT_FACE_MEMORY( face ) );
+
+    /* no need to finalize the logical font or the header */
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_face_init( FT_Stream      stream,
+                 PFR_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params )
+  {
+    FT_Error  error;
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+
+
+    /* load the header and check it */
+    error = pfr_header_load( &face->header, stream );
+    if ( error )
+      goto Exit;
+
+    if ( !pfr_header_check( &face->header ) )
+    {
+      FT_TRACE4(( "pfr_face_init: not a valid PFR font\n" ));
+      error = PFR_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* check face index */
+    {
+      FT_UInt  num_faces;
+
+
+      error = pfr_log_font_count( stream,
+                                  face->header.log_dir_offset,
+                                  &num_faces );
+      if ( error )
+        goto Exit;
+
+      face->root.num_faces = num_faces;
+    }
+
+    if ( face_index < 0 )
+      goto Exit;
+
+    if ( face_index >= face->root.num_faces )
+    {
+      FT_ERROR(( "pfr_face_init: invalid face index\n" ));
+      error = PFR_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* load the face */
+    error = pfr_log_font_load(
+               &face->log_font, stream, face_index,
+               face->header.log_dir_offset,
+               FT_BOOL( face->header.phy_font_max_size_high != 0 ) );
+    if ( error )
+      goto Exit;
+
+    /* now load the physical font descriptor */
+     error = pfr_phy_font_load( &face->phy_font, stream,
+                                 face->log_font.phys_offset,
+                                 face->log_font.phys_size );
+     if ( error )
+       goto Exit;
+
+     /* now, set-up all root face fields */
+     {
+       FT_Face      root     = FT_FACE( face );
+       PFR_PhyFont  phy_font = &face->phy_font;
+
+
+       root->face_index = face_index;
+       root->num_glyphs = phy_font->num_chars;
+       root->face_flags = FT_FACE_FLAG_SCALABLE;
+
+       if ( (phy_font->flags & PFR_PHY_PROPORTIONAL) == 0 )
+         root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+       if ( phy_font->flags & PFR_PHY_VERTICAL )
+         root->face_flags |= FT_FACE_FLAG_VERTICAL;
+       else
+         root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+
+       if ( phy_font->num_strikes > 0 )
+         root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
+
+       if ( phy_font->num_kern_pairs > 0 )
+         root->face_flags |= FT_FACE_FLAG_KERNING;
+
+       root->family_name = phy_font->font_id;
+       root->style_name  = NULL;  /* no style name in font file */
+
+       root->num_fixed_sizes = 0;
+       root->available_sizes = 0;
+
+       root->bbox         = phy_font->bbox;
+       root->units_per_EM = (FT_UShort)phy_font->outline_resolution;
+       root->ascender     = (FT_Short) phy_font->bbox.yMax;
+       root->descender    = (FT_Short) phy_font->bbox.yMin;
+       root->height       = (FT_Short)
+                              ( ( ( root->ascender - root->descender ) * 12 )
+                                / 10 );
+
+       /* now compute maximum advance width */
+       if ( ( phy_font->flags & PFR_PHY_PROPORTIONAL ) == 0 )
+         root->max_advance_width = (FT_Short)phy_font->standard_advance;
+       else
+       {
+         FT_Int    max = 0;
+         FT_UInt   count = phy_font->num_chars;
+         PFR_Char  gchar = phy_font->chars;
+
+
+         for ( ; count > 0; count--, gchar++ )
+         {
+           if ( max < gchar->advance )
+             max = gchar->advance;
+         }
+
+         root->max_advance_width = (FT_Short)max;
+       }
+
+       root->max_advance_height = root->height;
+
+       root->underline_position  = (FT_Short)( - root->units_per_EM / 10 );
+       root->underline_thickness = (FT_Short)(   root->units_per_EM / 30 );
+
+       /* create charmap */
+       {
+         FT_CharMapRec  charmap;
+
+
+         charmap.face        = root;
+         charmap.platform_id = 3;
+         charmap.encoding_id = 1;
+         charmap.encoding    = FT_ENCODING_UNICODE;
+
+         FT_CMap_New( &pfr_cmap_class_rec, NULL, &charmap, NULL );
+
+#if 0
+         /* Select default charmap */
+         if (root->num_charmaps)
+           root->charmap = root->charmaps[0];
+#endif
+       }
+
+       /* check whether we've loaded any kerning pairs */
+       if ( phy_font->num_kern_pairs )
+         root->face_flags |= FT_FACE_FLAG_KERNING;
+     }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    SLOT OBJECT METHOD                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_slot_init( PFR_Slot  slot )
+  {
+    FT_GlyphLoader  loader = slot->root.internal->loader;
+
+    pfr_glyph_init( &slot->glyph, loader );
+
+    return 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  pfr_slot_done( PFR_Slot  slot )
+  {
+    pfr_glyph_done( &slot->glyph );
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_slot_load( PFR_Slot  slot,
+                 PFR_Size  size,
+                 FT_UInt   gindex,
+                 FT_Int32  load_flags )
+  {
+    FT_Error     error;
+    PFR_Face     face    = (PFR_Face)slot->root.face;
+    PFR_Char     gchar;
+    FT_Outline*  outline = &slot->root.outline;
+    FT_ULong     gps_offset;
+
+    if (gindex > 0)
+      gindex--;
+
+    /* check that the glyph index is correct */
+    FT_ASSERT( gindex < face->phy_font.num_chars );
+
+    /* try to load an embedded bitmap */
+    if ( ( load_flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP ) ) == 0 )
+    {
+      error = pfr_slot_load_bitmap( slot, size, gindex );
+      if ( error == 0 )
+        goto Exit;
+    }
+
+    gchar               = face->phy_font.chars + gindex;
+    slot->root.format   = FT_GLYPH_FORMAT_OUTLINE;
+    outline->n_points   = 0;
+    outline->n_contours = 0;
+    gps_offset          = face->header.gps_section_offset;
+
+    /* load the glyph outline (FT_LOAD_NO_RECURSE isn't supported) */
+    error = pfr_glyph_load( &slot->glyph, face->root.stream,
+                            gps_offset, gchar->gps_offset, gchar->gps_size );
+
+    if ( !error )
+    {
+      FT_BBox            cbox;
+      FT_Glyph_Metrics*  metrics = &slot->root.metrics;
+      FT_Pos             advance;
+      FT_Int             em_metrics, em_outline;
+      FT_Bool            scaling;
+
+
+      scaling = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE ) == 0 );
+
+      /* copy outline data */
+      *outline = slot->glyph.loader->base.outline;
+
+      outline->flags &= ~FT_OUTLINE_OWNER;
+      outline->flags |= FT_OUTLINE_REVERSE_FILL;
+
+      if ( size && size->root.metrics.y_ppem < 24 )
+        outline->flags |= FT_OUTLINE_HIGH_PRECISION;
+
+      /* compute the advance vector */
+      metrics->horiAdvance = 0;
+      metrics->vertAdvance = 0;
+
+      advance    = gchar->advance;
+      em_metrics = face->phy_font.metrics_resolution;
+      em_outline = face->phy_font.outline_resolution;
+
+      if ( em_metrics != em_outline )
+        advance = FT_MulDiv( advance, em_outline, em_metrics );
+
+      if ( face->phy_font.flags & PFR_PHY_VERTICAL )
+        metrics->vertAdvance = advance;
+      else
+        metrics->horiAdvance = advance;
+
+      slot->root.linearHoriAdvance = metrics->horiAdvance;
+      slot->root.linearVertAdvance = metrics->vertAdvance;
+
+      /* make-up vertical metrics(?) */
+      metrics->vertBearingX = 0;
+      metrics->vertBearingY = 0;
+
+      /* scale when needed */
+      if ( scaling )
+      {
+        FT_Int      n;
+        FT_Fixed    x_scale = size->root.metrics.x_scale;
+        FT_Fixed    y_scale = size->root.metrics.y_scale;
+        FT_Vector*  vec     = outline->points;
+
+
+        /* scale outline points */
+        for ( n = 0; n < outline->n_points; n++, vec++ )
+        {
+          vec->x = FT_MulFix( vec->x, x_scale );
+          vec->y = FT_MulFix( vec->y, y_scale );
+        }
+
+        /* scale the advance */
+        metrics->horiAdvance = FT_MulFix( metrics->horiAdvance, x_scale );
+        metrics->vertAdvance = FT_MulFix( metrics->vertAdvance, y_scale );
+      }
+
+      /* compute the rest of the metrics */
+      FT_Outline_Get_CBox( outline, &cbox );
+
+      metrics->width        = cbox.xMax - cbox.xMin;
+      metrics->height       = cbox.yMax - cbox.yMin;
+      metrics->horiBearingX = cbox.xMin;
+      metrics->horiBearingY = cbox.yMax - metrics->height;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      KERNING METHOD                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( FT_Error )
+  pfr_face_get_kerning( PFR_Face    face,
+                        FT_UInt     glyph1,
+                        FT_UInt     glyph2,
+                        FT_Vector*  kerning )
+  {
+    FT_Error      error;
+    PFR_PhyFont   phy_font = &face->phy_font;
+    PFR_KernItem  item     = phy_font->kern_items;
+    FT_UInt32     idx      = PFR_KERN_INDEX( glyph1, glyph2 );
+
+
+    kerning->x = 0;
+    kerning->y = 0;
+
+    /* find the kerning item containing our pair */
+    while ( item )
+    {
+      if ( item->pair1 <= idx && idx <= item->pair2 )
+        goto Found_Item;
+
+      item = item->next;
+    }
+
+    /* not found */
+    goto Exit;
+
+  Found_Item:
+    {
+      /* perform simply binary search within the item */
+      FT_UInt    min, mid, max;
+      FT_Stream  stream = face->root.stream;
+      FT_Byte*   p;
+
+
+      if ( FT_STREAM_SEEK( item->offset )                       ||
+           FT_FRAME_ENTER( item->pair_count * item->pair_size ) )
+        goto Exit;
+
+      min = 0;
+      max = item->pair_count;
+      while ( min < max )
+      {
+        FT_UInt  char1, char2, charcode;
+
+
+        mid = ( min + max ) >> 1;
+        p   = stream->cursor + mid*item->pair_size;
+
+        if ( item->flags & PFR_KERN_2BYTE_CHAR )
+        {
+          char1 = FT_NEXT_USHORT( p );
+          char2 = FT_NEXT_USHORT( p );
+        }
+        else
+        {
+          char1 = FT_NEXT_USHORT( p );
+          char2 = FT_NEXT_USHORT( p );
+        }
+        charcode = PFR_KERN_INDEX( char1, char2 );
+
+        if ( idx == charcode )
+        {
+          if ( item->flags & PFR_KERN_2BYTE_ADJ )
+            kerning->x = item->base_adj + FT_NEXT_SHORT( p );
+          else
+            kerning->x = item->base_adj + FT_NEXT_CHAR( p );
+
+          break;
+        }
+        if ( idx > charcode )
+          min = mid + 1;
+        else
+          max = mid;
+      }
+
+      FT_FRAME_EXIT();
+    }
+
+  Exit:
+    return 0;
+  }
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrobjs.h
@@ -1,0 +1,96 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrobjs.h                                                              */
+/*                                                                         */
+/*    FreeType PFR object methods (specification).                         */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PFROBJS_H__
+#define __PFROBJS_H__
+
+#include "pfrtypes.h"
+
+
+FT_BEGIN_HEADER
+
+  typedef struct PFR_FaceRec_*  PFR_Face;
+
+  typedef struct PFR_SizeRec_*  PFR_Size;
+
+  typedef struct PFR_SlotRec_*  PFR_Slot;
+
+
+  typedef struct  PFR_FaceRec_
+  {
+    FT_FaceRec      root;
+    PFR_HeaderRec   header;
+    PFR_LogFontRec  log_font;
+    PFR_PhyFontRec  phy_font;
+
+  } PFR_FaceRec;
+
+
+  typedef struct  PFR_SizeRec_
+  {
+    FT_SizeRec  root;
+
+  } PFR_SizeRec;
+
+
+  typedef struct  PFR_SlotRec_
+  {
+    FT_GlyphSlotRec  root;
+    PFR_GlyphRec     glyph;
+
+  } PFR_SlotRec;
+
+
+  FT_LOCAL( FT_Error )
+  pfr_face_init( FT_Stream      stream,
+                 PFR_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params );
+
+  FT_LOCAL( void )
+  pfr_face_done( PFR_Face  face );
+
+
+  FT_LOCAL( FT_Error )
+  pfr_face_get_kerning( PFR_Face   face,
+                        FT_UInt    glyph1,
+                        FT_UInt    glyph2,
+                        FT_Vector* kerning );
+
+
+  FT_LOCAL( FT_Error )
+  pfr_slot_init( PFR_Slot  slot );
+
+  FT_LOCAL( void )
+  pfr_slot_done( PFR_Slot  slot );
+
+
+  FT_LOCAL( FT_Error )
+  pfr_slot_load( PFR_Slot  slot,
+                 PFR_Size  size,
+                 FT_UInt   gindex,
+                 FT_Int32  load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __PFROBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrsbit.c
@@ -1,0 +1,670 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrsbit.c                                                              */
+/*                                                                         */
+/*    FreeType PFR bitmap loader (body).                                   */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "pfrsbit.h"
+#include "pfrload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+#include "pfrerror.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pfr
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      PFR BIT WRITER                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct  PFR_BitWriter_
+  {
+    FT_Byte*  line;      /* current line start                    */
+    FT_Int    pitch;     /* line size in bytes                    */
+    FT_Int    width;     /* width in pixels/bits                  */
+    FT_Int    rows;      /* number of remaining rows to scan      */
+    FT_Int    total;     /* total number of bits to draw          */
+
+  } PFR_BitWriterRec, *PFR_BitWriter;
+
+
+  static void
+  pfr_bitwriter_init( PFR_BitWriter  writer,
+                      FT_Bitmap*     target,
+                      FT_Bool        decreasing )
+  {
+    writer->line   = target->buffer;
+    writer->pitch  = target->pitch;
+    writer->width  = target->width;
+    writer->rows   = target->rows;
+    writer->total  = writer->width * writer->rows;
+
+    if ( !decreasing )
+    {
+      writer->line += writer->pitch * ( target->rows-1 );
+      writer->pitch = -writer->pitch;
+    }
+  }
+
+
+  static void
+  pfr_bitwriter_decode_bytes( PFR_BitWriter  writer,
+                              FT_Byte*       p,
+                              FT_Byte*       limit )
+  {
+    FT_Int    n, reload;
+    FT_Int    left = writer->width;
+    FT_Byte*  cur  = writer->line;
+    FT_UInt   mask = 0x80;
+    FT_UInt   val  = 0;
+    FT_UInt   c    = 0;
+
+
+    n = (FT_Int)( limit - p ) * 8;
+    if ( n > writer->total )
+      n = writer->total;
+
+    reload = n & 7;
+
+    for ( ; n > 0; n-- )
+    {
+      if ( ( n & 7 ) == reload )
+        val = *p++;
+
+      if ( val & 0x80 )
+        c |= mask;
+
+      val  <<= 1;
+      mask >>= 1;
+
+      if ( --left <= 0 )
+      {
+        cur[0] = (FT_Byte)c;
+        left   = writer->width;
+        mask   = 0x80;
+
+        writer->line += writer->pitch;
+        cur           = writer->line;
+        c             = 0;
+      }
+      else if ( mask == 0 )
+      {
+        cur[0] = c;
+        mask   = 0x80;
+        c      = 0;
+        cur ++;
+      }
+    }
+
+    if ( mask != 0x80 )
+      cur[0] = c;
+  }
+
+
+  static void
+  pfr_bitwriter_decode_rle1( PFR_BitWriter  writer,
+                             FT_Byte*       p,
+                             FT_Byte*       limit )
+  {
+    FT_Int    n, phase, count, counts[2], reload;
+    FT_Int    left = writer->width;
+    FT_Byte*  cur  = writer->line;
+    FT_UInt   mask = 0x80;
+    FT_UInt   c    = 0;
+
+
+    n = writer->total;
+
+    phase     = 1;
+    counts[0] = 0;
+    counts[1] = 0;
+    count     = 0;
+    reload    = 1;
+
+    for ( ; n > 0; n-- )
+    {
+      if ( reload )
+      {
+        do
+        {
+          if ( phase )
+          {
+            FT_Int  v;
+
+
+            if ( p >= limit )
+              break;
+
+            v         = *p++;
+            counts[0] = v >> 4;
+            counts[1] = v & 15;
+            phase     = 0;
+            count     = counts[0];
+          }
+          else
+          {
+            phase = 1;
+            count = counts[1];
+          }
+
+        } while ( count == 0 );
+      }
+
+      if ( phase )
+        c |= mask;
+
+      mask >>= 1;
+
+      if ( --left <= 0 )
+      {
+        cur[0] = (FT_Byte) c;
+        left   = writer->width;
+        mask   = 0x80;
+
+        writer->line += writer->pitch;
+        cur           = writer->line;
+        c             = 0;
+      }
+      else if ( mask == 0 )
+      {
+        cur[0] = c;
+        mask   = 0x80;
+        c      = 0;
+        cur ++;
+      }
+
+      reload = ( --count <= 0 );
+    }
+
+    if ( mask != 0x80 )
+      cur[0] = (FT_Byte) c;
+  }
+
+
+  static void
+  pfr_bitwriter_decode_rle2( PFR_BitWriter  writer,
+                             FT_Byte*       p,
+                             FT_Byte*       limit )
+  {
+    FT_Int    n, phase, count, reload;
+    FT_Int    left = writer->width;
+    FT_Byte*  cur  = writer->line;
+    FT_UInt   mask = 0x80;
+    FT_UInt   c    = 0;
+
+
+    n = writer->total;
+
+    phase  = 1;
+    count  = 0;
+    reload = 1;
+
+    for ( ; n > 0; n-- )
+    {
+      if ( reload )
+      {
+        do
+        {
+          if ( p >= limit )
+            break;
+
+          count = *p++;
+          phase = phase ^ 1;
+
+        } while ( count == 0 );
+      }
+
+      if ( phase )
+        c |= mask;
+
+      mask >>= 1;
+
+      if ( --left <= 0 )
+      {
+        cur[0] = (FT_Byte) c;
+        c      = 0;
+        mask   = 0x80;
+        left   = writer->width;
+
+        writer->line += writer->pitch;
+        cur           = writer->line;
+      }
+      else if ( mask == 0 )
+      {
+        cur[0] = c;
+        c      = 0;
+        mask   = 0x80;
+        cur ++;
+      }
+
+      reload = ( --count <= 0 );
+    }
+
+    if ( mask != 0x80 )
+      cur[0] = (FT_Byte) c;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  BITMAP DATA DECODING                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  pfr_lookup_bitmap_data( FT_Byte*   base,
+                          FT_Byte*   limit,
+                          FT_Int     count,
+                          FT_Byte    flags,
+                          FT_UInt    char_code,
+                          FT_ULong*  found_offset,
+                          FT_ULong*  found_size )
+  {
+    FT_UInt   left, right, char_len;
+    FT_Bool   two = flags & 1;
+    FT_Byte*  buff;
+
+
+    char_len = 4;
+    if ( two )       char_len += 1;
+    if ( flags & 2 ) char_len += 1;
+    if ( flags & 4 ) char_len += 1;
+
+    left  = 0;
+    right = count;
+
+    while ( left < right )
+    {
+      FT_UInt  middle, code;
+
+
+      middle = ( left + right ) >> 1;
+      buff   = base + middle * char_len;
+
+      /* check that we are not outside of the table -- */
+      /* this is possible with broken fonts...         */
+      if ( buff + char_len > limit )
+        goto Fail;
+
+      if ( two )
+        code = PFR_NEXT_USHORT( buff );
+      else
+        code = PFR_NEXT_BYTE( buff );
+
+      if ( code == char_code )
+        goto Found_It;
+
+      if ( code < char_code )
+        left = middle;
+      else
+        right = middle;
+    }
+
+  Fail:
+    /* Not found */
+    *found_size   = 0;
+    *found_offset = 0;
+    return;
+
+  Found_It:
+    if ( flags & 2 )
+      *found_size = PFR_NEXT_USHORT( buff );
+    else
+      *found_size = PFR_NEXT_BYTE( buff );
+
+    if ( flags & 4 )
+      *found_offset = PFR_NEXT_ULONG( buff );
+    else
+      *found_offset = PFR_NEXT_USHORT( buff );
+  }
+
+
+  /* load bitmap metrics.  "*padvance" must be set to the default value */
+  /* before calling this function...                                    */
+  /*                                                                    */
+  static FT_Error
+  pfr_load_bitmap_metrics( FT_Byte**  pdata,
+                           FT_Byte*   limit,
+                           FT_Long    scaled_advance,
+                           FT_Long   *axpos,
+                           FT_Long   *aypos,
+                           FT_UInt   *axsize,
+                           FT_UInt   *aysize,
+                           FT_Long   *aadvance,
+                           FT_UInt   *aformat )
+  {
+    FT_Error  error = 0;
+    FT_Byte   flags;
+    FT_Char   b;
+    FT_Byte*  p = *pdata;
+    FT_Long   xpos, ypos, advance;
+    FT_UInt   xsize, ysize;
+
+
+    PFR_CHECK( 1 );
+    flags = PFR_NEXT_BYTE( p );
+
+    xpos    = 0;
+    ypos    = 0;
+    xsize   = 0;
+    ysize   = 0;
+    advance = 0;
+
+    switch ( flags & 3 )
+    {
+    case 0:
+      PFR_CHECK( 1 );
+      b    = PFR_NEXT_INT8( p );
+      xpos = b >> 4;
+      ypos = ( (FT_Char)( b << 4 ) ) >> 4;
+      break;
+
+    case 1:
+      PFR_CHECK( 2 );
+      xpos = PFR_NEXT_INT8( p );
+      ypos = PFR_NEXT_INT8( p );
+      break;
+
+    case 2:
+      PFR_CHECK( 4 );
+      xpos = PFR_NEXT_SHORT( p );
+      ypos = PFR_NEXT_SHORT( p );
+      break;
+
+    case 3:
+      PFR_CHECK( 6 );
+      xpos = PFR_NEXT_LONG( p );
+      ypos = PFR_NEXT_LONG( p );
+      break;
+
+    default:
+      ;
+    }
+
+    flags >>= 2;
+    switch ( flags & 3 )
+    {
+    case 0:
+      /* blank image */
+      xsize = 0;
+      ysize = 0;
+      break;
+
+    case 1:
+      PFR_CHECK( 1 );
+      b     = PFR_NEXT_BYTE( p );
+      xsize = ( b >> 4 ) & 0xF;
+      ysize = b & 0xF;
+      break;
+
+    case 2:
+      PFR_CHECK( 2 );
+      xsize = PFR_NEXT_BYTE( p );
+      ysize = PFR_NEXT_BYTE( p );
+      break;
+
+    case 3:
+      PFR_CHECK( 4 );
+      xsize = PFR_NEXT_USHORT( p );
+      ysize = PFR_NEXT_USHORT( p );
+      break;
+
+    default:
+      ;
+    }
+
+    flags >>= 2;
+    switch ( flags & 3 )
+    {
+    case 0:
+      advance = scaled_advance;
+      break;
+
+    case 1:
+      PFR_CHECK( 1 );
+      advance = PFR_NEXT_INT8( p ) << 8;
+      break;
+
+    case 2:
+      PFR_CHECK( 2 );
+      advance = PFR_NEXT_SHORT( p );
+      break;
+
+    case 3:
+      PFR_CHECK( 3 );
+      advance = PFR_NEXT_LONG( p );
+      break;
+
+    default:
+      ;
+    }
+
+    *axpos    = xpos;
+    *aypos    = ypos;
+    *axsize   = xsize;
+    *aysize   = ysize;
+    *aadvance = advance;
+    *aformat  = flags >> 2;
+    *pdata    = p;
+
+  Exit:
+    return error;
+
+  Too_Short:
+    error = PFR_Err_Invalid_Table;
+    FT_ERROR(( "pfr_load_bitmap_metrics: invalid glyph data\n" ));
+    goto Exit;
+  }
+
+
+  static FT_Error
+  pfr_load_bitmap_bits( FT_Byte*    p,
+                        FT_Byte*    limit,
+                        FT_UInt     format,
+                        FT_UInt     decreasing,
+                        FT_Bitmap*  target )
+  {
+    FT_Error          error = 0;
+    PFR_BitWriterRec  writer;
+
+
+    if ( target->rows > 0 && target->width > 0 )
+    {
+      pfr_bitwriter_init( &writer, target, decreasing );
+
+      switch ( format )
+      {
+      case 0: /* packed bits */
+        pfr_bitwriter_decode_bytes( &writer, p, limit );
+        break;
+
+      case 1: /* RLE1 */
+        pfr_bitwriter_decode_rle1( &writer, p, limit );
+        break;
+
+      case 2: /* RLE2 */
+        pfr_bitwriter_decode_rle2( &writer, p, limit );
+        break;
+
+      default:
+        FT_ERROR(( "pfr_read_bitmap_data: invalid image type\n" ));
+        error = FT_Err_Invalid_File_Format;
+      }
+    }
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     BITMAP LOADING                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( FT_Error )
+  pfr_slot_load_bitmap( PFR_Slot  glyph,
+                        PFR_Size  size,
+                        FT_UInt   glyph_index )
+  {
+    FT_Error     error;
+    PFR_Face     face   = (PFR_Face) glyph->root.face;
+    FT_Stream    stream = face->root.stream;
+    PFR_PhyFont  phys   = &face->phy_font;
+    FT_ULong     gps_offset;
+    FT_ULong     gps_size;
+    PFR_Char     character;
+    PFR_Strike   strike;
+
+
+    character = &phys->chars[glyph_index];
+
+    /* Look-up a bitmap strike corresponding to the current */
+    /* character dimensions                                 */
+    {
+      FT_UInt  n;
+
+
+      strike = phys->strikes;
+      for ( n = 0; n < phys->num_strikes; n++ )
+      {
+        if ( strike->x_ppm == (FT_UInt)size->root.metrics.x_ppem &&
+             strike->y_ppm == (FT_UInt)size->root.metrics.y_ppem )
+        {
+          goto Found_Strike;
+        }
+
+        strike++;
+      }
+
+      /* couldn't find it */
+      return FT_Err_Invalid_Argument;
+    }
+
+  Found_Strike:
+
+    /* Now lookup the glyph's position within the file */
+    {
+      FT_UInt  char_len;
+
+
+      char_len = 4;
+      if ( strike->flags & 1 ) char_len += 1;
+      if ( strike->flags & 2 ) char_len += 1;
+      if ( strike->flags & 4 ) char_len += 1;
+
+      /* Access data directly in the frame to speed lookups */
+      if ( FT_STREAM_SEEK( phys->bct_offset + strike->bct_offset ) ||
+           FT_FRAME_ENTER( char_len * strike->num_bitmaps )        )
+        goto Exit;
+
+      pfr_lookup_bitmap_data( stream->cursor,
+                              stream->limit,
+                              strike->num_bitmaps,
+                              strike->flags,
+                              character->char_code,
+                              &gps_offset,
+                              &gps_size );
+
+      FT_FRAME_EXIT();
+
+      if ( gps_size == 0 )
+      {
+        /* Could not find a bitmap program string for this glyph */
+        error = FT_Err_Invalid_Argument;
+        goto Exit;
+      }
+    }
+
+    /* get the bitmap metrics */
+    {
+      FT_Long   xpos, ypos, advance;
+      FT_UInt   xsize, ysize, format;
+      FT_Byte*  p;
+
+
+      advance = FT_MulDiv( size->root.metrics.x_ppem << 8,
+                           character->advance,
+                           phys->metrics_resolution );
+
+      /* XXX: handle linearHoriAdvance correctly! */
+
+      if ( FT_STREAM_SEEK( face->header.gps_section_offset + gps_offset ) ||
+           FT_FRAME_ENTER( gps_size )                                     )
+        goto Exit;
+
+      p     = stream->cursor;
+      error = pfr_load_bitmap_metrics( &p, stream->limit,
+                                       advance,
+                                       &xpos, &ypos,
+                                       &xsize, &ysize,
+                                       &advance, &format );
+      if ( !error )
+      {
+        glyph->root.format = FT_GLYPH_FORMAT_BITMAP;
+      
+        /* Set up glyph bitmap and metrics */
+        glyph->root.bitmap.width      = (FT_Int)xsize;
+        glyph->root.bitmap.rows       = (FT_Int)ysize;
+        glyph->root.bitmap.pitch      = (FT_Long)( xsize + 7 ) >> 3;
+        glyph->root.bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
+
+        glyph->root.metrics.width        = (FT_Long)xsize << 6;
+        glyph->root.metrics.height       = (FT_Long)ysize << 6;
+        glyph->root.metrics.horiBearingX = xpos << 6;
+        glyph->root.metrics.horiBearingY = ypos << 6;
+        glyph->root.metrics.horiAdvance  = ( ( advance >> 2 ) + 32 ) & -64;
+        glyph->root.metrics.vertBearingX = - glyph->root.metrics.width >> 1;
+        glyph->root.metrics.vertBearingY = 0;
+        glyph->root.metrics.vertAdvance  = size->root.metrics.height;
+
+        glyph->root.bitmap_left = xpos;
+        glyph->root.bitmap_top  = ypos + ysize;
+
+        /* Allocate and read bitmap data */
+        {
+          FT_Memory  memory = face->root.memory;
+          FT_Long    len    = glyph->root.bitmap.pitch * ysize;
+
+
+          if ( !FT_ALLOC( glyph->root.bitmap.buffer, len ) )
+          {
+            error = pfr_load_bitmap_bits( p,
+                                          stream->limit,
+                                          format,
+                                          face->header.color_flags & 2,
+                                          &glyph->root.bitmap );
+          }
+        }
+      }
+
+      FT_FRAME_EXIT();
+    }
+
+  Exit:
+    return error;
+  }
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrsbit.h
@@ -1,0 +1,36 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrsbit.h                                                              */
+/*                                                                         */
+/*    FreeType PFR bitmap loader (specification).                          */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PFRSBIT_H__
+#define __PFRSBIT_H__
+
+#include "pfrobjs.h"
+
+FT_BEGIN_HEADER
+
+  FT_LOCAL( FT_Error )
+  pfr_slot_load_bitmap( PFR_Slot  glyph,
+                        PFR_Size  size,
+                        FT_UInt   glyph_index );
+
+FT_END_HEADER
+
+#endif /* __PFR_SBIT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pfrtypes.h
@@ -1,0 +1,354 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pfrtypes.h                                                             */
+/*                                                                         */
+/*    FreeType PFR data structures (specification only).                   */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PFRTYPES_H__
+#define __PFRTYPES_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+
+FT_BEGIN_HEADER
+
+  /************************************************************************/
+
+  /* the PFR Header structure */
+  typedef struct  PFR_HeaderRec_
+  {
+    FT_UInt32  signature;
+    FT_UInt    version;
+    FT_UInt    signature2;
+    FT_UInt    header_size;
+
+    FT_UInt    log_dir_size;
+    FT_UInt    log_dir_offset;
+
+    FT_UInt    log_font_max_size;
+    FT_UInt32  log_font_section_size;
+    FT_UInt32  log_font_section_offset;
+
+    FT_UInt32  phy_font_max_size;
+    FT_UInt32  phy_font_section_size;
+    FT_UInt32  phy_font_section_offset;
+
+    FT_UInt    gps_max_size;
+    FT_UInt32  gps_section_size;
+    FT_UInt32  gps_section_offset;
+
+    FT_UInt    max_blue_values;
+    FT_UInt    max_x_orus;
+    FT_UInt    max_y_orus;
+
+    FT_UInt    phy_font_max_size_high;
+    FT_UInt    color_flags;
+
+    FT_UInt32  bct_max_size;
+    FT_UInt32  bct_set_max_size;
+    FT_UInt32  phy_bct_set_max_size;
+
+    FT_UInt    num_phy_fonts;
+    FT_UInt    max_vert_stem_snap;
+    FT_UInt    max_horz_stem_snap;
+    FT_UInt    max_chars;
+
+  } PFR_HeaderRec, *PFR_Header;
+
+
+  /* used in `color_flags' field of the PFR_Header */
+  typedef enum  PFR_HeaderFlags_
+  {
+    PFR_FLAG_BLACK_PIXEL   = 1,
+    PFR_FLAG_INVERT_BITMAP = 2
+
+  } PFR_HeaderFlags;
+
+
+  /************************************************************************/
+
+  typedef struct  PFR_LogFontRec_
+  {
+    FT_UInt32  size;
+    FT_UInt32  offset;
+
+    FT_Int32   matrix[4];
+    FT_UInt    stroke_flags;
+    FT_Int     stroke_thickness;
+    FT_Int     bold_thickness;
+    FT_Int32   miter_limit;
+
+    FT_UInt32  phys_size;
+    FT_UInt32  phys_offset;
+
+  } PFR_LogFontRec, *PFR_LogFont;
+
+
+  typedef enum  PFR_LogFlags_
+  {
+    PFR_LOG_EXTRA_ITEMS  = 0x40,
+    PFR_LOG_2BYTE_BOLD   = 0x20,
+    PFR_LOG_BOLD         = 0x10,
+    PFR_LOG_2BYTE_STROKE = 8,
+    PFR_LOG_STROKE       = 4,
+    PFR_LINE_JOIN_MASK   = 3
+
+  } PFR_LogFlags;
+
+
+  typedef enum  PFR_LineJoinFlags_
+  {
+    PFR_LINE_JOIN_MITER = 0,
+    PFR_LINE_JOIN_ROUND = 1,
+    PFR_LINE_JOIN_BEVEL = 2
+
+  } PFR_LineJoinFlags;
+
+
+  /************************************************************************/
+
+  typedef enum  PFR_BitmapFlags_
+  {
+    PFR_BITMAP_3BYTE_OFFSET   = 4,
+    PFR_BITMAP_2BYTE_SIZE     = 2,
+    PFR_BITMAP_2BYTE_CHARCODE = 1
+
+  } PFR_BitmapFlags;
+
+
+  typedef struct  PFR_BitmapCharRec_
+  {
+    FT_UInt    char_code;
+    FT_UInt    gps_size;
+    FT_UInt32  gps_offset;
+
+  } PFR_BitmapCharRec, *PFR_BitmapChar;
+
+
+  typedef enum  PFR_StrikeFlags_
+  {
+    PFR_STRIKE_2BYTE_COUNT  = 0x10,
+    PFR_STRIKE_3BYTE_OFFSET = 0x08,
+    PFR_STRIKE_3BYTE_SIZE   = 0x04,
+    PFR_STRIKE_2BYTE_YPPM   = 0x02,
+    PFR_STRIKE_2BYTE_XPPM   = 0x01
+
+  } PFR_StrikeFlags;
+
+
+  typedef struct  PFR_StrikeRec_
+  {
+    FT_UInt         x_ppm;
+    FT_UInt         y_ppm;
+    FT_UInt         flags;
+
+    FT_UInt32       gps_size;
+    FT_UInt32       gps_offset;
+
+    FT_UInt32       bct_size;
+    FT_UInt32       bct_offset;
+
+    /* optional */
+    FT_UInt         num_bitmaps;
+    PFR_BitmapChar  bitmaps;
+
+  } PFR_StrikeRec, *PFR_Strike;
+
+
+  /************************************************************************/
+
+  typedef struct  PFR_CharRec_
+  {
+    FT_UInt    char_code;
+    FT_Int     advance;
+    FT_UInt    gps_size;
+    FT_UInt32  gps_offset;
+
+  } PFR_CharRec, *PFR_Char;
+
+
+  /************************************************************************/
+
+  typedef struct  PFR_DimensionRec_
+  {
+    FT_UInt  standard;
+    FT_UInt  num_stem_snaps;
+    FT_Int*  stem_snaps;
+
+  } PFR_DimensionRec, *PFR_Dimension;
+
+  /************************************************************************/
+
+  typedef struct PFR_KernItemRec_*  PFR_KernItem;
+
+  typedef struct  PFR_KernItemRec_
+  {
+    PFR_KernItem  next;
+    FT_UInt       pair_count;
+    FT_UInt       pair_size;
+    FT_Int        base_adj;
+    FT_UInt       flags;
+    FT_UInt32     offset;
+    FT_UInt32     pair1;
+    FT_UInt32     pair2;
+
+  } PFR_KernItemRec;
+
+#define PFR_KERN_INDEX( g1, g2 ) \
+  ( ( (FT_UInt32)(g1) << 16 ) | (FT_UInt16)(g2) )
+
+  typedef struct  PFR_KernPairRec_
+  {
+    FT_UInt    glyph1;
+    FT_UInt    glyph2;
+    FT_Vector  kerning;
+
+  } PFR_KernPairRec, *PFR_KernPair;
+
+  /************************************************************************/
+
+  typedef struct  PFR_PhyFontRec_
+  {
+    FT_Memory          memory;
+    FT_UInt32          offset;
+
+    FT_UInt            font_ref_number;
+    FT_UInt            outline_resolution;
+    FT_UInt            metrics_resolution;
+    FT_BBox            bbox;
+    FT_UInt            flags;
+    FT_UInt            standard_advance;
+
+    PFR_DimensionRec   horizontal;
+    PFR_DimensionRec   vertical;
+
+    FT_String*         font_id;
+
+    FT_UInt            num_strikes;
+    FT_UInt            max_strikes;
+    PFR_StrikeRec*     strikes;
+
+    FT_UInt            num_blue_values;
+    FT_Int            *blue_values;
+    FT_UInt            blue_fuzz;
+    FT_UInt            blue_scale;
+
+    FT_UInt            num_chars;
+    FT_UInt32          chars_offset;
+    PFR_Char           chars;
+
+    FT_UInt            num_kern_pairs;
+    PFR_KernItem       kern_items;
+    PFR_KernItem*      kern_items_tail;
+
+    /* not part of the spec, but used during load */
+    FT_UInt32          bct_offset;
+    FT_Byte*           cursor;
+
+  } PFR_PhyFontRec, *PFR_PhyFont;
+
+
+  typedef enum  PFR_PhyFlags_
+  {
+    PFR_PHY_EXTRA_ITEMS      = 0x80,
+    PFR_PHY_3BYTE_GPS_OFFSET = 0x20,
+    PFR_PHY_2BYTE_GPS_SIZE   = 0x10,
+    PFR_PHY_ASCII_CODE       = 0x08,
+    PFR_PHY_PROPORTIONAL     = 0x04,
+    PFR_PHY_2BYTE_CHARCODE   = 0x02,
+    PFR_PHY_VERTICAL         = 0x01
+
+  } PFR_PhyFlags;
+
+
+  typedef enum PFR_KernFlags_
+  {
+    PFR_KERN_2BYTE_ADJ   = 0x01,
+    PFR_KERN_2BYTE_CHAR  = 0x02
+
+  } PFR_KernFlags;
+
+
+  /************************************************************************/
+
+  typedef enum  PFR_GlyphFlags_
+  {
+    PFR_GLYPH_IS_COMPOUND   = 0x80,
+    PFR_GLYPH_EXTRA_ITEMS   = 0x08,
+    PFR_GLYPH_1BYTE_XYCOUNT = 0x04,
+    PFR_GLYPH_XCOUNT        = 0x02,
+    PFR_GLYPH_YCOUNT        = 0x01
+
+  } PFR_GlyphFlags;
+
+
+  /* controlled coordinate */
+  typedef struct  PFR_CoordRec_
+  {
+    FT_UInt  org;
+    FT_UInt  cur;
+
+  } PFR_CoordRec, *PFR_Coord;
+
+
+  typedef struct  PFR_SubGlyphRec_
+  {
+    FT_Fixed   x_scale;
+    FT_Fixed   y_scale;
+    FT_Int     x_delta;
+    FT_Int     y_delta;
+    FT_UInt32  gps_offset;
+    FT_UInt    gps_size;
+
+  } PFR_SubGlyphRec, *PFR_SubGlyph;
+
+
+  typedef enum  PFR_SubgGlyphFlags_
+  {
+    PFR_SUBGLYPH_3BYTE_OFFSET = 0x80,
+    PFR_SUBGLYPH_2BYTE_SIZE   = 0x40,
+    PFR_SUBGLYPH_YSCALE       = 0x20,
+    PFR_SUBGLYPH_XSCALE       = 0x10
+
+  } PFR_SubGlyphFlags;
+
+
+  typedef struct  PFR_GlyphRec_
+  {
+    FT_Byte           format;
+
+    FT_UInt           num_x_control;
+    FT_UInt           num_y_control;
+    FT_UInt           max_xy_control;
+    FT_Pos*           x_control;
+    FT_Pos*           y_control;
+
+
+    FT_UInt           num_subs;
+    FT_UInt           max_subs;
+    PFR_SubGlyphRec*  subs;
+
+    FT_GlyphLoader    loader;
+    FT_Bool           path_begun;
+
+  } PFR_GlyphRec, *PFR_Glyph;
+
+
+FT_END_HEADER
+
+#endif /* __PFRTYPES_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psaux.c
@@ -1,0 +1,28 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psaux.c                                                                */
+/*                                                                         */
+/*    FreeType auxiliary PostScript driver component (body only).          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "psobjs.c"
+#include "psauxmod.c"
+#include "t1decode.c"
+#include "t1cmap.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psauxerr.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psauxerr.h                                                             */
+/*                                                                         */
+/*    PS auxiliary module error codes (specification only).                */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the PS auxiliary module error enumeration */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __PSAUXERR_H__
+#define __PSAUXERR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  PSaux_Err_
+#define FT_ERR_BASE    FT_Mod_Err_PSaux
+
+#include FT_ERRORS_H
+
+#endif /* __PSAUXERR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psauxmod.c
@@ -1,0 +1,118 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psauxmod.c                                                             */
+/*                                                                         */
+/*    FreeType auxiliary PostScript module implementation (body).          */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "psauxmod.h"
+#include "psobjs.h"
+#include "t1decode.h"
+#include "t1cmap.h"
+
+
+  FT_CALLBACK_TABLE_DEF
+  const PS_Table_FuncsRec  ps_table_funcs =
+  {
+    ps_table_new,
+    ps_table_done,
+    ps_table_add,
+    ps_table_release
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const PS_Parser_FuncsRec  ps_parser_funcs =
+  {
+    ps_parser_init,
+    ps_parser_done,
+    ps_parser_skip_spaces,
+    ps_parser_skip_alpha,
+    ps_parser_to_int,
+    ps_parser_to_fixed,
+    ps_parser_to_coord_array,
+    ps_parser_to_fixed_array,
+    ps_parser_to_token,
+    ps_parser_to_token_array,
+    ps_parser_load_field,
+    ps_parser_load_field_table
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const T1_Builder_FuncsRec  t1_builder_funcs =
+  {
+    t1_builder_init,
+    t1_builder_done,
+    t1_builder_check_points,
+    t1_builder_add_point,
+    t1_builder_add_point1,
+    t1_builder_add_contour,
+    t1_builder_start_point,
+    t1_builder_close_contour
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const T1_Decoder_FuncsRec  t1_decoder_funcs =
+  {
+    t1_decoder_init,
+    t1_decoder_done,
+    t1_decoder_parse_charstrings
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const T1_CMap_ClassesRec  t1_cmap_classes =
+  {
+    &t1_cmap_standard_class_rec,
+    &t1_cmap_expert_class_rec,
+    &t1_cmap_custom_class_rec,
+    &t1_cmap_unicode_class_rec
+  };
+
+
+  static
+  const PSAux_Interface  psaux_interface =
+  {
+    &ps_table_funcs,
+    &ps_parser_funcs,
+    &t1_builder_funcs,
+    &t1_decoder_funcs,
+
+    t1_decrypt,
+    
+    (const T1_CMap_ClassesRec*) &t1_cmap_classes,
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Module_Class  psaux_module_class =
+  {
+    0,
+    sizeof( FT_ModuleRec ),
+    "psaux",
+    0x10000L,
+    0x20000L,
+
+    &psaux_interface,  /* module-specific interface */
+
+    (FT_Module_Constructor)0,
+    (FT_Module_Destructor) 0,
+    (FT_Module_Requester)  0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psauxmod.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psauxmod.h                                                             */
+/*                                                                         */
+/*    FreeType auxiliary PostScript module implementation (specification). */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSAUXMOD_H__
+#define __PSAUXMOD_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Module_Class )  psaux_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __PSAUXMOD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo.h
@@ -1,0 +1,53 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo.h                                                              */
+/*                                                                         */
+/*    This header file defines the used hinting algorithm.                 */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used        */
+/*  modified and distributed under the terms of the FreeType project       */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO_H__
+#define __PSHALGO_H__
+
+FT_BEGIN_HEADER
+
+/* define to choose hinting algorithm */
+#define PSH_ALGORITHM_3
+
+#if defined(PSH_ALGORITHM_1)
+
+#  include "pshalgo1.h"
+#  define PS_HINTS_APPLY_FUNC  ps1_hints_apply
+
+#elif defined(PSH_ALGORITHM_2)
+
+#  include "pshalgo2.h"
+#  define PS_HINTS_APPLY_FUNC  ps2_hints_apply
+
+#elif defined(PSH_ALGORITHM_3)
+
+#  include "pshalgo3.h"
+#  define PS_HINTS_APPLY_FUNC  ps3_hints_apply
+
+#else
+
+#  error "invalid Postscript Hinter algorithm selection"
+
+#endif
+
+FT_END_HEADER
+
+#endif /* __PSHALGO_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo1.c
@@ -1,0 +1,785 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo1.c                                                             */
+/*                                                                         */
+/*    PostScript hinting algorithm 1 (body).                               */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used        */
+/*  modified and distributed under the terms of the FreeType project       */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo1.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pshalgo1
+
+#ifdef DEBUG_HINTER
+  PSH1_Hint_Table  ps1_debug_hint_table = 0;
+  PSH1_HintFunc    ps1_debug_hint_func  = 0;
+#endif
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /*****                                                              *****/
+ /*****                 BASIC HINTS RECORDINGS                       *****/
+ /*****                                                              *****/
+ /************************************************************************/
+ /************************************************************************/
+
+  /* return true iff two stem hints overlap */
+  static FT_Int
+  psh1_hint_overlap( PSH1_Hint  hint1,
+                     PSH1_Hint  hint2 )
+  {
+    return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+             hint2->org_pos + hint2->org_len >= hint1->org_pos );
+  }
+
+
+  /* destroy hints table */
+  static void
+  psh1_hint_table_done( PSH1_Hint_Table  table,
+                        FT_Memory        memory )
+  {
+    FT_FREE( table->zones );
+    table->num_zones = 0;
+    table->zone      = 0;
+
+    FT_FREE( table->sort );
+    FT_FREE( table->hints );
+    table->num_hints   = 0;
+    table->max_hints   = 0;
+    table->sort_global = 0;
+  }
+
+
+  /* deactivate all hints in a table */
+  static void
+  psh1_hint_table_deactivate( PSH1_Hint_Table  table )
+  {
+    FT_UInt    count = table->max_hints;
+    PSH1_Hint  hint  = table->hints;
+
+
+    for ( ; count > 0; count--, hint++ )
+    {
+      psh1_hint_deactivate( hint );
+      hint->order = -1;
+    }
+  }
+
+
+  /* internal function used to record a new hint */
+  static void
+  psh1_hint_table_record( PSH1_Hint_Table  table,
+                          FT_UInt          idx )
+  {
+    PSH1_Hint  hint = table->hints + idx;
+
+
+    if ( idx >= table->max_hints )
+    {
+      FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
+      return;
+    }
+
+    /* ignore active hints */
+    if ( psh1_hint_is_active( hint ) )
+      return;
+
+    psh1_hint_activate( hint );
+
+    /* now scan the current active hint set in order to determine */
+    /* if we are overlapping with another segment                 */
+    {
+      PSH1_Hint*  sorted = table->sort_global;
+      FT_UInt     count  = table->num_hints;
+      PSH1_Hint   hint2;
+
+
+      hint->parent = 0;
+      for ( ; count > 0; count--, sorted++ )
+      {
+        hint2 = sorted[0];
+
+        if ( psh1_hint_overlap( hint, hint2 ) )
+        {
+          hint->parent = hint2;
+          break;
+        }
+      }
+    }
+
+    if ( table->num_hints < table->max_hints )
+      table->sort_global[table->num_hints++] = hint;
+    else
+      FT_ERROR(( "%s.activate: too many sorted hints!  BUG!\n",
+                 "ps.fitter" ));
+  }
+
+
+  static void
+  psh1_hint_table_record_mask( PSH1_Hint_Table  table,
+                               PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   idx, limit;
+
+
+    limit = hint_mask->num_bits;
+
+    if ( limit != table->max_hints )
+      FT_ERROR(( "%s.activate_mask: invalid bit count (%d instead of %d)\n",
+                 "ps.fitter", hint_mask->num_bits, table->max_hints ));
+
+    for ( idx = 0; idx < limit; idx++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+
+      if ( val & mask )
+        psh1_hint_table_record( table, idx );
+
+      mask >>= 1;
+    }
+  }
+
+
+  /* create hints table */
+  static FT_Error
+  psh1_hint_table_init( PSH1_Hint_Table  table,
+                        PS_Hint_Table    hints,
+                        PS_Mask_Table    hint_masks,
+                        PS_Mask_Table    counter_masks,
+                        FT_Memory        memory )
+  {
+    FT_UInt   count = hints->num_hints;
+    FT_Error  error;
+
+    FT_UNUSED( counter_masks );
+
+
+    /* allocate our tables */
+    if ( FT_NEW_ARRAY( table->sort,  2 * count     ) ||
+         FT_NEW_ARRAY( table->hints,     count     ) ||
+         FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
+      goto Exit;
+
+    table->max_hints   = count;
+    table->sort_global = table->sort + count;
+    table->num_hints   = 0;
+    table->num_zones   = 0;
+    table->zone        = 0;
+
+    /* now, initialize the "hints" array */
+    {
+      PSH1_Hint  write = table->hints;
+      PS_Hint    read  = hints->hints;
+
+
+      for ( ; count > 0; count--, write++, read++ )
+      {
+        write->org_pos = read->pos;
+        write->org_len = read->len;
+        write->flags   = read->flags;
+      }
+    }
+
+    /* we now need to determine the initial "parent" stems; first  */
+    /* activate the hints that are given by the initial hint masks */
+    if ( hint_masks )
+    {
+      FT_UInt  Count = hint_masks->num_masks;
+      PS_Mask  Mask  = hint_masks->masks;
+
+
+      table->hint_masks = hint_masks;
+
+      for ( ; Count > 0; Count--, Mask++ )
+        psh1_hint_table_record_mask( table, Mask );
+    }
+
+    /* now, do a linear parse in case some hints were left alone */
+    if ( table->num_hints != table->max_hints )
+    {
+      FT_UInt   Index, Count;
+
+
+      FT_ERROR(( "%s.init: missing/incorrect hint masks!\n" ));
+      Count = table->max_hints;
+      for ( Index = 0; Index < Count; Index++ )
+        psh1_hint_table_record( table, Index );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  psh1_hint_table_activate_mask( PSH1_Hint_Table  table,
+                                 PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   idx, limit, count;
+
+
+    limit = hint_mask->num_bits;
+    count = 0;
+
+    psh1_hint_table_deactivate( table );
+
+    for ( idx = 0; idx < limit; idx++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+
+      if ( val & mask )
+      {
+        PSH1_Hint  hint = &table->hints[idx];
+
+
+        if ( !psh1_hint_is_active( hint ) )
+        {
+          PSH1_Hint*  sort = table->sort;
+          FT_UInt     count2;
+          PSH1_Hint   hint2;
+
+
+          for ( count2 = count; count2 > 0; count2--, sort++ )
+          {
+            hint2 = sort[0];
+            if ( psh1_hint_overlap( hint, hint2 ) )
+            {
+              FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
+                         "psf.hint" ));
+              break;
+            }
+          }
+
+          if ( count2 == 0 )
+          {
+            psh1_hint_activate( hint );
+            if ( count < table->max_hints )
+              table->sort[count++] = hint;
+            else
+              FT_ERROR(( "%s.activate_mask: too many active hints\n",
+                         "psf.hint" ));
+          }
+        }
+      }
+
+      mask >>= 1;
+    }
+    table->num_hints = count;
+
+    /* now, sort the hints; they are guaranteed to not overlap */
+    /* so we can compare their "org_pos" field directly        */
+    {
+      FT_Int      i1, i2;
+      PSH1_Hint   hint1, hint2;
+      PSH1_Hint*  sort = table->sort;
+
+
+      /* a simple bubble sort will do, since in 99% of cases, the hints */
+      /* will be already sorted; and the sort will be linear            */
+      for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+      {
+        hint1 = sort[i1];
+
+        for ( i2 = i1 - 1; i2 >= 0; i2-- )
+        {
+          hint2 = sort[i2];
+          if ( hint2->org_pos < hint1->org_pos )
+            break;
+
+          sort[i2 + 1] = hint2;
+          sort[i2]     = hint1;
+        }
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****               HINTS GRID-FITTING AND OPTIMIZATION             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#ifdef DEBUG_HINTER
+  void
+  ps_simple_scale( PSH1_Hint_Table  table,
+                   FT_Fixed         scale,
+                   FT_Fixed         delta,
+                   FT_Int           vertical )
+  {
+    PSH1_Hint  hint;
+    FT_UInt    count;
+
+
+    for ( count = 0; count < table->num_hints; count++ )
+    {
+      hint = table->sort[count];
+      if ( psh1_hint_is_active( hint ) )
+      {
+        hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+        hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+        if ( ps1_debug_hint_func )
+          ps1_debug_hint_func( hint, vertical );
+      }
+    }
+  }
+#endif
+
+
+  FT_LOCAL_DEF( FT_Error )
+  psh1_hint_table_optimize( PSH1_Hint_Table  table,
+                            PSH_Globals      globals,
+                            FT_Outline*      outline,
+                            FT_Int           vertical )
+  {
+    PSH_Dimension  dim   = &globals->dimension[vertical];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+    FT_UNUSED( outline );
+
+
+#ifdef DEBUG_HINTER
+    if ( ps_debug_no_vert_hints && vertical )
+    {
+      ps_simple_scale( table, scale, delta, vertical );
+      return 0;
+    }
+
+    if ( ps_debug_no_horz_hints && !vertical )
+    {
+      ps_simple_scale( table, scale, delta, vertical );
+      return 0;
+    }
+#endif
+
+    /* XXXX: for now, we only scale the hints to test all other aspects */
+    /*       of the PostScript hinter                                   */
+    {
+      PSH1_Hint  hint;
+      FT_UInt   count;
+
+
+      for ( count = 0; count < table->num_hints; count++ )
+      {
+        hint = table->sort[count];
+        if ( psh1_hint_is_active( hint ) )
+        {
+#if 1
+          FT_Pos  pos = FT_MulFix( hint->org_pos, scale ) + delta;
+          FT_Pos  len = FT_MulFix( hint->org_len, scale );
+
+          FT_Pos  fit_center;
+          FT_Pos  fit_len;
+
+          PSH_AlignmentRec  align;
+
+
+          /* compute fitted width/height */
+          fit_len = psh_dimension_snap_width( dim, hint->org_len );
+          if ( fit_len < 64 )
+            fit_len = 64;
+          else
+            fit_len = ( fit_len + 32 ) & -64;
+
+          hint->cur_len = fit_len;
+
+          /* check blue zones for horizontal stems */
+          align.align     = PSH_BLUE_ALIGN_NONE;
+          align.align_bot = align.align_top = 0;
+          if ( !vertical )
+          {
+            psh_blues_snap_stem( &globals->blues,
+                                 hint->org_pos + hint->org_len,
+                                 hint->org_pos,
+                                 &align );
+          }
+
+          switch ( align.align )
+          {
+          case PSH_BLUE_ALIGN_TOP:
+            /* the top of the stem is aligned against a blue zone */
+            hint->cur_pos = align.align_top - fit_len;
+            break;
+
+          case PSH_BLUE_ALIGN_BOT:
+            /* the bottom of the stem is aligned against a blue zone */
+            hint->cur_pos = align.align_bot;
+            break;
+
+          case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+            /* both edges of the stem are aligned against blue zones */
+            hint->cur_pos = align.align_bot;
+            hint->cur_len = align.align_top - align.align_bot;
+            break;
+
+          default:
+            /* normal processing */
+            if ( ( fit_len / 64 ) & 1 )
+            {
+              /* odd number of pixels */
+              fit_center = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
+            }
+            else
+            {
+              /* even number of pixels */
+              fit_center = ( pos + ( len >> 1 ) + 32 ) & -64;
+            }
+
+            hint->cur_pos = fit_center - ( fit_len >> 1 );
+          }
+
+# else
+
+          hint->cur_pos = ( FT_MulFix( hint->org_pos, scale ) + delta + 32 )
+                          & -64;
+          hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+# endif
+
+#ifdef DEBUG_HINTER
+        if ( ps1_debug_hint_func )
+          ps1_debug_hint_func( hint, vertical );
+#endif
+        }
+      }
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****               POINTS INTERPOLATION ROUTINES                   *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define PSH1_ZONE_MIN  -3200000
+#define PSH1_ZONE_MAX  +3200000
+
+#define xxDEBUG_ZONES
+
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+  static void
+  psh1_print_zone( PSH1_Zone  zone )
+  {
+    printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+             zone->scale / 65536.0,
+             zone->delta / 64.0,
+             zone->min,
+             zone->max );
+  }
+
+#else
+#define psh1_print_zone( x )  do { } while ( 0 )
+#endif
+
+  /* setup interpolation zones once the hints have been grid-fitted */
+  /* by the optimizer                                               */
+  static void
+  psh1_hint_table_setup_zones( PSH1_Hint_Table  table,
+                               FT_Fixed         scale,
+                               FT_Fixed         delta )
+  {
+    FT_UInt     count;
+    PSH1_Zone   zone;
+    PSH1_Hint  *sort, hint, hint2;
+
+
+    zone  = table->zones;
+
+    /* special case, no hints defined */
+    if ( table->num_hints == 0 )
+    {
+      zone->scale = scale;
+      zone->delta = delta;
+      zone->min   = PSH1_ZONE_MIN;
+      zone->max   = PSH1_ZONE_MAX;
+
+      table->num_zones = 1;
+      table->zone      = zone;
+      return;
+    }
+
+    /* the first zone is before the first hint    */
+    /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
+
+    sort = table->sort;
+    hint = sort[0];
+
+    zone->scale = scale;
+    zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
+    zone->min   = PSH1_ZONE_MIN;
+    zone->max   = hint->org_pos;
+
+    psh1_print_zone( zone );
+
+    zone++;
+
+    for ( count = table->num_hints; count > 0; count-- )
+    {
+      FT_Fixed  scale2;
+
+
+      if ( hint->org_len > 0 )
+      {
+        /* setup a zone for inner-stem interpolation */
+        /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0)   */
+        /* x' = x*s2 + x0' - x0*s2                   */
+
+        scale2      = FT_DivFix( hint->cur_len, hint->org_len );
+        zone->scale = scale2;
+        zone->min   = hint->org_pos;
+        zone->max   = hint->org_pos + hint->org_len;
+        zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
+
+        psh1_print_zone( zone );
+
+        zone++;
+      }
+
+      if ( count == 1 )
+        break;
+
+      sort++;
+      hint2 = sort[0];
+
+      /* setup zone for inter-stem interpolation */
+      /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1)     */
+      /* x' = x*s3 + x1' - x1*s3                 */
+
+      scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
+                          hint2->org_pos - (hint->org_pos + hint->org_len) );
+      zone->scale = scale2;
+      zone->min   = hint->org_pos + hint->org_len;
+      zone->max   = hint2->org_pos;
+      zone->delta = hint->cur_pos + hint->cur_len -
+                    FT_MulFix( zone->min, scale2 );
+
+      psh1_print_zone( zone );
+
+      zone++;
+
+      hint = hint2;
+    }
+
+    /* the last zone */
+    zone->scale = scale;
+    zone->min   = hint->org_pos + hint->org_len;
+    zone->max   = PSH1_ZONE_MAX;
+    zone->delta = hint->cur_pos + hint->cur_len -
+                  FT_MulFix( zone->min, scale );
+
+    psh1_print_zone( zone );
+
+    zone++;
+
+    table->num_zones = zone - table->zones;
+    table->zone      = table->zones;
+  }
+
+
+  /* tune a single coordinate with the current interpolation zones */
+  static FT_Pos
+  psh1_hint_table_tune_coord( PSH1_Hint_Table  table,
+                              FT_Int           coord )
+  {
+    PSH1_Zone   zone;
+
+
+    zone = table->zone;
+
+    if ( coord < zone->min )
+    {
+      do
+      {
+        if ( zone == table->zones )
+          break;
+
+        zone--;
+
+      } while ( coord < zone->min );
+      table->zone = zone;
+    }
+    else if ( coord > zone->max )
+    {
+      do
+      {
+        if ( zone == table->zones + table->num_zones - 1 )
+          break;
+
+        zone++;
+
+      } while ( coord > zone->max );
+      table->zone = zone;
+    }
+
+    return FT_MulFix( coord, zone->scale ) + zone->delta;
+  }
+
+
+  /* tune a given outline with current interpolation zones. */
+  /* The function only works in a single dimension.         */
+  static void
+  psh1_hint_table_tune_outline( PSH1_Hint_Table  table,
+                                FT_Outline*      outline,
+                                PSH_Globals      globals,
+                                FT_Int           vertical )
+
+  {
+    FT_UInt         count, first, last;
+    PS_Mask_Table   hint_masks = table->hint_masks;
+    PS_Mask         mask;
+    PSH_Dimension   dim        = &globals->dimension[vertical];
+    FT_Fixed        scale      = dim->scale_mult;
+    FT_Fixed        delta      = dim->scale_delta;
+
+
+    if ( hint_masks && hint_masks->num_masks > 0 )
+    {
+      first = 0;
+      mask  = hint_masks->masks;
+      count = hint_masks->num_masks;
+
+      for ( ; count > 0; count--, mask++ )
+      {
+        last = mask->end_point;
+
+        if ( last > first )
+        {
+          FT_Vector*   vec;
+          FT_Int       count2;
+
+
+          psh1_hint_table_activate_mask( table, mask );
+          psh1_hint_table_optimize( table, globals, outline, vertical );
+          psh1_hint_table_setup_zones( table, scale, delta );
+          last = mask->end_point;
+
+          vec    = outline->points + first;
+          count2 = last - first;
+
+          for ( ; count2 > 0; count2--, vec++ )
+          {
+            FT_Pos  x, *px;
+
+
+            px  = vertical ? &vec->x : &vec->y;
+            x   = *px;
+
+            *px = psh1_hint_table_tune_coord( table, (FT_Int)x );
+          }
+        }
+
+        first = last;
+      }
+    }
+    else    /* no hints in this glyph, simply scale the outline */
+    {
+      FT_Vector*  vec;
+
+
+      vec   = outline->points;
+      count = outline->n_points;
+
+      if ( vertical )
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->x = FT_MulFix( vec->x, scale ) + delta;
+      }
+      else
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->y = FT_MulFix( vec->y, scale ) + delta;
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     HIGH-LEVEL INTERFACE                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_Error
+  ps1_hints_apply( PS_Hints        ps_hints,
+                   FT_Outline*     outline,
+                   PSH_Globals     globals,
+                   FT_Render_Mode  hint_mode )
+  {
+    PSH1_Hint_TableRec  hints;
+    FT_Error            error = 0;
+    FT_Int              dimension;
+
+
+    FT_UNUSED( hint_mode );
+
+    for ( dimension = 1; dimension >= 0; dimension-- )
+    {
+      PS_Dimension  dim = &ps_hints->dimension[dimension];
+
+
+      /* initialize hints table */
+      FT_MEM_ZERO( &hints, sizeof ( hints ) );
+      error = psh1_hint_table_init( &hints,
+                                    &dim->hints,
+                                    &dim->masks,
+                                    &dim->counters,
+                                    ps_hints->memory );
+      if ( error )
+        goto Exit;
+
+      psh1_hint_table_tune_outline( &hints,
+                                    outline,
+                                    globals,
+                                    dimension );
+
+      psh1_hint_table_done( &hints, ps_hints->memory );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo1.h
@@ -1,0 +1,110 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo1.h                                                             */
+/*                                                                         */
+/*    PostScript hinting algorithm 1 (specification).                      */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO1_H__
+#define __PSHALGO1_H__
+
+#include "pshrec.h"
+
+FT_BEGIN_HEADER
+
+  typedef struct PSH1_HintRec_*  PSH1_Hint;
+
+  typedef enum
+  {
+    PSH1_HINT_FLAG_GHOST  = PS_HINT_FLAG_GHOST,
+    PSH1_HINT_FLAG_BOTTOM = PS_HINT_FLAG_BOTTOM,
+    PSH1_HINT_FLAG_ACTIVE = 4
+
+  } PSH1_Hint_Flags;
+
+#define psh1_hint_is_active( x )                          \
+          ( ( (x)->flags & PSH1_HINT_FLAG_ACTIVE ) != 0 )
+#define psh1_hint_is_ghost( x )                          \
+          ( ( (x)->flags & PSH1_HINT_FLAG_GHOST ) != 0 )
+
+#define psh1_hint_activate( x )    (x)->flags |= PSH1_HINT_FLAG_ACTIVE
+#define psh1_hint_deactivate( x )  (x)->flags &= ~PSH1_HINT_FLAG_ACTIVE
+
+  typedef struct  PSH1_HintRec_
+  {
+    FT_Int     org_pos;
+    FT_Int     org_len;
+    FT_Pos     cur_pos;
+    FT_Pos     cur_len;
+
+    FT_UInt    flags;
+
+    PSH1_Hint  parent;
+    FT_Int     order;
+
+  } PSH1_HintRec;
+
+
+  /* this is an interpolation zone used for strong points;  */
+  /* weak points are interpolated according to their strong */
+  /* neighbours                                             */
+  typedef struct  PSH1_ZoneRec_
+  {
+    FT_Fixed  scale;
+    FT_Fixed  delta;
+    FT_Pos    min;
+    FT_Pos    max;
+
+  } PSH1_ZoneRec, *PSH1_Zone;
+
+
+  typedef struct  PSH1_Hint_TableRec_
+  {
+    FT_UInt        max_hints;
+    FT_UInt        num_hints;
+    PSH1_Hint      hints;
+    PSH1_Hint*     sort;
+    PSH1_Hint*     sort_global;
+    FT_UInt        num_zones;
+    PSH1_Zone      zones;
+    PSH1_Zone      zone;
+    PS_Mask_Table  hint_masks;
+    PS_Mask_Table  counter_masks;
+
+  } PSH1_Hint_TableRec, *PSH1_Hint_Table;
+
+
+  extern FT_Error
+  ps1_hints_apply( PS_Hints        ps_hints,
+                   FT_Outline*     outline,
+                   PSH_Globals     globals,
+                   FT_Render_Mode  hint_mode );
+
+
+#ifdef DEBUG_HINTER
+  extern  PSH1_Hint_Table  ps1_debug_hint_table;
+
+  typedef void
+  (*PSH1_HintFunc)( PSH1_Hint  hint,
+                    FT_Bool    vertical );
+
+  extern PSH1_HintFunc  ps1_debug_hint_func;
+#endif
+
+FT_END_HEADER
+
+#endif /* __PSHALGO1_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo2.c
@@ -1,0 +1,1557 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo2.c                                                             */
+/*                                                                         */
+/*    PostScript hinting algorithm 2 (body).                               */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used        */
+/*  modified and distributed under the terms of the FreeType project       */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo2.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pshalgo2
+
+#ifdef DEBUG_HINTER
+  PSH2_Hint_Table  ps2_debug_hint_table = 0;
+  PSH2_HintFunc    ps2_debug_hint_func  = 0;
+  PSH2_Glyph       ps2_debug_glyph      = 0;
+#endif
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  BASIC HINTS RECORDINGS                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* return true iff two stem hints overlap */
+  static FT_Int
+  psh2_hint_overlap( PSH2_Hint  hint1,
+                     PSH2_Hint  hint2 )
+  {
+    return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+             hint2->org_pos + hint2->org_len >= hint1->org_pos );
+  }
+
+
+  /* destroy hints table */
+  static void
+  psh2_hint_table_done( PSH2_Hint_Table  table,
+                        FT_Memory        memory )
+  {
+    FT_FREE( table->zones );
+    table->num_zones = 0;
+    table->zone      = 0;
+
+    FT_FREE( table->sort );
+    FT_FREE( table->hints );
+    table->num_hints   = 0;
+    table->max_hints   = 0;
+    table->sort_global = 0;
+  }
+
+
+  /* deactivate all hints in a table */
+  static void
+  psh2_hint_table_deactivate( PSH2_Hint_Table  table )
+  {
+    FT_UInt   count = table->max_hints;
+    PSH2_Hint  hint  = table->hints;
+
+
+    for ( ; count > 0; count--, hint++ )
+    {
+      psh2_hint_deactivate( hint );
+      hint->order = -1;
+    }
+  }
+
+
+  /* internal function used to record a new hint */
+  static void
+  psh2_hint_table_record( PSH2_Hint_Table  table,
+                          FT_UInt          idx )
+  {
+    PSH2_Hint  hint = table->hints + idx;
+
+
+    if ( idx >= table->max_hints )
+    {
+      FT_ERROR(( "%s.activate: invalid hint index %d\n", idx ));
+      return;
+    }
+
+    /* ignore active hints */
+    if ( psh2_hint_is_active( hint ) )
+      return;
+
+    psh2_hint_activate( hint );
+
+    /* now scan the current active hint set in order to determine */
+    /* if we are overlapping with another segment                 */
+    {
+      PSH2_Hint*  sorted = table->sort_global;
+      FT_UInt     count  = table->num_hints;
+      PSH2_Hint   hint2;
+
+
+      hint->parent = 0;
+      for ( ; count > 0; count--, sorted++ )
+      {
+        hint2 = sorted[0];
+
+        if ( psh2_hint_overlap( hint, hint2 ) )
+        {
+          hint->parent = hint2;
+          break;
+        }
+      }
+    }
+
+    if ( table->num_hints < table->max_hints )
+      table->sort_global[table->num_hints++] = hint;
+    else
+      FT_ERROR(( "%s.activate: too many sorted hints!  BUG!\n",
+                 "ps.fitter" ));
+  }
+
+
+  static void
+  psh2_hint_table_record_mask( PSH2_Hint_Table  table,
+                               PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   idx, limit;
+
+
+    limit = hint_mask->num_bits;
+
+    for ( idx = 0; idx < limit; idx++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+
+      if ( val & mask )
+        psh2_hint_table_record( table, idx );
+
+      mask >>= 1;
+    }
+  }
+
+
+  /* create hints table */
+  static FT_Error
+  psh2_hint_table_init( PSH2_Hint_Table  table,
+                        PS_Hint_Table    hints,
+                        PS_Mask_Table    hint_masks,
+                        PS_Mask_Table    counter_masks,
+                        FT_Memory        memory )
+  {
+    FT_UInt   count = hints->num_hints;
+    FT_Error  error;
+
+    FT_UNUSED( counter_masks );
+
+
+    /* allocate our tables */
+    if ( FT_NEW_ARRAY( table->sort,  2 * count     ) ||
+         FT_NEW_ARRAY( table->hints,     count     ) ||
+         FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
+      goto Exit;
+
+    table->max_hints   = count;
+    table->sort_global = table->sort + count;
+    table->num_hints   = 0;
+    table->num_zones   = 0;
+    table->zone        = 0;
+
+    /* now, initialize the "hints" array */
+    {
+      PSH2_Hint  write = table->hints;
+      PS_Hint    read  = hints->hints;
+
+
+      for ( ; count > 0; count--, write++, read++ )
+      {
+        write->org_pos = read->pos;
+        write->org_len = read->len;
+        write->flags   = read->flags;
+      }
+    }
+
+    /* we now need to determine the initial "parent" stems; first  */
+    /* activate the hints that are given by the initial hint masks */
+    if ( hint_masks )
+    {
+      FT_UInt  Count = hint_masks->num_masks;
+      PS_Mask  Mask  = hint_masks->masks;
+
+
+      table->hint_masks = hint_masks;
+
+      for ( ; Count > 0; Count--, Mask++ )
+        psh2_hint_table_record_mask( table, Mask );
+    }
+
+    /* now, do a linear parse in case some hints were left alone */
+    if ( table->num_hints != table->max_hints )
+    {
+      FT_UInt   Index, Count;
+
+
+      FT_ERROR(( "%s.init: missing/incorrect hint masks!\n" ));
+      Count = table->max_hints;
+      for ( Index = 0; Index < Count; Index++ )
+        psh2_hint_table_record( table, Index );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  psh2_hint_table_activate_mask( PSH2_Hint_Table  table,
+                                 PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   idx, limit, count;
+
+
+    limit = hint_mask->num_bits;
+    count = 0;
+
+    psh2_hint_table_deactivate( table );
+
+    for ( idx = 0; idx < limit; idx++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+
+      if ( val & mask )
+      {
+        PSH2_Hint  hint = &table->hints[idx];
+
+
+        if ( !psh2_hint_is_active( hint ) )
+        {
+          FT_UInt     count2;
+
+#if 0
+          PSH2_Hint*  sort = table->sort;
+          PSH2_Hint   hint2;
+
+          for ( count2 = count; count2 > 0; count2--, sort++ )
+          {
+            hint2 = sort[0];
+            if ( psh2_hint_overlap( hint, hint2 ) )
+              FT_ERROR(( "%s.activate_mask: found overlapping hints\n",
+                         "psf.hint" ));
+          }
+#else
+          count2 = 0;
+#endif
+
+          if ( count2 == 0 )
+          {
+            psh2_hint_activate( hint );
+            if ( count < table->max_hints )
+              table->sort[count++] = hint;
+            else
+              FT_ERROR(( "%s.activate_mask: too many active hints\n",
+                         "psf.hint" ));
+          }
+        }
+      }
+
+      mask >>= 1;
+    }
+    table->num_hints = count;
+
+    /* now, sort the hints; they are guaranteed to not overlap */
+    /* so we can compare their "org_pos" field directly        */
+    {
+      FT_Int      i1, i2;
+      PSH2_Hint   hint1, hint2;
+      PSH2_Hint*  sort = table->sort;
+
+
+      /* a simple bubble sort will do, since in 99% of cases, the hints */
+      /* will be already sorted -- and the sort will be linear          */
+      for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+      {
+        hint1 = sort[i1];
+        for ( i2 = i1 - 1; i2 >= 0; i2-- )
+        {
+          hint2 = sort[i2];
+
+          if ( hint2->org_pos < hint1->org_pos )
+            break;
+
+          sort[i2 + 1] = hint2;
+          sort[i2]     = hint1;
+        }
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****               HINTS GRID-FITTING AND OPTIMIZATION             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#ifdef DEBUG_HINTER
+  static void
+  ps2_simple_scale( PSH2_Hint_Table  table,
+                    FT_Fixed         scale,
+                    FT_Fixed         delta,
+                    FT_Int           dimension )
+  {
+    PSH2_Hint  hint;
+    FT_UInt    count;
+
+
+    for ( count = 0; count < table->max_hints; count++ )
+    {
+      hint = table->hints + count;
+
+      hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+      hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+      if ( ps2_debug_hint_func )
+        ps2_debug_hint_func( hint, dimension );
+    }
+  }
+#endif
+
+
+  static void
+  psh2_hint_align( PSH2_Hint    hint,
+                   PSH_Globals  globals,
+                   FT_Int       dimension )
+  {
+    PSH_Dimension  dim   = &globals->dimension[dimension];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+
+    if ( !psh2_hint_is_fitted(hint) )
+    {
+      FT_Pos  pos = FT_MulFix( hint->org_pos, scale ) + delta;
+      FT_Pos  len = FT_MulFix( hint->org_len, scale );
+
+      FT_Pos  fit_center;
+      FT_Pos  fit_len;
+
+      PSH_AlignmentRec  align;
+
+
+      /* compute fitted width/height */
+      fit_len = 0;
+      if ( hint->org_len )
+      {
+        fit_len = psh_dimension_snap_width( dim, hint->org_len );
+        if ( fit_len < 64 )
+          fit_len = 64;
+        else
+          fit_len = ( fit_len + 32 ) & -64;
+      }
+
+      hint->cur_len = fit_len;
+
+      /* check blue zones for horizontal stems */
+      align.align = PSH_BLUE_ALIGN_NONE;
+      align.align_bot = align.align_top = 0;
+
+      if ( dimension == 1 )
+        psh_blues_snap_stem( &globals->blues,
+                             hint->org_pos + hint->org_len,
+                             hint->org_pos,
+                             &align );
+
+      switch ( align.align )
+      {
+      case PSH_BLUE_ALIGN_TOP:
+        /* the top of the stem is aligned against a blue zone */
+        hint->cur_pos = align.align_top - fit_len;
+        break;
+
+      case PSH_BLUE_ALIGN_BOT:
+        /* the bottom of the stem is aligned against a blue zone */
+        hint->cur_pos = align.align_bot;
+        break;
+
+      case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+        /* both edges of the stem are aligned against blue zones */
+        hint->cur_pos = align.align_bot;
+        hint->cur_len = align.align_top - align.align_bot;
+        break;
+
+      default:
+        {
+          PSH2_Hint  parent = hint->parent;
+
+
+          if ( parent )
+          {
+            FT_Pos  par_org_center, par_cur_center;
+            FT_Pos  cur_org_center, cur_delta;
+
+
+            /* ensure that parent is already fitted */
+            if ( !psh2_hint_is_fitted( parent ) )
+              psh2_hint_align( parent, globals, dimension );
+
+            par_org_center = parent->org_pos + ( parent->org_len / 2);
+            par_cur_center = parent->cur_pos + ( parent->cur_len / 2);
+            cur_org_center = hint->org_pos   + ( hint->org_len   / 2);
+
+            cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+#if 0
+            if ( cur_delta >= 0 )
+              cur_delta = ( cur_delta + 16 ) & -64;
+            else
+              cur_delta = -( (-cur_delta + 16 ) & -64 );
+#endif
+            pos = par_cur_center + cur_delta - ( len >> 1 );
+          }
+
+          /* normal processing */
+          if ( ( fit_len / 64 ) & 1 )
+          {
+            /* odd number of pixels */
+            fit_center = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
+          }
+          else
+          {
+            /* even number of pixels */
+            fit_center = ( pos + ( len >> 1 ) + 32 ) & -64;
+          }
+
+          hint->cur_pos = fit_center - ( fit_len >> 1 );
+        }
+      }
+
+      psh2_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+      if ( ps2_debug_hint_func )
+        ps2_debug_hint_func( hint, dimension );
+#endif
+    }
+  }
+
+
+  static void
+  psh2_hint_table_align_hints( PSH2_Hint_Table  table,
+                               PSH_Globals      globals,
+                               FT_Int           dimension )
+  {
+    PSH2_Hint      hint;
+    FT_UInt        count;
+
+#ifdef DEBUG_HINTER
+    PSH_Dimension  dim   = &globals->dimension[dimension];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+
+    if ( ps_debug_no_vert_hints && dimension == 0 )
+    {
+      ps2_simple_scale( table, scale, delta, dimension );
+      return;
+    }
+
+    if ( ps_debug_no_horz_hints && dimension == 1 )
+    {
+      ps2_simple_scale( table, scale, delta, dimension );
+      return;
+    }
+#endif
+
+    hint  = table->hints;
+    count = table->max_hints;
+
+    for ( ; count > 0; count--, hint++ )
+      psh2_hint_align( hint, globals, dimension );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                POINTS INTERPOLATION ROUTINES                  *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define PSH2_ZONE_MIN  -3200000
+#define PSH2_ZONE_MAX  +3200000
+
+#define xxDEBUG_ZONES
+
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+  static void
+  psh2_print_zone( PSH2_Zone  zone )
+  {
+    printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+             zone->scale/65536.0,
+             zone->delta/64.0,
+             zone->min,
+             zone->max );
+  }
+
+#else
+
+#define psh2_print_zone( x )   do { } while ( 0 )
+
+#endif
+
+#if 0
+  /* setup interpolation zones once the hints have been grid-fitted */
+  /* by the optimizer                                               */
+  static void
+  psh2_hint_table_setup_zones( PSH2_Hint_Table  table,
+                               FT_Fixed         scale,
+                               FT_Fixed         delta )
+  {
+    FT_UInt     count;
+    PSH2_Zone   zone;
+    PSH2_Hint  *sort, hint, hint2;
+
+
+    zone = table->zones;
+
+    /* special case, no hints defined */
+    if ( table->num_hints == 0 )
+    {
+      zone->scale = scale;
+      zone->delta = delta;
+      zone->min   = PSH2_ZONE_MIN;
+      zone->max   = PSH2_ZONE_MAX;
+
+      table->num_zones = 1;
+      table->zone      = zone;
+      return;
+    }
+
+    /* the first zone is before the first hint */
+    /* x' = (x-x0)*s + x0' = x*s + ( x0' - x0*s ) */
+    sort = table->sort;
+    hint = sort[0];
+
+    zone->scale = scale;
+    zone->delta = hint->cur_pos - FT_MulFix( hint->org_pos, scale );
+    zone->min   = PSH2_ZONE_MIN;
+    zone->max   = hint->org_pos;
+
+    psh2_print_zone( zone );
+
+    zone++;
+
+    for ( count = table->num_hints; count > 0; count-- )
+    {
+      FT_Fixed  scale2;
+
+
+      if ( hint->org_len > 0 )
+      {
+        /* setup a zone for inner-stem interpolation */
+        /* (x' - x0') = (x - x0)*(x1'-x0')/(x1-x0)   */
+        /* x' = x*s2 + x0' - x0*s2                   */
+
+        scale2      = FT_DivFix( hint->cur_len, hint->org_len );
+        zone->scale = scale2;
+        zone->min   = hint->org_pos;
+        zone->max   = hint->org_pos + hint->org_len;
+        zone->delta = hint->cur_pos - FT_MulFix( zone->min, scale2 );
+
+        psh2_print_zone( zone );
+
+        zone++;
+      }
+
+      if ( count == 1 )
+        break;
+
+      sort++;
+      hint2 = sort[0];
+
+      /* setup zone for inter-stem interpolation */
+      /* (x'-x1') = (x-x1)*(x2'-x1')/(x2-x1)     */
+      /* x' = x*s3 + x1' - x1*s3                 */
+
+      scale2 = FT_DivFix( hint2->cur_pos - (hint->cur_pos + hint->cur_len),
+                          hint2->org_pos - (hint->org_pos + hint->org_len) );
+      zone->scale = scale2;
+      zone->min   = hint->org_pos + hint->org_len;
+      zone->max   = hint2->org_pos;
+      zone->delta = hint->cur_pos + hint->cur_len -
+                    FT_MulFix( zone->min, scale2 );
+
+      psh2_print_zone( zone );
+
+      zone++;
+
+      hint = hint2;
+    }
+
+    /* the last zone */
+    zone->scale = scale;
+    zone->min   = hint->org_pos + hint->org_len;
+    zone->max   = PSH2_ZONE_MAX;
+    zone->delta = hint->cur_pos + hint->cur_len -
+                  FT_MulFix( zone->min, scale );
+
+    psh2_print_zone( zone );
+
+    zone++;
+
+    table->num_zones = zone - table->zones;
+    table->zone      = table->zones;
+  }
+#endif
+
+#if 0
+  /* tune a single coordinate with the current interpolation zones */
+  static FT_Pos
+  psh2_hint_table_tune_coord( PSH2_Hint_Table  table,
+                              FT_Int           coord )
+  {
+    PSH2_Zone   zone;
+
+
+    zone = table->zone;
+
+    if ( coord < zone->min )
+    {
+      do
+      {
+        if ( zone == table->zones )
+          break;
+
+        zone--;
+
+      } while ( coord < zone->min );
+      table->zone = zone;
+    }
+    else if ( coord > zone->max )
+    {
+      do
+      {
+        if ( zone == table->zones + table->num_zones - 1 )
+          break;
+
+        zone++;
+
+      } while ( coord > zone->max );
+      table->zone = zone;
+    }
+
+    return FT_MulFix( coord, zone->scale ) + zone->delta;
+  }
+#endif
+
+#if 0
+ /* tune a given outline with current interpolation zones */
+ /* the function only works in a single dimension..       */
+  static void
+  psh2_hint_table_tune_outline( PSH2_Hint_Table  table,
+                                FT_Outline*      outline,
+                                PSH_Globals      globals,
+                                FT_Int           dimension )
+
+  {
+    FT_UInt        count, first, last;
+    PS_Mask_Table  hint_masks = table->hint_masks;
+    PS_Mask        mask;
+    PSH_Dimension  dim        = &globals->dimension[dimension];
+    FT_Fixed       scale      = dim->scale_mult;
+    FT_Fixed       delta      = dim->scale_delta;
+
+
+    if ( hint_masks && hint_masks->num_masks > 0 )
+    {
+      first = 0;
+      mask  = hint_masks->masks;
+      count = hint_masks->num_masks;
+
+      for ( ; count > 0; count--, mask++ )
+      {
+        last = mask->end_point;
+
+        if ( last > first )
+        {
+          FT_Vector*   vec;
+          FT_Int       count2;
+
+
+          psh2_hint_table_activate_mask( table, mask );
+          psh2_hint_table_optimize( table, globals, outline, dimension );
+          psh2_hint_table_setup_zones( table, scale, delta );
+          last = mask->end_point;
+
+          vec    = outline->points + first;
+          count2 = last - first;
+
+          for ( ; count2 > 0; count2--, vec++ )
+          {
+            FT_Pos  x, *px;
+
+
+            px  = dimension ? &vec->y : &vec->x;
+            x   = *px;
+
+            *px = psh2_hint_table_tune_coord( table, (FT_Int)x );
+          }
+        }
+
+        first = last;
+      }
+    }
+    else    /* no hints in this glyph, simply scale the outline */
+    {
+      FT_Vector*  vec;
+
+
+      vec   = outline->points;
+      count = outline->n_points;
+
+      if ( dimension == 0 )
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->x = FT_MulFix( vec->x, scale ) + delta;
+      }
+      else
+      {
+        for ( ; count > 0; count--, vec++ )
+          vec->y = FT_MulFix( vec->y, scale ) + delta;
+      }
+    }
+  }
+#endif
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    HINTER GLYPH MANAGEMENT                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static int
+  psh2_point_is_extremum( PSH2_Point  point )
+  {
+    PSH2_Point  before = point;
+    PSH2_Point  after  = point;
+    FT_Pos      d_before;
+    FT_Pos      d_after;
+
+
+    do
+    {
+      before = before->prev;
+      if ( before == point )
+        return 0;
+
+      d_before = before->org_u - point->org_u;
+
+    } while ( d_before == 0 );
+
+    do
+    {
+      after = after->next;
+      if ( after == point )
+        return 0;
+
+      d_after = after->org_u - point->org_u;
+
+    } while ( d_after == 0 );
+
+    return ( ( d_before > 0 && d_after > 0 ) ||
+             ( d_before < 0 && d_after < 0 ) );
+  }
+
+
+  static void
+  psh2_glyph_done( PSH2_Glyph  glyph )
+  {
+    FT_Memory  memory = glyph->memory;
+
+
+    psh2_hint_table_done( &glyph->hint_tables[1], memory );
+    psh2_hint_table_done( &glyph->hint_tables[0], memory );
+
+    FT_FREE( glyph->points );
+    FT_FREE( glyph->contours );
+
+    glyph->num_points   = 0;
+    glyph->num_contours = 0;
+
+    glyph->memory = 0;
+  }
+
+
+  static int
+  psh2_compute_dir( FT_Pos  dx,
+                    FT_Pos  dy )
+  {
+    FT_Pos  ax, ay;
+    int     result = PSH2_DIR_NONE;
+
+
+    ax = ( dx >= 0 ) ? dx : -dx;
+    ay = ( dy >= 0 ) ? dy : -dy;
+
+    if ( ay * 12 < ax )
+    {
+      /* |dy| <<< |dx|  means a near-horizontal segment */
+      result = ( dx >= 0 ) ? PSH2_DIR_RIGHT : PSH2_DIR_LEFT;
+    }
+    else if ( ax * 12 < ay )
+    {
+      /* |dx| <<< |dy|  means a near-vertical segment */
+      result = ( dy >= 0 ) ? PSH2_DIR_UP : PSH2_DIR_DOWN;
+    }
+
+    return result;
+  }
+
+
+  static FT_Error
+  psh2_glyph_init( PSH2_Glyph   glyph,
+                   FT_Outline*  outline,
+                   PS_Hints     ps_hints,
+                   PSH_Globals  globals )
+  {
+    FT_Error   error;
+    FT_Memory  memory;
+
+
+    /* clear all fields */
+    FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
+
+    memory = globals->memory;
+
+    /* allocate and setup points + contours arrays */
+    if ( FT_NEW_ARRAY( glyph->points,   outline->n_points   ) ||
+         FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
+      goto Exit;
+
+    glyph->num_points   = outline->n_points;
+    glyph->num_contours = outline->n_contours;
+
+    {
+      FT_UInt       first = 0, next, n;
+      PSH2_Point    points  = glyph->points;
+      PSH2_Contour  contour = glyph->contours;
+
+
+      for ( n = 0; n < glyph->num_contours; n++ )
+      {
+        FT_Int      count;
+        PSH2_Point  point;
+
+
+        next  = outline->contours[n] + 1;
+        count = next - first;
+
+        contour->start = points + first;
+        contour->count = (FT_UInt)count;
+
+        if ( count > 0 )
+        {
+          point = points + first;
+
+          point->prev    = points + next - 1;
+          point->contour = contour;
+
+          for ( ; count > 1; count-- )
+          {
+            point[0].next = point + 1;
+            point[1].prev = point;
+            point++;
+            point->contour = contour;
+          }
+          point->next = points + first;
+        }
+
+        contour++;
+        first = next;
+      }
+    }
+
+    {
+      PSH2_Point  points = glyph->points;
+      PSH2_Point  point  = points;
+      FT_Vector*  vec    = outline->points;
+      FT_UInt     n;
+
+
+      for ( n = 0; n < glyph->num_points; n++, point++ )
+      {
+        FT_Int  n_prev = point->prev - points;
+        FT_Int  n_next = point->next - points;
+        FT_Pos  dxi, dyi, dxo, dyo;
+
+
+        if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
+          point->flags = PSH2_POINT_OFF;
+
+        dxi = vec[n].x - vec[n_prev].x;
+        dyi = vec[n].y - vec[n_prev].y;
+
+        point->dir_in = (FT_Char)psh2_compute_dir( dxi, dyi );
+
+        dxo = vec[n_next].x - vec[n].x;
+        dyo = vec[n_next].y - vec[n].y;
+
+        point->dir_out = (FT_Char)psh2_compute_dir( dxo, dyo );
+
+        /* detect smooth points */
+        if ( point->flags & PSH2_POINT_OFF )
+          point->flags |= PSH2_POINT_SMOOTH;
+        else if ( point->dir_in  != PSH2_DIR_NONE ||
+                  point->dir_out != PSH2_DIR_NONE )
+        {
+          if ( point->dir_in == point->dir_out )
+            point->flags |= PSH2_POINT_SMOOTH;
+        }
+        else
+        {
+          FT_Angle  angle_in, angle_out, diff;
+
+
+          angle_in  = FT_Atan2( dxi, dyi );
+          angle_out = FT_Atan2( dxo, dyo );
+
+          diff = angle_in - angle_out;
+          if ( diff < 0 )
+            diff = -diff;
+
+          if ( diff > FT_ANGLE_PI )
+            diff = FT_ANGLE_2PI - diff;
+
+          if ( diff < FT_ANGLE_PI / 16 )
+            point->flags |= PSH2_POINT_SMOOTH;
+        }
+      }
+    }
+
+    glyph->memory  = memory;
+    glyph->outline = outline;
+    glyph->globals = globals;
+
+    /* now deal with hints tables */
+    error = psh2_hint_table_init( &glyph->hint_tables [0],
+                                  &ps_hints->dimension[0].hints,
+                                  &ps_hints->dimension[0].masks,
+                                  &ps_hints->dimension[0].counters,
+                                  memory );
+    if ( error )
+      goto Exit;
+
+    error = psh2_hint_table_init( &glyph->hint_tables [1],
+                                  &ps_hints->dimension[1].hints,
+                                  &ps_hints->dimension[1].masks,
+                                  &ps_hints->dimension[1].counters,
+                                  memory );
+    if ( error )
+      goto Exit;
+
+  Exit:
+    return error;
+  }
+
+
+  /* load outline point coordinates into hinter glyph */
+  static void
+  psh2_glyph_load_points( PSH2_Glyph  glyph,
+                          FT_Int      dimension )
+  {
+    FT_Vector*  vec   = glyph->outline->points;
+    PSH2_Point  point = glyph->points;
+    FT_UInt     count = glyph->num_points;
+
+
+    for ( ; count > 0; count--, point++, vec++ )
+    {
+      point->flags &= PSH2_POINT_OFF | PSH2_POINT_SMOOTH;
+      point->hint   = 0;
+      if ( dimension == 0 )
+        point->org_u = vec->x;
+      else
+        point->org_u = vec->y;
+
+#ifdef DEBUG_HINTER
+      point->org_x = vec->x;
+      point->org_y = vec->y;
+#endif
+    }
+  }
+
+
+  /* save hinted point coordinates back to outline */
+  static void
+  psh2_glyph_save_points( PSH2_Glyph  glyph,
+                          FT_Int      dimension )
+  {
+    FT_UInt     n;
+    PSH2_Point  point = glyph->points;
+    FT_Vector*  vec   = glyph->outline->points;
+    char*       tags  = glyph->outline->tags;
+
+
+    for ( n = 0; n < glyph->num_points; n++ )
+    {
+      if ( dimension == 0 )
+        vec[n].x = point->cur_u;
+      else
+        vec[n].y = point->cur_u;
+
+      if ( psh2_point_is_strong( point ) )
+        tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
+
+#ifdef DEBUG_HINTER
+      if ( dimension == 0 )
+      {
+        point->cur_x   = point->cur_u;
+        point->flags_x = point->flags;
+      }
+      else
+      {
+        point->cur_y   = point->cur_u;
+        point->flags_y = point->flags;
+      }
+#endif
+      point++;
+    }
+  }
+
+
+#define PSH2_STRONG_THRESHOLD  10
+
+
+  static void
+  psh2_hint_table_find_strong_point( PSH2_Hint_Table  table,
+                                     PSH2_Point       point,
+                                     FT_Int           major_dir )
+  {
+    PSH2_Hint*   sort      = table->sort;
+    FT_UInt      num_hints = table->num_hints;
+
+
+    for ( ; num_hints > 0; num_hints--, sort++ )
+    {
+      PSH2_Hint  hint = sort[0];
+
+
+      if ( ABS( point->dir_in )  == major_dir ||
+           ABS( point->dir_out ) == major_dir )
+      {
+        FT_Pos  d;
+
+
+        d = point->org_u - hint->org_pos;
+        if ( ABS( d ) < PSH2_STRONG_THRESHOLD )
+        {
+        Is_Strong:
+          psh2_point_set_strong( point );
+          point->hint = hint;
+          break;
+        }
+
+        d -= hint->org_len;
+        if ( ABS( d ) < PSH2_STRONG_THRESHOLD )
+          goto Is_Strong;
+      }
+
+#if 1
+      if ( point->org_u >= hint->org_pos &&
+           point->org_u <= hint->org_pos + hint->org_len &&
+           psh2_point_is_extremum( point ) )
+      {
+        /* attach to hint, but don't mark as strong */
+        point->hint = hint;
+        break;
+      }
+#endif
+    }
+  }
+
+
+  /* find strong points in a glyph */
+  static void
+  psh2_glyph_find_strong_points( PSH2_Glyph  glyph,
+                                 FT_Int      dimension )
+  {
+    /* a point is strong if it is located on a stem                   */
+    /* edge and has an "in" or "out" tangent to the hint's direction  */
+    {
+      PSH2_Hint_Table  table     = &glyph->hint_tables[dimension];
+      PS_Mask          mask      = table->hint_masks->masks;
+      FT_UInt          num_masks = table->hint_masks->num_masks;
+      FT_UInt          first     = 0;
+      FT_Int           major_dir = dimension == 0 ? PSH2_DIR_UP : PSH2_DIR_RIGHT;
+
+
+      /* process secondary hints to "selected" points */
+      if ( num_masks > 1 && glyph->num_points > 0 )
+      {
+        first = mask->end_point;
+        mask++;
+        for ( ; num_masks > 1; num_masks--, mask++ )
+        {
+          FT_UInt  next;
+          FT_Int   count;
+
+
+          next  = mask->end_point;
+          count = next - first;
+          if ( count > 0 )
+          {
+            PSH2_Point  point = glyph->points + first;
+
+
+            psh2_hint_table_activate_mask( table, mask );
+
+            for ( ; count > 0; count--, point++ )
+              psh2_hint_table_find_strong_point( table, point, major_dir );
+          }
+          first = next;
+        }
+      }
+
+      /* process primary hints for all points */
+      if ( num_masks == 1 )
+      {
+        FT_UInt     count = glyph->num_points;
+        PSH2_Point  point = glyph->points;
+
+
+        psh2_hint_table_activate_mask( table, table->hint_masks->masks );
+        for ( ; count > 0; count--, point++ )
+        {
+          if ( !psh2_point_is_strong( point ) )
+            psh2_hint_table_find_strong_point( table, point, major_dir );
+        }
+      }
+
+      /* now, certain points may have been attached to hint and */
+      /* not marked as strong; update their flags then          */
+      {
+        FT_UInt     count = glyph->num_points;
+        PSH2_Point  point = glyph->points;
+
+
+        for ( ; count > 0; count--, point++ )
+          if ( point->hint && !psh2_point_is_strong( point ) )
+            psh2_point_set_strong( point );
+      }
+    }
+  }
+
+
+  /* interpolate strong points with the help of hinted coordinates */
+  static void
+  psh2_glyph_interpolate_strong_points( PSH2_Glyph  glyph,
+                                        FT_Int      dimension )
+  {
+    PSH_Dimension    dim   = &glyph->globals->dimension[dimension];
+    FT_Fixed         scale = dim->scale_mult;
+
+
+    {
+      FT_UInt     count = glyph->num_points;
+      PSH2_Point  point = glyph->points;
+
+
+      for ( ; count > 0; count--, point++ )
+      {
+        PSH2_Hint  hint = point->hint;
+
+
+        if ( hint )
+        {
+          FT_Pos  delta;
+
+
+          delta = point->org_u - hint->org_pos;
+
+          if ( delta <= 0 )
+            point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
+
+          else if ( delta >= hint->org_len )
+            point->cur_u = hint->cur_pos + hint->cur_len +
+                           FT_MulFix( delta - hint->org_len, scale );
+
+          else if ( hint->org_len > 0 )
+            point->cur_u = hint->cur_pos +
+                           FT_MulDiv( delta, hint->cur_len, hint->org_len );
+          else
+            point->cur_u = hint->cur_pos;
+
+          psh2_point_set_fitted( point );
+        }
+      }
+    }
+  }
+
+
+  static void
+  psh2_glyph_interpolate_normal_points( PSH2_Glyph  glyph,
+                                        FT_Int      dimension )
+  {
+#if 1
+    PSH_Dimension    dim   = &glyph->globals->dimension[dimension];
+    FT_Fixed         scale = dim->scale_mult;
+
+
+    /* first technique: a point is strong if it is a local extrema */
+    {
+      FT_UInt     count = glyph->num_points;
+      PSH2_Point  point = glyph->points;
+
+
+      for ( ; count > 0; count--, point++ )
+      {
+        if ( psh2_point_is_strong( point ) )
+          continue;
+
+        /* sometimes, some local extremas are smooth points */
+        if ( psh2_point_is_smooth( point ) )
+        {
+          if ( point->dir_in == PSH2_DIR_NONE  ||
+               point->dir_in != point->dir_out )
+            continue;
+
+          if ( !psh2_point_is_extremum( point ) )
+            continue;
+
+          point->flags &= ~PSH2_POINT_SMOOTH;
+        }
+
+        /* find best enclosing point coordinates */
+        {
+          PSH2_Point  before = 0;
+          PSH2_Point  after  = 0;
+
+          FT_Pos      diff_before = -32000;
+          FT_Pos      diff_after  =  32000;
+          FT_Pos      u = point->org_u;
+
+          FT_Int      count2 = glyph->num_points;
+          PSH2_Point  cur    = glyph->points;
+
+
+          for ( ; count2 > 0; count2--, cur++ )
+          {
+            if ( psh2_point_is_strong( cur ) )
+            {
+              FT_Pos   diff = cur->org_u - u;;
+
+
+              if ( diff <= 0 )
+              {
+                if ( diff > diff_before )
+                {
+                  diff_before = diff;
+                  before      = cur;
+                }
+              }
+              else if ( diff >= 0 )
+              {
+                if ( diff < diff_after )
+                {
+                  diff_after = diff;
+                  after      = cur;
+                }
+              }
+            }
+          }
+
+          if ( !before )
+          {
+            if ( !after )
+              continue;
+
+            /* we are before the first strong point coordinate; */
+            /* simply translate the point                       */
+            point->cur_u = after->cur_u +
+                           FT_MulFix( point->org_u - after->org_u, scale );
+          }
+          else if ( !after )
+          {
+            /* we are after the last strong point coordinate; */
+            /* simply translate the point                     */
+            point->cur_u = before->cur_u +
+                           FT_MulFix( point->org_u - before->org_u, scale );
+          }
+          else
+          {
+            if ( diff_before == 0 )
+              point->cur_u = before->cur_u;
+
+            else if ( diff_after == 0 )
+              point->cur_u = after->cur_u;
+
+            else
+              point->cur_u = before->cur_u +
+                             FT_MulDiv( u - before->org_u,
+                                        after->cur_u - before->cur_u,
+                                        after->org_u - before->org_u );
+          }
+
+          psh2_point_set_fitted( point );
+        }
+      }
+    }
+#endif
+  }
+
+
+  /* interpolate other points */
+  static void
+  psh2_glyph_interpolate_other_points( PSH2_Glyph  glyph,
+                                       FT_Int      dimension )
+  {
+    PSH_Dimension dim          = &glyph->globals->dimension[dimension];
+    FT_Fixed      scale        = dim->scale_mult;
+    FT_Fixed      delta        = dim->scale_delta;
+    PSH2_Contour  contour      = glyph->contours;
+    FT_UInt       num_contours = glyph->num_contours;
+
+
+    for ( ; num_contours > 0; num_contours--, contour++ )
+    {
+      PSH2_Point   start = contour->start;
+      PSH2_Point   first, next, point;
+      FT_UInt      fit_count;
+
+
+      /* count the number of strong points in this contour */
+      next      = start + contour->count;
+      fit_count = 0;
+      first     = 0;
+
+      for ( point = start; point < next; point++ )
+        if ( psh2_point_is_fitted( point ) )
+        {
+          if ( !first )
+            first = point;
+
+          fit_count++;
+        }
+
+      /* if there are less than 2 fitted points in the contour, we */
+      /* simply scale and eventually translate the contour points  */
+      if ( fit_count < 2 )
+      {
+        if ( fit_count == 1 )
+          delta = first->cur_u - FT_MulFix( first->org_u, scale );
+
+        for ( point = start; point < next; point++ )
+          if ( point != first )
+            point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
+
+        goto Next_Contour;
+      }
+
+      /* there are more than 2 strong points in this contour; we */
+      /* need to interpolate weak points between them            */
+      start = first;
+      do
+      {
+        point = first;
+
+        /* skip consecutive fitted points */
+        for (;;)
+        {
+          next = first->next;
+          if ( next == start )
+            goto Next_Contour;
+
+          if ( !psh2_point_is_fitted( next ) )
+            break;
+
+          first = next;
+        }
+
+        /* find next fitted point after unfitted one */
+        for (;;)
+        {
+          next = next->next;
+          if ( psh2_point_is_fitted( next ) )
+            break;
+        }
+
+        /* now interpolate between them */
+        {
+          FT_Pos    org_a, org_ab, cur_a, cur_ab;
+          FT_Pos    org_c, org_ac, cur_c;
+          FT_Fixed  scale_ab;
+
+
+          if ( first->org_u <= next->org_u )
+          {
+            org_a  = first->org_u;
+            cur_a  = first->cur_u;
+            org_ab = next->org_u - org_a;
+            cur_ab = next->cur_u - cur_a;
+          }
+          else
+          {
+            org_a  = next->org_u;
+            cur_a  = next->cur_u;
+            org_ab = first->org_u - org_a;
+            cur_ab = first->cur_u - cur_a;
+          }
+
+          scale_ab = 0x10000L;
+          if ( org_ab > 0 )
+            scale_ab = FT_DivFix( cur_ab, org_ab );
+
+          point = first->next;
+          do
+          {
+            org_c  = point->org_u;
+            org_ac = org_c - org_a;
+
+            if ( org_ac <= 0 )
+            {
+              /* on the left of the interpolation zone */
+              cur_c = cur_a + FT_MulFix( org_ac, scale );
+            }
+            else if ( org_ac >= org_ab )
+            {
+              /* on the right on the interpolation zone */
+              cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
+            }
+            else
+            {
+              /* within the interpolation zone */
+              cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
+            }
+
+            point->cur_u = cur_c;
+
+            point = point->next;
+
+          } while ( point != next );
+        }
+
+        /* keep going until all points in the contours have been processed */
+        first = next;
+
+      } while ( first != start );
+
+    Next_Contour:
+      ;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     HIGH-LEVEL INTERFACE                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_Error
+  ps2_hints_apply( PS_Hints        ps_hints,
+                   FT_Outline*     outline,
+                   PSH_Globals     globals,
+                   FT_Render_Mode  hint_mode )
+  {
+    PSH2_GlyphRec  glyphrec;
+    PSH2_Glyph     glyph = &glyphrec;
+    FT_Error       error;
+#ifdef DEBUG_HINTER
+    FT_Memory      memory;
+#endif
+    FT_Int         dimension;
+
+    FT_UNUSED( hint_mode );
+
+#ifdef DEBUG_HINTER
+    memory = globals->memory;
+
+    if ( ps2_debug_glyph )
+    {
+      psh2_glyph_done( ps2_debug_glyph );
+      FT_FREE( ps2_debug_glyph );
+    }
+
+    if ( FT_NEW( glyph ) )
+      return error;
+
+    ps2_debug_glyph = glyph;
+#endif
+
+    error = psh2_glyph_init( glyph, outline, ps_hints, globals );
+    if ( error )
+      goto Exit;
+
+    for ( dimension = 0; dimension < 2; dimension++ )
+    {
+      /* load outline coordinates into glyph */
+      psh2_glyph_load_points( glyph, dimension );
+
+      /* compute aligned stem/hints positions */
+      psh2_hint_table_align_hints( &glyph->hint_tables[dimension],
+                                   glyph->globals,
+                                   dimension );
+
+      /* find strong points, align them, then interpolate others */
+      psh2_glyph_find_strong_points( glyph, dimension );
+      psh2_glyph_interpolate_strong_points( glyph, dimension );
+      psh2_glyph_interpolate_normal_points( glyph, dimension );
+      psh2_glyph_interpolate_other_points( glyph, dimension );
+
+      /* save hinted coordinates back to outline */
+      psh2_glyph_save_points( glyph, dimension );
+    }
+
+  Exit:
+#ifndef DEBUG_HINTER
+    psh2_glyph_done( glyph );
+#endif
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo2.h
@@ -1,0 +1,203 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo2.h                                                             */
+/*                                                                         */
+/*    PostScript hinting algorithm 2 (specification).                      */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO2_H__
+#define __PSHALGO2_H__
+
+
+#include "pshrec.h"
+#include "pshglob.h"
+#include FT_TRIGONOMETRY_H
+
+
+FT_BEGIN_HEADER
+
+
+  typedef struct PSH2_HintRec_*  PSH2_Hint;
+
+  typedef enum
+  {
+    PSH2_HINT_GHOST  = PS_HINT_FLAG_GHOST,
+    PSH2_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
+    PSH2_HINT_ACTIVE = 4,
+    PSH2_HINT_FITTED = 8
+
+  } PSH2_Hint_Flags;
+
+
+#define psh2_hint_is_active( x )  ( ( (x)->flags & PSH2_HINT_ACTIVE ) != 0 )
+#define psh2_hint_is_ghost( x )   ( ( (x)->flags & PSH2_HINT_GHOST  ) != 0 )
+#define psh2_hint_is_fitted( x )  ( ( (x)->flags & PSH2_HINT_FITTED ) != 0 )
+
+#define psh2_hint_activate( x )    (x)->flags |=  PSH2_HINT_ACTIVE
+#define psh2_hint_deactivate( x )  (x)->flags &= ~PSH2_HINT_ACTIVE
+#define psh2_hint_set_fitted( x )  (x)->flags |=  PSH2_HINT_FITTED
+
+
+  typedef struct  PSH2_HintRec_
+  {
+    FT_Int     org_pos;
+    FT_Int     org_len;
+    FT_Pos     cur_pos;
+    FT_Pos     cur_len;
+    FT_UInt    flags;
+    PSH2_Hint  parent;
+    FT_Int     order;
+
+  } PSH2_HintRec;
+
+
+  /* this is an interpolation zone used for strong points;  */
+  /* weak points are interpolated according to their strong */
+  /* neighbours                                             */
+  typedef struct  PSH2_ZoneRec_
+  {
+    FT_Fixed  scale;
+    FT_Fixed  delta;
+    FT_Pos    min;
+    FT_Pos    max;
+
+  } PSH2_ZoneRec, *PSH2_Zone;
+
+
+  typedef struct  PSH2_Hint_TableRec_
+  {
+    FT_UInt        max_hints;
+    FT_UInt        num_hints;
+    PSH2_Hint      hints;
+    PSH2_Hint*     sort;
+    PSH2_Hint*     sort_global;
+    FT_UInt        num_zones;
+    PSH2_Zone      zones;
+    PSH2_Zone      zone;
+    PS_Mask_Table  hint_masks;
+    PS_Mask_Table  counter_masks;
+
+  } PSH2_Hint_TableRec, *PSH2_Hint_Table;
+
+
+  typedef struct PSH2_PointRec_*    PSH2_Point;
+  typedef struct PSH2_ContourRec_*  PSH2_Contour;
+
+  enum
+  {
+    PSH2_DIR_NONE  =  4,
+    PSH2_DIR_UP    =  1,
+    PSH2_DIR_DOWN  = -1,
+    PSH2_DIR_LEFT  = -2,
+    PSH2_DIR_RIGHT =  2
+  };
+
+  enum
+  {
+    PSH2_POINT_OFF    = 1,   /* point is off the curve  */
+    PSH2_POINT_STRONG = 2,   /* point is strong         */
+    PSH2_POINT_SMOOTH = 4,   /* point is smooth         */
+    PSH2_POINT_FITTED = 8    /* point is already fitted */
+  };
+
+
+  typedef struct  PSH2_PointRec_
+  {
+    PSH2_Point    prev;
+    PSH2_Point    next;
+    PSH2_Contour  contour;
+    FT_UInt       flags;
+    FT_Char       dir_in;
+    FT_Char       dir_out;
+    FT_Angle      angle_in;
+    FT_Angle      angle_out;
+    PSH2_Hint     hint;
+    FT_Pos        org_u;
+    FT_Pos        cur_u;
+#ifdef DEBUG_HINTER
+    FT_Pos        org_x;
+    FT_Pos        cur_x;
+    FT_Pos        org_y;
+    FT_Pos        cur_y;
+    FT_UInt       flags_x;
+    FT_UInt       flags_y;
+#endif
+
+  } PSH2_PointRec;
+
+
+#define psh2_point_is_strong( p )   ( (p)->flags & PSH2_POINT_STRONG )
+#define psh2_point_is_fitted( p )   ( (p)->flags & PSH2_POINT_FITTED )
+#define psh2_point_is_smooth( p )   ( (p)->flags & PSH2_POINT_SMOOTH )
+
+#define psh2_point_set_strong( p )  (p)->flags |= PSH2_POINT_STRONG
+#define psh2_point_set_fitted( p )  (p)->flags |= PSH2_POINT_FITTED
+#define psh2_point_set_smooth( p )  (p)->flags |= PSH2_POINT_SMOOTH
+
+
+  typedef struct  PSH2_ContourRec_
+  {
+    PSH2_Point  start;
+    FT_UInt     count;
+
+  } PSH2_ContourRec;
+
+
+  typedef struct  PSH2_GlyphRec_
+  {
+    FT_UInt             num_points;
+    FT_UInt             num_contours;
+
+    PSH2_Point          points;
+    PSH2_Contour        contours;
+
+    FT_Memory           memory;
+    FT_Outline*         outline;
+    PSH_Globals         globals;
+    PSH2_Hint_TableRec  hint_tables[2];
+
+    FT_Bool             vertical;
+    FT_Int              major_dir;
+    FT_Int              minor_dir;
+
+  } PSH2_GlyphRec, *PSH2_Glyph;
+
+
+#ifdef DEBUG_HINTER
+  extern PSH2_Hint_Table  ps2_debug_hint_table;
+
+  typedef void
+  (*PSH2_HintFunc)( PSH2_Hint  hint,
+                    FT_Bool    vertical );
+
+  extern PSH2_HintFunc    ps2_debug_hint_func;
+
+  extern PSH2_Glyph       ps2_debug_glyph;
+#endif
+
+
+  extern FT_Error
+  ps2_hints_apply( PS_Hints        ps_hints,
+                   FT_Outline*     outline,
+                   PSH_Globals     globals,
+                   FT_Render_Mode  hint_mode );
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHALGO2_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo3.c
@@ -1,0 +1,1757 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo3.c                                                             */
+/*                                                                         */
+/*    PostScript hinting algorithm 3 (body).                               */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used        */
+/*  modified and distributed under the terms of the FreeType project       */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshalgo3.h"
+
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pshalgo2
+
+
+#ifdef DEBUG_HINTER
+  PSH3_Hint_Table  ps3_debug_hint_table = 0;
+  PSH3_HintFunc    ps3_debug_hint_func  = 0;
+  PSH3_Glyph       ps3_debug_glyph      = 0;
+#endif
+
+
+#define  COMPUTE_INFLEXS  /* compute inflection points to optimize "S" and others */
+#define  STRONGER         /* slightly increase the contrast of smooth hinting */
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  BASIC HINTS RECORDINGS                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* return true iff two stem hints overlap */
+  static FT_Int
+  psh3_hint_overlap( PSH3_Hint  hint1,
+                     PSH3_Hint  hint2 )
+  {
+    return ( hint1->org_pos + hint1->org_len >= hint2->org_pos &&
+             hint2->org_pos + hint2->org_len >= hint1->org_pos );
+  }
+
+
+  /* destroy hints table */
+  static void
+  psh3_hint_table_done( PSH3_Hint_Table  table,
+                        FT_Memory        memory )
+  {
+    FT_FREE( table->zones );
+    table->num_zones = 0;
+    table->zone      = 0;
+
+    FT_FREE( table->sort );
+    FT_FREE( table->hints );
+    table->num_hints   = 0;
+    table->max_hints   = 0;
+    table->sort_global = 0;
+  }
+
+
+  /* deactivate all hints in a table */
+  static void
+  psh3_hint_table_deactivate( PSH3_Hint_Table  table )
+  {
+    FT_UInt    count = table->max_hints;
+    PSH3_Hint  hint  = table->hints;
+
+
+    for ( ; count > 0; count--, hint++ )
+    {
+      psh3_hint_deactivate( hint );
+      hint->order = -1;
+    }
+  }
+
+
+  /* internal function used to record a new hint */
+  static void
+  psh3_hint_table_record( PSH3_Hint_Table  table,
+                          FT_UInt          idx )
+  {
+    PSH3_Hint  hint = table->hints + idx;
+
+
+    if ( idx >= table->max_hints )
+    {
+      FT_ERROR(( "psh3_hint_table_record: invalid hint index %d\n", idx ));
+      return;
+    }
+
+    /* ignore active hints */
+    if ( psh3_hint_is_active( hint ) )
+      return;
+
+    psh3_hint_activate( hint );
+
+    /* now scan the current active hint set in order to determine */
+    /* if we are overlapping with another segment                 */
+    {
+      PSH3_Hint*  sorted = table->sort_global;
+      FT_UInt     count  = table->num_hints;
+      PSH3_Hint   hint2;
+
+
+      hint->parent = 0;
+      for ( ; count > 0; count--, sorted++ )
+      {
+        hint2 = sorted[0];
+
+        if ( psh3_hint_overlap( hint, hint2 ) )
+        {
+          hint->parent = hint2;
+          break;
+        }
+      }
+    }
+
+    if ( table->num_hints < table->max_hints )
+      table->sort_global[table->num_hints++] = hint;
+    else
+      FT_ERROR(( "psh3_hint_table_record: too many sorted hints!  BUG!\n" ));
+  }
+
+
+  static void
+  psh3_hint_table_record_mask( PSH3_Hint_Table  table,
+                               PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   idx, limit;
+
+
+    limit = hint_mask->num_bits;
+
+    for ( idx = 0; idx < limit; idx++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+
+      if ( val & mask )
+        psh3_hint_table_record( table, idx );
+
+      mask >>= 1;
+    }
+  }
+
+
+  /* create hints table */
+  static FT_Error
+  psh3_hint_table_init( PSH3_Hint_Table  table,
+                        PS_Hint_Table    hints,
+                        PS_Mask_Table    hint_masks,
+                        PS_Mask_Table    counter_masks,
+                        FT_Memory        memory )
+  {
+    FT_UInt   count = hints->num_hints;
+    FT_Error  error;
+
+    FT_UNUSED( counter_masks );
+
+
+    /* allocate our tables */
+    if ( FT_NEW_ARRAY( table->sort,  2 * count     ) ||
+         FT_NEW_ARRAY( table->hints,     count     ) ||
+         FT_NEW_ARRAY( table->zones, 2 * count + 1 ) )
+      goto Exit;
+
+    table->max_hints   = count;
+    table->sort_global = table->sort + count;
+    table->num_hints   = 0;
+    table->num_zones   = 0;
+    table->zone        = 0;
+
+    /* now, initialize the "hints" array */
+    {
+      PSH3_Hint  write = table->hints;
+      PS_Hint    read  = hints->hints;
+
+
+      for ( ; count > 0; count--, write++, read++ )
+      {
+        write->org_pos = read->pos;
+        write->org_len = read->len;
+        write->flags   = read->flags;
+      }
+    }
+
+    /* we now need to determine the initial "parent" stems; first  */
+    /* activate the hints that are given by the initial hint masks */
+    if ( hint_masks )
+    {
+      FT_UInt  Count = hint_masks->num_masks;
+      PS_Mask  Mask  = hint_masks->masks;
+
+
+      table->hint_masks = hint_masks;
+
+      for ( ; Count > 0; Count--, Mask++ )
+        psh3_hint_table_record_mask( table, Mask );
+    }
+
+    /* now, do a linear parse in case some hints were left alone */
+    if ( table->num_hints != table->max_hints )
+    {
+      FT_UInt  Index, Count;
+
+
+      FT_ERROR(( "psh3_hint_table_init: missing/incorrect hint masks!\n" ));
+      Count = table->max_hints;
+      for ( Index = 0; Index < Count; Index++ )
+        psh3_hint_table_record( table, Index );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  psh3_hint_table_activate_mask( PSH3_Hint_Table  table,
+                                 PS_Mask          hint_mask )
+  {
+    FT_Int    mask = 0, val = 0;
+    FT_Byte*  cursor = hint_mask->bytes;
+    FT_UInt   idx, limit, count;
+
+
+    limit = hint_mask->num_bits;
+    count = 0;
+
+    psh3_hint_table_deactivate( table );
+
+    for ( idx = 0; idx < limit; idx++ )
+    {
+      if ( mask == 0 )
+      {
+        val  = *cursor++;
+        mask = 0x80;
+      }
+
+      if ( val & mask )
+      {
+        PSH3_Hint  hint = &table->hints[idx];
+
+
+        if ( !psh3_hint_is_active( hint ) )
+        {
+          FT_UInt     count2;
+
+#if 0
+          PSH3_Hint*  sort = table->sort;
+          PSH3_Hint   hint2;
+
+
+          for ( count2 = count; count2 > 0; count2--, sort++ )
+          {
+            hint2 = sort[0];
+            if ( psh3_hint_overlap( hint, hint2 ) )
+              FT_ERROR(( "psh3_hint_table_activate_mask:"
+                         " found overlapping hints\n" ))
+          }
+#else
+          count2 = 0;
+#endif
+
+          if ( count2 == 0 )
+          {
+            psh3_hint_activate( hint );
+            if ( count < table->max_hints )
+              table->sort[count++] = hint;
+            else
+              FT_ERROR(( "psh3_hint_tableactivate_mask:"
+                         " too many active hints\n" ));
+          }
+        }
+      }
+
+      mask >>= 1;
+    }
+    table->num_hints = count;
+
+    /* now, sort the hints; they are guaranteed to not overlap */
+    /* so we can compare their "org_pos" field directly        */
+    {
+      FT_Int      i1, i2;
+      PSH3_Hint   hint1, hint2;
+      PSH3_Hint*  sort = table->sort;
+
+
+      /* a simple bubble sort will do, since in 99% of cases, the hints */
+      /* will be already sorted -- and the sort will be linear          */
+      for ( i1 = 1; i1 < (FT_Int)count; i1++ )
+      {
+        hint1 = sort[i1];
+        for ( i2 = i1 - 1; i2 >= 0; i2-- )
+        {
+          hint2 = sort[i2];
+
+          if ( hint2->org_pos < hint1->org_pos )
+            break;
+
+          sort[i2 + 1] = hint2;
+          sort[i2]     = hint1;
+        }
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****               HINTS GRID-FITTING AND OPTIMIZATION             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static FT_Pos
+  psh3_dimension_quantize_len( PSH_Dimension  dim,
+                               FT_Pos         len,
+                               FT_Bool        do_snapping )
+  {
+    if ( len <= 64 )
+      len = 64;
+    else
+    {
+      FT_Pos  delta = len - dim->stdw.widths[0].cur;
+
+
+      if ( delta < 0 )
+        delta = -delta;
+
+      if ( delta < 40 )
+      {
+        len = dim->stdw.widths[0].cur;
+        if ( len < 48 )
+          len = 48;
+      }
+
+      if ( len < 3 * 64 )
+      {
+        delta = ( len & 63 );
+        len  &= -64;
+
+        if ( delta < 10 )
+          len += delta;
+
+        else if ( delta < 32 )
+          len += 10;
+
+        else if ( delta < 54 )
+          len += 54;
+
+        else
+          len += delta;
+      }
+      else
+        len = ( len + 32 ) & -64;
+    }
+
+    if ( do_snapping )
+      len = ( len + 32 ) & -64;
+
+    return  len;
+  }
+
+
+#ifdef DEBUG_HINTER
+
+  static void
+  ps3_simple_scale( PSH3_Hint_Table  table,
+                    FT_Fixed         scale,
+                    FT_Fixed         delta,
+                    FT_Int           dimension )
+  {
+    PSH3_Hint  hint;
+    FT_UInt    count;
+
+
+    for ( count = 0; count < table->max_hints; count++ )
+    {
+      hint = table->hints + count;
+
+      hint->cur_pos = FT_MulFix( hint->org_pos, scale ) + delta;
+      hint->cur_len = FT_MulFix( hint->org_len, scale );
+
+      if ( ps3_debug_hint_func )
+        ps3_debug_hint_func( hint, dimension );
+    }
+  }
+
+#endif /* DEBUG_HINTER */
+
+
+  static FT_Fixed
+  psh3_hint_snap_stem_side_delta( FT_Fixed  pos,
+                                  FT_Fixed  len )
+  {
+    FT_Fixed  delta1 = ( ( pos + 32 ) & -64 ) - pos;
+    FT_Fixed  delta2 = ( ( pos + len + 32 ) & -64  ) - pos - len;
+
+
+    if ( ABS( delta1 ) <= ABS( delta2 ) )
+      return delta1;
+    else
+      return delta2;
+  }
+
+
+  static void
+  psh3_hint_align( PSH3_Hint    hint,
+                   PSH_Globals  globals,
+                   FT_Int       dimension,
+                   PSH3_Glyph   glyph )
+  {
+    PSH_Dimension  dim   = &globals->dimension[dimension];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+
+    if ( !psh3_hint_is_fitted( hint ) )
+    {
+      FT_Pos  pos = FT_MulFix( hint->org_pos, scale ) + delta;
+      FT_Pos  len = FT_MulFix( hint->org_len, scale );
+
+      FT_Int            do_snapping;
+      FT_Pos            fit_len;
+      PSH_AlignmentRec  align;
+
+
+      /* ignore stem alignments when requested through the hint flags */
+      if ( ( dimension == 0 && !glyph->do_horz_hints ) ||
+           ( dimension == 1 && !glyph->do_vert_hints ) )
+      {
+        hint->cur_pos = pos;
+        hint->cur_len = len;
+
+        psh3_hint_set_fitted( hint );
+        return;
+      }
+
+      /* perform stem snapping when requested */
+      do_snapping = ( dimension == 0 && glyph->do_horz_snapping ) ||
+                    ( dimension == 1 && glyph->do_vert_snapping );
+
+      hint->cur_len = fit_len = len;
+
+      /* check blue zones for horizontal stems */
+      align.align     = PSH_BLUE_ALIGN_NONE;
+      align.align_bot = align.align_top = 0;
+
+      if ( dimension == 1 )
+        psh_blues_snap_stem( &globals->blues,
+                             hint->org_pos + hint->org_len,
+                             hint->org_pos,
+                             &align );
+
+      switch ( align.align )
+      {
+      case PSH_BLUE_ALIGN_TOP:
+        /* the top of the stem is aligned against a blue zone */
+        hint->cur_pos = align.align_top - fit_len;
+        break;
+
+      case PSH_BLUE_ALIGN_BOT:
+        /* the bottom of the stem is aligned against a blue zone */
+        hint->cur_pos = align.align_bot;
+        break;
+
+      case PSH_BLUE_ALIGN_TOP | PSH_BLUE_ALIGN_BOT:
+        /* both edges of the stem are aligned against blue zones */
+        hint->cur_pos = align.align_bot;
+        hint->cur_len = align.align_top - align.align_bot;
+        break;
+
+      default:
+        {
+          PSH3_Hint  parent = hint->parent;
+
+
+          if ( parent )
+          {
+            FT_Pos  par_org_center, par_cur_center;
+            FT_Pos  cur_org_center, cur_delta;
+
+
+            /* ensure that parent is already fitted */
+            if ( !psh3_hint_is_fitted( parent ) )
+              psh3_hint_align( parent, globals, dimension, glyph );
+
+            par_org_center = parent->org_pos + ( parent->org_len >> 1 );
+            par_cur_center = parent->cur_pos + ( parent->cur_len >> 1 );
+            cur_org_center = hint->org_pos   + ( hint->org_len   >> 1 );
+
+            cur_delta = FT_MulFix( cur_org_center - par_org_center, scale );
+            pos       = par_cur_center + cur_delta - ( len >> 1 );
+          }
+
+          hint->cur_pos = pos;
+          hint->cur_len = fit_len;
+
+          if ( len <= 64 )
+          {
+            /* the stem is less than one pixel, we will center it */
+            /* around the nearest pixel center                    */
+            /*                                                    */
+            pos = ( pos + ( (len >> 1) & -64 ) );
+            len = 64;
+          }
+          else
+          {
+            len = psh3_dimension_quantize_len( dim, len, 0 );
+          }
+
+          /* now that we have a good hinted stem width, try to position */
+          /* the stem along a pixel grid integer coordinate             */
+          hint->cur_pos = pos + psh3_hint_snap_stem_side_delta( pos, len );
+          hint->cur_len = len;
+        }
+      }
+
+      if ( do_snapping )
+      {
+        pos = hint->cur_pos;
+        len = hint->cur_len;
+
+        if ( len < 64 )
+          len = 64;
+        else
+          len = ( len + 32 ) & -64;
+
+        switch ( align.align )
+        {
+          case PSH_BLUE_ALIGN_TOP:
+            hint->cur_pos = align.align_top - len;
+            hint->cur_len = len;
+            break;
+
+          case PSH_BLUE_ALIGN_BOT:
+            hint->cur_len = len;
+            break;
+
+          case PSH_BLUE_ALIGN_BOT | PSH_BLUE_ALIGN_TOP:
+            /* don't touch */
+            break;
+
+
+          default:
+            hint->cur_len = len;
+            if ( len & 64 )
+              pos = ( ( pos + ( len >> 1 ) ) & -64 ) + 32;
+            else
+              pos = ( pos + ( len >> 1 ) + 32 ) & -64;
+
+            hint->cur_pos = pos - ( len >> 1 );
+            hint->cur_len = len;
+        }
+      }
+
+      psh3_hint_set_fitted( hint );
+
+#ifdef DEBUG_HINTER
+      if ( ps3_debug_hint_func )
+        ps3_debug_hint_func( hint, dimension );
+#endif
+    }
+  }
+
+
+  static void
+  psh3_hint_table_align_hints( PSH3_Hint_Table  table,
+                               PSH_Globals      globals,
+                               FT_Int           dimension,
+                               PSH3_Glyph       glyph )
+  {
+    PSH3_Hint      hint;
+    FT_UInt        count;
+
+#ifdef DEBUG_HINTER
+
+    PSH_Dimension  dim   = &globals->dimension[dimension];
+    FT_Fixed       scale = dim->scale_mult;
+    FT_Fixed       delta = dim->scale_delta;
+
+
+    if ( ps_debug_no_vert_hints && dimension == 0 )
+    {
+      ps3_simple_scale( table, scale, delta, dimension );
+      return;
+    }
+
+    if ( ps_debug_no_horz_hints && dimension == 1 )
+    {
+      ps3_simple_scale( table, scale, delta, dimension );
+      return;
+    }
+
+#endif /* DEBUG_HINTER*/
+
+    hint  = table->hints;
+    count = table->max_hints;
+
+    for ( ; count > 0; count--, hint++ )
+      psh3_hint_align( hint, globals, dimension, glyph );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                POINTS INTERPOLATION ROUTINES                  *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define PSH3_ZONE_MIN  -3200000L
+#define PSH3_ZONE_MAX  +3200000L
+
+#define xxDEBUG_ZONES
+
+
+#ifdef DEBUG_ZONES
+
+#include <stdio.h>
+
+  static void
+  psh3_print_zone( PSH3_Zone  zone )
+  {
+    printf( "zone [scale,delta,min,max] = [%.3f,%.3f,%d,%d]\n",
+             zone->scale / 65536.0,
+             zone->delta / 64.0,
+             zone->min,
+             zone->max );
+  }
+
+#else
+
+#define psh3_print_zone( x )  do { } while ( 0 )
+
+#endif /* DEBUG_ZONES */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    HINTER GLYPH MANAGEMENT                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#ifdef COMPUTE_INFLEXS
+
+  /* compute all inflex points in a given glyph */
+  static void
+  psh3_glyph_compute_inflections( PSH3_Glyph  glyph )
+  {
+    FT_UInt  n;
+
+
+    for ( n = 0; n < glyph->num_contours; n++ )
+    {
+      PSH3_Point  first, start, end, before, after;
+      FT_Angle    angle_in, angle_seg, angle_out;
+      FT_Angle    diff_in, diff_out;
+      FT_Int      finished = 0;
+
+
+      /* we need at least 4 points to create an inflection point */
+      if ( glyph->contours[n].count < 4 )
+        continue;
+
+      /* compute first segment in contour */
+      first = glyph->contours[n].start;
+
+      start = end = first;
+      do
+      {
+        end = end->next;
+        if ( end == first )
+          goto Skip;
+
+      } while ( PSH3_POINT_EQUAL_ORG( end, first ) );
+
+      angle_seg = PSH3_POINT_ANGLE( start, end );
+
+      /* extend the segment start whenever possible */
+      before = start;
+      do
+      {
+        do
+        {
+          start  = before;
+          before = before->prev;
+          if ( before == first )
+            goto Skip;
+
+        } while ( PSH3_POINT_EQUAL_ORG( before, start ) );
+
+        angle_in = PSH3_POINT_ANGLE( before, start );
+
+      } while ( angle_in == angle_seg );
+
+      first   = start;
+      diff_in = FT_Angle_Diff( angle_in, angle_seg );
+
+      /* now, process all segments in the contour */
+      do
+      {
+        /* first, extend current segment's end whenever possible */
+        after = end;
+        do
+        {
+          do
+          {
+            end   = after;
+            after = after->next;
+            if ( after == first )
+              finished = 1;
+
+          } while ( PSH3_POINT_EQUAL_ORG( end, after ) );
+
+          angle_out = PSH3_POINT_ANGLE( end, after );
+
+        } while ( angle_out == angle_seg );
+
+        diff_out = FT_Angle_Diff( angle_seg, angle_out );
+
+        if ( ( diff_in ^ diff_out ) < 0 )
+        {
+          /* diff_in and diff_out have different signs, we have */
+          /* inflection points here...                          */
+
+          do
+          {
+            psh3_point_set_inflex( start );
+            start = start->next;
+          }
+          while ( start != end );
+
+          psh3_point_set_inflex( start );
+        }
+
+        start     = end;
+        end       = after;
+        angle_seg = angle_out;
+        diff_in   = diff_out;
+
+      } while ( !finished );
+
+    Skip:
+      ;
+    }
+  }
+
+#endif /* COMPUTE_INFLEXS */
+
+
+  static void
+  psh3_glyph_done( PSH3_Glyph  glyph )
+  {
+    FT_Memory  memory = glyph->memory;
+
+
+    psh3_hint_table_done( &glyph->hint_tables[1], memory );
+    psh3_hint_table_done( &glyph->hint_tables[0], memory );
+
+    FT_FREE( glyph->points );
+    FT_FREE( glyph->contours );
+
+    glyph->num_points   = 0;
+    glyph->num_contours = 0;
+
+    glyph->memory = 0;
+  }
+
+
+  static int
+  psh3_compute_dir( FT_Pos  dx,
+                    FT_Pos  dy )
+  {
+    FT_Pos  ax, ay;
+    int     result = PSH3_DIR_NONE;
+
+
+    ax = ( dx >= 0 ) ? dx : -dx;
+    ay = ( dy >= 0 ) ? dy : -dy;
+
+    if ( ay * 12 < ax )
+    {
+      /* |dy| <<< |dx|  means a near-horizontal segment */
+      result = ( dx >= 0 ) ? PSH3_DIR_RIGHT : PSH3_DIR_LEFT;
+    }
+    else if ( ax * 12 < ay )
+    {
+      /* |dx| <<< |dy|  means a near-vertical segment */
+      result = ( dy >= 0 ) ? PSH3_DIR_UP : PSH3_DIR_DOWN;
+    }
+
+    return result;
+  }
+
+
+  /* load outline point coordinates into hinter glyph */
+  static void
+  psh3_glyph_load_points( PSH3_Glyph  glyph,
+                          FT_Int      dimension )
+  {
+    FT_Vector*  vec   = glyph->outline->points;
+    PSH3_Point  point = glyph->points;
+    FT_UInt     count = glyph->num_points;
+
+
+    for ( ; count > 0; count--, point++, vec++ )
+    {
+      point->flags2 = 0;
+      point->hint   = NULL;
+      if ( dimension == 0 )
+      {
+        point->org_u = vec->x;
+        point->org_v = vec->y;
+      }
+      else
+      {
+        point->org_u = vec->y;
+        point->org_v = vec->x;
+      }
+
+#ifdef DEBUG_HINTER
+      point->org_x = vec->x;
+      point->org_y = vec->y;
+#endif
+
+    }
+  }
+
+
+  /* save hinted point coordinates back to outline */
+  static void
+  psh3_glyph_save_points( PSH3_Glyph  glyph,
+                          FT_Int      dimension )
+  {
+    FT_UInt     n;
+    PSH3_Point  point = glyph->points;
+    FT_Vector*  vec   = glyph->outline->points;
+    char*       tags  = glyph->outline->tags;
+
+
+    for ( n = 0; n < glyph->num_points; n++ )
+    {
+      if ( dimension == 0 )
+        vec[n].x = point->cur_u;
+      else
+        vec[n].y = point->cur_u;
+
+      if ( psh3_point_is_strong( point ) )
+        tags[n] |= (char)( ( dimension == 0 ) ? 32 : 64 );
+
+#ifdef DEBUG_HINTER
+
+      if ( dimension == 0 )
+      {
+        point->cur_x   = point->cur_u;
+        point->flags_x = point->flags2 | point->flags;
+      }
+      else
+      {
+        point->cur_y   = point->cur_u;
+        point->flags_y = point->flags2 | point->flags;
+      }
+
+#endif
+
+      point++;
+    }
+  }
+
+
+  static FT_Error
+  psh3_glyph_init( PSH3_Glyph   glyph,
+                   FT_Outline*  outline,
+                   PS_Hints     ps_hints,
+                   PSH_Globals  globals )
+  {
+    FT_Error   error;
+    FT_Memory  memory;
+
+
+    /* clear all fields */
+    FT_MEM_ZERO( glyph, sizeof ( *glyph ) );
+
+    memory = globals->memory;
+
+    /* allocate and setup points + contours arrays */
+    if ( FT_NEW_ARRAY( glyph->points,   outline->n_points   ) ||
+         FT_NEW_ARRAY( glyph->contours, outline->n_contours ) )
+      goto Exit;
+
+    glyph->num_points   = outline->n_points;
+    glyph->num_contours = outline->n_contours;
+
+    {
+      FT_UInt       first = 0, next, n;
+      PSH3_Point    points  = glyph->points;
+      PSH3_Contour  contour = glyph->contours;
+
+
+      for ( n = 0; n < glyph->num_contours; n++ )
+      {
+        FT_Int      count;
+        PSH3_Point  point;
+
+
+        next  = outline->contours[n] + 1;
+        count = next - first;
+
+        contour->start = points + first;
+        contour->count = (FT_UInt)count;
+
+        if ( count > 0 )
+        {
+          point = points + first;
+
+          point->prev    = points + next - 1;
+          point->contour = contour;
+
+          for ( ; count > 1; count-- )
+          {
+            point[0].next = point + 1;
+            point[1].prev = point;
+            point++;
+            point->contour = contour;
+          }
+          point->next = points + first;
+        }
+
+        contour++;
+        first = next;
+      }
+    }
+
+    {
+      PSH3_Point  points = glyph->points;
+      PSH3_Point  point  = points;
+      FT_Vector*  vec    = outline->points;
+      FT_UInt     n;
+
+
+      for ( n = 0; n < glyph->num_points; n++, point++ )
+      {
+        FT_Int  n_prev = point->prev - points;
+        FT_Int  n_next = point->next - points;
+        FT_Pos  dxi, dyi, dxo, dyo;
+
+
+        if ( !( outline->tags[n] & FT_CURVE_TAG_ON ) )
+          point->flags = PSH3_POINT_OFF;
+
+        dxi = vec[n].x - vec[n_prev].x;
+        dyi = vec[n].y - vec[n_prev].y;
+
+        point->dir_in = (FT_Char)psh3_compute_dir( dxi, dyi );
+
+        dxo = vec[n_next].x - vec[n].x;
+        dyo = vec[n_next].y - vec[n].y;
+
+        point->dir_out = (FT_Char)psh3_compute_dir( dxo, dyo );
+
+        /* detect smooth points */
+        if ( point->flags & PSH3_POINT_OFF )
+          point->flags |= PSH3_POINT_SMOOTH;
+        else if ( point->dir_in  != PSH3_DIR_NONE ||
+                  point->dir_out != PSH3_DIR_NONE )
+        {
+          if ( point->dir_in == point->dir_out )
+            point->flags |= PSH3_POINT_SMOOTH;
+        }
+        else
+        {
+          FT_Angle  angle_in, angle_out, diff;
+
+
+          angle_in  = FT_Atan2( dxi, dyi );
+          angle_out = FT_Atan2( dxo, dyo );
+
+          diff = angle_in - angle_out;
+          if ( diff < 0 )
+            diff = -diff;
+
+          if ( diff > FT_ANGLE_PI )
+            diff = FT_ANGLE_2PI - diff;
+
+          if ( diff < FT_ANGLE_PI / 16 )
+            point->flags |= PSH3_POINT_SMOOTH;
+        }
+      }
+    }
+
+    glyph->memory  = memory;
+    glyph->outline = outline;
+    glyph->globals = globals;
+
+#ifdef COMPUTE_INFLEXS
+    psh3_glyph_load_points( glyph, 0 );
+    psh3_glyph_compute_inflections( glyph );
+#endif /* COMPUTE_INFLEXS */
+
+    /* now deal with hints tables */
+    error = psh3_hint_table_init( &glyph->hint_tables [0],
+                                  &ps_hints->dimension[0].hints,
+                                  &ps_hints->dimension[0].masks,
+                                  &ps_hints->dimension[0].counters,
+                                  memory );
+    if ( error )
+      goto Exit;
+
+    error = psh3_hint_table_init( &glyph->hint_tables [1],
+                                  &ps_hints->dimension[1].hints,
+                                  &ps_hints->dimension[1].masks,
+                                  &ps_hints->dimension[1].counters,
+                                  memory );
+    if ( error )
+      goto Exit;
+
+  Exit:
+    return error;
+  }
+
+
+  /* compute all extrema in a glyph for a given dimension */
+  static void
+  psh3_glyph_compute_extrema( PSH3_Glyph  glyph )
+  {
+    FT_UInt  n;
+
+
+    /* first of all, compute all local extrema */
+    for ( n = 0; n < glyph->num_contours; n++ )
+    {
+      PSH3_Point  first = glyph->contours[n].start;
+      PSH3_Point  point, before, after;
+
+
+      point  = first;
+      before = point;
+      after  = point;
+
+      do
+      {
+        before = before->prev;
+        if ( before == first )
+          goto Skip;
+
+      } while ( before->org_u == point->org_u );
+
+      first = point = before->next;
+
+      for (;;)
+      {
+        after = point;
+        do
+        {
+          after = after->next;
+          if ( after == first )
+            goto Next;
+
+        } while ( after->org_u == point->org_u );
+
+        if ( before->org_u < point->org_u )
+        {
+          if ( after->org_u < point->org_u )
+          {
+            /* local maximum */
+            goto Extremum;
+          }
+        }
+        else /* before->org_u > point->org_u */
+        {
+          if ( after->org_u > point->org_u )
+          {
+            /* local minimum */
+          Extremum:
+            do
+            {
+              psh3_point_set_extremum( point );
+              point = point->next;
+
+            } while ( point != after );
+          }
+        }
+
+        before = after->prev;
+        point  = after;
+
+      } /* for  */
+
+    Next:
+      ;
+    }
+
+    /* for each extrema, determine its direction along the */
+    /* orthogonal axis                                     */
+    for ( n = 0; n < glyph->num_points; n++ )
+    {
+      PSH3_Point  point, before, after;
+
+
+      point  = &glyph->points[n];
+      before = point;
+      after  = point;
+
+      if ( psh3_point_is_extremum( point ) )
+      {
+        do
+        {
+          before = before->prev;
+          if ( before == point )
+            goto Skip;
+
+        } while ( before->org_v == point->org_v );
+
+        do
+        {
+          after = after->next;
+          if ( after == point )
+            goto Skip;
+
+        } while ( after->org_v == point->org_v );
+      }
+
+      if ( before->org_v < point->org_v &&
+           after->org_v  > point->org_v )
+      {
+        psh3_point_set_positive( point );
+      }
+      else if ( before->org_v > point->org_v &&
+                after->org_v  < point->org_v )
+      {
+        psh3_point_set_negative( point );
+      }
+
+    Skip:
+      ;
+    }
+  }
+
+
+#define PSH3_STRONG_THRESHOLD  30
+
+
+  /* major_dir is the direction for points on the bottom/left of the stem; */
+  /* Points on the top/right of the stem will have a direction of          */
+  /* -major_dir.                                                           */
+
+  static void
+  psh3_hint_table_find_strong_point( PSH3_Hint_Table  table,
+                                     PSH3_Point       point,
+                                     FT_Int           major_dir )
+  {
+    PSH3_Hint*  sort      = table->sort;
+    FT_UInt     num_hints = table->num_hints;
+    FT_Int      point_dir = 0;
+
+
+    if ( PSH3_DIR_COMPARE( point->dir_in, major_dir ) )
+      point_dir = point->dir_in;
+
+    else if ( PSH3_DIR_COMPARE( point->dir_out, major_dir ) )
+      point_dir = point->dir_out;
+
+    if ( point_dir )
+    {
+      FT_UInt  flag;
+
+
+      for ( ; num_hints > 0; num_hints--, sort++ )
+      {
+        PSH3_Hint  hint = sort[0];
+        FT_Pos     d;
+
+
+        if ( point_dir == major_dir )
+        {
+          flag = PSH3_POINT_EDGE_MIN;
+          d    = point->org_u - hint->org_pos;
+
+          if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+          {
+          Is_Strong:
+            psh3_point_set_strong( point );
+            point->flags2 |= flag;
+            point->hint    = hint;
+            break;
+          }
+        }
+        else if ( point_dir == -major_dir )
+        {
+          flag  = PSH3_POINT_EDGE_MAX;
+          d     = point->org_u - hint->org_pos - hint->org_len;
+
+          if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+            goto Is_Strong;
+        }
+      }
+    }
+
+#if 1
+    else if ( psh3_point_is_extremum( point ) )
+    {
+      /* treat extrema as special cases for stem edge alignment */
+      FT_UInt  min_flag, max_flag;
+
+
+      if ( major_dir == PSH3_DIR_HORIZONTAL )
+      {
+        min_flag = PSH3_POINT_POSITIVE;
+        max_flag = PSH3_POINT_NEGATIVE;
+      }
+      else
+      {
+        min_flag = PSH3_POINT_NEGATIVE;
+        max_flag = PSH3_POINT_POSITIVE;
+      }
+
+      for ( ; num_hints > 0; num_hints--, sort++ )
+      {
+        PSH3_Hint  hint = sort[0];
+        FT_Pos     d, flag;
+
+
+        if ( point->flags2 & min_flag )
+        {
+          flag = PSH3_POINT_EDGE_MIN;
+          d    = point->org_u - hint->org_pos;
+
+          if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+          {
+          Is_Strong2:
+            point->flags2 |= flag;
+            point->hint    = hint;
+            psh3_point_set_strong( point );
+            break;
+          }
+        }
+        else if ( point->flags2 & max_flag )
+        {
+          flag = PSH3_POINT_EDGE_MAX;
+          d    = point->org_u - hint->org_pos - hint->org_len;
+
+          if ( ABS( d ) < PSH3_STRONG_THRESHOLD )
+            goto Is_Strong2;
+        }
+
+        if ( point->org_u >= hint->org_pos                 &&
+             point->org_u <= hint->org_pos + hint->org_len )
+        {
+          point->hint = hint;
+        }
+      }
+    }
+
+#endif /* 1 */
+  }
+
+
+  /* find strong points in a glyph */
+  static void
+  psh3_glyph_find_strong_points( PSH3_Glyph  glyph,
+                                 FT_Int      dimension )
+  {
+    /* a point is strong if it is located on a stem                   */
+    /* edge and has an "in" or "out" tangent to the hint's direction  */
+    {
+      PSH3_Hint_Table  table     = &glyph->hint_tables[dimension];
+      PS_Mask          mask      = table->hint_masks->masks;
+      FT_UInt          num_masks = table->hint_masks->num_masks;
+      FT_UInt          first     = 0;
+      FT_Int           major_dir = dimension == 0 ? PSH3_DIR_VERTICAL
+                                                  : PSH3_DIR_HORIZONTAL;
+
+
+      /* process secondary hints to "selected" points */
+      if ( num_masks > 1 && glyph->num_points > 0 )
+      {
+        first = mask->end_point;
+        mask++;
+        for ( ; num_masks > 1; num_masks--, mask++ )
+        {
+          FT_UInt  next;
+          FT_Int   count;
+
+
+          next  = mask->end_point;
+          count = next - first;
+          if ( count > 0 )
+          {
+            PSH3_Point  point = glyph->points + first;
+
+
+            psh3_hint_table_activate_mask( table, mask );
+
+            for ( ; count > 0; count--, point++ )
+              psh3_hint_table_find_strong_point( table, point, major_dir );
+          }
+          first = next;
+        }
+      }
+
+      /* process primary hints for all points */
+      if ( num_masks == 1 )
+      {
+        FT_UInt     count = glyph->num_points;
+        PSH3_Point  point = glyph->points;
+
+
+        psh3_hint_table_activate_mask( table, table->hint_masks->masks );
+        for ( ; count > 0; count--, point++ )
+        {
+          if ( !psh3_point_is_strong( point ) )
+            psh3_hint_table_find_strong_point( table, point, major_dir );
+        }
+      }
+
+      /* now, certain points may have been attached to hint and */
+      /* not marked as strong; update their flags then          */
+      {
+        FT_UInt     count = glyph->num_points;
+        PSH3_Point  point = glyph->points;
+
+
+        for ( ; count > 0; count--, point++ )
+          if ( point->hint && !psh3_point_is_strong( point ) )
+            psh3_point_set_strong( point );
+      }
+    }
+  }
+
+
+  /* interpolate strong points with the help of hinted coordinates */
+  static void
+  psh3_glyph_interpolate_strong_points( PSH3_Glyph  glyph,
+                                        FT_Int      dimension )
+  {
+    PSH_Dimension  dim   = &glyph->globals->dimension[dimension];
+    FT_Fixed       scale = dim->scale_mult;
+
+
+    {
+      FT_UInt     count = glyph->num_points;
+      PSH3_Point  point = glyph->points;
+
+
+      for ( ; count > 0; count--, point++ )
+      {
+        PSH3_Hint  hint = point->hint;
+
+
+        if ( hint )
+        {
+          FT_Pos  delta;
+
+
+          if ( psh3_point_is_edge_min( point ) )
+          {
+            point->cur_u = hint->cur_pos;
+          }
+          else if ( psh3_point_is_edge_max( point ) )
+          {
+            point->cur_u = hint->cur_pos + hint->cur_len;
+          }
+          else
+          {
+            delta = point->org_u - hint->org_pos;
+
+            if ( delta <= 0 )
+              point->cur_u = hint->cur_pos + FT_MulFix( delta, scale );
+
+            else if ( delta >= hint->org_len )
+              point->cur_u = hint->cur_pos + hint->cur_len +
+                               FT_MulFix( delta - hint->org_len, scale );
+
+            else if ( hint->org_len > 0 )
+              point->cur_u = hint->cur_pos +
+                               FT_MulDiv( delta, hint->cur_len,
+                                          hint->org_len );
+            else
+              point->cur_u = hint->cur_pos;
+          }
+          psh3_point_set_fitted( point );
+        }
+      }
+    }
+  }
+
+
+  static void
+  psh3_glyph_interpolate_normal_points( PSH3_Glyph  glyph,
+                                        FT_Int      dimension )
+  {
+
+#if 1
+
+    PSH_Dimension  dim   = &glyph->globals->dimension[dimension];
+    FT_Fixed       scale = dim->scale_mult;
+
+
+    /* first technique: a point is strong if it is a local extrema */
+    {
+      FT_UInt     count = glyph->num_points;
+      PSH3_Point  point = glyph->points;
+
+
+      for ( ; count > 0; count--, point++ )
+      {
+        if ( psh3_point_is_strong( point ) )
+          continue;
+
+        /* sometimes, some local extremas are smooth points */
+        if ( psh3_point_is_smooth( point ) )
+        {
+          if ( point->dir_in == PSH3_DIR_NONE  ||
+               point->dir_in != point->dir_out )
+            continue;
+
+          if ( !psh3_point_is_extremum( point )   &&
+               !psh3_point_is_inflex( point ) )
+            continue;
+
+          point->flags &= ~PSH3_POINT_SMOOTH;
+        }
+
+        /* find best enclosing point coordinates */
+        {
+          PSH3_Point  before = 0;
+          PSH3_Point  after  = 0;
+
+          FT_Pos      diff_before = -32000;
+          FT_Pos      diff_after  =  32000;
+          FT_Pos      u = point->org_u;
+
+          FT_Int      count2 = glyph->num_points;
+          PSH3_Point  cur    = glyph->points;
+
+
+          for ( ; count2 > 0; count2--, cur++ )
+          {
+            if ( psh3_point_is_strong( cur ) )
+            {
+              FT_Pos  diff = cur->org_u - u;;
+
+
+              if ( diff <= 0 )
+              {
+                if ( diff > diff_before )
+                {
+                  diff_before = diff;
+                  before      = cur;
+                }
+              }
+              else if ( diff >= 0 )
+              {
+                if ( diff < diff_after )
+                {
+                  diff_after = diff;
+                  after      = cur;
+                }
+              }
+            }
+          }
+
+          if ( !before )
+          {
+            if ( !after )
+              continue;
+
+            /* we are before the first strong point coordinate; */
+            /* simply translate the point                       */
+            point->cur_u = after->cur_u +
+                           FT_MulFix( point->org_u - after->org_u, scale );
+          }
+          else if ( !after )
+          {
+            /* we are after the last strong point coordinate; */
+            /* simply translate the point                     */
+            point->cur_u = before->cur_u +
+                           FT_MulFix( point->org_u - before->org_u, scale );
+          }
+          else
+          {
+            if ( diff_before == 0 )
+              point->cur_u = before->cur_u;
+
+            else if ( diff_after == 0 )
+              point->cur_u = after->cur_u;
+
+            else
+              point->cur_u = before->cur_u +
+                             FT_MulDiv( u - before->org_u,
+                                        after->cur_u - before->cur_u,
+                                        after->org_u - before->org_u );
+          }
+
+          psh3_point_set_fitted( point );
+        }
+      }
+    }
+
+#endif /* 1 */
+
+  }
+
+
+  /* interpolate other points */
+  static void
+  psh3_glyph_interpolate_other_points( PSH3_Glyph  glyph,
+                                       FT_Int      dimension )
+  {
+    PSH_Dimension  dim          = &glyph->globals->dimension[dimension];
+    FT_Fixed       scale        = dim->scale_mult;
+    FT_Fixed       delta        = dim->scale_delta;
+    PSH3_Contour   contour      = glyph->contours;
+    FT_UInt        num_contours = glyph->num_contours;
+
+
+    for ( ; num_contours > 0; num_contours--, contour++ )
+    {
+      PSH3_Point  start = contour->start;
+      PSH3_Point  first, next, point;
+      FT_UInt     fit_count;
+
+
+      /* count the number of strong points in this contour */
+      next      = start + contour->count;
+      fit_count = 0;
+      first     = 0;
+
+      for ( point = start; point < next; point++ )
+        if ( psh3_point_is_fitted( point ) )
+        {
+          if ( !first )
+            first = point;
+
+          fit_count++;
+        }
+
+      /* if there are less than 2 fitted points in the contour, we */
+      /* simply scale and eventually translate the contour points  */
+      if ( fit_count < 2 )
+      {
+        if ( fit_count == 1 )
+          delta = first->cur_u - FT_MulFix( first->org_u, scale );
+
+        for ( point = start; point < next; point++ )
+          if ( point != first )
+            point->cur_u = FT_MulFix( point->org_u, scale ) + delta;
+
+        goto Next_Contour;
+      }
+
+      /* there are more than 2 strong points in this contour; we */
+      /* need to interpolate weak points between them            */
+      start = first;
+      do
+      {
+        point = first;
+
+        /* skip consecutive fitted points */
+        for (;;)
+        {
+          next = first->next;
+          if ( next == start )
+            goto Next_Contour;
+
+          if ( !psh3_point_is_fitted( next ) )
+            break;
+
+          first = next;
+        }
+
+        /* find next fitted point after unfitted one */
+        for (;;)
+        {
+          next = next->next;
+          if ( psh3_point_is_fitted( next ) )
+            break;
+        }
+
+        /* now interpolate between them */
+        {
+          FT_Pos    org_a, org_ab, cur_a, cur_ab;
+          FT_Pos    org_c, org_ac, cur_c;
+          FT_Fixed  scale_ab;
+
+
+          if ( first->org_u <= next->org_u )
+          {
+            org_a  = first->org_u;
+            cur_a  = first->cur_u;
+            org_ab = next->org_u - org_a;
+            cur_ab = next->cur_u - cur_a;
+          }
+          else
+          {
+            org_a  = next->org_u;
+            cur_a  = next->cur_u;
+            org_ab = first->org_u - org_a;
+            cur_ab = first->cur_u - cur_a;
+          }
+
+          scale_ab = 0x10000L;
+          if ( org_ab > 0 )
+            scale_ab = FT_DivFix( cur_ab, org_ab );
+
+          point = first->next;
+          do
+          {
+            org_c  = point->org_u;
+            org_ac = org_c - org_a;
+
+            if ( org_ac <= 0 )
+            {
+              /* on the left of the interpolation zone */
+              cur_c = cur_a + FT_MulFix( org_ac, scale );
+            }
+            else if ( org_ac >= org_ab )
+            {
+              /* on the right on the interpolation zone */
+              cur_c = cur_a + cur_ab + FT_MulFix( org_ac - org_ab, scale );
+            }
+            else
+            {
+              /* within the interpolation zone */
+              cur_c = cur_a + FT_MulFix( org_ac, scale_ab );
+            }
+
+            point->cur_u = cur_c;
+
+            point = point->next;
+
+          } while ( point != next );
+        }
+
+        /* keep going until all points in the contours have been processed */
+        first = next;
+
+      } while ( first != start );
+
+    Next_Contour:
+      ;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                     HIGH-LEVEL INTERFACE                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_Error
+  ps3_hints_apply( PS_Hints        ps_hints,
+                   FT_Outline*     outline,
+                   PSH_Globals     globals,
+                   FT_Render_Mode  hint_mode )
+  {
+    PSH3_GlyphRec  glyphrec;
+    PSH3_Glyph     glyph = &glyphrec;
+    FT_Error       error;
+#ifdef DEBUG_HINTER
+    FT_Memory      memory;
+#endif
+    FT_Int         dimension;
+
+
+#ifdef DEBUG_HINTER
+
+    memory = globals->memory;
+
+    if ( ps3_debug_glyph )
+    {
+      psh3_glyph_done( ps3_debug_glyph );
+      FT_FREE( ps3_debug_glyph );
+    }
+
+    if ( FT_NEW( glyph ) )
+      return error;
+
+    ps3_debug_glyph = glyph;
+
+#endif /* DEBUG_HINTER */
+
+    error = psh3_glyph_init( glyph, outline, ps_hints, globals );
+    if ( error )
+      goto Exit;
+
+    glyph->do_horz_hints = 1;
+    glyph->do_vert_hints = 1;
+
+    glyph->do_horz_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO ||
+                                       hint_mode == FT_RENDER_MODE_LCD  );
+
+    glyph->do_vert_snapping = FT_BOOL( hint_mode == FT_RENDER_MODE_MONO  ||
+                                       hint_mode == FT_RENDER_MODE_LCD_V );
+
+    for ( dimension = 0; dimension < 2; dimension++ )
+    {
+      /* load outline coordinates into glyph */
+      psh3_glyph_load_points( glyph, dimension );
+
+      /* compute local extrema */
+      psh3_glyph_compute_extrema( glyph );
+
+      /* compute aligned stem/hints positions */
+      psh3_hint_table_align_hints( &glyph->hint_tables[dimension],
+                                   glyph->globals,
+                                   dimension,
+                                   glyph );
+
+      /* find strong points, align them, then interpolate others */
+      psh3_glyph_find_strong_points( glyph, dimension );
+      psh3_glyph_interpolate_strong_points( glyph, dimension );
+      psh3_glyph_interpolate_normal_points( glyph, dimension );
+      psh3_glyph_interpolate_other_points( glyph, dimension );
+
+      /* save hinted coordinates back to outline */
+      psh3_glyph_save_points( glyph, dimension );
+    }
+
+  Exit:
+
+#ifndef DEBUG_HINTER
+    psh3_glyph_done( glyph );
+#endif
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshalgo3.h
@@ -1,0 +1,254 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshalgo3.h                                                             */
+/*                                                                         */
+/*    PostScript hinting algorithm 3 (specification).                      */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSHALGO3_H__
+#define __PSHALGO3_H__
+
+
+#include "pshrec.h"
+#include "pshglob.h"
+#include FT_TRIGONOMETRY_H
+
+
+FT_BEGIN_HEADER
+
+
+  /* handle to Hint structure */
+  typedef struct PSH3_HintRec_*  PSH3_Hint;
+
+  /* hint bit-flags */
+  typedef enum
+  {
+    PSH3_HINT_GHOST  = PS_HINT_FLAG_GHOST,
+    PSH3_HINT_BOTTOM = PS_HINT_FLAG_BOTTOM,
+    PSH3_HINT_ACTIVE = 4,
+    PSH3_HINT_FITTED = 8
+
+  } PSH3_Hint_Flags;
+
+
+#define psh3_hint_is_active( x )  ( ( (x)->flags & PSH3_HINT_ACTIVE ) != 0 )
+#define psh3_hint_is_ghost( x )   ( ( (x)->flags & PSH3_HINT_GHOST  ) != 0 )
+#define psh3_hint_is_fitted( x )  ( ( (x)->flags & PSH3_HINT_FITTED ) != 0 )
+
+#define psh3_hint_activate( x )    (x)->flags |=  PSH3_HINT_ACTIVE
+#define psh3_hint_deactivate( x )  (x)->flags &= ~PSH3_HINT_ACTIVE
+#define psh3_hint_set_fitted( x )  (x)->flags |=  PSH3_HINT_FITTED
+
+  /* hint structure */
+  typedef struct  PSH3_HintRec_
+  {
+    FT_Int     org_pos;
+    FT_Int     org_len;
+    FT_Pos     cur_pos;
+    FT_Pos     cur_len;
+    FT_UInt    flags;
+    PSH3_Hint  parent;
+    FT_Int     order;
+
+  } PSH3_HintRec;
+
+
+  /* this is an interpolation zone used for strong points;  */
+  /* weak points are interpolated according to their strong */
+  /* neighbours                                             */
+  typedef struct  PSH3_ZoneRec_
+  {
+    FT_Fixed  scale;
+    FT_Fixed  delta;
+    FT_Pos    min;
+    FT_Pos    max;
+
+  } PSH3_ZoneRec, *PSH3_Zone;
+
+
+  typedef struct  PSH3_Hint_TableRec_
+  {
+    FT_UInt        max_hints;
+    FT_UInt        num_hints;
+    PSH3_Hint      hints;
+    PSH3_Hint*     sort;
+    PSH3_Hint*     sort_global;
+    FT_UInt        num_zones;
+    PSH3_ZoneRec*  zones;
+    PSH3_Zone      zone;
+    PS_Mask_Table  hint_masks;
+    PS_Mask_Table  counter_masks;
+
+  } PSH3_Hint_TableRec, *PSH3_Hint_Table;
+
+
+  typedef struct PSH3_PointRec_*    PSH3_Point;
+  typedef struct PSH3_ContourRec_*  PSH3_Contour;
+
+  enum
+  {
+    PSH3_DIR_NONE  =  4,
+    PSH3_DIR_UP    = -1,
+    PSH3_DIR_DOWN  =  1,
+    PSH3_DIR_LEFT  = -2,
+    PSH3_DIR_RIGHT =  2
+  };
+
+#define PSH3_DIR_HORIZONTAL  2
+#define PSH3_DIR_VERTICAL    1
+
+#define PSH3_DIR_COMPARE( d1, d2 )  ( (d1) == (d2) || (d1) == -(d2) )
+#define PSH3_DIR_IS_HORIZONTAL( d )  PSH3_DIR_COMPARE( d, PSH3_DIR_HORIZONTAL )
+#define PSH3_DIR_IS_VERTICAL( d )    PSH3_DIR_COMPARE( d, PSH3_DIR_VERTICAL )
+
+
+ /* the following bit-flags are computed once by the glyph */
+ /* analyzer, for both dimensions                          */
+  enum
+  {
+    PSH3_POINT_OFF         = 1,   /* point is off the curve          */
+    PSH3_POINT_SMOOTH      = 2,   /* point is smooth                 */
+    PSH3_POINT_INFLEX      = 4    /* point is inflection             */
+  };
+
+#define psh3_point_is_smooth( p )  ( (p)->flags & PSH3_POINT_SMOOTH )
+#define psh3_point_is_off( p )     ( (p)->flags & PSH3_POINT_OFF    )
+#define psh3_point_is_inflex( p )  ( (p)->flags & PSH3_POINT_INFLEX )
+
+#define psh3_point_set_smooth( p )  (p)->flags |= PSH3_POINT_SMOOTH
+#define psh3_point_set_off( p )     (p)->flags |= PSH3_POINT_OFF
+#define psh3_point_set_inflex( p )  (p)->flags |= PSH3_POINT_INFLEX
+
+  /* the following bit-flags are re-computed for each dimension */
+  enum
+  {
+    PSH3_POINT_STRONG   = 16,   /* point is strong                             */
+    PSH3_POINT_FITTED   = 32,   /* point is already fitted                     */
+    PSH3_POINT_EXTREMUM = 64,   /* point is local extremum                     */
+    PSH3_POINT_POSITIVE = 128,  /* extremum has positive contour flow          */
+    PSH3_POINT_NEGATIVE = 256,  /* extremum has negative contour flow          */
+    PSH3_POINT_EDGE_MIN = 512,  /* point is aligned to left/bottom stem edge   */
+    PSH3_POINT_EDGE_MAX = 1024  /* point is aligned to top/right stem edge     */
+  };
+
+#define psh3_point_is_strong( p )    ( (p)->flags2 & PSH3_POINT_STRONG )
+#define psh3_point_is_fitted( p )    ( (p)->flags2 & PSH3_POINT_FITTED )
+#define psh3_point_is_extremum( p )  ( (p)->flags2 & PSH3_POINT_EXTREMUM )
+#define psh3_point_is_positive( p )  ( (p)->flags2 & PSH3_POINT_POSITIVE )
+#define psh3_point_is_negative( p )  ( (p)->flags2 & PSH3_POINT_NEGATIVE )
+#define psh3_point_is_edge_min( p )  ( (p)->flags2 & PSH3_POINT_EDGE_MIN )
+#define psh3_point_is_edge_max( p )  ( (p)->flags2 & PSH3_POINT_EDGE_MAX )
+
+#define psh3_point_set_strong( p )    (p)->flags2 |= PSH3_POINT_STRONG
+#define psh3_point_set_fitted( p )    (p)->flags2 |= PSH3_POINT_FITTED
+#define psh3_point_set_extremum( p )  (p)->flags2 |= PSH3_POINT_EXTREMUM
+#define psh3_point_set_positive( p )  (p)->flags2 |= PSH3_POINT_POSITIVE
+#define psh3_point_set_negative( p )  (p)->flags2 |= PSH3_POINT_NEGATIVE
+#define psh3_point_set_edge_min( p )  (p)->flags2 |= PSH3_POINT_EDGE_MIN
+#define psh3_point_set_edge_max( p )  (p)->flags2 |= PSH3_POINT_EDGE_MAX
+
+
+  typedef struct  PSH3_PointRec_
+  {
+    PSH3_Point    prev;
+    PSH3_Point    next;
+    PSH3_Contour  contour;
+    FT_UInt       flags;
+    FT_UInt       flags2;
+    FT_Char       dir_in;
+    FT_Char       dir_out;
+    FT_Angle      angle_in;
+    FT_Angle      angle_out;
+    PSH3_Hint     hint;
+    FT_Pos        org_u;
+    FT_Pos        org_v;
+    FT_Pos        cur_u;
+#ifdef DEBUG_HINTER
+    FT_Pos        org_x;
+    FT_Pos        cur_x;
+    FT_Pos        org_y;
+    FT_Pos        cur_y;
+    FT_UInt       flags_x;
+    FT_UInt       flags_y;
+#endif
+
+  } PSH3_PointRec;
+
+
+#define PSH3_POINT_EQUAL_ORG( a, b )  ( (a)->org_u == (b)->org_u && \
+                                        (a)->org_v == (b)->org_v )
+
+#define PSH3_POINT_ANGLE( a, b )  FT_Atan2( (b)->org_u - (a)->org_u,  \
+                                            (b)->org_v - (a)->org_v )
+
+  typedef struct  PSH3_ContourRec_
+  {
+    PSH3_Point  start;
+    FT_UInt     count;
+
+  } PSH3_ContourRec;
+
+
+  typedef struct  PSH3_GlyphRec_
+  {
+    FT_UInt             num_points;
+    FT_UInt             num_contours;
+
+    PSH3_Point          points;
+    PSH3_Contour        contours;
+
+    FT_Memory           memory;
+    FT_Outline*         outline;
+    PSH_Globals         globals;
+    PSH3_Hint_TableRec  hint_tables[2];
+
+    FT_Bool             vertical;
+    FT_Int              major_dir;
+    FT_Int              minor_dir;
+
+    FT_Bool             do_horz_hints;
+    FT_Bool             do_vert_hints;
+    FT_Bool             do_horz_snapping;
+    FT_Bool             do_vert_snapping;
+
+  } PSH3_GlyphRec, *PSH3_Glyph;
+
+
+#ifdef DEBUG_HINTER
+  extern PSH3_Hint_Table  ps3_debug_hint_table;
+
+  typedef void
+  (*PSH3_HintFunc)( PSH3_Hint  hint,
+                    FT_Bool    vertical );
+
+  extern PSH3_HintFunc    ps3_debug_hint_func;
+
+  extern PSH3_Glyph       ps3_debug_glyph;
+#endif
+
+
+  extern FT_Error
+  ps3_hints_apply( PS_Hints        ps_hints,
+                   FT_Outline*     outline,
+                   PSH_Globals     globals,
+                   FT_Render_Mode  hint_mode );
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHALGO3_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshglob.c
@@ -1,0 +1,743 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshglob.c                                                              */
+/*                                                                         */
+/*    PostScript hinter global hinting management (body).                  */
+/*    Inspired by the new auto-hinter module.                              */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used        */
+/*  modified and distributed under the terms of the FreeType project       */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_OBJECTS_H
+#include "pshglob.h"
+
+#ifdef DEBUG_HINTER
+  PSH_Globals  ps_debug_globals = 0;
+#endif
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       STANDARD WIDTHS                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* scale the widths/heights table */
+  static void
+  psh_globals_scale_widths( PSH_Globals  globals,
+                            FT_UInt      direction )
+  {
+    PSH_Dimension  dim   = &globals->dimension[direction];
+    PSH_Widths     stdw  = &dim->stdw;
+    FT_UInt        count = stdw->count;
+    PSH_Width      width = stdw->widths;
+    PSH_Width      stand = width;               /* standard width/height */
+    FT_Fixed       scale = dim->scale_mult;
+
+
+    if ( count > 0 )
+    {
+      width->cur = FT_MulFix( width->org, scale );
+      width->fit = FT_RoundFix( width->cur );
+
+      width++;
+      count--;
+
+      for ( ; count > 0; count--, width++ )
+      {
+        FT_Pos  w, dist;
+
+
+        w    = FT_MulFix( width->org, scale );
+        dist = w - stand->cur;
+
+        if ( dist < 0 )
+          dist = -dist;
+
+        if ( dist < 128 )
+          w = stand->cur;
+
+        width->cur = w;
+        width->fit = FT_RoundFix( w );
+      }
+    }
+  }
+
+
+  /* org_width is is font units, result in device pixels, 26.6 format */
+  FT_LOCAL_DEF( FT_Pos )
+  psh_dimension_snap_width( PSH_Dimension  dimension,
+                            FT_Int         org_width )
+  {
+    FT_UInt  n;
+    FT_Pos   width     = FT_MulFix( org_width, dimension->scale_mult );
+    FT_Pos   best      = 64 + 32 + 2;
+    FT_Pos   reference = width;
+
+
+    for ( n = 0; n < dimension->stdw.count; n++ )
+    {
+      FT_Pos  w;
+      FT_Pos  dist;
+
+
+      w = dimension->stdw.widths[n].cur;
+      dist = width - w;
+      if ( dist < 0 )
+        dist = -dist;
+      if ( dist < best )
+      {
+        best      = dist;
+        reference = w;
+      }
+    }
+
+    if ( width >= reference )
+    {
+      width -= 0x21;
+      if ( width < reference )
+        width = reference;
+    }
+    else
+    {
+      width += 0x21;
+      if ( width > reference )
+        width = reference;
+    }
+
+    return width;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       BLUE ZONES                              *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  psh_blues_set_zones_0( PSH_Blues       target,
+                         FT_Bool         is_others,
+                         FT_UInt         read_count,
+                         FT_Short*       read,
+                         PSH_Blue_Table  top_table,
+                         PSH_Blue_Table  bot_table )
+  {
+    FT_UInt  count_top = top_table->count;
+    FT_UInt  count_bot = bot_table->count;
+    FT_Bool  first     = 1;
+
+    FT_UNUSED( target );
+
+
+    for ( ; read_count > 0; read_count -= 2 )
+    {
+      FT_Int         reference, delta;
+      FT_UInt        count;
+      PSH_Blue_Zone  zones, zone;
+      FT_Bool        top;
+
+
+      /* read blue zone entry, and select target top/bottom zone */
+      top = 0;
+      if ( first || is_others )
+      {
+        reference = read[1];
+        delta     = read[0] - reference;
+
+        zones = bot_table->zones;
+        count = count_bot;
+        first = 0;
+      }
+      else
+      {
+        reference = read[0];
+        delta     = read[1] - reference;
+
+        zones = top_table->zones;
+        count = count_top;
+        top   = 1;
+      }
+
+      /* insert into sorted table */
+      zone = zones;
+      for ( ; count > 0; count--, zone++ )
+      {
+        if ( reference < zone->org_ref )
+          break;
+
+        if ( reference == zone->org_ref )
+        {
+          FT_Int  delta0 = zone->org_delta;
+
+
+          /* we have two zones on the same reference position -- */
+          /* only keep the largest one                           */
+          if ( delta < 0 )
+          {
+            if ( delta < delta0 )
+              zone->org_delta = delta;
+          }
+          else
+          {
+            if ( delta > delta0 )
+              zone->org_delta = delta;
+          }
+          goto Skip;
+        }
+      }
+
+      for ( ; count > 0; count-- )
+        zone[count] = zone[count-1];
+
+      zone->org_ref   = reference;
+      zone->org_delta = delta;
+
+      if ( top )
+        count_top++;
+      else
+        count_bot++;
+
+    Skip:
+      read += 2;
+    }
+
+    top_table->count = count_top;
+    bot_table->count = count_bot;
+  }
+
+
+  /* Re-read blue zones from the original fonts and store them into out */
+  /* private structure.  This function re-orders, sanitizes and         */
+  /* fuzz-expands the zones as well.                                    */
+  static void
+  psh_blues_set_zones( PSH_Blues  target,
+                       FT_UInt    count,
+                       FT_Short*  blues,
+                       FT_UInt    count_others,
+                       FT_Short*  other_blues,
+                       FT_Int     fuzz,
+                       FT_Int     family )
+  {
+    PSH_Blue_Table  top_table, bot_table;
+    FT_Int          count_top, count_bot;
+
+
+    if ( family )
+    {
+      top_table = &target->family_top;
+      bot_table = &target->family_bottom;
+    }
+    else
+    {
+      top_table = &target->normal_top;
+      bot_table = &target->normal_bottom;
+    }
+
+    /* read the input blue zones, and build two sorted tables  */
+    /* (one for the top zones, the other for the bottom zones) */
+    top_table->count = 0;
+    bot_table->count = 0;
+
+    /* first, the blues */
+    psh_blues_set_zones_0( target, 0,
+                           count, blues, top_table, bot_table );
+    psh_blues_set_zones_0( target, 1,
+                           count_others, other_blues, top_table, bot_table );
+
+    count_top = top_table->count;
+    count_bot = bot_table->count;
+
+    /* sanitize top table */
+    if ( count_top > 0 )
+    {
+      PSH_Blue_Zone  zone = top_table->zones;
+
+
+      for ( count = count_top; count > 0; count--, zone++ )
+      {
+        FT_Int  delta;
+
+
+        if ( count > 1 )
+        {
+          delta = zone[1].org_ref - zone[0].org_ref;
+          if ( zone->org_delta > delta )
+            zone->org_delta = delta;
+        }
+
+        zone->org_bottom = zone->org_ref;
+        zone->org_top    = zone->org_delta + zone->org_ref;
+      }
+    }
+
+    /* sanitize bottom table */
+    if ( count_bot > 0 )
+    {
+      PSH_Blue_Zone  zone = bot_table->zones;
+
+
+      for ( count = count_bot; count > 0; count--, zone++ )
+      {
+        FT_Int  delta;
+
+
+        if ( count > 1 )
+        {
+          delta = zone[0].org_ref - zone[1].org_ref;
+          if ( zone->org_delta < delta )
+            zone->org_delta = delta;
+        }
+
+        zone->org_top    = zone->org_ref;
+        zone->org_bottom = zone->org_delta + zone->org_ref;
+      }
+    }
+
+    /* expand top and bottom tables with blue fuzz */
+    {
+      FT_Int         dim, top, bot, delta;
+      PSH_Blue_Zone  zone;
+
+
+      zone  = top_table->zones;
+      count = count_top;
+
+      for ( dim = 1; dim >= 0; dim-- )
+      {
+        if ( count > 0 )
+        {
+          /* expand the bottom of the lowest zone normally */
+          zone->org_bottom -= fuzz;
+
+          /* expand the top and bottom of intermediate zones;    */
+          /* checking that the interval is smaller than the fuzz */
+          top = zone->org_top;
+
+          for ( count--; count > 0; count-- )
+          {
+            bot   = zone[1].org_bottom;
+            delta = bot - top;
+
+            if ( delta < 2 * fuzz )
+              zone[0].org_top = zone[1].org_bottom = top + delta / 2;
+            else
+            {
+              zone[0].org_top    = top + fuzz;
+              zone[1].org_bottom = bot - fuzz;
+            }
+
+            zone++;
+            top = zone->org_top;
+          }
+
+          /* expand the top of the highest zone normally */
+          zone->org_top = top + fuzz;
+        }
+        zone  = bot_table->zones;
+        count = count_bot;
+      }
+    }
+  }
+
+
+  /* reset the blues table when the device transform changes */
+  static void
+  psh_blues_scale_zones( PSH_Blues  blues,
+                         FT_Fixed   scale,
+                         FT_Pos     delta )
+  {
+    FT_UInt         count;
+    FT_UInt         num;
+    PSH_Blue_Table  table = 0;
+
+    /*                                                        */
+    /* Determine whether we need to suppress overshoots or    */
+    /* not.  We simply need to compare the vertical scale     */
+    /* parameter to the raw bluescale value.  Here is why:    */
+    /*                                                        */
+    /*   We need to suppress overshoots for all pointsizes.   */
+    /*   At 300dpi that satisfy:                              */
+    /*                                                        */
+    /*      pointsize < 240*bluescale + 0.49                  */
+    /*                                                        */
+    /*   This corresponds to:                                 */
+    /*                                                        */
+    /*      pixelsize < 1000*bluescale + 49/24                */
+    /*                                                        */
+    /*      scale*EM_Size < 1000*bluescale + 49/24            */
+    /*                                                        */
+    /*   However, for normal Type 1 fonts, EM_Size is 1000!   */
+    /*   We thus only check:                                  */
+    /*                                                        */
+    /*      scale < bluescale + 49/24000                      */
+    /*                                                        */
+    /*   which we shorten to                                  */
+    /*                                                        */
+    /*      "scale < bluescale"                               */
+    /*                                                        */
+    blues->no_overshoots = FT_BOOL( scale < blues->blue_scale );
+
+    /*                                                        */
+    /*  The blue threshold is the font units distance under   */
+    /*  which overshoots are suppressed due to the BlueShift  */
+    /*  even if the scale is greater than BlueScale.          */
+    /*                                                        */
+    /*  It is the smallest distance such that                 */
+    /*                                                        */
+    /*    dist <= BlueShift && dist*scale <= 0.5 pixels       */
+    /*                                                        */
+    {
+      FT_Int  threshold = blues->blue_shift;
+
+
+      while ( threshold > 0 && FT_MulFix( threshold, scale ) > 32 )
+        threshold --;
+
+      blues->blue_threshold = threshold;
+    }
+
+    for ( num = 0; num < 4; num++ )
+    {
+      PSH_Blue_Zone  zone;
+
+
+      switch ( num )
+      {
+      case 0:
+        table = &blues->normal_top;
+        break;
+      case 1:
+        table = &blues->normal_bottom;
+        break;
+      case 2:
+        table = &blues->family_top;
+        break;
+      default:
+        table = &blues->family_bottom;
+        break;
+      }
+
+      zone  = table->zones;
+      count = table->count;
+      for ( ; count > 0; count--, zone++ )
+      {
+        zone->cur_top    = FT_MulFix( zone->org_top,    scale ) + delta;
+        zone->cur_bottom = FT_MulFix( zone->org_bottom, scale ) + delta;
+        zone->cur_ref    = FT_MulFix( zone->org_ref,    scale ) + delta;
+        zone->cur_delta  = FT_MulFix( zone->org_delta,  scale );
+
+        /* round scaled reference position */
+        zone->cur_ref = ( zone->cur_ref + 32 ) & -64;
+
+#if 0
+        if ( zone->cur_ref > zone->cur_top )
+          zone->cur_ref -= 64;
+        else if ( zone->cur_ref < zone->cur_bottom )
+          zone->cur_ref += 64;
+#endif
+      }
+    }
+
+    /* process the families now */
+
+    for ( num = 0; num < 2; num++ )
+    {
+      PSH_Blue_Zone   zone1, zone2;
+      FT_UInt         count1, count2;
+      PSH_Blue_Table  normal, family;
+
+
+      switch ( num )
+      {
+      case 0:
+        normal = &blues->normal_top;
+        family = &blues->family_top;
+        break;
+
+      default:
+        normal = &blues->normal_bottom;
+        family = &blues->family_bottom;
+      }
+
+      zone1  = normal->zones;
+      count1 = normal->count;
+
+      for ( ; count1 > 0; count1--, zone1++ )
+      {
+        /* try to find a family zone whose reference position is less */
+        /* than 1 pixel far from the current zone                     */
+        zone2  = family->zones;
+        count2 = family->count;
+
+        for ( ; count2 > 0; count2--, zone2++ )
+        {
+          FT_Pos  Delta;
+
+
+          Delta = zone1->org_ref - zone2->org_ref;
+          if ( Delta < 0 )
+            Delta = -Delta;
+
+          if ( FT_MulFix( Delta, scale ) < 64 )
+          {
+            zone1->cur_top    = zone2->cur_top;
+            zone1->cur_bottom = zone2->cur_bottom;
+            zone1->cur_ref    = zone2->cur_ref;
+            zone1->cur_delta  = zone2->cur_delta;
+            break;
+          }
+        }
+      }
+    }
+  }
+
+
+  FT_LOCAL_DEF( void )
+  psh_blues_snap_stem( PSH_Blues      blues,
+                       FT_Int         stem_top,
+                       FT_Int         stem_bot,
+                       PSH_Alignment  alignment )
+  {
+    PSH_Blue_Table  table;
+    FT_UInt         count;
+    FT_Pos          delta;
+    PSH_Blue_Zone   zone;
+    FT_Int          no_shoots;
+
+
+    alignment->align = PSH_BLUE_ALIGN_NONE;
+
+    no_shoots = blues->no_overshoots;
+
+    /* lookup stem top in top zones table */
+    table = &blues->normal_top;
+    count = table->count;
+    zone  = table->zones;
+
+    for ( ; count > 0; count--, zone++ )
+    {
+      delta = stem_top - zone->org_bottom;
+      if ( delta < -blues->blue_fuzz )
+        break;
+
+      if ( stem_top <= zone->org_top + blues->blue_fuzz )
+      {
+        if ( no_shoots || delta <= blues->blue_threshold )
+        {
+          alignment->align    |= PSH_BLUE_ALIGN_TOP;
+          alignment->align_top = zone->cur_ref;
+        }
+        break;
+      }
+    }
+
+    /* look up stem bottom in bottom zones table */
+    table = &blues->normal_bottom;
+    count = table->count;
+    zone  = table->zones + count-1;
+
+    for ( ; count > 0; count--, zone-- )
+    {
+      delta = zone->org_top - stem_bot;
+      if ( delta < -blues->blue_fuzz )
+        break;
+
+      if ( stem_bot >= zone->org_bottom - blues->blue_fuzz )
+      {
+        if ( no_shoots || delta < blues->blue_shift )
+        {
+          alignment->align    |= PSH_BLUE_ALIGN_BOT;
+          alignment->align_bot = zone->cur_ref;
+        }
+        break;
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        GLOBAL HINTS                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  psh_globals_destroy( PSH_Globals  globals )
+  {
+    if ( globals )
+    {
+      FT_Memory  memory;
+
+
+      memory = globals->memory;
+      globals->dimension[0].stdw.count = 0;
+      globals->dimension[1].stdw.count = 0;
+
+      globals->blues.normal_top.count    = 0;
+      globals->blues.normal_bottom.count = 0;
+      globals->blues.family_top.count    = 0;
+      globals->blues.family_bottom.count = 0;
+
+      FT_FREE( globals );
+
+#ifdef DEBUG_HINTER
+      ps_debug_globals = 0;
+#endif
+    }
+  }
+
+
+  static FT_Error
+  psh_globals_new( FT_Memory     memory,
+                   T1_Private*   priv,
+                   PSH_Globals  *aglobals )
+  {
+    PSH_Globals  globals;
+    FT_Error     error;
+
+
+    if ( !FT_NEW( globals ) )
+    {
+      FT_UInt    count;
+      FT_Short*  read;
+
+
+      globals->memory = memory;
+
+      /* copy standard widths */
+      {
+        PSH_Dimension  dim   = &globals->dimension[1];
+        PSH_Width      write = dim->stdw.widths;
+
+
+        write->org = priv->standard_width[0];
+        write++;
+
+        read = priv->snap_widths;
+        for ( count = priv->num_snap_widths; count > 0; count-- )
+        {
+          write->org = *read;
+          write++;
+          read++;
+        }
+
+        dim->stdw.count = write - dim->stdw.widths;
+      }
+
+      /* copy standard heights */
+      {
+        PSH_Dimension  dim = &globals->dimension[0];
+        PSH_Width      write = dim->stdw.widths;
+
+
+        write->org = priv->standard_height[0];
+        write++;                           
+        read = priv->snap_heights;
+        for ( count = priv->num_snap_heights; count > 0; count-- )
+        {
+          write->org = *read;
+          write++;
+          read++;
+        }
+
+        dim->stdw.count = write - dim->stdw.widths;
+      }
+
+      /* copy blue zones */
+      psh_blues_set_zones( &globals->blues, priv->num_blue_values,
+                           priv->blue_values, priv->num_other_blues,
+                           priv->other_blues, priv->blue_fuzz, 0 );
+
+      psh_blues_set_zones( &globals->blues, priv->num_family_blues,
+                           priv->family_blues, priv->num_family_other_blues,
+                           priv->family_other_blues, priv->blue_fuzz, 1 );
+
+      globals->blues.blue_scale = priv->blue_scale
+                                  ? priv->blue_scale
+                                  : 0x28937L;   /* 0.039625 * 0x400000L */
+
+      globals->blues.blue_shift = priv->blue_shift
+                                  ? priv->blue_shift
+                                  : 7;
+
+      globals->blues.blue_fuzz = priv->blue_fuzz;
+
+      globals->dimension[0].scale_mult  = 0;
+      globals->dimension[0].scale_delta = 0;
+      globals->dimension[1].scale_mult  = 0;
+      globals->dimension[1].scale_delta = 0;
+
+#ifdef DEBUG_HINTER
+      ps_debug_globals = globals;
+#endif
+    }
+
+    *aglobals = globals;
+    return error;
+  }
+
+
+  static FT_Error
+  psh_globals_set_scale( PSH_Globals  globals,
+                         FT_Fixed     x_scale,
+                         FT_Fixed     y_scale,
+                         FT_Fixed     x_delta,
+                         FT_Fixed     y_delta )
+  {
+    PSH_Dimension  dim = &globals->dimension[0];
+
+
+    dim = &globals->dimension[0];
+    if ( x_scale != dim->scale_mult  ||
+         x_delta != dim->scale_delta )
+    {
+      dim->scale_mult  = x_scale;
+      dim->scale_delta = x_delta;
+
+      psh_globals_scale_widths( globals, 0 );
+    }
+
+    dim = &globals->dimension[1];
+    if ( y_scale != dim->scale_mult  ||
+         y_delta != dim->scale_delta )
+    {
+      dim->scale_mult  = y_scale;
+      dim->scale_delta = y_delta;
+
+      psh_globals_scale_widths( globals, 1 );
+      psh_blues_scale_zones( &globals->blues, y_scale, y_delta );
+    }
+
+    return 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  psh_globals_funcs_init( PSH_Globals_FuncsRec*  funcs )
+  {
+    funcs->create    = psh_globals_new;
+    funcs->set_scale = psh_globals_set_scale;
+    funcs->destroy   = psh_globals_destroy;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshglob.h
@@ -1,0 +1,187 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshglob.h                                                              */
+/*                                                                         */
+/*    PostScript hinter global hinting management.                         */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSHGLOB_H__
+#define __PSHGLOB_H__
+
+
+#include FT_FREETYPE_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    GLOBAL HINTS INTERNALS                     *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* @constant:                                                            */
+  /*    PS_GLOBALS_MAX_BLUE_ZONES                                          */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    The maximum number of blue zones in a font global hints structure. */
+  /*    See @PS_Globals_BluesRec.                                          */
+  /*                                                                       */
+#define PS_GLOBALS_MAX_BLUE_ZONES  16
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* @constant:                                                            */
+  /*    PS_GLOBALS_MAX_STD_WIDTHS                                          */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    The maximum number of standard and snap widths in either the       */
+  /*    horizontal or vertical direction.  See @PS_Globals_WidthsRec.      */
+  /*                                                                       */
+#define PS_GLOBALS_MAX_STD_WIDTHS  16
+
+
+  /* standard and snap width */
+  typedef struct  PSH_WidthRec_
+  {
+    FT_Int  org;
+    FT_Pos  cur;
+    FT_Pos  fit;
+
+  } PSH_WidthRec, *PSH_Width;
+
+
+  /* standard and snap widths table */
+  typedef struct  PSH_WidthsRec_
+  {
+    FT_UInt       count;
+    PSH_WidthRec  widths[PS_GLOBALS_MAX_STD_WIDTHS];
+
+  } PSH_WidthsRec, *PSH_Widths;
+
+
+  typedef struct  PSH_DimensionRec_
+  {
+    PSH_WidthsRec  stdw;
+    FT_Fixed       scale_mult;
+    FT_Fixed       scale_delta;
+
+  } PSH_DimensionRec, *PSH_Dimension;
+
+
+  /* blue zone descriptor */
+  typedef struct  PSH_Blue_ZoneRec_
+  {
+    FT_Int  org_ref;
+    FT_Int  org_delta;
+    FT_Int  org_top;
+    FT_Int  org_bottom;
+
+    FT_Pos  cur_ref;
+    FT_Pos  cur_delta;
+    FT_Pos  cur_bottom;
+    FT_Pos  cur_top;
+
+  } PSH_Blue_ZoneRec, *PSH_Blue_Zone;
+
+
+  typedef struct  PSH_Blue_TableRec_
+  {
+    FT_UInt           count;
+    PSH_Blue_ZoneRec  zones[PS_GLOBALS_MAX_BLUE_ZONES];
+
+  } PSH_Blue_TableRec, *PSH_Blue_Table;
+
+
+  /* blue zones table */
+  typedef struct  PSH_BluesRec_
+  {
+    PSH_Blue_TableRec  normal_top;
+    PSH_Blue_TableRec  normal_bottom;
+    PSH_Blue_TableRec  family_top;
+    PSH_Blue_TableRec  family_bottom;
+
+    FT_Fixed           blue_scale;
+    FT_Int             blue_shift;
+    FT_Int             blue_threshold;
+    FT_Int             blue_fuzz;
+    FT_Bool            no_overshoots;
+
+  } PSH_BluesRec, *PSH_Blues;
+
+
+  /* font globals.                                         */
+  /* dimension 0 => X coordinates + vertical hints/stems   */
+  /* dimension 1 => Y coordinates + horizontal hints/stems */
+  typedef struct  PSH_GlobalsRec_
+  {
+    FT_Memory         memory;
+    PSH_DimensionRec  dimension[2];
+    PSH_BluesRec      blues;
+
+  } PSH_GlobalsRec;
+
+
+#define PSH_BLUE_ALIGN_NONE  0
+#define PSH_BLUE_ALIGN_TOP   1
+#define PSH_BLUE_ALIGN_BOT   2
+
+
+  typedef struct  PSH_AlignmentRec_
+  {
+    int     align;
+    FT_Pos  align_top;
+    FT_Pos  align_bot;
+
+  } PSH_AlignmentRec, *PSH_Alignment;
+
+
+  FT_LOCAL( void )
+  psh_globals_funcs_init( PSH_Globals_FuncsRec*  funcs );
+
+
+  /* snap a stem width to fitter coordinates.  `org_width' is in font */
+  /* units.  The result is in device pixels (26.6 format).            */
+  FT_LOCAL( FT_Pos )
+  psh_dimension_snap_width( PSH_Dimension  dimension,
+                            FT_Int         org_width );
+
+  /* snap a stem to one or two blue zones */
+  FT_LOCAL( void )
+  psh_blues_snap_stem( PSH_Blues      blues,
+                       FT_Int         stem_top,
+                       FT_Int         stem_bot,
+                       PSH_Alignment  alignment );
+  /* */
+
+#ifdef DEBUG_HINTER
+  extern PSH_Globals  ps_debug_globals;
+#endif
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHGLOB_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshinter.c
@@ -1,0 +1,30 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshinter.c                                                             */
+/*                                                                         */
+/*    FreeType PostScript Hinting module                                   */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "pshrec.c"
+#include "pshglob.c"
+#include "pshalgo1.c"
+#include "pshalgo2.c"
+#include "pshalgo3.c"
+#include "pshmod.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshmod.c
@@ -1,0 +1,120 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshmod.c                                                               */
+/*                                                                         */
+/*    FreeType PostScript hinter module implementation (body).             */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include "pshrec.h"
+#include "pshalgo.h"
+
+
+  /* the Postscript Hinter module structure */
+  typedef struct  PS_Hinter_Module_Rec_
+  {
+    FT_ModuleRec          root;
+    PS_HintsRec           ps_hints;
+
+    PSH_Globals_FuncsRec  globals_funcs;
+    T1_Hints_FuncsRec     t1_funcs;
+    T2_Hints_FuncsRec     t2_funcs;
+
+  } PS_Hinter_ModuleRec, *PS_Hinter_Module;
+
+
+  /* finalize module */
+  FT_CALLBACK_DEF( void )
+  ps_hinter_done( PS_Hinter_Module  module )
+  {
+    module->t1_funcs.hints = NULL;
+    module->t2_funcs.hints = NULL;
+
+    ps_hints_done( &module->ps_hints );
+  }
+
+
+  /* initialize module, create hints recorder and the interface */
+  FT_CALLBACK_DEF( FT_Error )
+  ps_hinter_init( PS_Hinter_Module  module )
+  {
+    FT_Memory  memory = module->root.memory;
+
+
+    ps_hints_init( &module->ps_hints, memory );
+
+    psh_globals_funcs_init( &module->globals_funcs );
+
+    t1_hints_funcs_init( &module->t1_funcs );
+    module->t1_funcs.hints = (T1_Hints)&module->ps_hints;
+
+    t2_hints_funcs_init( &module->t2_funcs );
+    module->t2_funcs.hints = (T2_Hints)&module->ps_hints;
+
+    return 0;
+  }
+
+
+  /* returns global hints interface */
+  FT_CALLBACK_DEF( PSH_Globals_Funcs )
+  pshinter_get_globals_funcs( FT_Module  module )
+  {
+    return &((PS_Hinter_Module)module)->globals_funcs;
+  }
+
+
+  /* return Type 1 hints interface */
+  FT_CALLBACK_DEF( T1_Hints_Funcs )
+  pshinter_get_t1_funcs( FT_Module  module )
+  {
+    return &((PS_Hinter_Module)module)->t1_funcs;
+  }
+
+
+  /* return Type 2 hints interface */
+  FT_CALLBACK_DEF( T2_Hints_Funcs )
+  pshinter_get_t2_funcs( FT_Module  module )
+  {
+    return &((PS_Hinter_Module)module)->t2_funcs;
+  }
+
+
+  static
+  const PSHinter_Interface  pshinter_interface =
+  {
+    pshinter_get_globals_funcs,
+    pshinter_get_t1_funcs,
+    pshinter_get_t2_funcs
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Module_Class  pshinter_module_class =
+  {
+    0,
+    sizeof ( PS_Hinter_ModuleRec ),
+    "pshinter",
+    0x10000L,
+    0x20000L,
+
+    &pshinter_interface,            /* module-specific interface */
+
+    (FT_Module_Constructor)ps_hinter_init,
+    (FT_Module_Destructor) ps_hinter_done,
+    (FT_Module_Requester)  0        /* no additional interface for now */
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshmod.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshmod.h                                                               */
+/*                                                                         */
+/*    PostScript hinter module interface (specification).                  */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSHMOD_H__
+#define __PSHMOD_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Module_Class )  pshinter_module_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __PSHMOD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshrec.c
@@ -1,0 +1,1211 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshrec.c                                                               */
+/*                                                                         */
+/*    FreeType PostScript hints recorder (body).                           */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include "pshrec.h"
+#include "pshalgo.h"
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_pshrec
+
+#ifdef DEBUG_HINTER
+  PS_Hints  ps_debug_hints         = 0;
+  int       ps_debug_no_horz_hints = 0;
+  int       ps_debug_no_vert_hints = 0;
+#endif
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      PS_HINT MANAGEMENT                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* destroy hints table */
+  static void
+  ps_hint_table_done( PS_Hint_Table  table,
+                      FT_Memory      memory )
+  {
+    FT_FREE( table->hints );
+    table->num_hints = 0;
+    table->max_hints = 0;
+  }
+
+
+  /* ensure that a table can contain "count" elements */
+  static FT_Error
+  ps_hint_table_ensure( PS_Hint_Table  table,
+                        FT_UInt        count,
+                        FT_Memory      memory )
+  {
+    FT_UInt   old_max = table->max_hints;
+    FT_UInt   new_max = count;
+    FT_Error  error   = 0;
+
+
+    if ( new_max > old_max )
+    {
+      /* try to grow the table */
+      new_max = ( new_max + 7 ) & -8;
+      if ( !FT_RENEW_ARRAY( table->hints, old_max, new_max ) )
+        table->max_hints = new_max;
+    }
+    return error;
+  }
+
+
+  static FT_Error
+  ps_hint_table_alloc( PS_Hint_Table  table,
+                       FT_Memory      memory,
+                       PS_Hint       *ahint )
+  {
+    FT_Error  error = 0;
+    FT_UInt   count;
+    PS_Hint   hint = 0;
+
+
+    count = table->num_hints;
+    count++;
+
+    if ( count >= table->max_hints )
+    {
+      error = ps_hint_table_ensure( table, count, memory );
+      if ( error )
+        goto Exit;
+    }
+
+    hint        = table->hints + count - 1;
+    hint->pos   = 0;
+    hint->len   = 0;
+    hint->flags = 0;
+
+    table->num_hints = count;
+
+  Exit:
+    *ahint = hint;
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      PS_MASK MANAGEMENT                       *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* destroy mask */
+  static void
+  ps_mask_done( PS_Mask    mask,
+                FT_Memory  memory )
+  {
+    FT_FREE( mask->bytes );
+    mask->num_bits  = 0;
+    mask->max_bits  = 0;
+    mask->end_point = 0;
+  }
+
+
+  /* ensure that a mask can contain "count" bits */
+  static FT_Error
+  ps_mask_ensure( PS_Mask    mask,
+                  FT_UInt    count,
+                  FT_Memory  memory )
+  {
+    FT_UInt   old_max = ( mask->max_bits + 7 ) >> 3;
+    FT_UInt   new_max = ( count          + 7 ) >> 3;
+    FT_Error  error   = 0;
+
+
+    if ( new_max > old_max )
+    {
+      new_max = ( new_max + 7 ) & -8;
+      if ( !FT_RENEW_ARRAY( mask->bytes, old_max, new_max ) )
+        mask->max_bits = new_max * 8;
+    }
+    return error;
+  }
+
+
+  /* test a bit value in a given mask */
+  static FT_Int
+  ps_mask_test_bit( PS_Mask  mask,
+                    FT_Int   idx )
+  {
+    if ( (FT_UInt)idx >= mask->num_bits )
+      return 0;
+
+    return mask->bytes[idx >> 3] & ( 0x80 >> ( idx & 7 ) );
+  }
+
+
+  /* clear a given bit */
+  static void
+  ps_mask_clear_bit( PS_Mask  mask,
+                     FT_Int   idx )
+  {
+    FT_Byte*  p;
+
+
+    if ( (FT_UInt)idx >= mask->num_bits )
+      return;
+
+    p    = mask->bytes + ( idx >> 3 );
+    p[0] = (FT_Byte)( p[0] & ~( 0x80 >> ( idx & 7 ) ) );
+  }
+
+
+  /* set a given bit, possibly grow the mask */
+  static FT_Error
+  ps_mask_set_bit( PS_Mask    mask,
+                   FT_Int     idx,
+                   FT_Memory  memory )
+  {
+    FT_Error  error = 0;
+    FT_Byte*  p;
+
+
+    if ( idx < 0 )
+      goto Exit;
+
+    if ( (FT_UInt)idx >= mask->num_bits )
+    {
+      error = ps_mask_ensure( mask, idx + 1, memory );
+      if ( error )
+        goto Exit;
+
+      mask->num_bits = idx + 1;
+    }
+
+    p    = mask->bytes + ( idx >> 3 );
+    p[0] = (FT_Byte)( p[0] | ( 0x80 >> ( idx & 7 ) ) );
+
+  Exit:
+    return error;
+  }
+
+
+  /* destroy mask table */
+  static void
+  ps_mask_table_done( PS_Mask_Table  table,
+                      FT_Memory      memory )
+  {
+    FT_UInt  count = table->max_masks;
+    PS_Mask  mask  = table->masks;
+
+
+    for ( ; count > 0; count--, mask++ )
+      ps_mask_done( mask, memory );
+
+    FT_FREE( table->masks );
+    table->num_masks = 0;
+    table->max_masks = 0;
+  }
+
+
+  /* ensure that a mask table can contain "count" masks */
+  static FT_Error
+  ps_mask_table_ensure( PS_Mask_Table  table,
+                        FT_UInt        count,
+                        FT_Memory      memory )
+  {
+    FT_UInt   old_max = table->max_masks;
+    FT_UInt   new_max = count;
+    FT_Error  error   = 0;
+
+
+    if ( new_max > old_max )
+    {
+      new_max = ( new_max + 7 ) & -8;
+      if ( !FT_RENEW_ARRAY( table->masks, old_max, new_max ) )
+        table->max_masks = new_max;
+    }
+    return error;
+  }
+
+
+  /* allocate a new mask in a table */
+  static FT_Error
+  ps_mask_table_alloc( PS_Mask_Table  table,
+                       FT_Memory      memory,
+                       PS_Mask       *amask )
+  {
+    FT_UInt   count;
+    FT_Error  error = 0;
+    PS_Mask   mask  = 0;
+
+
+    count = table->num_masks;
+    count++;
+
+    if ( count > table->max_masks )
+    {
+      error = ps_mask_table_ensure( table, count, memory );
+      if ( error )
+        goto Exit;
+    }
+
+    mask             = table->masks + count - 1;
+    mask->num_bits   = 0;
+    mask->end_point  = 0;
+    table->num_masks = count;
+
+  Exit:
+    *amask = mask;
+    return error;
+  }
+
+
+  /* return last hint mask in a table, create one if the table is empty */
+  static FT_Error
+  ps_mask_table_last( PS_Mask_Table  table,
+                      FT_Memory      memory,
+                      PS_Mask       *amask )
+  {
+    FT_Error  error = 0;
+    FT_UInt   count;
+    PS_Mask   mask;
+
+
+    count = table->num_masks;
+    if ( count == 0 )
+    {
+      error = ps_mask_table_alloc( table, memory, &mask );
+      if ( error )
+        goto Exit;
+    }
+    else
+      mask = table->masks + count - 1;
+
+  Exit:
+    *amask = mask;
+    return error;
+  }
+
+
+  /* set a new mask to a given bit range */
+  static FT_Error
+  ps_mask_table_set_bits( PS_Mask_Table  table,
+                          FT_Byte*       source,
+                          FT_UInt        bit_pos,
+                          FT_UInt        bit_count,
+                          FT_Memory      memory )
+  {
+    FT_Error  error = 0;
+    PS_Mask   mask;
+
+
+    /* allocate new mask, and grow it to "bit_count" bits */
+    error = ps_mask_table_alloc( table, memory, &mask );
+    if ( error )
+      goto Exit;
+
+    error = ps_mask_ensure( mask, bit_count, memory );
+    if ( error )
+      goto Exit;
+
+    mask->num_bits = bit_count;
+
+    /* now, copy bits */
+    {
+      FT_Byte*  read  = source + ( bit_pos >> 3 );
+      FT_Int    rmask = 0x80 >> ( bit_pos & 7 );
+      FT_Byte*  write = mask->bytes;
+      FT_Int    wmask = 0x80;
+      FT_Int    val;
+
+
+      for ( ; bit_count > 0; bit_count-- )
+      {
+        val = write[0] & ~wmask;
+
+        if ( read[0] & rmask )
+          val |= wmask;
+
+        write[0] = (FT_Byte)val;
+
+        rmask >>= 1;
+        if ( rmask == 0 )
+        {
+          read++;
+          rmask = 0x80;
+        }
+
+        wmask >>= 1;
+        if ( wmask == 0 )
+        {
+          write++;
+          wmask = 0x80;
+        }
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /* test whether two masks in a table intersect */
+  static FT_Int
+  ps_mask_table_test_intersect( PS_Mask_Table  table,
+                                FT_Int         index1,
+                                FT_Int         index2 )
+  {
+    PS_Mask   mask1  = table->masks + index1;
+    PS_Mask   mask2  = table->masks + index2;
+    FT_Byte*  p1     = mask1->bytes;
+    FT_Byte*  p2     = mask2->bytes;
+    FT_UInt   count1 = mask1->num_bits;
+    FT_UInt   count2 = mask2->num_bits;
+    FT_UInt   count;
+
+
+    count = ( count1 <= count2 ) ? count1 : count2;
+    for ( ; count >= 8; count -= 8 )
+    {
+      if ( p1[0] & p2[0] )
+        return 1;
+
+      p1++;
+      p2++;
+    }
+
+    if ( count == 0 )
+      return 0;
+
+    return ( p1[0] & p2[0] ) & ~( 0xFF >> count );
+  }
+
+
+  /* merge two masks, used by ps_mask_table_merge_all */
+  static FT_Error
+  ps_mask_table_merge( PS_Mask_Table  table,
+                       FT_Int         index1,
+                       FT_Int         index2,
+                       FT_Memory      memory )
+  {
+    FT_UInt   temp;
+    FT_Error  error = 0;
+
+
+    /* swap index1 and index2 so that index1 < index2 */
+    if ( index1 > index2 )
+    {
+      temp   = index1;
+      index1 = index2;
+      index2 = temp;
+    }
+
+    if ( index1 < index2 && index1 >= 0 && index2 < (FT_Int)table->num_masks )
+    {
+      /* we need to merge the bitsets of index1 and index2 with a */
+      /* simple union                                             */
+      PS_Mask  mask1  = table->masks + index1;
+      PS_Mask  mask2  = table->masks + index2;
+      FT_UInt  count1 = mask1->num_bits;
+      FT_UInt  count2 = mask2->num_bits;
+      FT_Int   delta;
+
+
+      if ( count2 > 0 )
+      {
+        FT_UInt   pos;
+        FT_Byte*  read;
+        FT_Byte*  write;
+
+
+        /* if "count2" is greater than "count1", we need to grow the */
+        /* first bitset, and clear the highest bits                  */
+        if ( count2 > count1 )
+        {
+          error = ps_mask_ensure( mask1, count2, memory );
+          if ( error )
+            goto Exit;
+
+          for ( pos = count1; pos < count2; pos++ )
+            ps_mask_clear_bit( mask1, pos );
+        }
+
+        /* merge (unite) the bitsets */
+        read  = mask2->bytes;
+        write = mask1->bytes;
+        pos   = (FT_UInt)( ( count2 + 7 ) >> 3 );
+
+        for ( ; pos > 0; pos-- )
+        {
+          write[0] = (FT_Byte)( write[0] | read[0] );
+          write++;
+          read++;
+        }
+      }
+
+      /* Now, remove "mask2" from the list.  We need to keep the masks */
+      /* sorted in order of importance, so move table elements.        */
+      mask2->num_bits  = 0;
+      mask2->end_point = 0;
+
+      delta = table->num_masks - 1 - index2; /* number of masks to move */
+      if ( delta > 0 )
+      {
+        /* move to end of table for reuse */
+        PS_MaskRec  dummy = *mask2;
+
+
+        ft_memmove( mask2, mask2 + 1, delta * sizeof ( PS_MaskRec ) );
+
+        mask2[delta] = dummy;
+      }
+
+      table->num_masks--;
+    }
+    else
+      FT_ERROR(( "ps_mask_table_merge: ignoring invalid indices (%d,%d)\n",
+                 index1, index2 ));
+
+  Exit:
+    return error;
+  }
+
+
+  /* Try to merge all masks in a given table.  This is used to merge */
+  /* all counter masks into independent counter "paths".             */
+  /*                                                                 */
+  static FT_Error
+  ps_mask_table_merge_all( PS_Mask_Table  table,
+                           FT_Memory      memory )
+  {
+    FT_Int    index1, index2;
+    FT_Error  error = 0;
+
+
+    for ( index1 = table->num_masks - 1; index1 > 0; index1-- )
+    {
+      for ( index2 = index1 - 1; index2 >= 0; index2-- )
+      {
+        if ( ps_mask_table_test_intersect( table, index1, index2 ) )
+        {
+          error = ps_mask_table_merge( table, index2, index1, memory );
+          if ( error )
+            goto Exit;
+
+          break;
+        }
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    PS_DIMENSION MANAGEMENT                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* finalize a given dimension */
+  static void
+  ps_dimension_done( PS_Dimension  dimension,
+                     FT_Memory     memory )
+  {
+    ps_mask_table_done( &dimension->counters, memory );
+    ps_mask_table_done( &dimension->masks,    memory );
+    ps_hint_table_done( &dimension->hints,    memory );
+  }
+
+
+  /* initialize a given dimension */
+  static void
+  ps_dimension_init( PS_Dimension  dimension )
+  {
+    dimension->hints.num_hints    = 0;
+    dimension->masks.num_masks    = 0;
+    dimension->counters.num_masks = 0;
+  }
+
+
+#if 0
+
+  /* set a bit at a given index in the current hint mask */
+  static FT_Error
+  ps_dimension_set_mask_bit( PS_Dimension  dim,
+                             FT_UInt       idx,
+                             FT_Memory     memory )
+  {
+    PS_Mask  mask;
+    FT_Error  error = 0;
+
+
+    /* get last hint mask */
+    error = ps_mask_table_last( &dim->masks, memory, &mask );
+    if ( error )
+      goto Exit;
+
+    error = ps_mask_set_bit( mask, idx, memory );
+
+  Exit:
+    return error;
+  }
+
+#endif
+
+  /* set the end point in a mask, called from "End" & "Reset" methods */
+  static void
+  ps_dimension_end_mask( PS_Dimension  dim,
+                         FT_UInt       end_point )
+  {
+    FT_UInt  count = dim->masks.num_masks;
+    PS_Mask  mask;
+
+
+    if ( count > 0 )
+    {
+      mask            = dim->masks.masks + count - 1;
+      mask->end_point = end_point;
+    }
+  }
+
+
+  /* set the end point in the current mask, then create a new empty one */
+  /* (called by "Reset" method)                                         */
+  static FT_Error
+  ps_dimension_reset_mask( PS_Dimension  dim,
+                           FT_UInt       end_point,
+                           FT_Memory     memory )
+  {
+    PS_Mask  mask;
+
+
+    /* end current mask */
+    ps_dimension_end_mask( dim, end_point );
+
+    /* allocate new one */
+    return ps_mask_table_alloc( &dim->masks, memory, &mask );
+  }
+
+
+  /* set a new mask, called from the "T2Stem" method */
+  static FT_Error
+  ps_dimension_set_mask_bits( PS_Dimension    dim,
+                              const FT_Byte*  source,
+                              FT_UInt         source_pos,
+                              FT_UInt         source_bits,
+                              FT_UInt         end_point,
+                              FT_Memory       memory )
+  {
+    FT_Error  error = 0;
+
+
+    /* reset current mask, if any */
+    error = ps_dimension_reset_mask( dim, end_point, memory );
+    if ( error )
+      goto Exit;
+
+    /* set bits in new mask */
+    error = ps_mask_table_set_bits( &dim->masks, (FT_Byte*)source,
+                                    source_pos, source_bits, memory );
+
+  Exit:
+    return error;
+  }
+
+
+  /* add a new single stem (called from "T1Stem" method) */
+  static FT_Error
+  ps_dimension_add_t1stem( PS_Dimension  dim,
+                           FT_Int        pos,
+                           FT_Int        len,
+                           FT_Memory     memory,
+                           FT_Int       *aindex )
+  {
+    FT_Error  error = 0;
+    FT_UInt   flags = 0;
+
+
+    /* detect ghost stem */
+    if ( len < 0 )
+    {
+      flags |= PS_HINT_FLAG_GHOST;
+      if ( len == -21 )
+      {
+        flags |= PS_HINT_FLAG_BOTTOM;
+        pos   += len;
+      }
+      len = 0;
+    }
+
+    if ( aindex )
+      *aindex = -1;
+
+    /* now, lookup stem in the current hints table */
+    {
+      PS_Mask  mask;
+      FT_UInt  idx;
+      FT_UInt  max   = dim->hints.num_hints;
+      PS_Hint  hint  = dim->hints.hints;
+
+
+      for ( idx = 0; idx < max; idx++, hint++ )
+      {
+        if ( hint->pos == pos && hint->len == len )
+          break;
+      }
+
+      /* we need to create a new hint in the table */
+      if ( idx >= max )
+      {
+        error = ps_hint_table_alloc( &dim->hints, memory, &hint );
+        if ( error )
+          goto Exit;
+
+        hint->pos   = pos;
+        hint->len   = len;
+        hint->flags = flags;
+      }
+
+      /* now, store the hint in the current mask */
+      error = ps_mask_table_last( &dim->masks, memory, &mask );
+      if ( error )
+        goto Exit;
+
+      error = ps_mask_set_bit( mask, idx, memory );
+      if ( error )
+        goto Exit;
+
+      if ( aindex )
+        *aindex = (FT_Int)idx;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /* add a "hstem3/vstem3" counter to our dimension table */
+  static FT_Error
+  ps_dimension_add_counter( PS_Dimension  dim,
+                            FT_Int        hint1,
+                            FT_Int        hint2,
+                            FT_Int        hint3,
+                            FT_Memory     memory )
+  {
+    FT_Error  error   = 0;
+    FT_UInt   count   = dim->counters.num_masks;
+    PS_Mask   counter = dim->counters.masks;
+
+
+    /* try to find an existing counter mask that already uses */
+    /* one of these stems here                                */
+    for ( ; count > 0; count--, counter++ )
+    {
+      if ( ps_mask_test_bit( counter, hint1 ) ||
+           ps_mask_test_bit( counter, hint2 ) ||
+           ps_mask_test_bit( counter, hint3 ) )
+        break;
+    }
+
+    /* creat a new counter when needed */
+    if ( count == 0 )
+    {
+      error = ps_mask_table_alloc( &dim->counters, memory, &counter );
+      if ( error )
+        goto Exit;
+    }
+
+    /* now, set the bits for our hints in the counter mask */
+    error = ps_mask_set_bit( counter, hint1, memory );
+    if ( error )
+      goto Exit;
+
+    error = ps_mask_set_bit( counter, hint2, memory );
+    if ( error )
+      goto Exit;
+
+    error = ps_mask_set_bit( counter, hint3, memory );
+    if ( error )
+      goto Exit;
+
+  Exit:
+    return error;
+  }
+
+
+  /* end of recording session for a given dimension */
+  static FT_Error
+  ps_dimension_end( PS_Dimension  dim,
+                    FT_UInt       end_point,
+                    FT_Memory     memory )
+  {
+    /* end hint mask table */
+    ps_dimension_end_mask( dim, end_point );
+
+    /* merge all counter masks into independent "paths" */
+    return ps_mask_table_merge_all( &dim->counters, memory );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    PS_RECORDER MANAGEMENT                     *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* destroy hints */
+  FT_LOCAL( void )
+  ps_hints_done( PS_Hints  hints )
+  {
+    FT_Memory  memory = hints->memory;
+
+
+    ps_dimension_done( &hints->dimension[0], memory );
+    ps_dimension_done( &hints->dimension[1], memory );
+
+    hints->error  = 0;
+    hints->memory = 0;
+  }
+
+
+  FT_LOCAL( FT_Error )
+  ps_hints_init( PS_Hints   hints,
+                 FT_Memory  memory )
+  {
+    FT_MEM_ZERO( hints, sizeof ( *hints ) );
+    hints->memory = memory;
+    return 0;
+  }
+
+
+  /* initialize a hints for a new session */
+  static void
+  ps_hints_open( PS_Hints      hints,
+                 PS_Hint_Type  hint_type )
+  {
+    switch ( hint_type )
+    {
+    case PS_HINT_TYPE_1:
+    case PS_HINT_TYPE_2:
+      hints->error     = 0;
+      hints->hint_type = hint_type;
+
+      ps_dimension_init( &hints->dimension[0] );
+      ps_dimension_init( &hints->dimension[1] );
+      break;
+
+    default:
+      hints->error     = FT_Err_Invalid_Argument;
+      hints->hint_type = hint_type;
+
+      FT_ERROR(( "ps_hints_open: invalid charstring type!\n" ));
+      break;
+    }
+  }
+
+
+  /* add one or more stems to the current hints table */
+  static void
+  ps_hints_stem( PS_Hints  hints,
+                 FT_Int    dimension,
+                 FT_UInt   count,
+                 FT_Long*  stems )
+  {
+    if ( !hints->error )
+    {
+      /* limit "dimension" to 0..1 */
+      if ( dimension < 0 || dimension > 1 )
+      {
+        FT_ERROR(( "ps_hints_stem: invalid dimension (%d) used\n",
+                   dimension ));
+        dimension = ( dimension != 0 );
+      }
+
+      /* record the stems in the current hints/masks table */
+      switch ( hints->hint_type )
+      {
+      case PS_HINT_TYPE_1:  /* Type 1 "hstem" or "vstem" operator */
+      case PS_HINT_TYPE_2:  /* Type 2 "hstem" or "vstem" operator */
+        {
+          PS_Dimension  dim = &hints->dimension[dimension];
+
+
+          for ( ; count > 0; count--, stems += 2 )
+          {
+            FT_Error   error;
+            FT_Memory  memory = hints->memory;
+
+
+            error = ps_dimension_add_t1stem( dim, stems[0], stems[1],
+                                             memory, NULL );
+            if ( error )
+            {
+              FT_ERROR(( "ps_hints_stem: could not add stem"
+                         " (%d,%d) to hints table\n", stems[0], stems[1] ));
+
+              hints->error = error;
+              return;
+            }
+          }
+          break;
+        }
+
+      default:
+        FT_ERROR(( "ps_hints_stem: called with invalid hint type (%d)\n",
+                   hints->hint_type ));
+        break;
+      }
+    }
+  }
+
+
+  /* add one Type1 counter stem to the current hints table */
+  static void
+  ps_hints_t1stem3( PS_Hints  hints,
+                    FT_Int    dimension,
+                    FT_Long*  stems )
+  {
+    FT_Error  error = 0;
+
+
+    if ( !hints->error )
+    {
+      PS_Dimension  dim;
+      FT_Memory     memory = hints->memory;
+      FT_Int        count;
+      FT_Int        idx[3];
+
+
+      /* limit "dimension" to 0..1 */
+      if ( dimension < 0 || dimension > 1 )
+      {
+        FT_ERROR(( "ps_hints_t1stem3: invalid dimension (%d) used\n",
+                   dimension ));
+        dimension = ( dimension != 0 );
+      }
+
+      dim = &hints->dimension[dimension];
+
+      /* there must be 6 elements in the 'stem' array */
+      if ( hints->hint_type == PS_HINT_TYPE_1 )
+      {
+        /* add the three stems to our hints/masks table */
+        for ( count = 0; count < 3; count++, stems += 2 )
+        {
+          error = ps_dimension_add_t1stem( dim, stems[0], stems[1],
+                                           memory, &idx[count] );
+          if ( error )
+            goto Fail;
+        }
+
+        /* now, add the hints to the counters table */
+        error = ps_dimension_add_counter( dim, idx[0], idx[1], idx[2],
+                                          memory );
+        if ( error )
+          goto Fail;
+      }
+      else
+      {
+        FT_ERROR(( "ps_hints_t1stem3: called with invalid hint type!\n" ));
+        error = FT_Err_Invalid_Argument;
+        goto Fail;
+      }
+    }
+
+    return;
+
+  Fail:
+    FT_ERROR(( "ps_hints_t1stem3: could not add counter stems to table\n" ));
+    hints->error = error;
+  }
+
+
+  /* reset hints (only with Type 1 hints) */
+  static void
+  ps_hints_t1reset( PS_Hints  hints,
+                    FT_UInt   end_point )
+  {
+    FT_Error  error = 0;
+
+
+    if ( !hints->error )
+    {
+      FT_Memory  memory = hints->memory;
+
+
+      if ( hints->hint_type == PS_HINT_TYPE_1 )
+      {
+        error = ps_dimension_reset_mask( &hints->dimension[0],
+                                         end_point, memory );
+        if ( error )
+          goto Fail;
+
+        error = ps_dimension_reset_mask( &hints->dimension[1],
+                                         end_point, memory );
+        if ( error )
+          goto Fail;
+      }
+      else
+      {
+        /* invalid hint type */
+        error = FT_Err_Invalid_Argument;
+        goto Fail;
+      }
+    }
+    return;
+
+  Fail:
+    hints->error = error;
+  }
+
+
+  /* Type2 "hintmask" operator, add a new hintmask to each direction */
+  static void
+  ps_hints_t2mask( PS_Hints        hints,
+                   FT_UInt         end_point,
+                   FT_UInt         bit_count,
+                   const FT_Byte*  bytes )
+  {
+    FT_Error  error;
+
+
+    if ( !hints->error )
+    {
+      PS_Dimension  dim    = hints->dimension;
+      FT_Memory     memory = hints->memory;
+      FT_UInt       count1 = dim[0].hints.num_hints;
+      FT_UInt       count2 = dim[1].hints.num_hints;
+
+
+      /* check bit count; must be equal to current total hint count */
+      if ( bit_count !=  count1 + count2 )
+      {
+        FT_ERROR(( "ps_hints_t2mask: "
+                   "called with invalid bitcount %d (instead of %d)\n",
+                   bit_count, count1 + count2 ));
+        
+        /* simply ignore the operator */
+        return;
+      }
+
+      /* set-up new horizontal and vertical hint mask now */
+      error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1,
+                                          end_point, memory );
+      if ( error )
+        goto Fail;
+
+      error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2,
+                                          end_point, memory );
+      if ( error )
+        goto Fail;
+    }
+    return;
+
+  Fail:
+    hints->error = error;
+  }
+
+
+  static void
+  ps_hints_t2counter( PS_Hints        hints,
+                      FT_UInt         bit_count,
+                      const FT_Byte*  bytes )
+  {
+    FT_Error  error;
+
+
+    if ( !hints->error )
+    {
+      PS_Dimension  dim    = hints->dimension;
+      FT_Memory     memory = hints->memory;
+      FT_UInt       count1 = dim[0].hints.num_hints;
+      FT_UInt       count2 = dim[1].hints.num_hints;
+
+
+      /* check bit count, must be equal to current total hint count */
+      if ( bit_count !=  count1 + count2 )
+      {
+        FT_ERROR(( "ps_hints_t2counter: "
+                   "called with invalid bitcount %d (instead of %d)\n",
+                   bit_count, count1 + count2 ));
+                   
+        /* simply ignore the operator */
+        return;
+      }
+
+      /* set-up new horizontal and vertical hint mask now */
+      error = ps_dimension_set_mask_bits( &dim[0], bytes, 0, count1,
+                                          0, memory );
+      if ( error )
+        goto Fail;
+
+      error = ps_dimension_set_mask_bits( &dim[1], bytes, count1, count2,
+                                          0, memory );
+      if ( error )
+        goto Fail;
+    }
+    return;
+
+  Fail:
+    hints->error = error;
+  }
+
+
+  /* end recording session */
+  static FT_Error
+  ps_hints_close( PS_Hints  hints,
+                  FT_UInt   end_point )
+  {
+    FT_Error  error;
+
+
+    error = hints->error;
+    if ( !error )
+    {
+      FT_Memory     memory = hints->memory;
+      PS_Dimension  dim    = hints->dimension;
+
+
+      error = ps_dimension_end( &dim[0], end_point, memory );
+      if ( !error )
+      {
+        error = ps_dimension_end( &dim[1], end_point, memory );
+      }
+    }
+
+#ifdef DEBUG_HINTER
+    if ( !error )
+      ps_debug_hints = hints;
+#endif
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                TYPE 1 HINTS RECORDING INTERFACE               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  t1_hints_open( T1_Hints  hints )
+  {
+    ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_1 );
+  }
+
+  static void
+  t1_hints_stem( T1_Hints  hints,
+                 FT_Int    dimension,
+                 FT_Long*  coords )
+  {
+    ps_hints_stem( (PS_Hints)hints, dimension, 1, coords );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  t1_hints_funcs_init( T1_Hints_FuncsRec*  funcs )
+  {
+    FT_MEM_ZERO( (char*)funcs, sizeof ( *funcs ) );
+
+    funcs->open  = (T1_Hints_OpenFunc)    t1_hints_open;
+    funcs->close = (T1_Hints_CloseFunc)   ps_hints_close;
+    funcs->stem  = (T1_Hints_SetStemFunc) t1_hints_stem;
+    funcs->stem3 = (T1_Hints_SetStem3Func)ps_hints_t1stem3;
+    funcs->reset = (T1_Hints_ResetFunc)   ps_hints_t1reset;
+    funcs->apply = (T1_Hints_ApplyFunc)   PS_HINTS_APPLY_FUNC;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                TYPE 2 HINTS RECORDING INTERFACE               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  t2_hints_open( T2_Hints  hints )
+  {
+    ps_hints_open( (PS_Hints)hints, PS_HINT_TYPE_2 );
+  }
+
+
+  static void
+  t2_hints_stems( T2_Hints   hints,
+                  FT_Int     dimension,
+                  FT_Int     count,
+                  FT_Fixed*  coords )
+  {
+    FT_Pos  stems[32], y, n, total = count;
+
+
+    y = 0;
+    while ( total > 0 )
+    {
+      /* determine number of stems to write */
+      count = total;
+      if ( count > 16 )
+        count = 16;
+
+      /* compute integer stem positions in font units */
+      for ( n = 0; n < count * 2; n++ )
+      {
+        y       += coords[n];
+        stems[n] = ( y + 0x8000 ) >> 16;
+      }
+
+      /* compute lengths */
+      for ( n = 0; n < count * 2; n += 2 )
+        stems[n + 1] = stems[n + 1] - stems[n];
+
+      /* add them to the current dimension */
+      ps_hints_stem( (PS_Hints)hints, dimension, count, stems );
+
+      total -= count;
+    }
+  }
+
+
+  FT_LOCAL_DEF( void )
+  t2_hints_funcs_init( T2_Hints_FuncsRec*  funcs )
+  {
+    FT_MEM_ZERO( funcs, sizeof ( *funcs ) );
+
+    funcs->open    = (T2_Hints_OpenFunc)   t2_hints_open;
+    funcs->close   = (T2_Hints_CloseFunc)  ps_hints_close;
+    funcs->stems   = (T2_Hints_StemsFunc)  t2_hints_stems;
+    funcs->hintmask= (T2_Hints_MaskFunc)   ps_hints_t2mask;
+    funcs->counter = (T2_Hints_CounterFunc)ps_hints_t2counter;
+    funcs->apply   = (T2_Hints_ApplyFunc)  PS_HINTS_APPLY_FUNC;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pshrec.h
@@ -1,0 +1,180 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pshrec.h                                                               */
+/*                                                                         */
+/*    Postscript (Type1/Type2) hints recorder (specification).             */
+/*                                                                         */
+/*  Copyright 2001, 2002 by                                                */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /**************************************************************************/
+  /*                                                                        */
+  /*  The functions defined here are called from the Type 1, CID and CFF    */
+  /*  font drivers to record the hints of a given character/glyph.          */
+  /*                                                                        */
+  /*  The hints are recorded in a unified format, and are later processed   */
+  /*  by the "optimizer" and "fitter" to adjust the outlines to the pixel   */
+  /*  grid.                                                                 */
+  /*                                                                        */
+  /**************************************************************************/
+
+
+#ifndef __PSHREC_H__
+#define __PSHREC_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+#include "pshglob.h"
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                 GLYPH HINTS RECORDER INTERNALS                *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* handle to hint record */
+  typedef struct PS_HintRec_*  PS_Hint;
+
+  /* hint types */
+  typedef enum
+  {
+    PS_HINT_TYPE_1 = 1,
+    PS_HINT_TYPE_2 = 2
+
+  } PS_Hint_Type;
+
+
+  /* hint flags */
+  typedef enum
+  {
+    PS_HINT_FLAG_GHOST  = 1,
+    PS_HINT_FLAG_BOTTOM = 2
+
+  } PS_Hint_Flags;
+
+
+  /* hint descriptor */
+  typedef struct  PS_HintRec_
+  {
+    FT_Int   pos;
+    FT_Int   len;
+    FT_UInt  flags;
+
+  } PS_HintRec;
+
+
+#define ps_hint_is_active( x )  ( (x)->flags & PS_HINT_FLAG_ACTIVE )
+#define ps_hint_is_ghost( x )   ( (x)->flags & PS_HINT_FLAG_GHOST  )
+#define ps_hint_is_bottom( x )  ( (x)->flags & PS_HINT_FLAG_BOTTOM )
+
+
+  /* hints table descriptor */
+  typedef struct  PS_Hint_TableRec_
+  {
+    FT_UInt  num_hints;
+    FT_UInt  max_hints;
+    PS_Hint  hints;
+
+  } PS_Hint_TableRec, *PS_Hint_Table;
+
+
+  /* hint and counter mask descriptor */
+  typedef struct  PS_MaskRec_
+  {
+    FT_UInt   num_bits;
+    FT_UInt   max_bits;
+    FT_Byte*  bytes;
+    FT_UInt   end_point;
+
+  } PS_MaskRec, *PS_Mask;
+
+
+  /* masks and counters table descriptor */
+  typedef struct  PS_Mask_TableRec_
+  {
+    FT_UInt  num_masks;
+    FT_UInt  max_masks;
+    PS_Mask  masks;
+
+  } PS_Mask_TableRec, *PS_Mask_Table;
+
+
+ /* dimension-specific hints descriptor */
+  typedef struct  PS_DimensionRec_
+  {
+    PS_Hint_TableRec  hints;
+    PS_Mask_TableRec  masks;
+    PS_Mask_TableRec  counters;
+
+  } PS_DimensionRec, *PS_Dimension;
+
+
+  /* magic value used within PS_HintsRec */
+#define PS_HINTS_MAGIC  0x68696e74   /* "hint" */
+
+
+  /* glyph hints descriptor                                */
+  /* dimension 0 => X coordinates + vertical hints/stems   */
+  /* dimension 1 => Y coordinates + horizontal hints/stems */
+  typedef struct  PS_HintsRec_
+  {
+    FT_Memory        memory;
+    FT_Error         error;
+    FT_UInt32        magic;
+    PS_Hint_Type     hint_type;
+    PS_DimensionRec  dimension[2];
+
+  } PS_HintsRec, *PS_Hints;
+
+  /* */
+
+  /* initialize hints recorder */
+  FT_LOCAL( FT_Error )
+  ps_hints_init( PS_Hints   hints,
+                 FT_Memory  memory );
+
+  /* finalize hints recorder */
+  FT_LOCAL( void )
+  ps_hints_done( PS_Hints  hints );
+
+  /* initialize Type1 hints recorder interface */
+  FT_LOCAL( void )
+  t1_hints_funcs_init( T1_Hints_FuncsRec*  funcs );
+
+  /* initialize Type2 hints recorder interface */
+  FT_LOCAL( void )
+  t2_hints_funcs_init( T2_Hints_FuncsRec*  funcs );
+
+
+#ifdef DEBUG_HINTER
+  extern PS_Hints  ps_debug_hints;
+  extern  int      ps_debug_no_horz_hints;
+  extern  int      ps_debug_no_vert_hints;
+#endif
+
+ /* */
+
+
+FT_END_HEADER
+
+
+#endif /* __PS_HINTER_RECORD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psmodule.c
@@ -1,0 +1,357 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psmodule.c                                                             */
+/*                                                                         */
+/*    PSNames module implementation (body).                                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "psmodule.h"
+#include "pstables.h"
+
+#include "psnamerr.h"
+
+
+#ifndef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES
+
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+
+  /* return the Unicode value corresponding to a given glyph.  Note that */
+  /* we do deal with glyph variants by detecting a non-initial dot in    */
+  /* the name, as in `A.swash' or `e.final', etc.                        */
+  /*                                                                     */
+  static FT_UInt32
+  ps_unicode_value( const char*  glyph_name )
+  {
+    FT_Int  n;
+    char    first = glyph_name[0];
+    char    temp[64];
+
+
+    /* if the name begins with `uni', then the glyph name may be a */
+    /* hard-coded unicode character code.                          */
+    if ( glyph_name[0] == 'u' &&
+         glyph_name[1] == 'n' &&
+         glyph_name[2] == 'i' )
+    {
+      /* determine whether the next four characters following are */
+      /* hexadecimal.                                             */
+
+      /* XXX: Add code to deal with ligatures, i.e. glyph names like */
+      /*      `uniXXXXYYYYZZZZ'...                                   */
+
+      FT_Int       count;
+      FT_ULong     value = 0;
+      const char*  p     = glyph_name + 3;
+
+
+      for ( count = 4; count > 0; count--, p++ )
+      {
+        char          c = *p;
+        unsigned int  d;
+
+
+        d = (unsigned char)c - '0';
+        if ( d >= 10 )
+        {
+          d = (unsigned char)c - 'A';
+          if ( d >= 6 )
+            d = 16;
+          else
+            d += 10;
+        }
+
+        /* exit if a non-uppercase hexadecimal character was found */
+        if ( d >= 16 )
+          break;
+
+        value = ( value << 4 ) + d;
+      }
+      if ( count == 0 )
+        return value;
+    }
+
+    /* look for a non-initial dot in the glyph name in order to */
+    /* sort-out variants like `A.swash', `e.final', etc.        */
+    {
+      const char*  p;
+      int          len;
+
+
+      p = glyph_name;
+
+      while ( *p && *p != '.' )
+        p++;
+
+      len = (int)( p - glyph_name );
+
+      if ( *p && len < 64 )
+      {
+        ft_strncpy( temp, glyph_name, len );
+        temp[len]  = 0;
+        glyph_name = temp;
+      }
+    }
+
+    /* now, look up the glyph in the Adobe Glyph List */
+    for ( n = 0; n < NUM_ADOBE_GLYPHS; n++ )
+    {
+      const char*  name = sid_standard_names[n];
+
+
+      if ( first == name[0] && ft_strcmp( glyph_name, name ) == 0 )
+        return ps_names_to_unicode[n];
+    }
+
+    /* not found, there is probably no Unicode value for this glyph name */
+    return 0;
+  }
+
+
+  /* ft_qsort callback to sort the unicode map */
+  FT_CALLBACK_DEF( int )
+  compare_uni_maps( const void*  a,
+                    const void*  b )
+  {
+    PS_UniMap*  map1 = (PS_UniMap*)a;
+    PS_UniMap*  map2 = (PS_UniMap*)b;
+
+
+    return ( map1->unicode - map2->unicode );
+  }
+
+
+  /* Builds a table that maps Unicode values to glyph indices */
+  static FT_Error
+  ps_build_unicode_table( FT_Memory     memory,
+                          FT_UInt       num_glyphs,
+                          const char**  glyph_names,
+                          PS_Unicodes*  table )
+  {
+    FT_Error  error;
+
+
+    /* we first allocate the table */
+    table->num_maps = 0;
+    table->maps     = 0;
+
+    if ( !FT_NEW_ARRAY( table->maps, num_glyphs ) )
+    {
+      FT_UInt     n;
+      FT_UInt     count;
+      PS_UniMap*  map;
+      FT_UInt32   uni_char;
+
+
+      map = table->maps;
+
+      for ( n = 0; n < num_glyphs; n++ )
+      {
+        const char*  gname = glyph_names[n];
+
+
+        if ( gname )
+        {
+          uni_char = ps_unicode_value( gname );
+
+          if ( uni_char != 0 && uni_char != 0xFFFF )
+          {
+            map->unicode     = uni_char;
+            map->glyph_index = n;
+            map++;
+          }
+        }
+      }
+
+      /* now, compress the table a bit */
+      count = (FT_UInt)( map - table->maps );
+
+      if ( count > 0 && FT_REALLOC( table->maps,
+                                    num_glyphs * sizeof ( PS_UniMap ),
+                                    count * sizeof ( PS_UniMap ) ) )
+        count = 0;
+
+      if ( count == 0 )
+      {
+        FT_FREE( table->maps );
+        if ( !error )
+          error = PSnames_Err_Invalid_Argument;  /* no unicode chars here! */
+      }
+      else
+        /* sort the table in increasing order of unicode values */
+        ft_qsort( table->maps, count, sizeof ( PS_UniMap ), compare_uni_maps );
+
+      table->num_maps = count;
+    }
+
+    return error;
+  }
+
+
+  static FT_UInt
+  ps_lookup_unicode( PS_Unicodes*  table,
+                     FT_ULong      unicode )
+  {
+    PS_UniMap  *min, *max, *mid;
+
+
+    /* perform a binary search on the table */
+
+    min = table->maps;
+    max = min + table->num_maps - 1;
+
+    while ( min <= max )
+    {
+      mid = min + ( max - min ) / 2;
+      if ( mid->unicode == unicode )
+        return mid->glyph_index;
+
+      if ( min == max )
+        break;
+
+      if ( mid->unicode < unicode )
+        min = mid + 1;
+      else
+        max = mid - 1;
+    }
+
+    return 0xFFFF;
+  }
+
+
+  static FT_ULong
+  ps_next_unicode( PS_Unicodes*  table,
+                   FT_ULong      unicode )
+  {
+    PS_UniMap  *min, *max, *mid;
+
+
+    unicode++;
+    /* perform a binary search on the table */
+
+    min = table->maps;
+    max = min + table->num_maps - 1;
+
+    while ( min <= max )
+    {
+      mid = min + ( max - min ) / 2;
+      if ( mid->unicode == unicode )
+        return unicode;
+
+      if ( min == max )
+        break;
+
+      if ( mid->unicode < unicode )
+        min = mid + 1;
+      else
+        max = mid - 1;
+    }
+
+    if ( max < table->maps )
+      max = table->maps;
+
+    while ( max < table->maps + table->num_maps )
+    {
+      if ( unicode < max->unicode )
+        return max->unicode;
+      max++;
+    }
+
+    return 0;
+  }
+
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+
+  static const char*
+  ps_get_macintosh_name( FT_UInt  name_index )
+  {
+    if ( name_index >= 258 )
+      name_index = 0;
+
+    return ps_glyph_names[mac_standard_names[name_index]];
+  }
+
+
+  static const char*
+  ps_get_standard_strings( FT_UInt  sid )
+  {
+    return ( sid < NUM_SID_GLYPHS ? sid_standard_names[sid] : 0 );
+  }
+
+
+  static
+  const PSNames_Interface  psnames_interface =
+  {
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+    (PS_Unicode_Value_Func)    ps_unicode_value,
+    (PS_Build_Unicodes_Func)   ps_build_unicode_table,
+    (PS_Lookup_Unicode_Func)   ps_lookup_unicode,
+
+#else
+
+    0,
+    0,
+    0,
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+    (PS_Macintosh_Name_Func)    ps_get_macintosh_name,
+    (PS_Adobe_Std_Strings_Func) ps_get_standard_strings,
+
+    t1_standard_encoding,
+    t1_expert_encoding,
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+    (PS_Next_Unicode_Func)     ps_next_unicode
+#else
+    0
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+  };
+
+
+#endif /* !FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES */
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Module_Class  psnames_module_class =
+  {
+    0,  /* this is not a font driver, nor a renderer */
+    sizeof ( FT_ModuleRec ),
+
+    "psnames",  /* driver name                         */
+    0x10000L,   /* driver version                      */
+    0x20000L,   /* driver requires FreeType 2 or above */
+
+#ifdef FT_CONFIG_OPTION_NO_POSTSCRIPT_NAMES
+    0,
+#else
+    (void*)&psnames_interface,   /* module specific interface */
+#endif
+
+    (FT_Module_Constructor)0,
+    (FT_Module_Destructor) 0,
+    (FT_Module_Requester)  0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psmodule.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psmodule.h                                                             */
+/*                                                                         */
+/*    High-level PSNames module interface (specification).                 */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSMODULE_H__
+#define __PSMODULE_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Module_Class )  psnames_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __PSMODULE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psnamerr.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psnamerr.h                                                             */
+/*                                                                         */
+/*    PS names module error codes (specification only).                    */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the PS names module error enumeration     */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __PSNAMERR_H__
+#define __PSNAMERR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  PSnames_Err_
+#define FT_ERR_BASE    FT_Mod_Err_PSnames
+
+#include FT_ERRORS_H
+
+#endif /* __PSNAMERR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psnames.c
@@ -1,0 +1,25 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psnames.c                                                              */
+/*                                                                         */
+/*    FreeType PSNames module component (body only).                       */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "psmodule.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psobjs.c
@@ -1,0 +1,1403 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psobjs.c                                                               */
+/*                                                                         */
+/*    Auxiliary functions for PostScript fonts (body).                     */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "psobjs.h"
+
+#include "psauxerr.h"
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                             PS_TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ps_table_new                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a PS_Table.                                            */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    table  :: The address of the target table.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    count  :: The table size = the maximum number of elements.         */
+  /*                                                                       */
+  /*    memory :: The memory object to use for all subsequent              */
+  /*              reallocations.                                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  ps_table_new( PS_Table   table,
+                FT_Int     count,
+                FT_Memory  memory )
+  {
+    FT_Error  error;
+
+
+    table->memory = memory;
+    if ( FT_NEW_ARRAY( table->elements, count ) ||
+         FT_NEW_ARRAY( table->lengths,  count ) )
+      goto Exit;
+
+    table->max_elems = count;
+    table->init      = 0xDEADBEEFUL;
+    table->num_elems = 0;
+    table->block     = 0;
+    table->capacity  = 0;
+    table->cursor    = 0;
+
+    *(PS_Table_FuncsRec*)&table->funcs = ps_table_funcs;
+
+  Exit:
+    if ( error )
+      FT_FREE( table->elements );
+
+    return error;
+  }
+
+
+  static void
+  shift_elements( PS_Table  table,
+                  FT_Byte*  old_base )
+  {
+    FT_Long    delta  = (FT_Long)( table->block - old_base );
+    FT_Byte**  offset = table->elements;
+    FT_Byte**  limit  = offset + table->max_elems;
+
+
+    for ( ; offset < limit; offset++ )
+    {
+      if ( offset[0] )
+        offset[0] += delta;
+    }
+  }
+
+
+  static FT_Error
+  reallocate_t1_table( PS_Table  table,
+                       FT_Long   new_size )
+  {
+    FT_Memory  memory   = table->memory;
+    FT_Byte*   old_base = table->block;
+    FT_Error   error;
+
+
+    /* allocate new base block */
+    if ( FT_ALLOC( table->block, new_size ) )
+      return error;
+
+    /* copy elements and shift offsets */
+    if (old_base )
+    {
+      FT_MEM_COPY( table->block, old_base, table->capacity );
+      shift_elements( table, old_base );
+      FT_FREE( old_base );
+    }
+
+    table->capacity = new_size;
+
+    return PSaux_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ps_table_add                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Adds an object to a PS_Table, possibly growing its memory block.   */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    table  :: The target table.                                        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    idx  :: The index of the object in the table.                      */
+  /*                                                                       */
+  /*    object :: The address of the object to copy in memory.             */
+  /*                                                                       */
+  /*    length :: The length in bytes of the source object.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.  An error is returned if a  */
+  /*    reallocation fails.                                                */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  ps_table_add( PS_Table  table,
+                FT_Int    idx,
+                void*     object,
+                FT_Int    length )
+  {
+    if ( idx < 0 || idx > table->max_elems )
+    {
+      FT_ERROR(( "ps_table_add: invalid index\n" ));
+      return PSaux_Err_Invalid_Argument;
+    }
+
+    /* grow the base block if needed */
+    if ( table->cursor + length > table->capacity )
+    {
+      FT_Error   error;
+      FT_Offset  new_size  = table->capacity;
+      FT_Long    in_offset;
+
+
+      in_offset = (FT_Long)((FT_Byte*)object - table->block);
+      if ( (FT_ULong)in_offset >= table->capacity )
+        in_offset = -1;
+
+      while ( new_size < table->cursor + length )
+      {
+        /* increase size by 25% and round up to the nearest multiple of 1024 */
+        new_size += (new_size >> 2) + 1;
+        new_size  = ( new_size + 1023 ) & -1024;
+      }
+
+      error = reallocate_t1_table( table, new_size );
+      if ( error )
+        return error;
+
+      if ( in_offset >= 0 )
+        object = table->block + in_offset;
+    }
+
+    /* add the object to the base block and adjust offset */
+    table->elements[idx] = table->block + table->cursor;
+    table->lengths [idx] = length;
+    FT_MEM_COPY( table->block + table->cursor, object, length );
+
+    table->cursor += length;
+    return PSaux_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    ps_table_done                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a PS_TableRec (i.e., reallocate it to its current        */
+  /*    cursor).                                                           */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    table :: The target table.                                         */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This function does NOT release the heap's memory block.  It is up  */
+  /*    to the caller to clean it, or reference it in its own structures.  */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  ps_table_done( PS_Table  table )
+  {
+    FT_Memory  memory = table->memory;
+    FT_Error   error;
+    FT_Byte*   old_base = table->block;
+
+
+    /* should never fail, because rec.cursor <= rec.size */
+    if ( !old_base )
+      return;
+
+    if ( FT_ALLOC( table->block, table->cursor ) )
+      return;
+    FT_MEM_COPY( table->block, old_base, table->cursor );
+    shift_elements( table, old_base );
+
+    table->capacity = table->cursor;
+    FT_FREE( old_base );
+
+    FT_UNUSED( error );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ps_table_release( PS_Table  table )
+  {
+    FT_Memory  memory = table->memory;
+
+
+    if ( (FT_ULong)table->init == 0xDEADBEEFUL )
+    {
+      FT_FREE( table->block );
+      FT_FREE( table->elements );
+      FT_FREE( table->lengths );
+      table->init = 0;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                            T1 PARSER                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+#define IS_T1_WHITESPACE( c )  ( (c) == ' '  || (c) == '\t' )
+#define IS_T1_LINESPACE( c )   ( (c) == '\r' || (c) == '\n' )
+
+#define IS_T1_SPACE( c )  ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
+
+
+  FT_LOCAL_DEF( void )
+  ps_parser_skip_spaces( PS_Parser  parser )
+  {
+    FT_Byte* cur   = parser->cursor;
+    FT_Byte* limit = parser->limit;
+
+
+    while ( cur < limit )
+    {
+      FT_Byte  c = *cur;
+
+
+      if ( !IS_T1_SPACE( c ) )
+        break;
+      cur++;
+    }
+    parser->cursor = cur;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ps_parser_skip_alpha( PS_Parser  parser )
+  {
+    FT_Byte* cur   = parser->cursor;
+    FT_Byte* limit = parser->limit;
+
+
+    while ( cur < limit )
+    {
+      FT_Byte  c = *cur;
+
+
+      if ( IS_T1_SPACE( c ) )
+        break;
+      cur++;
+    }
+    parser->cursor = cur;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ps_parser_to_token( PS_Parser  parser,
+                      T1_Token   token )
+  {
+    FT_Byte*  cur;
+    FT_Byte*  limit;
+    FT_Byte   starter, ender;
+    FT_Int    embed;
+
+
+    token->type  = T1_TOKEN_TYPE_NONE;
+    token->start = 0;
+    token->limit = 0;
+
+    /* first of all, skip space */
+    ps_parser_skip_spaces( parser );
+
+    cur   = parser->cursor;
+    limit = parser->limit;
+
+    if ( cur < limit )
+    {
+      switch ( *cur )
+      {
+        /************* check for strings ***********************/
+      case '(':
+        token->type = T1_TOKEN_TYPE_STRING;
+        ender = ')';
+        goto Lookup_Ender;
+
+        /************* check for programs/array ****************/
+      case '{':
+        token->type = T1_TOKEN_TYPE_ARRAY;
+        ender = '}';
+        goto Lookup_Ender;
+
+        /************* check for table/array ******************/
+      case '[':
+        token->type = T1_TOKEN_TYPE_ARRAY;
+        ender = ']';
+
+      Lookup_Ender:
+        embed   = 1;
+        starter = *cur++;
+        token->start = cur;
+        while ( cur < limit )
+        {
+          if ( *cur == starter )
+            embed++;
+          else if ( *cur == ender )
+          {
+            embed--;
+            if ( embed <= 0 )
+            {
+              token->limit = cur++;
+              break;
+            }
+          }
+          cur++;
+        }
+        break;
+
+        /* **************** otherwise, it's any token **********/
+      default:
+        token->start = cur++;
+        token->type  = T1_TOKEN_TYPE_ANY;
+        while ( cur < limit && !IS_T1_SPACE( *cur ) )
+          cur++;
+
+        token->limit = cur;
+      }
+
+      if ( !token->limit )
+      {
+        token->start = 0;
+        token->type  = T1_TOKEN_TYPE_NONE;
+      }
+
+      parser->cursor = cur;
+    }
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ps_parser_to_token_array( PS_Parser  parser,
+                            T1_Token   tokens,
+                            FT_UInt    max_tokens,
+                            FT_Int*    pnum_tokens )
+  {
+    T1_TokenRec  master;
+
+
+    *pnum_tokens = -1;
+
+    ps_parser_to_token( parser, &master );
+    if ( master.type == T1_TOKEN_TYPE_ARRAY )
+    {
+      FT_Byte*  old_cursor = parser->cursor;
+      FT_Byte*  old_limit  = parser->limit;
+      T1_Token  cur        = tokens;
+      T1_Token  limit      = cur + max_tokens;
+
+
+      parser->cursor = master.start;
+      parser->limit  = master.limit;
+
+      while ( parser->cursor < parser->limit )
+      {
+        T1_TokenRec  token;
+
+
+        ps_parser_to_token( parser, &token );
+        if ( !token.type )
+          break;
+
+        if ( cur < limit )
+          *cur = token;
+
+        cur++;
+      }
+
+      *pnum_tokens = (FT_Int)( cur - tokens );
+
+      parser->cursor = old_cursor;
+      parser->limit  = old_limit;
+    }
+  }
+
+
+  static FT_Long
+  T1Radix( FT_Long    radixBase,
+           FT_Byte**  cur,
+           FT_Byte*   limit )
+  {
+    FT_Long  result = 0;
+    FT_Byte  radixEndChar0 =
+               (FT_Byte)( radixBase > 10 ? '9' + 1 : '0' + radixBase );
+    FT_Byte  radixEndChar1 =
+               (FT_Byte)( 'A' + radixBase - 10 );
+    FT_Byte  radixEndChar2 =
+               (FT_Byte)( 'a' + radixBase - 10 );
+
+
+    while( *cur < limit )
+    {
+      if ( (*cur)[0] >= '0' && (*cur)[0] < radixEndChar0 )
+        result = result * radixBase + (*cur)[0] - '0';
+
+      else if ( radixBase > 10 &&
+                (*cur)[0] >= 'A' && (*cur)[0] < radixEndChar1 )
+        result = result * radixBase + ( (*cur)[0] - 'A' + 10 );
+
+      else if ( radixBase > 10 &&
+                (*cur)[0] >= 'a' && (*cur)[0] < radixEndChar2 )
+        result = result * radixBase + ( (*cur)[0] - 'a' + 10 );
+
+      else
+        return result;
+
+      (*cur)++;
+    }
+
+    return result;
+  }
+
+
+  static FT_Long
+  t1_toint( FT_Byte**  cursor,
+            FT_Byte*   limit )
+  {
+    FT_Long   result = 0;
+    FT_Byte*  cur    = *cursor;
+    FT_Byte   c      = '\0', d;
+
+
+    for ( ; cur < limit; cur++ )
+    {
+      c = *cur;
+      d = (FT_Byte)( c - '0' );
+      if ( d < 10 )
+        break;
+
+      if ( c == '-' )
+      {
+        cur++;
+        break;
+      }
+    }
+
+    if ( cur < limit )
+    {
+      do
+      {
+        d = (FT_Byte)( cur[0] - '0' );
+        if ( d >= 10 )
+        {
+          if ( cur[0] == '#' )
+          {
+            cur++;
+            result = T1Radix( result, &cur, limit );
+          }
+          break;
+        }
+
+        result = result * 10 + d;
+        cur++;
+
+      } while ( cur < limit );
+
+      if ( c == '-' )
+        result = -result;
+    }
+
+    *cursor = cur;
+    return result;
+  }
+
+
+  static FT_Long
+  t1_tofixed( FT_Byte**  cursor,
+              FT_Byte*   limit,
+              FT_Long    power_ten )
+  {
+    FT_Byte*  cur  = *cursor;
+    FT_Long   num, divider, result;
+    FT_Int    sign = 0;
+    FT_Byte   d;
+
+
+    if ( cur >= limit )
+      return 0;
+
+    /* first of all, check the sign */
+    if ( *cur == '-' )
+    {
+      sign = 1;
+      cur++;
+    }
+
+    /* then, read the integer part, if any */
+    if ( *cur != '.' )
+      result = t1_toint( &cur, limit ) << 16;
+    else
+      result = 0;
+
+    num     = 0;
+    divider = 1;
+
+    if ( cur >= limit )
+      goto Exit;
+
+    /* read decimal part, if any */
+    if ( *cur == '.' && cur + 1 < limit )
+    {
+      cur++;
+
+      for (;;)
+      {
+        d = (FT_Byte)( *cur - '0' );
+        if ( d >= 10 )
+          break;
+
+        if ( divider < 10000000L )
+        {
+          num      = num * 10 + d;
+          divider *= 10;
+        }
+
+        cur++;
+        if ( cur >= limit )
+          break;
+      }
+    }
+
+    /* read exponent, if any */
+    if ( cur + 1 < limit && ( *cur == 'e' || *cur == 'E' ) )
+    {
+      cur++;
+      power_ten += t1_toint( &cur, limit );
+    }
+
+  Exit:
+    /* raise to power of ten if needed */
+    while ( power_ten > 0 )
+    {
+      result = result * 10;
+      num    = num * 10;
+      power_ten--;
+    }
+
+    while ( power_ten < 0 )
+    {
+      result  = result / 10;
+      divider = divider * 10;
+      power_ten++;
+    }
+
+    if ( num )
+      result += FT_DivFix( num, divider );
+
+    if ( sign )
+      result = -result;
+
+    *cursor = cur;
+    return result;
+  }
+
+
+  static FT_Int
+  t1_tocoordarray( FT_Byte**  cursor,
+                   FT_Byte*   limit,
+                   FT_Int     max_coords,
+                   FT_Short*  coords )
+  {
+    FT_Byte*  cur   = *cursor;
+    FT_Int    count = 0;
+    FT_Byte   c, ender;
+
+
+    if ( cur >= limit )
+      goto Exit;
+
+    /* check for the beginning of an array; if not, only one number will */
+    /* be read                                                           */
+    c     = *cur;
+    ender = 0;
+
+    if ( c == '[' )
+      ender = ']';
+
+    if ( c == '{' )
+      ender = '}';
+
+    if ( ender )
+      cur++;
+
+    /* now, read the coordinates */
+    for ( ; cur < limit; )
+    {
+      /* skip whitespace in front of data */
+      for (;;)
+      {
+        c = *cur;
+        if ( c != ' ' && c != '\t' )
+          break;
+
+        cur++;
+        if ( cur >= limit )
+          goto Exit;
+      }
+
+      if ( count >= max_coords || c == ender )
+        break;
+
+      coords[count] = (FT_Short)( t1_tofixed( &cur, limit, 0 ) >> 16 );
+      count++;
+
+      if ( !ender )
+        break;
+    }
+
+  Exit:
+    *cursor = cur;
+    return count;
+  }
+
+
+  static FT_Int
+  t1_tofixedarray( FT_Byte**  cursor,
+                   FT_Byte*   limit,
+                   FT_Int     max_values,
+                   FT_Fixed*  values,
+                   FT_Int     power_ten )
+  {
+    FT_Byte*  cur   = *cursor;
+    FT_Int    count = 0;
+    FT_Byte   c, ender;
+
+
+    if ( cur >= limit ) goto Exit;
+
+    /* check for the beginning of an array. If not, only one number will */
+    /* be read                                                           */
+    c     = *cur;
+    ender = 0;
+
+    if ( c == '[' )
+      ender = ']';
+
+    if ( c == '{' )
+      ender = '}';
+
+    if ( ender )
+      cur++;
+
+    /* now, read the values */
+    for ( ; cur < limit; )
+    {
+      /* skip whitespace in front of data */
+      for (;;)
+      {
+        c = *cur;
+        if ( c != ' ' && c != '\t' )
+          break;
+
+        cur++;
+        if ( cur >= limit )
+          goto Exit;
+      }
+
+      if ( count >= max_values || c == ender )
+        break;
+
+      values[count] = t1_tofixed( &cur, limit, power_ten );
+      count++;
+
+      if ( !ender )
+        break;
+    }
+
+  Exit:
+    *cursor = cur;
+    return count;
+  }
+
+
+#if 0
+
+  static FT_String*
+  t1_tostring( FT_Byte**  cursor,
+               FT_Byte*   limit,
+               FT_Memory  memory )
+  {
+    FT_Byte*    cur = *cursor;
+    FT_PtrDist  len = 0;
+    FT_Int      count;
+    FT_String*  result;
+    FT_Error    error;
+
+
+    /* XXX: some stupid fonts have a `Notice' or `Copyright' string     */
+    /*      that simply doesn't begin with an opening parenthesis, even */
+    /*      though they have a closing one!  E.g. "amuncial.pfb"        */
+    /*                                                                  */
+    /*      We must deal with these ill-fated cases there.  Note that   */
+    /*      these fonts didn't work with the old Type 1 driver as the   */
+    /*      notice/copyright was not recognized as a valid string token */
+    /*      and made the old token parser commit errors.                */
+
+    while ( cur < limit && ( *cur == ' ' || *cur == '\t' ) )
+      cur++;
+    if ( cur + 1 >= limit )
+      return 0;
+
+    if ( *cur == '(' )
+      cur++;  /* skip the opening parenthesis, if there is one */
+
+    *cursor = cur;
+    count   = 0;
+
+    /* then, count its length */
+    for ( ; cur < limit; cur++ )
+    {
+      if ( *cur == '(' )
+        count++;
+
+      else if ( *cur == ')' )
+      {
+        count--;
+        if ( count < 0 )
+          break;
+      }
+    }
+
+    len = cur - *cursor;
+    if ( cur >= limit || FT_ALLOC( result, len + 1 ) )
+      return 0;
+
+    /* now copy the string */
+    FT_MEM_COPY( result, *cursor, len );
+    result[len] = '\0';
+    *cursor = cur;
+    return result;
+  }
+
+#endif /* 0 */
+
+
+  static int
+  t1_tobool( FT_Byte**  cursor,
+             FT_Byte*   limit )
+  {
+    FT_Byte*  cur    = *cursor;
+    FT_Bool   result = 0;
+
+
+    /* return 1 if we find `true', 0 otherwise */
+    if ( cur + 3 < limit &&
+         cur[0] == 't' &&
+         cur[1] == 'r' &&
+         cur[2] == 'u' &&
+         cur[3] == 'e' )
+    {
+      result = 1;
+      cur   += 5;
+    }
+    else if ( cur + 4 < limit &&
+              cur[0] == 'f' &&
+              cur[1] == 'a' &&
+              cur[2] == 'l' &&
+              cur[3] == 's' &&
+              cur[4] == 'e' )
+    {
+      result = 0;
+      cur   += 6;
+    }
+
+    *cursor = cur;
+    return result;
+  }
+
+
+  /* Load a simple field (i.e. non-table) into the current list of objects */
+  FT_LOCAL_DEF( FT_Error )
+  ps_parser_load_field( PS_Parser       parser,
+                        const T1_Field  field,
+                        void**          objects,
+                        FT_UInt         max_objects,
+                        FT_ULong*       pflags )
+  {
+    T1_TokenRec  token;
+    FT_Byte*     cur;
+    FT_Byte*     limit;
+    FT_UInt      count;
+    FT_UInt      idx;
+    FT_Error     error;
+
+
+    ps_parser_to_token( parser, &token );
+    if ( !token.type )
+      goto Fail;
+
+    count = 1;
+    idx   = 0;
+    cur   = token.start;
+    limit = token.limit;
+
+    /* we must detect arrays */
+    if ( field->type == T1_FIELD_TYPE_BBOX )
+    {
+      T1_TokenRec  token2;
+      FT_Byte*     old_cur   = parser->cursor;
+      FT_Byte*     old_limit = parser->limit;
+
+
+      parser->cursor = token.start;
+      parser->limit  = token.limit;
+
+      ps_parser_to_token( parser, &token2 );
+      parser->cursor = old_cur;
+      parser->limit  = old_limit;
+
+      if ( token2.type == T1_TOKEN_TYPE_ARRAY )
+        goto FieldArray;
+    }
+    else if ( token.type == T1_TOKEN_TYPE_ARRAY )
+    {
+    FieldArray:
+      /* if this is an array, and we have no blend, an error occurs */
+      if ( max_objects == 0 )
+        goto Fail;
+
+      count = max_objects;
+      idx = 1;
+    }
+
+    for ( ; count > 0; count--, idx++ )
+    {
+      FT_Byte*    q = (FT_Byte*)objects[idx] + field->offset;
+      FT_Long     val;
+      FT_String*  string;
+
+
+      switch ( field->type )
+      {
+      case T1_FIELD_TYPE_BOOL:
+        val = t1_tobool( &cur, limit );
+        goto Store_Integer;
+
+      case T1_FIELD_TYPE_FIXED:
+        val = t1_tofixed( &cur, limit, 3 );
+        goto Store_Integer;
+
+      case T1_FIELD_TYPE_INTEGER:
+        val = t1_toint( &cur, limit );
+
+      Store_Integer:
+        switch ( field->size )
+        {
+        case 1:
+          *(FT_Byte*)q = (FT_Byte)val;
+          break;
+
+        case 2:
+          *(FT_UShort*)q = (FT_UShort)val;
+          break;
+
+        case 4:
+          *(FT_UInt32*)q = (FT_UInt32)val;
+          break;
+
+        default:                /* for 64-bit systems */
+          *(FT_Long*)q = val;
+        }
+        break;
+
+      case T1_FIELD_TYPE_STRING:
+        {
+          FT_Memory  memory = parser->memory;
+          FT_UInt    len    = (FT_UInt)( limit - cur );
+
+
+          if ( *(FT_String**)q )
+            /* with synthetic fonts, it's possible to find a field twice */
+            break;
+
+          if ( FT_ALLOC( string, len + 1 ) )
+            goto Exit;
+
+          FT_MEM_COPY( string, cur, len );
+          string[len] = 0;
+
+          *(FT_String**)q = string;
+        }
+        break;
+
+      case T1_FIELD_TYPE_BBOX:
+        {
+          FT_Fixed  temp[4];
+          FT_BBox*  bbox = (FT_BBox*)q;
+
+
+          /* we need the '[' and ']' delimiters */
+          token.start--;
+          token.limit++;
+          (void)t1_tofixedarray( &token.start, token.limit, 4, temp, 0 );
+
+          bbox->xMin = FT_RoundFix( temp[0] );
+          bbox->yMin = FT_RoundFix( temp[1] );
+          bbox->xMax = FT_RoundFix( temp[2] );
+          bbox->yMax = FT_RoundFix( temp[3] );
+        }
+        break;
+
+      default:
+        /* an error occured */
+        goto Fail;
+      }
+    }
+
+#if 0  /* obsolete - keep for reference */
+    if ( pflags )
+      *pflags |= 1L << field->flag_bit;
+#else
+    FT_UNUSED( pflags );
+#endif
+
+    error = PSaux_Err_Ok;
+
+  Exit:
+    return error;
+
+  Fail:
+    error = PSaux_Err_Invalid_File_Format;
+    goto Exit;
+  }
+
+
+#define T1_MAX_TABLE_ELEMENTS  32
+
+
+  FT_LOCAL_DEF( FT_Error )
+  ps_parser_load_field_table( PS_Parser       parser,
+                              const T1_Field  field,
+                              void**          objects,
+                              FT_UInt         max_objects,
+                              FT_ULong*       pflags )
+  {
+    T1_TokenRec  elements[T1_MAX_TABLE_ELEMENTS];
+    T1_Token     token;
+    FT_Int       num_elements;
+    FT_Error     error = 0;
+    FT_Byte*     old_cursor;
+    FT_Byte*     old_limit;
+    T1_FieldRec  fieldrec = *(T1_Field)field;
+
+
+#if 1
+    fieldrec.type = T1_FIELD_TYPE_INTEGER;
+    if ( field->type == T1_FIELD_TYPE_FIXED_ARRAY )
+      fieldrec.type = T1_FIELD_TYPE_FIXED;
+#endif
+
+    ps_parser_to_token_array( parser, elements, 32, &num_elements );
+    if ( num_elements < 0 )
+      goto Fail;
+
+    if ( num_elements > T1_MAX_TABLE_ELEMENTS )
+      num_elements = T1_MAX_TABLE_ELEMENTS;
+
+    old_cursor = parser->cursor;
+    old_limit  = parser->limit;
+
+    /* we store the elements count */
+    *(FT_Byte*)( (FT_Byte*)objects[0] + field->count_offset ) =
+      (FT_Byte)num_elements;
+
+    /* we now load each element, adjusting the field.offset on each one */
+    token = elements;
+    for ( ; num_elements > 0; num_elements--, token++ )
+    {
+      parser->cursor = token->start;
+      parser->limit  = token->limit;
+      ps_parser_load_field( parser, &fieldrec, objects, max_objects, 0 );
+      fieldrec.offset += fieldrec.size;
+    }
+
+#if 0  /* obsolete -- keep for reference */
+    if ( pflags )
+      *pflags |= 1L << field->flag_bit;
+#else
+    FT_UNUSED( pflags );
+#endif
+
+    parser->cursor = old_cursor;
+    parser->limit  = old_limit;
+
+  Exit:
+    return error;
+
+  Fail:
+    error = PSaux_Err_Invalid_File_Format;
+    goto Exit;
+  }
+
+
+  FT_LOCAL_DEF( FT_Long )
+  ps_parser_to_int( PS_Parser  parser )
+  {
+    return t1_toint( &parser->cursor, parser->limit );
+  }
+
+
+  FT_LOCAL_DEF( FT_Fixed )
+  ps_parser_to_fixed( PS_Parser  parser,
+                      FT_Int     power_ten )
+  {
+    return t1_tofixed( &parser->cursor, parser->limit, power_ten );
+  }
+
+
+  FT_LOCAL_DEF( FT_Int )
+  ps_parser_to_coord_array( PS_Parser  parser,
+                            FT_Int     max_coords,
+                            FT_Short*  coords )
+  {
+    return t1_tocoordarray( &parser->cursor, parser->limit,
+                            max_coords, coords );
+  }
+
+
+  FT_LOCAL_DEF( FT_Int )
+  ps_parser_to_fixed_array( PS_Parser  parser,
+                            FT_Int     max_values,
+                            FT_Fixed*  values,
+                            FT_Int     power_ten )
+  {
+    return t1_tofixedarray( &parser->cursor, parser->limit,
+                            max_values, values, power_ten );
+  }
+
+
+#if 0
+
+  FT_LOCAL_DEF( FT_String* )
+  T1_ToString( PS_Parser  parser )
+  {
+    return t1_tostring( &parser->cursor, parser->limit, parser->memory );
+  }
+
+
+  FT_LOCAL_DEF( FT_Bool )
+  T1_ToBool( PS_Parser  parser )
+  {
+    return t1_tobool( &parser->cursor, parser->limit );
+  }
+
+#endif /* 0 */
+
+
+  FT_LOCAL_DEF( void )
+  ps_parser_init( PS_Parser  parser,
+                  FT_Byte*   base,
+                  FT_Byte*   limit,
+                  FT_Memory  memory )
+  {
+    parser->error  = 0;
+    parser->base   = base;
+    parser->limit  = limit;
+    parser->cursor = base;
+    parser->memory = memory;
+    parser->funcs  = ps_parser_funcs;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  ps_parser_done( PS_Parser  parser )
+  {
+    FT_UNUSED( parser );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                            T1 BUILDER                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    t1_builder_init                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given glyph builder.                                 */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    builder :: A pointer to the glyph builder to initialize.           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face    :: The current face object.                                */
+  /*                                                                       */
+  /*    size    :: The current size object.                                */
+  /*                                                                       */
+  /*    glyph   :: The current glyph object.                               */
+  /*                                                                       */
+  /*    hinting :: Whether hinting should be applied.                      */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  t1_builder_init( T1_Builder    builder,
+                   FT_Face       face,
+                   FT_Size       size,
+                   FT_GlyphSlot  glyph,
+                   FT_Bool       hinting )
+  {
+    builder->path_begun  = 0;
+    builder->load_points = 1;
+
+    builder->face   = face;
+    builder->glyph  = glyph;
+    builder->memory = face->memory;
+
+    if ( glyph )
+    {
+      FT_GlyphLoader  loader = glyph->internal->loader;
+
+
+      builder->loader  = loader;
+      builder->base    = &loader->base.outline;
+      builder->current = &loader->current.outline;
+      FT_GlyphLoader_Rewind( loader );
+
+      builder->hints_globals = size->internal;
+      builder->hints_funcs   = 0;
+
+      if ( hinting )
+        builder->hints_funcs = glyph->internal->glyph_hints;
+    }
+
+    if ( size )
+    {
+      builder->scale_x = size->metrics.x_scale;
+      builder->scale_y = size->metrics.y_scale;
+    }
+
+    builder->pos_x = 0;
+    builder->pos_y = 0;
+
+    builder->left_bearing.x = 0;
+    builder->left_bearing.y = 0;
+    builder->advance.x      = 0;
+    builder->advance.y      = 0;
+
+    builder->funcs = t1_builder_funcs;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    t1_builder_done                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a given glyph builder.  Its contents can still be used   */
+  /*    after the call, but the function saves important information       */
+  /*    within the corresponding glyph slot.                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    builder :: A pointer to the glyph builder to finalize.             */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  t1_builder_done( T1_Builder  builder )
+  {
+    FT_GlyphSlot  glyph = builder->glyph;
+
+
+    if ( glyph )
+      glyph->outline = *builder->base;
+  }
+
+
+  /* check that there is enough space for `count' more points */
+  FT_LOCAL_DEF( FT_Error )
+  t1_builder_check_points( T1_Builder  builder,
+                           FT_Int      count )
+  {
+    return FT_GlyphLoader_CheckPoints( builder->loader, count, 0 );
+  }
+
+
+  /* add a new point, do not check space */
+  FT_LOCAL_DEF( void )
+  t1_builder_add_point( T1_Builder  builder,
+                        FT_Pos      x,
+                        FT_Pos      y,
+                        FT_Byte     flag )
+  {
+    FT_Outline*  outline = builder->current;
+
+
+    if ( builder->load_points )
+    {
+      FT_Vector*  point   = outline->points + outline->n_points;
+      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points;
+
+
+      if ( builder->shift )
+      {
+        x >>= 16;
+        y >>= 16;
+      }
+      point->x = x;
+      point->y = y;
+      *control = (FT_Byte)( flag ? FT_CURVE_TAG_ON : FT_CURVE_TAG_CUBIC );
+
+      builder->last = *point;
+    }
+    outline->n_points++;
+  }
+
+
+  /* check space for a new on-curve point, then add it */
+  FT_LOCAL_DEF( FT_Error )
+  t1_builder_add_point1( T1_Builder  builder,
+                         FT_Pos      x,
+                         FT_Pos      y )
+  {
+    FT_Error  error;
+
+
+    error = t1_builder_check_points( builder, 1 );
+    if ( !error )
+      t1_builder_add_point( builder, x, y, 1 );
+
+    return error;
+  }
+
+
+  /* check room for a new contour, then add it */
+  FT_LOCAL_DEF( FT_Error )
+  t1_builder_add_contour( T1_Builder  builder )
+  {
+    FT_Outline*  outline = builder->current;
+    FT_Error     error;
+
+
+    if ( !builder->load_points )
+    {
+      outline->n_contours++;
+      return PSaux_Err_Ok;
+    }
+
+    error = FT_GlyphLoader_CheckPoints( builder->loader, 0, 1 );
+    if ( !error )
+    {
+      if ( outline->n_contours > 0 )
+        outline->contours[outline->n_contours - 1] =
+          (short)( outline->n_points - 1 );
+
+      outline->n_contours++;
+    }
+
+    return error;
+  }
+
+
+  /* if a path was begun, add its first on-curve point */
+  FT_LOCAL_DEF( FT_Error )
+  t1_builder_start_point( T1_Builder  builder,
+                          FT_Pos      x,
+                          FT_Pos      y )
+  {
+    FT_Error  error = 0;
+
+
+    /* test whether we are building a new contour */
+    if ( !builder->path_begun )
+    {
+      builder->path_begun = 1;
+      error = t1_builder_add_contour( builder );
+      if ( !error )
+        error = t1_builder_add_point1( builder, x, y );
+    }
+    return error;
+  }
+
+
+  /* close the current contour */
+  FT_LOCAL_DEF( void )
+  t1_builder_close_contour( T1_Builder  builder )
+  {
+    FT_Outline*  outline = builder->current;
+
+
+    /* XXXX: We must not include the last point in the path if it */
+    /*       is located on the first point.                       */
+    if ( outline->n_points > 1 )
+    {
+      FT_Int      first   = 0;
+      FT_Vector*  p1      = outline->points + first;
+      FT_Vector*  p2      = outline->points + outline->n_points - 1;
+      FT_Byte*    control = (FT_Byte*)outline->tags + outline->n_points - 1;
+
+
+      if ( outline->n_contours > 1 )
+      {
+        first = outline->contours[outline->n_contours - 2] + 1;
+        p1    = outline->points + first;
+      }
+
+      /* `delete' last point only if it coincides with the first */
+      /* point and it is not a control point (which can happen). */
+      if ( p1->x == p2->x && p1->y == p2->y )
+        if ( *control == FT_CURVE_TAG_ON )
+          outline->n_points--;
+    }
+
+    if ( outline->n_contours > 0 )
+      outline->contours[outline->n_contours - 1] =
+        (short)( outline->n_points - 1 );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                            OTHER                              *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  t1_decrypt( FT_Byte*   buffer,
+              FT_Offset  length,
+              FT_UShort  seed )
+  {
+    while ( length > 0 )
+    {
+      FT_Byte  plain;
+
+
+      plain     = (FT_Byte)( *buffer ^ ( seed >> 8 ) );
+      seed      = (FT_UShort)( ( *buffer + seed ) * 52845U + 22719 );
+      *buffer++ = plain;
+      length--;
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/psobjs.h
@@ -1,0 +1,204 @@
+/***************************************************************************/
+/*                                                                         */
+/*  psobjs.h                                                               */
+/*                                                                         */
+/*    Auxiliary functions for PostScript fonts (specification).            */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __PSOBJS_H__
+#define __PSOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                             T1_TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_TABLE
+  const PS_Table_FuncsRec    ps_table_funcs;
+
+  FT_CALLBACK_TABLE
+  const PS_Parser_FuncsRec   ps_parser_funcs;
+
+  FT_CALLBACK_TABLE
+  const T1_Builder_FuncsRec  t1_builder_funcs;
+
+
+  FT_LOCAL( FT_Error )
+  ps_table_new( PS_Table   table,
+                FT_Int     count,
+                FT_Memory  memory );
+
+  FT_LOCAL( FT_Error )
+  ps_table_add( PS_Table  table,
+                FT_Int    idx,
+                void*     object,
+                FT_Int    length );
+
+  FT_LOCAL( void )
+  ps_table_done( PS_Table  table );
+
+
+  FT_LOCAL( void )
+  ps_table_release( PS_Table  table );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                            T1 PARSER                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL( void )
+  ps_parser_skip_spaces( PS_Parser  parser );
+
+  FT_LOCAL( void )
+  ps_parser_skip_alpha( PS_Parser  parser );
+
+  FT_LOCAL( void )
+  ps_parser_to_token( PS_Parser  parser,
+                      T1_Token   token );
+
+  FT_LOCAL( void )
+  ps_parser_to_token_array( PS_Parser  parser,
+                            T1_Token   tokens,
+                            FT_UInt    max_tokens,
+                            FT_Int*    pnum_tokens );
+
+  FT_LOCAL( FT_Error )
+  ps_parser_load_field( PS_Parser       parser,
+                        const T1_Field  field,
+                        void**          objects,
+                        FT_UInt         max_objects,
+                        FT_ULong*       pflags );
+
+  FT_LOCAL( FT_Error )
+  ps_parser_load_field_table( PS_Parser       parser,
+                              const T1_Field  field,
+                              void**          objects,
+                              FT_UInt         max_objects,
+                              FT_ULong*       pflags );
+
+  FT_LOCAL( FT_Long )
+  ps_parser_to_int( PS_Parser  parser );
+
+
+  FT_LOCAL( FT_Fixed )
+  ps_parser_to_fixed( PS_Parser  parser,
+                      FT_Int     power_ten );
+
+
+  FT_LOCAL( FT_Int )
+  ps_parser_to_coord_array( PS_Parser  parser,
+                            FT_Int     max_coords,
+                            FT_Short*  coords );
+
+  FT_LOCAL( FT_Int )
+  ps_parser_to_fixed_array( PS_Parser  parser,
+                            FT_Int     max_values,
+                            FT_Fixed*  values,
+                            FT_Int     power_ten );
+
+
+  FT_LOCAL( void )
+  ps_parser_init( PS_Parser  parser,
+                  FT_Byte*   base,
+                  FT_Byte*   limit,
+                  FT_Memory  memory );
+
+  FT_LOCAL( void )
+  ps_parser_done( PS_Parser  parser );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                            T1 BUILDER                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  t1_builder_init( T1_Builder    builder,
+                   FT_Face       face,
+                   FT_Size       size,
+                   FT_GlyphSlot  glyph,
+                   FT_Bool       hinting );
+
+  FT_LOCAL( void )
+  t1_builder_done( T1_Builder  builder );
+
+  FT_LOCAL( FT_Error )
+  t1_builder_check_points( T1_Builder  builder,
+                           FT_Int      count );
+
+  FT_LOCAL( void )
+  t1_builder_add_point( T1_Builder  builder,
+                        FT_Pos      x,
+                        FT_Pos      y,
+                        FT_Byte     flag );
+
+  FT_LOCAL( FT_Error )
+  t1_builder_add_point1( T1_Builder  builder,
+                         FT_Pos      x,
+                         FT_Pos      y );
+
+  FT_LOCAL( FT_Error )
+  t1_builder_add_contour( T1_Builder  builder );
+
+
+  FT_LOCAL( FT_Error )
+  t1_builder_start_point( T1_Builder  builder,
+                          FT_Pos      x,
+                          FT_Pos      y );
+
+
+  FT_LOCAL( void )
+  t1_builder_close_contour( T1_Builder  builder );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                            OTHER                              *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  t1_decrypt( FT_Byte*   buffer,
+              FT_Offset  length,
+              FT_UShort  seed );
+
+
+FT_END_HEADER
+
+#endif /* __PSOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/pstables.h
@@ -1,0 +1,2967 @@
+/***************************************************************************/
+/*                                                                         */
+/*  pstables.h                                                             */
+/*                                                                         */
+/*    PostScript glyph names (specification only).                         */
+/*                                                                         */
+/*  Copyright 2000-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /* this file has been generated automatically -- do not edit! */
+
+
+  static const char* const  ps_glyph_names[] =
+  {
+    ".null",
+    "nonmarkingreturn",
+    "nonbreakingspace",
+    "apple",
+    ".notdef",
+    "space",
+    "exclam",
+    "quotedbl",
+    "numbersign",
+    "dollar",
+    "percent",
+    "ampersand",
+    "quoteright",
+    "parenleft",
+    "parenright",
+    "asterisk",
+    "plus",
+    "comma",
+    "hyphen",
+    "period",
+    "slash",
+    "zero",
+    "one",
+    "two",
+    "three",
+    "four",
+    "five",
+    "six",
+    "seven",
+    "eight",
+    "nine",
+    "colon",
+    "semicolon",
+    "less",
+    "equal",
+    "greater",
+    "question",
+    "at",
+    "A",
+    "B",
+    "C",
+    "D",
+    "E",
+    "F",
+    "G",
+    "H",
+    "I",
+    "J",
+    "K",
+    "L",
+    "M",
+    "N",
+    "O",
+    "P",
+    "Q",
+    "R",
+    "S",
+    "T",
+    "U",
+    "V",
+    "W",
+    "X",
+    "Y",
+    "Z",
+    "bracketleft",
+    "backslash",
+    "bracketright",
+    "asciicircum",
+    "underscore",
+    "quoteleft",
+    "a",
+    "b",
+    "c",
+    "d",
+    "e",
+    "f",
+    "g",
+    "h",
+    "i",
+    "j",
+    "k",
+    "l",
+    "m",
+    "n",
+    "o",
+    "p",
+    "q",
+    "r",
+    "s",
+    "t",
+    "u",
+    "v",
+    "w",
+    "x",
+    "y",
+    "z",
+    "braceleft",
+    "bar",
+    "braceright",
+    "asciitilde",
+    "exclamdown",
+    "cent",
+    "sterling",
+    "fraction",
+    "yen",
+    "florin",
+    "section",
+    "currency",
+    "quotesingle",
+    "quotedblleft",
+    "guillemotleft",
+    "guilsinglleft",
+    "guilsinglright",
+    "fi",
+    "fl",
+    "endash",
+    "dagger",
+    "daggerdbl",
+    "periodcentered",
+    "paragraph",
+    "bullet",
+    "quotesinglbase",
+    "quotedblbase",
+    "quotedblright",
+    "guillemotright",
+    "ellipsis",
+    "perthousand",
+    "questiondown",
+    "grave",
+    "acute",
+    "circumflex",
+    "tilde",
+    "macron",
+    "breve",
+    "dotaccent",
+    "dieresis",
+    "ring",
+    "cedilla",
+    "hungarumlaut",
+    "ogonek",
+    "caron",
+    "emdash",
+    "AE",
+    "ordfeminine",
+    "Lslash",
+    "Oslash",
+    "OE",
+    "ordmasculine",
+    "ae",
+    "dotlessi",
+    "lslash",
+    "oslash",
+    "oe",
+    "germandbls",
+    "onesuperior",
+    "logicalnot",
+    "mu",
+    "trademark",
+    "Eth",
+    "onehalf",
+    "plusminus",
+    "Thorn",
+    "onequarter",
+    "divide",
+    "brokenbar",
+    "degree",
+    "thorn",
+    "threequarters",
+    "twosuperior",
+    "registered",
+    "minus",
+    "eth",
+    "multiply",
+    "threesuperior",
+    "copyright",
+    "Aacute",
+    "Acircumflex",
+    "Adieresis",
+    "Agrave",
+    "Aring",
+    "Atilde",
+    "Ccedilla",
+    "Eacute",
+    "Ecircumflex",
+    "Edieresis",
+    "Egrave",
+    "Iacute",
+    "Icircumflex",
+    "Idieresis",
+    "Igrave",
+    "Ntilde",
+    "Oacute",
+    "Ocircumflex",
+    "Odieresis",
+    "Ograve",
+    "Otilde",
+    "Scaron",
+    "Uacute",
+    "Ucircumflex",
+    "Udieresis",
+    "Ugrave",
+    "Yacute",
+    "Ydieresis",
+    "Zcaron",
+    "aacute",
+    "acircumflex",
+    "adieresis",
+    "agrave",
+    "aring",
+    "atilde",
+    "ccedilla",
+    "eacute",
+    "ecircumflex",
+    "edieresis",
+    "egrave",
+    "iacute",
+    "icircumflex",
+    "idieresis",
+    "igrave",
+    "ntilde",
+    "oacute",
+    "ocircumflex",
+    "odieresis",
+    "ograve",
+    "otilde",
+    "scaron",
+    "uacute",
+    "ucircumflex",
+    "udieresis",
+    "ugrave",
+    "yacute",
+    "ydieresis",
+    "zcaron",
+    "exclamsmall",
+    "Hungarumlautsmall",
+    "dollaroldstyle",
+    "dollarsuperior",
+    "ampersandsmall",
+    "Acutesmall",
+    "parenleftsuperior",
+    "parenrightsuperior",
+    "twodotenleader",
+    "onedotenleader",
+    "zerooldstyle",
+    "oneoldstyle",
+    "twooldstyle",
+    "threeoldstyle",
+    "fouroldstyle",
+    "fiveoldstyle",
+    "sixoldstyle",
+    "sevenoldstyle",
+    "eightoldstyle",
+    "nineoldstyle",
+    "commasuperior",
+    "threequartersemdash",
+    "periodsuperior",
+    "questionsmall",
+    "asuperior",
+    "bsuperior",
+    "centsuperior",
+    "dsuperior",
+    "esuperior",
+    "isuperior",
+    "lsuperior",
+    "msuperior",
+    "nsuperior",
+    "osuperior",
+    "rsuperior",
+    "ssuperior",
+    "tsuperior",
+    "ff",
+    "ffi",
+    "ffl",
+    "parenleftinferior",
+    "parenrightinferior",
+    "Circumflexsmall",
+    "hyphensuperior",
+    "Gravesmall",
+    "Asmall",
+    "Bsmall",
+    "Csmall",
+    "Dsmall",
+    "Esmall",
+    "Fsmall",
+    "Gsmall",
+    "Hsmall",
+    "Ismall",
+    "Jsmall",
+    "Ksmall",
+    "Lsmall",
+    "Msmall",
+    "Nsmall",
+    "Osmall",
+    "Psmall",
+    "Qsmall",
+    "Rsmall",
+    "Ssmall",
+    "Tsmall",
+    "Usmall",
+    "Vsmall",
+    "Wsmall",
+    "Xsmall",
+    "Ysmall",
+    "Zsmall",
+    "colonmonetary",
+    "onefitted",
+    "rupiah",
+    "Tildesmall",
+    "exclamdownsmall",
+    "centoldstyle",
+    "Lslashsmall",
+    "Scaronsmall",
+    "Zcaronsmall",
+    "Dieresissmall",
+    "Brevesmall",
+    "Caronsmall",
+    "Dotaccentsmall",
+    "Macronsmall",
+    "figuredash",
+    "hypheninferior",
+    "Ogoneksmall",
+    "Ringsmall",
+    "Cedillasmall",
+    "questiondownsmall",
+    "oneeighth",
+    "threeeighths",
+    "fiveeighths",
+    "seveneighths",
+    "onethird",
+    "twothirds",
+    "zerosuperior",
+    "foursuperior",
+    "fivesuperior",
+    "sixsuperior",
+    "sevensuperior",
+    "eightsuperior",
+    "ninesuperior",
+    "zeroinferior",
+    "oneinferior",
+    "twoinferior",
+    "threeinferior",
+    "fourinferior",
+    "fiveinferior",
+    "sixinferior",
+    "seveninferior",
+    "eightinferior",
+    "nineinferior",
+    "centinferior",
+    "dollarinferior",
+    "periodinferior",
+    "commainferior",
+    "Agravesmall",
+    "Aacutesmall",
+    "Acircumflexsmall",
+    "Atildesmall",
+    "Adieresissmall",
+    "Aringsmall",
+    "AEsmall",
+    "Ccedillasmall",
+    "Egravesmall",
+    "Eacutesmall",
+    "Ecircumflexsmall",
+    "Edieresissmall",
+    "Igravesmall",
+    "Iacutesmall",
+    "Icircumflexsmall",
+    "Idieresissmall",
+    "Ethsmall",
+    "Ntildesmall",
+    "Ogravesmall",
+    "Oacutesmall",
+    "Ocircumflexsmall",
+    "Otildesmall",
+    "Odieresissmall",
+    "OEsmall",
+    "Oslashsmall",
+    "Ugravesmall",
+    "Uacutesmall",
+    "Ucircumflexsmall",
+    "Udieresissmall",
+    "Yacutesmall",
+    "Thornsmall",
+    "Ydieresissmall",
+    "001.000",
+    "001.001",
+    "001.002",
+    "001.003",
+    "Black",
+    "Bold",
+    "Book",
+    "Light",
+    "Medium",
+    "Regular",
+    "Roman",
+    "Semibold",
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+    "AEacute",
+    "Abreve",
+    "Acute",
+    "Alpha",
+    "Alphatonos",
+    "Amacron",
+    "Aogonek",
+    "Aringacute",
+    "Beta",
+    "Cacute",
+    "Caron",
+    "Ccaron",
+    "Ccircumflex",
+    "Cdotaccent",
+    "Chi",
+    "Dcaron",
+    "Dcroat",
+    "Delta",
+    "Delta",
+    "Dieresis",
+    "DieresisAcute",
+    "DieresisGrave",
+    "Ebreve",
+    "Ecaron",
+    "Edotaccent",
+    "Emacron",
+    "Eng",
+    "Eogonek",
+    "Epsilon",
+    "Epsilontonos",
+    "Eta",
+    "Etatonos",
+    "Euro",
+    "Gamma",
+    "Gbreve",
+    "Gcaron",
+    "Gcircumflex",
+    "Gcommaaccent",
+    "Gdotaccent",
+    "Grave",
+    "H18533",
+    "H18543",
+    "H18551",
+    "H22073",
+    "Hbar",
+    "Hcircumflex",
+    "Hungarumlaut",
+    "IJ",
+    "Ibreve",
+    "Idotaccent",
+    "Ifraktur",
+    "Imacron",
+    "Iogonek",
+    "Iota",
+    "Iotadieresis",
+    "Iotatonos",
+    "Itilde",
+    "Jcircumflex",
+    "Kappa",
+    "Kcommaaccent",
+    "LL",
+    "Lacute",
+    "Lambda",
+    "Lcaron",
+    "Lcommaaccent",
+    "Ldot",
+    "Macron",
+    "Mu",
+    "Nacute",
+    "Ncaron",
+    "Ncommaaccent",
+    "Nu",
+    "Obreve",
+    "Ohorn",
+    "Ohungarumlaut",
+    "Omacron",
+    "Omega",
+    "Omega",
+    "Omegatonos",
+    "Omicron",
+    "Omicrontonos",
+    "Oslashacute",
+    "Phi",
+    "Pi",
+    "Psi",
+    "Racute",
+    "Rcaron",
+    "Rcommaaccent",
+    "Rfraktur",
+    "Rho",
+    "SF010000",
+    "SF020000",
+    "SF030000",
+    "SF040000",
+    "SF050000",
+    "SF060000",
+    "SF070000",
+    "SF080000",
+    "SF090000",
+    "SF100000",
+    "SF110000",
+    "SF190000",
+    "SF200000",
+    "SF210000",
+    "SF220000",
+    "SF230000",
+    "SF240000",
+    "SF250000",
+    "SF260000",
+    "SF270000",
+    "SF280000",
+    "SF360000",
+    "SF370000",
+    "SF380000",
+    "SF390000",
+    "SF400000",
+    "SF410000",
+    "SF420000",
+    "SF430000",
+    "SF440000",
+    "SF450000",
+    "SF460000",
+    "SF470000",
+    "SF480000",
+    "SF490000",
+    "SF500000",
+    "SF510000",
+    "SF520000",
+    "SF530000",
+    "SF540000",
+    "Sacute",
+    "Scedilla",
+    "Scedilla",
+    "Scircumflex",
+    "Scommaaccent",
+    "Sigma",
+    "Tau",
+    "Tbar",
+    "Tcaron",
+    "Tcommaaccent",
+    "Tcommaaccent",
+    "Theta",
+    "Ubreve",
+    "Uhorn",
+    "Uhungarumlaut",
+    "Umacron",
+    "Uogonek",
+    "Upsilon",
+    "Upsilon1",
+    "Upsilondieresis",
+    "Upsilontonos",
+    "Uring",
+    "Utilde",
+    "Wacute",
+    "Wcircumflex",
+    "Wdieresis",
+    "Wgrave",
+    "Xi",
+    "Ycircumflex",
+    "Ygrave",
+    "Zacute",
+    "Zdotaccent",
+    "Zeta",
+    "abreve",
+    "acutecomb",
+    "aeacute",
+    "afii00208",
+    "afii10017",
+    "afii10018",
+    "afii10019",
+    "afii10020",
+    "afii10021",
+    "afii10022",
+    "afii10023",
+    "afii10024",
+    "afii10025",
+    "afii10026",
+    "afii10027",
+    "afii10028",
+    "afii10029",
+    "afii10030",
+    "afii10031",
+    "afii10032",
+    "afii10033",
+    "afii10034",
+    "afii10035",
+    "afii10036",
+    "afii10037",
+    "afii10038",
+    "afii10039",
+    "afii10040",
+    "afii10041",
+    "afii10042",
+    "afii10043",
+    "afii10044",
+    "afii10045",
+    "afii10046",
+    "afii10047",
+    "afii10048",
+    "afii10049",
+    "afii10050",
+    "afii10051",
+    "afii10052",
+    "afii10053",
+    "afii10054",
+    "afii10055",
+    "afii10056",
+    "afii10057",
+    "afii10058",
+    "afii10059",
+    "afii10060",
+    "afii10061",
+    "afii10062",
+    "afii10063",
+    "afii10064",
+    "afii10065",
+    "afii10066",
+    "afii10067",
+    "afii10068",
+    "afii10069",
+    "afii10070",
+    "afii10071",
+    "afii10072",
+    "afii10073",
+    "afii10074",
+    "afii10075",
+    "afii10076",
+    "afii10077",
+    "afii10078",
+    "afii10079",
+    "afii10080",
+    "afii10081",
+    "afii10082",
+    "afii10083",
+    "afii10084",
+    "afii10085",
+    "afii10086",
+    "afii10087",
+    "afii10088",
+    "afii10089",
+    "afii10090",
+    "afii10091",
+    "afii10092",
+    "afii10093",
+    "afii10094",
+    "afii10095",
+    "afii10096",
+    "afii10097",
+    "afii10098",
+    "afii10099",
+    "afii10100",
+    "afii10101",
+    "afii10102",
+    "afii10103",
+    "afii10104",
+    "afii10105",
+    "afii10106",
+    "afii10107",
+    "afii10108",
+    "afii10109",
+    "afii10110",
+    "afii10145",
+    "afii10146",
+    "afii10147",
+    "afii10148",
+    "afii10192",
+    "afii10193",
+    "afii10194",
+    "afii10195",
+    "afii10196",
+    "afii10831",
+    "afii10832",
+    "afii10846",
+    "afii299",
+    "afii300",
+    "afii301",
+    "afii57381",
+    "afii57388",
+    "afii57392",
+    "afii57393",
+    "afii57394",
+    "afii57395",
+    "afii57396",
+    "afii57397",
+    "afii57398",
+    "afii57399",
+    "afii57400",
+    "afii57401",
+    "afii57403",
+    "afii57407",
+    "afii57409",
+    "afii57410",
+    "afii57411",
+    "afii57412",
+    "afii57413",
+    "afii57414",
+    "afii57415",
+    "afii57416",
+    "afii57417",
+    "afii57418",
+    "afii57419",
+    "afii57420",
+    "afii57421",
+    "afii57422",
+    "afii57423",
+    "afii57424",
+    "afii57425",
+    "afii57426",
+    "afii57427",
+    "afii57428",
+    "afii57429",
+    "afii57430",
+    "afii57431",
+    "afii57432",
+    "afii57433",
+    "afii57434",
+    "afii57440",
+    "afii57441",
+    "afii57442",
+    "afii57443",
+    "afii57444",
+    "afii57445",
+    "afii57446",
+    "afii57448",
+    "afii57449",
+    "afii57450",
+    "afii57451",
+    "afii57452",
+    "afii57453",
+    "afii57454",
+    "afii57455",
+    "afii57456",
+    "afii57457",
+    "afii57458",
+    "afii57470",
+    "afii57505",
+    "afii57506",
+    "afii57507",
+    "afii57508",
+    "afii57509",
+    "afii57511",
+    "afii57512",
+    "afii57513",
+    "afii57514",
+    "afii57519",
+    "afii57534",
+    "afii57636",
+    "afii57645",
+    "afii57658",
+    "afii57664",
+    "afii57665",
+    "afii57666",
+    "afii57667",
+    "afii57668",
+    "afii57669",
+    "afii57670",
+    "afii57671",
+    "afii57672",
+    "afii57673",
+    "afii57674",
+    "afii57675",
+    "afii57676",
+    "afii57677",
+    "afii57678",
+    "afii57679",
+    "afii57680",
+    "afii57681",
+    "afii57682",
+    "afii57683",
+    "afii57684",
+    "afii57685",
+    "afii57686",
+    "afii57687",
+    "afii57688",
+    "afii57689",
+    "afii57690",
+    "afii57694",
+    "afii57695",
+    "afii57700",
+    "afii57705",
+    "afii57716",
+    "afii57717",
+    "afii57718",
+    "afii57723",
+    "afii57793",
+    "afii57794",
+    "afii57795",
+    "afii57796",
+    "afii57797",
+    "afii57798",
+    "afii57799",
+    "afii57800",
+    "afii57801",
+    "afii57802",
+    "afii57803",
+    "afii57804",
+    "afii57806",
+    "afii57807",
+    "afii57839",
+    "afii57841",
+    "afii57842",
+    "afii57929",
+    "afii61248",
+    "afii61289",
+    "afii61352",
+    "afii61573",
+    "afii61574",
+    "afii61575",
+    "afii61664",
+    "afii63167",
+    "afii64937",
+    "aleph",
+    "alpha",
+    "alphatonos",
+    "amacron",
+    "angle",
+    "angleleft",
+    "angleright",
+    "anoteleia",
+    "aogonek",
+    "approxequal",
+    "aringacute",
+    "arrowboth",
+    "arrowdblboth",
+    "arrowdbldown",
+    "arrowdblleft",
+    "arrowdblright",
+    "arrowdblup",
+    "arrowdown",
+    "arrowhorizex",
+    "arrowleft",
+    "arrowright",
+    "arrowup",
+    "arrowupdn",
+    "arrowupdnbse",
+    "arrowvertex",
+    "asteriskmath",
+    "beta",
+    "block",
+    "braceex",
+    "braceleftbt",
+    "braceleftmid",
+    "bracelefttp",
+    "bracerightbt",
+    "bracerightmid",
+    "bracerighttp",
+    "bracketleftbt",
+    "bracketleftex",
+    "bracketlefttp",
+    "bracketrightbt",
+    "bracketrightex",
+    "bracketrighttp",
+    "cacute",
+    "carriagereturn",
+    "ccaron",
+    "ccircumflex",
+    "cdotaccent",
+    "chi",
+    "circle",
+    "circlemultiply",
+    "circleplus",
+    "club",
+    "commaaccent",
+    "congruent",
+    "copyrightsans",
+    "copyrightserif",
+    "cyrBreve",
+    "cyrFlex",
+    "cyrbreve",
+    "cyrflex",
+    "dblGrave",
+    "dblgrave",
+    "dcaron",
+    "dcroat",
+    "delta",
+    "diamond",
+    "dieresisacute",
+    "dieresisgrave",
+    "dieresistonos",
+    "dkshade",
+    "dnblock",
+    "dong",
+    "dotbelowcomb",
+    "dotlessj",
+    "dotmath",
+    "ebreve",
+    "ecaron",
+    "edotaccent",
+    "element",
+    "emacron",
+    "emptyset",
+    "eng",
+    "eogonek",
+    "epsilon",
+    "epsilontonos",
+    "equivalence",
+    "estimated",
+    "eta",
+    "etatonos",
+    "exclamdbl",
+    "existential",
+    "female",
+    "filledbox",
+    "filledrect",
+    "franc",
+    "gamma",
+    "gbreve",
+    "gcaron",
+    "gcircumflex",
+    "gcommaaccent",
+    "gdotaccent",
+    "gradient",
+    "gravecomb",
+    "greaterequal",
+    "hbar",
+    "hcircumflex",
+    "heart",
+    "hookabovecomb",
+    "house",
+    "ibreve",
+    "ij",
+    "imacron",
+    "infinity",
+    "integral",
+    "integralbt",
+    "integralex",
+    "integraltp",
+    "intersection",
+    "invbullet",
+    "invcircle",
+    "invsmileface",
+    "iogonek",
+    "iota",
+    "iotadieresis",
+    "iotadieresistonos",
+    "iotatonos",
+    "itilde",
+    "jcircumflex",
+    "kappa",
+    "kcommaaccent",
+    "kgreenlandic",
+    "lacute",
+    "lambda",
+    "lcaron",
+    "lcommaaccent",
+    "ldot",
+    "lessequal",
+    "lfblock",
+    "lira",
+    "ll",
+    "logicaland",
+    "logicalor",
+    "longs",
+    "lozenge",
+    "ltshade",
+    "male",
+    "minute",
+    "musicalnote",
+    "musicalnotedbl",
+    "nacute",
+    "napostrophe",
+    "ncaron",
+    "ncommaaccent",
+    "notelement",
+    "notequal",
+    "notsubset",
+    "nu",
+    "obreve",
+    "ohorn",
+    "ohungarumlaut",
+    "omacron",
+    "omega",
+    "omega1",
+    "omegatonos",
+    "omicron",
+    "omicrontonos",
+    "openbullet",
+    "orthogonal",
+    "oslashacute",
+    "parenleftbt",
+    "parenleftex",
+    "parenlefttp",
+    "parenrightbt",
+    "parenrightex",
+    "parenrighttp",
+    "partialdiff",
+    "perpendicular",
+    "peseta",
+    "phi",
+    "phi1",
+    "pi",
+    "prescription",
+    "product",
+    "propersubset",
+    "propersuperset",
+    "proportional",
+    "psi",
+    "quotereversed",
+    "racute",
+    "radical",
+    "radicalex",
+    "rcaron",
+    "rcommaaccent",
+    "reflexsubset",
+    "reflexsuperset",
+    "registersans",
+    "registerserif",
+    "revlogicalnot",
+    "rho",
+    "rtblock",
+    "sacute",
+    "scedilla",
+    "scedilla",
+    "scircumflex",
+    "scommaaccent",
+    "second",
+    "shade",
+    "sigma",
+    "sigma1",
+    "similar",
+    "smileface",
+    "spade",
+    "suchthat",
+    "summation",
+    "sun",
+    "tau",
+    "tbar",
+    "tcaron",
+    "tcommaaccent",
+    "tcommaaccent",
+    "therefore",
+    "theta",
+    "theta1",
+    "tildecomb",
+    "tonos",
+    "trademarksans",
+    "trademarkserif",
+    "triagdn",
+    "triaglf",
+    "triagrt",
+    "triagup",
+    "ubreve",
+    "uhorn",
+    "uhungarumlaut",
+    "umacron",
+    "underscoredbl",
+    "union",
+    "universal",
+    "uogonek",
+    "upblock",
+    "upsilon",
+    "upsilondieresis",
+    "upsilondieresistonos",
+    "upsilontonos",
+    "uring",
+    "utilde",
+    "wacute",
+    "wcircumflex",
+    "wdieresis",
+    "weierstrass",
+    "wgrave",
+    "xi",
+    "ycircumflex",
+    "ygrave",
+    "zacute",
+    "zdotaccent",
+    "zeta",
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+
+    NULL
+  };
+
+
+  static const char* const * const  sid_standard_names = ps_glyph_names + 4;
+
+
+#define NUM_SID_GLYPHS 391
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+#define NUM_ADOBE_GLYPHS 1058
+#else
+#define NUM_ADOBE_GLYPHS 391
+#endif
+
+
+  static const unsigned short  mac_standard_names[259] =
+  {
+    4,
+    0,
+    1,
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    108,
+    13,
+    14,
+    15,
+    16,
+    17,
+    18,
+    19,
+    20,
+    21,
+    22,
+    23,
+    24,
+    25,
+    26,
+    27,
+    28,
+    29,
+    30,
+    31,
+    32,
+    33,
+    34,
+    35,
+    36,
+    37,
+    38,
+    39,
+    40,
+    41,
+    42,
+    43,
+    44,
+    45,
+    46,
+    47,
+    48,
+    49,
+    50,
+    51,
+    52,
+    53,
+    54,
+    55,
+    56,
+    57,
+    58,
+    59,
+    60,
+    61,
+    62,
+    63,
+    64,
+    65,
+    66,
+    67,
+    68,
+    128,
+    70,
+    71,
+    72,
+    73,
+    74,
+    75,
+    76,
+    77,
+    78,
+    79,
+    80,
+    81,
+    82,
+    83,
+    84,
+    85,
+    86,
+    87,
+    88,
+    89,
+    90,
+    91,
+    92,
+    93,
+    94,
+    95,
+    96,
+    97,
+    98,
+    99,
+    177,
+    179,
+    181,
+    182,
+    190,
+    193,
+    199,
+    204,
+    207,
+    205,
+    206,
+    209,
+    208,
+    210,
+    211,
+    214,
+    212,
+    213,
+    215,
+    218,
+    216,
+    217,
+    219,
+    220,
+    223,
+    221,
+    222,
+    224,
+    226,
+    229,
+    227,
+    228,
+    116,
+    165,
+    101,
+    102,
+    106,
+    120,
+    119,
+    153,
+    169,
+    174,
+    157,
+    129,
+    135,
+    959,
+    142,
+    145,
+    917,
+    160,
+    941,
+    908,
+    104,
+    156,
+    980,
+    1018,
+    987,
+    985,
+    918,
+    143,
+    147,
+    471,
+    148,
+    151,
+    127,
+    100,
+    155,
+    994,
+    105,
+    815,
+    412,
+    110,
+    124,
+    125,
+    2,
+    178,
+    180,
+    195,
+    146,
+    152,
+    115,
+    141,
+    109,
+    123,
+    69,
+    12,
+    163,
+    948,
+    231,
+    202,
+    103,
+    107,
+    111,
+    112,
+    113,
+    114,
+    117,
+    118,
+    121,
+    122,
+    126,
+    176,
+    183,
+    175,
+    184,
+    185,
+    186,
+    187,
+    188,
+    189,
+    191,
+    192,
+    3,
+    194,
+    197,
+    198,
+    200,
+    149,
+    130,
+    131,
+    132,
+    133,
+    134,
+    136,
+    137,
+    138,
+    139,
+    140,
+    144,
+    150,
+    196,
+    225,
+    203,
+    232,
+    164,
+    158,
+    171,
+    201,
+    230,
+    161,
+    166,
+    170,
+    172,
+    154,
+    168,
+    173,
+    159,
+    162,
+    167,
+    899,
+    429,
+    901,
+    444,
+    526,
+    1006,
+    404,
+    847,
+    406,
+    849,
+    868,
+    0
+  };
+
+
+
+  static const unsigned short  ps_names_to_unicode[1059] =
+  {
+    0,
+    0x0020,
+    0x0021,
+    0x0022,
+    0x0023,
+    0x0024,
+    0x0025,
+    0x0026,
+    0x2019,
+    0x0028,
+    0x0029,
+    0x002A,
+    0x002B,
+    0x002C,
+    0x002D,
+    0x002E,
+    0x002F,
+    0x0030,
+    0x0031,
+    0x0032,
+    0x0033,
+    0x0034,
+    0x0035,
+    0x0036,
+    0x0037,
+    0x0038,
+    0x0039,
+    0x003A,
+    0x003B,
+    0x003C,
+    0x003D,
+    0x003E,
+    0x003F,
+    0x0040,
+    0x0041,
+    0x0042,
+    0x0043,
+    0x0044,
+    0x0045,
+    0x0046,
+    0x0047,
+    0x0048,
+    0x0049,
+    0x004A,
+    0x004B,
+    0x004C,
+    0x004D,
+    0x004E,
+    0x004F,
+    0x0050,
+    0x0051,
+    0x0052,
+    0x0053,
+    0x0054,
+    0x0055,
+    0x0056,
+    0x0057,
+    0x0058,
+    0x0059,
+    0x005A,
+    0x005B,
+    0x005C,
+    0x005D,
+    0x005E,
+    0x005F,
+    0x2018,
+    0x0061,
+    0x0062,
+    0x0063,
+    0x0064,
+    0x0065,
+    0x0066,
+    0x0067,
+    0x0068,
+    0x0069,
+    0x006A,
+    0x006B,
+    0x006C,
+    0x006D,
+    0x006E,
+    0x006F,
+    0x0070,
+    0x0071,
+    0x0072,
+    0x0073,
+    0x0074,
+    0x0075,
+    0x0076,
+    0x0077,
+    0x0078,
+    0x0079,
+    0x007A,
+    0x007B,
+    0x007C,
+    0x007D,
+    0x007E,
+    0x00A1,
+    0x00A2,
+    0x00A3,
+    0x2044,
+    0x00A5,
+    0x0192,
+    0x00A7,
+    0x00A4,
+    0x0027,
+    0x201C,
+    0x00AB,
+    0x2039,
+    0x203A,
+    0xFB01,
+    0xFB02,
+    0x2013,
+    0x2020,
+    0x2021,
+    0x00B7,
+    0x00B6,
+    0x2022,
+    0x201A,
+    0x201E,
+    0x201D,
+    0x00BB,
+    0x2026,
+    0x2030,
+    0x00BF,
+    0x0060,
+    0x00B4,
+    0x02C6,
+    0x02DC,
+    0x00AF,
+    0x02D8,
+    0x02D9,
+    0x00A8,
+    0x02DA,
+    0x00B8,
+    0x02DD,
+    0x02DB,
+    0x02C7,
+    0x2014,
+    0x00C6,
+    0x00AA,
+    0x0141,
+    0x00D8,
+    0x0152,
+    0x00BA,
+    0x00E6,
+    0x0131,
+    0x0142,
+    0x00F8,
+    0x0153,
+    0x00DF,
+    0x00B9,
+    0x00AC,
+    0x00B5,
+    0x2122,
+    0x00D0,
+    0x00BD,
+    0x00B1,
+    0x00DE,
+    0x00BC,
+    0x00F7,
+    0x00A6,
+    0x00B0,
+    0x00FE,
+    0x00BE,
+    0x00B2,
+    0x00AE,
+    0x2212,
+    0x00F0,
+    0x00D7,
+    0x00B3,
+    0x00A9,
+    0x00C1,
+    0x00C2,
+    0x00C4,
+    0x00C0,
+    0x00C5,
+    0x00C3,
+    0x00C7,
+    0x00C9,
+    0x00CA,
+    0x00CB,
+    0x00C8,
+    0x00CD,
+    0x00CE,
+    0x00CF,
+    0x00CC,
+    0x00D1,
+    0x00D3,
+    0x00D4,
+    0x00D6,
+    0x00D2,
+    0x00D5,
+    0x0160,
+    0x00DA,
+    0x00DB,
+    0x00DC,
+    0x00D9,
+    0x00DD,
+    0x0178,
+    0x017D,
+    0x00E1,
+    0x00E2,
+    0x00E4,
+    0x00E0,
+    0x00E5,
+    0x00E3,
+    0x00E7,
+    0x00E9,
+    0x00EA,
+    0x00EB,
+    0x00E8,
+    0x00ED,
+    0x00EE,
+    0x00EF,
+    0x00EC,
+    0x00F1,
+    0x00F3,
+    0x00F4,
+    0x00F6,
+    0x00F2,
+    0x00F5,
+    0x0161,
+    0x00FA,
+    0x00FB,
+    0x00FC,
+    0x00F9,
+    0x00FD,
+    0x00FF,
+    0x017E,
+    0xF721,
+    0xF6F8,
+    0xF724,
+    0xF6E4,
+    0xF726,
+    0xF7B4,
+    0x207D,
+    0x207E,
+    0x2025,
+    0x2024,
+    0xF730,
+    0xF731,
+    0xF732,
+    0xF733,
+    0xF734,
+    0xF735,
+    0xF736,
+    0xF737,
+    0xF738,
+    0xF739,
+    0xF6E2,
+    0xF6DE,
+    0xF6E8,
+    0xF73F,
+    0xF6E9,
+    0xF6EA,
+    0xF6E0,
+    0xF6EB,
+    0xF6EC,
+    0xF6ED,
+    0xF6EE,
+    0xF6EF,
+    0x207F,
+    0xF6F0,
+    0xF6F1,
+    0xF6F2,
+    0xF6F3,
+    0xFB00,
+    0xFB03,
+    0xFB04,
+    0x208D,
+    0x208E,
+    0xF6F6,
+    0xF6E6,
+    0xF760,
+    0xF761,
+    0xF762,
+    0xF763,
+    0xF764,
+    0xF765,
+    0xF766,
+    0xF767,
+    0xF768,
+    0xF769,
+    0xF76A,
+    0xF76B,
+    0xF76C,
+    0xF76D,
+    0xF76E,
+    0xF76F,
+    0xF770,
+    0xF771,
+    0xF772,
+    0xF773,
+    0xF774,
+    0xF775,
+    0xF776,
+    0xF777,
+    0xF778,
+    0xF779,
+    0xF77A,
+    0x20A1,
+    0xF6DC,
+    0xF6DD,
+    0xF6FE,
+    0xF7A1,
+    0xF7A2,
+    0xF6F9,
+    0xF6FD,
+    0xF6FF,
+    0xF7A8,
+    0xF6F4,
+    0xF6F5,
+    0xF6F7,
+    0xF7AF,
+    0x2012,
+    0xF6E5,
+    0xF6FB,
+    0xF6FC,
+    0xF7B8,
+    0xF7BF,
+    0x215B,
+    0x215C,
+    0x215D,
+    0x215E,
+    0x2153,
+    0x2154,
+    0x2070,
+    0x2074,
+    0x2075,
+    0x2076,
+    0x2077,
+    0x2078,
+    0x2079,
+    0x2080,
+    0x2081,
+    0x2082,
+    0x2083,
+    0x2084,
+    0x2085,
+    0x2086,
+    0x2087,
+    0x2088,
+    0x2089,
+    0xF6DF,
+    0xF6E3,
+    0xF6E7,
+    0xF6E1,
+    0xF7E0,
+    0xF7E1,
+    0xF7E2,
+    0xF7E3,
+    0xF7E4,
+    0xF7E5,
+    0xF7E6,
+    0xF7E7,
+    0xF7E8,
+    0xF7E9,
+    0xF7EA,
+    0xF7EB,
+    0xF7EC,
+    0xF7ED,
+    0xF7EE,
+    0xF7EF,
+    0xF7F0,
+    0xF7F1,
+    0xF7F2,
+    0xF7F3,
+    0xF7F4,
+    0xF7F5,
+    0xF7F6,
+    0xF6FA,
+    0xF7F8,
+    0xF7F9,
+    0xF7FA,
+    0xF7FB,
+    0xF7FC,
+    0xF7FD,
+    0xF7FE,
+    0xF7FF,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+
+#ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
+
+    0x01FC,
+    0x0102,
+    0xF6C9,
+    0x0391,
+    0x0386,
+    0x0100,
+    0x0104,
+    0x01FA,
+    0x0392,
+    0x0106,
+    0xF6CA,
+    0x010C,
+    0x0108,
+    0x010A,
+    0x03A7,
+    0x010E,
+    0x0110,
+    0x2206,
+    0x2206,
+    0xF6CB,
+    0xF6CC,
+    0xF6CD,
+    0x0114,
+    0x011A,
+    0x0116,
+    0x0112,
+    0x014A,
+    0x0118,
+    0x0395,
+    0x0388,
+    0x0397,
+    0x0389,
+    0x20AC,
+    0x0393,
+    0x011E,
+    0x01E6,
+    0x011C,
+    0x0122,
+    0x0120,
+    0xF6CE,
+    0x25CF,
+    0x25AA,
+    0x25AB,
+    0x25A1,
+    0x0126,
+    0x0124,
+    0xF6CF,
+    0x0132,
+    0x012C,
+    0x0130,
+    0x2111,
+    0x012A,
+    0x012E,
+    0x0399,
+    0x03AA,
+    0x038A,
+    0x0128,
+    0x0134,
+    0x039A,
+    0x0136,
+    0xF6BF,
+    0x0139,
+    0x039B,
+    0x013D,
+    0x013B,
+    0x013F,
+    0xF6D0,
+    0x039C,
+    0x0143,
+    0x0147,
+    0x0145,
+    0x039D,
+    0x014E,
+    0x01A0,
+    0x0150,
+    0x014C,
+    0x2126,
+    0x2126,
+    0x038F,
+    0x039F,
+    0x038C,
+    0x01FE,
+    0x03A6,
+    0x03A0,
+    0x03A8,
+    0x0154,
+    0x0158,
+    0x0156,
+    0x211C,
+    0x03A1,
+    0x250C,
+    0x2514,
+    0x2510,
+    0x2518,
+    0x253C,
+    0x252C,
+    0x2534,
+    0x251C,
+    0x2524,
+    0x2500,
+    0x2502,
+    0x2561,
+    0x2562,
+    0x2556,
+    0x2555,
+    0x2563,
+    0x2551,
+    0x2557,
+    0x255D,
+    0x255C,
+    0x255B,
+    0x255E,
+    0x255F,
+    0x255A,
+    0x2554,
+    0x2569,
+    0x2566,
+    0x2560,
+    0x2550,
+    0x256C,
+    0x2567,
+    0x2568,
+    0x2564,
+    0x2565,
+    0x2559,
+    0x2558,
+    0x2552,
+    0x2553,
+    0x256B,
+    0x256A,
+    0x015A,
+    0x015E,
+    0x015E,
+    0x015C,
+    0x0218,
+    0x03A3,
+    0x03A4,
+    0x0166,
+    0x0164,
+    0x0162,
+    0x0162,
+    0x0398,
+    0x016C,
+    0x01AF,
+    0x0170,
+    0x016A,
+    0x0172,
+    0x03A5,
+    0x03D2,
+    0x03AB,
+    0x038E,
+    0x016E,
+    0x0168,
+    0x1E82,
+    0x0174,
+    0x1E84,
+    0x1E80,
+    0x039E,
+    0x0176,
+    0x1EF2,
+    0x0179,
+    0x017B,
+    0x0396,
+    0x0103,
+    0x0301,
+    0x01FD,
+    0x2015,
+    0x0410,
+    0x0411,
+    0x0412,
+    0x0413,
+    0x0414,
+    0x0415,
+    0x0401,
+    0x0416,
+    0x0417,
+    0x0418,
+    0x0419,
+    0x041A,
+    0x041B,
+    0x041C,
+    0x041D,
+    0x041E,
+    0x041F,
+    0x0420,
+    0x0421,
+    0x0422,
+    0x0423,
+    0x0424,
+    0x0425,
+    0x0426,
+    0x0427,
+    0x0428,
+    0x0429,
+    0x042A,
+    0x042B,
+    0x042C,
+    0x042D,
+    0x042E,
+    0x042F,
+    0x0490,
+    0x0402,
+    0x0403,
+    0x0404,
+    0x0405,
+    0x0406,
+    0x0407,
+    0x0408,
+    0x0409,
+    0x040A,
+    0x040B,
+    0x040C,
+    0x040E,
+    0xF6C4,
+    0xF6C5,
+    0x0430,
+    0x0431,
+    0x0432,
+    0x0433,
+    0x0434,
+    0x0435,
+    0x0451,
+    0x0436,
+    0x0437,
+    0x0438,
+    0x0439,
+    0x043A,
+    0x043B,
+    0x043C,
+    0x043D,
+    0x043E,
+    0x043F,
+    0x0440,
+    0x0441,
+    0x0442,
+    0x0443,
+    0x0444,
+    0x0445,
+    0x0446,
+    0x0447,
+    0x0448,
+    0x0449,
+    0x044A,
+    0x044B,
+    0x044C,
+    0x044D,
+    0x044E,
+    0x044F,
+    0x0491,
+    0x0452,
+    0x0453,
+    0x0454,
+    0x0455,
+    0x0456,
+    0x0457,
+    0x0458,
+    0x0459,
+    0x045A,
+    0x045B,
+    0x045C,
+    0x045E,
+    0x040F,
+    0x0462,
+    0x0472,
+    0x0474,
+    0xF6C6,
+    0x045F,
+    0x0463,
+    0x0473,
+    0x0475,
+    0xF6C7,
+    0xF6C8,
+    0x04D9,
+    0x200E,
+    0x200F,
+    0x200D,
+    0x066A,
+    0x060C,
+    0x0660,
+    0x0661,
+    0x0662,
+    0x0663,
+    0x0664,
+    0x0665,
+    0x0666,
+    0x0667,
+    0x0668,
+    0x0669,
+    0x061B,
+    0x061F,
+    0x0621,
+    0x0622,
+    0x0623,
+    0x0624,
+    0x0625,
+    0x0626,
+    0x0627,
+    0x0628,
+    0x0629,
+    0x062A,
+    0x062B,
+    0x062C,
+    0x062D,
+    0x062E,
+    0x062F,
+    0x0630,
+    0x0631,
+    0x0632,
+    0x0633,
+    0x0634,
+    0x0635,
+    0x0636,
+    0x0637,
+    0x0638,
+    0x0639,
+    0x063A,
+    0x0640,
+    0x0641,
+    0x0642,
+    0x0643,
+    0x0644,
+    0x0645,
+    0x0646,
+    0x0648,
+    0x0649,
+    0x064A,
+    0x064B,
+    0x064C,
+    0x064D,
+    0x064E,
+    0x064F,
+    0x0650,
+    0x0651,
+    0x0652,
+    0x0647,
+    0x06A4,
+    0x067E,
+    0x0686,
+    0x0698,
+    0x06AF,
+    0x0679,
+    0x0688,
+    0x0691,
+    0x06BA,
+    0x06D2,
+    0x06D5,
+    0x20AA,
+    0x05BE,
+    0x05C3,
+    0x05D0,
+    0x05D1,
+    0x05D2,
+    0x05D3,
+    0x05D4,
+    0x05D5,
+    0x05D6,
+    0x05D7,
+    0x05D8,
+    0x05D9,
+    0x05DA,
+    0x05DB,
+    0x05DC,
+    0x05DD,
+    0x05DE,
+    0x05DF,
+    0x05E0,
+    0x05E1,
+    0x05E2,
+    0x05E3,
+    0x05E4,
+    0x05E5,
+    0x05E6,
+    0x05E7,
+    0x05E8,
+    0x05E9,
+    0x05EA,
+    0xFB2A,
+    0xFB2B,
+    0xFB4B,
+    0xFB1F,
+    0x05F0,
+    0x05F1,
+    0x05F2,
+    0xFB35,
+    0x05B4,
+    0x05B5,
+    0x05B6,
+    0x05BB,
+    0x05B8,
+    0x05B7,
+    0x05B0,
+    0x05B2,
+    0x05B1,
+    0x05B3,
+    0x05C2,
+    0x05C1,
+    0x05B9,
+    0x05BC,
+    0x05BD,
+    0x05BF,
+    0x05C0,
+    0x02BC,
+    0x2105,
+    0x2113,
+    0x2116,
+    0x202C,
+    0x202D,
+    0x202E,
+    0x200C,
+    0x066D,
+    0x02BD,
+    0x2135,
+    0x03B1,
+    0x03AC,
+    0x0101,
+    0x2220,
+    0x2329,
+    0x232A,
+    0x0387,
+    0x0105,
+    0x2248,
+    0x01FB,
+    0x2194,
+    0x21D4,
+    0x21D3,
+    0x21D0,
+    0x21D2,
+    0x21D1,
+    0x2193,
+    0xF8E7,
+    0x2190,
+    0x2192,
+    0x2191,
+    0x2195,
+    0x21A8,
+    0xF8E6,
+    0x2217,
+    0x03B2,
+    0x2588,
+    0xF8F4,
+    0xF8F3,
+    0xF8F2,
+    0xF8F1,
+    0xF8FE,
+    0xF8FD,
+    0xF8FC,
+    0xF8F0,
+    0xF8EF,
+    0xF8EE,
+    0xF8FB,
+    0xF8FA,
+    0xF8F9,
+    0x0107,
+    0x21B5,
+    0x010D,
+    0x0109,
+    0x010B,
+    0x03C7,
+    0x25CB,
+    0x2297,
+    0x2295,
+    0x2663,
+    0xF6C3,
+    0x2245,
+    0xF8E9,
+    0xF6D9,
+    0xF6D1,
+    0xF6D2,
+    0xF6D4,
+    0xF6D5,
+    0xF6D3,
+    0xF6D6,
+    0x010F,
+    0x0111,
+    0x03B4,
+    0x2666,
+    0xF6D7,
+    0xF6D8,
+    0x0385,
+    0x2593,
+    0x2584,
+    0x20AB,
+    0x0323,
+    0xF6BE,
+    0x22C5,
+    0x0115,
+    0x011B,
+    0x0117,
+    0x2208,
+    0x0113,
+    0x2205,
+    0x014B,
+    0x0119,
+    0x03B5,
+    0x03AD,
+    0x2261,
+    0x212E,
+    0x03B7,
+    0x03AE,
+    0x203C,
+    0x2203,
+    0x2640,
+    0x25A0,
+    0x25AC,
+    0x20A3,
+    0x03B3,
+    0x011F,
+    0x01E7,
+    0x011D,
+    0x0123,
+    0x0121,
+    0x2207,
+    0x0300,
+    0x2265,
+    0x0127,
+    0x0125,
+    0x2665,
+    0x0309,
+    0x2302,
+    0x012D,
+    0x0133,
+    0x012B,
+    0x221E,
+    0x222B,
+    0x2321,
+    0xF8F5,
+    0x2320,
+    0x2229,
+    0x25D8,
+    0x25D9,
+    0x263B,
+    0x012F,
+    0x03B9,
+    0x03CA,
+    0x0390,
+    0x03AF,
+    0x0129,
+    0x0135,
+    0x03BA,
+    0x0137,
+    0x0138,
+    0x013A,
+    0x03BB,
+    0x013E,
+    0x013C,
+    0x0140,
+    0x2264,
+    0x258C,
+    0x20A4,
+    0xF6C0,
+    0x2227,
+    0x2228,
+    0x017F,
+    0x25CA,
+    0x2591,
+    0x2642,
+    0x2032,
+    0x266A,
+    0x266B,
+    0x0144,
+    0x0149,
+    0x0148,
+    0x0146,
+    0x2209,
+    0x2260,
+    0x2284,
+    0x03BD,
+    0x014F,
+    0x01A1,
+    0x0151,
+    0x014D,
+    0x03C9,
+    0x03D6,
+    0x03CE,
+    0x03BF,
+    0x03CC,
+    0x25E6,
+    0x221F,
+    0x01FF,
+    0xF8ED,
+    0xF8EC,
+    0xF8EB,
+    0xF8F8,
+    0xF8F7,
+    0xF8F6,
+    0x2202,
+    0x22A5,
+    0x20A7,
+    0x03C6,
+    0x03D5,
+    0x03C0,
+    0x211E,
+    0x220F,
+    0x2282,
+    0x2283,
+    0x221D,
+    0x03C8,
+    0x201B,
+    0x0155,
+    0x221A,
+    0xF8E5,
+    0x0159,
+    0x0157,
+    0x2286,
+    0x2287,
+    0xF8E8,
+    0xF6DA,
+    0x2310,
+    0x03C1,
+    0x2590,
+    0x015B,
+    0x015F,
+    0x015F,
+    0x015D,
+    0x0219,
+    0x2033,
+    0x2592,
+    0x03C3,
+    0x03C2,
+    0x223C,
+    0x263A,
+    0x2660,
+    0x220B,
+    0x2211,
+    0x263C,
+    0x03C4,
+    0x0167,
+    0x0165,
+    0x0163,
+    0x0163,
+    0x2234,
+    0x03B8,
+    0x03D1,
+    0x0303,
+    0x0384,
+    0xF8EA,
+    0xF6DB,
+    0x25BC,
+    0x25C4,
+    0x25BA,
+    0x25B2,
+    0x016D,
+    0x01B0,
+    0x0171,
+    0x016B,
+    0x2017,
+    0x222A,
+    0x2200,
+    0x0173,
+    0x2580,
+    0x03C5,
+    0x03CB,
+    0x03B0,
+    0x03CD,
+    0x016F,
+    0x0169,
+    0x1E83,
+    0x0175,
+    0x1E85,
+    0x2118,
+    0x1E81,
+    0x03BE,
+    0x0177,
+    0x1EF3,
+    0x017A,
+    0x017C,
+    0x03B6,
+
+#endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
+    0
+  };
+
+
+
+  static const unsigned short  t1_standard_encoding[257] =
+  {
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    1,
+    2,
+    3,
+    4,
+    5,
+    6,
+    7,
+    8,
+    9,
+    10,
+    11,
+    12,
+    13,
+    14,
+    15,
+    16,
+    17,
+    18,
+    19,
+    20,
+    21,
+    22,
+    23,
+    24,
+    25,
+    26,
+    27,
+    28,
+    29,
+    30,
+    31,
+    32,
+    33,
+    34,
+    35,
+    36,
+    37,
+    38,
+    39,
+    40,
+    41,
+    42,
+    43,
+    44,
+    45,
+    46,
+    47,
+    48,
+    49,
+    50,
+    51,
+    52,
+    53,
+    54,
+    55,
+    56,
+    57,
+    58,
+    59,
+    60,
+    61,
+    62,
+    63,
+    64,
+    65,
+    66,
+    67,
+    68,
+    69,
+    70,
+    71,
+    72,
+    73,
+    74,
+    75,
+    76,
+    77,
+    78,
+    79,
+    80,
+    81,
+    82,
+    83,
+    84,
+    85,
+    86,
+    87,
+    88,
+    89,
+    90,
+    91,
+    92,
+    93,
+    94,
+    95,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    96,
+    97,
+    98,
+    99,
+    100,
+    101,
+    102,
+    103,
+    104,
+    105,
+    106,
+    107,
+    108,
+    109,
+    110,
+    0,
+    111,
+    112,
+    113,
+    114,
+    0,
+    115,
+    116,
+    117,
+    118,
+    119,
+    120,
+    121,
+    122,
+    0,
+    123,
+    0,
+    124,
+    125,
+    126,
+    127,
+    128,
+    129,
+    130,
+    131,
+    0,
+    132,
+    133,
+    0,
+    134,
+    135,
+    136,
+    137,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    138,
+    0,
+    139,
+    0,
+    0,
+    0,
+    0,
+    140,
+    141,
+    142,
+    143,
+    0,
+    0,
+    0,
+    0,
+    0,
+    144,
+    0,
+    0,
+    0,
+    145,
+    0,
+    0,
+    146,
+    147,
+    148,
+    149,
+    0,
+    0,
+    0,
+    0,
+    0
+  };
+
+
+  static const unsigned short  t1_expert_encoding[257] =
+  {
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    1,
+    229,
+    230,
+    0,
+    231,
+    232,
+    233,
+    234,
+    235,
+    236,
+    237,
+    238,
+    13,
+    14,
+    15,
+    99,
+    239,
+    240,
+    241,
+    242,
+    243,
+    244,
+    245,
+    246,
+    247,
+    248,
+    27,
+    28,
+    249,
+    250,
+    251,
+    252,
+    0,
+    253,
+    254,
+    255,
+    256,
+    257,
+    0,
+    0,
+    0,
+    258,
+    0,
+    0,
+    259,
+    260,
+    261,
+    262,
+    0,
+    0,
+    263,
+    264,
+    265,
+    0,
+    266,
+    109,
+    110,
+    267,
+    268,
+    269,
+    0,
+    270,
+    271,
+    272,
+    273,
+    274,
+    275,
+    276,
+    277,
+    278,
+    279,
+    280,
+    281,
+    282,
+    283,
+    284,
+    285,
+    286,
+    287,
+    288,
+    289,
+    290,
+    291,
+    292,
+    293,
+    294,
+    295,
+    296,
+    297,
+    298,
+    299,
+    300,
+    301,
+    302,
+    303,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    304,
+    305,
+    306,
+    0,
+    0,
+    307,
+    308,
+    309,
+    310,
+    311,
+    0,
+    312,
+    0,
+    0,
+    313,
+    0,
+    0,
+    314,
+    315,
+    0,
+    0,
+    316,
+    317,
+    318,
+    0,
+    0,
+    0,
+    158,
+    155,
+    163,
+    319,
+    320,
+    321,
+    322,
+    323,
+    324,
+    325,
+    0,
+    0,
+    326,
+    150,
+    164,
+    169,
+    327,
+    328,
+    329,
+    330,
+    331,
+    332,
+    333,
+    334,
+    335,
+    336,
+    337,
+    338,
+    339,
+    340,
+    341,
+    342,
+    343,
+    344,
+    345,
+    346,
+    347,
+    348,
+    349,
+    350,
+    351,
+    352,
+    353,
+    354,
+    355,
+    356,
+    357,
+    358,
+    359,
+    360,
+    361,
+    362,
+    363,
+    364,
+    365,
+    366,
+    367,
+    368,
+    369,
+    370,
+    371,
+    372,
+    373,
+    374,
+    375,
+    376,
+    377,
+    378,
+    0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/raster.c
@@ -1,0 +1,26 @@
+/***************************************************************************/
+/*                                                                         */
+/*  raster.c                                                               */
+/*                                                                         */
+/*    FreeType monochrome rasterer module component (body only).           */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftraster.c"
+#include "ftrend1.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/rasterrs.h
@@ -1,0 +1,41 @@
+/***************************************************************************/
+/*                                                                         */
+/*  rasterrs.h                                                             */
+/*                                                                         */
+/*    monochrome renderer error codes (specification only).                */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the monochrome renderer error enumeration */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __RASTERRS_H__
+#define __RASTERRS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  Raster_Err_
+#define FT_ERR_BASE    FT_Mod_Err_Raster
+
+#include FT_ERRORS_H
+
+#endif /* __RASTERRS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfdriver.c
@@ -1,0 +1,332 @@
+/***************************************************************************/
+/*                                                                         */
+/*  sfdriver.c                                                             */
+/*                                                                         */
+/*    High-level SFNT driver interface (body).                             */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "sfdriver.h"
+#include "ttload.h"
+#include "ttcmap.h"
+#include "sfobjs.h"
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#include "ttsbit.h"
+#endif
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+#include "ttpost.h"
+#endif
+
+
+  static void*
+  get_sfnt_table( TT_Face      face,
+                  FT_Sfnt_Tag  tag )
+  {
+    void*  table;
+
+
+    switch ( tag )
+    {
+    case ft_sfnt_head:
+      table = &face->header;
+      break;
+
+    case ft_sfnt_hhea:
+      table = &face->horizontal;
+      break;
+
+    case ft_sfnt_vhea:
+      table = face->vertical_info ? &face->vertical : 0;
+      break;
+
+    case ft_sfnt_os2:
+      table = face->os2.version == 0xFFFFU ? 0 : &face->os2;
+      break;
+
+    case ft_sfnt_post:
+      table = &face->postscript;
+      break;
+
+    case ft_sfnt_maxp:
+      table = &face->max_profile;
+      break;
+
+    case ft_sfnt_pclt:
+      table = face->pclt.Version ? &face->pclt : 0;
+      break;
+
+    default:
+      table = 0;
+    }
+
+    return table;
+  }
+
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+  static FT_Error
+  get_sfnt_glyph_name( TT_Face     face,
+                       FT_UInt     glyph_index,
+                       FT_Pointer  buffer,
+                       FT_UInt     buffer_max )
+  {
+    FT_String*  gname;
+    FT_Error    error;
+
+
+    error = tt_face_get_ps_name( face, glyph_index, &gname );
+    if ( !error && buffer_max > 0 )
+    {
+      FT_UInt  len = (FT_UInt)( ft_strlen( gname ) );
+
+
+      if ( len >= buffer_max )
+        len = buffer_max - 1;
+
+      FT_MEM_COPY( buffer, gname, len );
+      ((FT_Byte*)buffer)[len] = 0;
+    }
+
+    return error;
+  }
+
+
+  static const char*
+  get_sfnt_postscript_name( TT_Face  face )
+  {
+    FT_Int       n, found_win, found_apple;
+    const char*  result = NULL;
+
+
+    /* shouldn't happen, but just in case to avoid memory leaks */
+    if ( face->root.internal->postscript_name )
+      return face->root.internal->postscript_name;
+
+    /* scan the name table to see whether we have a Postscript name here, */
+    /* either in Macintosh or Windows platform encodings                  */
+    found_win   = -1;
+    found_apple = -1;
+
+    for ( n = 0; n < face->num_names; n++ )
+    {
+      TT_NameEntryRec*  name = face->name_table.names + n;
+
+
+      if ( name->nameID == 6 && name->stringLength > 0 )
+      {
+        if ( name->platformID == 3     &&
+             name->encodingID == 1     &&
+             name->languageID == 0x409 )
+          found_win = n;
+
+        if ( name->platformID == 1 &&
+             name->encodingID == 0 &&
+             name->languageID == 0 )
+          found_apple = n;
+      }
+    }
+
+    if ( found_win != -1 )
+    {
+      FT_Memory         memory = face->root.memory;
+      TT_NameEntryRec*  name   = face->name_table.names + found_win;
+      FT_UInt           len    = name->stringLength / 2;
+      FT_Error          error;
+
+
+      if ( !FT_ALLOC( result, name->stringLength + 1 ) )
+      {
+        FT_Stream   stream = face->name_table.stream;
+        FT_String*  r      = (FT_String*)result;
+        FT_Byte*    p      = (FT_Byte*)name->string;
+
+
+        if ( FT_STREAM_SEEK( name->stringOffset ) ||
+             FT_FRAME_ENTER( name->stringLength ) )
+        {
+          FT_FREE( result );
+          name->stringLength = 0;
+          name->stringOffset = 0;
+          FT_FREE( name->string );
+
+          goto Exit;
+        }
+
+        p = (FT_Byte*)stream->cursor;
+
+        for ( ; len > 0; len--, p += 2 )
+        {
+          if ( p[0] == 0 && p[1] >= 32 && p[1] < 128 )
+            *r++ = p[1];
+        }
+        *r = '\0';
+
+        FT_FRAME_EXIT();
+      }
+      goto Exit;
+    }
+
+    if ( found_apple != -1 )
+    {
+      FT_Memory         memory = face->root.memory;
+      TT_NameEntryRec*  name   = face->name_table.names + found_apple;
+      FT_UInt           len    = name->stringLength;
+      FT_Error          error;
+
+
+      if ( !FT_ALLOC( result, len + 1 ) )
+      {
+        FT_Stream  stream = face->name_table.stream;
+
+
+        if ( FT_STREAM_SEEK( name->stringOffset ) ||
+             FT_STREAM_READ( result, len )        )
+        {
+          name->stringOffset = 0;
+          name->stringLength = 0;
+          FT_FREE( name->string );
+          FT_FREE( result );
+          goto Exit;
+        }
+        ((char*)result)[len] = '\0';
+      }
+    }
+
+  Exit:
+    face->root.internal->postscript_name = result;
+    return result;
+  }
+
+
+#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+  FT_CALLBACK_DEF( FT_Module_Interface )
+  sfnt_get_interface( FT_Module    module,
+                      const char*  module_interface )
+  {
+    FT_UNUSED( module );
+
+    if ( ft_strcmp( module_interface, "get_sfnt" ) == 0 )
+      return (FT_Module_Interface)get_sfnt_table;
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+    if ( ft_strcmp( module_interface, "glyph_name" ) == 0 )
+      return (FT_Module_Interface)get_sfnt_glyph_name;
+#endif
+
+    if ( ft_strcmp( module_interface, "postscript_name" ) == 0 )
+      return (FT_Module_Interface)get_sfnt_postscript_name;
+
+    return 0;
+  }
+
+
+  static
+  const SFNT_Interface  sfnt_interface =
+  {
+    tt_face_goto_table,
+
+    sfnt_init_face,
+    sfnt_load_face,
+    sfnt_done_face,
+    sfnt_get_interface,
+
+    tt_face_load_any,
+    tt_face_load_sfnt_header,
+    tt_face_load_directory,
+
+    tt_face_load_header,
+    tt_face_load_metrics_header,
+    tt_face_load_cmap,
+    tt_face_load_max_profile,
+    tt_face_load_os2,
+    tt_face_load_postscript,
+
+    tt_face_load_names,
+    tt_face_free_names,
+
+    tt_face_load_hdmx,
+    tt_face_free_hdmx,
+
+    tt_face_load_kern,
+    tt_face_load_gasp,
+    tt_face_load_pclt,
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    /* see `ttload.h' */
+    tt_face_load_bitmap_header,
+
+    /* see `ttsbit.h' */
+    tt_face_set_sbit_strike,
+    tt_face_load_sbit_strikes,
+    tt_face_load_sbit_image,
+    tt_face_free_sbit_strikes,
+
+#else /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+    0,
+    0,
+    0,
+    0,
+    0,
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+    /* see `ttpost.h' */
+    tt_face_get_ps_name,
+    tt_face_free_ps_names,
+
+#else /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+    0,
+    0,
+
+#endif /* TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+    /* see `ttcmap.h' */
+    tt_face_load_charmap,
+    tt_face_free_charmap,
+  };
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Module_Class  sfnt_module_class =
+  {
+    0,  /* not a font driver or renderer */
+    sizeof( FT_ModuleRec ),
+
+    "sfnt",     /* driver name                            */
+    0x10000L,   /* driver version 1.0                     */
+    0x20000L,   /* driver requires FreeType 2.0 or higher */
+
+    (const void*)&sfnt_interface,  /* module specific interface */
+
+    (FT_Module_Constructor)0,
+    (FT_Module_Destructor) 0,
+    (FT_Module_Requester)  sfnt_get_interface
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfdriver.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/*                                                                         */
+/*  sfdriver.h                                                             */
+/*                                                                         */
+/*    High-level SFNT driver interface (specification).                    */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __SFDRIVER_H__
+#define __SFDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Module_Class )  sfnt_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __SFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sferrors.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/*                                                                         */
+/*  sferrors.h                                                             */
+/*                                                                         */
+/*    SFNT error codes (specification only).                               */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the SFNT error enumeration constants.     */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __SFERRORS_H__
+#define __SFERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  SFNT_Err_
+#define FT_ERR_BASE    FT_Mod_Err_SFNT
+
+#include FT_ERRORS_H
+
+#endif /* __SFERRORS_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfnt.c
@@ -1,0 +1,37 @@
+/***************************************************************************/
+/*                                                                         */
+/*  sfnt.c                                                                 */
+/*                                                                         */
+/*    Single object library component.                                     */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ttload.c"
+#include "ttcmap.c"
+#include "ttcmap0.c"
+#include "sfobjs.c"
+#include "sfdriver.c"
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+#include "ttsbit.c"
+#endif
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+#include "ttpost.c"
+#endif
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfobjs.c
@@ -1,0 +1,829 @@
+/***************************************************************************/
+/*                                                                         */
+/*  sfobjs.c                                                               */
+/*                                                                         */
+/*    SFNT object management (base).                                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "sfobjs.h"
+#include "ttload.h"
+#include "ttcmap0.h"
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_sfobjs
+
+
+
+  /* convert a UTF-16 name entry to ASCII */
+  static FT_String*
+  tt_name_entry_ascii_from_utf16( TT_NameEntry  entry,
+                                  FT_Memory     memory )
+  {
+    FT_String*  string;
+    FT_UInt     len, code, n;
+    FT_Byte*    read = (FT_Byte*)entry->string;
+
+
+    len = (FT_UInt)entry->stringLength / 2;
+
+    if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
+      return NULL;
+
+    for ( n = 0; n < len; n++ )
+    {
+      code = FT_NEXT_USHORT( read );
+      if ( code < 32 || code > 127 )
+        code = '?';
+
+      string[n] = (char)code;
+    }
+
+    string[len] = 0;
+
+    return string;
+  }
+
+
+  /* convert a UCS-4 name entry to ASCII */
+  static FT_String*
+  tt_name_entry_ascii_from_ucs4( TT_NameEntry  entry,
+                                 FT_Memory     memory )
+  {
+    FT_String*  string;
+    FT_UInt     len, code, n;
+    FT_Byte*    read = (FT_Byte*)entry->string;
+
+
+    len = (FT_UInt)entry->stringLength / 4;
+
+    if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
+      return NULL;
+
+    for ( n = 0; n < len; n++ )
+    {
+      code = (FT_UInt)FT_NEXT_ULONG( read );
+      if ( code < 32 || code > 127 )
+        code = '?';
+
+      string[n] = (char)code;
+    }
+
+    string[len] = 0;
+
+    return string;
+  }
+
+
+  /* convert an Apple Roman or symbol name entry to ASCII */
+  static FT_String*
+  tt_name_entry_ascii_from_other( TT_NameEntry  entry,
+                                  FT_Memory     memory )
+  {
+    FT_String*  string;
+    FT_UInt     len, code, n;
+    FT_Byte*    read = (FT_Byte*)entry->string;
+
+
+    len = (FT_UInt)entry->stringLength;
+
+    if ( FT_MEM_NEW_ARRAY( string, len + 1 ) )
+      return NULL;
+
+    for ( n = 0; n < len; n++ )
+    {
+      code = *read++;
+      if ( code < 32 || code > 127 )
+        code = '?';
+
+      string[n] = (char)code;
+    }
+
+    string[len] = 0;
+
+    return string;
+  }
+
+
+  typedef FT_String*  (*TT_NameEntry_ConvertFunc)( TT_NameEntry  entry,
+                                                   FT_Memory     memory );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_get_name                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Returns a given ENGLISH name record in ASCII.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the source face object.                      */
+  /*                                                                       */
+  /*    nameid :: The name id of the name record to return.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Character string.  NULL if no name is present.                     */
+  /*                                                                       */
+  static FT_String*
+  tt_face_get_name( TT_Face    face,
+                    FT_UShort  nameid )
+  {
+    FT_Memory         memory = face->root.memory;
+    FT_String*        result = NULL;
+    FT_UShort         n;
+    TT_NameEntryRec*  rec;
+    FT_Int            found_apple   = -1;
+    FT_Int            found_win     = -1;
+    FT_Int            found_unicode = -1;
+
+    TT_NameEntry_ConvertFunc  convert;
+
+
+    rec = face->name_table.names;
+    for ( n = 0; n < face->num_names; n++, rec++ )
+    {
+      /* According to the OpenType 1.3 specification, only Microsoft or  */
+      /* Apple platform IDs might be used in the `name' table.  The      */
+      /* `Unicode' platform is reserved for the `cmap' table, and the    */
+      /* `Iso' one is deprecated.                                        */
+      /*                                                                 */
+      /* However, the Apple TrueType specification doesn't say the same  */
+      /* thing and goes to suggest that all Unicode `name' table entries */
+      /* should be coded in UTF-16 (in big-endian format I suppose).     */
+      /*                                                                 */
+      if ( rec->nameID == nameid && rec->stringLength > 0 )
+      {
+        switch ( rec->platformID )
+        {
+        case TT_PLATFORM_APPLE_UNICODE:
+        case TT_PLATFORM_ISO:
+          /* there is `languageID' to check there.  We should use this */
+          /* field only as a last solution when nothing else is        */
+          /* available.                                                */
+          /*                                                           */
+          found_unicode = n;
+          break;
+
+        case TT_PLATFORM_MACINTOSH:
+          if ( rec->languageID == TT_MAC_LANGID_ENGLISH )
+            found_apple = n;
+
+          break;
+
+        case TT_PLATFORM_MICROSOFT:
+          /* we only take a non-English name when there is nothing */
+          /* else available in the font                            */
+          /*                                                       */
+          if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 )
+          {
+            switch ( rec->encodingID )
+            {
+            case TT_MS_ID_SYMBOL_CS:
+            case TT_MS_ID_UNICODE_CS:
+            case TT_MS_ID_UCS_4:
+              found_win = n;
+              break;
+
+            default:
+              ;
+            }
+          }
+          break;
+
+        default:
+          ;
+        }
+      }
+    }
+
+    /* some fonts contain invalid Unicode or Macintosh formatted entries; */
+    /* we will thus favor names encoded in Windows formats if available   */
+    /*                                                                    */
+    convert = NULL;
+    if ( found_win >= 0 )
+    {
+      rec = face->name_table.names + found_win;
+      switch ( rec->encodingID )
+      {
+      case TT_MS_ID_UNICODE_CS:
+      case TT_MS_ID_SYMBOL_CS:
+        convert = tt_name_entry_ascii_from_utf16;
+        break;
+
+      case TT_MS_ID_UCS_4:
+        convert = tt_name_entry_ascii_from_ucs4;
+        break;
+
+      default:
+        ;
+      }
+    }
+    else if ( found_apple >= 0 )
+    {
+      rec     = face->name_table.names + found_apple;
+      convert = tt_name_entry_ascii_from_other;
+    }
+    else if ( found_unicode >= 0 )
+    {
+      rec     = face->name_table.names + found_unicode;
+      convert = tt_name_entry_ascii_from_utf16;
+    }
+
+    if ( rec && convert )
+    {
+      if ( rec->string == NULL )
+      {
+        FT_Error   error;
+        FT_Stream  stream = face->name_table.stream;
+
+
+        if ( FT_NEW_ARRAY  ( rec->string, rec->stringLength ) ||
+             FT_STREAM_SEEK( rec->stringOffset )              ||
+             FT_STREAM_READ( rec->string, rec->stringLength ) )
+        {
+          FT_FREE( rec->string );
+          rec->stringLength = 0;
+          result            = NULL;
+          goto Exit;
+        }
+      }
+
+      result = convert( rec, memory );
+    }
+
+  Exit:
+    return result;
+  }
+
+
+  static FT_Encoding
+  sfnt_find_encoding( int  platform_id,
+                      int  encoding_id )
+  {
+    typedef struct  TEncoding
+    {
+      int          platform_id;
+      int          encoding_id;
+      FT_Encoding  encoding;
+
+    } TEncoding;
+
+    static
+    const TEncoding  tt_encodings[] =
+    {
+      { TT_PLATFORM_ISO,           -1,                  FT_ENCODING_UNICODE },
+
+      { TT_PLATFORM_APPLE_UNICODE, -1,                  FT_ENCODING_UNICODE },
+
+      { TT_PLATFORM_MACINTOSH,     TT_MAC_ID_ROMAN,     FT_ENCODING_APPLE_ROMAN },
+
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_SYMBOL_CS,  FT_ENCODING_MS_SYMBOL },
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_UCS_4,      FT_ENCODING_UNICODE },
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_UNICODE_CS, FT_ENCODING_UNICODE },
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_SJIS,       FT_ENCODING_MS_SJIS },
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_GB2312,     FT_ENCODING_MS_GB2312 },
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_BIG_5,      FT_ENCODING_MS_BIG5 },
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_WANSUNG,    FT_ENCODING_MS_WANSUNG },
+      { TT_PLATFORM_MICROSOFT,     TT_MS_ID_JOHAB,      FT_ENCODING_MS_JOHAB }
+    };
+
+    const TEncoding  *cur, *limit;
+
+
+    cur   = tt_encodings;
+    limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
+
+    for ( ; cur < limit; cur++ )
+    {
+      if ( cur->platform_id == platform_id )
+      {
+        if ( cur->encoding_id == encoding_id ||
+             cur->encoding_id == -1          )
+          return cur->encoding;
+      }
+    }
+
+    return FT_ENCODING_NONE;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  sfnt_init_face( FT_Stream      stream,
+                  TT_Face        face,
+                  FT_Int         face_index,
+                  FT_Int         num_params,
+                  FT_Parameter*  params )
+  {
+    FT_Error         error;
+    FT_Library       library = face->root.driver->root.library;
+    SFNT_Service     sfnt;
+    SFNT_HeaderRec   sfnt_header;
+
+    /* for now, parameters are unused */
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+
+
+    sfnt = (SFNT_Service)face->sfnt;
+    if ( !sfnt )
+    {
+      sfnt = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
+      if ( !sfnt )
+      {
+        error = SFNT_Err_Invalid_File_Format;
+        goto Exit;
+      }
+
+      face->sfnt       = sfnt;
+      face->goto_table = sfnt->goto_table;
+    }
+
+    if ( !face->psnames )
+    {
+      face->psnames = (PSNames_Service)
+                        FT_Get_Module_Interface( library, "psnames" );
+    }
+
+    /* check that we have a valid TrueType file */
+    error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header );
+    if ( error )
+      goto Exit;
+
+    face->format_tag = sfnt_header.format_tag;
+    face->num_tables = sfnt_header.num_tables;
+
+    /* Load font directory */
+    error = sfnt->load_directory( face, stream, &sfnt_header );
+    if ( error )
+      goto Exit;
+
+    face->root.num_faces = face->ttc_header.count;
+    if ( face->root.num_faces < 1 )
+      face->root.num_faces = 1;
+
+  Exit:
+    return error;
+  }
+
+
+#undef  LOAD_
+#define LOAD_( x )  ( ( error = sfnt->load_##x( face, stream ) ) \
+                      != SFNT_Err_Ok )
+
+
+  FT_LOCAL_DEF( FT_Error )
+  sfnt_load_face( FT_Stream      stream,
+                  TT_Face        face,
+                  FT_Int         face_index,
+                  FT_Int         num_params,
+                  FT_Parameter*  params )
+  {
+    FT_Error      error;
+    FT_Bool       has_outline;
+    FT_Bool       is_apple_sbit;
+
+    SFNT_Service  sfnt = (SFNT_Service)face->sfnt;
+
+    FT_UNUSED( face_index );
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+
+
+    /* Load tables */
+
+    /* We now support two SFNT-based bitmapped font formats.  They */
+    /* are recognized easily as they do not include a `glyf'       */
+    /* table.                                                      */
+    /*                                                             */
+    /* The first format comes from Apple, and uses a table named   */
+    /* `bhed' instead of `head' to store the font header (using    */
+    /* the same format).  It also doesn't include horizontal and   */
+    /* vertical metrics tables (i.e. `hhea' and `vhea' tables are  */
+    /* missing).                                                   */
+    /*                                                             */
+    /* The other format comes from Microsoft, and is used with     */
+    /* WinCE/PocketPC.  It looks like a standard TTF, except that  */
+    /* it doesn't contain outlines.                                */
+    /*                                                             */
+
+    /* do we have outlines in there? */
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    has_outline   = FT_BOOL( face->root.internal->incremental_interface != 0 ||
+                             tt_face_lookup_table( face, TTAG_glyf ) != 0         ||
+                             tt_face_lookup_table( face, TTAG_CFF ) != 0          );
+#else
+    has_outline   = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) != 0 ||
+                             tt_face_lookup_table( face, TTAG_CFF ) != 0  );
+#endif
+
+    is_apple_sbit = 0;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    /* if this font doesn't contain outlines, we try to load */
+    /* a `bhed' table                                        */
+    if ( !has_outline )
+      is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) );
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+    /* load the font header (`head' table) if this isn't an Apple */
+    /* sbit font file                                             */
+    if ( !is_apple_sbit && LOAD_( header ) )
+      goto Exit;
+
+    /* the following tables are often not present in embedded TrueType */
+    /* fonts within PDF documents, so don't check for them.            */
+    (void)LOAD_( max_profile );
+    (void)LOAD_( charmaps );
+
+    /* the following tables are optional in PCL fonts -- */
+    /* don't check for errors                            */
+    (void)LOAD_( names );
+    (void)LOAD_( psnames );
+
+    /* do not load the metrics headers and tables if this is an Apple */
+    /* sbit font file                                                 */
+    if ( !is_apple_sbit )
+    {
+      /* load the `hhea' and `hmtx' tables at once */
+      error = sfnt->load_metrics( face, stream, 0 );
+      if ( error )
+        goto Exit;
+
+      /* try to load the `vhea' and `vmtx' tables at once */
+      error = sfnt->load_metrics( face, stream, 1 );
+      if ( error )
+        goto Exit;
+
+      if ( LOAD_( os2 ) )
+        goto Exit;
+    }
+
+    /* the optional tables */
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    /* embedded bitmap support. */
+    if ( sfnt->load_sbits && LOAD_( sbits ) )
+    {
+      /* return an error if this font file has no outlines */
+      if ( error == SFNT_Err_Table_Missing && has_outline )
+        error = SFNT_Err_Ok;
+      else
+        goto Exit;
+    }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+    if ( LOAD_( hdmx )    ||
+         LOAD_( gasp )    ||
+         LOAD_( kerning ) ||
+         LOAD_( pclt )    )
+      goto Exit;
+
+    face->root.family_name = tt_face_get_name( face,
+                                               TT_NAME_ID_FONT_FAMILY );
+    face->root.style_name  = tt_face_get_name( face,
+                                               TT_NAME_ID_FONT_SUBFAMILY );
+
+    /* now set up root fields */
+    {
+      FT_Face    root = &face->root;
+      FT_Int32   flags = 0;
+      FT_Memory  memory;
+
+
+      memory = root->memory;
+
+      /*********************************************************************/
+      /*                                                                   */
+      /* Compute face flags.                                               */
+      /*                                                                   */
+      if ( has_outline == TRUE )
+        flags = FT_FACE_FLAG_SCALABLE;    /* scalable outlines */
+
+      flags |= FT_FACE_FLAG_SFNT      |   /* SFNT file format  */
+               FT_FACE_FLAG_HORIZONTAL;   /* horizontal data   */
+
+#ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
+      /* might need more polish to detect the presence of a Postscript */
+      /* name table in the font                                        */
+      flags |= FT_FACE_FLAG_GLYPH_NAMES;
+#endif
+
+      /* fixed width font? */
+      if ( face->postscript.isFixedPitch )
+        flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+      /* vertical information? */
+      if ( face->vertical_info )
+        flags |= FT_FACE_FLAG_VERTICAL;
+
+      /* kerning available ? */
+      if ( face->kern_pairs )
+        flags |= FT_FACE_FLAG_KERNING;
+
+      root->face_flags = flags;
+
+      /*********************************************************************/
+      /*                                                                   */
+      /* Compute style flags.                                              */
+      /*                                                                   */
+      flags = 0;
+      if ( has_outline == TRUE && face->os2.version != 0xFFFF )
+      {
+        /* we have an OS/2 table; use the `fsSelection' field */
+        if ( face->os2.fsSelection & 1 )
+          flags |= FT_STYLE_FLAG_ITALIC;
+
+        if ( face->os2.fsSelection & 32 )
+          flags |= FT_STYLE_FLAG_BOLD;
+      }
+      else
+      {
+        /* this is an old Mac font, use the header field */
+        if ( face->header.Mac_Style & 1 )
+          flags |= FT_STYLE_FLAG_BOLD;
+
+        if ( face->header.Mac_Style & 2 )
+          flags |= FT_STYLE_FLAG_ITALIC;
+      }
+
+      root->style_flags = flags;
+
+      /*********************************************************************/
+      /*                                                                   */
+      /* Polish the charmaps.                                              */
+      /*                                                                   */
+      /*   Try to set the charmap encoding according to the platform &     */
+      /*   encoding ID of each charmap.                                    */
+      /*                                                                   */
+
+      tt_face_build_cmaps( face );  /* ignore errors */
+
+
+      /* set the encoding fields */
+      {
+        FT_Int  m;
+
+
+        for ( m = 0; m < root->num_charmaps; m++ )
+        {
+          FT_CharMap  charmap = root->charmaps[m];
+
+
+          charmap->encoding = sfnt_find_encoding( charmap->platform_id,
+                                                  charmap->encoding_id );
+
+#if 0
+          if ( root->charmap     == NULL &&
+               charmap->encoding == FT_ENCODING_UNICODE )
+          {
+            /* set 'root->charmap' to the first Unicode encoding we find */
+            root->charmap = charmap;
+          }
+#endif
+        }
+      }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+      if ( face->num_sbit_strikes )
+      {
+        FT_ULong  n;
+
+
+        root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
+
+#if 0
+        /* XXX: I don't know criteria whether layout is horizontal */
+        /*      or vertical.                                       */
+        if ( has_outline.... )
+        {
+          ...
+          root->face_flags |= FT_FACE_FLAG_VERTICAL;
+        }
+#endif
+        root->num_fixed_sizes = face->num_sbit_strikes;
+
+        if ( FT_NEW_ARRAY( root->available_sizes, face->num_sbit_strikes ) )
+          goto Exit;
+
+        for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
+        {
+          root->available_sizes[n].width =
+            face->sbit_strikes[n].x_ppem;
+
+          root->available_sizes[n].height =
+            face->sbit_strikes[n].y_ppem;
+        }
+      }
+      else
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+      {
+        root->num_fixed_sizes = 0;
+        root->available_sizes = 0;
+      }
+
+      /*********************************************************************/
+      /*                                                                   */
+      /*  Set up metrics.                                                  */
+      /*                                                                   */
+      if ( has_outline == TRUE )
+      {
+        /* XXX What about if outline header is missing */
+        /*     (e.g. sfnt wrapped outline)?            */
+        root->bbox.xMin    = face->header.xMin;
+        root->bbox.yMin    = face->header.yMin;
+        root->bbox.xMax    = face->header.xMax;
+        root->bbox.yMax    = face->header.yMax;
+        root->units_per_EM = face->header.Units_Per_EM;
+
+
+        /* XXX: Computing the ascender/descender/height is very different */
+        /*      from what the specification tells you.  Apparently, we    */
+        /*      must be careful because                                   */
+        /*                                                                */
+        /*      - not all fonts have an OS/2 table; in this case, we take */
+        /*        the values in the horizontal header.  However, these    */
+        /*        values very often are not reliable.                     */
+        /*                                                                */
+        /*      - otherwise, the correct typographic values are in the    */
+        /*        sTypoAscender, sTypoDescender & sTypoLineGap fields.    */
+        /*                                                                */
+        /*        However, certains fonts have these fields set to 0.     */
+        /*        Rather, they have usWinAscent & usWinDescent correctly  */
+        /*        set (but with different values).                        */
+        /*                                                                */
+        /*      As an example, Arial Narrow is implemented through four   */
+        /*      files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
+        /*                                                                */
+        /*      Strangely, all fonts have the same values in their        */
+        /*      sTypoXXX fields, except ARIALNB which sets them to 0.     */
+        /*                                                                */
+        /*      On the other hand, they all have different                */
+        /*      usWinAscent/Descent values -- as a conclusion, the OS/2   */
+        /*      table cannot be used to compute the text height reliably! */
+        /*                                                                */
+
+        /* The ascender/descender/height are computed from the OS/2 table */
+        /* when found.  Otherwise, they're taken from the horizontal      */
+        /* header.                                                        */
+        /*                                                                */
+
+        root->ascender  = face->horizontal.Ascender;
+        root->descender = face->horizontal.Descender;
+
+        root->height    = (FT_Short)( root->ascender - root->descender +
+                                      face->horizontal.Line_Gap );
+
+        /* if the line_gap is 0, we add an extra 15% to the text height --  */
+        /* this computation is based on various versions of Times New Roman */
+        if ( face->horizontal.Line_Gap == 0 )
+          root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 );
+
+#if 0
+
+        /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */
+        /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF             */
+        if ( face->os2.version != 0xFFFF && root->ascender )
+        {
+          FT_Int  height;
+
+
+          root->ascender  =  face->os2.sTypoAscender;
+          root->descender = -face->os2.sTypoDescender;
+
+          height = root->ascender + root->descender + face->os2.sTypoLineGap;
+          if ( height > root->height )
+            root->height = height;
+        }
+
+#endif /* 0 */
+
+        root->max_advance_width   = face->horizontal.advance_Width_Max;
+
+        root->max_advance_height  = (FT_Short)( face->vertical_info
+                                      ? face->vertical.advance_Height_Max
+                                      : root->height );
+
+        root->underline_position  = face->postscript.underlinePosition;
+        root->underline_thickness = face->postscript.underlineThickness;
+
+        /* root->max_points   -- already set up */
+        /* root->max_contours -- already set up */
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+#undef LOAD_
+
+
+  FT_LOCAL_DEF( void )
+  sfnt_done_face( TT_Face  face )
+  {
+    FT_Memory     memory = face->root.memory;
+    SFNT_Service  sfnt   = (SFNT_Service)face->sfnt;
+
+
+    if ( sfnt )
+    {
+      /* destroy the postscript names table if it is loaded */
+      if ( sfnt->free_psnames )
+        sfnt->free_psnames( face );
+
+      /* destroy the embedded bitmaps table if it is loaded */
+      if ( sfnt->free_sbits )
+        sfnt->free_sbits( face );
+    }
+
+    /* freeing the kerning table */
+    FT_FREE( face->kern_pairs );
+    face->num_kern_pairs = 0;
+
+    /* freeing the collection table */
+    FT_FREE( face->ttc_header.offsets );
+    face->ttc_header.count = 0;
+
+    /* freeing table directory */
+    FT_FREE( face->dir_tables );
+    face->num_tables = 0;
+
+    {
+      FT_Stream  stream = FT_FACE_STREAM( face );
+
+
+      /* simply release the 'cmap' table frame */
+      FT_FRAME_RELEASE( face->cmap_table );
+      face->cmap_size = 0;
+    }
+
+    /* freeing the horizontal metrics */
+    FT_FREE( face->horizontal.long_metrics );
+    FT_FREE( face->horizontal.short_metrics );
+
+    /* freeing the vertical ones, if any */
+    if ( face->vertical_info )
+    {
+      FT_FREE( face->vertical.long_metrics  );
+      FT_FREE( face->vertical.short_metrics );
+      face->vertical_info = 0;
+    }
+
+    /* freeing the gasp table */
+    FT_FREE( face->gasp.gaspRanges );
+    face->gasp.numRanges = 0;
+
+    /* freeing the name table */
+    sfnt->free_names( face );
+
+    /* freeing the hdmx table */
+    sfnt->free_hdmx( face );
+
+    /* freeing family and style name */
+    FT_FREE( face->root.family_name );
+    FT_FREE( face->root.style_name );
+
+    /* freeing sbit size table */
+    face->root.num_fixed_sizes = 0;
+    if ( face->root.available_sizes )
+      FT_FREE( face->root.available_sizes );
+
+    face->sfnt = 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/sfobjs.h
@@ -1,0 +1,54 @@
+/***************************************************************************/
+/*                                                                         */
+/*  sfobjs.h                                                               */
+/*                                                                         */
+/*    SFNT object management (specification).                              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __SFOBJS_H__
+#define __SFOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  sfnt_init_face( FT_Stream      stream,
+                  TT_Face        face,
+                  FT_Int         face_index,
+                  FT_Int         num_params,
+                  FT_Parameter*  params );
+
+  FT_LOCAL( FT_Error )
+  sfnt_load_face( FT_Stream      stream,
+                  TT_Face        face,
+                  FT_Int         face_index,
+                  FT_Int         num_params,
+                  FT_Parameter*  params );
+
+  FT_LOCAL( void )
+  sfnt_done_face( TT_Face  face );
+
+
+FT_END_HEADER
+
+#endif /* __SFDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/smooth.c
@@ -1,0 +1,26 @@
+/***************************************************************************/
+/*                                                                         */
+/*  smooth.c                                                               */
+/*                                                                         */
+/*    FreeType anti-aliasing rasterer module component (body only).        */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ftgrays.c"
+#include "ftsmooth.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/stddef.h
@@ -1,0 +1,36 @@
+/* there's a better way.  we should use it. */
+#ifdef _STDDEF_H_
+#define	__STDDEF_H
+#endif
+#ifdef _SYS_TYPES_H_
+#define	__STDDEF_H
+#endif
+#ifdef _STDLIB_H_
+#define	__STDDEF_H
+#endif
+
+#ifndef __STDDEF_H
+#define __STDDEF_H	/* various */
+#define _STDDEF_H_	/* FreeBSD */
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef _PTRDIFF_T
+#define	_PTRDIFF_T
+typedef long ptrdiff_t;
+#endif
+#undef _BSD_PTRDIFF_T
+#ifndef _SIZE_T
+#define _SIZE_T
+typedef unsigned long size_t;
+#endif
+#undef _BSD_SIZE_T
+#ifndef _WCHAR_T
+#define _WCHAR_T
+typedef unsigned short wchar_t;
+#endif
+#undef _BSD_WCHAR_T
+
+#endif /* __STDDEF_H */
--- /dev/null
+++ b/libfreetype/t1afm.c
@@ -1,0 +1,282 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1afm.c                                                                */
+/*                                                                         */
+/*    AFM support for Type 1 fonts (body).                                 */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1afm.h"
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1afm
+
+
+  FT_LOCAL_DEF( void )
+  T1_Done_AFM( FT_Memory  memory,
+               T1_AFM*    afm )
+  {
+    FT_FREE( afm->kern_pairs );
+    afm->num_pairs = 0;
+    FT_FREE( afm );
+  }
+
+
+#undef  IS_KERN_PAIR
+#define IS_KERN_PAIR( p )  ( p[0] == 'K' && p[1] == 'P' )
+
+#define IS_ALPHANUM( c )  ( ft_isalnum( c ) || \
+                            c == '_'        || \
+                            c == '.'        )
+
+
+  /* read a glyph name and return the equivalent glyph index */
+  static FT_UInt
+  afm_atoindex( FT_Byte**  start,
+                FT_Byte*   limit,
+                T1_Font    type1 )
+  {
+    FT_Byte*    p = *start;
+    FT_PtrDist  len;
+    FT_UInt     result = 0;
+    char        temp[64];
+
+
+    /* skip whitespace */
+    while ( ( *p == ' ' || *p == '\t' || *p == ':' || *p == ';' ) &&
+            p < limit                                             )
+      p++;
+    *start = p;
+
+    /* now, read glyph name */
+    while ( IS_ALPHANUM( *p ) && p < limit )
+      p++;
+
+    len = p - *start;
+
+    if ( len > 0 && len < 64 )
+    {
+      FT_Int  n;
+
+
+      /* copy glyph name to intermediate array */
+      FT_MEM_COPY( temp, *start, len );
+      temp[len] = 0;
+
+      /* lookup glyph name in face array */
+      for ( n = 0; n < type1->num_glyphs; n++ )
+      {
+        char*  gname = (char*)type1->glyph_names[n];
+
+
+        if ( gname && gname[0] == temp[0] && ft_strcmp( gname, temp ) == 0 )
+        {
+          result = n;
+          break;
+        }
+      }
+    }
+    *start = p;
+    return result;
+  }
+
+
+  /* read an integer */
+  static int
+  afm_atoi( FT_Byte**  start,
+            FT_Byte*   limit )
+  {
+    FT_Byte*  p    = *start;
+    int       sum  = 0;
+    int       sign = 1;
+
+
+    /* skip everything that is not a number */
+    while ( p < limit && !isdigit( *p ) )
+    {
+      sign = 1;
+      if ( *p == '-' )
+        sign = -1;
+
+      p++;
+    }
+
+    while ( p < limit && isdigit( *p ) )
+    {
+      sum = sum * 10 + ( *p - '0' );
+      p++;
+    }
+    *start = p;
+
+    return sum * sign;
+  }
+
+
+#undef  KERN_INDEX
+#define KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
+
+
+  /* compare two kerning pairs */
+  FT_CALLBACK_DEF( int )
+  compare_kern_pairs( const void*  a,
+                      const void*  b )
+  {
+    T1_Kern_Pair*  pair1 = (T1_Kern_Pair*)a;
+    T1_Kern_Pair*  pair2 = (T1_Kern_Pair*)b;
+
+    FT_ULong  index1 = KERN_INDEX( pair1->glyph1, pair1->glyph2 );
+    FT_ULong  index2 = KERN_INDEX( pair2->glyph1, pair2->glyph2 );
+
+
+    return ( index1 - index2 );
+  }
+
+
+  /* parse an AFM file -- for now, only read the kerning pairs */
+  FT_LOCAL_DEF( FT_Error )
+  T1_Read_AFM( FT_Face    t1_face,
+               FT_Stream  stream )
+  {
+    FT_Error       error;
+    FT_Memory      memory = stream->memory;
+    FT_Byte*       start;
+    FT_Byte*       limit;
+    FT_Byte*       p;
+    FT_Int         count = 0;
+    T1_Kern_Pair*  pair;
+    T1_Font        type1 = &((T1_Face)t1_face)->type1;
+    T1_AFM*        afm   = 0;
+
+
+    if ( FT_FRAME_ENTER( stream->size ) )
+      return error;
+
+    start = (FT_Byte*)stream->cursor;
+    limit = (FT_Byte*)stream->limit;
+    p     = start;
+
+    /* we are now going to count the occurences of `KP' or `KPX' in */
+    /* the AFM file                                                 */
+    count = 0;
+    for ( p = start; p < limit - 3; p++ )
+    {
+      if ( IS_KERN_PAIR( p ) )
+        count++;
+    }
+
+    /* Actually, kerning pairs are simply optional! */
+    if ( count == 0 )
+      goto Exit;
+
+    /* allocate the pairs */
+    if ( FT_NEW( afm ) || FT_NEW_ARRAY( afm->kern_pairs, count ) )
+      goto Exit;
+
+    /* now, read each kern pair */
+    pair           = afm->kern_pairs;
+    afm->num_pairs = count;
+
+    /* save in face object */
+    ((T1_Face)t1_face)->afm_data = afm;
+
+    t1_face->face_flags |= FT_FACE_FLAG_KERNING;
+
+    for ( p = start; p < limit - 3; p++ )
+    {
+      if ( IS_KERN_PAIR( p ) )
+      {
+        FT_Byte*  q;
+
+
+        /* skip keyword (KP or KPX) */
+        q = p + 2;
+        if ( *q == 'X' )
+          q++;
+
+        pair->glyph1    = afm_atoindex( &q, limit, type1 );
+        pair->glyph2    = afm_atoindex( &q, limit, type1 );
+        pair->kerning.x = afm_atoi( &q, limit );
+
+        pair->kerning.y = 0;
+        if ( p[2] != 'X' )
+          pair->kerning.y = afm_atoi( &q, limit );
+
+        pair++;
+      }
+    }
+
+    /* now, sort the kern pairs according to their glyph indices */
+    ft_qsort( afm->kern_pairs, count, sizeof ( T1_Kern_Pair ),
+              compare_kern_pairs );
+
+  Exit:
+    if ( error )
+      FT_FREE( afm );
+
+    FT_FRAME_EXIT();
+
+    return error;
+  }
+
+
+  /* find the kerning for a given glyph pair */
+  FT_LOCAL_DEF( void )
+  T1_Get_Kerning( T1_AFM*     afm,
+                  FT_UInt     glyph1,
+                  FT_UInt     glyph2,
+                  FT_Vector*  kerning )
+  {
+    T1_Kern_Pair  *min, *mid, *max;
+    FT_ULong      idx = KERN_INDEX( glyph1, glyph2 );
+
+
+    /* simple binary search */
+    min = afm->kern_pairs;
+    max = min + afm->num_pairs - 1;
+
+    while ( min <= max )
+    {
+      FT_ULong  midi;
+
+
+      mid  = min + ( max - min ) / 2;
+      midi = KERN_INDEX( mid->glyph1, mid->glyph2 );
+
+      if ( midi == idx )
+      {
+        *kerning = mid->kerning;
+        return;
+      }
+
+      if ( midi < idx )
+        min = mid + 1;
+      else
+        max = mid - 1;
+    }
+
+    kerning->x = 0;
+    kerning->y = 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1afm.h
@@ -1,0 +1,66 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1afm.h                                                                */
+/*                                                                         */
+/*    AFM support for Type 1 fonts (specification).                        */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1AFM_H__
+#define __T1AFM_H__
+
+#include <ft2build.h>
+#include "t1objs.h"
+
+
+FT_BEGIN_HEADER
+
+
+  typedef struct  T1_Kern_Pair_
+  {
+    FT_UInt    glyph1;
+    FT_UInt    glyph2;
+    FT_Vector  kerning;
+
+  } T1_Kern_Pair;
+
+
+  typedef struct  T1_AFM_
+  {
+    FT_Int         num_pairs;
+    T1_Kern_Pair*  kern_pairs;
+
+  } T1_AFM;
+
+
+  FT_LOCAL( FT_Error )
+  T1_Read_AFM( FT_Face    face,
+               FT_Stream  stream );
+
+  FT_LOCAL( void )
+  T1_Done_AFM( FT_Memory  memory,
+               T1_AFM*    afm );
+
+  FT_LOCAL( void )
+  T1_Get_Kerning( T1_AFM*     afm,
+                  FT_UInt     glyph1,
+                  FT_UInt     glyph2,
+                  FT_Vector*  kerning );
+
+
+FT_END_HEADER
+
+#endif /* __T1AFM_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1cmap.c
@@ -1,0 +1,454 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1cmap.c                                                               */
+/*                                                                         */
+/*    Type 1 character map support (body).                                 */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "t1cmap.h"
+
+#include FT_INTERNAL_DEBUG_H
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****          TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  t1_cmap_std_init( T1_CMapStd  cmap,
+                    FT_Int      is_expert )
+  {
+    T1_Face          face    = (T1_Face)FT_CMAP_FACE( cmap );
+    PSNames_Service  psnames = (PSNames_Service)face->psnames;
+
+
+    cmap->num_glyphs    = face->type1.num_glyphs;
+    cmap->glyph_names   = (const char* const*)face->type1.glyph_names;
+    cmap->sid_to_string = psnames->adobe_std_strings;
+    cmap->code_to_sid   = is_expert ? psnames->adobe_expert_encoding
+                                    : psnames->adobe_std_encoding;
+
+    FT_ASSERT( cmap->code_to_sid != NULL );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  t1_cmap_std_done( T1_CMapStd  cmap )
+  {
+    cmap->num_glyphs    = 0;
+    cmap->glyph_names   = NULL;
+    cmap->sid_to_string = NULL;
+    cmap->code_to_sid   = NULL;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_std_char_index( T1_CMapStd  cmap,
+                          FT_UInt32   char_code )
+  {
+    FT_UInt  result = 0;
+
+
+    if ( char_code < 256 )
+    {
+      FT_UInt      code, n;
+      const char*  glyph_name;
+
+
+      /* convert character code to Adobe SID string */
+      code       = cmap->code_to_sid[char_code];
+      glyph_name = cmap->sid_to_string( code );
+
+      /* look for the corresponding glyph name */
+      for ( n = 0; n < cmap->num_glyphs; n++ )
+      {
+        const char* gname = cmap->glyph_names[n];
+
+
+        if ( gname && gname[0] == glyph_name[0]  &&
+             ft_strcmp( gname, glyph_name ) == 0 )
+        {
+          result = n;
+          break;
+        }
+      }
+    }
+
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_std_char_next( T1_CMapStd   cmap,
+                         FT_UInt32   *pchar_code )
+  {
+    FT_UInt    result    = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+
+
+    while ( char_code < 256 )
+    {
+      result = t1_cmap_std_char_index( cmap, char_code );
+      if ( result != 0 )
+        goto Exit;
+
+      char_code++;
+    }
+    char_code = 0;
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  t1_cmap_standard_init( T1_CMapStd  cmap )
+  {
+    t1_cmap_std_init( cmap, 0 );
+    return 0;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+  t1_cmap_standard_class_rec =
+  {
+    sizeof ( T1_CMapStdRec ),
+
+    (FT_CMap_InitFunc)     t1_cmap_standard_init,
+    (FT_CMap_DoneFunc)     t1_cmap_std_done,
+    (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
+    (FT_CMap_CharNextFunc) t1_cmap_std_char_next
+  };
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  t1_cmap_expert_init( T1_CMapStd  cmap )
+  {
+    t1_cmap_std_init( cmap, 1 );
+    return 0;
+  }
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+  t1_cmap_expert_class_rec =
+  {
+    sizeof ( T1_CMapStdRec ),
+
+    (FT_CMap_InitFunc)     t1_cmap_expert_init,
+    (FT_CMap_DoneFunc)     t1_cmap_std_done,
+    (FT_CMap_CharIndexFunc)t1_cmap_std_char_index,
+    (FT_CMap_CharNextFunc) t1_cmap_std_char_next
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    TYPE1 CUSTOM ENCODING CMAP                 *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  t1_cmap_custom_init( T1_CMapCustom  cmap )
+  {
+    T1_Face      face     = (T1_Face)FT_CMAP_FACE( cmap );
+    T1_Encoding  encoding = &face->type1.encoding;
+
+
+    cmap->first   = encoding->code_first;
+    cmap->count   = (FT_UInt)( encoding->code_last - cmap->first + 1 );
+    cmap->indices = encoding->char_index;
+
+    FT_ASSERT( cmap->indices != NULL );
+    FT_ASSERT( encoding->code_first <= encoding->code_last );
+
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  t1_cmap_custom_done( T1_CMapCustom  cmap )
+  {
+    cmap->indices = NULL;
+    cmap->first   = 0;
+    cmap->count   = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_custom_char_index( T1_CMapCustom  cmap,
+                             FT_UInt32      char_code )
+  {
+    FT_UInt    result = 0;
+
+
+    if ( ( char_code >= cmap->first )                  &&
+         ( char_code < ( cmap->first + cmap->count ) ) )
+      result = cmap->indices[char_code];
+
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_custom_char_next( T1_CMapCustom  cmap,
+                            FT_UInt32     *pchar_code )
+  {
+    FT_UInt    result = 0;
+    FT_UInt32  char_code = *pchar_code;
+
+
+    ++char_code;
+
+    if ( char_code < cmap->first )
+      char_code = cmap->first;
+
+    for ( ; char_code < ( cmap->first + cmap->count ); char_code++ )
+    {
+      result = cmap->indices[char_code];
+      if ( result != 0 )
+        goto Exit;
+    }
+
+    char_code = 0;
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+  t1_cmap_custom_class_rec =
+  {
+    sizeof ( T1_CMapCustomRec ),
+
+    (FT_CMap_InitFunc)     t1_cmap_custom_init,
+    (FT_CMap_DoneFunc)     t1_cmap_custom_done,
+    (FT_CMap_CharIndexFunc)t1_cmap_custom_char_index,
+    (FT_CMap_CharNextFunc) t1_cmap_custom_char_next
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****            TYPE1 SYNTHETIC UNICODE ENCODING CMAP              *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_CALLBACK_DEF( FT_Int )
+  t1_cmap_uni_pair_compare( const void*  pair1,
+                            const void*  pair2 )
+  {
+    FT_UInt32  u1 = ((T1_CMapUniPair)pair1)->unicode;
+    FT_UInt32  u2 = ((T1_CMapUniPair)pair2)->unicode;
+    
+
+    if ( u1 < u2 )
+      return -1;
+      
+    if ( u1 > u2 )
+      return +1;
+      
+    return 0;
+  }                            
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  t1_cmap_unicode_init( T1_CMapUnicode  cmap )
+  {
+    FT_Error         error;
+    FT_UInt          count;
+    T1_Face          face    = (T1_Face)FT_CMAP_FACE( cmap );
+    FT_Memory        memory  = FT_FACE_MEMORY( face );
+    PSNames_Service  psnames = (PSNames_Service)face->psnames;
+
+
+    cmap->num_pairs = 0;
+    cmap->pairs     = NULL;
+
+    count = face->type1.num_glyphs;
+
+    if ( !FT_NEW_ARRAY( cmap->pairs, count ) )
+    {
+      FT_UInt         n, new_count;
+      T1_CMapUniPair  pair;
+      FT_UInt32       uni_code;
+
+
+      pair = cmap->pairs;
+      for ( n = 0; n < count; n++ )
+      {
+        const char*  gname = face->type1.glyph_names[n];
+
+
+        /* build unsorted pair table by matching glyph names */
+        if ( gname )
+        {
+          uni_code = psnames->unicode_value( gname );
+
+          if ( uni_code != 0 )
+          {
+            pair->unicode = uni_code;
+            pair->gindex  = n;
+            pair++;
+          }
+        }
+      }
+      
+      new_count = (FT_UInt)( pair - cmap->pairs );
+      if ( new_count == 0 )
+      {
+        /* there are no unicode characters in here! */
+        FT_FREE( cmap->pairs );
+        error = FT_Err_Invalid_Argument;
+      }
+      else
+      {
+        /* re-allocate if the new array is much smaller than the original */
+        /* one                                                            */
+        if ( new_count != count && new_count < count / 2 )
+        {
+          (void)FT_RENEW_ARRAY( cmap->pairs, count, new_count );
+          error = 0;
+        }
+
+        /* sort the pairs table to allow efficient binary searches */
+        ft_qsort( cmap->pairs,
+                  new_count,
+                  sizeof ( T1_CMapUniPairRec ),
+                  t1_cmap_uni_pair_compare );
+
+        cmap->num_pairs = new_count;
+      }
+    }
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  t1_cmap_unicode_done( T1_CMapUnicode  cmap )
+  {
+    FT_Face    face   = FT_CMAP_FACE(cmap);
+    FT_Memory  memory = FT_FACE_MEMORY(face);
+
+    FT_FREE( cmap->pairs );
+    cmap->num_pairs = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_unicode_char_index( T1_CMapUnicode  cmap,
+                              FT_UInt32       char_code )
+  {
+    FT_UInt         min = 0;
+    FT_UInt         max = cmap->num_pairs;
+    FT_UInt         mid;
+    T1_CMapUniPair  pair;
+
+
+    while ( min < max )
+    {
+      mid  = min + ( max - min ) / 2;
+      pair = cmap->pairs + mid;
+
+      if ( pair->unicode == char_code )
+        return pair->gindex;
+
+      if ( pair->unicode < char_code )
+        min = mid + 1;
+      else
+        max = mid;
+    }
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_unicode_char_next( T1_CMapUnicode  cmap,
+                             FT_UInt32      *pchar_code )
+  {
+    FT_UInt    result    = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+
+
+  Restart:
+    {
+      FT_UInt         min = 0;
+      FT_UInt         max = cmap->num_pairs;
+      FT_UInt         mid;
+      T1_CMapUniPair  pair;
+
+
+      while ( min < max )
+      {
+        mid  = min + ( ( max - min ) >> 1 );
+        pair = cmap->pairs + mid;
+
+        if ( pair->unicode == char_code )
+        {
+          result = pair->gindex;
+          if ( result != 0 )
+            goto Exit;
+
+          char_code++;
+          goto Restart;
+        }
+
+        if ( pair->unicode < char_code )
+          min = mid+1;
+        else
+          max = mid;
+      }
+
+      /* we didn't find it, but we have a pair just above it */
+      char_code = 0;
+
+      if ( min < cmap->num_pairs )
+      {
+        pair   = cmap->pairs + min;
+        result = pair->gindex;
+        if ( result != 0 )
+          char_code = pair->unicode;
+      }
+    }
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF const FT_CMap_ClassRec
+  t1_cmap_unicode_class_rec =
+  {
+    sizeof ( T1_CMapUnicodeRec ),
+
+    (FT_CMap_InitFunc)     t1_cmap_unicode_init,
+    (FT_CMap_DoneFunc)     t1_cmap_unicode_done,
+    (FT_CMap_CharIndexFunc)t1_cmap_unicode_char_index,
+    (FT_CMap_CharNextFunc) t1_cmap_unicode_char_next
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1cmap.h
@@ -1,0 +1,124 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1cmap.h                                                               */
+/*                                                                         */
+/*    Type 1 character map support (specification).                        */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1CMAP_H__
+#define __T1CMAP_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****          TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* standard (and expert) encoding cmaps */
+  typedef struct T1_CMapStdRec_*  T1_CMapStd;
+
+  typedef struct  T1_CMapStdRec_
+  {
+    FT_CMapRec                 cmap;
+
+    const FT_UShort*           code_to_sid;
+    PS_Adobe_Std_Strings_Func  sid_to_string;
+
+    FT_UInt                    num_glyphs;
+    const char* const*         glyph_names;
+    
+  } T1_CMapStdRec;
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  t1_cmap_standard_class_rec;
+  
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  t1_cmap_expert_class_rec;
+  
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                  TYPE1 CUSTOM ENCODING CMAP                   *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct T1_CMapCustomRec_*  T1_CMapCustom;
+  
+  typedef struct  T1_CMapCustomRec_
+  {
+    FT_CMapRec  cmap;
+    FT_UInt     first;
+    FT_UInt     count;
+    FT_UShort*  indices;
+  
+  } T1_CMapCustomRec;
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  t1_cmap_custom_class_rec;
+  
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****             TYPE1 SYNTHETIC UNICODE ENCODING CMAP             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* unicode (syntehtic) cmaps */
+  typedef struct T1_CMapUnicodeRec_*  T1_CMapUnicode;
+
+  typedef struct  T1_CMapUniPairRec_
+  {
+    FT_UInt32  unicode;
+    FT_UInt    gindex;
+  
+  } T1_CMapUniPairRec, *T1_CMapUniPair;
+
+
+  typedef struct  T1_CMapUnicodeRec_
+  {
+    FT_CMapRec      cmap;
+    FT_UInt         num_pairs;
+    T1_CMapUniPair  pairs;
+
+  } T1_CMapUnicodeRec;
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  t1_cmap_unicode_class_rec;
+
+ /* */
+
+ 
+FT_END_HEADER
+
+#endif /* __T1CMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1decode.c
@@ -1,0 +1,1170 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1decode.c                                                             */
+/*                                                                         */
+/*    PostScript Type 1 decoding routines (body).                          */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+#include FT_OUTLINE_H
+
+#include "t1decode.h"
+#include "psobjs.h"
+
+#include "psauxerr.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1decode
+
+
+  typedef enum  T1_Operator_
+  {
+    op_none = 0,
+    op_endchar,
+    op_hsbw,
+    op_seac,
+    op_sbw,
+    op_closepath,
+    op_hlineto,
+    op_hmoveto,
+    op_hvcurveto,
+    op_rlineto,
+    op_rmoveto,
+    op_rrcurveto,
+    op_vhcurveto,
+    op_vlineto,
+    op_vmoveto,
+    op_dotsection,
+    op_hstem,
+    op_hstem3,
+    op_vstem,
+    op_vstem3,
+    op_div,
+    op_callothersubr,
+    op_callsubr,
+    op_pop,
+    op_return,
+    op_setcurrentpoint,
+
+    op_max    /* never remove this one */
+
+  } T1_Operator;
+
+
+  static
+  const FT_Int  t1_args_count[op_max] =
+  {
+    0, /* none */
+    0, /* endchar */
+    2, /* hsbw */
+    5, /* seac */
+    4, /* sbw */
+    0, /* closepath */
+    1, /* hlineto */
+    1, /* hmoveto */
+    4, /* hvcurveto */
+    2, /* rlineto */
+    2, /* rmoveto */
+    6, /* rrcurveto */
+    4, /* vhcurveto */
+    1, /* vlineto */
+    1, /* vmoveto */
+    0, /* dotsection */
+    2, /* hstem */
+    6, /* hstem3 */
+    2, /* vstem */
+    6, /* vstem3 */
+    2, /* div */
+   -1, /* callothersubr */
+    1, /* callsubr */
+    0, /* pop */
+    0, /* return */
+    2  /* setcurrentpoint */
+  };
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    t1_lookup_glyph_by_stdcharcode                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Looks up a given glyph by its StandardEncoding charcode.  Used to  */
+  /*    implement the SEAC Type 1 operator.                                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: The current face object.                               */
+  /*                                                                       */
+  /*    charcode :: The character code to look for.                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    A glyph index in the font face.  Returns -1 if the corresponding   */
+  /*    glyph wasn't found.                                                */
+  /*                                                                       */
+  static FT_Int
+  t1_lookup_glyph_by_stdcharcode( T1_Decoder  decoder,
+                                  FT_Int      charcode )
+  {
+    FT_UInt           n;
+    const FT_String*  glyph_name;
+    PSNames_Service   psnames = decoder->psnames;
+
+
+    /* check range of standard char code */
+    if ( charcode < 0 || charcode > 255 )
+      return -1;
+
+    glyph_name = psnames->adobe_std_strings(
+                   psnames->adobe_std_encoding[charcode]);
+
+    for ( n = 0; n < decoder->num_glyphs; n++ )
+    {
+      FT_String*  name = (FT_String*)decoder->glyph_names[n];
+
+
+      if ( name && name[0] == glyph_name[0]  &&
+           ft_strcmp( name,glyph_name ) == 0 )
+        return n;
+    }
+
+    return -1;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    t1operator_seac                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Implements the `seac' Type 1 operator for a Type 1 decoder.        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    decoder :: The current CID decoder.                                */
+  /*                                                                       */
+  /*    asb     :: The accent's side bearing.                              */
+  /*                                                                       */
+  /*    adx     :: The horizontal offset of the accent.                    */
+  /*                                                                       */
+  /*    ady     :: The vertical offset of the accent.                      */
+  /*                                                                       */
+  /*    bchar   :: The base character's StandardEncoding charcode.         */
+  /*                                                                       */
+  /*    achar   :: The accent character's StandardEncoding charcode.       */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  t1operator_seac( T1_Decoder  decoder,
+                   FT_Pos      asb,
+                   FT_Pos      adx,
+                   FT_Pos      ady,
+                   FT_Int      bchar,
+                   FT_Int      achar )
+  {
+    FT_Error     error;
+    FT_Int       bchar_index, achar_index;
+#if 0
+    FT_Int       n_base_points;
+    FT_Outline*  base = decoder->builder.base;
+#endif
+    FT_Vector    left_bearing, advance;
+
+
+    /* seac weirdness */
+    adx += decoder->builder.left_bearing.x;
+
+    /* `glyph_names' is set to 0 for CID fonts which do not */
+    /* include an encoding.  How can we deal with these?    */
+    if ( decoder->glyph_names == 0 )
+    {
+      FT_ERROR(( "t1operator_seac:" ));
+      FT_ERROR(( " glyph names table not available in this font!\n" ));
+      return PSaux_Err_Syntax_Error;
+    }
+
+    bchar_index = t1_lookup_glyph_by_stdcharcode( decoder, bchar );
+    achar_index = t1_lookup_glyph_by_stdcharcode( decoder, achar );
+
+    if ( bchar_index < 0 || achar_index < 0 )
+    {
+      FT_ERROR(( "t1operator_seac:" ));
+      FT_ERROR(( " invalid seac character code arguments\n" ));
+      return PSaux_Err_Syntax_Error;
+    }
+
+    /* if we are trying to load a composite glyph, do not load the */
+    /* accent character and return the array of subglyphs.         */
+    if ( decoder->builder.no_recurse )
+    {
+      FT_GlyphSlot    glyph  = (FT_GlyphSlot)decoder->builder.glyph;
+      FT_GlyphLoader  loader = glyph->internal->loader;
+      FT_SubGlyph     subg;
+
+
+      /* reallocate subglyph array if necessary */
+      error = FT_GlyphLoader_CheckSubGlyphs( loader, 2 );
+      if ( error )
+        goto Exit;
+
+      subg = loader->current.subglyphs;
+
+      /* subglyph 0 = base character */
+      subg->index = bchar_index;
+      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES |
+                    FT_SUBGLYPH_FLAG_USE_MY_METRICS;
+      subg->arg1  = 0;
+      subg->arg2  = 0;
+      subg++;
+
+      /* subglyph 1 = accent character */
+      subg->index = achar_index;
+      subg->flags = FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES;
+      subg->arg1  = adx - asb;
+      subg->arg2  = ady;
+
+      /* set up remaining glyph fields */
+      glyph->num_subglyphs = 2;
+      glyph->subglyphs     = loader->base.subglyphs;
+      glyph->format        = FT_GLYPH_FORMAT_COMPOSITE;
+
+      loader->current.num_subglyphs = 2;
+      goto Exit;
+    }
+
+    /* First load `bchar' in builder */
+    /* now load the unscaled outline */
+
+    FT_GlyphLoader_Prepare( decoder->builder.loader );  /* prepare loader */
+
+    error = t1_decoder_parse_glyph( decoder, bchar_index );
+    if ( error )
+      goto Exit;
+
+#if 0
+    n_base_points = base->n_points;
+#endif
+
+    /* save the left bearing and width of the base character */
+    /* as they will be erased by the next load.              */
+
+    left_bearing = decoder->builder.left_bearing;
+    advance      = decoder->builder.advance;
+
+    decoder->builder.left_bearing.x = 0;
+    decoder->builder.left_bearing.y = 0;
+
+    decoder->builder.pos_x = adx - asb;
+    decoder->builder.pos_y = ady;
+
+    /* Now load `achar' on top of */
+    /* the base outline           */
+    error = t1_decoder_parse_glyph( decoder, achar_index );
+    if ( error )
+      goto Exit;
+
+    /* restore the left side bearing and   */
+    /* advance width of the base character */
+
+    decoder->builder.left_bearing = left_bearing;
+    decoder->builder.advance      = advance;
+
+    /* XXX: old code doesn't work with PostScript hinter */
+#if 0
+    /* Finally, move the accent */
+    if ( decoder->builder.load_points )
+    {
+      FT_Outline  dummy;
+
+
+      dummy.n_points = (short)( base->n_points - n_base_points );
+      dummy.points   = base->points + n_base_points;
+
+      FT_Outline_Translate( &dummy, adx - asb, ady );
+    }
+#else
+    decoder->builder.pos_x = 0;
+    decoder->builder.pos_y = 0;
+#endif
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    t1_decoder_parse_charstrings                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Parses a given Type 1 charstrings program.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    decoder         :: The current Type 1 decoder.                     */
+  /*                                                                       */
+  /*    charstring_base :: The base address of the charstring stream.      */
+  /*                                                                       */
+  /*    charstring_len  :: The length in bytes of the charstring stream.   */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  t1_decoder_parse_charstrings( T1_Decoder  decoder,
+                                FT_Byte*    charstring_base,
+                                FT_UInt     charstring_len )
+  {
+    FT_Error         error;
+    T1_Decoder_Zone  zone;
+    FT_Byte*         ip;
+    FT_Byte*         limit;
+    T1_Builder       builder = &decoder->builder;
+    FT_Pos           x, y, orig_x, orig_y;
+
+    T1_Hints_Funcs   hinter;
+
+
+    /* we don't want to touch the source code -- use macro trick */
+#define start_point    t1_builder_start_point
+#define check_points   t1_builder_check_points
+#define add_point      t1_builder_add_point
+#define add_point1     t1_builder_add_point1
+#define add_contour    t1_builder_add_contour
+#define close_contour  t1_builder_close_contour
+
+    /* First of all, initialize the decoder */
+    decoder->top  = decoder->stack;
+    decoder->zone = decoder->zones;
+    zone          = decoder->zones;
+
+    builder->path_begun  = 0;
+
+    hinter = (T1_Hints_Funcs)builder->hints_funcs;
+
+    zone->base           = charstring_base;
+    limit = zone->limit  = charstring_base + charstring_len;
+    ip    = zone->cursor = zone->base;
+
+    error = PSaux_Err_Ok;
+
+    x = orig_x = builder->pos_x;
+    y = orig_y = builder->pos_y;
+
+    /* begin hints recording session, if any */
+    if ( hinter )
+      hinter->open( hinter->hints );
+
+    /* now, execute loop */
+    while ( ip < limit )
+    {
+      FT_Long*     top   = decoder->top;
+      T1_Operator  op    = op_none;
+      FT_Long      value = 0;
+
+
+      /*********************************************************************/
+      /*                                                                   */
+      /* Decode operator or operand                                        */
+      /*                                                                   */
+      /*                                                                   */
+
+      /* first of all, decompress operator or value */
+      switch ( *ip++ )
+      {
+      case 1:
+        op = op_hstem;
+        break;
+
+      case 3:
+        op = op_vstem;
+        break;
+      case 4:
+        op = op_vmoveto;
+        break;
+      case 5:
+        op = op_rlineto;
+        break;
+      case 6:
+        op = op_hlineto;
+        break;
+      case 7:
+        op = op_vlineto;
+        break;
+      case 8:
+        op = op_rrcurveto;
+        break;
+      case 9:
+        op = op_closepath;
+        break;
+      case 10:
+        op = op_callsubr;
+        break;
+      case 11:
+        op = op_return;
+        break;
+
+      case 13:
+        op = op_hsbw;
+        break;
+      case 14:
+        op = op_endchar;
+        break;
+
+      case 15:          /* undocumented, obsolete operator */
+        op = op_none;
+        break;
+
+      case 21:
+        op = op_rmoveto;
+        break;
+      case 22:
+        op = op_hmoveto;
+        break;
+
+      case 30:
+        op = op_vhcurveto;
+        break;
+      case 31:
+        op = op_hvcurveto;
+        break;
+
+      case 12:
+        if ( ip > limit )
+        {
+          FT_ERROR(( "t1_decoder_parse_charstrings: "
+                     "invalid escape (12+EOF)\n" ));
+          goto Syntax_Error;
+        }
+
+        switch ( *ip++ )
+        {
+        case 0:
+          op = op_dotsection;
+          break;
+        case 1:
+          op = op_vstem3;
+          break;
+        case 2:
+          op = op_hstem3;
+          break;
+        case 6:
+          op = op_seac;
+          break;
+        case 7:
+          op = op_sbw;
+          break;
+        case 12:
+          op = op_div;
+          break;
+        case 16:
+          op = op_callothersubr;
+          break;
+        case 17:
+          op = op_pop;
+          break;
+        case 33:
+          op = op_setcurrentpoint;
+          break;
+
+        default:
+          FT_ERROR(( "t1_decoder_parse_charstrings: "
+                     "invalid escape (12+%d)\n",
+                     ip[-1] ));
+          goto Syntax_Error;
+        }
+        break;
+
+      case 255:    /* four bytes integer */
+        if ( ip + 4 > limit )
+        {
+          FT_ERROR(( "t1_decoder_parse_charstrings: "
+                     "unexpected EOF in integer\n" ));
+          goto Syntax_Error;
+        }
+
+        value = (FT_Int32)( ((FT_Long)ip[0] << 24) |
+                            ((FT_Long)ip[1] << 16) |
+                            ((FT_Long)ip[2] << 8 ) |
+                                      ip[3] );
+        ip += 4;
+        break;
+
+      default:
+        if ( ip[-1] >= 32 )
+        {
+          if ( ip[-1] < 247 )
+            value = (FT_Long)ip[-1] - 139;
+          else
+          {
+            if ( ++ip > limit )
+            {
+              FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+              FT_ERROR(( "unexpected EOF in integer\n" ));
+              goto Syntax_Error;
+            }
+
+            if ( ip[-2] < 251 )
+              value =  ( ( (FT_Long)ip[-2] - 247 ) << 8 ) + ip[-1] + 108;
+            else
+              value = -( ( ( (FT_Long)ip[-2] - 251 ) << 8 ) + ip[-1] + 108 );
+          }
+        }
+        else
+        {
+          FT_ERROR(( "t1_decoder_parse_charstrings: "
+                     "invalid byte (%d)\n", ip[-1] ));
+          goto Syntax_Error;
+        }
+      }
+
+      /*********************************************************************/
+      /*                                                                   */
+      /*  Push value on stack, or process operator                         */
+      /*                                                                   */
+      /*                                                                   */
+      if ( op == op_none )
+      {
+        if ( top - decoder->stack >= T1_MAX_CHARSTRINGS_OPERANDS )
+        {
+          FT_ERROR(( "t1_decoder_parse_charstrings: stack overflow!\n" ));
+          goto Syntax_Error;
+        }
+
+        FT_TRACE4(( " %ld", value ));
+
+        *top++       = value;
+        decoder->top = top;
+      }
+      else if ( op == op_callothersubr )  /* callothersubr */
+      {
+        FT_TRACE4(( " callothersubr" ));
+
+        if ( top - decoder->stack < 2 )
+          goto Stack_Underflow;
+
+        top -= 2;
+        switch ( top[1] )
+        {
+        case 1:                     /* start flex feature */
+          if ( top[0] != 0 )
+            goto Unexpected_OtherSubr;
+
+          decoder->flex_state        = 1;
+          decoder->num_flex_vectors  = 0;
+          if ( start_point( builder, x, y ) ||
+               check_points( builder, 6 )   )
+            goto Memory_Error;
+          break;
+
+        case 2:                     /* add flex vectors */
+          {
+            FT_Int  idx;
+
+
+            if ( top[0] != 0 )
+              goto Unexpected_OtherSubr;
+
+            /* note that we should not add a point for index 0; */
+            /* this will move our current position to the flex  */
+            /* point without adding any point to the outline    */
+            idx = decoder->num_flex_vectors++;
+            if ( idx > 0 && idx < 7 )
+              add_point( builder,
+                         x,
+                         y,
+                         (FT_Byte)( idx == 3 || idx == 6 ) );
+          }
+          break;
+
+        case 0:                     /* end flex feature */
+          if ( top[0] != 3 )
+            goto Unexpected_OtherSubr;
+
+          if ( decoder->flex_state       == 0 ||
+               decoder->num_flex_vectors != 7 )
+          {
+            FT_ERROR(( "t1_decoder_parse_charstrings: "
+                       "unexpected flex end\n" ));
+            goto Syntax_Error;
+          }
+
+          /* now consume the remaining `pop pop setcurpoint' */
+          if ( ip + 6 > limit ||
+               ip[0] != 12 || ip[1] != 17 || /* pop */
+               ip[2] != 12 || ip[3] != 17 || /* pop */
+               ip[4] != 12 || ip[5] != 33 )  /* setcurpoint */
+          {
+            FT_ERROR(( "t1_decoder_parse_charstrings: "
+                       "invalid flex charstring\n" ));
+            goto Syntax_Error;
+          }
+
+          ip += 6;
+          decoder->flex_state = 0;
+          break;
+
+        case 3:                     /* change hints */
+          if ( top[0] != 1 )
+            goto Unexpected_OtherSubr;
+
+          /* eat the following `pop' */
+          if ( ip + 2 > limit )
+          {
+            FT_ERROR(( "t1_decoder_parse_charstrings: "
+                       "invalid escape (12+%d)\n", ip[-1] ));
+            goto Syntax_Error;
+          }
+
+          if ( ip[0] != 12 || ip[1] != 17 )
+          {
+            FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+            FT_ERROR(( "`pop' expected, found (%d %d)\n", ip[0], ip[1] ));
+            goto Syntax_Error;
+          }
+          ip += 2;
+
+          if ( hinter )
+            hinter->reset( hinter->hints, builder->current->n_points );
+
+          break;
+
+        case 12:
+        case 13:
+          /* counter control hints, clear stack */
+          top = decoder->stack;
+          break;
+
+        case 14:
+        case 15:
+        case 16:
+        case 17:
+        case 18:                    /* multiple masters */
+          {
+            PS_Blend  blend = decoder->blend;
+            FT_UInt   num_points, nn, mm;
+            FT_Long*  delta;
+            FT_Long*  values;
+
+
+            if ( !blend )
+            {
+              FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+              FT_ERROR(( "unexpected multiple masters operator!\n" ));
+              goto Syntax_Error;
+            }
+
+            num_points = (FT_UInt)top[1] - 13 + ( top[1] == 18 );
+            if ( top[0] != (FT_Int)( num_points * blend->num_designs ) )
+            {
+              FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+              FT_ERROR(( "incorrect number of mm arguments\n" ));
+              goto Syntax_Error;
+            }
+
+            top -= blend->num_designs * num_points;
+            if ( top < decoder->stack )
+              goto Stack_Underflow;
+
+            /* we want to compute:                                   */
+            /*                                                       */
+            /*  a0*w0 + a1*w1 + ... + ak*wk                          */
+            /*                                                       */
+            /* but we only have the a0, a1-a0, a2-a0, .. ak-a0       */
+            /* however, given that w0 + w1 + ... + wk == 1, we can   */
+            /* rewrite it easily as:                                 */
+            /*                                                       */
+            /*  a0 + (a1-a0)*w1 + (a2-a0)*w2 + .. + (ak-a0)*wk       */
+            /*                                                       */
+            /* where k == num_designs-1                              */
+            /*                                                       */
+            /* I guess that's why it's written in this `compact'     */
+            /* form.                                                 */
+            /*                                                       */
+            delta  = top + num_points;
+            values = top;
+            for ( nn = 0; nn < num_points; nn++ )
+            {
+              FT_Int  tmp = values[0];
+
+
+              for ( mm = 1; mm < blend->num_designs; mm++ )
+                tmp += FT_MulFix( *delta++, blend->weight_vector[mm] );
+
+              *values++ = tmp;
+            }
+            /* note that `top' will be incremented later by calls to `pop' */
+            break;
+          }
+
+        default:
+        Unexpected_OtherSubr:
+          FT_ERROR(( "t1_decoder_parse_charstrings: "
+                     "invalid othersubr [%d %d]!\n", top[0], top[1] ));
+          goto Syntax_Error;
+        }
+        decoder->top = top;
+      }
+      else  /* general operator */
+      {
+        FT_Int  num_args = t1_args_count[op];
+
+
+        if ( top - decoder->stack < num_args )
+          goto Stack_Underflow;
+
+        top -= num_args;
+
+        switch ( op )
+        {
+        case op_endchar:
+          FT_TRACE4(( " endchar" ));
+
+          close_contour( builder );
+
+          /* close hints recording session */
+          if ( hinter )
+          {
+            if (hinter->close( hinter->hints, builder->current->n_points ))
+              goto Syntax_Error;
+
+            /* apply hints to the loaded glyph outline now */
+            hinter->apply( hinter->hints,
+                           builder->current,
+                           (PSH_Globals) builder->hints_globals,
+                           decoder->hint_mode );
+          }
+
+          /* add current outline to the glyph slot */
+          FT_GlyphLoader_Add( builder->loader );
+
+          /* return now! */
+          FT_TRACE4(( "\n\n" ));
+          return PSaux_Err_Ok;
+
+        case op_hsbw:
+          FT_TRACE4(( " hsbw" ));
+
+          builder->left_bearing.x += top[0];
+          builder->advance.x       = top[1];
+          builder->advance.y       = 0;
+
+          orig_x = builder->last.x = x = builder->pos_x + top[0];
+          orig_y = builder->last.y = y = builder->pos_y;
+
+          FT_UNUSED( orig_y );
+
+          /* the `metrics_only' indicates that we only want to compute */
+          /* the glyph's metrics (lsb + advance width), not load the   */
+          /* rest of it; so exit immediately                           */
+          if ( builder->metrics_only )
+            return PSaux_Err_Ok;
+
+          break;
+
+        case op_seac:
+          /* return immediately after the processing */
+          return t1operator_seac( decoder, top[0], top[1],
+                                           top[2], top[3], top[4] );
+
+        case op_sbw:
+          FT_TRACE4(( " sbw" ));
+
+          builder->left_bearing.x += top[0];
+          builder->left_bearing.y += top[1];
+          builder->advance.x       = top[2];
+          builder->advance.y       = top[3];
+
+          builder->last.x = x = builder->pos_x + top[0];
+          builder->last.y = y = builder->pos_y + top[1];
+
+          /* the `metrics_only' indicates that we only want to compute */
+          /* the glyph's metrics (lsb + advance width), not load the   */
+          /* rest of it; so exit immediately                           */
+          if ( builder->metrics_only )
+            return PSaux_Err_Ok;
+
+          break;
+
+        case op_closepath:
+          FT_TRACE4(( " closepath" ));
+
+          close_contour( builder );
+          builder->path_begun = 0;
+          break;
+
+        case op_hlineto:
+          FT_TRACE4(( " hlineto" ));
+
+          if ( start_point( builder, x, y ) )
+            goto Memory_Error;
+
+          x += top[0];
+          goto Add_Line;
+
+        case op_hmoveto:
+          FT_TRACE4(( " hmoveto" ));
+
+          x += top[0];
+          if ( !decoder->flex_state )
+            builder->path_begun = 0;
+          break;
+
+        case op_hvcurveto:
+          FT_TRACE4(( " hvcurveto" ));
+
+          if ( start_point( builder, x, y ) ||
+               check_points( builder, 3 )   )
+            goto Memory_Error;
+
+          x += top[0];
+          add_point( builder, x, y, 0 );
+          x += top[1];
+          y += top[2];
+          add_point( builder, x, y, 0 );
+          y += top[3];
+          add_point( builder, x, y, 1 );
+          break;
+
+        case op_rlineto:
+          FT_TRACE4(( " rlineto" ));
+
+          if ( start_point( builder, x, y ) )
+            goto Memory_Error;
+
+          x += top[0];
+          y += top[1];
+
+        Add_Line:
+          if ( add_point1( builder, x, y ) )
+            goto Memory_Error;
+          break;
+
+        case op_rmoveto:
+          FT_TRACE4(( " rmoveto" ));
+
+          x += top[0];
+          y += top[1];
+          if ( !decoder->flex_state )
+            builder->path_begun = 0;
+          break;
+
+        case op_rrcurveto:
+          FT_TRACE4(( " rcurveto" ));
+
+          if ( start_point( builder, x, y ) ||
+               check_points( builder, 3 )   )
+            goto Memory_Error;
+
+          x += top[0];
+          y += top[1];
+          add_point( builder, x, y, 0 );
+
+          x += top[2];
+          y += top[3];
+          add_point( builder, x, y, 0 );
+
+          x += top[4];
+          y += top[5];
+          add_point( builder, x, y, 1 );
+          break;
+
+        case op_vhcurveto:
+          FT_TRACE4(( " vhcurveto" ));
+
+          if ( start_point( builder, x, y ) ||
+               check_points( builder, 3 )   )
+            goto Memory_Error;
+
+          y += top[0];
+          add_point( builder, x, y, 0 );
+          x += top[1];
+          y += top[2];
+          add_point( builder, x, y, 0 );
+          x += top[3];
+          add_point( builder, x, y, 1 );
+          break;
+
+        case op_vlineto:
+          FT_TRACE4(( " vlineto" ));
+
+          if ( start_point( builder, x, y ) )
+            goto Memory_Error;
+
+          y += top[0];
+          goto Add_Line;
+
+        case op_vmoveto:
+          FT_TRACE4(( " vmoveto" ));
+
+          y += top[0];
+          if ( !decoder->flex_state )
+            builder->path_begun = 0;
+          break;
+
+        case op_div:
+          FT_TRACE4(( " div" ));
+
+          if ( top[1] )
+          {
+            *top = top[0] / top[1];
+            ++top;
+          }
+          else
+          {
+            FT_ERROR(( "t1_decoder_parse_charstrings: division by 0\n" ));
+            goto Syntax_Error;
+          }
+          break;
+
+        case op_callsubr:
+          {
+            FT_Int  idx;
+
+
+            FT_TRACE4(( " callsubr" ));
+
+            idx = top[0];
+            if ( idx < 0 || idx >= (FT_Int)decoder->num_subrs )
+            {
+              FT_ERROR(( "t1_decoder_parse_charstrings: "
+                         "invalid subrs index\n" ));
+              goto Syntax_Error;
+            }
+
+            if ( zone - decoder->zones >= T1_MAX_SUBRS_CALLS )
+            {
+              FT_ERROR(( "t1_decoder_parse_charstrings: "
+                         "too many nested subrs\n" ));
+              goto Syntax_Error;
+            }
+
+            zone->cursor = ip;  /* save current instruction pointer */
+
+            zone++;
+
+            /* The Type 1 driver stores subroutines without the seed bytes. */
+            /* The CID driver stores subroutines with seed bytes.  This     */
+            /* case is taken care of when decoder->subrs_len == 0.          */
+            zone->base = decoder->subrs[idx];
+
+            if ( decoder->subrs_len )
+              zone->limit = zone->base + decoder->subrs_len[idx];
+            else
+            {
+              /* We are using subroutines from a CID font.  We must adjust */
+              /* for the seed bytes.                                       */
+              zone->base  += ( decoder->lenIV >= 0 ? decoder->lenIV : 0 );
+              zone->limit  = decoder->subrs[idx + 1];
+            }
+
+            zone->cursor = zone->base;
+
+            if ( !zone->base )
+            {
+              FT_ERROR(( "t1_decoder_parse_charstrings: "
+                         "invoking empty subrs!\n" ));
+              goto Syntax_Error;
+            }
+
+            decoder->zone = zone;
+            ip            = zone->base;
+            limit         = zone->limit;
+            break;
+          }
+
+        case op_pop:
+          FT_TRACE4(( " pop" ));
+
+          /* theoretically, the arguments are already on the stack */
+          top++;
+          break;
+
+        case op_return:
+          FT_TRACE4(( " return" ));
+
+          if ( zone <= decoder->zones )
+          {
+            FT_ERROR(( "t1_decoder_parse_charstrings: unexpected return\n" ));
+            goto Syntax_Error;
+          }
+
+          zone--;
+          ip            = zone->cursor;
+          limit         = zone->limit;
+          decoder->zone = zone;
+          break;
+
+        case op_dotsection:
+          FT_TRACE4(( " dotsection" ));
+
+          break;
+
+        case op_hstem:
+          FT_TRACE4(( " hstem" ));
+
+          /* record horizontal hint */
+          if ( hinter )
+          {
+            /* top[0] += builder->left_bearing.y; */
+            hinter->stem( hinter->hints, 1, top );
+          }
+
+          break;
+
+        case op_hstem3:
+          FT_TRACE4(( " hstem3" ));
+
+          /* record horizontal counter-controlled hints */
+          if ( hinter )
+            hinter->stem3( hinter->hints, 1, top );
+
+          break;
+
+        case op_vstem:
+          FT_TRACE4(( " vstem" ));
+
+          /* record vertical  hint */
+          if ( hinter )
+          {
+            top[0] += orig_x;
+            hinter->stem( hinter->hints, 0, top );
+          }
+
+          break;
+
+        case op_vstem3:
+          FT_TRACE4(( " vstem3" ));
+
+          /* record vertical counter-controlled hints */
+          if ( hinter )
+          {
+            FT_Pos  dx = orig_x;
+
+
+            top[0] += dx;
+            top[2] += dx;
+            top[4] += dx;
+            hinter->stem3( hinter->hints, 0, top );
+          }
+          break;
+
+        case op_setcurrentpoint:
+          FT_TRACE4(( " setcurrentpoint" ));
+
+          FT_ERROR(( "t1_decoder_parse_charstrings: " ));
+          FT_ERROR(( "unexpected `setcurrentpoint'\n" ));
+          goto Syntax_Error;
+
+        default:
+          FT_ERROR(( "t1_decoder_parse_charstrings: "
+                     "unhandled opcode %d\n", op ));
+          goto Syntax_Error;
+        }
+
+        decoder->top = top;
+
+      } /* general operator processing */
+
+    } /* while ip < limit */
+
+    FT_TRACE4(( "..end..\n\n" ));
+
+    return error;
+
+  Syntax_Error:
+    return PSaux_Err_Syntax_Error;
+
+  Stack_Underflow:
+    return PSaux_Err_Stack_Underflow;
+
+  Memory_Error:
+    return builder->error;
+  }
+
+
+  /* parse a single Type 1 glyph */
+  FT_LOCAL_DEF( FT_Error )
+  t1_decoder_parse_glyph( T1_Decoder  decoder,
+                          FT_UInt     glyph )
+  {
+    return decoder->parse_callback( decoder, glyph );
+  }
+
+
+  /* initialize T1 decoder */
+  FT_LOCAL_DEF( FT_Error )
+  t1_decoder_init( T1_Decoder           decoder,
+                   FT_Face              face,
+                   FT_Size              size,
+                   FT_GlyphSlot         slot,
+                   FT_Byte**            glyph_names,
+                   PS_Blend             blend,
+                   FT_Bool              hinting,
+                   FT_Render_Mode       hint_mode,
+                   T1_Decoder_Callback  parse_callback )
+  {
+    FT_MEM_ZERO( decoder, sizeof ( *decoder ) );
+
+    /* retrieve PSNames interface from list of current modules */
+    {
+      PSNames_Service  psnames = 0;
+
+
+      psnames = (PSNames_Service)FT_Get_Module_Interface(
+                  FT_FACE_LIBRARY(face), "psnames" );
+      if ( !psnames )
+      {
+        FT_ERROR(( "t1_decoder_init: " ));
+        FT_ERROR(( "the `psnames' module is not available\n" ));
+        return PSaux_Err_Unimplemented_Feature;
+      }
+
+      decoder->psnames = psnames;
+    }
+
+    t1_builder_init( &decoder->builder, face, size, slot, hinting );
+
+    decoder->num_glyphs     = (FT_UInt)face->num_glyphs;
+    decoder->glyph_names    = glyph_names;
+    decoder->hint_flags     = face->internal->hint_flags;
+    decoder->hint_mode      = hint_mode;
+    decoder->blend          = blend;
+    decoder->parse_callback = parse_callback;
+
+    decoder->funcs          = t1_decoder_funcs;
+
+    return 0;
+  }
+
+
+  /* finalize T1 decoder */
+  FT_LOCAL_DEF( void )
+  t1_decoder_done( T1_Decoder  decoder )
+  {
+    t1_builder_done( &decoder->builder );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1decode.h
@@ -1,0 +1,65 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1decode.h                                                             */
+/*                                                                         */
+/*    PostScript Type 1 decoding routines (specification).                 */
+/*                                                                         */
+/*  Copyright 2000-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1DECODE_H__
+#define __T1DECODE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_CALLBACK_TABLE
+  const T1_Decoder_FuncsRec  t1_decoder_funcs;
+
+
+  FT_LOCAL( FT_Error )
+  t1_decoder_parse_glyph( T1_Decoder  decoder,
+                          FT_UInt     glyph_index );
+
+  FT_LOCAL( FT_Error )
+  t1_decoder_parse_charstrings( T1_Decoder  decoder,
+                                FT_Byte*    base,
+                                FT_UInt     len );
+
+  FT_LOCAL( FT_Error )
+  t1_decoder_init( T1_Decoder           decoder,
+                   FT_Face              face,
+                   FT_Size              size,
+                   FT_GlyphSlot         slot,
+                   FT_Byte**            glyph_names,
+                   PS_Blend             blend,
+                   FT_Bool              hinting,
+                   FT_Render_Mode       hint_mode,
+                   T1_Decoder_Callback  parse_glyph );
+
+  FT_LOCAL( void )
+  t1_decoder_done( T1_Decoder  decoder );
+
+
+FT_END_HEADER
+
+#endif /* __T1DECODE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1driver.c
@@ -1,0 +1,279 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1driver.c                                                             */
+/*                                                                         */
+/*    Type 1 driver interface (body).                                      */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1driver.h"
+#include "t1gload.h"
+#include "t1load.h"
+
+#include "t1errors.h"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.h"
+#endif
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1driver
+
+
+  static FT_Error
+  t1_get_glyph_name( T1_Face     face,
+                     FT_UInt     glyph_index,
+                     FT_Pointer  buffer,
+                     FT_UInt     buffer_max )
+  {
+    FT_String*  gname;
+
+
+    gname = face->type1.glyph_names[glyph_index];
+
+    if ( buffer_max > 0 )
+    {
+      FT_UInt  len = (FT_UInt)( ft_strlen( gname ) );
+
+
+      if (len >= buffer_max)
+        len = buffer_max - 1;
+
+      FT_MEM_COPY( buffer, gname, len );
+      ((FT_Byte*)buffer)[len] = 0;
+    }
+
+    return T1_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    t1_get_name_index                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Uses the Type 1 font's `glyph_names' table to find a given glyph   */
+  /*    name's glyph index.                                                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face       :: A handle to the source face object.                  */
+  /*                                                                       */
+  /*    glyph_name :: The glyph name.                                      */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index.  0 means `undefined character code'.                  */
+  /*                                                                       */
+  static FT_UInt
+  t1_get_name_index( T1_Face     face,
+                     FT_String*  glyph_name )
+  {
+    FT_Int      i;
+    FT_String*  gname;
+
+
+    for ( i = 0; i < face->type1.num_glyphs; i++ )
+    {
+      gname = face->type1.glyph_names[i];
+
+      if ( !ft_strcmp( glyph_name, gname ) )
+        return (FT_UInt)i;
+    }
+
+    return 0;
+  }
+
+
+  static const char*
+  t1_get_ps_name( T1_Face  face )
+  {
+    return (const char*) face->type1.font_name;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Get_Interface                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Each driver can provide one or more extensions to the base         */
+  /*    FreeType API.  These can be used to access format specific         */
+  /*    features (e.g., all TrueType/OpenType resources share a common     */
+  /*    file structure and common tables which can be accessed through the */
+  /*    `sfnt' interface), or more simply generic ones (e.g., the          */
+  /*    `postscript names' interface which can be used to retrieve the     */
+  /*     PostScript name of a given glyph index).                          */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    driver       :: A handle to a driver object.                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    t1_interface :: A string designing the interface.  Examples are    */
+  /*                    `sfnt', `post_names', `charmaps', etc.             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    A typeless pointer to the extension's interface (normally a table  */
+  /*    of function pointers).  Returns NULL if the requested extension    */
+  /*    isn't available (i.e., wasn't compiled in the driver at build      */
+  /*    time).                                                             */
+  /*                                                                       */
+  static FT_Module_Interface
+  Get_Interface( FT_Driver         driver,
+                 const FT_String*  t1_interface )
+  {
+    FT_UNUSED( driver );
+    FT_UNUSED( t1_interface );
+
+    if ( ft_strcmp( (const char*)t1_interface, "glyph_name" ) == 0 )
+      return (FT_Module_Interface)t1_get_glyph_name;
+
+    if ( ft_strcmp( (const char*)t1_interface, "name_index" ) == 0 )
+      return (FT_Module_Interface)t1_get_name_index;
+
+    if ( ft_strcmp( (const char*)t1_interface, "postscript_name" ) == 0 )
+      return (FT_Module_Interface)t1_get_ps_name;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+    if ( ft_strcmp( (const char*)t1_interface, "get_mm" ) == 0 )
+      return (FT_Module_Interface)T1_Get_Multi_Master;
+
+    if ( ft_strcmp( (const char*)t1_interface, "set_mm_design") == 0 )
+      return (FT_Module_Interface)T1_Set_MM_Design;
+
+    if ( ft_strcmp( (const char*)t1_interface, "set_mm_blend") == 0 )
+      return (FT_Module_Interface)T1_Set_MM_Blend;
+#endif
+    return 0;
+  }
+
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Get_Kerning                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A driver method used to return the kerning vector between two      */
+  /*    glyphs of the same face.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face        :: A handle to the source face object.                 */
+  /*                                                                       */
+  /*    left_glyph  :: The index of the left glyph in the kern pair.       */
+  /*                                                                       */
+  /*    right_glyph :: The index of the right glyph in the kern pair.      */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    kerning     :: The kerning vector.  This is in font units for      */
+  /*                   scalable formats, and in pixels for fixed-sizes     */
+  /*                   formats.                                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only horizontal layouts (left-to-right & right-to-left) are        */
+  /*    supported by this function.  Other layouts, or more sophisticated  */
+  /*    kernings are out of scope of this method (the basic driver         */
+  /*    interface is meant to be simple).                                  */
+  /*                                                                       */
+  /*    They can be implemented by format-specific interfaces.             */
+  /*                                                                       */
+  static FT_Error
+  Get_Kerning( T1_Face     face,
+               FT_UInt     left_glyph,
+               FT_UInt     right_glyph,
+               FT_Vector*  kerning )
+  {
+    T1_AFM*  afm;
+
+
+    kerning->x = 0;
+    kerning->y = 0;
+
+    afm = (T1_AFM*)face->afm_data;
+    if ( afm )
+      T1_Get_Kerning( afm, left_glyph, right_glyph, kerning );
+
+    return T1_Err_Ok;
+  }
+
+
+#endif /* T1_CONFIG_OPTION_NO_AFM */
+
+
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  t1_driver_class =
+  {
+    {
+      ft_module_font_driver      |
+      ft_module_driver_scalable  |
+      ft_module_driver_has_hinter,
+
+      sizeof( FT_DriverRec ),
+
+      "type1",
+      0x10000L,
+      0x20000L,
+
+      0,   /* format interface */
+
+      (FT_Module_Constructor)T1_Driver_Init,
+      (FT_Module_Destructor) T1_Driver_Done,
+      (FT_Module_Requester)  Get_Interface,
+    },
+
+    sizeof( T1_FaceRec ),
+    sizeof( T1_SizeRec ),
+    sizeof( T1_GlyphSlotRec ),
+
+    (FT_Face_InitFunc)        T1_Face_Init,
+    (FT_Face_DoneFunc)        T1_Face_Done,
+    (FT_Size_InitFunc)        T1_Size_Init,
+    (FT_Size_DoneFunc)        T1_Size_Done,
+    (FT_Slot_InitFunc)        T1_GlyphSlot_Init,
+    (FT_Slot_DoneFunc)        T1_GlyphSlot_Done,
+
+    (FT_Size_ResetPointsFunc) T1_Size_Reset,
+    (FT_Size_ResetPixelsFunc) T1_Size_Reset,
+    (FT_Slot_LoadFunc)        T1_Load_Glyph,
+
+#ifdef T1_CONFIG_OPTION_NO_AFM
+    (FT_Face_GetKerningFunc)  0,
+    (FT_Face_AttachFunc)      0,
+#else
+    (FT_Face_GetKerningFunc)  Get_Kerning,
+    (FT_Face_AttachFunc)      T1_Read_AFM,
+#endif
+    (FT_Face_GetAdvancesFunc) 0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1driver.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1driver.h                                                             */
+/*                                                                         */
+/*    High-level Type 1 driver interface (specification).                  */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1DRIVER_H__
+#define __T1DRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Driver_ClassRec )  t1_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __T1DRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1errors.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1errors.h                                                             */
+/*                                                                         */
+/*    Type 1 error codes (specification only).                             */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the Type 1 error enumeration constants.   */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __T1ERRORS_H__
+#define __T1ERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  T1_Err_
+#define FT_ERR_BASE    FT_Mod_Err_Type1
+
+#include FT_ERRORS_H
+
+#endif /* __T1ERRORS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1gload.c
@@ -1,0 +1,416 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1gload.c                                                              */
+/*                                                                         */
+/*    Type 1 Glyph Loader (body).                                          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "t1gload.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+#include "t1errors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1gload
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /**********                                                      *********/
+  /**********            COMPUTE THE MAXIMUM ADVANCE WIDTH         *********/
+  /**********                                                      *********/
+  /**********    The following code is in charge of computing      *********/
+  /**********    the maximum advance width of the font.  It        *********/
+  /**********    quickly processes each glyph charstring to        *********/
+  /**********    extract the value from either a `sbw' or `seac'   *********/
+  /**********    operator.                                         *********/
+  /**********                                                      *********/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Parse_Glyph_And_Get_Char_String( T1_Decoder  decoder,
+                                      FT_UInt     glyph_index,
+                                      FT_Data*    char_string )
+  {
+    T1_Face   face  = (T1_Face)decoder->builder.face;
+    T1_Font   type1 = &face->type1;
+    FT_Error  error = 0;
+
+
+    decoder->font_matrix = type1->font_matrix;
+    decoder->font_offset = type1->font_offset;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    /* For incremental fonts get the character data using the */
+    /* callback function.                                     */
+    if ( face->root.internal->incremental_interface )
+      error = face->root.internal->incremental_interface->funcs->get_glyph_data(
+                face->root.internal->incremental_interface->object,
+                glyph_index, char_string );
+    else
+
+#endif
+
+    /* For ordinary fonts get the character data stored in the face record. */
+    {
+      char_string->pointer = type1->charstrings[glyph_index];
+      char_string->length  = type1->charstrings_len[glyph_index];
+    }
+
+    if ( !error )
+      error = decoder->funcs.parse_charstrings(
+                decoder, (FT_Byte*)char_string->pointer,
+                char_string->length );
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    /* Incremental fonts can optionally override the metrics. */
+    if ( !error && face->root.internal->incremental_interface                 &&
+         face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+    {
+      FT_Bool                    found = FALSE;
+      FT_Incremental_MetricsRec  metrics;
+
+
+      error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+                face->root.internal->incremental_interface->object,
+                glyph_index, FALSE, &metrics, &found );
+      if ( found )
+      {
+        decoder->builder.left_bearing.x = metrics.bearing_x;
+        decoder->builder.left_bearing.y = metrics.bearing_y;
+        decoder->builder.advance.x      = metrics.advance;
+        decoder->builder.advance.y      = 0;
+      }
+    }
+
+#endif
+
+  return error;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  T1_Parse_Glyph( T1_Decoder  decoder,
+                  FT_UInt     glyph_index )
+  {
+    FT_Data   glyph_data;
+    FT_Error  error = T1_Parse_Glyph_And_Get_Char_String( 
+                        decoder, glyph_index, &glyph_data );
+
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if ( !error )
+    {
+      T1_Face  face = (T1_Face)decoder->builder.face;
+
+
+	  if ( face->root.internal->incremental_interface )
+        face->root.internal->incremental_interface->funcs->free_glyph_data(
+          face->root.internal->incremental_interface->object,
+          &glyph_data );
+    }
+#endif
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Compute_Max_Advance( T1_Face  face,
+                          FT_Int*  max_advance )
+  {
+    FT_Error       error;
+    T1_DecoderRec  decoder;
+    FT_Int         glyph_index;
+    T1_Font        type1 = &face->type1;
+    PSAux_Service  psaux = (PSAux_Service)face->psaux;
+
+
+    *max_advance = 0;
+
+    /* initialize load decoder */
+    error = psaux->t1_decoder_funcs->init( &decoder,
+                                           (FT_Face)face,
+                                           0, /* size       */
+                                           0, /* glyph slot */
+                                           (FT_Byte**)type1->glyph_names,
+                                           face->blend,
+                                           0,
+                                           FT_RENDER_MODE_NORMAL,
+                                           T1_Parse_Glyph );
+    if ( error )
+      return error;
+
+    decoder.builder.metrics_only = 1;
+    decoder.builder.load_points  = 0;
+
+    decoder.num_subrs = type1->num_subrs;
+    decoder.subrs     = type1->subrs;
+    decoder.subrs_len = type1->subrs_len;
+
+    *max_advance = 0;
+
+    /* for each glyph, parse the glyph charstring and extract */
+    /* the advance width                                      */
+    for ( glyph_index = 0; glyph_index < type1->num_glyphs; glyph_index++ )
+    {
+      /* now get load the unscaled outline */
+      error = T1_Parse_Glyph( &decoder, glyph_index );
+      if ( glyph_index == 0 || decoder.builder.advance.x > *max_advance )
+        *max_advance = decoder.builder.advance.x;
+        
+      /* ignore the error if one occured - skip to next glyph */
+    }
+
+    return T1_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /**********                                                      *********/
+  /**********               UNHINTED GLYPH LOADER                  *********/
+  /**********                                                      *********/
+  /**********    The following code is in charge of loading a      *********/
+  /**********    single outline.  It completely ignores hinting    *********/
+  /**********    and is used when FT_LOAD_NO_HINTING is set.       *********/
+  /**********                                                      *********/
+  /**********      The Type 1 hinter is located in `t1hint.c'      *********/
+  /**********                                                      *********/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Load_Glyph( T1_GlyphSlot  glyph,
+                 T1_Size       size,
+                 FT_UInt       glyph_index,
+                 FT_Int32      load_flags )
+  {
+    FT_Error                error;
+    T1_DecoderRec           decoder;
+    T1_Face                 face = (T1_Face)glyph->root.face;
+    FT_Bool                 hinting;
+    T1_Font                 type1         = &face->type1;
+    PSAux_Service           psaux         = (PSAux_Service)face->psaux;
+    const T1_Decoder_Funcs  decoder_funcs = psaux->t1_decoder_funcs;
+
+    FT_Matrix               font_matrix;
+    FT_Vector               font_offset;
+    FT_Data                 glyph_data;
+    FT_Bool                 glyph_data_loaded = 0;
+
+
+    if ( load_flags & FT_LOAD_NO_RECURSE )
+      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+    glyph->x_scale = size->root.metrics.x_scale;
+    glyph->y_scale = size->root.metrics.y_scale;
+
+    glyph->root.outline.n_points   = 0;
+    glyph->root.outline.n_contours = 0;
+
+    hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_SCALE   ) == 0 &&
+                       ( load_flags & FT_LOAD_NO_HINTING ) == 0 );
+
+    glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+    error = decoder_funcs->init( &decoder,
+                                 (FT_Face)face,
+                                 (FT_Size)size,
+                                 (FT_GlyphSlot)glyph,
+                                 (FT_Byte**)type1->glyph_names,
+                                 face->blend,
+                                 FT_BOOL( hinting ),
+                                 FT_LOAD_TARGET_MODE(load_flags),
+                                 T1_Parse_Glyph );
+    if ( error )
+      goto Exit;
+
+    decoder.builder.no_recurse = FT_BOOL(
+                                   ( load_flags & FT_LOAD_NO_RECURSE ) != 0 );
+
+    decoder.num_subrs = type1->num_subrs;
+    decoder.subrs     = type1->subrs;
+    decoder.subrs_len = type1->subrs_len;
+
+    /* now load the unscaled outline */
+    error = T1_Parse_Glyph_And_Get_Char_String( &decoder, glyph_index,
+                                                &glyph_data );
+    if ( error )
+      goto Exit;
+    glyph_data_loaded = 1;
+
+    font_matrix = decoder.font_matrix;
+    font_offset = decoder.font_offset;
+
+    /* save new glyph tables */
+    decoder_funcs->done( &decoder );
+
+    /* now, set the metrics -- this is rather simple, as   */
+    /* the left side bearing is the xMin, and the top side */
+    /* bearing the yMax                                    */
+    if ( !error )
+    {
+      glyph->root.outline.flags &= FT_OUTLINE_OWNER;
+      glyph->root.outline.flags |= FT_OUTLINE_REVERSE_FILL;
+
+      /* for composite glyphs, return only left side bearing and */
+      /* advance width                                           */
+      if ( load_flags & FT_LOAD_NO_RECURSE )
+      {
+        FT_Slot_Internal  internal = glyph->root.internal;
+
+
+        glyph->root.metrics.horiBearingX = decoder.builder.left_bearing.x;
+        glyph->root.metrics.horiAdvance  = decoder.builder.advance.x;
+        internal->glyph_matrix           = font_matrix;
+        internal->glyph_delta            = font_offset;
+        internal->glyph_transformed      = 1;
+      }
+      else
+      {
+        FT_BBox            cbox;
+        FT_Glyph_Metrics*  metrics = &glyph->root.metrics;
+
+
+        /* copy the _unscaled_ advance width */
+        metrics->horiAdvance                    = decoder.builder.advance.x;
+        glyph->root.linearHoriAdvance           = decoder.builder.advance.x;
+        glyph->root.internal->glyph_transformed = 0;
+
+        /* make up vertical metrics */
+        metrics->vertBearingX = 0;
+        metrics->vertBearingY = 0;
+        metrics->vertAdvance  = 0;
+
+        glyph->root.linearVertAdvance = 0;
+
+        glyph->root.format = FT_GLYPH_FORMAT_OUTLINE;
+
+        if ( size && size->root.metrics.y_ppem < 24 )
+          glyph->root.outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+#if 1
+        /* apply the font matrix, if any */
+        FT_Outline_Transform( &glyph->root.outline, &font_matrix );
+
+        FT_Outline_Translate( &glyph->root.outline,
+                              font_offset.x,
+                              font_offset.y );
+#endif
+
+        if ( ( load_flags & FT_LOAD_NO_SCALE ) == 0 )
+        {
+          /* scale the outline and the metrics */
+          FT_Int       n;
+          FT_Outline*  cur = decoder.builder.base;
+          FT_Vector*   vec = cur->points;
+          FT_Fixed     x_scale = glyph->x_scale;
+          FT_Fixed     y_scale = glyph->y_scale;
+
+
+          /* First of all, scale the points, if we are not hinting */
+          if ( !hinting )
+            for ( n = cur->n_points; n > 0; n--, vec++ )
+            {
+              vec->x = FT_MulFix( vec->x, x_scale );
+              vec->y = FT_MulFix( vec->y, y_scale );
+            }
+
+          FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+          /* Then scale the metrics */
+          metrics->horiAdvance  = FT_MulFix( metrics->horiAdvance,  x_scale );
+          metrics->vertAdvance  = FT_MulFix( metrics->vertAdvance,  y_scale );
+
+          metrics->vertBearingX = FT_MulFix( metrics->vertBearingX, x_scale );
+          metrics->vertBearingY = FT_MulFix( metrics->vertBearingY, y_scale );
+
+          if ( hinting )
+          {
+            metrics->horiAdvance = ( metrics->horiAdvance + 32 ) & -64;
+            metrics->vertAdvance = ( metrics->vertAdvance + 32 ) & -64;
+
+            metrics->vertBearingX = ( metrics->vertBearingX + 32 ) & -64;
+            metrics->vertBearingY = ( metrics->vertBearingY + 32 ) & -64;
+          }
+        }
+
+        /* compute the other metrics */
+        FT_Outline_Get_CBox( &glyph->root.outline, &cbox );
+
+        /* grid fit the bounding box if necessary */
+        if ( hinting )
+        {
+          cbox.xMin &= -64;
+          cbox.yMin &= -64;
+          cbox.xMax  = ( cbox.xMax+63 ) & -64;
+          cbox.yMax  = ( cbox.yMax+63 ) & -64;
+        }
+
+        metrics->width  = cbox.xMax - cbox.xMin;
+        metrics->height = cbox.yMax - cbox.yMin;
+
+        metrics->horiBearingX = cbox.xMin;
+        metrics->horiBearingY = cbox.yMax;
+      }
+
+      /* Set control data to the glyph charstrings.  Note that this is */
+      /* _not_ zero-terminated.                                        */
+      glyph->root.control_data = (FT_Byte*)glyph_data.pointer;
+      glyph->root.control_len  = glyph_data.length;
+    }
+
+
+  Exit:
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if ( glyph_data_loaded && face->root.internal->incremental_interface )
+    {
+      face->root.internal->incremental_interface->funcs->free_glyph_data(
+        face->root.internal->incremental_interface->object,
+        &glyph_data );
+
+      /* Set the control data to null - it is no longer available if   */
+      /* loaded incrementally.                                         */
+      glyph->root.control_data = 0;
+      glyph->root.control_len  = 0;
+    }
+#endif
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1gload.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1gload.h                                                              */
+/*                                                                         */
+/*    Type 1 Glyph Loader (specification).                                 */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1GLOAD_H__
+#define __T1GLOAD_H__
+
+
+#include <ft2build.h>
+#include "t1objs.h"
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  T1_Compute_Max_Advance( T1_Face  face,
+                          FT_Int*  max_advance );
+
+  FT_LOCAL( FT_Error )
+  T1_Load_Glyph( T1_GlyphSlot  glyph,
+                 T1_Size       size,
+                 FT_UInt       glyph_index,
+                 FT_Int32      load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __T1GLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1load.c
@@ -1,0 +1,1791 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1load.c                                                               */
+/*                                                                         */
+/*    Type 1 font loader (body).                                           */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This is the new and improved Type 1 data loader for FreeType 2.  The  */
+  /* old loader has several problems: it is slow, complex, difficult to    */
+  /* maintain, and contains incredible hacks to make it accept some        */
+  /* ill-formed Type 1 fonts without hiccup-ing.  Moreover, about 5% of    */
+  /* the Type 1 fonts on my machine still aren't loaded correctly by it.   */
+  /*                                                                       */
+  /* This version is much simpler, much faster and also easier to read and */
+  /* maintain by a great order of magnitude.  The idea behind it is to     */
+  /* _not_ try to read the Type 1 token stream with a state machine (i.e.  */
+  /* a Postscript-like interpreter) but rather to perform simple pattern   */
+  /* matching.                                                             */
+  /*                                                                       */
+  /* Indeed, nearly all data definitions follow a simple pattern like      */
+  /*                                                                       */
+  /*  ... /Field <data> ...                                                */
+  /*                                                                       */
+  /* where <data> can be a number, a boolean, a string, or an array of     */
+  /* numbers.  There are a few exceptions, namely the encoding, font name, */
+  /* charstrings, and subrs; they are handled with a special pattern       */
+  /* matching routine.                                                     */
+  /*                                                                       */
+  /* All other common cases are handled very simply.  The matching rules   */
+  /* are defined in the file `t1tokens.h' through the use of several       */
+  /* macros calls PARSE_XXX.                                               */
+  /*                                                                       */
+  /* This file is included twice here; the first time to generate parsing  */
+  /* callback functions, the second to generate a table of keywords (with  */
+  /* pointers to the associated callback).                                 */
+  /*                                                                       */
+  /* The function `parse_dict' simply scans *linearly* a given dictionary  */
+  /* (either the top-level or private one) and calls the appropriate       */
+  /* callback when it encounters an immediate keyword.                     */
+  /*                                                                       */
+  /* This is by far the fastest way one can find to parse and read all     */
+  /* data.                                                                 */
+  /*                                                                       */
+  /* This led to tremendous code size reduction.  Note that later, the     */
+  /* glyph loader will also be _greatly_ simplified, and the automatic     */
+  /* hinter will replace the clumsy `t1hinter'.                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_CONFIG_CONFIG_H
+#include FT_MULTIPLE_MASTERS_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+#include "t1load.h"
+#include "t1errors.h"
+
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1load
+
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    MULTIPLE MASTERS SUPPORT                   *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static FT_Error
+  t1_allocate_blend( T1_Face  face,
+                     FT_UInt  num_designs,
+                     FT_UInt  num_axis )
+  {
+    PS_Blend   blend;
+    FT_Memory  memory = face->root.memory;
+    FT_Error   error  = 0;
+
+
+    blend = face->blend;
+    if ( !blend )
+    {
+      if ( FT_NEW( blend ) )
+        goto Exit;
+
+      face->blend = blend;
+    }
+
+    /* allocate design data if needed */
+    if ( num_designs > 0 )
+    {
+      if ( blend->num_designs == 0 )
+      {
+        FT_UInt  nn;
+
+
+        /* allocate the blend `private' and `font_info' dictionaries */
+        if ( FT_NEW_ARRAY( blend->font_infos[1], num_designs     ) ||
+             FT_NEW_ARRAY( blend->privates[1], num_designs       ) ||
+             FT_NEW_ARRAY( blend->bboxes[1], num_designs         ) ||
+             FT_NEW_ARRAY( blend->weight_vector, num_designs * 2 ) )
+          goto Exit;
+
+        blend->default_weight_vector = blend->weight_vector + num_designs;
+
+        blend->font_infos[0] = &face->type1.font_info;
+        blend->privates  [0] = &face->type1.private_dict;
+        blend->bboxes    [0] = &face->type1.font_bbox;
+
+        for ( nn = 2; nn <= num_designs; nn++ )
+        {
+          blend->privates[nn]   = blend->privates  [nn - 1] + 1;
+          blend->font_infos[nn] = blend->font_infos[nn - 1] + 1;
+          blend->bboxes[nn]     = blend->bboxes    [nn - 1] + 1;
+        }
+
+        blend->num_designs   = num_designs;
+      }
+      else if ( blend->num_designs != num_designs )
+        goto Fail;
+    }
+
+    /* allocate axis data if needed */
+    if ( num_axis > 0 )
+    {
+      if ( blend->num_axis != 0 && blend->num_axis != num_axis )
+        goto Fail;
+
+      blend->num_axis = num_axis;
+    }
+
+    /* allocate the blend design pos table if needed */
+    num_designs = blend->num_designs;
+    num_axis    = blend->num_axis;
+    if ( num_designs && num_axis && blend->design_pos[0] == 0 )
+    {
+      FT_UInt  n;
+
+
+      if ( FT_NEW_ARRAY( blend->design_pos[0], num_designs * num_axis ) )
+        goto Exit;
+
+      for ( n = 1; n < num_designs; n++ )
+        blend->design_pos[n] = blend->design_pos[0] + num_axis * n;
+    }
+
+  Exit:
+    return error;
+
+  Fail:
+    error = -1;
+    goto Exit;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Get_Multi_Master( T1_Face           face,
+                       FT_Multi_Master*  master )
+  {
+    PS_Blend  blend = face->blend;
+    FT_UInt   n;
+    FT_Error  error;
+
+
+    error = T1_Err_Invalid_Argument;
+
+    if ( blend )
+    {
+      master->num_axis    = blend->num_axis;
+      master->num_designs = blend->num_designs;
+
+      for ( n = 0; n < blend->num_axis; n++ )
+      {
+        FT_MM_Axis*   axis = master->axis + n;
+        PS_DesignMap  map = blend->design_map + n;
+
+
+        axis->name    = blend->axis_names[n];
+        axis->minimum = map->design_points[0];
+        axis->maximum = map->design_points[map->num_points - 1];
+      }
+      error = 0;
+    }
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Set_MM_Blend( T1_Face    face,
+                   FT_UInt    num_coords,
+                   FT_Fixed*  coords )
+  {
+    PS_Blend  blend = face->blend;
+    FT_Error  error;
+    FT_UInt   n, m;
+
+
+    error = T1_Err_Invalid_Argument;
+
+    if ( blend && blend->num_axis == num_coords )
+    {
+      /* recompute the weight vector from the blend coordinates */
+      error = T1_Err_Ok;
+
+      for ( n = 0; n < blend->num_designs; n++ )
+      {
+        FT_Fixed  result = 0x10000L;  /* 1.0 fixed */
+
+
+        for ( m = 0; m < blend->num_axis; m++ )
+        {
+          FT_Fixed  factor;
+
+
+          /* get current blend axis position */
+          factor = coords[m];
+          if ( factor < 0 )        factor = 0;
+          if ( factor > 0x10000L ) factor = 0x10000L;
+
+          if ( ( n & ( 1 << m ) ) == 0 )
+            factor = 0x10000L - factor;
+
+          result = FT_MulFix( result, factor );
+        }
+        blend->weight_vector[n] = result;
+      }
+
+      error = T1_Err_Ok;
+    }
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Set_MM_Design( T1_Face   face,
+                    FT_UInt   num_coords,
+                    FT_Long*  coords )
+  {
+    PS_Blend  blend = face->blend;
+    FT_Error  error;
+    FT_UInt   n, p;
+
+
+    error = T1_Err_Invalid_Argument;
+    if ( blend && blend->num_axis == num_coords )
+    {
+      /* compute the blend coordinates through the blend design map */
+      FT_Fixed  final_blends[T1_MAX_MM_DESIGNS];
+
+
+      for ( n = 0; n < blend->num_axis; n++ )
+      {
+        FT_Long       design  = coords[n];
+        FT_Fixed      the_blend;
+        PS_DesignMap  map     = blend->design_map + n;
+        FT_Fixed*     designs = map->design_points;
+        FT_Fixed*     blends  = map->blend_points;
+        FT_Int        before  = -1, after = -1;
+
+
+        for ( p = 0; p < (FT_UInt)map->num_points; p++ )
+        {
+          FT_Fixed  p_design = designs[p];
+
+
+          /* exact match ? */
+          if ( design == p_design )
+          {
+            the_blend = blends[p];
+            goto Found;
+          }
+
+          if ( design < p_design )
+          {
+            after = p;
+            break;
+          }
+
+          before = p;
+        }
+
+        /* now, interpolate if needed */
+        if ( before < 0 )
+          the_blend = blends[0];
+
+        else if ( after < 0 )
+          the_blend = blends[map->num_points - 1];
+
+        else
+          the_blend = FT_MulDiv( design         - designs[before],
+                                 blends [after] - blends [before],
+                                 designs[after] - designs[before] );
+
+      Found:
+        final_blends[n] = the_blend;
+      }
+
+      error = T1_Set_MM_Blend( face, num_coords, final_blends );
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  T1_Done_Blend( T1_Face  face )
+  {
+    FT_Memory  memory = face->root.memory;
+    PS_Blend   blend  = face->blend;
+
+
+    if ( blend )
+    {
+      FT_UInt  num_designs = blend->num_designs;
+      FT_UInt  num_axis    = blend->num_axis;
+      FT_UInt  n;
+
+
+      /* release design pos table */
+      FT_FREE( blend->design_pos[0] );
+      for ( n = 1; n < num_designs; n++ )
+        blend->design_pos[n] = 0;
+
+      /* release blend `private' and `font info' dictionaries */
+      FT_FREE( blend->privates[1] );
+      FT_FREE( blend->font_infos[1] );
+      FT_FREE( blend->bboxes[1] );
+
+      for ( n = 0; n < num_designs; n++ )
+      {
+        blend->privates  [n] = 0;
+        blend->font_infos[n] = 0;
+        blend->bboxes    [n] = 0;
+      }
+
+      /* release weight vectors */
+      FT_FREE( blend->weight_vector );
+      blend->default_weight_vector = 0;
+
+      /* release axis names */
+      for ( n = 0; n < num_axis; n++ )
+        FT_FREE( blend->axis_names[n] );
+
+      /* release design map */
+      for ( n = 0; n < num_axis; n++ )
+      {
+        PS_DesignMap  dmap = blend->design_map + n;
+
+
+        FT_FREE( dmap->design_points );
+        dmap->num_points = 0;
+      }
+
+      FT_FREE( face->blend );
+    }
+  }
+
+
+  static void
+  parse_blend_axis_types( T1_Face    face,
+                          T1_Loader  loader )
+  {
+    T1_TokenRec  axis_tokens[ T1_MAX_MM_AXIS ];
+    FT_Int       n, num_axis;
+    FT_Error     error = 0;
+    PS_Blend     blend;
+    FT_Memory    memory;
+
+
+    /* take an array of objects */
+    T1_ToTokenArray( &loader->parser, axis_tokens,
+                     T1_MAX_MM_AXIS, &num_axis );
+    if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+    {
+      FT_ERROR(( "parse_blend_axis_types: incorrect number of axes: %d\n",
+                 num_axis ));
+      error = T1_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    /* allocate blend if necessary */
+    error = t1_allocate_blend( face, 0, (FT_UInt)num_axis );
+    if ( error )
+      goto Exit;
+
+    blend  = face->blend;
+    memory = face->root.memory;
+
+    /* each token is an immediate containing the name of the axis */
+    for ( n = 0; n < num_axis; n++ )
+    {
+      T1_Token    token = axis_tokens + n;
+      FT_Byte*    name;
+      FT_PtrDist  len;
+
+
+      /* skip first slash, if any */
+      if ( token->start[0] == '/' )
+        token->start++;
+
+      len = token->limit - token->start;
+      if ( len <= 0 )
+      {
+        error = T1_Err_Invalid_File_Format;
+        goto Exit;
+      }
+
+      if ( FT_ALLOC( blend->axis_names[n], len + 1 ) )
+        goto Exit;
+
+      name = (FT_Byte*)blend->axis_names[n];
+      FT_MEM_COPY( name, token->start, len );
+      name[len] = 0;
+    }
+
+  Exit:
+    loader->parser.root.error = error;
+  }
+
+
+  static void
+  parse_blend_design_positions( T1_Face    face,
+                                T1_Loader  loader )
+  {
+    T1_TokenRec  design_tokens[ T1_MAX_MM_DESIGNS ];
+    FT_Int       num_designs;
+    FT_Int       num_axis;
+    T1_Parser    parser = &loader->parser;
+
+    FT_Error     error = 0;
+    PS_Blend     blend;
+
+
+    /* get the array of design tokens - compute number of designs */
+    T1_ToTokenArray( parser, design_tokens, T1_MAX_MM_DESIGNS, &num_designs );
+    if ( num_designs <= 0 || num_designs > T1_MAX_MM_DESIGNS )
+    {
+      FT_ERROR(( "parse_blend_design_positions:" ));
+      FT_ERROR(( " incorrect number of designs: %d\n",
+                 num_designs ));
+      error = T1_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    {
+      FT_Byte*  old_cursor = parser->root.cursor;
+      FT_Byte*  old_limit  = parser->root.limit;
+      FT_UInt   n;
+
+
+      blend    = face->blend;
+      num_axis = 0;  /* make compiler happy */
+
+      for ( n = 0; n < (FT_UInt)num_designs; n++ )
+      {
+        T1_TokenRec  axis_tokens[ T1_MAX_MM_DESIGNS ];
+        T1_Token     token;
+        FT_Int       axis, n_axis;
+
+
+        /* read axis/coordinates tokens */
+        token = design_tokens + n;
+        parser->root.cursor = token->start - 1;
+        parser->root.limit  = token->limit + 1;
+        T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &n_axis );
+
+        if ( n == 0 )
+        {
+          num_axis = n_axis;
+          error = t1_allocate_blend( face, num_designs, num_axis );
+          if ( error )
+            goto Exit;
+          blend = face->blend;
+        }
+        else if ( n_axis != num_axis )
+        {
+          FT_ERROR(( "parse_blend_design_positions: incorrect table\n" ));
+          error = T1_Err_Invalid_File_Format;
+          goto Exit;
+        }
+
+        /* now, read each axis token into the design position */
+        for ( axis = 0; axis < n_axis; axis++ )
+        {
+          T1_Token  token2 = axis_tokens + axis;
+
+
+          parser->root.cursor = token2->start;
+          parser->root.limit  = token2->limit;
+          blend->design_pos[n][axis] = T1_ToFixed( parser, 0 );
+        }
+      }
+
+      loader->parser.root.cursor = old_cursor;
+      loader->parser.root.limit  = old_limit;
+    }
+
+  Exit:
+    loader->parser.root.error = error;
+  }
+
+
+  static void
+  parse_blend_design_map( T1_Face    face,
+                          T1_Loader  loader )
+  {
+    FT_Error     error  = 0;
+    T1_Parser    parser = &loader->parser;
+    PS_Blend     blend;
+    T1_TokenRec  axis_tokens[T1_MAX_MM_AXIS];
+    FT_Int       n, num_axis;
+    FT_Byte*     old_cursor;
+    FT_Byte*     old_limit;
+    FT_Memory    memory = face->root.memory;
+
+
+    T1_ToTokenArray( parser, axis_tokens, T1_MAX_MM_AXIS, &num_axis );
+    if ( num_axis <= 0 || num_axis > T1_MAX_MM_AXIS )
+    {
+      FT_ERROR(( "parse_blend_design_map: incorrect number of axes: %d\n",
+                 num_axis ));
+      error = T1_Err_Invalid_File_Format;
+      goto Exit;
+    }
+    old_cursor = parser->root.cursor;
+    old_limit  = parser->root.limit;
+
+    error = t1_allocate_blend( face, 0, num_axis );
+    if ( error )
+      goto Exit;
+    blend = face->blend;
+
+    /* now, read each axis design map */
+    for ( n = 0; n < num_axis; n++ )
+    {
+      PS_DesignMap  map = blend->design_map + n;
+      T1_Token      token;
+      FT_Int        p, num_points;
+
+
+      token = axis_tokens + n;
+      parser->root.cursor = token->start;
+      parser->root.limit  = token->limit;
+
+      /* count the number of map points */
+      {
+        FT_Byte*  ptr   = token->start;
+        FT_Byte*  limit = token->limit;
+
+
+        num_points = 0;
+        for ( ; ptr < limit; ptr++ )
+          if ( ptr[0] == '[' )
+            num_points++;
+      }
+      if ( num_points <= 0 || num_points > T1_MAX_MM_MAP_POINTS )
+      {
+        FT_ERROR(( "parse_blend_design_map: incorrect table\n" ));
+        error = T1_Err_Invalid_File_Format;
+        goto Exit;
+      }
+
+      /* allocate design map data */
+      if ( FT_NEW_ARRAY( map->design_points, num_points * 2 ) )
+        goto Exit;
+      map->blend_points = map->design_points + num_points;
+      map->num_points   = (FT_Byte)num_points;
+
+      for ( p = 0; p < num_points; p++ )
+      {
+        map->design_points[p] = T1_ToInt( parser );
+        map->blend_points [p] = T1_ToFixed( parser, 0 );
+      }
+    }
+
+    parser->root.cursor = old_cursor;
+    parser->root.limit  = old_limit;
+
+  Exit:
+    parser->root.error = error;
+  }
+
+
+  static void
+  parse_weight_vector( T1_Face    face,
+                       T1_Loader  loader )
+  {
+    FT_Error     error  = 0;
+    T1_Parser    parser = &loader->parser;
+    PS_Blend     blend  = face->blend;
+    T1_TokenRec  master;
+    FT_UInt      n;
+    FT_Byte*     old_cursor;
+    FT_Byte*     old_limit;
+
+
+    if ( !blend || blend->num_designs == 0 )
+    {
+      FT_ERROR(( "parse_weight_vector: too early!\n" ));
+      error = T1_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    T1_ToToken( parser, &master );
+    if ( master.type != T1_TOKEN_TYPE_ARRAY )
+    {
+      FT_ERROR(( "parse_weight_vector: incorrect format!\n" ));
+      error = T1_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    old_cursor = parser->root.cursor;
+    old_limit  = parser->root.limit;
+
+    parser->root.cursor = master.start;
+    parser->root.limit  = master.limit;
+
+    for ( n = 0; n < blend->num_designs; n++ )
+    {
+      blend->default_weight_vector[n] =
+      blend->weight_vector[n]         = T1_ToFixed( parser, 0 );
+    }
+
+    parser->root.cursor = old_cursor;
+    parser->root.limit  = old_limit;
+
+  Exit:
+    parser->root.error = error;
+  }
+
+
+  /* the keyword `/shareddict' appears in some multiple master fonts   */
+  /* with a lot of Postscript garbage behind it (that's completely out */
+  /* of spec!); we detect it and terminate the parsing                 */
+  /*                                                                   */
+  static void
+  parse_shared_dict( T1_Face    face,
+                     T1_Loader  loader )
+  {
+    T1_Parser  parser = &loader->parser;
+
+    FT_UNUSED( face );
+
+
+    parser->root.cursor = parser->root.limit;
+    parser->root.error  = 0;
+  }
+
+#endif /* T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      TYPE 1 SYMBOL PARSING                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* First of all, define the token field static variables.  This is a set */
+  /* of T1_FieldRec variables used later.                                  */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static FT_Error
+  t1_load_keyword( T1_Face    face,
+                   T1_Loader  loader,
+                   T1_Field   field )
+  {
+    FT_Error  error;
+    void*     dummy_object;
+    void**    objects;
+    FT_UInt   max_objects;
+    PS_Blend  blend = face->blend;
+
+
+    /* if the keyword has a dedicated callback, call it */
+    if ( field->type == T1_FIELD_TYPE_CALLBACK )
+    {
+      field->reader( (FT_Face)face, loader );
+      error = loader->parser.root.error;
+      goto Exit;
+    }
+
+    /* now, the keyword is either a simple field, or a table of fields; */
+    /* we are now going to take care of it                              */
+    switch ( field->location )
+    {
+    case T1_FIELD_LOCATION_FONT_INFO:
+      dummy_object = &face->type1.font_info;
+      objects      = &dummy_object;
+      max_objects  = 0;
+
+      if ( blend )
+      {
+        objects     = (void**)blend->font_infos;
+        max_objects = blend->num_designs;
+      }
+      break;
+
+    case T1_FIELD_LOCATION_PRIVATE:
+      dummy_object = &face->type1.private_dict;
+      objects      = &dummy_object;
+      max_objects  = 0;
+
+      if ( blend )
+      {
+        objects     = (void**)blend->privates;
+        max_objects = blend->num_designs;
+      }
+      break;
+
+    case T1_FIELD_LOCATION_BBOX:
+      dummy_object = &face->type1.font_bbox;
+      objects      = &dummy_object;
+      max_objects  = 0;
+
+      if ( blend )
+      {
+        objects     = (void**)blend->bboxes;
+        max_objects = blend->num_designs;
+      }
+      break;
+
+    default:
+      dummy_object = &face->type1;
+      objects      = &dummy_object;
+      max_objects  = 0;
+    }
+
+    if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
+         field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
+      error = T1_Load_Field_Table( &loader->parser, field,
+                                   objects, max_objects, 0 );
+    else
+      error = T1_Load_Field( &loader->parser, field,
+                             objects, max_objects, 0 );
+
+  Exit:
+    return error;
+  }
+
+
+  static int
+  is_space( FT_Byte  c )
+  {
+    return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
+  }
+
+
+  static int
+  is_alpha( FT_Byte  c )
+  {
+    /* Note: we must accept "+" as a valid character, as it is used in */
+    /*       embedded type1 fonts in PDF documents.                    */
+    /*                                                                 */
+    return ( ft_isalnum( c ) ||
+             c == '.'        ||
+             c == '_'        ||
+             c == '-'        ||
+             c == '+'        );
+  }
+
+
+  static int
+  read_binary_data( T1_Parser  parser,
+                    FT_Long*   size,
+                    FT_Byte**  base )
+  {
+    FT_Byte*  cur;
+    FT_Byte*  limit = parser->root.limit;
+
+
+    /* the binary data has the following format */
+    /*                                          */
+    /* `size' [white*] RD white ....... ND      */
+    /*                                          */
+
+    T1_Skip_Spaces( parser );
+    cur = parser->root.cursor;
+
+    if ( cur < limit && (FT_Byte)( *cur - '0' ) < 10 )
+    {
+      *size = T1_ToInt( parser );
+
+      T1_Skip_Spaces( parser );
+      T1_Skip_Alpha ( parser );  /* `RD' or `-|' or something else */
+
+      /* there is only one whitespace char after the */
+      /* `RD' or `-|' token                          */
+      *base = parser->root.cursor + 1;
+
+      parser->root.cursor += *size + 1;
+      return 1;
+    }
+
+    FT_ERROR(( "read_binary_data: invalid size field\n" ));
+    parser->root.error = T1_Err_Invalid_File_Format;
+    return 0;
+  }
+
+
+  /* we will now define the routines used to handle */
+  /* the `/Encoding', `/Subrs', and `/CharStrings'  */
+  /* dictionaries                                   */
+
+  static void
+  parse_font_name( T1_Face    face,
+                   T1_Loader  loader )
+  {
+    T1_Parser   parser = &loader->parser;
+    FT_Error    error;
+    FT_Memory   memory = parser->root.memory;
+    FT_PtrDist  len;
+    FT_Byte*    cur;
+    FT_Byte*    cur2;
+    FT_Byte*    limit;
+
+
+    if ( face->type1.font_name )
+      /*  with synthetic fonts, it's possible we get here twice  */
+      return;
+
+    T1_Skip_Spaces( parser );
+
+    cur   = parser->root.cursor;
+    limit = parser->root.limit;
+
+    if ( cur >= limit - 1 || *cur != '/' )
+      return;
+
+    cur++;
+    cur2 = cur;
+    while ( cur2 < limit && is_alpha( *cur2 ) )
+      cur2++;
+
+    len = cur2 - cur;
+    if ( len > 0 )
+    {
+      if ( FT_ALLOC( face->type1.font_name, len + 1 ) )
+      {
+        parser->root.error = error;
+        return;
+      }
+
+      FT_MEM_COPY( face->type1.font_name, cur, len );
+      face->type1.font_name[len] = '\0';
+    }
+    parser->root.cursor = cur2;
+  }
+
+
+#if 0
+  static void
+  parse_font_bbox( T1_Face    face,
+                   T1_Loader  loader )
+  {
+    T1_Parser  parser = &loader->parser;
+    FT_Fixed   temp[4];
+    FT_BBox*   bbox   = &face->type1.font_bbox;
+
+
+    (void)T1_ToFixedArray( parser, 4, temp, 0 );
+    bbox->xMin = FT_RoundFix( temp[0] );
+    bbox->yMin = FT_RoundFix( temp[1] );
+    bbox->xMax = FT_RoundFix( temp[2] );
+    bbox->yMax = FT_RoundFix( temp[3] );
+  }
+#endif
+
+
+  static void
+  parse_font_matrix( T1_Face    face,
+                     T1_Loader  loader )
+  {
+    T1_Parser   parser = &loader->parser;
+    FT_Matrix*  matrix = &face->type1.font_matrix;
+    FT_Vector*  offset = &face->type1.font_offset;
+    FT_Face     root   = (FT_Face)&face->root;
+    FT_Fixed    temp[6];
+    FT_Fixed    temp_scale;
+
+
+    if ( matrix->xx || matrix->yx )
+      /* with synthetic fonts, it's possible we get here twice  */
+      return;
+
+    (void)T1_ToFixedArray( parser, 6, temp, 3 );
+
+    temp_scale = ABS( temp[3] );
+
+    /* Set Units per EM based on FontMatrix values.  We set the value to */
+    /* 1000 / temp_scale, because temp_scale was already multiplied by   */
+    /* 1000 (in t1_tofixed, from psobjs.c).                              */
+
+    root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
+                                                 temp_scale ) >> 16 );
+
+    /* we need to scale the values by 1.0/temp_scale */
+    if ( temp_scale != 0x10000L )
+    {
+      temp[0] = FT_DivFix( temp[0], temp_scale );
+      temp[1] = FT_DivFix( temp[1], temp_scale );
+      temp[2] = FT_DivFix( temp[2], temp_scale );
+      temp[4] = FT_DivFix( temp[4], temp_scale );
+      temp[5] = FT_DivFix( temp[5], temp_scale );
+      temp[3] = 0x10000L;
+    }
+
+    matrix->xx = temp[0];
+    matrix->yx = temp[1];
+    matrix->xy = temp[2];
+    matrix->yy = temp[3];
+
+    /* note that the offsets must be expressed in integer font units */
+    offset->x  = temp[4] >> 16;
+    offset->y  = temp[5] >> 16;
+  }
+
+
+  static void
+  parse_encoding( T1_Face    face,
+                  T1_Loader  loader )
+  {
+    T1_Parser      parser = &loader->parser;
+    FT_Byte*       cur    = parser->root.cursor;
+    FT_Byte*       limit  = parser->root.limit;
+
+    PSAux_Service  psaux  = (PSAux_Service)face->psaux;
+
+
+    /* skip whitespace */
+    while ( is_space( *cur ) )
+    {
+      cur++;
+      if ( cur >= limit )
+      {
+        FT_ERROR(( "parse_encoding: out of bounds!\n" ));
+        parser->root.error = T1_Err_Invalid_File_Format;
+        return;
+      }
+    }
+
+    /* if we have a number, then the encoding is an array, */
+    /* and we must load it now                             */
+    if ( (FT_Byte)( *cur - '0' ) < 10 )
+    {
+      T1_Encoding  encode     = &face->type1.encoding;
+      FT_Int       count, n;
+      PS_Table     char_table = &loader->encoding_table;
+      FT_Memory    memory     = parser->root.memory;
+      FT_Error     error;
+
+
+      if ( encode->char_index )
+        /*  with synthetic fonts, it's possible we get here twice  */
+        return;
+
+      /* read the number of entries in the encoding, should be 256 */
+      count = (FT_Int)T1_ToInt( parser );
+      if ( parser->root.error )
+        return;
+
+      /* we use a T1_Table to store our charnames */
+      loader->num_chars = encode->num_chars = count;
+      if ( FT_NEW_ARRAY( encode->char_index, count ) ||
+           FT_NEW_ARRAY( encode->char_name,  count ) ||
+           FT_SET_ERROR( psaux->ps_table_funcs->init(
+                           char_table, count, memory ) ) )
+      {
+        parser->root.error = error;
+        return;
+      }
+
+      /* We need to `zero' out encoding_table.elements */
+      for ( n = 0; n < count; n++ )
+      {
+        char*  notdef = (char *)".notdef";
+
+
+        T1_Add_Table( char_table, n, notdef, 8 );
+      }
+
+      /* Now, we will need to read a record of the form         */
+      /* ... charcode /charname ... for each entry in our table */
+      /*                                                        */
+      /* We simply look for a number followed by an immediate   */
+      /* name.  Note that this ignores correctly the sequence   */
+      /* that is often seen in type1 fonts:                     */
+      /*                                                        */
+      /*   0 1 255 { 1 index exch /.notdef put } for dup        */
+      /*                                                        */
+      /* used to clean the encoding array before anything else. */
+      /*                                                        */
+      /* We stop when we encounter a `def'.                     */
+
+      cur   = parser->root.cursor;
+      limit = parser->root.limit;
+      n     = 0;
+
+      for ( ; cur < limit; )
+      {
+        FT_Byte  c;
+
+
+        c = *cur;
+
+        /* we stop when we encounter a `def' */
+        if ( c == 'd' && cur + 3 < limit )
+        {
+          if ( cur[1] == 'e'       &&
+               cur[2] == 'f'       &&
+               is_space( cur[-1] ) &&
+               is_space( cur[3] )  )
+          {
+            FT_TRACE6(( "encoding end\n" ));
+            break;
+          }
+        }
+
+        /* otherwise, we must find a number before anything else */
+        if ( (FT_Byte)( c - '0' ) < 10 )
+        {
+          FT_Int  charcode;
+
+
+          parser->root.cursor = cur;
+          charcode = (FT_Int)T1_ToInt( parser );
+          cur      = parser->root.cursor;
+
+          /* skip whitespace */
+          while ( cur < limit && is_space( *cur ) )
+            cur++;
+
+          if ( cur < limit && *cur == '/' )
+          {
+            /* bingo, we have an immediate name -- it must be a */
+            /* character name                                   */
+            FT_Byte*    cur2 = cur + 1;
+            FT_PtrDist  len;
+
+
+            while ( cur2 < limit && is_alpha( *cur2 ) )
+              cur2++;
+
+            len = cur2 - cur - 1;
+
+            parser->root.error = T1_Add_Table( char_table, charcode,
+                                               cur + 1, len + 1 );
+            char_table->elements[charcode][len] = '\0';
+            if ( parser->root.error )
+              return;
+
+            cur = cur2;
+          }
+        }
+        else
+          cur++;
+      }
+
+      face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
+      parser->root.cursor       = cur;
+    }
+    /* Otherwise, we should have either `StandardEncoding', */
+    /* `ExpertEncoding', or `ISOLatin1Encoding'             */
+    else
+    {
+      if ( cur + 17 < limit                                            &&
+           ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+        face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+
+      else if ( cur + 15 < limit                                          &&
+                ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+        face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+
+      else if ( cur + 18 < limit                                             &&
+                ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
+        face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+
+      else
+      {
+        FT_ERROR(( "parse_encoding: invalid token!\n" ));
+        parser->root.error = T1_Err_Invalid_File_Format;
+      }
+    }
+  }
+
+
+  static void
+  parse_subrs( T1_Face    face,
+               T1_Loader  loader )
+  {
+    T1_Parser      parser = &loader->parser;
+    PS_Table       table  = &loader->subrs;
+    FT_Memory      memory = parser->root.memory;
+    FT_Error       error;
+    FT_Int         n;
+
+    PSAux_Service  psaux  = (PSAux_Service)face->psaux;
+
+
+    if ( loader->num_subrs )
+      /*  with synthetic fonts, it's possible we get here twice  */
+      return;
+
+    loader->num_subrs = (FT_Int)T1_ToInt( parser );
+    if ( parser->root.error )
+      return;
+
+    /* position the parser right before the `dup' of the first subr */
+    T1_Skip_Spaces( parser );
+    T1_Skip_Alpha( parser );      /* `array' */
+    T1_Skip_Spaces( parser );
+
+    /* initialize subrs array */
+    error = psaux->ps_table_funcs->init( table, loader->num_subrs, memory );
+    if ( error )
+      goto Fail;
+
+    /* the format is simple:                                 */
+    /*                                                       */
+    /*   `index' + binary data                               */
+    /*                                                       */
+    for ( n = 0; n < loader->num_subrs; n++ )
+    {
+      FT_Long   idx, size;
+      FT_Byte*  base;
+
+
+      /* If the next token isn't `dup', we are also done.  This */
+      /* happens when there are `holes' in the Subrs array.     */
+      if ( ft_strncmp( (char*)parser->root.cursor, "dup", 3 ) != 0 )
+        break;
+
+      idx = T1_ToInt( parser );
+
+      if ( !read_binary_data( parser, &size, &base ) )
+        return;
+
+      /* The binary string is followed by one token, e.g. `NP' */
+      /* (bound to `noaccess put') or by two separate tokens:  */
+      /* `noaccess' & `put'.  We position the parser right     */
+      /* before the next `dup', if any.                        */
+      T1_Skip_Spaces( parser );
+      T1_Skip_Alpha( parser );    /* `NP' or `I' or `noaccess' */
+      T1_Skip_Spaces( parser );
+
+      if ( ft_strncmp( (char*)parser->root.cursor, "put", 3 ) == 0 )
+      {
+        T1_Skip_Alpha( parser );  /* skip `put' */
+        T1_Skip_Spaces( parser );
+      }
+
+      /* some fonts use a value of -1 for lenIV to indicate that */
+      /* the charstrings are unencoded                           */
+      /*                                                         */
+      /* thanks to Tom Kacvinsky for pointing this out           */
+      /*                                                         */
+      if ( face->type1.private_dict.lenIV >= 0 )
+      {
+        FT_Byte*  temp;
+
+
+        /* t1_decrypt() shouldn't write to base -- make temporary copy */
+        if ( FT_ALLOC( temp, size ) )
+          goto Fail;
+        FT_MEM_COPY( temp, base, size );
+        psaux->t1_decrypt( temp, size, 4330 );
+        size -= face->type1.private_dict.lenIV;
+        error = T1_Add_Table( table, idx,
+                              temp + face->type1.private_dict.lenIV, size );
+        FT_FREE( temp );
+      }
+      else
+        error = T1_Add_Table( table, idx, base, size );
+      if ( error )
+        goto Fail;
+    }
+    return;
+
+  Fail:
+    parser->root.error = error;
+  }
+
+
+  static void
+  parse_charstrings( T1_Face    face,
+                     T1_Loader  loader )
+  {
+    T1_Parser      parser       = &loader->parser;
+    PS_Table       code_table   = &loader->charstrings;
+    PS_Table       name_table   = &loader->glyph_names;
+    PS_Table       swap_table   = &loader->swap_table;
+    FT_Memory      memory       = parser->root.memory;
+    FT_Error       error;
+
+    PSAux_Service  psaux        = (PSAux_Service)face->psaux;
+
+    FT_Byte*       cur;
+    FT_Byte*       limit        = parser->root.limit;
+    FT_Int         n;
+    FT_UInt        notdef_index = 0;
+    FT_Byte        notdef_found = 0;
+
+
+    if ( loader->num_glyphs )
+      /*  with synthetic fonts, it's possible we get here twice  */
+      return;
+
+    loader->num_glyphs = (FT_Int)T1_ToInt( parser );
+    if ( parser->root.error )
+      return;
+
+    /* initialize tables (leaving room for addition of .notdef, */
+    /* if necessary).                                           */
+
+    error = psaux->ps_table_funcs->init( code_table,
+                                         loader->num_glyphs + 1,
+                                         memory );
+    if ( error )
+      goto Fail;
+
+    error = psaux->ps_table_funcs->init( name_table,
+                                         loader->num_glyphs + 1,
+                                         memory );
+    if ( error )
+      goto Fail;
+
+    /* Initialize table for swapping index notdef_index and */
+    /* index 0 names and codes (if necessary).              */
+
+    error = psaux->ps_table_funcs->init( swap_table, 4, memory );
+
+    if ( error )
+      goto Fail;
+
+    n = 0;
+
+    for (;;)
+    {
+      FT_Long   size;
+      FT_Byte*  base;
+
+
+      /* the format is simple:                    */
+      /*   `/glyphname' + binary data             */
+      /*                                          */
+      /* note that we stop when we find a `def'   */
+      /*                                          */
+      T1_Skip_Spaces( parser );
+
+      cur = parser->root.cursor;
+      if ( cur >= limit )
+        break;
+
+      /* we stop when we find a `def' or `end' keyword */
+      if ( *cur   == 'd'   &&
+           cur + 3 < limit &&
+           cur[1] == 'e'   &&
+           cur[2] == 'f'   )
+        break;
+
+      if ( *cur   == 'e'   &&
+           cur + 3 < limit &&
+           cur[1] == 'n'   &&
+           cur[2] == 'd'   )
+        break;
+
+      if ( *cur != '/' )
+        T1_Skip_Alpha( parser );
+      else
+      {
+        FT_Byte*    cur2 = cur + 1;
+        FT_PtrDist  len;
+
+
+        while ( cur2 < limit && is_alpha( *cur2 ) )
+          cur2++;
+        len = cur2 - cur - 1;
+
+        error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
+        if ( error )
+          goto Fail;
+
+        /* add a trailing zero to the name table */
+        name_table->elements[n][len] = '\0';
+
+        /* record index of /.notdef              */
+        if ( ft_strcmp( (const char*)".notdef",
+                        (const char*)(name_table->elements[n]) ) == 0 )
+        {
+          notdef_index = n;
+          notdef_found = 1;
+        }
+
+        parser->root.cursor = cur2;
+        if ( !read_binary_data( parser, &size, &base ) )
+          return;
+
+        if ( face->type1.private_dict.lenIV >= 0 )
+        {
+          FT_Byte*  temp;
+
+
+          /* t1_decrypt() shouldn't write to base -- make temporary copy */
+          if ( FT_ALLOC( temp, size ) )
+            goto Fail;
+          FT_MEM_COPY( temp, base, size );
+          psaux->t1_decrypt( temp, size, 4330 );
+          size -= face->type1.private_dict.lenIV;
+          error = T1_Add_Table( code_table, n,
+                                temp + face->type1.private_dict.lenIV, size );
+          FT_FREE( temp );
+        }
+        else
+          error = T1_Add_Table( code_table, n, base, size );
+        if ( error )
+          goto Fail;
+
+        n++;
+        if ( n >= loader->num_glyphs )
+          break;
+      }
+    }
+
+    loader->num_glyphs = n;
+
+    /* if /.notdef is found but does not occupy index 0, do our magic.      */
+    if ( ft_strcmp( (const char*)".notdef",
+                    (const char*)name_table->elements[0] ) &&
+         notdef_found                                      )
+    {
+      /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0    */
+      /* name and code entries to swap_table. Then place notdef_index name */
+      /* and code entries into swap_table.  Then swap name and code        */
+      /* entries at indices notdef_index and 0 using values stored in      */
+      /* swap_table.                                                       */
+
+      /* Index 0 name */
+      error = T1_Add_Table( swap_table, 0,
+                            name_table->elements[0],
+                            name_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      /* Index 0 code */
+      error = T1_Add_Table( swap_table, 1,
+                            code_table->elements[0],
+                            code_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      /* Index notdef_index name */
+      error = T1_Add_Table( swap_table, 2,
+                            name_table->elements[notdef_index],
+                            name_table->lengths [notdef_index] );
+      if ( error )
+        goto Fail;
+
+      /* Index notdef_index code */
+      error = T1_Add_Table( swap_table, 3,
+                            code_table->elements[notdef_index],
+                            code_table->lengths [notdef_index] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( name_table, notdef_index,
+                            swap_table->elements[0],
+                            swap_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( code_table, notdef_index,
+                            swap_table->elements[1],
+                            swap_table->lengths [1] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( name_table, 0,
+                            swap_table->elements[2],
+                            swap_table->lengths [2] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( code_table, 0,
+                            swap_table->elements[3],
+                            swap_table->lengths [3] );
+      if ( error )
+        goto Fail;
+
+    }
+    else if ( !notdef_found )
+    {
+      /* notdef_index is already 0, or /.notdef is undefined in   */
+      /* charstrings dictionary.  Worry about /.notdef undefined. */
+      /* We take index 0 and add it to the end of the table(s)    */
+      /* and add our own /.notdef glyph to index 0.               */
+
+      /* 0 333 hsbw endchar                                      */
+      FT_Byte  notdef_glyph[] = {0x8B, 0xF7, 0xE1, 0x0D, 0x0E};
+      char*    notdef_name    = (char *)".notdef";
+
+
+      error = T1_Add_Table( swap_table, 0,
+                            name_table->elements[0],
+                            name_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( swap_table, 1,
+                            code_table->elements[0],
+                            code_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( name_table, 0, notdef_name, 8 );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( code_table, 0, notdef_glyph, 5 );
+
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( name_table, n,
+                            swap_table->elements[0],
+                            swap_table->lengths [0] );
+      if ( error )
+        goto Fail;
+
+      error = T1_Add_Table( code_table, n,
+                            swap_table->elements[1],
+                            swap_table->lengths [1] );
+      if ( error )
+        goto Fail;
+
+      /* we added a glyph. */
+      loader->num_glyphs = n + 1;
+    }
+
+    return;
+
+  Fail:
+    parser->root.error = error;
+  }
+
+
+  static
+  const T1_FieldRec  t1_keywords[] =
+  {
+
+#include "t1tokens.h"
+
+    /* now add the special functions... */
+    T1_FIELD_CALLBACK( "FontName", parse_font_name )
+#if 0    
+    T1_FIELD_CALLBACK( "FontBBox", parse_font_bbox )
+#endif    
+    T1_FIELD_CALLBACK( "FontMatrix", parse_font_matrix )
+    T1_FIELD_CALLBACK( "Encoding", parse_encoding )
+    T1_FIELD_CALLBACK( "Subrs", parse_subrs )
+    T1_FIELD_CALLBACK( "CharStrings", parse_charstrings )
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+    T1_FIELD_CALLBACK( "BlendDesignPositions", parse_blend_design_positions )
+    T1_FIELD_CALLBACK( "BlendDesignMap", parse_blend_design_map )
+    T1_FIELD_CALLBACK( "BlendAxisTypes", parse_blend_axis_types )
+    T1_FIELD_CALLBACK( "WeightVector", parse_weight_vector )
+    T1_FIELD_CALLBACK( "shareddict", parse_shared_dict )
+#endif
+
+    { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
+  };
+
+
+  static FT_Error
+  parse_dict( T1_Face    face,
+              T1_Loader  loader,
+              FT_Byte*   base,
+              FT_Long    size )
+  {
+    T1_Parser  parser = &loader->parser;
+
+
+    parser->root.cursor = base;
+    parser->root.limit  = base + size;
+    parser->root.error  = 0;
+
+    {
+      FT_Byte*  cur   = base;
+      FT_Byte*  limit = cur + size;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        /* look for `FontDirectory', which causes problems on some fonts */
+        if ( *cur == 'F' && cur + 25 < limit                    &&
+             ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+        {
+          FT_Byte*  cur2;
+
+
+          /* skip the `FontDirectory' keyword */
+          cur += 13;
+          cur2 = cur;
+
+          /* lookup the `known' keyword */
+          while ( cur < limit && *cur != 'k'           &&
+                  ft_strncmp( (char*)cur, "known", 5 ) )
+            cur++;
+
+          if ( cur < limit )
+          {
+            T1_TokenRec  token;
+
+
+            /* skip the `known' keyword and the token following it */
+            cur += 5;
+            loader->parser.root.cursor = cur;
+            T1_ToToken( &loader->parser, &token );
+
+            /* if the last token was an array, skip it! */
+            if ( token.type == T1_TOKEN_TYPE_ARRAY )
+              cur2 = parser->root.cursor;
+          }
+          cur = cur2;
+        }
+        /* look for immediates */
+        else if ( *cur == '/' && cur + 2 < limit )
+        {
+          FT_Byte*    cur2;
+          FT_PtrDist  len;
+
+
+          cur++;
+          cur2 = cur;
+          while ( cur2 < limit && is_alpha( *cur2 ) )
+            cur2++;
+
+          len = cur2 - cur;
+          if ( len > 0 && len < 22 )
+          {
+            {
+              /* now, compare the immediate name to the keyword table */
+              T1_Field  keyword = (T1_Field)t1_keywords;
+
+
+              for (;;)
+              {
+                FT_Byte*  name;
+
+
+                name = (FT_Byte*)keyword->ident;
+                if ( !name )
+                  break;
+
+                if ( cur[0] == name[0]                     &&
+                     len == ft_strlen( (const char*)name ) )
+                {
+                  FT_PtrDist  n;
+
+
+                  for ( n = 1; n < len; n++ )
+                    if ( cur[n] != name[n] )
+                      break;
+
+                  if ( n >= len )
+                  {
+                    /* we found it -- run the parsing callback! */
+                    parser->root.cursor = cur2;
+                    T1_Skip_Spaces( parser );
+                    parser->root.error = t1_load_keyword( face,
+                                                          loader,
+                                                          keyword );
+                    if ( parser->root.error )
+                      return parser->root.error;
+
+                    cur = parser->root.cursor;
+                    break;
+                  }
+                }
+                keyword++;
+              }
+            }
+          }
+        }
+      }
+    }
+    return parser->root.error;
+  }
+
+
+  static void
+  t1_init_loader( T1_Loader  loader,
+                  T1_Face    face )
+  {
+    FT_UNUSED( face );
+
+    FT_MEM_ZERO( loader, sizeof ( *loader ) );
+    loader->num_glyphs = 0;
+    loader->num_chars  = 0;
+
+    /* initialize the tables -- simply set their `init' field to 0 */
+    loader->encoding_table.init = 0;
+    loader->charstrings.init    = 0;
+    loader->glyph_names.init    = 0;
+    loader->subrs.init          = 0;
+    loader->swap_table.init     = 0;
+    loader->fontdata            = 0;
+  }
+
+
+  static void
+  t1_done_loader( T1_Loader  loader )
+  {
+    T1_Parser  parser = &loader->parser;
+
+
+    /* finalize tables */
+    T1_Release_Table( &loader->encoding_table );
+    T1_Release_Table( &loader->charstrings );
+    T1_Release_Table( &loader->glyph_names );
+    T1_Release_Table( &loader->swap_table );
+    T1_Release_Table( &loader->subrs );
+
+    /* finalize parser */
+    T1_Finalize_Parser( parser );
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Open_Face( T1_Face  face )
+  {
+    T1_LoaderRec   loader;
+    T1_Parser      parser;
+    T1_Font        type1 = &face->type1;
+    FT_Error       error;
+
+    PSAux_Service  psaux = (PSAux_Service)face->psaux;
+
+
+    t1_init_loader( &loader, face );
+
+    /* default lenIV */
+    type1->private_dict.lenIV = 4;
+
+    /* default blue fuzz, we put it there since 0 is a valid value */
+    type1->private_dict.blue_fuzz = 1;
+
+    parser = &loader.parser;
+    error  = T1_New_Parser( parser,
+                            face->root.stream,
+                            face->root.memory,
+                            psaux );
+    if ( error )
+      goto Exit;
+
+    error = parse_dict( face, &loader, parser->base_dict, parser->base_len );
+    if ( error )
+      goto Exit;
+
+    error = T1_Get_Private_Dict( parser, psaux );
+    if ( error )
+      goto Exit;
+
+    error = parse_dict( face, &loader, parser->private_dict,
+                        parser->private_len );
+    if ( error )
+      goto Exit;
+
+    /* now, propagate the subrs, charstrings, and glyphnames tables */
+    /* to the Type1 data                                            */
+    type1->num_glyphs = loader.num_glyphs;
+
+    if ( loader.subrs.init )
+    {
+      loader.subrs.init  = 0;
+      type1->num_subrs   = loader.num_subrs;
+      type1->subrs_block = loader.subrs.block;
+      type1->subrs       = loader.subrs.elements;
+      type1->subrs_len   = loader.subrs.lengths;
+    }
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if ( !face->root.internal->incremental_interface )
+#endif
+      if ( !loader.charstrings.init )
+      {
+        FT_ERROR(( "T1_Open_Face: no charstrings array in face!\n" ));
+        error = T1_Err_Invalid_File_Format;
+      }
+
+    loader.charstrings.init  = 0;
+    type1->charstrings_block = loader.charstrings.block;
+    type1->charstrings       = loader.charstrings.elements;
+    type1->charstrings_len   = loader.charstrings.lengths;
+
+    /* we copy the glyph names `block' and `elements' fields; */
+    /* the `lengths' field must be released later             */
+    type1->glyph_names_block    = loader.glyph_names.block;
+    type1->glyph_names          = (FT_String**)loader.glyph_names.elements;
+    loader.glyph_names.block    = 0;
+    loader.glyph_names.elements = 0;
+
+    /* we must now build type1.encoding when we have a custom array */
+    if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
+    {
+      FT_Int    charcode, idx, min_char, max_char;
+      FT_Byte*  char_name;
+      FT_Byte*  glyph_name;
+
+
+      /* OK, we do the following: for each element in the encoding  */
+      /* table, look up the index of the glyph having the same name */
+      /* the index is then stored in type1.encoding.char_index, and */
+      /* a the name to type1.encoding.char_name                     */
+
+      min_char = +32000;
+      max_char = -32000;
+
+      charcode = 0;
+      for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
+      {
+        type1->encoding.char_index[charcode] = 0;
+        type1->encoding.char_name [charcode] = (char *)".notdef";
+
+        char_name = loader.encoding_table.elements[charcode];
+        if ( char_name )
+          for ( idx = 0; idx < type1->num_glyphs; idx++ )
+          {
+            glyph_name = (FT_Byte*)type1->glyph_names[idx];
+            if ( ft_strcmp( (const char*)char_name,
+                            (const char*)glyph_name ) == 0 )
+            {
+              type1->encoding.char_index[charcode] = (FT_UShort)idx;
+              type1->encoding.char_name [charcode] = (char*)glyph_name;
+
+              /* Change min/max encoded char only if glyph name is */
+              /* not /.notdef                                      */
+              if ( ft_strcmp( (const char*)".notdef",
+                              (const char*)glyph_name ) != 0 )
+              {
+                if ( charcode < min_char ) min_char = charcode;
+                if ( charcode > max_char ) max_char = charcode;
+              }
+              break;
+            }
+          }
+      }
+      type1->encoding.code_first = min_char;
+      type1->encoding.code_last  = max_char;
+      type1->encoding.num_chars  = loader.num_chars;
+    }
+
+  Exit:
+    t1_done_loader( &loader );
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1load.h
@@ -1,0 +1,84 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1load.h                                                               */
+/*                                                                         */
+/*    Type 1 font loader (specification).                                  */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1LOAD_H__
+#define __T1LOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+#include FT_MULTIPLE_MASTERS_H
+
+#include "t1parse.h"
+
+
+FT_BEGIN_HEADER
+
+
+  typedef struct  T1_Loader_
+  {
+    T1_ParserRec  parser;          /* parser used to read the stream */
+
+    FT_Int        num_chars;       /* number of characters in encoding */
+    PS_TableRec   encoding_table;  /* PS_Table used to store the       */
+                                   /* encoding character names         */
+
+    FT_Int        num_glyphs;
+    PS_TableRec   glyph_names;
+    PS_TableRec   charstrings;
+    PS_TableRec   swap_table;      /* For moving .notdef glyph to index 0. */
+
+    FT_Int        num_subrs;
+    PS_TableRec   subrs;
+    FT_Bool       fontdata;
+
+  } T1_LoaderRec, *T1_Loader;
+
+
+  FT_LOCAL( FT_Error )
+  T1_Open_Face( T1_Face  face );
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+
+  FT_LOCAL( FT_Error )
+  T1_Get_Multi_Master( T1_Face           face,
+                       FT_Multi_Master*  master );
+
+  FT_LOCAL( FT_Error )
+  T1_Set_MM_Blend( T1_Face    face,
+                   FT_UInt    num_coords,
+                   FT_Fixed*  coords );
+
+  FT_LOCAL( FT_Error )
+  T1_Set_MM_Design( T1_Face   face,
+                    FT_UInt   num_coords,
+                    FT_Long*  coords );
+
+  FT_LOCAL( void )
+  T1_Done_Blend( T1_Face  face );
+
+#endif /* !T1_CONFIG_OPTION_NO_MM_SUPPORT */
+
+
+FT_END_HEADER
+
+#endif /* __T1LOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1objs.c
@@ -1,0 +1,541 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1objs.c                                                               */
+/*                                                                         */
+/*    Type 1 objects manager (body).                                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+
+#include "t1gload.h"
+#include "t1load.h"
+
+#include "t1errors.h"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.h"
+#endif
+
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1objs
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                            SIZE FUNCTIONS                             */
+  /*                                                                       */
+  /*  note that we store the global hints in the size's "internal" root    */
+  /*  field                                                                */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static PSH_Globals_Funcs
+  T1_Size_Get_Globals_Funcs( T1_Size  size )
+  {
+    T1_Face           face     = (T1_Face)size->root.face;
+    PSHinter_Service  pshinter = (PSHinter_Service)face->pshinter;
+    FT_Module         module;
+
+
+    module = FT_Get_Module( size->root.face->driver->root.library,
+                            "pshinter" );
+    return ( module && pshinter && pshinter->get_globals_funcs )
+           ? pshinter->get_globals_funcs( module )
+           : 0 ;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  T1_Size_Done( T1_Size  size )
+  {
+    if ( size->root.internal )
+    {
+      PSH_Globals_Funcs  funcs;
+
+
+      funcs = T1_Size_Get_Globals_Funcs( size );
+      if ( funcs )
+        funcs->destroy( (PSH_Globals)size->root.internal );
+
+      size->root.internal = 0;
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Size_Init( T1_Size  size )
+  {
+    FT_Error           error = 0;
+    PSH_Globals_Funcs  funcs = T1_Size_Get_Globals_Funcs( size );
+
+
+    if ( funcs )
+    {
+      PSH_Globals  globals;
+      T1_Face      face = (T1_Face)size->root.face;
+
+
+      error = funcs->create( size->root.face->memory,
+                             &face->type1.private_dict, &globals );
+      if ( !error )
+        size->root.internal = (FT_Size_Internal)(void*)globals;
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Size_Reset( T1_Size  size )
+  {
+    PSH_Globals_Funcs  funcs = T1_Size_Get_Globals_Funcs( size );
+    FT_Error           error = 0;
+
+
+    if ( funcs )
+      error = funcs->set_scale( (PSH_Globals)size->root.internal,
+                                 size->root.metrics.x_scale,
+                                 size->root.metrics.y_scale,
+                                 0, 0 );
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                            SLOT  FUNCTIONS                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  T1_GlyphSlot_Done( T1_GlyphSlot  slot )
+  {
+    slot->root.internal->glyph_hints = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_GlyphSlot_Init( T1_GlyphSlot  slot )
+  {
+    T1_Face           face;
+    PSHinter_Service  pshinter;
+
+
+    face     = (T1_Face)slot->root.face;
+    pshinter = (PSHinter_Service)face->pshinter;
+
+    if ( pshinter )
+    {
+      FT_Module  module;
+
+
+      module = FT_Get_Module( slot->root.face->driver->root.library, "pshinter" );
+      if (module)
+      {
+        T1_Hints_Funcs  funcs;
+
+        funcs = pshinter->get_t1_funcs( module );
+        slot->root.internal->glyph_hints = (void*)funcs;
+      }
+    }
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                            FACE  FUNCTIONS                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    T1_Face_Done                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The face object destructor.                                        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A typeless pointer to the face object to destroy.          */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  T1_Face_Done( T1_Face  face )
+  {
+    FT_Memory  memory;
+    T1_Font    type1 = &face->type1;
+
+
+    if ( face )
+    {
+      memory = face->root.memory;
+
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+      /* release multiple masters information */
+      T1_Done_Blend( face );
+      face->blend = 0;
+#endif
+
+      /* release font info strings */
+      {
+        PS_FontInfo  info = &type1->font_info;
+
+
+        FT_FREE( info->version );
+        FT_FREE( info->notice );
+        FT_FREE( info->full_name );
+        FT_FREE( info->family_name );
+        FT_FREE( info->weight );
+      }
+
+      /* release top dictionary */
+      FT_FREE( type1->charstrings_len );
+      FT_FREE( type1->charstrings );
+      FT_FREE( type1->glyph_names );
+
+      FT_FREE( type1->subrs );
+      FT_FREE( type1->subrs_len );
+
+      FT_FREE( type1->subrs_block );
+      FT_FREE( type1->charstrings_block );
+      FT_FREE( type1->glyph_names_block );
+
+      FT_FREE( type1->encoding.char_index );
+      FT_FREE( type1->encoding.char_name );
+      FT_FREE( type1->font_name );
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+      /* release afm data if present */
+      if ( face->afm_data )
+        T1_Done_AFM( memory, (T1_AFM*)face->afm_data );
+#endif
+
+      /* release unicode map, if any */
+      FT_FREE( face->unicode_map.maps );
+      face->unicode_map.num_maps = 0;
+
+      face->root.family_name = 0;
+      face->root.style_name  = 0;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    T1_Face_Init                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The face object constructor.                                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream     ::  input stream where to load font data.               */
+  /*                                                                       */
+  /*    face_index :: The index of the font face in the resource.          */
+  /*                                                                       */
+  /*    num_params :: Number of additional generic parameters.  Ignored.   */
+  /*                                                                       */
+  /*    params     :: Additional generic parameters.  Ignored.             */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face       :: The face record to build.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  T1_Face_Init( FT_Stream      stream,
+                T1_Face        face,
+                FT_Int         face_index,
+                FT_Int         num_params,
+                FT_Parameter*  params )
+  {
+    FT_Error          error;
+    PSNames_Service   psnames;
+    PSAux_Service     psaux;
+    PSHinter_Service  pshinter;
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+    FT_UNUSED( face_index );
+    FT_UNUSED( stream );
+
+
+    face->root.num_faces = 1;
+
+    face->psnames = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+                                             "psnames" );
+    psnames = (PSNames_Service)face->psnames;
+
+    face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+                                           "psaux" );
+    psaux = (PSAux_Service)face->psaux;
+
+    face->pshinter = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+                                              "pshinter" );
+    pshinter = (PSHinter_Service)face->pshinter;
+
+    /* open the tokenizer, this will also check the font format */
+    error = T1_Open_Face( face );
+    if ( error )
+      goto Exit;
+
+    /* if we just wanted to check the format, leave successfully now */
+    if ( face_index < 0 )
+      goto Exit;
+
+    /* check the face index */
+    if ( face_index != 0 )
+    {
+      FT_ERROR(( "T1_Face_Init: invalid face index\n" ));
+      error = T1_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* Now, load the font program into the face object */
+
+    /* Init the face object fields */
+    /* Now set up root face fields */
+    {
+      FT_Face  root = (FT_Face)&face->root;
+
+
+      root->num_glyphs = face->type1.num_glyphs;
+      root->face_index = face_index;
+
+      root->face_flags = FT_FACE_FLAG_SCALABLE;
+      root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+      root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
+
+      if ( face->type1.font_info.is_fixed_pitch )
+        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+      if ( face->blend )
+        root->face_flags |= FT_FACE_FLAG_MULTIPLE_MASTERS;
+
+      /* XXX: TODO -- add kerning with .afm support */
+
+      /* get style name -- be careful, some broken fonts only */
+      /* have a `/FontName' dictionary entry!                 */
+      root->family_name = face->type1.font_info.family_name;
+      if ( root->family_name )
+      {
+        char*  full   = face->type1.font_info.full_name;
+        char*  family = root->family_name;
+
+
+        if ( full )
+        {
+          while ( *family && *full == *family )
+          {
+            family++;
+            full++;
+          }
+
+          root->style_name = ( *full == ' ' ? full + 1
+                                            : (char *)"Regular" );
+        }
+        else
+          root->style_name = (char *)"Regular";
+      }
+      else
+      {
+        /* do we have a `/FontName'? */
+        if ( face->type1.font_name )
+        {
+          root->family_name = face->type1.font_name;
+          root->style_name  = (char *)"Regular";
+        }
+      }
+
+      /* compute style flags */
+      root->style_flags = 0;
+      if ( face->type1.font_info.italic_angle )
+        root->style_flags |= FT_STYLE_FLAG_ITALIC;
+      if ( face->type1.font_info.weight )
+      {
+        if ( !ft_strcmp( face->type1.font_info.weight, "Bold"  ) ||
+             !ft_strcmp( face->type1.font_info.weight, "Black" ) )
+          root->style_flags |= FT_STYLE_FLAG_BOLD;
+      }
+
+      /* no embedded bitmap support */
+      root->num_fixed_sizes = 0;
+      root->available_sizes = 0;
+
+      root->bbox.xMin =   face->type1.font_bbox.xMin             >> 16;
+      root->bbox.yMin =   face->type1.font_bbox.yMin             >> 16;
+      root->bbox.xMax = ( face->type1.font_bbox.xMax + 0xFFFFU ) >> 16;
+      root->bbox.yMax = ( face->type1.font_bbox.yMax + 0xFFFFU ) >> 16;
+
+      /* Set units_per_EM if we didn't set it in parse_font_matrix. */
+      if ( !root->units_per_EM )
+        root->units_per_EM = 1000;
+
+      root->ascender  = (FT_Short)( root->bbox.yMax );
+      root->descender = (FT_Short)( root->bbox.yMin );
+      root->height    = (FT_Short)(
+                          ( ( root->ascender - root->descender ) * 12 ) / 10 );
+
+      /* now compute the maximum advance width */
+      root->max_advance_width =
+        (FT_Short)( root->bbox.xMax );
+      {
+        FT_Int  max_advance;
+
+
+        error = T1_Compute_Max_Advance( face, &max_advance );
+
+        /* in case of error, keep the standard width */
+        if ( !error )
+          root->max_advance_width = (FT_Short)max_advance;
+        else
+          error = 0;   /* clear error */
+      }
+
+      root->max_advance_height = root->height;
+
+      root->underline_position  = face->type1.font_info.underline_position;
+      root->underline_thickness = face->type1.font_info.underline_thickness;
+
+      root->internal->max_points   = 0;
+      root->internal->max_contours = 0;
+    }
+
+    {
+      FT_Face  root = &face->root;
+
+
+      if ( psnames && psaux )
+      {
+        FT_CharMapRec    charmap;
+        T1_CMap_Classes  cmap_classes = psaux->t1_cmap_classes;
+        FT_CMap_Class    clazz;
+
+
+        charmap.face = root;
+
+        /* first of all, try to synthetize a Unicode charmap */
+        charmap.platform_id = 3;
+        charmap.encoding_id = 1;
+        charmap.encoding    = FT_ENCODING_UNICODE;
+
+        FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL );
+
+        /* now, generate an Adobe Standard encoding when appropriate */
+        charmap.platform_id = 7;
+        clazz               = NULL;
+
+        switch ( face->type1.encoding_type )
+        {
+        case T1_ENCODING_TYPE_STANDARD:
+          charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
+          charmap.encoding_id = 0;
+          clazz               = cmap_classes->standard;
+          break;
+
+        case T1_ENCODING_TYPE_EXPERT:
+          charmap.encoding    = FT_ENCODING_ADOBE_EXPERT;
+          charmap.encoding_id = 1;
+          clazz               = cmap_classes->expert;
+          break;
+
+        case T1_ENCODING_TYPE_ARRAY:
+          charmap.encoding    = FT_ENCODING_ADOBE_CUSTOM;
+          charmap.encoding_id = 2;
+          clazz               = cmap_classes->custom;
+          break;
+
+        case T1_ENCODING_TYPE_ISOLATIN1:
+          charmap.encoding    = FT_ENCODING_ADOBE_LATIN_1;
+          charmap.encoding_id = 3;
+          clazz               = cmap_classes->unicode;
+          break;
+
+        default:
+          ;
+        }
+
+        if ( clazz )
+          FT_CMap_New( clazz, NULL, &charmap, NULL );
+
+#if 0
+        /* Select default charmap */
+        if (root->num_charmaps)
+          root->charmap = root->charmaps[0];
+#endif
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    T1_Driver_Init                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given Type 1 driver object.                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    driver :: A handle to the target driver object.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  T1_Driver_Init( T1_Driver  driver )
+  {
+    FT_UNUSED( driver );
+
+    return T1_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    T1_Driver_Done                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a given Type 1 driver.                                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    driver :: A handle to the target Type 1 driver.                    */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  T1_Driver_Done( T1_Driver  driver )
+  {
+    FT_UNUSED( driver );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1objs.h
@@ -1,0 +1,170 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1objs.h                                                               */
+/*                                                                         */
+/*    Type 1 objects manager (specification).                              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1OBJS_H__
+#define __T1OBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  /* The following structures must be defined by the hinter */
+  typedef struct T1_Size_Hints_   T1_Size_Hints;
+  typedef struct T1_Glyph_Hints_  T1_Glyph_Hints;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    T1_Driver                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 driver object.                                */
+  /*                                                                       */
+  typedef struct T1_DriverRec_   *T1_Driver;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    T1_Size                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 size object.                                  */
+  /*                                                                       */
+  typedef struct T1_SizeRec_*  T1_Size;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    T1_GlyphSlot                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 glyph slot object.                            */
+  /*                                                                       */
+  typedef struct T1_GlyphSlotRec_*  T1_GlyphSlot;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    T1_CharMap                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a Type 1 character mapping object.                     */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The Type 1 format doesn't use a charmap but an encoding table.     */
+  /*    The driver is responsible for making up charmap objects            */
+  /*    corresponding to these tables.                                     */
+  /*                                                                       */
+  typedef struct T1_CharMapRec_*   T1_CharMap;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                  HERE BEGINS THE TYPE1 SPECIFIC STUFF                 */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    T1_SizeRec                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Type 1 size record.                                                */
+  /*                                                                       */
+  typedef struct  T1_SizeRec_
+  {
+    FT_SizeRec  root;
+
+  } T1_SizeRec;
+
+
+  FT_LOCAL( void )
+  T1_Size_Done( T1_Size  size );
+
+  FT_LOCAL( FT_Error )
+  T1_Size_Reset( T1_Size  size );
+
+  FT_LOCAL( FT_Error )
+  T1_Size_Init( T1_Size  size );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    T1_GlyphSlotRec                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Type 1 glyph slot record.                                          */
+  /*                                                                       */
+  typedef struct  T1_GlyphSlotRec_
+  {
+    FT_GlyphSlotRec  root;
+
+    FT_Bool          hint;
+    FT_Bool          scaled;
+
+    FT_Int           max_points;
+    FT_Int           max_contours;
+
+    FT_Fixed         x_scale;
+    FT_Fixed         y_scale;
+
+  } T1_GlyphSlotRec;
+
+
+  FT_LOCAL( FT_Error )
+  T1_Face_Init( FT_Stream      stream,
+                T1_Face        face,
+                FT_Int         face_index,
+                FT_Int         num_params,
+                FT_Parameter*  params );
+
+  FT_LOCAL( void )
+  T1_Face_Done( T1_Face  face );
+
+  FT_LOCAL( FT_Error )
+  T1_GlyphSlot_Init( T1_GlyphSlot  slot );
+  
+  FT_LOCAL( void )
+  T1_GlyphSlot_Done( T1_GlyphSlot  slot );
+
+  FT_LOCAL( FT_Error )
+  T1_Driver_Init( T1_Driver  driver );
+
+  FT_LOCAL( void )
+  T1_Driver_Done( T1_Driver  driver );
+
+
+FT_END_HEADER
+
+#endif /* __T1OBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1parse.c
@@ -1,0 +1,460 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1parse.c                                                              */
+/*                                                                         */
+/*    Type 1 parser (body).                                                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The Type 1 parser is in charge of the following:                      */
+  /*                                                                       */
+  /*  - provide an implementation of a growing sequence of objects called  */
+  /*    a `T1_Table' (used to build various tables needed by the loader).  */
+  /*                                                                       */
+  /*  - opening .pfb and .pfa files to extract their top-level and private */
+  /*    dictionaries.                                                      */
+  /*                                                                       */
+  /*  - read numbers, arrays & strings from any dictionary.                */
+  /*                                                                       */
+  /* See `t1load.c' to see how data is loaded from the font file.          */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+#include "t1parse.h"
+
+#include "t1errors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t1parse
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                   INPUT STREAM PARSER                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+#define IS_T1_WHITESPACE( c )  ( (c) == ' '  || (c) == '\t' )
+#define IS_T1_LINESPACE( c )   ( (c) == '\r' || (c) == '\n' )
+
+#define IS_T1_SPACE( c )  ( IS_T1_WHITESPACE( c ) || IS_T1_LINESPACE( c ) )
+
+
+  typedef struct  PFB_Tag_
+  {
+    FT_UShort  tag;
+    FT_Long    size;
+
+  } PFB_Tag;
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PFB_Tag
+
+
+  static
+  const FT_Frame_Field  pfb_tag_fields[] =
+  {
+    FT_FRAME_START( 6 ),
+      FT_FRAME_USHORT ( tag ),
+      FT_FRAME_LONG_LE( size ),
+    FT_FRAME_END
+  };
+
+
+  static FT_Error
+  read_pfb_tag( FT_Stream   stream,
+                FT_UShort*  tag,
+                FT_Long*    size )
+  {
+    FT_Error  error;
+    PFB_Tag   head;
+
+
+    *tag  = 0;
+    *size = 0;
+    if ( !FT_STREAM_READ_FIELDS( pfb_tag_fields, &head ) )
+    {
+      if ( head.tag == 0x8001U || head.tag == 0x8002U )
+      {
+        *tag  = head.tag;
+        *size = head.size;
+      }
+    }
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_New_Parser( T1_Parser      parser,
+                 FT_Stream      stream,
+                 FT_Memory      memory,
+                 PSAux_Service  psaux )
+  {
+    FT_Error   error;
+    FT_UShort  tag;
+    FT_Long    size;
+
+
+    psaux->ps_parser_funcs->init( &parser->root,0, 0, memory );
+
+    parser->stream       = stream;
+    parser->base_len     = 0;
+    parser->base_dict    = 0;
+    parser->private_len  = 0;
+    parser->private_dict = 0;
+    parser->in_pfb       = 0;
+    parser->in_memory    = 0;
+    parser->single_block = 0;
+
+    /******************************************************************/
+    /*                                                                */
+    /* Here a short summary of what is going on:                      */
+    /*                                                                */
+    /*   When creating a new Type 1 parser, we try to locate and load */
+    /*   the base dictionary if this is possible (i.e. for PFB        */
+    /*   files).  Otherwise, we load the whole font into memory.      */
+    /*                                                                */
+    /*   When `loading' the base dictionary, we only setup pointers   */
+    /*   in the case of a memory-based stream.  Otherwise, we         */
+    /*   allocate and load the base dictionary in it.                 */
+    /*                                                                */
+    /*   parser->in_pfb is set if we are in a binary (".pfb") font.   */
+    /*   parser->in_memory is set if we have a memory stream.         */
+    /*                                                                */
+
+    /* try to compute the size of the base dictionary;   */
+    /* look for a Postscript binary file tag, i.e 0x8001 */
+    if ( FT_STREAM_SEEK( 0L ) )
+      goto Exit;
+
+    error = read_pfb_tag( stream, &tag, &size );
+    if ( error )
+      goto Exit;
+
+    if ( tag != 0x8001U )
+    {
+      /* assume that this is a PFA file for now; an error will */
+      /* be produced later when more things are checked        */
+      if ( FT_STREAM_SEEK( 0L ) )
+        goto Exit;
+      size = stream->size;
+    }
+    else
+      parser->in_pfb = 1;
+
+    /* now, try to load `size' bytes of the `base' dictionary we */
+    /* found previously                                          */
+
+    /* if it is a memory-based resource, set up pointers */
+    if ( !stream->read )
+    {
+      parser->base_dict = (FT_Byte*)stream->base + stream->pos;
+      parser->base_len  = size;
+      parser->in_memory = 1;
+
+      /* check that the `size' field is valid */
+      if ( FT_STREAM_SKIP( size ) )
+        goto Exit;
+    }
+    else
+    {
+      /* read segment in memory */
+      if ( FT_ALLOC( parser->base_dict, size )     ||
+           FT_STREAM_READ( parser->base_dict, size ) )
+        goto Exit;
+      parser->base_len = size;
+    }
+
+    /* Now check font format; we must see `%!PS-AdobeFont-1' */
+    /* or `%!FontType'                                       */
+    {
+      if ( size <= 16                                       ||
+           ( ft_strncmp( (const char*)parser->base_dict,
+                         "%!PS-AdobeFont-1", 16 )        &&
+             ft_strncmp( (const char*)parser->base_dict,
+                         "%!FontType", 10 )              )  )
+      {
+        FT_TRACE2(( "[not a Type1 font]\n" ));
+        error = T1_Err_Unknown_File_Format;
+      }
+      else
+      {
+        parser->root.base   = parser->base_dict;
+        parser->root.cursor = parser->base_dict;
+        parser->root.limit  = parser->root.cursor + parser->base_len;
+      }
+    }
+
+  Exit:
+    if ( error && !parser->in_memory )
+      FT_FREE( parser->base_dict );
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  T1_Finalize_Parser( T1_Parser  parser )
+  {
+    FT_Memory  memory = parser->root.memory;
+
+
+    /* always free the private dictionary */
+    FT_FREE( parser->private_dict );
+
+    /* free the base dictionary only when we have a disk stream */
+    if ( !parser->in_memory )
+      FT_FREE( parser->base_dict );
+
+    parser->root.funcs.done( &parser->root );
+  }
+
+
+  /* return the value of an hexadecimal digit */
+  static int
+  hexa_value( char  c )
+  {
+    unsigned int  d;
+
+
+    d = (unsigned int)( c - '0' );
+    if ( d <= 9 )
+      return (int)d;
+
+    d = (unsigned int)( c - 'a' );
+    if ( d <= 5 )
+      return (int)( d + 10 );
+
+    d = (unsigned int)( c - 'A' );
+    if ( d <= 5 )
+      return (int)( d + 10 );
+
+    return -1;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T1_Get_Private_Dict( T1_Parser      parser,
+                       PSAux_Service  psaux )
+  {
+    FT_Stream  stream = parser->stream;
+    FT_Memory  memory = parser->root.memory;
+    FT_Error   error  = 0;
+    FT_Long    size;
+
+
+    if ( parser->in_pfb )
+    {
+      /* in the case of the PFB format, the private dictionary can be  */
+      /* made of several segments.  We thus first read the number of   */
+      /* segments to compute the total size of the private dictionary  */
+      /* then re-read them into memory.                                */
+      FT_Long    start_pos = FT_STREAM_POS();
+      FT_UShort  tag;
+
+
+      parser->private_len = 0;
+      for (;;)
+      {
+        error = read_pfb_tag( stream, &tag, &size );
+        if ( error )
+          goto Fail;
+
+        if ( tag != 0x8002U )
+          break;
+
+        parser->private_len += size;
+
+        if ( FT_STREAM_SKIP( size ) )
+          goto Fail;
+      }
+
+      /* Check that we have a private dictionary there */
+      /* and allocate private dictionary buffer        */
+      if ( parser->private_len == 0 )
+      {
+        FT_ERROR(( "T1_Get_Private_Dict:" ));
+        FT_ERROR(( " invalid private dictionary section\n" ));
+        error = T1_Err_Invalid_File_Format;
+        goto Fail;
+      }
+
+      if ( FT_STREAM_SEEK( start_pos )                             ||
+           FT_ALLOC( parser->private_dict, parser->private_len ) )
+        goto Fail;
+
+      parser->private_len = 0;
+      for (;;)
+      {
+        error = read_pfb_tag( stream, &tag, &size );
+        if ( error || tag != 0x8002U )
+        {
+          error = T1_Err_Ok;
+          break;
+        }
+
+        if ( FT_STREAM_READ( parser->private_dict + parser->private_len, size ) )
+          goto Fail;
+
+        parser->private_len += size;
+      }
+    }
+    else
+    {
+      /* we have already `loaded' the whole PFA font file into memory; */
+      /* if this is a memory resource, allocate a new block to hold    */
+      /* the private dict. Otherwise, simply overwrite into the base   */
+      /* dictionary block in the heap.                                 */
+
+      /* first of all, look at the `eexec' keyword */
+      FT_Byte*  cur   = parser->base_dict;
+      FT_Byte*  limit = cur + parser->base_len;
+      FT_Byte   c;
+
+
+      for (;;)
+      {
+        c = cur[0];
+        if ( c == 'e' && cur + 9 < limit )  /* 9 = 5 letters for `eexec' + */
+                                            /* newline + 4 chars           */
+        {
+          if ( cur[1] == 'e' && cur[2] == 'x' &&
+               cur[3] == 'e' && cur[4] == 'c' )
+          {
+            cur += 6; /* we skip the newling after the `eexec' */
+
+            /* XXX: Some fonts use DOS-linefeeds, i.e. \r\n; we need to */
+            /*      skip the extra \n if we find it                     */
+            if ( cur[0] == '\n' )
+              cur++;
+
+            break;
+          }
+        }
+        cur++;
+        if ( cur >= limit )
+        {
+          FT_ERROR(( "T1_Get_Private_Dict:" ));
+          FT_ERROR(( " could not find `eexec' keyword\n" ));
+          error = T1_Err_Invalid_File_Format;
+          goto Exit;
+        }
+      }
+
+      /* now determine where to write the _encrypted_ binary private  */
+      /* dictionary.  We overwrite the base dictionary for disk-based */
+      /* resources and allocate a new block otherwise                 */
+
+      size = (FT_Long)( parser->base_len - ( cur - parser->base_dict ) );
+
+      if ( parser->in_memory )
+      {
+        /* note that we allocate one more byte to put a terminating `0' */
+        if ( FT_ALLOC( parser->private_dict, size + 1 ) )
+          goto Fail;
+        parser->private_len = size;
+      }
+      else
+      {
+        parser->single_block = 1;
+        parser->private_dict = parser->base_dict;
+        parser->private_len  = size;
+        parser->base_dict    = 0;
+        parser->base_len     = 0;
+      }
+
+      /* now determine whether the private dictionary is encoded in binary */
+      /* or hexadecimal ASCII format -- decode it accordingly              */
+
+      /* we need to access the next 4 bytes (after the final \r following */
+      /* the `eexec' keyword); if they all are hexadecimal digits, then   */
+      /* we have a case of ASCII storage                                  */
+
+      if ( ( hexa_value( cur[0] ) | hexa_value( cur[1] ) |
+             hexa_value( cur[2] ) | hexa_value( cur[3] ) ) < 0 )
+
+        /* binary encoding -- `simply' copy the private dict */
+        FT_MEM_COPY( parser->private_dict, cur, size );
+
+      else
+      {
+        /* ASCII hexadecimal encoding */
+
+        FT_Byte*  write;
+        FT_Int    count;
+
+
+        write = parser->private_dict;
+        count = 0;
+
+        for ( ;cur < limit; cur++ )
+        {
+          int  hex1;
+
+
+          /* check for newline */
+          if ( cur[0] == '\r' || cur[0] == '\n' )
+            continue;
+
+          /* exit if we have a non-hexadecimal digit that isn't a newline */
+          hex1 = hexa_value( cur[0] );
+          if ( hex1 < 0 || cur + 1 >= limit )
+            break;
+
+          /* otherwise, store byte */
+          *write++ = (FT_Byte)( ( hex1 << 4 ) | hexa_value( cur[1] ) );
+          count++;
+          cur++;
+        }
+
+        /* put a safeguard */
+        parser->private_len = write - parser->private_dict;
+        *write++ = 0;
+      }
+    }
+
+    /* we now decrypt the encoded binary private dictionary */
+    psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
+    parser->root.base   = parser->private_dict;
+    parser->root.cursor = parser->private_dict;
+    parser->root.limit  = parser->root.cursor + parser->private_len;
+
+  Fail:
+  Exit:
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1parse.h
@@ -1,0 +1,135 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1parse.h                                                              */
+/*                                                                         */
+/*    Type 1 parser (specification).                                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T1PARSE_H__
+#define __T1PARSE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    T1_ParserRec                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A PS_ParserRec is an object used to parse a Type 1 fonts very      */
+  /*    quickly.                                                           */
+  /*                                                                       */
+  /* <Fields>                                                              */
+  /*    root         :: The root parser.                                   */
+  /*                                                                       */
+  /*    stream       :: The current input stream.                          */
+  /*                                                                       */
+  /*    base_dict    :: A pointer to the top-level dictionary.             */
+  /*                                                                       */
+  /*    base_len     :: The length in bytes of the top dictionary.         */
+  /*                                                                       */
+  /*    private_dict :: A pointer to the private dictionary.               */
+  /*                                                                       */
+  /*    private_len  :: The length in bytes of the private dictionary.     */
+  /*                                                                       */
+  /*    in_pfb       :: A boolean.  Indicates that we are handling a PFB   */
+  /*                    file.                                              */
+  /*                                                                       */
+  /*    in_memory    :: A boolean.  Indicates a memory-based stream.       */
+  /*                                                                       */
+  /*    single_block :: A boolean.  Indicates that the private dictionary  */
+  /*                    is stored in lieu of the base dictionary.          */
+  /*                                                                       */
+  typedef struct  T1_ParserRec_
+  {
+    PS_ParserRec  root;
+    FT_Stream     stream;
+
+    FT_Byte*      base_dict;
+    FT_Long       base_len;
+
+    FT_Byte*      private_dict;
+    FT_Long       private_len;
+
+    FT_Byte       in_pfb;
+    FT_Byte       in_memory;
+    FT_Byte       single_block;
+
+  } T1_ParserRec, *T1_Parser;
+
+
+#define T1_Add_Table( p, i, o, l )  (p)->funcs.add( (p), i, o, l )
+#define T1_Done_Table( p )          \
+          do                        \
+          {                         \
+            if ( (p)->funcs.done )  \
+              (p)->funcs.done( p ); \
+          } while ( 0 )
+#define T1_Release_Table( p )          \
+          do                           \
+          {                            \
+            if ( (p)->funcs.release )  \
+              (p)->funcs.release( p ); \
+          } while ( 0 )
+
+
+#define T1_Skip_Spaces( p )  (p)->root.funcs.skip_spaces( &(p)->root )
+#define T1_Skip_Alpha( p )   (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define T1_ToInt( p )       (p)->root.funcs.to_int( &(p)->root )
+#define T1_ToFixed( p, t )  (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define T1_ToCoordArray( p, m, c )                           \
+          (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define T1_ToFixedArray( p, m, f, t )                           \
+          (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define T1_ToToken( p, t )                          \
+          (p)->root.funcs.to_token( &(p)->root, t )
+#define T1_ToTokenArray( p, t, m, c )                           \
+          (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define T1_Load_Field( p, f, o, m, pf )                         \
+          (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
+
+#define T1_Load_Field_Table( p, f, o, m, pf )                         \
+          (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
+
+
+  FT_LOCAL( FT_Error )
+  T1_New_Parser( T1_Parser      parser,
+                 FT_Stream      stream,
+                 FT_Memory      memory,
+                 PSAux_Service  psaux );
+
+  FT_LOCAL( FT_Error )
+  T1_Get_Private_Dict( T1_Parser      parser,
+                       PSAux_Service  psaux );
+
+  FT_LOCAL( void )
+  T1_Finalize_Parser( T1_Parser  parser );
+
+
+FT_END_HEADER
+
+#endif /* __T1PARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t1tokens.h
@@ -1,0 +1,80 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t1tokens.h                                                             */
+/*                                                                         */
+/*    Type 1 tokenizer (specification).                                    */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PS_FontInfoRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FONT_INFO
+
+  T1_FIELD_STRING   ( "version", version )
+  T1_FIELD_STRING   ( "Notice", notice )
+  T1_FIELD_STRING   ( "FullName", full_name )
+  T1_FIELD_STRING   ( "FamilyName", family_name )
+  T1_FIELD_STRING   ( "Weight", weight )
+
+  T1_FIELD_NUM      ( "ItalicAngle", italic_angle )
+  T1_FIELD_TYPE_BOOL( "isFixedPitch", is_fixed_pitch )
+  T1_FIELD_NUM      ( "UnderlinePosition", underline_position )
+  T1_FIELD_NUM      ( "UnderlineThickness", underline_thickness )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  PS_PrivateRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_PRIVATE
+
+  T1_FIELD_NUM       ( "UniqueID", unique_id )
+  T1_FIELD_NUM       ( "lenIV", lenIV )
+  T1_FIELD_NUM       ( "LanguageGroup", language_group )
+  T1_FIELD_NUM       ( "password", password )
+
+  T1_FIELD_FIXED     ( "BlueScale", blue_scale )
+  T1_FIELD_NUM       ( "BlueShift", blue_shift )
+  T1_FIELD_NUM       ( "BlueFuzz",  blue_fuzz )
+
+  T1_FIELD_NUM_TABLE ( "BlueValues", blue_values, 14 )
+  T1_FIELD_NUM_TABLE ( "OtherBlues", other_blues, 10 )
+  T1_FIELD_NUM_TABLE ( "FamilyBlues", family_blues, 14 )
+  T1_FIELD_NUM_TABLE ( "FamilyOtherBlues", family_other_blues, 10 )
+
+  T1_FIELD_NUM_TABLE2( "StdHW", standard_width,  1 )
+  T1_FIELD_NUM_TABLE2( "StdVW", standard_height, 1 )
+  T1_FIELD_NUM_TABLE2( "MinFeature", min_feature, 2 )
+
+  T1_FIELD_NUM_TABLE ( "StemSnapH", snap_widths, 12 )
+  T1_FIELD_NUM_TABLE ( "StemSnapV", snap_heights, 12 )
+
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  T1_FontRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FONT_DICT
+
+  T1_FIELD_NUM( "PaintType", paint_type )
+  T1_FIELD_NUM( "FontType", font_type )
+  T1_FIELD_NUM( "StrokeWidth", stroke_width )
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  FT_BBox
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_BBOX
+
+  T1_FIELD_BBOX("FontBBox", xMin )
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42drivr.c
@@ -1,0 +1,169 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t42drivr.c                                                             */
+/*                                                                         */
+/*    High-level Type 42 driver interface (body).                          */
+/*                                                                         */
+/*  Copyright 2002 by Roberto Alameda.                                     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This driver implements Type42 fonts as described in the               */
+  /* Technical Note #5012 from Adobe, with these limitations:              */
+  /*                                                                       */
+  /* 1) CID Fonts are not currently supported.                             */
+  /* 2) Incremental fonts making use of the GlyphDirectory keyword         */
+  /*    will be loaded, but the rendering will be using the TrueType       */
+  /*    tables.                                                            */
+  /* 3) The sfnts array is expected to be ASCII, not binary.               */
+  /* 4) As for Type1 fonts, CDevProc is not supported.                     */
+  /* 5) The Metrics dictionary is not supported.                           */
+  /* 6) AFM metrics are not supported.                                     */
+  /*                                                                       */
+  /* In other words, this driver supports Type42 fonts derived from        */
+  /* TrueType fonts in a non-CID manner, as done by usual conversion       */
+  /* programs.                                                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include "t42drivr.h"
+#include "t42objs.h"
+#include "t42error.h"
+#include FT_INTERNAL_DEBUG_H
+
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t42
+
+
+  static FT_Error
+  t42_get_glyph_name( T42_Face    face,
+                      FT_UInt     glyph_index,
+                      FT_Pointer  buffer,
+                      FT_UInt     buffer_max )
+  {
+    FT_String*  gname;
+
+
+    gname = face->type1.glyph_names[glyph_index];
+
+    if ( buffer_max > 0 )
+    {
+      FT_UInt  len = (FT_UInt)( ft_strlen( gname ) );
+
+
+      if ( len >= buffer_max )
+        len = buffer_max - 1;
+
+      FT_MEM_COPY( buffer, gname, len );
+      ((FT_Byte*)buffer)[len] = 0;
+    }
+
+    return T42_Err_Ok;
+  }
+
+
+  static const char*
+  t42_get_ps_name( T42_Face  face )
+  {
+    return (const char*)face->type1.font_name;
+  }
+
+
+  static FT_UInt
+  t42_get_name_index( T42_Face    face,
+                      FT_String*  glyph_name )
+  {
+    FT_Int      i;
+    FT_String*  gname;
+
+
+    for ( i = 0; i < face->type1.num_glyphs; i++ )
+    {
+      gname = face->type1.glyph_names[i];
+
+      if ( !ft_strcmp( glyph_name, gname ) )
+        return ft_atoi( (const char *)face->type1.charstrings[i] );
+    }
+
+    return 0;
+  }
+
+
+  static FT_Module_Interface
+  T42_Get_Interface( FT_Driver         driver,
+                     const FT_String*  t42_interface )
+  {
+    FT_UNUSED( driver );
+
+    /* Any additional interface are defined here */
+    if (ft_strcmp( (const char*)t42_interface, "glyph_name" ) == 0 )
+      return (FT_Module_Interface)t42_get_glyph_name;
+
+    if ( ft_strcmp( (const char*)t42_interface, "name_index" ) == 0 )
+      return (FT_Module_Interface)t42_get_name_index;
+
+    if ( ft_strcmp( (const char*)t42_interface, "postscript_name" ) == 0 )
+      return (FT_Module_Interface)t42_get_ps_name;
+
+    return 0;
+  }
+
+
+  const FT_Driver_ClassRec  t42_driver_class =
+  {
+    {
+      ft_module_font_driver      |
+      ft_module_driver_scalable  |
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+      ft_module_driver_has_hinter,
+#else
+      0,
+#endif
+
+      sizeof ( T42_DriverRec ),
+
+      "type42",
+      0x10000L,
+      0x20000L,
+
+      0,    /* format interface */
+
+      (FT_Module_Constructor)T42_Driver_Init,
+      (FT_Module_Destructor) T42_Driver_Done,
+      (FT_Module_Requester)  T42_Get_Interface,
+    },
+
+    sizeof ( T42_FaceRec ),
+    sizeof ( T42_SizeRec ),
+    sizeof ( T42_GlyphSlotRec ),
+
+    (FT_Face_InitFunc)        T42_Face_Init,
+    (FT_Face_DoneFunc)        T42_Face_Done,
+    (FT_Size_InitFunc)        T42_Size_Init,
+    (FT_Size_DoneFunc)        T42_Size_Done,
+    (FT_Slot_InitFunc)        T42_GlyphSlot_Init,
+    (FT_Slot_DoneFunc)        T42_GlyphSlot_Done,
+
+    (FT_Size_ResetPointsFunc) T42_Size_SetChars,
+    (FT_Size_ResetPixelsFunc) T42_Size_SetPixels,
+    (FT_Slot_LoadFunc)        T42_GlyphSlot_Load,
+
+    (FT_Face_GetKerningFunc)  0,
+    (FT_Face_AttachFunc)      0,
+
+    (FT_Face_GetAdvancesFunc) 0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42drivr.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t42drivr.h                                                             */
+/*                                                                         */
+/*    High-level Type 42 driver interface (specification).                 */
+/*                                                                         */
+/*  Copyright 2002 by Roberto Alameda.                                     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T42DRIVR_H__
+#define __T42DRIVR_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Driver_ClassRec )  t42_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __T42DRIVR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42error.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t42error.h                                                             */
+/*                                                                         */
+/*    Type 42 error codes (specification only).                            */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the Type 42 error enumeration constants.  */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __T42ERROR_H__
+#define __T42ERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  T42_Err_
+#define FT_ERR_BASE    FT_Mod_Err_T42
+
+#include FT_ERRORS_H
+
+#endif /* __T42ERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42objs.c
@@ -1,0 +1,637 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t42objs.c                                                              */
+/*                                                                         */
+/*    Type 42 objects manager (body).                                      */
+/*                                                                         */
+/*  Copyright 2002 by Roberto Alameda.                                     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "t42objs.h"
+#include "t42parse.h"
+#include "t42error.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_LIST_H
+
+
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t42
+
+
+  static FT_Error
+  T42_Open_Face( T42_Face  face )
+  {
+    T42_LoaderRec  loader;
+    T42_Parser     parser;
+    T1_Font        type1 = &face->type1;
+    FT_Memory      memory = face->root.memory;
+    FT_Error       error;
+
+    PSAux_Service  psaux  = (PSAux_Service)face->psaux;
+
+
+    t42_loader_init( &loader, face );
+
+    parser = &loader.parser;
+
+    if ( FT_ALLOC( face->ttf_data, 12 ) )
+      goto Exit;
+
+    error = t42_parser_init( parser,
+                             face->root.stream,
+                             memory,
+                             psaux);
+    if ( error )
+      goto Exit;
+
+    error = t42_parse_dict( face, &loader, parser->base_dict, parser->base_len );
+
+    if ( type1->font_type != 42 )
+    {
+      error = T42_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* now, propagate the charstrings and glyphnames tables */
+    /* to the Type1 data                                    */
+    type1->num_glyphs = loader.num_glyphs;
+
+    if ( !loader.charstrings.init ) {
+      FT_ERROR(( "T42_Open_Face: no charstrings array in face!\n" ));
+      error = T42_Err_Invalid_File_Format;
+    }
+
+    loader.charstrings.init  = 0;
+    type1->charstrings_block = loader.charstrings.block;
+    type1->charstrings       = loader.charstrings.elements;
+    type1->charstrings_len   = loader.charstrings.lengths;
+
+    /* we copy the glyph names `block' and `elements' fields; */
+    /* the `lengths' field must be released later             */
+    type1->glyph_names_block    = loader.glyph_names.block;
+    type1->glyph_names          = (FT_String**)loader.glyph_names.elements;
+    loader.glyph_names.block    = 0;
+    loader.glyph_names.elements = 0;
+
+    /* we must now build type1.encoding when we have a custom array */
+    if ( type1->encoding_type == T1_ENCODING_TYPE_ARRAY )
+    {
+      FT_Int    charcode, idx, min_char, max_char;
+      FT_Byte*  char_name;
+      FT_Byte*  glyph_name;
+
+
+      /* OK, we do the following: for each element in the encoding   */
+      /* table, look up the index of the glyph having the same name  */
+      /* as defined in the CharStrings array.                        */
+      /* The index is then stored in type1.encoding.char_index, and  */
+      /* the name in type1.encoding.char_name                        */
+
+      min_char = +32000;
+      max_char = -32000;
+
+      charcode = 0;
+      for ( ; charcode < loader.encoding_table.max_elems; charcode++ )
+      {
+        type1->encoding.char_index[charcode] = 0;
+        type1->encoding.char_name [charcode] = (char *)".notdef";
+
+        char_name = loader.encoding_table.elements[charcode];
+        if ( char_name )
+          for ( idx = 0; idx < type1->num_glyphs; idx++ )
+          {
+            glyph_name = (FT_Byte*)type1->glyph_names[idx];
+            if ( ft_strcmp( (const char*)char_name,
+                            (const char*)glyph_name ) == 0 )
+            {
+              type1->encoding.char_index[charcode] = (FT_UShort)idx;
+              type1->encoding.char_name [charcode] = (char*)glyph_name;
+
+              /* Change min/max encoded char only if glyph name is */
+              /* not /.notdef                                      */
+              if ( ft_strcmp( (const char*)".notdef",
+                              (const char*)glyph_name ) != 0 )
+              {
+                if ( charcode < min_char ) min_char = charcode;
+                if ( charcode > max_char ) max_char = charcode;
+              }
+              break;
+            }
+          }
+      }
+      type1->encoding.code_first = min_char;
+      type1->encoding.code_last  = max_char;
+      type1->encoding.num_chars  = loader.num_chars;
+    }
+
+  Exit:
+    t42_loader_done( &loader );
+    return error;
+  }
+
+
+  /***************** Driver Functions *************/
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T42_Face_Init( FT_Stream      stream,
+                 T42_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params )
+  {
+    FT_Error          error;
+    PSNames_Service   psnames;
+    PSAux_Service     psaux;
+    FT_Face           root    = (FT_Face)&face->root;
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+    FT_UNUSED( face_index );
+    FT_UNUSED( stream );
+
+
+    face->ttf_face       = NULL;
+    face->root.num_faces = 1;
+
+    face->psnames = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+                                             "psnames" );
+    psnames = (PSNames_Service)face->psnames;
+
+    face->psaux = FT_Get_Module_Interface( FT_FACE_LIBRARY( face ),
+                                           "psaux" );
+    psaux = (PSAux_Service)face->psaux;
+
+    /* open the tokenizer, this will also check the font format */
+    error = T42_Open_Face( face );
+    if ( error )
+      goto Exit;
+
+    /* if we just wanted to check the format, leave successfully now */
+    if ( face_index < 0 )
+      goto Exit;
+
+    /* check the face index */
+    if ( face_index != 0 )
+    {
+      FT_ERROR(( "T42_Face_Init: invalid face index\n" ));
+      error = T42_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    /* Now, load the font program into the face object */
+
+    /* Init the face object fields */
+    /* Now set up root face fields */
+
+    root->num_glyphs   = face->type1.num_glyphs;
+    root->num_charmaps = 0;
+    root->face_index   = face_index;
+
+    root->face_flags  = FT_FACE_FLAG_SCALABLE;
+    root->face_flags |= FT_FACE_FLAG_HORIZONTAL;
+    root->face_flags |= FT_FACE_FLAG_GLYPH_NAMES;
+
+    if ( face->type1.font_info.is_fixed_pitch )
+      root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+    /* XXX: TODO -- add kerning with .afm support */
+
+    /* get style name -- be careful, some broken fonts only */
+    /* have a `/FontName' dictionary entry!                 */
+    root->family_name = face->type1.font_info.family_name;
+    if ( root->family_name )
+    {
+      char*  full   = face->type1.font_info.full_name;
+      char*  family = root->family_name;
+
+
+      if ( full )
+      {
+        while ( *family && *full == *family )
+        {
+          family++;
+          full++;
+        }
+
+        root->style_name = ( *full == ' ' ? full + 1
+                                          : (char *)"Regular" );
+      }
+      else
+        root->style_name = (char *)"Regular";
+    }
+    else
+    {
+      /* do we have a `/FontName'? */
+      if ( face->type1.font_name )
+      {
+        root->family_name = face->type1.font_name;
+        root->style_name  = (char *)"Regular";
+      }
+    }
+
+    /* no embedded bitmap support */
+    root->num_fixed_sizes = 0;
+    root->available_sizes = 0;
+
+    /* Load the TTF font embedded in the T42 font */
+    error = FT_New_Memory_Face( FT_FACE_LIBRARY( face ),
+                                face->ttf_data,
+                                face->ttf_size,
+                                0,
+                                &face->ttf_face );
+    if ( error )
+      goto Exit;
+
+    FT_Done_Size( face->ttf_face->size );
+
+    /* Ignore info in FontInfo dictionary and use the info from the  */
+    /* loaded TTF font.  The PostScript interpreter also ignores it. */
+    root->bbox         = face->ttf_face->bbox;
+    root->units_per_EM = face->ttf_face->units_per_EM;
+
+    root->ascender  = face->ttf_face->ascender;
+    root->descender = face->ttf_face->descender;
+    root->height    = face->ttf_face->height;
+
+    root->max_advance_width  = face->ttf_face->max_advance_width;
+    root->max_advance_height = face->ttf_face->max_advance_height;
+
+    root->underline_position  = face->type1.font_info.underline_position;
+    root->underline_thickness = face->type1.font_info.underline_thickness;
+
+    root->internal->max_points   = 0;
+    root->internal->max_contours = 0;
+
+    /* compute style flags */
+    root->style_flags = 0;
+    if ( face->type1.font_info.italic_angle )
+      root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+    if ( face->ttf_face->style_flags & FT_STYLE_FLAG_BOLD )
+      root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+    if ( face->ttf_face->face_flags & FT_FACE_FLAG_VERTICAL )
+      root->face_flags |= FT_FACE_FLAG_VERTICAL;
+
+    {
+      if ( psnames && psaux )
+      {
+        FT_CharMapRec    charmap;
+        T1_CMap_Classes  cmap_classes = psaux->t1_cmap_classes;
+        FT_CMap_Class    clazz;
+
+
+        charmap.face = root;
+
+        /* first of all, try to synthetize a Unicode charmap */
+        charmap.platform_id = 3;
+        charmap.encoding_id = 1;
+        charmap.encoding    = FT_ENCODING_UNICODE;
+
+        FT_CMap_New( cmap_classes->unicode, NULL, &charmap, NULL );
+
+        /* now, generate an Adobe Standard encoding when appropriate */
+        charmap.platform_id = 7;
+        clazz               = NULL;
+
+        switch ( face->type1.encoding_type )
+        {
+        case T1_ENCODING_TYPE_STANDARD:
+          charmap.encoding    = FT_ENCODING_ADOBE_STANDARD;
+          charmap.encoding_id = 0;
+          clazz               = cmap_classes->standard;
+          break;
+
+        case T1_ENCODING_TYPE_EXPERT:
+          charmap.encoding    = FT_ENCODING_ADOBE_EXPERT;
+          charmap.encoding_id = 1;
+          clazz               = cmap_classes->expert;
+          break;
+
+        case T1_ENCODING_TYPE_ARRAY:
+          charmap.encoding    = FT_ENCODING_ADOBE_CUSTOM;
+          charmap.encoding_id = 2;
+          clazz               = cmap_classes->custom;
+          break;
+
+        case T1_ENCODING_TYPE_ISOLATIN1:
+          charmap.encoding    = FT_ENCODING_ADOBE_LATIN_1;
+          charmap.encoding_id = 3;
+          clazz               = cmap_classes->unicode;
+          break;
+
+        default:
+          ;
+        }
+
+        if ( clazz )
+          FT_CMap_New( clazz, NULL, &charmap, NULL );
+
+#if 0
+        /* Select default charmap */
+        if (root->num_charmaps)
+          root->charmap = root->charmaps[0];
+#endif
+      }
+    }
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  T42_Face_Done( T42_Face  face )
+  {
+    T1_Font      type1;
+    PS_FontInfo  info;
+    FT_Memory    memory;
+
+
+    if ( face )
+    {
+      type1  = &face->type1;
+      info   = &type1->font_info;
+      memory = face->root.memory;
+
+      /* delete internal ttf face prior to freeing face->ttf_data */
+      if ( face->ttf_face )
+        FT_Done_Face( face->ttf_face );
+
+      /* release font info strings */
+      FT_FREE( info->version );
+      FT_FREE( info->notice );
+      FT_FREE( info->full_name );
+      FT_FREE( info->family_name );
+      FT_FREE( info->weight );
+
+      /* release top dictionary */
+      FT_FREE( type1->charstrings_len );
+      FT_FREE( type1->charstrings );
+      FT_FREE( type1->glyph_names );
+
+      FT_FREE( type1->charstrings_block );
+      FT_FREE( type1->glyph_names_block );
+
+      FT_FREE( type1->encoding.char_index );
+      FT_FREE( type1->encoding.char_name );
+      FT_FREE( type1->font_name );
+
+      FT_FREE( face->ttf_data );
+
+#if 0
+      /* release afm data if present */
+      if ( face->afm_data )
+        T1_Done_AFM( memory, (T1_AFM*)face->afm_data );
+#endif
+
+      /* release unicode map, if any */
+      FT_FREE( face->unicode_map.maps );
+      face->unicode_map.num_maps = 0;
+
+      face->root.family_name = 0;
+      face->root.style_name  = 0;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    T42_Driver_Init                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given Type 42 driver object.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    driver :: A handle to the target driver object.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  T42_Driver_Init( T42_Driver  driver )
+  {
+    FT_Module  ttmodule;
+
+
+    ttmodule = FT_Get_Module( FT_MODULE(driver)->library, "truetype" );
+    driver->ttclazz = (FT_Driver_Class)ttmodule->clazz;
+
+    return T42_Err_Ok;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  T42_Driver_Done( T42_Driver  driver )
+  {
+    FT_UNUSED( driver );
+  }
+
+
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T42_Size_Init( T42_Size  size )
+  {
+    FT_Face   face = size->root.face;
+    T42_Face  t42face = (T42_Face)face;
+    FT_Size   ttsize;
+    FT_Error  error   = T42_Err_Ok;
+
+
+    error = FT_New_Size( t42face->ttf_face, &ttsize );
+    size->ttsize = ttsize;
+
+    FT_Activate_Size( ttsize );
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  T42_Size_Done( T42_Size  size )
+  {
+    FT_Face      face    = size->root.face;
+    T42_Face     t42face = (T42_Face)face;
+    FT_ListNode  node;
+
+
+    node = FT_List_Find( &t42face->ttf_face->sizes_list, size->ttsize );
+    if ( node )
+    {
+      FT_Done_Size( size->ttsize );
+      size->ttsize = NULL;
+    }
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T42_GlyphSlot_Init( T42_GlyphSlot  slot )
+  {
+    FT_Face       face    = slot->root.face;
+    T42_Face      t42face = (T42_Face)face;
+    FT_GlyphSlot  ttslot;
+    FT_Error      error   = T42_Err_Ok;
+
+
+    if ( face->glyph == NULL )
+    {
+      /* First glyph slot for this face */
+      slot->ttslot = t42face->ttf_face->glyph;
+    }
+    else
+    {
+      error = FT_New_GlyphSlot( t42face->ttf_face, &ttslot );
+      slot->ttslot = ttslot;
+    }
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  T42_GlyphSlot_Done( T42_GlyphSlot slot )
+  {
+    FT_Face       face    = slot->root.face;
+    T42_Face      t42face = (T42_Face)face;
+    FT_GlyphSlot  cur     = t42face->ttf_face->glyph;
+
+
+    while ( cur )
+    {
+      if ( cur == slot->ttslot )
+      {
+        FT_Done_GlyphSlot( slot->ttslot );
+        break;
+      }
+
+      cur = cur->next;
+    }
+  }
+
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T42_Size_SetChars( T42_Size    size,
+                     FT_F26Dot6  char_width,
+                     FT_F26Dot6  char_height,
+                     FT_UInt     horz_resolution,
+                     FT_UInt     vert_resolution )
+  {
+    FT_Face   face    = size->root.face;
+    T42_Face  t42face = (T42_Face)face;
+
+
+    FT_Activate_Size(size->ttsize);
+
+    return FT_Set_Char_Size( t42face->ttf_face,
+                             char_width,
+                             char_height,
+                             horz_resolution,
+                             vert_resolution );
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T42_Size_SetPixels( T42_Size  size,
+                      FT_UInt   pixel_width,
+                      FT_UInt   pixel_height )
+  {
+    FT_Face   face    = size->root.face;
+    T42_Face  t42face = (T42_Face)face;
+
+
+    FT_Activate_Size(size->ttsize);
+
+    return FT_Set_Pixel_Sizes( t42face->ttf_face,
+                               pixel_width,
+                               pixel_height );
+  }
+
+
+  static void
+  ft_glyphslot_clear( FT_GlyphSlot  slot )
+  {
+    /* free bitmap if needed */
+    if ( slot->flags & FT_GLYPH_OWN_BITMAP )
+    {
+      FT_Memory  memory = FT_FACE_MEMORY( slot->face );
+
+
+      FT_FREE( slot->bitmap.buffer );
+      slot->flags &= ~FT_GLYPH_OWN_BITMAP;
+    }
+
+    /* clear all public fields in the glyph slot */
+    FT_ZERO( &slot->metrics );
+    FT_ZERO( &slot->outline );
+    FT_ZERO( &slot->bitmap );
+
+    slot->bitmap_left   = 0;
+    slot->bitmap_top    = 0;
+    slot->num_subglyphs = 0;
+    slot->subglyphs     = 0;
+    slot->control_data  = 0;
+    slot->control_len   = 0;
+    slot->other         = 0;
+    slot->format        = FT_GLYPH_FORMAT_NONE;
+
+    slot->linearHoriAdvance = 0;
+    slot->linearVertAdvance = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  T42_GlyphSlot_Load( FT_GlyphSlot  glyph,
+                      FT_Size       size,
+                      FT_Int        glyph_index,
+                      FT_Int32      load_flags )
+  {
+    FT_Error         error;
+    T42_GlyphSlot    t42slot = (T42_GlyphSlot)glyph;
+    T42_Size         t42size = (T42_Size)size;
+    FT_Driver_Class  ttclazz = ((T42_Driver)glyph->face->driver)->ttclazz;
+
+
+    ft_glyphslot_clear( t42slot->ttslot );
+    error = ttclazz->load_glyph( t42slot->ttslot,
+                                 t42size->ttsize,
+                                 glyph_index,
+                                 load_flags | FT_LOAD_NO_BITMAP );
+
+    if ( !error )
+    {
+      glyph->metrics = t42slot->ttslot->metrics;
+
+      glyph->linearHoriAdvance = t42slot->ttslot->linearHoriAdvance;
+      glyph->linearVertAdvance = t42slot->ttslot->linearVertAdvance;
+
+      glyph->format  = t42slot->ttslot->format;
+      glyph->outline = t42slot->ttslot->outline;
+
+      glyph->bitmap      = t42slot->ttslot->bitmap;
+      glyph->bitmap_left = t42slot->ttslot->bitmap_left;
+      glyph->bitmap_top  = t42slot->ttslot->bitmap_top;
+
+      glyph->num_subglyphs = t42slot->ttslot->num_subglyphs;
+      glyph->subglyphs     = t42slot->ttslot->subglyphs;
+
+      glyph->control_data  = t42slot->ttslot->control_data;
+      glyph->control_len   = t42slot->ttslot->control_len;
+    }
+
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42objs.h
@@ -1,0 +1,126 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t42objs.h                                                              */
+/*                                                                         */
+/*    Type 42 objects manager (specification).                             */
+/*                                                                         */
+/*  Copyright 2002 by Roberto Alameda.                                     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T42OBJS_H__
+#define __T42OBJS_H__
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TYPE1_TABLES_H
+#include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_TYPE42_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DRIVER_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+#include FT_INTERNAL_POSTSCRIPT_HINTS_H
+
+
+FT_BEGIN_HEADER
+
+
+  /* Type42 size */
+  typedef struct  T42_SizeRec_
+  {
+    FT_SizeRec  root;
+    FT_Size     ttsize;
+
+  } T42_SizeRec, *T42_Size;
+
+
+  /* Type42 slot */
+  typedef struct  T42_GlyphSlotRec_
+  {
+    FT_GlyphSlotRec  root;
+    FT_GlyphSlot     ttslot;
+
+  } T42_GlyphSlotRec, *T42_GlyphSlot;
+
+
+  /* Type 42 driver */
+  typedef struct  T42_DriverRec_
+  {
+    FT_DriverRec     root;
+    FT_Driver_Class  ttclazz;
+    void*            extension_component;
+
+  } T42_DriverRec, *T42_Driver;
+
+
+  /* */
+
+
+  FT_LOCAL( FT_Error )
+  T42_Face_Init( FT_Stream      stream,
+                 T42_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params );
+
+
+  FT_LOCAL( void )
+  T42_Face_Done( T42_Face  face );
+
+
+  FT_LOCAL( FT_Error )
+  T42_Size_Init( T42_Size  size );
+
+
+  FT_LOCAL( FT_Error )
+  T42_Size_SetChars( T42_Size    size,
+                     FT_F26Dot6  char_width,
+                     FT_F26Dot6  char_height,
+                     FT_UInt     horz_resolution,
+                     FT_UInt     vert_resolution );
+
+  FT_LOCAL( FT_Error )
+  T42_Size_SetPixels( T42_Size  size,
+                      FT_UInt   pixel_width,
+                      FT_UInt   pixel_height );
+
+  FT_LOCAL( void )
+  T42_Size_Done( T42_Size  size );
+
+
+  FT_LOCAL( FT_Error )
+  T42_GlyphSlot_Init( T42_GlyphSlot  slot );
+
+
+  FT_LOCAL( FT_Error )
+  T42_GlyphSlot_Load( FT_GlyphSlot  glyph,
+                      FT_Size       size,
+                      FT_Int        glyph_index,
+                      FT_Int32      load_flags );
+
+  FT_LOCAL( void )
+  T42_GlyphSlot_Done( T42_GlyphSlot slot );
+
+
+  FT_LOCAL( FT_Error )
+  T42_Driver_Init( T42_Driver  driver );
+
+  FT_LOCAL( void )
+  T42_Driver_Done( T42_Driver  driver );
+
+ /* */
+
+FT_END_HEADER
+
+
+#endif /* __T42OBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42parse.c
@@ -1,0 +1,994 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t42parse.c                                                             */
+/*                                                                         */
+/*    Type 42 font parser (body).                                          */
+/*                                                                         */
+/*  Copyright 2002 by Roberto Alameda.                                     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include "t42parse.h"
+#include "t42error.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_LIST_H
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_t42
+
+
+  static void
+  t42_parse_font_name( T42_Face    face,
+                       T42_Loader  loader );
+                       
+  static void
+  t42_parse_font_bbox( T42_Face    face,
+                       T42_Loader  loader );
+                       
+  static void
+  t42_parse_font_matrix( T42_Face    face,
+                         T42_Loader  loader );
+  static void
+  t42_parse_encoding( T42_Face    face,
+                      T42_Loader  loader );
+                      
+  static void
+  t42_parse_charstrings( T42_Face    face,
+                         T42_Loader  loader );
+                         
+  static void
+  t42_parse_sfnts( T42_Face    face,
+                   T42_Loader  loader );
+
+
+  static const
+  T1_FieldRec  t42_keywords[] = {
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  T1_FontInfo
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FONT_INFO
+
+    T1_FIELD_STRING   ( "version",            version )
+    T1_FIELD_STRING   ( "Notice",             notice )
+    T1_FIELD_STRING   ( "FullName",           full_name )
+    T1_FIELD_STRING   ( "FamilyName",         family_name )
+    T1_FIELD_STRING   ( "Weight",             weight )
+    T1_FIELD_NUM      ( "ItalicAngle",        italic_angle )
+    T1_FIELD_TYPE_BOOL( "isFixedPitch",       is_fixed_pitch )
+    T1_FIELD_NUM      ( "UnderlinePosition",  underline_position )
+    T1_FIELD_NUM      ( "UnderlineThickness", underline_thickness )
+
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  T1_FontRec
+#undef  T1CODE
+#define T1CODE        T1_FIELD_LOCATION_FONT_DICT
+
+    T1_FIELD_NUM( "PaintType",   paint_type )
+    T1_FIELD_NUM( "FontType",    font_type )
+    T1_FIELD_NUM( "StrokeWidth", stroke_width )
+
+    T1_FIELD_CALLBACK( "FontName",    t42_parse_font_name )
+    T1_FIELD_CALLBACK( "FontBBox",    t42_parse_font_bbox )
+    T1_FIELD_CALLBACK( "FontMatrix",  t42_parse_font_matrix )
+    T1_FIELD_CALLBACK( "Encoding",    t42_parse_encoding )
+    T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings )
+    T1_FIELD_CALLBACK( "sfnts",       t42_parse_sfnts )
+
+    { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0 }
+  };
+
+
+#define T1_Add_Table( p, i, o, l )  (p)->funcs.add( (p), i, o, l )
+#define T1_Done_Table( p )          \
+          do                        \
+          {                         \
+            if ( (p)->funcs.done )  \
+              (p)->funcs.done( p ); \
+          } while ( 0 )
+#define T1_Release_Table( p )          \
+          do                           \
+          {                            \
+            if ( (p)->funcs.release )  \
+              (p)->funcs.release( p ); \
+          } while ( 0 )
+
+#define T1_Skip_Spaces( p )  (p)->root.funcs.skip_spaces( &(p)->root )
+#define T1_Skip_Alpha( p )   (p)->root.funcs.skip_alpha ( &(p)->root )
+
+#define T1_ToInt( p )       (p)->root.funcs.to_int( &(p)->root )
+#define T1_ToFixed( p, t )  (p)->root.funcs.to_fixed( &(p)->root, t )
+
+#define T1_ToCoordArray( p, m, c )                           \
+          (p)->root.funcs.to_coord_array( &(p)->root, m, c )
+#define T1_ToFixedArray( p, m, f, t )                           \
+          (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
+#define T1_ToToken( p, t )                          \
+          (p)->root.funcs.to_token( &(p)->root, t )
+#define T1_ToTokenArray( p, t, m, c )                           \
+          (p)->root.funcs.to_token_array( &(p)->root, t, m, c )
+
+#define T1_Load_Field( p, f, o, m, pf )                         \
+          (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
+#define T1_Load_Field_Table( p, f, o, m, pf )                         \
+          (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
+
+
+  /********************* Parsing Functions ******************/
+
+  FT_LOCAL_DEF( FT_Error )
+  t42_parser_init( T42_Parser     parser,
+                   FT_Stream      stream,
+                   FT_Memory      memory,
+                   PSAux_Service  psaux )
+  {
+    FT_Error  error = T42_Err_Ok;
+    FT_Long   size;
+
+
+    psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
+
+    parser->stream    = stream;
+    parser->base_len  = 0;
+    parser->base_dict = 0;
+    parser->in_memory = 0;
+
+    /*******************************************************************/
+    /*                                                                 */
+    /* Here a short summary of what is going on:                       */
+    /*                                                                 */
+    /*   When creating a new Type 42 parser, we try to locate and load */
+    /*   the base dictionary, loading the whole font into memory.      */
+    /*                                                                 */
+    /*   When `loading' the base dictionary, we only setup pointers in */
+    /*   the case of a memory-based stream.  Otherwise, we allocate    */
+    /*   and load the base dictionary in it.                           */
+    /*                                                                 */
+    /*   parser->in_memory is set if we have a memory stream.          */
+    /*                                                                 */
+
+    if ( FT_STREAM_SEEK( 0L ) )
+      goto Exit;
+
+    size = stream->size;
+
+    /* now, try to load `size' bytes of the `base' dictionary we */
+    /* found previously                                          */
+
+    /* if it is a memory-based resource, set up pointers */
+    if ( !stream->read )
+    {
+      parser->base_dict = (FT_Byte*)stream->base + stream->pos;
+      parser->base_len  = size;
+      parser->in_memory = 1;
+
+      /* check that the `size' field is valid */
+      if ( FT_STREAM_SKIP( size ) )
+        goto Exit;
+    }
+    else
+    {
+      /* read segment in memory */
+      if ( FT_ALLOC( parser->base_dict, size )       ||
+           FT_STREAM_READ( parser->base_dict, size ) )
+        goto Exit;
+
+      parser->base_len = size;
+    }
+
+    /* Now check font format; we must see `%!PS-TrueTypeFont' */
+    if (size <= 17                                    ||
+        ( ft_strncmp( (const char*)parser->base_dict,
+                      "%!PS-TrueTypeFont", 17) )      )
+      error = T42_Err_Unknown_File_Format;
+    else
+    {
+      parser->root.base   = parser->base_dict;
+      parser->root.cursor = parser->base_dict;
+      parser->root.limit  = parser->root.cursor + parser->base_len;
+    }
+
+  Exit:
+    if ( error && !parser->in_memory )
+      FT_FREE( parser->base_dict );
+
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  t42_parser_done( T42_Parser  parser )
+  {
+    FT_Memory  memory = parser->root.memory;
+
+
+    /* free the base dictionary only when we have a disk stream */
+    if ( !parser->in_memory )
+      FT_FREE( parser->base_dict );
+
+    parser->root.funcs.done( &parser->root );
+  }
+
+
+  static int
+  t42_is_alpha( FT_Byte  c )
+  {
+    /* Note: we must accept "+" as a valid character, as it is used in */
+    /*       embedded type1 fonts in PDF documents.                    */
+    /*                                                                 */
+    return ( ft_isalnum( c ) ||
+             c == '.'        ||
+             c == '_'        ||
+             c == '-'        ||
+             c == '+'        );
+  }
+
+
+  static int
+  t42_is_space( FT_Byte  c )
+  {
+    return ( c == ' ' || c == '\t' || c == '\r' || c == '\n' );
+  }
+
+
+  static void
+  t42_parse_font_name( T42_Face    face,
+                       T42_Loader  loader )
+  {
+    T42_Parser  parser = &loader->parser;
+    FT_Error    error;
+    FT_Memory   memory = parser->root.memory;
+    FT_Int      len;
+    FT_Byte*    cur;
+    FT_Byte*    cur2;
+    FT_Byte*    limit;
+
+
+    T1_Skip_Spaces( parser );
+
+    cur   = parser->root.cursor;
+    limit = parser->root.limit;
+
+    if ( cur >= limit - 1              ||
+         ( *cur != '/' && *cur != '(') )
+      return;
+
+    cur++;
+    cur2 = cur;
+    while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+      cur2++;
+
+    len = (FT_Int)( cur2 - cur );
+    if ( len > 0 )
+    {
+      if ( FT_ALLOC( face->type1.font_name, len + 1 ) )
+      {
+        parser->root.error = error;
+        return;
+      }
+
+      FT_MEM_COPY( face->type1.font_name, cur, len );
+      face->type1.font_name[len] = '\0';
+    }
+    parser->root.cursor = cur2;
+  }
+
+
+  static void
+  t42_parse_font_bbox( T42_Face   face,
+                       T42_Loader  loader )
+  {
+    T42_Parser  parser = &loader->parser;
+    FT_BBox*    bbox   = &face->type1.font_bbox;
+
+    bbox->xMin = T1_ToInt( parser );
+    bbox->yMin = T1_ToInt( parser );
+    bbox->xMax = T1_ToInt( parser );
+    bbox->yMax = T1_ToInt( parser );
+  }
+
+
+  static void
+  t42_parse_font_matrix( T42_Face    face,
+                         T42_Loader  loader )
+  {
+    T42_Parser  parser = &loader->parser;
+    FT_Matrix*  matrix = &face->type1.font_matrix;
+    FT_Vector*  offset = &face->type1.font_offset;
+    FT_Face     root   = (FT_Face)&face->root;
+    FT_Fixed    temp[6];
+    FT_Fixed    temp_scale;
+
+
+    (void)T1_ToFixedArray( parser, 6, temp, 3 );
+
+    temp_scale = ABS( temp[3] );
+
+    /* Set Units per EM based on FontMatrix values.  We set the value to */
+    /* 1000 / temp_scale, because temp_scale was already multiplied by   */
+    /* 1000 (in t1_tofixed, from psobjs.c).                              */
+
+    root->units_per_EM = (FT_UShort)( FT_DivFix( 1000 * 0x10000L,
+                                                 temp_scale ) >> 16 );
+
+    /* we need to scale the values by 1.0/temp_scale */
+    if ( temp_scale != 0x10000L ) {
+      temp[0] = FT_DivFix( temp[0], temp_scale );
+      temp[1] = FT_DivFix( temp[1], temp_scale );
+      temp[2] = FT_DivFix( temp[2], temp_scale );
+      temp[4] = FT_DivFix( temp[4], temp_scale );
+      temp[5] = FT_DivFix( temp[5], temp_scale );
+      temp[3] = 0x10000L;
+    }
+
+    matrix->xx = temp[0];
+    matrix->yx = temp[1];
+    matrix->xy = temp[2];
+    matrix->yy = temp[3];
+
+    /* note that the offsets must be expressed in integer font units */
+    offset->x  = temp[4] >> 16;
+    offset->y  = temp[5] >> 16;
+  }
+
+
+  static void
+  t42_parse_encoding( T42_Face    face,
+                      T42_Loader  loader )
+  {
+    T42_Parser     parser = &loader->parser;
+    FT_Byte*       cur    = parser->root.cursor;
+    FT_Byte*       limit  = parser->root.limit;
+
+    PSAux_Service  psaux  = (PSAux_Service)face->psaux;
+
+
+    /* skip whitespace */
+    while ( t42_is_space( *cur ) )
+    {
+      cur++;
+      if ( cur >= limit )
+      {
+        FT_ERROR(( "t42_parse_encoding: out of bounds!\n" ));
+        parser->root.error = T42_Err_Invalid_File_Format;
+        return;
+      }
+    }
+
+    /* if we have a number, then the encoding is an array, */
+    /* and we must load it now                             */
+    if ( (FT_Byte)( *cur - '0' ) < 10 )
+    {
+      T1_Encoding  encode     = &face->type1.encoding;
+      FT_Int       count, n;
+      PS_Table     char_table = &loader->encoding_table;
+      FT_Memory    memory     = parser->root.memory;
+      FT_Error     error;
+
+
+      /* read the number of entries in the encoding, should be 256 */
+      count = T1_ToInt( parser );
+      if ( parser->root.error )
+        return;
+
+      /* we use a T1_Table to store our charnames */
+      loader->num_chars = encode->num_chars = count;
+      if ( FT_NEW_ARRAY( encode->char_index, count ) ||
+           FT_NEW_ARRAY( encode->char_name,  count ) ||
+           FT_SET_ERROR( psaux->ps_table_funcs->init(
+                           char_table, count, memory ) ) )
+      {
+        parser->root.error = error;
+        return;
+      }
+
+      /* We need to `zero' out encoding_table.elements */
+      for ( n = 0; n < count; n++ )
+      {
+        char*  notdef = (char *)".notdef";
+
+
+        T1_Add_Table( char_table, n, notdef, 8 );
+      }
+
+      /* Now, we will need to read a record of the form         */
+      /* ... charcode /charname ... for each entry in our table */
+      /*                                                        */
+      /* We simply look for a number followed by an immediate   */
+      /* name.  Note that this ignores correctly the sequence   */
+      /* that is often seen in type1 fonts:                     */
+      /*                                                        */
+      /*   0 1 255 { 1 index exch /.notdef put } for dup        */
+      /*                                                        */
+      /* used to clean the encoding array before anything else. */
+      /*                                                        */
+      /* We stop when we encounter a `def'.                     */
+
+      cur   = parser->root.cursor;
+      limit = parser->root.limit;
+      n     = 0;
+
+      for ( ; cur < limit; )
+      {
+        FT_Byte  c;
+
+
+        c = *cur;
+
+        /* we stop when we encounter a `def' */
+        if ( c == 'd' && cur + 3 < limit )
+        {
+          if ( cur[1] == 'e'       &&
+               cur[2] == 'f'       &&
+               t42_is_space( cur[-1] ) &&
+               t42_is_space( cur[3] )  )
+          {
+            FT_TRACE6(( "encoding end\n" ));
+            break;
+          }
+        }
+
+        /* otherwise, we must find a number before anything else */
+        if ( (FT_Byte)( c - '0' ) < 10 )
+        {
+          FT_Int  charcode;
+
+
+          parser->root.cursor = cur;
+          charcode = T1_ToInt( parser );
+          cur      = parser->root.cursor;
+
+          /* skip whitespace */
+          while ( cur < limit && t42_is_space( *cur ) )
+            cur++;
+
+          if ( cur < limit && *cur == '/' )
+          {
+            /* bingo, we have an immediate name -- it must be a */
+            /* character name                                   */
+            FT_Byte*  cur2 = cur + 1;
+            FT_Int    len;
+
+
+            while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+              cur2++;
+
+            len = (FT_Int)( cur2 - cur - 1 );
+
+            parser->root.error = T1_Add_Table( char_table, charcode,
+                                               cur + 1, len + 1 );
+            char_table->elements[charcode][len] = '\0';
+            if ( parser->root.error )
+              return;
+
+            cur = cur2;
+          }
+        }
+        else
+          cur++;
+      }
+
+      face->type1.encoding_type  = T1_ENCODING_TYPE_ARRAY;
+      parser->root.cursor        = cur;
+    }
+    /* Otherwise, we should have either `StandardEncoding', */
+    /* `ExpertEncoding', or `ISOLatin1Encoding'             */
+    else
+    {
+      if ( cur + 17 < limit                                            &&
+           ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
+        face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
+
+      else if ( cur + 15 < limit                                          &&
+                ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
+        face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
+
+      else if ( cur + 18 < limit                                             &&
+                ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
+        face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
+
+      else {
+        FT_ERROR(( "t42_parse_encoding: invalid token!\n" ));
+        parser->root.error = T42_Err_Invalid_File_Format;
+      }
+    }
+  }
+
+
+  static FT_UInt
+  t42_hexval( FT_Byte  v )
+  {
+    FT_UInt  d;
+    
+    d = (FT_UInt)( v - 'A' );
+    if ( d < 6 )
+    {
+      d += 10;
+      goto Exit;
+    }
+      
+    d = (FT_UInt)( v - 'a' );
+    if ( d < 6 )
+    {
+      d += 10;
+      goto Exit;
+    }
+      
+    d = (FT_UInt)( v - '0' );
+    if ( d < 10 )
+      goto Exit;
+      
+    d = 0;
+ 
+  Exit:         
+    return d;
+  }
+
+
+  static void
+  t42_parse_sfnts( T42_Face    face,
+                   T42_Loader  loader )
+  {
+    T42_Parser  parser = &loader->parser;
+    FT_Memory   memory = parser->root.memory;
+    FT_Byte*    cur    = parser->root.cursor;
+    FT_Byte*    limit  = parser->root.limit;
+    FT_Error    error;
+    FT_Int      num_tables = 0, status;
+    FT_ULong    count, ttf_size = 0, string_size = 0;
+    FT_Bool     in_string  = 0;
+    FT_Byte     v = 0;
+
+
+    /* The format is `/sfnts [ <...> <...> ... ] def' */
+
+    while ( t42_is_space( *cur ) )
+      cur++;
+
+    if (*cur++ == '[')
+    {
+      status = 0;
+      count = 0;
+    }
+    else
+    {
+      FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector!\n" ));
+      error = T42_Err_Invalid_File_Format;
+      goto Fail;
+    }
+
+    while ( cur < limit - 2 )
+    {
+      while ( t42_is_space( *cur ) )
+        cur++;
+
+      switch ( *cur )
+      {
+      case ']':
+        parser->root.cursor = cur++;
+        return;
+
+      case '<':
+        in_string   = 1;
+        string_size = 0;
+        cur++;
+        continue;
+
+      case '>':
+        if ( !in_string )
+        {
+          FT_ERROR(( "t42_parse_sfnts: found unpaired `>'!\n" ));
+          error = T42_Err_Invalid_File_Format;
+          goto Fail;
+        }
+
+        /* A string can have, as a last byte,         */
+        /* a zero byte for padding.  If so, ignore it */
+        if ( ( v == 0 ) && ( string_size % 2 == 1 ) )
+          count--;
+        in_string = 0;
+        cur++;
+        continue;
+
+      case '%':
+        if ( !in_string )
+        {
+          /* Comment found; skip till end of line */
+          while ( *cur != '\n' )
+            cur++;
+          continue;
+        }
+        else
+        {
+          FT_ERROR(( "t42_parse_sfnts: found `%' in string!\n" ));
+          error = T42_Err_Invalid_File_Format;
+          goto Fail;
+        }
+
+      default:
+        if ( !ft_xdigit( *cur ) || !ft_xdigit( *(cur + 1) ) )
+        {
+          FT_ERROR(( "t42_parse_sfnts: found non-hex characters in string" ));
+          error = T42_Err_Invalid_File_Format;
+          goto Fail;
+        }
+
+        v = (FT_Byte)( 16 * t42_hexval( cur[0] ) + t42_hexval( cur[1] ) );
+        cur += 2;
+        string_size++;
+      }
+
+      switch ( status )
+      {
+      case 0: /* The '[' was read, so load offset table, 12 bytes */
+        if ( count < 12 )
+        {
+          face->ttf_data[count++] = v;
+          continue;
+        }
+        else
+        {
+          num_tables = 16 * face->ttf_data[4] + face->ttf_data[5];
+          status     = 1;
+          ttf_size   = 12 + 16 * num_tables;
+
+          if ( FT_REALLOC( face->ttf_data, 12, ttf_size ) )
+            goto Fail;
+        }
+        /* No break, fall-through */
+
+      case 1: /* The offset table is read; read now the table directory */
+        if ( count < ttf_size )
+        {
+          face->ttf_data[count++] = v;
+          continue;
+        }
+        else
+        {
+          int      i;
+          FT_ULong len;
+
+
+          for ( i = 0; i < num_tables; i++ )
+          {
+            FT_Byte*  p = face->ttf_data + 12 + 16*i + 12;
+            
+            len = FT_PEEK_ULONG( p );
+
+            /* Pad to a 4-byte boundary length */
+            ttf_size += ( len + 3 ) & ~3;
+          }
+
+          status         = 2;
+          face->ttf_size = ttf_size;
+
+          if ( FT_REALLOC( face->ttf_data, 12 + 16 * num_tables,
+                           ttf_size + 1 ) )
+            goto Fail;
+        }
+        /* No break, fall-through */
+
+      case 2: /* We are reading normal tables; just swallow them */
+        face->ttf_data[count++] = v;
+
+      }
+    }
+
+    /* If control reaches this point, the format was not valid */
+    error = T42_Err_Invalid_File_Format;
+
+  Fail:
+    parser->root.error = error;
+  }
+
+
+  static void
+  t42_parse_charstrings( T42_Face    face,
+                         T42_Loader  loader )
+  {
+    T42_Parser     parser     = &loader->parser;
+    PS_Table       code_table = &loader->charstrings;
+    PS_Table       name_table = &loader->glyph_names;
+    FT_Memory      memory     = parser->root.memory;
+    FT_Error       error;
+
+    PSAux_Service  psaux      = (PSAux_Service)face->psaux;
+
+    FT_Byte*       cur;
+    FT_Byte*       limit      = parser->root.limit;
+    FT_Int         n;
+
+
+    loader->num_glyphs = T1_ToInt( parser );
+    if ( parser->root.error )
+      return;
+
+    /* initialize tables */
+
+    error = psaux->ps_table_funcs->init( code_table,
+                                         loader->num_glyphs,
+                                         memory );
+    if ( error )
+      goto Fail;
+
+    error = psaux->ps_table_funcs->init( name_table,
+                                         loader->num_glyphs,
+                                         memory );
+    if ( error )
+      goto Fail;
+
+    n = 0;
+
+    for (;;)
+    {
+      /* the format is simple:                    */
+      /*   `/glyphname' + index + def             */
+      /*                                          */
+      /* note that we stop when we find an `end'  */
+      /*                                          */
+      T1_Skip_Spaces( parser );
+
+      cur = parser->root.cursor;
+      if ( cur >= limit )
+        break;
+
+      /* we stop when we find an `end' keyword */
+      if ( *cur   == 'e'   &&
+           cur + 3 < limit &&
+           cur[1] == 'n'   &&
+           cur[2] == 'd'   )
+        break;
+
+      if ( *cur != '/' )
+        T1_Skip_Alpha( parser );
+      else
+      {
+        FT_Byte*  cur2 = cur + 1;
+        FT_Int    len;
+
+
+        while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+          cur2++;
+        len = (FT_Int)( cur2 - cur - 1 );
+
+        error = T1_Add_Table( name_table, n, cur + 1, len + 1 );
+        if ( error )
+          goto Fail;
+
+        /* add a trailing zero to the name table */
+        name_table->elements[n][len] = '\0';
+
+        parser->root.cursor = cur2;
+        T1_Skip_Spaces( parser );
+
+        cur2 = cur = parser->root.cursor;
+        if ( cur >= limit )
+          break;
+
+        while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+          cur2++;
+        len = (FT_Int)( cur2 - cur );
+
+        error = T1_Add_Table( code_table, n, cur, len + 1 );
+        if ( error )
+          goto Fail;
+
+        code_table->elements[n][len] = '\0';
+
+        n++;
+        if ( n >= loader->num_glyphs )
+          break;
+      }
+    }
+
+    /* Index 0 must be a .notdef element */
+    if ( ft_strcmp( (char *)name_table->elements[0], ".notdef" ) )
+    {
+      FT_ERROR(( "t42_parse_charstrings: Index 0 is not `.notdef'!\n" ));
+      error = T42_Err_Invalid_File_Format;
+      goto Fail;
+    }
+
+    loader->num_glyphs = n;
+    return;
+
+  Fail:
+    parser->root.error = error;
+  }
+
+
+  static FT_Error
+  t42_load_keyword( T42_Face    face,
+                    T42_Loader  loader,
+                    T1_Field    field )
+  {
+    FT_Error  error;
+    void*     dummy_object;
+    void**    objects;
+    FT_UInt   max_objects = 0;
+
+
+    /* if the keyword has a dedicated callback, call it */
+    if ( field->type == T1_FIELD_TYPE_CALLBACK ) {
+      field->reader( (FT_Face)face, loader );
+      error = loader->parser.root.error;
+      goto Exit;
+    }
+
+    /* now, the keyword is either a simple field, or a table of fields; */
+    /* we are now going to take care of it                              */
+    switch ( field->location )
+    {
+    case T1_FIELD_LOCATION_FONT_INFO:
+      dummy_object = &face->type1.font_info;
+      objects      = &dummy_object;
+      break;
+
+    default:
+      dummy_object = &face->type1;
+      objects      = &dummy_object;
+    }
+
+    if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
+         field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
+      error = T1_Load_Field_Table( &loader->parser, field,
+                                   objects, max_objects, 0 );
+    else
+      error = T1_Load_Field( &loader->parser, field,
+                             objects, max_objects, 0 );
+
+   Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  t42_parse_dict( T42_Face    face,
+                  T42_Loader  loader,
+                  FT_Byte*    base,
+                  FT_Long     size )
+  {
+    T42_Parser  parser = &loader->parser;
+    FT_Byte*    cur    = base;
+    FT_Byte*    limit  = cur + size;
+    FT_UInt     n_keywords = sizeof ( t42_keywords ) / 
+                             sizeof ( t42_keywords[0] );
+
+
+    parser->root.cursor = base;
+    parser->root.limit  = base + size;
+    parser->root.error  = 0;
+
+    for ( ; cur < limit; cur++ )
+    {
+      /* look for `FontDirectory', which causes problems on some fonts */
+      if ( *cur == 'F' && cur + 25 < limit                    &&
+           ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
+      {
+        FT_Byte*  cur2;
+
+
+        /* skip the `FontDirectory' keyword */
+        cur += 13;
+        cur2 = cur;
+
+        /* lookup the `known' keyword */
+        while ( cur < limit && *cur != 'k'           &&
+                ft_strncmp( (char*)cur, "known", 5 ) )
+          cur++;
+
+        if ( cur < limit )
+        {
+          T1_TokenRec  token;
+
+
+          /* skip the `known' keyword and the token following it */
+          cur += 5;
+          loader->parser.root.cursor = cur;
+          T1_ToToken( &loader->parser, &token );
+
+          /* if the last token was an array, skip it! */
+          if ( token.type == T1_TOKEN_TYPE_ARRAY )
+            cur2 = parser->root.cursor;
+        }
+        cur = cur2;
+      }
+      /* look for immediates */
+      else if ( *cur == '/' && cur + 2 < limit )
+      {
+        FT_Byte*  cur2;
+        FT_UInt    i, len;
+
+
+        cur++;
+        cur2 = cur;
+        while ( cur2 < limit && t42_is_alpha( *cur2 ) )
+          cur2++;
+
+        len  = (FT_UInt)( cur2 - cur );
+        if ( len > 0 && len < 22 ) /* XXX What shall it this 22? */
+        {
+          /* now, compare the immediate name to the keyword table */
+
+          /* Loop through all known keywords */
+          for ( i = 0; i < n_keywords; i++ )
+          {
+            T1_Field  keyword = (T1_Field)&t42_keywords[i];
+            FT_Byte   *name   = (FT_Byte*)keyword->ident;
+
+
+            if ( !name )
+              continue;
+
+            if ( ( len == ft_strlen( (const char *)name ) ) &&
+                 ( ft_memcmp( cur, name, len ) == 0 )       )
+            {
+              /* we found it -- run the parsing callback! */
+              parser->root.cursor = cur2;
+              T1_Skip_Spaces( parser );
+              parser->root.error = t42_load_keyword(face,
+                                                    loader,
+                                                    keyword );
+              if ( parser->root.error )
+                return parser->root.error;
+              cur = parser->root.cursor;
+              break;
+            }
+          }
+        }
+      }
+    }
+    return parser->root.error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  t42_loader_init( T42_Loader  loader,
+                   T42_Face    face )
+  {
+    FT_UNUSED( face );
+
+    FT_MEM_ZERO( loader, sizeof ( *loader ) );
+    loader->num_glyphs = 0;
+    loader->num_chars  = 0;
+
+    /* initialize the tables -- simply set their `init' field to 0 */
+    loader->encoding_table.init = 0;
+    loader->charstrings.init    = 0;
+    loader->glyph_names.init    = 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  t42_loader_done( T42_Loader  loader )
+  {
+    T42_Parser  parser = &loader->parser;
+
+
+    /* finalize tables */
+    T1_Release_Table( &loader->encoding_table );
+    T1_Release_Table( &loader->charstrings );
+    T1_Release_Table( &loader->glyph_names );
+
+    /* finalize parser */
+    t42_parser_done( parser );
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/t42parse.h
@@ -1,0 +1,89 @@
+/***************************************************************************/
+/*                                                                         */
+/*  t42parse.h                                                             */
+/*                                                                         */
+/*    Type 42 font parser (specification).                                 */
+/*                                                                         */
+/*  Copyright 2002 by Roberto Alameda.                                     */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __T42PARSE_H__
+#define __T42PARSE_H__
+
+
+#include "t42objs.h"
+#include FT_INTERNAL_POSTSCRIPT_AUX_H
+
+
+FT_BEGIN_HEADER
+
+  typedef struct  T42_ParserRec_
+  {
+    PS_ParserRec  root;
+    FT_Stream     stream;
+
+    FT_Byte*      base_dict;
+    FT_Int        base_len;
+
+    FT_Byte       in_memory;
+
+  } T42_ParserRec, *T42_Parser;
+
+
+  typedef struct  T42_Loader_
+  {
+    T42_ParserRec  parser;          /* parser used to read the stream */
+
+    FT_Int         num_chars;       /* number of characters in encoding */
+    PS_TableRec    encoding_table;  /* PS_Table used to store the       */
+                                    /* encoding character names         */
+
+    FT_Int         num_glyphs;
+    PS_TableRec    glyph_names;
+    PS_TableRec    charstrings;
+
+  } T42_LoaderRec, *T42_Loader;
+
+
+  FT_LOCAL( FT_Error )
+  t42_parser_init( T42_Parser     parser,
+                   FT_Stream      stream,
+                   FT_Memory      memory,
+                   PSAux_Service  psaux );
+
+  FT_LOCAL( void )
+  t42_parser_done( T42_Parser  parser );
+
+
+  FT_LOCAL( FT_Error )
+  t42_parse_dict( T42_Face    face,
+                  T42_Loader  loader,
+                  FT_Byte*    base,
+                  FT_Long     size );
+
+
+  FT_LOCAL( void )
+  t42_loader_init( T42_Loader  loader,
+                   T42_Face    face );
+
+  FT_LOCAL( void )
+  t42_loader_done( T42_Loader  loader );
+
+
+ /* */
+
+FT_END_HEADER
+
+
+#endif /* __T42PARSE_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/test_bbox.c
@@ -1,0 +1,160 @@
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_BBOX_H
+
+
+#include <time.h>    /* for clock() */
+
+/* SunOS 4.1.* does not define CLOCKS_PER_SEC, so include <sys/param.h> */
+/* to get the HZ macro which is the equivalent.                         */
+#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
+#include <sys/param.h>
+#define CLOCKS_PER_SEC HZ
+#endif
+
+  static long
+  get_time( void )
+  {
+    return clock() * 10000L / CLOCKS_PER_SEC;
+  }
+
+
+
+
+  /* test bbox computations */
+
+#define  XSCALE    65536
+#define  XX(x)     ((FT_Pos)(x*XSCALE))
+#define  XVEC(x,y)  { XX(x), XX(y) }
+#define  XVAL(x)   ((x)/(1.0*XSCALE))
+
+  /* dummy outline #1 */
+  static FT_Vector  dummy_vec_1[4] =
+  {
+#if 1
+    XVEC( 408.9111, 535.3164 ),
+    XVEC( 455.8887, 634.396  ),
+    XVEC( -37.8765, 786.2207 ),
+    XVEC( 164.6074, 535.3164 )
+#else
+    { (FT_Int32)0x0198E93DL , (FT_Int32)0x021750FFL },  /* 408.9111, 535.3164 */
+    { (FT_Int32)0x01C7E312L , (FT_Int32)0x027A6560L },  /* 455.8887, 634.3960 */
+    { (FT_Int32)0xFFDA1F9EL , (FT_Int32)0x0312387FL },  /* -37.8765, 786.2207 */
+    { (FT_Int32)0x00A49B7EL , (FT_Int32)0x021750FFL }   /* 164.6074, 535.3164 */
+#endif
+   };
+
+  static char  dummy_tag_1[4] =
+  {
+    FT_CURVE_TAG_ON,
+    FT_CURVE_TAG_CUBIC,
+    FT_CURVE_TAG_CUBIC,
+    FT_CURVE_TAG_ON
+  };
+
+  static short  dummy_contour_1[1] =
+  {
+    3
+  };
+
+  static FT_Outline  dummy_outline_1 =
+  {
+    1,
+    4,
+    dummy_vec_1,
+    dummy_tag_1,
+    dummy_contour_1,
+    0
+  };
+
+
+  /* dummy outline #2 */
+  static FT_Vector  dummy_vec_2[4] =
+  {
+    XVEC( 100.0, 100.0 ),
+    XVEC( 100.0, 200.0 ),
+    XVEC( 200.0, 200.0 ),
+    XVEC( 200.0, 133.0 )
+  };
+
+  static FT_Outline  dummy_outline_2 =
+  {
+    1,
+    4,
+    dummy_vec_2,
+    dummy_tag_1,
+    dummy_contour_1,
+    0
+  };
+
+
+  static void
+  dump_outline( FT_Outline*  outline )
+  {
+    FT_BBox  bbox;
+
+    /* compute and display cbox */
+    FT_Outline_Get_CBox( outline, &bbox );
+    printf( "cbox = [%.2f %.2f %.2f %.2f]\n",
+             XVAL( bbox.xMin ),
+             XVAL( bbox.yMin ),
+             XVAL( bbox.xMax ),
+             XVAL( bbox.yMax ) );
+
+    /* compute and display bbox */
+    FT_Outline_Get_BBox( outline, &bbox );
+    printf( "bbox = [%.2f %.2f %.2f %.2f]\n",
+             XVAL( bbox.xMin ),
+             XVAL( bbox.yMin ),
+             XVAL( bbox.xMax ),
+             XVAL( bbox.yMax ) );
+  }
+
+
+
+  static void
+  profile_outline( FT_Outline*   outline,
+                   long          repeat )
+  {
+    FT_BBox  bbox;
+    long     count;
+    long     time0;
+
+    time0 = get_time();
+    for ( count = repeat; count > 0; count-- )
+      FT_Outline_Get_CBox( outline, &bbox );
+
+    time0 = get_time() - time0;
+    printf( "time = %5.2f cbox = [%.2f %.2f %.2f %.2f]\n",
+             ((double)time0/10000.0),
+             XVAL( bbox.xMin ),
+             XVAL( bbox.yMin ),
+             XVAL( bbox.xMax ),
+             XVAL( bbox.yMax ) );
+
+
+    time0 = get_time();
+    for ( count = repeat; count > 0; count-- )
+      FT_Outline_Get_BBox( outline, &bbox );
+
+    time0 = get_time() - time0;
+    printf( "time = %5.2f bbox = [%.2f %.2f %.2f %.2f]\n",
+             ((double)time0/10000.0),
+             XVAL( bbox.xMin ),
+             XVAL( bbox.yMin ),
+             XVAL( bbox.xMax ),
+             XVAL( bbox.yMax ) );
+  }
+
+#define REPEAT  100000L
+
+  int  main( int  argc, char**  argv )
+  {
+    printf( "outline #1\n" );
+    profile_outline( &dummy_outline_1, REPEAT );
+
+    printf( "outline #2\n" );
+    profile_outline( &dummy_outline_2, REPEAT );
+    return 0;
+  }
+
--- /dev/null
+++ b/libfreetype/test_trig.c
@@ -1,0 +1,236 @@
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_TRIGONOMETRY_H
+
+#include <math.h>
+#include <stdio.h>
+
+#define  PI   3.14159265358979323846
+#define  SPI  (PI/FT_ANGLE_PI)
+
+/* the precision in 16.16 fixed float points of the checks. Expect */
+/* between 2 and 5 noise LSB bits during operations, due to        */
+/* rounding errors..                                               */
+#define  THRESHOLD  64
+
+  static  error = 0;
+
+  static void
+  test_cos( void )
+  {
+    FT_Fixed  f1, f2;
+    double    d1, d2;
+    int       i;
+
+    for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+    {
+      f1 = FT_Cos(i);
+      d1 = f1/65536.0;
+      d2 = cos( i*SPI );
+      f2 = (FT_Fixed)(d2*65536.0);
+
+      if ( abs( f2-f1 ) > THRESHOLD )
+      {
+        error = 1;
+        printf( "FT_Cos[%3d] = %.7f  cos[%3d] = %.7f\n",
+                (i >> 16), f1/65536.0, (i >> 16), d2 );
+      }
+    }
+  }
+
+
+
+  static void
+  test_sin( void )
+  {
+    FT_Fixed  f1, f2;
+    double    d1, d2;
+    int       i;
+
+    for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+    {
+      f1 = FT_Sin(i);
+      d1 = f1/65536.0;
+      d2 = sin( i*SPI );
+      f2 = (FT_Fixed)(d2*65536.0);
+
+      if ( abs( f2-f1 ) > THRESHOLD )
+      {
+        error = 1;
+        printf( "FT_Sin[%3d] = %.7f  sin[%3d] = %.7f\n",
+                (i >> 16), f1/65536.0, (i >> 16), d2 );
+      }
+    }
+  }
+
+
+  static void
+  test_tan( void )
+  {
+    FT_Fixed  f1, f2;
+    double    d1, d2;
+    int       i;
+
+    for ( i = 0; i < FT_ANGLE_PI2-0x2000000; i += 0x10000 )
+    {
+      f1 = FT_Tan(i);
+      d1 = f1/65536.0;
+      d2 = tan( i*SPI );
+      f2 = (FT_Fixed)(d2*65536.0);
+
+      if ( abs( f2-f1 ) > THRESHOLD )
+      {
+        error = 1;
+        printf( "FT_Tan[%3d] = %.7f  tan[%3d] = %.7f\n",
+                (i >> 16), f1/65536.0, (i >> 16), d2 );
+      }
+    }
+  }
+
+
+  static void
+  test_atan2( void )
+  {
+    FT_Fixed  c2, s2;
+    double    l, a, c1, s1;
+    int       i, j;
+
+    for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+    {
+      l  = 5.0;
+      a  = i*SPI;
+
+      c1 = l * cos(a);
+      s1 = l * sin(a);
+
+      c2 = (FT_Fixed)(c1*65536.0);
+      s2 = (FT_Fixed)(s1*65536.0);
+
+      j  = FT_Atan2( c2, s2 );
+      if ( j < 0 )
+        j += FT_ANGLE_2PI;
+
+      if ( abs( i - j ) > 1 )
+      {
+        printf( "FT_Atan2( %.7f, %.7f ) = %.5f, atan = %.5f\n",
+                c2/65536.0, s2/65536.0, j/65536.0, i/65536.0 );
+      }
+    }
+  }
+
+  static void
+  test_unit( void )
+  {
+    FT_Vector  v;
+    double     a, c1, s1;
+    FT_Fixed   c2, s2;
+    int        i;
+
+    for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+    {
+      FT_Vector_Unit( &v, i );
+      a  = ( i*SPI );
+      c1 = cos(a);
+      s1 = sin(a);
+      c2 = (FT_Fixed)(c1*65536.0);
+      s2 = (FT_Fixed)(s1*65536.0);
+
+      if ( abs( v.x-c2 ) > THRESHOLD ||
+           abs( v.y-s2 ) > THRESHOLD )
+      {
+        error = 1;
+        printf( "FT_Vector_Unit[%3d] = ( %.7f, %.7f )  vec = ( %.7f, %.7f )\n",
+                (i >> 16),
+                v.x/65536.0, v.y/65536.0,
+                c1, s1 );
+      }
+    }
+  }
+
+
+  static void
+  test_length( void )
+  {
+    FT_Vector  v;
+    FT_Fixed   l, l2;
+    int        i;
+
+    for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+    {
+      l   = (FT_Fixed)(500.0*65536.0);
+      v.x = (FT_Fixed)( l * cos( i*SPI ) );
+      v.y = (FT_Fixed)( l * sin( i*SPI ) );
+      l2  = FT_Vector_Length( &v );
+
+      if ( abs( l2-l ) > THRESHOLD )
+      {
+        error = 1;
+        printf( "FT_Length( %.7f, %.7f ) = %.5f, length = %.5f\n",
+                v.x/65536.0, v.y/65536.0, l2/65536.0, l/65536.0 );
+      }
+    }
+  }
+
+
+  static void
+  test_rotate( void )
+  {
+    FT_Fixed  c2, s2, c4, s4;
+    FT_Vector v;
+    double    l, ra, a, c1, s1, cra, sra, c3, s3;
+    int       i, j, rotate;
+
+    for ( rotate = 0; rotate < FT_ANGLE_2PI; rotate += 0x10000 )
+    {
+      ra  = rotate*SPI;
+      cra = cos( ra );
+      sra = sin( ra );
+
+      for ( i = 0; i < FT_ANGLE_2PI; i += 0x10000 )
+      {
+        l  = 500.0;
+        a  = i*SPI;
+
+        c1 = l * cos(a);
+        s1 = l * sin(a);
+
+        v.x = c2 = (FT_Fixed)(c1*65536.0);
+        v.y = s2 = (FT_Fixed)(s1*65536.0);
+
+        FT_Vector_Rotate( &v, rotate );
+
+        c3 = c1 * cra - s1 * sra;
+        s3 = c1 * sra + s1 * cra;
+
+        c4 = (FT_Fixed)(c3*65536.0);
+        s4 = (FT_Fixed)(s3*65536.0);
+
+        if ( abs( c4 - v.x ) > THRESHOLD ||
+             abs( s4 - v.y ) > THRESHOLD )
+        {
+          error = 1;
+          printf( "FT_Rotate( (%.7f,%.7f), %.5f ) = ( %.7f, %.7f ), rot = ( %.7f, %.7f )\n",
+                  c1, s1, ra,
+                  c2/65536.0, s2/65536.0,
+                  c4/65536.0, s4/65536.0 );
+        }
+      }
+    }
+  }
+
+
+  int main( void )
+  {
+    test_cos();
+    test_sin();
+    test_tan();
+    test_atan2();
+    test_unit();
+    test_length();
+    test_rotate();
+
+    if (!error)
+      printf( "trigonometry test ok !\n" );
+
+    return !error;
+  }
--- /dev/null
+++ b/libfreetype/truetype.c
@@ -1,0 +1,32 @@
+/***************************************************************************/
+/*                                                                         */
+/*  truetype.c                                                             */
+/*                                                                         */
+/*    FreeType TrueType driver component (body only).                      */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "ttdriver.c"   /* driver interface */
+#include "ttpload.c"    /* tables loader    */
+#include "ttgload.c"    /* glyph loader     */
+#include "ttobjs.c"     /* object manager   */
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.c"
+#endif
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap.c
@@ -1,0 +1,1110 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttcmap.c                                                               */
+/*                                                                         */
+/*    TrueType character mapping table (cmap) support (body).              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include "ttload.h"
+#include "ttcmap.h"
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttcmap
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index0( TT_CMapTable  charmap,
+                  FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next0( TT_CMapTable  charmap,
+                 FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index2( TT_CMapTable  charmap,
+                  FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next2( TT_CMapTable  charmap,
+                 FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index4( TT_CMapTable  charmap,
+                  FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next4( TT_CMapTable  charmap,
+                 FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index6( TT_CMapTable  charmap,
+                  FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next6( TT_CMapTable  charmap,
+                 FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index8_12( TT_CMapTable  charmap,
+                     FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next8_12( TT_CMapTable  charmap,
+                    FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index10( TT_CMapTable  charmap,
+                   FT_ULong      char_code );
+
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next10( TT_CMapTable  charmap,
+                  FT_ULong      char_code );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_charmap                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads a given TrueType character map into memory.                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the parent face object.                      */
+  /*                                                                       */
+  /*    stream :: A handle to the current stream object.                   */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    table  :: A pointer to a cmap object.                              */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The function assumes that the stream is already in use (i.e.,      */
+  /*    opened).  In case of error, all partially allocated tables are     */
+  /*    released.                                                          */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_charmap( TT_Face       face,
+                        TT_CMapTable  cmap,
+                        FT_Stream     stream )
+  {
+    FT_Error     error;
+    FT_Memory    memory;
+    FT_UShort    num_SH, num_Seg, i;
+    FT_ULong     j, n;
+
+    FT_UShort    u, l;
+
+    TT_CMap0     cmap0;
+    TT_CMap2     cmap2;
+    TT_CMap4     cmap4;
+    TT_CMap6     cmap6;
+    TT_CMap8_12  cmap8_12;
+    TT_CMap10    cmap10;
+
+    TT_CMap2SubHeader  cmap2sub;
+    TT_CMap4Segment    segments;
+    TT_CMapGroup       groups;
+
+
+    if ( cmap->loaded )
+      return SFNT_Err_Ok;
+
+    memory = stream->memory;
+
+    if ( FT_STREAM_SEEK( cmap->offset ) )
+      return error;
+
+    switch ( cmap->format )
+    {
+    case 0:
+      cmap0 = &cmap->c.cmap0;
+
+      if ( FT_READ_USHORT( cmap0->language )           ||
+           FT_ALLOC( cmap0->glyphIdArray, 256L )       ||
+           FT_STREAM_READ( cmap0->glyphIdArray, 256L ) )
+        goto Fail;
+
+      cmap->get_index     = code_to_index0;
+      cmap->get_next_char = code_to_next0;
+      break;
+
+    case 2:
+      num_SH = 0;
+      cmap2  = &cmap->c.cmap2;
+
+      /* allocate subheader keys */
+
+      if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) ||
+           FT_FRAME_ENTER( 2L + 512L )               )
+        goto Fail;
+
+      cmap2->language = FT_GET_USHORT();
+
+      for ( i = 0; i < 256; i++ )
+      {
+        u = (FT_UShort)( FT_GET_USHORT() / 8 );
+        cmap2->subHeaderKeys[i] = u;
+
+        if ( num_SH < u )
+          num_SH = u;
+      }
+
+      FT_FRAME_EXIT();
+
+      /* load subheaders */
+
+      cmap2->numGlyphId = l = (FT_UShort)(
+        ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 );
+
+      if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) ||
+           FT_FRAME_ENTER( ( num_SH + 1 ) * 8L )         )
+      {
+        FT_FREE( cmap2->subHeaderKeys );
+        goto Fail;
+      }
+
+      cmap2sub = cmap2->subHeaders;
+
+      for ( i = 0; i <= num_SH; i++ )
+      {
+        cmap2sub->firstCode     = FT_GET_USHORT();
+        cmap2sub->entryCount    = FT_GET_USHORT();
+        cmap2sub->idDelta       = FT_GET_SHORT();
+        /* we apply the location offset immediately */
+        cmap2sub->idRangeOffset = (FT_UShort)(
+          FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 );
+
+        cmap2sub++;
+      }
+
+      FT_FRAME_EXIT();
+
+      /* load glyph IDs */
+
+      if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) ||
+           FT_FRAME_ENTER( l * 2L )               )
+      {
+        FT_FREE( cmap2->subHeaders );
+        FT_FREE( cmap2->subHeaderKeys );
+        goto Fail;
+      }
+
+      for ( i = 0; i < l; i++ )
+        cmap2->glyphIdArray[i] = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+
+      cmap->get_index = code_to_index2;
+      cmap->get_next_char = code_to_next2;
+      break;
+
+    case 4:
+      cmap4 = &cmap->c.cmap4;
+
+      /* load header */
+
+      if ( FT_FRAME_ENTER( 10L ) )
+        goto Fail;
+
+      cmap4->language      = FT_GET_USHORT();
+      cmap4->segCountX2    = FT_GET_USHORT();
+      cmap4->searchRange   = FT_GET_USHORT();
+      cmap4->entrySelector = FT_GET_USHORT();
+      cmap4->rangeShift    = FT_GET_USHORT();
+
+      num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 );
+
+      FT_FRAME_EXIT();
+
+      /* load segments */
+
+      if ( FT_NEW_ARRAY( cmap4->segments, num_Seg )   ||
+           FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) )
+        goto Fail;
+
+      segments = cmap4->segments;
+
+      for ( i = 0; i < num_Seg; i++ )
+        segments[i].endCount = FT_GET_USHORT();
+
+      (void)FT_GET_USHORT();
+
+      for ( i = 0; i < num_Seg; i++ )
+        segments[i].startCount = FT_GET_USHORT();
+
+      for ( i = 0; i < num_Seg; i++ )
+        segments[i].idDelta = FT_GET_SHORT();
+
+      for ( i = 0; i < num_Seg; i++ )
+        segments[i].idRangeOffset = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+
+      cmap4->numGlyphId = l = (FT_UShort)(
+        ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 );
+
+      /* load IDs */
+
+      if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) ||
+           FT_FRAME_ENTER( l * 2L )               )
+      {
+        FT_FREE( cmap4->segments );
+        goto Fail;
+      }
+
+      for ( i = 0; i < l; i++ )
+        cmap4->glyphIdArray[i] = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+
+      cmap4->last_segment = cmap4->segments;
+
+      cmap->get_index     = code_to_index4;
+      cmap->get_next_char = code_to_next4;
+      break;
+
+    case 6:
+      cmap6 = &cmap->c.cmap6;
+
+      if ( FT_FRAME_ENTER( 6L ) )
+        goto Fail;
+
+      cmap6->language   = FT_GET_USHORT();
+      cmap6->firstCode  = FT_GET_USHORT();
+      cmap6->entryCount = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+
+      l = cmap6->entryCount;
+
+      if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) ||
+           FT_FRAME_ENTER( l * 2L )               )
+        goto Fail;
+
+      for ( i = 0; i < l; i++ )
+        cmap6->glyphIdArray[i] = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+      cmap->get_index     = code_to_index6;
+      cmap->get_next_char = code_to_next6;
+      break;
+
+    case 8:
+    case 12:
+      cmap8_12 = &cmap->c.cmap8_12;
+
+      if ( FT_FRAME_ENTER( 8L ) )
+        goto Fail;
+
+      cmap->length       = FT_GET_ULONG();
+      cmap8_12->language = FT_GET_ULONG();
+
+      FT_FRAME_EXIT();
+
+      if ( cmap->format == 8 )
+        if ( FT_STREAM_SKIP( 8192L ) )
+          goto Fail;
+
+      if ( FT_READ_ULONG( cmap8_12->nGroups ) )
+        goto Fail;
+
+      n = cmap8_12->nGroups;
+
+      if ( FT_NEW_ARRAY( cmap8_12->groups, n ) ||
+           FT_FRAME_ENTER( n * 3 * 4L )        )
+        goto Fail;
+
+      groups = cmap8_12->groups;
+
+      for ( j = 0; j < n; j++ )
+      {
+        groups[j].startCharCode = FT_GET_ULONG();
+        groups[j].endCharCode   = FT_GET_ULONG();
+        groups[j].startGlyphID  = FT_GET_ULONG();
+      }
+
+      FT_FRAME_EXIT();
+
+      cmap8_12->last_group = cmap8_12->groups;
+
+      cmap->get_index     = code_to_index8_12;
+      cmap->get_next_char = code_to_next8_12;
+      break;
+
+    case 10:
+      cmap10 = &cmap->c.cmap10;
+
+      if ( FT_FRAME_ENTER( 16L ) )
+        goto Fail;
+
+      cmap->length          = FT_GET_ULONG();
+      cmap10->language      = FT_GET_ULONG();
+      cmap10->startCharCode = FT_GET_ULONG();
+      cmap10->numChars      = FT_GET_ULONG();
+
+      FT_FRAME_EXIT();
+
+      n = cmap10->numChars;
+
+      if ( FT_NEW_ARRAY( cmap10->glyphs, n ) ||
+           FT_FRAME_ENTER( n * 2L )          )
+        goto Fail;
+
+      for ( j = 0; j < n; j++ )
+        cmap10->glyphs[j] = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+      cmap->get_index     = code_to_index10;
+      cmap->get_next_char = code_to_next10;
+      break;
+
+    default:   /* corrupt character mapping table */
+      return SFNT_Err_Invalid_CharMap_Format;
+
+    }
+
+    return SFNT_Err_Ok;
+
+  Fail:
+    tt_face_free_charmap( face, cmap );
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_free_charmap                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Destroys a character mapping table.                                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A handle to the parent face object.                        */
+  /*                                                                       */
+  /*    cmap :: A handle to a cmap object.                                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_free_charmap( TT_Face       face,
+                        TT_CMapTable  cmap )
+  {
+    FT_Memory  memory;
+
+
+    if ( !cmap )
+      return SFNT_Err_Ok;
+
+    memory = face->root.driver->root.memory;
+
+    switch ( cmap->format )
+    {
+    case 0:
+      FT_FREE( cmap->c.cmap0.glyphIdArray );
+      break;
+
+    case 2:
+      FT_FREE( cmap->c.cmap2.subHeaderKeys );
+      FT_FREE( cmap->c.cmap2.subHeaders );
+      FT_FREE( cmap->c.cmap2.glyphIdArray );
+      break;
+
+    case 4:
+      FT_FREE( cmap->c.cmap4.segments );
+      FT_FREE( cmap->c.cmap4.glyphIdArray );
+      cmap->c.cmap4.segCountX2 = 0;
+      break;
+
+    case 6:
+      FT_FREE( cmap->c.cmap6.glyphIdArray );
+      cmap->c.cmap6.entryCount = 0;
+      break;
+
+    case 8:
+    case 12:
+      FT_FREE( cmap->c.cmap8_12.groups );
+      cmap->c.cmap8_12.nGroups = 0;
+      break;
+
+    case 10:
+      FT_FREE( cmap->c.cmap10.glyphs );
+      cmap->c.cmap10.numChars = 0;
+      break;
+
+    default:
+      /* invalid table format, do nothing */
+      ;
+    }
+
+    cmap->loaded = FALSE;
+    return SFNT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_index0                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts the character code into a glyph index.  Uses format 0.    */
+  /*    `charCode' must be in the range 0x00-0xFF (otherwise 0 is          */
+  /*    returned).                                                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap0    :: A pointer to a cmap table in format 0.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index0( TT_CMapTable  cmap,
+                  FT_ULong      charCode )
+  {
+    TT_CMap0  cmap0 = &cmap->c.cmap0;
+
+
+    return ( charCode <= 0xFF ? cmap0->glyphIdArray[charCode] : 0 );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_next0                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finds the next encoded character after the given one.  Uses        */
+  /*    format 0. `charCode' must be in the range 0x00-0xFF (otherwise 0   */
+  /*    is returned).                                                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap0    :: A pointer to a cmap table in format 0.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next char code.  0 if no higher one is encoded.                    */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next0( TT_CMapTable  cmap,
+                 FT_ULong      charCode )
+  {
+    TT_CMap0  cmap0 = &cmap->c.cmap0;
+
+
+    while ( ++charCode <= 0xFF )
+      if ( cmap0->glyphIdArray[charCode] )
+        return ( charCode );
+    return ( 0 );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_index2                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts the character code into a glyph index.  Uses format 2.    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap2    :: A pointer to a cmap table in format 2.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index2( TT_CMapTable  cmap,
+                  FT_ULong      charCode )
+  {
+    FT_UInt            result, index1, offset;
+    FT_UInt            char_lo;
+    FT_ULong           char_hi;
+    TT_CMap2SubHeader  sh2;
+    TT_CMap2           cmap2;
+
+
+    cmap2   = &cmap->c.cmap2;
+    result  = 0;
+    char_lo = (FT_UInt)( charCode & 0xFF );
+    char_hi = charCode >> 8;
+
+    if ( char_hi == 0 )
+    {
+      /* an 8-bit character code -- we use the subHeader 0 in this case */
+      /* to test whether the character code is in the charmap           */
+      index1 = cmap2->subHeaderKeys[char_lo];
+      if ( index1 != 0 )
+        return 0;
+    }
+    else
+    {
+      /* a 16-bit character code */
+      index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
+      if ( index1 == 0 )
+        return 0;
+    }
+
+    sh2      = cmap2->subHeaders + index1;
+    char_lo -= sh2->firstCode;
+
+    if ( char_lo < (FT_UInt)sh2->entryCount )
+    {
+      offset = sh2->idRangeOffset / 2 + char_lo;
+      if ( offset < (FT_UInt)cmap2->numGlyphId )
+      {
+        result = cmap2->glyphIdArray[offset];
+        if ( result )
+          result = ( result + sh2->idDelta ) & 0xFFFFU;
+      }
+    }
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_next2                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 2.                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap2    :: A pointer to a cmap table in format 2.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next2( TT_CMapTable  cmap,
+                 FT_ULong      charCode )
+  {
+    FT_UInt            index1, offset;
+    FT_UInt            char_lo;
+    FT_ULong           char_hi;
+    TT_CMap2SubHeader  sh2;
+    TT_CMap2           cmap2;
+
+
+    cmap2 = &cmap->c.cmap2;
+    charCode++;
+
+    /*
+     * This is relatively simplistic -- look for a subHeader containing
+     * glyphs and then walk to the first glyph in that subHeader.
+     */
+    while ( charCode < 0x10000L )
+    {
+      char_lo = (FT_UInt)( charCode & 0xFF );
+      char_hi = charCode >> 8;
+
+      if ( char_hi == 0 )
+      {
+        /* an 8-bit character code -- we use the subHeader 0 in this case */
+        /* to test whether the character code is in the charmap           */
+        index1 = cmap2->subHeaderKeys[char_lo];
+        if ( index1 != 0 )
+        {
+          charCode++;
+          continue;
+        }
+      }
+      else
+      {
+        /* a 16-bit character code */
+        index1 = cmap2->subHeaderKeys[char_hi & 0xFF];
+        if ( index1 == 0 )
+        {
+          charCode = ( char_hi + 1 ) << 8;
+          continue;
+        }
+      }
+
+      sh2      = cmap2->subHeaders + index1;
+      char_lo -= sh2->firstCode;
+
+      if ( char_lo > (FT_UInt)sh2->entryCount )
+      {
+        charCode = ( char_hi + 1 ) << 8;
+        continue;
+      }
+
+      offset = sh2->idRangeOffset / 2 + char_lo;
+      if ( offset >= (FT_UInt)cmap2->numGlyphId ||
+           cmap2->glyphIdArray[offset] == 0     )
+      {
+        charCode++;
+        continue;
+      }
+
+      return charCode;
+    }
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_index4                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts the character code into a glyph index.  Uses format 4.    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap4    :: A pointer to a cmap table in format 4.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index4( TT_CMapTable  cmap,
+                  FT_ULong      charCode )
+  {
+    FT_UInt             result, index1, segCount;
+    TT_CMap4            cmap4;
+    TT_CMap4SegmentRec  *seg4, *limit;
+
+
+    cmap4    = &cmap->c.cmap4;
+    result   = 0;
+    segCount = cmap4->segCountX2 / 2;
+    limit    = cmap4->segments + segCount;
+
+    /* first, check against the last used segment */
+
+    seg4 = cmap4->last_segment;
+
+    /* the following is equivalent to performing two tests, as in         */
+    /*                                                                    */
+    /*  if ( charCode >= seg4->startCount && charCode <= seg4->endCount ) */
+    /*                                                                    */
+    /* This is a bit strange, but it is faster, and the idea behind the   */
+    /* cache is to significantly speed up charcode to glyph index         */
+    /* conversion.                                                        */
+
+    if ( (FT_ULong)( charCode       - seg4->startCount ) <
+         (FT_ULong)( seg4->endCount - seg4->startCount ) )
+      goto Found1;
+
+    for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
+    {
+      /* the ranges are sorted in increasing order.  If we are out of */
+      /* the range here, the char code isn't in the charmap, so exit. */
+
+      if ( charCode > (FT_UInt)seg4->endCount )
+        continue;
+
+      if ( charCode >= (FT_UInt)seg4->startCount )
+        goto Found;
+    }
+    return 0;
+
+  Found:
+    cmap4->last_segment = seg4;
+
+  Found1:
+    /* if the idRangeOffset is 0, we can compute the glyph index */
+    /* directly                                                  */
+
+    if ( seg4->idRangeOffset == 0 )
+      result = (FT_UInt)( charCode + seg4->idDelta ) & 0xFFFFU;
+    else
+    {
+      /* otherwise, we must use the glyphIdArray to do it */
+      index1 = (FT_UInt)( seg4->idRangeOffset / 2
+                          + ( charCode - seg4->startCount )
+                          + ( seg4 - cmap4->segments )
+                          - segCount );
+
+      if ( index1 < (FT_UInt)cmap4->numGlyphId &&
+           cmap4->glyphIdArray[index1] != 0    )
+        result = ( cmap4->glyphIdArray[index1] + seg4->idDelta ) & 0xFFFFU;
+    }
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_next4                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 4.                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap     :: A pointer to a cmap table in format 4.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next4( TT_CMapTable  cmap,
+                 FT_ULong      charCode )
+  {
+    FT_UInt             index1, segCount;
+    TT_CMap4            cmap4;
+    TT_CMap4SegmentRec  *seg4, *limit;
+
+
+    cmap4    = &cmap->c.cmap4;
+    segCount = cmap4->segCountX2 / 2;
+    limit    = cmap4->segments + segCount;
+
+    charCode++;
+
+    for ( seg4 = cmap4->segments; seg4 < limit; seg4++ )
+    {
+      /* The ranges are sorted in increasing order.  If we are out of */
+      /* the range here, the char code isn't in the charmap, so exit. */
+
+      if ( charCode <= (FT_UInt)seg4->endCount )
+        goto Found;
+    }
+    return 0;
+
+  Found:
+    if ( charCode < (FT_ULong) seg4->startCount )
+      charCode = seg4->startCount;
+
+    /* if the idRangeOffset is 0, all chars in the map exist */
+
+    if ( seg4->idRangeOffset == 0 )
+      return ( charCode );
+
+    while ( charCode <= (FT_UInt) seg4->endCount )
+    {
+      /* otherwise, we must use the glyphIdArray to do it */
+      index1 = (FT_UInt)( seg4->idRangeOffset / 2
+                          + ( charCode - seg4->startCount )
+                          + ( seg4 - cmap4->segments )
+                          - segCount );
+
+      if ( index1 < (FT_UInt)cmap4->numGlyphId &&
+           cmap4->glyphIdArray[index1] != 0    )
+        return ( charCode );
+      charCode++;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_index6                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts the character code into a glyph index.  Uses format 6.    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap6    :: A pointer to a cmap table in format 6.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index6( TT_CMapTable  cmap,
+                  FT_ULong      charCode )
+  {
+    TT_CMap6  cmap6;
+    FT_UInt   result = 0;
+
+
+    cmap6     = &cmap->c.cmap6;
+    charCode -= cmap6->firstCode;
+
+    if ( charCode < (FT_UInt)cmap6->entryCount )
+      result = cmap6->glyphIdArray[charCode];
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_next6                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 6.                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap     :: A pointer to a cmap table in format 6.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next6( TT_CMapTable  cmap,
+                 FT_ULong      charCode )
+  {
+    TT_CMap6  cmap6;
+
+
+    charCode++;
+
+    cmap6 = &cmap->c.cmap6;
+
+    if ( charCode < (FT_ULong) cmap6->firstCode )
+      charCode = cmap6->firstCode;
+
+    charCode -= cmap6->firstCode;
+
+    while ( charCode < (FT_UInt)cmap6->entryCount )
+    {
+      if ( cmap6->glyphIdArray[charCode] != 0 )
+        return charCode + cmap6->firstCode;
+      charCode++;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_index8_12                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts the (possibly 32bit) character code into a glyph index.   */
+  /*    Uses format 8 or 12.                                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap8_12 :: A pointer to a cmap table in format 8 or 12.           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index8_12( TT_CMapTable  cmap,
+                     FT_ULong      charCode )
+  {
+    TT_CMap8_12      cmap8_12;
+    TT_CMapGroupRec  *group, *limit;
+
+
+    cmap8_12 = &cmap->c.cmap8_12;
+    limit    = cmap8_12->groups + cmap8_12->nGroups;
+
+    /* first, check against the last used group */
+
+    group = cmap8_12->last_group;
+
+    /* the following is equivalent to performing two tests, as in       */
+    /*                                                                  */
+    /*  if ( charCode >= group->startCharCode &&                        */
+    /*       charCode <= group->endCharCode   )                         */
+    /*                                                                  */
+    /* This is a bit strange, but it is faster, and the idea behind the */
+    /* cache is to significantly speed up charcode to glyph index       */
+    /* conversion.                                                      */
+
+    if ( (FT_ULong)( charCode           - group->startCharCode ) <
+         (FT_ULong)( group->endCharCode - group->startCharCode ) )
+      goto Found1;
+
+    for ( group = cmap8_12->groups; group < limit; group++ )
+    {
+      /* the ranges are sorted in increasing order.  If we are out of */
+      /* the range here, the char code isn't in the charmap, so exit. */
+
+      if ( charCode > group->endCharCode )
+        continue;
+
+      if ( charCode >= group->startCharCode )
+        goto Found;
+    }
+    return 0;
+
+  Found:
+    cmap8_12->last_group = group;
+
+  Found1:
+    return (FT_UInt)( group->startGlyphID +
+                      ( charCode - group->startCharCode ) );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_next8_12                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 8 or 12.             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap     :: A pointer to a cmap table in format 8 or 12.           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next8_12( TT_CMapTable  cmap,
+                    FT_ULong      charCode )
+  {
+    TT_CMap8_12      cmap8_12;
+    TT_CMapGroupRec  *group, *limit;
+
+
+    charCode++;
+    cmap8_12 = &cmap->c.cmap8_12;
+    limit    = cmap8_12->groups + cmap8_12->nGroups;
+
+    for ( group = cmap8_12->groups; group < limit; group++ )
+    {
+      /* the ranges are sorted in increasing order.  If we are out of */
+      /* the range here, the char code isn't in the charmap, so exit. */
+
+      if ( charCode <= group->endCharCode )
+        goto Found;
+    }
+    return 0;
+
+  Found:
+    if ( charCode < group->startCharCode )
+      charCode = group->startCharCode;
+
+    return charCode;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_index10                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Converts the (possibly 32bit) character code into a glyph index.   */
+  /*    Uses format 10.                                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap10   :: A pointer to a cmap table in format 10.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Glyph index into the glyphs array.  0 if the glyph does not exist. */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_UInt )
+  code_to_index10( TT_CMapTable  cmap,
+                   FT_ULong      charCode )
+  {
+    TT_CMap10  cmap10;
+    FT_UInt    result = 0;
+
+
+    cmap10    = &cmap->c.cmap10;
+    charCode -= cmap10->startCharCode;
+
+    /* the overflow trick for comparison works here also since the number */
+    /* of glyphs (even if numChars is specified as ULong in the specs) in */
+    /* an OpenType font is limited to 64k                                 */
+
+    if ( charCode < cmap10->numChars )
+      result = cmap10->glyphs[charCode];
+
+    return result;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    code_to_next10                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Find the next encoded character.  Uses format 10.                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    charCode :: The wanted character code.                             */
+  /*                                                                       */
+  /*    cmap     :: A pointer to a cmap table in format 10.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Next encoded character.  0 if none exists.                         */
+  /*                                                                       */
+  FT_CALLBACK_DEF( FT_ULong )
+  code_to_next10( TT_CMapTable  cmap,
+                  FT_ULong      charCode )
+  {
+    TT_CMap10  cmap10;
+
+
+    charCode++;
+    cmap10 = &cmap->c.cmap10;
+
+    if ( charCode < cmap10->startCharCode )
+      charCode = cmap10->startCharCode;
+
+    charCode -= cmap10->startCharCode;
+
+    /* the overflow trick for comparison works here also since the number */
+    /* of glyphs (even if numChars is specified as ULong in the specs) in */
+    /* an OpenType font is limited to 64k                                 */
+
+    while ( charCode < cmap10->numChars )
+    {
+      if ( cmap10->glyphs[charCode] )
+        return ( charCode + cmap10->startCharCode );
+      charCode++;
+    }
+
+    return 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap.h
@@ -1,0 +1,45 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttcmap.h                                                               */
+/*                                                                         */
+/*    TrueType character mapping table (cmap) support (specification).     */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTCMAP_H__
+#define __TTCMAP_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_charmap( TT_Face       face,
+                        TT_CMapTable  cmap,
+                        FT_Stream     input );
+
+  FT_LOCAL( FT_Error )
+  tt_face_free_charmap( TT_Face       face,
+                        TT_CMapTable  cmap );
+
+
+FT_END_HEADER
+
+#endif /* __TTCMAP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap0.c
@@ -1,0 +1,1784 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttcmap0.c                                                              */
+/*                                                                         */
+/*    TrueType new character mapping table (cmap) support (body).          */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include "ttload.h"
+#include "ttcmap0.h"
+
+#include "sferrors.h"
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttcmap
+
+
+#define TT_PEEK_SHORT   FT_PEEK_SHORT
+#define TT_PEEK_USHORT  FT_PEEK_USHORT
+#define TT_PEEK_LONG    FT_PEEK_LONG
+#define TT_PEEK_ULONG   FT_PEEK_ULONG
+
+#define TT_NEXT_SHORT   FT_NEXT_SHORT
+#define TT_NEXT_USHORT  FT_NEXT_USHORT
+#define TT_NEXT_LONG    FT_NEXT_LONG
+#define TT_NEXT_ULONG   FT_NEXT_ULONG
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  tt_cmap_init( TT_CMap   cmap,
+                FT_Byte*  table )
+  {
+    cmap->data = table;
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           FORMAT 0                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME        OFFSET         TYPE          DESCRIPTION                */
+  /*                                                                       */
+  /*   format      0              USHORT        must be 0                  */
+  /*   length      2              USHORT        table length in bytes      */
+  /*   language    4              USHORT        Mac language code          */
+  /*   glyph_ids   6              BYTE[256]     array of glyph indices     */
+  /*               262                                                     */
+  /*                                                                       */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_0
+
+  FT_CALLBACK_DEF( void )
+  tt_cmap0_validate( FT_Byte*      table,
+                     FT_Validator  valid )
+  {
+    FT_Byte*  p      = table + 2;
+    FT_UInt   length = TT_NEXT_USHORT( p );
+
+
+    if ( table + length > valid->limit || length < 262 )
+      FT_INVALID_TOO_SHORT;
+
+    /* check glyph indices whenever necessary */
+    if ( valid->level >= FT_VALIDATE_TIGHT )
+    {
+      FT_UInt  n, idx;
+
+
+      p = table + 6;
+      for ( n = 0; n < 256; n++ )
+      {
+        idx = *p++;
+        if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+          FT_INVALID_GLYPH_ID;
+      }
+    }
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap0_char_index( TT_CMap    cmap,
+                       FT_UInt32  char_code )
+  {
+    FT_Byte*  table = cmap->data;
+
+
+    return char_code < 256 ? table[6 + char_code] : 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap0_char_next( TT_CMap     cmap,
+                      FT_UInt32  *pchar_code )
+  {
+    FT_Byte*   table    = cmap->data;
+    FT_UInt32  charcode = *pchar_code;
+    FT_UInt32  result   = 0;
+    FT_UInt    gindex   = 0;
+
+
+    table += 6;  /* go to glyph ids */
+    while ( ++charcode < 256 )
+    {
+      gindex = table[charcode];
+      if ( gindex != 0 )
+      {
+        result = charcode;
+        break;
+      }
+    }
+
+    *pchar_code = result;
+    return gindex;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap0_class_rec =
+  {
+    {
+      sizeof( TT_CMapRec ),
+
+      (FT_CMap_InitFunc)     tt_cmap_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap0_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap0_char_next
+    },
+    0,
+    (TT_CMap_ValidateFunc)   tt_cmap0_validate
+  };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_0 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          FORMAT 2                             *****/
+  /*****                                                               *****/
+  /***** This is used for certain CJK encodings that encode text in a  *****/
+  /***** mixed 8/16 bits encoding along the following lines:           *****/
+  /*****                                                               *****/
+  /***** * Certain byte values correspond to an 8-bit character code   *****/
+  /*****   (typically in the range 0..127 for ASCII compatibility).    *****/
+  /*****                                                               *****/
+  /***** * Certain byte values signal the first byte of a 2-byte       *****/
+  /*****   character code (but these values are also valid as the      *****/
+  /*****   second byte of a 2-byte character).                         *****/
+  /*****                                                               *****/
+  /***** The following charmap lookup and iteration functions all      *****/
+  /***** assume that the value "charcode" correspond to following:     *****/
+  /*****                                                               *****/
+  /*****   - For one byte characters, "charcode" is simply the         *****/
+  /*****     character code.                                           *****/
+  /*****                                                               *****/
+  /*****   - For two byte characters, "charcode" is the 2-byte         *****/
+  /*****     character code in big endian format.  More exactly:       *****/
+  /*****                                                               *****/
+  /*****       (charcode >> 8)    is the first byte value              *****/
+  /*****       (charcode & 0xFF)  is the second byte value             *****/
+  /*****                                                               *****/
+  /***** Note that not all values of "charcode" are valid according    *****/
+  /***** to these rules, and the function moderately check the         *****/
+  /***** arguments.                                                    *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME        OFFSET         TYPE            DESCRIPTION              */
+  /*                                                                       */
+  /*   format      0              USHORT          must be 2                */
+  /*   length      2              USHORT          table length in bytes    */
+  /*   language    4              USHORT          Mac language code        */
+  /*   keys        6              USHORT[256]     sub-header keys          */
+  /*   subs        518            SUBHEAD[NSUBS]  sub-headers array        */
+  /*   glyph_ids   518+NSUB*8     USHORT[]        glyph id array           */
+  /*                                                                       */
+  /* The `keys' table is used to map charcode high-bytes to sub-headers.   */
+  /* The value of `NSUBS' is the number of sub-headers defined in the      */
+  /* table and is computed by finding the maximum of the `keys' table.     */
+  /*                                                                       */
+  /* Note that for any n, `keys[n]' is a byte offset within the `subs'     */
+  /* table, i.e., it is the corresponding sub-header index multiplied      */
+  /* by 8.                                                                 */
+  /*                                                                       */
+  /* Each sub-header has the following format:                             */
+  /*                                                                       */
+  /*   NAME        OFFSET      TYPE            DESCRIPTION                 */
+  /*                                                                       */
+  /*   first       0           USHORT          first valid low-byte        */
+  /*   count       2           USHORT          number of valid low-bytes   */
+  /*   delta       4           SHORT           see below                   */
+  /*   offset      6           USHORT          see below                   */
+  /*                                                                       */
+  /* A sub-header defines, for each high-byte, the range of valid          */
+  /* low-bytes within the charmap.  Note that the range defined by `first' */
+  /* and `count' must be completely included in the interval [0..255]      */
+  /* according to the specification.                                       */
+  /*                                                                       */
+  /* If a character code is contained within a given sub-header, then      */
+  /* mapping it to a glyph index is done as follows:                       */
+  /*                                                                       */
+  /* * The value of `offset' is read.  This is a _byte_ distance from the  */
+  /*   location of the `offset' field itself into a slice of the           */
+  /*   `glyph_ids' table.  Let's call it `slice' (it's a USHORT[] too).    */
+  /*                                                                       */
+  /* * The value `slice[char.lo - first]' is read.  If it is 0, there is   */
+  /*   no glyph for the charcode.  Otherwise, the value of `delta' is      */
+  /*   added to it (modulo 65536) to form a new glyph index.               */
+  /*                                                                       */
+  /* It is up to the validation routine to check that all offsets fall     */
+  /* within the glyph ids table (and not within the `subs' table itself or */
+  /* outside of the CMap).                                                 */
+  /*                                                                       */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_2
+
+  FT_CALLBACK_DEF( void )
+  tt_cmap2_validate( FT_Byte*      table,
+                     FT_Validator  valid )
+  {
+    FT_Byte*  p      = table + 2;           /* skip format */
+    FT_UInt   length = TT_PEEK_USHORT( p );
+    FT_UInt   n, max_subs;
+    FT_Byte*  keys;                         /* keys table */
+    FT_Byte*  subs;                         /* sub-headers */
+    FT_Byte*  glyph_ids;                    /* glyph id array */
+
+
+    if ( table + length > valid->limit || length < 6 + 512 )
+      FT_INVALID_TOO_SHORT;
+
+    keys = table + 6;
+
+    /* parse keys to compute sub-headers count */
+    p        = keys;
+    max_subs = 0;
+    for ( n = 0; n < 256; n++ )
+    {
+      FT_UInt  idx = TT_NEXT_USHORT( p );
+
+
+      /* value must be multiple of 8 */
+      if ( valid->level >= FT_VALIDATE_PARANOID && ( idx & 7 ) != 0 )
+        FT_INVALID_DATA;
+
+      idx >>= 3;
+
+      if ( idx > max_subs )
+        max_subs = idx;
+    }
+
+    FT_ASSERT( p == table + 518 );
+
+    subs      = p;
+    glyph_ids = subs + (max_subs + 1) * 8;
+    if ( glyph_ids > valid->limit )
+      FT_INVALID_TOO_SHORT;
+
+    /* parse sub-headers */
+    for ( n = 0; n <= max_subs; n++ )
+    {
+      FT_UInt   first_code, code_count, offset;
+      FT_Int    delta;
+      FT_Byte*  ids;
+
+
+      first_code = TT_NEXT_USHORT( p );
+      code_count = TT_NEXT_USHORT( p );
+      delta      = TT_NEXT_SHORT( p );
+      offset     = TT_NEXT_USHORT( p );
+
+      /* check range within 0..255 */
+      if ( valid->level >= FT_VALIDATE_PARANOID )
+      {
+        if ( first_code >= 256 || first_code + code_count > 256 )
+          FT_INVALID_DATA;
+      }
+
+      /* check offset */
+      if ( offset != 0 )
+      {
+        ids = p - 2 + offset;
+        if ( ids < glyph_ids || ids + code_count*2 > table + length )
+          FT_INVALID_OFFSET;
+
+        /* check glyph ids */
+        if ( valid->level >= FT_VALIDATE_TIGHT )
+        {
+          FT_Byte*  limit = p + code_count * 2;
+          FT_UInt   idx;
+
+
+          for ( ; p < limit; )
+          {
+            idx = TT_NEXT_USHORT( p );
+            if ( idx != 0 )
+            {
+              idx = ( idx + delta ) & 0xFFFFU;
+              if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+                FT_INVALID_GLYPH_ID;
+            }
+          }
+        }
+      }
+    }
+  }
+
+
+  /* return sub header corresponding to a given character code */
+  /* NULL on invalid charcode                                  */
+  static FT_Byte*
+  tt_cmap2_get_subheader( FT_Byte*   table,
+                          FT_UInt32  char_code )
+  {
+    FT_Byte*  result = NULL;
+
+
+    if ( char_code < 0x10000UL )
+    {
+      FT_UInt   char_lo = (FT_UInt)( char_code & 0xFF );
+      FT_UInt   char_hi = (FT_UInt)( char_code >> 8 );
+      FT_Byte*  p       = table + 6;    /* keys table */
+      FT_Byte*  subs    = table + 518;  /* subheaders table */
+      FT_Byte*  sub;
+
+
+      if ( char_hi == 0 )
+      {
+        /* an 8-bit character code -- we use subHeader 0 in this case */
+        /* to test whether the character code is in the charmap       */
+        /*                                                            */
+        sub = subs;  /* jump to first sub-header */
+
+        /* check that the sub-header for this byte is 0, which */
+        /* indicates that it's really a valid one-byte value   */
+        /* Otherwise, return 0                                 */
+        /*                                                     */
+        p += char_lo * 2;
+        if ( TT_PEEK_USHORT( p ) != 0 )
+          goto Exit;
+      }
+      else
+      {
+        /* a 16-bit character code */
+        p  += char_hi * 2;                          /* jump to key entry  */
+        sub = subs + ( TT_PEEK_USHORT( p ) & -8 );  /* jump to sub-header */
+
+        /* check that the hi byte isn't a valid one-byte value */
+        if ( sub == subs )
+          goto Exit;
+      }
+      result = sub;
+    }
+  Exit:
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap2_char_index( TT_CMap    cmap,
+                       FT_UInt32  char_code )
+  {
+    FT_Byte*  table   = cmap->data;
+    FT_UInt   result  = 0;
+    FT_Byte*  subheader;
+
+
+    subheader = tt_cmap2_get_subheader( table, char_code );
+    if ( subheader )
+    {
+      FT_Byte*  p   = subheader;
+      FT_UInt   idx = (FT_UInt)(char_code & 0xFF);
+      FT_UInt   start, count;
+      FT_Int    delta;
+      FT_UInt   offset;
+
+
+      start  = TT_NEXT_USHORT( p );
+      count  = TT_NEXT_USHORT( p );
+      delta  = TT_NEXT_SHORT ( p );
+      offset = TT_PEEK_USHORT( p );
+
+      idx -= start;
+      if ( idx < count && offset != 0 )
+      {
+        p  += offset + 2 * idx;
+        idx = TT_PEEK_USHORT( p );
+
+        if ( idx != 0 )
+          result = (FT_UInt)( idx + delta ) & 0xFFFFU;
+      }
+    }
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap2_char_next( TT_CMap     cmap,
+                      FT_UInt32  *pcharcode )
+  {
+    FT_Byte*   table    = cmap->data;
+    FT_UInt    gindex   = 0;
+    FT_UInt32  result   = 0;
+    FT_UInt32  charcode = *pcharcode + 1;
+    FT_Byte*   subheader;
+
+
+    while ( charcode < 0x10000UL )
+    {
+      subheader = tt_cmap2_get_subheader( table, charcode );
+      if ( subheader )
+      {
+        FT_Byte*  p       = subheader;
+        FT_UInt   start   = TT_NEXT_USHORT( p );
+        FT_UInt   count   = TT_NEXT_USHORT( p );
+        FT_Int    delta   = TT_NEXT_SHORT ( p );
+        FT_UInt   offset  = TT_PEEK_USHORT( p );
+        FT_UInt   char_lo = (FT_UInt)( charcode & 0xFF );
+        FT_UInt   pos, idx;
+
+
+        if ( offset == 0 )
+          goto Next_SubHeader;
+
+        if ( char_lo < start )
+        {
+          char_lo = start;
+          pos     = 0;
+        }
+        else
+          pos = (FT_UInt)( char_lo - start );
+
+        p       += offset + pos * 2;
+        charcode = ( charcode & -256 ) + char_lo;
+
+        for ( ; pos < count; pos++, charcode++ )
+        {
+          idx = TT_NEXT_USHORT( p );
+
+          if ( idx != 0 )
+          {
+            gindex = ( idx + delta ) & 0xFFFFU;
+            if ( gindex != 0 )
+            {
+              result = charcode;
+              goto Exit;
+            }
+          }
+        }
+      }
+
+      /* jump to next sub-header, i.e. higher byte value */
+    Next_SubHeader:
+      charcode = ( charcode & -256 ) + 256;
+    }
+
+  Exit:
+    *pcharcode = result;
+
+    return gindex;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap2_class_rec =
+  {
+    {
+      sizeof( TT_CMapRec ),
+
+      (FT_CMap_InitFunc)     tt_cmap_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap2_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap2_char_next
+    },
+    2,
+    (TT_CMap_ValidateFunc)   tt_cmap2_validate
+  };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_2 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                           FORMAT 4                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME          OFFSET         TYPE              DESCRIPTION          */
+  /*                                                                       */
+  /*   format        0              USHORT            must be 4            */
+  /*   length        2              USHORT            table length         */
+  /*                                                  in bytes             */
+  /*   language      4              USHORT            Mac language code    */
+  /*                                                                       */
+  /*   segCountX2    6              USHORT            2*NUM_SEGS           */
+  /*   searchRange   8              USHORT            2*(1 << LOG_SEGS)    */
+  /*   entrySelector 10             USHORT            LOG_SEGS             */
+  /*   rangeShift    12             USHORT            segCountX2 -         */
+  /*                                                    searchRange        */
+  /*                                                                       */
+  /*   endCount      14             USHORT[NUM_SEGS]  end charcode for     */
+  /*                                                  each segment; last   */
+  /*                                                  is 0xFFFF            */
+  /*                                                                       */
+  /*   pad           14+NUM_SEGS*2  USHORT            padding              */
+  /*                                                                       */
+  /*   startCount    16+NUM_SEGS*2  USHORT[NUM_SEGS]  first charcode for   */
+  /*                                                  each segment         */
+  /*                                                                       */
+  /*   idDelta       16+NUM_SEGS*4  SHORT[NUM_SEGS]   delta for each       */
+  /*                                                  segment              */
+  /*   idOffset      16+NUM_SEGS*6  SHORT[NUM_SEGS]   range offset for     */
+  /*                                                  each segment; can be */
+  /*                                                  zero                 */
+  /*                                                                       */
+  /*   glyphIds      16+NUM_SEGS*8  USHORT[]          array of glyph id    */
+  /*                                                  ranges               */
+  /*                                                                       */
+  /* Character codes are modelled by a series of ordered (increasing)      */
+  /* intervals called segments.  Each segment has start and end codes,     */
+  /* provided by the `startCount' and `endCount' arrays.  Segments must    */
+  /* not be overlapping and the last segment should always contain the     */
+  /* `0xFFFF' endCount.                                                    */
+  /*                                                                       */
+  /* The fields `searchRange', `entrySelector' and `rangeShift' are better */
+  /* ignored (they are traces of over-engineering in the TrueType          */
+  /* specification).                                                       */
+  /*                                                                       */
+  /* Each segment also has a signed `delta', as well as an optional offset */
+  /* within the `glyphIds' table.                                          */
+  /*                                                                       */
+  /* If a segment's idOffset is 0, the glyph index corresponding to any    */
+  /* charcode within the segment is obtained by adding the value of        */
+  /* `idDelta' directly to the charcode, modulo 65536.                     */
+  /*                                                                       */
+  /* Otherwise, a glyph index is taken from the glyph ids sub-array for    */
+  /* the segment, and the value of `idDelta' is added to it.               */
+  /*                                                                       */
+  /*                                                                       */
+  /* Finally, note that certain fonts contain invalid charmaps that        */
+  /* contain end=0xFFFF, start=0xFFFF, delta=0x0001, offset=0xFFFF at the  */
+  /* of their charmaps (e.g. opens___.ttf which comes with OpenOffice.org) */
+  /* we need special code to deal with them correctly...                   */
+  /*                                                                       */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_4
+
+  FT_CALLBACK_DEF( void )
+  tt_cmap4_validate( FT_Byte*      table,
+                     FT_Validator  valid )
+  {
+    FT_Byte*  p      = table + 2;               /* skip format */
+    FT_UInt   length = TT_NEXT_USHORT( p );
+    FT_Byte   *ends, *starts, *offsets, *deltas, *glyph_ids;
+    FT_UInt   num_segs;
+
+
+    /* in certain fonts, the `length' field is invalid and goes */
+    /* out of bound.  We try to correct this here...            */
+    if ( length < 16 )
+      FT_INVALID_TOO_SHORT;
+
+    if ( table + length > valid->limit )
+    {
+      if ( valid->level >= FT_VALIDATE_TIGHT )
+        FT_INVALID_TOO_SHORT;
+
+      length = (FT_UInt)( valid->limit - table );
+    }
+
+    p        = table + 6;
+    num_segs = TT_NEXT_USHORT( p );   /* read segCountX2 */
+
+    if ( valid->level >= FT_VALIDATE_PARANOID )
+    {
+      /* check that we have an even value here */
+      if ( num_segs & 1 )
+        FT_INVALID_DATA;
+    }
+
+    num_segs /= 2;
+
+    /* check the search parameters - even though we never use them */
+    /*                                                             */
+    if ( valid->level >= FT_VALIDATE_PARANOID )
+    {
+      /* check the values of 'searchRange', 'entrySelector', 'rangeShift' */
+      FT_UInt  search_range   = TT_NEXT_USHORT( p );
+      FT_UInt  entry_selector = TT_NEXT_USHORT( p );
+      FT_UInt  range_shift    = TT_NEXT_USHORT( p );
+
+
+      if ( ( search_range | range_shift ) & 1 )  /* must be even values */
+        FT_INVALID_DATA;
+
+      search_range /= 2;
+      range_shift  /= 2;
+
+      /* `search range' is the greatest power of 2 that is <= num_segs */
+
+      if ( search_range                > num_segs                 ||
+           search_range * 2            < num_segs                 ||
+           search_range + range_shift != num_segs                 ||
+           search_range               != ( 1U << entry_selector ) )
+        FT_INVALID_DATA;
+    }
+
+    ends      = table   + 14;
+    starts    = table   + 16 + num_segs * 2;
+    deltas    = starts  + num_segs * 2;
+    offsets   = deltas  + num_segs * 2;
+    glyph_ids = offsets + num_segs * 2;
+
+    if ( glyph_ids > table + length )
+      FT_INVALID_TOO_SHORT;
+
+    /* check last segment, its end count must be FFFF */
+    if ( valid->level >= FT_VALIDATE_PARANOID )
+    {
+      p = ends + ( num_segs - 1 ) * 2;
+      if ( TT_PEEK_USHORT( p ) != 0xFFFFU )
+        FT_INVALID_DATA;
+    }
+
+    /* check that segments are sorted in increasing order and do not */
+    /* overlap; check also the offsets                               */
+    {
+      FT_UInt  start, end, last = 0, offset, n;
+      FT_Int   delta;
+
+
+      for ( n = 0; n < num_segs; n++ )
+      {
+        p = starts + n * 2;
+        start = TT_PEEK_USHORT( p );
+        p = ends + n * 2;
+        end = TT_PEEK_USHORT( p );
+        p = deltas + n * 2;
+        delta = TT_PEEK_SHORT( p );
+        p = offsets + n * 2;
+        offset = TT_PEEK_USHORT( p );
+
+        if ( start > end )
+          FT_INVALID_DATA;
+
+        /* this test should be performed at default validation level;  */
+        /* unfortunately, some popular Asian fonts present overlapping */
+        /* ranges in their charmaps                                    */
+        /*                                                             */
+        if ( valid->level >= FT_VALIDATE_TIGHT )
+        {
+          if ( n > 0 && start <= last )
+            FT_INVALID_DATA;
+        }
+
+        if ( offset && offset != 0xFFFFU )
+        {
+          p += offset;  /* start of glyph id array */
+
+          /* check that we point within the glyph ids table only */
+          if ( p < glyph_ids                                ||
+               p + ( end - start + 1 ) * 2 > table + length )
+            FT_INVALID_DATA;
+
+          /* check glyph indices within the segment range */
+          if ( valid->level >= FT_VALIDATE_TIGHT )
+          {
+            FT_UInt  i, idx;
+
+
+            for ( i = start; i < end; i++ )
+            {
+              idx = FT_NEXT_USHORT( p );
+              if ( idx != 0 )
+              {
+                idx = (FT_UInt)( idx + delta ) & 0xFFFFU;
+
+                if ( idx >= TT_VALID_GLYPH_COUNT( valid ) )
+                  FT_INVALID_GLYPH_ID;
+              }
+            }
+          }
+        }
+        else if ( offset == 0xFFFFU )
+        {
+          /* Some fonts (erroneously?) use a range offset of 0xFFFF */
+          /* to mean missing glyph in cmap table                    */
+          /*                                                        */
+          if ( valid->level >= FT_VALIDATE_PARANOID                     ||
+               n != num_segs - 1                                        ||
+               !( start == 0xFFFFU && end == 0xFFFFU && delta == 0x1U ) )
+            FT_INVALID_DATA;
+        }
+
+        last = end;
+      }
+    }
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap4_char_index( TT_CMap    cmap,
+                       FT_UInt32  char_code )
+  {
+    FT_Byte*  table  = cmap->data;
+    FT_UInt   result = 0;
+
+
+    if ( char_code < 0x10000UL )
+    {
+      FT_UInt   idx, num_segs2;
+      FT_Int    delta;
+      FT_UInt   code = (FT_UInt)char_code;
+      FT_Byte*  p;
+
+
+      p         = table + 6;
+      num_segs2 = TT_PEEK_USHORT( p ) & -2;  /* be paranoid! */
+
+#if 1
+      /* Some fonts have more than 170 segments in their charmaps! */
+      /* We changed this function to use a more efficient binary   */
+      /* search for improving performance                          */
+      {
+        FT_UInt  min = 0;
+        FT_UInt  max = num_segs2 >> 1;
+        FT_UInt  mid, start, end, offset;
+
+
+        while ( min < max )
+        {
+          mid   = ( min + max ) >> 1;
+          p     = table + 14 + mid * 2;
+          end   = TT_NEXT_USHORT( p );
+          p    += num_segs2;
+          start = TT_PEEK_USHORT( p);
+
+          if ( code < start )
+            max = mid;
+
+          else if ( code > end )
+            min = mid + 1;
+
+          else
+          {
+            /* we found the segment */
+            idx = code;
+
+            p += num_segs2;
+            delta = TT_PEEK_SHORT( p );
+
+            p += num_segs2;
+            offset = TT_PEEK_USHORT( p );
+
+            if ( offset == 0xFFFFU )
+              goto Exit;
+
+            if ( offset != 0 )
+            {
+              p  += offset + 2 * ( idx - start );
+              idx = TT_PEEK_USHORT( p );
+            }
+
+            if ( idx != 0 )
+              result = (FT_UInt)( idx + delta ) & 0xFFFFU;
+
+            goto Exit;
+          }
+        }
+      }
+
+#else /* 0 - old code */
+
+      {
+        FT_UInt   n;
+        FT_Byte*  q;
+
+
+        p = table + 14;               /* ends table   */
+        q = table + 16 + num_segs2;   /* starts table */
+
+
+        for ( n = 0; n < num_segs2; n += 2 )
+        {
+          FT_UInt  end   = TT_NEXT_USHORT( p );
+          FT_UInt  start = TT_NEXT_USHORT( q );
+          FT_UInt  offset;
+
+
+          if ( code < start )
+            break;
+
+          if ( code <= end )
+          {
+            idx = code;
+
+            p = q + num_segs2 - 2;
+            delta = TT_PEEK_SHORT( p );
+            p += num_segs2;
+            offset = TT_PEEK_USHORT( p );
+
+            if ( offset == 0xFFFFU )
+              goto Exit;
+
+            if ( offset != 0 )
+            {
+              p  += offset + 2 * ( idx - start );
+              idx = TT_PEEK_USHORT( p );
+            }
+
+            if ( idx != 0 )
+              result = (FT_UInt)( idx + delta ) & 0xFFFFU;
+          }
+        }
+      }
+
+#endif /* 0 */
+
+    }
+
+  Exit:
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap4_char_next( TT_CMap     cmap,
+                      FT_UInt32  *pchar_code )
+  {
+    FT_Byte*   table     = cmap->data;
+    FT_UInt32  result    = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+    FT_UInt    gindex    = 0;
+    FT_Byte*   p;
+    FT_Byte*   q;
+    FT_UInt    code, num_segs2;
+
+
+    if ( char_code >= 0x10000UL )
+      goto Exit;
+
+    code      = (FT_UInt)char_code;
+    p         = table + 6;
+    num_segs2 = TT_PEEK_USHORT(p) & -2;  /* ensure even-ness */
+
+    for (;;)
+    {
+      FT_UInt  offset, n;
+      FT_Int   delta;
+
+
+      p = table + 14;              /* ends table  */
+      q = table + 16 + num_segs2;  /* starts table */
+
+      for ( n = 0; n < num_segs2; n += 2 )
+      {
+        FT_UInt  end   = TT_NEXT_USHORT( p );
+        FT_UInt  start = TT_NEXT_USHORT( q );
+
+
+        if ( code < start )
+          code = start;
+
+        if ( code <= end )
+        {
+          p = q + num_segs2 - 2;
+          delta = TT_PEEK_SHORT( p );
+          p += num_segs2;
+          offset = TT_PEEK_USHORT( p );
+
+          if ( offset != 0 && offset != 0xFFFFU )
+          {
+            /* parse the glyph ids array for non-0 index */
+            p += offset + ( code - start ) * 2;
+            while ( code <= end )
+            {
+              gindex = TT_NEXT_USHORT( p );
+              if ( gindex != 0 )
+              {
+                gindex = (FT_UInt)( gindex + delta ) & 0xFFFFU;
+                if ( gindex != 0 )
+                  break;
+              }
+              code++;
+            }
+          }
+          else if ( offset == 0xFFFFU )
+          {
+            /* an offset of 0xFFFF means an empty glyph in certain fonts! */
+            code = end;
+            break;
+          }
+          else
+            gindex = (FT_UInt)( code + delta ) & 0xFFFFU;
+
+          if ( gindex == 0 )
+            break;
+
+          result = code;
+          goto Exit;
+        }
+      }
+
+      /* loop to next trial charcode */
+      if ( code >= 0xFFFFU )
+        break;
+
+      code++;
+    }
+    return (FT_UInt)result;
+
+  Exit:
+    *pchar_code = result;
+    return gindex;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap4_class_rec =
+  {
+    {
+      sizeof ( TT_CMapRec ),
+
+      (FT_CMap_InitFunc)     tt_cmap_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap4_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap4_char_next
+    },
+    4,
+    (TT_CMap_ValidateFunc)   tt_cmap4_validate
+  };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_4 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          FORMAT 6                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME        OFFSET          TYPE             DESCRIPTION            */
+  /*                                                                       */
+  /*   format       0              USHORT           must be 4              */
+  /*   length       2              USHORT           table length in bytes  */
+  /*   language     4              USHORT           Mac language code      */
+  /*                                                                       */
+  /*   first        6              USHORT           first segment code     */
+  /*   count        8              USHORT           segment size in chars  */
+  /*   glyphIds     10             USHORT[count]    glyph ids              */
+  /*                                                                       */
+  /* A very simplified segment mapping.                                    */
+  /*                                                                       */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_6
+
+  FT_CALLBACK_DEF( void )
+  tt_cmap6_validate( FT_Byte*      table,
+                     FT_Validator  valid )
+  {
+    FT_Byte*  p;
+    FT_UInt   length, start, count;
+
+
+    if ( table + 10 > valid->limit )
+      FT_INVALID_TOO_SHORT;
+
+    p      = table + 2;
+    length = TT_NEXT_USHORT( p );
+
+    p      = table + 6;             /* skip language */
+    start  = TT_NEXT_USHORT( p );
+    count  = TT_NEXT_USHORT( p );
+
+    if ( table + length > valid->limit || length < 10 + count * 2 )
+      FT_INVALID_TOO_SHORT;
+
+    /* check glyph indices */
+    if ( valid->level >= FT_VALIDATE_TIGHT )
+    {
+      FT_UInt  gindex;
+
+
+      for ( ; count > 0; count-- )
+      {
+        gindex = TT_NEXT_USHORT( p );
+        if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
+          FT_INVALID_GLYPH_ID;
+      }
+    }
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap6_char_index( TT_CMap    cmap,
+                       FT_UInt32  char_code )
+  {
+    FT_Byte*  table  = cmap->data;
+    FT_UInt   result = 0;
+    FT_Byte*  p      = table + 6;
+    FT_UInt   start  = TT_NEXT_USHORT( p );
+    FT_UInt   count  = TT_NEXT_USHORT( p );
+    FT_UInt   idx    = (FT_UInt)( char_code - start );
+
+
+    if ( idx < count )
+    {
+      p += 2 * idx;
+      result = TT_PEEK_USHORT( p );
+    }
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap6_char_next( TT_CMap     cmap,
+                      FT_UInt32  *pchar_code )
+  {
+    FT_Byte*   table     = cmap->data;
+    FT_UInt32  result    = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+    FT_UInt    gindex    = 0;
+
+    FT_Byte*   p         = table + 6;
+    FT_UInt    start     = TT_NEXT_USHORT( p );
+    FT_UInt    count     = TT_NEXT_USHORT( p );
+    FT_UInt    idx;
+
+
+    if ( char_code >= 0x10000UL )
+      goto Exit;
+
+    if ( char_code < start )
+      char_code = start;
+
+    idx = (FT_UInt)( char_code - start );
+    p  += 2 * idx;
+
+    for ( ; idx < count; idx++ )
+    {
+      gindex = TT_NEXT_USHORT( p );
+      if ( gindex != 0 )
+      {
+        result = char_code;
+        break;
+      }
+      char_code++;
+    }
+
+  Exit:
+    *pchar_code = result;
+    return gindex;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap6_class_rec =
+  {
+    {
+      sizeof ( TT_CMapRec ),
+
+      (FT_CMap_InitFunc)     tt_cmap_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap6_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap6_char_next
+    },
+    6,
+    (TT_CMap_ValidateFunc)   tt_cmap6_validate
+  };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_6 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          FORMAT 8                             *****/
+  /*****                                                               *****/
+  /***** It's hard to completely understand what the OpenType spec     *****/
+  /***** says about this format, but here is my conclusion.            *****/
+  /*****                                                               *****/
+  /***** The purpose of this format is to easily map UTF-16 text to    *****/
+  /***** glyph indices.  Basically, the `char_code' must be in one of  *****/
+  /***** the following formats:                                        *****/
+  /*****                                                               *****/
+  /*****   - A 16-bit value that isn't part of the Unicode Surrogates  *****/
+  /*****     Area (i.e. U+D800-U+DFFF).                                *****/
+  /*****                                                               *****/
+  /*****   - A 32-bit value, made of two surrogate values, i.e.. if    *****/
+  /*****     `char_code = (char_hi << 16) | char_lo', then both        *****/
+  /*****     `char_hi' and `char_lo' must be in the Surrogates Area.   *****/
+  /*****      Area.                                                    *****/
+  /*****                                                               *****/
+  /***** The 'is32' table embedded in the charmap indicates whether a  *****/
+  /***** given 16-bit value is in the surrogates area or not.          *****/
+  /*****                                                               *****/
+  /***** So, for any given `char_code', we can assert the following:   *****/
+  /*****                                                               *****/
+  /*****   If `char_hi == 0' then we must have `is32[char_lo] == 0'.   *****/
+  /*****                                                               *****/
+  /*****   If `char_hi != 0' then we must have both                    *****/
+  /*****   `is32[char_hi] != 0' and `is32[char_lo] != 0'.              *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME        OFFSET         TYPE        DESCRIPTION                  */
+  /*                                                                       */
+  /*   format      0              USHORT      must be 8                    */
+  /*   reseved     2              USHORT      reserved                     */
+  /*   length      4              ULONG       length in bytes              */
+  /*   language    8              ULONG       Mac language code            */
+  /*   is32        12             BYTE[8192]  32-bitness bitmap            */
+  /*   count       8204           ULONG       number of groups             */
+  /*                                                                       */
+  /* This header is followed by 'count' groups of the following format:    */
+  /*                                                                       */
+  /*   start       0              ULONG       first charcode               */
+  /*   end         4              ULONG       last charcode                */
+  /*   startId     8              ULONG       start glyph id for the group */
+  /*                                                                       */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_8
+
+  FT_CALLBACK_DEF( void )
+  tt_cmap8_validate( FT_Byte*      table,
+                     FT_Validator  valid )
+  {
+    FT_Byte*   p = table + 4;
+    FT_Byte*   is32;
+    FT_UInt32  length;
+    FT_UInt32  num_groups;
+
+
+    if ( table + 16 + 8192 > valid->limit )
+      FT_INVALID_TOO_SHORT;
+
+    length = TT_NEXT_ULONG( p );
+    if ( table + length > valid->limit || length < 8208 )
+      FT_INVALID_TOO_SHORT;
+
+    is32       = table + 12;
+    p          = is32  + 8192;          /* skip `is32' array */
+    num_groups = TT_NEXT_ULONG( p );
+
+    if ( p + num_groups * 12 > valid->limit )
+      FT_INVALID_TOO_SHORT;
+
+    /* check groups, they must be in increasing order */
+    {
+      FT_UInt32  n, start, end, start_id, count, last = 0;
+
+
+      for ( n = 0; n < num_groups; n++ )
+      {
+        FT_UInt   hi, lo;
+
+
+        start    = TT_NEXT_ULONG( p );
+        end      = TT_NEXT_ULONG( p );
+        start_id = TT_NEXT_ULONG( p );
+
+        if ( start > end )
+          FT_INVALID_DATA;
+
+        if ( n > 0 && start <= last )
+          FT_INVALID_DATA;
+
+        if ( valid->level >= FT_VALIDATE_TIGHT )
+        {
+          if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
+            FT_INVALID_GLYPH_ID;
+
+          count = (FT_UInt32)( end - start + 1 );
+
+          if ( start & ~0xFFFFU )
+          {
+            /* start_hi != 0; check that is32[i] is 1 for each i in */
+            /* the `hi' and `lo' of the range [start..end]          */
+            for ( ; count > 0; count--, start++ )
+            {
+              hi = (FT_UInt)( start >> 16 );
+              lo = (FT_UInt)( start & 0xFFFFU );
+
+              if ( (is32[hi >> 3] & ( 0x80 >> ( hi & 7 ) ) ) == 0 )
+                FT_INVALID_DATA;
+
+              if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) == 0 )
+                FT_INVALID_DATA;
+            }
+          }
+          else
+          {
+            /* start_hi == 0; check that is32[i] is 0 for each i in */
+            /* the range [start..end]                               */
+
+            /* end_hi cannot be != 0! */
+            if ( end & ~0xFFFFU )
+              FT_INVALID_DATA;
+
+            for ( ; count > 0; count--, start++ )
+            {
+              lo = (FT_UInt)( start & 0xFFFFU );
+
+              if ( (is32[lo >> 3] & ( 0x80 >> ( lo & 7 ) ) ) != 0 )
+                FT_INVALID_DATA;
+            }
+          }
+        }
+
+        last = end;
+      }
+    }
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap8_char_index( TT_CMap    cmap,
+                       FT_UInt32  char_code )
+  {
+    FT_Byte*   table      = cmap->data;
+    FT_UInt    result     = 0;
+    FT_Byte*   p          = table + 8204;
+    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
+    FT_UInt32  start, end, start_id;
+
+
+    for ( ; num_groups > 0; num_groups-- )
+    {
+      start    = TT_NEXT_ULONG( p );
+      end      = TT_NEXT_ULONG( p );
+      start_id = TT_NEXT_ULONG( p );
+
+      if ( char_code < start )
+        break;
+
+      if ( char_code <= end )
+      {
+        result = (FT_UInt)( start_id + char_code - start );
+        break;
+      }
+    }
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap8_char_next( TT_CMap     cmap,
+                      FT_UInt32  *pchar_code )
+  {
+    FT_UInt32  result     = 0;
+    FT_UInt32  char_code  = *pchar_code + 1;
+    FT_UInt    gindex     = 0;
+    FT_Byte*   table      = cmap->data;
+    FT_Byte*   p          = table + 8204;
+    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
+    FT_UInt32  start, end, start_id;
+
+
+    p = table + 8208;
+
+    for ( ; num_groups > 0; num_groups-- )
+    {
+      start    = TT_NEXT_ULONG( p );
+      end      = TT_NEXT_ULONG( p );
+      start_id = TT_NEXT_ULONG( p );
+
+      if ( char_code < start )
+        char_code = start;
+
+      if ( char_code <= end )
+      {
+        gindex = (FT_UInt)( char_code - start + start_id );
+        if ( gindex != 0 )
+        {
+          result = char_code;
+          goto Exit;
+        }
+      }
+    }
+
+  Exit:
+    *pchar_code = result;
+    return gindex;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap8_class_rec =
+  {
+    {
+      sizeof ( TT_CMapRec ),
+
+      (FT_CMap_InitFunc)     tt_cmap_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap8_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap8_char_next
+    },
+    8,
+    (TT_CMap_ValidateFunc)   tt_cmap8_validate
+  };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_8 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          FORMAT 10                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME      OFFSET  TYPE               DESCRIPTION                    */
+  /*                                                                       */
+  /*   format     0      USHORT             must be 10                     */
+  /*   reserved   2      USHORT             reserved                       */
+  /*   length     4      ULONG              length in bytes                */
+  /*   language   8      ULONG              Mac language code              */
+  /*                                                                       */
+  /*   start     12      ULONG              first char in range            */
+  /*   count     16      ULONG              number of chars in range       */
+  /*   glyphIds  20      USHORT[count]      glyph indices covered          */
+  /*                                                                       */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_10
+
+  FT_CALLBACK_DEF( void )
+  tt_cmap10_validate( FT_Byte*      table,
+                      FT_Validator  valid )
+  {
+    FT_Byte*  p = table + 4;
+    FT_ULong  length, start, count;
+
+
+    if ( table + 20 > valid->limit )
+      FT_INVALID_TOO_SHORT;
+
+    length = TT_NEXT_ULONG( p );
+    p      = table + 12;
+    start  = TT_NEXT_ULONG( p );
+    count  = TT_NEXT_ULONG( p );
+
+    if ( table + length > valid->limit || length < 20 + count * 2 )
+      FT_INVALID_TOO_SHORT;
+
+    /* check glyph indices */
+    if ( valid->level >= FT_VALIDATE_TIGHT )
+    {
+      FT_UInt  gindex;
+
+
+      for ( ; count > 0; count-- )
+      {
+        gindex = TT_NEXT_USHORT( p );
+        if ( gindex >= TT_VALID_GLYPH_COUNT( valid ) )
+          FT_INVALID_GLYPH_ID;
+      }
+    }
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap10_char_index( TT_CMap    cmap,
+                        FT_UInt32  char_code )
+  {
+    FT_Byte*   table  = cmap->data;
+    FT_UInt    result = 0;
+    FT_Byte*   p      = table + 12;
+    FT_UInt32  start  = TT_NEXT_ULONG( p );
+    FT_UInt32  count  = TT_NEXT_ULONG( p );
+    FT_UInt32  idx    = (FT_ULong)( char_code - start );
+
+
+    if ( idx < count )
+    {
+      p     += 2 * idx;
+      result = TT_PEEK_USHORT( p );
+    }
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap10_char_next( TT_CMap     cmap,
+                       FT_UInt32  *pchar_code )
+  {
+    FT_Byte*   table     = cmap->data;
+    FT_UInt32  result    = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+    FT_UInt    gindex    = 0;
+    FT_Byte*   p         = table + 12;
+    FT_UInt32  start     = TT_NEXT_ULONG( p );
+    FT_UInt32  count     = TT_NEXT_ULONG( p );
+    FT_UInt32  idx;
+
+
+    if ( char_code < start )
+      char_code = start;
+
+    idx = (FT_UInt32)( char_code - start );
+    p  += 2 * idx;
+
+    for ( ; idx < count; idx++ )
+    {
+      gindex = TT_NEXT_USHORT( p );
+      if ( gindex != 0 )
+      {
+        result = char_code;
+        break;
+      }
+      char_code++;
+    }
+
+    *pchar_code = char_code;
+    return gindex;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap10_class_rec =
+  {
+    {
+      sizeof ( TT_CMapRec ),
+
+      (FT_CMap_InitFunc)     tt_cmap_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap10_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap10_char_next
+    },
+    10,
+    (TT_CMap_ValidateFunc)   tt_cmap10_validate
+  };
+
+#endif /* TT_CONFIG_CMAP_FORMAT_10 */
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          FORMAT 12                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TABLE OVERVIEW                                                        */
+  /* --------------                                                        */
+  /*                                                                       */
+  /*   NAME        OFFSET     TYPE       DESCRIPTION                       */
+  /*                                                                       */
+  /*   format      0          USHORT     must be 12                        */
+  /*   reserved    2          USHORT     reserved                          */
+  /*   length      4          ULONG      length in bytes                   */
+  /*   language    8          ULONG      Mac language code                 */
+  /*   count       12         ULONG      number of groups                  */
+  /*               16                                                      */
+  /*                                                                       */
+  /* This header is followed by `count' groups of the following format:    */
+  /*                                                                       */
+  /*   start       0          ULONG      first charcode                    */
+  /*   end         4          ULONG      last charcode                     */
+  /*   startId     8          ULONG      start glyph id for the group      */
+  /*                                                                       */
+
+#ifdef TT_CONFIG_CMAP_FORMAT_12
+
+  FT_CALLBACK_DEF( void )
+  tt_cmap12_validate( FT_Byte*      table,
+                      FT_Validator  valid )
+  {
+    FT_Byte*   p;
+    FT_ULong   length;
+    FT_ULong   num_groups;
+
+
+    if ( table + 16 > valid->limit )
+      FT_INVALID_TOO_SHORT;
+
+    p      = table + 4;
+    length = TT_NEXT_ULONG( p );
+
+    p          = table + 12;
+    num_groups = TT_NEXT_ULONG( p );
+
+    if ( table + length > valid->limit || length < 16 + 12 * num_groups )
+      FT_INVALID_TOO_SHORT;
+
+    /* check groups, they must be in increasing order */
+    {
+      FT_ULong  n, start, end, start_id, last = 0;
+
+
+      for ( n = 0; n < num_groups; n++ )
+      {
+        start    = TT_NEXT_ULONG( p );
+        end      = TT_NEXT_ULONG( p );
+        start_id = TT_NEXT_ULONG( p );
+
+        if ( start > end )
+          FT_INVALID_DATA;
+
+        if ( n > 0 && start <= last )
+          FT_INVALID_DATA;
+
+        if ( valid->level >= FT_VALIDATE_TIGHT )
+        {
+          if ( start_id + end - start >= TT_VALID_GLYPH_COUNT( valid ) )
+            FT_INVALID_GLYPH_ID;
+        }
+
+        last = end;
+      }
+    }
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap12_char_index( TT_CMap    cmap,
+                        FT_UInt32  char_code )
+  {
+    FT_UInt    result     = 0;
+    FT_Byte*   table      = cmap->data;
+    FT_Byte*   p          = table + 12;
+    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
+    FT_UInt32  start, end, start_id;
+
+
+    for ( ; num_groups > 0; num_groups-- )
+    {
+      start    = TT_NEXT_ULONG( p );
+      end      = TT_NEXT_ULONG( p );
+      start_id = TT_NEXT_ULONG( p );
+
+      if ( char_code < start )
+        break;
+
+      if ( char_code <= end )
+      {
+        result = (FT_UInt)( start_id + char_code - start );
+        break;
+      }
+    }
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  tt_cmap12_char_next( TT_CMap     cmap,
+                       FT_UInt32  *pchar_code )
+  {
+    FT_Byte*   table      = cmap->data;
+    FT_UInt32  result     = 0;
+    FT_UInt32  char_code  = *pchar_code + 1;
+    FT_UInt    gindex     = 0;
+    FT_Byte*   p          = table + 12;
+    FT_UInt32  num_groups = TT_NEXT_ULONG( p );
+    FT_UInt32  start, end, start_id;
+
+
+    p = table + 16;
+
+    for ( ; num_groups > 0; num_groups-- )
+    {
+      start    = TT_NEXT_ULONG( p );
+      end      = TT_NEXT_ULONG( p );
+      start_id = TT_NEXT_ULONG( p );
+
+      if ( char_code < start )
+        char_code = start;
+
+      if ( char_code <= end )
+      {
+        gindex = (FT_UInt)(char_code - start + start_id);
+        if ( gindex != 0 )
+        {
+          result = char_code;
+          goto Exit;
+        }
+      }
+    }
+
+  Exit:
+    *pchar_code = result;
+    return gindex;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const TT_CMap_ClassRec  tt_cmap12_class_rec =
+  {
+    {
+      sizeof ( TT_CMapRec ),
+
+      (FT_CMap_InitFunc)     tt_cmap_init,
+      (FT_CMap_DoneFunc)     NULL,
+      (FT_CMap_CharIndexFunc)tt_cmap12_char_index,
+      (FT_CMap_CharNextFunc) tt_cmap12_char_next
+    },
+    12,
+    (TT_CMap_ValidateFunc)   tt_cmap12_validate
+  };
+
+
+#endif /* TT_CONFIG_CMAP_FORMAT_12 */
+
+
+  static const TT_CMap_Class  tt_cmap_classes[] =
+  {
+#ifdef TT_CONFIG_CMAP_FORMAT_0
+    &tt_cmap0_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_2
+    &tt_cmap2_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_4
+    &tt_cmap4_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_6
+    &tt_cmap6_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_8
+    &tt_cmap8_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_10
+    &tt_cmap10_class_rec,
+#endif
+
+#ifdef TT_CONFIG_CMAP_FORMAT_12
+    &tt_cmap12_class_rec,
+#endif
+
+    NULL,
+  };
+
+
+  /* parse the `cmap' table and build the corresponding TT_CMap objects */
+  /* in the current face                                                */
+  /*                                                                    */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_build_cmaps( TT_Face  face )
+  {
+    FT_Byte*           table = face->cmap_table;
+    FT_Byte*           limit = table + face->cmap_size;
+    FT_UInt volatile   num_cmaps;
+    FT_Byte* volatile  p     = table;
+
+
+    if ( p + 4 > limit )
+      return FT_Err_Invalid_Table;
+
+    /* only recognize format 0 */
+    if ( TT_NEXT_USHORT( p ) != 0 )
+    {
+      p -= 2;
+      FT_ERROR(( "tt_face_build_cmaps: unsupported `cmap' table format = %d\n",
+                 TT_PEEK_USHORT( p ) ));
+      return FT_Err_Invalid_Table;
+    }
+
+    num_cmaps = TT_NEXT_USHORT( p );
+
+    for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- )
+    {
+      FT_CharMapRec  charmap;
+      FT_UInt32      offset;
+
+
+      charmap.platform_id = TT_NEXT_USHORT( p );
+      charmap.encoding_id = TT_NEXT_USHORT( p );
+      charmap.face        = FT_FACE( face );
+      charmap.encoding    = FT_ENCODING_NONE;  /* will be filled later */
+      offset              = TT_NEXT_ULONG( p );
+
+      if ( offset && table + offset + 2 < limit )
+      {
+        FT_Byte*                       cmap   = table + offset;
+        FT_UInt                        format = TT_PEEK_USHORT( cmap );
+        const TT_CMap_Class* volatile  pclazz = tt_cmap_classes;
+        TT_CMap_Class                  clazz;
+
+
+        for ( ; *pclazz; pclazz++ )
+        {
+          clazz = *pclazz;
+          if ( clazz->format == format )
+          {
+            volatile TT_ValidatorRec  valid;
+
+
+            ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit,
+                               FT_VALIDATE_DEFAULT );
+
+            valid.num_glyphs = (FT_UInt)face->root.num_glyphs;
+
+            if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer ) == 0 )
+            {
+              /* validate this cmap sub-table */
+              clazz->validate( cmap, FT_VALIDATOR( &valid ) );
+            }
+
+            if ( valid.validator.error == 0 )
+              (void)FT_CMap_New( (FT_CMap_Class)clazz, cmap, &charmap, NULL );
+            else
+            {
+              FT_ERROR(( "tt_face_build_cmaps:" ));
+              FT_ERROR(( " broken cmap sub-table ignored!\n" ));
+            }
+          }
+        }
+      }
+    }
+
+    return 0;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttcmap0.h
@@ -1,0 +1,74 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttcmap0.h                                                              */
+/*                                                                         */
+/*    TrueType new character mapping table (cmap) support (specification). */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTCMAP0_H__
+#define __TTCMAP0_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+  typedef struct  TT_CMapRec_
+  {
+    FT_CMapRec  cmap;
+    FT_Byte*    data;           /* pointer to in-memory cmap table */
+
+  } TT_CMapRec, *TT_CMap;
+
+  typedef const struct TT_CMap_ClassRec_*  TT_CMap_Class;
+
+
+  typedef FT_Error
+  (*TT_CMap_ValidateFunc)( FT_Byte*      data,
+                           FT_Validator  valid );
+
+  typedef struct  TT_CMap_ClassRec_
+  {
+    FT_CMap_ClassRec      clazz;
+    FT_UInt               format;
+    TT_CMap_ValidateFunc  validate;
+
+  } TT_CMap_ClassRec;
+
+
+  typedef struct  TT_ValidatorRec_
+  {
+    FT_ValidatorRec  validator;
+    FT_UInt          num_glyphs;
+
+  } TT_ValidatorRec, *TT_Validator;
+
+
+#define TT_VALIDATOR( x )          ((TT_Validator)( x ))
+#define TT_VALID_GLYPH_COUNT( x )  TT_VALIDATOR( x )->num_glyphs
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_build_cmaps( TT_Face  face );
+
+
+FT_END_HEADER
+
+#endif /* __TTCMAP0_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttdriver.c
@@ -1,0 +1,420 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttdriver.c                                                             */
+/*                                                                         */
+/*    TrueType font driver implementation (body).                          */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_IDS_H
+
+#include "ttdriver.h"
+#include "ttgload.h"
+
+#include "tterrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttdriver
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                          F A C E S                              ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+#undef  PAIR_TAG
+#define PAIR_TAG( left, right )  ( ( (FT_ULong)left << 16 ) | \
+                                     (FT_ULong)right        )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Get_Kerning                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A driver method used to return the kerning vector between two      */
+  /*    glyphs of the same face.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face        :: A handle to the source face object.                 */
+  /*                                                                       */
+  /*    left_glyph  :: The index of the left glyph in the kern pair.       */
+  /*                                                                       */
+  /*    right_glyph :: The index of the right glyph in the kern pair.      */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    kerning     :: The kerning vector.  This is in font units for      */
+  /*                   scalable formats, and in pixels for fixed-sizes     */
+  /*                   formats.                                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only horizontal layouts (left-to-right & right-to-left) are        */
+  /*    supported by this function.  Other layouts, or more sophisticated  */
+  /*    kernings, are out of scope of this method (the basic driver        */
+  /*    interface is meant to be simple).                                  */
+  /*                                                                       */
+  /*    They can be implemented by format-specific interfaces.             */
+  /*                                                                       */
+  static FT_Error
+  Get_Kerning( TT_Face     face,
+               FT_UInt     left_glyph,
+               FT_UInt     right_glyph,
+               FT_Vector*  kerning )
+  {
+    TT_Kern0_Pair  pair;
+
+
+    if ( !face )
+      return TT_Err_Invalid_Face_Handle;
+
+    kerning->x = 0;
+    kerning->y = 0;
+
+    if ( face->kern_pairs )
+    {
+      /* there are some kerning pairs in this font file! */
+      FT_ULong  search_tag = PAIR_TAG( left_glyph, right_glyph );
+      FT_Long   left, right;
+
+
+      left  = 0;
+      right = face->num_kern_pairs - 1;
+
+      while ( left <= right )
+      {
+        FT_Int    middle = left + ( ( right - left ) >> 1 );
+        FT_ULong  cur_pair;
+
+
+        pair     = face->kern_pairs + middle;
+        cur_pair = PAIR_TAG( pair->left, pair->right );
+
+        if ( cur_pair == search_tag )
+          goto Found;
+
+        if ( cur_pair < search_tag )
+          left = middle + 1;
+        else
+          right = middle - 1;
+      }
+    }
+
+  Exit:
+    return TT_Err_Ok;
+
+  Found:
+    kerning->x = pair->value;
+    goto Exit;
+  }
+
+
+#undef PAIR_TAG
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                           S I Z E S                             ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Set_Char_Sizes                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A driver method used to reset a size's character sizes (horizontal */
+  /*    and vertical) expressed in fractional points.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    char_width      :: The character width expressed in 26.6           */
+  /*                       fractional points.                              */
+  /*                                                                       */
+  /*    char_height     :: The character height expressed in 26.6          */
+  /*                       fractional points.                              */
+  /*                                                                       */
+  /*    horz_resolution :: The horizontal resolution of the output device. */
+  /*                                                                       */
+  /*    vert_resolution :: The vertical resolution of the output device.   */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    size            :: A handle to the target size object.             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Set_Char_Sizes( TT_Size     size,
+                  FT_F26Dot6  char_width,
+                  FT_F26Dot6  char_height,
+                  FT_UInt     horz_resolution,
+                  FT_UInt     vert_resolution )
+  {
+    FT_Size_Metrics*  metrics = &size->root.metrics;
+    TT_Face           face    = (TT_Face)size->root.face;
+    FT_Long           dim_x, dim_y;
+
+
+    /* This bit flag, when set, indicates that the pixel size must be */
+    /* truncated to an integer.  Nearly all TrueType fonts have this  */
+    /* bit set, as hinting won't work really well otherwise.          */
+    /*                                                                */
+    /* However, for those rare fonts who do not set it, we override   */
+    /* the default computations performed by the base layer.  I       */
+    /* really don't know whether this is useful, but hey, that's the  */
+    /* spec :-)                                                       */
+    /*                                                                */
+    if ( ( face->header.Flags & 8 ) == 0 )
+    {
+      /* Compute pixel sizes in 26.6 units */
+      dim_x = ( char_width  * horz_resolution + 36 ) / 72;
+      dim_y = ( char_height * vert_resolution + 36 ) / 72;
+
+      metrics->x_scale = FT_DivFix( dim_x, face->root.units_per_EM );
+      metrics->y_scale = FT_DivFix( dim_y, face->root.units_per_EM );
+
+      metrics->x_ppem  = (FT_UShort)( dim_x >> 6 );
+      metrics->y_ppem  = (FT_UShort)( dim_y >> 6 );
+    }
+
+    size->ttmetrics.valid = FALSE;
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+    size->strike_index    = 0xFFFF;
+#endif
+
+    return tt_size_reset( size );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Set_Pixel_Sizes                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A driver method used to reset a size's character sizes (horizontal */
+  /*    and vertical) expressed in integer pixels.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    pixel_width  :: The character width expressed in integer pixels.   */
+  /*                                                                       */
+  /*    pixel_height :: The character height expressed in integer pixels.  */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    size         :: A handle to the target size object.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Set_Pixel_Sizes( TT_Size  size,
+                   FT_UInt  pixel_width,
+                   FT_UInt  pixel_height )
+  {
+    FT_UNUSED( pixel_width );
+    FT_UNUSED( pixel_height );
+
+    /* many things have been pre-computed by the base layer */
+
+    size->ttmetrics.valid = FALSE;
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+    size->strike_index    = 0xFFFF;
+#endif
+
+    return tt_size_reset( size );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Load_Glyph                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A driver method used to load a glyph within a given glyph slot.    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    slot        :: A handle to the target slot object where the glyph  */
+  /*                   will be loaded.                                     */
+  /*                                                                       */
+  /*    size        :: A handle to the source face size at which the glyph */
+  /*                   must be scaled, loaded, etc.                        */
+  /*                                                                       */
+  /*    glyph_index :: The index of the glyph in the font file.            */
+  /*                                                                       */
+  /*    load_flags  :: A flag indicating what to load for this glyph.  The */
+  /*                   FTLOAD_??? constants can be used to control the     */
+  /*                   glyph loading process (e.g., whether the outline    */
+  /*                   should be scaled, whether to load bitmaps or not,   */
+  /*                   whether to hint the outline, etc).                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Load_Glyph( TT_GlyphSlot  slot,
+              TT_Size       size,
+              FT_UShort     glyph_index,
+              FT_Int32      load_flags )
+  {
+    FT_Error  error;
+
+
+    if ( !slot )
+      return TT_Err_Invalid_Slot_Handle;
+
+    /* check whether we want a scaled outline or bitmap */
+    if ( !size )
+      load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+
+    if ( load_flags & FT_LOAD_NO_SCALE )
+      size = NULL;
+
+    /* reset the size object if necessary */
+    if ( size )
+    {
+      /* these two object must have the same parent */
+      if ( size->root.face != slot->face )
+        return TT_Err_Invalid_Face_Handle;
+
+      if ( !size->ttmetrics.valid )
+      {
+        if ( FT_SET_ERROR( tt_size_reset( size ) ) )
+          return error;
+      }
+    }
+
+    /* now load the glyph outline if necessary */
+    error = TT_Load_Glyph( size, slot, glyph_index, load_flags );
+
+    /* force drop-out mode to 2 - irrelevant now */
+    /* slot->outline.dropout_mode = 2; */
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                D R I V E R  I N T E R F A C E                   ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static FT_Module_Interface
+  tt_get_interface( TT_Driver    driver,
+                    const char*  tt_interface )
+  {
+    FT_Module     sfntd = FT_Get_Module( driver->root.root.library,
+                                         "sfnt" );
+    SFNT_Service  sfnt;
+
+
+    /* only return the default interface from the SFNT module */
+    if ( sfntd )
+    {
+      sfnt = (SFNT_Service)( sfntd->clazz->module_interface );
+      if ( sfnt )
+        return sfnt->get_interface( FT_MODULE( driver ), tt_interface );
+    }
+
+    return 0;
+  }
+
+
+  /* The FT_DriverInterface structure is defined in ftdriver.h. */
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  tt_driver_class =
+  {
+    {
+      ft_module_font_driver     |
+      ft_module_driver_scalable |
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+      ft_module_driver_has_hinter,
+#else
+      0,
+#endif
+
+      sizeof ( TT_DriverRec ),
+
+      "truetype",      /* driver name                           */
+      0x10000L,        /* driver version == 1.0                 */
+      0x20000L,        /* driver requires FreeType 2.0 or above */
+
+      (void*)0,        /* driver specific interface */
+
+      (FT_Module_Constructor)tt_driver_init,
+      (FT_Module_Destructor) tt_driver_done,
+      (FT_Module_Requester)  tt_get_interface,
+    },
+
+    sizeof ( TT_FaceRec ),
+    sizeof ( TT_SizeRec ),
+    sizeof ( FT_GlyphSlotRec ),
+
+
+    (FT_Face_InitFunc)        tt_face_init,
+    (FT_Face_DoneFunc)        tt_face_done,
+    (FT_Size_InitFunc)        tt_size_init,
+    (FT_Size_DoneFunc)        tt_size_done,
+    (FT_Slot_InitFunc)        0,
+    (FT_Slot_DoneFunc)        0,
+
+    (FT_Size_ResetPointsFunc) Set_Char_Sizes,
+    (FT_Size_ResetPixelsFunc) Set_Pixel_Sizes,
+    (FT_Slot_LoadFunc)        Load_Glyph,
+
+    (FT_Face_GetKerningFunc)  Get_Kerning,
+    (FT_Face_AttachFunc)      0,
+    (FT_Face_GetAdvancesFunc) 0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttdriver.h
@@ -1,0 +1,38 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttdriver.h                                                             */
+/*                                                                         */
+/*    High-level TrueType driver interface (specification).                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTDRIVER_H__
+#define __TTDRIVER_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Driver_ClassRec )  tt_driver_class;
+
+
+FT_END_HEADER
+
+#endif /* __TTDRIVER_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/tterrors.h
@@ -1,0 +1,40 @@
+/***************************************************************************/
+/*                                                                         */
+/*  tterrors.h                                                             */
+/*                                                                         */
+/*    TrueType error codes (specification only).                           */
+/*                                                                         */
+/*  Copyright 2001 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the TrueType error enumeration            */
+  /* constants.                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __TTERRORS_H__
+#define __TTERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  TT_Err_
+#define FT_ERR_BASE    FT_Mod_Err_TrueType
+
+#include FT_ERRORS_H
+
+#endif /* __TTERRORS_H__ */
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttgload.c
@@ -1,0 +1,1783 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttgload.c                                                              */
+/*                                                                         */
+/*    TrueType Glyph Loader (body).                                        */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_SFNT_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_OUTLINE_H
+
+#include "ttgload.h"
+
+#include "tterrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttgload
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Composite font flags.                                                 */
+  /*                                                                       */
+#define ARGS_ARE_WORDS             0x0001
+#define ARGS_ARE_XY_VALUES         0x0002
+#define ROUND_XY_TO_GRID           0x0004
+#define WE_HAVE_A_SCALE            0x0008
+/* reserved                        0x0010 */
+#define MORE_COMPONENTS            0x0020
+#define WE_HAVE_AN_XY_SCALE        0x0040
+#define WE_HAVE_A_2X2              0x0080
+#define WE_HAVE_INSTR              0x0100
+#define USE_MY_METRICS             0x0200
+#define OVERLAP_COMPOUND           0x0400
+#define SCALED_COMPONENT_OFFSET    0x0800
+#define UNSCALED_COMPONENT_OFFSET  0x1000
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Get_Metrics                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Returns the horizontal or vertical metrics in font units for a     */
+  /*    given glyph.  The metrics are the left side bearing (resp. top     */
+  /*    side bearing) and advance width (resp. advance height).            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    header  :: A pointer to either the horizontal or vertical metrics  */
+  /*               structure.                                              */
+  /*                                                                       */
+  /*    idx     :: The glyph index.                                        */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    bearing :: The bearing, either left side or top side.              */
+  /*                                                                       */
+  /*    advance :: The advance width resp. advance height.                 */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This function will much probably move to another component in the  */
+  /*    near future, but I haven't decided which yet.                      */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  TT_Get_Metrics( TT_HoriHeader*  header,
+                  FT_UInt         idx,
+                  FT_Short*       bearing,
+                  FT_UShort*      advance )
+  {
+    TT_LongMetrics  longs_m;
+    FT_UShort       k = header->number_Of_HMetrics;
+
+
+    if ( k == 0 )
+    {
+      *bearing = *advance = 0;
+      return;
+    }
+
+    if ( idx < (FT_UInt)k )
+    {
+      longs_m  = (TT_LongMetrics )header->long_metrics + idx;
+      *bearing = longs_m->bearing;
+      *advance = longs_m->advance;
+    }
+    else
+    {
+      *bearing = ((TT_ShortMetrics*)header->short_metrics)[idx - k];
+      *advance = ((TT_LongMetrics )header->long_metrics)[k - 1].advance;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Returns the horizontal metrics in font units for a given glyph.  If   */
+  /* `check' is true, take care of monospaced fonts by returning the       */
+  /* advance width maximum.                                                */
+  /*                                                                       */
+  static void
+  Get_HMetrics( TT_Face     face,
+                FT_UInt     idx,
+                FT_Bool     check,
+                FT_Short*   lsb,
+                FT_UShort*  aw )
+  {
+    TT_Get_Metrics( &face->horizontal, idx, lsb, aw );
+
+    if ( check && face->postscript.isFixedPitch )
+      *aw = face->horizontal.advance_Width_Max;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Returns the advance width table for a given pixel size if it is found */
+  /* in the font's `hdmx' table (if any).                                  */
+  /*                                                                       */
+  static FT_Byte*
+  Get_Advance_Widths( TT_Face    face,
+                      FT_UShort  ppem )
+  {
+    FT_UShort  n;
+
+
+    for ( n = 0; n < face->hdmx.num_records; n++ )
+      if ( face->hdmx.records[n].ppem == ppem )
+        return face->hdmx.records[n].widths;
+
+    return NULL;
+  }
+
+
+#define cur_to_org( n, zone ) \
+          FT_MEM_COPY( (zone)->org, (zone)->cur, (n) * sizeof ( FT_Vector ) )
+
+#define org_to_cur( n, zone ) \
+          FT_MEM_COPY( (zone)->cur, (zone)->org, (n) * sizeof ( FT_Vector ) )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Translates an array of coordinates.                                   */
+  /*                                                                       */
+  static void
+  translate_array( FT_UInt     n,
+                   FT_Vector*  coords,
+                   FT_Pos      delta_x,
+                   FT_Pos      delta_y )
+  {
+    FT_UInt  k;
+
+
+    if ( delta_x )
+      for ( k = 0; k < n; k++ )
+        coords[k].x += delta_x;
+
+    if ( delta_y )
+      for ( k = 0; k < n; k++ )
+        coords[k].y += delta_y;
+  }
+
+
+  static void
+  tt_prepare_zone( TT_GlyphZone  zone,
+                   FT_GlyphLoad  load,
+                   FT_UInt       start_point,
+                   FT_UInt       start_contour )
+  {
+    zone->n_points   = (FT_UShort)( load->outline.n_points - start_point );
+    zone->n_contours = (FT_Short) ( load->outline.n_contours - start_contour );
+    zone->org        = load->extra_points + start_point;
+    zone->cur        = load->outline.points + start_point;
+    zone->tags       = (FT_Byte*)load->outline.tags + start_point;
+    zone->contours   = (FT_UShort*)load->outline.contours + start_contour;
+  }
+
+
+#undef  IS_HINTED
+#define IS_HINTED( flags )  ( ( flags & FT_LOAD_NO_HINTING ) == 0 )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The following functions are used by default with TrueType fonts.      */
+  /* However, they can be replaced by alternatives if we need to support   */
+  /* TrueType-compressed formats (like MicroType) in the future.           */
+  /*                                                                       */
+  /*************************************************************************/
+
+  FT_CALLBACK_DEF( FT_Error )
+  TT_Access_Glyph_Frame( TT_Loader  loader,
+                         FT_UInt    glyph_index,
+                         FT_ULong   offset,
+                         FT_UInt    byte_count )
+  {
+    FT_Error   error;
+    FT_Stream  stream = loader->stream;
+
+    /* for non-debug mode */
+    FT_UNUSED( glyph_index );
+
+
+    FT_TRACE5(( "Glyph %ld\n", glyph_index ));
+
+    /* the following line sets the `error' variable through macros! */
+    if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) )
+      return error;
+
+    return TT_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  TT_Forget_Glyph_Frame( TT_Loader  loader )
+  {
+    FT_Stream  stream = loader->stream;
+
+
+    FT_FRAME_EXIT();
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  TT_Load_Glyph_Header( TT_Loader  loader )
+  {
+    FT_Stream  stream   = loader->stream;
+    FT_Int     byte_len = loader->byte_len - 10;
+
+
+    if ( byte_len < 0 )
+      return TT_Err_Invalid_Outline;
+
+    loader->n_contours = FT_GET_SHORT();
+
+    loader->bbox.xMin = FT_GET_SHORT();
+    loader->bbox.yMin = FT_GET_SHORT();
+    loader->bbox.xMax = FT_GET_SHORT();
+    loader->bbox.yMax = FT_GET_SHORT();
+
+    FT_TRACE5(( "  # of contours: %d\n", loader->n_contours ));
+    FT_TRACE5(( "  xMin: %4d  xMax: %4d\n", loader->bbox.xMin,
+                                            loader->bbox.xMax ));
+    FT_TRACE5(( "  yMin: %4d  yMax: %4d\n", loader->bbox.yMin,
+                                            loader->bbox.yMax ));
+    loader->byte_len = byte_len;
+
+    return TT_Err_Ok;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  TT_Load_Simple_Glyph( TT_Loader  load )
+  {
+    FT_Error        error;
+    FT_Stream       stream     = load->stream;
+    FT_GlyphLoader  gloader    = load->gloader;
+    FT_Int          n_contours = load->n_contours;
+    FT_Outline*     outline;
+    TT_Face         face       = (TT_Face)load->face;
+    TT_GlyphSlot    slot       = (TT_GlyphSlot)load->glyph;
+    FT_UShort       n_ins;
+    FT_Int          n, n_points;
+    FT_Int          byte_len   = load->byte_len;
+
+
+    /* reading the contours endpoints & number of points */
+    {
+      short*  cur   = gloader->current.outline.contours;
+      short*  limit = cur + n_contours;
+
+
+      /* check space for contours array + instructions count */
+      byte_len -= 2 * ( n_contours + 1 );
+      if ( byte_len < 0 )
+        goto Invalid_Outline;
+
+      for ( ; cur < limit; cur++ )
+        cur[0] = FT_GET_USHORT();
+
+      n_points = 0;
+      if ( n_contours > 0 )
+        n_points = cur[-1] + 1;
+
+      error = FT_GlyphLoader_CheckPoints( gloader, n_points + 2, 0 );
+      if ( error )
+        goto Fail;
+
+      /* we'd better check the contours table right now */
+      outline = &gloader->current.outline;
+
+      for ( cur = outline->contours + 1; cur < limit; cur++ )
+        if ( cur[-1] >= cur[0] )
+          goto Invalid_Outline;
+    }
+
+    /* reading the bytecode instructions */
+    slot->control_len  = 0;
+    slot->control_data = 0;
+
+    n_ins = FT_GET_USHORT();
+
+    FT_TRACE5(( "  Instructions size: %d\n", n_ins ));
+
+    if ( n_ins > face->max_profile.maxSizeOfInstructions )
+    {
+      FT_TRACE0(( "TT_Load_Simple_Glyph: Too many instructions!\n" ));
+      error = TT_Err_Too_Many_Hints;
+      goto Fail;
+    }
+
+    byte_len -= n_ins;
+    if ( byte_len < 0 )
+    {
+      FT_TRACE0(( "TT_Load_Simple_Glyph: Instruction count mismatch!\n" ));
+      error = TT_Err_Too_Many_Hints;
+      goto Fail;
+    }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    if ( ( load->load_flags                        &
+         ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) ) == 0 &&
+           load->instructions )
+    {
+      slot->control_len  = n_ins;
+      slot->control_data = load->instructions;
+
+      FT_MEM_COPY( load->instructions, stream->cursor, n_ins );
+    }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    stream->cursor += n_ins;
+
+    /* reading the point tags */
+    {
+      FT_Byte*  flag  = (FT_Byte*)outline->tags;
+      FT_Byte*  limit = flag + n_points;
+      FT_Byte   c, count;
+
+
+      while ( flag < limit )
+      {
+        if ( --byte_len < 0 )
+          goto Invalid_Outline;
+
+        *flag++ = c = FT_GET_BYTE();
+        if ( c & 8 )
+        {
+          if ( --byte_len < 0 )
+            goto Invalid_Outline;
+
+          count = FT_GET_BYTE();
+          if ( flag + count > limit )
+            goto Invalid_Outline;
+
+          for ( ; count > 0; count-- )
+            *flag++ = c;
+        }
+      }
+
+      /* check that there is enough room to load the coordinates */
+      for ( flag = (FT_Byte*)outline->tags; flag < limit; flag++ )
+      {
+        if ( *flag & 2 )
+          byte_len -= 1;
+        else if ( ( *flag & 16 ) == 0 )
+          byte_len -= 2;
+
+        if ( *flag & 4 )
+          byte_len -= 1;
+        else if ( ( *flag & 32 ) == 0 )
+          byte_len -= 2;
+      }
+
+      if ( byte_len < 0 )
+        goto Invalid_Outline;
+    }
+
+    /* reading the X coordinates */
+
+    {
+      FT_Vector*  vec   = outline->points;
+      FT_Vector*  limit = vec + n_points;
+      FT_Byte*    flag  = (FT_Byte*)outline->tags;
+      FT_Pos      x     = 0;
+
+
+      for ( ; vec < limit; vec++, flag++ )
+      {
+        FT_Pos  y = 0;
+
+
+        if ( *flag & 2 )
+        {
+          y = FT_GET_BYTE();
+          if ( ( *flag & 16 ) == 0 )
+            y = -y;
+        }
+        else if ( ( *flag & 16 ) == 0 )
+          y = FT_GET_SHORT();
+
+        x     += y;
+        vec->x = x;
+      }
+    }
+
+    /* reading the Y coordinates */
+
+    {
+      FT_Vector*  vec   = gloader->current.outline.points;
+      FT_Vector*  limit = vec + n_points;
+      FT_Byte*    flag  = (FT_Byte*)outline->tags;
+      FT_Pos      x     = 0;
+
+
+      for ( ; vec < limit; vec++, flag++ )
+      {
+        FT_Pos  y = 0;
+
+
+        if ( *flag & 4 )
+        {
+          y = FT_GET_BYTE();
+          if ( ( *flag & 32 ) == 0 )
+            y = -y;
+        }
+        else if ( ( *flag & 32 ) == 0 )
+          y = FT_GET_SHORT();
+
+        x     += y;
+        vec->y = x;
+      }
+    }
+
+    /* clear the touch tags */
+    for ( n = 0; n < n_points; n++ )
+      outline->tags[n] &= FT_CURVE_TAG_ON;
+
+    outline->n_points   = (FT_UShort)n_points;
+    outline->n_contours = (FT_Short) n_contours;
+
+    load->byte_len = byte_len;
+
+  Fail:
+    return error;
+
+  Invalid_Outline:
+    error = TT_Err_Invalid_Outline;
+    goto Fail;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  TT_Load_Composite_Glyph( TT_Loader  loader )
+  {
+    FT_Error        error;
+    FT_Stream       stream  = loader->stream;
+    FT_GlyphLoader  gloader = loader->gloader;
+    FT_SubGlyph     subglyph;
+    FT_UInt         num_subglyphs;
+    FT_Int          byte_len = loader->byte_len;
+
+
+    num_subglyphs = 0;
+
+    do
+    {
+      FT_Fixed  xx, xy, yy, yx;
+
+
+      /* check that we can load a new subglyph */
+      error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 );
+      if ( error )
+        goto Fail;
+
+      /* check space */
+      byte_len -= 4;
+      if ( byte_len < 0 )
+        goto Invalid_Composite;
+
+      subglyph = gloader->current.subglyphs + num_subglyphs;
+
+      subglyph->arg1 = subglyph->arg2 = 0;
+
+      subglyph->flags = FT_GET_USHORT();
+      subglyph->index = FT_GET_USHORT();
+
+      /* check space */
+      byte_len -= 2;
+      if ( subglyph->flags & ARGS_ARE_WORDS )
+        byte_len -= 2;
+      if ( subglyph->flags & WE_HAVE_A_SCALE )
+        byte_len -= 2;
+      else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
+        byte_len -= 4;
+      else if ( subglyph->flags & WE_HAVE_A_2X2 )
+        byte_len -= 8;
+
+      if ( byte_len < 0 )
+        goto Invalid_Composite;
+
+      /* read arguments */
+      if ( subglyph->flags & ARGS_ARE_WORDS )
+      {
+        subglyph->arg1 = FT_GET_SHORT();
+        subglyph->arg2 = FT_GET_SHORT();
+      }
+      else
+      {
+        subglyph->arg1 = FT_GET_CHAR();
+        subglyph->arg2 = FT_GET_CHAR();
+      }
+
+      /* read transform */
+      xx = yy = 0x10000L;
+      xy = yx = 0;
+
+      if ( subglyph->flags & WE_HAVE_A_SCALE )
+      {
+        xx = (FT_Fixed)FT_GET_SHORT() << 2;
+        yy = xx;
+      }
+      else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
+      {
+        xx = (FT_Fixed)FT_GET_SHORT() << 2;
+        yy = (FT_Fixed)FT_GET_SHORT() << 2;
+      }
+      else if ( subglyph->flags & WE_HAVE_A_2X2 )
+      {
+        xx = (FT_Fixed)FT_GET_SHORT() << 2;
+        yx = (FT_Fixed)FT_GET_SHORT() << 2;
+        xy = (FT_Fixed)FT_GET_SHORT() << 2;
+        yy = (FT_Fixed)FT_GET_SHORT() << 2;
+      }
+
+      subglyph->transform.xx = xx;
+      subglyph->transform.xy = xy;
+      subglyph->transform.yx = yx;
+      subglyph->transform.yy = yy;
+
+      num_subglyphs++;
+
+    } while ( subglyph->flags & MORE_COMPONENTS );
+
+    gloader->current.num_subglyphs = num_subglyphs;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+    {
+      /* we must undo the FT_FRAME_ENTER in order to point to the */
+      /* composite instructions, if we find some.               */
+      /* we will process them later...                          */
+      /*                                                        */
+      loader->ins_pos = (FT_ULong)( FT_STREAM_POS() +
+                                    stream->cursor - stream->limit );
+    }
+#endif
+
+    loader->byte_len = byte_len;
+
+  Fail:
+    return error;
+
+  Invalid_Composite:
+    error = TT_Err_Invalid_Composite;
+    goto Fail;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  TT_Init_Glyph_Loading( TT_Face  face )
+  {
+    face->access_glyph_frame   = TT_Access_Glyph_Frame;
+    face->read_glyph_header    = TT_Load_Glyph_Header;
+    face->read_simple_glyph    = TT_Load_Simple_Glyph;
+    face->read_composite_glyph = TT_Load_Composite_Glyph;
+    face->forget_glyph_frame   = TT_Forget_Glyph_Frame;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Process_Simple_Glyph                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Once a simple glyph has been loaded, it needs to be processed.     */
+  /*    Usually, this means scaling and hinting through bytecode           */
+  /*    interpretation.                                                    */
+  /*                                                                       */
+  static FT_Error
+  TT_Process_Simple_Glyph( TT_Loader  load,
+                           FT_Bool    debug )
+  {
+    FT_GlyphLoader  gloader  = load->gloader;
+    FT_Outline*     outline  = &gloader->current.outline;
+    FT_UInt         n_points = outline->n_points;
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+    FT_UInt         n_ins;
+#endif
+    TT_GlyphZone    zone     = &load->zone;
+    FT_Error        error    = TT_Err_Ok;
+
+    FT_UNUSED( debug );  /* used by truetype interpreter only */
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+    n_ins = load->glyph->control_len;
+#endif
+
+    /* add shadow points */
+
+    /* Now add the two shadow points at n and n + 1.    */
+    /* We need the left side bearing and advance width. */
+
+    {
+      FT_Vector*  pp1;
+      FT_Vector*  pp2;
+
+
+      /* pp1 = xMin - lsb */
+      pp1    = outline->points + n_points;
+      pp1->x = load->bbox.xMin - load->left_bearing;
+      pp1->y = 0;
+
+      /* pp2 = pp1 + aw */
+      pp2    = pp1 + 1;
+      pp2->x = pp1->x + load->advance;
+      pp2->y = 0;
+
+      outline->tags[n_points    ] = 0;
+      outline->tags[n_points + 1] = 0;
+    }
+
+    /* Note that we return two more points that are not */
+    /* part of the glyph outline.                       */
+
+    n_points += 2;
+
+    /* set up zone for hinting */
+    tt_prepare_zone( zone, &gloader->current, 0, 0 );
+
+    /* eventually scale the glyph */
+    if ( !( load->load_flags & FT_LOAD_NO_SCALE ) )
+    {
+      FT_Vector*  vec     = zone->cur;
+      FT_Vector*  limit   = vec + n_points;
+      FT_Fixed    x_scale = load->size->metrics.x_scale;
+      FT_Fixed    y_scale = load->size->metrics.y_scale;
+
+
+      /* first scale the glyph points */
+      for ( ; vec < limit; vec++ )
+      {
+        vec->x = FT_MulFix( vec->x, x_scale );
+        vec->y = FT_MulFix( vec->y, y_scale );
+      }
+    }
+
+    cur_to_org( n_points, zone );
+
+    /* eventually hint the glyph */
+    if ( IS_HINTED( load->load_flags ) )
+    {
+      FT_Pos  x = zone->org[n_points-2].x;
+
+
+      x = ( ( x + 32 ) & -64 ) - x;
+      translate_array( n_points, zone->org, x, 0 );
+
+      org_to_cur( n_points, zone );
+
+      zone->cur[n_points - 1].x = ( zone->cur[n_points - 1].x + 32 ) & -64;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+      /* now consider hinting */
+      if ( n_ins > 0 )
+      {
+        error = TT_Set_CodeRange( load->exec, tt_coderange_glyph,
+                                  load->exec->glyphIns, n_ins );
+        if ( error )
+          goto Exit;
+
+        load->exec->is_composite     = FALSE;
+        load->exec->pedantic_hinting = (FT_Bool)( load->load_flags &
+                                                  FT_LOAD_PEDANTIC );
+        load->exec->pts              = *zone;
+        load->exec->pts.n_points    += 2;
+
+        error = TT_Run_Context( load->exec, debug );
+        if ( error && load->exec->pedantic_hinting )
+          goto Exit;
+
+        error = TT_Err_Ok;  /* ignore bytecode errors in non-pedantic mode */
+      }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    }
+
+    /* save glyph phantom points */
+    if ( !load->preserve_pps )
+    {
+      load->pp1 = zone->cur[n_points - 2];
+      load->pp2 = zone->cur[n_points - 1];
+    }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+  Exit:
+#endif
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    load_truetype_glyph                                                */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads a given truetype glyph.  Handles composites and uses a       */
+  /*    TT_Loader object.                                                  */
+  /*                                                                       */
+  static FT_Error
+  load_truetype_glyph( TT_Loader  loader,
+                       FT_UInt    glyph_index )
+  {
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+    FT_Stream       stream = loader->stream;
+#endif
+
+    FT_Error        error;
+    TT_Face         face   = (TT_Face)loader->face;
+    FT_ULong        offset;
+    FT_Int          contours_count;
+    FT_UInt         num_points, count;
+    FT_Fixed        x_scale, y_scale;
+    FT_GlyphLoader  gloader = loader->gloader;
+    FT_Bool         opened_frame = 0;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    struct FT_StreamRec_  inc_stream;
+    FT_Data               glyph_data;
+    FT_Bool               glyph_data_loaded = 0;
+#endif
+
+
+    /* check glyph index */
+    if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
+    {
+      error = TT_Err_Invalid_Glyph_Index;
+      goto Exit;
+    }
+
+    loader->glyph_index = glyph_index;
+    num_points          = 0;
+
+    x_scale = 0x10000L;
+    y_scale = 0x10000L;
+    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+    {
+      x_scale = loader->size->metrics.x_scale;
+      y_scale = loader->size->metrics.y_scale;
+    }
+
+    /* get horizontal metrics */
+    {
+      FT_Short   left_bearing = 0;
+      FT_UShort  advance_width = 0;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+      FT_Bool    metrics_found = FALSE;
+
+
+      /* If this is an incrementally loaded font see if there are */
+      /* overriding metrics for this glyph.                       */
+      if ( face->root.internal->incremental_interface &&
+           face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+      {
+        FT_Incremental_MetricsRec  m;
+
+
+        error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+                  face->root.internal->incremental_interface->object,
+                  glyph_index, FALSE, &m, &metrics_found );
+        if ( error )
+          goto Exit;
+        left_bearing  = (FT_Short)m.bearing_x;
+        advance_width = (FT_UShort)m.advance;
+      }
+
+      if ( !metrics_found )
+        Get_HMetrics( face, glyph_index,
+                      (FT_Bool)!( loader->load_flags &
+                                  FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ),
+                      &left_bearing,
+                      &advance_width );
+
+#else
+
+      Get_HMetrics( face, glyph_index,
+                    (FT_Bool)!( loader->load_flags &
+                                FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ),
+                    &left_bearing,
+                    &advance_width );
+
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+      loader->left_bearing = left_bearing;
+      loader->advance      = advance_width;
+
+      if ( !loader->linear_def )
+      {
+        loader->linear_def = 1;
+        loader->linear     = advance_width;
+      }
+    }
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    /* Set `offset' to the start of the glyph program relative to the  */
+    /* start of the 'glyf' table, and `count' to the length of the     */
+    /* glyph program in bytes.                                         */
+    /*                                                                 */
+    /* If we are loading glyph data via the incremental interface, set */
+    /* the loader stream to a memory stream reading the data returned  */
+    /* by the interface.                                               */
+
+    if ( face->root.internal->incremental_interface )
+    {
+      error = face->root.internal->incremental_interface->funcs->get_glyph_data(
+                face->root.internal->incremental_interface->object,
+                glyph_index, &glyph_data );
+      if ( error )
+        goto Exit;
+
+      glyph_data_loaded = 1;
+      offset            = 0;
+      count             = glyph_data.length;
+
+      FT_MEM_ZERO( &inc_stream, sizeof ( inc_stream ) );
+      FT_Stream_OpenMemory( &inc_stream,
+                            glyph_data.pointer, glyph_data.length );
+
+      loader->stream = &inc_stream;
+    }
+    else
+
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+    {
+      offset = face->glyph_locations[glyph_index];
+      count  = 0;
+
+      if ( glyph_index < (FT_UInt)face->num_locations - 1 )
+        count = face->glyph_locations[glyph_index + 1] - offset;
+    }
+
+    if ( count == 0 )
+    {
+      /* as described by Frederic Loyer, these are spaces, and */
+      /* not the unknown glyph.                                */
+      loader->bbox.xMin = 0;
+      loader->bbox.xMax = 0;
+      loader->bbox.yMin = 0;
+      loader->bbox.yMax = 0;
+
+      loader->pp1.x = 0;
+      loader->pp2.x = loader->advance;
+
+      if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+        loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+      if ( loader->exec )
+        loader->exec->glyphSize = 0;
+
+#endif
+
+      error = TT_Err_Ok;
+      goto Exit;
+    }
+
+    loader->byte_len = (FT_Int)count;
+
+    offset = loader->glyf_offset + offset;
+
+    /* access glyph frame */
+    error = face->access_glyph_frame( loader, glyph_index, offset, count );
+    if ( error )
+      goto Exit;
+
+    opened_frame = 1;
+
+    /* read first glyph header */
+    error = face->read_glyph_header( loader );
+    if ( error )
+      goto Fail;
+
+    contours_count = loader->n_contours;
+
+    count -= 10;
+
+    loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
+    loader->pp1.y = 0;
+    loader->pp2.x = loader->pp1.x + loader->advance;
+    loader->pp2.y = 0;
+
+    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+    {
+      loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
+      loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
+    }
+
+    /***********************************************************************/
+    /***********************************************************************/
+    /***********************************************************************/
+
+    /* if it is a simple glyph, load it */
+
+    if ( contours_count >= 0 )
+    {
+      /* check that we can add the contours to the glyph */
+      error = FT_GlyphLoader_CheckPoints( gloader, 0, contours_count );
+      if ( error )
+        goto Fail;
+
+      error = face->read_simple_glyph( loader );
+      if ( error )
+        goto Fail;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+      {
+        TT_Size  size = (TT_Size)loader->size;
+
+
+        error = TT_Process_Simple_Glyph( loader,
+                                         (FT_Bool)( size && size->debug ) );
+      }
+
+#else
+
+      error = TT_Process_Simple_Glyph( loader, 0 );
+
+#endif
+
+      if ( error )
+        goto Fail;
+
+      FT_GlyphLoader_Add( gloader );
+
+      /* Note: We could have put the simple loader source there */
+      /*       but the code is fat enough already :-)           */
+    }
+
+    /***********************************************************************/
+    /***********************************************************************/
+    /***********************************************************************/
+
+    /* otherwise, load a composite! */
+    else
+    {
+      TT_GlyphSlot  glyph = (TT_GlyphSlot)loader->glyph;
+      FT_UInt       start_point;
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+      FT_UInt       start_contour;
+      FT_ULong      ins_pos;  /* position of composite instructions, if any */
+#endif
+
+
+      /* for each subglyph, read composite header */
+      start_point   = gloader->base.outline.n_points;
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+      start_contour = gloader->base.outline.n_contours;
+#endif
+
+      error = face->read_composite_glyph( loader );
+      if ( error )
+        goto Fail;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+      ins_pos = loader->ins_pos;
+#endif
+      face->forget_glyph_frame( loader );
+      opened_frame = 0;
+
+      /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
+      /* `as is' in the glyph slot (the client application will be     */
+      /* responsible for interpreting these data)...                   */
+      /*                                                               */
+      if ( loader->load_flags & FT_LOAD_NO_RECURSE )
+      {
+        /* set up remaining glyph fields */
+        FT_GlyphLoader_Add( gloader );
+
+        glyph->num_subglyphs = gloader->base.num_subglyphs;
+        glyph->format        = FT_GLYPH_FORMAT_COMPOSITE;
+        glyph->subglyphs     = gloader->base.subglyphs;
+
+        goto Exit;
+      }
+
+      /*********************************************************************/
+      /*********************************************************************/
+      /*********************************************************************/
+
+      /* Now, read each subglyph independently. */
+      {
+        FT_Int       n, num_base_points, num_new_points;
+        FT_SubGlyph  subglyph       = 0;
+
+        FT_UInt      num_subglyphs  = gloader->current.num_subglyphs;
+        FT_UInt      num_base_subgs = gloader->base.num_subglyphs;
+
+
+        FT_GlyphLoader_Add( gloader );
+
+        for ( n = 0; n < (FT_Int)num_subglyphs; n++ )
+        {
+          FT_Vector  pp1, pp2;
+          FT_Pos     x, y;
+
+
+          /* Each time we call load_truetype_glyph in this loop, the   */
+          /* value of `gloader.base.subglyphs' can change due to table */
+          /* reallocations.  We thus need to recompute the subglyph    */
+          /* pointer on each iteration.                                */
+          subglyph = gloader->base.subglyphs + num_base_subgs + n;
+
+          pp1 = loader->pp1;
+          pp2 = loader->pp2;
+
+          num_base_points = gloader->base.outline.n_points;
+
+          error = load_truetype_glyph( loader, subglyph->index );
+          if ( error )
+            goto Fail;
+
+          /* restore subglyph pointer */
+          subglyph = gloader->base.subglyphs + num_base_subgs + n;
+
+          if ( subglyph->flags & USE_MY_METRICS )
+          {
+            pp1 = loader->pp1;
+            pp2 = loader->pp2;
+          }
+          else
+          {
+            loader->pp1 = pp1;
+            loader->pp2 = pp2;
+          }
+
+          num_points = gloader->base.outline.n_points;
+
+          num_new_points = num_points - num_base_points;
+
+          /* now perform the transform required for this subglyph */
+
+          if ( subglyph->flags & ( WE_HAVE_A_SCALE     |
+                                   WE_HAVE_AN_XY_SCALE |
+                                   WE_HAVE_A_2X2       ) )
+          {
+            FT_Vector*  cur   = gloader->base.outline.points +
+                                  num_base_points;
+            FT_Vector*  org   = gloader->base.extra_points +
+                                  num_base_points;
+            FT_Vector*  limit = cur + num_new_points;
+
+
+            for ( ; cur < limit; cur++, org++ )
+            {
+              FT_Vector_Transform( cur, &subglyph->transform );
+              FT_Vector_Transform( org, &subglyph->transform );
+            }
+          }
+
+          /* apply offset */
+
+          if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
+          {
+            FT_UInt     k = subglyph->arg1;
+            FT_UInt     l = subglyph->arg2;
+            FT_Vector*  p1;
+            FT_Vector*  p2;
+
+
+            if ( start_point + k >= (FT_UInt)num_base_points ||
+                               l >= (FT_UInt)num_new_points  )
+            {
+              error = TT_Err_Invalid_Composite;
+              goto Fail;
+            }
+
+            l += num_base_points;
+
+            p1 = gloader->base.outline.points + start_point + k;
+            p2 = gloader->base.outline.points + start_point + l;
+
+            x = p1->x - p2->x;
+            y = p1->y - p2->y;
+          }
+          else
+          {
+            x = subglyph->arg1;
+            y = subglyph->arg2;
+
+  /* Use a default value dependent on                                     */
+  /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED.  This is useful for old TT */
+  /* fonts which don't set the xxx_COMPONENT_OFFSET bit.                  */
+
+#ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
+            if ( !( subglyph->flags & UNSCALED_COMPONENT_OFFSET ) &&
+#else
+            if (  ( subglyph->flags & SCALED_COMPONENT_OFFSET ) &&
+#endif
+                  ( subglyph->flags & ( WE_HAVE_A_SCALE     |
+                                        WE_HAVE_AN_XY_SCALE |
+                                        WE_HAVE_A_2X2       )) )
+            {
+#if 0
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This algorithm is what Apple documents.  But it doesn't work.         */
+  /*                                                                       */
+              int  a = subglyph->transform.xx > 0 ?  subglyph->transform.xx
+                                                  : -subglyph->transform.xx;
+              int  b = subglyph->transform.yx > 0 ?  subglyph->transform.yx
+                                                  : -subglyph->transform.yx;
+              int  c = subglyph->transform.xy > 0 ?  subglyph->transform.xy
+                                                  : -subglyph->transform.xy;
+              int  d = subglyph->transform.yy > 0 ? subglyph->transform.yy
+                                                  : -subglyph->transform.yy;
+              int  m = a > b ? a : b;
+              int  n = c > d ? c : d;
+
+
+              if ( a - b <= 33 && a - b >= -33 )
+                m *= 2;
+              if ( c - d <= 33 && c - d >= -33 )
+                n *= 2;
+              x = FT_MulFix( x, m );
+              y = FT_MulFix( y, n );
+
+#else /* 0 */
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This algorithm is a guess and works much better than the above.       */
+  /*                                                                       */
+              int  mac_xscale = FT_SqrtFixed(
+                                  FT_MulFix( subglyph->transform.xx,
+                                             subglyph->transform.xx ) +
+                                  FT_MulFix( subglyph->transform.xy,
+                                             subglyph->transform.xy) );
+              int  mac_yscale = FT_SqrtFixed(
+                                  FT_MulFix( subglyph->transform.yy,
+                                             subglyph->transform.yy ) +
+                                  FT_MulFix( subglyph->transform.yx,
+                                             subglyph->transform.yx ) );
+
+
+              x = FT_MulFix( x, mac_xscale );
+              y = FT_MulFix( y, mac_yscale );
+#endif /* 0 */
+
+            }
+
+            if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
+            {
+              x = FT_MulFix( x, x_scale );
+              y = FT_MulFix( y, y_scale );
+
+              if ( subglyph->flags & ROUND_XY_TO_GRID )
+              {
+                x = ( x + 32 ) & -64;
+                y = ( y + 32 ) & -64;
+              }
+            }
+          }
+
+          if ( x || y )
+          {
+            translate_array( num_new_points,
+                             gloader->base.outline.points + num_base_points,
+                             x, y );
+
+            translate_array( num_new_points,
+                             gloader->base.extra_points + num_base_points,
+                             x, y );
+          }
+        }
+
+        /*******************************************************************/
+        /*******************************************************************/
+        /*******************************************************************/
+
+        /* we have finished loading all sub-glyphs; now, look for */
+        /* instructions for this composite!                       */
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+        if ( num_subglyphs > 0               &&
+             loader->exec                    &&
+             ins_pos > 0                     &&
+             subglyph->flags & WE_HAVE_INSTR )
+        {
+          FT_UShort       n_ins;
+          TT_ExecContext  exec = loader->exec;
+          TT_GlyphZone    pts;
+          FT_Vector*      pp1;
+
+
+          /* read size of instructions */
+          if ( FT_STREAM_SEEK( ins_pos ) ||
+               FT_READ_USHORT( n_ins ) )
+            goto Fail;
+          FT_TRACE5(( "  Instructions size = %d\n", n_ins ));
+
+          /* in some fonts? */
+          if ( n_ins == 0xFFFFU )
+            n_ins = 0;
+
+          /* check it */
+          if ( n_ins > face->max_profile.maxSizeOfInstructions )
+          {
+            FT_TRACE0(( "Too many instructions (%d) in composite glyph %ld\n",
+                        n_ins, subglyph->index ));
+            error = TT_Err_Too_Many_Hints;
+            goto Fail;
+          }
+
+          /* read the instructions */
+          if ( FT_STREAM_READ( exec->glyphIns, n_ins ) )
+            goto Fail;
+
+          glyph->control_data = exec->glyphIns;
+          glyph->control_len  = n_ins;
+
+          error = TT_Set_CodeRange( exec,
+                                    tt_coderange_glyph,
+                                    exec->glyphIns,
+                                    n_ins );
+          if ( error )
+            goto Fail;
+
+          /* prepare the execution context */
+          tt_prepare_zone( &exec->pts, &gloader->base,
+                           start_point, start_contour );
+          pts = &exec->pts;
+
+          pts->n_points   = (short)(num_points + 2);
+          pts->n_contours = gloader->base.outline.n_contours;
+
+          /* add phantom points */
+          pp1    = pts->cur + num_points;
+          pp1[0] = loader->pp1;
+          pp1[1] = loader->pp2;
+
+          pts->tags[num_points    ] = 0;
+          pts->tags[num_points + 1] = 0;
+
+          /* if hinting, round the phantom points */
+          if ( IS_HINTED( loader->load_flags ) )
+          {
+            pp1[0].x = ( ( loader->pp1.x + 32 ) & -64 );
+            pp1[1].x = ( ( loader->pp2.x + 32 ) & -64 );
+          }
+
+          {
+            FT_UInt  k;
+
+
+            for ( k = 0; k < num_points; k++ )
+              pts->tags[k] &= FT_CURVE_TAG_ON;
+          }
+
+          cur_to_org( num_points + 2, pts );
+
+          /* now consider hinting */
+          if ( IS_HINTED( loader->load_flags ) && n_ins > 0 )
+          {
+            exec->is_composite     = TRUE;
+            exec->pedantic_hinting =
+              (FT_Bool)( loader->load_flags & FT_LOAD_PEDANTIC );
+
+            error = TT_Run_Context( exec, ((TT_Size)loader->size)->debug );
+            if ( error && exec->pedantic_hinting )
+              goto Fail;
+          }
+
+          /* save glyph origin and advance points */
+          loader->pp1 = pp1[0];
+          loader->pp2 = pp1[1];
+        }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+      }
+      /* end of composite loading */
+    }
+
+    /***********************************************************************/
+    /***********************************************************************/
+    /***********************************************************************/
+
+  Fail:
+    if ( opened_frame )
+      face->forget_glyph_frame( loader );
+
+  Exit:
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+    if ( glyph_data_loaded )
+      face->root.internal->incremental_interface->funcs->free_glyph_data(
+        face->root.internal->incremental_interface->object,
+        &glyph_data );
+#endif
+
+    return error;
+  }
+
+
+  static FT_Error
+  compute_glyph_metrics( TT_Loader   loader,
+                         FT_UInt     glyph_index )
+  {
+    FT_BBox       bbox;
+    TT_Face       face = (TT_Face)loader->face;
+    FT_Fixed      y_scale;
+    TT_GlyphSlot  glyph = loader->glyph;
+    TT_Size       size = (TT_Size)loader->size;
+
+
+    y_scale = 0x10000L;
+    if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
+      y_scale = size->root.metrics.y_scale;
+
+    if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE )
+    {
+      glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS;
+
+      /* copy outline to our glyph slot */
+      FT_GlyphLoader_CopyPoints( glyph->internal->loader, loader->gloader );
+      glyph->outline = glyph->internal->loader->base.outline;
+
+      /* translate array so that (0,0) is the glyph's origin */
+      FT_Outline_Translate( &glyph->outline, -loader->pp1.x, 0 );
+
+      FT_Outline_Get_CBox( &glyph->outline, &bbox );
+
+      if ( IS_HINTED( loader->load_flags ) )
+      {
+        /* grid-fit the bounding box */
+        bbox.xMin &= -64;
+        bbox.yMin &= -64;
+        bbox.xMax  = ( bbox.xMax + 63 ) & -64;
+        bbox.yMax  = ( bbox.yMax + 63 ) & -64;
+      }
+    }
+    else
+      bbox = loader->bbox;
+
+    /* get the device-independent horizontal advance.  It is scaled later */
+    /* by the base layer.                                                 */
+    {
+      FT_Pos  advance = loader->linear;
+
+
+      /* the flag FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH was introduced to */
+      /* correctly support DynaLab fonts, which have an incorrect       */
+      /* `advance_Width_Max' field!  It is used, to my knowledge,       */
+      /* exclusively in the X-TrueType font server.                     */
+      /*                                                                */
+      if ( face->postscript.isFixedPitch                                     &&
+           ( loader->load_flags & FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH ) == 0 )
+        advance = face->horizontal.advance_Width_Max;
+
+      /* we need to return the advance in font units in linearHoriAdvance, */
+      /* it will be scaled later by the base layer.                        */
+      glyph->linearHoriAdvance = advance;
+    }
+
+    glyph->metrics.horiBearingX = bbox.xMin;
+    glyph->metrics.horiBearingY = bbox.yMax;
+    glyph->metrics.horiAdvance  = loader->pp2.x - loader->pp1.x;
+
+    /* don't forget to hint the advance when we need to */
+    if ( IS_HINTED( loader->load_flags ) )
+      glyph->metrics.horiAdvance = ( glyph->metrics.horiAdvance + 32 ) & -64;
+
+    /* Now take care of vertical metrics.  In the case where there is    */
+    /* no vertical information within the font (relatively common), make */
+    /* up some metrics by `hand'...                                      */
+
+    {
+      FT_Short   top_bearing;    /* vertical top side bearing (EM units) */
+      FT_UShort  advance_height; /* vertical advance height   (EM units) */
+
+      FT_Pos     left;     /* scaled vertical left side bearing */
+      FT_Pos     top;      /* scaled vertical top side bearing  */
+      FT_Pos     advance;  /* scaled vertical advance height    */
+      FT_Bool    metrics_found = FALSE;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+      /* If this is an incrementally loaded font see if there are */
+      /* overriding metrics for this glyph.                       */
+      if ( face->root.internal->incremental_interface &&
+           face->root.internal->incremental_interface->funcs->get_glyph_metrics )
+      {
+        FT_Incremental_MetricsRec  m;
+        FT_Error                   error =
+          face->root.internal->incremental_interface->funcs->get_glyph_metrics(
+            face->root.internal->incremental_interface->object,
+            glyph_index, TRUE, &m, &metrics_found );
+
+
+        if ( error )
+          return error;
+
+        top_bearing    = (FT_Short)m.bearing_y;
+        advance_height = (FT_UShort)m.advance;
+      }
+
+#endif /* FT_CONFIG_OPTION_INCREMENTAL */
+
+      /* Get the unscaled top bearing and advance height. */
+      if ( !metrics_found && face->vertical_info &&
+           face->vertical.number_Of_VMetrics > 0 )
+      {
+        /* Don't assume that both the vertical header and vertical */
+        /* metrics are present in the same font :-)                */
+
+        TT_Get_Metrics( (TT_HoriHeader*)&face->vertical,
+                        glyph_index,
+                        &top_bearing,
+                        &advance_height );
+      }
+      else
+      {
+        /* Make up the distances from the horizontal header.   */
+
+        /* NOTE: The OS/2 values are the only `portable' ones, */
+        /*       which is why we use them, if there is an OS/2 */
+        /*       table in the font.  Otherwise, we use the     */
+        /*       values defined in the horizontal header.      */
+        /*                                                     */
+        /* NOTE2: The sTypoDescender is negative, which is why */
+        /*        we compute the baseline-to-baseline distance */
+        /*        here with:                                   */
+        /*             ascender - descender + linegap          */
+        /*                                                     */
+        if ( face->os2.version != 0xFFFFU )
+        {
+          top_bearing    = (FT_Short)( face->os2.sTypoLineGap / 2 );
+          advance_height = (FT_UShort)( face->os2.sTypoAscender -
+                                        face->os2.sTypoDescender +
+                                        face->os2.sTypoLineGap );
+        }
+        else
+        {
+          top_bearing    = (FT_Short)( face->horizontal.Line_Gap / 2 );
+          advance_height = (FT_UShort)( face->horizontal.Ascender  +
+                                        face->horizontal.Descender +
+                                        face->horizontal.Line_Gap );
+        }
+      }
+
+      /* We must adjust the top_bearing value from the bounding box given */
+      /* in the glyph header to te bounding box calculated with           */
+      /* FT_Get_Outline_CBox().                                           */
+
+      /* scale the metrics */
+      if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
+      {
+        top     = FT_MulFix( top_bearing + loader->bbox.yMax, y_scale )
+                    - bbox.yMax;
+        advance = FT_MulFix( advance_height, y_scale );
+      }
+      else
+      {
+        top     = top_bearing + loader->bbox.yMax - bbox.yMax;
+        advance = advance_height;
+      }
+
+      /* set the advance height in design units.  It is scaled later by */
+      /* the base layer.                                                */
+      glyph->linearVertAdvance = advance_height;
+
+      /* XXX: for now, we have no better algorithm for the lsb, but it */
+      /*      should work fine.                                        */
+      /*                                                               */
+      left = ( bbox.xMin - bbox.xMax ) / 2;
+
+      /* grid-fit them if necessary */
+      if ( IS_HINTED( loader->load_flags ) )
+      {
+        left   &= -64;
+        top     = ( top + 63     ) & -64;
+        advance = ( advance + 32 ) & -64;
+      }
+
+      glyph->metrics.vertBearingX = left;
+      glyph->metrics.vertBearingY = top;
+      glyph->metrics.vertAdvance  = advance;
+    }
+
+    /* adjust advance width to the value contained in the hdmx table */
+    if ( !face->postscript.isFixedPitch && size &&
+         IS_HINTED( loader->load_flags )        )
+    {
+      FT_Byte*  widths = Get_Advance_Widths( face,
+                                             size->root.metrics.x_ppem );
+
+
+      if ( widths )
+        glyph->metrics.horiAdvance = widths[glyph_index] << 6;
+    }
+
+    /* set glyph dimensions */
+    glyph->metrics.width  = bbox.xMax - bbox.xMin;
+    glyph->metrics.height = bbox.yMax - bbox.yMin;
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Load_Glyph                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A function used to load a single glyph within a given glyph slot,  */
+  /*    for a given size.                                                  */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    glyph       :: A handle to a target slot object where the glyph    */
+  /*                   will be loaded.                                     */
+  /*                                                                       */
+  /*    size        :: A handle to the source face size at which the glyph */
+  /*                   must be scaled/loaded.                              */
+  /*                                                                       */
+  /*    glyph_index :: The index of the glyph in the font file.            */
+  /*                                                                       */
+  /*    load_flags  :: A flag indicating what to load for this glyph.  The */
+  /*                   FT_LOAD_XXX constants can be used to control the    */
+  /*                   glyph loading process (e.g., whether the outline    */
+  /*                   should be scaled, whether to load bitmaps or not,   */
+  /*                   whether to hint the outline, etc).                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Load_Glyph( TT_Size       size,
+                 TT_GlyphSlot  glyph,
+                 FT_UShort     glyph_index,
+                 FT_Int32      load_flags )
+  {
+    SFNT_Service  sfnt;
+    TT_Face       face;
+    FT_Stream     stream;
+    FT_Error      error;
+    TT_LoaderRec  loader;
+
+
+    face   = (TT_Face)glyph->face;
+    sfnt   = (SFNT_Service)face->sfnt;
+    stream = face->root.stream;
+    error  = 0;
+
+    if ( !size || ( load_flags & FT_LOAD_NO_SCALE )   ||
+                  ( load_flags & FT_LOAD_NO_RECURSE ) )
+    {
+      size        = NULL;
+      load_flags |= FT_LOAD_NO_SCALE   |
+                    FT_LOAD_NO_HINTING |
+                    FT_LOAD_NO_BITMAP;
+    }
+
+    glyph->num_subglyphs = 0;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    /* try to load embedded bitmap if any              */
+    /*                                                 */
+    /* XXX: The convention should be emphasized in     */
+    /*      the documents because it can be confusing. */
+    if ( size                                    &&
+         size->strike_index != 0xFFFFU           &&
+         sfnt->load_sbits                        &&
+         ( load_flags & FT_LOAD_NO_BITMAP ) == 0 )
+
+    {
+      TT_SBit_MetricsRec  metrics;
+
+
+      error = sfnt->load_sbit_image( face,
+                                     size->strike_index,
+                                     glyph_index,
+                                     load_flags,
+                                     stream,
+                                     &glyph->bitmap,
+                                     &metrics );
+      if ( !error )
+      {
+        glyph->outline.n_points   = 0;
+        glyph->outline.n_contours = 0;
+
+        glyph->metrics.width  = (FT_Pos)metrics.width  << 6;
+        glyph->metrics.height = (FT_Pos)metrics.height << 6;
+
+        glyph->metrics.horiBearingX = (FT_Pos)metrics.horiBearingX << 6;
+        glyph->metrics.horiBearingY = (FT_Pos)metrics.horiBearingY << 6;
+        glyph->metrics.horiAdvance  = (FT_Pos)metrics.horiAdvance  << 6;
+
+        glyph->metrics.vertBearingX = (FT_Pos)metrics.vertBearingX << 6;
+        glyph->metrics.vertBearingY = (FT_Pos)metrics.vertBearingY << 6;
+        glyph->metrics.vertAdvance  = (FT_Pos)metrics.vertAdvance  << 6;
+
+        glyph->format = FT_GLYPH_FORMAT_BITMAP;
+        if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
+        {
+          glyph->bitmap_left = metrics.vertBearingX;
+          glyph->bitmap_top  = metrics.vertBearingY;
+        }
+        else
+        {
+          glyph->bitmap_left = metrics.horiBearingX;
+          glyph->bitmap_top  = metrics.horiBearingY;
+        }
+        return error;
+      }
+    }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+    /* return immediately if we only want the embedded bitmaps */
+    if ( load_flags & FT_LOAD_SBITS_ONLY )
+      return FT_Err_Invalid_Argument;
+
+    /* seek to the beginning of the glyph table.  For Type 42 fonts      */
+    /* the table might be accessed from a Postscript stream or something */
+    /* else...                                                           */
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    /* Don't look for the glyph table if this is an incremental font. */
+    if ( !face->root.internal->incremental_interface )
+
+#endif
+
+    {
+      error = face->goto_table( face, TTAG_glyf, stream, 0 );
+      if ( error )
+      {
+        FT_ERROR(( "TT_Load_Glyph: could not access glyph table\n" ));
+        goto Exit;
+      }
+    }
+
+    FT_MEM_ZERO( &loader, sizeof ( loader ) );
+
+    /* update the glyph zone bounds */
+    {
+      FT_GlyphLoader  gloader = FT_FACE_DRIVER(face)->glyph_loader;
+
+
+      loader.gloader = gloader;
+
+      FT_GlyphLoader_Rewind( gloader );
+
+      tt_prepare_zone( &loader.zone, &gloader->base, 0, 0 );
+      tt_prepare_zone( &loader.base, &gloader->base, 0, 0 );
+    }
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    if ( size )
+    {
+      /* query new execution context */
+      loader.exec = size->debug ? size->context : TT_New_Context( face );
+      if ( !loader.exec )
+        return TT_Err_Could_Not_Find_Context;
+
+      TT_Load_Context( loader.exec, face, size );
+      loader.instructions = loader.exec->glyphIns;
+
+      /* load default graphics state - if needed */
+      if ( size->GS.instruct_control & 2 )
+        loader.exec->GS = tt_default_graphics_state;
+    }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    /* clear all outline flags, except the `owner' one */
+    glyph->outline.flags = 0;
+
+    /* let's initialize the rest of our loader now */
+
+    loader.load_flags    = load_flags;
+
+    loader.face   = (FT_Face)face;
+    loader.size   = (FT_Size)size;
+    loader.glyph  = (FT_GlyphSlot)glyph;
+    loader.stream = stream;
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+    if ( face->root.internal->incremental_interface )
+      loader.glyf_offset = 0;
+    else
+
+#endif
+
+      loader.glyf_offset = FT_STREAM_POS();
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    /* if the cvt program has disabled hinting, the argument */
+    /* is ignored.                                           */
+    if ( size && ( size->GS.instruct_control & 1 ) )
+      loader.load_flags |= FT_LOAD_NO_HINTING;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    /* Main loading loop */
+    glyph->format        = FT_GLYPH_FORMAT_OUTLINE;
+    glyph->num_subglyphs = 0;
+
+    error = load_truetype_glyph( &loader, glyph_index );
+    if ( !error )
+      compute_glyph_metrics( &loader, glyph_index );
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    if ( !size || !size->debug )
+      TT_Done_Context( loader.exec );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    /* Set the `high precision' bit flag.                           */
+    /* This is _critical_ to get correct output for monochrome      */
+    /* TrueType glyphs at all sizes using the bytecode interpreter. */
+    /*                                                              */
+    if ( size && size->root.metrics.y_ppem < 24 )
+      glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
+
+  Exit:
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttgload.h
@@ -1,0 +1,55 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttgload.h                                                              */
+/*                                                                         */
+/*    TrueType Glyph Loader (specification).                               */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTGLOAD_H__
+#define __TTGLOAD_H__
+
+
+#include <ft2build.h>
+#include "ttobjs.h"
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.h"
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( void )
+  TT_Get_Metrics( TT_HoriHeader*  header,
+                  FT_UInt         index,
+                  FT_Short*       bearing,
+                  FT_UShort*      advance );
+
+  FT_LOCAL( void )
+  TT_Init_Glyph_Loading( TT_Face  face );
+
+  FT_LOCAL( FT_Error )
+  TT_Load_Glyph( TT_Size       size,
+                 TT_GlyphSlot  glyph,
+                 FT_UShort     glyph_index,
+                 FT_Int32      load_flags );
+
+
+FT_END_HEADER
+
+#endif /* __TTGLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttinterp.c
@@ -1,0 +1,7496 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttinterp.c                                                             */
+/*                                                                         */
+/*    TrueType bytecode interpreter (body).                                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_TRIGONOMETRY_H
+#include FT_SYSTEM_H
+
+#include "ttinterp.h"
+
+#include "tterrors.h"
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+
+#define TT_MULFIX  FT_MulFix
+#define TT_MULDIV  FT_MulDiv
+#define TT_INT64   FT_Int64
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttinterp
+
+#undef  NO_APPLE_PATENT
+#define APPLE_THRESHOLD  0x4000000L
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* In order to detect infinite loops in the code, we set up a counter    */
+  /* within the run loop.  A single stroke of interpretation is now        */
+  /* limitet to a maximal number of opcodes defined below.                 */
+  /*                                                                       */
+#define MAX_RUNNABLE_OPCODES  1000000L
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* There are two kinds of implementations:                               */
+  /*                                                                       */
+  /* a. static implementation                                              */
+  /*                                                                       */
+  /*    The current execution context is a static variable, which fields   */
+  /*    are accessed directly by the interpreter during execution.  The    */
+  /*    context is named `cur'.                                            */
+  /*                                                                       */
+  /*    This version is non-reentrant, of course.                          */
+  /*                                                                       */
+  /* b. indirect implementation                                            */
+  /*                                                                       */
+  /*    The current execution context is passed to _each_ function as its  */
+  /*    first argument, and each field is thus accessed indirectly.        */
+  /*                                                                       */
+  /*    This version is fully re-entrant.                                  */
+  /*                                                                       */
+  /* The idea is that an indirect implementation may be slower to execute  */
+  /* on low-end processors that are used in some systems (like 386s or     */
+  /* even 486s).                                                           */
+  /*                                                                       */
+  /* As a consequence, the indirect implementation is now the default, as  */
+  /* its performance costs can be considered negligible in our context.    */
+  /* Note, however, that we kept the same source with macros because:      */
+  /*                                                                       */
+  /* - The code is kept very close in design to the Pascal code used for   */
+  /*   development.                                                        */
+  /*                                                                       */
+  /* - It's much more readable that way!                                   */
+  /*                                                                       */
+  /* - It's still open to experimentation and tuning.                      */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTERPRETER     /* indirect implementation */
+
+#define CUR  (*exc)                             /* see ttobjs.h */
+
+#else                                           /* static implementation */
+
+#define CUR  cur
+
+  static
+  TT_ExecContextRec  cur;   /* static exec. context variable */
+
+  /* apparently, we have a _lot_ of direct indexing when accessing  */
+  /* the static `cur', which makes the code bigger (due to all the  */
+  /* four bytes addresses).                                         */
+
+#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The instruction argument stack.                                       */
+  /*                                                                       */
+#define INS_ARG  EXEC_OP_ FT_Long*  args    /* see ttobjs.h for EXEC_OP_ */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This macro is used whenever `exec' is unused in a function, to avoid  */
+  /* stupid warnings from pedantic compilers.                              */
+  /*                                                                       */
+#define FT_UNUSED_EXEC  FT_UNUSED( CUR )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This macro is used whenever `args' is unused in a function, to avoid  */
+  /* stupid warnings from pedantic compilers.                              */
+  /*                                                                       */
+#define FT_UNUSED_ARG  FT_UNUSED_EXEC; FT_UNUSED( args )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The following macros hide the use of EXEC_ARG and EXEC_ARG_ to        */
+  /* increase readabilty of the code.                                      */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#define SKIP_Code() \
+          SkipCode( EXEC_ARG )
+
+#define GET_ShortIns() \
+          GetShortIns( EXEC_ARG )
+
+#define NORMalize( x, y, v ) \
+          Normalize( EXEC_ARG_ x, y, v )
+
+#define SET_SuperRound( scale, flags ) \
+          SetSuperRound( EXEC_ARG_ scale, flags )
+
+#define ROUND_None( d, c ) \
+          Round_None( EXEC_ARG_ d, c )
+
+#define INS_Goto_CodeRange( range, ip ) \
+          Ins_Goto_CodeRange( EXEC_ARG_ range, ip )
+
+#define CUR_Func_project( x, y ) \
+          CUR.func_project( EXEC_ARG_ x, y )
+
+#define CUR_Func_move( z, p, d ) \
+          CUR.func_move( EXEC_ARG_ z, p, d )
+
+#define CUR_Func_dualproj( x, y ) \
+          CUR.func_dualproj( EXEC_ARG_ x, y )
+
+#define CUR_Func_freeProj( x, y ) \
+          CUR.func_freeProj( EXEC_ARG_ x, y )
+
+#define CUR_Func_round( d, c ) \
+          CUR.func_round( EXEC_ARG_ d, c )
+
+#define CUR_Func_read_cvt( index ) \
+          CUR.func_read_cvt( EXEC_ARG_ index )
+
+#define CUR_Func_write_cvt( index, val ) \
+          CUR.func_write_cvt( EXEC_ARG_ index, val )
+
+#define CUR_Func_move_cvt( index, val ) \
+          CUR.func_move_cvt( EXEC_ARG_ index, val )
+
+#define CURRENT_Ratio() \
+          Current_Ratio( EXEC_ARG )
+
+#define CURRENT_Ppem() \
+          Current_Ppem( EXEC_ARG )
+
+#define CUR_Ppem() \
+          Cur_PPEM( EXEC_ARG )
+
+#define INS_SxVTL( a, b, c, d ) \
+          Ins_SxVTL( EXEC_ARG_ a, b, c, d )
+
+#define COMPUTE_Funcs() \
+          Compute_Funcs( EXEC_ARG )
+
+#define COMPUTE_Round( a ) \
+          Compute_Round( EXEC_ARG_ a )
+
+#define COMPUTE_Point_Displacement( a, b, c, d ) \
+          Compute_Point_Displacement( EXEC_ARG_ a, b, c, d )
+
+#define MOVE_Zp2_Point( a, b, c, t ) \
+          Move_Zp2_Point( EXEC_ARG_ a, b, c, t )
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Instruction dispatch function, as used by the interpreter.            */
+  /*                                                                       */
+  typedef void  (*TInstruction_Function)( INS_ARG );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* A simple bounds-checking macro.                                       */
+  /*                                                                       */
+#define BOUNDS( x, n )  ( (FT_UInt)(x) >= (FT_UInt)(n) )
+
+
+#undef  SUCCESS
+#define SUCCESS  0
+
+#undef  FAILURE
+#define FAILURE  1
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                        CODERANGE FUNCTIONS                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Goto_CodeRange                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Switches to a new code range (updates the code related elements in */
+  /*    `exec', and `IP').                                                 */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    range :: The new execution code range.                             */
+  /*                                                                       */
+  /*    IP    :: The new IP in the new code range.                         */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    exec  :: The target execution context.                             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Goto_CodeRange( TT_ExecContext  exec,
+                     FT_Int          range,
+                     FT_Long         IP )
+  {
+    TT_CodeRange*  coderange;
+
+
+    FT_ASSERT( range >= 1 && range <= 3 );
+
+    coderange = &exec->codeRangeTable[range - 1];
+
+    FT_ASSERT( coderange->base != NULL );
+
+    /* NOTE: Because the last instruction of a program may be a CALL */
+    /*       which will return to the first byte *after* the code    */
+    /*       range, we test for IP <= Size instead of IP < Size.     */
+    /*                                                               */
+    FT_ASSERT( (FT_ULong)IP <= coderange->size );
+
+    exec->code     = coderange->base;
+    exec->codeSize = coderange->size;
+    exec->IP       = IP;
+    exec->curRange = range;
+
+    return TT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Set_CodeRange                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Sets a code range.                                                 */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    range  :: The code range index.                                    */
+  /*                                                                       */
+  /*    base   :: The new code base.                                       */
+  /*                                                                       */
+  /*    length :: The range size in bytes.                                 */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    exec   :: The target execution context.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Set_CodeRange( TT_ExecContext  exec,
+                    FT_Int          range,
+                    void*           base,
+                    FT_Long         length )
+  {
+    FT_ASSERT( range >= 1 && range <= 3 );
+
+    exec->codeRangeTable[range - 1].base = (FT_Byte*)base;
+    exec->codeRangeTable[range - 1].size = length;
+
+    return TT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Clear_CodeRange                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Clears a code range.                                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    range :: The code range index.                                     */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    exec  :: The target execution context.                             */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Does not set the Error variable.                                   */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Clear_CodeRange( TT_ExecContext  exec,
+                      FT_Int          range )
+  {
+    FT_ASSERT( range >= 1 && range <= 3 );
+
+    exec->codeRangeTable[range - 1].base = NULL;
+    exec->codeRangeTable[range - 1].size = 0;
+
+    return TT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                   EXECUTION CONTEXT ROUTINES                          */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Destroy_Context                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Destroys a given context.                                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    exec   :: A handle to the target execution context.                */
+  /*                                                                       */
+  /*    memory :: A handle to the parent memory object.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only the glyph loader and debugger should call this function.      */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Destroy_Context( TT_ExecContext  exec,
+                      FT_Memory       memory )
+  {
+    /* free composite load stack */
+    FT_FREE( exec->loadStack );
+    exec->loadSize = 0;
+
+    /* points zone */
+    exec->maxPoints   = 0;
+    exec->maxContours = 0;
+
+    /* free stack */
+    FT_FREE( exec->stack );
+    exec->stackSize = 0;
+
+    /* free call stack */
+    FT_FREE( exec->callStack );
+    exec->callSize = 0;
+    exec->callTop  = 0;
+
+    /* free glyph code range */
+    FT_FREE( exec->glyphIns );
+    exec->glyphSize = 0;
+
+    exec->size = NULL;
+    exec->face = NULL;
+
+    FT_FREE( exec );
+    return TT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Init_Context                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a context object.                                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory :: A handle to the parent memory object.                    */
+  /*                                                                       */
+  /*    face   :: A handle to the source TrueType face object.             */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    exec   :: A handle to the target execution context.                */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Init_Context( TT_ExecContext  exec,
+                TT_Face         face,
+                FT_Memory       memory )
+  {
+    FT_Error  error;
+
+
+    FT_TRACE1(( "Init_Context: new object at 0x%08p, parent = 0x%08p\n",
+                exec, face ));
+
+    exec->memory   = memory;
+    exec->callSize = 32;
+
+    if ( FT_NEW_ARRAY( exec->callStack, exec->callSize ) )
+      goto Fail_Memory;
+
+    /* all values in the context are set to 0 already, but this is */
+    /* here as a remainder                                         */
+    exec->maxPoints   = 0;
+    exec->maxContours = 0;
+
+    exec->stackSize = 0;
+    exec->loadSize  = 0;
+    exec->glyphSize = 0;
+
+    exec->stack     = NULL;
+    exec->loadStack = NULL;
+    exec->glyphIns  = NULL;
+
+    exec->face = face;
+    exec->size = NULL;
+
+    return TT_Err_Ok;
+
+  Fail_Memory:
+    FT_ERROR(( "Init_Context: not enough memory for 0x%08lx\n",
+               (FT_Long)exec ));
+    TT_Destroy_Context( exec, memory );
+
+    return error;
+ }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Update_Max                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Checks the size of a buffer and reallocates it if necessary.       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory     :: A handle to the parent memory object.                */
+  /*                                                                       */
+  /*    multiplier :: The size in bytes of each element in the buffer.     */
+  /*                                                                       */
+  /*    new_max    :: The new capacity (size) of the buffer.               */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    size       :: The address of the buffer's current size expressed   */
+  /*                  in elements.                                         */
+  /*                                                                       */
+  /*    buff       :: The address of the buffer base pointer.              */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Update_Max( FT_Memory  memory,
+              FT_ULong*  size,
+              FT_Long    multiplier,
+              void**     buff,
+              FT_ULong   new_max )
+  {
+    FT_Error  error;
+
+
+    if ( *size < new_max )
+    {
+      FT_FREE( *buff );
+      if ( FT_ALLOC( *buff, new_max * multiplier ) )
+        return error;
+      *size = new_max;
+    }
+
+    return TT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Load_Context                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Prepare an execution context for glyph hinting.                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A handle to the source face object.                        */
+  /*                                                                       */
+  /*    size :: A handle to the source size object.                        */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    exec :: A handle to the target execution context.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only the glyph loader and debugger should call this function.      */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Load_Context( TT_ExecContext  exec,
+                   TT_Face         face,
+                   TT_Size         size )
+  {
+    FT_Int          i;
+    FT_ULong        tmp;
+    TT_MaxProfile*  maxp;
+    FT_Error        error;
+
+
+    exec->face = face;
+    maxp       = &face->max_profile;
+    exec->size = size;
+
+    if ( size )
+    {
+      exec->numFDefs   = size->num_function_defs;
+      exec->maxFDefs   = size->max_function_defs;
+      exec->numIDefs   = size->num_instruction_defs;
+      exec->maxIDefs   = size->max_instruction_defs;
+      exec->FDefs      = size->function_defs;
+      exec->IDefs      = size->instruction_defs;
+      exec->tt_metrics = size->ttmetrics;
+      exec->metrics    = size->root.metrics;
+
+      exec->maxFunc    = size->max_func;
+      exec->maxIns     = size->max_ins;
+
+      for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
+        exec->codeRangeTable[i] = size->codeRangeTable[i];
+
+      /* set graphics state */
+      exec->GS = size->GS;
+
+      exec->cvtSize = size->cvt_size;
+      exec->cvt     = size->cvt;
+
+      exec->storeSize = size->storage_size;
+      exec->storage   = size->storage;
+
+      exec->twilight  = size->twilight;
+    }
+
+    error = Update_Max( exec->memory,
+                        &exec->loadSize,
+                        sizeof ( TT_SubGlyphRec ),
+                        (void**)&exec->loadStack,
+                        exec->face->max_components + 1 );
+    if ( error )
+      return error;
+
+    /* XXX: We reserve a little more elements on the stack to deal safely */
+    /*      with broken fonts like arialbs, courbs, timesbs, etc.         */
+    tmp = exec->stackSize;
+    error = Update_Max( exec->memory,
+                        &tmp,
+                        sizeof ( FT_F26Dot6 ),
+                        (void**)&exec->stack,
+                        maxp->maxStackElements + 32 );
+    exec->stackSize = (FT_UInt)tmp;
+    if ( error )
+      return error;
+
+    tmp = exec->glyphSize;
+    error = Update_Max( exec->memory,
+                        &tmp,
+                        sizeof ( FT_Byte ),
+                        (void**)&exec->glyphIns,
+                        maxp->maxSizeOfInstructions );
+    exec->glyphSize = (FT_UShort)tmp;
+    if ( error )
+      return error;
+
+    exec->pts.n_points   = 0;
+    exec->pts.n_contours = 0;
+
+    exec->instruction_trap = FALSE;
+
+    return TT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Save_Context                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Saves the code ranges in a `size' object.                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    exec :: A handle to the source execution context.                  */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    size :: A handle to the target size object.                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only the glyph loader and debugger should call this function.      */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Save_Context( TT_ExecContext  exec,
+                   TT_Size         size )
+  {
+    FT_Int  i;
+
+
+    /* XXXX: Will probably disappear soon with all the code range */
+    /*       management, which is now rather obsolete.            */
+    /*                                                            */
+    size->num_function_defs    = exec->numFDefs;
+    size->num_instruction_defs = exec->numIDefs;
+
+    size->max_func = exec->maxFunc;
+    size->max_ins  = exec->maxIns;
+
+    for ( i = 0; i < TT_MAX_CODE_RANGES; i++ )
+      size->codeRangeTable[i] = exec->codeRangeTable[i];
+
+    return TT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Run_Context                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Executes one or more instructions in the execution context.        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    debug :: A Boolean flag.  If set, the function sets some internal  */
+  /*             variables and returns immediately, otherwise TT_RunIns()  */
+  /*             is called.                                                */
+  /*                                                                       */
+  /*             This is commented out currently.                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    exec  :: A handle to the target execution context.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    TrueTyoe error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only the glyph loader and debugger should call this function.      */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Run_Context( TT_ExecContext  exec,
+                  FT_Bool         debug )
+  {
+    FT_Error  error;
+
+
+    if ( ( error = TT_Goto_CodeRange( exec, tt_coderange_glyph, 0  ) )
+           != TT_Err_Ok )
+      return error;
+
+    exec->zp0 = exec->pts;
+    exec->zp1 = exec->pts;
+    exec->zp2 = exec->pts;
+
+    exec->GS.gep0 = 1;
+    exec->GS.gep1 = 1;
+    exec->GS.gep2 = 1;
+
+    exec->GS.projVector.x = 0x4000;
+    exec->GS.projVector.y = 0x0000;
+
+    exec->GS.freeVector = exec->GS.projVector;
+    exec->GS.dualVector = exec->GS.projVector;
+
+    exec->GS.round_state = 1;
+    exec->GS.loop        = 1;
+
+    /* some glyphs leave something on the stack. so we clean it */
+    /* before a new execution.                                  */
+    exec->top     = 0;
+    exec->callTop = 0;
+
+#if 1
+    FT_UNUSED( debug );
+
+    return exec->face->interpreter( exec );
+#else
+    if ( !debug )
+      return TT_RunIns( exec );
+    else
+      return TT_Err_Ok;
+#endif
+  }
+
+
+  const TT_GraphicsState  tt_default_graphics_state =
+  {
+    0, 0, 0,
+    { 0x4000, 0 },
+    { 0x4000, 0 },
+    { 0x4000, 0 },
+    1, 64, 1,
+    TRUE, 68, 0, 0, 9, 3,
+    0, FALSE, 2, 1, 1, 1
+  };
+
+
+  /* documentation is in ttinterp.h */
+
+  FT_EXPORT_DEF( TT_ExecContext )
+  TT_New_Context( TT_Face  face )
+  {
+    TT_Driver       driver;
+    TT_ExecContext  exec;
+    FT_Memory       memory;
+
+
+    if ( !face )
+      return 0;
+
+    driver = (TT_Driver)face->root.driver;
+
+    memory = driver->root.root.memory;
+    exec   = driver->context;
+
+    if ( !driver->context )
+    {
+      FT_Error  error;
+
+
+      /* allocate object */
+      if ( FT_NEW( exec ) )
+        goto Exit;
+
+      /* initialize it */
+      error = Init_Context( exec, face, memory );
+      if ( error )
+        goto Fail;
+
+      /* store it into the driver */
+      driver->context = exec;
+    }
+
+  Exit:
+    return driver->context;
+
+  Fail:
+    FT_FREE( exec );
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Done_Context                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Discards an execution context.                                     */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    exec :: A handle to the target execution context.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only the glyph loader and debugger should call this function.      */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  TT_Done_Context( TT_ExecContext  exec )
+  {
+    /* Nothing at all for now */
+    FT_UNUSED( exec );
+
+    return TT_Err_Ok;
+  }
+
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Before an opcode is executed, the interpreter verifies that there are */
+  /* enough arguments on the stack, with the help of the Pop_Push_Count    */
+  /* table.                                                                */
+  /*                                                                       */
+  /* For each opcode, the first column gives the number of arguments that  */
+  /* are popped from the stack; the second one gives the number of those   */
+  /* that are pushed in result.                                            */
+  /*                                                                       */
+  /* Note that for opcodes with a varying number of parameters, either 0   */
+  /* or 1 arg is verified before execution, depending on the nature of the */
+  /* instruction:                                                          */
+  /*                                                                       */
+  /* - if the number of arguments is given by the bytecode stream or the   */
+  /*   loop variable, 0 is chosen.                                         */
+  /*                                                                       */
+  /* - if the first argument is a count n that is followed by arguments    */
+  /*   a1 .. an, then 1 is chosen.                                         */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#undef  PACK
+#define PACK( x, y )  ( ( x << 4 ) | y )
+
+
+  static
+  const FT_Byte  Pop_Push_Count[256] =
+  {
+    /* opcodes are gathered in groups of 16 */
+    /* please keep the spaces as they are   */
+
+    /*  SVTCA  y  */  PACK( 0, 0 ),
+    /*  SVTCA  x  */  PACK( 0, 0 ),
+    /*  SPvTCA y  */  PACK( 0, 0 ),
+    /*  SPvTCA x  */  PACK( 0, 0 ),
+    /*  SFvTCA y  */  PACK( 0, 0 ),
+    /*  SFvTCA x  */  PACK( 0, 0 ),
+    /*  SPvTL //  */  PACK( 2, 0 ),
+    /*  SPvTL +   */  PACK( 2, 0 ),
+    /*  SFvTL //  */  PACK( 2, 0 ),
+    /*  SFvTL +   */  PACK( 2, 0 ),
+    /*  SPvFS     */  PACK( 2, 0 ),
+    /*  SFvFS     */  PACK( 2, 0 ),
+    /*  GPV       */  PACK( 0, 2 ),
+    /*  GFV       */  PACK( 0, 2 ),
+    /*  SFvTPv    */  PACK( 0, 0 ),
+    /*  ISECT     */  PACK( 5, 0 ),
+
+    /*  SRP0      */  PACK( 1, 0 ),
+    /*  SRP1      */  PACK( 1, 0 ),
+    /*  SRP2      */  PACK( 1, 0 ),
+    /*  SZP0      */  PACK( 1, 0 ),
+    /*  SZP1      */  PACK( 1, 0 ),
+    /*  SZP2      */  PACK( 1, 0 ),
+    /*  SZPS      */  PACK( 1, 0 ),
+    /*  SLOOP     */  PACK( 1, 0 ),
+    /*  RTG       */  PACK( 0, 0 ),
+    /*  RTHG      */  PACK( 0, 0 ),
+    /*  SMD       */  PACK( 1, 0 ),
+    /*  ELSE      */  PACK( 0, 0 ),
+    /*  JMPR      */  PACK( 1, 0 ),
+    /*  SCvTCi    */  PACK( 1, 0 ),
+    /*  SSwCi     */  PACK( 1, 0 ),
+    /*  SSW       */  PACK( 1, 0 ),
+
+    /*  DUP       */  PACK( 1, 2 ),
+    /*  POP       */  PACK( 1, 0 ),
+    /*  CLEAR     */  PACK( 0, 0 ),
+    /*  SWAP      */  PACK( 2, 2 ),
+    /*  DEPTH     */  PACK( 0, 1 ),
+    /*  CINDEX    */  PACK( 1, 1 ),
+    /*  MINDEX    */  PACK( 1, 0 ),
+    /*  AlignPTS  */  PACK( 2, 0 ),
+    /*  INS_$28   */  PACK( 0, 0 ),
+    /*  UTP       */  PACK( 1, 0 ),
+    /*  LOOPCALL  */  PACK( 2, 0 ),
+    /*  CALL      */  PACK( 1, 0 ),
+    /*  FDEF      */  PACK( 1, 0 ),
+    /*  ENDF      */  PACK( 0, 0 ),
+    /*  MDAP[0]   */  PACK( 1, 0 ),
+    /*  MDAP[1]   */  PACK( 1, 0 ),
+
+    /*  IUP[0]    */  PACK( 0, 0 ),
+    /*  IUP[1]    */  PACK( 0, 0 ),
+    /*  SHP[0]    */  PACK( 0, 0 ),
+    /*  SHP[1]    */  PACK( 0, 0 ),
+    /*  SHC[0]    */  PACK( 1, 0 ),
+    /*  SHC[1]    */  PACK( 1, 0 ),
+    /*  SHZ[0]    */  PACK( 1, 0 ),
+    /*  SHZ[1]    */  PACK( 1, 0 ),
+    /*  SHPIX     */  PACK( 1, 0 ),
+    /*  IP        */  PACK( 0, 0 ),
+    /*  MSIRP[0]  */  PACK( 2, 0 ),
+    /*  MSIRP[1]  */  PACK( 2, 0 ),
+    /*  AlignRP   */  PACK( 0, 0 ),
+    /*  RTDG      */  PACK( 0, 0 ),
+    /*  MIAP[0]   */  PACK( 2, 0 ),
+    /*  MIAP[1]   */  PACK( 2, 0 ),
+
+    /*  NPushB    */  PACK( 0, 0 ),
+    /*  NPushW    */  PACK( 0, 0 ),
+    /*  WS        */  PACK( 2, 0 ),
+    /*  RS        */  PACK( 1, 1 ),
+    /*  WCvtP     */  PACK( 2, 0 ),
+    /*  RCvt      */  PACK( 1, 1 ),
+    /*  GC[0]     */  PACK( 1, 1 ),
+    /*  GC[1]     */  PACK( 1, 1 ),
+    /*  SCFS      */  PACK( 2, 0 ),
+    /*  MD[0]     */  PACK( 2, 1 ),
+    /*  MD[1]     */  PACK( 2, 1 ),
+    /*  MPPEM     */  PACK( 0, 1 ),
+    /*  MPS       */  PACK( 0, 1 ),
+    /*  FlipON    */  PACK( 0, 0 ),
+    /*  FlipOFF   */  PACK( 0, 0 ),
+    /*  DEBUG     */  PACK( 1, 0 ),
+
+    /*  LT        */  PACK( 2, 1 ),
+    /*  LTEQ      */  PACK( 2, 1 ),
+    /*  GT        */  PACK( 2, 1 ),
+    /*  GTEQ      */  PACK( 2, 1 ),
+    /*  EQ        */  PACK( 2, 1 ),
+    /*  NEQ       */  PACK( 2, 1 ),
+    /*  ODD       */  PACK( 1, 1 ),
+    /*  EVEN      */  PACK( 1, 1 ),
+    /*  IF        */  PACK( 1, 0 ),
+    /*  EIF       */  PACK( 0, 0 ),
+    /*  AND       */  PACK( 2, 1 ),
+    /*  OR        */  PACK( 2, 1 ),
+    /*  NOT       */  PACK( 1, 1 ),
+    /*  DeltaP1   */  PACK( 1, 0 ),
+    /*  SDB       */  PACK( 1, 0 ),
+    /*  SDS       */  PACK( 1, 0 ),
+
+    /*  ADD       */  PACK( 2, 1 ),
+    /*  SUB       */  PACK( 2, 1 ),
+    /*  DIV       */  PACK( 2, 1 ),
+    /*  MUL       */  PACK( 2, 1 ),
+    /*  ABS       */  PACK( 1, 1 ),
+    /*  NEG       */  PACK( 1, 1 ),
+    /*  FLOOR     */  PACK( 1, 1 ),
+    /*  CEILING   */  PACK( 1, 1 ),
+    /*  ROUND[0]  */  PACK( 1, 1 ),
+    /*  ROUND[1]  */  PACK( 1, 1 ),
+    /*  ROUND[2]  */  PACK( 1, 1 ),
+    /*  ROUND[3]  */  PACK( 1, 1 ),
+    /*  NROUND[0] */  PACK( 1, 1 ),
+    /*  NROUND[1] */  PACK( 1, 1 ),
+    /*  NROUND[2] */  PACK( 1, 1 ),
+    /*  NROUND[3] */  PACK( 1, 1 ),
+
+    /*  WCvtF     */  PACK( 2, 0 ),
+    /*  DeltaP2   */  PACK( 1, 0 ),
+    /*  DeltaP3   */  PACK( 1, 0 ),
+    /*  DeltaCn[0] */ PACK( 1, 0 ),
+    /*  DeltaCn[1] */ PACK( 1, 0 ),
+    /*  DeltaCn[2] */ PACK( 1, 0 ),
+    /*  SROUND    */  PACK( 1, 0 ),
+    /*  S45Round  */  PACK( 1, 0 ),
+    /*  JROT      */  PACK( 2, 0 ),
+    /*  JROF      */  PACK( 2, 0 ),
+    /*  ROFF      */  PACK( 0, 0 ),
+    /*  INS_$7B   */  PACK( 0, 0 ),
+    /*  RUTG      */  PACK( 0, 0 ),
+    /*  RDTG      */  PACK( 0, 0 ),
+    /*  SANGW     */  PACK( 1, 0 ),
+    /*  AA        */  PACK( 1, 0 ),
+
+    /*  FlipPT    */  PACK( 0, 0 ),
+    /*  FlipRgON  */  PACK( 2, 0 ),
+    /*  FlipRgOFF */  PACK( 2, 0 ),
+    /*  INS_$83   */  PACK( 0, 0 ),
+    /*  INS_$84   */  PACK( 0, 0 ),
+    /*  ScanCTRL  */  PACK( 1, 0 ),
+    /*  SDVPTL[0] */  PACK( 2, 0 ),
+    /*  SDVPTL[1] */  PACK( 2, 0 ),
+    /*  GetINFO   */  PACK( 1, 1 ),
+    /*  IDEF      */  PACK( 1, 0 ),
+    /*  ROLL      */  PACK( 3, 3 ),
+    /*  MAX       */  PACK( 2, 1 ),
+    /*  MIN       */  PACK( 2, 1 ),
+    /*  ScanTYPE  */  PACK( 1, 0 ),
+    /*  InstCTRL  */  PACK( 2, 0 ),
+    /*  INS_$8F   */  PACK( 0, 0 ),
+
+    /*  INS_$90  */   PACK( 0, 0 ),
+    /*  INS_$91  */   PACK( 0, 0 ),
+    /*  INS_$92  */   PACK( 0, 0 ),
+    /*  INS_$93  */   PACK( 0, 0 ),
+    /*  INS_$94  */   PACK( 0, 0 ),
+    /*  INS_$95  */   PACK( 0, 0 ),
+    /*  INS_$96  */   PACK( 0, 0 ),
+    /*  INS_$97  */   PACK( 0, 0 ),
+    /*  INS_$98  */   PACK( 0, 0 ),
+    /*  INS_$99  */   PACK( 0, 0 ),
+    /*  INS_$9A  */   PACK( 0, 0 ),
+    /*  INS_$9B  */   PACK( 0, 0 ),
+    /*  INS_$9C  */   PACK( 0, 0 ),
+    /*  INS_$9D  */   PACK( 0, 0 ),
+    /*  INS_$9E  */   PACK( 0, 0 ),
+    /*  INS_$9F  */   PACK( 0, 0 ),
+
+    /*  INS_$A0  */   PACK( 0, 0 ),
+    /*  INS_$A1  */   PACK( 0, 0 ),
+    /*  INS_$A2  */   PACK( 0, 0 ),
+    /*  INS_$A3  */   PACK( 0, 0 ),
+    /*  INS_$A4  */   PACK( 0, 0 ),
+    /*  INS_$A5  */   PACK( 0, 0 ),
+    /*  INS_$A6  */   PACK( 0, 0 ),
+    /*  INS_$A7  */   PACK( 0, 0 ),
+    /*  INS_$A8  */   PACK( 0, 0 ),
+    /*  INS_$A9  */   PACK( 0, 0 ),
+    /*  INS_$AA  */   PACK( 0, 0 ),
+    /*  INS_$AB  */   PACK( 0, 0 ),
+    /*  INS_$AC  */   PACK( 0, 0 ),
+    /*  INS_$AD  */   PACK( 0, 0 ),
+    /*  INS_$AE  */   PACK( 0, 0 ),
+    /*  INS_$AF  */   PACK( 0, 0 ),
+
+    /*  PushB[0]  */  PACK( 0, 1 ),
+    /*  PushB[1]  */  PACK( 0, 2 ),
+    /*  PushB[2]  */  PACK( 0, 3 ),
+    /*  PushB[3]  */  PACK( 0, 4 ),
+    /*  PushB[4]  */  PACK( 0, 5 ),
+    /*  PushB[5]  */  PACK( 0, 6 ),
+    /*  PushB[6]  */  PACK( 0, 7 ),
+    /*  PushB[7]  */  PACK( 0, 8 ),
+    /*  PushW[0]  */  PACK( 0, 1 ),
+    /*  PushW[1]  */  PACK( 0, 2 ),
+    /*  PushW[2]  */  PACK( 0, 3 ),
+    /*  PushW[3]  */  PACK( 0, 4 ),
+    /*  PushW[4]  */  PACK( 0, 5 ),
+    /*  PushW[5]  */  PACK( 0, 6 ),
+    /*  PushW[6]  */  PACK( 0, 7 ),
+    /*  PushW[7]  */  PACK( 0, 8 ),
+
+    /*  MDRP[00]  */  PACK( 1, 0 ),
+    /*  MDRP[01]  */  PACK( 1, 0 ),
+    /*  MDRP[02]  */  PACK( 1, 0 ),
+    /*  MDRP[03]  */  PACK( 1, 0 ),
+    /*  MDRP[04]  */  PACK( 1, 0 ),
+    /*  MDRP[05]  */  PACK( 1, 0 ),
+    /*  MDRP[06]  */  PACK( 1, 0 ),
+    /*  MDRP[07]  */  PACK( 1, 0 ),
+    /*  MDRP[08]  */  PACK( 1, 0 ),
+    /*  MDRP[09]  */  PACK( 1, 0 ),
+    /*  MDRP[10]  */  PACK( 1, 0 ),
+    /*  MDRP[11]  */  PACK( 1, 0 ),
+    /*  MDRP[12]  */  PACK( 1, 0 ),
+    /*  MDRP[13]  */  PACK( 1, 0 ),
+    /*  MDRP[14]  */  PACK( 1, 0 ),
+    /*  MDRP[15]  */  PACK( 1, 0 ),
+
+    /*  MDRP[16]  */  PACK( 1, 0 ),
+    /*  MDRP[17]  */  PACK( 1, 0 ),
+    /*  MDRP[18]  */  PACK( 1, 0 ),
+    /*  MDRP[19]  */  PACK( 1, 0 ),
+    /*  MDRP[20]  */  PACK( 1, 0 ),
+    /*  MDRP[21]  */  PACK( 1, 0 ),
+    /*  MDRP[22]  */  PACK( 1, 0 ),
+    /*  MDRP[23]  */  PACK( 1, 0 ),
+    /*  MDRP[24]  */  PACK( 1, 0 ),
+    /*  MDRP[25]  */  PACK( 1, 0 ),
+    /*  MDRP[26]  */  PACK( 1, 0 ),
+    /*  MDRP[27]  */  PACK( 1, 0 ),
+    /*  MDRP[28]  */  PACK( 1, 0 ),
+    /*  MDRP[29]  */  PACK( 1, 0 ),
+    /*  MDRP[30]  */  PACK( 1, 0 ),
+    /*  MDRP[31]  */  PACK( 1, 0 ),
+
+    /*  MIRP[00]  */  PACK( 2, 0 ),
+    /*  MIRP[01]  */  PACK( 2, 0 ),
+    /*  MIRP[02]  */  PACK( 2, 0 ),
+    /*  MIRP[03]  */  PACK( 2, 0 ),
+    /*  MIRP[04]  */  PACK( 2, 0 ),
+    /*  MIRP[05]  */  PACK( 2, 0 ),
+    /*  MIRP[06]  */  PACK( 2, 0 ),
+    /*  MIRP[07]  */  PACK( 2, 0 ),
+    /*  MIRP[08]  */  PACK( 2, 0 ),
+    /*  MIRP[09]  */  PACK( 2, 0 ),
+    /*  MIRP[10]  */  PACK( 2, 0 ),
+    /*  MIRP[11]  */  PACK( 2, 0 ),
+    /*  MIRP[12]  */  PACK( 2, 0 ),
+    /*  MIRP[13]  */  PACK( 2, 0 ),
+    /*  MIRP[14]  */  PACK( 2, 0 ),
+    /*  MIRP[15]  */  PACK( 2, 0 ),
+
+    /*  MIRP[16]  */  PACK( 2, 0 ),
+    /*  MIRP[17]  */  PACK( 2, 0 ),
+    /*  MIRP[18]  */  PACK( 2, 0 ),
+    /*  MIRP[19]  */  PACK( 2, 0 ),
+    /*  MIRP[20]  */  PACK( 2, 0 ),
+    /*  MIRP[21]  */  PACK( 2, 0 ),
+    /*  MIRP[22]  */  PACK( 2, 0 ),
+    /*  MIRP[23]  */  PACK( 2, 0 ),
+    /*  MIRP[24]  */  PACK( 2, 0 ),
+    /*  MIRP[25]  */  PACK( 2, 0 ),
+    /*  MIRP[26]  */  PACK( 2, 0 ),
+    /*  MIRP[27]  */  PACK( 2, 0 ),
+    /*  MIRP[28]  */  PACK( 2, 0 ),
+    /*  MIRP[29]  */  PACK( 2, 0 ),
+    /*  MIRP[30]  */  PACK( 2, 0 ),
+    /*  MIRP[31]  */  PACK( 2, 0 )
+  };
+
+
+  static
+  const FT_Char  opcode_length[256] =
+  {
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+
+   -1,-1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    2, 3, 4, 5,  6, 7, 8, 9,  3, 5, 7, 9, 11,13,15,17,
+
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,
+    1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1,  1, 1, 1, 1
+  };
+
+  static
+  const FT_Vector  Null_Vector = {0,0};
+
+
+#undef PACK
+
+
+#undef  NULL_Vector
+#define NULL_Vector  (FT_Vector*)&Null_Vector
+
+
+  /* compute (a*b)/2^14 with maximal accuracy and rounding */
+  static FT_Int32
+  TT_MulFix14( FT_Int32  a,
+               FT_Int    b )
+  {
+    FT_Int32   m, s, hi;
+    FT_UInt32  l, lo;
+
+
+    /* compute ax*bx as 64-bit value */
+    l  = (FT_UInt32)( ( a & 0xFFFFU ) * b );
+    m  = ( a >> 16 ) * b;
+
+    lo = l + (FT_UInt32)( m << 16 );
+    hi = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo < l );
+
+    /* divide the result by 2^14 with rounding */
+    s   = hi >> 31;
+    l   = lo + (FT_UInt32)s;
+    hi += s + ( l < lo );
+    lo  = l;
+
+    l   = lo + 0x2000U;
+    hi += (l < lo);
+
+    return ( hi << 18 ) | ( l >> 14 );
+  }
+
+
+  /* compute (ax*bx+ay*by)/2^14 with maximal accuracy and rounding */
+  static FT_Int32
+  TT_DotFix14( FT_Int32  ax,
+               FT_Int32  ay,
+               FT_Int    bx,
+               FT_Int    by )
+  {
+    FT_Int32   m, s, hi1, hi2, hi;
+    FT_UInt32  l, lo1, lo2, lo;
+
+
+    /* compute ax*bx as 64-bit value */
+    l = (FT_UInt32)( ( ax & 0xFFFFU ) * bx );
+    m = ( ax >> 16 ) * bx;
+
+    lo1 = l + (FT_UInt32)( m << 16 );
+    hi1 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo1 < l );
+
+    /* compute ay*by as 64-bit value */
+    l = (FT_UInt32)( ( ay & 0xFFFFU ) * by );
+    m = ( ay >> 16 ) * by;
+
+    lo2 = l + (FT_UInt32)( m << 16 );
+    hi2 = ( m >> 16 ) + ( (FT_Int32)l >> 31 ) + ( lo2 < l );
+
+    /* add them */
+    lo = lo1 + lo2;
+    hi = hi1 + hi2 + ( lo < lo1 );
+
+    /* divide the result by 2^14 with rounding */
+    s   = hi >> 31;
+    l   = lo + (FT_UInt32)s;
+    hi += s + ( l < lo );
+    lo  = l;
+
+    l   = lo + 0x2000U;
+    hi += ( l < lo );
+
+    return ( hi << 18 ) | ( l >> 14 );
+  }
+
+
+  /* return length of given vector */
+
+#if 0
+
+  static FT_Int32
+  TT_VecLen( FT_Int32  x,
+             FT_Int32  y )
+  {
+    FT_Int32   m, hi1, hi2, hi;
+    FT_UInt32  l, lo1, lo2, lo;
+
+
+    /* compute x*x as 64-bit value */
+    lo = (FT_UInt32)( x & 0xFFFFU );
+    hi = x >> 16;
+
+    l  = lo * lo;
+    m  = hi * lo;
+    hi = hi * hi;
+
+    lo1 = l + (FT_UInt32)( m << 17 );
+    hi1 = hi + ( m >> 15 ) + ( lo1 < l );
+
+    /* compute y*y as 64-bit value */
+    lo = (FT_UInt32)( y & 0xFFFFU );
+    hi = y >> 16;
+
+    l  = lo * lo;
+    m  = hi * lo;
+    hi = hi * hi;
+
+    lo2 = l + (FT_UInt32)( m << 17 );
+    hi2 = hi + ( m >> 15 ) + ( lo2 < l );
+
+    /* add them to get 'x*x+y*y' as 64-bit value */
+    lo = lo1 + lo2;
+    hi = hi1 + hi2 + ( lo < lo1 );
+
+    /* compute the square root of this value */
+    {
+      FT_UInt32  root, rem, test_div;
+      FT_Int     count;
+
+
+      root = 0;
+
+      {
+        rem   = 0;
+        count = 32;
+        do
+        {
+          rem      = ( rem << 2 ) | ( (FT_UInt32)hi >> 30 );
+          hi       = (  hi << 2 ) | (            lo >> 30 );
+          lo     <<= 2;
+          root   <<= 1;
+          test_div = ( root << 1 ) + 1;
+
+          if ( rem >= test_div )
+          {
+            rem  -= test_div;
+            root += 1;
+          }
+        } while ( --count );
+      }
+
+      return (FT_Int32)root;
+    }
+  }
+
+#else
+
+  /* this version uses FT_Vector_Length which computes the same value */
+  /* much, much faster..                                              */
+  /*                                                                  */
+  static FT_F26Dot6
+  TT_VecLen( FT_F26Dot6  X,
+             FT_F26Dot6  Y )
+  {
+    FT_Vector  v;
+
+
+    v.x = X;
+    v.y = Y;
+
+    return FT_Vector_Length( &v );
+  }
+
+#endif
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Current_Ratio                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Returns the current aspect ratio scaling factor depending on the   */
+  /*    projection vector's state and device resolutions.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The aspect ratio in 16.16 format, always <= 1.0 .                  */
+  /*                                                                       */
+  static FT_Long
+  Current_Ratio( EXEC_OP )
+  {
+    if ( CUR.tt_metrics.ratio )
+      return CUR.tt_metrics.ratio;
+
+    if ( CUR.GS.projVector.y == 0 )
+      CUR.tt_metrics.ratio = CUR.tt_metrics.x_ratio;
+
+    else if ( CUR.GS.projVector.x == 0 )
+      CUR.tt_metrics.ratio = CUR.tt_metrics.y_ratio;
+
+    else
+    {
+      FT_Long  x, y;
+
+      x = TT_MULDIV( CUR.GS.projVector.x, CUR.tt_metrics.x_ratio, 0x4000 );
+      y = TT_MULDIV( CUR.GS.projVector.y, CUR.tt_metrics.y_ratio, 0x4000 );
+      CUR.tt_metrics.ratio = TT_VecLen( x, y );
+    }
+
+    return CUR.tt_metrics.ratio;
+  }
+
+
+  static FT_Long
+  Current_Ppem( EXEC_OP )
+  {
+    return TT_MULFIX( CUR.tt_metrics.ppem, CURRENT_Ratio() );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Functions related to the control value table (CVT).                   */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_F26Dot6 )
+  Read_CVT( EXEC_OP_ FT_ULong  idx )
+  {
+    return CUR.cvt[idx];
+  }
+
+
+  FT_CALLBACK_DEF( FT_F26Dot6 )
+  Read_CVT_Stretched( EXEC_OP_ FT_ULong  idx )
+  {
+    return TT_MULFIX( CUR.cvt[idx], CURRENT_Ratio() );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  Write_CVT( EXEC_OP_ FT_ULong    idx,
+                      FT_F26Dot6  value )
+  {
+    CUR.cvt[idx] = value;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  Write_CVT_Stretched( EXEC_OP_ FT_ULong    idx,
+                                FT_F26Dot6  value )
+  {
+    CUR.cvt[idx] = FT_DivFix( value, CURRENT_Ratio() );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  Move_CVT( EXEC_OP_ FT_ULong    idx,
+                     FT_F26Dot6  value )
+  {
+    CUR.cvt[idx] += value;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  Move_CVT_Stretched( EXEC_OP_ FT_ULong    idx,
+                               FT_F26Dot6  value )
+  {
+    CUR.cvt[idx] += FT_DivFix( value, CURRENT_Ratio() );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    GetShortIns                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Returns a short integer taken from the instruction stream at       */
+  /*    address IP.                                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Short read at code[IP].                                            */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This one could become a macro.                                     */
+  /*                                                                       */
+  static FT_Short
+  GetShortIns( EXEC_OP )
+  {
+    /* Reading a byte stream so there is no endianess (DaveP) */
+    CUR.IP += 2;
+    return (FT_Short)( ( CUR.code[CUR.IP - 2] << 8 ) +
+                         CUR.code[CUR.IP - 1]      );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Ins_Goto_CodeRange                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Goes to a certain code range in the instruction stream.            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    aRange :: The index of the code range.                             */
+  /*                                                                       */
+  /*    aIP    :: The new IP address in the code range.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    SUCCESS or FAILURE.                                                */
+  /*                                                                       */
+  static FT_Bool
+  Ins_Goto_CodeRange( EXEC_OP_ FT_Int    aRange,
+                               FT_ULong  aIP )
+  {
+    TT_CodeRange*  range;
+
+
+    if ( aRange < 1 || aRange > 3 )
+    {
+      CUR.error = TT_Err_Bad_Argument;
+      return FAILURE;
+    }
+
+    range = &CUR.codeRangeTable[aRange - 1];
+
+    if ( range->base == NULL )     /* invalid coderange */
+    {
+      CUR.error = TT_Err_Invalid_CodeRange;
+      return FAILURE;
+    }
+
+    /* NOTE: Because the last instruction of a program may be a CALL */
+    /*       which will return to the first byte *after* the code    */
+    /*       range, we test for AIP <= Size, instead of AIP < Size.  */
+
+    if ( aIP > range->size )
+    {
+      CUR.error = TT_Err_Code_Overflow;
+      return FAILURE;
+    }
+
+    CUR.code     = range->base;
+    CUR.codeSize = range->size;
+    CUR.IP       = aIP;
+    CUR.curRange = aRange;
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Direct_Move                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Moves a point by a given distance along the freedom vector.  The   */
+  /*    point will be `touched'.                                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    point    :: The index of the point to move.                        */
+  /*                                                                       */
+  /*    distance :: The distance to apply.                                 */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    zone     :: The affected glyph zone.                               */
+  /*                                                                       */
+  static void
+  Direct_Move( EXEC_OP_ TT_GlyphZone  zone,
+                        FT_UShort     point,
+                        FT_F26Dot6    distance )
+  {
+    FT_F26Dot6  v;
+
+
+    v = CUR.GS.freeVector.x;
+
+    if ( v != 0 )
+    {
+
+#ifdef NO_APPLE_PATENT
+
+      if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
+        zone->cur[point].x += distance;
+
+#else
+
+      zone->cur[point].x += TT_MULDIV( distance,
+                                       v * 0x10000L,
+                                       CUR.F_dot_P );
+
+#endif
+
+      zone->tags[point] |= FT_CURVE_TAG_TOUCH_X;
+    }
+
+    v = CUR.GS.freeVector.y;
+
+    if ( v != 0 )
+    {
+
+#ifdef NO_APPLE_PATENT
+
+      if ( ABS( CUR.F_dot_P ) > APPLE_THRESHOLD )
+        zone->cur[point].y += distance;
+
+#else
+
+      zone->cur[point].y += TT_MULDIV( distance,
+                                       v * 0x10000L,
+                                       CUR.F_dot_P );
+
+#endif
+
+      zone->tags[point] |= FT_CURVE_TAG_TOUCH_Y;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Special versions of Direct_Move()                                     */
+  /*                                                                       */
+  /*   The following versions are used whenever both vectors are both      */
+  /*   along one of the coordinate unit vectors, i.e. in 90% of the cases. */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static void
+  Direct_Move_X( EXEC_OP_ TT_GlyphZone  zone,
+                          FT_UShort     point,
+                          FT_F26Dot6    distance )
+  {
+    FT_UNUSED_EXEC;
+
+    zone->cur[point].x += distance;
+    zone->tags[point]  |= FT_CURVE_TAG_TOUCH_X;
+  }
+
+
+  static void
+  Direct_Move_Y( EXEC_OP_ TT_GlyphZone  zone,
+                          FT_UShort     point,
+                          FT_F26Dot6    distance )
+  {
+    FT_UNUSED_EXEC;
+
+    zone->cur[point].y += distance;
+    zone->tags[point]  |= FT_CURVE_TAG_TOUCH_Y;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_None                                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Does not round, but adds engine compensation.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance (not) to round.                       */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The compensated distance.                                          */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The TrueType specification says very few about the relationship    */
+  /*    between rounding and engine compensation.  However, it seems from  */
+  /*    the description of super round that we should add the compensation */
+  /*    before rounding.                                                   */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_None( EXEC_OP_ FT_F26Dot6  distance,
+                       FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6  val;
+
+    FT_UNUSED_EXEC;
+
+
+    if ( distance >= 0 )
+    {
+      val = distance + compensation;
+      if ( val < 0 )
+        val = 0;
+    }
+    else {
+      val = distance - compensation;
+      if ( val > 0 )
+        val = 0;
+    }
+    return val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_To_Grid                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Rounds value to grid after adding engine compensation.             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance to round.                             */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Rounded distance.                                                  */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
+                          FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6  val;
+
+    FT_UNUSED_EXEC;
+
+
+    if ( distance >= 0 )
+    {
+      val = distance + compensation + 32;
+      if ( val > 0 )
+        val &= ~63;
+      else
+        val = 0;
+    }
+    else
+    {
+      val = -( ( compensation - distance + 32 ) & -64 );
+      if ( val > 0 )
+        val = 0;
+    }
+
+    return  val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_To_Half_Grid                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Rounds value to half grid after adding engine compensation.        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance to round.                             */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Rounded distance.                                                  */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_To_Half_Grid( EXEC_OP_ FT_F26Dot6  distance,
+                               FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6  val;
+
+    FT_UNUSED_EXEC;
+
+
+    if ( distance >= 0 )
+    {
+      val = ( ( distance + compensation ) & -64 ) + 32;
+      if ( val < 0 )
+        val = 0;
+    }
+    else
+    {
+      val = -( ( (compensation - distance) & -64 ) + 32 );
+      if ( val > 0 )
+        val = 0;
+    }
+
+    return val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_Down_To_Grid                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Rounds value down to grid after adding engine compensation.        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance to round.                             */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Rounded distance.                                                  */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_Down_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
+                               FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6  val;
+
+    FT_UNUSED_EXEC;
+
+
+    if ( distance >= 0 )
+    {
+      val = distance + compensation;
+      if ( val > 0 )
+        val &= ~63;
+      else
+        val = 0;
+    }
+    else
+    {
+      val = -( ( compensation - distance ) & -64 );
+      if ( val > 0 )
+        val = 0;
+    }
+
+    return val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_Up_To_Grid                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Rounds value up to grid after adding engine compensation.          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance to round.                             */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Rounded distance.                                                  */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_Up_To_Grid( EXEC_OP_ FT_F26Dot6  distance,
+                             FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6  val;
+
+
+    FT_UNUSED_EXEC;
+
+    if ( distance >= 0 )
+    {
+      val = distance + compensation + 63;
+      if ( val > 0 )
+        val &= ~63;
+      else
+        val = 0;
+    }
+    else
+    {
+      val = -( ( compensation - distance + 63 ) & -64 );
+      if ( val > 0 )
+        val = 0;
+    }
+
+    return val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_To_Double_Grid                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Rounds value to double grid after adding engine compensation.      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance to round.                             */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Rounded distance.                                                  */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_To_Double_Grid( EXEC_OP_ FT_F26Dot6  distance,
+                                 FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6 val;
+
+    FT_UNUSED_EXEC;
+
+
+    if ( distance >= 0 )
+    {
+      val = distance + compensation + 16;
+      if ( val > 0 )
+        val &= ~31;
+      else
+        val = 0;
+    }
+    else
+    {
+      val = -( ( compensation - distance + 16 ) & -32 );
+      if ( val > 0 )
+        val = 0;
+    }
+
+    return val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_Super                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Super-rounds value to grid after adding engine compensation.       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance to round.                             */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Rounded distance.                                                  */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The TrueType specification says very few about the relationship    */
+  /*    between rounding and engine compensation.  However, it seems from  */
+  /*    the description of super round that we should add the compensation */
+  /*    before rounding.                                                   */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_Super( EXEC_OP_ FT_F26Dot6  distance,
+                        FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6  val;
+
+
+    if ( distance >= 0 )
+    {
+      val = ( distance - CUR.phase + CUR.threshold + compensation ) &
+              -CUR.period;
+      if ( val < 0 )
+        val = 0;
+      val += CUR.phase;
+    }
+    else
+    {
+      val = -( ( CUR.threshold - CUR.phase - distance + compensation ) &
+               -CUR.period );
+      if ( val > 0 )
+        val = 0;
+      val -= CUR.phase;
+    }
+
+    return val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Round_Super_45                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Super-rounds value to grid after adding engine compensation.       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    distance     :: The distance to round.                             */
+  /*                                                                       */
+  /*    compensation :: The engine compensation.                           */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Rounded distance.                                                  */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    There is a separate function for Round_Super_45() as we may need   */
+  /*    greater precision.                                                 */
+  /*                                                                       */
+  static FT_F26Dot6
+  Round_Super_45( EXEC_OP_ FT_F26Dot6  distance,
+                           FT_F26Dot6  compensation )
+  {
+    FT_F26Dot6  val;
+
+
+    if ( distance >= 0 )
+    {
+      val = ( ( distance - CUR.phase + CUR.threshold + compensation ) /
+                CUR.period ) * CUR.period;
+      if ( val < 0 )
+        val = 0;
+      val += CUR.phase;
+    }
+    else
+    {
+      val = -( ( ( CUR.threshold - CUR.phase - distance + compensation ) /
+                   CUR.period ) * CUR.period );
+      if ( val > 0 )
+        val = 0;
+      val -= CUR.phase;
+    }
+
+    return val;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Compute_Round                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Sets the rounding mode.                                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    round_mode :: The rounding mode to be used.                        */
+  /*                                                                       */
+  static void
+  Compute_Round( EXEC_OP_ FT_Byte  round_mode )
+  {
+    switch ( round_mode )
+    {
+    case TT_Round_Off:
+      CUR.func_round = (TT_Round_Func)Round_None;
+      break;
+
+    case TT_Round_To_Grid:
+      CUR.func_round = (TT_Round_Func)Round_To_Grid;
+      break;
+
+    case TT_Round_Up_To_Grid:
+      CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
+      break;
+
+    case TT_Round_Down_To_Grid:
+      CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
+      break;
+
+    case TT_Round_To_Half_Grid:
+      CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
+      break;
+
+    case TT_Round_To_Double_Grid:
+      CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
+      break;
+
+    case TT_Round_Super:
+      CUR.func_round = (TT_Round_Func)Round_Super;
+      break;
+
+    case TT_Round_Super_45:
+      CUR.func_round = (TT_Round_Func)Round_Super_45;
+      break;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    SetSuperRound                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Sets Super Round parameters.                                       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    GridPeriod :: Grid period                                          */
+  /*    selector   :: SROUND opcode                                        */
+  /*                                                                       */
+  static void
+  SetSuperRound( EXEC_OP_ FT_F26Dot6  GridPeriod,
+                          FT_Long     selector )
+  {
+    switch ( (FT_Int)( selector & 0xC0 ) )
+    {
+      case 0:
+        CUR.period = GridPeriod / 2;
+        break;
+
+      case 0x40:
+        CUR.period = GridPeriod;
+        break;
+
+      case 0x80:
+        CUR.period = GridPeriod * 2;
+        break;
+
+      /* This opcode is reserved, but... */
+
+      case 0xC0:
+        CUR.period = GridPeriod;
+        break;
+    }
+
+    switch ( (FT_Int)( selector & 0x30 ) )
+    {
+    case 0:
+      CUR.phase = 0;
+      break;
+
+    case 0x10:
+      CUR.phase = CUR.period / 4;
+      break;
+
+    case 0x20:
+      CUR.phase = CUR.period / 2;
+      break;
+
+    case 0x30:
+      CUR.phase = GridPeriod * 3 / 4;
+      break;
+    }
+
+    if ( (selector & 0x0F) == 0 )
+      CUR.threshold = CUR.period - 1;
+    else
+      CUR.threshold = ( (FT_Int)( selector & 0x0F ) - 4 ) * CUR.period / 8;
+
+    CUR.period    /= 256;
+    CUR.phase     /= 256;
+    CUR.threshold /= 256;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Project                                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the projection of vector given by (v2-v1) along the       */
+  /*    current projection vector.                                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    v1 :: First input vector.                                          */
+  /*    v2 :: Second input vector.                                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The distance in F26dot6 format.                                    */
+  /*                                                                       */
+  static FT_F26Dot6
+  Project( EXEC_OP_ FT_Vector*  v1,
+                    FT_Vector*  v2 )
+  {
+    return TT_DotFix14( v1->x - v2->x,
+                        v1->y - v2->y,
+                        CUR.GS.projVector.x,
+                        CUR.GS.projVector.y );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Dual_Project                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the projection of the vector given by (v2-v1) along the   */
+  /*    current dual vector.                                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    v1 :: First input vector.                                          */
+  /*    v2 :: Second input vector.                                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The distance in F26dot6 format.                                    */
+  /*                                                                       */
+  static FT_F26Dot6
+  Dual_Project( EXEC_OP_ FT_Vector*  v1,
+                         FT_Vector*  v2 )
+  {
+    return TT_DotFix14( v1->x - v2->x,
+                        v1->y - v2->y,
+                        CUR.GS.dualVector.x,
+                        CUR.GS.dualVector.y );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Free_Project                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the projection of the vector given by (v2-v1) along the   */
+  /*    current freedom vector.                                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    v1 :: First input vector.                                          */
+  /*    v2 :: Second input vector.                                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The distance in F26dot6 format.                                    */
+  /*                                                                       */
+  static FT_F26Dot6
+  Free_Project( EXEC_OP_ FT_Vector*  v1,
+                         FT_Vector*  v2 )
+  {
+    return TT_DotFix14( v1->x - v2->x,
+                        v1->y - v2->y,
+                        CUR.GS.freeVector.x,
+                        CUR.GS.freeVector.y );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Project_x                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the projection of the vector given by (v2-v1) along the   */
+  /*    horizontal axis.                                                   */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    v1 :: First input vector.                                          */
+  /*    v2 :: Second input vector.                                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The distance in F26dot6 format.                                    */
+  /*                                                                       */
+  static FT_F26Dot6
+  Project_x( EXEC_OP_ FT_Vector*  v1,
+                      FT_Vector*  v2 )
+  {
+    FT_UNUSED_EXEC;
+
+    return ( v1->x - v2->x );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Project_y                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the projection of the vector given by (v2-v1) along the   */
+  /*    vertical axis.                                                     */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    v1 :: First input vector.                                          */
+  /*    v2 :: Second input vector.                                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The distance in F26dot6 format.                                    */
+  /*                                                                       */
+  static FT_F26Dot6
+  Project_y( EXEC_OP_ FT_Vector*  v1,
+                      FT_Vector*  v2 )
+  {
+    FT_UNUSED_EXEC;
+
+   return ( v1->y - v2->y );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Compute_Funcs                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Computes the projection and movement function pointers according   */
+  /*    to the current graphics state.                                     */
+  /*                                                                       */
+  static void
+  Compute_Funcs( EXEC_OP )
+  {
+    if ( CUR.GS.freeVector.x == 0x4000 )
+    {
+      CUR.func_freeProj = (TT_Project_Func)Project_x;
+      CUR.F_dot_P       = CUR.GS.projVector.x * 0x10000L;
+    }
+    else
+    {
+      if ( CUR.GS.freeVector.y == 0x4000 )
+      {
+        CUR.func_freeProj = (TT_Project_Func)Project_y;
+        CUR.F_dot_P       = CUR.GS.projVector.y * 0x10000L;
+      }
+      else
+      {
+        CUR.func_freeProj = (TT_Project_Func)Free_Project;
+        CUR.F_dot_P = (FT_Long)CUR.GS.projVector.x * CUR.GS.freeVector.x * 4 +
+                      (FT_Long)CUR.GS.projVector.y * CUR.GS.freeVector.y * 4;
+      }
+    }
+
+    if ( CUR.GS.projVector.x == 0x4000 )
+      CUR.func_project = (TT_Project_Func)Project_x;
+    else
+    {
+      if ( CUR.GS.projVector.y == 0x4000 )
+        CUR.func_project = (TT_Project_Func)Project_y;
+      else
+        CUR.func_project = (TT_Project_Func)Project;
+    }
+
+    if ( CUR.GS.dualVector.x == 0x4000 )
+      CUR.func_dualproj = (TT_Project_Func)Project_x;
+    else
+    {
+      if ( CUR.GS.dualVector.y == 0x4000 )
+        CUR.func_dualproj = (TT_Project_Func)Project_y;
+      else
+        CUR.func_dualproj = (TT_Project_Func)Dual_Project;
+    }
+
+    CUR.func_move = (TT_Move_Func)Direct_Move;
+
+    if ( CUR.F_dot_P == 0x40000000L )
+    {
+      if ( CUR.GS.freeVector.x == 0x4000 )
+        CUR.func_move = (TT_Move_Func)Direct_Move_X;
+      else
+      {
+        if ( CUR.GS.freeVector.y == 0x4000 )
+          CUR.func_move = (TT_Move_Func)Direct_Move_Y;
+      }
+    }
+
+    /* at small sizes, F_dot_P can become too small, resulting   */
+    /* in overflows and `spikes' in a number of glyphs like `w'. */
+
+    if ( ABS( CUR.F_dot_P ) < 0x4000000L )
+      CUR.F_dot_P = 0x40000000L;
+
+    /* Disable cached aspect ratio */
+    CUR.tt_metrics.ratio = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Normalize                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Norms a vector.                                                    */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    Vx :: The horizontal input vector coordinate.                      */
+  /*    Vy :: The vertical input vector coordinate.                        */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    R  :: The normed unit vector.                                      */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    Returns FAILURE if a vector parameter is zero.                     */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    In case Vx and Vy are both zero, Normalize() returns SUCCESS, and  */
+  /*    R is undefined.                                                    */
+  /*                                                                       */
+
+
+  static FT_Bool
+  Normalize( EXEC_OP_ FT_F26Dot6      Vx,
+                      FT_F26Dot6      Vy,
+                      FT_UnitVector*  R )
+  {
+    FT_F26Dot6  W;
+    FT_Bool     S1, S2;
+
+    FT_UNUSED_EXEC;
+
+
+    if ( ABS( Vx ) < 0x10000L && ABS( Vy ) < 0x10000L )
+    {
+      Vx *= 0x100;
+      Vy *= 0x100;
+
+      W = TT_VecLen( Vx, Vy );
+
+      if ( W == 0 )
+      {
+        /* XXX: UNDOCUMENTED! It seems that it is possible to try   */
+        /*      to normalize the vector (0,0).  Return immediately. */
+        return SUCCESS;
+      }
+
+      R->x = (FT_F2Dot14)FT_MulDiv( Vx, 0x4000L, W );
+      R->y = (FT_F2Dot14)FT_MulDiv( Vy, 0x4000L, W );
+
+      return SUCCESS;
+    }
+
+    W = TT_VecLen( Vx, Vy );
+
+    Vx = FT_MulDiv( Vx, 0x4000L, W );
+    Vy = FT_MulDiv( Vy, 0x4000L, W );
+
+    W = Vx * Vx + Vy * Vy;
+
+    /* Now, we want that Sqrt( W ) = 0x4000 */
+    /* Or 0x1000000 <= W < 0x1004000        */
+
+    if ( Vx < 0 )
+    {
+      Vx = -Vx;
+      S1 = TRUE;
+    }
+    else
+      S1 = FALSE;
+
+    if ( Vy < 0 )
+    {
+      Vy = -Vy;
+      S2 = TRUE;
+    }
+    else
+      S2 = FALSE;
+
+    while ( W < 0x1000000L )
+    {
+      /* We need to increase W by a minimal amount */
+      if ( Vx < Vy )
+        Vx++;
+      else
+        Vy++;
+
+      W = Vx * Vx + Vy * Vy;
+    }
+
+    while ( W >= 0x1004000L )
+    {
+      /* We need to decrease W by a minimal amount */
+      if ( Vx < Vy )
+        Vx--;
+      else
+        Vy--;
+
+      W = Vx * Vx + Vy * Vy;
+    }
+
+    /* Note that in various cases, we can only  */
+    /* compute a Sqrt(W) of 0x3FFF, eg. Vx = Vy */
+
+    if ( S1 )
+      Vx = -Vx;
+
+    if ( S2 )
+      Vy = -Vy;
+
+    R->x = (FT_F2Dot14)Vx;   /* Type conversion */
+    R->y = (FT_F2Dot14)Vy;   /* Type conversion */
+
+    return SUCCESS;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Here we start with the implementation of the various opcodes.         */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static FT_Bool
+  Ins_SxVTL( EXEC_OP_ FT_UShort       aIdx1,
+                      FT_UShort       aIdx2,
+                      FT_Int          aOpc,
+                      FT_UnitVector*  Vec )
+  {
+    FT_Long     A, B, C;
+    FT_Vector*  p1;
+    FT_Vector*  p2;
+
+
+    if ( BOUNDS( aIdx1, CUR.zp2.n_points ) ||
+         BOUNDS( aIdx2, CUR.zp1.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return FAILURE;
+    }
+
+    p1 = CUR.zp1.cur + aIdx2;
+    p2 = CUR.zp2.cur + aIdx1;
+
+    A = p1->x - p2->x;
+    B = p1->y - p2->y;
+
+    if ( ( aOpc & 1 ) != 0 )
+    {
+      C =  B;   /* counter clockwise rotation */
+      B =  A;
+      A = -C;
+    }
+
+    NORMalize( A, B, Vec );
+
+    return SUCCESS;
+  }
+
+
+  /* When not using the big switch statements, the interpreter uses a */
+  /* call table defined later below in this source.  Each opcode must */
+  /* thus have a corresponding function, even trivial ones.           */
+  /*                                                                  */
+  /* They are all defined there.                                      */
+
+#define DO_SVTCA                            \
+  {                                         \
+    FT_Short  A, B;                         \
+                                            \
+                                            \
+    A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+    B = A ^ (FT_Short)0x4000;               \
+                                            \
+    CUR.GS.freeVector.x = A;                \
+    CUR.GS.projVector.x = A;                \
+    CUR.GS.dualVector.x = A;                \
+                                            \
+    CUR.GS.freeVector.y = B;                \
+    CUR.GS.projVector.y = B;                \
+    CUR.GS.dualVector.y = B;                \
+                                            \
+    COMPUTE_Funcs();                        \
+  }
+
+
+#define DO_SPVTCA                           \
+  {                                         \
+    FT_Short  A, B;                         \
+                                            \
+                                            \
+    A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+    B = A ^ (FT_Short)0x4000;               \
+                                            \
+    CUR.GS.projVector.x = A;                \
+    CUR.GS.dualVector.x = A;                \
+                                            \
+    CUR.GS.projVector.y = B;                \
+    CUR.GS.dualVector.y = B;                \
+                                            \
+    COMPUTE_Funcs();                        \
+  }
+
+
+#define DO_SFVTCA                           \
+  {                                         \
+    FT_Short  A, B;                         \
+                                            \
+                                            \
+    A = (FT_Short)( CUR.opcode & 1 ) << 14; \
+    B = A ^ (FT_Short)0x4000;               \
+                                            \
+    CUR.GS.freeVector.x = A;                \
+    CUR.GS.freeVector.y = B;                \
+                                            \
+    COMPUTE_Funcs();                        \
+  }
+
+
+#define DO_SPVTL                                      \
+    if ( INS_SxVTL( (FT_UShort)args[1],               \
+                    (FT_UShort)args[0],               \
+                    CUR.opcode,                       \
+                    &CUR.GS.projVector ) == SUCCESS ) \
+    {                                                 \
+      CUR.GS.dualVector = CUR.GS.projVector;          \
+      COMPUTE_Funcs();                                \
+    }
+
+
+#define DO_SFVTL                                      \
+    if ( INS_SxVTL( (FT_UShort)args[1],               \
+                    (FT_UShort)args[0],               \
+                    CUR.opcode,                       \
+                    &CUR.GS.freeVector ) == SUCCESS ) \
+      COMPUTE_Funcs();
+
+
+#define DO_SFVTPV                          \
+    CUR.GS.freeVector = CUR.GS.projVector; \
+    COMPUTE_Funcs();
+
+
+#define DO_SPVFS                                \
+  {                                             \
+    FT_Short  S;                                \
+    FT_Long   X, Y;                             \
+                                                \
+                                                \
+    /* Only use low 16bits, then sign extend */ \
+    S = (FT_Short)args[1];                      \
+    Y = (FT_Long)S;                             \
+    S = (FT_Short)args[0];                      \
+    X = (FT_Long)S;                             \
+                                                \
+    NORMalize( X, Y, &CUR.GS.projVector );      \
+                                                \
+    CUR.GS.dualVector = CUR.GS.projVector;      \
+    COMPUTE_Funcs();                            \
+  }
+
+
+#define DO_SFVFS                                \
+  {                                             \
+    FT_Short  S;                                \
+    FT_Long   X, Y;                             \
+                                                \
+                                                \
+    /* Only use low 16bits, then sign extend */ \
+    S = (FT_Short)args[1];                      \
+    Y = (FT_Long)S;                             \
+    S = (FT_Short)args[0];                      \
+    X = S;                                      \
+                                                \
+    NORMalize( X, Y, &CUR.GS.freeVector );      \
+    COMPUTE_Funcs();                            \
+  }
+
+
+#define DO_GPV                     \
+    args[0] = CUR.GS.projVector.x; \
+    args[1] = CUR.GS.projVector.y;
+
+
+#define DO_GFV                     \
+    args[0] = CUR.GS.freeVector.x; \
+    args[1] = CUR.GS.freeVector.y;
+
+
+#define DO_SRP0                      \
+    CUR.GS.rp0 = (FT_UShort)args[0];
+
+
+#define DO_SRP1                      \
+    CUR.GS.rp1 = (FT_UShort)args[0];
+
+
+#define DO_SRP2                      \
+    CUR.GS.rp2 = (FT_UShort)args[0];
+
+
+#define DO_RTHG                                         \
+    CUR.GS.round_state = TT_Round_To_Half_Grid;         \
+    CUR.func_round = (TT_Round_Func)Round_To_Half_Grid;
+
+
+#define DO_RTG                                     \
+    CUR.GS.round_state = TT_Round_To_Grid;         \
+    CUR.func_round = (TT_Round_Func)Round_To_Grid;
+
+
+#define DO_RTDG                                           \
+    CUR.GS.round_state = TT_Round_To_Double_Grid;         \
+    CUR.func_round = (TT_Round_Func)Round_To_Double_Grid;
+
+
+#define DO_RUTG                                       \
+    CUR.GS.round_state = TT_Round_Up_To_Grid;         \
+    CUR.func_round = (TT_Round_Func)Round_Up_To_Grid;
+
+
+#define DO_RDTG                                         \
+    CUR.GS.round_state = TT_Round_Down_To_Grid;         \
+    CUR.func_round = (TT_Round_Func)Round_Down_To_Grid;
+
+
+#define DO_ROFF                                 \
+    CUR.GS.round_state = TT_Round_Off;          \
+    CUR.func_round = (TT_Round_Func)Round_None;
+
+
+#define DO_SROUND                                \
+    SET_SuperRound( 0x4000, args[0] );           \
+    CUR.GS.round_state = TT_Round_Super;         \
+    CUR.func_round = (TT_Round_Func)Round_Super;
+
+
+#define DO_S45ROUND                                 \
+    SET_SuperRound( 0x2D41, args[0] );              \
+    CUR.GS.round_state = TT_Round_Super_45;         \
+    CUR.func_round = (TT_Round_Func)Round_Super_45;
+
+
+#define DO_SLOOP                       \
+    if ( args[0] < 0 )                 \
+      CUR.error = TT_Err_Bad_Argument; \
+    else                               \
+      CUR.GS.loop = args[0];
+
+
+#define DO_SMD                         \
+    CUR.GS.minimum_distance = args[0];
+
+
+#define DO_SCVTCI                                     \
+    CUR.GS.control_value_cutin = (FT_F26Dot6)args[0];
+
+
+#define DO_SSWCI                                     \
+    CUR.GS.single_width_cutin = (FT_F26Dot6)args[0];
+
+
+    /* XXX: UNDOCUMENTED! or bug in the Windows engine? */
+    /*                                                  */
+    /* It seems that the value that is read here is     */
+    /* expressed in 16.16 format rather than in font    */
+    /* units.                                           */
+    /*                                                  */
+#define DO_SSW                                                 \
+    CUR.GS.single_width_value = (FT_F26Dot6)( args[0] >> 10 );
+
+
+#define DO_FLIPON            \
+    CUR.GS.auto_flip = TRUE;
+
+
+#define DO_FLIPOFF            \
+    CUR.GS.auto_flip = FALSE;
+
+
+#define DO_SDB                             \
+    CUR.GS.delta_base = (FT_Short)args[0];
+
+
+#define DO_SDS                              \
+    CUR.GS.delta_shift = (FT_Short)args[0];
+
+
+#define DO_MD  /* nothing */
+
+
+#define DO_MPPEM              \
+    args[0] = CURRENT_Ppem();
+
+
+  /* Note: The pointSize should be irrelevant in a given font program; */
+  /*       we thus decide to return only the ppem.                     */
+#if 0
+
+#define DO_MPS                       \
+    args[0] = CUR.metrics.pointSize;
+
+#else
+
+#define DO_MPS                \
+    args[0] = CURRENT_Ppem();
+
+#endif /* 0 */
+
+
+#define DO_DUP         \
+    args[1] = args[0];
+
+
+#define DO_CLEAR     \
+    CUR.new_top = 0;
+
+
+#define DO_SWAP        \
+  {                    \
+    FT_Long  L;        \
+                       \
+                       \
+    L       = args[0]; \
+    args[0] = args[1]; \
+    args[1] = L;       \
+  }
+
+
+#define DO_DEPTH       \
+    args[0] = CUR.top;
+
+
+#define DO_CINDEX                           \
+  {                                         \
+    FT_Long  L;                             \
+                                            \
+                                            \
+    L = args[0];                            \
+                                            \
+    if ( L <= 0 || L > CUR.args )           \
+      CUR.error = TT_Err_Invalid_Reference; \
+    else                                    \
+      args[0] = CUR.stack[CUR.args - L];    \
+  }
+
+
+#define DO_JROT               \
+    if ( args[1] != 0 )       \
+    {                         \
+      CUR.IP      += args[0]; \
+      CUR.step_ins = FALSE;   \
+    }
+
+
+#define DO_JMPR             \
+    CUR.IP      += args[0]; \
+    CUR.step_ins = FALSE;
+
+
+#define DO_JROF               \
+    if ( args[1] == 0 )       \
+    {                         \
+      CUR.IP      += args[0]; \
+      CUR.step_ins = FALSE;   \
+    }
+
+
+#define DO_LT                        \
+    args[0] = ( args[0] < args[1] );
+
+
+#define DO_LTEQ                       \
+    args[0] = ( args[0] <= args[1] );
+
+
+#define DO_GT                        \
+    args[0] = ( args[0] > args[1] );
+
+
+#define DO_GTEQ                       \
+    args[0] = ( args[0] >= args[1] );
+
+
+#define DO_EQ                         \
+    args[0] = ( args[0] == args[1] );
+
+
+#define DO_NEQ                        \
+    args[0] = ( args[0] != args[1] );
+
+
+#define DO_ODD                                                  \
+    args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 64 );
+
+
+#define DO_EVEN                                                \
+    args[0] = ( ( CUR_Func_round( args[0], 0 ) & 127 ) == 0 );
+
+
+#define DO_AND                        \
+    args[0] = ( args[0] && args[1] );
+
+
+#define DO_OR                         \
+    args[0] = ( args[0] || args[1] );
+
+
+#define DO_NOT          \
+    args[0] = !args[0];
+
+
+#define DO_ADD          \
+    args[0] += args[1];
+
+
+#define DO_SUB          \
+    args[0] -= args[1];
+
+
+#define DO_DIV                                      \
+    if ( args[1] == 0 )                             \
+      CUR.error = TT_Err_Divide_By_Zero;            \
+    else                                            \
+      args[0] = TT_MULDIV( args[0], 64L, args[1] );
+
+
+#define DO_MUL                                    \
+    args[0] = TT_MULDIV( args[0], args[1], 64L );
+
+
+#define DO_ABS                \
+    args[0] = ABS( args[0] );
+
+
+#define DO_NEG          \
+    args[0] = -args[0];
+
+
+#define DO_FLOOR    \
+    args[0] &= -64;
+
+
+#define DO_CEILING                    \
+    args[0] = ( args[0] + 63 ) & -64;
+
+
+#define DO_RS                          \
+   {                                   \
+     FT_ULong  I = (FT_ULong)args[0];  \
+                                       \
+                                       \
+     if ( BOUNDS( I, CUR.storeSize ) ) \
+     {                                 \
+       if ( CUR.pedantic_hinting )     \
+       {                               \
+         ARRAY_BOUND_ERROR;            \
+       }                               \
+       else                            \
+         args[0] = 0;                  \
+     }                                 \
+     else                              \
+       args[0] = CUR.storage[I];       \
+   }
+
+
+#define DO_WS                          \
+   {                                   \
+     FT_ULong  I = (FT_ULong)args[0];  \
+                                       \
+                                       \
+     if ( BOUNDS( I, CUR.storeSize ) ) \
+     {                                 \
+       if ( CUR.pedantic_hinting )     \
+       {                               \
+         ARRAY_BOUND_ERROR;            \
+       }                               \
+     }                                 \
+     else                              \
+       CUR.storage[I] = args[1];       \
+   }
+
+
+#define DO_RCVT                          \
+   {                                     \
+     FT_ULong  I = (FT_ULong)args[0];    \
+                                         \
+                                         \
+     if ( BOUNDS( I, CUR.cvtSize ) )     \
+     {                                   \
+       if ( CUR.pedantic_hinting )       \
+       {                                 \
+         ARRAY_BOUND_ERROR;              \
+       }                                 \
+       else                              \
+         args[0] = 0;                    \
+     }                                   \
+     else                                \
+       args[0] = CUR_Func_read_cvt( I ); \
+   }
+
+
+#define DO_WCVTP                         \
+   {                                     \
+     FT_ULong  I = (FT_ULong)args[0];    \
+                                         \
+                                         \
+     if ( BOUNDS( I, CUR.cvtSize ) )     \
+     {                                   \
+       if ( CUR.pedantic_hinting )       \
+       {                                 \
+         ARRAY_BOUND_ERROR;              \
+       }                                 \
+     }                                   \
+     else                                \
+       CUR_Func_write_cvt( I, args[1] ); \
+   }
+
+
+#define DO_WCVTF                                                \
+   {                                                            \
+     FT_ULong  I = (FT_ULong)args[0];                           \
+                                                                \
+                                                                \
+     if ( BOUNDS( I, CUR.cvtSize ) )                            \
+     {                                                          \
+       if ( CUR.pedantic_hinting )                              \
+       {                                                        \
+         ARRAY_BOUND_ERROR;                                     \
+       }                                                        \
+     }                                                          \
+     else                                                       \
+       CUR.cvt[I] = TT_MULFIX( args[1], CUR.tt_metrics.scale ); \
+   }
+
+
+#define DO_DEBUG                     \
+    CUR.error = TT_Err_Debug_OpCode;
+
+
+#define DO_ROUND                                                   \
+    args[0] = CUR_Func_round(                                      \
+                args[0],                                           \
+                CUR.tt_metrics.compensations[CUR.opcode - 0x68] );
+
+
+#define DO_NROUND                                                            \
+    args[0] = ROUND_None( args[0],                                           \
+                          CUR.tt_metrics.compensations[CUR.opcode - 0x6C] );
+
+
+#define DO_MAX               \
+    if ( args[1] > args[0] ) \
+      args[0] = args[1];
+
+
+#define DO_MIN               \
+    if ( args[1] < args[0] ) \
+      args[0] = args[1];
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+#undef  ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR                   \
+    {                                       \
+      CUR.error = TT_Err_Invalid_Reference; \
+      return;                               \
+    }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SVTCA[a]:     Set (F and P) Vectors to Coordinate Axis                */
+  /* Opcode range: 0x00-0x01                                               */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_SVTCA( INS_ARG )
+  {
+    DO_SVTCA
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SPVTCA[a]:    Set PVector to Coordinate Axis                          */
+  /* Opcode range: 0x02-0x03                                               */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_SPVTCA( INS_ARG )
+  {
+    DO_SPVTCA
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SFVTCA[a]:    Set FVector to Coordinate Axis                          */
+  /* Opcode range: 0x04-0x05                                               */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_SFVTCA( INS_ARG )
+  {
+    DO_SFVTCA
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SPVTL[a]:     Set PVector To Line                                     */
+  /* Opcode range: 0x06-0x07                                               */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_SPVTL( INS_ARG )
+  {
+    DO_SPVTL
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SFVTL[a]:     Set FVector To Line                                     */
+  /* Opcode range: 0x08-0x09                                               */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_SFVTL( INS_ARG )
+  {
+    DO_SFVTL
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SFVTPV[]:     Set FVector To PVector                                  */
+  /* Opcode range: 0x0E                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_SFVTPV( INS_ARG )
+  {
+    DO_SFVTPV
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SPVFS[]:      Set PVector From Stack                                  */
+  /* Opcode range: 0x0A                                                    */
+  /* Stack:        f2.14 f2.14 -->                                         */
+  /*                                                                       */
+  static void
+  Ins_SPVFS( INS_ARG )
+  {
+    DO_SPVFS
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SFVFS[]:      Set FVector From Stack                                  */
+  /* Opcode range: 0x0B                                                    */
+  /* Stack:        f2.14 f2.14 -->                                         */
+  /*                                                                       */
+  static void
+  Ins_SFVFS( INS_ARG )
+  {
+    DO_SFVFS
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* GPV[]:        Get Projection Vector                                   */
+  /* Opcode range: 0x0C                                                    */
+  /* Stack:        ef2.14 --> ef2.14                                       */
+  /*                                                                       */
+  static void
+  Ins_GPV( INS_ARG )
+  {
+    DO_GPV
+  }
+
+
+  /*************************************************************************/
+  /* GFV[]:        Get Freedom Vector                                      */
+  /* Opcode range: 0x0D                                                    */
+  /* Stack:        ef2.14 --> ef2.14                                       */
+  /*                                                                       */
+  static void
+  Ins_GFV( INS_ARG )
+  {
+    DO_GFV
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SRP0[]:       Set Reference Point 0                                   */
+  /* Opcode range: 0x10                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SRP0( INS_ARG )
+  {
+    DO_SRP0
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SRP1[]:       Set Reference Point 1                                   */
+  /* Opcode range: 0x11                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SRP1( INS_ARG )
+  {
+    DO_SRP1
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SRP2[]:       Set Reference Point 2                                   */
+  /* Opcode range: 0x12                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SRP2( INS_ARG )
+  {
+    DO_SRP2
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* RTHG[]:       Round To Half Grid                                      */
+  /* Opcode range: 0x19                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_RTHG( INS_ARG )
+  {
+    DO_RTHG
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* RTG[]:        Round To Grid                                           */
+  /* Opcode range: 0x18                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_RTG( INS_ARG )
+  {
+    DO_RTG
+  }
+
+
+  /*************************************************************************/
+  /* RTDG[]:       Round To Double Grid                                    */
+  /* Opcode range: 0x3D                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_RTDG( INS_ARG )
+  {
+    DO_RTDG
+  }
+
+
+  /*************************************************************************/
+  /* RUTG[]:       Round Up To Grid                                        */
+  /* Opcode range: 0x7C                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_RUTG( INS_ARG )
+  {
+    DO_RUTG
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* RDTG[]:       Round Down To Grid                                      */
+  /* Opcode range: 0x7D                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_RDTG( INS_ARG )
+  {
+    DO_RDTG
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ROFF[]:       Round OFF                                               */
+  /* Opcode range: 0x7A                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_ROFF( INS_ARG )
+  {
+    DO_ROFF
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SROUND[]:     Super ROUND                                             */
+  /* Opcode range: 0x76                                                    */
+  /* Stack:        Eint8 -->                                               */
+  /*                                                                       */
+  static void
+  Ins_SROUND( INS_ARG )
+  {
+    DO_SROUND
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* S45ROUND[]:   Super ROUND 45 degrees                                  */
+  /* Opcode range: 0x77                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_S45ROUND( INS_ARG )
+  {
+    DO_S45ROUND
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SLOOP[]:      Set LOOP variable                                       */
+  /* Opcode range: 0x17                                                    */
+  /* Stack:        int32? -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SLOOP( INS_ARG )
+  {
+    DO_SLOOP
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SMD[]:        Set Minimum Distance                                    */
+  /* Opcode range: 0x1A                                                    */
+  /* Stack:        f26.6 -->                                               */
+  /*                                                                       */
+  static void
+  Ins_SMD( INS_ARG )
+  {
+    DO_SMD
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SCVTCI[]:     Set Control Value Table Cut In                          */
+  /* Opcode range: 0x1D                                                    */
+  /* Stack:        f26.6 -->                                               */
+  /*                                                                       */
+  static void
+  Ins_SCVTCI( INS_ARG )
+  {
+    DO_SCVTCI
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SSWCI[]:      Set Single Width Cut In                                 */
+  /* Opcode range: 0x1E                                                    */
+  /* Stack:        f26.6 -->                                               */
+  /*                                                                       */
+  static void
+  Ins_SSWCI( INS_ARG )
+  {
+    DO_SSWCI
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SSW[]:        Set Single Width                                        */
+  /* Opcode range: 0x1F                                                    */
+  /* Stack:        int32? -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SSW( INS_ARG )
+  {
+    DO_SSW
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FLIPON[]:     Set auto-FLIP to ON                                     */
+  /* Opcode range: 0x4D                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_FLIPON( INS_ARG )
+  {
+    DO_FLIPON
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FLIPOFF[]:    Set auto-FLIP to OFF                                    */
+  /* Opcode range: 0x4E                                                    */
+  /* Stack: -->                                                            */
+  /*                                                                       */
+  static void
+  Ins_FLIPOFF( INS_ARG )
+  {
+    DO_FLIPOFF
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SANGW[]:      Set ANGle Weight                                        */
+  /* Opcode range: 0x7E                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SANGW( INS_ARG )
+  {
+    /* instruction not supported anymore */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SDB[]:        Set Delta Base                                          */
+  /* Opcode range: 0x5E                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SDB( INS_ARG )
+  {
+    DO_SDB
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SDS[]:        Set Delta Shift                                         */
+  /* Opcode range: 0x5F                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SDS( INS_ARG )
+  {
+    DO_SDS
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MPPEM[]:      Measure Pixel Per EM                                    */
+  /* Opcode range: 0x4B                                                    */
+  /* Stack:        --> Euint16                                             */
+  /*                                                                       */
+  static void
+  Ins_MPPEM( INS_ARG )
+  {
+    DO_MPPEM
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MPS[]:        Measure Point Size                                      */
+  /* Opcode range: 0x4C                                                    */
+  /* Stack:        --> Euint16                                             */
+  /*                                                                       */
+  static void
+  Ins_MPS( INS_ARG )
+  {
+    DO_MPS
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DUP[]:        DUPlicate the top stack's element                       */
+  /* Opcode range: 0x20                                                    */
+  /* Stack:        StkElt --> StkElt StkElt                                */
+  /*                                                                       */
+  static void
+  Ins_DUP( INS_ARG )
+  {
+    DO_DUP
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* POP[]:        POP the stack's top element                             */
+  /* Opcode range: 0x21                                                    */
+  /* Stack:        StkElt -->                                              */
+  /*                                                                       */
+  static void
+  Ins_POP( INS_ARG )
+  {
+    /* nothing to do */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* CLEAR[]:      CLEAR the entire stack                                  */
+  /* Opcode range: 0x22                                                    */
+  /* Stack:        StkElt... -->                                           */
+  /*                                                                       */
+  static void
+  Ins_CLEAR( INS_ARG )
+  {
+    DO_CLEAR
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SWAP[]:       SWAP the stack's top two elements                       */
+  /* Opcode range: 0x23                                                    */
+  /* Stack:        2 * StkElt --> 2 * StkElt                               */
+  /*                                                                       */
+  static void
+  Ins_SWAP( INS_ARG )
+  {
+    DO_SWAP
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DEPTH[]:      return the stack DEPTH                                  */
+  /* Opcode range: 0x24                                                    */
+  /* Stack:        --> uint32                                              */
+  /*                                                                       */
+  static void
+  Ins_DEPTH( INS_ARG )
+  {
+    DO_DEPTH
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* CINDEX[]:     Copy INDEXed element                                    */
+  /* Opcode range: 0x25                                                    */
+  /* Stack:        int32 --> StkElt                                        */
+  /*                                                                       */
+  static void
+  Ins_CINDEX( INS_ARG )
+  {
+    DO_CINDEX
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* EIF[]:        End IF                                                  */
+  /* Opcode range: 0x59                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_EIF( INS_ARG )
+  {
+    /* nothing to do */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* JROT[]:       Jump Relative On True                                   */
+  /* Opcode range: 0x78                                                    */
+  /* Stack:        StkElt int32 -->                                        */
+  /*                                                                       */
+  static void
+  Ins_JROT( INS_ARG )
+  {
+    DO_JROT
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* JMPR[]:       JuMP Relative                                           */
+  /* Opcode range: 0x1C                                                    */
+  /* Stack:        int32 -->                                               */
+  /*                                                                       */
+  static void
+  Ins_JMPR( INS_ARG )
+  {
+    DO_JMPR
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* JROF[]:       Jump Relative On False                                  */
+  /* Opcode range: 0x79                                                    */
+  /* Stack:        StkElt int32 -->                                        */
+  /*                                                                       */
+  static void
+  Ins_JROF( INS_ARG )
+  {
+    DO_JROF
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* LT[]:         Less Than                                               */
+  /* Opcode range: 0x50                                                    */
+  /* Stack:        int32? int32? --> bool                                  */
+  /*                                                                       */
+  static void
+  Ins_LT( INS_ARG )
+  {
+    DO_LT
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* LTEQ[]:       Less Than or EQual                                      */
+  /* Opcode range: 0x51                                                    */
+  /* Stack:        int32? int32? --> bool                                  */
+  /*                                                                       */
+  static void
+  Ins_LTEQ( INS_ARG )
+  {
+    DO_LTEQ
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* GT[]:         Greater Than                                            */
+  /* Opcode range: 0x52                                                    */
+  /* Stack:        int32? int32? --> bool                                  */
+  /*                                                                       */
+  static void
+  Ins_GT( INS_ARG )
+  {
+    DO_GT
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* GTEQ[]:       Greater Than or EQual                                   */
+  /* Opcode range: 0x53                                                    */
+  /* Stack:        int32? int32? --> bool                                  */
+  /*                                                                       */
+  static void
+  Ins_GTEQ( INS_ARG )
+  {
+    DO_GTEQ
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* EQ[]:         EQual                                                   */
+  /* Opcode range: 0x54                                                    */
+  /* Stack:        StkElt StkElt --> bool                                  */
+  /*                                                                       */
+  static void
+  Ins_EQ( INS_ARG )
+  {
+    DO_EQ
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* NEQ[]:        Not EQual                                               */
+  /* Opcode range: 0x55                                                    */
+  /* Stack:        StkElt StkElt --> bool                                  */
+  /*                                                                       */
+  static void
+  Ins_NEQ( INS_ARG )
+  {
+    DO_NEQ
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ODD[]:        Is ODD                                                  */
+  /* Opcode range: 0x56                                                    */
+  /* Stack:        f26.6 --> bool                                          */
+  /*                                                                       */
+  static void
+  Ins_ODD( INS_ARG )
+  {
+    DO_ODD
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* EVEN[]:       Is EVEN                                                 */
+  /* Opcode range: 0x57                                                    */
+  /* Stack:        f26.6 --> bool                                          */
+  /*                                                                       */
+  static void
+  Ins_EVEN( INS_ARG )
+  {
+    DO_EVEN
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* AND[]:        logical AND                                             */
+  /* Opcode range: 0x5A                                                    */
+  /* Stack:        uint32 uint32 --> uint32                                */
+  /*                                                                       */
+  static void
+  Ins_AND( INS_ARG )
+  {
+    DO_AND
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* OR[]:         logical OR                                              */
+  /* Opcode range: 0x5B                                                    */
+  /* Stack:        uint32 uint32 --> uint32                                */
+  /*                                                                       */
+  static void
+  Ins_OR( INS_ARG )
+  {
+    DO_OR
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* NOT[]:        logical NOT                                             */
+  /* Opcode range: 0x5C                                                    */
+  /* Stack:        StkElt --> uint32                                       */
+  /*                                                                       */
+  static void
+  Ins_NOT( INS_ARG )
+  {
+    DO_NOT
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ADD[]:        ADD                                                     */
+  /* Opcode range: 0x60                                                    */
+  /* Stack:        f26.6 f26.6 --> f26.6                                   */
+  /*                                                                       */
+  static void
+  Ins_ADD( INS_ARG )
+  {
+    DO_ADD
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SUB[]:        SUBtract                                                */
+  /* Opcode range: 0x61                                                    */
+  /* Stack:        f26.6 f26.6 --> f26.6                                   */
+  /*                                                                       */
+  static void
+  Ins_SUB( INS_ARG )
+  {
+    DO_SUB
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DIV[]:        DIVide                                                  */
+  /* Opcode range: 0x62                                                    */
+  /* Stack:        f26.6 f26.6 --> f26.6                                   */
+  /*                                                                       */
+  static void
+  Ins_DIV( INS_ARG )
+  {
+    DO_DIV
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MUL[]:        MULtiply                                                */
+  /* Opcode range: 0x63                                                    */
+  /* Stack:        f26.6 f26.6 --> f26.6                                   */
+  /*                                                                       */
+  static void
+  Ins_MUL( INS_ARG )
+  {
+    DO_MUL
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ABS[]:        ABSolute value                                          */
+  /* Opcode range: 0x64                                                    */
+  /* Stack:        f26.6 --> f26.6                                         */
+  /*                                                                       */
+  static void
+  Ins_ABS( INS_ARG )
+  {
+    DO_ABS
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* NEG[]:        NEGate                                                  */
+  /* Opcode range: 0x65                                                    */
+  /* Stack: f26.6 --> f26.6                                                */
+  /*                                                                       */
+  static void
+  Ins_NEG( INS_ARG )
+  {
+    DO_NEG
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FLOOR[]:      FLOOR                                                   */
+  /* Opcode range: 0x66                                                    */
+  /* Stack:        f26.6 --> f26.6                                         */
+  /*                                                                       */
+  static void
+  Ins_FLOOR( INS_ARG )
+  {
+    DO_FLOOR
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* CEILING[]:    CEILING                                                 */
+  /* Opcode range: 0x67                                                    */
+  /* Stack:        f26.6 --> f26.6                                         */
+  /*                                                                       */
+  static void
+  Ins_CEILING( INS_ARG )
+  {
+    DO_CEILING
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* RS[]:         Read Store                                              */
+  /* Opcode range: 0x43                                                    */
+  /* Stack:        uint32 --> uint32                                       */
+  /*                                                                       */
+  static void
+  Ins_RS( INS_ARG )
+  {
+    DO_RS
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* WS[]:         Write Store                                             */
+  /* Opcode range: 0x42                                                    */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_WS( INS_ARG )
+  {
+    DO_WS
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* WCVTP[]:      Write CVT in Pixel units                                */
+  /* Opcode range: 0x44                                                    */
+  /* Stack:        f26.6 uint32 -->                                        */
+  /*                                                                       */
+  static void
+  Ins_WCVTP( INS_ARG )
+  {
+    DO_WCVTP
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* WCVTF[]:      Write CVT in Funits                                     */
+  /* Opcode range: 0x70                                                    */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_WCVTF( INS_ARG )
+  {
+    DO_WCVTF
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* RCVT[]:       Read CVT                                                */
+  /* Opcode range: 0x45                                                    */
+  /* Stack:        uint32 --> f26.6                                        */
+  /*                                                                       */
+  static void
+  Ins_RCVT( INS_ARG )
+  {
+    DO_RCVT
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* AA[]:         Adjust Angle                                            */
+  /* Opcode range: 0x7F                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_AA( INS_ARG )
+  {
+    /* intentionally no longer supported */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DEBUG[]:      DEBUG.  Unsupported.                                    */
+  /* Opcode range: 0x4F                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  /* Note: The original instruction pops a value from the stack.           */
+  /*                                                                       */
+  static void
+  Ins_DEBUG( INS_ARG )
+  {
+    DO_DEBUG
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ROUND[ab]:    ROUND value                                             */
+  /* Opcode range: 0x68-0x6B                                               */
+  /* Stack:        f26.6 --> f26.6                                         */
+  /*                                                                       */
+  static void
+  Ins_ROUND( INS_ARG )
+  {
+    DO_ROUND
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* NROUND[ab]:   No ROUNDing of value                                    */
+  /* Opcode range: 0x6C-0x6F                                               */
+  /* Stack:        f26.6 --> f26.6                                         */
+  /*                                                                       */
+  static void
+  Ins_NROUND( INS_ARG )
+  {
+    DO_NROUND
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MAX[]:        MAXimum                                                 */
+  /* Opcode range: 0x68                                                    */
+  /* Stack:        int32? int32? --> int32                                 */
+  /*                                                                       */
+  static void
+  Ins_MAX( INS_ARG )
+  {
+    DO_MAX
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MIN[]:        MINimum                                                 */
+  /* Opcode range: 0x69                                                    */
+  /* Stack:        int32? int32? --> int32                                 */
+  /*                                                                       */
+  static void
+  Ins_MIN( INS_ARG )
+  {
+    DO_MIN
+  }
+
+
+#endif  /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The following functions are called as is within the switch statement. */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MINDEX[]:     Move INDEXed element                                    */
+  /* Opcode range: 0x26                                                    */
+  /* Stack:        int32? --> StkElt                                       */
+  /*                                                                       */
+  static void
+  Ins_MINDEX( INS_ARG )
+  {
+    FT_Long  L, K;
+
+
+    L = args[0];
+
+    if ( L <= 0 || L > CUR.args )
+    {
+      CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    K = CUR.stack[CUR.args - L];
+
+    FT_MEM_MOVE( &CUR.stack[CUR.args - L    ],
+                 &CUR.stack[CUR.args - L + 1],
+                 ( L - 1 ) * sizeof ( FT_Long ) );
+
+    CUR.stack[CUR.args - 1] = K;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ROLL[]:       ROLL top three elements                                 */
+  /* Opcode range: 0x8A                                                    */
+  /* Stack:        3 * StkElt --> 3 * StkElt                               */
+  /*                                                                       */
+  static void
+  Ins_ROLL( INS_ARG )
+  {
+    FT_Long  A, B, C;
+
+    FT_UNUSED_EXEC;
+
+
+    A = args[2];
+    B = args[1];
+    C = args[0];
+
+    args[2] = C;
+    args[1] = A;
+    args[0] = B;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MANAGING THE FLOW OF CONTROL                                          */
+  /*                                                                       */
+  /*   Instructions appear in the specification's order.                   */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  static FT_Bool
+  SkipCode( EXEC_OP )
+  {
+    CUR.IP += CUR.length;
+
+    if ( CUR.IP < CUR.codeSize )
+    {
+      CUR.opcode = CUR.code[CUR.IP];
+
+      CUR.length = opcode_length[CUR.opcode];
+      if ( CUR.length < 0 )
+      {
+        if ( CUR.IP + 1 > CUR.codeSize )
+          goto Fail_Overflow;
+        CUR.length = CUR.code[CUR.IP + 1] + 2;
+      }
+
+      if ( CUR.IP + CUR.length <= CUR.codeSize )
+        return SUCCESS;
+    }
+
+  Fail_Overflow:
+    CUR.error = TT_Err_Code_Overflow;
+    return FAILURE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* IF[]:         IF test                                                 */
+  /* Opcode range: 0x58                                                    */
+  /* Stack:        StkElt -->                                              */
+  /*                                                                       */
+  static void
+  Ins_IF( INS_ARG )
+  {
+    FT_Int   nIfs;
+    FT_Bool  Out;
+
+
+    if ( args[0] != 0 )
+      return;
+
+    nIfs = 1;
+    Out = 0;
+
+    do
+    {
+      if ( SKIP_Code() == FAILURE )
+        return;
+
+      switch ( CUR.opcode )
+      {
+      case 0x58:      /* IF */
+        nIfs++;
+        break;
+
+      case 0x1B:      /* ELSE */
+        Out = FT_BOOL( nIfs == 1 );
+        break;
+
+      case 0x59:      /* EIF */
+        nIfs--;
+        Out = FT_BOOL( nIfs == 0 );
+        break;
+      }
+    } while ( Out == 0 );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ELSE[]:       ELSE                                                    */
+  /* Opcode range: 0x1B                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_ELSE( INS_ARG )
+  {
+    FT_Int  nIfs;
+
+    FT_UNUSED_ARG;
+
+
+    nIfs = 1;
+
+    do
+    {
+      if ( SKIP_Code() == FAILURE )
+        return;
+
+      switch ( CUR.opcode )
+      {
+      case 0x58:    /* IF */
+        nIfs++;
+        break;
+
+      case 0x59:    /* EIF */
+        nIfs--;
+        break;
+      }
+    } while ( nIfs != 0 );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DEFINING AND USING FUNCTIONS AND INSTRUCTIONS                         */
+  /*                                                                       */
+  /*   Instructions appear in the specification's order.                   */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FDEF[]:       Function DEFinition                                     */
+  /* Opcode range: 0x2C                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_FDEF( INS_ARG )
+  {
+    FT_ULong       n;
+    TT_DefRecord*  rec;
+    TT_DefRecord*  limit;
+
+
+    /* some font programs are broken enough to redefine functions! */
+    /* We will then parse the current table.                       */
+
+    rec   = CUR.FDefs;
+    limit = rec + CUR.numFDefs;
+    n     = args[0];
+
+    for ( ; rec < limit; rec++ )
+    {
+      if ( rec->opc == n )
+        break;
+    }
+
+    if ( rec == limit )
+    {
+      /* check that there is enough room for new functions */
+      if ( CUR.numFDefs >= CUR.maxFDefs )
+      {
+        CUR.error = TT_Err_Too_Many_Function_Defs;
+        return;
+      }
+      CUR.numFDefs++;
+    }
+
+    rec->range  = CUR.curRange;
+    rec->opc    = n;
+    rec->start  = CUR.IP + 1;
+    rec->active = TRUE;
+
+    if ( n > CUR.maxFunc )
+      CUR.maxFunc = n;
+
+    /* Now skip the whole function definition. */
+    /* We don't allow nested IDEFS & FDEFs.    */
+
+    while ( SKIP_Code() == SUCCESS )
+    {
+      switch ( CUR.opcode )
+      {
+      case 0x89:    /* IDEF */
+      case 0x2C:    /* FDEF */
+        CUR.error = TT_Err_Nested_DEFS;
+        return;
+
+      case 0x2D:   /* ENDF */
+        return;
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ENDF[]:       END Function definition                                 */
+  /* Opcode range: 0x2D                                                    */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_ENDF( INS_ARG )
+  {
+    TT_CallRec*  pRec;
+
+    FT_UNUSED_ARG;
+
+
+    if ( CUR.callTop <= 0 )     /* We encountered an ENDF without a call */
+    {
+      CUR.error = TT_Err_ENDF_In_Exec_Stream;
+      return;
+    }
+
+    CUR.callTop--;
+
+    pRec = &CUR.callStack[CUR.callTop];
+
+    pRec->Cur_Count--;
+
+    CUR.step_ins = FALSE;
+
+    if ( pRec->Cur_Count > 0 )
+    {
+      CUR.callTop++;
+      CUR.IP = pRec->Cur_Restart;
+    }
+    else
+      /* Loop through the current function */
+      INS_Goto_CodeRange( pRec->Caller_Range,
+                          pRec->Caller_IP );
+
+    /* Exit the current call frame.                      */
+
+    /* NOTE: If the last intruction of a program is a    */
+    /*       CALL or LOOPCALL, the return address is     */
+    /*       always out of the code range.  This is a    */
+    /*       valid address, and it is why we do not test */
+    /*       the result of Ins_Goto_CodeRange() here!    */
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* CALL[]:       CALL function                                           */
+  /* Opcode range: 0x2B                                                    */
+  /* Stack:        uint32? -->                                             */
+  /*                                                                       */
+  static void
+  Ins_CALL( INS_ARG )
+  {
+    FT_ULong       F;
+    TT_CallRec*    pCrec;
+    TT_DefRecord*  def;
+
+
+    /* first of all, check the index */
+
+    F = args[0];
+    if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+      goto Fail;
+
+    /* Except for some old Apple fonts, all functions in a TrueType */
+    /* font are defined in increasing order, starting from 0.  This */
+    /* means that we normally have                                  */
+    /*                                                              */
+    /*    CUR.maxFunc+1 == CUR.numFDefs                             */
+    /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
+    /*                                                              */
+    /* If this isn't true, we need to look up the function table.   */
+
+    def = CUR.FDefs + F;
+    if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
+    {
+      /* look up the FDefs table */
+      TT_DefRecord*  limit;
+
+
+      def   = CUR.FDefs;
+      limit = def + CUR.numFDefs;
+
+      while ( def < limit && def->opc != F )
+        def++;
+
+      if ( def == limit )
+        goto Fail;
+    }
+
+    /* check that the function is active */
+    if ( !def->active )
+      goto Fail;
+
+    /* check the call stack */
+    if ( CUR.callTop >= CUR.callSize )
+    {
+      CUR.error = TT_Err_Stack_Overflow;
+      return;
+    }
+
+    pCrec = CUR.callStack + CUR.callTop;
+
+    pCrec->Caller_Range = CUR.curRange;
+    pCrec->Caller_IP    = CUR.IP + 1;
+    pCrec->Cur_Count    = 1;
+    pCrec->Cur_Restart  = def->start;
+
+    CUR.callTop++;
+
+    INS_Goto_CodeRange( def->range,
+                        def->start );
+
+    CUR.step_ins = FALSE;
+    return;
+
+  Fail:
+    CUR.error = TT_Err_Invalid_Reference;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* LOOPCALL[]:   LOOP and CALL function                                  */
+  /* Opcode range: 0x2A                                                    */
+  /* Stack:        uint32? Eint16? -->                                     */
+  /*                                                                       */
+  static void
+  Ins_LOOPCALL( INS_ARG )
+  {
+    FT_ULong       F;
+    TT_CallRec*    pCrec;
+    TT_DefRecord*  def;
+
+
+    /* first of all, check the index */
+    F = args[1];
+    if ( BOUNDS( F, CUR.maxFunc + 1 ) )
+      goto Fail;
+
+    /* Except for some old Apple fonts, all functions in a TrueType */
+    /* font are defined in increasing order, starting from 0.  This */
+    /* means that we normally have                                  */
+    /*                                                              */
+    /*    CUR.maxFunc+1 == CUR.numFDefs                             */
+    /*    CUR.FDefs[n].opc == n for n in 0..CUR.maxFunc             */
+    /*                                                              */
+    /* If this isn't true, we need to look up the function table.   */
+
+    def = CUR.FDefs + F;
+    if ( CUR.maxFunc + 1 != CUR.numFDefs || def->opc != F )
+    {
+      /* look up the FDefs table */
+      TT_DefRecord*  limit;
+
+
+      def   = CUR.FDefs;
+      limit = def + CUR.numFDefs;
+
+      while ( def < limit && def->opc != F )
+        def++;
+
+      if ( def == limit )
+        goto Fail;
+    }
+
+    /* check that the function is active */
+    if ( !def->active )
+      goto Fail;
+
+    /* check stack */
+    if ( CUR.callTop >= CUR.callSize )
+    {
+      CUR.error = TT_Err_Stack_Overflow;
+      return;
+    }
+
+    if ( args[0] > 0 )
+    {
+      pCrec = CUR.callStack + CUR.callTop;
+
+      pCrec->Caller_Range = CUR.curRange;
+      pCrec->Caller_IP    = CUR.IP + 1;
+      pCrec->Cur_Count    = (FT_Int)args[0];
+      pCrec->Cur_Restart  = def->start;
+
+      CUR.callTop++;
+
+      INS_Goto_CodeRange( def->range, def->start );
+
+      CUR.step_ins = FALSE;
+    }
+    return;
+
+  Fail:
+    CUR.error = TT_Err_Invalid_Reference;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* IDEF[]:       Instruction DEFinition                                  */
+  /* Opcode range: 0x89                                                    */
+  /* Stack:        Eint8 -->                                               */
+  /*                                                                       */
+  static void
+  Ins_IDEF( INS_ARG )
+  {
+    TT_DefRecord*  def;
+    TT_DefRecord*  limit;
+
+
+    /*  First of all, look for the same function in our table */
+
+    def   = CUR.IDefs;
+    limit = def + CUR.numIDefs;
+
+    for ( ; def < limit; def++ )
+      if ( def->opc == (FT_ULong)args[0] )
+        break;
+
+    if ( def == limit )
+    {
+      /* check that there is enough room for a new instruction */
+      if ( CUR.numIDefs >= CUR.maxIDefs )
+      {
+        CUR.error = TT_Err_Too_Many_Instruction_Defs;
+        return;
+      }
+      CUR.numIDefs++;
+    }
+
+    def->opc    = args[0];
+    def->start  = CUR.IP+1;
+    def->range  = CUR.curRange;
+    def->active = TRUE;
+
+    if ( (FT_ULong)args[0] > CUR.maxIns )
+      CUR.maxIns = args[0];
+
+    /* Now skip the whole function definition. */
+    /* We don't allow nested IDEFs & FDEFs.    */
+
+    while ( SKIP_Code() == SUCCESS )
+    {
+      switch ( CUR.opcode )
+      {
+      case 0x89:   /* IDEF */
+      case 0x2C:   /* FDEF */
+        CUR.error = TT_Err_Nested_DEFS;
+        return;
+      case 0x2D:   /* ENDF */
+        return;
+      }
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* PUSHING DATA ONTO THE INTERPRETER STACK                               */
+  /*                                                                       */
+  /*   Instructions appear in the specification's order.                   */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* NPUSHB[]:     PUSH N Bytes                                            */
+  /* Opcode range: 0x40                                                    */
+  /* Stack:        --> uint32...                                           */
+  /*                                                                       */
+  static void
+  Ins_NPUSHB( INS_ARG )
+  {
+    FT_UShort  L, K;
+
+
+    L = (FT_UShort)CUR.code[CUR.IP + 1];
+
+    if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+    {
+      CUR.error = TT_Err_Stack_Overflow;
+      return;
+    }
+
+    for ( K = 1; K <= L; K++ )
+      args[K - 1] = CUR.code[CUR.IP + K + 1];
+
+    CUR.new_top += L;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* NPUSHW[]:     PUSH N Words                                            */
+  /* Opcode range: 0x41                                                    */
+  /* Stack:        --> int32...                                            */
+  /*                                                                       */
+  static void
+  Ins_NPUSHW( INS_ARG )
+  {
+    FT_UShort  L, K;
+
+
+    L = (FT_UShort)CUR.code[CUR.IP + 1];
+
+    if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+    {
+      CUR.error = TT_Err_Stack_Overflow;
+      return;
+    }
+
+    CUR.IP += 2;
+
+    for ( K = 0; K < L; K++ )
+      args[K] = GET_ShortIns();
+
+    CUR.step_ins = FALSE;
+    CUR.new_top += L;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* PUSHB[abc]:   PUSH Bytes                                              */
+  /* Opcode range: 0xB0-0xB7                                               */
+  /* Stack:        --> uint32...                                           */
+  /*                                                                       */
+  static void
+  Ins_PUSHB( INS_ARG )
+  {
+    FT_UShort  L, K;
+
+
+    L = (FT_UShort)(CUR.opcode - 0xB0 + 1);
+
+    if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+    {
+      CUR.error = TT_Err_Stack_Overflow;
+      return;
+    }
+
+    for ( K = 1; K <= L; K++ )
+      args[K - 1] = CUR.code[CUR.IP + K];
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* PUSHW[abc]:   PUSH Words                                              */
+  /* Opcode range: 0xB8-0xBF                                               */
+  /* Stack:        --> int32...                                            */
+  /*                                                                       */
+  static void
+  Ins_PUSHW( INS_ARG )
+  {
+    FT_UShort  L, K;
+
+
+    L = (FT_UShort)(CUR.opcode - 0xB8 + 1);
+
+    if ( BOUNDS( L, CUR.stackSize + 1 - CUR.top ) )
+    {
+      CUR.error = TT_Err_Stack_Overflow;
+      return;
+    }
+
+    CUR.IP++;
+
+    for ( K = 0; K < L; K++ )
+      args[K] = GET_ShortIns();
+
+    CUR.step_ins = FALSE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MANAGING THE GRAPHICS STATE                                           */
+  /*                                                                       */
+  /*  Instructions appear in the specs' order.                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* GC[a]:        Get Coordinate projected onto                           */
+  /* Opcode range: 0x46-0x47                                               */
+  /* Stack:        uint32 --> f26.6                                        */
+  /*                                                                       */
+  /* BULLSHIT: Measures from the original glyph must be taken along the    */
+  /*           dual projection vector!                                     */
+  /*                                                                       */
+  static void
+  Ins_GC( INS_ARG )
+  {
+    FT_ULong    L;
+    FT_F26Dot6  R;
+
+
+    L = (FT_ULong)args[0];
+
+    if ( BOUNDS( L, CUR.zp2.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+      {
+        CUR.error = TT_Err_Invalid_Reference;
+        return;
+      }
+      else
+        R = 0;
+    }
+    else
+    {
+      if ( CUR.opcode & 1 )
+        R = CUR_Func_dualproj( CUR.zp2.org + L, NULL_Vector );
+      else
+        R = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+    }
+
+    args[0] = R;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SCFS[]:       Set Coordinate From Stack                               */
+  /* Opcode range: 0x48                                                    */
+  /* Stack:        f26.6 uint32 -->                                        */
+  /*                                                                       */
+  /* Formula:                                                              */
+  /*                                                                       */
+  /*   OA := OA + ( value - OA.p )/( f.p ) * f                             */
+  /*                                                                       */
+  static void
+  Ins_SCFS( INS_ARG )
+  {
+    FT_Long    K;
+    FT_UShort  L;
+
+
+    L = (FT_UShort)args[0];
+
+    if ( BOUNDS( L, CUR.zp2.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    K = CUR_Func_project( CUR.zp2.cur + L, NULL_Vector );
+
+    CUR_Func_move( &CUR.zp2, L, args[1] - K );
+
+    /* not part of the specs, but here for safety */
+
+    if ( CUR.GS.gep2 == 0 )
+      CUR.zp2.org[L] = CUR.zp2.cur[L];
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MD[a]:        Measure Distance                                        */
+  /* Opcode range: 0x49-0x4A                                               */
+  /* Stack:        uint32 uint32 --> f26.6                                 */
+  /*                                                                       */
+  /* BULLSHIT: Measure taken in the original glyph must be along the dual  */
+  /*           projection vector.                                          */
+  /*                                                                       */
+  /* Second BULLSHIT: Flag attributes are inverted!                        */
+  /*                  0 => measure distance in original outline            */
+  /*                  1 => measure distance in grid-fitted outline         */
+  /*                                                                       */
+  /* Third one: `zp0 - zp1', and not `zp2 - zp1!                           */
+  /*                                                                       */
+  static void
+  Ins_MD( INS_ARG )
+  {
+    FT_UShort   K, L;
+    FT_F26Dot6  D;
+
+
+    K = (FT_UShort)args[1];
+    L = (FT_UShort)args[0];
+
+    if( BOUNDS( L, CUR.zp0.n_points ) ||
+        BOUNDS( K, CUR.zp1.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+      {
+        CUR.error = TT_Err_Invalid_Reference;
+        return;
+      }
+      D = 0;
+    }
+    else
+    {
+      if ( CUR.opcode & 1 )
+        D = CUR_Func_project( CUR.zp0.cur + L, CUR.zp1.cur + K );
+      else
+        D = CUR_Func_dualproj( CUR.zp0.org + L, CUR.zp1.org + K );
+    }
+
+    args[0] = D;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SDPVTL[a]:    Set Dual PVector to Line                                */
+  /* Opcode range: 0x86-0x87                                               */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_SDPVTL( INS_ARG )
+  {
+    FT_Long    A, B, C;
+    FT_UShort  p1, p2;   /* was FT_Int in pas type ERROR */
+
+
+    p1 = (FT_UShort)args[1];
+    p2 = (FT_UShort)args[0];
+
+    if ( BOUNDS( p2, CUR.zp1.n_points ) ||
+         BOUNDS( p1, CUR.zp2.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    {
+      FT_Vector* v1 = CUR.zp1.org + p2;
+      FT_Vector* v2 = CUR.zp2.org + p1;
+
+
+      A = v1->x - v2->x;
+      B = v1->y - v2->y;
+    }
+
+    if ( ( CUR.opcode & 1 ) != 0 )
+    {
+      C =  B;   /* counter clockwise rotation */
+      B =  A;
+      A = -C;
+    }
+
+    NORMalize( A, B, &CUR.GS.dualVector );
+
+    {
+      FT_Vector*  v1 = CUR.zp1.cur + p2;
+      FT_Vector*  v2 = CUR.zp2.cur + p1;
+
+
+      A = v1->x - v2->x;
+      B = v1->y - v2->y;
+    }
+
+    if ( ( CUR.opcode & 1 ) != 0 )
+    {
+      C =  B;   /* counter clockwise rotation */
+      B =  A;
+      A = -C;
+    }
+
+    NORMalize( A, B, &CUR.GS.projVector );
+
+    COMPUTE_Funcs();
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SZP0[]:       Set Zone Pointer 0                                      */
+  /* Opcode range: 0x13                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SZP0( INS_ARG )
+  {
+    switch ( (FT_Int)args[0] )
+    {
+    case 0:
+      CUR.zp0 = CUR.twilight;
+      break;
+
+    case 1:
+      CUR.zp0 = CUR.pts;
+      break;
+
+    default:
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    CUR.GS.gep0 = (FT_UShort)args[0];
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SZP1[]:       Set Zone Pointer 1                                      */
+  /* Opcode range: 0x14                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SZP1( INS_ARG )
+  {
+    switch ( (FT_Int)args[0] )
+    {
+    case 0:
+      CUR.zp1 = CUR.twilight;
+      break;
+
+    case 1:
+      CUR.zp1 = CUR.pts;
+      break;
+
+    default:
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    CUR.GS.gep1 = (FT_UShort)args[0];
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SZP2[]:       Set Zone Pointer 2                                      */
+  /* Opcode range: 0x15                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SZP2( INS_ARG )
+  {
+    switch ( (FT_Int)args[0] )
+    {
+    case 0:
+      CUR.zp2 = CUR.twilight;
+      break;
+
+    case 1:
+      CUR.zp2 = CUR.pts;
+      break;
+
+    default:
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    CUR.GS.gep2 = (FT_UShort)args[0];
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SZPS[]:       Set Zone PointerS                                       */
+  /* Opcode range: 0x16                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SZPS( INS_ARG )
+  {
+    switch ( (FT_Int)args[0] )
+    {
+    case 0:
+      CUR.zp0 = CUR.twilight;
+      break;
+
+    case 1:
+      CUR.zp0 = CUR.pts;
+      break;
+
+    default:
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    CUR.zp1 = CUR.zp0;
+    CUR.zp2 = CUR.zp0;
+
+    CUR.GS.gep0 = (FT_UShort)args[0];
+    CUR.GS.gep1 = (FT_UShort)args[0];
+    CUR.GS.gep2 = (FT_UShort)args[0];
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* INSTCTRL[]:   INSTruction ConTRoL                                     */
+  /* Opcode range: 0x8e                                                    */
+  /* Stack:        int32 int32 -->                                         */
+  /*                                                                       */
+  static void
+  Ins_INSTCTRL( INS_ARG )
+  {
+    FT_Long  K, L;
+
+
+    K = args[1];
+    L = args[0];
+
+    if ( K < 1 || K > 2 )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    if ( L != 0 )
+        L = K;
+
+    CUR.GS.instruct_control = FT_BOOL(
+      ( (FT_Byte)CUR.GS.instruct_control & ~(FT_Byte)K ) | (FT_Byte)L );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SCANCTRL[]:   SCAN ConTRoL                                            */
+  /* Opcode range: 0x85                                                    */
+  /* Stack:        uint32? -->                                             */
+  /*                                                                       */
+  static void
+  Ins_SCANCTRL( INS_ARG )
+  {
+    FT_Int  A;
+
+
+    /* Get Threshold */
+    A = (FT_Int)( args[0] & 0xFF );
+
+    if ( A == 0xFF )
+    {
+      CUR.GS.scan_control = TRUE;
+      return;
+    }
+    else if ( A == 0 )
+    {
+      CUR.GS.scan_control = FALSE;
+      return;
+    }
+
+    A *= 64;
+
+#if 0
+    if ( (args[0] & 0x100) != 0 && CUR.metrics.pointSize <= A )
+      CUR.GS.scan_control = TRUE;
+#endif
+
+    if ( (args[0] & 0x200) != 0 && CUR.tt_metrics.rotated )
+      CUR.GS.scan_control = TRUE;
+
+    if ( (args[0] & 0x400) != 0 && CUR.tt_metrics.stretched )
+      CUR.GS.scan_control = TRUE;
+
+#if 0
+    if ( (args[0] & 0x800) != 0 && CUR.metrics.pointSize > A )
+      CUR.GS.scan_control = FALSE;
+#endif
+
+    if ( (args[0] & 0x1000) != 0 && CUR.tt_metrics.rotated )
+      CUR.GS.scan_control = FALSE;
+
+    if ( (args[0] & 0x2000) != 0 && CUR.tt_metrics.stretched )
+      CUR.GS.scan_control = FALSE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SCANTYPE[]:   SCAN TYPE                                               */
+  /* Opcode range: 0x8D                                                    */
+  /* Stack:        uint32? -->                                             */
+  /*                                                                       */
+  static void
+  Ins_SCANTYPE( INS_ARG )
+  {
+    /* for compatibility with future enhancements, */
+    /* we must ignore new modes                    */
+
+    if ( args[0] >= 0 && args[0] <= 5 )
+    {
+      if ( args[0] == 3 )
+        args[0] = 2;
+
+      CUR.GS.scan_type = (FT_Int)args[0];
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MANAGING OUTLINES                                                     */
+  /*                                                                       */
+  /*   Instructions appear in the specification's order.                   */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FLIPPT[]:     FLIP PoinT                                              */
+  /* Opcode range: 0x80                                                    */
+  /* Stack:        uint32... -->                                           */
+  /*                                                                       */
+  static void
+  Ins_FLIPPT( INS_ARG )
+  {
+    FT_UShort  point;
+
+    FT_UNUSED_ARG;
+
+
+    if ( CUR.top < CUR.GS.loop )
+    {
+      CUR.error = TT_Err_Too_Few_Arguments;
+      return;
+    }
+
+    while ( CUR.GS.loop > 0 )
+    {
+      CUR.args--;
+
+      point = (FT_UShort)CUR.stack[CUR.args];
+
+      if ( BOUNDS( point, CUR.pts.n_points ) )
+      {
+        if ( CUR.pedantic_hinting )
+        {
+          CUR.error = TT_Err_Invalid_Reference;
+          return;
+        }
+      }
+      else
+        CUR.pts.tags[point] ^= FT_CURVE_TAG_ON;
+
+      CUR.GS.loop--;
+    }
+
+    CUR.GS.loop = 1;
+    CUR.new_top = CUR.args;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FLIPRGON[]:   FLIP RanGe ON                                           */
+  /* Opcode range: 0x81                                                    */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_FLIPRGON( INS_ARG )
+  {
+    FT_UShort  I, K, L;
+
+
+    K = (FT_UShort)args[1];
+    L = (FT_UShort)args[0];
+
+    if ( BOUNDS( K, CUR.pts.n_points ) ||
+         BOUNDS( L, CUR.pts.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    for ( I = L; I <= K; I++ )
+      CUR.pts.tags[I] |= FT_CURVE_TAG_ON;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* FLIPRGOFF:    FLIP RanGe OFF                                          */
+  /* Opcode range: 0x82                                                    */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_FLIPRGOFF( INS_ARG )
+  {
+    FT_UShort  I, K, L;
+
+
+    K = (FT_UShort)args[1];
+    L = (FT_UShort)args[0];
+
+    if ( BOUNDS( K, CUR.pts.n_points ) ||
+         BOUNDS( L, CUR.pts.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    for ( I = L; I <= K; I++ )
+      CUR.pts.tags[I] &= ~FT_CURVE_TAG_ON;
+  }
+
+
+  static FT_Bool
+  Compute_Point_Displacement( EXEC_OP_ FT_F26Dot6*   x,
+                                       FT_F26Dot6*   y,
+                                       TT_GlyphZone  zone,
+                                       FT_UShort*    refp )
+  {
+    TT_GlyphZoneRec  zp;
+    FT_UShort        p;
+    FT_F26Dot6       d;
+
+
+    if ( CUR.opcode & 1 )
+    {
+      zp = CUR.zp0;
+      p  = CUR.GS.rp1;
+    }
+    else
+    {
+      zp = CUR.zp1;
+      p  = CUR.GS.rp2;
+    }
+
+    if ( BOUNDS( p, zp.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return FAILURE;
+    }
+
+    *zone = zp;
+    *refp = p;
+
+    d = CUR_Func_project( zp.cur + p, zp.org + p );
+
+#ifdef NO_APPLE_PATENT
+
+    *x = TT_MulFix14( d, CUR.GS.freeVector.x );
+    *y = TT_MulFix14( d, CUR.GS.freeVector.y );
+
+#else
+
+    *x = TT_MULDIV( d,
+                    (FT_Long)CUR.GS.freeVector.x * 0x10000L,
+                    CUR.F_dot_P );
+    *y = TT_MULDIV( d,
+                    (FT_Long)CUR.GS.freeVector.y * 0x10000L,
+                    CUR.F_dot_P );
+
+#endif /* NO_APPLE_PATENT */
+
+    return SUCCESS;
+  }
+
+
+  static void
+  Move_Zp2_Point( EXEC_OP_ FT_UShort   point,
+                           FT_F26Dot6  dx,
+                           FT_F26Dot6  dy,
+                           FT_Bool     touch )
+  {
+    if ( CUR.GS.freeVector.x != 0 )
+    {
+      CUR.zp2.cur[point].x += dx;
+      if ( touch )
+        CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X;
+    }
+
+    if ( CUR.GS.freeVector.y != 0 )
+    {
+      CUR.zp2.cur[point].y += dy;
+      if ( touch )
+        CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SHP[a]:       SHift Point by the last point                           */
+  /* Opcode range: 0x32-0x33                                               */
+  /* Stack:        uint32... -->                                           */
+  /*                                                                       */
+  static void
+  Ins_SHP( INS_ARG )
+  {
+    TT_GlyphZoneRec  zp;
+    FT_UShort        refp;
+
+    FT_F26Dot6       dx,
+                     dy;
+    FT_UShort        point;
+
+    FT_UNUSED_ARG;
+
+
+    if ( CUR.top < CUR.GS.loop )
+    {
+      CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+      return;
+
+    while ( CUR.GS.loop > 0 )
+    {
+      CUR.args--;
+      point = (FT_UShort)CUR.stack[CUR.args];
+
+      if ( BOUNDS( point, CUR.zp2.n_points ) )
+      {
+        if ( CUR.pedantic_hinting )
+        {
+          CUR.error = TT_Err_Invalid_Reference;
+          return;
+        }
+      }
+      else
+        /* XXX: UNDOCUMENTED! SHP touches the points */
+        MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+      CUR.GS.loop--;
+    }
+
+    CUR.GS.loop = 1;
+    CUR.new_top = CUR.args;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SHC[a]:       SHift Contour                                           */
+  /* Opcode range: 0x34-35                                                 */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SHC( INS_ARG )
+  {
+    TT_GlyphZoneRec zp;
+    FT_UShort       refp;
+    FT_F26Dot6      dx,
+                    dy;
+
+    FT_Short        contour;
+    FT_UShort       first_point, last_point, i;
+
+
+    contour = (FT_UShort)args[0];
+
+    if ( BOUNDS( contour, CUR.pts.n_contours ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+      return;
+
+    if ( contour == 0 )
+      first_point = 0;
+    else
+      first_point = (FT_UShort)(CUR.pts.contours[contour - 1] + 1);
+
+    last_point = CUR.pts.contours[contour];
+
+    /* XXX: this is probably wrong... at least it prevents memory */
+    /*      corruption when zp2 is the twilight zone              */
+    if ( last_point > CUR.zp2.n_points )
+    {
+      if ( CUR.zp2.n_points > 0 )
+        last_point = (FT_UShort)(CUR.zp2.n_points - 1);
+      else
+        last_point = 0;
+    }
+
+    /* XXX: UNDOCUMENTED! SHC doesn't touch the points */
+    for ( i = first_point; i <= last_point; i++ )
+    {
+      if ( zp.cur != CUR.zp2.cur || refp != i )
+        MOVE_Zp2_Point( i, dx, dy, FALSE );
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SHZ[a]:       SHift Zone                                              */
+  /* Opcode range: 0x36-37                                                 */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_SHZ( INS_ARG )
+  {
+    TT_GlyphZoneRec zp;
+    FT_UShort       refp;
+    FT_F26Dot6      dx,
+                    dy;
+
+    FT_UShort       last_point, i;
+
+
+    if ( BOUNDS( args[0], 2 ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
+      return;
+
+    if ( CUR.zp2.n_points > 0 )
+      last_point = (FT_UShort)(CUR.zp2.n_points - 1);
+    else
+      last_point = 0;
+
+    /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */
+    for ( i = 0; i <= last_point; i++ )
+    {
+      if ( zp.cur != CUR.zp2.cur || refp != i )
+        MOVE_Zp2_Point( i, dx, dy, FALSE );
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* SHPIX[]:      SHift points by a PIXel amount                          */
+  /* Opcode range: 0x38                                                    */
+  /* Stack:        f26.6 uint32... -->                                     */
+  /*                                                                       */
+  static void
+  Ins_SHPIX( INS_ARG )
+  {
+    FT_F26Dot6  dx, dy;
+    FT_UShort   point;
+
+
+    if ( CUR.top < CUR.GS.loop + 1 )
+    {
+      CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    dx = TT_MulFix14( args[0], CUR.GS.freeVector.x );
+    dy = TT_MulFix14( args[0], CUR.GS.freeVector.y );
+
+    while ( CUR.GS.loop > 0 )
+    {
+      CUR.args--;
+
+      point = (FT_UShort)CUR.stack[CUR.args];
+
+      if ( BOUNDS( point, CUR.zp2.n_points ) )
+      {
+        if ( CUR.pedantic_hinting )
+        {
+          CUR.error = TT_Err_Invalid_Reference;
+          return;
+        }
+      }
+      else
+        MOVE_Zp2_Point( point, dx, dy, TRUE );
+
+      CUR.GS.loop--;
+    }
+
+    CUR.GS.loop = 1;
+    CUR.new_top = CUR.args;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MSIRP[a]:     Move Stack Indirect Relative Position                   */
+  /* Opcode range: 0x3A-0x3B                                               */
+  /* Stack:        f26.6 uint32 -->                                        */
+  /*                                                                       */
+  static void
+  Ins_MSIRP( INS_ARG )
+  {
+    FT_UShort   point;
+    FT_F26Dot6  distance;
+
+
+    point = (FT_UShort)args[0];
+
+    if ( BOUNDS( point,      CUR.zp1.n_points ) ||
+         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    /* XXX: UNDOCUMENTED! behaviour */
+    if ( CUR.GS.gep0 == 0 )   /* if in twilight zone */
+    {
+      CUR.zp1.org[point] = CUR.zp0.org[CUR.GS.rp0];
+      CUR.zp1.cur[point] = CUR.zp1.org[point];
+    }
+
+    distance = CUR_Func_project( CUR.zp1.cur + point,
+                                 CUR.zp0.cur + CUR.GS.rp0 );
+
+    CUR_Func_move( &CUR.zp1, point, args[1] - distance );
+
+    CUR.GS.rp1 = CUR.GS.rp0;
+    CUR.GS.rp2 = point;
+
+    if ( (CUR.opcode & 1) != 0 )
+      CUR.GS.rp0 = point;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MDAP[a]:      Move Direct Absolute Point                              */
+  /* Opcode range: 0x2E-0x2F                                               */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_MDAP( INS_ARG )
+  {
+    FT_UShort   point;
+    FT_F26Dot6  cur_dist,
+                distance;
+
+
+    point = (FT_UShort)args[0];
+
+    if ( BOUNDS( point, CUR.zp0.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    /* XXX: Is there some undocumented feature while in the */
+    /*      twilight zone? ?                                */
+    if ( ( CUR.opcode & 1 ) != 0 )
+    {
+      cur_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+      distance = CUR_Func_round( cur_dist,
+                                 CUR.tt_metrics.compensations[0] ) - cur_dist;
+    }
+    else
+      distance = 0;
+
+    CUR_Func_move( &CUR.zp0, point, distance );
+
+    CUR.GS.rp0 = point;
+    CUR.GS.rp1 = point;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MIAP[a]:      Move Indirect Absolute Point                            */
+  /* Opcode range: 0x3E-0x3F                                               */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_MIAP( INS_ARG )
+  {
+    FT_ULong    cvtEntry;
+    FT_UShort   point;
+    FT_F26Dot6  distance,
+                org_dist;
+
+
+    cvtEntry = (FT_ULong)args[1];
+    point    = (FT_UShort)args[0];
+
+    if ( BOUNDS( point,    CUR.zp0.n_points ) ||
+         BOUNDS( cvtEntry, CUR.cvtSize )      )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    /* UNDOCUMENTED!                                     */
+    /*                                                   */
+    /* The behaviour of an MIAP instruction is quite     */
+    /* different when used in the twilight zone.         */
+    /*                                                   */
+    /* First, no control value cutin test is performed   */
+    /* as it would fail anyway.  Second, the original    */
+    /* point, i.e. (org_x,org_y) of zp0.point, is set    */
+    /* to the absolute, unrounded distance found in      */
+    /* the CVT.                                          */
+    /*                                                   */
+    /* This is used in the CVT programs of the Microsoft */
+    /* fonts Arial, Times, etc., in order to re-adjust   */
+    /* some key font heights.  It allows the use of the  */
+    /* IP instruction in the twilight zone, which        */
+    /* otherwise would be `illegal' according to the     */
+    /* specification.                                    */
+    /*                                                   */
+    /* We implement it with a special sequence for the   */
+    /* twilight zone.  This is a bad hack, but it seems  */
+    /* to work.                                          */
+
+    distance = CUR_Func_read_cvt( cvtEntry );
+
+    if ( CUR.GS.gep0 == 0 )   /* If in twilight zone */
+    {
+      CUR.zp0.org[point].x = TT_MulFix14( distance, CUR.GS.freeVector.x );
+      CUR.zp0.org[point].y = TT_MulFix14( distance, CUR.GS.freeVector.y ),
+      CUR.zp0.cur[point]   = CUR.zp0.org[point];
+    }
+
+    org_dist = CUR_Func_project( CUR.zp0.cur + point, NULL_Vector );
+
+    if ( ( CUR.opcode & 1 ) != 0 )   /* rounding and control cutin flag */
+    {
+      if ( ABS( distance - org_dist ) > CUR.GS.control_value_cutin )
+        distance = org_dist;
+
+      distance = CUR_Func_round( distance, CUR.tt_metrics.compensations[0] );
+    }
+
+    CUR_Func_move( &CUR.zp0, point, distance - org_dist );
+
+    CUR.GS.rp0 = point;
+    CUR.GS.rp1 = point;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MDRP[abcde]:  Move Direct Relative Point                              */
+  /* Opcode range: 0xC0-0xDF                                               */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_MDRP( INS_ARG )
+  {
+    FT_UShort   point;
+    FT_F26Dot6  org_dist, distance;
+
+
+    point = (FT_UShort)args[0];
+
+    if ( BOUNDS( point,      CUR.zp1.n_points ) ||
+         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    /* XXX: Is there some undocumented feature while in the */
+    /*      twilight zone?                                  */
+
+    org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+                                  CUR.zp0.org + CUR.GS.rp0 );
+
+    /* single width cutin test */
+
+    if ( ABS( org_dist ) < CUR.GS.single_width_cutin )
+    {
+      if ( org_dist >= 0 )
+        org_dist = CUR.GS.single_width_value;
+      else
+        org_dist = -CUR.GS.single_width_value;
+    }
+
+    /* round flag */
+
+    if ( ( CUR.opcode & 4 ) != 0 )
+      distance = CUR_Func_round(
+                   org_dist,
+                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
+    else
+      distance = ROUND_None(
+                   org_dist,
+                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
+
+    /* minimum distance flag */
+
+    if ( ( CUR.opcode & 8 ) != 0 )
+    {
+      if ( org_dist >= 0 )
+      {
+        if ( distance < CUR.GS.minimum_distance )
+          distance = CUR.GS.minimum_distance;
+      }
+      else
+      {
+        if ( distance > -CUR.GS.minimum_distance )
+          distance = -CUR.GS.minimum_distance;
+      }
+    }
+
+    /* now move the point */
+
+    org_dist = CUR_Func_project( CUR.zp1.cur + point,
+                                 CUR.zp0.cur + CUR.GS.rp0 );
+
+    CUR_Func_move( &CUR.zp1, point, distance - org_dist );
+
+    CUR.GS.rp1 = CUR.GS.rp0;
+    CUR.GS.rp2 = point;
+
+    if ( ( CUR.opcode & 16 ) != 0 )
+      CUR.GS.rp0 = point;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MIRP[abcde]:  Move Indirect Relative Point                            */
+  /* Opcode range: 0xE0-0xFF                                               */
+  /* Stack:        int32? uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_MIRP( INS_ARG )
+  {
+    FT_UShort   point;
+    FT_ULong    cvtEntry;
+
+    FT_F26Dot6  cvt_dist,
+                distance,
+                cur_dist,
+                org_dist;
+
+
+    point    = (FT_UShort)args[0];
+    cvtEntry = (FT_ULong)( args[1] + 1 );
+
+    /* XXX: UNDOCUMENTED! cvt[-1] = 0 always */
+
+    if ( BOUNDS( point,      CUR.zp1.n_points ) ||
+         BOUNDS( cvtEntry,   CUR.cvtSize + 1 )  ||
+         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    if ( !cvtEntry )
+      cvt_dist = 0;
+    else
+      cvt_dist = CUR_Func_read_cvt( cvtEntry - 1 );
+
+    /* single width test */
+
+    if ( ABS( cvt_dist ) < CUR.GS.single_width_cutin )
+    {
+      if ( cvt_dist >= 0 )
+        cvt_dist =  CUR.GS.single_width_value;
+      else
+        cvt_dist = -CUR.GS.single_width_value;
+    }
+
+    /* XXX: UNDOCUMENTED! -- twilight zone */
+
+    if ( CUR.GS.gep1 == 0 )
+    {
+      CUR.zp1.org[point].x = CUR.zp0.org[CUR.GS.rp0].x +
+                             TT_MulFix14( cvt_dist, CUR.GS.freeVector.x );
+
+      CUR.zp1.org[point].y = CUR.zp0.org[CUR.GS.rp0].y +
+                             TT_MulFix14( cvt_dist, CUR.GS.freeVector.y );
+
+      CUR.zp1.cur[point] = CUR.zp1.org[point];
+    }
+
+    org_dist = CUR_Func_dualproj( CUR.zp1.org + point,
+                                  CUR.zp0.org + CUR.GS.rp0 );
+
+    cur_dist = CUR_Func_project( CUR.zp1.cur + point,
+                                 CUR.zp0.cur + CUR.GS.rp0 );
+
+    /* auto-flip test */
+
+    if ( CUR.GS.auto_flip )
+    {
+      if ( ( org_dist ^ cvt_dist ) < 0 )
+        cvt_dist = -cvt_dist;
+    }
+
+    /* control value cutin and round */
+
+    if ( ( CUR.opcode & 4 ) != 0 )
+    {
+      /* XXX: UNDOCUMENTED!  Only perform cut-in test when both points */
+      /*      refer to the same zone.                                  */
+
+      if ( CUR.GS.gep0 == CUR.GS.gep1 )
+        if ( ABS( cvt_dist - org_dist ) >= CUR.GS.control_value_cutin )
+          cvt_dist = org_dist;
+
+      distance = CUR_Func_round(
+                   cvt_dist,
+                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
+    }
+    else
+      distance = ROUND_None(
+                   cvt_dist,
+                   CUR.tt_metrics.compensations[CUR.opcode & 3] );
+
+    /* minimum distance test */
+
+    if ( ( CUR.opcode & 8 ) != 0 )
+    {
+      if ( org_dist >= 0 )
+      {
+        if ( distance < CUR.GS.minimum_distance )
+          distance = CUR.GS.minimum_distance;
+      }
+      else
+      {
+        if ( distance > -CUR.GS.minimum_distance )
+          distance = -CUR.GS.minimum_distance;
+      }
+    }
+
+    CUR_Func_move( &CUR.zp1, point, distance - cur_dist );
+
+    CUR.GS.rp1 = CUR.GS.rp0;
+
+    if ( ( CUR.opcode & 16 ) != 0 )
+      CUR.GS.rp0 = point;
+
+    /* XXX: UNDOCUMENTED! */
+
+    CUR.GS.rp2 = point;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ALIGNRP[]:    ALIGN Relative Point                                    */
+  /* Opcode range: 0x3C                                                    */
+  /* Stack:        uint32 uint32... -->                                    */
+  /*                                                                       */
+  static void
+  Ins_ALIGNRP( INS_ARG )
+  {
+    FT_UShort   point;
+    FT_F26Dot6  distance;
+
+    FT_UNUSED_ARG;
+
+
+    if ( CUR.top < CUR.GS.loop ||
+         BOUNDS( CUR.GS.rp0, CUR.zp0.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    while ( CUR.GS.loop > 0 )
+    {
+      CUR.args--;
+
+      point = (FT_UShort)CUR.stack[CUR.args];
+
+      if ( BOUNDS( point, CUR.zp1.n_points ) )
+      {
+        if ( CUR.pedantic_hinting )
+        {
+          CUR.error = TT_Err_Invalid_Reference;
+          return;
+        }
+      }
+      else
+      {
+        distance = CUR_Func_project( CUR.zp1.cur + point,
+                                     CUR.zp0.cur + CUR.GS.rp0 );
+
+        CUR_Func_move( &CUR.zp1, point, -distance );
+      }
+
+      CUR.GS.loop--;
+    }
+
+    CUR.GS.loop = 1;
+    CUR.new_top = CUR.args;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ISECT[]:      moves point to InterSECTion                             */
+  /* Opcode range: 0x0F                                                    */
+  /* Stack:        5 * uint32 -->                                          */
+  /*                                                                       */
+  static void
+  Ins_ISECT( INS_ARG )
+  {
+    FT_UShort   point,
+                a0, a1,
+                b0, b1;
+
+    FT_F26Dot6  discriminant;
+
+    FT_F26Dot6  dx,  dy,
+                dax, day,
+                dbx, dby;
+
+    FT_F26Dot6  val;
+
+    FT_Vector   R;
+
+
+    point = (FT_UShort)args[0];
+
+    a0 = (FT_UShort)args[1];
+    a1 = (FT_UShort)args[2];
+    b0 = (FT_UShort)args[3];
+    b1 = (FT_UShort)args[4];
+
+    if ( BOUNDS( b0, CUR.zp0.n_points )  ||
+         BOUNDS( b1, CUR.zp0.n_points )  ||
+         BOUNDS( a0, CUR.zp1.n_points )  ||
+         BOUNDS( a1, CUR.zp1.n_points )  ||
+         BOUNDS( point, CUR.zp2.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    dbx = CUR.zp0.cur[b1].x - CUR.zp0.cur[b0].x;
+    dby = CUR.zp0.cur[b1].y - CUR.zp0.cur[b0].y;
+
+    dax = CUR.zp1.cur[a1].x - CUR.zp1.cur[a0].x;
+    day = CUR.zp1.cur[a1].y - CUR.zp1.cur[a0].y;
+
+    dx = CUR.zp0.cur[b0].x - CUR.zp1.cur[a0].x;
+    dy = CUR.zp0.cur[b0].y - CUR.zp1.cur[a0].y;
+
+    CUR.zp2.tags[point] |= FT_CURVE_TAG_TOUCH_BOTH;
+
+    discriminant = TT_MULDIV( dax, -dby, 0x40 ) +
+                   TT_MULDIV( day, dbx, 0x40 );
+
+    if ( ABS( discriminant ) >= 0x40 )
+    {
+      val = TT_MULDIV( dx, -dby, 0x40 ) + TT_MULDIV( dy, dbx, 0x40 );
+
+      R.x = TT_MULDIV( val, dax, discriminant );
+      R.y = TT_MULDIV( val, day, discriminant );
+
+      CUR.zp2.cur[point].x = CUR.zp1.cur[a0].x + R.x;
+      CUR.zp2.cur[point].y = CUR.zp1.cur[a0].y + R.y;
+    }
+    else
+    {
+      /* else, take the middle of the middles of A and B */
+
+      CUR.zp2.cur[point].x = ( CUR.zp1.cur[a0].x +
+                               CUR.zp1.cur[a1].x +
+                               CUR.zp0.cur[b0].x +
+                               CUR.zp0.cur[b1].x ) / 4;
+      CUR.zp2.cur[point].y = ( CUR.zp1.cur[a0].y +
+                               CUR.zp1.cur[a1].y +
+                               CUR.zp0.cur[b0].y +
+                               CUR.zp0.cur[b1].y ) / 4;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* ALIGNPTS[]:   ALIGN PoinTS                                            */
+  /* Opcode range: 0x27                                                    */
+  /* Stack:        uint32 uint32 -->                                       */
+  /*                                                                       */
+  static void
+  Ins_ALIGNPTS( INS_ARG )
+  {
+    FT_UShort   p1, p2;
+    FT_F26Dot6  distance;
+
+
+    p1 = (FT_UShort)args[0];
+    p2 = (FT_UShort)args[1];
+
+    if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
+         BOUNDS( args[1], CUR.zp0.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    distance = CUR_Func_project( CUR.zp0.cur + p2,
+                                 CUR.zp1.cur + p1 ) / 2;
+
+    CUR_Func_move( &CUR.zp1, p1, distance );
+    CUR_Func_move( &CUR.zp0, p2, -distance );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* IP[]:         Interpolate Point                                       */
+  /* Opcode range: 0x39                                                    */
+  /* Stack:        uint32... -->                                           */
+  /*                                                                       */
+  static void
+  Ins_IP( INS_ARG )
+  {
+    FT_F26Dot6  org_a, org_b, org_x,
+                cur_a, cur_b, cur_x,
+                distance;
+    FT_UShort   point;
+
+    FT_UNUSED_ARG;
+
+
+    if ( CUR.top < CUR.GS.loop )
+    {
+      CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    /* XXX: There are some glyphs in some braindead but popular  */
+    /*      fonts out there (e.g. [aeu]grave in monotype.ttf)    */
+    /*      calling IP[] with bad values of rp[12].              */
+    /*      Do something sane when this odd thing happens.       */
+
+    if ( BOUNDS( CUR.GS.rp1, CUR.zp0.n_points ) ||
+         BOUNDS( CUR.GS.rp2, CUR.zp1.n_points ) )
+    {
+      org_a = cur_a = 0;
+      org_b = cur_b = 0;
+    }
+    else
+    {
+      org_a = CUR_Func_dualproj( CUR.zp0.org + CUR.GS.rp1, NULL_Vector );
+      org_b = CUR_Func_dualproj( CUR.zp1.org + CUR.GS.rp2, NULL_Vector );
+
+      cur_a = CUR_Func_project( CUR.zp0.cur + CUR.GS.rp1, NULL_Vector );
+      cur_b = CUR_Func_project( CUR.zp1.cur + CUR.GS.rp2, NULL_Vector );
+    }
+
+    while ( CUR.GS.loop > 0 )
+    {
+      CUR.args--;
+
+      point = (FT_UShort)CUR.stack[CUR.args];
+      if ( BOUNDS( point, CUR.zp2.n_points ) )
+      {
+        if ( CUR.pedantic_hinting )
+        {
+          CUR.error = TT_Err_Invalid_Reference;
+          return;
+        }
+      }
+      else
+      {
+        org_x = CUR_Func_dualproj( CUR.zp2.org + point, NULL_Vector );
+        cur_x = CUR_Func_project ( CUR.zp2.cur + point, NULL_Vector );
+
+        if ( ( org_a <= org_b && org_x <= org_a ) ||
+             ( org_a >  org_b && org_x >= org_a ) )
+
+          distance = ( cur_a - org_a ) + ( org_x - cur_x );
+
+        else if ( ( org_a <= org_b  &&  org_x >= org_b ) ||
+                  ( org_a >  org_b  &&  org_x <  org_b ) )
+
+          distance = ( cur_b - org_b ) + ( org_x - cur_x );
+
+        else
+           /* note: it seems that rounding this value isn't a good */
+           /*       idea (cf. width of capital `S' in Times)       */
+
+           distance = TT_MULDIV( cur_b - cur_a,
+                                 org_x - org_a,
+                                 org_b - org_a ) + ( cur_a - cur_x );
+
+        CUR_Func_move( &CUR.zp2, point, distance );
+      }
+
+      CUR.GS.loop--;
+    }
+
+    CUR.GS.loop = 1;
+    CUR.new_top = CUR.args;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* UTP[a]:       UnTouch Point                                           */
+  /* Opcode range: 0x29                                                    */
+  /* Stack:        uint32 -->                                              */
+  /*                                                                       */
+  static void
+  Ins_UTP( INS_ARG )
+  {
+    FT_UShort  point;
+    FT_Byte    mask;
+
+
+    point = (FT_UShort)args[0];
+
+    if ( BOUNDS( point, CUR.zp0.n_points ) )
+    {
+      if ( CUR.pedantic_hinting )
+        CUR.error = TT_Err_Invalid_Reference;
+      return;
+    }
+
+    mask = 0xFF;
+
+    if ( CUR.GS.freeVector.x != 0 )
+      mask &= ~FT_CURVE_TAG_TOUCH_X;
+
+    if ( CUR.GS.freeVector.y != 0 )
+      mask &= ~FT_CURVE_TAG_TOUCH_Y;
+
+    CUR.zp0.tags[point] &= mask;
+  }
+
+
+  /* Local variables for Ins_IUP: */
+  struct  LOC_Ins_IUP
+  {
+    FT_Vector*  orgs;   /* original and current coordinate */
+    FT_Vector*  curs;   /* arrays                          */
+  };
+
+
+  static void
+  Shift( FT_UInt              p1,
+         FT_UInt              p2,
+         FT_UInt              p,
+         struct LOC_Ins_IUP*  LINK )
+  {
+    FT_UInt     i;
+    FT_F26Dot6  x;
+
+
+    x = LINK->curs[p].x - LINK->orgs[p].x;
+
+    for ( i = p1; i < p; i++ )
+      LINK->curs[i].x += x;
+
+    for ( i = p + 1; i <= p2; i++ )
+      LINK->curs[i].x += x;
+  }
+
+
+  static void
+  Interp( FT_UInt              p1,
+          FT_UInt              p2,
+          FT_UInt              ref1,
+          FT_UInt              ref2,
+          struct LOC_Ins_IUP*  LINK )
+  {
+    FT_UInt     i;
+    FT_F26Dot6  x, x1, x2, d1, d2;
+
+
+    if ( p1 > p2 )
+      return;
+
+    x1 = LINK->orgs[ref1].x;
+    d1 = LINK->curs[ref1].x - LINK->orgs[ref1].x;
+    x2 = LINK->orgs[ref2].x;
+    d2 = LINK->curs[ref2].x - LINK->orgs[ref2].x;
+
+    if ( x1 == x2 )
+    {
+      for ( i = p1; i <= p2; i++ )
+      {
+        x = LINK->orgs[i].x;
+
+        if ( x <= x1 )
+          x += d1;
+        else
+          x += d2;
+
+        LINK->curs[i].x = x;
+      }
+      return;
+    }
+
+    if ( x1 < x2 )
+    {
+      for ( i = p1; i <= p2; i++ )
+      {
+        x = LINK->orgs[i].x;
+
+        if ( x <= x1 )
+          x += d1;
+        else
+        {
+          if ( x >= x2 )
+            x += d2;
+          else
+            x = LINK->curs[ref1].x +
+                  TT_MULDIV( x - x1,
+                             LINK->curs[ref2].x - LINK->curs[ref1].x,
+                             x2 - x1 );
+        }
+        LINK->curs[i].x = x;
+      }
+      return;
+    }
+
+    /* x2 < x1 */
+
+    for ( i = p1; i <= p2; i++ )
+    {
+      x = LINK->orgs[i].x;
+      if ( x <= x2 )
+        x += d2;
+      else
+      {
+        if ( x >= x1 )
+          x += d1;
+        else
+          x = LINK->curs[ref1].x +
+              TT_MULDIV( x - x1,
+                         LINK->curs[ref2].x - LINK->curs[ref1].x,
+                         x2 - x1 );
+      }
+      LINK->curs[i].x = x;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* IUP[a]:       Interpolate Untouched Points                            */
+  /* Opcode range: 0x30-0x31                                               */
+  /* Stack:        -->                                                     */
+  /*                                                                       */
+  static void
+  Ins_IUP( INS_ARG )
+  {
+    struct LOC_Ins_IUP  V;
+    FT_Byte             mask;
+
+    FT_UInt   first_point;   /* first point of contour        */
+    FT_UInt   end_point;     /* end point (last+1) of contour */
+
+    FT_UInt   first_touched; /* first touched point in contour   */
+    FT_UInt   cur_touched;   /* current touched point in contour */
+
+    FT_UInt   point;         /* current point   */
+    FT_Short  contour;       /* current contour */
+
+    FT_UNUSED_ARG;
+
+
+    if ( CUR.opcode & 1 )
+    {
+      mask   = FT_CURVE_TAG_TOUCH_X;
+      V.orgs = CUR.pts.org;
+      V.curs = CUR.pts.cur;
+    }
+    else
+    {
+      mask   = FT_CURVE_TAG_TOUCH_Y;
+      V.orgs = (FT_Vector*)( (FT_Pos*)CUR.pts.org + 1 );
+      V.curs = (FT_Vector*)( (FT_Pos*)CUR.pts.cur + 1 );
+    }
+
+    contour = 0;
+    point   = 0;
+
+    do
+    {
+      end_point   = CUR.pts.contours[contour];
+      first_point = point;
+
+      while ( point <= end_point && (CUR.pts.tags[point] & mask) == 0 )
+        point++;
+
+      if ( point <= end_point )
+      {
+        first_touched = point;
+        cur_touched   = point;
+
+        point++;
+
+        while ( point <= end_point )
+        {
+          if ( ( CUR.pts.tags[point] & mask ) != 0 )
+          {
+            if ( point > 0 )
+              Interp( cur_touched + 1,
+                      point - 1,
+                      cur_touched,
+                      point,
+                      &V );
+            cur_touched = point;
+          }
+
+          point++;
+        }
+
+        if ( cur_touched == first_touched )
+          Shift( first_point, end_point, cur_touched, &V );
+        else
+        {
+          Interp( (FT_UShort)( cur_touched + 1 ),
+                  end_point,
+                  cur_touched,
+                  first_touched,
+                  &V );
+
+          if ( first_touched > 0 )
+            Interp( first_point,
+                    first_touched - 1,
+                    cur_touched,
+                    first_touched,
+                    &V );
+        }
+      }
+      contour++;
+    } while ( contour < CUR.pts.n_contours );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DELTAPn[]:    DELTA exceptions P1, P2, P3                             */
+  /* Opcode range: 0x5D,0x71,0x72                                          */
+  /* Stack:        uint32 (2 * uint32)... -->                              */
+  /*                                                                       */
+  static void
+  Ins_DELTAP( INS_ARG )
+  {
+    FT_ULong   k, nump;
+    FT_UShort  A;
+    FT_ULong   C;
+    FT_Long    B;
+
+
+    nump = (FT_ULong)args[0];   /* some points theoretically may occur more
+                                   than once, thus UShort isn't enough */
+
+    for ( k = 1; k <= nump; k++ )
+    {
+      if ( CUR.args < 2 )
+      {
+        CUR.error = TT_Err_Too_Few_Arguments;
+        return;
+      }
+
+      CUR.args -= 2;
+
+      A = (FT_UShort)CUR.stack[CUR.args + 1];
+      B = CUR.stack[CUR.args];
+
+      /* XXX: Because some popular fonts contain some invalid DeltaP */
+      /*      instructions, we simply ignore them when the stacked   */
+      /*      point reference is off limit, rather than returning an */
+      /*      error.  As a delta instruction doesn't change a glyph  */
+      /*      in great ways, this shouldn't be a problem.            */
+
+      if ( !BOUNDS( A, CUR.zp0.n_points ) )
+      {
+        C = ( (FT_ULong)B & 0xF0 ) >> 4;
+
+        switch ( CUR.opcode )
+        {
+        case 0x5D:
+          break;
+
+        case 0x71:
+          C += 16;
+          break;
+
+        case 0x72:
+          C += 32;
+          break;
+        }
+
+        C += CUR.GS.delta_base;
+
+        if ( CURRENT_Ppem() == (FT_Long)C )
+        {
+          B = ( (FT_ULong)B & 0xF ) - 8;
+          if ( B >= 0 )
+            B++;
+          B = B * 64 / ( 1L << CUR.GS.delta_shift );
+
+          CUR_Func_move( &CUR.zp0, A, B );
+        }
+      }
+      else
+        if ( CUR.pedantic_hinting )
+          CUR.error = TT_Err_Invalid_Reference;
+    }
+
+    CUR.new_top = CUR.args;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* DELTACn[]:    DELTA exceptions C1, C2, C3                             */
+  /* Opcode range: 0x73,0x74,0x75                                          */
+  /* Stack:        uint32 (2 * uint32)... -->                              */
+  /*                                                                       */
+  static void
+  Ins_DELTAC( INS_ARG )
+  {
+    FT_ULong  nump, k;
+    FT_ULong  A, C;
+    FT_Long   B;
+
+
+    nump = (FT_ULong)args[0];
+
+    for ( k = 1; k <= nump; k++ )
+    {
+      if ( CUR.args < 2 )
+      {
+        CUR.error = TT_Err_Too_Few_Arguments;
+        return;
+      }
+
+      CUR.args -= 2;
+
+      A = (FT_ULong)CUR.stack[CUR.args + 1];
+      B = CUR.stack[CUR.args];
+
+      if ( BOUNDS( A, CUR.cvtSize ) )
+      {
+        if ( CUR.pedantic_hinting )
+        {
+          CUR.error = TT_Err_Invalid_Reference;
+          return;
+        }
+      }
+      else
+      {
+        C = ( (FT_ULong)B & 0xF0 ) >> 4;
+
+        switch ( CUR.opcode )
+        {
+        case 0x73:
+          break;
+
+        case 0x74:
+          C += 16;
+          break;
+
+        case 0x75:
+          C += 32;
+          break;
+        }
+
+        C += CUR.GS.delta_base;
+
+        if ( CURRENT_Ppem() == (FT_Long)C )
+        {
+          B = ( (FT_ULong)B & 0xF ) - 8;
+          if ( B >= 0 )
+            B++;
+          B = B * 64 / ( 1L << CUR.GS.delta_shift );
+
+          CUR_Func_move_cvt( A, B );
+        }
+      }
+    }
+
+    CUR.new_top = CUR.args;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* MISC. INSTRUCTIONS                                                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* GETINFO[]:    GET INFOrmation                                         */
+  /* Opcode range: 0x88                                                    */
+  /* Stack:        uint32 --> uint32                                       */
+  /*                                                                       */
+  /* XXX: According to Apple specs, bits 1 & 2 of the argument ought to be */
+  /*      consulted before rotated/stretched info is returned.             */
+  static void
+  Ins_GETINFO( INS_ARG )
+  {
+    FT_Long  K;
+
+
+    K = 0;
+
+    /* We return then Windows 3.1 version number */
+    /* for the font scaler                       */
+    if ( ( args[0] & 1 ) != 0 )
+      K = 3;
+
+    /* Has the glyph been rotated ? */
+    if ( CUR.tt_metrics.rotated )
+      K |= 0x80;
+
+    /* Has the glyph been stretched ? */
+    if ( CUR.tt_metrics.stretched )
+      K |= 0x100;
+
+    args[0] = K;
+  }
+
+
+  static void
+  Ins_UNKNOWN( INS_ARG )
+  {
+    TT_DefRecord*  def   = CUR.IDefs;
+    TT_DefRecord*  limit = def + CUR.numIDefs;
+
+    FT_UNUSED_ARG;
+
+
+    for ( ; def < limit; def++ )
+    {
+      if ( (FT_Byte)def->opc == CUR.opcode && def->active )
+      {
+        TT_CallRec*  call;
+
+
+        if ( CUR.callTop >= CUR.callSize )
+        {
+          CUR.error = TT_Err_Stack_Overflow;
+          return;
+        }
+
+        call = CUR.callStack + CUR.callTop++;
+
+        call->Caller_Range = CUR.curRange;
+        call->Caller_IP    = CUR.IP+1;
+        call->Cur_Count    = 1;
+        call->Cur_Restart  = def->start;
+
+        INS_Goto_CodeRange( def->range, def->start );
+
+        CUR.step_ins = FALSE;
+        return;
+      }
+    }
+
+    CUR.error = TT_Err_Invalid_Opcode;
+  }
+
+
+#ifndef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+
+  static
+  TInstruction_Function  Instruct_Dispatch[256] =
+  {
+    /* Opcodes are gathered in groups of 16. */
+    /* Please keep the spaces as they are.   */
+
+    /*  SVTCA  y  */  Ins_SVTCA,
+    /*  SVTCA  x  */  Ins_SVTCA,
+    /*  SPvTCA y  */  Ins_SPVTCA,
+    /*  SPvTCA x  */  Ins_SPVTCA,
+    /*  SFvTCA y  */  Ins_SFVTCA,
+    /*  SFvTCA x  */  Ins_SFVTCA,
+    /*  SPvTL //  */  Ins_SPVTL,
+    /*  SPvTL +   */  Ins_SPVTL,
+    /*  SFvTL //  */  Ins_SFVTL,
+    /*  SFvTL +   */  Ins_SFVTL,
+    /*  SPvFS     */  Ins_SPVFS,
+    /*  SFvFS     */  Ins_SFVFS,
+    /*  GPV       */  Ins_GPV,
+    /*  GFV       */  Ins_GFV,
+    /*  SFvTPv    */  Ins_SFVTPV,
+    /*  ISECT     */  Ins_ISECT,
+
+    /*  SRP0      */  Ins_SRP0,
+    /*  SRP1      */  Ins_SRP1,
+    /*  SRP2      */  Ins_SRP2,
+    /*  SZP0      */  Ins_SZP0,
+    /*  SZP1      */  Ins_SZP1,
+    /*  SZP2      */  Ins_SZP2,
+    /*  SZPS      */  Ins_SZPS,
+    /*  SLOOP     */  Ins_SLOOP,
+    /*  RTG       */  Ins_RTG,
+    /*  RTHG      */  Ins_RTHG,
+    /*  SMD       */  Ins_SMD,
+    /*  ELSE      */  Ins_ELSE,
+    /*  JMPR      */  Ins_JMPR,
+    /*  SCvTCi    */  Ins_SCVTCI,
+    /*  SSwCi     */  Ins_SSWCI,
+    /*  SSW       */  Ins_SSW,
+
+    /*  DUP       */  Ins_DUP,
+    /*  POP       */  Ins_POP,
+    /*  CLEAR     */  Ins_CLEAR,
+    /*  SWAP      */  Ins_SWAP,
+    /*  DEPTH     */  Ins_DEPTH,
+    /*  CINDEX    */  Ins_CINDEX,
+    /*  MINDEX    */  Ins_MINDEX,
+    /*  AlignPTS  */  Ins_ALIGNPTS,
+    /*  INS_0x28  */  Ins_UNKNOWN,
+    /*  UTP       */  Ins_UTP,
+    /*  LOOPCALL  */  Ins_LOOPCALL,
+    /*  CALL      */  Ins_CALL,
+    /*  FDEF      */  Ins_FDEF,
+    /*  ENDF      */  Ins_ENDF,
+    /*  MDAP[0]   */  Ins_MDAP,
+    /*  MDAP[1]   */  Ins_MDAP,
+
+    /*  IUP[0]    */  Ins_IUP,
+    /*  IUP[1]    */  Ins_IUP,
+    /*  SHP[0]    */  Ins_SHP,
+    /*  SHP[1]    */  Ins_SHP,
+    /*  SHC[0]    */  Ins_SHC,
+    /*  SHC[1]    */  Ins_SHC,
+    /*  SHZ[0]    */  Ins_SHZ,
+    /*  SHZ[1]    */  Ins_SHZ,
+    /*  SHPIX     */  Ins_SHPIX,
+    /*  IP        */  Ins_IP,
+    /*  MSIRP[0]  */  Ins_MSIRP,
+    /*  MSIRP[1]  */  Ins_MSIRP,
+    /*  AlignRP   */  Ins_ALIGNRP,
+    /*  RTDG      */  Ins_RTDG,
+    /*  MIAP[0]   */  Ins_MIAP,
+    /*  MIAP[1]   */  Ins_MIAP,
+
+    /*  NPushB    */  Ins_NPUSHB,
+    /*  NPushW    */  Ins_NPUSHW,
+    /*  WS        */  Ins_WS,
+    /*  RS        */  Ins_RS,
+    /*  WCvtP     */  Ins_WCVTP,
+    /*  RCvt      */  Ins_RCVT,
+    /*  GC[0]     */  Ins_GC,
+    /*  GC[1]     */  Ins_GC,
+    /*  SCFS      */  Ins_SCFS,
+    /*  MD[0]     */  Ins_MD,
+    /*  MD[1]     */  Ins_MD,
+    /*  MPPEM     */  Ins_MPPEM,
+    /*  MPS       */  Ins_MPS,
+    /*  FlipON    */  Ins_FLIPON,
+    /*  FlipOFF   */  Ins_FLIPOFF,
+    /*  DEBUG     */  Ins_DEBUG,
+
+    /*  LT        */  Ins_LT,
+    /*  LTEQ      */  Ins_LTEQ,
+    /*  GT        */  Ins_GT,
+    /*  GTEQ      */  Ins_GTEQ,
+    /*  EQ        */  Ins_EQ,
+    /*  NEQ       */  Ins_NEQ,
+    /*  ODD       */  Ins_ODD,
+    /*  EVEN      */  Ins_EVEN,
+    /*  IF        */  Ins_IF,
+    /*  EIF       */  Ins_EIF,
+    /*  AND       */  Ins_AND,
+    /*  OR        */  Ins_OR,
+    /*  NOT       */  Ins_NOT,
+    /*  DeltaP1   */  Ins_DELTAP,
+    /*  SDB       */  Ins_SDB,
+    /*  SDS       */  Ins_SDS,
+
+    /*  ADD       */  Ins_ADD,
+    /*  SUB       */  Ins_SUB,
+    /*  DIV       */  Ins_DIV,
+    /*  MUL       */  Ins_MUL,
+    /*  ABS       */  Ins_ABS,
+    /*  NEG       */  Ins_NEG,
+    /*  FLOOR     */  Ins_FLOOR,
+    /*  CEILING   */  Ins_CEILING,
+    /*  ROUND[0]  */  Ins_ROUND,
+    /*  ROUND[1]  */  Ins_ROUND,
+    /*  ROUND[2]  */  Ins_ROUND,
+    /*  ROUND[3]  */  Ins_ROUND,
+    /*  NROUND[0] */  Ins_NROUND,
+    /*  NROUND[1] */  Ins_NROUND,
+    /*  NROUND[2] */  Ins_NROUND,
+    /*  NROUND[3] */  Ins_NROUND,
+
+    /*  WCvtF     */  Ins_WCVTF,
+    /*  DeltaP2   */  Ins_DELTAP,
+    /*  DeltaP3   */  Ins_DELTAP,
+    /*  DeltaCn[0] */ Ins_DELTAC,
+    /*  DeltaCn[1] */ Ins_DELTAC,
+    /*  DeltaCn[2] */ Ins_DELTAC,
+    /*  SROUND    */  Ins_SROUND,
+    /*  S45Round  */  Ins_S45ROUND,
+    /*  JROT      */  Ins_JROT,
+    /*  JROF      */  Ins_JROF,
+    /*  ROFF      */  Ins_ROFF,
+    /*  INS_0x7B  */  Ins_UNKNOWN,
+    /*  RUTG      */  Ins_RUTG,
+    /*  RDTG      */  Ins_RDTG,
+    /*  SANGW     */  Ins_SANGW,
+    /*  AA        */  Ins_AA,
+
+    /*  FlipPT    */  Ins_FLIPPT,
+    /*  FlipRgON  */  Ins_FLIPRGON,
+    /*  FlipRgOFF */  Ins_FLIPRGOFF,
+    /*  INS_0x83  */  Ins_UNKNOWN,
+    /*  INS_0x84  */  Ins_UNKNOWN,
+    /*  ScanCTRL  */  Ins_SCANCTRL,
+    /*  SDPVTL[0] */  Ins_SDPVTL,
+    /*  SDPVTL[1] */  Ins_SDPVTL,
+    /*  GetINFO   */  Ins_GETINFO,
+    /*  IDEF      */  Ins_IDEF,
+    /*  ROLL      */  Ins_ROLL,
+    /*  MAX       */  Ins_MAX,
+    /*  MIN       */  Ins_MIN,
+    /*  ScanTYPE  */  Ins_SCANTYPE,
+    /*  InstCTRL  */  Ins_INSTCTRL,
+    /*  INS_0x8F  */  Ins_UNKNOWN,
+
+    /*  INS_0x90  */   Ins_UNKNOWN,
+    /*  INS_0x91  */   Ins_UNKNOWN,
+    /*  INS_0x92  */   Ins_UNKNOWN,
+    /*  INS_0x93  */   Ins_UNKNOWN,
+    /*  INS_0x94  */   Ins_UNKNOWN,
+    /*  INS_0x95  */   Ins_UNKNOWN,
+    /*  INS_0x96  */   Ins_UNKNOWN,
+    /*  INS_0x97  */   Ins_UNKNOWN,
+    /*  INS_0x98  */   Ins_UNKNOWN,
+    /*  INS_0x99  */   Ins_UNKNOWN,
+    /*  INS_0x9A  */   Ins_UNKNOWN,
+    /*  INS_0x9B  */   Ins_UNKNOWN,
+    /*  INS_0x9C  */   Ins_UNKNOWN,
+    /*  INS_0x9D  */   Ins_UNKNOWN,
+    /*  INS_0x9E  */   Ins_UNKNOWN,
+    /*  INS_0x9F  */   Ins_UNKNOWN,
+
+    /*  INS_0xA0  */   Ins_UNKNOWN,
+    /*  INS_0xA1  */   Ins_UNKNOWN,
+    /*  INS_0xA2  */   Ins_UNKNOWN,
+    /*  INS_0xA3  */   Ins_UNKNOWN,
+    /*  INS_0xA4  */   Ins_UNKNOWN,
+    /*  INS_0xA5  */   Ins_UNKNOWN,
+    /*  INS_0xA6  */   Ins_UNKNOWN,
+    /*  INS_0xA7  */   Ins_UNKNOWN,
+    /*  INS_0xA8  */   Ins_UNKNOWN,
+    /*  INS_0xA9  */   Ins_UNKNOWN,
+    /*  INS_0xAA  */   Ins_UNKNOWN,
+    /*  INS_0xAB  */   Ins_UNKNOWN,
+    /*  INS_0xAC  */   Ins_UNKNOWN,
+    /*  INS_0xAD  */   Ins_UNKNOWN,
+    /*  INS_0xAE  */   Ins_UNKNOWN,
+    /*  INS_0xAF  */   Ins_UNKNOWN,
+
+    /*  PushB[0]  */  Ins_PUSHB,
+    /*  PushB[1]  */  Ins_PUSHB,
+    /*  PushB[2]  */  Ins_PUSHB,
+    /*  PushB[3]  */  Ins_PUSHB,
+    /*  PushB[4]  */  Ins_PUSHB,
+    /*  PushB[5]  */  Ins_PUSHB,
+    /*  PushB[6]  */  Ins_PUSHB,
+    /*  PushB[7]  */  Ins_PUSHB,
+    /*  PushW[0]  */  Ins_PUSHW,
+    /*  PushW[1]  */  Ins_PUSHW,
+    /*  PushW[2]  */  Ins_PUSHW,
+    /*  PushW[3]  */  Ins_PUSHW,
+    /*  PushW[4]  */  Ins_PUSHW,
+    /*  PushW[5]  */  Ins_PUSHW,
+    /*  PushW[6]  */  Ins_PUSHW,
+    /*  PushW[7]  */  Ins_PUSHW,
+
+    /*  MDRP[00]  */  Ins_MDRP,
+    /*  MDRP[01]  */  Ins_MDRP,
+    /*  MDRP[02]  */  Ins_MDRP,
+    /*  MDRP[03]  */  Ins_MDRP,
+    /*  MDRP[04]  */  Ins_MDRP,
+    /*  MDRP[05]  */  Ins_MDRP,
+    /*  MDRP[06]  */  Ins_MDRP,
+    /*  MDRP[07]  */  Ins_MDRP,
+    /*  MDRP[08]  */  Ins_MDRP,
+    /*  MDRP[09]  */  Ins_MDRP,
+    /*  MDRP[10]  */  Ins_MDRP,
+    /*  MDRP[11]  */  Ins_MDRP,
+    /*  MDRP[12]  */  Ins_MDRP,
+    /*  MDRP[13]  */  Ins_MDRP,
+    /*  MDRP[14]  */  Ins_MDRP,
+    /*  MDRP[15]  */  Ins_MDRP,
+
+    /*  MDRP[16]  */  Ins_MDRP,
+    /*  MDRP[17]  */  Ins_MDRP,
+    /*  MDRP[18]  */  Ins_MDRP,
+    /*  MDRP[19]  */  Ins_MDRP,
+    /*  MDRP[20]  */  Ins_MDRP,
+    /*  MDRP[21]  */  Ins_MDRP,
+    /*  MDRP[22]  */  Ins_MDRP,
+    /*  MDRP[23]  */  Ins_MDRP,
+    /*  MDRP[24]  */  Ins_MDRP,
+    /*  MDRP[25]  */  Ins_MDRP,
+    /*  MDRP[26]  */  Ins_MDRP,
+    /*  MDRP[27]  */  Ins_MDRP,
+    /*  MDRP[28]  */  Ins_MDRP,
+    /*  MDRP[29]  */  Ins_MDRP,
+    /*  MDRP[30]  */  Ins_MDRP,
+    /*  MDRP[31]  */  Ins_MDRP,
+
+    /*  MIRP[00]  */  Ins_MIRP,
+    /*  MIRP[01]  */  Ins_MIRP,
+    /*  MIRP[02]  */  Ins_MIRP,
+    /*  MIRP[03]  */  Ins_MIRP,
+    /*  MIRP[04]  */  Ins_MIRP,
+    /*  MIRP[05]  */  Ins_MIRP,
+    /*  MIRP[06]  */  Ins_MIRP,
+    /*  MIRP[07]  */  Ins_MIRP,
+    /*  MIRP[08]  */  Ins_MIRP,
+    /*  MIRP[09]  */  Ins_MIRP,
+    /*  MIRP[10]  */  Ins_MIRP,
+    /*  MIRP[11]  */  Ins_MIRP,
+    /*  MIRP[12]  */  Ins_MIRP,
+    /*  MIRP[13]  */  Ins_MIRP,
+    /*  MIRP[14]  */  Ins_MIRP,
+    /*  MIRP[15]  */  Ins_MIRP,
+
+    /*  MIRP[16]  */  Ins_MIRP,
+    /*  MIRP[17]  */  Ins_MIRP,
+    /*  MIRP[18]  */  Ins_MIRP,
+    /*  MIRP[19]  */  Ins_MIRP,
+    /*  MIRP[20]  */  Ins_MIRP,
+    /*  MIRP[21]  */  Ins_MIRP,
+    /*  MIRP[22]  */  Ins_MIRP,
+    /*  MIRP[23]  */  Ins_MIRP,
+    /*  MIRP[24]  */  Ins_MIRP,
+    /*  MIRP[25]  */  Ins_MIRP,
+    /*  MIRP[26]  */  Ins_MIRP,
+    /*  MIRP[27]  */  Ins_MIRP,
+    /*  MIRP[28]  */  Ins_MIRP,
+    /*  MIRP[29]  */  Ins_MIRP,
+    /*  MIRP[30]  */  Ins_MIRP,
+    /*  MIRP[31]  */  Ins_MIRP
+  };
+
+
+#endif /* !TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* RUN                                                                   */
+  /*                                                                       */
+  /*  This function executes a run of opcodes.  It will exit in the        */
+  /*  following cases:                                                     */
+  /*                                                                       */
+  /*  - Errors (in which case it returns FALSE).                           */
+  /*                                                                       */
+  /*  - Reaching the end of the main code range (returns TRUE).            */
+  /*    Reaching the end of a code range within a function call is an      */
+  /*    error.                                                             */
+  /*                                                                       */
+  /*  - After executing one single opcode, if the flag `Instruction_Trap'  */
+  /*    is set to TRUE (returns TRUE).                                     */
+  /*                                                                       */
+  /*  On exit whith TRUE, test IP < CodeSize to know wether it comes from  */
+  /*  an instruction trap or a normal termination.                         */
+  /*                                                                       */
+  /*                                                                       */
+  /*  Note: The documented DEBUG opcode pops a value from the stack.  This */
+  /*        behaviour is unsupported; here a DEBUG opcode is always an     */
+  /*        error.                                                         */
+  /*                                                                       */
+  /*                                                                       */
+  /* THIS IS THE INTERPRETER'S MAIN LOOP.                                  */
+  /*                                                                       */
+  /*  Instructions appear in the specification's order.                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /* documentation is in ttinterp.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  TT_RunIns( TT_ExecContext  exc )
+  {
+    FT_Long  ins_counter = 0;  /* executed instructions counter */
+
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+    cur = *exc;
+#endif
+
+    /* set CVT functions */
+    CUR.tt_metrics.ratio = 0;
+    if ( CUR.metrics.x_ppem != CUR.metrics.y_ppem )
+    {
+      /* non-square pixels, use the stretched routines */
+      CUR.func_read_cvt  = Read_CVT_Stretched;
+      CUR.func_write_cvt = Write_CVT_Stretched;
+      CUR.func_move_cvt  = Move_CVT_Stretched;
+    }
+    else
+    {
+      /* square pixels, use normal routines */
+      CUR.func_read_cvt  = Read_CVT;
+      CUR.func_write_cvt = Write_CVT;
+      CUR.func_move_cvt  = Move_CVT;
+    }
+
+    COMPUTE_Funcs();
+    COMPUTE_Round( (FT_Byte)exc->GS.round_state );
+
+    do
+    {
+      CUR.opcode = CUR.code[CUR.IP];
+
+      if ( ( CUR.length = opcode_length[CUR.opcode] ) < 0 )
+      {
+        if ( CUR.IP + 1 > CUR.codeSize )
+          goto LErrorCodeOverflow_;
+
+        CUR.length = CUR.code[CUR.IP + 1] + 2;
+      }
+
+      if ( CUR.IP + CUR.length > CUR.codeSize )
+        goto LErrorCodeOverflow_;
+
+      /* First, let's check for empty stack and overflow */
+      CUR.args = CUR.top - ( Pop_Push_Count[CUR.opcode] >> 4 );
+
+      /* `args' is the top of the stack once arguments have been popped. */
+      /* One can also interpret it as the index of the last argument.    */
+      if ( CUR.args < 0 )
+      {
+        CUR.error = TT_Err_Too_Few_Arguments;
+        goto LErrorLabel_;
+      }
+
+      CUR.new_top = CUR.args + ( Pop_Push_Count[CUR.opcode] & 15 );
+
+      /* `new_top' is the new top of the stack, after the instruction's */
+      /* execution.  `top' will be set to `new_top' after the `switch'  */
+      /* statement.                                                     */
+      if ( CUR.new_top > CUR.stackSize )
+      {
+        CUR.error = TT_Err_Stack_Overflow;
+        goto LErrorLabel_;
+      }
+
+      CUR.step_ins = TRUE;
+      CUR.error    = TT_Err_Ok;
+
+#ifdef TT_CONFIG_OPTION_INTERPRETER_SWITCH
+
+      {
+        FT_Long*  args   = CUR.stack + CUR.args;
+        FT_Byte   opcode = CUR.opcode;
+
+
+#undef  ARRAY_BOUND_ERROR
+#define ARRAY_BOUND_ERROR  goto Set_Invalid_Ref
+
+
+        switch ( opcode )
+        {
+        case 0x00:  /* SVTCA y  */
+        case 0x01:  /* SVTCA x  */
+        case 0x02:  /* SPvTCA y */
+        case 0x03:  /* SPvTCA x */
+        case 0x04:  /* SFvTCA y */
+        case 0x05:  /* SFvTCA x */
+          {
+            FT_Short AA, BB;
+
+
+            AA = (FT_Short)( ( opcode & 1 ) << 14 );
+            BB = (FT_Short)( AA ^ 0x4000 );
+
+            if ( opcode < 4 )
+            {
+              CUR.GS.projVector.x = AA;
+              CUR.GS.projVector.y = BB;
+
+              CUR.GS.dualVector.x = AA;
+              CUR.GS.dualVector.y = BB;
+            }
+
+            if ( ( opcode & 2 ) == 0 )
+            {
+              CUR.GS.freeVector.x = AA;
+              CUR.GS.freeVector.y = BB;
+            }
+
+            COMPUTE_Funcs();
+          }
+          break;
+
+        case 0x06:  /* SPvTL // */
+        case 0x07:  /* SPvTL +  */
+          DO_SPVTL
+          break;
+
+        case 0x08:  /* SFvTL // */
+        case 0x09:  /* SFvTL +  */
+          DO_SFVTL
+          break;
+
+        case 0x0A:  /* SPvFS */
+          DO_SPVFS
+          break;
+
+        case 0x0B:  /* SFvFS */
+          DO_SFVFS
+          break;
+
+        case 0x0C:  /* GPV */
+          DO_GPV
+          break;
+
+        case 0x0D:  /* GFV */
+          DO_GFV
+          break;
+
+        case 0x0E:  /* SFvTPv */
+          DO_SFVTPV
+          break;
+
+        case 0x0F:  /* ISECT  */
+          Ins_ISECT( EXEC_ARG_ args );
+          break;
+
+        case 0x10:  /* SRP0 */
+          DO_SRP0
+          break;
+
+        case 0x11:  /* SRP1 */
+          DO_SRP1
+          break;
+
+        case 0x12:  /* SRP2 */
+          DO_SRP2
+          break;
+
+        case 0x13:  /* SZP0 */
+          Ins_SZP0( EXEC_ARG_ args );
+          break;
+
+        case 0x14:  /* SZP1 */
+          Ins_SZP1( EXEC_ARG_ args );
+          break;
+
+        case 0x15:  /* SZP2 */
+          Ins_SZP2( EXEC_ARG_ args );
+          break;
+
+        case 0x16:  /* SZPS */
+          Ins_SZPS( EXEC_ARG_ args );
+          break;
+
+        case 0x17:  /* SLOOP */
+          DO_SLOOP
+          break;
+
+        case 0x18:  /* RTG */
+          DO_RTG
+          break;
+
+        case 0x19:  /* RTHG */
+          DO_RTHG
+          break;
+
+        case 0x1A:  /* SMD */
+          DO_SMD
+          break;
+
+        case 0x1B:  /* ELSE */
+          Ins_ELSE( EXEC_ARG_ args );
+          break;
+
+        case 0x1C:  /* JMPR */
+          DO_JMPR
+          break;
+
+        case 0x1D:  /* SCVTCI */
+          DO_SCVTCI
+          break;
+
+        case 0x1E:  /* SSWCI */
+          DO_SSWCI
+          break;
+
+        case 0x1F:  /* SSW */
+          DO_SSW
+          break;
+
+        case 0x20:  /* DUP */
+          DO_DUP
+          break;
+
+        case 0x21:  /* POP */
+          /* nothing :-) */
+          break;
+
+        case 0x22:  /* CLEAR */
+          DO_CLEAR
+          break;
+
+        case 0x23:  /* SWAP */
+          DO_SWAP
+          break;
+
+        case 0x24:  /* DEPTH */
+          DO_DEPTH
+          break;
+
+        case 0x25:  /* CINDEX */
+          DO_CINDEX
+          break;
+
+        case 0x26:  /* MINDEX */
+          Ins_MINDEX( EXEC_ARG_ args );
+          break;
+
+        case 0x27:  /* ALIGNPTS */
+          Ins_ALIGNPTS( EXEC_ARG_ args );
+          break;
+
+        case 0x28:  /* ???? */
+          Ins_UNKNOWN( EXEC_ARG_ args );
+          break;
+
+        case 0x29:  /* UTP */
+          Ins_UTP( EXEC_ARG_ args );
+          break;
+
+        case 0x2A:  /* LOOPCALL */
+          Ins_LOOPCALL( EXEC_ARG_ args );
+          break;
+
+        case 0x2B:  /* CALL */
+          Ins_CALL( EXEC_ARG_ args );
+          break;
+
+        case 0x2C:  /* FDEF */
+          Ins_FDEF( EXEC_ARG_ args );
+          break;
+
+        case 0x2D:  /* ENDF */
+          Ins_ENDF( EXEC_ARG_ args );
+          break;
+
+        case 0x2E:  /* MDAP */
+        case 0x2F:  /* MDAP */
+          Ins_MDAP( EXEC_ARG_ args );
+          break;
+
+
+        case 0x30:  /* IUP */
+        case 0x31:  /* IUP */
+          Ins_IUP( EXEC_ARG_ args );
+          break;
+
+        case 0x32:  /* SHP */
+        case 0x33:  /* SHP */
+          Ins_SHP( EXEC_ARG_ args );
+          break;
+
+        case 0x34:  /* SHC */
+        case 0x35:  /* SHC */
+          Ins_SHC( EXEC_ARG_ args );
+          break;
+
+        case 0x36:  /* SHZ */
+        case 0x37:  /* SHZ */
+          Ins_SHZ( EXEC_ARG_ args );
+          break;
+
+        case 0x38:  /* SHPIX */
+          Ins_SHPIX( EXEC_ARG_ args );
+          break;
+
+        case 0x39:  /* IP    */
+          Ins_IP( EXEC_ARG_ args );
+          break;
+
+        case 0x3A:  /* MSIRP */
+        case 0x3B:  /* MSIRP */
+          Ins_MSIRP( EXEC_ARG_ args );
+          break;
+
+        case 0x3C:  /* AlignRP */
+          Ins_ALIGNRP( EXEC_ARG_ args );
+          break;
+
+        case 0x3D:  /* RTDG */
+          DO_RTDG
+          break;
+
+        case 0x3E:  /* MIAP */
+        case 0x3F:  /* MIAP */
+          Ins_MIAP( EXEC_ARG_ args );
+          break;
+
+        case 0x40:  /* NPUSHB */
+          Ins_NPUSHB( EXEC_ARG_ args );
+          break;
+
+        case 0x41:  /* NPUSHW */
+          Ins_NPUSHW( EXEC_ARG_ args );
+          break;
+
+        case 0x42:  /* WS */
+          DO_WS
+          break;
+
+      Set_Invalid_Ref:
+            CUR.error = TT_Err_Invalid_Reference;
+          break;
+
+        case 0x43:  /* RS */
+          DO_RS
+          break;
+
+        case 0x44:  /* WCVTP */
+          DO_WCVTP
+          break;
+
+        case 0x45:  /* RCVT */
+          DO_RCVT
+          break;
+
+        case 0x46:  /* GC */
+        case 0x47:  /* GC */
+          Ins_GC( EXEC_ARG_ args );
+          break;
+
+        case 0x48:  /* SCFS */
+          Ins_SCFS( EXEC_ARG_ args );
+          break;
+
+        case 0x49:  /* MD */
+        case 0x4A:  /* MD */
+          Ins_MD( EXEC_ARG_ args );
+          break;
+
+        case 0x4B:  /* MPPEM */
+          DO_MPPEM
+          break;
+
+        case 0x4C:  /* MPS */
+          DO_MPS
+          break;
+
+        case 0x4D:  /* FLIPON */
+          DO_FLIPON
+          break;
+
+        case 0x4E:  /* FLIPOFF */
+          DO_FLIPOFF
+          break;
+
+        case 0x4F:  /* DEBUG */
+          DO_DEBUG
+          break;
+
+        case 0x50:  /* LT */
+          DO_LT
+          break;
+
+        case 0x51:  /* LTEQ */
+          DO_LTEQ
+          break;
+
+        case 0x52:  /* GT */
+          DO_GT
+          break;
+
+        case 0x53:  /* GTEQ */
+          DO_GTEQ
+          break;
+
+        case 0x54:  /* EQ */
+          DO_EQ
+          break;
+
+        case 0x55:  /* NEQ */
+          DO_NEQ
+          break;
+
+        case 0x56:  /* ODD */
+          DO_ODD
+          break;
+
+        case 0x57:  /* EVEN */
+          DO_EVEN
+          break;
+
+        case 0x58:  /* IF */
+          Ins_IF( EXEC_ARG_ args );
+          break;
+
+        case 0x59:  /* EIF */
+          /* do nothing */
+          break;
+
+        case 0x5A:  /* AND */
+          DO_AND
+          break;
+
+        case 0x5B:  /* OR */
+          DO_OR
+          break;
+
+        case 0x5C:  /* NOT */
+          DO_NOT
+          break;
+
+        case 0x5D:  /* DELTAP1 */
+          Ins_DELTAP( EXEC_ARG_ args );
+          break;
+
+        case 0x5E:  /* SDB */
+          DO_SDB
+          break;
+
+        case 0x5F:  /* SDS */
+          DO_SDS
+          break;
+
+        case 0x60:  /* ADD */
+          DO_ADD
+          break;
+
+        case 0x61:  /* SUB */
+          DO_SUB
+          break;
+
+        case 0x62:  /* DIV */
+          DO_DIV
+          break;
+
+        case 0x63:  /* MUL */
+          DO_MUL
+          break;
+
+        case 0x64:  /* ABS */
+          DO_ABS
+          break;
+
+        case 0x65:  /* NEG */
+          DO_NEG
+          break;
+
+        case 0x66:  /* FLOOR */
+          DO_FLOOR
+          break;
+
+        case 0x67:  /* CEILING */
+          DO_CEILING
+          break;
+
+        case 0x68:  /* ROUND */
+        case 0x69:  /* ROUND */
+        case 0x6A:  /* ROUND */
+        case 0x6B:  /* ROUND */
+          DO_ROUND
+          break;
+
+        case 0x6C:  /* NROUND */
+        case 0x6D:  /* NROUND */
+        case 0x6E:  /* NRRUND */
+        case 0x6F:  /* NROUND */
+          DO_NROUND
+          break;
+
+        case 0x70:  /* WCVTF */
+          DO_WCVTF
+          break;
+
+        case 0x71:  /* DELTAP2 */
+        case 0x72:  /* DELTAP3 */
+          Ins_DELTAP( EXEC_ARG_ args );
+          break;
+
+        case 0x73:  /* DELTAC0 */
+        case 0x74:  /* DELTAC1 */
+        case 0x75:  /* DELTAC2 */
+          Ins_DELTAC( EXEC_ARG_ args );
+          break;
+
+        case 0x76:  /* SROUND */
+          DO_SROUND
+          break;
+
+        case 0x77:  /* S45Round */
+          DO_S45ROUND
+          break;
+
+        case 0x78:  /* JROT */
+          DO_JROT
+          break;
+
+        case 0x79:  /* JROF */
+          DO_JROF
+          break;
+
+        case 0x7A:  /* ROFF */
+          DO_ROFF
+          break;
+
+        case 0x7B:  /* ???? */
+          Ins_UNKNOWN( EXEC_ARG_ args );
+          break;
+
+        case 0x7C:  /* RUTG */
+          DO_RUTG
+          break;
+
+        case 0x7D:  /* RDTG */
+          DO_RDTG
+          break;
+
+        case 0x7E:  /* SANGW */
+        case 0x7F:  /* AA    */
+          /* nothing - obsolete */
+          break;
+
+        case 0x80:  /* FLIPPT */
+          Ins_FLIPPT( EXEC_ARG_ args );
+          break;
+
+        case 0x81:  /* FLIPRGON */
+          Ins_FLIPRGON( EXEC_ARG_ args );
+          break;
+
+        case 0x82:  /* FLIPRGOFF */
+          Ins_FLIPRGOFF( EXEC_ARG_ args );
+          break;
+
+        case 0x83:  /* UNKNOWN */
+        case 0x84:  /* UNKNOWN */
+          Ins_UNKNOWN( EXEC_ARG_ args );
+          break;
+
+        case 0x85:  /* SCANCTRL */
+          Ins_SCANCTRL( EXEC_ARG_ args );
+          break;
+
+        case 0x86:  /* SDPVTL */
+        case 0x87:  /* SDPVTL */
+          Ins_SDPVTL( EXEC_ARG_ args );
+          break;
+
+        case 0x88:  /* GETINFO */
+          Ins_GETINFO( EXEC_ARG_ args );
+          break;
+
+        case 0x89:  /* IDEF */
+          Ins_IDEF( EXEC_ARG_ args );
+          break;
+
+        case 0x8A:  /* ROLL */
+          Ins_ROLL( EXEC_ARG_ args );
+          break;
+
+        case 0x8B:  /* MAX */
+          DO_MAX
+          break;
+
+        case 0x8C:  /* MIN */
+          DO_MIN
+          break;
+
+        case 0x8D:  /* SCANTYPE */
+          Ins_SCANTYPE( EXEC_ARG_ args );
+          break;
+
+        case 0x8E:  /* INSTCTRL */
+          Ins_INSTCTRL( EXEC_ARG_ args );
+          break;
+
+        case 0x8F:
+          Ins_UNKNOWN( EXEC_ARG_ args );
+          break;
+
+        default:
+          if ( opcode >= 0xE0 )
+            Ins_MIRP( EXEC_ARG_ args );
+          else if ( opcode >= 0xC0 )
+            Ins_MDRP( EXEC_ARG_ args );
+          else if ( opcode >= 0xB8 )
+            Ins_PUSHW( EXEC_ARG_ args );
+          else if ( opcode >= 0xB0 )
+            Ins_PUSHB( EXEC_ARG_ args );
+          else
+            Ins_UNKNOWN( EXEC_ARG_ args );
+        }
+
+      }
+
+#else
+
+      Instruct_Dispatch[CUR.opcode]( EXEC_ARG_ &CUR.stack[CUR.args] );
+
+#endif /* TT_CONFIG_OPTION_INTERPRETER_SWITCH */
+
+      if ( CUR.error != TT_Err_Ok )
+      {
+        switch ( CUR.error )
+        {
+        case TT_Err_Invalid_Opcode: /* looking for redefined instructions */
+          {
+            TT_DefRecord*  def   = CUR.IDefs;
+            TT_DefRecord*  limit = def + CUR.numIDefs;
+
+
+            for ( ; def < limit; def++ )
+            {
+              if ( def->active && CUR.opcode == (FT_Byte)def->opc )
+              {
+                TT_CallRec*  callrec;
+
+
+                if ( CUR.callTop >= CUR.callSize )
+                {
+                  CUR.error = TT_Err_Invalid_Reference;
+                  goto LErrorLabel_;
+                }
+
+                callrec = &CUR.callStack[CUR.callTop];
+
+                callrec->Caller_Range = CUR.curRange;
+                callrec->Caller_IP    = CUR.IP + 1;
+                callrec->Cur_Count    = 1;
+                callrec->Cur_Restart  = def->start;
+
+                if ( INS_Goto_CodeRange( def->range, def->start ) == FAILURE )
+                  goto LErrorLabel_;
+
+                goto LSuiteLabel_;
+              }
+            }
+          }
+
+          CUR.error = TT_Err_Invalid_Opcode;
+          goto LErrorLabel_;
+
+#if 0
+          break;   /* Unreachable code warning suppression.             */
+                   /* Leave to remind in case a later change the editor */
+                   /* to consider break;                                */
+#endif
+
+        default:
+          goto LErrorLabel_;
+
+#if 0
+        break;
+#endif
+        }
+      }
+
+      CUR.top = CUR.new_top;
+
+      if ( CUR.step_ins )
+        CUR.IP += CUR.length;
+
+      /* increment instruction counter and check if we didn't */
+      /* run this program for too long (e.g. infinite loops). */
+      if ( ++ins_counter > MAX_RUNNABLE_OPCODES )
+        return TT_Err_Execution_Too_Long;
+
+    LSuiteLabel_:
+      if ( CUR.IP >= CUR.codeSize )
+      {
+        if ( CUR.callTop > 0 )
+        {
+          CUR.error = TT_Err_Code_Overflow;
+          goto LErrorLabel_;
+        }
+        else
+          goto LNo_Error_;
+      }
+    } while ( !CUR.instruction_trap );
+
+  LNo_Error_:
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+    *exc = cur;
+#endif
+
+    return TT_Err_Ok;
+
+  LErrorCodeOverflow_:
+    CUR.error = TT_Err_Code_Overflow;
+
+  LErrorLabel_:
+
+#ifdef TT_CONFIG_OPTION_STATIC_RASTER
+    *exc = cur;
+#endif
+
+    return CUR.error;
+  }
+
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttinterp.h
@@ -1,0 +1,317 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttinterp.h                                                             */
+/*                                                                         */
+/*    TrueType bytecode interpreter (specification).                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTINTERP_H__
+#define __TTINTERP_H__
+
+
+#include <ft2build.h>
+#include "ttobjs.h"
+
+
+FT_BEGIN_HEADER
+
+
+#ifndef TT_CONFIG_OPTION_STATIC_INTEPRETER  /* indirect implementation */
+
+#define EXEC_OP_   TT_ExecContext  exc,
+#define EXEC_OP    TT_ExecContext  exc
+#define EXEC_ARG_  exc,
+#define EXEC_ARG   exc
+
+#else                                       /* static implementation */
+
+#define EXEC_OP_   /* void */
+#define EXEC_OP    /* void */
+#define EXEC_ARG_  /* void */
+#define EXEC_ARG   /* void */
+
+#endif /* TT_CONFIG_OPTION_STATIC_INTERPRETER */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Rounding mode constants.                                              */
+  /*                                                                       */
+#define TT_Round_Off             5
+#define TT_Round_To_Half_Grid    0
+#define TT_Round_To_Grid         1
+#define TT_Round_To_Double_Grid  2
+#define TT_Round_Up_To_Grid      4
+#define TT_Round_Down_To_Grid    3
+#define TT_Round_Super           6
+#define TT_Round_Super_45        7
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Function types used by the interpreter, depending on various modes    */
+  /* (e.g. the rounding mode, whether to render a vertical or horizontal   */
+  /* line etc).                                                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+  /* Rounding function */
+  typedef FT_F26Dot6
+  (*TT_Round_Func)( EXEC_OP_ FT_F26Dot6  distance,
+                             FT_F26Dot6  compensation );
+
+  /* Point displacement along the freedom vector routine */
+  typedef void
+  (*TT_Move_Func)( EXEC_OP_ TT_GlyphZone  zone,
+                            FT_UShort     point,
+                            FT_F26Dot6    distance );
+
+  /* Distance projection along one of the projection vectors */
+  typedef FT_F26Dot6
+  (*TT_Project_Func)( EXEC_OP_ FT_Vector*  v1,
+                               FT_Vector*  v2 );
+
+  /* reading a cvt value.  Take care of non-square pixels if necessary */
+  typedef FT_F26Dot6
+  (*TT_Get_CVT_Func)( EXEC_OP_ FT_ULong  idx );
+
+  /* setting or moving a cvt value.  Take care of non-square pixels  */
+  /* if necessary                                                    */
+  typedef void
+  (*TT_Set_CVT_Func)( EXEC_OP_ FT_ULong    idx,
+                               FT_F26Dot6  value );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This structure defines a call record, used to manage function calls.  */
+  /*                                                                       */
+  typedef struct  TT_CallRec_
+  {
+    FT_Int   Caller_Range;
+    FT_Long  Caller_IP;
+    FT_Long  Cur_Count;
+    FT_Long  Cur_Restart;
+
+  } TT_CallRec, *TT_CallStack;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The main structure for the interpreter which collects all necessary   */
+  /* variables and states.                                                 */
+  /*                                                                       */
+  typedef struct  TT_ExecContextRec_
+  {
+    TT_Face            face;
+    TT_Size            size;
+    FT_Memory          memory;
+
+    /* instructions state */
+
+    FT_Error           error;      /* last execution error */
+
+    FT_Long            top;        /* top of exec. stack   */
+
+    FT_UInt            stackSize;  /* size of exec. stack  */
+    FT_Long*           stack;      /* current exec. stack  */
+
+    FT_Long            args;
+    FT_UInt            new_top;    /* new top after exec.  */
+
+    TT_GlyphZoneRec    zp0,        /* zone records */
+                       zp1,
+                       zp2,
+                       pts,
+                       twilight;
+
+    FT_Size_Metrics    metrics;
+    TT_Size_Metrics    tt_metrics; /* size metrics */
+
+    TT_GraphicsState   GS;         /* current graphics state */
+
+    FT_Int             curRange;  /* current code range number   */
+    FT_Byte*           code;      /* current code range          */
+    FT_Long            IP;        /* current instruction pointer */
+    FT_Long            codeSize;  /* size of current range       */
+
+    FT_Byte            opcode;    /* current opcode              */
+    FT_Int             length;    /* length of current opcode    */
+
+    FT_Bool            step_ins;  /* true if the interpreter must */
+                                  /* increment IP after ins. exec */
+    FT_Long            cvtSize;
+    FT_Long*           cvt;
+
+    FT_UInt            glyphSize; /* glyph instructions buffer size */
+    FT_Byte*           glyphIns;  /* glyph instructions buffer */
+
+    FT_UInt            numFDefs;  /* number of function defs         */
+    FT_UInt            maxFDefs;  /* maximum number of function defs */
+    TT_DefArray        FDefs;     /* table of FDefs entries          */
+
+    FT_UInt            numIDefs;  /* number of instruction defs */
+    FT_UInt            maxIDefs;  /* maximum number of ins defs */
+    TT_DefArray        IDefs;     /* table of IDefs entries     */
+
+    FT_UInt            maxFunc;   /* maximum function index     */
+    FT_UInt            maxIns;    /* maximum instruction index  */
+
+    FT_Int             callTop,    /* top of call stack during execution */
+                       callSize;   /* size of call stack */
+    TT_CallStack       callStack;  /* call stack */
+
+    FT_UShort          maxPoints;    /* capacity of this context's `pts' */
+    FT_Short           maxContours;  /* record, expressed in points and  */
+                                     /* contours.                        */
+
+    TT_CodeRangeTable  codeRangeTable;  /* table of valid code ranges */
+                                        /* useful for the debugger   */
+
+    FT_UShort          storeSize;  /* size of current storage */
+    FT_Long*           storage;    /* storage area            */
+
+    FT_F26Dot6         period;     /* values used for the */
+    FT_F26Dot6         phase;      /* `SuperRounding'     */
+    FT_F26Dot6         threshold;
+
+#if 0
+    /* this seems to be unused */
+    FT_Int             cur_ppem;   /* ppem along the current proj vector */
+#endif
+
+    FT_Bool            instruction_trap; /* If `True', the interpreter will */
+                                         /* exit after each instruction     */
+
+    TT_GraphicsState   default_GS;       /* graphics state resulting from   */
+                                         /* the prep program                */
+    FT_Bool            is_composite;     /* true if the glyph is composite  */
+    FT_Bool            pedantic_hinting; /* true if pedantic interpretation */
+
+    /* latest interpreter additions */
+
+    FT_Long            F_dot_P;    /* dot product of freedom and projection */
+                                   /* vectors                               */
+    TT_Round_Func      func_round; /* current rounding function             */
+
+    TT_Project_Func    func_project,   /* current projection function */
+                       func_dualproj,  /* current dual proj. function */
+                       func_freeProj;  /* current freedom proj. func  */
+
+    TT_Move_Func       func_move;      /* current point move function */
+
+    TT_Get_CVT_Func    func_read_cvt;  /* read a cvt entry              */
+    TT_Set_CVT_Func    func_write_cvt; /* write a cvt entry (in pixels) */
+    TT_Set_CVT_Func    func_move_cvt;  /* incr a cvt entry (in pixels)  */
+
+    FT_ULong           loadSize;
+    TT_SubGlyph_Stack  loadStack;      /* loading subglyph stack */
+
+  } TT_ExecContextRec;
+
+
+  extern const TT_GraphicsState  tt_default_graphics_state;
+
+
+  FT_LOCAL( FT_Error )
+  TT_Goto_CodeRange( TT_ExecContext  exec,
+                     FT_Int          range,
+                     FT_Long         IP );
+
+  FT_LOCAL( FT_Error )
+  TT_Set_CodeRange( TT_ExecContext  exec,
+                    FT_Int          range,
+                    void*           base,
+                    FT_Long         length );
+
+  FT_LOCAL( FT_Error )
+  TT_Clear_CodeRange( TT_ExecContext  exec,
+                      FT_Int          range );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_New_Context                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Queries the face context for a given font.  Note that there is     */
+  /*    now a _single_ execution context in the TrueType driver which is   */
+  /*    shared among faces.                                                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A handle to the source face object.                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    A handle to the execution context.  Initialized for `face'.        */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only the glyph loader and debugger should call this function.      */
+  /*                                                                       */
+  FT_EXPORT( TT_ExecContext )
+  TT_New_Context( TT_Face  face );
+
+
+  FT_LOCAL( FT_Error )
+  TT_Done_Context( TT_ExecContext  exec );
+
+  FT_LOCAL( FT_Error )
+  TT_Destroy_Context( TT_ExecContext  exec,
+                      FT_Memory       memory );
+
+  FT_LOCAL( FT_Error )
+  TT_Load_Context( TT_ExecContext  exec,
+                   TT_Face         face,
+                   TT_Size         size );
+
+  FT_LOCAL( FT_Error )
+  TT_Save_Context( TT_ExecContext  exec,
+                   TT_Size         ins );
+
+  FT_LOCAL( FT_Error )
+  TT_Run_Context( TT_ExecContext  exec,
+                  FT_Bool         debug );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_RunIns                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Executes one or more instruction in the execution context.  This   */
+  /*    is the main function of the TrueType opcode interpreter.           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    exec :: A handle to the target execution context.                  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    Only the object manager and debugger should call this function.    */
+  /*                                                                       */
+  /*    This function is publicly exported because it is directly          */
+  /*    invoked by the TrueType debugger.                                  */
+  /*                                                                       */
+  FT_EXPORT( FT_Error )
+  TT_RunIns( TT_ExecContext  exec );
+
+
+FT_END_HEADER
+
+#endif /* __TTINTERP_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttload.c
@@ -1,0 +1,1849 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttload.c                                                               */
+/*                                                                         */
+/*    Load the basic TrueType tables, i.e., tables that can be either in   */
+/*    TTF or OTF fonts (body).                                             */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttload.h"
+#include "ttcmap.h"
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttload
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_lookup_table                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Looks for a TrueType table by name.                                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A face object handle.                                      */
+  /*                                                                       */
+  /*    tag  :: The searched tag.                                          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    A pointer to the table directory entry.  0 if not found.           */
+  /*                                                                       */
+  FT_LOCAL_DEF( TT_Table  )
+  tt_face_lookup_table( TT_Face   face,
+                        FT_ULong  tag  )
+  {
+    TT_Table  entry;
+    TT_Table  limit;
+
+
+    FT_TRACE3(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ",
+                face,
+                (FT_Char)( tag >> 24 ),
+                (FT_Char)( tag >> 16 ),
+                (FT_Char)( tag >> 8  ),
+                (FT_Char)( tag       ) ));
+
+    entry = face->dir_tables;
+    limit = entry + face->num_tables;
+
+    for ( ; entry < limit; entry++ )
+    {
+      /* For compatibility with Windows, we consider 0-length */
+      /* tables the same as missing tables.                   */
+      if ( entry->Tag == tag && entry->Length != 0 )
+      {
+        FT_TRACE3(( "found table.\n" ));
+        return entry;
+      }
+    }
+
+    FT_TRACE3(( "could not find table!\n" ));
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_goto_table                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Looks for a TrueType table by name, then seek a stream to it.      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A face object handle.                                    */
+  /*                                                                       */
+  /*    tag    :: The searched tag.                                        */
+  /*                                                                       */
+  /*    stream :: The stream to seek when the table is found.              */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    length :: The length of the table if found, undefined otherwise.   */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_goto_table( TT_Face    face,
+                      FT_ULong   tag,
+                      FT_Stream  stream,
+                      FT_ULong*  length )
+  {
+    TT_Table  table;
+    FT_Error  error;
+
+
+    table = tt_face_lookup_table( face, tag );
+    if ( table )
+    {
+      if ( length )
+        *length = table->Length;
+
+      if ( FT_STREAM_SEEK( table->Offset ) )
+       goto Exit;
+    }
+    else
+      error = SFNT_Err_Table_Missing;
+
+  Exit:
+    return error;
+  }
+
+
+ /* In theory, we should check the values of `search_range',               */
+ /* `entry_selector', and `range_shift' to detect non-SFNT based files     */
+ /* whose header might also start with 0x100000L (yes, these exist).       */
+ /*                                                                        */
+ /* Very unfortunately, many TrueType fonts don't have these fields        */
+ /* set correctly and we must ignore them to support them.  An alternative */
+ /* way to check the font file is thus to:                                 */
+ /*                                                                        */
+ /* - check that `num_tables' is valid                                     */
+ /* - look for a "head" table, check its size, and parse it to             */
+ /*   see if its "magic" field is correctly set                            */
+ /*                                                                        */
+ /* When checking directory entries, ignore the tables `glyx' and `locx'   */
+ /* which are hacked-out versions of `glyf' and `loca' in some PostScript  */
+ /* Type 42 fonts, and will generally be invalid.                          */
+ /*                                                                        */
+  static FT_Error
+  sfnt_dir_check( FT_Stream  stream,
+                  FT_ULong   offset,
+                  FT_UInt    num_tables )
+   {
+    FT_Error        error;
+    FT_UInt         nn, has_head = 0;
+
+    const FT_ULong  glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' );
+    const FT_ULong  locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' );
+
+    static const FT_Frame_Field  sfnt_dir_entry_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_TableRec
+
+      FT_FRAME_START( 16 ),
+        FT_FRAME_ULONG( Tag ),
+        FT_FRAME_ULONG( CheckSum ),
+        FT_FRAME_ULONG( Offset ),
+        FT_FRAME_ULONG( Length ),
+      FT_FRAME_END
+    };
+
+
+    /* if 'num_tables' is 0, read the table count from the file */
+    if ( num_tables == 0 )
+    {
+      FT_ULong  format_tag;
+
+
+      if ( FT_STREAM_SEEK( offset )     ||
+           FT_READ_ULONG ( format_tag ) ||
+           FT_READ_USHORT( num_tables ) ||
+           FT_STREAM_SKIP( 6 )          )
+        goto Bad_Format;
+
+      if ( offset + 12 + num_tables*16 > stream->size )
+        goto Bad_Format;
+    }
+    else if ( FT_STREAM_SEEK( offset + 12 ) )
+      goto Bad_Format;
+
+    for ( nn = 0; nn < num_tables; nn++ )
+    {
+      TT_TableRec  table;
+
+
+      if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) )
+        goto Bad_Format;
+
+      if ( table.Offset + table.Length > stream->size     &&
+           table.Tag != glyx_tag && table.Tag != locx_tag )
+        goto Bad_Format;
+
+      if ( table.Tag == TTAG_head )
+      {
+        FT_UInt32  magic;
+
+
+        has_head = 1;
+
+        if ( table.Length != 0x36                ||
+             FT_STREAM_SEEK( table.Offset + 12 ) ||
+             FT_READ_ULONG( magic )              ||
+             magic != 0x5F0F3CF5UL               )
+          goto Bad_Format;
+
+        if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) )
+          goto Bad_Format;
+      }
+    }
+
+    if ( has_head == 0 )
+      goto Bad_Format;
+
+  Exit:
+    return  error;
+
+  Bad_Format:
+    error = FT_Err_Unknown_File_Format;
+    goto Exit;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_sfnt_header                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the header of a SFNT font file.  Supports collections.       */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face       :: A handle to the target face object.                  */
+  /*                                                                       */
+  /*    stream     :: The input stream.                                    */
+  /*                                                                       */
+  /*    face_index :: If the font is a collection, the number of the font  */
+  /*                  in the collection, ignored otherwise.                */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    sfnt       :: The SFNT header.                                     */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The stream cursor must be at the font file's origin.               */
+  /*                                                                       */
+  /*    This function recognizes fonts embedded in a `TrueType collection' */
+  /*                                                                       */
+  /*    The header will be checked whether it is valid by looking at the   */
+  /*    values of `search_range', `entry_selector', and `range_shift'.     */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_sfnt_header( TT_Face      face,
+                            FT_Stream    stream,
+                            FT_Long      face_index,
+                            SFNT_Header  sfnt )
+  {
+    FT_Error   error;
+    FT_ULong   format_tag, offset;
+    FT_Memory  memory = stream->memory;
+
+    static const FT_Frame_Field  sfnt_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  SFNT_HeaderRec
+
+      FT_FRAME_START( 8 ),
+        FT_FRAME_USHORT( num_tables ),
+        FT_FRAME_USHORT( search_range ),
+        FT_FRAME_USHORT( entry_selector ),
+        FT_FRAME_USHORT( range_shift ),
+      FT_FRAME_END
+    };
+
+    static const FT_Frame_Field  ttc_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TTC_HeaderRec
+
+      FT_FRAME_START( 8 ),
+        FT_FRAME_LONG( version ),
+        FT_FRAME_LONG( count   ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n",
+                face, face_index ));
+
+    face->ttc_header.tag     = 0;
+    face->ttc_header.version = 0;
+    face->ttc_header.count   = 0;
+
+    face->num_tables = 0;
+
+    /* first of all, read the first 4 bytes.  If it is `ttcf', then the */
+    /* file is a TrueType collection, otherwise it can be any other     */
+    /* kind of font.                                                    */
+    /*                                                                  */
+    offset = FT_STREAM_POS();
+
+    if ( FT_READ_ULONG( format_tag ) )
+      goto Exit;
+
+    if ( format_tag == TTAG_ttcf )
+    {
+      FT_Int  n;
+
+
+      FT_TRACE3(( "tt_face_load_sfnt_header: file is a collection\n" ));
+
+      /* It is a TrueType collection, i.e. a file containing several */
+      /* font files.  Read the font directory now                    */
+      if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
+        goto Exit;
+
+      /* now read the offsets of each font in the file */
+      if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ||
+           FT_FRAME_ENTER( face->ttc_header.count * 4L )                    )
+        goto Exit;
+
+      for ( n = 0; n < face->ttc_header.count; n++ )
+        face->ttc_header.offsets[n] = FT_GET_ULONG();
+
+      FT_FRAME_EXIT();
+
+      /* check face index */
+      if ( face_index >= face->ttc_header.count )
+      {
+        error = SFNT_Err_Bad_Argument;
+        goto Exit;
+      }
+
+      /* seek to the appropriate TrueType file, then read tag */
+      offset = face->ttc_header.offsets[face_index];
+
+      if ( FT_STREAM_SEEK( offset ) ||
+           FT_READ_LONG( format_tag )                             )
+        goto Exit;
+    }
+
+    /* the format tag was read, now check the rest of the header */
+    sfnt->format_tag = format_tag;
+    sfnt->offset     = offset;
+
+    if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
+      goto Exit;
+
+    /* now check the sfnt directory */
+    error = sfnt_dir_check( stream, offset, sfnt->num_tables );
+    if ( error )
+    {
+      FT_TRACE2(( "tt_face_load_sfnt_header: file is not SFNT!\n" ));
+      error = SFNT_Err_Unknown_File_Format;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_directory                                             */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the table directory into a face object.                      */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /*    sfnt   :: The SFNT directory header.                               */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The stream cursor must be at the font file's origin.               */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_directory( TT_Face      face,
+                          FT_Stream    stream,
+                          SFNT_Header  sfnt )
+  {
+    FT_Error     error;
+    FT_Memory    memory = stream->memory;
+
+    TT_TableRec  *entry, *limit;
+
+
+    FT_TRACE2(( "tt_face_load_directory: %08p\n", face ));
+
+    FT_TRACE2(( "-- Tables count:   %12u\n",  sfnt->num_tables ));
+    FT_TRACE2(( "-- Format version: %08lx\n", sfnt->format_tag ));
+
+    face->num_tables = sfnt->num_tables;
+
+    if ( FT_NEW_ARRAY( face->dir_tables, face->num_tables ) )
+      goto Exit;
+
+    if ( FT_STREAM_SEEK( sfnt->offset + 12 )      ||
+         FT_FRAME_ENTER( face->num_tables * 16L ) )
+      goto Exit;
+
+    entry = face->dir_tables;
+    limit = entry + face->num_tables;
+
+    for ( ; entry < limit; entry++ )
+    {                    /* loop through the tables and get all entries */
+      entry->Tag      = FT_GET_TAG4();
+      entry->CheckSum = FT_GET_ULONG();
+      entry->Offset   = FT_GET_LONG();
+      entry->Length   = FT_GET_LONG();
+
+      FT_TRACE2(( "  %c%c%c%c  -  %08lx  -  %08lx\n",
+                  (FT_Char)( entry->Tag >> 24 ),
+                  (FT_Char)( entry->Tag >> 16 ),
+                  (FT_Char)( entry->Tag >> 8  ),
+                  (FT_Char)( entry->Tag       ),
+                  entry->Offset,
+                  entry->Length ));
+    }
+
+    FT_FRAME_EXIT();
+
+    FT_TRACE2(( "Directory loaded\n\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_any                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads any font table into client memory.                           */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: The face object to look for.                             */
+  /*                                                                       */
+  /*    tag    :: The tag of table to load.  Use the value 0 if you want   */
+  /*              to access the whole font file, else set this parameter   */
+  /*              to a valid TrueType table tag that you can forge with    */
+  /*              the MAKE_TT_TAG macro.                                   */
+  /*                                                                       */
+  /*    offset :: The starting offset in the table (or the file if         */
+  /*              tag == 0).                                               */
+  /*                                                                       */
+  /*    length :: The address of the decision variable:                    */
+  /*                                                                       */
+  /*                If length == NULL:                                     */
+  /*                  Loads the whole table.  Returns an error if          */
+  /*                  `offset' == 0!                                       */
+  /*                                                                       */
+  /*                If *length == 0:                                       */
+  /*                  Exits immediately; returning the length of the given */
+  /*                  table or of the font file, depending on the value of */
+  /*                  `tag'.                                               */
+  /*                                                                       */
+  /*                If *length != 0:                                       */
+  /*                  Loads the next `length' bytes of table or font,      */
+  /*                  starting at offset `offset' (in table or font too).  */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    buffer :: The address of target buffer.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_any( TT_Face    face,
+                    FT_ULong   tag,
+                    FT_Long    offset,
+                    FT_Byte*   buffer,
+                    FT_ULong*  length )
+  {
+    FT_Error   error;
+    FT_Stream  stream;
+    TT_Table   table;
+    FT_ULong   size;
+
+
+    if ( tag != 0 )
+    {
+      /* look for tag in font directory */
+      table = tt_face_lookup_table( face, tag );
+      if ( !table )
+      {
+        error = SFNT_Err_Table_Missing;
+        goto Exit;
+      }
+
+      offset += table->Offset;
+      size    = table->Length;
+    }
+    else
+      /* tag == 0 -- the user wants to access the font file directly */
+      size = face->root.stream->size;
+
+    if ( length && *length == 0 )
+    {
+      *length = size;
+
+      return SFNT_Err_Ok;
+    }
+
+    if ( length )
+      size = *length;
+
+    stream = face->root.stream;
+    /* the `if' is syntactic sugar for picky compilers */
+    if ( FT_STREAM_READ_AT( offset, buffer, size ) )
+      goto Exit;
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_generic_header                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the TrueType table `head' or `bhed'.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  tt_face_load_generic_header( TT_Face    face,
+                               FT_Stream  stream,
+                               FT_ULong   tag )
+  {
+    FT_Error    error;
+    TT_Header*  header;
+
+    static const FT_Frame_Field  header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_Header
+
+      FT_FRAME_START( 54 ),
+        FT_FRAME_ULONG ( Table_Version ),
+        FT_FRAME_ULONG ( Font_Revision ),
+        FT_FRAME_LONG  ( CheckSum_Adjust ),
+        FT_FRAME_LONG  ( Magic_Number ),
+        FT_FRAME_USHORT( Flags ),
+        FT_FRAME_USHORT( Units_Per_EM ),
+        FT_FRAME_LONG  ( Created[0] ),
+        FT_FRAME_LONG  ( Created[1] ),
+        FT_FRAME_LONG  ( Modified[0] ),
+        FT_FRAME_LONG  ( Modified[1] ),
+        FT_FRAME_SHORT ( xMin ),
+        FT_FRAME_SHORT ( yMin ),
+        FT_FRAME_SHORT ( xMax ),
+        FT_FRAME_SHORT ( yMax ),
+        FT_FRAME_USHORT( Mac_Style ),
+        FT_FRAME_USHORT( Lowest_Rec_PPEM ),
+        FT_FRAME_SHORT ( Font_Direction ),
+        FT_FRAME_SHORT ( Index_To_Loc_Format ),
+        FT_FRAME_SHORT ( Glyph_Data_Format ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( "tt_face_load_generic_header: "
+                "%08p, looking up font table `%c%c%c%c'.\n",
+                face,
+                (FT_Char)( tag >> 24 ),
+                (FT_Char)( tag >> 16 ),
+                (FT_Char)( tag >> 8  ),
+                (FT_Char)( tag       ) ));
+
+    error = face->goto_table( face, tag, stream, 0 );
+    if ( error )
+    {
+      FT_TRACE2(( "tt_face_load_generic_header: Font table is missing!\n" ));
+      goto Exit;
+    }
+
+    header = &face->header;
+
+    if ( FT_STREAM_READ_FIELDS( header_fields, header ) )
+      goto Exit;
+
+    FT_TRACE2(( "    Units per EM: %8u\n", header->Units_Per_EM ));
+    FT_TRACE2(( "    IndexToLoc:   %8d\n", header->Index_To_Loc_Format ));
+    FT_TRACE2(( "tt_face_load_generic_header: Font table loaded.\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_header( TT_Face    face,
+                       FT_Stream  stream )
+  {
+    return tt_face_load_generic_header( face, stream, TTAG_head );
+  }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_bitmap_header( TT_Face    face,
+                              FT_Stream  stream )
+  {
+    return tt_face_load_generic_header( face, stream, TTAG_bhed );
+  }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_max_profile                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the maximum profile into a face object.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_max_profile( TT_Face    face,
+                            FT_Stream  stream )
+  {
+    FT_Error        error;
+    TT_MaxProfile*  maxProfile = &face->max_profile;
+
+    const FT_Frame_Field  maxp_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_MaxProfile
+
+      FT_FRAME_START( 6 ),
+        FT_FRAME_LONG  ( version ),
+        FT_FRAME_USHORT( numGlyphs ),
+      FT_FRAME_END
+    };
+
+    const FT_Frame_Field  maxp_fields_extra[] =
+    {
+      FT_FRAME_START( 26 ),
+        FT_FRAME_USHORT( maxPoints ),
+        FT_FRAME_USHORT( maxContours ),
+        FT_FRAME_USHORT( maxCompositePoints ),
+        FT_FRAME_USHORT( maxCompositeContours ),
+        FT_FRAME_USHORT( maxZones ),
+        FT_FRAME_USHORT( maxTwilightPoints ),
+        FT_FRAME_USHORT( maxStorage ),
+        FT_FRAME_USHORT( maxFunctionDefs ),
+        FT_FRAME_USHORT( maxInstructionDefs ),
+        FT_FRAME_USHORT( maxStackElements ),
+        FT_FRAME_USHORT( maxSizeOfInstructions ),
+        FT_FRAME_USHORT( maxComponentElements ),
+        FT_FRAME_USHORT( maxComponentDepth ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( "Load_TT_MaxProfile: %08p\n", face ));
+
+    error = face->goto_table( face, TTAG_maxp, stream, 0 );
+    if ( error )
+      goto Exit;
+
+    if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) )
+      goto Exit;
+
+    maxProfile->maxPoints             = 0;
+    maxProfile->maxContours           = 0;
+    maxProfile->maxCompositePoints    = 0;
+    maxProfile->maxCompositeContours  = 0;
+    maxProfile->maxZones              = 0;
+    maxProfile->maxTwilightPoints     = 0;
+    maxProfile->maxStorage            = 0;
+    maxProfile->maxFunctionDefs       = 0;
+    maxProfile->maxInstructionDefs    = 0;
+    maxProfile->maxStackElements      = 0;
+    maxProfile->maxSizeOfInstructions = 0;
+    maxProfile->maxComponentElements  = 0;
+    maxProfile->maxComponentDepth     = 0;
+
+    if ( maxProfile->version >= 0x10000L )
+    {
+      if ( FT_STREAM_READ_FIELDS( maxp_fields_extra, maxProfile ) )
+        goto Exit;
+
+      /* XXX: an adjustment that is necessary to load certain */
+      /*      broken fonts like `Keystrokes MT' :-(           */
+      /*                                                      */
+      /*   We allocate 64 function entries by default when    */
+      /*   the maxFunctionDefs field is null.                 */
+
+      if ( maxProfile->maxFunctionDefs == 0 )
+        maxProfile->maxFunctionDefs = 64;
+
+      face->root.num_glyphs = maxProfile->numGlyphs;
+
+      face->root.internal->max_points =
+        (FT_UShort)MAX( maxProfile->maxCompositePoints,
+                        maxProfile->maxPoints );
+
+      face->root.internal->max_contours =
+        (FT_Short)MAX( maxProfile->maxCompositeContours,
+                       maxProfile->maxContours );
+
+      face->max_components = (FT_ULong)maxProfile->maxComponentElements +
+                             maxProfile->maxComponentDepth;
+
+      /* XXX: some fonts have maxComponents set to 0; we will */
+      /*      then use 16 of them by default.                 */
+      if ( face->max_components == 0 )
+        face->max_components = 16;
+
+      /* We also increase maxPoints and maxContours in order to support */
+      /* some broken fonts.                                             */
+      face->root.internal->max_points   += (FT_UShort)8;
+      face->root.internal->max_contours += (FT_Short) 4;
+    }
+
+    FT_TRACE2(( "MAXP loaded.\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_metrics                                               */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the horizontal or vertical metrics table into a face object. */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the target face object.                    */
+  /*                                                                       */
+  /*    stream   :: The input stream.                                      */
+  /*                                                                       */
+  /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  tt_face_load_metrics( TT_Face    face,
+                        FT_Stream  stream,
+                        FT_Bool    vertical )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+    FT_ULong   table_len;
+    FT_Long    num_shorts, num_longs, num_shorts_checked;
+
+    TT_LongMetrics *   longs;
+    TT_ShortMetrics**  shorts;
+
+
+    FT_TRACE2(( "TT_Load_%s_Metrics: %08p\n", vertical ? "Vertical"
+                                                       : "Horizontal",
+                                              face ));
+
+    if ( vertical )
+    {
+      /* The table is optional, quit silently if it wasn't found       */
+      /*                                                               */
+      /* XXX: Some fonts have a valid vertical header with a non-null  */
+      /*      `number_of_VMetrics' fields, but no corresponding `vmtx' */
+      /*      table to get the metrics from (e.g. mingliu).            */
+      /*                                                               */
+      /*      For safety, we set the field to 0!                       */
+      /*                                                               */
+      error = face->goto_table( face, TTAG_vmtx, stream, &table_len );
+      if ( error )
+      {
+        /* Set number_Of_VMetrics to 0! */
+        FT_TRACE2(( "  no vertical header in file.\n" ));
+        face->vertical.number_Of_VMetrics = 0;
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+
+      num_longs = face->vertical.number_Of_VMetrics;
+      longs     = (TT_LongMetrics *)&face->vertical.long_metrics;
+      shorts    = (TT_ShortMetrics**)&face->vertical.short_metrics;
+    }
+    else
+    {
+      error = face->goto_table( face, TTAG_hmtx, stream, &table_len );
+      if ( error )
+      {
+        FT_ERROR(( " no horizontal metrics in file!\n" ));
+        error = SFNT_Err_Hmtx_Table_Missing;
+        goto Exit;
+      }
+
+      num_longs = face->horizontal.number_Of_HMetrics;
+      longs     = (TT_LongMetrics *)&face->horizontal.long_metrics;
+      shorts    = (TT_ShortMetrics**)&face->horizontal.short_metrics;
+    }
+
+    /* never trust derived values */
+
+    num_shorts         = face->max_profile.numGlyphs - num_longs;
+    num_shorts_checked = ( table_len - num_longs * 4L ) / 2;
+
+    if ( num_shorts < 0 )
+    {
+      FT_ERROR(( "TT_Load_%s_Metrics: more metrics than glyphs!\n",
+                 vertical ? "Vertical"
+                          : "Horizontal" ));
+
+      error = vertical ? SFNT_Err_Invalid_Vert_Metrics
+                       : SFNT_Err_Invalid_Horiz_Metrics;
+      goto Exit;
+    }
+
+    if ( FT_NEW_ARRAY( *longs,  num_longs  ) ||
+         FT_NEW_ARRAY( *shorts, num_shorts ) )
+      goto Exit;
+
+    if ( FT_FRAME_ENTER( table_len ) )
+      goto Exit;
+
+    {
+      TT_LongMetrics  cur   = *longs;
+      TT_LongMetrics  limit = cur + num_longs;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        cur->advance = FT_GET_USHORT();
+        cur->bearing = FT_GET_SHORT();
+      }
+    }
+
+    /* do we have an inconsistent number of metric values? */
+    {
+      TT_ShortMetrics*  cur   = *shorts;
+      TT_ShortMetrics*  limit = cur + MIN( num_shorts, num_shorts_checked );
+
+
+      for ( ; cur < limit; cur++ )
+        *cur = FT_GET_SHORT();
+
+      /* we fill up the missing left side bearings with the     */
+      /* last valid value.  Since this will occur for buggy CJK */
+      /* fonts usually only, nothing serious will happen        */
+      if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 )
+      {
+        FT_Short  val = (*shorts)[num_shorts_checked - 1];
+
+
+        limit = *shorts + num_shorts;
+        for ( ; cur < limit; cur++ )
+          *cur = val;
+      }
+    }
+
+    FT_FRAME_EXIT();
+
+    FT_TRACE2(( "loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_metrics_header                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the horizontal or vertical header in a face object.          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face     :: A handle to the target face object.                    */
+  /*                                                                       */
+  /*    stream   :: The input stream.                                      */
+  /*                                                                       */
+  /*    vertical :: A boolean flag.  If set, load vertical metrics.        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_metrics_header( TT_Face    face,
+                               FT_Stream  stream,
+                               FT_Bool    vertical )
+  {
+    FT_Error        error;
+    TT_HoriHeader*  header;
+
+    const FT_Frame_Field  metrics_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_HoriHeader
+
+      FT_FRAME_START( 36 ),
+        FT_FRAME_ULONG ( Version ),
+        FT_FRAME_SHORT ( Ascender ),
+        FT_FRAME_SHORT ( Descender ),
+        FT_FRAME_SHORT ( Line_Gap ),
+        FT_FRAME_USHORT( advance_Width_Max ),
+        FT_FRAME_SHORT ( min_Left_Side_Bearing ),
+        FT_FRAME_SHORT ( min_Right_Side_Bearing ),
+        FT_FRAME_SHORT ( xMax_Extent ),
+        FT_FRAME_SHORT ( caret_Slope_Rise ),
+        FT_FRAME_SHORT ( caret_Slope_Run ),
+        FT_FRAME_SHORT ( caret_Offset ),
+        FT_FRAME_SHORT ( Reserved[0] ),
+        FT_FRAME_SHORT ( Reserved[1] ),
+        FT_FRAME_SHORT ( Reserved[2] ),
+        FT_FRAME_SHORT ( Reserved[3] ),
+        FT_FRAME_SHORT ( metric_Data_Format ),
+        FT_FRAME_USHORT( number_Of_HMetrics ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( vertical ? "Vertical header " : "Horizontal header " ));
+
+    if ( vertical )
+    {
+      face->vertical_info = 0;
+
+      /* The vertical header table is optional, so return quietly if */
+      /* we don't find it.                                           */
+      error = face->goto_table( face, TTAG_vhea, stream, 0 );
+      if ( error )
+      {
+        error = SFNT_Err_Ok;
+        goto Exit;
+      }
+
+      face->vertical_info = 1;
+      header = (TT_HoriHeader*)&face->vertical;
+    }
+    else
+    {
+      /* The horizontal header is mandatory; return an error if we */
+      /* don't find it.                                            */
+      error = face->goto_table( face, TTAG_hhea, stream, 0 );
+      if ( error )
+      {
+        error = SFNT_Err_Horiz_Header_Missing;
+        goto Exit;
+      }
+
+      header = &face->horizontal;
+    }
+
+    if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) )
+      goto Exit;
+
+    header->long_metrics  = NULL;
+    header->short_metrics = NULL;
+
+    FT_TRACE2(( "loaded\n" ));
+
+    /* Now try to load the corresponding metrics */
+
+    error = tt_face_load_metrics( face, stream, vertical );
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_names                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the name records.                                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_names( TT_Face    face,
+                      FT_Stream  stream )
+  {
+    FT_Error      error;
+    FT_Memory     memory = stream->memory;
+    FT_ULong      table_pos, table_len;
+    FT_ULong      storage_start, storage_limit;
+    FT_UInt       count;
+    TT_NameTable  table;
+
+    static const FT_Frame_Field  name_table_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_NameTableRec
+
+      FT_FRAME_START( 6 ),
+        FT_FRAME_USHORT( format ),
+        FT_FRAME_USHORT( numNameRecords ),
+        FT_FRAME_USHORT( storageOffset ),
+      FT_FRAME_END
+    };
+
+    static const FT_Frame_Field  name_record_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_NameEntryRec
+
+      /* no FT_FRAME_START */
+        FT_FRAME_USHORT( platformID ),
+        FT_FRAME_USHORT( encodingID ),
+        FT_FRAME_USHORT( languageID ),
+        FT_FRAME_USHORT( nameID ),
+        FT_FRAME_USHORT( stringLength ),
+        FT_FRAME_USHORT( stringOffset ),
+      FT_FRAME_END
+    };
+
+
+    table         = &face->name_table;
+    table->stream = stream;
+
+    FT_TRACE2(( "Names " ));
+
+    error = face->goto_table( face, TTAG_name, stream, &table_len );
+    if ( error )
+    {
+      /* The name table is required so indicate failure. */
+      FT_TRACE2(( "is missing!\n" ));
+      error = SFNT_Err_Name_Table_Missing;
+      goto Exit;
+    }
+
+    table_pos = FT_STREAM_POS();
+
+
+    if ( FT_STREAM_READ_FIELDS( name_table_fields, table ) )
+      goto Exit;
+
+    /* Some popular asian fonts have an invalid `storageOffset' value   */
+    /* (it should be at least "6 + 12*num_names").  However, the string */
+    /* offsets, computed as "storageOffset + entry->stringOffset", are  */
+    /* valid pointers within the name table...                          */
+    /*                                                                  */
+    /* We thus can't check `storageOffset' right now.                   */
+    /*                                                                  */
+    storage_start = table_pos + 6 + 12*table->numNameRecords;
+    storage_limit = table_pos + table_len;
+
+    if ( storage_start > storage_limit )
+    {
+      FT_ERROR(( "tt_face_load_names: invalid `name' table\n" ));
+      error = SFNT_Err_Name_Table_Missing;
+      goto Exit;
+    }
+
+    /* Allocate the array of name records. */
+    count                 = table->numNameRecords;
+    table->numNameRecords = 0;
+
+    if ( FT_NEW_ARRAY( table->names, count ) ||
+         FT_FRAME_ENTER( count * 12 )        )
+      goto Exit;
+
+    /* Load the name records and determine how much storage is needed */
+    /* to hold the strings themselves.                                */
+    {
+      TT_NameEntryRec*  entry = table->names;
+
+
+      for ( ; count > 0; count-- )
+      {
+        if ( FT_STREAM_READ_FIELDS( name_record_fields, entry ) )
+          continue;
+
+        /* check that the name is not empty */
+        if ( entry->stringLength == 0 )
+          continue;
+
+        /* check that the name string is within the table */
+        entry->stringOffset += table_pos + table->storageOffset;
+        if ( entry->stringOffset                       < storage_start ||
+             entry->stringOffset + entry->stringLength > storage_limit )
+        {
+          /* invalid entry - ignore it */
+          entry->stringOffset = 0;
+          entry->stringLength = 0;
+          continue;
+        }
+
+        entry++;
+      }
+
+      table->numNameRecords = (FT_UInt)( entry - table->names );
+    }
+
+    FT_FRAME_EXIT();
+
+    FT_TRACE2(( "loaded\n" ));
+
+    /* everything went well, update face->num_names */
+    face->num_names = (FT_UShort) table->numNameRecords;
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_free_names                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Frees the name records.                                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A handle to the target face object.                        */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  tt_face_free_names( TT_Face  face )
+  {
+    FT_Memory     memory = face->root.driver->root.memory;
+    TT_NameTable  table  = &face->name_table;
+    TT_NameEntry  entry  = table->names;
+    FT_UInt       count  = table->numNameRecords;
+
+
+    for ( ; count > 0; count--, entry++ )
+    {
+      FT_FREE( entry->string );
+      entry->stringLength = 0;
+    }
+
+    /* free strings table */
+    FT_FREE( table->names );
+
+    table->numNameRecords = 0;
+    table->format         = 0;
+    table->storageOffset  = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_cmap                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the cmap directory in a face object.  The cmaps itselves are */
+  /*    loaded on demand in the `ttcmap.c' module.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_cmap( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error  error;
+
+
+    error = face->goto_table( face, TTAG_cmap, stream, &face->cmap_size );
+    if ( error )
+    {
+      FT_TRACE2(( "No `cmap' table in font !\n" ));
+      error = SFNT_Err_CMap_Table_Missing;
+      goto Exit;
+    }
+
+    if ( !FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) )
+      FT_TRACE2(( "`cmap' table loaded\n" ));
+    else
+    {
+      FT_ERROR(( "`cmap' table is too short!\n" ));
+      face->cmap_size = 0;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_os2                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the OS2 table.                                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_os2( TT_Face    face,
+                    FT_Stream  stream )
+  {
+    FT_Error  error;
+    TT_OS2*   os2;
+
+    const FT_Frame_Field  os2_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_OS2
+
+      FT_FRAME_START( 78 ),
+        FT_FRAME_USHORT( version ),
+        FT_FRAME_SHORT ( xAvgCharWidth ),
+        FT_FRAME_USHORT( usWeightClass ),
+        FT_FRAME_USHORT( usWidthClass ),
+        FT_FRAME_SHORT ( fsType ),
+        FT_FRAME_SHORT ( ySubscriptXSize ),
+        FT_FRAME_SHORT ( ySubscriptYSize ),
+        FT_FRAME_SHORT ( ySubscriptXOffset ),
+        FT_FRAME_SHORT ( ySubscriptYOffset ),
+        FT_FRAME_SHORT ( ySuperscriptXSize ),
+        FT_FRAME_SHORT ( ySuperscriptYSize ),
+        FT_FRAME_SHORT ( ySuperscriptXOffset ),
+        FT_FRAME_SHORT ( ySuperscriptYOffset ),
+        FT_FRAME_SHORT ( yStrikeoutSize ),
+        FT_FRAME_SHORT ( yStrikeoutPosition ),
+        FT_FRAME_SHORT ( sFamilyClass ),
+        FT_FRAME_BYTE  ( panose[0] ),
+        FT_FRAME_BYTE  ( panose[1] ),
+        FT_FRAME_BYTE  ( panose[2] ),
+        FT_FRAME_BYTE  ( panose[3] ),
+        FT_FRAME_BYTE  ( panose[4] ),
+        FT_FRAME_BYTE  ( panose[5] ),
+        FT_FRAME_BYTE  ( panose[6] ),
+        FT_FRAME_BYTE  ( panose[7] ),
+        FT_FRAME_BYTE  ( panose[8] ),
+        FT_FRAME_BYTE  ( panose[9] ),
+        FT_FRAME_ULONG ( ulUnicodeRange1 ),
+        FT_FRAME_ULONG ( ulUnicodeRange2 ),
+        FT_FRAME_ULONG ( ulUnicodeRange3 ),
+        FT_FRAME_ULONG ( ulUnicodeRange4 ),
+        FT_FRAME_BYTE  ( achVendID[0] ),
+        FT_FRAME_BYTE  ( achVendID[1] ),
+        FT_FRAME_BYTE  ( achVendID[2] ),
+        FT_FRAME_BYTE  ( achVendID[3] ),
+
+        FT_FRAME_USHORT( fsSelection ),
+        FT_FRAME_USHORT( usFirstCharIndex ),
+        FT_FRAME_USHORT( usLastCharIndex ),
+        FT_FRAME_SHORT ( sTypoAscender ),
+        FT_FRAME_SHORT ( sTypoDescender ),
+        FT_FRAME_SHORT ( sTypoLineGap ),
+        FT_FRAME_USHORT( usWinAscent ),
+        FT_FRAME_USHORT( usWinDescent ),
+      FT_FRAME_END
+    };
+
+    const FT_Frame_Field  os2_fields_extra[] =
+    {
+      FT_FRAME_START( 8 ),
+        FT_FRAME_ULONG( ulCodePageRange1 ),
+        FT_FRAME_ULONG( ulCodePageRange2 ),
+      FT_FRAME_END
+    };
+
+    const FT_Frame_Field  os2_fields_extra2[] =
+    {
+      FT_FRAME_START( 10 ),
+        FT_FRAME_SHORT ( sxHeight ),
+        FT_FRAME_SHORT ( sCapHeight ),
+        FT_FRAME_USHORT( usDefaultChar ),
+        FT_FRAME_USHORT( usBreakChar ),
+        FT_FRAME_USHORT( usMaxContext ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( "OS/2 Table " ));
+
+    /* We now support old Mac fonts where the OS/2 table doesn't  */
+    /* exist.  Simply put, we set the `version' field to 0xFFFF   */
+    /* and test this value each time we need to access the table. */
+    error = face->goto_table( face, TTAG_OS2, stream, 0 );
+    if ( error )
+    {
+      FT_TRACE2(( "is missing!\n" ));
+      face->os2.version = 0xFFFFU;
+      error = SFNT_Err_Ok;
+      goto Exit;
+    }
+
+    os2 = &face->os2;
+
+    if ( FT_STREAM_READ_FIELDS( os2_fields, os2 ) )
+      goto Exit;
+
+    os2->ulCodePageRange1 = 0;
+    os2->ulCodePageRange2 = 0;
+    os2->sxHeight         = 0;
+    os2->sCapHeight       = 0;
+    os2->usDefaultChar    = 0;
+    os2->usBreakChar      = 0;
+    os2->usMaxContext     = 0;
+
+    if ( os2->version >= 0x0001 )
+    {
+      /* only version 1 tables */
+      if ( FT_STREAM_READ_FIELDS( os2_fields_extra, os2 ) )
+        goto Exit;
+
+      if ( os2->version >= 0x0002 )
+      {
+        /* only version 2 tables */
+        if ( FT_STREAM_READ_FIELDS( os2_fields_extra2, os2 ) )
+          goto Exit;
+      }
+    }
+
+    FT_TRACE2(( "loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_postscript                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the Postscript table.                                        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_postscript( TT_Face    face,
+                           FT_Stream  stream )
+  {
+    FT_Error        error;
+    TT_Postscript*  post = &face->postscript;
+
+    static const FT_Frame_Field  post_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_Postscript
+
+      FT_FRAME_START( 32 ),
+        FT_FRAME_ULONG( FormatType ),
+        FT_FRAME_ULONG( italicAngle ),
+        FT_FRAME_SHORT( underlinePosition ),
+        FT_FRAME_SHORT( underlineThickness ),
+        FT_FRAME_ULONG( isFixedPitch ),
+        FT_FRAME_ULONG( minMemType42 ),
+        FT_FRAME_ULONG( maxMemType42 ),
+        FT_FRAME_ULONG( minMemType1 ),
+        FT_FRAME_ULONG( maxMemType1 ),
+      FT_FRAME_END
+    };
+
+
+    FT_TRACE2(( "PostScript " ));
+
+    error = face->goto_table( face, TTAG_post, stream, 0 );
+    if ( error )
+      return SFNT_Err_Post_Table_Missing;
+
+    if ( FT_STREAM_READ_FIELDS( post_fields, post ) )
+      return error;
+
+    /* we don't load the glyph names, we do that in another */
+    /* module (ttpost).                                     */
+    FT_TRACE2(( "loaded\n" ));
+
+    return SFNT_Err_Ok;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_pclt                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the PCL 5 Table.                                             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_pclt( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    static const FT_Frame_Field  pclt_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_PCLT
+
+      FT_FRAME_START( 54 ),
+        FT_FRAME_ULONG ( Version ),
+        FT_FRAME_ULONG ( FontNumber ),
+        FT_FRAME_USHORT( Pitch ),
+        FT_FRAME_USHORT( xHeight ),
+        FT_FRAME_USHORT( Style ),
+        FT_FRAME_USHORT( TypeFamily ),
+        FT_FRAME_USHORT( CapHeight ),
+        FT_FRAME_BYTES ( TypeFace, 16 ),
+        FT_FRAME_BYTES ( CharacterComplement, 8 ),
+        FT_FRAME_BYTES ( FileName, 6 ),
+        FT_FRAME_CHAR  ( StrokeWeight ),
+        FT_FRAME_CHAR  ( WidthType ),
+        FT_FRAME_BYTE  ( SerifStyle ),
+        FT_FRAME_BYTE  ( Reserved ),
+      FT_FRAME_END
+    };
+
+    FT_Error  error;
+    TT_PCLT*  pclt = &face->pclt;
+
+
+    FT_TRACE2(( "PCLT " ));
+
+    /* optional table */
+    error = face->goto_table( face, TTAG_PCLT, stream, 0 );
+    if ( error )
+    {
+      FT_TRACE2(( "missing (optional)\n" ));
+      pclt->Version = 0;
+      return SFNT_Err_Ok;
+    }
+
+    if ( FT_STREAM_READ_FIELDS( pclt_fields, pclt ) )
+      goto Exit;
+
+    FT_TRACE2(( "loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_gasp                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the `gasp' table into a face object.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_gasp( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+    FT_UInt        j,num_ranges;
+    TT_GaspRange   gaspranges;
+
+
+    FT_TRACE2(( "tt_face_load_gasp: %08p\n", face ));
+
+    /* the gasp table is optional */
+    error = face->goto_table( face, TTAG_gasp, stream, 0 );
+    if ( error )
+      return SFNT_Err_Ok;
+
+    if ( FT_FRAME_ENTER( 4L ) )
+      goto Exit;
+
+    face->gasp.version   = FT_GET_USHORT();
+    face->gasp.numRanges = FT_GET_USHORT();
+
+    FT_FRAME_EXIT();
+
+    num_ranges = face->gasp.numRanges;
+    FT_TRACE3(( "number of ranges = %d\n", num_ranges ));
+
+    if ( FT_NEW_ARRAY( gaspranges, num_ranges ) ||
+         FT_FRAME_ENTER( num_ranges * 4L )      )
+      goto Exit;
+
+    face->gasp.gaspRanges = gaspranges;
+
+    for ( j = 0; j < num_ranges; j++ )
+    {
+      gaspranges[j].maxPPEM  = FT_GET_USHORT();
+      gaspranges[j].gaspFlag = FT_GET_USHORT();
+
+      FT_TRACE3(( " [max:%d flag:%d]",
+                    gaspranges[j].maxPPEM,
+                    gaspranges[j].gaspFlag ));
+    }
+    FT_TRACE3(( "\n" ));
+
+    FT_FRAME_EXIT();
+    FT_TRACE2(( "GASP loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( int )
+  tt_kern_pair_compare( const void*  a,
+                        const void*  b );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_kern                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the first kerning table with format 0 in the font.  Only     */
+  /*    accepts the first horizontal kerning table.  Developers should use */
+  /*    the `ftxkern' extension to access other kerning tables in the font */
+  /*    file, if they really want to.                                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_kern( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+    FT_UInt    n, num_tables;
+
+
+    /* the kern table is optional; exit silently if it is missing */
+    error = face->goto_table( face, TTAG_kern, stream, 0 );
+    if ( error )
+      return SFNT_Err_Ok;
+
+    if ( FT_FRAME_ENTER( 4L ) )
+      goto Exit;
+
+    (void)FT_GET_USHORT();         /* version */
+    num_tables = FT_GET_USHORT();
+
+    FT_FRAME_EXIT();
+
+    for ( n = 0; n < num_tables; n++ )
+    {
+      FT_UInt  coverage;
+      FT_UInt  length;
+
+
+      if ( FT_FRAME_ENTER( 6L ) )
+        goto Exit;
+
+      (void)FT_GET_USHORT();           /* version                 */
+      length   = FT_GET_USHORT() - 6;  /* substract header length */
+      coverage = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+
+      if ( coverage == 0x0001 )
+      {
+        FT_UInt        num_pairs;
+        TT_Kern0_Pair  pair;
+        TT_Kern0_Pair  limit;
+
+
+        /* found a horizontal format 0 kerning table! */
+        if ( FT_FRAME_ENTER( 8L ) )
+          goto Exit;
+
+        num_pairs = FT_GET_USHORT();
+
+        /* skip the rest */
+
+        FT_FRAME_EXIT();
+
+        /* allocate array of kerning pairs */
+        if ( FT_NEW_ARRAY( face->kern_pairs, num_pairs ) ||
+             FT_FRAME_ENTER( 6L * num_pairs )            )
+          goto Exit;
+
+        pair  = face->kern_pairs;
+        limit = pair + num_pairs;
+        for ( ; pair < limit; pair++ )
+        {
+          pair->left  = FT_GET_USHORT();
+          pair->right = FT_GET_USHORT();
+          pair->value = FT_GET_USHORT();
+        }
+
+        FT_FRAME_EXIT();
+
+        face->num_kern_pairs   = num_pairs;
+        face->kern_table_index = n;
+
+        /* ensure that the kerning pair table is sorted (yes, some */
+        /* fonts have unsorted tables!)                            */
+        {
+          FT_UInt        i;
+          TT_Kern0_Pair  pair0;
+
+
+          pair0 = face->kern_pairs;
+
+          for ( i = 1; i < num_pairs; i++, pair0++ )
+          {
+            if ( tt_kern_pair_compare( pair0, pair0 + 1 ) != -1 )
+            {
+              ft_qsort( (void*)face->kern_pairs, (int)num_pairs,
+                        sizeof ( TT_Kern0_PairRec ), tt_kern_pair_compare );
+              break;
+            }
+          }
+        }
+
+        goto Exit;
+      }
+
+      if ( FT_STREAM_SKIP( length ) )
+        goto Exit;
+    }
+
+    /* no kern table found -- doesn't matter */
+    face->kern_table_index = -1;
+    face->num_kern_pairs   = 0;
+    face->kern_pairs       = NULL;
+
+  Exit:
+    return error;
+  }
+
+
+#undef  TT_KERN_INDEX
+#define TT_KERN_INDEX( g1, g2 )  ( ( (FT_ULong)g1 << 16 ) | g2 )
+
+
+  FT_CALLBACK_DEF( int )
+  tt_kern_pair_compare( const void*  a,
+                        const void*  b )
+  {
+    TT_Kern0_Pair  pair1 = (TT_Kern0_Pair)a;
+    TT_Kern0_Pair  pair2 = (TT_Kern0_Pair)b;
+
+    FT_ULong  index1 = TT_KERN_INDEX( pair1->left, pair1->right );
+    FT_ULong  index2 = TT_KERN_INDEX( pair2->left, pair2->right );
+
+
+    return ( index1 < index2 ? -1 :
+           ( index1 > index2 ?  1 : 0 ));
+  }
+
+
+#undef TT_KERN_INDEX
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_hdmx                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the horizontal device metrics table.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_hdmx( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+    TT_Hdmx    hdmx = &face->hdmx;
+    FT_Long    num_glyphs;
+    FT_Long    record_size;
+
+
+    hdmx->version     = 0;
+    hdmx->num_records = 0;
+    hdmx->records     = 0;
+
+    /* this table is optional */
+    error = face->goto_table( face, TTAG_hdmx, stream, 0 );
+    if ( error )
+      return SFNT_Err_Ok;
+
+    if ( FT_FRAME_ENTER( 8L ) )
+      goto Exit;
+
+    hdmx->version     = FT_GET_USHORT();
+    hdmx->num_records = FT_GET_SHORT();
+    record_size       = FT_GET_LONG();
+
+    FT_FRAME_EXIT();
+
+    /* Only recognize format 0 */
+    if ( hdmx->version != 0 )
+      goto Exit;
+
+    if ( FT_NEW_ARRAY( hdmx->records, hdmx->num_records ) )
+      goto Exit;
+
+    num_glyphs   = face->root.num_glyphs;
+    record_size -= num_glyphs + 2;
+
+    {
+      TT_HdmxEntry  cur   = hdmx->records;
+      TT_HdmxEntry  limit = cur + hdmx->num_records;
+
+
+      for ( ; cur < limit; cur++ )
+      {
+        /* read record */
+        if ( FT_READ_BYTE( cur->ppem      ) ||
+             FT_READ_BYTE( cur->max_width ) )
+          goto Exit;
+
+        if ( FT_ALLOC( cur->widths, num_glyphs )       ||
+             FT_STREAM_READ( cur->widths, num_glyphs ) )
+          goto Exit;
+
+        /* skip padding bytes */
+        if ( record_size > 0 && FT_STREAM_SKIP( record_size ) )
+            goto Exit;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_free_hdmx                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Frees the horizontal device metrics table.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A handle to the target face object.                        */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  tt_face_free_hdmx( TT_Face  face )
+  {
+    if ( face )
+    {
+      FT_Int     n;
+      FT_Memory  memory = face->root.driver->root.memory;
+
+
+      for ( n = 0; n < face->hdmx.num_records; n++ )
+        FT_FREE( face->hdmx.records[n].widths );
+
+      FT_FREE( face->hdmx.records );
+      face->hdmx.num_records = 0;
+    }
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttload.h
@@ -1,0 +1,137 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttload.h                                                               */
+/*                                                                         */
+/*    Load the basic TrueType tables, i.e., tables that can be either in   */
+/*    TTF or OTF fonts (specification).                                    */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTLOAD_H__
+#define __TTLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( TT_Table  )
+  tt_face_lookup_table( TT_Face   face,
+                        FT_ULong  tag );
+
+  FT_LOCAL( FT_Error )
+  tt_face_goto_table( TT_Face    face,
+                      FT_ULong   tag,
+                      FT_Stream  stream,
+                      FT_ULong*  length );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_sfnt_header( TT_Face      face,
+                            FT_Stream    stream,
+                            FT_Long      face_index,
+                            SFNT_Header  sfnt );
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_directory( TT_Face      face,
+                          FT_Stream    stream,
+                          SFNT_Header  sfnt );
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_any( TT_Face    face,
+                    FT_ULong   tag,
+                    FT_Long    offset,
+                    FT_Byte*   buffer,
+                    FT_ULong*  length );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_header( TT_Face    face,
+                       FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_metrics_header( TT_Face    face,
+                               FT_Stream  stream,
+                               FT_Bool    vertical );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_cmap( TT_Face    face,
+                     FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_max_profile( TT_Face    face,
+                            FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_names( TT_Face    face,
+                      FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_os2( TT_Face    face,
+                    FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_postscript( TT_Face    face,
+                           FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_hdmx( TT_Face    face,
+                     FT_Stream  stream );
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_pclt( TT_Face    face,
+                     FT_Stream  stream );
+
+  FT_LOCAL( void )
+  tt_face_free_names( TT_Face  face );
+
+
+  FT_LOCAL( void )
+  tt_face_free_hdmx ( TT_Face  face );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_kern( TT_Face    face,
+                     FT_Stream  stream );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_gasp( TT_Face    face,
+                     FT_Stream  stream );
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_bitmap_header( TT_Face    face,
+                              FT_Stream  stream );
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+FT_END_HEADER
+
+#endif /* __TTLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttobjs.c
@@ -1,0 +1,861 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttobjs.c                                                               */
+/*                                                                         */
+/*    Objects manager (body).                                              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_INTERNAL_SFNT_H
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#include "ttgload.h"
+#include "ttpload.h"
+
+#include "tterrors.h"
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+#include "ttinterp.h"
+#endif
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttobjs
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                       GLYPH ZONE FUNCTIONS                            */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_glyphzone_done                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Deallocates a glyph zone.                                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    zone :: A pointer to the target glyph zone.                        */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  tt_glyphzone_done( TT_GlyphZone  zone )
+  {
+    FT_Memory  memory = zone->memory;
+
+
+    FT_FREE( zone->contours );
+    FT_FREE( zone->tags );
+    FT_FREE( zone->cur );
+    FT_FREE( zone->org );
+
+    zone->max_points   = zone->n_points   = 0;
+    zone->max_contours = zone->n_contours = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_glyphzone_new                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Allocates a new glyph zone.                                        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    memory      :: A handle to the current memory object.              */
+  /*                                                                       */
+  /*    maxPoints   :: The capacity of glyph zone in points.               */
+  /*                                                                       */
+  /*    maxContours :: The capacity of glyph zone in contours.             */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    zone        :: A pointer to the target glyph zone record.          */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_glyphzone_new( FT_Memory     memory,
+                    FT_UShort     maxPoints,
+                    FT_Short      maxContours,
+                    TT_GlyphZone  zone )
+  {
+    FT_Error  error;
+
+
+    if ( maxPoints > 0 )
+      maxPoints += 2;
+
+    FT_MEM_ZERO( zone, sizeof ( *zone ) );
+    zone->memory = memory;
+
+    if ( FT_NEW_ARRAY( zone->org,      maxPoints * 2 ) ||
+         FT_NEW_ARRAY( zone->cur,      maxPoints * 2 ) ||
+         FT_NEW_ARRAY( zone->tags,     maxPoints     ) ||
+         FT_NEW_ARRAY( zone->contours, maxContours   ) )
+    {
+      tt_glyphzone_done( zone );
+    }
+
+    return error;
+  }
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_init                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given TrueType face object.                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream     :: The source font stream.                              */
+  /*                                                                       */
+  /*    face_index :: The index of the font face in the resource.          */
+  /*                                                                       */
+  /*    num_params :: Number of additional generic parameters.  Ignored.   */
+  /*                                                                       */
+  /*    params     :: Additional generic parameters.  Ignored.             */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face       :: The newly built face object.                         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_init( FT_Stream      stream,
+                TT_Face        face,
+                FT_Int         face_index,
+                FT_Int         num_params,
+                FT_Parameter*  params )
+  {
+    FT_Error      error;
+    FT_Library    library;
+    SFNT_Service  sfnt;
+
+
+    library = face->root.driver->root.library;
+    sfnt    = (SFNT_Service)FT_Get_Module_Interface( library, "sfnt" );
+    if ( !sfnt )
+      goto Bad_Format;
+
+    /* create input stream from resource */
+    if ( FT_STREAM_SEEK( 0 ) )
+      goto Exit;
+
+    /* check that we have a valid TrueType file */
+    error = sfnt->init_face( stream, face, face_index, num_params, params );
+    if ( error )
+      goto Exit;
+
+    /* We must also be able to accept Mac/GX fonts, as well as OT ones */
+    if ( face->format_tag != 0x00010000L &&    /* MS fonts  */
+         face->format_tag != TTAG_true   )     /* Mac fonts */
+    {
+      FT_TRACE2(( "[not a valid TTF font]\n" ));
+      goto Bad_Format;
+    }
+
+    /* If we are performing a simple font format check, exit immediately */
+    if ( face_index < 0 )
+      return TT_Err_Ok;
+
+    /* Load font directory */
+    error = sfnt->load_face( stream, face, face_index, num_params, params );
+    if ( error )
+      goto Exit;
+
+    if ( face->root.face_flags & FT_FACE_FLAG_SCALABLE )
+      {
+
+#ifdef FT_CONFIG_OPTION_INCREMENTAL
+
+        if ( !face->root.internal->incremental_interface )
+          error = tt_face_load_loca( face, stream );
+        if ( !error )
+          error = tt_face_load_cvt      ( face, stream ) ||
+                  tt_face_load_fpgm ( face, stream );
+
+#else
+
+        if ( !error )
+          error = tt_face_load_loca( face, stream ) ||
+                  tt_face_load_cvt      ( face, stream ) ||
+                  tt_face_load_fpgm ( face, stream );
+
+#endif
+
+      }
+
+    /* initialize standard glyph loading routines */
+    TT_Init_Glyph_Loading( face );
+
+  Exit:
+    return error;
+
+  Bad_Format:
+    error = TT_Err_Unknown_File_Format;
+    goto Exit;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_done                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a given face object.                                     */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: A pointer to the face object to destroy.                   */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  tt_face_done( TT_Face  face )
+  {
+    FT_Memory     memory = face->root.memory;
+    FT_Stream     stream = face->root.stream;
+
+    SFNT_Service  sfnt   = (SFNT_Service)face->sfnt;
+
+
+    /* for `extended TrueType formats' (i.e. compressed versions) */
+    if ( face->extra.finalizer )
+      face->extra.finalizer( face->extra.data );
+
+    if ( sfnt )
+      sfnt->done_face( face );
+
+    /* freeing the locations table */
+    FT_FREE( face->glyph_locations );
+    face->num_locations = 0;
+
+    /* freeing the CVT */
+    FT_FREE( face->cvt );
+    face->cvt_size = 0;
+
+    /* freeing the programs */
+    FT_FRAME_RELEASE( face->font_program );
+    FT_FRAME_RELEASE( face->cvt_program );
+    face->font_program_size = 0;
+    face->cvt_program_size  = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*                           SIZE  FUNCTIONS                             */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_size_init                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a new TrueType size object.                            */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    size :: A handle to the size object.                               */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_size_init( TT_Size  size )
+  {
+    FT_Error  error = TT_Err_Ok;
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    TT_Face    face   = (TT_Face)size->root.face;
+    FT_Memory  memory = face->root.memory;
+    FT_Int     i;
+
+    TT_ExecContext  exec;
+    FT_UShort       n_twilight;
+    TT_MaxProfile*  maxp = &face->max_profile;
+
+
+    size->ttmetrics.valid = FALSE;
+
+    size->max_function_defs    = maxp->maxFunctionDefs;
+    size->max_instruction_defs = maxp->maxInstructionDefs;
+
+    size->num_function_defs    = 0;
+    size->num_instruction_defs = 0;
+
+    size->max_func = 0;
+    size->max_ins  = 0;
+
+    size->cvt_size     = face->cvt_size;
+    size->storage_size = maxp->maxStorage;
+
+    /* Set default metrics */
+    {
+      FT_Size_Metrics*  metrics  = &size->root.metrics;
+      TT_Size_Metrics*  metrics2 = &size->ttmetrics;
+
+
+      metrics->x_ppem = 0;
+      metrics->y_ppem = 0;
+
+      metrics2->rotated   = FALSE;
+      metrics2->stretched = FALSE;
+
+      /* set default compensation (all 0) */
+      for ( i = 0; i < 4; i++ )
+        metrics2->compensations[i] = 0;
+    }
+
+    /* allocate function defs, instruction defs, cvt, and storage area */
+    if ( FT_NEW_ARRAY( size->function_defs,    size->max_function_defs    ) ||
+         FT_NEW_ARRAY( size->instruction_defs, size->max_instruction_defs ) ||
+         FT_NEW_ARRAY( size->cvt,              size->cvt_size             ) ||
+         FT_NEW_ARRAY( size->storage,          size->storage_size         ) )
+
+      goto Fail_Memory;
+
+    /* reserve twilight zone */
+    n_twilight = maxp->maxTwilightPoints;
+    error = tt_glyphzone_new( memory, n_twilight, 0, &size->twilight );
+    if ( error )
+      goto Fail_Memory;
+
+    size->twilight.n_points = n_twilight;
+
+    /* set `face->interpreter' according to the debug hook present */
+    {
+      FT_Library  library = face->root.driver->root.library;
+
+
+      face->interpreter = (TT_Interpreter)
+                            library->debug_hooks[FT_DEBUG_HOOK_TRUETYPE];
+      if ( !face->interpreter )
+        face->interpreter = (TT_Interpreter)TT_RunIns;
+    }
+
+    /* Fine, now execute the font program! */
+    exec = size->context;
+    /* size objects used during debugging have their own context */
+    if ( !size->debug )
+      exec = TT_New_Context( face );
+
+    if ( !exec )
+    {
+      error = TT_Err_Could_Not_Find_Context;
+      goto Fail_Memory;
+    }
+
+    size->GS = tt_default_graphics_state;
+    TT_Load_Context( exec, face, size );
+
+    exec->callTop   = 0;
+    exec->top       = 0;
+
+    exec->period    = 64;
+    exec->phase     = 0;
+    exec->threshold = 0;
+
+    {
+      FT_Size_Metrics*  metrics    = &exec->metrics;
+      TT_Size_Metrics*  tt_metrics = &exec->tt_metrics;
+
+
+      metrics->x_ppem   = 0;
+      metrics->y_ppem   = 0;
+      metrics->x_scale  = 0;
+      metrics->y_scale  = 0;
+
+      tt_metrics->ppem  = 0;
+      tt_metrics->scale = 0;
+      tt_metrics->ratio = 0x10000L;
+    }
+
+    exec->instruction_trap = FALSE;
+
+    exec->cvtSize = size->cvt_size;
+    exec->cvt     = size->cvt;
+
+    exec->F_dot_P = 0x10000L;
+
+    /* allow font program execution */
+    TT_Set_CodeRange( exec,
+                      tt_coderange_font,
+                      face->font_program,
+                      face->font_program_size );
+
+    /* disable CVT and glyph programs coderange */
+    TT_Clear_CodeRange( exec, tt_coderange_cvt );
+    TT_Clear_CodeRange( exec, tt_coderange_glyph );
+
+    if ( face->font_program_size > 0 )
+    {
+      error = TT_Goto_CodeRange( exec, tt_coderange_font, 0 );
+      if ( !error )
+        error = face->interpreter( exec );
+
+      if ( error )
+        goto Fail_Exec;
+    }
+    else
+      error = TT_Err_Ok;
+
+    TT_Save_Context( exec, size );
+
+    if ( !size->debug )
+      TT_Done_Context( exec );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    size->ttmetrics.valid = FALSE;
+    return error;
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+  Fail_Exec:
+    if ( !size->debug )
+      TT_Done_Context( exec );
+
+  Fail_Memory:
+
+    tt_size_done( size );
+    return error;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_size_done                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The TrueType size object finalizer.                                */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    size :: A handle to the target size object.                        */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  tt_size_done( TT_Size  size )
+  {
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    FT_Memory  memory = size->root.face->memory;
+
+
+    if ( size->debug )
+    {
+      /* the debug context must be deleted by the debugger itself */
+      size->context = NULL;
+      size->debug   = FALSE;
+    }
+
+    FT_FREE( size->cvt );
+    size->cvt_size = 0;
+
+    /* free storage area */
+    FT_FREE( size->storage );
+    size->storage_size = 0;
+
+    /* twilight zone */
+    tt_glyphzone_done( &size->twilight );
+
+    FT_FREE( size->function_defs );
+    FT_FREE( size->instruction_defs );
+
+    size->num_function_defs    = 0;
+    size->max_function_defs    = 0;
+    size->num_instruction_defs = 0;
+    size->max_instruction_defs = 0;
+
+    size->max_func = 0;
+    size->max_ins  = 0;
+
+#endif
+
+    size->ttmetrics.valid = FALSE;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Reset_Outline_Size                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Resets a TrueType outline size when resolutions and character      */
+  /*    dimensions have been changed.                                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    size :: A handle to the target size object.                        */
+  /*                                                                       */
+  static FT_Error
+  Reset_Outline_Size( TT_Size  size )
+  {
+    TT_Face           face;
+    FT_Error          error = TT_Err_Ok;
+
+    FT_Size_Metrics*  metrics;
+
+
+    if ( size->ttmetrics.valid )
+      return TT_Err_Ok;
+
+    face = (TT_Face)size->root.face;
+
+    metrics = &size->root.metrics;
+
+    if ( metrics->x_ppem < 1 || metrics->y_ppem < 1 )
+      return TT_Err_Invalid_PPem;
+
+    /* compute new transformation */
+    if ( metrics->x_ppem >= metrics->y_ppem )
+    {
+      size->ttmetrics.scale   = metrics->x_scale;
+      size->ttmetrics.ppem    = metrics->x_ppem;
+      size->ttmetrics.x_ratio = 0x10000L;
+      size->ttmetrics.y_ratio = FT_MulDiv( metrics->y_ppem,
+                                           0x10000L,
+                                           metrics->x_ppem );
+    }
+    else
+    {
+      size->ttmetrics.scale   = metrics->y_scale;
+      size->ttmetrics.ppem    = metrics->y_ppem;
+      size->ttmetrics.x_ratio = FT_MulDiv( metrics->x_ppem,
+                                           0x10000L,
+                                           metrics->y_ppem );
+      size->ttmetrics.y_ratio = 0x10000L;
+    }
+
+    /* Compute root ascender, descender, test height, and max_advance */
+    metrics->ascender    = ( FT_MulFix( face->root.ascender,
+                                        metrics->y_scale ) + 32 ) & -64;
+    metrics->descender   = ( FT_MulFix( face->root.descender,
+                                        metrics->y_scale ) + 32 ) & -64;
+    metrics->height      = ( FT_MulFix( face->root.height,
+                                        metrics->y_scale ) + 32 ) & -64;
+    metrics->max_advance = ( FT_MulFix( face->root.max_advance_width,
+                                        metrics->x_scale ) + 32 ) & -64;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+    /* set to `invalid' by default */
+    size->strike_index = 0xFFFFU;
+#endif
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    {
+      TT_ExecContext  exec;
+      FT_UInt         i, j;
+
+
+      /* Scale the cvt values to the new ppem.          */
+      /* We use by default the y ppem to scale the CVT. */
+      for ( i = 0; i < size->cvt_size; i++ )
+        size->cvt[i] = FT_MulFix( face->cvt[i], size->ttmetrics.scale );
+
+      /* All twilight points are originally zero */
+      for ( j = 0; j < (FT_UInt)size->twilight.n_points; j++ )
+      {
+        size->twilight.org[j].x = 0;
+        size->twilight.org[j].y = 0;
+        size->twilight.cur[j].x = 0;
+        size->twilight.cur[j].y = 0;
+      }
+
+      /* clear storage area */
+      for ( i = 0; i < (FT_UInt)size->storage_size; i++ )
+        size->storage[i] = 0;
+
+      size->GS = tt_default_graphics_state;
+
+      /* get execution context and run prep program */
+      if ( size->debug )
+        exec = size->context;
+      else
+        exec = TT_New_Context( face );
+      /* debugging instances have their own context */
+
+      if ( !exec )
+        return TT_Err_Could_Not_Find_Context;
+
+      TT_Load_Context( exec, face, size );
+
+      TT_Set_CodeRange( exec,
+                        tt_coderange_cvt,
+                        face->cvt_program,
+                        face->cvt_program_size );
+
+      TT_Clear_CodeRange( exec, tt_coderange_glyph );
+
+      exec->instruction_trap = FALSE;
+
+      exec->top     = 0;
+      exec->callTop = 0;
+
+      if ( face->cvt_program_size > 0 )
+      {
+        error = TT_Goto_CodeRange( exec, tt_coderange_cvt, 0 );
+        if ( error )
+          goto End;
+
+        if ( !size->debug )
+          error = face->interpreter( exec );
+      }
+      else
+        error = TT_Err_Ok;
+
+      size->GS = exec->GS;
+      /* save default graphics state */
+
+    End:
+      TT_Save_Context( exec, size );
+
+      if ( !size->debug )
+        TT_Done_Context( exec );
+      /* debugging instances keep their context */
+    }
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+    if ( !error )
+      size->ttmetrics.valid = TRUE;
+
+    return error;
+  }
+
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    Reset_SBit_Size                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Resets a TrueType sbit size when resolutions and character         */
+  /*    dimensions have been changed.                                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    size :: A handle to the target size object.                        */
+  /*                                                                       */
+  static FT_Error
+  Reset_SBit_Size( TT_Size  size )
+  {
+    TT_Face           face;
+    FT_Error          error = TT_Err_Ok;
+
+    FT_ULong          strike_index;
+    FT_Size_Metrics*  metrics;
+    FT_Size_Metrics*  sbit_metrics;
+    SFNT_Service      sfnt;
+
+
+    metrics = &size->root.metrics;
+
+    if ( size->strike_index != 0xFFFFU )
+      return TT_Err_Ok;
+
+    face = (TT_Face)size->root.face;
+    sfnt = (SFNT_Service)face->sfnt;
+
+    sbit_metrics = &size->strike_metrics;
+
+    error = sfnt->set_sbit_strike(face,
+                                  metrics->x_ppem, metrics->y_ppem,
+                                  &strike_index);
+
+    if ( !error )
+    {
+      TT_SBit_Strike  strike = face->sbit_strikes + strike_index;
+
+
+      sbit_metrics->x_ppem      = metrics->x_ppem;
+      sbit_metrics->y_ppem      = metrics->y_ppem;
+#if 0
+      /*
+       * sbit_metrics->?_scale
+       * are not used now.
+       */
+      sbit_metrics->x_scale     = 1 << 16;
+      sbit_metrics->y_scale     = 1 << 16;
+#endif
+
+      sbit_metrics->ascender    = strike->hori.ascender  << 6;
+      sbit_metrics->descender   = strike->hori.descender << 6;
+
+      /* XXX: Is this correct? */
+      sbit_metrics->height      = sbit_metrics->ascender -
+                                  sbit_metrics->descender;
+
+      /* XXX: Is this correct? */
+      sbit_metrics->max_advance = ( strike->hori.min_origin_SB +
+                                    strike->hori.max_width     +
+                                    strike->hori.min_advance_SB ) << 6;
+
+      size->strike_index = strike_index;
+    }
+    else
+    {
+      size->strike_index = 0xFFFFU;
+
+      sbit_metrics->x_ppem      = 0;
+      sbit_metrics->y_ppem      = 0;
+      sbit_metrics->ascender    = 0;
+      sbit_metrics->descender   = 0;
+      sbit_metrics->height      = 0;
+      sbit_metrics->max_advance = 0;
+    }
+
+    return error;
+  }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_size_reset                                                      */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Resets a TrueType size when resolutions and character dimensions   */
+  /*    have been changed.                                                 */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    size :: A handle to the target size object.                        */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_size_reset( TT_Size  size )
+  {
+    FT_Face   face;
+    FT_Error  error = TT_Err_Ok;
+
+
+    face = size->root.face;
+
+    if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+    {
+      if ( !size->ttmetrics.valid )
+        error = Reset_Outline_Size( size );
+
+      if ( error )
+        return error;
+    }
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    if ( face->face_flags & FT_FACE_FLAG_FIXED_SIZES )
+    {
+      if ( size->strike_index == 0xFFFFU )
+        error = Reset_SBit_Size( size );
+
+      if ( !error && !( face->face_flags & FT_FACE_FLAG_SCALABLE ) )
+        size->root.metrics = size->strike_metrics;
+    }
+
+#endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
+
+    if ( face->face_flags & FT_FACE_FLAG_SCALABLE )
+      return TT_Err_Ok;
+    else
+      return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_driver_init                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Initializes a given TrueType driver object.                        */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    driver :: A handle to the target driver object.                    */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_driver_init( TT_Driver  driver )
+  {
+    FT_Error  error;
+
+
+    /* set `extra' in glyph loader */
+    error = FT_GlyphLoader_CreateExtra( FT_DRIVER( driver )->glyph_loader );
+
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_driver_done                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Finalizes a given TrueType driver.                                 */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    driver :: A handle to the target TrueType driver.                  */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  tt_driver_done( TT_Driver  driver )
+  {
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    /* destroy the execution context */
+    if ( driver->context )
+    {
+      TT_Destroy_Context( driver->context, driver->root.root.memory );
+      driver->context = NULL;
+    }
+#else
+    FT_UNUSED( driver );
+#endif
+
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttobjs.h
@@ -1,0 +1,422 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttobjs.h                                                               */
+/*                                                                         */
+/*    Objects manager (specification).                                     */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTOBJS_H__
+#define __TTOBJS_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    TT_Driver                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a TrueType driver object.                              */
+  /*                                                                       */
+  typedef struct TT_DriverRec_*  TT_Driver;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    TT_Instance                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a TrueType size object.                                */
+  /*                                                                       */
+  typedef struct TT_SizeRec_*  TT_Size;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Type>                                                                */
+  /*    TT_GlyphSlot                                                       */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    A handle to a TrueType glyph slot object.                          */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    This is a direct typedef of FT_GlyphSlot, as there is nothing      */
+  /*    specific about the TrueType glyph slot.                            */
+  /*                                                                       */
+  typedef FT_GlyphSlot  TT_GlyphSlot;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Struct>                                                              */
+  /*    TT_GraphicsState                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    The TrueType graphics state used during bytecode interpretation.   */
+  /*                                                                       */
+  typedef struct  TT_GraphicsState_
+  {
+    FT_UShort      rp0;
+    FT_UShort      rp1;
+    FT_UShort      rp2;
+
+    FT_UnitVector  dualVector;
+    FT_UnitVector  projVector;
+    FT_UnitVector  freeVector;
+
+    FT_Long        loop;
+    FT_F26Dot6     minimum_distance;
+    FT_Int         round_state;
+
+    FT_Bool        auto_flip;
+    FT_F26Dot6     control_value_cutin;
+    FT_F26Dot6     single_width_cutin;
+    FT_F26Dot6     single_width_value;
+    FT_Short       delta_base;
+    FT_Short       delta_shift;
+
+    FT_Byte        instruct_control;
+    FT_Bool        scan_control;
+    FT_Int         scan_type;
+
+    FT_UShort      gep0;
+    FT_UShort      gep1;
+    FT_UShort      gep2;
+
+  } TT_GraphicsState;
+
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+  FT_LOCAL( void )
+  tt_glyphzone_done( TT_GlyphZone  zone );
+
+  FT_LOCAL( FT_Error )
+  tt_glyphzone_new( FT_Memory     memory,
+                    FT_UShort     maxPoints,
+                    FT_Short      maxContours,
+                    TT_GlyphZone  zone );
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /*  EXECUTION SUBTABLES                                                  */
+  /*                                                                       */
+  /*  These sub-tables relate to instruction execution.                    */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#define TT_MAX_CODE_RANGES  3
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* There can only be 3 active code ranges at once:                       */
+  /*   - the Font Program                                                  */
+  /*   - the CVT Program                                                   */
+  /*   - a glyph's instructions set                                        */
+  /*                                                                       */
+  typedef enum  TT_CodeRange_Tag_
+  {
+    tt_coderange_none = 0,
+    tt_coderange_font,
+    tt_coderange_cvt,
+    tt_coderange_glyph
+
+  } TT_CodeRange_Tag;
+
+
+  typedef struct  TT_CodeRange_
+  {
+    FT_Byte*  base;
+    FT_ULong  size;
+
+  } TT_CodeRange;
+
+  typedef TT_CodeRange  TT_CodeRangeTable[TT_MAX_CODE_RANGES];
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Defines a function/instruction definition record.                     */
+  /*                                                                       */
+  typedef struct  TT_DefRecord_
+  {
+    FT_Int   range;      /* in which code range is it located? */
+    FT_Long  start;      /* where does it start?               */
+    FT_UInt  opc;        /* function #, or instruction code    */
+    FT_Bool  active;     /* is it active?                      */
+
+  } TT_DefRecord, *TT_DefArray;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Subglyph transformation record.                                       */
+  /*                                                                       */
+  typedef struct  TT_Transform_
+  {
+    FT_Fixed    xx, xy;     /* transformation matrix coefficients */
+    FT_Fixed    yx, yy;
+    FT_F26Dot6  ox, oy;     /* offsets        */
+
+  } TT_Transform;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Subglyph loading record.  Used to load composite components.          */
+  /*                                                                       */
+  typedef struct  TT_SubglyphRec_
+  {
+    FT_Long          index;        /* subglyph index; initialized with -1 */
+    FT_Bool          is_scaled;    /* is the subglyph scaled?             */
+    FT_Bool          is_hinted;    /* should it be hinted?                */
+    FT_Bool          preserve_pps; /* preserve phantom points?            */
+
+    FT_Long          file_offset;
+
+    FT_BBox          bbox;
+    FT_Pos           left_bearing;
+    FT_Pos           advance;
+
+    TT_GlyphZoneRec  zone;
+
+    FT_Long          arg1;         /* first argument                      */
+    FT_Long          arg2;         /* second argument                     */
+
+    FT_UShort        element_flag; /* current load element flag           */
+
+    TT_Transform     transform;    /* transformation matrix               */
+
+    FT_Vector        pp1, pp2;     /* phantom points                      */
+
+  } TT_SubGlyphRec, *TT_SubGlyph_Stack;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* A note regarding non-squared pixels:                                  */
+  /*                                                                       */
+  /* (This text will probably go into some docs at some time; for now, it  */
+  /*  is kept here to explain some definitions in the TIns_Metrics         */
+  /*  record).                                                             */
+  /*                                                                       */
+  /* The CVT is a one-dimensional array containing values that control     */
+  /* certain important characteristics in a font, like the height of all   */
+  /* capitals, all lowercase letter, default spacing or stem width/height. */
+  /*                                                                       */
+  /* These values are found in FUnits in the font file, and must be scaled */
+  /* to pixel coordinates before being used by the CVT and glyph programs. */
+  /* Unfortunately, when using distinct x and y resolutions (or distinct x */
+  /* and y pointsizes), there are two possible scalings.                   */
+  /*                                                                       */
+  /* A first try was to implement a `lazy' scheme where all values were    */
+  /* scaled when first used.  However, while some values are always used   */
+  /* in the same direction, some others are used under many different      */
+  /* circumstances and orientations.                                       */
+  /*                                                                       */
+  /* I have found a simpler way to do the same, and it even seems to work  */
+  /* in most of the cases:                                                 */
+  /*                                                                       */
+  /* - All CVT values are scaled to the maximum ppem size.                 */
+  /*                                                                       */
+  /* - When performing a read or write in the CVT, a ratio factor is used  */
+  /*   to perform adequate scaling.  Example:                              */
+  /*                                                                       */
+  /*     x_ppem = 14                                                       */
+  /*     y_ppem = 10                                                       */
+  /*                                                                       */
+  /*   We choose ppem = x_ppem = 14 as the CVT scaling size.  All cvt      */
+  /*   entries are scaled to it.                                           */
+  /*                                                                       */
+  /*     x_ratio = 1.0                                                     */
+  /*     y_ratio = y_ppem/ppem (< 1.0)                                     */
+  /*                                                                       */
+  /*   We compute the current ratio like:                                  */
+  /*                                                                       */
+  /*   - If projVector is horizontal,                                      */
+  /*       ratio = x_ratio = 1.0                                           */
+  /*                                                                       */
+  /*   - if projVector is vertical,                                        */
+  /*       ratio = y_ratio                                                 */
+  /*                                                                       */
+  /*   - else,                                                             */
+  /*       ratio = sqrt( (proj.x * x_ratio) ^ 2 + (proj.y * y_ratio) ^ 2 ) */
+  /*                                                                       */
+  /*   Reading a cvt value returns                                         */
+  /*     ratio * cvt[index]                                                */
+  /*                                                                       */
+  /*   Writing a cvt value in pixels:                                      */
+  /*     cvt[index] / ratio                                                */
+  /*                                                                       */
+  /*   The current ppem is simply                                          */
+  /*     ratio * ppem                                                      */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Metrics used by the TrueType size and context objects.                */
+  /*                                                                       */
+  typedef struct  TT_Size_Metrics_
+  {
+    /* for non-square pixels */
+    FT_Long     x_ratio;
+    FT_Long     y_ratio;
+
+    FT_UShort   ppem;               /* maximum ppem size              */
+    FT_Long     ratio;              /* current ratio                  */
+    FT_Fixed    scale;
+
+    FT_F26Dot6  compensations[4];   /* device-specific compensations  */
+
+    FT_Bool     valid;
+
+    FT_Bool     rotated;            /* `is the glyph rotated?'-flag   */
+    FT_Bool     stretched;          /* `is the glyph stretched?'-flag */
+
+  } TT_Size_Metrics;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TrueType size class.                                                  */
+  /*                                                                       */
+  typedef struct  TT_SizeRec_
+  {
+    FT_SizeRec         root;
+
+    TT_Size_Metrics    ttmetrics;
+
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+
+    FT_UInt            strike_index;    /* 0xFFFF to indicate invalid */
+    FT_Size_Metrics    strike_metrics;  /* current strike's metrics   */
+
+#endif
+
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+
+    FT_UInt            num_function_defs; /* number of function definitions */
+    FT_UInt            max_function_defs;
+    TT_DefArray        function_defs;     /* table of function definitions  */
+
+    FT_UInt            num_instruction_defs;  /* number of ins. definitions */
+    FT_UInt            max_instruction_defs;
+    TT_DefArray        instruction_defs;      /* table of ins. definitions  */
+
+    FT_UInt            max_func;
+    FT_UInt            max_ins;
+
+    TT_CodeRangeTable  codeRangeTable;
+
+    TT_GraphicsState   GS;
+
+    FT_ULong           cvt_size;      /* the scaled control value table */
+    FT_Long*           cvt;
+
+    FT_UShort          storage_size; /* The storage area is now part of */
+    FT_Long*           storage;      /* the instance                    */
+
+    TT_GlyphZoneRec    twilight;     /* The instance's twilight zone    */
+
+    /* debugging variables */
+
+    /* When using the debugger, we must keep the */
+    /* execution context tied to the instance    */
+    /* object rather than asking it on demand.   */
+
+    FT_Bool            debug;
+    TT_ExecContext     context;
+
+#endif /* TT_CONFIG_OPTION_BYTECODE_INTERPRETER */
+
+  } TT_SizeRec;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* TrueType driver class.                                                */
+  /*                                                                       */
+  typedef struct  TT_DriverRec_
+  {
+    FT_DriverRec     root;
+    TT_ExecContext   context;  /* execution context        */
+    TT_GlyphZoneRec  zone;     /* glyph loader points zone */
+
+    void*            extension_component;
+
+  } TT_DriverRec;
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Face functions                                                        */
+  /*                                                                       */
+  FT_LOCAL( FT_Error )
+  tt_face_init( FT_Stream      stream,
+                TT_Face        face,
+                FT_Int         face_index,
+                FT_Int         num_params,
+                FT_Parameter*  params );
+
+  FT_LOCAL( void )
+  tt_face_done( TT_Face  face );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Size functions                                                        */
+  /*                                                                       */
+  FT_LOCAL( FT_Error )
+  tt_size_init( TT_Size  size );
+
+  FT_LOCAL( void )
+  tt_size_done( TT_Size  size );
+
+  FT_LOCAL( FT_Error )
+  tt_size_reset( TT_Size  size );
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* Driver functions                                                      */
+  /*                                                                       */
+  FT_LOCAL( FT_Error )
+  tt_driver_init( TT_Driver  driver );
+
+  FT_LOCAL( void )
+  tt_driver_done( TT_Driver  driver );
+
+
+FT_END_HEADER
+
+#endif /* __TTOBJS_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpload.c
@@ -1,0 +1,264 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttpload.c                                                              */
+/*                                                                         */
+/*    TrueType glyph data/program tables loader (body).                    */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+
+#include "ttpload.h"
+
+#include "tterrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttpload
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_loca                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the locations table.                                         */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_loca( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+    FT_Short   LongOffsets;
+    FT_ULong   table_len;
+
+
+    FT_TRACE2(( "Locations " ));
+    LongOffsets = face->header.Index_To_Loc_Format;
+
+    error = face->goto_table( face, TTAG_loca, stream, &table_len );
+    if ( error )
+    {
+      error = TT_Err_Locations_Missing;
+      goto Exit;
+    }
+
+    if ( LongOffsets != 0 )
+    {
+      face->num_locations = (FT_UShort)( table_len >> 2 );
+
+      FT_TRACE2(( "(32bit offsets): %12d ", face->num_locations ));
+
+      if ( FT_NEW_ARRAY( face->glyph_locations, face->num_locations ) )
+        goto Exit;
+
+      if ( FT_FRAME_ENTER( face->num_locations * 4L ) )
+        goto Exit;
+
+      {
+        FT_Long*  loc   = face->glyph_locations;
+        FT_Long*  limit = loc + face->num_locations;
+
+
+        for ( ; loc < limit; loc++ )
+          *loc = FT_GET_LONG();
+      }
+
+      FT_FRAME_EXIT();
+    }
+    else
+    {
+      face->num_locations = (FT_UShort)( table_len >> 1 );
+
+      FT_TRACE2(( "(16bit offsets): %12d ", face->num_locations ));
+
+      if ( FT_NEW_ARRAY( face->glyph_locations, face->num_locations ) )
+        goto Exit;
+
+      if ( FT_FRAME_ENTER( face->num_locations * 2L ) )
+        goto Exit;
+      {
+        FT_Long*  loc   = face->glyph_locations;
+        FT_Long*  limit = loc + face->num_locations;
+
+
+        for ( ; loc < limit; loc++ )
+          *loc = (FT_Long)( (FT_ULong)FT_GET_USHORT() * 2 );
+      }
+      FT_FRAME_EXIT();
+    }
+
+    FT_TRACE2(( "loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_cvt                                                   */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the control value table into a face object.                  */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_cvt( TT_Face    face,
+                    FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+    FT_ULong   table_len;
+
+
+    FT_TRACE2(( "CVT " ));
+
+    error = face->goto_table( face, TTAG_cvt, stream, &table_len );
+    if ( error )
+    {
+      FT_TRACE2(( "is missing!\n" ));
+
+      face->cvt_size = 0;
+      face->cvt      = NULL;
+      error          = TT_Err_Ok;
+
+      goto Exit;
+    }
+
+    face->cvt_size = table_len / 2;
+
+    if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
+      goto Exit;
+
+    if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
+      goto Exit;
+
+    {
+      FT_Short*  cur   = face->cvt;
+      FT_Short*  limit = cur + face->cvt_size;
+
+
+      for ( ; cur <  limit; cur++ )
+        *cur = FT_GET_SHORT();
+    }
+
+    FT_FRAME_EXIT();
+    FT_TRACE2(( "loaded\n" ));
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_fpgm                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the font program and the cvt program.                        */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    face   :: A handle to the target face object.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream :: A handle to the input stream.                            */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_fpgm( TT_Face    face,
+                     FT_Stream  stream )
+  {
+    FT_Error   error;
+    FT_ULong   table_len;
+
+
+    FT_TRACE2(( "Font program " ));
+
+    /* The font program is optional */
+    error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
+    if ( error )
+    {
+      face->font_program      = NULL;
+      face->font_program_size = 0;
+
+      FT_TRACE2(( "is missing!\n" ));
+    }
+    else
+    {
+      face->font_program_size = table_len;
+      if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
+        goto Exit;
+
+      FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
+    }
+
+    FT_TRACE2(( "Prep program " ));
+
+    error = face->goto_table( face, TTAG_prep, stream, &table_len );
+    if ( error )
+    {
+      face->cvt_program      = NULL;
+      face->cvt_program_size = 0;
+      error                  = TT_Err_Ok;
+
+      FT_TRACE2(( "is missing!\n" ));
+    }
+    else
+    {
+      face->cvt_program_size = table_len;
+      if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
+        goto Exit;
+
+      FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
+    }
+
+  Exit:
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpload.h
@@ -1,0 +1,48 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttpload.h                                                              */
+/*                                                                         */
+/*    TrueType glyph data/program tables loader (specification).           */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTPLOAD_H__
+#define __TTPLOAD_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_loca( TT_Face    face,
+                     FT_Stream  stream );
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_cvt( TT_Face    face,
+                    FT_Stream  stream );
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_fpgm( TT_Face    face,
+                     FT_Stream  stream );
+
+
+FT_END_HEADER
+
+#endif /* __TTPLOAD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpost.c
@@ -1,0 +1,521 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttpost.c                                                               */
+/*                                                                         */
+/*    Postcript name table processing for TrueType and OpenType fonts      */
+/*    (body).                                                              */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The post table is not completely loaded by the core engine.  This     */
+  /* file loads the missing PS glyph names and implements an API to access */
+  /* them.                                                                 */
+  /*                                                                       */
+  /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttpost.h"
+#include "ttload.h"
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttpost
+
+
+  /* If this configuration macro is defined, we rely on the `PSNames' */
+  /* module to grab the glyph names.                                  */
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+
+
+#include FT_INTERNAL_POSTSCRIPT_NAMES_H
+
+#define MAC_NAME( x )  ( (FT_String*)psnames->macintosh_name( x ) )
+
+
+#else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+   /* Otherwise, we ignore the `PSNames' module, and provide our own  */
+   /* table of Mac names.  Thus, it is possible to build a version of */
+   /* FreeType without the Type 1 driver & PSNames module.            */
+
+#define MAC_NAME( x )  tt_post_default_names[x]
+
+  /* the 258 default Mac PS glyph names */
+
+  static const FT_String*  tt_post_default_names[258] =
+  {
+    /*   0 */
+    ".notdef", ".null", "CR", "space", "exclam",
+    "quotedbl", "numbersign", "dollar", "percent", "ampersand",
+    /*  10 */
+    "quotesingle", "parenleft", "parenright", "asterisk", "plus",
+    "comma", "hyphen", "period", "slash", "zero",
+    /*  20 */
+    "one", "two", "three", "four", "five",
+    "six", "seven", "eight", "nine", "colon",
+    /*  30 */
+    "semicolon", "less", "equal", "greater", "question",
+    "at", "A", "B", "C", "D",
+    /*  40 */
+    "E", "F", "G", "H", "I",
+    "J", "K", "L", "M", "N",
+    /*  50 */
+    "O", "P", "Q", "R", "S",
+    "T", "U", "V", "W", "X",
+    /*  60 */
+    "Y", "Z", "bracketleft", "backslash", "bracketright",
+    "asciicircum", "underscore", "grave", "a", "b",
+    /*  70 */
+    "c", "d", "e", "f", "g",
+    "h", "i", "j", "k", "l",
+    /*  80 */
+    "m", "n", "o", "p", "q",
+    "r", "s", "t", "u", "v",
+    /*  90 */
+    "w", "x", "y", "z", "braceleft",
+    "bar", "braceright", "asciitilde", "Adieresis", "Aring",
+    /* 100 */
+    "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis",
+    "aacute", "agrave", "acircumflex", "adieresis", "atilde",
+    /* 110 */
+    "aring", "ccedilla", "eacute", "egrave", "ecircumflex",
+    "edieresis", "iacute", "igrave", "icircumflex", "idieresis",
+    /* 120 */
+    "ntilde", "oacute", "ograve", "ocircumflex", "odieresis",
+    "otilde", "uacute", "ugrave", "ucircumflex", "udieresis",
+    /* 130 */
+    "dagger", "degree", "cent", "sterling", "section",
+    "bullet", "paragraph", "germandbls", "registered", "copyright",
+    /* 140 */
+    "trademark", "acute", "dieresis", "notequal", "AE",
+    "Oslash", "infinity", "plusminus", "lessequal", "greaterequal",
+    /* 150 */
+    "yen", "mu", "partialdiff", "summation", "product",
+    "pi", "integral", "ordfeminine", "ordmasculine", "Omega",
+    /* 160 */
+    "ae", "oslash", "questiondown", "exclamdown", "logicalnot",
+    "radical", "florin", "approxequal", "Delta", "guillemotleft",
+    /* 170 */
+    "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde",
+    "Otilde", "OE", "oe", "endash", "emdash",
+    /* 180 */
+    "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide",
+    "lozenge", "ydieresis", "Ydieresis", "fraction", "currency",
+    /* 190 */
+    "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl",
+    "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
+    /* 200 */
+    "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute",
+    "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex",
+    /* 210 */
+    "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave",
+    "dotlessi", "circumflex", "tilde", "macron", "breve",
+    /* 220 */
+    "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek",
+    "caron", "Lslash", "lslash", "Scaron", "scaron",
+    /* 230 */
+    "Zcaron", "zcaron", "brokenbar", "Eth", "eth",
+    "Yacute", "yacute", "Thorn", "thorn", "minus",
+    /* 240 */
+    "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf",
+    "onequarter", "threequarters", "franc", "Gbreve", "gbreve",
+    /* 250 */
+    "Idot", "Scedilla", "scedilla", "Cacute", "cacute",
+    "Ccaron", "ccaron", "dmacron",
+  };
+
+
+#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
+
+
+  static FT_Error
+  load_format_20( TT_Face    face,
+                  FT_Stream  stream )
+  {
+    FT_Memory   memory = stream->memory;
+    FT_Error    error;
+
+    FT_Int      num_glyphs;
+    FT_UShort   num_names;
+
+    FT_UShort*  glyph_indices = 0;
+    FT_Char**   name_strings  = 0;
+
+
+    if ( FT_READ_USHORT( num_glyphs ) )
+      goto Exit;
+
+    /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
+    /* than the value in the maxp table (cf. cyberbit.ttf).             */
+
+    /* There already exist fonts which have more than 32768 glyph names */
+    /* in this table, so the test for this threshold has been dropped.  */
+
+    if ( num_glyphs > face->root.num_glyphs )
+    {
+      error = SFNT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    /* load the indices */
+    {
+      FT_Int  n;
+
+
+      if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) ||
+           FT_FRAME_ENTER( num_glyphs * 2L )          )
+        goto Fail;
+
+      for ( n = 0; n < num_glyphs; n++ )
+        glyph_indices[n] = FT_GET_USHORT();
+
+      FT_FRAME_EXIT();
+    }
+
+    /* compute number of names stored in table */
+    {
+      FT_Int  n;
+
+
+      num_names = 0;
+
+      for ( n = 0; n < num_glyphs; n++ )
+      {
+        FT_Int  idx;
+
+
+        idx = glyph_indices[n];
+        if ( idx >= 258 )
+        {
+          idx -= 257;
+          if ( idx > num_names )
+            num_names = (FT_UShort)idx;
+        }
+      }
+    }
+
+    /* now load the name strings */
+    {
+      FT_UShort  n;
+
+
+      if ( FT_NEW_ARRAY( name_strings, num_names ) )
+        goto Fail;
+
+      for ( n = 0; n < num_names; n++ )
+      {
+        FT_UInt  len;
+
+
+        if ( FT_READ_BYTE  ( len )                    ||
+             FT_NEW_ARRAY( name_strings[n], len + 1 ) ||
+             FT_STREAM_READ  ( name_strings[n], len ) )
+          goto Fail1;
+
+        name_strings[n][len] = '\0';
+      }
+    }
+
+    /* all right, set table fields and exit successfuly */
+    {
+      TT_Post_20  table = &face->postscript_names.names.format_20;
+
+
+      table->num_glyphs    = (FT_UShort)num_glyphs;
+      table->num_names     = (FT_UShort)num_names;
+      table->glyph_indices = glyph_indices;
+      table->glyph_names   = name_strings;
+    }
+    return SFNT_Err_Ok;
+
+  Fail1:
+    {
+      FT_UShort  n;
+
+
+      for ( n = 0; n < num_names; n++ )
+        FT_FREE( name_strings[n] );
+    }
+
+  Fail:
+    FT_FREE( name_strings );
+    FT_FREE( glyph_indices );
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  load_format_25( TT_Face    face,
+                  FT_Stream  stream )
+  {
+    FT_Memory  memory = stream->memory;
+    FT_Error   error;
+
+    FT_Int     num_glyphs;
+    FT_Char*   offset_table = 0;
+
+
+    /* UNDOCUMENTED!  This value appears only in the Apple TT specs. */
+    if ( FT_READ_USHORT( num_glyphs ) )
+      goto Exit;
+
+    /* check the number of glyphs */
+    if ( num_glyphs > face->root.num_glyphs || num_glyphs > 258 )
+    {
+      error = SFNT_Err_Invalid_File_Format;
+      goto Exit;
+    }
+
+    if ( FT_ALLOC( offset_table, num_glyphs )       ||
+         FT_STREAM_READ( offset_table, num_glyphs ) )
+      goto Fail;
+
+    /* now check the offset table */
+    {
+      FT_Int  n;
+
+
+      for ( n = 0; n < num_glyphs; n++ )
+      {
+        FT_Long  idx = (FT_Long)n + offset_table[n];
+
+
+        if ( idx < 0 || idx > num_glyphs )
+        {
+          error = SFNT_Err_Invalid_File_Format;
+          goto Fail;
+        }
+      }
+    }
+
+    /* OK, set table fields and exit successfuly */
+    {
+      TT_Post_25  table = &face->postscript_names.names.format_25;
+
+
+      table->num_glyphs = (FT_UShort)num_glyphs;
+      table->offsets    = offset_table;
+    }
+
+    return SFNT_Err_Ok;
+
+  Fail:
+    FT_FREE( offset_table );
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  load_post_names( TT_Face  face )
+  {
+    FT_Stream  stream;
+    FT_Error   error;
+    FT_Fixed   format;
+
+
+    /* get a stream for the face's resource */
+    stream = face->root.stream;
+
+    /* seek to the beginning of the PS names table */
+    error = face->goto_table( face, TTAG_post, stream, 0 );
+    if ( error )
+      goto Exit;
+
+    format = face->postscript.FormatType;
+
+    /* go to beginning of subtable */
+    if ( FT_STREAM_SKIP( 32 ) )
+      goto Exit;
+
+    /* now read postscript table */
+    if ( format == 0x00020000L )
+      error = load_format_20( face, stream );
+    else if ( format == 0x00028000L )
+      error = load_format_25( face, stream );
+    else
+      error = SFNT_Err_Invalid_File_Format;
+
+    face->postscript_names.loaded = 1;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  tt_face_free_ps_names( TT_Face  face )
+  {
+    FT_Memory      memory = face->root.memory;
+    TT_Post_Names  names  = &face->postscript_names;
+    FT_Fixed       format;
+
+
+    if ( names->loaded )
+    {
+      format = face->postscript.FormatType;
+
+      if ( format == 0x00020000L )
+      {
+        TT_Post_20  table = &names->names.format_20;
+        FT_UShort   n;
+
+
+        FT_FREE( table->glyph_indices );
+        table->num_glyphs = 0;
+
+        for ( n = 0; n < table->num_names; n++ )
+          FT_FREE( table->glyph_names[n] );
+
+        FT_FREE( table->glyph_names );
+        table->num_names = 0;
+      }
+      else if ( format == 0x00028000L )
+      {
+        TT_Post_25  table = &names->names.format_25;
+
+
+        FT_FREE( table->offsets );
+        table->num_glyphs = 0;
+      }
+    }
+    names->loaded = 0;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_get_ps_name                                                */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Gets the PostScript glyph name of a glyph.                         */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: A handle to the parent face.                             */
+  /*                                                                       */
+  /*    idx    :: The glyph index.                                         */
+  /*                                                                       */
+  /*    PSname :: The address of a string pointer.  Will be NULL in case   */
+  /*              of error, otherwise it is a pointer to the glyph name.   */
+  /*                                                                       */
+  /*              You must not modify the returned string!                 */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_get_ps_name( TT_Face      face,
+                       FT_UInt      idx,
+                       FT_String**  PSname )
+  {
+    FT_Error         error;
+    TT_Post_Names    names;
+    FT_Fixed         format;
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+    PSNames_Service  psnames;
+#endif
+
+
+    if ( !face )
+      return SFNT_Err_Invalid_Face_Handle;
+
+    if ( idx >= (FT_UInt)face->root.num_glyphs )
+      return SFNT_Err_Invalid_Glyph_Index;
+
+#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
+    psnames = (PSNames_Service)face->psnames;
+    if ( !psnames )
+      return SFNT_Err_Unimplemented_Feature;
+#endif
+
+    names = &face->postscript_names;
+
+    /* `.notdef' by default */
+    *PSname = MAC_NAME( 0 );
+
+    format = face->postscript.FormatType;
+
+    if ( format == 0x00010000L )
+    {
+      if ( idx < 258 )                    /* paranoid checking */
+        *PSname = MAC_NAME( idx );
+    }
+    else if ( format == 0x00020000L )
+    {
+      TT_Post_20  table = &names->names.format_20;
+
+
+      if ( !names->loaded )
+      {
+        error = load_post_names( face );
+        if ( error )
+          goto End;
+      }
+
+      if ( idx < (FT_UInt)table->num_glyphs )
+      {
+        FT_UShort  name_index = table->glyph_indices[idx];
+
+
+        if ( name_index < 258 )
+          *PSname = MAC_NAME( name_index );
+        else
+          *PSname = (FT_String*)table->glyph_names[name_index - 258];
+      }
+    }
+    else if ( format == 0x00028000L )
+    {
+      TT_Post_25  table = &names->names.format_25;
+
+
+      if ( !names->loaded )
+      {
+        error = load_post_names( face );
+        if ( error )
+          goto End;
+      }
+
+      if ( idx < (FT_UInt)table->num_glyphs )    /* paranoid checking */
+      {
+        idx    += table->offsets[idx];
+        *PSname = MAC_NAME( idx );
+      }
+    }
+    
+    /* nothing to do for format == 0x00030000L */
+
+  End:
+    return SFNT_Err_Ok;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttpost.h
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttpost.h                                                               */
+/*                                                                         */
+/*    Postcript name table processing for TrueType and OpenType fonts      */
+/*    (specification).                                                     */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTPOST_H__
+#define __TTPOST_H__
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_get_ps_name( TT_Face      face,
+                       FT_UInt      idx,
+                       FT_String**  PSname );
+
+  FT_LOCAL( void )
+  tt_face_free_ps_names( TT_Face  face );
+
+
+FT_END_HEADER
+
+#endif /* __TTPOST_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttsbit.c
@@ -1,0 +1,1474 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttsbit.c                                                               */
+/*                                                                         */
+/*    TrueType and OpenType embedded bitmap support (body).                */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TAGS_H
+#include "ttsbit.h"
+
+#include "sferrors.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_ttsbit
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    blit_sbit                                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Blits a bitmap from an input stream into a given target.  Supports */
+  /*    x and y offsets as well as byte padded lines.                      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    target      :: The target bitmap/pixmap.                           */
+  /*                                                                       */
+  /*    source      :: The input packed bitmap data.                       */
+  /*                                                                       */
+  /*    line_bits   :: The number of bits per line.                        */
+  /*                                                                       */
+  /*    byte_padded :: A flag which is true if lines are byte-padded.      */
+  /*                                                                       */
+  /*    x_offset    :: The horizontal offset.                              */
+  /*                                                                       */
+  /*    y_offset    :: The vertical offset.                                */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    IMPORTANT: The x and y offsets are relative to the top corner of   */
+  /*               the target bitmap (unlike the normal TrueType           */
+  /*               convention).  A positive y offset indicates a downwards */
+  /*               direction!                                              */
+  /*                                                                       */
+  static void
+  blit_sbit( FT_Bitmap*  target,
+             FT_Byte*    source,
+             FT_Int      line_bits,
+             FT_Bool     byte_padded,
+             FT_Int      x_offset,
+             FT_Int      y_offset )
+  {
+    FT_Byte*   line_buff;
+    FT_Int     line_incr;
+    FT_Int     height;
+
+    FT_UShort  acc;
+    FT_UInt    loaded;
+
+
+    /* first of all, compute starting write position */
+    line_incr = target->pitch;
+    line_buff = target->buffer;
+
+    if ( line_incr < 0 )
+      line_buff -= line_incr * ( target->rows - 1 );
+
+    line_buff += ( x_offset >> 3 ) + y_offset * line_incr;
+
+    /***********************************************************************/
+    /*                                                                     */
+    /* We use the extra-classic `accumulator' trick to extract the bits    */
+    /* from the source byte stream.                                        */
+    /*                                                                     */
+    /* Namely, the variable `acc' is a 16-bit accumulator containing the   */
+    /* last `loaded' bits from the input stream.  The bits are shifted to  */
+    /* the upmost position in `acc'.                                       */
+    /*                                                                     */
+    /***********************************************************************/
+
+    acc    = 0;  /* clear accumulator   */
+    loaded = 0;  /* no bits were loaded */
+
+    for ( height = target->rows; height > 0; height-- )
+    {
+      FT_Byte*  cur   = line_buff;        /* current write cursor          */
+      FT_Int    count = line_bits;        /* # of bits to extract per line */
+      FT_Byte   shift = (FT_Byte)( x_offset & 7 ); /* current write shift  */
+      FT_Byte   space = (FT_Byte)( 8 - shift );
+
+
+      /* first of all, read individual source bytes */
+      if ( count >= 8 )
+      {
+        count -= 8;
+        {
+          do
+          {
+            FT_Byte  val;
+
+
+            /* ensure that there are at least 8 bits in the accumulator */
+            if ( loaded < 8 )
+            {
+              acc    |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded ));
+              loaded += 8;
+            }
+
+            /* now write one byte */
+            val = (FT_Byte)( acc >> 8 );
+            if ( shift )
+            {
+              cur[0] |= (FT_Byte)( val >> shift );
+              cur[1] |= (FT_Byte)( val << space );
+            }
+            else
+              cur[0] |= val;
+
+            cur++;
+            acc   <<= 8;  /* remove bits from accumulator */
+            loaded -= 8;
+            count  -= 8;
+
+          } while ( count >= 0 );
+        }
+
+        /* restore `count' to correct value */
+        count += 8;
+      }
+
+      /* now write remaining bits (count < 8) */
+      if ( count > 0 )
+      {
+        FT_Byte  val;
+
+
+        /* ensure that there are at least `count' bits in the accumulator */
+        if ( (FT_Int)loaded < count )
+        {
+          acc    |= (FT_UShort)((FT_UShort)*source++ << ( 8 - loaded ));
+          loaded += 8;
+        }
+
+        /* now write remaining bits */
+        val     = (FT_Byte)( ( (FT_Byte)( acc >> 8 ) ) & ~( 0xFF >> count ) );
+        cur[0] |= (FT_Byte)( val >> shift );
+
+        if ( count > space )
+          cur[1] |= (FT_Byte)( val << space );
+
+        acc   <<= count;
+        loaded -= count;
+      }
+
+      /* now, skip to next line */
+      if ( byte_padded )
+      {
+        acc    = 0;
+        loaded = 0;   /* clear accumulator on byte-padded lines */
+      }
+
+      line_buff += line_incr;
+    }
+  }
+
+
+  const FT_Frame_Field  sbit_metrics_fields[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_SBit_MetricsRec
+
+    FT_FRAME_START( 8 ),
+      FT_FRAME_BYTE( height ),
+      FT_FRAME_BYTE( width ),
+
+      FT_FRAME_CHAR( horiBearingX ),
+      FT_FRAME_CHAR( horiBearingY ),
+      FT_FRAME_BYTE( horiAdvance ),
+
+      FT_FRAME_CHAR( vertBearingX ),
+      FT_FRAME_CHAR( vertBearingY ),
+      FT_FRAME_BYTE( vertAdvance ),
+    FT_FRAME_END
+  };
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Load_SBit_Const_Metrics                                         */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the metrics for `EBLC' index tables format 2 and 5.          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    range  :: The target range.                                        */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Load_SBit_Const_Metrics( TT_SBit_Range  range,
+                           FT_Stream      stream )
+  {
+    FT_Error  error;
+
+
+    if ( FT_READ_ULONG( range->image_size ) )
+      return error;
+
+    return FT_STREAM_READ_FIELDS( sbit_metrics_fields, &range->metrics );
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Load_SBit_Range_Codes                                           */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the range codes for `EBLC' index tables format 4 and 5.      */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    range        :: The target range.                                  */
+  /*                                                                       */
+  /*    stream       :: The input stream.                                  */
+  /*                                                                       */
+  /*    load_offsets :: A flag whether to load the glyph offset table.     */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Load_SBit_Range_Codes( TT_SBit_Range  range,
+                         FT_Stream      stream,
+                         FT_Bool        load_offsets )
+  {
+    FT_Error   error;
+    FT_ULong   count, n, size;
+    FT_Memory  memory = stream->memory;
+
+
+    if ( FT_READ_ULONG( count ) )
+      goto Exit;
+
+    range->num_glyphs = count;
+
+    /* Allocate glyph offsets table if needed */
+    if ( load_offsets )
+    {
+      if ( FT_NEW_ARRAY( range->glyph_offsets, count ) )
+        goto Exit;
+
+      size = count * 4L;
+    }
+    else
+      size = count * 2L;
+
+    /* Allocate glyph codes table and access frame */
+    if ( FT_NEW_ARRAY ( range->glyph_codes, count ) ||
+         FT_FRAME_ENTER( size )                     )
+      goto Exit;
+
+    for ( n = 0; n < count; n++ )
+    {
+      range->glyph_codes[n] = FT_GET_USHORT();
+
+      if ( load_offsets )
+        range->glyph_offsets[n] = (FT_ULong)range->image_offset +
+                                  FT_GET_USHORT();
+    }
+
+    FT_FRAME_EXIT();
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    TT_Load_SBit_Range                                                 */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads a given `EBLC' index/range table.                            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    range  :: The target range.                                        */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  static FT_Error
+  Load_SBit_Range( TT_SBit_Range  range,
+                   FT_Stream      stream )
+  {
+    FT_Error   error;
+    FT_Memory  memory = stream->memory;
+
+
+    switch( range->index_format )
+    {
+    case 1:   /* variable metrics with 4-byte offsets */
+    case 3:   /* variable metrics with 2-byte offsets */
+      {
+        FT_ULong  num_glyphs, n;
+        FT_Int    size_elem;
+        FT_Bool   large = FT_BOOL( range->index_format == 1 );
+
+
+        num_glyphs        = range->last_glyph - range->first_glyph + 1L;
+        range->num_glyphs = num_glyphs;
+        num_glyphs++;                       /* XXX: BEWARE - see spec */
+
+        size_elem = large ? 4 : 2;
+
+        if ( FT_NEW_ARRAY( range->glyph_offsets, num_glyphs ) ||
+             FT_FRAME_ENTER( num_glyphs * size_elem )         )
+          goto Exit;
+
+        for ( n = 0; n < num_glyphs; n++ )
+          range->glyph_offsets[n] = (FT_ULong)( range->image_offset +
+                                                ( large ? FT_GET_ULONG()
+                                                        : FT_GET_USHORT() ) );
+        FT_FRAME_EXIT();
+      }
+      break;
+
+    case 2:   /* all glyphs have identical metrics */
+      error = Load_SBit_Const_Metrics( range, stream );
+      break;
+
+    case 4:
+      error = Load_SBit_Range_Codes( range, stream, 1 );
+      break;
+
+    case 5:
+      error = Load_SBit_Const_Metrics( range, stream )   ||
+              Load_SBit_Range_Codes( range, stream, 0 );
+      break;
+
+    default:
+      error = SFNT_Err_Invalid_File_Format;
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_sbit_strikes                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads the table of embedded bitmap sizes for this face.            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face   :: The target face object.                                  */
+  /*                                                                       */
+  /*    stream :: The input stream.                                        */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_sbit_strikes( TT_Face    face,
+                             FT_Stream  stream )
+  {
+    FT_Error   error  = 0;
+    FT_Memory  memory = stream->memory;
+    FT_Fixed   version;
+    FT_ULong   num_strikes;
+    FT_ULong   table_base;
+
+    const FT_Frame_Field  sbit_line_metrics_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_SBit_LineMetricsRec
+
+      /* no FT_FRAME_START */
+        FT_FRAME_CHAR( ascender ),
+        FT_FRAME_CHAR( descender ),
+        FT_FRAME_BYTE( max_width ),
+
+        FT_FRAME_CHAR( caret_slope_numerator ),
+        FT_FRAME_CHAR( caret_slope_denominator ),
+        FT_FRAME_CHAR( caret_offset ),
+
+        FT_FRAME_CHAR( min_origin_SB ),
+        FT_FRAME_CHAR( min_advance_SB ),
+        FT_FRAME_CHAR( max_before_BL ),
+        FT_FRAME_CHAR( min_after_BL ),
+        FT_FRAME_CHAR( pads[0] ),
+        FT_FRAME_CHAR( pads[1] ),
+      FT_FRAME_END
+    };
+
+    const FT_Frame_Field  strike_start_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_SBit_StrikeRec
+
+      /* no FT_FRAME_START */
+        FT_FRAME_ULONG( ranges_offset ),
+        FT_FRAME_SKIP_LONG,
+        FT_FRAME_ULONG( num_ranges ),
+        FT_FRAME_ULONG( color_ref ),
+      FT_FRAME_END
+    };
+
+    const FT_Frame_Field  strike_end_fields[] =
+    {
+      /* no FT_FRAME_START */
+        FT_FRAME_USHORT( start_glyph ),
+        FT_FRAME_USHORT( end_glyph ),
+        FT_FRAME_BYTE  ( x_ppem ),
+        FT_FRAME_BYTE  ( y_ppem ),
+        FT_FRAME_BYTE  ( bit_depth ),
+        FT_FRAME_CHAR  ( flags ),
+      FT_FRAME_END
+    };
+
+
+    face->num_sbit_strikes = 0;
+
+    /* this table is optional */
+    error = face->goto_table( face, TTAG_EBLC, stream, 0 );
+    if ( error )
+      error = face->goto_table( face, TTAG_bloc, stream, 0 );
+    if ( error )
+      goto Exit;
+
+    table_base = FT_STREAM_POS();
+    if ( FT_FRAME_ENTER( 8L ) )
+      goto Exit;
+
+    version     = FT_GET_LONG();
+    num_strikes = FT_GET_ULONG();
+
+    FT_FRAME_EXIT();
+
+    /* check version number and strike count */
+    if ( version     != 0x00020000L ||
+         num_strikes >= 0x10000L    )
+    {
+      FT_ERROR(( "tt_face_load_sbit_strikes: invalid table version!\n" ));
+      error = SFNT_Err_Invalid_File_Format;
+
+      goto Exit;
+    }
+
+    /* allocate the strikes table */
+    if ( FT_NEW_ARRAY( face->sbit_strikes, num_strikes ) )
+      goto Exit;
+
+    face->num_sbit_strikes = num_strikes;
+
+    /* now read each strike table separately */
+    {
+      TT_SBit_Strike  strike = face->sbit_strikes;
+      FT_ULong        count  = num_strikes;
+
+
+      if ( FT_FRAME_ENTER( 48L * num_strikes ) )
+        goto Exit;
+
+      while ( count > 0 )
+      {
+        if ( FT_STREAM_READ_FIELDS( strike_start_fields, strike )             ||
+             FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->hori ) ||
+             FT_STREAM_READ_FIELDS( sbit_line_metrics_fields, &strike->vert ) ||
+             FT_STREAM_READ_FIELDS( strike_end_fields, strike )               )
+          break;
+
+        count--;
+        strike++;
+      }
+
+      FT_FRAME_EXIT();
+    }
+
+    /* allocate the index ranges for each strike table */
+    {
+      TT_SBit_Strike  strike = face->sbit_strikes;
+      FT_ULong        count  = num_strikes;
+
+
+      while ( count > 0 )
+      {
+        TT_SBit_Range  range;
+        FT_ULong       count2 = strike->num_ranges;
+
+
+        if ( FT_NEW_ARRAY( strike->sbit_ranges, strike->num_ranges ) )
+          goto Exit;
+
+        /* read each range */
+        if ( FT_STREAM_SEEK( table_base + strike->ranges_offset ) ||
+             FT_FRAME_ENTER( strike->num_ranges * 8L )            )
+          goto Exit;
+
+        range = strike->sbit_ranges;
+        while ( count2 > 0 )
+        {
+          range->first_glyph  = FT_GET_USHORT();
+          range->last_glyph   = FT_GET_USHORT();
+          range->table_offset = table_base + strike->ranges_offset +
+                                  FT_GET_ULONG();
+          count2--;
+          range++;
+        }
+
+        FT_FRAME_EXIT();
+
+        /* Now, read each index table */
+        count2 = strike->num_ranges;
+        range  = strike->sbit_ranges;
+        while ( count2 > 0 )
+        {
+          /* Read the header */
+          if ( FT_STREAM_SEEK( range->table_offset ) ||
+               FT_FRAME_ENTER( 8L )                  )
+            goto Exit;
+
+          range->index_format = FT_GET_USHORT();
+          range->image_format = FT_GET_USHORT();
+          range->image_offset = FT_GET_ULONG();
+
+          FT_FRAME_EXIT();
+
+          error = Load_SBit_Range( range, stream );
+          if ( error )
+            goto Exit;
+
+          count2--;
+          range++;
+        }
+
+        count--;
+        strike++;
+      }
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_free_sbit_strikes                                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Releases the embedded bitmap tables.                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face :: The target face object.                                    */
+  /*                                                                       */
+  FT_LOCAL_DEF( void )
+  tt_face_free_sbit_strikes( TT_Face  face )
+  {
+    FT_Memory       memory       = face->root.memory;
+    TT_SBit_Strike  strike       = face->sbit_strikes;
+    TT_SBit_Strike  strike_limit = strike + face->num_sbit_strikes;
+
+
+    if ( strike )
+    {
+      for ( ; strike < strike_limit; strike++ )
+      {
+        TT_SBit_Range  range       = strike->sbit_ranges;
+        TT_SBit_Range  range_limit = range + strike->num_ranges;
+
+
+        if ( range )
+        {
+          for ( ; range < range_limit; range++ )
+          {
+            /* release the glyph offsets and codes tables */
+            /* where appropriate                          */
+            FT_FREE( range->glyph_offsets );
+            FT_FREE( range->glyph_codes );
+          }
+        }
+        FT_FREE( strike->sbit_ranges );
+        strike->num_ranges = 0;
+      }
+      FT_FREE( face->sbit_strikes );
+    }
+    face->num_sbit_strikes = 0;
+  }
+
+
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_set_sbit_strike( TT_Face    face,
+                           FT_Int     x_ppem,
+                           FT_Int     y_ppem,
+                           FT_ULong  *astrike_index )
+  {
+    FT_ULong  i;
+
+
+    if ( x_ppem < 0 || x_ppem > 255 ||
+         y_ppem < 1 || y_ppem > 255 )
+      return SFNT_Err_Invalid_PPem;
+
+    for ( i = 0; i < face->num_sbit_strikes; i++ )
+    {
+      if ( ( face->sbit_strikes[i].y_ppem  == y_ppem )    &&
+           ( ( x_ppem == 0 )                            ||
+             ( face->sbit_strikes[i].x_ppem == x_ppem ) ) )
+      {
+        *astrike_index = i;
+        return SFNT_Err_Ok;
+      }
+    }
+
+    return SFNT_Err_Invalid_PPem;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    find_sbit_range                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Scans a given strike's ranges and return, for a given glyph        */
+  /*    index, the corresponding sbit range, and `EBDT' offset.            */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    glyph_index   :: The glyph index.                                  */
+  /*                                                                       */
+  /*    strike        :: The source/current sbit strike.                   */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    arange        :: The sbit range containing the glyph index.        */
+  /*                                                                       */
+  /*    aglyph_offset :: The offset of the glyph data in `EBDT' table.     */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means the glyph index was found.           */
+  /*                                                                       */
+  static FT_Error
+  find_sbit_range( FT_UInt          glyph_index,
+                   TT_SBit_Strike   strike,
+                   TT_SBit_Range   *arange,
+                   FT_ULong        *aglyph_offset )
+  {
+    TT_SBit_RangeRec  *range, *range_limit;
+
+
+    /* check whether the glyph index is within this strike's */
+    /* glyph range                                           */
+    if ( glyph_index < (FT_UInt)strike->start_glyph ||
+         glyph_index > (FT_UInt)strike->end_glyph   )
+      goto Fail;
+
+    /* scan all ranges in strike */
+    range       = strike->sbit_ranges;
+    range_limit = range + strike->num_ranges;
+    if ( !range )
+      goto Fail;
+
+    for ( ; range < range_limit; range++ )
+    {
+      if ( glyph_index >= (FT_UInt)range->first_glyph &&
+           glyph_index <= (FT_UInt)range->last_glyph  )
+      {
+        FT_UShort  delta = (FT_UShort)( glyph_index - range->first_glyph );
+
+
+        switch ( range->index_format )
+        {
+        case 1:
+        case 3:
+          *aglyph_offset = range->glyph_offsets[delta];
+          break;
+
+        case 2:
+          *aglyph_offset = range->image_offset +
+                           range->image_size * delta;
+          break;
+
+        case 4:
+        case 5:
+          {
+            FT_ULong  n;
+
+
+            for ( n = 0; n < range->num_glyphs; n++ )
+            {
+              if ( (FT_UInt)range->glyph_codes[n] == glyph_index )
+              {
+                if ( range->index_format == 4 )
+                  *aglyph_offset = range->glyph_offsets[n];
+                else
+                  *aglyph_offset = range->image_offset +
+                                   n * range->image_size;
+                goto Found;
+              }
+            }
+          }
+
+        /* fall-through */
+        default:
+          goto Fail;
+        }
+
+      Found:
+        /* return successfully! */
+        *arange  = range;
+        return 0;
+      }
+    }
+
+  Fail:
+    *arange        = 0;
+    *aglyph_offset = 0;
+
+    return SFNT_Err_Invalid_Argument;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    find_sbit_image                                                    */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Checks whether an embedded bitmap (an `sbit') exists for a given   */
+  /*    glyph, at a given strike.                                          */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face          :: The target face object.                           */
+  /*                                                                       */
+  /*    glyph_index   :: The glyph index.                                  */
+  /*                                                                       */
+  /*    strike_index  :: The current strike index.                         */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    arange        :: The SBit range containing the glyph index.        */
+  /*                                                                       */
+  /*    astrike       :: The SBit strike containing the glyph index.       */
+  /*                                                                       */
+  /*    aglyph_offset :: The offset of the glyph data in `EBDT' table.     */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.  Returns                    */
+  /*    SFNT_Err_Invalid_Argument if no sbit exists for the requested      */
+  /*    glyph.                                                             */
+  /*                                                                       */
+  static FT_Error
+  find_sbit_image( TT_Face          face,
+                   FT_UInt          glyph_index,
+                   FT_ULong         strike_index,
+                   TT_SBit_Range   *arange,
+                   TT_SBit_Strike  *astrike,
+                   FT_ULong        *aglyph_offset )
+  {
+    FT_Error        error;
+    TT_SBit_Strike  strike;
+
+
+    if ( !face->sbit_strikes                        ||
+         ( face->num_sbit_strikes <= strike_index ) )
+      goto Fail;
+
+    strike = &face->sbit_strikes[strike_index];
+
+    error = find_sbit_range( glyph_index, strike,
+                             arange, aglyph_offset );
+    if ( error )
+      goto Fail;
+
+    *astrike = strike;
+
+    return SFNT_Err_Ok;
+
+  Fail:
+    /* no embedded bitmap for this glyph in face */
+    *arange        = 0;
+    *astrike       = 0;
+    *aglyph_offset = 0;
+
+    return SFNT_Err_Invalid_Argument;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    load_sbit_metrics                                                  */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Gets the big metrics for a given SBit.                             */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    stream      :: The input stream.                                   */
+  /*                                                                       */
+  /*    range       :: The SBit range containing the glyph.                */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    big_metrics :: A big SBit metrics structure for the glyph.         */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.                             */
+  /*                                                                       */
+  /* <Note>                                                                */
+  /*    The stream cursor must be positioned at the glyph's offset within  */
+  /*    the `EBDT' table before the call.                                  */
+  /*                                                                       */
+  /*    If the image format uses variable metrics, the stream cursor is    */
+  /*    positioned just after the metrics header in the `EBDT' table on    */
+  /*    function exit.                                                     */
+  /*                                                                       */
+  static FT_Error
+  load_sbit_metrics( FT_Stream        stream,
+                     TT_SBit_Range    range,
+                     TT_SBit_Metrics  metrics )
+  {
+    FT_Error  error = SFNT_Err_Ok;
+
+
+    switch ( range->image_format )
+    {
+    case 1:
+    case 2:
+    case 8:
+      /* variable small metrics */
+      {
+        TT_SBit_SmallMetricsRec  smetrics;
+
+        const FT_Frame_Field  sbit_small_metrics_fields[] =
+        {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_SBit_SmallMetricsRec
+
+          FT_FRAME_START( 5 ),
+            FT_FRAME_BYTE( height ),
+            FT_FRAME_BYTE( width ),
+            FT_FRAME_CHAR( bearingX ),
+            FT_FRAME_CHAR( bearingY ),
+            FT_FRAME_BYTE( advance ),
+          FT_FRAME_END
+        };
+
+
+        /* read small metrics */
+        if ( FT_STREAM_READ_FIELDS( sbit_small_metrics_fields, &smetrics ) )
+          goto Exit;
+
+        /* convert it to a big metrics */
+        metrics->height       = smetrics.height;
+        metrics->width        = smetrics.width;
+        metrics->horiBearingX = smetrics.bearingX;
+        metrics->horiBearingY = smetrics.bearingY;
+        metrics->horiAdvance  = smetrics.advance;
+
+        /* these metrics are made up at a higher level when */
+        /* needed.                                          */
+        metrics->vertBearingX = 0;
+        metrics->vertBearingY = 0;
+        metrics->vertAdvance  = 0;
+      }
+      break;
+
+    case 6:
+    case 7:
+    case 9:
+      /* variable big metrics */
+      if ( FT_STREAM_READ_FIELDS( sbit_metrics_fields, metrics ) )
+        goto Exit;
+      break;
+
+    case 5:
+    default:  /* constant metrics */
+      if ( range->index_format == 2 || range->index_format == 5 )
+        *metrics = range->metrics;
+      else
+        return SFNT_Err_Invalid_File_Format;
+   }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    crop_bitmap                                                        */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Crops a bitmap to its tightest bounding box, and adjusts its       */
+  /*    metrics.                                                           */
+  /*                                                                       */
+  /* <InOut>                                                               */
+  /*    map     :: The bitmap.                                             */
+  /*                                                                       */
+  /*    metrics :: The corresponding metrics structure.                    */
+  /*                                                                       */
+  static void
+  crop_bitmap( FT_Bitmap*       map,
+               TT_SBit_Metrics  metrics )
+  {
+    /***********************************************************************/
+    /*                                                                     */
+    /* In this situation, some bounding boxes of embedded bitmaps are too  */
+    /* large.  We need to crop it to a reasonable size.                    */
+    /*                                                                     */
+    /*      ---------                                                      */
+    /*      |       |                -----                                 */
+    /*      |  ***  |                |***|                                 */
+    /*      |   *   |                | * |                                 */
+    /*      |   *   |    ------>     | * |                                 */
+    /*      |   *   |                | * |                                 */
+    /*      |   *   |                | * |                                 */
+    /*      |  ***  |                |***|                                 */
+    /*      ---------                -----                                 */
+    /*                                                                     */
+    /***********************************************************************/
+
+    FT_Int    rows, count;
+    FT_Long   line_len;
+    FT_Byte*  line;
+
+
+    /***********************************************************************/
+    /*                                                                     */
+    /* first of all, check the top-most lines of the bitmap, and remove    */
+    /* them if they're empty.                                              */
+    /*                                                                     */
+    {
+      line     = (FT_Byte*)map->buffer;
+      rows     = map->rows;
+      line_len = map->pitch;
+
+
+      for ( count = 0; count < rows; count++ )
+      {
+        FT_Byte*  cur   = line;
+        FT_Byte*  limit = line + line_len;
+
+
+        for ( ; cur < limit; cur++ )
+          if ( cur[0] )
+            goto Found_Top;
+
+        /* the current line was empty - skip to next one */
+        line  = limit;
+      }
+
+    Found_Top:
+      /* check that we have at least one filled line */
+      if ( count >= rows )
+        goto Empty_Bitmap;
+
+      /* now, crop the empty upper lines */
+      if ( count > 0 )
+      {
+        line = (FT_Byte*)map->buffer;
+
+        FT_MEM_MOVE( line, line + count * line_len,
+                     ( rows - count ) * line_len );
+
+        metrics->height       = (FT_Byte)( metrics->height - count );
+        metrics->horiBearingY = (FT_Char)( metrics->horiBearingY - count );
+        metrics->vertBearingY = (FT_Char)( metrics->vertBearingY - count );
+
+        map->rows -= count;
+        rows      -= count;
+      }
+    }
+
+    /***********************************************************************/
+    /*                                                                     */
+    /* second, crop the lower lines                                        */
+    /*                                                                     */
+    {
+      line = (FT_Byte*)map->buffer + ( rows - 1 ) * line_len;
+
+      for ( count = 0; count < rows; count++ )
+      {
+        FT_Byte*  cur   = line;
+        FT_Byte*  limit = line + line_len;
+
+
+        for ( ; cur < limit; cur++ )
+          if ( cur[0] )
+            goto Found_Bottom;
+
+        /* the current line was empty - skip to previous one */
+        line -= line_len;
+      }
+
+    Found_Bottom:
+      if ( count > 0 )
+      {
+        metrics->height  = (FT_Byte)( metrics->height - count );
+        rows            -= count;
+        map->rows       -= count;
+      }
+    }
+
+    /***********************************************************************/
+    /*                                                                     */
+    /* third, get rid of the space on the left side of the glyph           */
+    /*                                                                     */
+    do
+    {
+      FT_Byte*  limit;
+
+
+      line  = (FT_Byte*)map->buffer;
+      limit = line + rows * line_len;
+
+      for ( ; line < limit; line += line_len )
+        if ( line[0] & 0x80 )
+          goto Found_Left;
+
+      /* shift the whole glyph one pixel to the left */
+      line  = (FT_Byte*)map->buffer;
+      limit = line + rows * line_len;
+
+      for ( ; line < limit; line += line_len )
+      {
+        FT_Int    n, width = map->width;
+        FT_Byte   old;
+        FT_Byte*  cur = line;
+
+
+        old = (FT_Byte)(cur[0] << 1);
+        for ( n = 8; n < width; n += 8 )
+        {
+          FT_Byte  val;
+
+
+          val    = cur[1];
+          cur[0] = (FT_Byte)( old | ( val >> 7 ) );
+          old    = (FT_Byte)( val << 1 );
+          cur++;
+        }
+        cur[0] = old;
+      }
+
+      map->width--;
+      metrics->horiBearingX++;
+      metrics->vertBearingX++;
+      metrics->width--;
+
+    } while ( map->width > 0 );
+
+  Found_Left:
+
+    /***********************************************************************/
+    /*                                                                     */
+    /* finally, crop the bitmap width to get rid of the space on the right */
+    /* side of the glyph.                                                  */
+    /*                                                                     */
+    do
+    {
+      FT_Int    right = map->width - 1;
+      FT_Byte*  limit;
+      FT_Byte   mask;
+
+
+      line  = (FT_Byte*)map->buffer + ( right >> 3 );
+      limit = line + rows * line_len;
+      mask  = (FT_Byte)( 0x80 >> ( right & 7 ) );
+
+      for ( ; line < limit; line += line_len )
+        if ( line[0] & mask )
+          goto Found_Right;
+
+      /* crop the whole glyph to the right */
+      map->width--;
+      metrics->width--;
+
+    } while ( map->width > 0 );
+
+  Found_Right:
+    /* all right, the bitmap was cropped */
+    return;
+
+  Empty_Bitmap:
+    map->width      = 0;
+    map->rows       = 0;
+    map->pitch      = 0;
+    map->pixel_mode = FT_PIXEL_MODE_MONO;
+  }
+
+
+  static FT_Error
+  Load_SBit_Single( FT_Bitmap*       map,
+                    FT_Int           x_offset,
+                    FT_Int           y_offset,
+                    FT_Int           pix_bits,
+                    FT_UShort        image_format,
+                    TT_SBit_Metrics  metrics,
+                    FT_Stream        stream )
+  {
+    FT_Error  error;
+
+
+    /* check that the source bitmap fits into the target pixmap */
+    if ( x_offset < 0 || x_offset + metrics->width  > map->width ||
+         y_offset < 0 || y_offset + metrics->height > map->rows  )
+    {
+      error = SFNT_Err_Invalid_Argument;
+
+      goto Exit;
+    }
+
+    {
+      FT_Int   glyph_width  = metrics->width;
+      FT_Int   glyph_height = metrics->height;
+      FT_Int   glyph_size;
+      FT_Int   line_bits    = pix_bits * glyph_width;
+      FT_Bool  pad_bytes    = 0;
+
+
+      /* compute size of glyph image */
+      switch ( image_format )
+      {
+      case 1:  /* byte-padded formats */
+      case 6:
+        {
+          FT_Int  line_length;
+
+
+          switch ( pix_bits )
+          {
+          case 1:
+            line_length = ( glyph_width + 7 ) >> 3;
+            break;
+          case 2:
+            line_length = ( glyph_width + 3 ) >> 2;
+            break;
+          case 4:
+            line_length = ( glyph_width + 1 ) >> 1;
+            break;
+          default:
+            line_length =   glyph_width;
+          }
+
+          glyph_size = glyph_height * line_length;
+          pad_bytes  = 1;
+        }
+        break;
+
+      case 2:
+      case 5:
+      case 7:
+        line_bits  =   glyph_width  * pix_bits;
+        glyph_size = ( glyph_height * line_bits + 7 ) >> 3;
+        break;
+
+      default:  /* invalid format */
+        return SFNT_Err_Invalid_File_Format;
+      }
+
+      /* Now read data and draw glyph into target pixmap       */
+      if ( FT_FRAME_ENTER( glyph_size ) )
+        goto Exit;
+
+      /* don't forget to multiply `x_offset' by `map->pix_bits' as */
+      /* the sbit blitter doesn't make a difference between pixmap */
+      /* depths.                                                   */
+      blit_sbit( map, (FT_Byte*)stream->cursor, line_bits, pad_bytes,
+                 x_offset * pix_bits, y_offset );
+
+      FT_FRAME_EXIT();
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  Load_SBit_Image( TT_SBit_Strike   strike,
+                   TT_SBit_Range    range,
+                   FT_ULong         ebdt_pos,
+                   FT_ULong         glyph_offset,
+                   FT_Bitmap*       map,
+                   FT_Int           x_offset,
+                   FT_Int           y_offset,
+                   FT_Stream        stream,
+                   TT_SBit_Metrics  metrics )
+  {
+    FT_Memory  memory = stream->memory;
+    FT_Error   error;
+
+
+    /* place stream at beginning of glyph data and read metrics */
+    if ( FT_STREAM_SEEK( ebdt_pos + glyph_offset ) )
+      goto Exit;
+
+    error = load_sbit_metrics( stream, range, metrics );
+    if ( error )
+      goto Exit;
+
+    /* this function is recursive.  At the top-level call, the */
+    /* field map.buffer is NULL.  We thus begin by finding the */
+    /* dimensions of the higher-level glyph to allocate the    */
+    /* final pixmap buffer                                     */
+    if ( map->buffer == 0 )
+    {
+      FT_Long  size;
+
+
+      map->width = metrics->width;
+      map->rows  = metrics->height;
+
+      switch ( strike->bit_depth )
+      {
+      case 1:
+        map->pixel_mode = FT_PIXEL_MODE_MONO;
+        map->pitch      = ( map->width + 7 ) >> 3;
+        break;
+
+      case 2:
+        map->pixel_mode = FT_PIXEL_MODE_GRAY2;
+        map->pitch      = ( map->width + 3 ) >> 2;
+        break;
+
+      case 4:
+        map->pixel_mode = FT_PIXEL_MODE_GRAY4;
+        map->pitch      = ( map->width + 1 ) >> 1;
+        break;
+
+      case 8:
+        map->pixel_mode = FT_PIXEL_MODE_GRAY;
+        map->pitch      = map->width;
+        break;
+
+      default:
+        return SFNT_Err_Invalid_File_Format;
+      }
+
+      size = map->rows * map->pitch;
+
+      /* check that there is no empty image */
+      if ( size == 0 )
+        goto Exit;     /* exit successfully! */
+
+      if ( FT_ALLOC( map->buffer, size ) )
+        goto Exit;
+    }
+
+    switch ( range->image_format )
+    {
+    case 1:  /* single sbit image - load it */
+    case 2:
+    case 5:
+    case 6:
+    case 7:
+      return Load_SBit_Single( map, x_offset, y_offset, strike->bit_depth,
+                               range->image_format, metrics, stream );
+
+    case 8:  /* compound format */
+      FT_Stream_Skip( stream, 1L );
+      /* fallthrough */
+
+    case 9:
+      break;
+
+    default: /* invalid image format */
+      return SFNT_Err_Invalid_File_Format;
+    }
+
+    /* All right, we have a compound format.  First of all, read */
+    /* the array of elements.                                    */
+    {
+      TT_SBit_Component  components;
+      TT_SBit_Component  comp;
+      FT_UShort          num_components, count;
+
+
+      if ( FT_READ_USHORT( num_components )           ||
+           FT_NEW_ARRAY( components, num_components ) )
+        goto Exit;
+
+      count = num_components;
+
+      if ( FT_FRAME_ENTER( 4L * num_components ) )
+        goto Fail_Memory;
+
+      for ( comp = components; count > 0; count--, comp++ )
+      {
+        comp->glyph_code = FT_GET_USHORT();
+        comp->x_offset   = FT_GET_CHAR();
+        comp->y_offset   = FT_GET_CHAR();
+      }
+
+      FT_FRAME_EXIT();
+
+      /* Now recursively load each element glyph */
+      count = num_components;
+      comp  = components;
+      for ( ; count > 0; count--, comp++ )
+      {
+        TT_SBit_Range       elem_range;
+        TT_SBit_MetricsRec  elem_metrics;
+        FT_ULong            elem_offset;
+
+
+        /* find the range for this element */
+        error = find_sbit_range( comp->glyph_code,
+                                 strike,
+                                 &elem_range,
+                                 &elem_offset );
+        if ( error )
+          goto Fail_Memory;
+
+        /* now load the element, recursively */
+        error = Load_SBit_Image( strike,
+                                 elem_range,
+                                 ebdt_pos,
+                                 elem_offset,
+                                 map,
+                                 x_offset + comp->x_offset,
+                                 y_offset + comp->y_offset,
+                                 stream,
+                                 &elem_metrics );
+        if ( error )
+          goto Fail_Memory;
+      }
+
+    Fail_Memory:
+      FT_FREE( components );
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    tt_face_load_sbit_image                                            */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    Loads a given glyph sbit image from the font resource.  This also  */
+  /*    returns its metrics.                                               */
+  /*                                                                       */
+  /* <Input>                                                               */
+  /*    face         :: The target face object.                            */
+  /*                                                                       */
+  /*    strike_index :: The current strike index.                          */
+  /*                                                                       */
+  /*    glyph_index  :: The current glyph index.                           */
+  /*                                                                       */
+  /*    load_flags   :: The glyph load flags (the code checks for the flag */
+  /*                    FT_LOAD_CROP_BITMAP).                              */
+  /*                                                                       */
+  /*    stream       :: The input stream.                                  */
+  /*                                                                       */
+  /* <Output>                                                              */
+  /*    map          :: The target pixmap.                                 */
+  /*                                                                       */
+  /*    metrics      :: A big sbit metrics structure for the glyph image.  */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    FreeType error code.  0 means success.  Returns an error if no     */
+  /*    glyph sbit exists for the index.                                   */
+  /*                                                                       */
+  /*  <Note>                                                               */
+  /*    The `map.buffer' field is always freed before the glyph is loaded. */
+  /*                                                                       */
+  FT_LOCAL_DEF( FT_Error )
+  tt_face_load_sbit_image( TT_Face              face,
+                           FT_ULong             strike_index,
+                           FT_UInt              glyph_index,
+                           FT_UInt              load_flags,
+                           FT_Stream            stream,
+                           FT_Bitmap           *map,
+                           TT_SBit_MetricsRec  *metrics )
+  {
+    FT_Error        error;
+    FT_Memory       memory = stream->memory;
+    FT_ULong        ebdt_pos, glyph_offset;
+
+    TT_SBit_Strike  strike;
+    TT_SBit_Range   range;
+
+
+    /* Check whether there is a glyph sbit for the current index */
+    error = find_sbit_image( face, glyph_index, strike_index,
+                             &range, &strike, &glyph_offset );
+    if ( error )
+      goto Exit;
+
+    /* now, find the location of the `EBDT' table in */
+    /* the font file                                 */
+    error = face->goto_table( face, TTAG_EBDT, stream, 0 );
+    if ( error )
+      error = face->goto_table( face, TTAG_bdat, stream, 0 );
+    if (error)
+      goto Exit;
+
+    ebdt_pos = FT_STREAM_POS();
+
+    /* clear the bitmap & load the bitmap */
+    if ( face->root.glyph->flags & FT_GLYPH_OWN_BITMAP )
+      FT_FREE( map->buffer );
+
+    map->rows = map->pitch = map->width = 0;
+
+    error = Load_SBit_Image( strike, range, ebdt_pos, glyph_offset,
+                             map, 0, 0, stream, metrics );
+    if ( error )
+      goto Exit;
+
+    /* the glyph slot owns this bitmap buffer */
+    face->root.glyph->flags |= FT_GLYPH_OWN_BITMAP;
+
+    /* setup vertical metrics if needed */
+    if ( strike->flags & 1 )
+    {
+      /* in case of a horizontal strike only */
+      FT_Int  advance;
+
+
+      advance = strike->hori.ascender - strike->hori.descender;
+
+      /* some heuristic values */
+
+      metrics->vertBearingX = (FT_Char)(-metrics->width / 2 );
+      metrics->vertBearingY = (FT_Char)( advance / 10 );
+      metrics->vertAdvance  = (FT_Char)( advance * 12 / 10 );
+    }
+
+    /* Crop the bitmap now, unless specified otherwise */
+    if ( load_flags & FT_LOAD_CROP_BITMAP )
+      crop_bitmap( map, metrics );
+
+  Exit:
+    return error;
+  }
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/ttsbit.h
@@ -1,0 +1,59 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ttsbit.h                                                               */
+/*                                                                         */
+/*    TrueType and OpenType embedded bitmap support (specification).       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __TTSBIT_H__
+#define __TTSBIT_H__
+
+
+#include <ft2build.h>
+#include "ttload.h"
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_sbit_strikes( TT_Face    face,
+                             FT_Stream  stream );
+
+  FT_LOCAL( void )
+  tt_face_free_sbit_strikes( TT_Face  face );
+
+
+  FT_LOCAL( FT_Error )
+  tt_face_set_sbit_strike( TT_Face    face,
+                           FT_Int     x_ppem,
+                           FT_Int     y_ppem,
+                           FT_ULong  *astrike_index );
+
+  FT_LOCAL( FT_Error )
+  tt_face_load_sbit_image( TT_Face              face,
+                           FT_ULong             strike_index,
+                           FT_UInt              glyph_index,
+                           FT_UInt              load_flags,
+                           FT_Stream            stream,
+                           FT_Bitmap           *map,
+                           TT_SBit_MetricsRec  *metrics );
+
+
+FT_END_HEADER
+
+#endif /* __TTSBIT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/type1.c
@@ -1,0 +1,33 @@
+/***************************************************************************/
+/*                                                                         */
+/*  type1.c                                                                */
+/*                                                                         */
+/*    FreeType Type 1 driver component (body only).                        */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "t1parse.c"
+#include "t1load.c"
+#include "t1objs.c"
+#include "t1driver.c"
+#include "t1gload.c"
+
+#ifndef T1_CONFIG_OPTION_NO_AFM
+#include "t1afm.c"
+#endif
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/type1cid.c
@@ -1,0 +1,29 @@
+/***************************************************************************/
+/*                                                                         */
+/*  type1cid.c                                                             */
+/*                                                                         */
+/*    FreeType OpenType driver component (body only).                      */
+/*                                                                         */
+/*  Copyright 1996-2001 by                                                 */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "cidparse.c"
+#include "cidload.c"
+#include "cidobjs.c"
+#include "cidriver.c"
+#include "cidgload.c"
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/type42.c
@@ -1,0 +1,25 @@
+/***************************************************************************/
+/*                                                                         */
+/*  type42.c                                                               */
+/*                                                                         */
+/*    FreeType Type 42 driver component.                                   */
+/*                                                                         */
+/*  Copyright 2002 by                                                      */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "t42objs.c"
+#include "t42parse.c"
+#include "t42drivr.c"
+
+/* END */
--- /dev/null
+++ b/libfreetype/winfnt.c
@@ -1,0 +1,691 @@
+/***************************************************************************/
+/*                                                                         */
+/*  winfnt.c                                                               */
+/*                                                                         */
+/*    FreeType font driver for Windows FNT/FON files                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_FNT_TYPES_H
+
+#include "winfnt.h"
+
+#include "fnterrs.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_winfnt
+
+
+  static
+  const FT_Frame_Field  winmz_header_fields[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  WinMZ_HeaderRec
+
+    FT_FRAME_START( 64 ),
+      FT_FRAME_USHORT_LE ( magic ),
+      FT_FRAME_SKIP_BYTES( 29 * 2 ),
+      FT_FRAME_ULONG_LE  ( lfanew ),
+    FT_FRAME_END
+  };
+
+  static
+  const FT_Frame_Field  winne_header_fields[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  WinNE_HeaderRec
+
+    FT_FRAME_START( 40 ),
+      FT_FRAME_USHORT_LE ( magic ),
+      FT_FRAME_SKIP_BYTES( 34 ),
+      FT_FRAME_USHORT_LE ( resource_tab_offset ),
+      FT_FRAME_USHORT_LE ( rname_tab_offset ),
+    FT_FRAME_END
+  };
+
+  static
+  const FT_Frame_Field  winfnt_header_fields[] =
+  {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  WinFNT_HeaderRec
+
+    FT_FRAME_START( 134 ),
+      FT_FRAME_USHORT_LE( version ),
+      FT_FRAME_ULONG_LE ( file_size ),
+      FT_FRAME_BYTES    ( copyright, 60 ),
+      FT_FRAME_USHORT_LE( file_type ),
+      FT_FRAME_USHORT_LE( nominal_point_size ),
+      FT_FRAME_USHORT_LE( vertical_resolution ),
+      FT_FRAME_USHORT_LE( horizontal_resolution ),
+      FT_FRAME_USHORT_LE( ascent ),
+      FT_FRAME_USHORT_LE( internal_leading ),
+      FT_FRAME_USHORT_LE( external_leading ),
+      FT_FRAME_BYTE     ( italic ),
+      FT_FRAME_BYTE     ( underline ),
+      FT_FRAME_BYTE     ( strike_out ),
+      FT_FRAME_USHORT_LE( weight ),
+      FT_FRAME_BYTE     ( charset ),
+      FT_FRAME_USHORT_LE( pixel_width ),
+      FT_FRAME_USHORT_LE( pixel_height ),
+      FT_FRAME_BYTE     ( pitch_and_family ),
+      FT_FRAME_USHORT_LE( avg_width ),
+      FT_FRAME_USHORT_LE( max_width ),
+      FT_FRAME_BYTE     ( first_char ),
+      FT_FRAME_BYTE     ( last_char ),
+      FT_FRAME_BYTE     ( default_char ),
+      FT_FRAME_BYTE     ( break_char ),
+      FT_FRAME_USHORT_LE( bytes_per_row ),
+      FT_FRAME_ULONG_LE ( device_offset ),
+      FT_FRAME_ULONG_LE ( face_name_offset ),
+      FT_FRAME_ULONG_LE ( bits_pointer ),
+      FT_FRAME_ULONG_LE ( bits_offset ),
+      FT_FRAME_BYTE     ( reserved ),
+      FT_FRAME_ULONG_LE ( flags ),
+      FT_FRAME_USHORT_LE( A_space ),
+      FT_FRAME_USHORT_LE( B_space ),
+      FT_FRAME_USHORT_LE( C_space ),
+      FT_FRAME_USHORT_LE( color_table_offset ),
+      FT_FRAME_BYTES    ( reserved, 4 ),
+    FT_FRAME_END
+  };
+
+
+  static void
+  fnt_font_done( FNT_Font   font,
+                 FT_Stream  stream )
+  {
+    if ( font->fnt_frame )
+      FT_FRAME_RELEASE( font->fnt_frame );
+
+    font->fnt_size  = 0;
+    font->fnt_frame = 0;
+  }
+
+
+  static FT_Error
+  fnt_font_load( FNT_Font   font,
+                 FT_Stream  stream )
+  {
+    FT_Error       error;
+    WinFNT_Header  header = &font->header;
+
+
+    /* first of all, read the FNT header */
+    if ( FT_STREAM_SEEK( font->offset )                   ||
+         FT_STREAM_READ_FIELDS( winfnt_header_fields, header ) )
+      goto Exit;
+
+    /* check header */
+    if ( header->version != 0x200 &&
+         header->version != 0x300 )
+    {
+      FT_TRACE2(( "[not a valid FNT file]\n" ));
+      error = FNT_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    if ( header->file_type & 1 )
+    {
+      FT_TRACE2(( "[can't handle vector FNT fonts]\n" ));
+      error = FNT_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
+    /* small fixup -- some fonts have the `pixel_width' field set to 0 */
+    if ( header->pixel_width == 0 )
+      header->pixel_width = header->pixel_height;
+
+    /* this is a FNT file/table, we now extract its frame */
+    if ( FT_STREAM_SEEK( font->offset )                         ||
+         FT_FRAME_EXTRACT( header->file_size, font->fnt_frame ) )
+      goto Exit;
+
+  Exit:
+    return error;
+  }
+
+
+  static void
+  fnt_face_done_fonts( FNT_Face  face )
+  {
+    FT_Memory  memory = FT_FACE( face )->memory;
+    FT_Stream  stream = FT_FACE( face )->stream;
+    FNT_Font   cur    = face->fonts;
+    FNT_Font   limit  = cur + face->num_fonts;
+
+
+    for ( ; cur < limit; cur++ )
+      fnt_font_done( cur, stream );
+
+    FT_FREE( face->fonts );
+    face->num_fonts = 0;
+  }
+
+
+  static FT_Error
+  fnt_face_get_dll_fonts( FNT_Face  face )
+  {
+    FT_Error         error;
+    FT_Stream        stream = FT_FACE( face )->stream;
+    FT_Memory        memory = FT_FACE( face )->memory;
+    WinMZ_HeaderRec  mz_header;
+
+
+    face->fonts     = 0;
+    face->num_fonts = 0;
+
+    /* does it begin with a MZ header? */
+    if ( FT_STREAM_SEEK( 0 )                                 ||
+         FT_STREAM_READ_FIELDS( winmz_header_fields, &mz_header ) )
+      goto Exit;
+
+    error = FNT_Err_Unknown_File_Format;
+    if ( mz_header.magic == WINFNT_MZ_MAGIC )
+    {
+      /* yes, now look for a NE header in the file */
+      WinNE_HeaderRec  ne_header;
+
+
+      if ( FT_STREAM_SEEK( mz_header.lfanew )                  ||
+           FT_STREAM_READ_FIELDS( winne_header_fields, &ne_header ) )
+        goto Exit;
+
+      error = FNT_Err_Unknown_File_Format;
+      if ( ne_header.magic == WINFNT_NE_MAGIC )
+      {
+        /* good, now look in the resource table for each FNT resource */
+        FT_ULong   res_offset = mz_header.lfanew +
+                                ne_header.resource_tab_offset;
+
+        FT_UShort  size_shift;
+        FT_UShort  font_count  = 0;
+        FT_ULong   font_offset = 0;
+
+
+        if ( FT_STREAM_SEEK( res_offset ) ||
+             FT_FRAME_ENTER( ne_header.rname_tab_offset -
+                             ne_header.resource_tab_offset ) )
+          goto Exit;
+
+        size_shift = FT_GET_USHORT_LE();
+
+        for (;;)
+        {
+          FT_UShort  type_id, count;
+
+
+          type_id = FT_GET_USHORT_LE();
+          if ( !type_id )
+            break;
+
+          count = FT_GET_USHORT_LE();
+
+          if ( type_id == 0x8008 )
+          {
+            font_count  = count;
+            font_offset = (FT_ULong)( FT_STREAM_POS() + 4 +
+                                      ( stream->cursor - stream->limit ) );
+            break;
+          }
+
+          stream->cursor += 4 + count * 12;
+        }
+        FT_FRAME_EXIT();
+
+        if ( !font_count || !font_offset )
+        {
+          FT_TRACE2(( "this file doesn't contain any FNT resources!\n" ));
+          error = FNT_Err_Unknown_File_Format;
+          goto Exit;
+        }
+
+        if ( FT_STREAM_SEEK( font_offset )           ||
+             FT_NEW_ARRAY( face->fonts, font_count ) )
+          goto Exit;
+
+        face->num_fonts = font_count;
+
+        if ( FT_FRAME_ENTER( (FT_Long)font_count * 12 ) )
+          goto Exit;
+
+        /* now read the offset and position of each FNT font */
+        {
+          FNT_Font  cur   = face->fonts;
+          FNT_Font  limit = cur + font_count;
+
+
+          for ( ; cur < limit; cur++ )
+          {
+            cur->offset     = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
+            cur->fnt_size   = (FT_ULong)FT_GET_USHORT_LE() << size_shift;
+            cur->size_shift = size_shift;
+            stream->cursor += 8;
+          }
+        }
+        FT_FRAME_EXIT();
+
+        /* finally, try to load each font there */
+        {
+          FNT_Font  cur   = face->fonts;
+          FNT_Font  limit = cur + font_count;
+
+
+          for ( ; cur < limit; cur++ )
+          {
+            error = fnt_font_load( cur, stream );
+            if ( error )
+              goto Fail;
+          }
+        }
+      }
+    }
+
+  Fail:
+    if ( error )
+      fnt_face_done_fonts( face );
+
+  Exit:
+    return error;
+  }
+
+
+
+  typedef struct  FNT_CMapRec_
+  {
+    FT_CMapRec  cmap;
+    FT_UInt32   first;
+    FT_UInt32   count;
+
+  } FNT_CMapRec, *FNT_CMap;
+
+
+  static FT_Error
+  fnt_cmap_init( FNT_CMap  cmap )
+  {
+    FNT_Face  face = (FNT_Face)FT_CMAP_FACE( cmap );
+    FNT_Font  font = face->fonts;
+
+
+    cmap->first = (FT_UInt32)  font->header.first_char;
+    cmap->count = (FT_UInt32)( font->header.last_char - cmap->first + 1 );
+
+    return 0;
+  }
+
+
+  static FT_UInt
+  fnt_cmap_char_index( FNT_CMap   cmap,
+                       FT_UInt32  char_code )
+  {
+    FT_UInt  gindex = 0;
+
+
+    char_code -= cmap->first;
+    if ( char_code < cmap->count )
+      gindex = char_code + 1;
+
+    return gindex;
+  }
+
+
+  static FT_UInt
+  fnt_cmap_char_next( FNT_CMap    cmap,
+                      FT_UInt32  *pchar_code )
+  {
+    FT_UInt    gindex = 0;
+    FT_UInt32  result = 0;
+    FT_UInt32  char_code = *pchar_code + 1;
+
+
+    if ( char_code <= cmap->first )
+    {
+      result = cmap->first;
+      gindex = 1;
+    }
+    else
+    {
+      char_code -= cmap->first;
+      if ( char_code < cmap->count )
+      {
+        result = cmap->first + char_code;
+        gindex = char_code + 1;
+      }
+    }
+
+    *pchar_code = result;
+    return gindex;
+  }
+
+
+  static FT_CMap_ClassRec  fnt_cmap_class_rec =
+  {
+    sizeof ( FNT_CMapRec ),
+
+    (FT_CMap_InitFunc)     fnt_cmap_init,
+    (FT_CMap_DoneFunc)     NULL,
+    (FT_CMap_CharIndexFunc)fnt_cmap_char_index,
+    (FT_CMap_CharNextFunc) fnt_cmap_char_next
+  };
+
+  static FT_CMap_Class  fnt_cmap_class = &fnt_cmap_class_rec;
+
+
+
+  static void
+  FNT_Face_Done( FNT_Face  face )
+  {
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+    fnt_face_done_fonts( face );
+
+    FT_FREE( face->root.available_sizes );
+    face->root.num_fixed_sizes = 0;
+  }
+
+
+  static FT_Error
+  FNT_Face_Init( FT_Stream      stream,
+                 FNT_Face       face,
+                 FT_Int         face_index,
+                 FT_Int         num_params,
+                 FT_Parameter*  params )
+  {
+    FT_Error   error;
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
+    FT_UNUSED( num_params );
+    FT_UNUSED( params );
+    FT_UNUSED( face_index );
+
+
+    /* try to load several fonts from a DLL */
+    error = fnt_face_get_dll_fonts( face );
+    if ( error )
+    {
+      /* this didn't work, now try to load a single FNT font */
+      FNT_Font  font;
+
+
+      if ( FT_NEW( face->fonts ) )
+        goto Exit;
+
+      face->num_fonts = 1;
+      font            = face->fonts;
+
+      font->offset   = 0;
+      font->fnt_size = stream->size;
+
+      error = fnt_font_load( font, stream );
+      if ( error )
+        goto Fail;
+    }
+
+    /* all right, one or more fonts were loaded; we now need to */
+    /* fill the root FT_Face fields with relevant information   */
+    {
+      FT_Face   root  = FT_FACE( face );
+      FNT_Font  fonts = face->fonts;
+      FNT_Font  limit = fonts + face->num_fonts;
+      FNT_Font  cur;
+
+
+      root->num_faces  = 1;
+      root->face_flags = FT_FACE_FLAG_FIXED_SIZES |
+                         FT_FACE_FLAG_HORIZONTAL;
+
+      if ( fonts->header.avg_width == fonts->header.max_width )
+        root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+
+      if ( fonts->header.italic )
+        root->style_flags |= FT_STYLE_FLAG_ITALIC;
+
+      if ( fonts->header.weight >= 800 )
+        root->style_flags |= FT_STYLE_FLAG_BOLD;
+
+      /* Setup the `fixed_sizes' array */
+      if ( FT_NEW_ARRAY( root->available_sizes, face->num_fonts ) )
+        goto Fail;
+
+      root->num_fixed_sizes = face->num_fonts;
+
+      {
+        FT_Bitmap_Size*  size = root->available_sizes;
+
+
+        for ( cur = fonts; cur < limit; cur++, size++ )
+        {
+          size->width  = cur->header.pixel_width;
+          size->height = cur->header.pixel_height;
+        }
+      }
+
+      {
+        FT_CharMapRec  charmap;
+
+        charmap.encoding    = FT_ENCODING_UNICODE;
+        charmap.platform_id = 3;
+        charmap.encoding_id = 1;
+        charmap.face        = root;
+
+        error = FT_CMap_New( fnt_cmap_class,
+                             NULL,
+                             &charmap,
+                             NULL );
+        if ( error )
+          goto Fail;
+
+        /* Select default charmap */
+        if ( root->num_charmaps )
+          root->charmap = root->charmaps[0];
+      }
+
+      /* setup remaining flags */
+      root->num_glyphs = fonts->header.last_char -
+                         fonts->header.first_char + 1;
+
+      root->family_name = (FT_String*)fonts->fnt_frame +
+                          fonts->header.face_name_offset;
+      root->style_name  = (char *)"Regular";
+
+      if ( root->style_flags & FT_STYLE_FLAG_BOLD )
+      {
+        if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+          root->style_name = (char *)"Bold Italic";
+        else
+          root->style_name = (char *)"Bold";
+      }
+      else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+        root->style_name = (char *)"Italic";
+    }
+
+  Fail:
+    if ( error )
+      FNT_Face_Done( face );
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  FNT_Size_Set_Pixels( FNT_Size  size )
+  {
+    /* look up a font corresponding to the current pixel size */
+    FNT_Face  face  = (FNT_Face)FT_SIZE_FACE( size );
+    FNT_Font  cur   = face->fonts;
+    FNT_Font  limit = cur + face->num_fonts;
+
+
+    size->font = 0;
+    for ( ; cur < limit; cur++ )
+    {
+      /* we only compare the character height, as fonts used some strange */
+      /* values                                                           */
+      if ( cur->header.pixel_height == size->root.metrics.y_ppem )
+      {
+        size->font = cur;
+
+        size->root.metrics.ascender  = cur->header.ascent * 64;
+        size->root.metrics.descender = ( cur->header.pixel_height -
+                                           cur->header.ascent ) * 64;
+        size->root.metrics.height    = cur->header.pixel_height * 64;
+        break;
+      }
+    }
+
+    return ( size->font ? FNT_Err_Ok : FNT_Err_Invalid_Pixel_Size );
+  }
+
+
+  static FT_Error
+  FNT_Load_Glyph( FT_GlyphSlot  slot,
+                  FNT_Size      size,
+                  FT_UInt       glyph_index,
+                  FT_Int32      load_flags )
+  {
+    FNT_Font    font  = size->font;
+    FT_Error    error = 0;
+    FT_Byte*    p;
+    FT_Int      len;
+    FT_Bitmap*  bitmap = &slot->bitmap;
+    FT_ULong    offset;
+    FT_Bool     new_format;
+
+    FT_UNUSED( slot );
+    FT_UNUSED( load_flags );
+
+
+    if ( !font )
+    {
+      error = FNT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    if ( glyph_index > 0 )
+      glyph_index--;
+    else
+      glyph_index = font->header.default_char - font->header.first_char;
+
+    new_format = FT_BOOL( font->header.version == 0x300 );
+    len        = new_format ? 6 : 4;
+
+    /* jump to glyph entry */
+    p = font->fnt_frame + 118 + len * glyph_index;
+
+    bitmap->width = FT_NEXT_SHORT_LE( p );
+
+    if ( new_format )
+      offset = FT_NEXT_ULONG_LE( p );
+    else
+      offset = FT_NEXT_USHORT_LE( p );
+
+    /* jump to glyph data */
+    p = font->fnt_frame + /* font->header.bits_offset */ + offset;
+
+    /* allocate and build bitmap */
+    {
+      FT_Memory  memory = FT_FACE_MEMORY( slot->face );
+      FT_Int     pitch  = ( bitmap->width + 7 ) >> 3;
+      FT_Byte*   column;
+      FT_Byte*   write;
+
+
+      bitmap->pitch      = pitch;
+      bitmap->rows       = font->header.pixel_height;
+      bitmap->pixel_mode = FT_PIXEL_MODE_MONO;
+
+      if ( FT_ALLOC( bitmap->buffer, pitch * bitmap->rows ) )
+        goto Exit;
+
+      column = (FT_Byte*)bitmap->buffer;
+
+      for ( ; pitch > 0; pitch--, column++ )
+      {
+        FT_Byte*  limit = p + bitmap->rows;
+
+
+        for ( write = column; p < limit; p++, write += bitmap->pitch )
+          write[0] = p[0];
+      }
+    }
+
+    slot->flags       = FT_GLYPH_OWN_BITMAP;
+    slot->bitmap_left = 0;
+    slot->bitmap_top  = font->header.ascent;
+    slot->format      = FT_GLYPH_FORMAT_BITMAP;
+
+    /* now set up metrics */
+    slot->metrics.horiAdvance  = bitmap->width << 6;
+    slot->metrics.horiBearingX = 0;
+    slot->metrics.horiBearingY = slot->bitmap_top << 6;
+
+    slot->linearHoriAdvance    = (FT_Fixed)bitmap->width << 16;
+    slot->format               = FT_GLYPH_FORMAT_BITMAP;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Driver_ClassRec  winfnt_driver_class =
+  {
+    {
+      ft_module_font_driver,
+      sizeof ( FT_DriverRec ),
+
+      "winfonts",
+      0x10000L,
+      0x20000L,
+
+      0,
+
+      (FT_Module_Constructor)0,
+      (FT_Module_Destructor) 0,
+      (FT_Module_Requester)  0
+    },
+
+    sizeof( FNT_FaceRec ),
+    sizeof( FNT_SizeRec ),
+    sizeof( FT_GlyphSlotRec ),
+
+    (FT_Face_InitFunc)        FNT_Face_Init,
+    (FT_Face_DoneFunc)        FNT_Face_Done,
+    (FT_Size_InitFunc)        0,
+    (FT_Size_DoneFunc)        0,
+    (FT_Slot_InitFunc)        0,
+    (FT_Slot_DoneFunc)        0,
+
+    (FT_Size_ResetPointsFunc) FNT_Size_Set_Pixels,
+    (FT_Size_ResetPixelsFunc) FNT_Size_Set_Pixels,
+    (FT_Slot_LoadFunc)        FNT_Load_Glyph,
+
+    (FT_Face_GetKerningFunc)  0,
+    (FT_Face_AttachFunc)      0,
+    (FT_Face_GetAdvancesFunc) 0
+  };
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/winfnt.h
@@ -1,0 +1,39 @@
+/***************************************************************************/
+/*                                                                         */
+/*  winfnt.h                                                               */
+/*                                                                         */
+/*    FreeType font driver for Windows FNT/FON files                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002 by                                           */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#ifndef __WINFNT_H__
+#define __WINFNT_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Driver_ClassRec )  winfnt_driver_class;
+
+
+FT_END_HEADER
+
+
+#endif /* __WINFNT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/libfreetype/zconf.h
@@ -1,0 +1,275 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zconf.h,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_	z_deflateInit_
+#  define deflate	z_deflate
+#  define deflateEnd	z_deflateEnd
+#  define inflateInit_ 	z_inflateInit_
+#  define inflate	z_inflate
+#  define inflateEnd	z_inflateEnd
+#  define deflateInit2_	z_deflateInit2_
+#  define deflateSetDictionary z_deflateSetDictionary
+#  define deflateCopy	z_deflateCopy
+#  define deflateReset	z_deflateReset
+#  define deflateParams	z_deflateParams
+#  define inflateInit2_	z_inflateInit2_
+#  define inflateSetDictionary z_inflateSetDictionary
+#  define inflateSync	z_inflateSync
+#  define inflateSyncPoint z_inflateSyncPoint
+#  define inflateReset	z_inflateReset
+#  define compress	z_compress
+#  define compress2	z_compress2
+#  define uncompress	z_uncompress
+#  define adler32	z_adler32
+#  define crc32		z_crc32
+#  define get_crc_table z_get_crc_table
+
+#  define Byte		z_Byte
+#  define uInt		z_uInt
+#  define uLong		z_uLong
+#  define Bytef	        z_Bytef
+#  define charf		z_charf
+#  define intf		z_intf
+#  define uIntf		z_uIntf
+#  define uLongf	z_uLongf
+#  define voidpf	z_voidpf
+#  define voidp		z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#  define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
+#  define STDC
+#endif
+#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
+#  ifndef STDC
+#    define STDC
+#  endif
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Old Borland C incorrectly complains about missing returns: */
+#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
+#  define NEED_DUMMY_RETURN
+#endif
+
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+   /* MSC small or medium model */
+#  define SMALL_MEDIUM
+#  ifdef _MSC_VER
+#    define FAR _far
+#  else
+#    define FAR far
+#  endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#  ifndef __32BIT__
+#    define SMALL_MEDIUM
+#    define FAR _far
+#  endif
+#endif
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if defined(ZLIB_DLL)
+#  if defined(_WINDOWS) || defined(WINDOWS)
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+#    define ZEXPORT  WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA  WINAPIV
+#    else
+#      define ZEXPORTVA  FAR _cdecl _export
+#    endif
+#  endif
+#  if defined (__BORLANDC__)
+#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
+#      include <windows.h>
+#      define ZEXPORT __declspec(dllexport) WINAPI
+#      define ZEXPORTRVA __declspec(dllexport) WINAPIV
+#    else
+#      if defined (_Windows) && defined (__DLL__)
+#        define ZEXPORT _export
+#        define ZEXPORTVA _export
+#      endif
+#    endif
+#  endif
+#endif
+
+
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+#ifndef ZEXTERN
+#  define ZEXTERN static
+#endif
+#ifndef ZEXTERNDEF
+#  define ZEXTERNDEF  static
+#endif
+
+#ifndef FAR
+#   define FAR
+#endif
+
+#if !defined(MACOS) && !defined(TARGET_OS_MAC)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  define z_off_t  off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define  z_off_t long
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(inflate_blocks,"INBL")
+#   pragma map(inflate_blocks_new,"INBLNE")
+#   pragma map(inflate_blocks_free,"INBLFR")
+#   pragma map(inflate_blocks_reset,"INBLRE")
+#   pragma map(inflate_codes_free,"INCOFR")
+#   pragma map(inflate_codes,"INCO")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_flush,"INFLU")
+#   pragma map(inflate_mask,"INMA")
+#   pragma map(inflate_set_dictionary,"INSEDI2")
+#   pragma map(inflate_copyright,"INCOPY")
+#   pragma map(inflate_trees_bits,"INTRBI")
+#   pragma map(inflate_trees_dynamic,"INTRDY")
+#   pragma map(inflate_trees_fixed,"INTRFI")
+#   pragma map(inflate_trees_free,"INTRFR")
+#endif
+
+#endif /* _ZCONF_H */
--- /dev/null
+++ b/libfreetype/zlib.h
@@ -1,0 +1,830 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.1.4, March 11th, 2002
+
+  Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.1.4"
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+
+                        /* basic functions */
+
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  the compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).
+*/
+
+
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may some
+  introduce some output latency (reading input without producing any output)
+  except when forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
+  output as possible to the output buffer. The flushing behavior of inflate is
+  not specified for values of the flush parameter other than Z_SYNC_FLUSH
+  and Z_FINISH, but the current implementation actually flushes as much output
+  as possible anyway.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+     If a preset dictionary is needed at this point (see inflateSetDictionary
+  below), inflate sets strm-adler to the adler32 checksum of the
+  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise
+  it sets strm->adler to the adler32 checksum of all output produced
+  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
+  an error code as described below. At the end of the stream, inflate()
+  checks that its computed adler32 checksum is equal to that saved by the
+  compressor and returns Z_STREAM_END only if the checksum is correct.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect
+  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
+  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
+  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
+  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
+  case, the application may then call inflateSync to look for a good
+  compression block.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front.
+
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. If a compressed stream with a larger window size is given as
+   input, inflate() will return with the error code Z_DATA_ERROR instead of
+   trying to allocate a larger window.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
+   memLevel). msg is set to null if there is no error message.  inflateInit2
+   does not perform any decompression apart from reading the zlib header if
+   present: this will be done by inflate(). (So next_in and avail_in may be
+   modified, but next_out and avail_out are unchanged.)
+*/
+
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate
+   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the Adler32 value returned by this call of
+   inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+/*
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least 0.1% larger than
+   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h". (See the description
+   of deflateInit2 for more information about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).
+*/
+
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+/*
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is NULL, this function returns the required initial value
+   for the crc. Pre- and post-conditioning (one's complement) is performed
+   within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
--- /dev/null
+++ b/libfreetype/zutil.c
@@ -1,0 +1,181 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id: zutil.c,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#include "zutil.h"
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
--- /dev/null
+++ b/libfreetype/zutil.h
@@ -1,0 +1,216 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2002 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id: zutil.h,v 1.2 2002/11/06 22:32:54 davidT Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#include "zlib.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#ifdef MSDOS
+#  define OS_CODE  0x00
+#  if defined(__TURBOC__) || defined(__BORLANDC__)
+#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+       /* Allow compilation with ANSI keywords only enabled */
+       void _Cdecl farfree( void *block );
+       void *_Cdecl farmalloc( unsigned long nbytes );
+#    else
+#     include <alloc.h>
+#    endif
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+#  define OS_CODE  0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  0x07
+#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#    include <unix.h> /* for fdopen */
+#  else
+#    ifndef fdopen
+#      define fdopen(fd,mode) NULL /* No fdopen() */
+#    endif
+#  endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0F
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+#  define fdopen(fd,type)  _fdopen(fd,type)
+#endif
+
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#ifdef HAVE_STRERROR
+   extern char *strerror OF((int));
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy ft_memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
+   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+#  include <stdio.h>
+   extern int z_verbose;
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
+				       uInt len));
+local voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+local void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
--- /dev/null
+++ b/libinterp/NOTICE
@@ -1,0 +1,17 @@
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2009 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libinterp/README
@@ -1,0 +1,1 @@
+comp-68020.c has not been tested recently
--- /dev/null
+++ b/libinterp/alt.c
@@ -1,0 +1,294 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define OP(fn)	void fn(void)
+#define W(p)	*((WORD*)(p))
+
+#define CANGET(c)	((c)->size > 0)
+#define CANPUT(c)	((c)->buf != H && (c)->size < (c)->buf->len)
+
+extern	OP(isend);
+extern	OP(irecv);
+
+/*
+ * Count the number of ready channels in an array of channels
+ * Set each channel's alt pointer to the owning prog
+ */
+static int
+altmark(Channel *c, Prog *p)
+{
+	int nrdy;
+	Array *a;
+	Channel **ca, **ec;
+
+	nrdy = 0;
+	a = (Array*)c;
+	ca = (Channel**)a->data;
+	ec = ca + a->len;
+	while(ca < ec) {
+		c = *ca;
+		if(c != H) {
+			if(c->send->prog || CANGET(c))
+				nrdy++;
+			cqadd(&c->recv, p);
+		}
+		ca++;
+	}
+
+	return nrdy;
+}
+
+/*
+ * Remove alt references to an array of channels
+ */
+static void
+altunmark(Channel *c, WORD *ptr, Prog *p, int sr, Channel **sel, int dn)
+{
+	int n;
+	Array *a;
+	Channel **ca, **ec;
+
+	n = 0;
+	a = (Array*)c;
+	ca = (Channel**)a->data;
+	ec = ca + a->len;
+	while(ca < ec) {
+		c = *ca;
+		if(c != H && c->recv->prog)
+			cqdelp(&c->recv, p);
+		if(sr == 1 && *sel == c) {
+			W(p->R.d) = dn;
+			p->ptr = ptr + 1;
+			ptr[0] = n;
+			*sel = nil;
+		}
+		ca++;
+		n++;
+	}
+}
+
+/*
+ * ALT Pass 1 - Count the number of ready channels and mark
+ * each channel as ALT by this prog
+ */
+static int
+altrdy(Alt *a, Prog *p)
+{
+	char *e;
+	Type *t;
+	int nrdy;
+	Channel *c;
+	Altc *ac, *eac;
+
+	e = nil;
+	nrdy = 0;
+
+	ac = a->ac + a->nsend;
+	eac = ac + a->nrecv;
+	while(ac < eac) {
+		c = ac->c;
+		ac++;
+		if(c == H) {
+			e = exNilref;
+			continue;
+		}
+		t = D2H(c)->t;
+		if(t == &Tarray)
+			nrdy += altmark(c, p);
+		else {
+			if(c->send->prog || CANGET(c))
+				nrdy++;
+			cqadd(&c->recv, p);
+		}
+	}
+
+	ac = a->ac;
+	eac = ac + a->nsend;
+	while(ac < eac) {
+		c = ac->c;
+		ac++;
+		if(c == H) {
+			e = exNilref;
+			continue;
+		}
+		if(c->recv->prog || CANPUT(c)) {
+			if(c->recv->prog == p) {
+				e = exAlt;
+				continue;
+			}
+			nrdy++;
+		}
+		cqadd(&c->send, p);
+	}
+
+	if(e != nil) {
+		altdone(a, p, nil, -1);
+		error(e);
+	}
+
+	return nrdy;
+}
+
+/*
+ * ALT Pass 3 - Pull out of an ALT cancelling the channel pointers in each item
+ */
+void
+altdone(Alt *a, Prog *p, Channel *sel, int sr)
+{
+	int n;
+	Type *t;
+	Channel *c;
+	Altc *ac, *eac;
+
+	n = 0;
+	ac = a->ac;
+	eac = a->ac + a->nsend;
+	while(ac < eac) {
+		c = ac->c;
+		if(c != H) {
+			if(c->send->prog)
+				cqdelp(&c->send, p);
+			if(sr == 0 && c == sel) {
+				p->ptr = ac->ptr;
+				W(p->R.d) = n;
+				sel = nil;
+			}
+		}
+		ac++;
+		n++;
+	}
+
+	eac = a->ac + a->nsend + a->nrecv;
+	while(ac < eac) {
+		c = ac->c;
+		if(c != H) {
+			t = D2H(c)->t;
+			if(t == &Tarray)
+				altunmark(c, ac->ptr, p, sr, &sel, n);
+			else {
+				if(c->recv->prog)
+					cqdelp(&c->recv, p);
+				if(sr == 1 && c == sel) {
+					p->ptr = ac->ptr;
+					W(p->R.d) = n;
+					sel = nil;
+				}
+			}
+		}
+		ac++;
+		n++;
+	}
+}
+
+/*
+ * ALT Pass 2 - Perform the communication on the chosen channel
+ */
+static void
+altcomm(Alt *a, int which)
+{
+	Type *t;
+	Array *r;
+	int n, an;
+	WORD *ptr;
+	Altc *ac, *eac;
+	Channel *c, **ca, **ec;
+
+	n = 0;
+	ac = a->ac;
+	eac = ac + a->nsend;
+	while(ac < eac) {
+		c = ac->c;
+		if((c->recv->prog != nil || CANPUT(c)) && which-- == 0) {
+			W(R.d) = n;
+			R.s = ac->ptr;
+			R.d = &c;
+			isend();
+			return;
+		}
+		ac++;
+		n++;
+	}
+
+	eac = eac + a->nrecv;
+	while(ac < eac) {
+		c = ac->c;
+		t = D2H(c)->t;
+		if(t == &Tarray) {
+			an = 0;
+			r = (Array*)c;
+			ca = (Channel**)r->data;
+			ec = ca + r->len;
+			while(ca < ec) {
+				c = *ca;
+				if(c != H && (c->send->prog != nil || CANGET(c)) && which-- == 0) {
+					W(R.d) = n;
+					R.s = &c;
+					ptr = ac->ptr;
+					R.d = ptr + 1;
+					ptr[0] = an;
+					irecv();
+					return;
+				}
+				ca++;
+				an++;
+			}
+		}
+		else
+		if((c->send->prog != nil || CANGET(c)) && which-- == 0) {
+			W(R.d) = n;
+			R.s = &c;
+			R.d = ac->ptr;
+			irecv();
+			return;	
+		}
+		ac++;
+		n++;
+	}
+	return;
+}
+
+void
+altgone(Prog *p)
+{
+	Alt *a;
+
+	if (p->state == Palt) {
+		a = p->R.s;
+		altdone(a, p, nil, -1);
+		p->kill = "alt channel hungup";
+		addrun(p);
+	}
+}
+
+void
+xecalt(int block)
+{
+	Alt *a;
+	Prog *p;
+	int nrdy;
+	static ulong xrand = 0x20342;
+
+	p = currun();
+
+	a = R.s;
+	nrdy = altrdy(a, p);
+	if(nrdy == 0) {
+		if(block) {
+			delrun(Palt);
+			p->R.s = R.s;
+			p->R.d = R.d;
+			R.IC = 1;
+			R.t = 1;
+			return;
+		}
+		W(R.d) = a->nsend + a->nrecv;
+		altdone(a, p, nil, -1);
+		return;
+	}
+
+	xrand = xrand*1103515245 + 12345;
+	altcomm(a, (xrand>>8)%nrdy);
+	altdone(a, p, nil, -1);
+}
--- /dev/null
+++ b/libinterp/comp-386.c
@@ -1,0 +1,1991 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define DOT			((ulong)code)
+
+#define	RESCHED 1	/* check for interpreter reschedule */
+
+enum
+{
+	RAX	= 0,
+	RAH	= 4,
+	RCX	= 1,
+	RDX	= 2,
+	RBX	= 3,
+	RSP	= 4,
+	RBP	= 5,
+	RSI	= 6,
+	RDI	= 7,
+
+	RFP	= RSI,
+	RMP	= RDI,
+	RTA	= RDX,
+	RTMP	= RBX,
+
+	Omovzxb	= 0xb6,
+	Omovzxw	= 0xb7,
+	Osal	= 0xd1,
+	Oaddf	= 0xdc,
+	Ocall	= 0xe8,
+	Ocallrm	= 0xff,
+	Ocdq	= 0x99,
+	Ocld	= 0xfc,
+	Ocmpb	= 0x38,
+	Ocmpw	= 0x39,
+	Ocmpi	= 0x83,
+	Odecrm	= 0xff,
+	Oincr	= 0x40,
+	Oincrm	= 0xff,
+	Ojccl	= 0x83,
+	Ojcsl	= 0x82,
+	Ojeqb	= 0x74,
+	Ojeql	= 0x84,
+	Ojgel	= 0x8d,
+	Ojgtl	= 0x8f,
+	Ojhil	= 0x87,
+	Ojlel	= 0x8e,
+	Ojlsl	= 0x86,
+	Ojltl	= 0x8c,
+	Ojol	= 0x80,
+	Ojnol	= 0x81,
+	Ojbl	= 0x82,
+	Ojael	= 0x83,
+	Ojal	= 0x87,
+	Ojnel	= 0x85,
+	Ojbel	= 0x86,
+	Ojneb	= 0x75,
+	Ojgtb	= 0x7f,
+	Ojgeb	= 0x7d,
+	Ojleb	= 0x7e,
+	Ojltb	= 0x7c,
+	Ojmp	= 0xe9,
+	Ojmpb	= 0xeb,
+	Ojmprm	= 0xff,
+	Oldb	= 0x8a,
+	Olds	= 0x89,
+	Oldw	= 0x8b,
+	Olea	= 0x8d,
+	Otestib	= 0xf6,
+	Oshld	= 0xa5,
+	Oshrd	= 0xad,
+	Osar	= 0xd3,
+	Osarimm = 0xc1,
+	Omov	= 0xc7,
+	Omovf	= 0xdd,
+	Omovimm	= 0xb8,
+	Omovsb	= 0xa4,
+	Orep	= 0xf3,
+	Oret	= 0xc3,
+	Oshl	= 0xd3,
+	Oshr	= 0xd1,
+	Ostb	= 0x88,
+	Ostw	= 0x89,
+	Osubf	= 0xdc,
+	Oxchg	= 0x87,
+	OxchgAX	= 0x90,
+	Oxor	= 0x31,
+	Opopl	= 0x58,
+	Opushl	= 0x50,
+	Opushrm	= 0xff,
+	Oneg	= 0xf7,
+
+	SRCOP	= (1<<0),
+	DSTOP	= (1<<1),
+	WRTPC	= (1<<2),
+	TCHECK	= (1<<3),
+	NEWPC	= (1<<4),
+	DBRAN	= (1<<5),
+	THREOP	= (1<<6),
+
+	ANDAND	= 1,
+	OROR	= 2,
+	EQAND	= 3,
+
+	MacFRP	= 0,
+	MacRET	= 1,
+	MacCASE	= 2,
+	MacCOLR	= 3,
+	MacMCAL	= 4,
+	MacFRAM	= 5,
+	MacMFRA	= 6,
+	MacRELQ = 7,
+	NMACRO
+};
+
+static	uchar*	code;
+static	uchar*	base;
+static	ulong*	patch;
+static	int	pass;
+static	Module*	mod;
+static	uchar*	tinit;
+static	ulong*	litpool;
+static	int	nlit;
+static	void	macfrp(void);
+static	void	macret(void);
+static	void	maccase(void);
+static	void	maccolr(void);
+static	void	macmcal(void);
+static	void	macfram(void);
+static	void	macmfra(void);
+static	void	macrelq(void);
+static	ulong	macro[NMACRO];
+	void	(*comvec)(void);
+extern	void	das(uchar*, int);
+
+#define T(r)	*((void**)(R.r))
+
+struct
+{
+	int	idx;
+	void	(*gen)(void);
+} mactab[] =
+{
+	MacFRP,		macfrp,		/* decrement and free pointer */
+	MacRET,		macret,		/* return instruction */
+	MacCASE,	maccase,	/* case instruction */
+	MacCOLR,	maccolr,	/* increment and color pointer */
+	MacMCAL,	macmcal,	/* mcall bottom half */
+	MacFRAM,	macfram,	/* frame instruction */
+	MacMFRA,	macmfra,	/* punt mframe because t->initialize==0 */
+	MacRELQ,		macrelq,	/* reschedule */
+};
+
+static void
+bounds(void)
+{
+	error(exBounds);
+}
+
+static void
+rdestroy(void)
+{
+	destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+	Prog *p;
+	Frame *f;
+
+	if((void*)R.dt == H)
+		error(exModule);
+
+	f = (Frame*)R.FP;
+	if(f == H)
+		error(exModule);
+
+	f->mr = nil;
+	((void(*)(Frame*))R.dt)(f);
+	R.SP = (uchar*)f;
+	R.FP = f->fp;
+	if(f->t == nil)
+		unextend(f);
+	else
+		freeptrs(f, f->t);
+	p = currun();
+	if(p->kill != nil)
+		error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+
+	t = (Type*)R.s;
+	if(t == H)
+		error(exModule);
+
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP = nsp;
+	f->t = t;
+	f->mr = nil;
+	initmem(t, f);
+	T(d) = f;
+}
+
+static int
+bc(int o)
+{
+	if(o < 127 && o > -128)
+		return 1;
+	return 0;
+}
+
+static void
+urk(void)
+{
+	error(exCompile);
+}
+
+static void
+genb(uchar o)
+{
+	*code++ = o;
+}
+
+static void
+gen2(uchar o1, uchar o2)
+{
+	code[0] = o1;
+	code[1] = o2;
+	code += 2;
+}
+
+static void
+genw(ulong o)
+{
+	*(ulong*)code = o;
+	code += 4;
+}
+
+static void
+modrm(int inst, ulong disp, int rm, int r)
+{
+	*code++ = inst;
+	if(disp == 0) {
+		*code++ = (0<<6)|(r<<3)|rm;
+		return;
+	}
+	if(bc(disp)) {
+		code[0] = (1<<6)|(r<<3)|rm;
+		code[1] = disp;
+		code += 2;
+		return;
+	}
+	*code++ = (2<<6)|(r<<3)|rm;
+	*(ulong*)code = disp;
+	code += 4;
+}
+
+static void
+con(ulong o, int r)
+{
+	if(o == 0) {
+		gen2(Oxor, (3<<6)|(r<<3)|r);
+		return;
+	}
+	genb(Omovimm+r);
+	genw(o);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+	int ir, rta;
+
+	switch(UXSRC(i->add)) {
+	default:
+		print("%D\n", i);
+		urk();
+	case SRC(AFP):
+		modrm(mi, i->s.ind, RFP, r);
+		return;
+	case SRC(AMP):
+		modrm(mi, i->s.ind, RMP, r);
+		return;
+	case SRC(AIMM):
+		con(i->s.imm, r);
+		return;
+	case SRC(AIND|AFP):
+		ir = RFP;
+		break;
+	case SRC(AIND|AMP):
+		ir = RMP;
+		break;
+	}
+	rta = RTA;
+	if(mi == Olea)
+		rta = r;
+	modrm(Oldw, i->s.i.f, ir, rta);
+	modrm(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+	int ir, rta;
+
+	switch(UXDST(i->add)) {
+	default:
+		print("%D\n", i);
+		urk();
+	case DST(AIMM):
+		con(i->d.imm, r);
+		return;
+	case DST(AFP):
+		modrm(mi, i->d.ind, RFP, r);
+		return;
+	case DST(AMP):
+		modrm(mi, i->d.ind, RMP, r);
+		return;
+	case DST(AIND|AFP):
+		ir = RFP;
+		break;
+	case DST(AIND|AMP):
+		ir = RMP;
+		break;
+	}
+	rta = RTA;
+	if(mi == Olea)
+		rta = r;
+	modrm(Oldw, i->d.i.f, ir, rta);
+	modrm(mi, i->d.i.s, rta, r);
+}
+
+static void
+bra(ulong dst, int op)
+{
+	dst -= (DOT+5);
+	genb(op);
+	genw(dst);
+}
+
+static void
+rbra(ulong dst, int op)
+{
+	dst += (ulong)base;
+	dst -= DOT+5;
+	genb(op);
+	genw(dst);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+	nlit++;
+
+	genb(Omovimm+RAX);
+	genw((ulong)litpool);
+	modrm(Ostw, roff, RTMP, RAX);
+
+	if(pass == 0)
+		return;
+
+	*litpool = imm;
+	litpool++;	
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+	ulong pc;
+
+	con((ulong)&R, RTMP);
+
+	if(m & SRCOP) {
+		if(UXSRC(i->add) == SRC(AIMM))
+			literal(i->s.imm, O(REG, s));
+		else {
+			opwld(i, Olea, RAX);
+			modrm(Ostw, O(REG, s), RTMP, RAX);
+		}
+	}
+
+	if(m & DSTOP) {
+		opwst(i, Olea, 0);
+		modrm(Ostw, O(REG, d), RTMP, RAX);
+	}
+	if(m & WRTPC) {
+		modrm(Omov, O(REG, PC), RTMP, 0);
+		pc = patch[i-mod->prog+1];
+		genw((ulong)base + pc);
+	}
+	if(m & DBRAN) {
+		pc = patch[(Inst*)i->d.imm-mod->prog];
+		literal((ulong)base+pc, O(REG, d));
+	}
+
+	switch(i->add&ARM) {
+	case AXNON:
+		if(m & THREOP) {
+			modrm(Oldw, O(REG, d), RTMP, RAX);
+			modrm(Ostw, O(REG, m), RTMP, RAX);
+		}
+		break;
+	case AXIMM:
+		literal((short)i->reg, O(REG, m));
+		break;
+	case AXINF:
+		modrm(Olea, i->reg, RFP, RAX);
+		modrm(Ostw, O(REG, m), RTMP, RAX);
+		break;
+	case AXINM:
+		modrm(Olea, i->reg, RMP, RAX);
+		modrm(Ostw, O(REG, m), RTMP, RAX);
+		break;
+	}
+	modrm(Ostw, O(REG, FP), RTMP, RFP);
+
+	bra((ulong)fn, Ocall);
+
+	con((ulong)&R, RTMP);
+	if(m & TCHECK) {
+		modrm(Ocmpi, O(REG, t), RTMP, 7);// CMPL $0, R.t
+		genb(0x00);
+		gen2(Ojeqb, 0x06);		// JEQ	.+6
+		genb(Opopl+RDI);
+		genb(Opopl+RSI);
+		genb(Opopl+RDX);
+		genb(Opopl+RCX);
+		genb(Opopl+RBX);
+		genb(Oret);
+	}
+
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+
+	if(m & NEWPC) {
+		modrm(Oldw, O(REG, PC), RTMP, RAX);
+		gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+	}
+}
+
+static void
+mid(Inst *i, uchar mi, int r)
+{
+	int ir;
+
+	switch(i->add&ARM) {
+	default:
+		opwst(i, mi, r);
+		return;
+	case AXIMM:
+		con((short)i->reg, r);
+		return;
+	case AXINF:
+		ir = RFP;
+		break;
+	case AXINM:
+		ir = RMP;
+		break;
+	}
+	modrm(mi, i->reg, ir, r);
+}
+
+static void
+arith(Inst *i, int op2, int rm)
+{
+	if(UXSRC(i->add) != SRC(AIMM)) {
+		if(i->add&ARM) {
+			mid(i, Oldw, RAX);
+			opwld(i, op2|2, 0);
+			opwst(i, Ostw, 0);
+			return;
+		}
+		opwld(i, Oldw, RAX);
+		opwst(i, op2, 0);
+		return;
+	}
+	if(i->add&ARM) {
+		mid(i, Oldw, RAX);
+		if(bc(i->s.imm)) {
+			gen2(0x83, (3<<6)|(rm<<3)|RAX);
+			genb(i->s.imm);
+		}
+		else {
+			gen2(0x81, (3<<6)|(rm<<3)|RAX);
+			genw(i->s.imm);
+		}
+		opwst(i, Ostw, RAX);
+		return;
+	}
+	if(bc(i->s.imm)) {
+		opwst(i, 0x83, rm);
+		genb(i->s.imm);
+		return;
+	}
+	opwst(i, 0x81, rm);
+	genw(i->s.imm);
+}
+
+static void
+arithb(Inst *i, int op2)
+{
+	if(UXSRC(i->add) == SRC(AIMM))
+		urk();
+
+	if(i->add&ARM) {
+		mid(i, Oldb, RAX);
+		opwld(i, op2|2, 0);
+		opwst(i, Ostb, 0);
+		return;
+	}
+	opwld(i, Oldb, RAX);
+	opwst(i, op2, RAX);
+}
+
+static void
+shift(Inst *i, int ld, int st, int op, int r)
+{
+	mid(i, ld, RAX);
+	opwld(i, Oldw, RCX);
+	gen2(op, (3<<6)|(r<<3)|RAX);
+	opwst(i, st, RAX);
+}
+
+static void
+arithf(Inst *i, int op)
+{
+	opwld(i, Omovf, 0);
+	mid(i, 0xdc, op);
+	opwst(i, Omovf, 3);
+}
+
+static void
+cmpl(int r, ulong v)
+{
+	if(bc(v)) {
+		gen2(0x83, (3<<6)|(7<<3)|r);
+		genb(v);
+		return;
+	}
+	gen2(0x81, (3<<6)|(7<<3)|r);
+	genw(v);
+}
+
+static int
+swapbraop(int b)
+{
+	switch(b) {
+	case Ojgel:
+		return Ojlel;
+	case Ojlel:
+		return Ojgel;
+	case Ojgtl:
+		return Ojltl;
+	case Ojltl:
+		return Ojgtl;
+	}
+	return b;
+}
+
+static void
+schedcheck(Inst *i)
+{
+	if(RESCHED && i->d.ins <= i){
+		con((ulong)&R, RTMP);
+		/* sub $1, R.IC */
+		modrm(0x83, O(REG, IC), RTMP, 5);
+		genb(1);
+		gen2(Ojgtb, 5);
+		rbra(macro[MacRELQ], Ocall);
+	}
+}
+
+static void
+cbra(Inst *i, int jmp)
+{
+	if(RESCHED)
+		schedcheck(i);
+	mid(i, Oldw, RAX);
+	if(UXSRC(i->add) == SRC(AIMM)) {
+		cmpl(RAX, i->s.imm);
+		jmp = swapbraop(jmp);
+	}
+	else
+		opwld(i, Ocmpw, RAX);
+	genb(0x0f);
+	rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+	ulong dst;
+	uchar *label;
+
+	if(RESCHED)
+		schedcheck(i);
+	opwld(i, Olea, RTMP);
+	mid(i, Olea, RTA);
+	modrm(Oldw, 4, RTA, RAX);
+	modrm(Ocmpw, 4, RTMP, RAX);
+	label = 0;
+	dst = patch[i->d.ins-mod->prog];
+	switch(mode) {
+	case ANDAND:
+		gen2(Ojneb, 0);
+		label = code-1;
+		break;
+	case OROR:
+		genb(0x0f);
+		rbra(dst, jmsw);
+		break;
+	case EQAND:
+		genb(0x0f);
+		rbra(dst, jmsw);
+		gen2(Ojneb, 0);
+		label = code-1;
+		break;
+	}
+	modrm(Oldw, 0, RTA, RAX);
+	modrm(Ocmpw, 0, RTMP, RAX);
+	genb(0x0f);
+	rbra(dst, jlsw);
+	if(label != nil)
+		*label = code-label-1;
+}
+
+static void
+cbrab(Inst *i, int jmp)
+{
+	if(RESCHED)
+		schedcheck(i);
+	mid(i, Oldb, RAX);
+	if(UXSRC(i->add) == SRC(AIMM))
+		urk();
+
+	opwld(i, Ocmpb, RAX);
+	genb(0x0f);
+	rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+cbraf(Inst *i, int jmp)
+{
+	if(RESCHED)
+		schedcheck(i);
+	opwld(i, Omovf, 0);
+	mid(i, 0xdc, 3);	// FCOMP
+	genb(0x9b);		// FWAIT
+	gen2(0xdf, 0xe0);	// FSTSW AX
+	genb(0x9e);		// SAHF
+
+	genb(0x0f);
+	rbra(patch[i->d.ins-mod->prog], jmp);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+	int l;
+	WORD *t, *e;
+
+	if(w != 0) {
+		opwld(i, Oldw, RAX);		// v
+		genb(Opushl+RSI);
+		opwst(i, Olea, RSI);		// table
+		rbra(macro[MacCASE], Ojmp);
+	}
+
+	t = (WORD*)(mod->origmp+i->d.ind+4);
+	l = t[-1];
+
+	/* have to take care not to relocate the same table twice - 
+	 * the limbo compiler can duplicate a case instruction
+	 * during its folding phase
+	 */
+
+	if(pass == 0) {
+		if(l >= 0)
+			t[-1] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-1] = -l-1;			/* Set real count */
+	e = t + t[-1]*3;
+	while(t < e) {
+		t[2] = (ulong)base + patch[t[2]];
+		t += 3;
+	}
+	t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+comcasel(Inst *i)
+{
+	int l;
+	WORD *t, *e;
+
+	t = (WORD*)(mod->origmp+i->d.ind+8);
+	l = t[-2];
+	if(pass == 0) {
+		if(l >= 0)
+			t[-2] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-2] = -l-1;			/* Set real count */
+	e = t + t[-2]*6;
+	while(t < e) {
+		t[4] = (ulong)base + patch[t[4]];
+		t += 6;
+	}
+	t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+	int o;
+	uchar *punt, *mlnil;
+
+	opwld(i, Oldw, RAX);
+	cmpl(RAX, (ulong)H);
+	gen2(Ojeqb, 0);
+	mlnil = code - 1;
+	if((i->add&ARM) == AXIMM) {
+		o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+		modrm(Oldw, o, RAX, RTA);
+	} else {
+		gen2(Oldw, (3<<6)|(RTMP<<3)|RAX);	// MOVL	AX, RTMP
+		mid(i, Oldw, RCX);			// index
+		gen2(Olea, (0<<6)|(0<<3)|4);		// lea	(AX)(RCX*8)
+		genb((3<<6)|(RCX<<3)|RAX);		// assumes sizeof(Modl) == 8 hence 3
+		o = OA(Modlink, links)+O(Modl, frame);
+		modrm(Oldw, o, RAX, RTA);		// frame
+		genb(OxchgAX+RTMP);			// get old AX back
+	}
+	modrm(0x83, O(Type, initialize), RTA, 7);
+	genb(0);
+	gen2(Ojneb, 0);
+	punt = code - 1;
+	genb(OxchgAX+RTA);
+	opwst(i, Olea, RTA);
+	*mlnil = code-mlnil-1;
+	rbra(macro[MacMFRA], Ocall);
+	rbra(patch[i-mod->prog+1], Ojmp);
+
+	*punt = code-punt-1;
+	rbra(macro[MacFRAM], Ocall);
+	opwst(i, Ostw, RCX);
+}
+
+static void
+commcall(Inst *i)
+{
+	uchar *mlnil;
+
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	opwld(i, Oldw, RCX);
+	modrm(Omov, O(Frame, lr), RCX, 0);	// MOVL $.+1, lr(CX)	f->lr = R.PC
+	genw((ulong)base+patch[i-mod->prog+1]);
+	modrm(Ostw, O(Frame, fp), RCX, RFP); 	// MOVL RFP, fp(CX)	f->fp = R.FP
+	modrm(Oldw, O(REG, M), RTMP, RTA);	// MOVL R.M, RTA
+	modrm(Ostw, O(Frame, mr), RCX, RTA);	// MOVL RTA, mr(CX) 	f->mr = R.M
+	opwst(i, Oldw, RTA);			// MOVL ml, RTA
+	cmpl(RTA, (ulong)H);
+	gen2(Ojeqb, 0);
+	mlnil = code - 1;
+	if((i->add&ARM) == AXIMM)
+		modrm(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RTA, RAX);
+	else {
+		genb(Opushl+RCX);
+		mid(i, Oldw, RCX);		// index
+		gen2(Olea, (0<<6)|(0<<3)|4);	// lea	(RTA)(RCX*8)
+		genb((3<<6)|(RCX<<3)|RTA);	// assumes sizeof(Modl) == 8 hence 3
+		modrm(Oldw, OA(Modlink, links)+O(Modl, u.pc), RAX, RAX);
+		genb(Opopl+RCX);
+	}
+	*mlnil = code-mlnil-1;
+	rbra(macro[MacMCAL], Ocall);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+	opwld(i, Olea, RTMP);
+	mid(i, Olea, RTA);
+	modrm(Oldw, 0, RTA, RAX);	// MOVL	0(RTA), AX
+	modrm(op, 0, RTMP, RAX);	// ADDL 0(RTMP), AX
+	modrm(Oldw, 4, RTA, RCX);	// MOVL 4(RTA), CX
+	modrm(opc, 4, RTMP, RCX);	// ADCL 4(RTMP), CX
+	if((i->add&ARM) != AXNON)
+		opwst(i, Olea, RTA);
+	modrm(Ostw, 0, RTA, RAX);
+	modrm(Ostw, 4, RTA, RCX);
+}
+
+static void
+shll(Inst *i)
+{
+	uchar *label, *label1;
+
+	opwld(i, Oldw, RCX);
+	mid(i, Olea, RTA);
+	gen2(Otestib, (3<<6)|(0<<3)|RCX);
+	genb(0x20);
+	gen2(Ojneb, 0);
+	label = code-1;
+	modrm(Oldw, 0, RTA, RAX);
+	modrm(Oldw, 4, RTA, RBX);
+	genb(0x0f);
+	gen2(Oshld, (3<<6)|(RAX<<3)|RBX);
+	gen2(Oshl, (3<<6)|(4<<3)|RAX);
+	gen2(Ojmpb, 0);
+	label1 = code-1;
+	*label = code-label-1;
+	modrm(Oldw, 0, RTA, RBX);
+	con(0, RAX);
+	gen2(Oshl, (3<<6)|(4<<3)|RBX);
+	*label1 = code-label1-1;
+	opwst(i, Olea, RTA);
+	modrm(Ostw, 0, RTA, RAX);
+	modrm(Ostw, 4, RTA, RBX);
+}
+
+static void
+shrl(Inst *i)
+{
+	uchar *label, *label1;
+
+	opwld(i, Oldw, RCX);
+	mid(i, Olea, RTA);
+	gen2(Otestib, (3<<6)|(0<<3)|RCX);
+	genb(0x20);
+	gen2(Ojneb, 0);
+	label = code-1;
+	modrm(Oldw, 0, RTA, RAX);
+	modrm(Oldw, 4, RTA, RBX);
+	genb(0x0f);
+	gen2(Oshrd, (3<<6)|(RBX<<3)|RAX);
+	gen2(Osar, (3<<6)|(7<<3)|RBX);
+	gen2(Ojmpb, 0);
+	label1 = code-1;
+	*label = code-label-1;
+	modrm(Oldw, 4, RTA, RBX);
+	gen2(Oldw, (3<<6)|(RAX<<3)|RBX);
+	gen2(Osarimm, (3<<6)|(7<<3)|RBX);
+	genb(0x1f);
+	gen2(Osar, (3<<6)|(7<<3)|RAX);
+	*label1 = code-label1-1;
+	opwst(i, Olea, RTA);
+	modrm(Ostw, 0, RTA, RAX);
+	modrm(Ostw, 4, RTA, RBX);
+}
+
+static
+void
+compdbg(void)
+{
+	print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+	int r;
+	WORD *t, *e;
+	char buf[64];
+
+	if(0) {
+		Inst xx;
+		xx.add = AXIMM|SRC(AIMM);
+		xx.s.imm = (ulong)code;
+		xx.reg = i-mod->prog;
+		punt(&xx, SRCOP, compdbg);
+	}
+
+	switch(i->op) {
+	default:
+		snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+		error(buf);
+		break;
+	case IMCALL:
+		if((i->add&ARM) == AXIMM)
+			commcall(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case ISEND:
+	case IRECV:
+	case IALT:
+		punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+		break;
+	case ISPAWN:
+		punt(i, SRCOP|DBRAN, optab[i->op]);
+		break;
+	case IBNEC:
+	case IBEQC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+		punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+		break;
+	case ICASEC:
+		comcase(i, 0);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case ICASEL:
+		comcasel(i);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case IADDC:
+	case IMULL:
+	case IDIVL:
+	case IMODL:
+	case IMNEWZ:
+	case ILSRW:
+	case ILSRL:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ILOAD:
+	case INEWA:
+	case INEWAZ:
+	case INEW:
+	case INEWZ:
+	case ISLICEA:
+	case ISLICELA:
+	case ICONSB:
+	case ICONSW:
+	case ICONSL:
+	case ICONSF:
+	case ICONSM:
+	case ICONSMP:
+	case ICONSP:
+	case IMOVMP:
+	case IHEADMP:
+	case IHEADL:
+	case IINSC:
+	case ICVTAC:
+	case ICVTCW:
+	case ICVTWC:
+	case ICVTLC:
+	case ICVTCL:
+	case ICVTFC:
+	case ICVTCF:
+	case ICVTRF:
+	case ICVTFR:
+	case ICVTWS:
+	case ICVTSW:
+	case IMSPAWN:
+	case ICVTCA:
+	case ISLICEC:
+	case INBALT:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case INEWCM:
+	case INEWCMP:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IMFRAME:
+		if((i->add&ARM) == AXIMM)
+			commframe(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case INEWCB:
+	case INEWCW:
+	case INEWCF:
+	case INEWCP:
+	case INEWCL:
+		punt(i, DSTOP|THREOP, optab[i->op]);
+		break;
+	case IEXIT:
+		punt(i, 0, optab[i->op]);
+		break;
+	case ICVTBW:
+		opwld(i, Oldb, RAX);
+		genb(0x0f);
+		gen2(0xb6, (3<<6)|(RAX<<3)|RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ICVTWB:
+		opwld(i, Oldw, RAX);
+		opwst(i, Ostb, RAX);
+		break;
+	case ICVTFW:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, Omovf, 0);
+		opwst(i, 0xdb, 3);
+		break;
+	case ICVTWF:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, 0xdb, 0);
+		opwst(i, Omovf, 3);
+		break;
+	case ICVTLF:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, 0xdf, 5);
+		opwst(i, Omovf, 3);
+		break;
+	case ICVTFL:
+		if(1){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, Omovf, 0);
+		opwst(i, 0xdf, 7);
+		break;
+	case IHEADM:
+		opwld(i, Oldw, RAX);
+		modrm(Olea, OA(List, data), RAX, RAX);
+		goto movm;
+	case IMOVM:
+		opwld(i, Olea, RAX);
+	movm:
+		opwst(i, Olea, RBX);
+		mid(i, Oldw, RCX);
+		genb(OxchgAX+RSI);
+		gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+		genb(Ocld);
+		gen2(Orep, Omovsb);
+		genb(OxchgAX+RSI);
+		gen2(Oxchg, (3<<6)|(RDI<<3)|RBX);
+		break;
+	case IRET:
+		rbra(macro[MacRET], Ojmp);
+		break;
+	case IFRAME:
+		if(UXSRC(i->add) != SRC(AIMM)) {
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		tinit[i->s.imm] = 1;
+		con((ulong)mod->type[i->s.imm], RTA);
+		rbra(macro[MacFRAM], Ocall);
+		opwst(i, Ostw, RCX);
+		break;
+	case ILEA:
+		if(UXSRC(i->add) == SRC(AIMM)) {
+			gen2(Ojmpb, 4);
+			genw(i->s.imm);
+			con((ulong)(code-4), RAX);
+		}
+		else
+			opwld(i, Olea, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case IHEADW:
+		opwld(i, Oldw, RAX);
+		modrm(Oldw, OA(List, data), RAX, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case IHEADF:
+		opwld(i, Oldw, RAX);
+		modrm(Omovf, OA(List, data), RAX, 0);
+		opwst(i, Omovf, 3);
+		break;
+	case IHEADB:
+		opwld(i, Oldw, RAX);
+		modrm(Oldb, OA(List, data), RAX, RAX);
+		opwst(i, Ostb, RAX);
+		break;
+	case ITAIL:
+		opwld(i, Oldw, RAX);
+		modrm(Oldw, O(List, tail), RAX, RBX);
+		goto movp;
+	case IMOVP:
+	case IHEADP:
+		opwld(i, Oldw, RBX);
+		if(i->op == IHEADP)
+			modrm(Oldw, OA(List, data), RBX, RBX);
+	movp:
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x05);
+		rbra(macro[MacCOLR], Ocall);
+		opwst(i, Oldw, RAX);
+		opwst(i, Ostw, RBX);
+		rbra(macro[MacFRP], Ocall);
+		break;
+	case ILENA:
+		opwld(i, Oldw, RBX);
+		con(0, RAX);
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x02);
+		modrm(Oldw, O(Array, len), RBX, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ILENC:
+		opwld(i, Oldw, RBX);
+		con(0, RAX);
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x09);
+		modrm(Oldw, O(String, len), RBX, RAX);
+		cmpl(RAX, 0);
+		gen2(Ojgeb, 0x02);
+		gen2(Oneg, (3<<6)|(3<<3)|RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ILENL:
+		con(0, RAX);
+		opwld(i, Oldw, RBX);
+		cmpl(RBX, (ulong)H);
+		gen2(Ojeqb, 0x05);
+		modrm(Oldw, O(List, tail), RBX, RBX);
+		genb(Oincr+RAX);
+		gen2(Ojmpb, 0xf6);
+		opwst(i, Ostw, RAX);
+		break;
+	case IBEQF:
+		cbraf(i, Ojeql);
+		break;
+	case IBNEF:
+		cbraf(i, Ojnel);
+		break;
+	case IBLEF:
+		cbraf(i, Ojlsl);
+		break;
+	case IBLTF:
+		cbraf(i, Ojcsl);
+		break;
+	case IBGEF:
+		cbraf(i, Ojccl);
+		break;
+	case IBGTF:
+		cbraf(i, Ojhil);
+		break;
+	case IBEQW:
+		cbra(i, Ojeql);
+		break;
+	case IBLEW:
+		cbra(i, Ojlel);
+		break;
+	case IBNEW:
+		cbra(i, Ojnel);
+		break;
+	case IBGTW:
+		cbra(i, Ojgtl);
+		break;
+	case IBLTW:
+		cbra(i, Ojltl);
+		break;
+	case IBGEW:
+		cbra(i, Ojgel);
+		break;
+	case IBEQB:
+		cbrab(i, Ojeql);
+		break;
+	case IBLEB:
+		cbrab(i, Ojlsl);
+		break;
+	case IBNEB:
+		cbrab(i, Ojnel);
+		break;
+	case IBGTB:
+		cbrab(i, Ojhil);
+		break;
+	case IBLTB:
+		cbrab(i, Ojbl);
+		break;
+	case IBGEB:
+		cbrab(i, Ojael);
+		break;
+	case ISUBW:
+		arith(i, 0x29, 5);
+		break;
+	case ISUBB:
+		arithb(i, 0x28);
+		break;
+	case ISUBF:
+		arithf(i, 5);
+		break;
+	case IADDW:
+		arith(i, 0x01, 0);
+		break;
+	case IADDB:
+		arithb(i, 0x00);
+		break;
+	case IADDF:
+		arithf(i, 0);
+		break;
+	case IORW:
+		arith(i, 0x09, 1);
+		break;
+	case IORB:
+		arithb(i, 0x08);
+		break;
+	case IANDW:
+		arith(i, 0x21, 4);
+		break;
+	case IANDB:
+		arithb(i, 0x20);
+		break;
+	case IXORW:
+		arith(i, Oxor, 6);
+		break;
+	case IXORB:
+		arithb(i, 0x30);
+		break;
+	case ISHLW:
+		shift(i, Oldw, Ostw, 0xd3, 4);
+		break;
+	case ISHLB:
+		shift(i, Oldb, Ostb, 0xd2, 4);
+		break;
+	case ISHRW:
+		shift(i, Oldw, Ostw, 0xd3, 7);
+		break;
+	case ISHRB:
+		shift(i, Oldb, Ostb, 0xd2, 5);
+		break;
+	case IMOVF:
+		opwld(i, Omovf, 0);
+		opwst(i, Omovf, 3);
+		break;
+	case INEGF:
+		opwld(i, Omovf, 0);
+		genb(0xd9);
+		genb(0xe0);
+		opwst(i, Omovf, 3);
+		break;
+	case IMOVB:
+		opwld(i, Oldb, RAX);
+		opwst(i, Ostb, RAX);
+		break;
+	case IMOVW:
+	case ICVTLW:			// Little endian
+		if(UXSRC(i->add) == SRC(AIMM)) {
+			opwst(i, Omov, RAX);
+			genw(i->s.imm);
+			break;
+		}
+		opwld(i, Oldw, RAX);
+		opwst(i, Ostw, RAX);
+		break;
+	case ICVTWL:
+		opwst(i, Olea, RTMP);
+		opwld(i, Oldw, RAX);
+		modrm(Ostw, 0, RTMP, RAX);
+		genb(0x99);
+		modrm(Ostw, 4, RTMP, RDX);
+		break;
+	case ICALL:
+		if(UXDST(i->add) != DST(AIMM))
+			opwst(i, Oldw, RTA);
+		opwld(i, Oldw, RAX);
+		modrm(Omov, O(Frame, lr), RAX, 0);	// MOVL $.+1, lr(AX)
+		genw((ulong)base+patch[i-mod->prog+1]);
+		modrm(Ostw, O(Frame, fp), RAX, RFP); 	// MOVL RFP, fp(AX)
+		gen2(Oldw, (3<<6)|(RFP<<3)|RAX);	// MOVL AX,RFP
+		if(UXDST(i->add) != DST(AIMM)){
+			gen2(Ojmprm, (3<<6)|(4<<3)|RTA);
+			break;
+		}
+		/* no break */
+	case IJMP:
+		if(RESCHED)
+			schedcheck(i);
+		rbra(patch[i->d.ins-mod->prog], Ojmp);
+		break;
+	case IMOVPC:
+		opwst(i, Omov, RAX);
+		genw(patch[i->s.imm]+(ulong)base);
+		break;
+	case IGOTO:
+		opwst(i, Olea, RBX);
+		opwld(i, Oldw, RAX);
+		gen2(Ojmprm, (0<<6)|(4<<3)|4);
+		genb((2<<6)|(RAX<<3)|RBX);
+
+		if(pass == 0)
+			break;
+
+		t = (WORD*)(mod->origmp+i->d.ind);
+		e = t + t[-1];
+		t[-1] = 0;
+		while(t < e) {
+			t[0] = (ulong)base + patch[t[0]];
+			t++;
+		}
+		break;
+	case IMULF:
+		arithf(i, 1);
+		break;
+	case IDIVF:
+		arithf(i, 7);
+		break;
+	case IMODW:
+	case IDIVW:
+	case IMULW:
+		mid(i, Oldw, RAX);
+		opwld(i, Oldw, RTMP);
+		if(i->op == IMULW)
+			gen2(0xf7, (3<<6)|(4<<3)|RTMP);
+		else {
+			genb(Ocdq);
+			gen2(0xf7, (3<<6)|(7<<3)|RTMP);	// IDIV AX, RTMP
+			if(i->op == IMODW)
+				genb(0x90+RDX);		// XCHG	AX, DX
+		}
+		opwst(i, Ostw, RAX);
+		break;
+	case IMODB:
+	case IDIVB:
+	case IMULB:
+		mid(i, Oldb, RAX);
+		opwld(i, Oldb, RTMP);
+		if(i->op == IMULB)
+			gen2(0xf6, (3<<6)|(4<<3)|RTMP);
+		else {
+			genb(Ocdq);
+			gen2(0xf6, (3<<6)|(7<<3)|RTMP);	// IDIV AX, RTMP
+			if(i->op == IMODB)
+				genb(0x90+RDX);		// XCHG	AX, DX
+		}
+		opwst(i, Ostb, RAX);
+		break;
+	case IINDX:
+		opwld(i, Oldw, RTMP);			// MOVW	xx(s), BX
+
+		if(bflag){
+			opwst(i, Oldw, RAX);
+			modrm(0x3b, O(Array, len), RTMP, RAX);	/* CMP index, len */
+			gen2(0x72, 5);		/* JB */
+			bra((ulong)bounds, Ocall);
+			modrm(Oldw, O(Array, t), RTMP, RTA);
+			modrm(0xf7, O(Type, size), RTA, 5);		/* IMULL AX, xx(t) */
+		}
+		else{
+			modrm(Oldw, O(Array, t), RTMP, RAX);	// MOVW	t(BX), AX
+			modrm(Oldw, O(Type, size), RAX, RAX);	// MOVW size(AX), AX
+			if(UXDST(i->add) == DST(AIMM)) {
+				gen2(0x69, (3<<6)|(RAX<<3)|0);
+				genw(i->d.imm);
+			}
+			else
+				opwst(i, 0xf7, 5);		// IMULL AX,xx(d)
+		}
+
+		modrm(0x03, O(Array, data), RBX, RAX);	// ADDL data(BX), AX
+		r = RMP;
+		if((i->add&ARM) == AXINF)
+			r = RFP;
+		modrm(Ostw, i->reg, r, RAX);
+		break;
+	case IINDB:
+		r = 0;
+		goto idx;
+	case IINDF:
+	case IINDL:
+		r = 3;
+		goto idx;
+	case IINDW:
+		r = 2;
+	idx:
+		opwld(i, Oldw, RAX);
+		opwst(i, Oldw, RTMP);
+		if(bflag){
+			modrm(0x3b, O(Array, len), RAX, RTMP);	/* CMP index, len */
+			gen2(0x72, 5);		/* JB */
+			bra((ulong)bounds, Ocall);
+		}
+		modrm(Oldw, O(Array, data), RAX, RAX);
+		gen2(Olea, (0<<6)|(0<<3)|4);		/* lea	(AX)(RTMP*r) */
+		genb((r<<6)|(RTMP<<3)|RAX);
+		r = RMP;
+		if((i->add&ARM) == AXINF)
+			r = RFP;
+		modrm(Ostw, i->reg, r, RAX);
+		break;
+	case IINDC:
+		opwld(i, Oldw, RAX);			// string
+		mid(i, Oldw, RBX);			// index
+		if(bflag){
+			modrm(Oldw, O(String, len), RAX, RTA);
+			cmpl(RTA, 0);
+			gen2(Ojltb, 16);
+			gen2(0x3b, (3<<6)|(RBX<<3)|RTA);	/* cmp index, len */
+			gen2(0x72, 5);		/* JB */
+			bra((ulong)bounds, Ocall);
+			genb(0x0f);
+			gen2(Omovzxb, (1<<6)|(0<<3)|4);
+			gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+			gen2(Ojmpb, sizeof(Rune)==4? 10: 11);
+			gen2(Oneg, (3<<6)|(3<<3)|RTA);
+			gen2(0x3b, (3<<6)|(RBX<<3)|RTA);	/* cmp index, len */
+			gen2(0x73, 0xee);		/* JNB */
+			if(sizeof(Rune) == 4){
+				gen2(Oldw, (1<<6)|(0<<3)|4);
+				gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+			}else{
+				genb(0x0f);
+				gen2(Omovzxw, (1<<6)|(0<<3)|4);
+				gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+			}
+			opwst(i, Ostw, RAX);
+			break;
+		}
+		modrm(Ocmpi, O(String, len), RAX, 7);
+		genb(0);
+		gen2(Ojltb, 7);
+		genb(0x0f);
+		gen2(Omovzxb, (1<<6)|(0<<3)|4);		/* movzbx 12(AX)(RBX*1), RAX */
+		gen2((0<<6)|(RBX<<3)|RAX, O(String, data));
+		if(sizeof(Rune) == 4){
+			gen2(Ojmpb, 4);
+			gen2(Oldw, (1<<6)|(0<<3)|4);		/* movl 12(AX)(RBX*4), RAX */
+			gen2((2<<6)|(RBX<<3)|RAX, O(String, data));
+		}else{
+			gen2(Ojmpb, 5);
+			genb(0x0f);
+			gen2(Omovzxw, (1<<6)|(0<<3)|4);		/* movzwx 12(AX)(RBX*2), RAX */
+			gen2((1<<6)|(RBX<<3)|RAX, O(String, data));
+		}
+		opwst(i, Ostw, RAX);
+		break;
+	case ICASE:
+		comcase(i, 1);
+		break;
+	case IMOVL:
+		opwld(i, Olea, RTA);
+		opwst(i, Olea, RTMP);
+		modrm(Oldw, 0, RTA, RAX);
+		modrm(Ostw, 0, RTMP, RAX);
+		modrm(Oldw, 4, RTA, RAX);
+		modrm(Ostw, 4, RTMP, RAX);
+		break;
+	case IADDL:
+		larith(i, 0x03, 0x13);
+		break;
+	case ISUBL:
+		larith(i, 0x2b, 0x1b);
+		break;
+	case IORL:
+		larith(i, 0x0b, 0x0b);
+		break;
+	case IANDL:
+		larith(i, 0x23, 0x23);
+		break;
+	case IXORL:
+		larith(i, 0x33, 0x33);
+		break;
+	case IBEQL:
+		cbral(i, Ojnel, Ojeql, ANDAND);
+		break;
+	case IBNEL:
+		cbral(i, Ojnel, Ojnel, OROR);
+		break;
+	case IBLEL:
+		cbral(i, Ojltl, Ojbel, EQAND);
+		break;
+	case IBGTL:
+		cbral(i, Ojgtl, Ojal, EQAND);
+		break;
+	case IBLTL:
+		cbral(i, Ojltl, Ojbl, EQAND);
+		break;
+	case IBGEL:
+		cbral(i, Ojgtl, Ojael, EQAND);
+		break;
+	case ISHLL:
+		shll(i);
+		break;
+	case ISHRL:
+		shrl(i);
+		break;
+	case IRAISE:
+		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case IMULX:
+	case IDIVX:
+	case ICVTXX:
+	case IMULX0:
+	case IDIVX0:
+	case ICVTXX0:
+	case IMULX1:
+	case IDIVX1:
+	case ICVTXX1:
+	case ICVTFX:
+	case ICVTXF:
+	case IEXPW:
+	case IEXPL:
+	case IEXPF:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ISELF:
+		punt(i, DSTOP, optab[i->op]);
+		break;
+	}
+}
+
+static void
+preamble(void)
+{
+	if(comvec)
+		return;
+
+	comvec = malloc(32);
+	if(comvec == nil)
+		error(exNomem);
+	code = (uchar*)comvec;
+
+	genb(Opushl+RBX);
+	genb(Opushl+RCX);
+	genb(Opushl+RDX);
+	genb(Opushl+RSI);
+	genb(Opushl+RDI);
+	con((ulong)&R, RTMP);
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+	modrm(Ojmprm, O(REG, PC), RTMP, 4);
+
+	segflush(comvec, 32);
+}
+
+static void
+maccase(void)
+{
+	uchar *loop, *def, *lab1;
+
+	modrm(Oldw, 0, RSI, RDX);		// n = t[0]
+	modrm(Olea, 4, RSI, RSI);		// t = &t[1]
+	gen2(Oldw, (3<<6)|(RBX<<3)|RDX);	// MOVL	DX, BX
+	gen2(Oshr, (3<<6)|(4<<3)|RBX);		// SHL	BX,1
+	gen2(0x01, (3<<6)|(RDX<<3)|RBX);	// ADDL	DX, BX	BX = n*3
+	gen2(Opushrm, (0<<6)|(6<<3)|4);
+	genb((2<<6)|(RBX<<3)|RSI);		// PUSHL 0(SI)(BX*4)
+	loop = code;
+	cmpl(RDX, 0);
+	gen2(Ojleb, 0);
+	def = code-1;
+	gen2(Oldw, (3<<6)|(RCX<<3)|RDX);	// MOVL	DX, CX	n2 = n
+	gen2(Oshr, (3<<6)|(5<<3)|RCX);		// SHR	CX,1	n2 = n2>>1
+	gen2(Oldw, (3<<6)|(RBX<<3)|RCX);	// MOVL	CX, BX
+	gen2(Oshr, (3<<6)|(4<<3)|RBX);		// SHL	BX,1
+	gen2(0x01, (3<<6)|(RCX<<3)|RBX);	// ADDL	CX, BX	BX = n2*3
+	gen2(0x3b, (0<<6)|(RAX<<3)|4);
+	genb((2<<6)|(RBX<<3)|RSI);		// CMPL AX, 0(SI)(BX*4)
+	gen2(Ojgeb, 0);				// JGE	lab1
+	lab1 = code-1;
+	gen2(Oldw, (3<<6)|(RDX<<3)|RCX);
+	gen2(Ojmpb, loop-code-2);
+	*lab1 = code-lab1-1;			// lab1:
+	gen2(0x3b, (1<<6)|(RAX<<3)|4);
+	gen2((2<<6)|(RBX<<3)|RSI, 4);		// CMPL AX, 4(SI)(BX*4)
+	gen2(Ojltb, 0);
+	lab1 = code-1;
+	gen2(Olea, (1<<6)|(RSI<<3)|4);
+	gen2((2<<6)|(RBX<<3)|RSI, 12);		// LEA	12(SI)(RBX*4), RSI
+	gen2(0x2b, (3<<6)|(RDX<<3)|RCX);	// SUBL	CX, DX		n -= n2
+	gen2(Odecrm, (3<<6)|(1<<3)|RDX);	// DECL	DX		n -= 1
+	gen2(Ojmpb, loop-code-2);
+	*lab1 = code-lab1-1;			// lab1:
+	gen2(Oldw, (1<<6)|(RAX<<3)|4);
+	gen2((2<<6)|(RBX<<3)|RSI, 8);		// MOVL 8(SI)(BX*4), AX
+	genb(Opopl+RSI);			// ditch default
+	genb(Opopl+RSI);
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);	// JMP*L AX
+	*def = code-def-1;			// def:
+	genb(Opopl+RAX);			// ditch default
+	genb(Opopl+RSI);
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);
+}
+
+static void
+macfrp(void)
+{
+	cmpl(RAX, (ulong)H);			// CMPL AX, $H
+	gen2(Ojneb, 0x01);			// JNE	.+1
+	genb(Oret);				// RET
+	modrm(0x83, O(Heap, ref)-sizeof(Heap), RAX, 7);
+	genb(0x01);				// CMP	AX.ref, $1
+	gen2(Ojeqb, 0x04);			// JNE	.+4
+	modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RAX, 1);
+	genb(Oret);				// DEC	AX.ref
+						// RET
+	con((ulong)&R, RTMP);			// MOV  $R, RTMP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL	RFP, R.FP
+	modrm(Ostw, O(REG, s), RTMP, RAX);	// MOVL	RAX, R.s
+	bra((ulong)rdestroy, Ocall);		// CALL rdestroy
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, FP), RTMP, RFP);	// MOVL	R.MP, RMP
+	modrm(Oldw, O(REG, MP), RTMP, RMP);	// MOVL R.FP, RFP
+	genb(Oret);
+}
+
+static void
+macret(void)
+{
+	Inst i;
+	uchar *s;
+	static ulong lpunt, lnomr, lfrmr, linterp;
+
+	s = code;
+
+	lpunt -= 2;
+	lnomr -= 2;
+	lfrmr -= 2;
+	linterp -= 2;
+
+	con(0, RBX);				// MOVL  $0, RBX
+	modrm(Oldw, O(Frame, t), RFP, RAX);	// MOVL  t(FP), RAX
+	gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX);	// CMPL  RAX, RBX
+	gen2(Ojeqb, lpunt-(code-s));		// JEQ	 lpunt
+	modrm(Oldw, O(Type, destroy), RAX, RAX);// MOVL  destroy(RAX), RAX
+	gen2(Ocmpw, (3<<6)|(RAX<<3)|RBX);	// CMPL	 RAX, RBX
+	gen2(Ojeqb, lpunt-(code-s));		// JEQ	 lpunt
+	modrm(Ocmpw, O(Frame, fp), RFP, RBX);	// CMPL	 fp(FP), RBX
+	gen2(Ojeqb, lpunt-(code-s));		// JEQ	 lpunt
+	modrm(Ocmpw, O(Frame, mr), RFP, RBX);	// CMPL	 mr(FP), RBX
+	gen2(Ojeqb, lnomr-(code-s));		// JEQ	 lnomr
+	con((ulong)&R, RTMP);			// MOVL	 $R, RTMP
+	modrm(Oldw, O(REG, M), RTMP, RTA);	// MOVL	 R.M, RTA
+	modrm(Odecrm, O(Heap, ref)-sizeof(Heap), RTA, 1);
+	gen2(Ojneb, lfrmr-(code-s));		// JNE	 lfrmr
+	modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+	gen2(Ojmpb, lpunt-(code-s));		// JMP	 lpunt
+	lfrmr = code - s;
+	modrm(Oldw, O(Frame, mr), RFP, RTA);	// MOVL	 mr(FP), RTA
+	modrm(Ostw, O(REG, M), RTMP, RTA);	// MOVL	 RTA, R.M
+	modrm(Oldw, O(Modlink, MP), RTA, RMP);	// MOVL	 MP(RTA), RMP
+	modrm(Ostw, O(REG, MP), RTMP, RMP);	// MOVL	 RMP, R.MP
+	modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+	genb(0x00);
+	gen2(Ojeqb, linterp-(code-s));		// JEQ	linterp
+	lnomr = code - s;
+	gen2(Ocallrm, (3<<6)|(2<<3)|RAX);	// CALL* AX
+	con((ulong)&R, RTMP);			// MOVL	 $R, RTMP
+	modrm(Ostw, O(REG, SP), RTMP, RFP);	// MOVL  RFP, R.SP
+	modrm(Oldw, O(Frame, lr), RFP, RAX);	// MOVL  lr(RFP), RAX
+	modrm(Oldw, O(Frame, fp), RFP, RFP);	// MOVL  fp(RFP), RFP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL  RFP, R.FP
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);	// JMP*L AX
+
+	linterp = code - s;			// return to uncompiled code
+	gen2(Ocallrm, (3<<6)|(2<<3)|RAX);	// CALL* AX
+	con((ulong)&R, RTMP);			// MOVL	 $R, RTMP
+	modrm(Ostw, O(REG, SP), RTMP, RFP);	// MOVL  RFP, R.SP
+	modrm(Oldw, O(Frame, lr), RFP, RAX);	// MOVL  lr(RFP), RAX
+	modrm(Ostw, O(REG, PC), RTMP, RAX);	// MOVL  RAX, R.PC
+	modrm(Oldw, O(Frame, fp), RFP, RFP);	// MOVL  fp(RFP), RFP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL  RFP, R.FP
+	genb(Opopl+RDI);			// return to uncompiled code
+	genb(Opopl+RSI);
+	genb(Opopl+RDX);
+	genb(Opopl+RCX);
+	genb(Opopl+RBX);
+	genb(Oret);
+						// label:
+	lpunt = code - s;
+
+	i.add = AXNON;
+	punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+	modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RBX, 0);
+	gen2(Oldw, (0<<6)|(RAX<<3)|5);		// INCL	ref(BX)
+	genw((ulong)&mutator);			// MOVL	mutator, RAX
+	modrm(Ocmpw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+	gen2(Ojneb, 0x01);			// CMPL	color(BX), RAX
+	genb(Oret);				// MOVL $propagator,RTMP
+	con(propagator, RAX);			// MOVL	RTMP, color(BX)
+	modrm(Ostw, O(Heap, color)-sizeof(Heap), RBX, RAX);
+	gen2(Ostw, (0<<6)|(RAX<<3)|5);		// can be any !0 value
+	genw((ulong)&nprop);			// MOVL	RBX, nprop
+	genb(Oret);
+}
+
+static void
+macmcal(void)
+{
+	uchar *label, *mlnil, *interp;
+
+	cmpl(RAX, (ulong)H);
+	gen2(Ojeqb, 0);
+	mlnil = code - 1;
+	modrm(0x83, O(Modlink, prog), RTA, 7);	// CMPL $0, ml->prog
+	genb(0x00);
+	gen2(Ojneb, 0);				// JNE	patch
+	label = code-1;
+	*mlnil = code-mlnil-1;
+	modrm(Ostw, O(REG, FP), RTMP, RCX);
+	modrm(Ostw, O(REG, dt), RTMP, RAX);
+	bra((ulong)rmcall, Ocall);		// CALL rmcall
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+	genb(Oret);				// RET
+	*label = code-label-1;			// patch:
+	gen2(Oldw, (3<<6)|(RFP<<3)|RCX);	// MOVL CX, RFP		R.FP = f
+	modrm(Ostw, O(REG, M), RTMP, RTA);	// MOVL RTA, R.M
+	modrm(Oincrm, O(Heap, ref)-sizeof(Heap), RTA, 0);
+	modrm(Oldw, O(Modlink, MP), RTA, RMP);	// MOVL R.M->mp, RMP
+	modrm(Ostw, O(REG, MP), RTMP, RMP);	// MOVL RMP, R.MP	R.MP = ml->MP
+	modrm(Ocmpi, O(Modlink, compiled), RTA, 7);// CMPL $0, M.compiled
+	genb(0x00);
+	genb(Opopl+RTA);			// balance call
+	gen2(Ojeqb, 0);				// JEQ	interp
+	interp = code-1;
+	gen2(Ojmprm, (3<<6)|(4<<3)|RAX);	// JMP*L AX
+	*interp = code-interp-1;		// interp:
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL FP, R.FP
+	modrm(Ostw, O(REG, PC), RTMP, RAX);	// MOVL PC, R.PC
+	genb(Opopl+RDI);			// call to uncompiled code
+	genb(Opopl+RSI);
+	genb(Opopl+RDX);
+	genb(Opopl+RCX);
+	genb(Opopl+RBX);
+	genb(Oret);
+}
+
+static void
+macfram(void)
+{
+	uchar *label;
+
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, SP), RTMP, RAX);	// MOVL	R.SP, AX
+	modrm(0x03, O(Type, size), RTA, RAX);	// ADDL size(RCX), RAX
+	modrm(0x3b, O(REG, TS), RTMP, RAX);	// CMPL	AX, R.TS
+	gen2(0x7c, 0x00);			// JL	.+(patch)
+	label = code-1;
+
+	modrm(Ostw, O(REG, s), RTMP, RTA);
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL	RFP, R.FP
+	bra((ulong)extend, Ocall);		// CALL	extend
+	con((ulong)&R, RTMP);
+	modrm(Oldw, O(REG, FP), RTMP, RFP);	// MOVL	R.MP, RMP
+	modrm(Oldw, O(REG, MP), RTMP, RMP);	// MOVL R.FP, RFP
+	modrm(Oldw, O(REG, s), RTMP, RCX);	// MOVL	R.s, *R.d
+	genb(Oret);				// RET
+	*label = code-label-1;
+	modrm(Oldw, O(REG, SP), RTMP, RCX);	// MOVL	R.SP, CX
+	modrm(Ostw, O(REG, SP), RTMP, RAX);	// MOVL	AX, R.SP
+
+	modrm(Ostw, O(Frame, t), RCX, RTA);	// MOVL	RTA, t(CX) f->t = t
+	modrm(Omov, REGMOD*4, RCX, 0);     	// MOVL $0, mr(CX) f->mr
+	genw(0);
+	modrm(Oldw, O(Type, initialize), RTA, RTA);
+	gen2(Ojmprm, (3<<6)|(4<<3)|RTA);	// JMP*L RTA
+	genb(Oret);				// RET
+}
+
+static void
+macmfra(void)
+{
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Ostw, O(REG, FP), RTMP, RFP);
+	modrm(Ostw, O(REG, s), RTMP, RAX);	// Save type
+	modrm(Ostw, O(REG, d), RTMP, RTA);	// Save destination
+	bra((ulong)rmfram, Ocall);		// CALL rmfram
+	con((ulong)&R, RTMP);			// MOVL	$R, RTMP
+	modrm(Oldw, O(REG, FP), RTMP, RFP);
+	modrm(Oldw, O(REG, MP), RTMP, RMP);
+	genb(Oret);				// RET
+}
+
+static void
+macrelq(void)
+{
+	modrm(Ostw, O(REG, FP), RTMP, RFP);	// MOVL FP, R.FP
+	genb(Opopl+RAX);
+	modrm(Ostw, O(REG, PC), RTMP, RAX);	// MOVL PC, R.PC
+	genb(Opopl+RDI);
+	genb(Opopl+RSI);
+	genb(Opopl+RDX);
+	genb(Opopl+RCX);
+	genb(Opopl+RBX);
+	genb(Oret);
+}
+
+void
+comd(Type *t)
+{
+	int i, j, m, c;
+
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m) {
+				modrm(Oldw, j, RFP, RAX);
+				rbra(macro[MacFRP], Ocall);
+			}
+			j += sizeof(WORD*);
+		}
+	}
+	genb(Oret);
+}
+
+void
+comi(Type *t)
+{
+	int i, j, m, c;
+
+	con((ulong)H, RAX);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m)
+				modrm(Ostw, j, RCX, RAX);
+			j += sizeof(WORD*);
+		}
+	}
+	genb(Oret);
+}
+
+void
+typecom(Type *t)
+{
+	int n;
+	uchar *tmp;
+
+	if(t == nil || t->initialize != 0)
+		return;
+
+	tmp = mallocz(4096*sizeof(uchar), 0);
+	if(tmp == nil)
+		error(exNomem);
+
+	code = tmp;
+	comi(t);
+	n = code - tmp;
+	code = tmp;
+	comd(t);
+	n += code - tmp;
+	free(tmp);
+
+	code = mallocz(n, 0);
+	if(code == nil)
+		return;
+
+	t->initialize = code;
+	comi(t);
+	t->destroy = code;
+	comd(t);
+
+	if(cflag > 3)
+		print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+			(ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+
+	segflush(t->initialize, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+	Handler *h;
+	Except *e;
+
+	if((h = m->htab) == nil)
+		return;
+	for( ; h->etab != nil; h++){
+		h->pc1 = p[h->pc1];
+		h->pc2 = p[h->pc2];
+		for(e = h->etab; e->s != nil; e++)
+			e->pc = p[e->pc];
+		if(e->pc != -1)
+			e->pc = p[e->pc];
+	}
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+	ulong v;
+	Modl *e;
+	Link *l;
+	int i, n;
+	uchar *s, *tmp;
+
+	base = nil;
+	patch = mallocz(size*sizeof(*patch), 0);
+	tinit = malloc(m->ntype*sizeof(*tinit));
+	tmp = mallocz(4096*sizeof(uchar),0);
+	if(tinit == nil || patch == nil || tmp == nil)
+		goto bad;
+
+	preamble();
+
+	mod = m;
+	n = 0;
+	pass = 0;
+	nlit = 0;
+
+	for(i = 0; i < size; i++) {
+		code = tmp;
+		comp(&m->prog[i]);
+		patch[i] = n;
+		n += code - tmp;
+	}
+
+	for(i = 0; i < nelem(mactab); i++) {
+		code = tmp;
+		mactab[i].gen();
+		macro[mactab[i].idx] = n;
+		n += code - tmp;
+	}
+
+	n = (n+3)&~3;
+
+	nlit *= sizeof(ulong);
+	base = mallocz(n + nlit, 0);
+	if(base == nil)
+		goto bad;
+
+	if(cflag > 3)
+		print("dis=%5d %5d 386=%5d asm=%.8lux lit=%d: %s\n",
+			size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+	pass++;
+	nlit = 0;
+	litpool = (ulong*)(base+n);
+	code = base;
+
+	for(i = 0; i < size; i++) {
+		s = code;
+		comp(&m->prog[i]);
+		if(cflag > 4) {
+			print("%D\n", &m->prog[i]);
+			das(s, code-s);
+		}
+	}
+
+	for(i = 0; i < nelem(mactab); i++)
+		mactab[i].gen();
+
+	v = (ulong)base;
+	for(l = m->ext; l->name; l++) {
+		l->u.pc = (Inst*)(v+patch[l->u.pc-m->prog]);
+		typecom(l->frame);
+	}
+	if(ml != nil) {
+		e = &ml->links[0];
+		for(i = 0; i < ml->nlinks; i++) {
+			e->u.pc = (Inst*)(v+patch[e->u.pc-m->prog]);
+			typecom(e->frame);
+			e++;
+		}
+	}
+	for(i = 0; i < m->ntype; i++) {
+		if(tinit[i] != 0)
+			typecom(m->type[i]);
+	}
+	patchex(m, patch);
+	m->entry = (Inst*)(v+patch[mod->entry-mod->prog]);
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(m->prog);
+	m->prog = (Inst*)base;
+	m->compiled = 1;
+	segflush(base, n*sizeof(base));
+	return 1;
+bad:
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(base);
+	return 0;
+}
+
--- /dev/null
+++ b/libinterp/comp-arm.c
@@ -1,0 +1,2280 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+/*
+ * to do:
+ *	eliminate litpool?
+ *	eliminate long constants in comi/comd
+ *	enable and check inline FP code (not much point with fpemu)
+ */
+
+#define	RESCHED 1	/* check for interpreter reschedule */
+#define	SOFTFP	1
+
+enum
+{
+	R0	= 0,
+	R1	= 1,
+	R2	= 2,
+	R3	= 3,
+	R4	= 4,
+	R5	= 5,
+	R6	= 6,
+	R7	= 7,
+	R8	= 8,
+	R9	= 9,
+	R10	= 10,
+	R11	= 11,
+	R12	= 12,		/* C's SB */
+	R13	= 13,		/* C's SP */
+	R14	= 14,		/* Link Register */
+	R15	= 15,		/* PC */
+
+	RLINK	= 14,
+
+	RFP	= R9,		/* Frame Pointer */
+	RMP	= R8,		/* Module Pointer */
+	RTA	= R7,		/* Intermediate address for double indirect */
+	RCON	= R6,		/* Constant builder */
+	RREG	= R5,		/* Pointer to REG */
+	RA3	= R4,		/* gpr 3 */
+	RA2	= R3,		/* gpr 2 2+3 = L */
+	RA1	= R2,		/* gpr 1 */
+	RA0	= R1,		/* gpr 0 0+1 = L */
+
+
+	FA2	= 2,		/* Floating */
+	FA3	= 3,
+	FA4	= 4,
+	FA5	= 5,
+
+	EQ	= 0,
+	NE	= 1,
+	CS	= 2,
+	CC	= 3,
+	MI	= 4,
+	PL	= 5,
+	VS	= 6,
+	VC	= 7,
+	HI	= 8,
+	LS	= 9,
+	GE	= 10,
+	LT	= 11,
+	GT	= 12,
+	LE	= 13,
+	AL	= 14,
+	NV	= 15,
+
+	HS	= CS,
+	LO	= CC,
+
+	And	= 0,
+	Eor	= 1,
+	Sub	= 2,
+	Rsb	= 3,
+	Add	= 4,
+	Adc	= 5,
+	Sbc	= 6,
+	Rsc	= 7,
+	Tst	= 8,
+	Teq	= 9,
+	Cmp	= 10,
+	Cmn	= 11,
+	Orr	= 12,
+	Mov	= 13,
+	Bic	= 14,
+	Mvn	= 15,
+
+	Adf	= 0,
+	Muf	= 1,
+	Suf	= 2,
+	Rsf	= 3,
+	Dvf	= 4,
+	Rdf	= 5,
+	Rmf	= 8,
+
+	Mvf	= 0,
+	Mnf	= 1,
+	Abs	= 2,
+	Rnd	= 3,
+
+	Flt	= 0,
+	Fix	= 1,
+
+	Cmf	= 4,
+	Cnf	= 5,
+
+	Lea	= 100,		/* macro memory ops */
+	Ldw,
+	Ldb,
+	Stw,
+	Stb,
+	Ldf,
+	Stf,
+	Ldh,
+
+	Blo	= 0,	/* offset of low order word in big */
+	Bhi	= 4,	/* offset of high order word in big */
+
+	Lg2Rune	= 2,
+
+	NCON	= (0xFFC-8)/4,
+
+	SRCOP	= (1<<0),
+	DSTOP	= (1<<1),
+	WRTPC	= (1<<2),
+	TCHECK	= (1<<3),
+	NEWPC	= (1<<4),
+	DBRAN	= (1<<5),
+	THREOP	= (1<<6),
+
+	ANDAND	= 1,
+	OROR	= 2,
+	EQAND	= 3,
+
+	MacFRP	= 0,
+	MacRET,
+	MacCASE,
+	MacCOLR,
+	MacMCAL,
+	MacFRAM,
+	MacMFRA,
+	MacRELQ,
+	NMACRO
+};
+
+#define BITS(B)				(1<<B)
+#define IMM(O)				(O & ((1<<12)-1))
+#define SBIT	(1<<20)
+#define PBIT	(1<<24)
+#define UPBIT	(1<<23)
+
+#define LDW(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|\
+					  (Rn<<16)|(Rd<<12)|IMM(O)
+#define STW(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|\
+					  (Rn<<16)|(Rd<<12)|IMM(O)
+#define LDB(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
+					  (Rn<<16)|(Rd<<12)|IMM(O)
+#define STB(C, Rn, Rd, O)		*code++ = (C<<28)|(1<<26)|(1<<24)|(1<<23)|(1<<22)|\
+					  (Rn<<16)|(Rd<<12)|IMM(O)
+
+#define LDxP(C, Rn, Rd, O, B)		*code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|(1<<20)|\
+					  (Rn<<16)|(Rd<<12)|IMM(O)
+#define STxP(C, Rn, Rd, O, B)		*code++ = (C<<28)|(1<<26)|(B<<22)|(1<<23)|\
+					  (Rn<<16)|(Rd<<12)|IMM(O)
+#define LDRW(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|\
+					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define STRW(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|\
+					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define LDRB(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<20)|(1<<22)|\
+					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
+#define STRB(C, Rn, Rd, SH, R)		*code++ = (C<<28)|(3<<25)|(1<<24)|(1<<23)|(1<<22)|\
+					  (Rn<<16)|(Rd<<12)|(SH<<4)|R
+
+#define DPI(C, Op, Rn, Rd, RO, O)	*code++ = (C<<28)|(1<<25)|(Op<<21)|\
+					  (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define DP(C, Op, Rn, Rd, Sh, Ro)	*code++ = (C<<28)|(Op<<21)|(Rn<<16)|\
+					  (Rd<<12)|((Sh)<<4)|Ro
+#define CMPI(C, Rn, Rd, RO, O)	*code++ = (C<<28)|(1<<25)|(Cmp<<21)|(1<<20)|\
+					  (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define CMNI(C, Rn, Rd, RO, O)	*code++ = (C<<28)|(1<<25)|(Cmn<<21)|(1<<20)|\
+					  (Rn<<16)|(Rd<<12)|(RO<<8)|((O)&0xff)
+#define CMP(C, Rn, Rd, Sh, Ro)	*code++ = (C<<28)|(Cmp<<21)|(Rn<<16)|(1<<20)|\
+					  (Rd<<12)|((Sh)<<4)|Ro
+#define CMN(C, Rn, Rd, Sh, Ro)	*code++ = (C<<28)|(Cmn<<21)|(Rn<<16)|(1<<20)|\
+					  (Rd<<12)|((Sh)<<4)|Ro
+#define MUL(C, Rm, Rs, Rd)		*code++ = (C<<28)|(Rd<<16)|(Rm<<0)|(Rs<<8)|\
+					  (9<<4)
+
+#define LDF(C, Rn, Fd, O)		*code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|(1<<20)|\
+					  (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
+#define STF(C, Rn, Fd, O)		*code++ = (C<<28)|(6<<25)|(1<<24)|(1<<23)|\
+					  (Rn<<16)|(1<<15)|(Fd<<12)|(1<<8)|((O)&0xff)
+#define CMF(C, Fn, Fm)	*code++ = (C<<28)|(7<<25)|(4<<21)|(1<<20)|(Fn<<16)|\
+						(0xF<<12)|(1<<8)|(1<<4)|(Fm)
+
+#define LDH(C, Rn, Rd, O)		*code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<22)|(1<<20)|\
+					  (Rn<<16)|(Rd<<12)|(((O)&0xf0)<<4)|(0xb<<4)|((O)&0xf)
+#define LDRH(C, Rn, Rd, Rm)		*code++ = (C<<28)|(0<<25)|(1<<24)|(1<<23)|(1<<20)|\
+					  (Rn<<16)|(Rd<<12)|(0xb<<4)|Rm
+
+#define CPDO2(C, Op, Fn, Fd, Fm)	*code++ = (C<<28)|(0xE<<24)|(Op<<20)|(Fn<<16)|(Fd<<12)|(1<<8)|(1<<7)|(Fm)
+#define CPDO1(C, Op, Fd, Fm)	CPDO2((C),(Op),0,(Fd),(Fm))|(1<<15)
+#define CPFLT(C, Fn, Rd)	*code++ = (C<<28)|(0xE<<24)|(0<<20)|(Fn<<16)|(Rd<<12)|(1<<8)|(9<<4)
+#define CPFIX(C, Rd, Fm)	*code++ = (C<<28)|(0xE<<24)|(1<<20)|(0<<16)|(Rd<<12)|(1<<8)|(9<<4)|(Fm)
+
+#define BRAW(C, o)			((C<<28)|(5<<25)|((o) & 0x00ffffff))
+#define BRA(C, o)			gen(BRAW((C),(o)))
+#define IA(s, o)			(ulong)(base+s[o])
+#define BRADIS(C, o)			BRA(C, (IA(patch, o)-(ulong)code-8)>>2)
+#define BRAMAC(r, o)			BRA(r, (IA(macro, o)-(ulong)code-8)>>2)
+#define BRANCH(C, o)				gen(BRAW(C, ((ulong)(o)-(ulong)code-8)>>2))
+#define CALL(o)				gen(BRAW(AL, ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
+#define CCALL(C,o)				gen(BRAW((C), ((ulong)(o)-(ulong)code-8)>>2)|(1<<24))
+#define CALLMAC(C,o)			gen(BRAW((C), (IA(macro, o)-(ulong)code-8)>>2)|(1<<24))
+#define RELPC(pc)			(ulong)(base+(pc))
+#define RETURN				DPI(AL, Add, RLINK, R15, 0, 0)				
+#define CRETURN(C)				DPI(C, Add, RLINK, R15, 0, 0)				
+#define PATCH(ptr)			*ptr |= (((ulong)code-(ulong)(ptr)-8)>>2) & 0x00ffffff
+
+#define MOV(src, dst)			DP(AL, Mov, 0, dst, 0, src)
+
+#define FITS12(v)	((ulong)(v)<BITS(12))
+#define FITS8(v)	((ulong)(v)<BITS(8))
+#define FITS5(v)	((ulong)(v)<BITS(5))
+
+/* assumes H==-1 */
+#define CMPH(C, r)		CMNI(C, r, 0, 0, 1)
+#define NOTNIL(r)	(CMPH(AL, (r)), CCALL(EQ, nullity))
+
+/* array bounds checking */
+#define BCK(r, rb)	(CMP(AL, rb, 0, 0, r), CCALL(LS, bounds))
+#define BCKI(i, rb)	(CMPI(AL, rb, 0, 0, i), CCALL(LS, bounds))
+#define BCKR(i, rb)	(CMPI(AL, rb, 0, 0, 0)|(i), CCALL(LS, bounds))
+
+static	ulong*	code;
+static	ulong*	base;
+static	ulong*	patch;
+static	ulong	codeoff;
+static	int	pass;
+static	int	puntpc = 1;
+static	Module*	mod;
+static	uchar*	tinit;
+static	ulong*	litpool;
+static	int	nlit;
+static	ulong	macro[NMACRO];
+	void	(*comvec)(void);
+static	void	macfrp(void);
+static	void	macret(void);
+static	void	maccase(void);
+static	void	maccolr(void);
+static	void	macmcal(void);
+static	void	macfram(void);
+static	void	macmfra(void);
+static	void	macrelq(void);
+static	void movmem(Inst*);
+static	void mid(Inst*, int, int);
+extern	void	das(ulong*, int);
+
+#define T(r)	*((void**)(R.r))
+
+struct
+{
+	int	idx;
+	void	(*gen)(void);
+	char*	name;
+} mactab[] =
+{
+	MacFRP,		macfrp,		"FRP", 	/* decrement and free pointer */
+	MacRET,		macret,		"RET",	/* return instruction */
+	MacCASE,	maccase,	"CASE",	/* case instruction */
+	MacCOLR,	maccolr,	"COLR",	/* increment and color pointer */
+	MacMCAL,	macmcal,	"MCAL",	/* mcall bottom half */
+	MacFRAM,	macfram,	"FRAM",	/* frame instruction */
+	MacMFRA,	macmfra,	"MFRA",	/* punt mframe because t->initialize==0 */
+	MacRELQ,		macrelq,	/* reschedule */
+};
+
+typedef struct Const Const;
+struct Const
+{
+	ulong	o;
+	ulong*	code;
+	ulong*	pc;
+};
+
+typedef struct Con Con;
+struct Con
+{
+	int	ptr;
+	Const	table[NCON];	
+};
+static Con rcon;
+
+static void
+rdestroy(void)
+{
+	destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+	Frame *f;
+	Prog *p;
+
+	if((void*)R.dt == H)
+		error(exModule);
+
+	f = (Frame*)R.FP;
+	if(f == H)
+		error(exModule);
+
+	f->mr = nil;
+	((void(*)(Frame*))R.dt)(f);
+	R.SP = (uchar*)f;
+	R.FP = f->fp;
+	if(f->t == nil)
+		unextend(f);
+	else
+		freeptrs(f, f->t);
+	p = currun();
+	if(p->kill != nil)
+		error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+
+	if(R.d == H)
+		error(exModule);
+	t = (Type*)R.s;
+	if(t == H)
+		error(exModule);
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP = nsp;
+	f->t = t;
+	f->mr = nil;
+	initmem(t, f);
+	T(d) = f;
+}
+
+static void
+urk(char *s)
+{
+	USED(s);
+	error(exCompile);	//production
+	//panic("compile failed: urk: %s\n", s);	//debugging
+}
+
+static void
+gen(ulong w)
+{
+	*code++ = w;
+}
+
+static long
+immrot(ulong v)
+{
+	int i;
+
+	for(i=0; i<16; i++) {
+		if((v & ~0xff) == 0)
+			return (i<<8) | v | (1<<25);
+		v = (v<<2) | (v>>30);
+	}
+	return 0;
+}
+
+static long
+immaddr(long v)
+{
+
+	if(v >= 0 && v <= 0xfff)
+		return (v & 0xfff) |
+			(1<<24) |	/* pre indexing */
+			(1<<23);	/* pre indexing, up */
+	if(v >= -0xfff && v < 0)
+		return (-v & 0xfff) |
+			(1<<24);	/* pre indexing */
+	return 0;
+}
+
+static void
+flushcon(int genbr)
+{
+	int i;
+	Const *c;
+	ulong disp;
+
+	if(rcon.ptr == 0)
+		return;
+	if(genbr){
+		if(0)print("BR %d(PC)=%8.8p (len=%d)\n", (rcon.ptr*4+4-8)>>2, code+rcon.ptr+1, rcon.ptr);
+		BRA(AL, (rcon.ptr*4+4-8)>>2);
+	}
+	c = &rcon.table[0];
+	for(i = 0; i < rcon.ptr; i++) {
+		if(pass){
+			disp = (code - c->code) * sizeof(*code) - 8;
+			if(disp >= BITS(12))
+				print("INVALID constant range %lud", disp);
+			if(0)print("data %8.8p %8.8lux (%8.8p, ins=%8.8lux cpc=%8.8p)\n", code, c->o, c->code, *c->code, c->pc);
+			*c->code |= (disp&0xfff);
+		}
+		*code++ = c->o;
+		c++;
+	}
+	rcon.ptr = 0;
+}
+
+static void
+flushchk(void)
+{
+	if(rcon.ptr >= NCON || rcon.ptr > 0 && (code+codeoff+2-rcon.table[0].pc)*sizeof(*code) >= BITS(12)-256){  // 256 allows for a little delay in calling flushchk
+		if(0)print("flushed constant table: len %ux disp %ld\n", rcon.ptr, (code+codeoff-rcon.table[0].pc)*sizeof(*code)-8);
+		flushcon(1);
+	}
+}
+
+static void
+ccon(int cc, ulong o, int r, int opt)
+{
+	ulong u;
+	Const *c;
+
+	if(opt != 0) {
+		u = o & ~0xff;
+		if(u == 0) {
+			DPI(cc, Mov, 0, r, 0, o);
+			return;		
+		}
+		if(u == ~0xff) {
+			DPI(cc, Mvn, 0, r, 0, ~o);
+			return;
+		}
+		u = immrot(o);
+		if(u) {
+			DPI(cc, Mov, 0, r, 0, 0) | u;
+			return;
+		}
+		u = o & ~0xffff;
+		if(u == 0) {
+			DPI(cc, Mov, 0, r, 0, o);
+			DPI(cc, Orr, r, r, (24/2), o>>8);
+			return;
+		}
+	}
+	flushchk();
+	c = &rcon.table[rcon.ptr++];
+	c->o = o;
+	c->code = code;
+	c->pc = code+codeoff;
+	LDW(cc, R15, r, 0);
+}
+
+static void
+memc(int c, int inst, ulong disp, int rm, int r)
+{
+	int bit;
+
+	if(inst == Lea) {
+		if(disp < BITS(8)) {
+			if(disp != 0 || rm != r)
+				DPI(c, Add, rm, r, 0, disp);
+			return;
+		}
+		if(-disp < BITS(8)) {
+			DPI(c, Sub, rm, r, 0, -disp);
+			return;
+		}
+		bit = immrot(disp);
+		if(bit) {
+			DPI(c, Add, rm, r, 0, 0) | bit;
+			return;
+		}
+		ccon(c, disp, RCON, 1);
+		DP(c, Add, rm, r, 0, RCON);
+		return;
+	}
+
+	if(disp < BITS(12) || -disp < BITS(12)) {	/* Direct load */
+		if(disp < BITS(12))
+			bit = 0;
+		else {
+			disp = -disp;
+			bit = UPBIT;
+		}
+		switch(inst) {
+		case Ldw:
+			LDW(c, rm, r, disp);
+			break;
+		case Ldb:
+			LDB(c, rm, r, disp);
+			break;
+		case Stw:
+			STW(c, rm, r, disp);
+			break;
+		case Stb:
+			STB(c, rm, r, disp);
+			break;
+		}
+		if(bit)
+			code[-1] ^= bit;
+		return;
+	}
+
+	ccon(c, disp, RCON, 1);
+	switch(inst) {
+	case Ldw:
+		LDRW(c, rm, r, 0, RCON);
+		break;
+	case Ldb:
+		LDRB(c, rm, r, 0, RCON);
+		break;
+	case Stw:
+		STRW(c, rm, r, 0, RCON);
+		break;
+	case Stb:
+		STRB(c, rm, r, 0, RCON);
+		break;
+	}
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+	ccon(AL, o, r, opt);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+	memc(AL, inst, disp, rm, r);
+}
+
+static void
+opx(int mode, Adr *a, int mi, int r, int li)
+{
+	int ir, rta;
+
+	switch(mode) {
+	default:
+		urk("opx");
+	case AFP:
+		mem(mi, a->ind, RFP, r);
+		return;
+	case AMP:
+		mem(mi, a->ind, RMP, r);
+		return;
+	case AIMM:
+		con(a->imm, r, 1);
+		if(mi == Lea) {	/* could be simpler if con generates reachable literal */
+			mem(Stw, li, RREG, r);
+			mem(Lea, li, RREG, r);
+		}
+		return;
+	case AIND|AFP:
+		ir = RFP;
+		break;
+	case AIND|AMP:
+		ir = RMP;
+		break;
+	}
+	rta = RTA;
+	if(mi == Lea)
+		rta = r;
+	mem(Ldw, a->i.f, ir, rta);
+	mem(mi, a->i.s, rta, r);
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+	opx(USRC(i->add), &i->s, op, reg, O(REG, st));
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+	opx(UDST(i->add), &i->d, op, reg, O(REG, dt));
+}
+
+static void
+memfl(int cc, int inst, ulong disp, int rm, int r)
+{
+	int bit, wd;
+
+	wd = (disp&03)==0;
+	bit = 0;
+	if(wd && disp < BITS(10))
+		disp >>= 2;	/* direct load */
+	else if(wd && -disp < BITS(10)){
+		bit = UPBIT;
+		disp = -disp >> 2;
+	}else{
+		ccon(cc, disp, RCON, 1);
+		DP(cc, Add, RCON, RCON, 0, rm);
+		rm = RCON;
+		disp = 0;
+	}
+	switch(inst) {
+	case Ldf:
+		LDF(cc, rm, r, disp);
+		break;
+	case Stf:
+		STF(cc, rm, r, disp);
+		break;
+	}
+	if(bit)
+		code[-1] ^= bit;
+}
+
+static void
+opfl(Adr *a, int am, int mi, int r)
+{
+	int ir;
+
+	switch(am) {
+	default:
+		urk("opfl");
+	case AFP:
+		memfl(AL, mi, a->ind, RFP, r);
+		return;
+	case AMP:
+		memfl(AL, mi, a->ind, RMP, r);
+		return;
+	case AIND|AFP:
+		ir = RFP;
+		break;
+	case AIND|AMP:
+		ir = RMP;
+		break;
+	}
+	mem(Ldw, a->i.f, ir, RTA);
+	memfl(AL, mi, a->i.s, RTA, r);
+}
+
+static void
+opflld(Inst *i, int mi, int r)
+{
+	opfl(&i->s, USRC(i->add), mi, r);
+}
+
+static void
+opflst(Inst *i, int mi, int r)
+{
+	opfl(&i->d, UDST(i->add), mi, r);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+	nlit++;
+
+	con((ulong)litpool, RTA, 0);
+	mem(Stw, roff, RREG, RTA);
+
+	if(pass == 0)
+		return;
+
+	*litpool = imm;
+	litpool++;	
+}
+
+static void
+schedcheck(Inst *i)
+{
+	if(RESCHED && i->d.ins <= i){
+		mem(Ldw, O(REG, IC), RREG, RA0);
+		DPI(AL, Sub, RA0, RA0, 0, 1) | SBIT;
+		mem(Stw, O(REG, IC), RREG, RA0);
+		/* CMPI(AL, RA0, 0, 0, 1); */
+		CALLMAC(LE, MacRELQ);
+	}
+}
+
+static void
+bounds(void)
+{
+	/* mem(Stw, O(REG,FP), RREG, RFP); */
+	error(exBounds);
+}
+
+static void
+nullity(void)
+{
+	/* mem(Stw, O(REG,FP), RREG, RFP); */
+	error(exNilref);
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+	ulong pc;
+
+	if(m & SRCOP) {
+		if(UXSRC(i->add) == SRC(AIMM))
+			literal(i->s.imm, O(REG, s));
+		else {
+			opwld(i, Lea, RA0);
+			mem(Stw, O(REG, s), RREG, RA0);
+		}
+	}
+
+	if(m & DSTOP) {
+		opwst(i, Lea, RA0);
+		mem(Stw, O(REG, d), RREG, RA0);
+	}
+	if(m & WRTPC) {
+		con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+		mem(Stw, O(REG, PC), RREG, RA0);
+	}
+	if(m & DBRAN) {
+		pc = patch[i->d.ins-mod->prog];
+		literal((ulong)(base+pc), O(REG, d));
+	}
+
+	switch(i->add&ARM) {
+	case AXNON:
+		if(m & THREOP) {
+			mem(Ldw, O(REG, d), RREG, RA0);
+			mem(Stw, O(REG, m), RREG, RA0);
+		}
+		break;
+	case AXIMM:
+		literal((short)i->reg, O(REG,m));
+		break;
+	case AXINF:
+		mem(Lea, i->reg, RFP, RA2);
+		mem(Stw, O(REG, m), RREG, RA2);
+		break;
+	case AXINM:
+		mem(Lea, i->reg, RMP, RA2);
+		mem(Stw, O(REG, m), RREG, RA2);
+		break;
+	}
+	mem(Stw, O(REG, FP), RREG, RFP);
+
+	CALL(fn);
+
+	con((ulong)&R, RREG, 1);
+	if(m & TCHECK) {
+		mem(Ldw, O(REG, t), RREG, RA0);
+		CMPI(AL, RA0, 0, 0, 0);
+		memc(NE, Ldw, O(REG, xpc), RREG, RLINK);
+		CRETURN(NE);		/* if(R.t) goto(R.xpc) */
+	}
+	mem(Ldw, O(REG, FP), RREG, RFP);
+	mem(Ldw, O(REG, MP), RREG, RMP);
+
+	if(m & NEWPC){
+		mem(Ldw, O(REG, PC), RREG, R15);
+		flushcon(0);
+	}
+}
+
+static void
+midfl(Inst *i, int mi, int r)
+{
+	int ir;
+
+	switch(i->add&ARM) {
+	default:
+		opflst(i, mi, r);
+		return;
+	case AXIMM:
+		con((short)i->reg, r, 1);	// BUG
+		return;
+	case AXINF:
+		ir = RFP;
+		break;
+	case AXINM:
+		ir = RMP;
+		break;
+	}
+	memfl(AL, mi, i->reg, ir, r);
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+	int ir;
+
+	switch(i->add&ARM) {
+	default:
+		opwst(i, mi, r);
+		return;
+	case AXIMM:
+		if(mi == Lea)
+			urk("mid/lea");
+		con((short)i->reg, r, 1);
+		return;
+	case AXINF:
+		ir = RFP;
+		break;
+	case AXINM:
+		ir = RMP;
+		break;
+	}
+	mem(mi, i->reg, ir, r);
+}
+
+static int
+swapbraop(int b)
+{
+	switch(b) {
+	case GE:
+		return LE;
+	case LE:
+		return GE;
+	case GT:
+		return LT;
+	case LT:
+		return GT;
+	}
+	return b;
+}
+
+static void
+cbra(Inst *i, int r)
+{
+	if(RESCHED)
+		schedcheck(i);
+	if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm)) {
+		mid(i, Ldw, RA1);
+		CMPI(AL, RA1, 0, 0, i->s.imm);
+		r = swapbraop(r);
+	} else if(UXSRC(i->add) == SRC(AIMM) && FITS8(-i->s.imm)) {
+		mid(i, Ldw, RA1);
+		CMNI(AL, RA1, 0, 0, -i->s.imm);
+		r = swapbraop(r);
+	} else if((i->add & ARM) == AXIMM && FITS8(i->reg)) {
+		opwld(i, Ldw, RA1);
+		CMPI(AL, RA1, 0, 0, i->reg);
+	} else if((i->add & ARM) == AXIMM && FITS8(-(short)i->reg)) {
+		opwld(i, Ldw, RA1);
+		CMNI(AL, RA1, 0, 0, -(short)i->reg);
+	} else {
+		opwld(i, Ldw, RA0);
+		mid(i, Ldw, RA1);
+		CMP(AL, RA0, 0, 0, RA1);
+	}
+	BRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbrab(Inst *i, int r)
+{
+	if(RESCHED)
+		schedcheck(i);
+	if(UXSRC(i->add) == SRC(AIMM)) {
+		mid(i, Ldb, RA1);
+		CMPI(AL, RA1, 0, 0, i->s.imm&0xFF);
+		r = swapbraop(r);
+	} else if((i->add & ARM) == AXIMM) {
+		opwld(i, Ldb, RA1);
+		CMPI(AL, RA1, 0, 0, i->reg&0xFF);
+	} else {
+		opwld(i, Ldb, RA0);
+		mid(i, Ldb, RA1);
+		CMP(AL, RA0, 0, 0, RA1);
+	}
+	BRADIS(r, i->d.ins-mod->prog);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+	ulong dst, *label;
+
+	if(RESCHED)
+		schedcheck(i);
+	opwld(i, Lea, RA1);
+	mid(i, Lea, RA3);
+	mem(Ldw, Bhi, RA1, RA2);
+	mem(Ldw, Bhi, RA3, RA0);
+	CMP(AL, RA2, 0, 0, RA0);
+	label = nil;
+	dst = i->d.ins-mod->prog;
+	switch(mode) {
+	case ANDAND:
+		label = code;
+		BRA(jmsw, 0);
+		break;
+	case OROR:
+		BRADIS(jmsw, dst);
+		break;
+	case EQAND:
+		BRADIS(jmsw, dst);
+		label = code;
+		BRA(NE, 0);
+		break;
+	}
+	mem(Ldw, Blo, RA3, RA0);
+	mem(Ldw, Blo, RA1, RA2);
+	CMP(AL, RA2, 0, 0, RA0);
+	BRADIS(jlsw, dst);
+	if(label != nil)
+		PATCH(label);
+}
+
+static void
+cbraf(Inst *i, int r)
+{
+	if(RESCHED)
+		schedcheck(i);
+	if(!SOFTFP){
+		ulong *s=code;
+		opflld(i, Ldf, FA4);
+		midfl(i, Ldf, FA2);
+		CMF(AL, FA4, FA2);
+		BRADIS(r, i->d.ins-mod->prog);
+		if(pass){print("%D\n", i); das(s, code-s);}
+	}else
+		punt(i, SRCOP|THREOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+}	
+
+static void
+comcase(Inst *i, int w)
+{
+	int l;
+	WORD *t, *e;
+
+	if(w != 0) {
+		opwld(i, Ldw, RA1);		// v
+		opwst(i, Lea, RA3);		// table
+		BRAMAC(AL, MacCASE);
+	}
+
+	t = (WORD*)(mod->origmp+i->d.ind+4);
+	l = t[-1];
+
+	/* have to take care not to relocate the same table twice - 
+	 * the limbo compiler can duplicate a case instruction
+	 * during its folding phase
+	 */
+
+	if(pass == 0) {
+		if(l >= 0)
+			t[-1] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-1] = -l-1;			/* Set real count */
+	e = t + t[-1]*3;
+	while(t < e) {
+		t[2] = RELPC(patch[t[2]]);
+		t += 3;
+	}
+	t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+	int l;
+	WORD *t, *e;
+
+	t = (WORD*)(mod->origmp+i->d.ind+8);
+	l = t[-2];
+	if(pass == 0) {
+		if(l >= 0)
+			t[-2] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-2] = -l-1;			/* Set real count */
+	e = t + t[-2]*6;
+	while(t < e) {
+		t[4] = RELPC(patch[t[4]]);
+		t += 6;
+	}
+	t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+	ulong *punt, *mlnil;
+
+	opwld(i, Ldw, RA0);
+	CMPH(AL, RA0);
+	mlnil = code;
+	BRA(EQ, 0);
+
+	if((i->add&ARM) == AXIMM) {
+		mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), RA0, RA3);
+	} else {
+		mid(i, Ldw, RA1);
+		DP(AL, Add, RA0, RA1, (3<<3), RA1);	// assumes sizeof(Modl) == 8
+		mem(Ldw, OA(Modlink, links)+O(Modl, frame), RA1, RA3);
+	}
+
+	mem(Ldw, O(Type, initialize), RA3, RA1);
+	CMPI(AL, RA1, 0, 0, 0);
+	punt = code;
+	BRA(NE, 0);
+
+	opwst(i, Lea, RA0);
+
+	/* Type in RA3, destination in RA0 */
+	PATCH(mlnil);
+	con(RELPC(patch[i-mod->prog+1]), RLINK, 0);
+	BRAMAC(AL, MacMFRA);
+
+	/* Type in RA3 */
+	PATCH(punt);
+	CALLMAC(AL, MacFRAM);
+	opwst(i, Stw, RA2);
+}
+
+static void
+commcall(Inst *i)
+{
+	ulong *mlnil;
+
+	opwld(i, Ldw, RA2);
+	con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+	mem(Stw, O(Frame, lr), RA2, RA0);
+	mem(Stw, O(Frame, fp), RA2, RFP);
+	mem(Ldw, O(REG, M), RREG, RA3);
+	mem(Stw, O(Frame, mr), RA2, RA3);
+	opwst(i, Ldw, RA3);
+	CMPH(AL, RA3);
+	mlnil = code;
+	BRA(EQ, 0);
+	if((i->add&ARM) == AXIMM) {
+		mem(Ldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
+	} else {
+		mid(i, Ldw, RA1);
+		DP(AL, Add, RA3, RA1, (3<<3), RA1);	// assumes sizeof(Modl) == 8
+		mem(Ldw, OA(Modlink, links)+O(Modl, u.pc), RA1, RA0);
+	}
+	PATCH(mlnil);
+	CALLMAC(AL, MacMCAL);
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+	opwld(i, Lea, RA0);
+	mid(i, Lea, RA3);
+	mem(Ldw, Blo, RA0, RA1);	// ls
+	mem(Ldw, Blo, RA3, RA2);
+	DP(AL, op, RA2, RA2, 0, RA1) | SBIT;	// ls: RA2 = RA2 op RA1
+	mem(Ldw, Bhi, RA0, RA1);
+	mem(Ldw, Bhi, RA3, RA0);
+	DP(AL, opc, RA0, RA0, 0, RA1);	// ms: RA0 = RA0 opc RA1
+	if((i->add&ARM) != AXNON)
+		opwst(i, Lea, RA3);
+	mem(Stw, Blo, RA3, RA2);
+	mem(Stw, Bhi, RA3, RA0);
+}
+
+static void
+movloop(Inst *i, int s)
+{
+	int b;
+
+	b = (s==1);
+	opwst(i, Lea, RA2);
+	LDxP(AL, RA1, RA0, s, b);
+	STxP(AL, RA2, RA0, s, b);
+	DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
+	BRA(NE, (-3*4-8)>>2);
+}
+
+static void
+movmem(Inst *i)
+{
+	ulong *cp;
+
+	// source address already in RA1
+	if((i->add&ARM) != AXIMM){
+		mid(i, Ldw, RA3);
+		CMPI(AL, RA3, 0, 0, 0);
+		cp = code;
+		BRA(LE, 0);
+		movloop(i, 1);
+		PATCH(cp);
+		return;
+	}
+	switch(i->reg){
+	case 0:
+		break;
+	case 4:
+		LDW(AL, RA1, RA2, 0);
+		opwst(i, Stw, RA2);
+		break;
+	case 8:
+		LDW(AL, RA1, RA2, 0);
+		opwst(i, Lea, RA3);
+		LDW(AL, RA1, RA1, 4);
+		STW(AL, RA3, RA2, 0);
+		STW(AL, RA3, RA1, 4);
+		break;
+	default:
+		// could use ldm/stm loop...
+		if((i->reg&3) == 0) {
+			con(i->reg>>2, RA3, 1);
+			movloop(i, 4);
+		} else {
+			con(i->reg, RA3, 1);
+			movloop(i, 1);
+		}
+		break;
+	}
+}
+
+static
+void
+compdbg(void)
+{
+	print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comgoto(Inst *i)
+{
+	WORD *t, *e;
+
+	opwld(i, Ldw, RA1);
+	opwst(i, Lea, RA0);
+	LDRW(AL, RA0, R15, (2<<3), RA1);
+	flushcon(0);
+
+	if(pass == 0)
+		return;
+
+	t = (WORD*)(mod->origmp+i->d.ind);
+	e = t + t[-1];
+	t[-1] = 0;
+	while(t < e) {
+		t[0] = RELPC(patch[t[0]]);
+		t++;
+	}
+}
+
+static void
+comp(Inst *i)
+{
+	int r, imm;
+	char buf[64];
+//ulong *s = code;
+	if(0) {
+		Inst xx;
+		xx.add = AXIMM|SRC(AIMM);
+		xx.s.imm = (ulong)code;
+		xx.reg = i-mod->prog;
+		puntpc = 0;
+		punt(&xx, SRCOP, compdbg);
+		puntpc = 1;
+		flushcon(1);
+	}
+	flushchk();
+
+	switch(i->op) {
+	default:
+		snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+		error(buf);
+		break;
+	case IMCALL:
+		if((i->add&ARM) == AXIMM)
+			commcall(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case ISEND:
+	case IRECV:
+	case IALT:
+		punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+		break;
+	case ISPAWN:
+		punt(i, SRCOP|DBRAN, optab[i->op]);
+		break;
+	case IBNEC:
+	case IBEQC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+		punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+		break;
+	case ICASEC:
+		comcase(i, 0);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case ICASEL:
+		comcasel(i);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case IADDC:
+	case IMULL:
+	case IDIVL:
+	case IMODL:
+	case IMNEWZ:
+	case ILSRW:
+	case ILSRL:
+	case IMODW:
+	case IMODB:
+	case IDIVW:
+	case IDIVB:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ILOAD:
+	case INEWA:
+	case INEWAZ:
+	case INEW:
+	case INEWZ:
+	case ISLICEA:
+	case ISLICELA:
+	case ICONSB:
+	case ICONSW:
+	case ICONSL:
+	case ICONSF:
+	case ICONSM:
+	case ICONSMP:
+	case ICONSP:
+	case IMOVMP:
+	case IHEADMP:
+	case IHEADB:
+	case IHEADW:
+	case IHEADL:
+	case IINSC:
+	case ICVTAC:
+	case ICVTCW:
+	case ICVTWC:
+	case ICVTLC:
+	case ICVTCL:
+	case ICVTFC:
+	case ICVTCF:
+	case ICVTRF:
+	case ICVTFR:
+	case ICVTWS:
+	case ICVTSW:
+	case IMSPAWN:
+	case ICVTCA:
+	case ISLICEC:
+	case INBALT:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case INEWCM:
+	case INEWCMP:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IMFRAME:
+		if((i->add&ARM) == AXIMM)
+			commframe(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ICASE:
+		comcase(i, 1);
+		break;
+	case IGOTO:
+		comgoto(i);
+		break;
+	case IMOVF:
+		if(!SOFTFP){
+			opflld(i, Ldf, FA2);
+			opflst(i, Stf, FA2);
+			break;
+		}
+		/* if no hardware, just fall through */
+	case IMOVL:
+		opwld(i, Lea, RA1);
+		LDW(AL, RA1, RA2, 0);
+		LDW(AL, RA1, RA3, 4);
+		opwst(i, Lea, RA1);
+		STW(AL, RA1, RA2, 0);
+		STW(AL, RA1, RA3, 4);
+		break;
+		break;
+	case IHEADM:
+		opwld(i, Ldw, RA1);
+		NOTNIL(RA1);
+		if(OA(List,data) != 0)
+			DPI(AL, Add, RA1, RA1, 0, OA(List,data));
+		movmem(i);
+		break;
+/*
+	case IHEADW:
+		opwld(i, Ldw, RA0);
+		NOTNIL(RA0);
+		mem(Ldw, OA(List, data), RA0, RA0);
+		opwst(i, Stw, RA0);
+		break;
+*/
+	case IMOVM:
+		opwld(i, Lea, RA1);
+		movmem(i);
+		break;
+	case IFRAME:
+		if(UXSRC(i->add) != SRC(AIMM)) {
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		tinit[i->s.imm] = 1;
+		con((ulong)mod->type[i->s.imm], RA3, 1);
+		CALL(base+macro[MacFRAM]);
+		opwst(i, Stw, RA2);
+		break;
+	case INEWCB:
+	case INEWCW:
+	case INEWCF:
+	case INEWCP:
+	case INEWCL:
+		punt(i, DSTOP|THREOP, optab[i->op]);
+		break;
+	case IEXIT:
+		punt(i, 0, optab[i->op]);
+		break;
+	case ICVTBW:
+		opwld(i, Ldb, RA0);
+		opwst(i, Stw, RA0);
+		break;
+	case ICVTWB:
+		opwld(i, Ldw, RA0);
+		opwst(i, Stb, RA0);
+		break;
+	case ILEA:
+		opwld(i, Lea, RA0);
+		opwst(i, Stw, RA0);
+		break;
+	case IMOVW:
+		opwld(i, Ldw, RA0);
+		opwst(i, Stw, RA0);
+		break;
+	case IMOVB:
+		opwld(i, Ldb, RA0);
+		opwst(i, Stb, RA0);
+		break;
+	case ITAIL:
+		opwld(i, Ldw, RA0);
+		NOTNIL(RA0);
+		mem(Ldw, O(List, tail), RA0, RA1);
+		goto movp;
+	case IMOVP:
+		opwld(i, Ldw, RA1);
+		goto movp;
+	case IHEADP:
+		opwld(i, Ldw, RA0);
+		NOTNIL(RA0);
+		mem(Ldw, OA(List, data), RA0, RA1);
+	movp:
+		CMPH(AL, RA1);
+		CALLMAC(NE, MacCOLR);		// colour if not H
+		opwst(i, Lea, RA2);
+		mem(Ldw, 0,RA2, RA0);
+		mem(Stw, 0,RA2, RA1);
+		CALLMAC(AL, MacFRP);
+		break;
+	case ILENA:
+		opwld(i, Ldw, RA1);
+		con(0, RA0, 1);
+		CMPH(AL, RA1);
+		LDW(NE, RA1, RA0, O(Array,len));
+		opwst(i, Stw, RA0);
+		break;
+	case ILENC:
+		opwld(i, Ldw, RA1);
+		con(0, RA0, 1);
+		CMPH(AL, RA1);
+		memc(NE, Ldw, O(String,len),RA1, RA0);
+		CMPI(AL, RA0, 0, 0, 0);
+		DPI(LT, Rsb, RA0, RA0, 0, 0);
+		opwst(i, Stw, RA0);
+		break;
+	case ILENL:
+		con(0, RA0, 1);
+		opwld(i, Ldw, RA1);
+
+		CMPH(AL, RA1);
+		LDW(NE, RA1, RA1, O(List, tail));
+		DPI(NE, Add, RA0, RA0, 0, 1);
+		BRA(NE, (-4*3-8)>>2);
+
+		opwst(i, Stw, RA0);
+		break;
+	case ICALL:
+		opwld(i, Ldw, RA0);
+		con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+		mem(Stw, O(Frame, lr), RA0, RA1);
+		mem(Stw, O(Frame, fp), RA0, RFP);
+		MOV(RA0, RFP);
+		BRADIS(AL, i->d.ins-mod->prog);
+		flushcon(0);
+		break;
+	case IJMP:
+		if(RESCHED)
+			schedcheck(i);
+		BRADIS(AL, i->d.ins-mod->prog);
+		flushcon(0);
+		break;
+	case IBEQW:
+		cbra(i, EQ);
+		break;		
+	case IBNEW:
+		cbra(i, NE);
+		break;
+	case IBLTW:
+		cbra(i, LT);
+		break;
+	case IBLEW:
+		cbra(i, LE);
+		break;
+	case IBGTW:
+		cbra(i, GT);
+		break;
+	case IBGEW:
+		cbra(i, GE);
+		break;
+	case IBEQB:
+		cbrab(i, EQ);
+		break;
+	case IBNEB:
+		cbrab(i, NE);
+		break;
+	case IBLTB:
+		cbrab(i, LT);
+		break;
+	case IBLEB:
+		cbrab(i, LE);
+		break;
+	case IBGTB:
+		cbrab(i, GT);
+		break;
+	case IBGEB:
+		cbrab(i, GE);
+		break;
+	case IBEQF:
+		cbraf(i, EQ);
+		break;
+	case IBNEF:
+		cbraf(i, NE);
+		break;
+	case IBLTF:
+		cbraf(i, LT);
+		break;
+	case IBLEF:
+		cbraf(i, LE);
+		break;
+	case IBGTF:
+		cbraf(i, GT);
+		break;
+	case IBGEF:
+		cbraf(i, GE);
+		break;
+	case IRET:
+		mem(Ldw, O(Frame,t), RFP, RA1);
+		BRAMAC(AL, MacRET);
+		break;
+	case IMULW:
+		opwld(i, Ldw, RA1);
+		mid(i, Ldw, RA0);
+		MUL(AL, RA1, RA0, RA0);
+		opwst(i, Stw, RA0);
+		break;
+	case IMULB:
+		opwld(i, Ldb, RA1);
+		mid(i, Ldb, RA0);
+		MUL(AL, RA1, RA0, RA0);
+		opwst(i, Stb, RA0);
+		break;
+	case IORW:
+		r = Orr;
+		goto arithw;
+	case IANDW:
+		r = And;
+		goto arithw;
+	case IXORW:
+		r = Eor;
+		goto arithw;
+	case ISUBW:
+		r = Sub;
+		goto arithw;
+	case IADDW:
+		r = Add;
+	arithw:
+		mid(i, Ldw, RA1);
+		if(UXSRC(i->add) == SRC(AIMM) && FITS8(i->s.imm))
+			DPI(AL, r, RA1, RA0, 0, i->s.imm);
+		else if(UXSRC(i->add) == SRC(AIMM) && immrot(i->s.imm)){
+			DPI(AL, r, RA1, RA0, 0, 0) | immrot(i->s.imm);
+			//print("rot: %ux %ux\n", i->s.imm, immrot(i->s.imm)); das(code-1, 1);
+		} else {
+			opwld(i, Ldw, RA0);
+			DP(AL, r, RA1, RA0, 0, RA0);
+		}
+		opwst(i, Stw, RA0);
+		break;
+	case ISHRW:
+		r = 2;
+	shiftw:
+		mid(i, Ldw, RA1);
+		if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
+			DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
+		else {
+			opwld(i, Ldw, RA0);
+			DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
+		}
+		opwst(i, Stw, RA0);
+		break;
+	case ISHLW:
+		r = 0;
+		goto shiftw;
+		break;
+	case IORB:
+		r = Orr;
+		goto arithb;
+	case IANDB:
+		r = And;
+		goto arithb;
+	case IXORB:
+		r = Eor;
+		goto arithb;
+	case ISUBB:
+		r = Sub;
+		goto arithb;
+	case IADDB:
+		r = Add;
+	arithb:
+		mid(i, Ldb, RA1);
+		if(UXSRC(i->add) == SRC(AIMM))
+			DPI(AL, r, RA1, RA0, 0, i->s.imm);
+		else {
+			opwld(i, Ldb, RA0);
+			DP(AL, r, RA1, RA0, 0, RA0);
+		}
+		opwst(i, Stb, RA0);
+		break;
+	case ISHRB:
+		r = 2;
+		goto shiftb;
+	case ISHLB:
+		r = 0;
+	shiftb:
+		mid(i, Ldb, RA1);
+		if(UXSRC(i->add) == SRC(AIMM) && FITS5(i->s.imm))
+			DP(AL, Mov, 0, RA0, ((i->s.imm&0x3F)<<3)|(r<<1), RA1);
+		else {
+			opwld(i, Ldw, RA0);
+			DP(AL, Mov, 0, RA0, (RA0<<4)|(r<<1)|1, RA1);
+		}
+		opwst(i, Stb, RA0);
+		break;
+	case IINDC:
+		opwld(i, Ldw, RA1);			// RA1 = string
+		NOTNIL(RA1);
+		imm = 1;
+		if((i->add&ARM) != AXIMM || !FITS12((short)i->reg<<Lg2Rune) || immrot((short)i->reg) == 0){
+			mid(i, Ldw, RA2);			// RA2 = i
+			imm = 0;
+		}
+		mem(Ldw, O(String,len),RA1, RA0);	// len<0 => index Runes, otherwise bytes
+		if(bflag){
+			DPI(AL, Orr, RA0, RA3, 0, 0);
+			DPI(LT, Rsb, RA3, RA3, 0, 0);
+			if(imm)
+				BCKR(immrot((short)i->reg), RA3);
+			else
+				BCK(RA2, RA3);
+		}
+		DPI(AL, Add, RA1, RA1, 0, O(String,data));
+		CMPI(AL, RA0, 0, 0, 0);
+		if(imm){
+			LDB(GE, RA1, RA3, i->reg);
+			LDW(LT, RA1, RA3, (short)i->reg<<Lg2Rune);
+		} else {
+			LDRB(GE, RA1, RA3, 0, RA2);
+			DP(LT, Mov, 0, RA2, (Lg2Rune<<3), RA2);
+			LDRW(LT, RA1, RA3, 0, RA2);
+		}
+		opwst(i, Stw, RA3);
+//if(pass){print("%D\n", i); das(s, code-s);}
+		break;
+	case IINDL:
+	case IINDF:
+	case IINDW:
+	case IINDB:
+		opwld(i, Ldw, RA0);			/* a */
+		NOTNIL(RA0);
+		if(bflag)
+			mem(Ldw, O(Array, len), RA0, RA2);
+		mem(Ldw, O(Array, data), RA0, RA0);
+		r = 0;
+		switch(i->op) {
+		case IINDL:
+		case IINDF:
+			r = 3;
+			break;
+		case IINDW:
+			r = 2;
+			break;
+		}
+		if(UXDST(i->add) == DST(AIMM) && (imm = immrot(i->d.imm)) != 0) {
+			if(bflag)
+				BCKR(imm, RA2);
+			if(i->d.imm != 0)
+				DPI(AL, Add, RA0, RA0, 0, 0) | immrot(i->d.imm<<r);
+		} else {
+			opwst(i, Ldw, RA1);
+			if(bflag)
+				BCK(RA1, RA2);
+			DP(AL, Add, RA0, RA0, r<<3, RA1);
+		}
+		mid(i, Stw, RA0);
+//if(pass){print("%D\n", i); das(s, code-s);}
+		break;
+	case IINDX:
+		opwld(i, Ldw, RA0);			/* a */
+		NOTNIL(RA0);
+		opwst(i, Ldw, RA1);			/* i */
+
+		if(bflag){
+			mem(Ldw, O(Array, len), RA0, RA2);
+			BCK(RA1, RA2);
+		}
+		mem(Ldw, O(Array, t), RA0, RA2);
+		mem(Ldw, O(Array, data), RA0, RA0);
+		mem(Ldw, O(Type, size), RA2, RA2);
+		MUL(AL, RA2, RA1, RA1);
+		DP(AL, Add, RA1, RA0, 0, RA0);
+		mid(i, Stw, RA0);
+//if(pass){print("%D\n", i); das(s, code-s);}
+		break;
+	case IADDL:
+		larith(i, Add, Adc);
+		break;
+	case ISUBL:
+		larith(i, Sub, Sbc);
+		break;
+	case IORL:
+		larith(i, Orr, Orr);
+		break;
+	case IANDL:
+		larith(i, And, And);
+		break;
+	case IXORL:
+		larith(i, Eor, Eor);
+		break;
+	case ICVTWL:
+		opwld(i, Ldw, RA1);
+		opwst(i, Lea, RA2);
+		DP(AL, Mov, 0, RA0, (0<<3)|(2<<1), RA1);	// ASR 32
+		STW(AL, RA2, RA1, Blo);
+		STW(AL, RA2, RA0, Bhi);
+		break;
+	case ICVTLW:
+		opwld(i, Lea, RA0);
+		mem(Ldw, Blo, RA0, RA0);
+		opwst(i, Stw, RA0);
+		break;
+	case IBEQL:
+		cbral(i, NE, EQ, ANDAND);
+		break;
+	case IBNEL:
+		cbral(i, NE, NE, OROR);
+		break;
+	case IBLEL:
+		cbral(i, LT, LS, EQAND);
+		break;
+	case IBGTL:
+		cbral(i, GT, HI, EQAND);
+		break;
+	case IBLTL:
+		cbral(i, LT, CC, EQAND);
+		break;
+	case IBGEL:
+		cbral(i, GT, CS, EQAND);
+		break;
+	case ICVTFL:
+	case ICVTLF:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case IDIVF:
+		r = Dvf;
+		goto arithf;
+	case IMULF:
+		r = Muf;
+		goto arithf;
+	case ISUBF:
+		r = Suf;
+		goto arithf;
+	case IADDF:
+		r = Adf;
+	arithf:
+		if(SOFTFP){
+			/* software fp */
+			USED(r);
+			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+			break;
+		}
+		opflld(i, Ldf, FA2);
+		midfl(i, Ldf, FA4);
+		CPDO2(AL, r, FA4, FA4, FA2);
+		opflst(i, Stf, FA4);
+		break;
+	case INEGF:
+		if(SOFTFP){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opflld(i, Ldf, FA2);
+		CPDO1(AL, Mnf, FA2, FA2);
+		opflst(i, Stf, FA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+		break;
+	case ICVTWF:
+		if(SOFTFP){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opwld(i, Ldw, RA2);
+		CPFLT(AL, FA2, RA2);
+		opflst(i, Stf, FA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+		break;
+	case ICVTFW:
+		if(SOFTFP){
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		opflld(i, Ldf, FA2);
+		CPFIX(AL, RA2, FA2);
+		opwst(i, Stw, RA2);
+//if(pass){print("%D\n", i); das(s, code-s);}
+		break;
+	case ISHLL:
+		/* should do better */
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ISHRL:
+		/* should do better */
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IRAISE:
+		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case IMULX:
+	case IDIVX:
+	case ICVTXX:
+	case IMULX0:
+	case IDIVX0:
+	case ICVTXX0:
+	case IMULX1:
+	case IDIVX1:
+	case ICVTXX1:
+	case ICVTFX:
+	case ICVTXF:
+	case IEXPW:
+	case IEXPL:
+	case IEXPF:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ISELF:
+		punt(i, DSTOP, optab[i->op]);
+		break;
+	}
+}
+
+static void
+preamble(void)
+{
+	if(comvec)
+		return;
+
+	comvec = malloc(10 * sizeof(*code));
+	if(comvec == nil)
+		error(exNomem);
+	code = (ulong*)comvec;
+
+	con((ulong)&R, RREG, 0);
+	mem(Stw, O(REG, xpc), RREG, RLINK);
+	mem(Ldw, O(REG, FP), RREG, RFP);
+	mem(Ldw, O(REG, MP), RREG, RMP);
+	mem(Ldw, O(REG, PC), RREG, R15);
+	pass++;
+	flushcon(0);
+	pass--;
+
+	segflush(comvec, 10 * sizeof(*code));
+}
+
+static void
+maccase(void)
+{
+	ulong *cp1, *loop, *inner;
+/*
+ * RA1 = value (input arg), t
+ * RA2 = count, n
+ * RA3 = table pointer (input arg)
+ * RA0  = n/2, n2
+ * RCON  = pivot element t+n/2*3, l
+ */
+	LDW(AL, RA3, RA2, 0);	// count from table
+	MOV(RA3, RLINK);	// initial table pointer
+
+	loop = code;			// loop:
+	CMPI(AL, RA2, 0, 0, 0);
+	cp1 = code;
+	BRA(LE, 0);	// n <= 0? goto out
+
+	inner = code;
+	DP(AL, Mov, 0, RA0, (1<<3)|2, RA2);	// n2 = n>>1
+	DP(AL, Add, RA0, RCON, (1<<3), RA0);	// n' = n2+(n2<<1) = 3*n2
+	DP(AL, Add, RA3, RCON, (2<<3), RCON);	// l = t + n2*3;
+
+	LDW(AL, RCON, RTA, 4);
+	CMP(AL, RA1, 0, 0, RTA);
+	DP(LT, Mov, 0, RA2, 0, RA0);	// v < l[1]? n=n2
+	BRANCH(LT, loop);	// v < l[1]? goto loop
+
+	LDW(AL, RCON, RTA, 8);
+	CMP(AL, RA1, 0, 0, RTA);
+	LDW(LT, RCON, R15, 12);	// v >= l[1] && v < l[2] => found; goto l[3]
+
+	// v >= l[2] (high)
+	DPI(AL, Add, RCON, RA3, 0, 12);	// t = l+3;
+	DPI(AL, Add, RA0, RTA, 0, 1);
+	DP(AL, Sub, RA2, RA2, 0, RTA) | SBIT;	// n -= n2+1
+	BRANCH(GT, inner);	// n > 0? goto loop
+
+	PATCH(cp1);	// out:
+	LDW(AL, RLINK, RA2, 0);		// initial n
+	DP(AL, Add, RA2, RA2, (1<<3), RA2);	// n = n+(n<<1) = 3*n
+	DP(AL, Add, RLINK, RLINK, (2<<3), RA2);	// t' = &(initial t)[n*3]
+	LDW(AL, RLINK, R15, 4);		// goto (initial t)[n*3+1]
+}
+
+static void
+macfrp(void)
+{
+	/* destroy the pointer in RA0 */
+	CMPH(AL, RA0);
+	CRETURN(EQ);		// arg == H? => return
+
+	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+	DPI(AL, Sub, RA2, RA2, 0, 1) | SBIT;
+	memc(NE, Stw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+	CRETURN(NE);		// --h->ref != 0 => return
+
+	mem(Stw, O(REG, FP), RREG, RFP);
+	mem(Stw, O(REG, st), RREG, RLINK);
+	mem(Stw, O(REG, s), RREG, RA0);
+	CALL(rdestroy);
+	con((ulong)&R, RREG, 1);
+	mem(Ldw, O(REG, st), RREG, RLINK);
+	mem(Ldw, O(REG, FP), RREG, RFP);
+	mem(Ldw, O(REG, MP), RREG, RMP);
+	RETURN;
+	flushcon(0);
+}
+
+static void
+maccolr(void)
+{
+	/* color the pointer in RA1 */
+	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+	DPI(AL, Add, RA0, RA0, 0, 1);
+	mem(Stw, O(Heap, ref)-sizeof(Heap), RA1, RA0);	// h->ref++
+	con((ulong)&mutator, RA2, 1);
+	mem(Ldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+	mem(Ldw, 0, RA2, RA2);
+	CMP(AL, RA0, 0, 0, RA2);
+	CRETURN(EQ);	// return if h->color == mutator
+	con(propagator, RA2, 1);
+	mem(Stw, O(Heap, color)-sizeof(Heap), RA1, RA2);	// h->color = propagator
+	con((ulong)&nprop, RA2, 1);
+	mem(Stw, 0, RA2, RA2);	// nprop = !0
+	RETURN;
+	flushcon(0);
+}
+
+static void
+macret(void)
+{
+	Inst i;
+	ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+
+	CMPI(AL, RA1, 0, 0, 0);
+	cp1 = code;
+	BRA(EQ, 0);				// t(Rfp) == 0
+
+	mem(Ldw, O(Type,destroy),RA1, RA0);
+	CMPI(AL, RA0, 0, 0, 0);
+	cp2 = code;
+	BRA(EQ, 0);				// destroy(t(fp)) == 0
+
+	mem(Ldw, O(Frame,fp),RFP, RA2);
+	CMPI(AL, RA2, 0, 0, 0);
+	cp3 = code;
+	BRA(EQ, 0);				// fp(Rfp) == 0
+
+	mem(Ldw, O(Frame,mr),RFP, RA3);
+	CMPI(AL, RA3, 0, 0, 0);
+	cp4 = code;
+	BRA(EQ, 0);				// mr(Rfp) == 0
+
+	mem(Ldw, O(REG,M),RREG, RA2);
+	mem(Ldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+	DPI(AL, Sub, RA3, RA3, 0, 1) | SBIT;
+	cp5 = code;
+	BRA(EQ, 0);				// --ref(arg) == 0
+	mem(Stw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+
+	mem(Ldw, O(Frame,mr),RFP, RA1);
+	mem(Stw, O(REG,M),RREG, RA1);
+	mem(Ldw, O(Modlink,MP),RA1, RMP);
+	mem(Stw, O(REG,MP),RREG, RMP);
+	mem(Ldw, O(Modlink,compiled), RA1, RA3);	// R.M->compiled
+	CMPI(AL, RA3, 0, 0, 0);
+	linterp = code;
+	BRA(EQ, 0);
+
+	PATCH(cp4);
+	MOV(R15, R14);		// call destroy(t(fp))
+	MOV(RA0, R15);
+
+	mem(Stw, O(REG,SP),RREG, RFP);
+	mem(Ldw, O(Frame,lr),RFP, RA1);
+	mem(Ldw, O(Frame,fp),RFP, RFP);
+	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
+	DP(AL, Mov, 0, R15, 0, RA1);		// goto lr(Rfp), if compiled
+
+	PATCH(linterp);
+	MOV(R15, R14);		// call destroy(t(fp))
+	MOV(RA0, R15);
+
+	mem(Stw, O(REG,SP),RREG, RFP);
+	mem(Ldw, O(Frame,lr),RFP, RA1);
+	mem(Ldw, O(Frame,fp),RFP, RFP);
+	mem(Stw, O(REG,PC),RREG, RA1);	// R.PC = fp->lr
+	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
+	mem(Ldw, O(REG, xpc), RREG, RLINK);
+	RETURN;		// return to xec uncompiled code
+
+	PATCH(cp1);
+	PATCH(cp2);
+	PATCH(cp3);
+	PATCH(cp5);
+	i.add = AXNON;
+	punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+macmcal(void)
+{
+	ulong *lab;
+
+	CMPH(AL, RA0);
+	memc(NE, Ldw, O(Modlink, prog), RA3, RA1);	// RA0 != H
+	CMPI(NE, RA1, 0, 0, 0);	// RA0 != H
+	lab = code;
+	BRA(NE, 0);	// RA0 != H && m->prog!=0
+
+	mem(Stw, O(REG, st), RREG, RLINK);
+	mem(Stw, O(REG, FP), RREG, RA2);
+	mem(Stw, O(REG, dt), RREG, RA0);
+	CALL(rmcall);				// CALL rmcall
+
+	con((ulong)&R, RREG, 1);		// MOVL	$R, RREG
+	mem(Ldw, O(REG, st), RREG, RLINK);
+	mem(Ldw, O(REG, FP), RREG, RFP);
+	mem(Ldw, O(REG, MP), RREG, RMP);
+	RETURN;
+
+	PATCH(lab);				// patch:
+	DP(AL, Mov, 0, RFP, 0, RA2);
+	mem(Stw, O(REG, M), RREG, RA3);	// MOVL RA3, R.M
+	mem(Ldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+	DPI(AL, Add, RA1, RA1, 0, 1);
+	mem(Stw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+	mem(Ldw, O(Modlink, MP), RA3, RMP);	// MOVL R.M->mp, RMP
+	mem(Stw, O(REG, MP), RREG, RMP);	// MOVL RA3, R.MP	R.MP = ml->m
+	mem(Ldw, O(Modlink,compiled), RA3, RA1);	// M.compiled?
+	CMPI(AL, RA1, 0, 0, 0);
+	DP(NE, Mov, 0, R15, 0, RA0);	// return to compiled code
+	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
+	mem(Stw, O(REG,PC),RREG, RA0);	// R.PC = RPC
+	mem(Ldw, O(REG, xpc), RREG, RLINK);
+	RETURN;		// return to xec uncompiled code
+	flushcon(0);
+}
+
+static void
+macfram(void)
+{
+	ulong *lab1;
+
+	mem(Ldw, O(REG, SP), RREG, RA0);	// MOVL	R.SP, RA0
+	mem(Ldw, O(Type, size), RA3, RA1);
+	DP(AL, Add, RA0, RA0, 0, RA1);		// nsp = R.SP + t->size
+	mem(Ldw, O(REG, TS), RREG, RA1);
+	CMP(AL, RA0, 0, 0, RA1);	// nsp :: R.TS
+	lab1 = code;
+	BRA(CS, 0);	// nsp >= R.TS; must expand
+
+	mem(Ldw, O(REG, SP), RREG, RA2);	// MOVL	R.SP, RA2
+	mem(Stw, O(REG, SP), RREG, RA0);	// MOVL	RA0, R.SP
+
+	mem(Stw, O(Frame, t), RA2, RA3);	// MOVL	RA3, t(RA2) f->t = t
+	con(0, RA0, 1);
+	mem(Stw, O(Frame,mr), RA2, RA0);     	// MOVL $0, mr(RA2) f->mr
+	mem(Ldw, O(Type, initialize), RA3, R15);	// become t->init(RA2), returning RA2
+
+	PATCH(lab1);
+	mem(Stw, O(REG, s), RREG, RA3);
+	mem(Stw, O(REG, st), RREG, RLINK);
+	mem(Stw, O(REG, FP), RREG, RFP);	// MOVL	RFP, R.FP
+	CALL(extend);				// CALL	extend
+
+	con((ulong)&R, RREG, 1);
+	mem(Ldw, O(REG, st), RREG, RLINK);
+	mem(Ldw, O(REG, FP), RREG, RFP);	// MOVL	R.FP, RFP
+	mem(Ldw, O(REG, s), RREG, RA2);	// MOVL	R.s, *R.d
+	mem(Ldw, O(REG, MP), RREG, RMP);	// MOVL R.MP, RMP
+	RETURN;					// RET
+}
+
+static void
+macmfra(void)
+{
+	mem(Stw, O(REG, st), RREG, RLINK);
+	mem(Stw, O(REG, s), RREG, RA3);	// Save type
+	mem(Stw, O(REG, d), RREG, RA0);	// Save destination
+	mem(Stw, O(REG, FP), RREG, RFP);
+	CALL(rmfram);				// CALL rmfram
+
+	con((ulong)&R, RREG, 1);
+	mem(Ldw, O(REG, st), RREG, RLINK);
+	mem(Ldw, O(REG, FP), RREG, RFP);
+	mem(Ldw, O(REG, MP), RREG, RMP);
+	RETURN;
+}
+
+static void
+macrelq(void)
+{
+	mem(Stw, O(REG,FP),RREG, RFP);	// R.FP = RFP
+	mem(Stw, O(REG,PC),RREG, RLINK);	// R.PC = RLINK
+	mem(Ldw, O(REG, xpc), RREG, RLINK);
+	RETURN;
+}
+
+void
+comd(Type *t)
+{
+	int i, j, m, c;
+
+	mem(Stw, O(REG, dt), RREG, RLINK);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m) {
+				mem(Ldw, j, RFP, RA0);
+				CALL(base+macro[MacFRP]);
+			}
+			j += sizeof(WORD*);
+		}
+		flushchk();
+	}
+	mem(Ldw, O(REG, dt), RREG, RLINK);
+	RETURN;
+	flushcon(0);
+}
+
+void
+comi(Type *t)
+{
+	int i, j, m, c;
+
+	con((ulong)H, RA0, 1);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m)
+				mem(Stw, j, RA2, RA0);
+			j += sizeof(WORD*);
+		}
+		flushchk();
+	}
+	RETURN;
+	flushcon(0);
+}
+
+void
+typecom(Type *t)
+{
+	int n;
+	ulong *tmp, *start;
+
+	if(t == nil || t->initialize != 0)
+		return;
+
+	tmp = mallocz(4096*sizeof(ulong), 0);
+	if(tmp == nil)
+		error(exNomem);
+
+	code = tmp;
+	comi(t);
+	n = code - tmp;
+	code = tmp;
+	comd(t);
+	n += code - tmp;
+	free(tmp);
+
+	n *= sizeof(*code);
+	code = mallocz(n, 0);
+	if(code == nil)
+		return;
+
+	start = code;
+	t->initialize = code;
+	comi(t);
+	t->destroy = code;
+	comd(t);
+
+	segflush(start, n);
+
+	if(cflag > 3)
+		print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+			t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+	Handler *h;
+	Except *e;
+
+	if((h = m->htab) == nil)
+		return;
+	for( ; h->etab != nil; h++){
+		h->pc1 = p[h->pc1];
+		h->pc2 = p[h->pc2];
+		for(e = h->etab; e->s != nil; e++)
+			e->pc = p[e->pc];
+		if(e->pc != -1)
+			e->pc = p[e->pc];
+	}
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+	Link *l;
+	Modl *e;
+	int i, n;
+	ulong *s, *tmp;
+
+	base = nil;
+	patch = mallocz(size*sizeof(*patch), 0);
+	tinit = malloc(m->ntype*sizeof(*tinit));
+	tmp = malloc(4096*sizeof(ulong));
+	if(tinit == nil || patch == nil || tmp == nil)
+		goto bad;
+
+	preamble();
+
+	mod = m;
+	n = 0;
+	pass = 0;
+	nlit = 0;
+
+	for(i = 0; i < size; i++) {
+		codeoff = n;
+		code = tmp;
+		comp(&m->prog[i]);
+		patch[i] = n;
+		n += code - tmp;
+	}
+
+	for(i = 0; i < nelem(mactab); i++) {
+		codeoff = n;
+		code = tmp;
+		mactab[i].gen();
+		macro[mactab[i].idx] = n;
+		n += code - tmp;
+	}
+	code = tmp;
+	flushcon(0);
+	n += code - tmp;
+
+	base = mallocz((n+nlit)*sizeof(*code), 0);
+	if(base == nil)
+		goto bad;
+
+	if(cflag > 3)
+		print("dis=%5d %5d 386=%5d asm=%.8p: %s\n",
+			size, size*sizeof(Inst), n, base, m->name);
+
+	pass++;
+	nlit = 0;
+	litpool = base+n;
+	code = base;
+	n = 0;
+	codeoff = 0;
+	for(i = 0; i < size; i++) {
+		s = code;
+		comp(&m->prog[i]);
+		if(patch[i] != n) {
+			print("%3d %D\n", i, &m->prog[i]);
+			print("%lud != %d\n", patch[i], n);
+			urk("phase error");
+		}
+		n += code - s;
+		if(cflag > 4) {
+			print("%3d %D\n", i, &m->prog[i]);
+			das(s, code-s);
+		}
+	}
+
+	for(i = 0; i < nelem(mactab); i++) {
+		s = code;
+		mactab[i].gen();
+		if(macro[mactab[i].idx] != n){
+			print("mac phase err: %lud != %d\n", macro[mactab[i].idx], n);
+			urk("phase error");
+		}
+		n += code - s;
+		if(cflag > 4) {
+			print("%s:\n", mactab[i].name);
+			das(s, code-s);
+		}
+	}
+	s = code;
+	flushcon(0);
+	n += code - s;
+
+	for(l = m->ext; l->name; l++) {
+		l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+		typecom(l->frame);
+	}
+	if(ml != nil) {
+		e = &ml->links[0];
+		for(i = 0; i < ml->nlinks; i++) {
+			e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+			typecom(e->frame);
+			e++;
+		}
+	}
+	for(i = 0; i < m->ntype; i++) {
+		if(tinit[i] != 0)
+			typecom(m->type[i]);
+	}
+	patchex(m, patch);
+	m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(m->prog);
+	m->prog = (Inst*)base;
+	m->compiled = 1;
+	segflush(base, n*sizeof(*base));
+	return 1;
+bad:
+	free(patch);
+	free(tinit);
+	free(base);
+	free(tmp);
+	return 0;
+}
--- /dev/null
+++ b/libinterp/comp-mips.c
@@ -1,0 +1,1962 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+#define T(r)	*((void**)(R.r))
+
+#define	SRR(op,c,r1,r2)		gen((op)|((c)<<6)|((r1)<<16)|((r2)<<11))
+#define	RRR(op,r1,r2,r3)	gen((op)|((r1)<<16)|((r2)<<21)|((r3)<<11))
+#define	FRRR(op,r1,r2,r3)	gen((op)|((r1)<<16)|((r2)<<11)|((r3)<<6))
+#define	FI(op,c)		gen((op)|((c)&0xffff))
+#define	IRR(op,c,r1,r2)		gen((op)|((c)&0xffff)|((r1)<<21)|((r2)<<16))
+#define	BRRI(op,r1,r2,c)	gen((op)|((r1)<<21)|((r2)<<16)|((c)&0xffff))
+#define	BRI(op,r,c)		gen((op)|((r)<<21)|((c)&0xffff))
+#define	JR(op,r)		gen((op)|((r)<<21))
+#define	J(op,c)			gen((op)|(((ulong)(c)>>2)&0x3FFFFFFUL))
+
+#ifndef HIOFFSET
+#define	HIOFFSET	0	/* big endian */
+#endif
+
+enum
+{
+	Rzero	= 0,
+
+	Ro1	= 8,
+	Ro2	= 9,
+	Ro3	= 10,
+	Ri	= 11,
+	Rj	= 12,
+
+	Rmp	= 13,
+	Rfp	= 14,
+	Rreg	= 15,
+
+	Rpic	= 25,
+	Rlink	= 31,
+
+	Rf1	= 4,
+	Rf2	= 6,
+
+	Olw	= 0x23<<26,
+	Olbu	= 0x24<<26,
+	Olhu	= 0x25<<26,
+	Osw	= 0x2b<<26,
+	Osb	= 0x28<<26,
+	Oaddui	= 0x09<<26,
+	Olui	= 0x0f<<26,
+	Oori	= 0x0d<<26,
+	Odiv	= (0x00<<26) | 0x1a,
+	Omul	= (0x00<<26) | 0x18,
+	Omfhi	= (0x00<<26) | 0x10,
+	Omflo	= (0x00<<26) | 0x12,
+	Osubu	= (0x00<<26) | 0x23,
+	Oaddu	= (0x00<<26) | 0x21,
+	Oand	= (0x00<<26) | 0x24,
+	Oor	= (0x00<<26) | 0x25,
+	Oxor	= (0x00<<26) | 0x26,
+	Odelay	= (0x00<<26) | 0x27,
+	Osll	= (0x00<<26) | 0x00,
+	Osrl	= (0x00<<26) | 0x02,
+	Osra	= (0x00<<26) | 0x03,
+	Osllv	= (0x00<<26) | 0x04,
+	Osrlv	= (0x00<<26) | 0x06,
+	Osrav	= (0x00<<26) | 0x07,
+	Oslt	= (0x00<<26) | 0x2a,
+	Osltu	= (0x00<<26) | 0x2b,
+	Obeq	= 0x04<<26,
+	Obne	= 0x05<<26,
+	Obltz	= (0x01<<26) | (0x0<<16),
+	Obgtz	= (0x07<<26) | (0x0<<16),
+	Oblez	= (0x06<<26) | (0x0<<16),
+	Obgez	= (0x01<<26) | (0x1<<16),
+	Ojr	= (0x00<<26) | 0x08,
+	Ojalr	= (0x00<<26) | 0x09 | (Rlink<<11),
+	Oj	= (0x02<<26),
+	Ojal	= (0x03<<26),
+	Olea	= Oaddui,		// pseudo op
+
+	Olf	= 0x31<<26,
+	Osf	= 0x39<<26,
+	Oaddf	= (0x11<<26) | (17<<21) | 0,
+	Osubf	= (0x11<<26) | (17<<21) | 1,
+	Omulf	= (0x11<<26) | (17<<21) | 2,
+	Odivf	= (0x11<<26) | (17<<21) | 3,
+	Onegf	= (0x11<<26) | (17<<21) | 7,
+
+	Ocvtwf	= (0x11<<26) | (20<<21) | 33,
+	Ocvtfw	= (0x11<<26) | (17<<21) | 36,
+
+	Ofeq	= (0x11<<26) | (17<<21) | (3<<4) | 2,
+	Oflt	= (0x11<<26) | (17<<21) | (3<<4) | 12,
+
+	Obrf	= (0x11<<26) | (0x100<<16),
+	Obrt	= (0x11<<26) | (0x101<<16),
+
+	SRCOP	= (1<<0),
+	DSTOP	= (1<<1),
+	WRTPC	= (1<<2),
+	TCHECK	= (1<<3),
+	NEWPC	= (1<<4),
+	DBRAN	= (1<<5),
+	THREOP	= (1<<6),
+
+	ANDAND	= 1,
+	OROR,
+	EQAND,
+
+	XOR,
+	IOR,
+	AND,
+	ADD,
+	SUB,
+
+	OMASK	= (1<<4) - 1,
+	REV1	= 1<<4,
+	REV2	= 1<<5,
+
+	Bhi		= HIOFFSET,
+	Blo		= Bhi ^ 4,
+
+	MacRET	= 0,
+	MacFRP,
+	MacINDX,
+	MacCASE,
+	MacLENA,
+	MacFRAM,
+	MacMOVM,
+	MacCOLR,
+	MacMCAL,
+	MacMFRA,
+	MacEND,
+	NMACRO
+};
+
+extern	char	Tmodule[];
+	void	(*comvec)(void);
+extern	void	das(ulong*);
+static	ulong*	code;
+static	ulong*	base;
+static	ulong*	patch;
+static	int	pass;
+static	int	regdelay;
+static	Module*	mod;
+static	ulong*	tinit;
+static	ulong*	litpool;
+static	int	nlit;
+static	ulong	macro[NMACRO];
+static	void	rdestroy(void);
+static	void	macret(void);
+static	void	macfrp(void);
+static	void	macindx(void);
+static	void	maccase(void);
+static	void	maclena(void);
+static	void	macfram(void);
+static	void	macmovm(void);
+static	void	maccvtfw(void);
+static	void	maccolr(void);
+static	void	macend(void);
+static	void	macmcal(void);
+static	void	macmfra(void);
+
+struct
+{
+	int	o;
+	void	(*f)(void);
+} macinit[] =
+{
+	MacFRP,		macfrp,		/* decrement and free pointer */
+	MacRET,		macret,		/* return instruction */
+	MacCASE,	maccase,	/* case instruction */
+	MacCOLR,	maccolr,	/* increment and color pointer */
+	MacFRAM,	macfram,	/* frame instruction */
+	MacMCAL,	macmcal,	/* mcall bottom half */
+	MacMFRA,	macmfra,	/* punt mframe because t->initialize==0 */
+	MacMOVM,	macmovm,
+	MacLENA,	maclena,
+	MacINDX,	macindx,
+	MacEND,		macend,
+	0
+};
+
+static void
+rdestroy(void)
+{
+	destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+	Prog *p;
+	Frame *f;
+
+	f = (Frame*)R.FP;
+	if(f == H)
+		error(exModule);
+
+	f->mr = nil;
+	((void(*)(Frame*))R.dt)(f);
+	R.SP = (uchar*)f;
+	R.FP = f->fp;
+	if(f->t == nil)
+		unextend(f);
+	else
+		freeptrs(f, f->t);
+	p = currun();
+	if(p->kill != nil)
+		error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+
+	t = (Type*)R.s;
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP = nsp;
+	f->t = t;
+	f->mr = nil;
+	initmem(t, f);
+	T(d) = f;
+}
+
+void
+urk(char *s)
+{
+	print("urk: %s\n", s);
+	exits(0);
+}
+
+void
+gen(ulong o)
+{
+	*code++ = o;
+}
+
+void
+delay(void)
+{
+	gen(Odelay);
+}
+
+int
+bigc(long c)
+{
+	c >>= 15;
+	if(c == 0 || c == -1)
+		return 0;
+	return 1;
+}
+
+void
+ldbigc(ulong c, int reg)
+{
+	IRR(Olui, c>>16,Rzero,reg);
+	IRR(Oori, c,reg,reg);
+}
+
+void
+ldc(ulong c, int reg)
+{
+
+	if(bigc(c))
+		ldbigc(c, reg);
+	else
+		IRR(Oaddui, c,Rzero, reg);
+}
+
+void
+xchg(void)
+{
+	ulong t;
+
+	t = code[-1];
+	code[-1] = code[-2];
+	code[-2] = t;
+}
+
+void
+opx(int mode, Adr *a, int op, int reg, int del)
+{
+	ulong c;
+	int r, rx;
+
+	switch(mode) {
+	case AFP:
+		c = a->ind;
+		if(bigc(c))
+			urk("bigc op1b 1");
+		if(regdelay == Rfp)
+			delay();
+		IRR(op, c,Rfp, reg);
+		break;
+	case AMP:
+		c = a->ind;
+		if(bigc(c))
+			urk("bigc op1b 2");
+		if(regdelay == Rmp)
+			delay();
+		IRR(op, c,Rmp, reg);
+		break;
+	case AIMM:
+		if(op == Olea) {
+			if(a->imm != 0) {
+				ldc(a->imm, reg);
+				IRR(Osw, O(REG,st),Rreg, reg);
+			} else
+				IRR(Osw, O(REG,st),Rreg, Rzero);
+			IRR(Oaddui, O(REG,st),Rreg, reg);
+		} else
+			ldc(a->imm, reg);
+		return;
+	case AIND|AFP:
+		r = Rfp;
+		goto offset;
+	case AIND|AMP:
+		r = Rmp;
+	offset:
+		if(regdelay == r)
+			delay();
+		c = a->i.s;
+		rx = Ri;
+		if(op == Olea || op == Olw)
+			rx = reg;
+		IRR(Olw, a->i.f,r, rx);
+		if(c != 0 || op != Oaddui) {
+			delay();
+			IRR(op, c,rx, reg);
+		}
+		break;
+	}
+	if(op != Olea && del)
+		delay();
+	regdelay = 0;
+}
+
+void
+op1(Inst *i, int op, int reg, int del)
+{
+	opx(USRC(i->add), &i->s, op, reg, del);
+}
+
+void
+op3(Inst *i, int op, int reg, int del)
+{
+	opx(UDST(i->add), &i->d, op, reg, del);
+}
+
+void
+op2(Inst *i, int op, int reg, int del)
+{
+	switch(i->add & ARM) {
+	case AXNON:
+		op3(i, op, reg, del);
+		return;
+	case AXIMM:
+		if(op == Olea) {
+			if((short)i->reg != 0) {
+				ldc((short)i->reg, reg);
+				IRR(Osw, O(REG,t),Rreg, reg);
+			} else
+				IRR(Osw, O(REG,t),Rreg, Rzero);
+			IRR(Oaddui, O(REG,t),Rreg, reg);
+		} else
+			ldc((short)i->reg, reg);
+		return;
+	case AXINF:
+		IRR(op, i->reg,Rfp, reg);
+		break;
+	case AXINM:
+		IRR(op, i->reg,Rmp, reg);
+		break;
+	}
+	if(op != Olea && del)
+		delay();
+}
+
+ulong
+branch(Inst *i)
+{
+	ulong rel;
+
+	if(base == 0)
+		return 0;
+	rel = patch[(Inst*)i->d.imm - mod->prog];
+	rel += (base - code) - 1;
+	return rel & 0xffff;
+}
+
+static void
+literal(ulong imm, int roff)
+{
+	nlit++;
+
+	ldbigc((ulong)litpool, Ro1);
+	IRR(Osw, roff, Rreg, Ro1);
+
+	if(pass == 0)
+		return;
+
+	*litpool = imm;
+	litpool++;	
+}
+
+void
+punt(Inst *i, int m, void (*fn)(void))
+{
+	ulong *cp, pc;
+
+	if(m & SRCOP) {
+		op1(i, Olea, Ro1, 1);
+		IRR(Osw, O(REG,s),Rreg, Ro1);
+	}
+	if(m & DSTOP) {
+		op3(i, Olea, Ro3, 1);
+		IRR(Osw, O(REG,d),Rreg, Ro3);
+	}
+	if(m & WRTPC) {
+		pc = patch[i-mod->prog+1];
+		ldbigc((ulong)(base+pc), Ro1);
+		IRR(Osw, O(REG,PC),Rreg, Ro1);
+	}
+	if(m & DBRAN) {
+		pc = patch[(Inst*)i->d.imm-mod->prog];
+		literal((ulong)(base+pc), O(REG, d));
+	}
+
+	if((i->add&ARM) == AXNON) {
+		if(m & THREOP) {
+			delay();
+			IRR(Olw, O(REG,d),Rreg, Ro2);
+			delay();
+			IRR(Osw, O(REG,m),Rreg, Ro2);
+		}
+	} else {
+		op2(i, Olea, Ro2, 1);
+		IRR(Osw, O(REG,m),Rreg, Ro2);
+	}
+
+	ldc((ulong)fn, Rpic);
+	JR(Ojalr, Rpic);
+	IRR(Osw, O(REG,FP),Rreg, Rfp);
+
+	ldc((ulong)&R, Rreg);
+	IRR(Olw, O(REG,FP),Rreg, Rfp);
+	IRR(Olw, O(REG,MP),Rreg, Rmp);
+	regdelay = Rmp;
+
+	if(m & TCHECK) {
+		IRR(Olw, O(REG,t),Rreg, Ro1);
+		xchg();
+		cp = code;
+		BRRI(Obeq,Ro1,Rzero,0);
+		IRR(Olw, O(REG,xpc),Rreg, Ro2);
+		delay();
+		JR(Ojr, Ro2);
+		delay();
+		*cp |= (code - cp) - 1;
+		regdelay = 0;
+	}
+
+	if(m & NEWPC) {
+		IRR(Olw, O(REG,PC),Rreg, Ro1);
+		if(m & TCHECK)
+			delay();
+		else
+			xchg();
+		JR(Ojr, Ro1);
+		delay();
+		regdelay = 0;
+	}
+}
+				
+static void
+comgoto(Inst *i)
+{
+	WORD *t, *e;
+
+	op1(i, Olw, Ro2, 0);
+	op3(i, Olea, Ro3, 0);
+	SRR(Osll, 2, Ro2, Ro2);
+	RRR(Oaddu, Ro2, Ro3, Ro3);
+	IRR(Olw, 0,Ro3, Ro1);
+	delay();
+	JR(Ojr, Ro1);
+	delay();
+
+	if(pass == 0)
+		return;
+
+	t = (WORD*)(mod->origmp+i->d.ind);
+	e = t + t[-1];
+	t[-1] = 0;
+	while(t < e) {
+		t[0] = (ulong)(base + patch[t[0]]);
+		t++;
+	}
+}
+
+static void
+comcase(Inst *i, int w)
+{
+	int l;
+	WORD *t, *e;
+
+	if(w != 0) {
+		op1(i, Olw, Ro1, 0);		// v
+		op3(i, Olea, Ro3, 0);		// table
+		J(Oj, base+macro[MacCASE]);
+		xchg();
+	}
+	
+	t = (WORD*)(mod->origmp+i->d.ind+4);
+	l = t[-1];
+
+	/* have to take care not to relocate the same table twice - 
+	 * the limbo compiler can duplicate a case instruction
+	 * during its folding phase
+	 */
+
+	if(pass == 0) {
+		if(l >= 0)
+			t[-1] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-1] = -l-1;			/* Set real count */
+	e = t + t[-1]*3;
+	while(t < e) {
+		t[2] = (ulong)(base + patch[t[2]]);
+		t += 3;
+	}
+	t[0] = (ulong)(base + patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+	int l;
+	WORD *t, *e;
+
+	t = (WORD*)(mod->origmp+i->d.ind+8);
+	l = t[-2];
+	if(pass == 0) {
+		if(l >= 0)
+			t[-2] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-2] = -l-1;			/* Set real count */
+	e = t + t[-2]*6;
+	while(t < e) {
+		t[4] = (ulong)base + patch[t[4]];
+		t += 6;
+	}
+	t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+	Modlink *ml;
+	ulong *cp1, *cp2;
+
+	op1(i, Olw, Ro1, 0);
+	ldc((ulong)H, Ri);
+	cp1 = code;
+	BRRI(Obeq, Ro1,Ri, 0);
+	delay();
+
+	ml = nil;
+	IRR(Olw, (ulong)&ml->links[i->reg].frame,Ro1, Ri);
+	delay();
+	IRR(Olw, O(Type,initialize),Ri, Ro2);
+	delay();
+	cp2 = code;
+	BRRI(Obne, Ro2,Rzero, 0);
+	delay();
+
+	op3(i, Olea, Rj, 0);
+
+	*cp1 |= (code - cp1) - 1;
+	ldbigc((ulong)(base+patch[i-mod->prog+1]), Rlink);
+	J(Oj, base+macro[MacMFRA]);
+	xchg();
+
+	*cp2 |= (code - cp2) - 1;
+	J(Ojal, base+macro[MacFRAM]);
+	delay();
+	op3(i, Osw, Ro1, 0);
+}
+
+static void
+commcall(Inst *i)
+{
+	Modlink *ml;
+
+	op1(i, Olw, Ro1, 0);				// f in Ro1
+	IRR(Olw, O(REG,M),Rreg, Ro3);
+	IRR(Osw, O(Frame,fp),Ro1, Rfp);			// f->fp = R.FP
+	IRR(Osw, O(Frame,mr),Ro1, Ro3);			// f->mr = R.M
+	op3(i, Olw, Ri, 1);
+	ml = nil;
+	IRR(Olw, (ulong)&ml->links[i->reg].u.pc,Ri, Rj);// ml->entry in Rj
+	J(Ojal, base+macro[MacMCAL]);
+	xchg();
+}
+
+static void
+cbral(Inst *i, int op, int mode)
+{
+	ulong *cp;
+
+	cp = 0;
+	op1(i, Olea, Ri, 0);
+	op2(i, Olea, Rj, 0);
+	IRR(Olw, Bhi,Ri, Ro1);
+	IRR(Olw, Bhi,Rj, Ro2);
+	IRR(Olw, Blo,Ri, Ri);
+
+	switch(mode & OMASK) {
+	case ANDAND:
+		cp = code;
+		BRRI(Obne, Ro2,Ro1, 0);
+		goto b1;
+
+	case OROR:
+		BRRI(Obne, Ro2,Ro1, branch(i));
+	b1:
+		IRR(Olw, Blo,Rj, Rj);
+		delay();
+		BRRI(op, Rj,Ri, branch(i));
+		break;
+
+	case EQAND:
+		if(mode & REV1)
+			RRR(Oslt, Ro2,Ro1, Ro3);
+		else
+			RRR(Oslt, Ro1,Ro2, Ro3);
+		BRI(Obne, Ro3, branch(i));
+		IRR(Olw, Blo,Rj, Rj);
+		cp = code;
+		BRRI(Obne, Ro2,Ro1, 0);
+		if(mode & REV2)
+			RRR(Osltu, Rj,Ri, Ro3);
+		else
+			RRR(Osltu, Ri,Rj, Ro3);
+		BRI(op, Ro3, branch(i));
+		break;
+	}
+	delay();
+	if(cp)
+		*cp |= (code - cp) - 1;
+}
+
+static void
+op12(Inst *i, int b1flag, int b2flag)
+{
+	int o1, o2;
+
+	o1 = Olw;
+	if(b1flag)
+		o1 = Olbu;
+	o2 = Olw;
+	if(b2flag)
+		o2 = Olbu;
+	if((i->add & ARM) == AXIMM) {
+		op1(i, o1, Ro1, 0);
+		op2(i, o2, Ro2, 1);
+	} else {
+		op2(i, o2, Ro2, 0);
+		op1(i, o1, Ro1, 1);
+	}
+}
+
+static void
+op13(Inst *i, int o1, int o2)
+{
+	op1(i, o1, Ro1, 1);
+	op3(i, o2, Ro1, 0);
+}
+
+static void
+shrl(Inst *i)
+{
+	int c;
+
+	if(USRC(i->add) != AIMM) {
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		return;
+	}
+	c = i->s.imm;
+	op2(i, Olea, Ro3, 1);
+	IRR(Olw, Bhi,Ro3, Ro1);
+	if(c >= 32) {
+		if((i->add&ARM) != AXNON)
+			op3(i, Olea, Ro3, 0);
+		else
+			delay();
+		SRR(Osra, 31, Ro1, Ro2);
+		IRR(Osw, Bhi,Ro3, Ro2);
+		if(c >= 64) {
+			IRR(Osw, Blo,Ro3, Ro2);
+			return;
+		}
+		if(c > 32)
+			SRR(Osra, c-32, Ro1, Ro1);
+		IRR(Osw, Blo,Ro3, Ro1);
+		return;
+	}
+	IRR(Olw, Blo,Ro3, Ro2);
+	if((i->add&ARM) != AXNON)
+		op3(i, Olea, Ro3, !c);
+	if(c != 0) {
+		SRR(Osll, 32-c, Ro1, Ri);
+		SRR(Osra, c, Ro1, Ro1);
+		SRR(Osrl, c, Ro2, Ro2);
+		RRR(Oor, Ri, Ro2, Ro2);
+	}
+	IRR(Osw, Blo,Ro3, Ro2);
+	IRR(Osw, Bhi,Ro3, Ro1);
+}
+
+static void
+shll(Inst *i)
+{
+	int c;
+
+	if(USRC(i->add) != AIMM) {
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		return;
+	}
+	c = i->s.imm;
+	if(c >= 64) {
+		op3(i, Olea, Ro3, 1);
+		IRR(Osw, Bhi,Ro3, Rzero);
+		IRR(Osw, Blo,Ro3, Rzero);
+		return;
+	}
+	op2(i, Olea, Ro3, 1);
+	if(c >= 32) {
+		IRR(Olw, Blo,Ro3, Ro1);
+		if((i->add&ARM) != AXNON)
+			op3(i, Olea, Ro3, 1);
+		IRR(Osw, Blo,Ro3, Rzero);
+		if(c > 32)
+			SRR(Osll, c-32, Ro1, Ro1);
+		IRR(Osw, Bhi,Ro3, Ro1);
+		return;
+	}
+	IRR(Olw, Blo,Ro3, Ro2);
+	IRR(Olw, Bhi,Ro3, Ro1);
+	if((i->add&ARM) != AXNON)
+		op3(i, Olea, Ro3, !c);
+	if(c != 0) {
+		SRR(Osrl, 32-c, Ro2, Ri);
+		SRR(Osll, c, Ro2, Ro2);
+		SRR(Osll, c, Ro1, Ro1);
+		RRR(Oor, Ri, Ro1, Ro1);
+	}
+	IRR(Osw, Blo,Ro3, Ro2);
+	IRR(Osw, Bhi,Ro3, Ro1);
+}
+
+static void
+compdbg(void)
+{
+	print("%s:%d@%.8ux\n", R.M->m->name, R.t, R.st);
+}
+
+static void
+comp(Inst *i)
+{
+	int o, q, b;
+	ulong *cp, *cp1;
+	char buf[64];
+
+	if(0) {
+		Inst xx;
+		xx.add = AXIMM|SRC(AIMM);
+		xx.s.imm = (ulong)code;
+		xx.reg = i-mod->prog;
+		punt(&xx, SRCOP, compdbg);
+	}
+
+	switch(i->op) {
+	default:
+		snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+		error(buf);
+		break;
+	case IMCALL:
+		if((i->add&ARM) == AXIMM)
+			commcall(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case ISEND:
+	case IRECV:
+	case IALT:
+		punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+		break;
+	case ISPAWN:
+		punt(i, SRCOP|DBRAN, optab[i->op]);
+		break;
+	case IBNEC:
+	case IBEQC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+		punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+		break;
+	case ICASEC:
+		comcase(i, 0);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case ICASEL:
+		comcasel(i);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case IADDC:
+	case IMULL:
+	case IDIVL:
+	case IMODL:
+	case ILSRL:
+	case IMNEWZ:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IMFRAME:
+		if((i->add&ARM) == AXIMM)
+			commframe(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ILOAD:
+	case INEWA:
+	case INEWAZ:
+	case INEW:
+	case INEWZ:
+	case ISLICEA:
+	case ISLICELA:
+	case ICONSB:
+	case ICONSW:
+	case ICONSL:
+	case ICONSF:
+	case ICONSM:
+	case ICONSMP:
+	case ICONSP:
+	case IMOVMP:
+	case IHEADL:
+	case IHEADMP:
+	case IINDC:
+	case ILENC:
+	case IINSC:
+	case ICVTAC:
+	case ICVTCW:
+	case ICVTWC:
+	case ICVTCL:
+	case ICVTLC:
+	case ICVTFC:
+	case ICVTCF:
+	case ICVTFL:
+	case ICVTLF:
+	case ICVTFR:
+	case ICVTRF:
+	case IMSPAWN:
+	case ICVTCA:
+	case ISLICEC:
+	case INBALT:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case INEWCM:
+	case INEWCMP:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case INEWCB:
+	case INEWCW:
+	case INEWCF:
+	case INEWCP:
+	case INEWCL:
+		punt(i, DSTOP|THREOP, optab[i->op]);
+		break;
+	case IEXIT:
+		punt(i, 0, optab[i->op]);
+		break;
+	case ICVTWB:
+		op13(i, Olw, Osb);
+		break;
+	case ICVTBW:
+		op13(i, Olbu, Osw);
+		break;
+	case ICVTWS:
+		op13(i, Olw, Osb);
+		break;
+	case ICVTSW:
+		op13(i, Olhu, Osw);
+		break;
+	case IMOVB:
+		op13(i, Olbu, Osb);
+		break;
+	case IMOVW:
+		if(USRC(i->add) == AIMM && i->s.imm == 0) {
+			op3(i, Osw, Rzero, 0);
+			break;
+		}
+		op13(i, Olw, Osw);
+		break;
+	case ICVTLW:
+		op1(i, Olea, Ro1, 1);
+		IRR(Olw, Blo,Ro1, Ro1);
+		delay();
+		op3(i, Osw, Ro1, 0);
+		break;
+	case ICVTWL:
+		op1(i, Olw, Ro1, 0);
+		op3(i, Olea, Ro2, 0);
+		SRR(Osra, 31, Ro1, Ro3);
+		IRR(Osw, Blo,Ro2, Ro1);
+		IRR(Osw, Bhi,Ro2, Ro3);
+		break;
+	case IHEADM:
+		op1(i, Olw, Ro1, 1);
+		IRR(Oaddui, OA(List,data),Ro1,  Ro1);
+		goto m1;
+	case IMOVM:
+		op1(i, Olea, Ro1, 0);
+	m1:
+		op2(i, Olw, Ro2, 0);
+		op3(i, Olea, Ro3, 0);
+		J(Ojal, base+macro[MacMOVM]);
+		xchg();
+		break;
+	case IRET:
+		J(Oj, base+macro[MacRET]);
+		delay();
+		break;
+	case IFRAME:
+		if(UXSRC(i->add) != SRC(AIMM)) {
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		ldc((ulong)mod->type[i->s.imm], Ri);
+		J(Ojal, base+macro[MacFRAM]);
+		xchg();
+		op3(i, Osw, Ro1, 0);
+		tinit[i->s.imm] = 1;
+		break;
+	case ILEA:
+		op13(i, Olea, Osw);
+		break;
+	case IHEADW:
+		op1(i, Olw, Ro1, 1);
+		IRR(Olw, OA(List,data),Ro1, Ro1);
+		delay();
+		op3(i, Osw, Ro1, 0);
+		break;
+	case IHEADF:
+		op1(i, Olw, Ro1, 1);
+		IRR(Olw, OA(List,data),Ro1, Ro2);
+		IRR(Olw, OA(List,data)+4,Ro1, Ro3);
+		op3(i, Olea, Ro1, 1);
+		IRR(Osw, 0,Ro1, Ro2);
+		IRR(Osw, 4,Ro1, Ro3);
+		break;
+	case IHEADB:
+		op1(i, Olw, Ro1, 1);
+		IRR(Olbu , OA(List,data),Ro1, Ro1);
+		delay();
+		op3(i, Osb, Ro1, 0);
+		break;
+	case ITAIL:
+		op1(i, Olw, Ro1, 1);
+		IRR(Olw, O(List,tail),Ro1, Ro1);
+		goto movp;
+	case IMOVP:
+		op1(i, Olw, Ro1, 0);
+		goto movp;
+	case IHEADP:
+		op1(i, Olw, Ro1, 1);
+		IRR(Olw, OA(List,data),Ro1, Ro1);
+	movp:
+		ldc((ulong)H, Ro2);
+		cp = code;
+		BRRI(Obeq,Ro1,Ro2,0);
+		ldbigc((ulong)&mutator, Ri);
+		J(Ojal, base+macro[MacCOLR]);
+		xchg();
+		*cp |= (code - cp) - 1;
+		op3(i, Olea, Ro3, 1);
+		IRR(Olw, 0,Ro3, Ri);
+		J(Ojal, base+macro[MacFRP]);
+		IRR(Osw, 0,Ro3, Ro1);
+		break;
+	case ILENA:
+		op1(i, Olw, Ri, 0);
+		J(Ojal, base+macro[MacLENA]);
+		xchg();
+		op3(i, Osw, Ro1, 0);
+		break;
+	case ILENL:
+		op1(i, Olw, Ro1, 0);
+		ldc((ulong)H, Ro2);
+		cp = code;
+		BRRI(Obeq, Ro1,Ro2, 0);
+		ldc(0, Ro3);
+
+		cp1 = code;
+		IRR(Olw, O(List,tail),Ro1, Ro1);
+		IRR(Oaddui, 1,Ro3, Ro3);
+		BRRI(Obne, Ro1,Ro2, (cp1-code)-1);
+		delay();
+
+		*cp |= (code - cp) - 1;
+		op3(i, Osw, Ro3, 0);
+		break;
+	case IMOVL:
+	case IMOVF:
+		op1(i, Olea, Ro1, 1);
+		IRR(Olw, 0,Ro1, Ro2);
+		IRR(Olw, 4,Ro1, Ro3);
+		op3(i, Olea, Ro1, 1);
+		IRR(Osw, 0,Ro1, Ro2);
+		IRR(Osw, 4,Ro1, Ro3);
+		break;
+	case ICVTFW:
+		op1(i, Olea, Ro1, 1);
+		IRR(Olf, Bhi,Ro1, Rf2+1);
+		IRR(Olf, Blo,Ro1, Rf2);
+		delay();
+		FRRR(Ocvtfw, 0, Rf2, Rf2);
+		op3(i, Olea, Ro2, 1);
+		IRR(Osf, 0,Ro2, Rf2);
+		break;
+	case ICVTWF:
+		op1(i, Olea, Ro1, 1);
+		IRR(Olf, 0,Ro1, Rf2);
+		delay();
+		FRRR(Ocvtwf, 0, Rf2, Rf2);
+		op3(i, Olea, Ro2, 1);
+		IRR(Osf, Bhi,Ro2, Rf2+1);
+		IRR(Osf, Blo,Ro2, Rf2);
+		break;
+	case INEGF:
+		op1(i, Olea, Ro1, 1);
+		IRR(Olf, Bhi,Ro1, Rf1+1);
+		IRR(Olf, Blo,Ro1, Rf1);
+		op3(i, Olea, Ro2, 1);
+		FRRR(Onegf, 0, Rf1,Rf2);
+		IRR(Osf, Bhi,Ro2, Rf2+1);
+		IRR(Osf, Blo,Ro2, Rf2);
+		break;
+	case IXORL:
+	case IORL:
+	case IANDL:
+	case IADDL:
+	case ISUBL:
+		op1(i, Olea, Ro1, 0);
+		op2(i, Olea, Ro3, 0);
+
+		IRR(Olw, Blo,Ro1, Rj);	/* ls */
+		IRR(Olw, Blo,Ro3, Ro2);
+		IRR(Olw, Bhi,Ro1, Ri);	/* ms */
+		IRR(Olw, Bhi,Ro3, Ro1);
+
+		switch(i->op) {
+		case IXORL:
+			o = Oxor;
+			goto l1;
+		case IORL:
+			o = Oor;
+			goto l1;
+		case IANDL:
+			o = Oand;
+		l1:
+			RRR(o, Ri,Ro1, Ro1);
+			RRR(o, Rj,Ro2, Ro2);
+			break;
+		case IADDL:
+			RRR(Oaddu, Ri,Ro1, Ro1);
+			RRR(Oaddu, Rj,Ro2, Ro2);
+			RRR(Osltu, Rj,Ro2, Ri);
+			RRR(Oaddu, Ri,Ro1, Ro1);
+			break;
+		case ISUBL:
+			RRR(Osubu, Ri,Ro1, Ro1);
+			RRR(Osltu, Rj,Ro2, Ri);
+			RRR(Osubu, Rj,Ro2, Ro2);
+			RRR(Osubu, Ri,Ro1, Ro1);
+			break;
+		}
+		if((i->add&ARM) != AXNON)
+			op3(i, Olea, Ro3, 1);
+		IRR(Osw, Bhi,Ro3, Ro1);
+		IRR(Osw, Blo,Ro3, Ro2);
+		break;
+	case ISHLL:
+		shll(i);
+		break;
+	case ISHRL:
+		shrl(i);
+		break;
+	case IADDF:
+	case ISUBF:
+	case IMULF:
+	case IDIVF:
+	case IBEQF:
+	case IBGEF:
+	case IBGTF:
+	case IBLEF:
+	case IBLTF:
+	case IBNEF:
+		op1(i, Olea, Ro1, 0);
+		op2(i, Olea, Ro2, 0);
+		IRR(Olf, Bhi,Ro1, Rf1+1);
+		IRR(Olf, Blo,Ro1, Rf1);
+		IRR(Olf, Bhi,Ro2, Rf2+1);
+		IRR(Olf, Blo,Ro2, Rf2);
+		switch(i->op) {
+		case IADDF:	o = Oaddf; goto f1;
+		case ISUBF:	o = Osubf; goto f1;
+		case IMULF:	o = Omulf; goto f1;
+		case IDIVF:	o = Odivf; goto f1;
+		case IBEQF:	o = Ofeq; q = Obrt; goto f2;
+		case IBGEF:	o = Oflt; q = Obrf; goto f3;
+		case IBGTF:	o = Oflt; q = Obrt; goto f2;
+		case IBLEF:	o = Oflt; q = Obrf; goto f2;
+		case IBLTF:	o = Oflt; q = Obrt; goto f3;
+		case IBNEF:	o = Ofeq; q = Obrf; goto f2;
+		f1:
+			op3(i, Olea, Ro1, 0);
+			FRRR(o, Rf1,Rf2, Rf2);
+			IRR(Osf, Bhi,Ro1, Rf2+1);
+			IRR(Osf, Blo,Ro1, Rf2);
+			break;
+		f2:
+			delay();
+			FRRR(o, Rf1,Rf2, 0);
+			goto f4;
+		f3:
+			delay();
+			FRRR(o, Rf2,Rf1, 0);
+			goto f4;
+		f4:
+			delay();
+			FI(q, branch(i));
+			delay();
+			break;
+		}
+		break;
+
+	case IBLTB:
+	case IBLEB:
+	case IBGTB:
+	case IBGEB:
+	case IBEQB:
+	case IBNEB:
+		b = 1;
+		goto s1;
+	case IBLTW:
+	case IBLEW:
+	case IBGTW:
+	case IBGEW:
+	case IBEQW:
+	case IBNEW:
+		b = 0;
+	s1:
+		op12(i, b, b);
+		switch(i->op) {
+		case IBLTB:
+		case IBLTW:	o = Obne; goto b1;
+		case IBGEB:
+		case IBGEW:	o = Obeq; goto b1;
+		case IBGTB:
+		case IBGTW:	o = Obne; goto b2;
+		case IBLEB:
+		case IBLEW:	o = Obeq; goto b2;
+		case IBEQB:
+		case IBEQW:	o = Obeq; goto b3;
+		case IBNEB:
+		case IBNEW:	o = Obne; goto b3;
+		b1:	RRR(Oslt, Ro2,Ro1, Ro3);
+			BRI(o,Ro3, branch(i));
+			break;
+		b2:	RRR(Oslt, Ro1,Ro2, Ro3);
+			BRI(o,Ro3, branch(i));
+			break;
+		b3:	BRRI(o, Ro2,Ro1, branch(i));
+			break;
+		}
+		delay();
+		break;
+
+	case IBEQL:
+		cbral(i, Obeq, ANDAND);
+		break;
+	case IBNEL:
+		cbral(i, Obne, OROR);
+		break;
+	case IBLEL:
+		cbral(i, Obeq, EQAND|REV1);
+		break;
+	case IBGTL:
+		cbral(i, Obne, EQAND);
+		break;
+	case IBLTL:
+		cbral(i, Obne, EQAND|REV1|REV2);
+		break;
+	case IBGEL:
+		cbral(i, Obeq, EQAND|REV2);
+		break;
+
+	case ISUBB:
+	case IADDB:
+	case IANDB:
+	case IORB:
+	case IXORB:
+	case IMODB:
+	case IDIVB:
+	case IMULB:
+		b = 1;
+		op12(i, b, b);
+		goto s2;
+	case ISHLB:
+	case ISHRB:
+		b = 1;
+		op12(i, 0, b);
+		goto s2;
+	case ISUBW:
+	case IADDW:
+	case IANDW:
+	case IORW:
+	case IXORW:
+	case ISHLW:
+	case ISHRW:
+	case IMODW:
+	case IDIVW:
+	case IMULW:
+		b = 0;
+		op12(i, b, b);
+	s2:
+		switch(i->op) {
+		case IADDB:
+		case IADDW:	o = Oaddu; goto c1;
+		case ISUBB:
+		case ISUBW:	o = Osubu; goto c1;
+		case IANDB:
+		case IANDW:	o = Oand; goto c1;
+		case IORB:
+		case IORW:	o = Oor; goto c1;
+		case IXORB:
+		case IXORW:	o = Oxor; goto c1;
+		c1:
+			RRR(o, Ro1,Ro2, Ro3);
+			break;
+		case ISHLB:
+		case ISHLW:	o = Osllv; goto c2;
+		case ILSRW:	o = Osrlv; goto c2;
+		case ISHRB:
+		case ISHRW:	o = Osrav; goto c2;
+		c2:
+			RRR(o, Ro2,Ro1, Ro3);
+			break;
+		case IMULB:
+		case IMULW:	q = Omul; o = Omflo; goto c3;
+		case IDIVB:
+		case IDIVW:	q = Odiv; o = Omflo; goto c3;
+		case IMODB:
+		case IMODW:	q = Odiv; o = Omfhi; goto c3;
+		c3:
+			RRR(q, Ro1,Ro2, Rzero);
+			RRR(o, Rzero,Rzero, Ro3);
+			break;
+		}
+		op3(i, b? Osb: Osw, Ro3, 0);
+		break;
+	case ICALL:
+		op1(i, Olw, Ro1, 0);
+		ldbigc((ulong)(base+patch[i-mod->prog+1]), Ro2);
+		IRR(Osw, O(Frame,lr),Ro1, Ro2);
+		IRR(Osw, O(Frame,fp),Ro1, Rfp);
+		J(Oj, base+patch[(Inst*)i->d.imm - mod->prog]);
+		RRR(Oaddu, Ro1,Rzero, Rfp);
+		break;
+	case IJMP:
+		J(Oj, base+patch[(Inst*)i->d.imm - mod->prog]);
+		delay();
+		break;
+	case IGOTO:
+		comgoto(i);
+		break;
+	case IINDX:
+		op1(i, Olw, Ro1, 0);				/* Ro1 = a */
+		op3(i, Olw, Ro3, 0);				/* Ro2 = i */
+		J(Ojal, base+macro[MacINDX]);
+		xchg();
+		op2(i, Osw, Ro2, 0);
+		break;
+	case IINDB:
+	case IINDF:
+	case IINDW:
+	case IINDL:
+		op1(i, Olw, Ro1, 0);			/* Ro1 = a */
+		op3(i, Olw, Ro3, 0);			/* Ro3 = i */
+		IRR(Olw, O(Array,data),Ro1, Ro1);	/* Ro1 = a->data */
+		switch(i->op) {
+		case IINDL:
+		case IINDF:
+			SRR(Osll, 3, Ro3, Ro3);		/* Ro3 = i*8 */
+			break;
+		case IINDW:
+			SRR(Osll, 2, Ro3, Ro3);		/* Ro3 = i*4 */
+			break;
+		case IINDB:
+			delay();
+			break;
+		}
+		RRR(Oaddu, Ro1,Ro3, Ro2);		/* Ro2 = i*size + data */
+		op2(i, Osw, Ro2, 0);
+		break;
+	case ICASE:
+		comcase(i, 1);
+		break;
+	case IRAISE:
+		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case IMULX:
+	case IDIVX:
+	case ICVTXX:
+	case IMULX0:
+	case IDIVX0:
+	case ICVTXX0:
+	case IMULX1:
+	case IDIVX1:
+	case ICVTXX1:
+	case ICVTFX:
+	case ICVTXF:
+	case IEXPW:
+	case IEXPL:
+	case IEXPF:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ISELF:
+		punt(i, DSTOP, optab[i->op]);
+		break;
+	}
+}
+
+static void
+preamble(void)
+{
+	ldc((ulong)&R, Rreg);
+	IRR(Olw, O(REG,PC),Rreg, Ri);
+	IRR(Olw, O(REG,FP),Rreg, Rfp);
+	IRR(Olw, O(REG,MP),Rreg, Rmp);
+	IRR(Osw, O(REG,xpc),Rreg, Rlink);
+	JR(Ojr, Ri);
+	delay();
+}
+
+static void
+macfrp(void)
+{
+	ulong *cp1, *cp2;
+
+	ldc((ulong)H, Ro1);
+	cp1 = code;
+	BRRI(Obeq, Ri,Ro1, 0);			// arg == $H
+	delay();
+
+	IRR(Olw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+	ldc((ulong)1, Ro1);
+	cp2 = code;
+	BRRI(Obeq, Ro1,Ro2, 0);			// ref(arg) == $1
+	IRR(Oaddui, -1,Ro2, Ro2);		// ref(arg)--
+	JR(Ojr, Rlink);
+	IRR(Osw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+
+	*cp2 |= (code - cp2) - 1;
+	IRR(Osw, O(REG,st),Rreg, Rlink);
+	IRR(Osw, O(REG,FP),Rreg, Rfp);
+
+	ldc((ulong)rdestroy, Rpic);
+	JR(Ojalr, Rpic);				// CALL	destroy
+	IRR(Osw, O(REG,s),Rreg, Ri);
+
+	ldc((ulong)&R, Rreg);
+	IRR(Olw, O(REG,st),Rreg, Rlink);
+	IRR(Olw, O(REG,FP),Rreg, Rfp);
+	IRR(Olw, O(REG,MP),Rreg, Rmp);
+
+	*cp1 |= (code - cp1) - 1;
+	JR(Ojr, Rlink);
+	delay();
+}
+
+static void
+macret(void)
+{
+	ulong *cp1, *cp2, *cp3, *cp4, *cp5, *cp6;
+	Inst i;
+
+// NOTE this needs to be scheduled
+
+	IRR(Olw, O(Frame,t),Rfp, Ro1);
+	delay();
+	cp1 = code;
+	BRRI(Obeq, Ro1,Rzero, 0);		// t(Rfp) == 0
+	delay();
+
+	IRR(Olw, O(Type,destroy),Ro1, Rpic);
+	delay();
+	cp2 = code;
+	BRRI(Obeq, Rpic,Rzero, 0);		// destroy(t(fp)) == 0
+	delay();
+
+	IRR(Olw, O(Frame,fp),Rfp, Ro2);
+	delay();
+	cp3 = code;
+	BRRI(Obeq, Ro2,Rzero, 0);		// fp(Rfp) == 0
+	delay();
+
+	IRR(Olw, O(Frame,mr),Rfp, Ro3);
+	delay();
+	cp4 = code;
+	BRRI(Obeq, Ro3,Rzero, 0);		// mr(Rfp) == 0
+	delay();
+
+	IRR(Olw, O(REG,M),Rreg, Ro2);
+	delay();
+	IRR(Olw, O(Heap,ref)-sizeof(Heap),Ro2, Ro3);
+	delay();
+	IRR(Oaddui, -1,Ro3, Ro3);
+	cp5 = code;
+	BRRI(Obeq, Ro3,Rzero, 0);		// --ref(arg) == 0
+	delay();
+	IRR(Osw, O(Heap,ref)-sizeof(Heap),Ro2, Ro3);
+
+	IRR(Olw, O(Frame,mr),Rfp, Ro1);
+	delay();
+	IRR(Osw, O(REG,M),Rreg, Ro1);
+	IRR(Olw, O(Modlink,compiled),Ro1, Ro2);	// check for uncompiled module
+	IRR(Olw, O(Modlink,MP),Ro1, Rmp);
+	cp6 = code;
+	BRRI(Obeq, Ro2,Rzero, 0);
+	IRR(Osw, O(REG,MP),Rreg, Rmp);
+
+	*cp4 |= (code - cp4) - 1;
+	JR(Ojalr, Rpic);			// call destroy(t(fp))
+	delay();
+	IRR(Osw, O(REG,SP),Rreg, Rfp);
+	IRR(Olw, O(Frame,lr),Rfp, Ro1);
+	IRR(Olw, O(Frame,fp),Rfp, Rfp);
+	IRR(Osw, O(REG,FP),Rreg, Rfp);
+	JR(Ojr, Ro1);				// goto lr(Rfp)
+	delay();
+
+	*cp6 |= (code - cp6) - 1;		// returning to uncompiled module
+	JR(Ojalr, Rpic);			// call destroy(t(fp))
+	delay();
+	IRR(Osw, O(REG,SP),Rreg, Rfp);
+	IRR(Olw, O(Frame,lr),Rfp, Ro1);
+	IRR(Olw, O(Frame,fp),Rfp, Rfp);
+	IRR(Osw, O(REG,FP),Rreg, Rfp);
+	IRR(Olw, O(REG,xpc),Rreg, Ro2);
+	JR(Ojr, Ro2);				// return to uncompiled code
+	IRR(Osw, O(REG,PC),Rreg, Ro1);
+ 
+	*cp1 |= (code - cp1) - 1;
+	*cp2 |= (code - cp2) - 1;
+	*cp3 |= (code - cp3) - 1;
+	*cp5 |= (code - cp5) - 1;
+	i.add = AXNON;
+	punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+macindx(void)
+{
+
+	IRR(Olw, O(Array,t),Ro1, Ro2);
+	IRR(Olw, O(Array,data),Ro1, Ro1);		// Ro1 = data
+	IRR(Olw, O(Type,size),Ro2, Ro2);		// Ro2 = size
+	delay();
+
+	RRR(Omul, Ro3,Ro2,Rzero);			// Ro2 = i*size
+	RRR(Omflo, Rzero,Rzero,Ro2);
+	JR(Ojr, Rlink);
+	RRR(Oaddu, Ro1,Ro2,Ro2);			// Ro2 = i*size + data
+}
+
+static void
+maccase(void)
+{
+	ulong *cp1, *cp2, *cp3;
+
+/*
+ * Ro1 = value (input arg), t
+ * Ro2 = count, n
+ * Ro3 = table pointer (input arg)
+ * Ri  = n/2, n2
+ * Rj  = pivot element t+n/2*3, l
+ */
+
+	IRR(Olw, 0,Ro3, Ro2);		// count
+	IRR(Oaddui, 0,Ro3, Rlink);	// initial table pointer
+
+	cp1 = code;			// loop:
+	BRI(Oblez,Ro2, 0);		// n <= 0? goto out
+	SRR(Osra, 1, Ro2, Ri);		// n2 = n>>1
+	SRR(Osll, 1, Ri, Rj);
+	RRR(Oaddu, Rj, Ri, Rj);
+	SRR(Osll, 2, Rj, Rj);
+	RRR(Oaddu, Ro3, Rj, Rj);	// l = t + n2*3;
+	IRR(Olw, 4,Rj, Rpic);
+	delay();
+	RRR(Oslt, Rpic, Ro1, Rpic);
+	cp2 = code;
+	BRI(Obne, Rpic, 0);		// v < l[1]? goto low
+	delay();
+
+	IRR(Olw, 8,Rj, Rpic);
+	delay();
+	RRR(Oslt, Rpic, Ro1, Rpic);
+	cp3 = code;
+	BRI(Obeq, Rpic, 0);		// v >= l[2]? goto high
+	delay();
+
+	IRR(Olw, 12,Rj, Ro3);		// found
+	delay();
+	JR(Ojr, Ro3);
+	delay();
+
+	*cp2 |= (code - cp2) - 1;	// low:
+	BRRI(Obeq, Rzero,Rzero, (cp1-code)-1);
+	IRR(Oaddui, 0, Ri, Ro2);	// n = n2
+
+	*cp3 |= (code - cp3) - 1;	// high:
+	IRR(Oaddui, 12, Rj, Ro3);	// t = l+3;
+	IRR(Oaddui, 1, Ri, Rpic);
+	BRRI(Obeq, Rzero,Rzero, (cp1-code)-1);
+	RRR(Osubu, Rpic, Ro2, Ro2);	// n -= n2 + 1
+
+	*cp1 |= (code - cp1) - 1;	// out:
+	IRR(Olw, 0,Rlink, Ro2);		// initial n
+	delay();
+	SRR(Osll, 1, Ro2, Ro3);
+	RRR(Oaddu, Ro3, Ro2, Ro2);
+	SRR(Osll, 2, Ro2, Ro2);
+	RRR(Oaddu, Ro2, Rlink, Rlink);
+	IRR(Olw, 4,Rlink, Ro3);		// (initital t)[n*3+1]
+	delay();
+	JR(Ojr, Ro3);
+	delay();
+}
+
+static void
+maclena(void)
+{
+	ulong *cp;
+
+	ldc((ulong)H, Ro1);
+	cp = code;
+	BRRI(Obeq, Ri,Ro1, 0);
+	delay();
+	IRR(Olw, O(Array,len),Ri, Ro1);
+	JR(Ojr, Rlink);
+	delay();
+	*cp |= (code - cp) - 1;
+	JR(Ojr, Rlink);
+	ldc(0, Ro1);
+}
+
+static	void
+macmcal(void)
+{
+	ulong *cp1, *cp2;
+
+	IRR(Olw, O(Modlink,prog),Ri, Ro2);
+	IRR(Osw, O(Frame,lr),Ro1, Rlink);	// f->lr = return
+	cp1 = code;
+	BRRI(Obne, Ro2, Rzero, 0);		// CMPL ml->m->prog != 0
+	IRR(Oaddui, 0,Ro1, Rfp);		// R.FP = f
+
+	IRR(Osw, O(REG,st),Rreg, Rlink);
+	ldc((ulong)rmcall, Rpic);
+	IRR(Osw, O(REG,FP),Rreg, Ro1);
+	IRR(Osw, O(REG,dt),Rreg, Rj);
+	JR(Ojalr, Rpic);			// CALL	rmcall
+	xchg();
+	ldc((ulong)&R, Rreg);
+	IRR(Olw, O(REG,st),Rreg, Rlink);
+	IRR(Olw, O(REG,FP),Rreg, Rfp);
+	IRR(Olw, O(REG,MP),Rreg, Rmp);
+	JR(Ojr, Rlink);
+	delay();
+
+	*cp1 |= (code - cp1) - 1;
+	IRR(Olw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+	IRR(Osw, O(REG,M),Rreg, Ri);
+	IRR(Oaddui, 1,Ro2, Ro2);
+	IRR(Olw, O(Modlink,MP),Ri, Rmp);
+	IRR(Olw, O(Modlink,compiled),Ri, Ro1);
+	IRR(Osw, O(Heap,ref)-sizeof(Heap),Ri, Ro2);
+	cp2 = code;
+	BRRI(Obeq, Ro1,Rzero, 0);
+	IRR(Osw, O(REG,MP),Rreg, Rmp);
+
+	JR(Ojr, Rj);
+	delay();
+
+	*cp2 |= (code - cp2) - 1;
+	IRR(Osw, O(REG,FP),Rreg, Rfp);		// call to uncompiled code
+	IRR(Olw, O(REG,xpc),Rreg, Ro1);
+	JR(Ojr, Ro1);
+	IRR(Osw, O(REG,PC),Rreg, Rj); 
+}
+
+static	void
+macmfra(void)
+{
+	ldc((ulong)rmfram, Rpic);
+	IRR(Osw, O(REG,st),Rreg, Rlink);
+	IRR(Osw, O(REG,FP),Rreg, Rfp);
+	IRR(Osw, O(REG,s),Rreg, Ri);
+	IRR(Osw, O(REG,d),Rreg, Rj);
+	JR(Ojalr, Rpic);			// CALL	rmfram
+	xchg();
+	ldc((ulong)&R, Rreg);
+	IRR(Olw, O(REG,st),Rreg, Rlink);
+	IRR(Olw, O(REG,FP),Rreg, Rfp);
+	IRR(Olw, O(REG,MP),Rreg, Rmp);
+	JR(Ojr, Rlink);
+	delay();
+}
+
+static void
+macfram(void)
+{
+	ulong *cp;
+
+	/*
+	 * Ri has t
+	 */
+	IRR(Olw, O(Type,initialize),Ri, Rj);
+	IRR(Olw, O(Type,size),Ri, Ro3);		// MOVL $t->size, Ro3
+	IRR(Olw, O(REG,SP),Rreg, Ro2);		// MOVL	R.SP, Ro2
+	IRR(Olw, O(REG,TS),Rreg, Ro1);		// MOVL	R.TS, Ro1
+	RRR(Oaddu,Ro3,Ro2, Ro2);		// ADDL $t->size, Ro2
+	RRR(Osltu, Ro1,Ro2, Ro3);		// CMP Ro1,Ro2,Ro3
+	cp = code;
+	BRI(Obne,Ro3,0);			// BLT Ro3,**
+	delay();
+
+	IRR(Osw, O(REG,s),Rreg, Ri);		// MOVL	t, R.s
+	IRR(Osw, O(REG,st),Rreg, Rlink);	// MOVL	Rlink, R.st
+	ldc((ulong)extend, Rpic);
+	JR(Ojalr, Rpic);			// CALL	extend
+	IRR(Osw, O(REG,FP),Rreg, Rfp);		// MOVL	RFP, R.FP
+	ldc((ulong)&R, Rreg);
+	IRR(Olw, O(REG,st),Rreg, Rlink);	// reload registers
+	IRR(Olw, O(REG,FP),Rreg, Rfp);
+	IRR(Olw, O(REG,MP),Rreg, Rmp);
+	IRR(Olw, O(REG,s),Rreg, Ro1);		// return arg
+	JR(Ojr, Rlink);
+	delay();
+
+	*cp |= (code - cp) - 1;
+	IRR(Olw, O(REG,SP),Rreg, Ro1);
+	IRR(Osw, O(REG,SP),Rreg, Ro2);
+	IRR(Osw, O(Frame,mr),Ro1, Rzero);
+	JR(Ojr, Rj);				// return from tinit to main program
+	IRR(Osw, O(Frame,t),Ro1, Ri);
+}
+
+static void
+macmovm(void)
+{
+	ulong *cp1, *cp2;
+
+	/*
+	 * from = Ro1
+	 * to = Ro3
+	 * count = Ro2
+	 */
+
+	cp1 = code;
+	BRRI(Obeq, Ro2, Rzero, 0);
+	delay();
+
+	cp2 = code;
+	IRR(Olbu, 0,Ro1, Ri);
+	IRR(Oaddui, -1,Ro2, Ro2);
+	IRR(Osb, 0,Ro3, Ri);
+	IRR(Oaddui, 1,Ro1, Ro1);
+	BRRI(Obne, Ro2, Rzero, (cp2-code)-1);
+	IRR(Oaddui, 1,Ro3, Ro3);
+
+	*cp1 |= (code - cp1) - 1;
+	JR(Ojr, Rlink);
+	delay();
+}
+
+static void
+maccolr(void)
+{
+	ulong *cp;
+
+	IRR(Olw, 0,Ri, Ri);
+	IRR(Olw, O(Heap,color)-sizeof(Heap),Ro1, Ro3);
+
+	IRR(Olw, O(Heap,ref)-sizeof(Heap),Ro1, Ro2);
+
+	cp = code;
+	BRRI(Obeq, Ri, Ro3, 0);
+	IRR(Oaddui, 1,Ro2, Ro2);
+
+	ldc(propagator, Ro3);
+	IRR(Osw, O(Heap,color)-sizeof(Heap),Ro1, Ro3);
+	ldc((ulong)&nprop, Ro3);
+	IRR(Osw, 0,Ro3, Ro1);
+
+	*cp |= (code - cp) - 1;
+	JR(Ojr, Rlink);
+	IRR(Osw, O(Heap,ref)-sizeof(Heap),Ro1, Ro2);
+}
+
+static void
+macend(void)
+{
+}
+
+void
+comd(Type *t)
+{
+	int i, j, m, c;
+
+	IRR(Osw, O(REG,dt),Rreg, Rlink);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m) {
+				J(Ojal, base+macro[MacFRP]);
+				IRR(Olw, j,Rfp, Ri);
+			}
+			j += sizeof(WORD*);
+		}
+	}
+	IRR(Olw, O(REG,dt),Rreg, Rlink);
+	delay();
+	JR(Ojr, Rlink);
+	delay();
+}
+
+void
+comi(Type *t)
+{
+	int i, j, m, c;
+
+	ldc((ulong)H, Ri);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m)
+				IRR(Osw, j,Ro1, Ri);
+			j += sizeof(WORD*);
+		}
+	}
+	JR(Ojr, Rlink);
+	xchg();
+}
+
+void
+typecom(Type *t)
+{
+	int n;
+	ulong *tmp, *start;
+
+	if(t == nil || t->initialize != 0)
+		return;
+
+	tmp = mallocz(4096, 0);
+	if(tmp == nil)
+		return;
+	code = tmp;
+	comi(t);
+	n = code - tmp;
+	code = tmp;
+	comd(t);
+	n += code - tmp;
+	free(tmp);
+
+	n *= sizeof(*code);
+	code = mallocz(n, 0);
+	if(code == nil)
+		return;
+
+	start = code;
+	t->initialize = code;
+	comi(t);
+	t->destroy = code;
+	comd(t);
+
+	segflush(start, n);
+
+	if(cflag > 1)
+		print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+			t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+	Handler *h;
+	Except *e;
+
+	if((h = m->htab) == nil)
+		return;
+	for( ; h->etab != nil; h++){
+		h->pc1 = p[h->pc1];
+		h->pc2 = p[h->pc2];
+		for(e = h->etab; e->s != nil; e++)
+			e->pc = p[e->pc];
+		if(e->pc != -1)
+			e->pc = p[e->pc];
+	}
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+	Link *l;
+	Modl *e;
+	int i, n;
+	ulong *s, tmp[512];
+
+	patch = mallocz(size*sizeof(*patch), 0);
+	tinit = malloc(m->ntype*sizeof(*tinit));
+	base = 0;
+
+	if(!comvec) {
+		i = 10;		/* length of comvec */
+		code = malloc(i*sizeof(*code));
+		s = code;
+		preamble();
+		if(code >= (ulong*)(s + i))
+			urk("preamble");
+		comvec = (void*)s;
+		segflush(s, i*sizeof(*s));
+		if(cflag > 1) {
+			print("comvec\n");
+			while(s < code)
+				das(s++);
+		}/**/
+	}
+
+	mod = m;
+	n = 0;
+	regdelay = 0;
+	pass = 0;
+	nlit = 0;
+
+	for(i = 0; i < size; i++) {
+		code = tmp;
+		comp(&m->prog[i]);
+		if(code >= &tmp[nelem(tmp)]) {
+			print("%3d %D\n", i, &m->prog[i]);
+			urk("tmp ovflo");
+		}
+		patch[i] = n;
+		n += code - tmp;
+	}
+
+	for(i=0; macinit[i].f; i++) {
+		code = tmp;
+		(*macinit[i].f)();
+		macro[macinit[i].o] = n;
+		n += code - tmp;
+	}
+
+	base = malloc((n+nlit)*sizeof(*base));
+	if(cflag > 1)
+		print("dis=%5d %5d mips=%5d asm=%.8p lit=%d: %s\n",
+			size, size*sizeof(Inst), n, base, nlit, m->name);
+
+	pass++;
+	code = base;
+	litpool = base+n;
+	n = 0;
+	nlit = 0;
+	regdelay = 0;
+
+	for(i = 0; i < size; i++) {
+		s = code;
+		comp(&m->prog[i]);
+		if(patch[i] != n) {
+			print("%3d %D\n", i, &m->prog[i]);
+			urk(exCphase);
+		}
+		n += code - s;
+		if(cflag > 1) {
+			print("%3d %D\n", i, &m->prog[i]);
+			while(s < code)
+				das(s++);
+		}/**/
+	}
+
+	for(i=0; macinit[i].f; i++) {
+		if(macro[macinit[i].o] != n) {
+			print("macinit %d\n", macinit[i].o);
+			urk(exCphase);
+		}
+		s = code;
+		(*macinit[i].f)();
+		n += code - s;
+		if(cflag > 1) {
+			print("macinit %d\n", macinit[i].o);
+			while(s < code)
+				das(s++);
+		}/**/
+	}
+
+	for(l = m->ext; l->name; l++) {
+		l->u.pc = (Inst*)(base+patch[l->u.pc-m->prog]);
+		typecom(l->frame);
+	}
+	if(ml != nil) {
+		e = &ml->links[0];
+		for(i = 0; i < ml->nlinks; i++) {
+			e->u.pc = (Inst*)(base+patch[e->u.pc-m->prog]);
+			typecom(e->frame);
+			e++;
+		}
+	}
+	for(i = 0; i < m->ntype; i++) {
+		if(tinit[i] != 0)
+			typecom(m->type[i]);
+	}
+	patchex(m, patch);
+	m->entry = (Inst*)(base+patch[mod->entry-mod->prog]);
+	free(patch);
+	free(tinit);
+	free(m->prog);
+	m->prog = (Inst*)base;
+	m->compiled = 1;
+	segflush(base, n*sizeof(*base));
+	return 1;
+}
--- /dev/null
+++ b/libinterp/comp-power.c
@@ -1,0 +1,2261 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+/*
+ * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
+ */
+
+#define	ROMABLE	0	/* costs something to zero patch vectors */
+#define	RESCHED 1	/* check for interpreter reschedule */
+
+#define PATCH(ptr)		   *ptr |= ((ulong)code-(ulong)ptr) & 0xfffc
+
+#define T(r)	*((void**)(R.r))
+
+#define	XO(o,xo)	(((o)<<26)|((xo)<<1))
+
+/* botch: ARRR, AIRR, LRRR, etc have dest first (will fix soon) */
+
+#define	OPARRR(o,d,a,b)	((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define	ARRR(o,d,a,b)		gen((o)|((d)<<21)|((a)<<16)|((b)<<11))
+#define	AIRR(o,d,a,v)		gen((o)|((d)<<21)|((a)<<16)|((v)&0xFFFF))
+#define	IRR(o,v,a,d)	AIRR((o),(d),(a),(v))
+#define	RRR(o,b,a,d)	ARRR((o),(d),(a),(b))
+#define	LRRR(o,a,s,b)		ARRR((o),(s),(a),(b))
+#define	LIRR(o,a,s,v)		AIRR((o),(s),(a),(v))
+#define	Bx(li,aa)		gen((18<<26)|((li)&0x3FFFFFC)|((aa)<<1))
+#define	RLW(op,a,s,sh,mb,me) ((op)|(((s)&31L)<<21)|(((a)&31L)<<16)|(((sh)&31L)<<11)|\
+					(((mb)&31L)<<6)|(((me)&31L)<<1))
+#define	MFSPR(s, d)	gen(XO(31,339) | ((d)<<21) | ((s)<<11))
+#define	MTSPR(s, d)	gen(XO(31,467) | ((s)<<21) | ((d)<<11));
+
+#define	SLWI(d,a,n)	gen(slw((d),(a),(n),0))
+#define	LRET()	gen(Oblr)
+
+#define	SETR0()	if(macjit){	AIRR(Oaddi, Rzero, 0, 0); }		/* set R0 to 0 */
+
+/* assumes H can be formed from signed halfword */
+#define	CMPH(r)		AIRR(Ocmpi, Rcrf0, (r), (ulong)H);
+#define NOTNIL(r)	(CMPH((r)), CCALL(EQ, bounds))
+
+enum
+{
+	Rzero	= 0,	/* zero by design, not definition (P9/Inferno) */
+
+	Rsp = 1,
+	Rsb = 2,
+	Rarg	= 3,
+
+	Ro1	= 8,
+	Ro2	= 9,
+	Ro3	= 10,
+	Ri	= 11,
+	Rj	= 12,
+
+	Rmp	= 13,
+	Rfp	= 14,
+	Rreg	= 15,
+	Rta	= 16,		/* unused */
+	Rpic	= 17,		/* address for computed goto, for move to CTR or LR */
+
+	Rcon = 26,	/* constant builder; temporary */
+	/* 27, 28, 29, 30 are potentially external registers (P9/Inferno) */
+	Rlink = 31,	/* holds copies of LR; linker temp */
+
+	Rfret	= 0,
+	Rf1	= 4,
+	Rf2	= 6,
+	Rfcvi	= 27,	/* floating conversion constant (P9/Inferno) */
+	Rfzero = 28,	/* 0.0 (P9/Inferno) */
+	Rfhalf = 29,	/* 0.5 (P9/Inferno) */
+
+	Rlr = 8<<5,	/* SPR(LR) */
+	Rctr = 9<<5,	/* SPR(CTR) */
+
+	Rcrf0 = 0,		/* condition code field 0 */
+	Rcrf1 = 1<<2,	/* condition code field 1 */
+
+	Rcrbrel = 31,	/* condition code bit set to force relinquish */
+
+	Olwz	= XO(32, 0),
+	Olwzu = XO(33, 0),
+	Olwzx = XO(31, 23),
+	Olbz	= XO(34, 0),
+	Olbzu = XO(35, 0),
+	Olbzx = XO(31, 87),
+	Olfd	= XO(50, 0),
+	Olhz	= XO(40, 0),
+	Olhzx = XO(31, 279),
+	Ostw	= XO(36, 0),
+	Ostwu = XO(37, 0),
+	Ostwx = XO(31, 151),
+	Ostb	= XO(38, 0),
+	Ostbu = XO(39, 0),
+	Ostbx = XO(31, 215),
+	Osth	= XO(44,0),
+	Osthx = XO(31, 407),
+	Ostfd	= XO(54, 0),
+	Ostfdu	= XO(55, 0),
+
+	Oaddc	= XO(31,10),
+	Oadde	= XO(31, 138),
+	Oaddi	= XO(14, 0),	/* simm */
+	Oaddic_	= XO(13, 0),
+	Oaddis	= XO(15, 0),
+	Ocrxor	= XO(19, 193),
+	Ofadd	= XO(63, 21),
+	Ofcmpo	= XO(63, 32),
+	Ofctiwz	= XO(63, 15),
+	Ofsub	= XO(63, 20),
+	Ofmr	= XO(63, 72),
+	Ofmul	= XO(63, 25),
+	Ofdiv	= XO(63, 18),
+	Ofneg	= XO(63, 40),
+	Oori		= XO(24,0),	/* uimm */
+	Ooris	= XO(25,0),	/* uimm */
+	Odivw	= XO(31, 491),
+	Odivwu	= XO(31, 459),
+	Omulhw	= XO(31, 75),
+	Omulhwu	= XO(31, 11),
+	Omulli	= XO(7, 0),
+	Omullw	= XO(31, 235),
+	Osubf	= XO(31, 40),
+	Osubfc	= XO(31,8),
+	Osubfe	= XO(31,136),
+	Osubfic	= XO(8, 0),
+	Oadd	= XO(31, 266),
+	Oand	= XO(31, 28),
+	Oneg	= XO(31, 104),
+	Oor		= XO(31, 444),
+	Oxor		= XO(31, 316),
+
+	Ocmpi = XO(11, 0),
+	Ocmp = XO(31, 0),
+	Ocmpl = XO(31, 32),
+	Ocmpli = XO(10,0),
+
+	Orlwinm = XO(21, 0),
+	Oslw	= XO(31, 24),
+	Osraw = XO(31,792),
+	Osrawi =	XO(31,824),
+	Osrw = XO(31,536),
+
+	Cnone	= OPARRR(0,20,0,0),	/* unconditional */
+	Ceq		= OPARRR(0,12,2,0),
+	Cle		= OPARRR(0,4,1,0),
+	Clt		= OPARRR(0,12,0,0),
+	Cdnz	= OPARRR(0,16,0,0),
+	Cgt		= OPARRR(0,12,1,0),
+	Cne		= OPARRR(0,4,2,0),
+	Cge		= OPARRR(0,4,0,0),
+	Cle1		= OPARRR(0,4,5,0),	/* Cle on CR1 */
+	Crelq	= OPARRR(0,12,Rcrbrel,0),	/* relinquish */
+	Cnrelq	= OPARRR(0,4,Rcrbrel,0),	/* not relinquish */
+	Cpredict	= OPARRR(0,1,0,0),	/* reverse prediction */
+	Lk		= 1,
+	Aa		= 2,
+
+	Obeq	= OPARRR(16<<26,12,2,0),
+	Obge	= OPARRR(16<<26,4,0,0),
+	Obgt		= OPARRR(16<<26,12,1,0),
+	Oble		= OPARRR(16<<26,4,1,0),
+	Oblt		= OPARRR(16<<26,12,0,0),
+	Obne	= OPARRR(16<<26,4,2,0),
+
+	Ob		= XO(18, 0),
+	Obc		= XO(16, 0),
+	Obcctr	= XO(19,528),
+	Obcctrl	= Obcctr | Lk,
+	Obctr	= Obcctr | Cnone,
+	Obctrl	= Obctr | Lk,
+	Obclr	= XO(19, 16),
+	Oblr		= Obclr | Cnone,
+	Oblrl		= Oblr | Lk,
+
+	Olea	= 100,		// pseudo op
+
+	SRCOP	= (1<<0),
+	DSTOP	= (1<<1),
+	WRTPC	= (1<<2),	/* update R.PC */
+	TCHECK	= (1<<3),	/* check R.t for continue/ret */
+	NEWPC	= (1<<4),	/* goto R.PC */
+	DBRAN	= (1<<5),	/* dest is branch */
+	THREOP	= (1<<6),
+
+	Lg2Rune	= sizeof(Rune)==4? 2: 1,
+	ANDAND	= 1,
+	OROR,
+	EQAND,
+
+	MacRET	= 0,
+	MacFRP,
+	MacCASE,
+	MacFRAM,
+	MacCOLR,
+	MacMCAL,
+	MacMFRA,
+	MacCVTFW,
+	MacRELQ,
+	MacEND,
+	NMACRO
+};
+
+	void	(*comvec)(void);
+	int	macjit;
+extern	long	das(ulong*);
+static	ulong*	code;
+static	ulong*	base;
+static	ulong*	patch;
+static	int	pass;
+static	Module*	mod;
+static	ulong*	tinit;
+static	ulong*	litpool;
+static	int	nlit;
+static	ulong	macro[NMACRO];
+static	void	ldbigc(long, int);
+static	void	rdestroy(void);
+static	void	macret(void);
+static	void	macfrp(void);
+static	void	maccase(void);
+static	void	maccvtfw(void);
+static	void	macfram(void);
+static	void	maccolr(void);
+static	void	macend(void);
+static	void	macmcal(void);
+static	void	macmfra(void);
+static	void	macrelq(void);
+static	void	movmem(Inst*);
+
+struct
+{
+	int	o;
+	void	(*f)(void);
+} macinit[] =
+{
+	MacFRP,		macfrp,		/* decrement and free pointer */
+	MacRET,		macret,		/* return instruction */
+	MacCASE,	maccase,	/* case instruction */
+	MacCOLR,	maccolr,	/* increment and color pointer */
+	MacFRAM,	macfram,	/* frame instruction */
+	MacMCAL,	macmcal,	/* mcall bottom half */
+	MacMFRA,	macmfra,	/* punt mframe because t->initialize==0 */
+	MacCVTFW,	maccvtfw,
+	MacRELQ,		macrelq,	/* reschedule */
+	MacEND,		macend,
+	0
+};
+
+static void
+rdestroy(void)
+{
+	destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+	Frame *f;
+	Prog *p;
+
+	if((void*)R.dt == H)
+		error(exModule);
+
+	f = (Frame*)R.FP;
+	if(f == H)
+		error(exModule);
+
+	f->mr = nil;
+	((void(*)(Frame*))R.dt)(f);
+	R.SP = (uchar*)f;
+	R.FP = f->fp;
+	if(f->t == nil)
+		unextend(f);
+	else
+		freeptrs(f, f->t);
+	p = currun();
+	if(p->kill != nil)
+		error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+
+	t = (Type*)R.s;
+	if(t == H)
+		error(exModule);
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP = nsp;
+	f->t = t;
+	f->mr = nil;
+	initmem(t, f);
+	T(d) = f;
+}
+
+void
+urk(char *s)
+{
+	print("compile failed: %s\n", s);	// debugging
+	error(exCompile);	// production
+}
+
+static void
+gen(ulong o)
+{
+	*code++ = o;
+}
+
+static void
+br(ulong op, ulong disp)
+{
+	*code++ = op | (disp & 0xfffc);
+}
+
+static void
+mfspr(int d, int s)
+{
+	MFSPR(s, d);
+}
+
+static void
+mtspr(int d, int s)
+{
+	MTSPR(s, d);
+}
+
+static ulong
+slw(int d, int s, int v, int rshift)
+{
+	int m0, m1;
+
+	if(v < 0 || v > 32)
+		urk("slw v");
+	if(v < 0)
+		v = 0;
+	else if(v > 32)
+		v = 32;
+	if(rshift) {	/* shift right */
+		m0 = v;
+		m1 = 31;
+		v = 32-v;
+	} else {
+		m0 = 0;
+		m1 = 31-v;
+	}
+	return RLW(Orlwinm, d, s, v, m0, m1);
+}
+
+static void
+jr(int reg)
+{
+	mtspr(Rctr, reg);	/* code would be faster if this were loaded well before branch */
+	gen(Obctr);
+}
+
+static void
+jrl(int reg)
+{
+	mtspr(Rctr, reg);
+	gen(Obctrl);
+}
+
+static void
+jrc(int op, int reg)
+{
+	mtspr(Rctr, reg);
+	gen(Obcctr | op);
+}
+
+static long
+brdisp(ulong *dest)
+{
+	ulong d, top;
+
+	d = (ulong)dest - (ulong)code;
+	if(!ROMABLE)
+		return d & 0x3fffffc;
+	top = d>>25;
+	if(top == 0 || top == 0x7F){
+		/* fits in 26-bit signed displacement */
+		return d & 0x3fffffc;
+	}
+	return -1;
+}
+
+static void
+jmp(ulong *dest)
+{
+	long d;
+
+	if((d = brdisp(dest)) < 0){
+		ldbigc((ulong)dest, Rpic);	/* Rpic & Rctr must be free */
+		jr(Rpic);
+	} else
+		gen(Ob | d);
+}
+
+static void
+jmpl(ulong *dest)
+{
+	long d;
+
+	if((d = brdisp(dest)) < 0){
+		ldbigc((ulong)dest, Rpic);	/* Rpic must be free */
+		jrl(Rpic);
+	} else
+		gen(Ob | d | Lk);
+}
+
+static void
+jmpc(int op, ulong *dest)
+{
+	ldbigc((ulong)dest, Rpic);
+	jrc(op, Rpic);
+}
+
+static int
+bigc(long c)
+{
+	if(c >= -0x8000 && c <= 0x7FFF)
+		return 0;
+	return 1;
+}
+
+static void
+ldbigc(long c, int reg)
+{
+	AIRR(Oaddis, reg,Rzero,c>>16);
+	LIRR(Oori, reg,reg,c);
+}
+
+static void
+ldc(long c, int reg)
+{
+	if(!bigc(c))
+		AIRR(Oaddi, reg, Rzero, c);
+	else if((ulong)c <= 0xFFFF)
+		LIRR(Oori, reg, Rzero, c);
+	else if((c&0xFFFF) == 0)
+		LIRR(Ooris, reg, Rzero, c>>16);
+	else {
+		AIRR(Oaddis, reg,Rzero,c>>16);
+		LIRR(Oori, reg,reg,c);
+	}
+}
+
+static void
+mem(int inst, long disp, int rm, int r)
+{
+	if(bigc(disp)) {
+		ldc(disp, Rcon);
+		switch(inst){
+		default: 		urk("mem op"); break;
+		case Olea:		inst = Oadd; break;
+		case Olwz:	inst = Olwzx; break;
+		case Olbz:		inst = Olbzx; break;
+		case Olhz:		inst = Olhzx; break;
+		case Ostw:	inst = Ostwx; break;
+		case Ostb:		inst = Ostbx; break;
+		case Osth:		inst = Osthx; break;
+		}
+		ARRR(inst, r, Rcon, rm);
+	} else {
+		if(inst == Olea)
+			inst = Oaddi;
+		AIRR(inst, r, rm,disp);
+	}
+}
+
+static void
+opx(int mode, Adr *a, int op, int reg)
+{
+	ulong c;
+	int r, rx, lea;
+
+	lea = 0;
+	if(op == Olea){
+		lea = 1;
+		op = Oaddi;
+	}
+	switch(mode) {
+	case AFP:
+		c = a->ind;
+		if(bigc(c))
+			urk("bigc op1b 1");
+		AIRR(op, reg, Rfp,c);
+		break;
+	case AMP:
+		c = a->ind;
+		if(bigc(c))
+			urk("bigc op1b 2");
+		AIRR(op, reg, Rmp,c);
+		break;
+	case AIMM:
+		if(lea) {
+			if(a->imm != 0) {
+				ldc(a->imm, reg);
+				AIRR(Ostw, reg, Rreg,O(REG,st));
+			} else
+				AIRR(Ostw, Rzero, Rreg,O(REG,st));
+			AIRR(Oaddi, reg, Rreg,O(REG,st));
+		} else
+			ldc(a->imm, reg);
+		return;
+	case AIND|AFP:
+		r = Rfp;
+		goto offset;
+	case AIND|AMP:
+		r = Rmp;
+	offset:
+		c = a->i.s;
+		rx = Ri;
+		if(lea || op == Olwz)
+			rx = reg;
+		AIRR(Olwz, rx, r,a->i.f);
+		if(!lea || c != 0)
+			AIRR(op, reg, rx,c);
+		break;
+	}
+}
+
+static void
+opwld(Inst *i, int op, int reg)
+{
+	opx(USRC(i->add), &i->s, op, reg);
+}
+
+static void
+opwst(Inst *i, int op, int reg)
+{
+	opx(UDST(i->add), &i->d, op, reg);
+}
+
+static void
+op2(Inst *i, int op, int reg)
+{
+	int lea;
+
+	lea = 0;
+	if(op == Olea){
+		op = Oaddi;
+		lea = 1;
+	}
+	switch(i->add & ARM) {
+	case AXNON:
+		if(lea)
+			op = Olea;
+		opwst(i, op, reg);
+		return;
+	case AXIMM:
+		if(lea)
+			urk("op2/lea");
+		ldc((short)i->reg, reg);
+		return;
+	case AXINF:
+		IRR(op, i->reg,Rfp, reg);
+		break;
+	case AXINM:
+		IRR(op, i->reg,Rmp, reg);
+		break;
+	}
+}
+
+static void
+op12(Inst *i, int b1flag, int b2flag)
+{
+	int o1, o2;
+
+	o1 = Olwz;
+	if(b1flag)
+		o1 = Olbz;
+	o2 = Olwz;
+	if(b2flag)
+		o2 = Olbz;
+	if((i->add & ARM) == AXIMM) {
+		opwld(i, o1, Ro1);
+		op2(i, o2, Ro2);
+	} else {
+		op2(i, o2, Ro2);
+		opwld(i, o1, Ro1);
+	}
+}
+
+static void
+op13(Inst *i, int o1, int o2)
+{
+	opwld(i, o1, Ro1);
+	opwst(i, o2, Ro1);
+}
+
+static ulong
+branch(Inst *i)
+{
+	ulong rel;
+
+	if(base == 0)
+		return 0;
+	rel = (ulong)(base+patch[i->d.ins - mod->prog]);
+	rel -= (ulong)code;
+	if(rel & 3 || (long)rel <= -(1<<16) || (long)rel >= 1<<16)
+		urk("branch off");
+	return rel & 0xfffc;
+}
+
+static void
+schedcheck(Inst *i)
+{
+	ulong *cp;
+
+	if(i != nil && i->d.ins != nil && i->d.ins > i)
+		return;	/* only backwards jumps can loop: needn't check forward ones */
+	cp = code;
+	gen(Obc | Cnrelq | Cpredict);
+	jmpl(base+macro[MacRELQ]);
+	PATCH(cp);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+	nlit++;
+
+	ldbigc((ulong)litpool, Ro1);
+	IRR(Ostw, roff, Rreg, Ro1);
+
+	if(pass == 0)
+		return;
+
+	*litpool = imm;
+	litpool++;	
+}
+
+static void
+bounds(void)
+{
+	/* mem(Ostw, O(REG,FP), Rreg, Rfp); */
+	error(exBounds);
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+	ulong pc;
+
+	if(m & SRCOP) {
+		if(UXSRC(i->add) == SRC(AIMM))
+			literal(i->s.imm, O(REG, s));
+		else {
+			opwld(i, Olea, Ro1);
+			mem(Ostw, O(REG, s), Rreg, Ro1);
+		}
+	}
+	if(m & DSTOP) {
+		opwst(i, Olea, Ro3);
+		IRR(Ostw, O(REG,d),Rreg, Ro3);
+	}
+	if(m & WRTPC) {
+		pc = patch[i-mod->prog+1];
+		ldbigc((ulong)(base+pc), Ro1);
+		IRR(Ostw, O(REG,PC),Rreg, Ro1);
+	}
+	if(m & DBRAN) {
+		pc = patch[i->d.ins-mod->prog];
+		literal((ulong)(base+pc), O(REG, d));
+	}
+
+	switch(i->add&ARM) {
+	case AXNON:
+		if(m & THREOP) {
+			IRR(Olwz, O(REG,d),Rreg, Ro2);
+			IRR(Ostw, O(REG,m),Rreg, Ro2);
+		}
+		break;
+	case AXIMM:
+		literal((short)i->reg, O(REG,m));
+		break;
+	case AXINF:
+		mem(Olea, i->reg, Rfp, Ro2);
+		mem(Ostw, O(REG, m), Rreg, Ro2);
+		break;
+	case AXINM:
+		mem(Olea, i->reg, Rmp, Ro2);
+		mem(Ostw, O(REG, m), Rreg, Ro2);
+		break;
+	}
+	IRR(Ostw, O(REG,FP),Rreg, Rfp);
+
+	jmpl((ulong*)fn);
+
+	ldc((ulong)&R, Rreg);
+	SETR0();
+	if(m & TCHECK) {
+		IRR(Olwz, O(REG,t),Rreg, Ro1);
+		IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+		IRR(Ocmpi, 0, Ro1, Rcrf0);
+		mtspr(Rctr, Ro2);
+		gen(Obcctr | Cne);
+	}
+	IRR(Olwz, O(REG,FP),Rreg, Rfp);
+	IRR(Olwz, O(REG,MP),Rreg, Rmp);
+
+	if(m & NEWPC) {
+		IRR(Olwz, O(REG,PC),Rreg, Ro1);
+		jr(Ro1);
+	}
+}
+				
+static void
+comgoto(Inst *i)
+{
+	WORD *t, *e;
+
+	opwld(i, Olwz, Ro2);
+	opwst(i, Olea, Ro3);
+	SLWI(Ro2, Ro2, 2);
+	ARRR(Olwzx, Ro1, Ro3,Ro2);
+	jr(Ro1);
+
+	if(pass == 0)
+		return;
+
+	t = (WORD*)(mod->origmp+i->d.ind);
+	e = t + t[-1];
+	t[-1] = 0;
+	while(t < e) {
+		t[0] = (ulong)(base + patch[t[0]]);
+		t++;
+	}
+}
+
+static void
+comcase(Inst *i, int w)
+{
+	int l;
+	WORD *t, *e;
+
+	if(w != 0) {
+		opwld(i, Olwz, Ro1);		// v
+		opwst(i, Olea, Ro3);		// table
+		jmp(base+macro[MacCASE]);
+	}
+
+	t = (WORD*)(mod->origmp+i->d.ind+4);
+	l = t[-1];
+	
+	/* have to take care not to relocate the same table twice - 
+	 * the limbo compiler can duplicate a case instruction
+	 * during its folding phase
+	 */
+
+	if(pass == 0) {
+		if(l >= 0)
+			t[-1] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-1] = -l-1;			/* Set real count */
+	e = t + t[-1]*3;
+	while(t < e) {
+		t[2] = (ulong)(base + patch[t[2]]);
+		t += 3;
+	}
+	t[0] = (ulong)(base + patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+	int l;
+	WORD *t, *e;
+
+	t = (WORD*)(mod->origmp+i->d.ind+8);
+	l = t[-2];
+	if(pass == 0) {
+		if(l >= 0)
+			t[-2] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-2] = -l-1;			/* Set real count */
+	e = t + t[-2]*6;
+	while(t < e) {
+		t[4] = (ulong)base + patch[t[4]];
+		t += 6;
+	}
+	t[0] = (ulong)base + patch[t[0]];
+}
+
+static void
+commframe(Inst *i)
+{
+	ulong *cp1, *cp2;
+
+	opwld(i, Olwz, Ri);	// must use Ri for MacFRAM
+	CMPH(Ri);
+	cp1 = code;
+	br(Obeq, 0);
+
+	if((i->add&ARM) == AXIMM) {
+		mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame), Ri, Ri);
+	} else {
+		op2(i, Olwz, Ro2);
+		SLWI(Ro2, Ro2, 3);	// assumes sizeof(Modl) == 8
+		ARRR(Oadd, Ri, Ro2, Ro2);
+		mem(Olwz, OA(Modlink, links)+O(Modl, frame), Ri, Ri);
+	}
+
+	AIRR(Olwz, Ro2, Ri,O(Type,initialize));
+	AIRR(Ocmpi, Rcrf0, Ro2, 0);
+	cp2 = code;
+	br(Obne, 0);
+
+	opwst(i, Olea, Rj);
+
+	PATCH(cp1);
+	ldbigc((ulong)(base+patch[i-mod->prog+1]), Rpic);
+	mtspr(Rlr, Rpic);
+	jmp(base+macro[MacMFRA]);
+
+	PATCH(cp2);
+	jmpl(base+macro[MacFRAM]);
+	opwst(i, Ostw, Ro1);
+}
+
+static void
+commcall(Inst *i)
+{
+	opwld(i, Olwz, Ro1);				// f in Ro1
+	AIRR(Olwz, Ro3, Rreg,O(REG,M));
+	AIRR(Ostw, Rfp, Ro1,O(Frame,fp));			// f->fp = R.FP
+	AIRR(Ostw, Ro3, Ro1,O(Frame,mr));			// f->mr = R.M
+	opwst(i, Olwz, Ri);
+	if((i->add&ARM) == AXIMM) {
+		mem(Olwz, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), Ri, Rj);	// ml->entry in Rj
+	} else {
+		op2(i, Olwz, Rj);
+		SLWI(Rj, Rj, 3);	// assumes sizeof(Modl) == 8
+		ARRR(Oadd, Ri, Rj, Rj);
+		mem(Olwz, OA(Modlink, links)+O(Modl, u.pc), Rj, Rj);
+	}
+	jmpl(base+macro[MacMCAL]);
+}
+
+static int
+swapbraop(int b)
+{
+	switch(b) {
+	case Obge:
+		return Oble;
+	case Oble:
+		return Obge;
+	case Obgt:
+		return Oblt;
+	case Oblt:
+		return Obgt;
+	}
+	return b;
+}
+
+static void
+cbra(Inst *i, int op)
+{
+	if(RESCHED)
+		schedcheck(i);
+	if(UXSRC(i->add) == SRC(AIMM) && !bigc(i->s.imm)) {
+		op2(i, Olwz, Ro1);
+		AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm);
+		op = swapbraop(op);
+	} else if((i->add & ARM) == AXIMM) {
+		opwld(i, Olwz, Ro1);
+		AIRR(Ocmpi, Rcrf0, Ro1, i->reg);
+	} else {
+		op12(i, 0, 0);
+		ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+	}
+	br(op, branch(i));
+}
+
+static void
+cbrab(Inst *i, int op)
+{
+	if(RESCHED)
+		schedcheck(i);
+	if(UXSRC(i->add) == SRC(AIMM)) {
+		op2(i, Olbz, Ro1);
+		AIRR(Ocmpi, Rcrf0, Ro1, i->s.imm&0xFF);
+		op = swapbraop(op);
+	} else if((i->add & ARM) == AXIMM) {
+		opwld(i, Olbz, Ro1);
+		AIRR(Ocmpi, Rcrf0, Ro1, i->reg&0xFF);	// mask i->reg?
+	} else {
+		op12(i, 1, 1);
+		ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+	}
+	br(op, branch(i));
+}
+
+static void
+cbraf(Inst *i, int op)
+{
+	if(RESCHED)
+		schedcheck(i);
+	opwld(i, Olfd, Rf1);
+	op2(i, Olfd, Rf2);
+	ARRR(Ofcmpo, Rcrf0, Rf1, Rf2);
+	br(op, branch(i));
+}
+
+static void
+cbral(Inst *i, int cms, int cls, int mode)
+{
+	ulong *cp;
+
+	if(RESCHED)
+		schedcheck(i);
+	cp = nil;
+	opwld(i, Olea, Ri);
+	op2(i, Olea, Rj);
+	IRR(Olwz, 0,Ri, Ro1);
+	IRR(Olwz, 0,Rj, Ro2);
+	ARRR(Ocmp, Rcrf0, Ro1, Ro2);
+	switch(mode) {
+	case ANDAND:
+		cp = code;
+		br(cms, 0);
+		break;
+	case OROR:
+		br(cms, branch(i));
+		break;
+	case EQAND:
+		br(cms, branch(i));
+		cp = code;
+		br(Obne, 0);
+		break;
+	}
+	IRR(Olwz, 4,Ri, Ro1);
+	IRR(Olwz, 4,Rj, Ro2);
+	ARRR(Ocmpl, Rcrf0, Ro1, Ro2);
+	br(cls, branch(i));
+	if(cp)
+		PATCH(cp);
+}
+
+static void
+shrl(Inst *i)
+{
+//	int c;
+
+//	if(USRC(i->add) != AIMM) {
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		return;
+//	}
+/*
+	c = i->s.imm;
+	op2(i, Olea, Ro3);
+	IRR(Olwz, 0,Ro3, Ro1);
+	if(c >= 32) {
+		if((i->add&ARM) != AXNON)
+			opwst(i, Olea, Ro3);
+		SRR(Osra, 31, Ro1, Ro2);
+		IRR(Ostw, 0,Ro3, Ro2);
+		if(c >= 64) {
+			IRR(Ostw, 4,Ro3, Ro2);
+			return;
+		}
+		if(c > 32)
+			SRR(Osra, c-32, Ro1, Ro1);
+		IRR(Ostw, 4,Ro3, Ro1);
+		return;
+	}
+	IRR(Olwz, 4,Ro3, Ro2);
+	if((i->add&ARM) != AXNON)
+		opwst(i, Olea, Ro3);
+	if(c != 0) {
+		SRR(Osll, 32-c, Ro1, Ri);
+		SRR(Osra, c, Ro1, Ro1);
+		SRR(Osrl, c, Ro2, Ro2);
+		RRR(Oor, Ri, Ro2, Ro2);
+	}
+	IRR(Ostw, 4,Ro3, Ro2);
+	IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+shll(Inst *i)
+{
+//	int c;
+
+//	if(USRC(i->add) != AIMM) {
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		return;
+//	}
+/*
+	c = i->s.imm;
+	if(c >= 64) {
+		opwst(i, Olea, Ro3);
+		IRR(Ostw, 0,Ro3, Rzero);
+		IRR(Ostw, 4,Ro3, Rzero);
+		return;
+	}
+	op2(i, Olea, Ro3);
+	if(c >= 32) {
+		IRR(Olwz, 4,Ro3, Ro1);
+		if((i->add&ARM) != AXNON)
+			opwst(i, Olea, Ro3);
+		IRR(Ostw, 4,Ro3, Rzero);
+		if(c > 32)
+			SRR(Osll, c-32, Ro1, Ro1);
+		IRR(Ostw, 0,Ro3, Ro1);
+		return;
+	}
+	IRR(Olwz, 4,Ro3, Ro2);
+	IRR(Olwz, 0,Ro3, Ro1);
+	if((i->add&ARM) != AXNON)
+		opwst(i, Olea, Ro3);
+	if(c != 0) {
+		SRR(Osrl, 32-c, Ro2, Ri);
+		SRR(Osll, c, Ro2, Ro2);
+		SRR(Osll, c, Ro1, Ro1);
+		RRR(Oor, Ri, Ro1, Ro1);
+	}
+	IRR(Ostw, 4,Ro3, Ro2);
+	IRR(Ostw, 0,Ro3, Ro1);
+*/
+}
+
+static void
+compdbg(void)
+{
+	print("%s:%lud@%.8lux\n", R.M->m->name, *(ulong*)R.m, *(ulong*)R.s);
+}
+
+static void
+comp(Inst *i)
+{
+	int o, q, b;
+	ulong *cp, *cp1;
+	char buf[64];
+
+	if(0) {
+		Inst xx;
+		xx.add = AXIMM|SRC(AIMM);
+		xx.s.imm = (ulong)code;
+		xx.reg = i-mod->prog;
+		punt(&xx, SRCOP, compdbg);
+	}
+
+	switch(i->op) {
+	default:
+		snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+		error(buf);
+		break;
+	case IMCALL:
+		if((i->add&ARM) == AXIMM)
+			commcall(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case ISEND:
+	case IRECV:
+	case IALT:
+		punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+		break;
+	case ISPAWN:
+		punt(i, SRCOP|DBRAN, optab[i->op]);
+		break;
+	case IBNEC:
+	case IBEQC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+		punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+		break;
+	case ICASEC:
+		comcase(i, 0);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case ICASEL:
+		comcasel(i);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case IADDC:
+	case IMULL:
+	case IDIVL:
+	case IMODL:
+	case IMNEWZ:
+	case ILSRW:
+	case ILSRL:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IMFRAME:
+		if((i->add&ARM) == AXIMM)
+			commframe(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ILOAD:
+	case INEWA:
+	case INEWAZ:
+	case INEW:
+	case INEWZ:
+	case ISLICEA:
+	case ISLICELA:
+	case ICONSB:
+	case ICONSW:
+	case ICONSL:
+	case ICONSF:
+	case ICONSM:
+	case ICONSMP:
+	case ICONSP:
+	case IMOVMP:
+	case IHEADMP:
+	case IINSC:
+	case ICVTAC:
+	case ICVTCW:
+	case ICVTWC:
+	case ICVTCL:
+	case ICVTLC:
+	case ICVTFC:
+	case ICVTCF:
+	case ICVTFL:
+	case ICVTLF:
+	case ICVTRF:
+	case ICVTFR:
+	case ICVTWS:
+	case ICVTSW:
+	case IMSPAWN:
+	case ICVTCA:
+	case ISLICEC:
+	case INBALT:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case INEWCM:
+	case INEWCMP:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case INEWCB:
+	case INEWCW:
+	case INEWCF:
+	case INEWCP:
+	case INEWCL:
+		punt(i, DSTOP|THREOP, optab[i->op]);
+		break;
+	case IEXIT:
+		punt(i, 0, optab[i->op]);
+		break;
+	case ICVTWB:
+		op13(i, Olwz, Ostb);
+		break;
+	case ICVTBW:
+		op13(i, Olbz, Ostw);
+		break;
+	case IMOVB:
+		if(USRC(i->add) == AIMM && i->s.imm == 0) {
+			opwst(i, Ostb, Rzero);
+			break;
+		}
+		op13(i, Olbz, Ostb);
+		break;
+	case IMOVW:
+		if(USRC(i->add) == AIMM && i->s.imm == 0) {
+			opwst(i, Ostw, Rzero);
+			break;
+		}
+		op13(i, Olwz, Ostw);
+		break;
+	case ICVTLW:
+		opwld(i, Olea, Ro1);
+		AIRR(Olwz, Ro2, Ro1,4);
+		opwst(i, Ostw, Ro2);
+		break;
+	case ICVTWL:
+		opwld(i, Olwz, Ro1);
+		opwst(i, Olea, Ro2);
+		LRRR(Osrawi, Ro3, Ro1, 31);
+		AIRR(Ostw, Ro1, Ro2,4);
+		AIRR(Ostw, Ro3, Ro2,0);
+		break;
+	case IHEADM:
+		opwld(i, Olwz, Ro1);
+		AIRR(Oaddi, Ro1, Ro1,OA(List,data));
+		movmem(i);
+		break;
+	case IMOVM:
+		opwld(i, Olea, Ro1);
+		movmem(i);
+		break;
+	case IRET:
+		jmp(base+macro[MacRET]);
+		break;
+	case IFRAME:
+		if(UXSRC(i->add) != SRC(AIMM)) {
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		tinit[i->s.imm] = 1;
+		ldc((ulong)mod->type[i->s.imm], Ri);
+		jmpl(base+macro[MacFRAM]);
+		opwst(i, Ostw, Ro1);
+		break;
+	case ILEA:
+		op13(i, Olea, Ostw);
+		break;
+	case IHEADW:
+		opwld(i, Olwz, Ro1);
+		AIRR(Olwz, Ro1, Ro1,OA(List,data));
+		opwst(i, Ostw, Ro1);
+		break;
+	case IHEADF:
+		opwld(i, Olwz, Ro1);
+		AIRR(Olfd, Rf1, Ro1,OA(List,data));
+		opwst(i, Ostfd, Rf1);
+		break;
+	case IHEADB:
+		opwld(i, Olwz, Ro1);
+		AIRR(Olbz, Ro1, Ro1,OA(List,data));
+		opwst(i, Ostb, Ro1);
+		break;
+	case ITAIL:
+		opwld(i, Olwz, Ro1);
+		AIRR(Olwz, Ro1, Ro1,O(List,tail));
+		goto movp;
+	case IMOVP:
+		opwld(i, Olwz, Ro1);
+		goto movp;
+	case IHEADP:
+		opwld(i, Olwz, Ro1);
+		AIRR(Olwz, Ro1, Ro1,OA(List,data));
+	movp:
+		CMPH(Ro1);
+		cp = code;
+		br(Obeq, 0);
+		jmpl(base+macro[MacCOLR]);
+		PATCH(cp);
+		opwst(i, Olea, Ro3);
+		AIRR(Olwz, Ri, Ro3,0);
+		AIRR(Ostw, Ro1, Ro3,0);
+		jmpl(base+macro[MacFRP]);
+		break;
+	case ILENA:
+		opwld(i, Olwz, Ri);
+		ldc(0, Ro1);
+		CMPH(Ri);
+		cp = code;
+		br(Obeq, 0);
+		AIRR(Olwz, Ro1, Ri,O(Array,len));
+		PATCH(cp);
+		opwst(i, Ostw, Ro1);
+		break;
+	case ILENC:
+		opwld(i, Olwz, Ri);
+		ldc(0, Ro1);
+		CMPH(Ri);
+		cp = code;
+		br(Obeq, 0);
+		AIRR(Olwz, Ro1, Ri,O(String,len));
+		AIRR(Ocmpi, Rcrf0, Ro1, 0);
+		br(Obge, 2*4);	// BGE 2(PC); skip
+		ARRR(Oneg, Ro1, Ro1, 0);
+		PATCH(cp);
+		opwst(i, Ostw, Ro1);
+		break;
+	case ILENL:
+		opwld(i, Olwz, Ro1);
+		ldc(0, Ro3);
+		CMPH(Ro1);
+		cp = code;
+		br(Obeq, 0);
+
+		cp1 = code;
+		AIRR(Olwz, Ro1, Ro1,O(List,tail));
+		AIRR(Oaddi, Ro3, Ro3, 1);
+		CMPH(Ro1);
+		br(Obne, ((ulong)cp1-(ulong)code));
+
+		PATCH(cp);
+		opwst(i, Ostw, Ro3);
+		break;
+	case IMOVL:
+		opwld(i, Olea, Ro1);
+		AIRR(Olwz, Ro2, Ro1,0);
+		AIRR(Olwz, Ro3, Ro1,4);
+		opwst(i, Olea, Ro1);
+		AIRR(Ostw, Ro2, Ro1,0);
+		AIRR(Ostw, Ro3, Ro1,4);
+		break;
+	case IMOVF:
+		opwld(i, Olfd, Rf1);
+		opwst(i, Ostfd, Rf1);
+		break;
+	case ICVTFW:
+		if(!macjit){
+			opwld(i, Olfd, Rf1);
+			jmpl(base+macro[MacCVTFW]);
+			opwst(i, Ostw, Ro1);
+			break;
+		}
+	case ICVTWF:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case INEGF:
+		opwld(i, Olfd, Rf1);
+		ARRR(Ofneg, Rf2, 0, Rf1);
+		opwst(i, Ostfd, Rf2);
+		break;
+	case IXORL:
+	case IORL:
+	case IANDL:
+	case IADDL:
+	case ISUBL:
+		opwld(i, Olea, Ro1);
+		op2(i, Olea, Ro3);
+
+		AIRR(Olwz, Rj, Ro1,4);	/* ls */
+		AIRR(Olwz, Ro2, Ro3,4);
+		AIRR(Olwz, Ri, Ro1,0);	/* ms */
+		AIRR(Olwz, Ro1, Ro3,0);
+
+		switch(i->op) {
+		case IXORL:
+			o = Oxor;
+			goto l1;
+		case IORL:
+			o = Oor;
+			goto l1;
+		case IANDL:
+			o = Oand;
+		l1:
+			LRRR(o, Ro1, Ri, Ro1);
+			LRRR(o, Ro2, Rj, Ro2);
+			break;
+		case IADDL:
+			RRR(Oaddc, Rj,Ro2, Ro2);
+			RRR(Oadde, Ri,Ro1, Ro1);
+			break;
+		case ISUBL:
+			RRR(Osubfc, Ro2,Rj, Ro2);
+			RRR(Osubfe, Ro1,Ri, Ro1);
+			break;
+		}
+		if((i->add&ARM) != AXNON)
+			opwst(i, Olea, Ro3);
+		IRR(Ostw, 0,Ro3, Ro1);
+		IRR(Ostw, 4,Ro3, Ro2);
+		break;
+	case ISHLL:
+		shll(i);
+		break;
+	case ISHRL:
+		shrl(i);
+		break;
+	case IADDF:	o = Ofadd; goto f1;
+	case ISUBF:	o = Ofsub; goto f1;
+	case IMULF:	o = Ofmul; goto f1;
+	case IDIVF:	o = Ofdiv; goto f1;
+	f1:
+		opwld(i, Olfd, Rf1);
+		op2(i, Olfd, Rf2);
+		if(o == Ofmul)
+			gen(o | (Rf2<<21) | (Rf2<<16) | (Rf1<<6));	/* odd one out: op D,A,-,C */
+		else
+			ARRR(o, Rf2, Rf2, Rf1);
+		opwst(i, Ostfd, Rf2);
+		break;
+
+	case IBEQF:
+		cbraf(i, Obeq);
+		break;
+	case IBGEF:
+		cbraf(i, Obge);
+	case IBGTF:
+		cbraf(i, Obgt);
+		break;
+	case IBLEF:
+		cbraf(i, Oble);
+		break;
+	case IBLTF:
+		cbraf(i, Oblt);
+		break;
+	case IBNEF:
+		cbraf(i, Obne);
+		break;
+
+	case IBLTB:
+		cbrab(i, Oblt);
+		break;
+	case IBLEB:
+		cbrab(i, Oble);
+		break;
+	case IBGTB:
+		cbrab(i, Obgt);
+		break;
+	case IBGEB:
+		cbrab(i, Obge);
+		break;
+	case IBEQB:
+		cbrab(i, Obeq);
+		break;
+	case IBNEB:
+		cbrab(i, Obne);
+		break;
+
+	case IBLTW:
+		cbra(i, Oblt);
+		break;
+	case IBLEW:
+		cbra(i, Oble);
+		break;
+	case IBGTW:
+		cbra(i, Obgt);
+		break;
+	case IBGEW:
+		cbra(i, Obge);
+		break;
+	case IBEQW:
+		cbra(i, Obeq);
+		break;
+	case IBNEW:
+		cbra(i, Obne);
+		break;
+
+	case IBEQL:
+		cbral(i, Obne, Obeq, ANDAND);
+		break;
+	case IBNEL:
+		cbral(i, Obne, Obne, OROR);
+		break;
+	case IBLTL:
+		cbral(i, Oblt, Oblt, EQAND);
+		break;
+	case IBLEL:
+		cbral(i, Oblt, Oble, EQAND);
+		break;
+	case IBGTL:
+		cbral(i, Obgt, Obgt, EQAND);
+		break;
+	case IBGEL:
+		cbral(i, Obgt, Obge, EQAND);
+		break;
+
+	case ISUBB:
+	case IADDB:
+	case IANDB:
+	case IORB:
+	case IXORB:
+	case IMODB:
+	case IDIVB:
+	case IMULB:
+		b = 1;
+		op12(i, b, b);
+		goto s2;
+	case ISHLB:
+	case ISHRB:
+		b = 1;
+		op12(i, 0, b);
+		goto s2;
+	case ISUBW:
+	case IADDW:
+	case IANDW:
+	case IORW:
+	case IXORW:
+	case ISHLW:
+	case ISHRW:
+	case IMODW:
+	case IDIVW:
+	case IMULW:
+		b = 0;
+		op12(i, b, b);
+	s2:
+		q = 0;
+		switch(i->op) {
+		case ISUBB:
+		case ISUBW:	o = Osubf; q = Osubfic;
+			// TO DO: if immediate operand, should use opcode q
+			USED(q);
+			ARRR(o, Ro3, Ro1, Ro2);
+			break;
+		case IADDB:
+		case IADDW:	o = Oadd; q = Oaddi; goto c1;
+		case IMULB:
+		case IMULW:	o = Omullw; q = Omulli; goto c1;
+		case IDIVB:
+		case IDIVW:	o = Odivw; goto c1;
+		c1:
+			// TO DO: if immediate operand, should use opcode q
+			USED(q);
+			ARRR(o, Ro3, Ro2, Ro1);
+			break;
+		case IANDB:
+		case IANDW:	o = Oand; goto c2;
+		case IORB:
+		case IORW:	o = Oor; goto c2;
+		case IXORB:
+		case IXORW:	o = Oxor; goto c2;
+		case ISHLB:
+		case ISHLW:	o = Oslw; goto c2;
+		case ISHRB:
+		case ISHRW:	o = Osraw; goto c2;
+		c2:
+			LRRR(o, Ro3,Ro2,Ro1);
+			break;
+		case IMODB:
+		case IMODW:
+			ARRR(Odivw, Ro3, Ro2, Ro1);
+			ARRR(Omullw, Ro3, Ro3, Ro1);
+			ARRR(Osubf, Ro3, Ro3, Ro2);
+			break;
+		}
+		opwst(i, b? Ostb: Ostw, Ro3);
+		break;
+	case ICALL:
+		opwld(i, Olwz, Ro1);	/* f = T(s) */
+		ldbigc((ulong)(base+patch[i-mod->prog+1]), Ro2);	/* R.pc */
+		AIRR(Ostw, Rfp, Ro1,O(Frame,fp));	/* f->fp = R.fp */
+		AIRR(Ostw, Ro2, Ro1,O(Frame,lr));	/* f->lr = R.pc */
+		AIRR(Oaddi, Rfp, Ro1, 0);	/* R.fp = (uchar*)f */
+		jmp(base+patch[i->d.ins - mod->prog]);
+		break;
+	case IJMP:
+		if(RESCHED)
+			schedcheck(i);
+		jmp(base+patch[i->d.ins - mod->prog]);
+		break;
+	case IGOTO:
+		comgoto(i);
+		break;
+	case IINDC:
+		opwld(i, Olwz, Ro1);			// Ro1 = string
+		if((i->add&ARM) != AXIMM)
+			op2(i, Olwz, Ro2);			// Ro2 = i
+		AIRR(Olwz, Ri, Ro1,O(String,len));	// len<0 => index Runes, otherwise bytes
+		AIRR(Oaddi, Ro1, Ro1,O(String,data));
+		AIRR(Ocmpi, Rcrf0, Ri, 0);
+		if(bflag){
+			br(Obge, 2*4);
+			ARRR(Oneg, Ri, Ri, 0);
+			if((i->add&ARM) != AXIMM)
+				ARRR(Ocmpl, Rcrf1, Ri, Ro2);		/* CMPU len, i */
+			else
+				AIRR(Ocmpli, Rcrf1, Ri, i->reg);	/* CMPU len, i */
+			jmpc(Cle1, (ulong*)bounds);
+		}
+		cp = code;
+		br(Obge, 0);
+		if((i->add&ARM) != AXIMM){
+			SLWI(Ro2, Ro2, Lg2Rune);
+			if(sizeof(Rune) == 4)
+				ARRR(Olwz, Ro3, Ro1, Ro2);
+			else
+				ARRR(Olhzx, Ro3, Ro1, Ro2);
+		} else
+			mem(Olwz, (short)i->reg<<Lg2Rune, Ro1, Ro3);	/* BUG: TO DO: 16-bit signed displacement */
+		gen(Ob | (2*4));	// skip
+		PATCH(cp);
+		if((i->add&ARM) != AXIMM)
+			ARRR(Olbzx, Ro3, Ro1, Ro2);
+		else
+			AIRR(Olbz, Ro3, Ro1,i->reg);
+		opwst(i, Ostw, Ro3);
+		break;
+	case IINDX:
+	case IINDB:
+	case IINDF:
+	case IINDW:
+	case IINDL:
+		opwld(i, Olwz, Ro1);			/* Ro1 = a */
+		opwst(i, Olwz, Ro3);			/* Ro3 = i */
+		if(bflag){
+			AIRR(Olwz, Ro2, Ro1, O(Array, len));		/* Ro2 = a->len */
+			ARRR(Ocmpl, Rcrf0, Ro3, Ro2);			/* CMPU i, len */
+			jmpc(Cge, (ulong*)bounds);
+		}
+		// TO DO: check a != H
+		AIRR(Olwz, Ro2, Ro1,O(Array,data));	/* Ro2 = a->data */
+		switch(i->op) {
+		case IINDX:
+			AIRR(Olwz, Ri, Ro1,O(Array,t));			// Ri = a->t
+			AIRR(Olwz, Ro1, Ri,O(Type,size));		// Ro1 = a->t->size
+			ARRR(Omullw, Ro3, Ro3, Ro1);			// Ro3 = i*size
+			break;
+		case IINDL:
+		case IINDF:
+			SLWI(Ro3, Ro3, 3);		/* Ro3 = i*8 */
+			break;
+		case IINDW:
+			SLWI(Ro3, Ro3, 2);		/* Ro3 = i*4 */
+			break;
+		case IINDB:
+			/* no further work */
+			break;
+		}
+		ARRR(Oadd, Ro2, Ro2, Ro3);		/* Ro2 = i*size + data */
+		op2(i, Ostw, Ro2);
+		break;
+	case ICASE:
+		comcase(i, 1);
+		break;
+	case IRAISE:
+		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case IMULX:
+	case IDIVX:
+	case ICVTXX:
+	case IMULX0:
+	case IDIVX0:
+	case ICVTXX0:
+	case IMULX1:
+	case IDIVX1:
+	case ICVTXX1:
+	case ICVTFX:
+	case ICVTXF:
+	case IEXPW:
+	case IEXPL:
+	case IEXPF:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ISELF:
+		punt(i, DSTOP, optab[i->op]);
+		break;
+	}
+}
+
+enum {
+	PREFLEN = 20,	/* max instruction words in comvec */
+};
+
+static void
+preamble(void)
+{
+	ulong *s;
+
+	if(comvec != nil)
+		return;
+	s = code = malloc(PREFLEN*sizeof(*code));
+	if(s == nil)
+		error(exNomem);
+	ldc((ulong)&R, Rreg);
+	SETR0();
+	mfspr(Rlink, Rlr);
+	AIRR(Ostw, Rlink, Rreg,O(REG,xpc));
+	AIRR(Olwz, Ri, Rreg,O(REG,PC));
+	mtspr(Rctr, Ri);
+	AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+	AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+	gen(Obctr);
+	if(code >= (ulong*)(s + PREFLEN))
+		urk("preamble");
+	comvec = (void*)s;
+	segflush(s, PREFLEN*sizeof(*s));
+	if(cflag > 3) {
+		print("comvec\n");
+		while(s < code)
+			s += das(s);
+	}
+}
+
+static void
+macfrp(void)
+{
+	CMPH(Ri);
+	gen(Obclr | Ceq);	// arg == $H? => return
+
+	AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+	AIRR(Oaddic_, Rj, Ro2, -1);		// ref(arg)-- and test
+	AIRR(Ostw, Rj, Ri,O(Heap,ref)-sizeof(Heap));
+	gen(Obclr | Cne);		// ref(arg) nonzero? => return
+
+	AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap));	// restore ref count of 1 for destroy
+	mfspr(Rlink, Rlr);
+	AIRR(Ostw, Rlink, Rreg,O(REG,st));
+	AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+	AIRR(Ostw, Ri, Rreg,O(REG,s));
+
+	jmpl((ulong*)rdestroy);				// CALL	destroy
+
+	ldc((ulong)&R, Rreg);
+	SETR0();
+	AIRR(Olwz, Rlink, Rreg,O(REG,st));
+	mtspr(Rlr, Rlink);
+	AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+	AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+	LRET();
+}
+
+static void
+macret(void)
+{
+	ulong *cp1, *cp2, *cp3, *cp4, *cp5, *linterp;
+	Inst i;
+
+	AIRR(Olwz, Ro1, Rfp,O(Frame,t));
+	AIRR(Ocmpi, Rcrf0, Ro1, 0);
+	cp1 = code;
+	br(Obeq, 0);		// t(Rfp) == 0
+
+	AIRR(Olwz, Rpic, Ro1,O(Type,destroy));
+	AIRR(Ocmpi, Rcrf0, Rpic, 0);
+	cp2 = code;
+	br(Obeq, 0);		// destroy(t(fp)) == 0
+
+	AIRR(Olwz, Ro2, Rfp,O(Frame,fp));
+	AIRR(Ocmpi, Rcrf0, Ro2, 0);
+	cp3 = code;
+	br(Obeq, 0);		// fp(Rfp) == 0
+
+	AIRR(Olwz, Ro3, Rfp,O(Frame,mr));
+	AIRR(Ocmpi, Rcrf0, Ro3, 0);
+	cp4 = code;
+	br(Obeq, 0);		// mr(Rfp) == 0
+
+	AIRR(Olwz, Ro2, Rreg,O(REG,M));
+	AIRR(Olwz, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+	AIRR(Oaddic_, Ro3, Ro3, -1);	// --ref(arg), set cc
+	cp5 = code;
+	br(Obeq, 0);	// --ref(arg) == 0?
+	AIRR(Ostw, Ro3, Ro2,O(Heap,ref)-sizeof(Heap));
+
+	AIRR(Olwz, Ro1, Rfp,O(Frame,mr));
+	AIRR(Ostw, Ro1, Rreg,O(REG,M));
+	AIRR(Olwz, Rmp, Ro1,O(Modlink,MP));
+	AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+	AIRR(Olwz, Ro3, Ro1,O(Modlink,compiled));	// R.M->compiled?
+	AIRR(Ocmpi, Rcrf0, Ro3, 0);
+	linterp = code;
+	br(Obeq, 0);
+
+	PATCH(cp4);
+	jrl(Rpic);			// call destroy(t(fp))
+	AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+	AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+	AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+	AIRR(Ostw, Rfp, Rreg,O(REG,FP));	// R.FP = Rfp
+	jr(Ro1);				// goto lr(Rfp)
+
+	PATCH(linterp);
+	jrl(Rpic);			// call destroy(t(fp))
+	AIRR(Ostw, Rfp, Rreg,O(REG,SP));
+	AIRR(Olwz, Ro1, Rfp,O(Frame,lr));
+	AIRR(Olwz, Rfp, Rfp,O(Frame,fp));
+	AIRR(Ostw, Ro1, Rreg,O(REG,PC));	// R.PC = fp->lr
+	AIRR(Ostw, Rfp, Rreg,O(REG,FP));	// R.FP = Rfp
+	AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+	mtspr(Rlr, Rpic);
+	gen(Oblr);		// return to xec uncompiled code
+
+	PATCH(cp1);
+	PATCH(cp2);
+	PATCH(cp3);
+	PATCH(cp5);
+	i.add = AXNON;
+	punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccase(void)
+{
+	ulong *cp1, *cp2, *cp3, *loop;
+
+/*
+ * Ro1 = value (input arg), t
+ * Ro2 = count, n
+ * Ro3 = table pointer (input arg)
+ * Ri  = n/2, n2
+ * Rj  = pivot element t+n/2*3, l
+ */
+
+	IRR(Olwz, 0,Ro3, Ro2);		// count
+	IRR(Oaddi, 0,Ro3, Rlink);	// initial table pointer
+
+	loop = code;			// loop:
+	AIRR(Ocmpi, Rcrf0, Ro2, 0);
+	cp1 = code;
+	br(Oble, 0);	// n <= 0? goto out
+	LRRR(Osrawi, Ri, Ro2, 1);		// n2 = n>>1
+	SLWI(Rj, Ri, 1);
+	ARRR(Oadd, Rj, Rj, Ri);
+	SLWI(Rj, Rj, 2);
+	ARRR(Oadd, Rj, Rj, Ro3);	// l = t + n2*3;
+	AIRR(Olwz, Rpic, Rj,4);
+	ARRR(Ocmp, Rcrf0, Ro1, Rpic);
+	cp2 = code;
+	br(Oblt, 0);		// v < l[1]? goto low
+
+	IRR(Olwz, 8,Rj, Rpic);
+	ARRR(Ocmp, Rcrf0, Ro1, Rpic);
+	cp3 = code;
+	br(Obge, 0);		// v >= l[2]? goto high
+
+	IRR(Olwz, 12,Rj, Ro3);		// found
+	jr(Ro3);
+
+	PATCH(cp2);	// low:
+	IRR(Oaddi, 0, Ri, Ro2);	// n = n2
+	jmp(loop);
+
+	PATCH(cp3);	// high:
+	IRR(Oaddi, 12, Rj, Ro3);	// t = l+3;
+	IRR(Oaddi, 1, Ri, Rpic);
+	RRR(Osubf, Ro2, Rpic, Ro2);	// n -= n2 + 1
+	jmp(loop);
+
+	PATCH(cp1);	// out:
+	IRR(Olwz, 0,Rlink, Ro2);		// initial n
+	SLWI(Ro3, Ro2, 1);
+	RRR(Oadd, Ro3, Ro2, Ro2);
+	SLWI(Ro2, Ro2, 2);
+	RRR(Oadd, Ro2, Rlink, Rlink);
+	IRR(Olwz, 4,Rlink, Ro3);		// (initial t)[n*3+1]
+	jr(Ro3);
+}
+
+static	void
+macmcal(void)
+{
+	ulong *cp;
+
+	AIRR(Olwz, Ro2, Ri,O(Modlink,prog));
+	mfspr(Rlink, Rlr);
+	AIRR(Ostw, Rlink, Ro1,O(Frame,lr));	// f->lr = return
+	AIRR(Ocmpi, Rcrf0, Ro2, 0);
+	AIRR(Oaddi, Rfp, Ro1, 0);		// R.FP = f
+	cp = code;
+	br(Obne, 0);		// CMPL ml->m->prog != 0
+
+	AIRR(Ostw, Rlink, Rreg,O(REG,st));
+	AIRR(Ostw, Ro1, Rreg,O(REG,FP));
+	AIRR(Ostw, Rj, Rreg,O(REG,dt));
+	jmpl((ulong*)rmcall);			// CALL	rmcall
+	ldc((ulong)&R, Rreg);
+	SETR0();
+	AIRR(Olwz, Rlink, Rreg,O(REG,st));
+	mtspr(Rlr, Rlink);
+	AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+	AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+	gen(Oblr);	// RET
+
+	PATCH(cp);
+	AIRR(Olwz, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+	AIRR(Ostw, Ri, Rreg,O(REG,M));
+	AIRR(Oaddi, Ro2, Ro2, 1);
+	AIRR(Olwz, Rmp, Ri,O(Modlink,MP));
+	AIRR(Ostw, Ro2, Ri,O(Heap,ref)-sizeof(Heap));
+	AIRR(Ostw, Rmp, Rreg,O(REG,MP));
+	AIRR(Olwz, Ro2, Ri,O(Modlink,compiled));
+	AIRR(Ocmpi, Rcrf0, Ro2, 0);
+	mtspr(Rctr, Rj);
+	gen(Obcctr | Cne);	// return to compiled code
+
+	AIRR(Ostw, Rfp, Rreg,O(REG,FP));	// R.FP = Rfp
+	AIRR(Ostw, Rj, Rreg,O(REG,PC));	// R.PC = Rj
+	AIRR(Olwz, Rpic, Rreg,O(REG,xpc));
+	mtspr(Rlr, Rpic);
+	gen(Oblr);		// return to xec uncompiled code
+}
+
+static	void
+macmfra(void)
+{
+	mfspr(Rlink, Rlr);
+	AIRR(Ostw, Rlink, Rreg,O(REG,st));
+	AIRR(Ostw, Rfp, Rreg,O(REG,FP));
+	AIRR(Ostw, Ri, Rreg,O(REG,s));
+	AIRR(Ostw, Rj, Rreg,O(REG,d));
+	jmpl((ulong*)rmfram);
+	ldc((ulong)&R, Rreg);
+	SETR0();
+	AIRR(Olwz, Rlink, Rreg,O(REG,st));
+	mtspr(Rlr, Rlink);
+	AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+	AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+	gen(Oblr);
+}
+
+static void
+macfram(void)
+{
+	ulong *cp;
+
+	/*
+	 * Ri has t
+	 */
+	AIRR(Olwz, Ro2, Ri,O(Type,size));		// MOVW t->size, Ro3
+	AIRR(Olwz, Ro1, Rreg,O(REG,SP));		// MOVW	R.SP, Ro1  (=(Frame*)R.SP)
+	AIRR(Olwz, Ro3, Rreg,O(REG,TS));		// MOVW	R.TS, tmp
+	ARRR(Oadd, Ro2, Ro2, Ro1);		// ADD Ro1, t->size, nsp
+	ARRR(Ocmpl, Rcrf0, Ro2, Ro3);		// CMPU nsp,tmp (nsp >= R.TS?)
+	cp = code;
+	br(Obge, 0);			// BGE expand
+
+	AIRR(Olwz, Rj, Ri,O(Type,initialize));
+	mtspr(Rctr, Rj);
+	AIRR(Ostw, Ro2, Rreg,O(REG,SP));		// R.SP = nsp
+	AIRR(Ostw, Rzero, Ro1,O(Frame,mr));	// Ro1->mr = nil
+	AIRR(Ostw, Ri, Ro1,O(Frame,t));		// Ro1->t = t
+	gen(Obctr);				// become t->init(Ro1), returning Ro1
+
+	PATCH(cp);					// expand:
+	AIRR(Ostw, Ri, Rreg,O(REG,s));		// MOVL	t, R.s
+	mfspr(Rlink, Rlr);
+	AIRR(Ostw, Rlink, Rreg,O(REG,st));	// MOVL	Rlink, R.st
+	AIRR(Ostw, Rfp, Rreg,O(REG,FP));		// MOVL	RFP, R.FP
+	jmpl((ulong*)extend);		// CALL	extend
+	ldc((ulong)&R, Rreg);
+	SETR0();
+	AIRR(Olwz, Rlink, Rreg,O(REG,st));	// reload registers
+	mtspr(Rlr, Rlink);
+	AIRR(Olwz, Rfp, Rreg,O(REG,FP));
+	AIRR(Olwz, Rmp, Rreg,O(REG,MP));
+	AIRR(Olwz, Ro1, Rreg,O(REG,s));		// return R.s set by extend
+	LRET();	// RET
+}
+
+static void
+movloop(int ldu, int stu, int adj)
+{
+	ulong *cp;
+
+	AIRR(Oaddi, Ro1, Ro1, -adj);	// adjust for update ld/st
+	AIRR(Oaddi, Ro3, Ro3, -adj);
+	mtspr(Rctr, Ro2);
+
+	cp = code;			// l0:
+	AIRR(ldu, Ri, Ro1,adj);
+	AIRR(stu, Ri, Ro3,adj);
+	br(Obc | Cdnz, ((ulong)cp-(ulong)code));	// DBNZ l0
+}
+
+static void
+movmem(Inst *i)
+{
+	ulong *cp;
+
+	// source address already in Ro1
+	if((i->add&ARM) != AXIMM){
+		op2(i, Olwz, Ro2);
+		AIRR(Ocmpi, Rcrf0, Ro2, 0);
+		cp = code;
+		br(Oble, 0);
+		opwst(i, Olea, Ro3);
+		movloop(Olbzu, Ostbu, 1);
+		PATCH(cp);
+		return;
+	}
+	switch(i->reg){
+	case 4:
+		AIRR(Olwz, Ro2, Ro1,0);
+		opwst(i, Ostw, Ro2);
+		break;
+	case 8:
+		AIRR(Olwz, Ro2, Ro1,0);
+		opwst(i, Olea, Ro3);
+		AIRR(Olwz, Ro1, Ro1,4);
+		AIRR(Ostw, Ro2, Ro3,0);
+		AIRR(Ostw, Ro1, Ro3,4);
+		break;
+	default:
+		// could use lwsi/stwsi loop...
+		opwst(i, Olea, Ro3);
+		if((i->reg&3) == 0) {
+			ldc(i->reg>>2, Ro2);
+			movloop(Olwzu, Ostwu, 4);
+		} else {
+			ldc(i->reg, Ro2);
+			movloop(Olbzu, Ostbu, 1);
+		}
+		break;
+	}
+}
+
+static void
+maccolr(void)
+{
+	ldbigc((ulong)&mutator, Ri);
+	AIRR(Olwz, Ri, Ri,0);
+	AIRR(Olwz, Ro3, Ro1,O(Heap,color)-sizeof(Heap));	// h->color
+
+	AIRR(Olwz, Ro2, Ro1,O(Heap,ref)-sizeof(Heap));	// h->ref
+
+	ARRR(Ocmp, Rcrf0, Ri, Ro3);
+	AIRR(Oaddi, Ro2, Ro2, 1);	// h->ref++
+	AIRR(Ostw, Ro2, Ro1,O(Heap,ref)-sizeof(Heap));
+	gen(Obclr | Ceq);	// return if h->color == mutator
+
+	ldc(propagator, Ro3);
+	AIRR(Ostw, Ro3, Ro1,O(Heap,color)-sizeof(Heap));	// h->color = propagator
+	ldc((ulong)&nprop, Ro3);
+	AIRR(Ostw, Ro1, Ro3,0);	// nprop = !0
+	LRET();
+}
+
+static void
+maccvtfw(void)
+{
+	ulong *cp;
+
+	ARRR(Ofcmpo, Rcrf0, Rf1, Rfzero);
+	ARRR(Ofneg, Rf2, 0, Rfhalf);
+	cp = code;
+	br(Oblt, 0);
+	ARRR(Ofmr, Rf2, 0, Rfhalf);
+	PATCH(cp);
+	ARRR(Ofadd, Rf1, Rf1, Rf2);	//x<0? x-.5: x+.5
+	ARRR(Ofctiwz, Rf2, 0, Rf1);
+	/* avoid using Ostfdu for now, since software emulation will run on same stack */
+	if(0){
+		AIRR(Ostfdu, Rf2, Rsp,-8);		// MOVDU Rf2, -8(R1)    (store in temp)
+	}else{
+		AIRR(Oaddi, Rsp, Rsp, -8);		// SUB $8, R1
+		AIRR(Ostfd, Rf2, Rsp,0);		// MOVD Rf2, 0(R1)    (store in temp)
+	}
+	AIRR(Olwz, Ro1, Rsp,4);		// MOVW 4(R1), Ro1
+	AIRR(Oaddi, Rsp, Rsp, 8);		// ADD $8, R1
+	LRET();
+}
+
+static void
+macrelq(void)
+{
+	ARRR(Ocrxor, Rcrbrel, Rcrbrel, Rcrbrel);	/* clear the relinquish condition */
+	mfspr(Rlink, Rlr);
+	IRR(Ostw, O(REG,FP),Rreg, Rfp);
+	IRR(Ostw, O(REG,PC),Rreg, Rlink);
+	IRR(Olwz, O(REG,xpc),Rreg, Ro2);
+	jr(Ro2);
+}
+
+static void
+macend(void)
+{
+}
+
+void
+comd(Type *t)
+{
+	int i, j, m, c;
+
+	mfspr(Rlink, Rlr);
+	AIRR(Ostw, Rlink, Rreg,O(REG,dt));
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m) {
+				mem(Olwz, j, Rfp, Ri);
+				jmpl(base+macro[MacFRP]);
+			}
+			j += sizeof(WORD*);
+		}
+	}
+	AIRR(Olwz, Rlink, Rreg,O(REG,dt));
+	mtspr(Rlr, Rlink);
+	gen(Oblr);
+}
+
+void
+comi(Type *t)
+{
+	int i, j, m, c;
+
+	ldc((ulong)H, Ri);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m)
+				mem(Ostw, j, Ro1, Ri);
+			j += sizeof(WORD*);
+		}
+	}
+	LRET();
+}
+
+void
+typecom(Type *t)
+{
+	int n;
+	ulong *tmp, *start;
+
+	if(t == nil || t->initialize != 0)
+		return;
+
+	tmp = mallocz(4096*sizeof(ulong), 0);
+	if(tmp == nil)
+		error(exNomem);
+
+	code = tmp;
+	comi(t);
+	n = code - tmp;
+	code = tmp;
+	comd(t);
+	n += code - tmp;
+	free(tmp);
+
+	n *= sizeof(*code);
+	code = mallocz(n, 0);
+	if(code == nil)
+		return;
+
+	start = code;
+	t->initialize = code;
+	comi(t);
+	t->destroy = code;
+	comd(t);
+
+	segflush(start, n);
+
+	if(cflag > 3)
+		print("typ= %.8lux %4d i %.8lux d %.8lux asm=%d\n",
+			(ulong)t, t->size, (ulong)t->initialize, (ulong)t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+	Handler *h;
+	Except *e;
+
+	if((h = m->htab) == nil)
+		return;
+	for( ; h->etab != nil; h++){
+		h->pc1 = p[h->pc1];
+		h->pc2 = p[h->pc2];
+		for(e = h->etab; e->s != nil; e++)
+			e->pc = p[e->pc];
+		if(e->pc != -1)
+			e->pc = p[e->pc];
+	}
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+	Link *l;
+	Modl *e;
+	int i, n;
+	ulong *s, *tmp;
+
+	base = nil;
+	patch = mallocz(size*sizeof(*patch), ROMABLE);
+	tinit = malloc(m->ntype*sizeof(*tinit));
+	tmp = malloc(4096*sizeof(ulong));
+	if(tinit == nil || patch == nil || tmp == nil)
+		goto bad;
+
+	preamble();
+
+	mod = m;
+	n = 0;
+	pass = 0;
+	nlit = 0;
+
+	for(i = 0; i < size; i++) {
+		code = tmp;
+		comp(&m->prog[i]);
+		if(code >= &tmp[4096]) {
+			print("%3d %D\n", i, &m->prog[i]);
+			urk("tmp ovflo");
+		}
+		patch[i] = n;
+		n += code - tmp;
+	}
+
+	for(i=0; macinit[i].f; i++) {
+		code = tmp;
+		(*macinit[i].f)();
+		macro[macinit[i].o] = n;
+		n += code - tmp;
+	}
+
+	base = mallocz((n+nlit)*sizeof(*base), 0);
+	if(base == nil)
+		goto bad;
+
+	if(cflag > 3)
+		print("dis=%5d %5d ppc=%5d asm=%.8lux lit=%d: %s\n",
+			size, size*sizeof(Inst), n, (ulong)base, nlit, m->name);
+
+	pass++;
+	nlit = 0;
+	litpool = base+n;
+	code = base;
+	n = 0;
+
+	for(i = 0; i < size; i++) {
+		s = code;
+		comp(&m->prog[i]);
+		if(patch[i] != n) {
+			print("%3d %D\n", i, &m->prog[i]);
+			urk("phase error");
+		}
+		n += code - s;
+		if(cflag > 3) {
+			print("%3d %D\n", i, &m->prog[i]);
+			while(s < code)
+				s += das(s);
+		}/**/
+	}
+
+	for(i=0; macinit[i].f; i++) {
+		if(macro[macinit[i].o] != n) {
+			print("macinit %d\n", macinit[i].o);
+			urk("phase error");
+		}
+		s = code;
+		(*macinit[i].f)();
+		n += code - s;
+		if(cflag > 3) {
+			print("macinit %d\n", macinit[i].o);
+			while(s < code)
+				s += das(s);
+		}/**/
+	}
+
+	for(l = m->ext; l->name; l++) {
+		l->u.pc = (Inst*)(base+patch[l->u.pc-m->prog]);
+		typecom(l->frame);
+	}
+	if(ml != nil) {
+		e = &ml->links[0];
+		for(i = 0; i < ml->nlinks; i++) {
+			e->u.pc = (Inst*)(base+patch[e->u.pc-m->prog]);
+			typecom(e->frame);
+			e++;
+		}
+	}
+	for(i = 0; i < m->ntype; i++) {
+		if(tinit[i] != 0)
+			typecom(m->type[i]);
+	}
+	patchex(m, patch);
+	m->entry = (Inst*)(base+patch[mod->entry-mod->prog]);
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(m->prog);
+	m->prog = (Inst*)base;
+	m->compiled = 1;
+	segflush(base, n*sizeof(*base));
+	return 1;
+bad:
+	free(patch);
+	free(tinit);
+	free(base);
+	free(tmp);
+	return 0;
+}
--- /dev/null
+++ b/libinterp/comp-sparc.c
@@ -1,0 +1,1882 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+
+enum
+{
+	R8	= 8,		/* SUN calls these %o0 - %o7 */
+	R9	= 9,
+	R10	= 10,
+	R11	= 11,
+	R12	= 12,
+	R13	= 13,
+	R14	= 14,		/* SUN %sp */
+	R15	= 15,		/* R15/%o7 is the default link register */
+
+	R16	= 16,		/* SUN calls these %l0 - %l7 */
+	R17	= 17,
+	R18	= 18,
+	R19	= 19,
+	R20	= 20,
+	R21	= 21,
+	R22	= 22,
+	R23	= 23,
+	RLINK	= 15,
+
+	RZ	= 0,		/* Always 0 */
+	RFP	= R23,		/* Frame Pointer */
+	RMP	= R22,		/* Module Pointer */
+	RTA	= R21,		/* Intermediate address for double indirect */
+	RREG	= R20,		/* Pointer to REG */
+	RA3	= R19,		/* gpr 3 */
+	RA2	= R18,		/* gpr 2 2+3 = L */
+	RA1	= R17,		/* gpr 1 */
+	RA0	= R16,		/* gpr 0 0+1 = L */
+
+	RCON	= R8,		/* Constant builder */
+
+	FA2	= 2,		/* Floating */
+	FA3	= 3,
+	FA4	= 4,
+	FA5	= 5,
+
+	Olea	= (1<<20),	/* Pseudo op */
+	Owry	= 48,
+	Omul	= 11,
+	Oumul	= 10,
+	Osdiv	= 15,
+	Osll	= 37,
+	Osra	= 39,
+	Osrl	= 38,
+	Osethi	= 4,
+	Oadd	= 0,
+	Oaddcc	= 16,
+	Oaddx	= 8,
+	Osub	= 4,
+	Osubcc	= 20,
+	Osubx	= 12,
+	Oor	= 2,
+	Oand	= 1,
+	Oxor	= 3,
+	Oldw	= 0,
+	Oldsh	= 10,
+	Ostw	= 4,
+	Osth	= 6,
+	Ojmpl	= 56,
+	Ocall	= 1,
+	Ocmp	= 20,		/* subcc */
+	Oldbu	= 1,
+	Ostb	= 5,
+	Oba	= 8,
+	Obn	= 0,
+	Obne	= 9,
+	Obe	= 1,
+	Obg	= 10,
+	Oble	= 2,
+	Obge	= 11,
+	Obl	= 3,
+	Obgu	= 12,
+	Obleu	= 4,
+	Obcc	= 13,
+	Obcs	= 5,
+	Obpos	= 14,
+	Obneg	= 6,
+	Obvc	= 15,
+	Obvs	= 7,
+	OfaddD	= 66,
+	OfsubD	= 70,
+	OfdivD	= 78,
+	OfmulD	= 74,
+	Oldf	= 32,
+	Ostf	= 36,
+	OfDtoQ	= 206,
+	OfnegS	= 5,
+	OfcmpD	= 82,
+	Ofba	= 8,
+	Ofbe	= 9,
+	Ofbg	= 6,
+	Ofbge	= 11,
+	Ofbl	= 4,
+	Ofble	= 13,
+	Ofbne	= 1,
+	OfWtoD	= 200,
+	OfDtoW	= 210,
+	Osave	= 60,
+	Orestore= 61,
+
+	SRCOP	= (1<<0),
+	DSTOP	= (1<<1),
+	WRTPC	= (1<<2),
+	TCHECK	= (1<<3),
+	NEWPC	= (1<<4),
+	DBRAN	= (1<<5),
+	THREOP	= (1<<6),
+
+	ANDAND	= 1,
+	OROR	= 2,
+	EQAND	= 3,
+
+	MacFRP	= 0,
+	MacRET	= 1,
+	MacCASE	= 2,
+	MacCOLR	= 3,
+	MacMCAL	= 4,
+	MacFRAM	= 5,
+	MacMFRA	= 6,
+	NMACRO
+};
+
+#define OP(n)			   (n<<30)
+#define I13(i)			   ((i)&0x1fff)
+#define D22(i)			   ((i)&0x3fffff)
+#define PC30(pc)		   (((ulong)(pc) - (ulong)code)>>2)
+
+#define CALL(addr)		   *code=OP(1)|PC30(addr); code++
+#define FM2I(op2, i, rd)	   *code=OP(0)|(rd<<25)|(op2<<22)|D22(i); code++
+#define BRA(cond, disp)		   *code=OP(0)|(cond<<25)|(2<<22)|D22((disp)); code++
+#define BRAF(cond, disp)	   *code=OP(0)|(cond<<25)|(6<<22)|D22((disp)); code++
+#define BRADIS(r, o)		   BRA(r, ((ulong)(base+patch[o])-(ulong)code)>>2)
+#define BRAFDIS(r, o)		   BRAF(r, ((ulong)(base+patch[o])-(ulong)code)>>2)
+#define BRAMAC(r, o)		   BRA(r, ((ulong)(base+macro[o])-(ulong)code)>>2);
+#define FM3I(op, op3, i, rs1, rd)  *code++=OP(op)|(rd<<25)|(op3<<19)|(rs1<<14)|\
+					   (1<<13)|I13(i)
+#define FM3(op, op3, rs2, rs1, rd) *code++=OP(op)|(rd<<25)|(op3<<19)|(rs1<<14)|rs2
+#define FMF1(opf, rs2, rs1, rd)	   *code++=OP(2)|(rd<<25)|(52<<19)|(rs1<<14)|(opf<<5)|rs2
+#define FMF2(opf, rs2, rs1, rd)	   *code++=OP(2)|(rd<<25)|(53<<19)|(rs1<<14)|(opf<<5)|rs2
+#define NOOP			   *code++=(4<<22)
+#define RETURN			   FM3I(2, Ojmpl, 8, RLINK, RZ);
+#define MOV(s, d)		   FM3(2, Oor, s, RZ, d)
+
+#define RELPC(pc)		   (ulong)(base+pc)
+#define PATCH(ptr)		   *ptr |= (code-ptr) & 0x3fffff
+
+static	ulong*	code;
+static	ulong*	base;
+static	ulong*	patch;
+static	int	pass;
+static	int	puntpc = 1;
+static	Module*	mod;
+static	uchar*	tinit;
+static	ulong*	litpool;
+static	int	nlit;
+static	void	macfrp(void);
+static	void	macret(void);
+static	void	maccase(void);
+static	void	maccolr(void);
+static	void	macmcal(void);
+static	void	macfram(void);
+static	void	macmfra(void);
+static	ulong	macro[NMACRO];
+	void	(*comvec)(void);
+extern	void	das(ulong*, int);
+
+#define T(r)	*((void**)(R.r))
+
+struct
+{
+	int	idx;
+	void	(*gen)(void);
+	char*	name;
+} mactab[] =
+{
+	MacFRP,		macfrp,		"FRP", 	/* decrement and free pointer */
+	MacRET,		macret,		"RET",	/* return instruction */
+	MacCASE,	maccase,	"CASE",	/* case instruction */
+	MacCOLR,	maccolr,	"COLR",	/* increment and color pointer */
+	MacMCAL,	macmcal,	"MCAL",	/* mcall bottom half */
+	MacFRAM,	macfram,	"FRAM",	/* frame instruction */
+	MacMFRA,	macmfra,	"MFRA",	/* punt mframe because t->initialize==0 */
+};
+
+static void
+rdestroy(void)
+{
+	destroy(R.s);
+}
+
+static void
+rmcall(void)
+{
+	Prog *p;
+	Frame *f;
+
+	f = (Frame*)R.FP;
+	if(f == H)
+		error(exModule);
+
+	f->mr = nil;
+	((void(*)(Frame*))R.dt)(f);
+	R.SP = (uchar*)f;
+	R.FP = f->fp;
+	if(f->t == nil)
+		unextend(f);
+	else
+		freeptrs(f, f->t);
+	p = currun();
+	if(p->kill != nil)
+		error(p->kill);
+}
+
+static void
+rmfram(void)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+
+	if(R.d == H)
+                error(exModule);
+        t = (Type*)R.s;
+        if(t == H)
+                error(exModule);
+
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP = nsp;
+	f->t = t;
+	f->mr = nil;
+	initmem(t, f);
+	T(d) = f;
+}
+
+static void
+urk(void)
+{
+	error(exCompile);
+}
+
+static int
+bc(long c)
+{
+	c &= ~0xfffL;
+	if (c == 0 || c == ~0xfffL)
+		return 1;
+
+	return 0;
+}
+
+static void
+con(ulong o, int r, int opt)
+{
+	if(opt != 0) {
+		if(bc(o)) {	
+			FM3I(2, Oadd, o & 0x1fff, RZ, r);
+			return;
+		}
+		if((o & 0x3ff) == 0) {
+			FM2I(Osethi, o>>10, r);
+			return;
+		}
+	}
+	FM2I(Osethi, o>>10, r);
+	FM3I(2, Oadd, o & 0x3ff, r, r);
+}
+
+static void
+mem(int inst, ulong disp, int rm, int r)
+{
+	int op;
+
+	op = 3;
+	if(inst == Olea) {
+		op = 2;
+		inst = Oadd;
+	}
+	if(bc(disp)) {
+		FM3I(op, inst, disp, rm, r);
+		return;
+	}
+	con(disp, RCON, 1);
+	FM3(op, inst, RCON, rm, r);
+}
+
+static void
+opwld(Inst *i, int mi, int r)
+{
+	int ir, rta;
+
+	switch(UXSRC(i->add)) {
+	default:
+		print("%D\n", i);
+		urk();
+	case SRC(AFP):
+		mem(mi, i->s.ind, RFP, r);
+		return;
+	case SRC(AMP):
+		mem(mi, i->s.ind, RMP, r);
+		return;
+	case SRC(AIMM):
+		con(i->s.imm, r, 1);
+		if(mi == Olea) {
+			mem(Ostw, O(REG, st), RREG, r);
+			con((ulong)&R.st, r, 1);
+		}
+		return;
+	case SRC(AIND|AFP):
+		ir = RFP;
+		break;
+	case SRC(AIND|AMP):
+		ir = RMP;
+		break;
+	}
+	rta = RTA;
+	if(mi == Olea)
+		rta = r;
+	mem(Oldw, i->s.i.f, ir, rta);
+	mem(mi, i->s.i.s, rta, r);
+}
+
+static void
+opwst(Inst *i, int mi, int r)
+{
+	int ir, rta;
+
+	switch(UXDST(i->add)) {
+	default:
+		print("%D\n", i);
+		urk();
+	case DST(AIMM):
+		con(i->d.imm, r, 1);
+		return;
+	case DST(AFP):
+		mem(mi, i->d.ind, RFP, r);
+		return;
+	case DST(AMP):
+		mem(mi, i->d.ind, RMP, r);
+		return;
+	case DST(AIND|AFP):
+		ir = RFP;
+		break;
+	case DST(AIND|AMP):
+		ir = RMP;
+		break;
+	}
+	rta = RTA;
+	if(mi == Olea)
+		rta = r;
+	mem(Oldw, i->d.i.f, ir, rta);
+	mem(mi, i->d.i.s, rta, r);
+}
+
+static void
+opfl(Adr *a, int am, int mi, int r)
+{
+	int ir;
+
+	switch(am) {
+	default:
+		urk();
+	case AFP:
+		mem(mi, a->ind, RFP, r);
+		mem(mi, a->ind+4, RFP, r+1);
+		return;
+	case AMP:
+		mem(mi, a->ind, RMP, r);
+		mem(mi, a->ind+4, RMP, r+1);
+		return;
+	case AIND|AFP:
+		ir = RFP;
+		break;
+	case AIND|AMP:
+		ir = RMP;
+		break;
+	}
+	mem(Oldw, a->i.f, ir, RTA);
+	mem(mi, a->i.s, RTA, r);
+	mem(mi, a->i.s+4, RTA, r+1);
+}
+
+static void
+opflld(Inst *i, int mi, int r)
+{
+	opfl(&i->s, USRC(i->add), mi, r);
+}
+
+static void
+opflst(Inst *i, int mi, int r)
+{
+	opfl(&i->d, UDST(i->add), mi, r);
+}
+
+static void
+literal(ulong imm, int roff)
+{
+	nlit++;
+
+	con((ulong)litpool, RTA, 0);
+	mem(Ostw, roff, RREG, RTA);
+
+	if(pass == 0)
+		return;
+
+	*litpool = imm;
+	litpool++;	
+}
+
+static void
+punt(Inst *i, int m, void (*fn)(void))
+{
+	ulong pc;
+
+	if(m & SRCOP) {
+		if(UXSRC(i->add) == SRC(AIMM))
+			literal(i->s.imm, O(REG, s));
+		else {
+			opwld(i, Olea, RA0);
+			mem(Ostw, O(REG, s), RREG, RA0);
+		}
+	}
+
+	if(m & DSTOP) {
+		opwst(i, Olea, RA0);
+		mem(Ostw, O(REG, d), RREG, RA0);
+	}
+	if(m & WRTPC) {
+		con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+		mem(Ostw, O(REG, PC), RREG, RA0);
+	}
+	if(m & DBRAN) {
+		pc = patch[(Inst*)i->d.imm-mod->prog];
+		literal(RELPC(pc), O(REG, d));
+	}
+
+	switch(i->add&ARM) {
+	case AXNON:
+		if(m & THREOP) {
+			mem(Oldw, O(REG, d), RREG, RA0);
+			mem(Ostw, O(REG, m), RREG, RA0);
+		}
+		break;
+	case AXIMM:
+		literal((short)i->reg, O(REG, m));
+		break;
+	case AXINF:
+		mem(Olea, i->reg, RFP, RA0);
+		mem(Ostw, O(REG, m), RREG, RA0);
+		break;
+	case AXINM:
+		mem(Olea, i->reg, RMP, RA0);
+		mem(Ostw, O(REG, m), RREG, RA0);
+		break;
+	}
+
+	CALL(fn);
+	mem(Ostw, O(REG, FP), RREG, RFP);
+
+	con((ulong)&R, RREG, 1);
+	if(m & TCHECK) {
+		mem(Oldw, O(REG, t), RREG, RA0);
+		FM3I(2, Ocmp, 0, RA0, RZ);
+		BRA(Obe, 5);
+		NOOP;				
+		mem(Oldw, O(REG, xpc), RREG, RLINK);
+		RETURN;
+		NOOP;
+	}
+
+	mem(Oldw, O(REG, FP), RREG, RFP);
+	mem(Oldw, O(REG, MP), RREG, RMP);
+
+	if(m & NEWPC) {
+		mem(Oldw, O(REG, PC), RREG, RA0);
+		FM3I(2, Ojmpl, 0, RA0, RZ);
+		NOOP;
+	}
+}
+
+static void
+midfl(Inst *i, int mi, int r)
+{
+	int ir;
+
+	switch(i->add&ARM) {
+	default:
+		opflst(i, mi, r);
+		return;
+	case AXIMM:
+		con((short)i->reg, r, 1);
+		return;
+	case AXINF:
+		ir = RFP;
+		break;
+	case AXINM:
+		ir = RMP;
+		break;
+	}
+	mem(mi, i->reg, ir, r);
+	mem(mi, i->reg+4, ir, r+1);
+}
+
+static void
+mid(Inst *i, int mi, int r)
+{
+	int ir;
+
+	switch(i->add&ARM) {
+	default:
+		opwst(i, mi, r);
+		return;
+	case AXIMM:
+		con((short)i->reg, r, 1);
+		return;
+	case AXINF:
+		ir = RFP;
+		break;
+	case AXINM:
+		ir = RMP;
+		break;
+	}
+	mem(mi, i->reg, ir, r);
+}
+
+static void
+cbral(Inst *i, int jmsw, int jlsw, int mode)
+{
+	ulong dst, *label;
+
+	opwld(i, Olea, RA1);
+	mid(i, Olea, RA3);
+	mem(Oldw, 0, RA1, RA2);
+	mem(Oldw, 0, RA3, RA0);
+	FM3(2, Ocmp, RA0, RA2, RZ);
+	label = nil;
+	dst = i->d.ins-mod->prog;
+	switch(mode) {
+	case ANDAND:
+		label = code;
+		BRA(jmsw, 0);
+		break;
+	case OROR:
+		BRADIS(jmsw, dst);
+		break;
+	case EQAND:
+		BRADIS(jmsw, dst);
+		NOOP;
+		label = code;
+		BRA(Obne, 0);
+		break;
+	}
+	NOOP;
+	mem(Oldw, 4, RA3, RA0);
+	mem(Oldw, 4, RA1, RA2);
+	FM3(2, Ocmp, RA0, RA2, RZ);
+	BRADIS(jlsw, dst);
+	if(label != nil)
+		PATCH(label);
+}
+
+static void
+comcase(Inst *i, int w)
+{
+	int l;
+	WORD *t, *e;
+
+	if(w != 0) {
+		opwld(i, Oldw, RA0);		// v
+		opwst(i, Olea, RCON);		// table
+		BRAMAC(Oba, MacCASE);
+		NOOP;
+	}
+
+	t = (WORD*)(mod->origmp+i->d.ind+4);
+	l = t[-1];
+	
+	/* have to take care not to relocate the same table twice - 
+	 * the limbo compiler can duplicate a case instruction
+	 * during its folding phase
+	 */
+
+	if(pass == 0) {
+		if(l >= 0)
+			t[-1] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-1] = -l-1;			/* Set real count */
+	e = t + t[-1]*3;
+	while(t < e) {
+		t[2] = RELPC(patch[t[2]]);
+		t += 3;
+	}
+	t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+comcasel(Inst *i)
+{
+	int l;
+	WORD *t, *e;
+
+	t = (WORD*)(mod->origmp+i->d.ind+8);
+	l = t[-2];
+	if(pass == 0) {
+		if(l >= 0)
+			t[-2] = -l-1;	/* Mark it not done */
+		return;
+	}
+	if(l >= 0)			/* Check pass 2 done */
+		return;
+	t[-2] = -l-1;			/* Set real count */
+	e = t + t[-2]*6;
+	while(t < e) {
+		t[4] = RELPC(patch[t[4]]);
+		t += 6;
+	}
+	t[0] = RELPC(patch[t[0]]);
+}
+
+static void
+commframe(Inst *i)
+{
+	int o;
+	ulong *punt, *mlnil;
+
+	opwld(i, Oldw, RA0);
+	FM3I(2, Ocmp, -1, RA0, RZ);
+	mlnil = code;
+	BRA(Obe, 0);
+	NOOP;
+	
+	if((i->add&ARM) == AXIMM) {
+		o = OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, frame);
+		mem(Oldw, o, RA0, RA3);
+	} else {
+		mid(i, Oldw, RA1);
+		FM3I(2, Osll, 3, RA1, RA1);		// assumes sizeof(Modl) == 8
+		FM3(2, Oadd, RA0, RA1, RA1);
+		o = OA(Modlink, links)+O(Modl, frame);
+		mem(Oldw, o, RA1, RA3);
+	}
+	mem(Oldw, O(Type, initialize), RA3, RA1);
+	FM3I(2, Ocmp, 0, RA1, RZ);
+	punt = code;
+	BRA(Obne, 0);
+	NOOP;
+
+	opwst(i, Olea, RA0);
+
+	/* Type in RA3, destination in RA0 */
+	PATCH(mlnil);
+	con(RELPC(patch[i-mod->prog+1])-8, RLINK, 0);
+	BRAMAC(Oba, MacMFRA);
+	NOOP;
+
+	/* Type in RA3 */
+	PATCH(punt);
+	CALL(base+macro[MacFRAM]);
+	NOOP;
+	opwst(i, Ostw, RA2);
+}
+
+static void
+commcall(Inst *i)
+{
+	opwld(i, Oldw, RA2);
+	con(RELPC(patch[i-mod->prog+1]), RA0, 0);
+	mem(Ostw, O(Frame, lr), RA2, RA0);
+	mem(Ostw, O(Frame, fp), RA2, RFP);
+	mem(Oldw, O(REG, M), RREG, RA3);
+	mem(Ostw, O(Frame, mr), RA2, RA3);
+	opwst(i, Oldw, RA3);
+	if((i->add&ARM) == AXIMM) {
+		CALL(base+macro[MacMCAL]);
+		mem(Oldw, OA(Modlink, links)+i->reg*sizeof(Modl)+O(Modl, u.pc), RA3, RA0);
+	} else {
+		mid(i, Oldw, RA1);
+		FM3I(2, Osll, 3, RA1, RA1);		// assumes sizeof(Modl) == 8
+		FM3(2, Oadd, RA1, RA3, RA0);
+		CALL(base+macro[MacMCAL]);
+		mem(Oldw, OA(Modlink, links)+O(Modl, u.pc), RA0, RA0);
+	}
+}
+
+static void
+larith(Inst *i, int op, int opc)
+{
+	opflld(i, Oldw, RA0);
+	midfl(i, Oldw, RA2);
+	FM3(2, op, RA1, RA3, RA1);
+	FM3(2, opc, RA0, RA2, RA0);
+	opflst(i, Ostw, RA0);
+}
+
+static void
+movloop(Inst *i, int ld, int st)
+{
+	int s;
+
+	s = 1;
+	if(ld == Oldw)
+		s = 4;
+	opwld(i, Olea, RA1);
+	opwst(i, Olea, RA2);
+	mem(ld, 0, RA1, RA0);
+	mem(st, 0, RA2, RA0);
+	FM3I(2, Oadd, s, RA2, RA2);
+	FM3I(2, Oaddcc, -1, RA3, RA3);
+	BRA(Obne, -4);
+	FM3I(2, Oadd, s, RA1, RA1);
+}
+
+static
+void
+compdbg(void)
+{
+	print("%s:%d@%.8ux\n", R.M->m->name, R.t, R.st);
+}
+
+static void
+shll(Inst *i)
+{
+	ulong *lab0, *lab1, *lab2;
+
+	opwld(i, Oldw, RA2);
+	midfl(i, Oldw, RA0);
+	FM3I(2, Ocmp, RZ, RA2, RZ);
+	lab0 = code;
+	BRA(Obe, 0);
+	FM3I(2, Ocmp, 32, RA2, RZ);
+	lab1 = code;
+	BRA(Obl, 0);
+	NOOP;
+	FM3I(2, Osub, 32, RA2, RA2);
+	FM3(2, Osll, RA2, RA1, RA0);
+	lab2 = code;
+	BRA(Oba, 0);
+	MOV(RZ, RA1);
+
+	PATCH(lab1);
+	FM3(2, Osll, RA2, RA0, RA0);
+	con(32, RA3, 1);
+	FM3(2, Osub, RA2, RA3, RA3);
+	FM3(2, Osrl, RA3, RA1, RA3);
+	FM3(2, Oor, RA0, RA3, RA0);
+	FM3(2, Osll, RA2, RA1, RA1);
+
+	PATCH(lab0);
+	PATCH(lab2);
+	opflst(i, Ostw, RA0);
+}
+
+static void
+comp(Inst *i)
+{
+	int r;
+	WORD *t, *e;
+	char buf[64];
+
+	if(0) {
+		Inst xx;
+		xx.add = AXIMM|SRC(AIMM);
+		xx.s.imm = (ulong)code;
+		xx.reg = i-mod->prog;
+		puntpc = 0;
+		punt(&xx, SRCOP, compdbg);
+		puntpc = 1;
+	}
+
+	switch(i->op) {
+	default:
+		snprint(buf, sizeof buf, "%s compile, no '%D'", mod->name, i);
+		error(buf);
+		break;
+	case IMCALL:
+		if((i->add&ARM) == AXIMM)
+			commcall(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case ISEND:
+	case IRECV:
+	case IALT:
+		punt(i, SRCOP|DSTOP|TCHECK|WRTPC, optab[i->op]);
+		break;
+	case ISPAWN:
+		punt(i, SRCOP|DBRAN, optab[i->op]);
+		break;
+	case IBNEC:
+	case IBEQC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+		punt(i, SRCOP|DBRAN|NEWPC|WRTPC, optab[i->op]);
+		break;
+	case ICASEC:
+		comcase(i, 0);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case ICASEL:
+		comcasel(i);
+		punt(i, SRCOP|DSTOP|NEWPC, optab[i->op]);
+		break;
+	case IADDC:
+	case IMULL:
+	case IDIVL:
+	case IMODL:
+	case IMODW:
+	case IMODB:
+	case IMNEWZ:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ILOAD:
+	case INEWA:
+	case INEWAZ:
+	case INEW:
+	case INEWZ:
+	case ISLICEA:
+	case ISLICELA:
+	case ICONSB:
+	case ICONSW:
+	case ICONSL:
+	case ICONSF:
+	case ICONSM:
+	case ICONSMP:
+	case ICONSP:
+	case IMOVMP:
+	case IHEADMP:
+	case IHEADM:
+	case IHEADB:
+	case IHEADW:
+	case IHEADL:
+	case IHEADF:
+	case IINDC:
+	case ILENC:
+	case IINSC:
+	case ICVTAC:
+	case ICVTCW:
+	case ICVTWC:
+	case ICVTLC:
+	case ICVTCL:
+	case ICVTFC:
+	case ICVTCF:
+	case ICVTRF:
+	case ICVTFR:
+	case IMSPAWN:
+	case ICVTCA:
+	case ISLICEC:
+	case INBALT:
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case INEWCM:
+	case INEWCMP:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IMFRAME:
+		if((i->add&ARM) == AXIMM)
+			commframe(i);
+		else
+			punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ICASE:
+		comcase(i, 1);
+		break;
+	case IGOTO:
+		opwld(i, Oldw, RA1);
+		opwst(i, Olea, RA0);
+		FM3I(2, Osll, 2, RA1, RA1);
+		FM3(3, Oldw, RA1, RA0, RA0);
+		FM3I(2, Ojmpl, 0, RA0, RZ);
+		NOOP;
+
+		if(pass == 0)
+			break;
+
+		t = (WORD*)(mod->origmp+i->d.ind);
+		e = t + t[-1];
+		t[-1] = 0;
+		while(t < e) {
+			t[0] = RELPC(patch[t[0]]);
+			t++;
+		}
+		break;
+	case IMOVL:
+	movl:
+		opflld(i, Oldw, RA0);
+		opflst(i, Ostw, RA0);
+		break;
+	case IMOVM:
+		if((i->add&ARM) == AXIMM) {
+			if(i->reg == 8)
+				goto movl;
+			if((i->reg&3) == 0) {
+				con(i->reg>>2, RA3, 1);
+				movloop(i, Oldw, Ostw);
+				break;
+			} 
+		}
+		mid(i, Oldw, RA3);
+		movloop(i, Oldbu, Ostb);
+		break;
+	case IFRAME:
+		if(UXSRC(i->add) != SRC(AIMM)) {
+			punt(i, SRCOP|DSTOP, optab[i->op]);
+			break;
+		}
+		tinit[i->s.imm] = 1;
+		con((ulong)mod->type[i->s.imm], RA3, 1);
+		CALL(base+macro[MacFRAM]);
+		NOOP;
+		opwst(i, Ostw, RA2);
+		break;
+	case INEWCB:
+	case INEWCW:
+	case INEWCF:
+	case INEWCP:
+	case INEWCL:
+		punt(i, DSTOP|THREOP, optab[i->op]);
+		break;
+	case IEXIT:
+		punt(i, 0, optab[i->op]);
+		break;
+	case ICVTBW:
+		opwld(i, Oldbu, RA0);
+		opwst(i, Ostw, RA0);
+		break;
+	case ICVTWB:
+		opwld(i, Oldw, RA0);
+		opwst(i, Ostb, RA0);
+		break;
+	case ILEA:
+		opwld(i, Olea, RA0);
+		opwst(i, Ostw, RA0);
+		break;
+	case IMOVW:
+		opwld(i, Oldw, RA0);
+		opwst(i, Ostw, RA0);
+		break;
+	case IMOVB:
+		opwld(i, Oldbu, RA0);
+		opwst(i, Ostb, RA0);
+		break;
+	case ICVTSW:
+		opwld(i, Oldsh, RA0);
+		opwst(i, Ostw, RA0);
+		break;
+	case ICVTWS:
+		opwld(i, Oldw, RA0);
+		opwst(i, Osth, RA0);
+		break;
+	case ITAIL:
+		opwld(i, Oldw, RA0);
+		mem(Oldw, O(List, tail), RA0, RA1);
+		goto movp;
+	case IMOVP:
+	case IHEADP:
+		opwld(i, Oldw, RA1);
+		if(i->op == IHEADP)
+			mem(Oldw, OA(List, data), RA1, RA1);
+	movp:
+		FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+		BRA(Obe, 5);
+		con((ulong)&mutator, RA2, 1);
+		CALL(base+macro[MacCOLR]);
+		mem(Oldw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+		opwst(i, Oldw, RA0);
+		opwst(i, Ostw, RA1);
+		CALL(base+macro[MacFRP]);
+		NOOP;
+		break;
+	case ILENA:
+		opwld(i, Oldw, RA1);
+		FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+		BRA(Obe, 3);
+		con(0, RA0, 1);
+		mem(Oldw, O(Array, len), RA1, RA0);
+		opwst(i, Ostw, RA0);
+		break;
+	case ILENL:
+		con(0, RA0, 1);
+		opwld(i, Oldw, RA1);
+		FM3I(2, Ocmp, (ulong)H, RA1, RZ);
+		BRA(Obe, 5);
+		NOOP;
+		mem(Oldw, O(List, tail), RA1, RA1);
+		BRA(Oba, -4);
+		FM3I(2, Oadd, 1, RA0, RA0);
+		opwst(i, Ostw, RA0);
+		break;
+	case ICALL:
+		opwld(i, Oldw, RA0);
+		con(RELPC(patch[i-mod->prog+1]), RA1, 0);
+		mem(Ostw, O(Frame, lr), RA0, RA1);
+		mem(Ostw, O(Frame, fp), RA0, RFP);
+		BRADIS(Oba, i->d.ins-mod->prog);
+		MOV(RA0, RFP);
+		break;
+	case IJMP:
+		BRADIS(Oba, i->d.ins-mod->prog);
+		NOOP;
+		break;
+	case IBEQW:
+		r = Obe;
+	braw:
+		opwld(i, Oldw, RA1);
+		mid(i, Oldw, RA0);
+		FM3(2, Ocmp, RA0, RA1, RZ);
+		BRADIS(r, i->d.ins-mod->prog);
+		NOOP;
+		break;		
+	case IBNEW:
+		r = Obne;
+		goto braw;
+	case IBLTW:
+		r = Obl;
+		goto braw;
+	case IBLEW:
+		r = Oble;
+		goto braw;
+	case IBGTW:
+		r = Obg;
+		goto braw;
+	case IBGEW:
+		r = Obge;
+		goto braw;
+	case IBEQB:
+		r = Obe;
+	brab:
+		opwld(i, Oldbu, RA1);
+		mid(i, Oldbu, RA0);
+		FM3(2, Ocmp, RA0, RA1, RZ);
+		BRADIS(r, i->d.ins-mod->prog);
+		NOOP;
+		break;		
+	case IBNEB:
+		r = Obne;
+		goto brab;
+	case IBLTB:
+		r = Obl;
+		goto brab;
+	case IBLEB:
+		r = Oble;
+		goto brab;
+	case IBGTB:
+		r = Obg;
+		goto brab;
+	case IBGEB:
+		r = Obge;
+		goto brab;
+	case IBEQF:
+		r = Ofbe;
+	braf:
+		opflld(i, Oldf, FA4);
+		midfl(i, Oldf, FA2);
+		FMF2(OfcmpD, FA2, FA4, 0);
+		NOOP;
+		BRAFDIS(r, i->d.ins-mod->prog);
+		NOOP;
+		break;		
+	case IBNEF:
+		r = Ofbne;
+		goto braf;
+	case IBLTF:
+		r = Ofbl;
+		goto braf;
+	case IBLEF:
+		r = Ofble;
+		goto braf;
+	case IBGTF:
+		r = Ofbg;
+		goto braf;
+	case IBGEF:
+		r = Ofbge;
+		goto braf;
+	case IRET:
+		BRAMAC(Oba, MacRET);
+		mem(Oldw, O(Frame,t), RFP, RA1);
+		break;
+	case IORW:
+		r = Oor;
+		goto arithw;
+	case IANDW:
+		r = Oand;
+		goto arithw;
+	case IXORW:
+		r = Oxor;
+		goto arithw;
+	case ISUBW:
+		r = Osub;
+		goto arithw;
+	case ISHRW:
+		r = Osra;
+		goto arithw;
+	case ISHLW:
+		r = Osll;
+		goto arithw;
+	case ILSRW:
+		r = Osrl;
+		goto arithw;
+	case IMULW:
+		r = Omul;
+		goto arithw;
+	case IDIVW:
+		r = Osdiv;
+		goto arithw;
+	case IADDW:
+		r = Oadd;
+	arithw:
+		mid(i, Oldw, RA1);
+		if(i->op == IDIVW) {
+			FM3I(2, Osra, 31, RA1, RA0);
+			FM3(2, Owry, RZ, RA0, 0);
+		}
+		if(UXSRC(i->add) == SRC(AIMM) && bc(i->s.imm))
+			FM3I(2, r, i->s.imm, RA1, RA0);
+		else {
+			opwld(i, Oldw, RA0);
+			FM3(2, r, RA0, RA1, RA0);
+		}
+		opwst(i, Ostw, RA0);
+		break;
+	case IORB:
+		r = Oor;
+		goto arithb;
+	case IANDB:
+		r = Oand;
+		goto arithb;
+	case IXORB:
+		r = Oxor;
+		goto arithb;
+	case ISUBB:
+		r = Osub;
+		goto arithb;
+	case IMULB:
+		r = Omul;
+		goto arithb;
+	case IDIVB:
+		FM3(2, Owry, RZ, RZ, 0);
+		r = Osdiv;
+		goto arithb;
+	case IADDB:
+		r = Oadd;
+	arithb:
+		mid(i, Oldbu, RA1);
+		opwld(i, Oldbu, RA0);
+		FM3(2, r, RA0, RA1, RA0);
+		opwst(i, Ostb, RA0);
+		break;
+	case ISHRB:
+		r = Osra;
+		goto shiftb;
+	case ISHLB:
+		r = Osll;
+	shiftb:
+		mid(i, Oldbu, RA1);
+		if(UXSRC(i->add) == SRC(AIMM) && bc(i->s.imm))
+			FM3I(2, r, i->s.imm, RA1, RA0);
+		else {
+			opwld(i, Oldw, RA0);
+			FM3(2, r, RA0, RA1, RA0);
+		}
+		opwst(i, Ostb, RA0);
+		break;
+	case IINDL:
+	case IINDF:
+	case IINDW:
+	case IINDB:
+		opwld(i, Oldw, RA0);			/* a */
+		r = 0;
+		switch(i->op) {
+		case IINDL:
+		case IINDF:
+			r = 3;
+			break;
+		case IINDW:
+			r = 2;
+			break;
+		}
+		if(UXDST(i->add) == DST(AIMM) && bc(i->d.imm<<r)) {
+			mem(Oldw, O(Array, data), RA0, RA0);
+			FM3I(2, Oadd, (i->d.imm<<r), RA0, RA0);
+		}
+		else {
+			opwst(i, Oldw, RA1);
+			mem(Oldw, O(Array, data), RA0, RA0);
+			if(r != 0)
+				FM3I(2, Osll, r, RA1, RA1);
+			FM3(2, Oadd, RA0, RA1, RA0);
+		}
+		r = RMP;
+		if((i->add&ARM) == AXINF)
+			r = RFP;
+		mem(Ostw, i->reg, r, RA0);
+		break;
+	case IINDX:
+		opwld(i, Oldw, RA0);			/* a */
+		/*
+		r = 0;
+		if(UXDST(i->add) == DST(AIMM) && bc(i->d.imm<<r))
+			r = i->d.imm<<r;
+		else
+		*/
+			opwst(i, Oldw, RA1);		/* i */
+		mem(Oldw, O(Array, t), RA0, RA2);
+		mem(Oldw, O(Array, data), RA0, RA0);
+		mem(Oldw, O(Type, size), RA2, RA2);
+		/*
+		if(r != 0)
+			FM3I(2, Oumul, r, RA2, RA1);
+		else
+		*/
+			FM3(2, Oumul, RA1, RA2, RA1);
+		FM3(2, Oadd, RA0, RA1, RA0);
+		r = RMP;
+		if((i->add&ARM) == AXINF)
+			r = RFP;
+		mem(Ostw, i->reg, r, RA0);
+		break;
+	case IADDL:
+		larith(i, Oaddcc, Oaddx);
+		break;
+	case ISUBL:
+		larith(i, Osubcc, Osubx);
+		break;
+	case IORL:
+		larith(i, Oor, Oor);
+		break;
+	case IANDL:
+		larith(i, Oand, Oand);
+		break;
+	case IXORL:
+		larith(i, Oxor, Oxor);
+		break;
+	case ICVTWL:
+		opwld(i, Oldw, RA1);
+		FM3I(2, Osra, 31, RA1, RA0);
+		opflst(i, Ostw, RA0);
+		break;
+	case ICVTLW:
+		opwld(i, Olea, RA0);
+		mem(Oldw, 4, RA0, RA0);
+		opwst(i, Ostw, RA0);
+		break;
+	case IBEQL:
+		cbral(i, Obne, Obe, ANDAND);
+		break;
+	case IBNEL:
+		cbral(i, Obne, Obne, OROR);
+		break;
+	case IBLEL:
+		cbral(i, Obl, Obleu, EQAND);
+		break;
+	case IBGTL:
+		cbral(i, Obg, Obgu, EQAND);
+		break;
+	case IBLTL:
+		cbral(i, Obl, Obcs, EQAND);
+		break;
+	case IBGEL:
+		cbral(i, Obg, Obcc, EQAND);
+		break;
+	case IMOVF:
+		opflld(i, Oldf, FA2);
+		opflst(i, Ostf, FA2);
+		break;
+	case IDIVF:
+		r = OfdivD;
+		goto arithf;
+	case IMULF:
+		r = OfmulD;
+		goto arithf;
+	case ISUBF:
+		r = OfsubD;
+		goto arithf;
+	case IADDF:
+		r = OfaddD;
+	arithf:
+		opflld(i, Oldf, FA2);
+		midfl(i, Oldf, FA4);
+		FMF1(r, FA2, FA4, FA4);
+		opflst(i, Ostf, FA4);
+		break;
+	case INEGF:
+		opflld(i, Oldf, FA2);
+		FMF1(OfnegS, FA2, 0, FA2);
+		opflst(i, Ostf, FA2);
+		break;
+	case ICVTFL:
+		// >= Sparc 8
+		// opflld(i, Oldf, FA2);
+		// FMF1(OfDtoQ, FA2, 0, FA2);
+		// opflst(i, Ostf, FA2);
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case ICVTLF:
+		// >= Sparc 8
+		// opflld(i, Oldf, FA2);
+		// FMF1(OfQtoD, FA2, 0, FA2);
+		// opflst(i, Ostf, FA2);
+		punt(i, SRCOP|DSTOP, optab[i->op]);
+		break;
+	case ICVTWF:
+		opwld(i, Oldf, FA2);
+		FMF1(OfWtoD, FA2, 0, FA2);
+		opflst(i, Ostf, FA2);
+		break;
+	case ICVTFW:
+		opflld(i, Oldf, FA2);
+		FMF1(OfDtoW, FA2, 0, FA2);
+		opwst(i, Ostf, FA2);
+		break;
+	case ISHLL:
+		shll(i);
+		break;
+	case ISHRL:
+	case ILSRL:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case IRAISE:
+		punt(i, SRCOP|WRTPC|NEWPC, optab[i->op]);
+		break;
+	case IMULX:
+	case IDIVX:
+	case ICVTXX:
+	case IMULX0:
+	case IDIVX0:
+	case ICVTXX0:
+	case IMULX1:
+	case IDIVX1:
+	case ICVTXX1:
+	case ICVTFX:
+	case ICVTXF:
+	case IEXPW:
+	case IEXPL:
+	case IEXPF:
+		punt(i, SRCOP|DSTOP|THREOP, optab[i->op]);
+		break;
+	case ISELF:
+		punt(i, DSTOP, optab[i->op]);
+		break;
+	}
+}
+
+static void
+preamble(void)
+{
+	ulong *start;
+
+	if(comvec)
+		return;
+
+	comvec = malloc(10 * sizeof(*code));
+	if(comvec == nil)
+		error(exNomem);
+	code = (ulong*)comvec;
+	start = code;
+
+	con((ulong)&R, RREG, 1);
+	mem(Ostw, O(REG, xpc), RREG, RLINK);
+	mem(Oldw, O(REG, PC), RREG, RA0);
+	mem(Oldw, O(REG, FP), RREG, RFP);
+	FM3I(2, Ojmpl, 0, RA0, RZ);
+	mem(Oldw, O(REG, MP), RREG, RMP);
+
+	segflush(comvec, 10 * sizeof(*code));
+
+	if(cflag > 4) {
+		print("comvec:\n");
+		das(start, code-start);
+	}
+}
+
+static void
+maccase(void)
+{
+	ulong *loop, *def, *lab1;
+
+	mem(Oldw, 0, RCON, RA3);		// n = t[0]
+	FM3I(2, Oadd, 4, RCON, RCON);
+	MOV(RA3, RA1);
+	FM3I(2, Osll, 1, RA1, RA1);
+	FM3(2, Oadd, RA3, RA1, RA1);
+	FM3I(2, Osll, 2, RA1, RA1);
+	FM3(3, Oldw, RCON, RA1, RLINK);
+
+	loop = code;
+	FM3(2, Ocmp, RZ, RA3, RZ);
+	def = code;
+	BRA(Oble, 0);
+	NOOP;
+
+	MOV(RA3, RA2);				// MOVL	DX, CX	n2 = n
+	FM3I(2, Osra, 1, RA2, RA2);		// SHR	CX,1	n2 = n2>>1
+	MOV(RA2, RA1);
+	FM3I(2, Osll, 1, RA1, RA1);
+	FM3(2, Oadd, RA2, RA1, RA1);
+	FM3I(2, Osll, 2, RA1, RA1);
+
+	FM3(3, Oldw, RA1, RCON, RTA);		// MOV	(RA1+RCON), RTA
+	FM3(2, Ocmp, RTA, RA0, RZ);
+	lab1 = code;
+	BRA(Obge, 0);
+	NOOP;
+	MOV(RA2, RA3);				// n = n2
+	BRA(Oba, loop-code);
+	NOOP;
+
+	PATCH(lab1);
+	FM3I(2, Oadd, 4, RA1, RTA);
+	FM3(3, Oldw, RTA, RCON, RTA);		// MOV	(RA1+RCON), RTA
+	FM3(2, Ocmp, RTA, RA0, RZ);
+	lab1 = code;
+	BRA(Obl, 0);
+	NOOP;
+
+	FM3I(2, Oadd, 12, RA1, RTA);
+	FM3(2, Oadd, RTA, RCON, RCON);
+	FM3(2, Osub, RA2, RA3, RA3);		// SUBL	CX, DX		n -= n2
+	FM3I(2, Oadd, -1, RA3, RA3);		// DECL	DX		n -= 1
+	BRA(Oba, loop-code);
+	NOOP;
+
+	PATCH(lab1);
+	FM3I(2, Oadd, 8, RA1, RTA);
+	FM3(3, Oldw, RTA, RCON, RLINK);
+
+	PATCH(def);
+	FM3I(2, Ojmpl, 0, RLINK, RZ);
+	NOOP;
+}
+
+static void
+macfrp(void)
+{
+	ulong *lab1, *lab2;
+
+	/* destroy the pointer in RA0 */
+	FM3I(2, Ocmp, -1, RA0, RZ);
+	lab1 = code;
+	BRA(Obe, 0);
+	NOOP;
+	mem(Oldw, O(Heap, ref)-sizeof(Heap), RA0, RA2);
+	FM3I(2, Oadd, -1, RA2, RA2);
+	FM3I(2, Ocmp, 0, RA2, RZ);
+	lab2 = code;
+	BRA(Obne, 0);
+	NOOP;
+	mem(Ostw, O(REG, FP), RREG, RFP);
+	mem(Ostw, O(REG, st), RREG, RLINK);
+	CALL(rdestroy);
+	mem(Ostw, O(REG, s), RREG, RA0);
+	con((ulong)&R, RREG, 1);
+	mem(Oldw, O(REG, st), RREG, RLINK);
+	mem(Oldw, O(REG, FP), RREG, RFP);
+	RETURN;
+	mem(Oldw, O(REG, MP), RREG, RMP);
+	PATCH(lab2);
+	mem(Ostw, O(Heap, ref)-sizeof(Heap), RA0, RA2);	
+	PATCH(lab1);
+	RETURN;
+	NOOP;
+}
+
+static void
+macret(void)
+{
+	Inst i;
+	ulong *cp1, *cp2, *cp3, *cp4, *cp5, *cp6;
+
+	FM3I(2, Ocmp, 0, RA1, RZ);
+	cp1 = code;
+	BRA(Obe, 0);				// t(Rfp) == 0
+	NOOP;
+
+	mem(Oldw, O(Type,destroy),RA1, RA0);
+	FM3I(2, Ocmp, 0, RA0, RZ);
+	cp2 = code;
+	BRA(Obe, 0);				// destroy(t(fp)) == 0
+	NOOP;
+
+	mem(Oldw, O(Frame,fp),RFP, RA2);
+	FM3I(2, Ocmp, 0, RA2, RZ);
+	cp3 = code;
+	BRA(Obe, 0);				// fp(Rfp) == 0
+	NOOP;
+
+	mem(Oldw, O(Frame,mr),RFP, RA3);
+	FM3I(2, Ocmp, 0, RA3, RZ);
+	cp4 = code;
+	BRA(Obe, 0);				// mr(Rfp) == 0
+	NOOP;
+
+	mem(Oldw, O(REG,M),RREG, RA2);
+	mem(Oldw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+	FM3I(2, Oaddcc, -1, RA3, RA3);
+	cp5 = code;
+	BRA(Obe, 0);				// --ref(arg) == 0
+	NOOP;
+	mem(Ostw, O(Heap,ref)-sizeof(Heap),RA2, RA3);
+
+	mem(Oldw, O(Frame,mr),RFP, RA1);
+	mem(Ostw, O(REG,M),RREG, RA1);
+	mem(Oldw, O(Modlink,compiled),RA1, RA2);	// check for uncompiled code
+	mem(Oldw, O(Modlink,MP),RA1, RMP);
+	FM3I(2, Ocmp, 0, RA2, RZ);
+	cp6 = code;
+	BRA(Obe, 0);
+	NOOP;
+	mem(Ostw, O(REG,MP),RREG, RMP);
+
+	PATCH(cp4);
+	FM3I(2, Ojmpl, 0, RA0, RLINK);		// call destroy(t(fp))
+	NOOP;
+	mem(Ostw, O(REG,SP),RREG, RFP);
+	mem(Oldw, O(Frame,lr),RFP, RA1);
+	mem(Oldw, O(Frame,fp),RFP, RFP);
+	mem(Ostw, O(REG,FP),RREG, RFP);
+	FM3I(2, Ojmpl, 0, RA1, RZ);		// goto lr(Rfp)
+	NOOP;
+
+	PATCH(cp6);
+	FM3I(2, Ojmpl, 0, RA0, RLINK);		// call destroy(t(fp))
+	NOOP;
+	mem(Ostw, O(REG,SP),RREG, RFP);
+	mem(Oldw, O(Frame,lr),RFP, RA1);
+	mem(Oldw, O(Frame,fp),RFP, RFP);
+	mem(Ostw, O(REG,FP),RREG, RFP);
+	mem(Oldw, O(REG,xpc),RREG, RA2);
+	FM3I(2, Oadd, 0x8, RA2, RA2);
+	FM3I(2, Ojmpl, 0, RA2, RZ);		// return to uncompiled code
+	mem(Ostw, O(REG,PC),RREG, RA1);
+	
+	PATCH(cp1);
+	PATCH(cp2);
+	PATCH(cp3);
+	PATCH(cp5);
+	i.add = AXNON;
+	punt(&i, TCHECK|NEWPC, optab[IRET]);
+}
+
+static void
+maccolr(void)
+{
+	ulong *br;
+
+	/* color the pointer in RA1 */
+	FM3I(2, Oadd, 1, RA0, RA0);
+	mem(Ostw, O(Heap, ref)-sizeof(Heap), RA1, RA0);
+	mem(Oldw, O(Heap, color)-sizeof(Heap), RA1, RA0);
+	mem(Oldw, 0, RA2, RA2);
+	FM3(2, Ocmp, RA0, RA2, RZ);
+	br = code;
+	BRA(Obe, 0);
+	con(propagator, RA2, 1);
+	mem(Ostw, O(Heap, color)-sizeof(Heap), RA1, RA2);	
+	con((ulong)&nprop, RA2, 1);
+	RETURN;
+	mem(Ostw, 0, RA2, RA2);	
+	PATCH(br);
+	RETURN;
+	NOOP;
+}
+
+static void
+macmcal(void)
+{
+	ulong *lab1, *lab2;
+
+	mem(Oldw, O(Modlink, prog), RA3, RA1);
+	FM3I(2, Ocmp, 0, RA1, RZ);
+	lab1 = code;
+	BRA(Obne, 0);
+	NOOP;
+
+	mem(Ostw, O(REG, st), RREG, RLINK);
+	mem(Ostw, O(REG, FP), RREG, RA2);
+	CALL(rmcall);				// CALL rmcall
+	mem(Ostw, O(REG, dt), RREG, RA0);
+
+	con((ulong)&R, RREG, 1);		// MOVL	$R, RREG
+	mem(Oldw, O(REG, st), RREG, RLINK);
+	mem(Oldw, O(REG, FP), RREG, RFP);
+	mem(Oldw, O(REG, MP), RREG, RMP);
+	RETURN;
+	NOOP;
+
+	PATCH(lab1);				// patch:
+	FM3(2, Oor, RA2, RZ, RFP);
+	mem(Ostw, O(REG, M), RREG, RA3);	// MOVL RA3, R.M
+	mem(Oldw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+	FM3I(2, Oadd, 1, RA1, RA1);
+	mem(Ostw, O(Heap, ref)-sizeof(Heap), RA3, RA1);
+	mem(Oldw, O(Modlink, compiled), RA3, RA1);
+	mem(Oldw, O(Modlink, MP), RA3, RMP);	// MOVL R.M->MP, RMP
+	FM3I(2, Ocmp, 0, RA1, RZ);
+	lab2 = code;
+	BRA(Obe, 0);
+	mem(Ostw, O(REG, MP), RREG, RMP);	// MOVL RA3, R.MP	R.MP = ml->MP
+
+	FM3I(2, Ojmpl, 0, RA0, RZ);
+	NOOP;
+
+	PATCH(lab2);
+	mem(Ostw, O(REG,FP),RREG, RFP);
+	mem(Oldw, O(REG,xpc),RREG, RA1);
+	FM3I(2, Oadd, 0x8, RA1, RA1);
+	FM3I(2, Ojmpl, 0, RA1, RZ);		// call to uncompiled code
+	mem(Ostw, O(REG,PC),RREG, RA0);
+}
+
+static void
+macfram(void)
+{
+	ulong *lab1;
+
+	mem(Oldw, O(REG, SP), RREG, RA0);	// MOVL	R.SP, RA0
+	mem(Oldw, O(Type, size), RA3, RA1);
+	FM3(2, Oadd, RA0, RA1, RA0);
+	mem(Oldw, O(REG, TS), RREG, RA1);
+	FM3(2, Ocmp, RA1, RA0, RZ);
+	lab1 = code;
+	BRA(Obl, 0);
+	NOOP;
+
+	mem(Ostw, O(REG, s), RREG, RA3);
+	mem(Ostw, O(REG, st), RREG, RLINK);
+	CALL(extend);				// CALL	extend
+	mem(Ostw, O(REG, FP), RREG, RFP);	// MOVL	RFP, R.FP
+
+	con((ulong)&R, RREG, 1);
+	mem(Oldw, O(REG, st), RREG, RLINK);
+	mem(Oldw, O(REG, FP), RREG, RFP);	// MOVL	R.MP, RMP
+	mem(Oldw, O(REG, s), RREG, RA2);	// MOVL	R.s, *R.d
+	mem(Oldw, O(REG, MP), RREG, RMP);	// MOVL R.MP, RMP
+	RETURN;					// RET
+	NOOP;
+
+	PATCH(lab1);
+	mem(Oldw, O(REG, SP), RREG, RA2);	// MOVL	R.SP, RA2
+	mem(Ostw, O(REG, SP), RREG, RA0);	// MOVL	RA0, R.SP
+
+	mem(Ostw, O(Frame, t), RA2, RA3);	// MOVL	RA3, t(RA2) f->t = t
+	mem(Oldw, O(Type, initialize), RA3, RA3);
+	FM3I(2, Ojmpl, 0, RA3, RZ);
+	mem(Ostw, REGMOD*4, RA2, RZ);     	// MOVL $0, mr(RA2) f->mr
+}
+
+static void
+macmfra(void)
+{
+	mem(Ostw, O(REG, st), RREG, RLINK);
+	mem(Ostw, O(REG, s), RREG, RA3);	// Save type
+	mem(Ostw, O(REG, d), RREG, RA0);	// Save destination
+	CALL(rmfram);				// CALL rmfram
+	mem(Ostw, O(REG, FP), RREG, RFP);
+
+	con((ulong)&R, RREG, 1);
+	mem(Oldw, O(REG, st), RREG, RLINK);
+	mem(Oldw, O(REG, FP), RREG, RFP);
+	mem(Oldw, O(REG, MP), RREG, RMP);
+	RETURN;
+	NOOP;
+}
+
+void
+comd(Type *t)
+{
+	int i, j, m, c;
+
+	mem(Ostw, O(REG, dt), RREG, RLINK);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m) {
+				CALL(base+macro[MacFRP]);
+				mem(Oldw, j, RFP, RA0);
+			}
+			j += sizeof(WORD*);
+		}
+	}
+	mem(Oldw, O(REG, dt), RREG, RLINK);
+	RETURN;
+	NOOP;
+}
+
+void
+comi(Type *t)
+{
+	int i, j, m, c;
+
+	con((ulong)H, RA0, 1);
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		j = i<<5;
+		for(m = 0x80; m != 0; m >>= 1) {
+			if(c & m)
+				mem(Ostw, j, RA2, RA0);
+			j += sizeof(WORD*);
+		}
+	}
+	RETURN;
+	NOOP;
+}
+
+void
+typecom(Type *t)
+{
+	int n;
+	ulong *tmp, *start;
+
+	if(t == nil || t->initialize != 0)
+		return;
+
+	tmp = mallocz(4096*sizeof(ulong), 0);
+	if(tmp == nil)
+		error(exNomem);
+
+	code = tmp;
+	comi(t);
+	n = code - tmp;
+	code = tmp;
+	comd(t);
+	n += code - tmp;
+	free(tmp);
+
+	n *= sizeof(*code);
+	code = mallocz(n, 0);
+	if(code == nil)
+		return;
+
+	start = code;
+	t->initialize = code;
+	comi(t);
+	t->destroy = code;
+	comd(t);
+
+	segflush(start, n);
+
+	if(cflag > 1)
+		print("typ= %.8p %4d i %.8p d %.8p asm=%d\n",
+			t, t->size, t->initialize, t->destroy, n);
+}
+
+static void
+patchex(Module *m, ulong *p)
+{
+	Handler *h;
+	Except *e;
+
+	if((h = m->htab) == nil)
+		return;
+	for( ; h->etab != nil; h++){
+		h->pc1 = p[h->pc1];
+		h->pc2 = p[h->pc2];
+		for(e = h->etab; e->s != nil; e++)
+			e->pc = p[e->pc];
+		if(e->pc != -1)
+			e->pc = p[e->pc];
+	}
+}
+
+int
+compile(Module *m, int size, Modlink *ml)
+{
+	Link *l;
+	Modl *e;
+	int i, n;
+	ulong *s, *tmp;
+
+	base = nil;
+	patch = mallocz(size*sizeof(*patch), 0);
+	tinit = malloc(m->ntype*sizeof(*tinit));
+	tmp = mallocz(1024*sizeof(ulong), 0);
+	if(tinit == nil || patch == nil || tmp == nil)
+		goto bad;
+
+	preamble();
+
+	mod = m;
+	n = 0;
+	pass = 0;
+	nlit = 0;
+
+	for(i = 0; i < size; i++) {
+		code = tmp;
+		comp(&m->prog[i]);
+		patch[i] = n;
+		n += code - tmp;
+	}
+
+	for(i = 0; i < nelem(mactab); i++) {
+		code = tmp;
+		mactab[i].gen();
+		macro[mactab[i].idx] = n;
+		n += code - tmp;
+	}
+
+	base = mallocz((n+nlit)*sizeof(*code), 0);
+	if(base == nil)
+		goto bad;
+
+	if(cflag > 1)
+		print("dis=%5d %5d sparc=%5d asm=%.8p lit=%d: %s\n",
+			size, size*sizeof(Inst), n, base, nlit, m->name);
+
+	pass++;
+	nlit = 0;
+	litpool = base+n;
+	code = base;
+
+	for(i = 0; i < size; i++) {
+		s = code;
+		comp(&m->prog[i]);
+		if(cflag > 2) {
+			print("%d %D\n", i, &m->prog[i]);
+			das(s, code-s);
+		}
+	}
+
+	for(i = 0; i < nelem(mactab); i++) {
+		s = code;
+		mactab[i].gen();
+		if(cflag > 2) {
+			print("%s:\n", mactab[i].name);
+			das(s, code-s);
+		}
+	}
+
+	if(n != (code - base))
+		error(exCphase);
+
+	for(l = m->ext; l->name; l++) {
+		l->u.pc = (Inst*)RELPC(patch[l->u.pc-m->prog]);
+		typecom(l->frame);
+	}
+	if(ml != nil) {
+		e = &ml->links[0];
+		for(i = 0; i < ml->nlinks; i++) {
+			e->u.pc = (Inst*)RELPC(patch[e->u.pc-m->prog]);
+			typecom(e->frame);
+			e++;
+		}
+	}
+	for(i = 0; i < m->ntype; i++) {
+		if(tinit[i] != 0)
+			typecom(m->type[i]);
+	}
+	patchex(m, patch);
+	m->entry = (Inst*)RELPC(patch[mod->entry-mod->prog]);
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(m->prog);
+	m->prog = (Inst*)base;
+	m->compiled = 1;
+	segflush(base, n*sizeof(*base));
+	return 1;
+bad:
+	free(patch);
+	free(tinit);
+	free(tmp);
+	free(base);
+	return 0;
+}
--- /dev/null
+++ b/libinterp/comp-spim.c
@@ -1,0 +1,2 @@
+#define	HIOFFSET	4	/* byte offset of high-order word in little-endian vlongs */
+#include	"comp-mips.c"
--- /dev/null
+++ b/libinterp/conv.c
@@ -1,0 +1,110 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "mathi.h"
+
+enum
+{
+	TOKI0,
+	TOKI1,
+	TOKI2,
+	TOKI3,
+	TOKSB,
+	TOKFP
+};
+#include "tab.h"
+
+typedef struct Addr	Addr;
+struct Addr
+{
+	uchar	mode;
+	Adr	a;
+};
+
+#pragma	varargck	type	"a"	Addr*
+
+char*	opnam[256];
+int	iconv(Fmt*);
+int	aconv(Fmt*);
+
+int
+aconv(Fmt *f)
+{
+	Addr *a;
+	char buf[64];
+
+	a = va_arg(f->args, Addr*);
+	if(a == nil)
+		return fmtstrcpy(f, "AZ");
+	switch(a->mode & AMASK) {
+	case AFP:	sprint(buf, "%d(fp)", a->a.ind);	break;
+	case AMP:	sprint(buf, "%d(mp)", a->a.ind);	break;
+	case AIMM:	sprint(buf, "$%d", a->a.imm);		break;
+	case AIND|AFP:	sprint(buf, "%d(%d(fp))", a->a.i.s, a->a.i.f); break;
+	case AIND|AMP:	sprint(buf, "%d(%d(mp))", a->a.i.s, a->a.i.f); break;
+	}
+	return fmtstrcpy(f, buf);
+}
+
+int
+Dconv(Fmt *f)
+{
+	int j;
+	Inst *i;
+	Addr s, d;
+	char buf[128];
+	static int init;
+
+	if(init == 0) {
+		for(j = 0; keywds[j].name != nil; j++)
+			opnam[keywds[j].op] = keywds[j].name;
+
+		fmtinstall('a', aconv);
+		init = 1;
+	}
+
+	i = va_arg(f->args, Inst*);
+	if(i == nil)
+		return fmtstrcpy(f, "IZ");
+
+	switch(keywds[i->op].terminal) {
+	case TOKI0:
+		sprint(buf, "%s", opnam[i->op]);
+		break;
+	case TOKI1:
+		d.a = i->d;
+		d.mode = UDST(i->add);
+		sprint(buf, "%s\t%a", opnam[i->op], &d);
+		break;
+	case TOKI3:
+		d.a = i->d;
+		d.mode = UDST(i->add);
+		s.a = i->s;
+		s.mode = USRC(i->add);
+		switch(i->add&ARM) {
+		default:
+			sprint(buf, "%s\t%a, %a", opnam[i->op], &s, &d);
+			break;
+		case AXIMM:
+			sprint(buf, "%s\t%a, $%d, %a", opnam[i->op], &s, i->reg, &d);
+			break;
+		case AXINF:
+			sprint(buf, "%s\t%a, %d(fp), %a", opnam[i->op], &s, i->reg, &d);
+			break;
+		case AXINM:
+			sprint(buf, "%s\t%a, %d(mp), %a", opnam[i->op], &s, i->reg, &d);
+			break;
+		}
+		break;
+	case TOKI2:
+		d.a = i->d;
+		d.mode = UDST(i->add);
+		s.a = i->s;
+		s.mode = USRC(i->add);
+		sprint(buf, "%s\t%a, %a", opnam[i->op], &s, &d);
+		break;
+	}
+
+	return fmtstrcpy(f, buf);
+}
+
--- /dev/null
+++ b/libinterp/crypt.c
@@ -1,0 +1,1348 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include "runt.h"
+#include "cryptmod.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "raise.h"
+#include "ipint.h"
+
+#define	MPX(x)	checkIPint((void*)(x))
+
+static Type*	TDigestState;
+static Type*	TAESstate;
+static Type*	TDESstate;
+static Type*	TIDEAstate;
+static Type*	TBFstate;
+static Type*	TRC4state;
+
+static Type*	TSKdsa;
+static Type*	TPKdsa;
+static Type*	TPKsigdsa;
+static Type*	TSKeg;
+static Type*	TPKeg;
+static Type*	TPKsigeg;
+static Type*	TSKrsa;
+static Type*	TPKrsa;
+static Type*	TPKsigrsa;
+
+static uchar DigestStatemap[] = Crypt_DigestState_map;
+static uchar AESstatemap[] = Crypt_AESstate_map;
+static uchar DESstatemap[] = Crypt_DESstate_map;
+static uchar IDEAstatemap[] = Crypt_IDEAstate_map;
+static uchar BFstatemap[] = Crypt_BFstate_map;
+static uchar RC4statemap[] = Crypt_RC4state_map;
+
+static uchar DSAskmap[] = Crypt_SK_DSA_map;
+static uchar DSApkmap[] = Crypt_PK_DSA_map;
+static uchar DSAsigmap[] = Crypt_PKsig_DSA_map;
+static uchar EGskmap[] = Crypt_SK_Elgamal_map;
+static uchar EGpkmap[] = Crypt_PK_Elgamal_map;
+static uchar EGsigmap[] = Crypt_PKsig_Elgamal_map;
+static uchar RSAskmap[] = Crypt_SK_RSA_map;
+static uchar RSApkmap[] = Crypt_PK_RSA_map;
+static uchar RSAsigmap[] = Crypt_PKsig_RSA_map;
+
+static char exBadBsize[]	= "data not multiple of block size";
+static char exBadKey[]	= "bad encryption key";
+static char exBadDigest[]	= "bad digest value";
+static char exBadIvec[]	= "bad ivec";
+static char exBadState[] = "bad encryption state";
+
+/*
+ * these structures reveal the C state of Limbo adts in crypt.m
+ */
+
+typedef struct XDigestState XDigestState;
+typedef struct XAESstate XAESstate;
+typedef struct XDESstate XDESstate;
+typedef struct XIDEAstate XIDEAstate;
+typedef struct XBFstate XBFstate;
+typedef struct XRC4state XRC4state;
+
+/* digest state */
+struct XDigestState
+{
+	Crypt_DigestState	x;
+	DigestState	state;
+};
+
+/* AES state */
+struct XAESstate
+{
+	Crypt_AESstate	x;
+	AESstate	state;
+};
+
+/* DES state */
+struct XDESstate
+{
+	Crypt_DESstate	x;
+	DESstate	state;
+};
+
+/* IDEA state */
+struct XIDEAstate
+{
+	Crypt_IDEAstate	x;
+	IDEAstate	state;
+};
+
+/* BF state */
+struct XBFstate
+{
+	Crypt_BFstate	x;
+	BFstate	state;
+};
+
+/* RC4 state */
+struct XRC4state
+{
+	Crypt_RC4state	x;
+	RC4state	state;
+};
+
+static Crypt_PK*
+newPK(Type *t, int pick)
+{
+	Heap *h;
+	Crypt_PK *sk;
+
+	h = heap(t);
+	sk = H2D(Crypt_PK*, h);
+	sk->pick = pick;
+	return sk;
+}
+
+static Crypt_SK*
+newSK(Crypt_SK** ret, Type *t, int pick)
+{
+	Heap *h;
+	Crypt_SK *sk;
+
+	h = heap(t);
+	sk = H2D(Crypt_SK*, h);
+	sk->pick = pick;
+	if(ret != nil)
+		*ret = sk;
+	switch(pick){
+	case Crypt_PK_RSA:
+		sk->u.RSA.pk = newPK(TPKrsa, Crypt_PK_RSA);
+		break;
+	case Crypt_PK_Elgamal:
+		sk->u.Elgamal.pk = newPK(TPKeg, Crypt_PK_Elgamal);
+		break;
+	case Crypt_PK_DSA:
+		sk->u.DSA.pk = newPK(TPKdsa, Crypt_PK_DSA);
+		break;
+	default:
+		error(exType);
+	}
+	return sk;
+}
+
+static Crypt_PKsig*
+newPKsig(Type *t, int pick)
+{
+	Heap *h;
+	Crypt_PKsig *s;
+
+	h = heap(t);
+	s = H2D(Crypt_PKsig*, h);
+	s->pick = pick;
+	return s;
+}
+
+static IPints_IPint*
+ipcopymp(mpint* b)
+{
+	if(b == nil)
+		return H;
+	return newIPint(mpcopy(b));
+}
+
+/*
+ *  digests
+ */
+void
+DigestState_copy(void *fp)
+{
+	F_DigestState_copy *f;
+	Heap *h;
+	XDigestState *ds, *ods;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	if(f->d != H){
+		ods = checktype(f->d, TDigestState, "DigestState", 0);
+		h = heap(TDigestState);
+		ds = H2D(XDigestState*, h); 	
+		memmove(&ds->state, &ods->state, sizeof(ds->state)); 
+		*f->ret = (Crypt_DigestState*)ds;
+	}
+}
+
+static Crypt_DigestState*
+crypt_digest_x(Array *buf, int n, Array *digest, int dlen, Crypt_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, DigestState*))
+{
+	Heap *h;
+	XDigestState *ds;
+	uchar *cbuf, *cdigest;
+
+	if(buf != H){
+		if(n > buf->len)
+			n = buf->len;
+		cbuf = buf->data;
+	}else{
+		if(n != 0)
+			error(exInval);
+		cbuf = nil;
+	}
+
+	if(digest != H){
+		if(digest->len < dlen)
+			error(exBadDigest);
+		cdigest = digest->data;
+	} else
+		cdigest = nil;
+
+	if(state == H){
+		h = heap(TDigestState);
+		ds = H2D(XDigestState*, h);
+		memset(&ds->state, 0, sizeof(ds->state));
+	} else
+		ds = checktype(state, TDigestState, "DigestState", 1);
+
+	(*fn)(cbuf, n, cdigest, &ds->state);
+
+	return (Crypt_DigestState*)ds;
+}
+
+void
+Crypt_sha1(void *fp)
+{
+	F_Crypt_sha1 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1);
+}
+
+void
+Crypt_sha224(void *fp)
+{
+	F_Crypt_sha224 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224);
+}
+
+void
+Crypt_sha256(void *fp)
+{
+	F_Crypt_sha256 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256);
+}
+
+void
+Crypt_sha384(void *fp)
+{
+	F_Crypt_sha384 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384);
+}
+
+void
+Crypt_sha512(void *fp)
+{
+	F_Crypt_sha512 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = crypt_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512);
+}
+
+void
+Crypt_md5(void *fp)
+{
+	F_Crypt_md5 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5);
+}
+
+void
+Crypt_md4(void *fp)
+{
+	F_Crypt_md4 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = crypt_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4);
+}
+
+static Crypt_DigestState*
+crypt_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Crypt_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*))
+{
+	Heap *h;
+	XDigestState *ds;
+	uchar *cdata, *cdigest;
+
+	if(data != H){
+		if(n > data->len)
+			n = data->len;
+		cdata = data->data;
+	}else{
+		if(n != 0)
+			error(exInval);
+		cdata = nil;
+	}
+
+	if(key == H || key->len > 64)
+		error(exBadKey);
+
+	if(digest != H){
+		if(digest->len < dlen)
+			error(exBadDigest);
+		cdigest = digest->data;
+	} else
+		cdigest = nil;
+
+	if(state == H){
+		h = heap(TDigestState);
+		ds = H2D(XDigestState*, h);
+		memset(&ds->state, 0, sizeof(ds->state));
+	} else
+		ds = checktype(state, TDigestState, "DigestState", 1);
+
+	(*fn)(cdata, n, key->data, key->len, cdigest, &ds->state);
+
+	return (Crypt_DigestState*)ds;
+}
+
+void
+Crypt_hmac_sha1(void *fp)
+{
+	F_Crypt_hmac_sha1 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	*f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1);
+}
+
+void
+Crypt_hmac_md5(void *fp)
+{
+	F_Crypt_hmac_md5 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	*f->ret = crypt_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5);
+}
+
+void
+Crypt_dhparams(void *fp)
+{
+	F_Crypt_dhparams *f;
+	mpint *p, *alpha;
+	void *v;
+
+	f = fp;
+	v = f->ret->t0;
+	f->ret->t0 = H;
+	destroy(v);
+	v = f->ret->t1;
+	f->ret->t1 = H;
+	destroy(v);
+
+	p = mpnew(0);
+	alpha = mpnew(0);
+	release();
+	if(f->nbits == 1024)
+		DSAprimes(alpha, p, nil);
+	else
+		gensafeprime(p, alpha, f->nbits, 0);
+	acquire();
+	f->ret->t0 = newIPint(alpha);
+	f->ret->t1 = newIPint(p);
+}
+
+void
+cryptmodinit(void)
+{
+	ipintsmodinit();	/* TIPint */
+
+	TDigestState = dtype(freeheap, sizeof(XDigestState), DigestStatemap, sizeof(DigestStatemap));
+	TAESstate = dtype(freeheap, sizeof(XAESstate), AESstatemap, sizeof(AESstatemap));
+	TDESstate = dtype(freeheap, sizeof(XDESstate), DESstatemap, sizeof(DESstatemap));
+	TIDEAstate = dtype(freeheap, sizeof(XIDEAstate), IDEAstatemap, sizeof(IDEAstatemap));
+	TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap, sizeof(BFstatemap));
+	TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap, sizeof(RC4statemap));
+
+	TSKdsa = dtype(freeheap, Crypt_SK_DSA_size, DSAskmap, sizeof(DSAskmap));
+	TPKdsa = dtype(freeheap, Crypt_PK_DSA_size, DSApkmap, sizeof(DSApkmap));
+	TPKsigdsa = dtype(freeheap, Crypt_PKsig_DSA_size, DSAsigmap, sizeof(DSAsigmap));
+	TSKeg = dtype(freeheap, Crypt_SK_Elgamal_size, EGskmap, sizeof(EGskmap));
+	TPKeg = dtype(freeheap, Crypt_PK_Elgamal_size, EGpkmap, sizeof(EGpkmap));
+	TPKsigeg = dtype(freeheap, Crypt_PKsig_Elgamal_size, EGsigmap, sizeof(EGsigmap));
+	TSKrsa = dtype(freeheap, Crypt_SK_RSA_size, RSAskmap, sizeof(RSAskmap));
+	TPKrsa = dtype(freeheap, Crypt_PK_RSA_size, RSApkmap, sizeof(RSApkmap));
+	TPKsigrsa = dtype(freeheap, Crypt_PKsig_RSA_size, RSAsigmap, sizeof(RSAsigmap));
+
+	builtinmod("$Crypt", Cryptmodtab, Cryptmodlen);
+}
+
+void
+Crypt_dessetup(void *fp)
+{
+	F_Crypt_dessetup *f;
+	Heap *h;
+	XDESstate *ds;
+	uchar *ivec;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->key == H)
+		error(exNilref);
+	if(f->key->len < 8)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len < 8)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TDESstate);
+	ds = H2D(XDESstate*, h);
+	setupDESstate(&ds->state, f->key->data, ivec);
+
+	*f->ret = (Crypt_DESstate*)ds;
+}
+
+void
+Crypt_desecb(void *fp)
+{
+	F_Crypt_desecb *f;
+	XDESstate *ds;
+	int i;
+	uchar *p;
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	ds = checktype(f->state, TDESstate, exBadState, 0);
+	p = f->buf->data;
+
+	for(i = 8; i <= f->n; i += 8, p += 8)
+		block_cipher(ds->state.expanded, p, f->direction);
+}
+
+void
+Crypt_descbc(void *fp)
+{
+	F_Crypt_descbc *f;
+	XDESstate *ds;
+	uchar *p, *ep, *ip, *p2, *eip;
+	uchar tmp[8];
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	ds = checktype(f->state, TDESstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0){
+		for(ep = p + f->n; p < ep; p += 8){
+			p2 = p;
+			ip = ds->state.ivec;
+			for(eip = ip+8; ip < eip; )
+				*p2++ ^= *ip++;
+			block_cipher(ds->state.expanded, p, 0);
+			memmove(ds->state.ivec, p, 8);
+		}
+	} else {
+		for(ep = p + f->n; p < ep; ){
+			memmove(tmp, p, 8);
+			block_cipher(ds->state.expanded, p, 1);
+			p2 = tmp;
+			ip = ds->state.ivec;
+			for(eip = ip+8; ip < eip; ){
+				*p++ ^= *ip;
+				*ip++ = *p2++;
+			}
+		}
+	}
+}
+
+void
+Crypt_ideasetup(void *fp)
+{
+	F_Crypt_ideasetup *f;
+	Heap *h;
+	XIDEAstate *is;
+	uchar *ivec;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->key == H)
+		error(exNilref);
+	if(f->key->len < 16)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len < 8)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TIDEAstate);
+	is = H2D(XIDEAstate*, h);
+
+	setupIDEAstate(&is->state, f->key->data, ivec);
+
+	*f->ret = (Crypt_IDEAstate*)is;
+}
+
+void
+Crypt_ideaecb(void *fp)
+{
+	F_Crypt_ideaecb *f;
+	XIDEAstate *is;
+	int i;
+	uchar *p;
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	is = checktype(f->state, TIDEAstate, exBadState, 0);
+	p = f->buf->data;
+
+	for(i = 8; i <= f->n; i += 8, p += 8)
+		idea_cipher(is->state.edkey, p, f->direction);
+}
+
+void
+Crypt_ideacbc(void *fp)
+{
+	F_Crypt_ideacbc *f;
+	XIDEAstate *is;
+	uchar *p, *ep, *ip, *p2, *eip;
+	uchar tmp[8];
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	is = checktype(f->state, TIDEAstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0){
+		for(ep = p + f->n; p < ep; p += 8){
+			p2 = p;
+			ip = is->state.ivec;
+			for(eip = ip+8; ip < eip; )
+				*p2++ ^= *ip++;
+			idea_cipher(is->state.edkey, p, 0);
+			memmove(is->state.ivec, p, 8);
+		}
+	} else {
+		for(ep = p + f->n; p < ep; ){
+			memmove(tmp, p, 8);
+			idea_cipher(is->state.edkey, p, 1);
+			p2 = tmp;
+			ip = is->state.ivec;
+			for(eip = ip+8; ip < eip; ){
+				*p++ ^= *ip;
+				*ip++ = *p2++;
+			}
+		}
+	}
+}
+
+void
+Crypt_aessetup(void *fp)
+{
+	F_Crypt_aessetup *f;
+	Heap *h;
+	XAESstate *is;
+	uchar *ivec;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->key == H)
+		error(exNilref);
+	if(f->key->len != 16 && f->key->len != 24 && f->key->len != 32)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len < AESbsize)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TAESstate);
+	is = H2D(XAESstate*, h);
+
+	setupAESstate(&is->state, f->key->data, f->key->len, ivec);
+
+	*f->ret = (Crypt_AESstate*)is;
+}
+
+void
+Crypt_aescbc(void *fp)
+{
+	F_Crypt_aescbc *f;
+	XAESstate *is;
+	uchar *p;
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+
+	is = checktype(f->state, TAESstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0)
+		aesCBCencrypt(p, f->n, &is->state);
+	else
+		aesCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Crypt_blowfishsetup(void *fp)
+{
+	F_Crypt_blowfishsetup *f;
+	Heap *h;
+	XBFstate *is;
+	uchar *ivec;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->key == H)
+		error(exNilref);
+	if(f->key->len <= 0)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len != BFbsize)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TBFstate);
+	is = H2D(XBFstate*, h);
+
+	setupBFstate(&is->state, f->key->data, f->key->len, ivec);
+
+	*f->ret = (Crypt_BFstate*)is;
+}
+
+void
+Crypt_blowfishcbc(void *fp)
+{
+	F_Crypt_blowfishcbc *f;
+	XBFstate *is;
+	uchar *p;
+
+	f = fp;
+
+	if(f->state == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	is = checktype(f->state, TBFstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0)
+		bfCBCencrypt(p, f->n, &is->state);
+	else
+		bfCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Crypt_rc4setup(void *fp)
+{
+	F_Crypt_rc4setup *f;
+	Heap *h;
+	XRC4state *is;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->seed == H)
+		error(exNilref);
+
+	h = heap(TRC4state);
+	is = H2D(XRC4state*, h);
+
+	setupRC4state(&is->state, f->seed->data, f->seed->len);
+
+	*f->ret = (Crypt_RC4state*)is;
+}
+
+void
+Crypt_rc4(void *fp)
+{
+	F_Crypt_rc4 *f;
+	XRC4state *is;
+	uchar *p;
+
+	f = fp;
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	is = checktype(f->state, TRC4state, exBadState, 0);
+	p = f->buf->data;
+	rc4(&is->state, p, f->n);
+}
+
+void
+Crypt_rc4skip(void *fp)
+{
+	F_Crypt_rc4skip *f;
+	XRC4state *is;
+
+	f = fp;
+	is = checktype(f->state, TRC4state, exBadState, 0);
+	rc4skip(&is->state, f->n);
+}
+
+void
+Crypt_rc4back(void *fp)
+{
+	F_Crypt_rc4back *f;
+	XRC4state *is;
+
+	f = fp;
+	is = checktype(f->state, TRC4state, exBadState, 0);
+	rc4back(&is->state, f->n);
+}
+
+/*
+ *  public/secret keys, signing and verifying
+ */
+
+/*
+ * DSA
+ */
+
+static void
+dsapk2pub(DSApub* p, Crypt_PK* pk)
+{
+	if(pk == H)
+		error(exNilref);
+	if(pk->pick != Crypt_PK_DSA)
+		error(exType);
+	p->p = MPX(pk->u.DSA.p);
+	p->q = MPX(pk->u.DSA.q);
+	p->alpha = MPX(pk->u.DSA.alpha);
+	p->key = MPX(pk->u.DSA.key);
+}
+
+static void
+dsask2priv(DSApriv* p, Crypt_SK* sk)
+{
+	if(sk == H)
+		error(exNilref);
+	if(sk->pick != Crypt_SK_DSA)
+		error(exType);
+	dsapk2pub(&p->pub, sk->u.DSA.pk);
+	p->secret = MPX(sk->u.DSA.secret);
+}
+
+static void
+dsapriv2sk(Crypt_SK* sk, DSApriv* p)
+{
+	Crypt_PK *pk;
+
+	pk = sk->u.DSA.pk;
+	pk->u.DSA.p = ipcopymp(p->pub.p);
+	pk->u.DSA.q = ipcopymp(p->pub.q);
+	pk->u.DSA.alpha = ipcopymp(p->pub.alpha);
+	pk->u.DSA.key = ipcopymp(p->pub.key);
+	sk->u.DSA.secret = ipcopymp(p->secret);
+}
+
+static void
+dsaxgen(Crypt_SK* sk, DSApub* oldpk)
+{
+	DSApriv *p;
+
+	release();
+	p = dsagen(oldpk);
+	acquire();
+	dsapriv2sk(sk, p);
+	dsaprivfree(p);
+}
+
+void
+Crypt_dsagen(void *fp)
+{
+	F_Crypt_dsagen *f;
+	Crypt_SK *sk;
+	DSApub pub, *oldpk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+	oldpk = nil;
+	if(f->oldpk != H && f->oldpk->pick == Crypt_PK_DSA){
+		dsapk2pub(&pub, f->oldpk);
+		oldpk = &pub;
+	}
+	dsaxgen(sk, oldpk);
+}
+
+/*
+ * Elgamal
+ */
+
+static void
+egpk2pub(EGpub* p, Crypt_PK* pk)
+{
+	if(pk == H)
+		error(exNilref);
+	if(pk->pick != Crypt_PK_Elgamal)
+		error(exType);
+	p->p = MPX(pk->u.Elgamal.p);
+	p->alpha = MPX(pk->u.Elgamal.alpha);
+	p->key = MPX(pk->u.Elgamal.key);
+}
+
+static void
+egsk2priv(EGpriv* p, Crypt_SK* sk)
+{
+	if(sk == H)
+		error(exNilref);
+	if(sk->pick != Crypt_SK_Elgamal)
+		error(exType);
+	egpk2pub(&p->pub, sk->u.Elgamal.pk);
+	p->secret = MPX(sk->u.Elgamal.secret);
+}
+
+static void
+egpriv2sk(Crypt_SK* sk, EGpriv* p)
+{
+	Crypt_PK* pk;
+
+	pk = sk->u.Elgamal.pk;
+	pk->u.Elgamal.p = ipcopymp(p->pub.p);
+	pk->u.Elgamal.alpha = ipcopymp(p->pub.alpha);
+	pk->u.Elgamal.key = ipcopymp(p->pub.key);
+	sk->u.Elgamal.secret = ipcopymp(p->secret);
+}
+
+static void
+egxgen(Crypt_SK* sk, int nlen, int nrep)
+{
+	EGpriv *p;
+
+	release();
+	for(;;){
+		p = eggen(nlen, nrep);
+		if(mpsignif(p->pub.p) == nlen)
+			break;
+		egprivfree(p);
+	}
+	acquire();
+	egpriv2sk(sk, p);
+	egprivfree(p);
+}
+	
+
+void
+Crypt_eggen(void *fp)
+{
+	F_Crypt_eggen *f;
+	Crypt_SK *sk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+	egxgen(sk, f->nlen, f->nrep);
+}
+
+/*
+ * RSA
+ */
+
+static void
+rsapk2pub(RSApub* p, Crypt_PK* pk)
+{
+	if(pk == H)
+		error(exNilref);
+	if(pk->pick != Crypt_PK_RSA)
+		error(exType);
+	p->n = MPX(pk->u.RSA.n);
+	p->ek = MPX(pk->u.RSA.ek);
+}
+
+static void
+rsask2priv(RSApriv* p, Crypt_SK* sk)
+{
+	if(sk == H)
+		error(exNilref);
+	if(sk->pick != Crypt_SK_RSA)
+		error(exType);
+	rsapk2pub(&p->pub, sk->u.RSA.pk);
+	p->dk = MPX(sk->u.RSA.dk);
+	p->p = MPX(sk->u.RSA.p);
+	p->q = MPX(sk->u.RSA.q);
+	p->kp = MPX(sk->u.RSA.kp);
+	p->kq = MPX(sk->u.RSA.kq);
+	p->c2 = MPX(sk->u.RSA.c2);
+}
+
+static void
+rsapriv2sk(Crypt_SK* sk, RSApriv* p)
+{
+	Crypt_PK *pk;
+
+	pk = sk->u.RSA.pk;
+	pk->u.RSA.n = ipcopymp(p->pub.n);
+	pk->u.RSA.ek = ipcopymp(p->pub.ek);
+	sk->u.RSA.dk = ipcopymp(p->dk);
+	sk->u.RSA.p = ipcopymp(p->p);
+	sk->u.RSA.q = ipcopymp(p->q);
+	sk->u.RSA.kp = ipcopymp(p->kp);
+	sk->u.RSA.kq = ipcopymp(p->kq);
+	sk->u.RSA.c2 = ipcopymp(p->c2);
+}
+
+static void
+rsaxgen(Crypt_SK *sk, int nlen, int elen, int nrep)
+{
+	RSApriv *p;
+
+	release();
+	for(;;){
+		p = rsagen(nlen, elen, nrep);
+		if(mpsignif(p->pub.n) == nlen)
+			break;
+		rsaprivfree(p);
+	}
+	acquire();
+	rsapriv2sk(sk, p);
+	rsaprivfree(p);
+}
+
+void
+Crypt_rsagen(void *fp)
+{
+	F_Crypt_rsagen *f;
+	Crypt_SK *sk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+	rsaxgen(sk, f->nlen, f->elen, f->nrep);
+}
+
+void
+Crypt_rsafill(void *fp)
+{
+	F_Crypt_rsafill *f;
+	Crypt_SK *sk;
+	RSApriv *p;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+	release();
+	p = rsafill(MPX(f->n), MPX(f->ek), MPX(f->dk),
+			MPX(f->p), MPX(f->q));
+	acquire();
+	if(p == nil) {
+		*f->ret = H;
+		destroy(sk);
+	}else{
+		rsapriv2sk(sk, p);
+		rsaprivfree(p);
+	}
+}
+
+void
+Crypt_rsaencrypt(void *fp)
+{
+	F_Crypt_rsaencrypt *f;
+	RSApub p;
+	mpint *m, *o;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	rsapk2pub(&p, f->k);
+	m = MPX(f->m);
+	release();
+	o = rsaencrypt(&p, m, nil);
+	acquire();
+	*f->ret = newIPint(o);
+}
+
+void
+Crypt_rsadecrypt(void *fp)
+{
+	F_Crypt_rsadecrypt *f;
+	RSApriv p;
+	mpint *m, *o;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	rsask2priv(&p, f->k);
+	m = MPX(f->m);
+	release();
+	o = rsadecrypt(&p, m, nil);
+	acquire();
+	*f->ret = newIPint(o);
+}
+
+/*
+ * generic key functions
+ */
+
+void
+Crypt_genSK(void *fp)
+{
+	F_Crypt_genSK *f;
+	Crypt_SK *sk;
+	char *sa;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sa = string2c(f->algname);
+	if(strcmp(sa, "rsa") == 0){
+		sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+		rsaxgen(sk, f->length, 6, 0);
+	}else if(strcmp(sa, "dsa") == 0){
+		sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+		dsaxgen(sk, nil);
+	}else if(strcmp(sa, "elgamal") == 0){
+		sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+		egxgen(sk, f->length, 0);
+	}
+	/* genSK returns nil for unknown algorithm */
+}
+
+void
+Crypt_genSKfromPK(void *fp)
+{
+	F_Crypt_genSKfromPK *f;
+	Crypt_SK *sk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->pk == H)
+		error(exNilref);
+	switch(f->pk->pick){
+	case Crypt_PK_RSA: {
+			RSApub p;
+
+			rsapk2pub(&p, f->pk);
+			sk = newSK(f->ret, TSKrsa, Crypt_SK_RSA);
+			rsaxgen(sk, mpsignif(p.n), mpsignif(p.ek), 0);
+		}
+		break;
+	case Crypt_PK_Elgamal: {
+			EGpub p;
+
+			egpk2pub(&p, f->pk);
+			sk = newSK(f->ret, TSKeg, Crypt_SK_Elgamal);
+			egxgen(sk, mpsignif(p.p), 0);
+		}
+		break;
+	case Crypt_PK_DSA: {
+			DSApub p;
+
+			dsapk2pub(&p, f->pk);
+			sk = newSK(f->ret, TSKdsa, Crypt_SK_DSA);
+			dsaxgen(sk, &p);
+		}
+		break;
+	default:
+		/* shouldn't happen */
+		error(exType);
+	}
+}
+
+void
+Crypt_sktopk(void *fp)
+{
+	F_Crypt_sktopk *f;
+	Crypt_PK *pk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+	if(f->sk == H)
+		error(exNilref);
+	switch(f->sk->pick){
+	case Crypt_PK_RSA:
+		pk = f->sk->u.RSA.pk;
+		break;
+	case Crypt_PK_Elgamal:
+		pk = f->sk->u.Elgamal.pk;
+		break;
+	case Crypt_PK_DSA:
+		pk = f->sk->u.DSA.pk;
+		break;
+	default:
+		pk = H;
+		error(exType);
+	}
+	if(pk == H)
+		return;
+	D2H(pk)->ref++;
+	*f->ret = pk;
+}
+
+void
+Crypt_sign(void *fp)
+{
+	F_Crypt_sign *f;
+	Crypt_PKsig *sig;
+	mpint *m;
+	void *v;
+	
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->m == H || f->sk == H)
+		error(exNilref);
+	m = MPX(f->m);
+	switch(f->sk->pick){
+	case Crypt_SK_RSA: {
+			RSApriv p;
+			mpint *s;
+
+			rsask2priv(&p, f->sk);
+			release();
+			s = rsadecrypt(&p, m, nil);
+			acquire();
+			sig = newPKsig(TPKsigrsa, Crypt_PKsig_RSA);
+			sig->u.RSA.n = newIPint(s);
+		}
+		break;
+	case Crypt_SK_Elgamal: {
+			EGpriv p;
+			EGsig *s;
+
+			egsk2priv(&p, f->sk);
+			release();
+			s = egsign(&p, m);
+			acquire();
+			sig = newPKsig(TPKsigeg, Crypt_PKsig_Elgamal);
+			sig->u.Elgamal.r = ipcopymp(s->r);
+			sig->u.Elgamal.s = ipcopymp(s->s);
+			egsigfree(s);
+		}
+		break;
+	case Crypt_SK_DSA: {
+			DSApriv p;
+			DSAsig *s;
+
+			dsask2priv(&p, f->sk);
+			m = MPX(f->m);
+			release();
+			s = dsasign(&p, m);
+			acquire();
+			sig = newPKsig(TPKsigdsa, Crypt_PKsig_DSA);
+			sig->u.DSA.r = ipcopymp(s->r);
+			sig->u.DSA.s = ipcopymp(s->s);
+			dsasigfree(s);
+		}
+		break;
+	default:
+		sig = H;
+		error(exType);
+	}
+	*f->ret = sig;
+}
+
+void
+Crypt_verify(void *fp)
+{
+	F_Crypt_verify *f;
+	mpint *m;
+
+	f = fp;
+	*f->ret = 0;
+	if(f->sig == H || f->pk == H)
+		error(exNilref);
+	if(f->sig->pick != f->pk->pick)
+		return;	/* key type and signature mismatch, doesn't validate */
+	m = MPX(f->m);
+	switch(f->pk->pick){
+	case Crypt_PK_RSA: {
+			RSApub p;
+			mpint *sig, *t;
+
+			rsapk2pub(&p, f->pk);
+			sig = MPX(f->sig->u.RSA.n);
+			release();
+			t = rsaencrypt(&p, sig, nil);
+			*f->ret = mpcmp(t, m) == 0;
+			mpfree(t);
+			acquire();
+		}
+		break;
+	case Crypt_PK_Elgamal: {
+			EGpub p;
+			EGsig sig;
+
+			egpk2pub(&p, f->pk);
+			sig.r = MPX(f->sig->u.Elgamal.r);
+			sig.s = MPX(f->sig->u.Elgamal.s);
+			release();
+			*f->ret = egverify(&p, &sig, m) == 0;
+			acquire();
+		}
+		break;
+	case Crypt_PK_DSA: {
+			DSApub p;
+			DSAsig sig;
+
+			dsapk2pub(&p, f->pk);
+			sig.r = MPX(f->sig->u.DSA.r);
+			sig.s = MPX(f->sig->u.DSA.s);
+			release();
+			*f->ret = dsaverify(&p, &sig, m) == 0;
+			acquire();
+		}
+		break;
+	default:
+		error(exType);
+	}
+}
--- /dev/null
+++ b/libinterp/das-386.c
@@ -1,0 +1,1630 @@
+#include <lib9.h>
+#include <kernel.h>
+
+int	i386inst(ulong, char, char*, int);
+int	i386das(ulong, char*, int);
+int	i386instlen(ulong);
+
+static uchar *dasdata;
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+	ulong d;
+
+	d = p/16;
+	if(d)
+		buf = _hexify(buf, d, zeros-1);
+	else
+		while(zeros--)
+			*buf++ = '0';
+	*buf++ = "0123456789abcdef"[p&0x0f];
+	return buf;
+}
+
+/*
+ *  an instruction
+ */
+typedef struct Instr Instr;
+struct	Instr
+{
+	uchar	mem[1+1+1+1+2+1+1+4+4];		/* raw instruction */
+	ulong	addr;		/* address of start of instruction */
+	int	n;		/* number of bytes in instruction */
+	char	*prefix;	/* instr prefix */
+	char	*segment;	/* segment override */
+	uchar	jumptype;	/* set to the operand type for jump/ret/call */
+	char	osize;		/* 'W' or 'L' */
+	char	asize;		/* address size 'W' or 'L' */
+	uchar	mod;		/* bits 6-7 of mod r/m field */
+	uchar	reg;		/* bits 3-5 of mod r/m field */
+	char	ss;		/* bits 6-7 of SIB */
+	char	index;		/* bits 3-5 of SIB */
+	char	base;		/* bits 0-2 of SIB */
+	short	seg;		/* segment of far address */
+	ulong	disp;		/* displacement */
+	ulong 	imm;		/* immediate */
+	ulong 	imm2;		/* second immediate operand */
+	char	*curr;		/* fill level in output buffer */
+	char	*end;		/* end of output buffer */
+	char	*err;		/* error message */
+};
+
+	/* 386 register (ha!) set */
+enum{
+	AX=0,
+	CX,
+	DX,
+	BX,
+	SP,
+	BP,
+	SI,
+	DI,
+};
+	/* Operand Format codes */
+/*
+%A	-	address size register modifier (!asize -> 'E')
+%C	-	Control register CR0/CR1/CR2
+%D	-	Debug register DR0/DR1/DR2/DR3/DR6/DR7
+%I	-	second immediate operand
+%O	-	Operand size register modifier (!osize -> 'E')
+%T	-	Test register TR6/TR7
+%S	-	size code ('W' or 'L')
+%X	-	Weird opcode: OSIZE == 'W' => "CBW"; else => "CWDE"
+%d	-	displacement 16-32 bits
+%e	-	effective address - Mod R/M value
+%f	-	floating point register F0-F7 - from Mod R/M register
+%g	-	segment register
+%i	-	immediate operand 8-32 bits
+%p	-	PC-relative - signed displacement in immediate field
+%r	-	Reg from Mod R/M
+%x	-	Weird opcode: OSIZE == 'W' => "CWD"; else => "CDQ"
+*/
+
+typedef struct Optable Optable;
+struct Optable
+{
+	char	operand[2];
+	void	*proto;		/* actually either (char*) or (Optable*) */
+};
+	/* Operand decoding codes */
+enum {
+	Ib = 1,			/* 8-bit immediate - (no sign extension)*/
+	Ibs,			/* 8-bit immediate (sign extended) */
+	Jbs,			/* 8-bit sign-extended immediate in jump or call */
+	Iw,			/* 16-bit immediate -> imm */
+	Iw2,			/* 16-bit immediate -> imm2 */
+	Iwd,			/* Operand-sized immediate (no sign extension)*/
+	Awd,			/* Address offset */
+	Iwds,			/* Operand-sized immediate (sign extended) */
+	RM,			/* Word or long R/M field with register (/r) */
+	RMB,			/* Byte R/M field with register (/r) */
+	RMOP,			/* Word or long R/M field with op code (/digit) */
+	RMOPB,			/* Byte R/M field with op code (/digit) */
+	RMR,			/* R/M register only (mod = 11) */
+	RMM,			/* R/M memory only (mod = 0/1/2) */
+	R0,			/* Base reg of Mod R/M is literal 0x00 */
+	R1,			/* Base reg of Mod R/M is literal 0x01 */
+	FRMOP,			/* Floating point R/M field with opcode */
+	FRMEX,			/* Extended floating point R/M field with opcode */
+	JUMP,			/* Jump or Call flag - no operand */
+	RET,			/* Return flag - no operand */
+	OA,			/* literal 0x0a byte */
+	PTR,			/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+	AUX,			/* Multi-byte op code - Auxiliary table */
+	PRE,			/* Instr Prefix */
+	SEG,			/* Segment Prefix */
+	OPOVER,			/* Operand size override */
+	ADDOVER,		/* Address size override */
+};
+	
+static Optable optab0F00[8]=
+{
+	0,0,		"MOVW	LDT,%e",
+	0,0,		"MOVW	TR,%e",
+	0,0,		"MOVW	%e,LDT",
+	0,0,		"MOVW	%e,TR",
+	0,0,		"VERR	%e",
+	0,0,		"VERW	%e",
+};
+
+static Optable optab0F01[8]=
+{
+	0,0,		"MOVL	GDTR,%e",
+	0,0,		"MOVL	IDTR,%e",
+	0,0,		"MOVL	%e,GDTR",
+	0,0,		"MOVL	%e,IDTR",
+	0,0,		"MOVW	MSW,%e",	/* word */
+	0,0,		nil,
+	0,0,		"MOVW	%e,MSW",	/* word */
+};
+
+static Optable optab0FBA[8]=
+{
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	Ib,0,		"BT%S	%i,%e",
+	Ib,0,		"BTS%S	%i,%e",
+	Ib,0,		"BTR%S	%i,%e",
+	Ib,0,		"BTC%S	%i,%e",
+};
+
+static Optable optab0F[256]=
+{
+	RMOP,0,		optab0F00,
+	RMOP,0,		optab0F01,
+	RM,0,		"LAR	%e,%r",
+	RM,0,		"LSL	%e,%r",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"CLTS",
+	0,0,		nil,
+	0,0,		"INVD",
+	0,0,		"WBINVD",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	RMR,0,		"MOVL	%C,%e",		/* [0x20] */
+	RMR,0,		"MOVL	%D,%e",
+	RMR,0,		"MOVL	%e,%C",
+	RMR,0,		"MOVL	%e,%D",
+	RMR,0,		"MOVL	%T,%e",
+	0,0,		nil,
+	RMR,0,		"MOVL	%e,%T",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		"WRMSR",		/* [0x30] */
+	0,0,		"RDTSC",
+	0,0,		"RDMSR",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+
+	Iwds,0,		"JOS	%p",	/* [0x80] */
+	Iwds,0,		"JOC	%p",
+	Iwds,0,		"JCS	%p",
+	Iwds,0,		"JCC	%p",
+	Iwds,0,		"JEQ	%p",
+	Iwds,0,		"JNE	%p",
+	Iwds,0,		"JLS	%p",
+	Iwds,0,		"JHI	%p",
+	Iwds,0,		"JMI	%p",
+	Iwds,0,		"JPL	%p",
+	Iwds,0,		"JPS	%p",
+	Iwds,0,		"JPC	%p",
+	Iwds,0,		"JLT	%p",
+	Iwds,0,		"JGE	%p",
+	Iwds,0,		"JLE	%p",
+	Iwds,0,		"JGT	%p",
+
+	RMB,0,		"SETOS	%e",	/* [0x90] */
+	RMB,0,		"SETOC	%e",
+	RMB,0,		"SETCS	%e",
+	RMB,0,		"SETCC	%e",
+	RMB,0,		"SETEQ	%e",
+	RMB,0,		"SETNE	%e",
+	RMB,0,		"SETLS	%e",
+	RMB,0,		"SETHI	%e",
+	RMB,0,		"SETMI	%e",
+	RMB,0,		"SETPL	%e",
+	RMB,0,		"SETPS	%e",
+	RMB,0,		"SETPC	%e",
+	RMB,0,		"SETLT	%e",
+	RMB,0,		"SETGE	%e",
+	RMB,0,		"SETLE	%e",
+	RMB,0,		"SETGT	%e",
+
+	0,0,		"PUSHL	FS",	/* [0xa0] */
+	0,0,		"POPL	FS",
+	0,0,		"CPUID",
+	RM,0,		"BT%S	%r,%e",
+	RM,Ib,		"SHLD%S	%r,%i,%e",
+	RM,0,		"SHLD%S	%r,CL,%e",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"PUSHL	GS",
+	0,0,		"POPL	GS",
+	0,0,		nil,
+	RM,0,		"BTS%S	%r,%e",
+	RM,Ib,		"SHRD%S	%r,%i,%e",
+	RM,0,		"SHRD%S	%r,CL,%e",
+	0,0,		nil,
+	RM,0,		"IMUL%S	%e,%r",
+
+	0,0,		nil,
+	0,0,		nil,
+	RMM,0,		"LSS	%e,%r",	/* [0xb2] */
+	RM,0,		"BTR%S	%r,%e",
+	RMM,0,		"LFS	%e,%r",
+	RMM,0,		"LGS	%e,%r",
+	RMB,0,		"MOVBZX	%e,%R",
+	RM,0,		"MOVWZX	%e,%R",
+	0,0,		nil,
+	0,0,		nil,
+	RMOP,0,		optab0FBA,
+	RM,0,		"BTC%S	%e,%r",
+	RM,0,		"BSF%S	%e,%r",
+	RM,0,		"BSR%S	%e,%r",
+	RMB,0,		"MOVBSX	%e,%R",
+	RM,0,		"MOVWSX	%e,%R",
+};
+
+static Optable optab80[8]=
+{
+	Ib,0,		"ADDB	%i,%e",
+	Ib,0,		"ORB	%i,%e",
+	Ib,0,		"ADCB	%i,%e",
+	Ib,0,		"SBBB	%i,%e",
+	Ib,0,		"ANDB	%i,%e",
+	Ib,0,		"SUBB	%i,%e",
+	Ib,0,		"XORB	%i,%e",
+	Ib,0,		"CMPB	%e,%i",
+};
+
+static Optable optab81[8]=
+{
+	Iwd,0,		"ADD%S	%i,%e",
+	Iwd,0,		"OR%S	%i,%e",
+	Iwd,0,		"ADC%S	%i,%e",
+	Iwd,0,		"SBB%S	%i,%e",
+	Iwd,0,		"AND%S	%i,%e",
+	Iwd,0,		"SUB%S	%i,%e",
+	Iwd,0,		"XOR%S	%i,%e",
+	Iwd,0,		"CMP%S	%e,%i",
+};
+
+static Optable optab83[8]=
+{
+	Ibs,0,		"ADD%S	%i,%e",
+	Ibs,0,		"OR%S	%i,%e",
+	Ibs,0,		"ADC%S	%i,%e",
+	Ibs,0,		"SBB%S	%i,%e",
+	Ibs,0,		"AND%S	%i,%e",
+	Ibs,0,		"SUB%S	%i,%e",
+	Ibs,0,		"XOR%S	%i,%e",
+	Ibs,0,		"CMP%S	%e,%i",
+};
+
+static Optable optabC0[8] =
+{
+	Ib,0,		"ROLB	%i,%e",
+	Ib,0,		"RORB	%i,%e",
+	Ib,0,		"RCLB	%i,%e",
+	Ib,0,		"RCRB	%i,%e",
+	Ib,0,		"SHLB	%i,%e",
+	Ib,0,		"SHRB	%i,%e",
+	0,0,		nil,
+	Ib,0,		"SARB	%i,%e",
+};
+
+static Optable optabC1[8] =
+{
+	Ib,0,		"ROL%S	%i,%e",
+	Ib,0,		"ROR%S	%i,%e",
+	Ib,0,		"RCL%S	%i,%e",
+	Ib,0,		"RCR%S	%i,%e",
+	Ib,0,		"SHL%S	%i,%e",
+	Ib,0,		"SHR%S	%i,%e",
+	0,0,		nil,
+	Ib,0,		"SAR%S	%i,%e",
+};
+
+static Optable optabD0[8] =
+{
+	0,0,		"ROLB	%e",
+	0,0,		"RORB	%e",
+	0,0,		"RCLB	%e",
+	0,0,		"RCRB	%e",
+	0,0,		"SHLB	%e",
+	0,0,		"SHRB	%e",
+	0,0,		nil,
+	0,0,		"SARB	%e",
+};
+
+static Optable optabD1[8] =
+{
+	0,0,		"ROL%S	%e",
+	0,0,		"ROR%S	%e",
+	0,0,		"RCL%S	%e",
+	0,0,		"RCR%S	%e",
+	0,0,		"SHL%S	%e",
+	0,0,		"SHR%S	%e",
+	0,0,		nil,
+	0,0,		"SAR%S	%e",
+};
+
+static Optable optabD2[8] =
+{
+	0,0,		"ROLB	CL,%e",
+	0,0,		"RORB	CL,%e",
+	0,0,		"RCLB	CL,%e",
+	0,0,		"RCRB	CL,%e",
+	0,0,		"SHLB	CL,%e",
+	0,0,		"SHRB	CL,%e",
+	0,0,		nil,
+	0,0,		"SARB	CL,%e",
+};
+
+static Optable optabD3[8] =
+{
+	0,0,		"ROL%S	CL,%e",
+	0,0,		"ROR%S	CL,%e",
+	0,0,		"RCL%S	CL,%e",
+	0,0,		"RCR%S	CL,%e",
+	0,0,		"SHL%S	CL,%e",
+	0,0,		"SHR%S	CL,%e",
+	0,0,		nil,
+	0,0,		"SAR%S	CL,%e",
+};
+
+static Optable optabD8[8+8] =
+{
+	0,0,		"FADDF	%e,F0",
+	0,0,		"FMULF	%e,F0",
+	0,0,		"FCOMF	%e,F0",
+	0,0,		"FCOMFP	%e,F0",
+	0,0,		"FSUBF	%e,F0",
+	0,0,		"FSUBRF	%e,F0",
+	0,0,		"FDIVF	%e,F0",
+	0,0,		"FDIVRF	%e,F0",
+	0,0,		"FADDD	%f,F0",
+	0,0,		"FMULD	%f,F0",
+	0,0,		"FCOMD	%f,F0",
+	0,0,		"FCOMPD	%f,F0",
+	0,0,		"FSUBD	%f,F0",
+	0,0,		"FSUBRD	%f,F0",
+	0,0,		"FDIVD	%f,F0",
+	0,0,		"FDIVRD	%f,F0",
+};
+/*
+ *	optabD9 and optabDB use the following encoding: 
+ *	if (0 <= modrm <= 2) instruction = optabDx[modrm&0x07];
+ *	else instruction = optabDx[(modrm&0x3f)+8];
+ *
+ *	the instructions for MOD == 3, follow the 8 instructions
+ *	for the other MOD values stored at the front of the table.
+ */
+static Optable optabD9[64+8] =
+{
+	0,0,		"FMOVF	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVF	F0,%e",
+	0,0,		"FMOVFP	F0,%e",
+	0,0,		"FLDENV%S %e",
+	0,0,		"FLDCW	%e",
+	0,0,		"FSTENV%S %e",
+	0,0,		"FSTCW	%e",
+	0,0,		"FMOVD	F0,F0",		/* Mod R/M = 11xx xxxx*/
+	0,0,		"FMOVD	F1,F0",
+	0,0,		"FMOVD	F2,F0",
+	0,0,		"FMOVD	F3,F0",
+	0,0,		"FMOVD	F4,F0",
+	0,0,		"FMOVD	F5,F0",
+	0,0,		"FMOVD	F6,F0",
+	0,0,		"FMOVD	F7,F0",
+	0,0,		"FXCHD	F0,F0",
+	0,0,		"FXCHD	F1,F0",
+	0,0,		"FXCHD	F2,F0",
+	0,0,		"FXCHD	F3,F0",
+	0,0,		"FXCHD	F4,F0",
+	0,0,		"FXCHD	F5,F0",
+	0,0,		"FXCHD	F6,F0",
+	0,0,		"FXCHD	F7,F0",
+	0,0,		"FNOP",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FCHS",		/* [0x28] */
+	0,0,		"FABS",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FTST",
+	0,0,		"FXAM",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FLD1",
+	0,0,		"FLDL2T",
+	0,0,		"FLDL2E",
+	0,0,		"FLDPI",
+	0,0,		"FLDLG2",
+	0,0,		"FLDLN2",
+	0,0,		"FLDZ",
+	0,0,		nil,
+	0,0,		"F2XM1",
+	0,0,		"FYL2X",
+	0,0,		"FPTAN",
+	0,0,		"FPATAN",
+	0,0,		"FXTRACT",
+	0,0,		"FPREM1",
+	0,0,		"FDECSTP",
+	0,0,		"FNCSTP",
+	0,0,		"FPREM",
+	0,0,		"FYL2XP1",
+	0,0,		"FSQRT",
+	0,0,		"FSINCOS",
+	0,0,		"FRNDINT",
+	0,0,		"FSCALE",
+	0,0,		"FSIN",
+	0,0,		"FCOS",
+};
+
+static Optable optabDA[8+8] =
+{
+	0,0,		"FADDL	%e,F0",
+	0,0,		"FMULL	%e,F0",
+	0,0,		"FCOML	%e,F0",
+	0,0,		"FCOMLP	%e,F0",
+	0,0,		"FSUBL	%e,F0",
+	0,0,		"FSUBRL	%e,F0",
+	0,0,		"FDIVL	%e,F0",
+	0,0,		"FDIVRL	%e,F0",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	R1,0,		"FUCOMPP",	/* [0x0d] */
+};
+
+static Optable optabDB[8+64] =
+{
+	0,0,		"FMOVL	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVL	F0,%e",
+	0,0,		"FMOVLP	F0,%e",
+	0,0,		nil,
+	0,0,		"FMOVX	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVXP	F0,%e",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FCLEX",	/* [0x2a] */
+	0,0,		"FINIT",
+};
+
+static Optable optabDC[8+8] =
+{
+	0,0,		"FADDD	%e,F0",
+	0,0,		"FMULD	%e,F0",
+	0,0,		"FCOMD	%e,F0",
+	0,0,		"FCOMDP	%e,F0",
+	0,0,		"FSUBD	%e,F0",
+	0,0,		"FSUBRD	%e,F0",
+	0,0,		"FDIVD	%e,F0",
+	0,0,		"FDIVRD	%e,F0",
+	0,0,		"FADDD	F0,%f",
+	0,0,		"FMULD	F0,%f",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		"FSUBRD	F0,%f",
+	0,0,		"FSUBD	F0,%f",
+	0,0,		"FDIVRD	F0,%f",
+	0,0,		"FDIVD	F0,%f",
+};
+
+static Optable optabDD[8+8] =
+{
+	0,0,		"FMOVD	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVD	F0,%e",
+	0,0,		"FMOVDP	F0,%e",
+	0,0,		"FRSTOR%S %e",
+	0,0,		nil,
+	0,0,		"FSAVE%S %e",
+	0,0,		"FSTSW	%e",
+	0,0,		"FFREED	%f",
+	0,0,		nil,
+	0,0,		"FMOVD	%f,F0",
+	0,0,		"FMOVDP	%f,F0",
+	0,0,		"FUCOMD	%f,F0",
+	0,0,		"FUCOMDP %f,F0",
+};
+
+static Optable optabDE[8+8] =
+{
+	0,0,		"FADDW	%e,F0",
+	0,0,		"FMULW	%e,F0",
+	0,0,		"FCOMW	%e,F0",
+	0,0,		"FCOMWP	%e,F0",
+	0,0,		"FSUBW	%e,F0",
+	0,0,		"FSUBRW	%e,F0",
+	0,0,		"FDIVW	%e,F0",
+	0,0,		"FDIVRW	%e,F0",
+	0,0,		"FADDDP	F0,%f",
+	0,0,		"FMULDP	F0,%f",
+	0,0,		nil,
+	R1,0,		"FCOMPDP",
+	0,0,		"FSUBRDP F0,%f",
+	0,0,		"FSUBDP	F0,%f",
+	0,0,		"FDIVRDP F0,%f",
+	0,0,		"FDIVDP	F0,%f",
+};
+
+static Optable optabDF[8+8] =
+{
+	0,0,		"FMOVW	%e,F0",
+	0,0,		nil,
+	0,0,		"FMOVW	F0,%e",
+	0,0,		"FMOVWP	F0,%e",
+	0,0,		"FBLD	%e",
+	0,0,		"FMOVL	%e,F0",
+	0,0,		"FBSTP	%e",
+	0,0,		"FMOVLP	F0,%e",
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	0,0,		nil,
+	R0,0,		"FSTSW	%OAX",
+};
+
+static Optable optabF6[8] =
+{
+	Ib,0,		"TESTB	%i,%e",
+	0,0,		nil,
+	0,0,		"NOTB	%e",
+	0,0,		"NEGB	%e",
+	0,0,		"MULB	AL,%e",
+	0,0,		"IMULB	AL,%e",
+	0,0,		"DIVB	AL,%e",
+	0,0,		"IDIVB	AL,%e",
+};
+
+static Optable optabF7[8] =
+{
+	Iwd,0,		"TEST%S	%i,%e",
+	0,0,		nil,
+	0,0,		"NOT%S	%e",
+	0,0,		"NEG%S	%e",
+	0,0,		"MUL%S	%OAX,%e",
+	0,0,		"IMUL%S	%OAX,%e",
+	0,0,		"DIV%S	%OAX,%e",
+	0,0,		"IDIV%S	%OAX,%e",
+};
+
+static Optable optabFE[8] =
+{
+	0,0,		"INCB	%e",
+	0,0,		"DECB	%e",
+};
+
+static Optable optabFF[8] =
+{
+	0,0,		"INC%S	%e",
+	0,0,		"DEC%S	%e",
+	JUMP,0,		"CALL*%S %e",
+	JUMP,0,		"CALLF*%S %e",
+	JUMP,0,		"JMP*%S	%e",
+	JUMP,0,		"JMPF*%S %e",
+	0,0,		"PUSHL	%e",
+};
+
+static Optable optable[256] =
+{
+	RMB,0,		"ADDB	%r,%e",
+	RM,0,		"ADD%S	%r,%e",
+	RMB,0,		"ADDB	%e,%r",
+	RM,0,		"ADD%S	%e,%r",
+	Ib,0,		"ADDB	%i,AL",
+	Iwd,0,		"ADD%S	%i,%OAX",
+	0,0,		"PUSHL	ES",
+	0,0,		"POPL	ES",
+	RMB,0,		"ORB	%r,%e",
+	RM,0,		"OR%S	%r,%e",
+	RMB,0,		"ORB	%e,%r",
+	RM,0,		"OR%S	%e,%r",
+	Ib,0,		"ORB	%i,AL",
+	Iwd,0,		"OR%S	%i,%OAX",
+	0,0,		"PUSHL	CS",
+	AUX,0,		optab0F,
+	RMB,0,		"ADCB	%r,%e",
+	RM,0,		"ADC%S	%r,%e",
+	RMB,0,		"ADCB	%e,%r",
+	RM,0,		"ADC%S	%e,%r",
+	Ib,0,		"ADCB	%i,AL",
+	Iwd,0,		"ADC%S	%i,%OAX",
+	0,0,		"PUSHL	SS",
+	0,0,		"POPL	SS",
+	RMB,0,		"SBBB	%r,%e",
+	RM,0,		"SBB%S	%r,%e",
+	RMB,0,		"SBBB	%e,%r",
+	RM,0,		"SBB%S	%e,%r",
+	Ib,0,		"SBBB	%i,AL",
+	Iwd,0,		"SBB%S	%i,%OAX",
+	0,0,		"PUSHL	DS",
+	0,0,		"POPL	DS",
+	RMB,0,		"ANDB	%r,%e",
+	RM,0,		"AND%S	%r,%e",
+	RMB,0,		"ANDB	%e,%r",
+	RM,0,		"AND%S	%e,%r",
+	Ib,0,		"ANDB	%i,AL",
+	Iwd,0,		"AND%S	%i,%OAX",
+	SEG,0,		"ES:",
+	0,0,		"DAA",
+	RMB,0,		"SUBB	%r,%e",
+	RM,0,		"SUB%S	%r,%e",
+	RMB,0,		"SUBB	%e,%r",
+	RM,0,		"SUB%S	%e,%r",
+	Ib,0,		"SUBB	%i,AL",
+	Iwd,0,		"SUB%S	%i,%OAX",
+	SEG,0,		"CS:",
+	0,0,		"DAS",
+	RMB,0,		"XORB	%r,%e",
+	RM,0,		"XOR%S	%r,%e",
+	RMB,0,		"XORB	%e,%r",
+	RM,0,		"XOR%S	%e,%r",
+	Ib,0,		"XORB	%i,AL",
+	Iwd,0,		"XOR%S	%i,%OAX",
+	SEG,0,		"SS:",
+	0,0,		"AAA",
+	RMB,0,		"CMPB	%r,%e",
+	RM,0,		"CMP%S	%r,%e",
+	RMB,0,		"CMPB	%e,%r",
+	RM,0,		"CMP%S	%e,%r",
+	Ib,0,		"CMPB	%i,AL",
+	Iwd,0,		"CMP%S	%i,%OAX",
+	SEG,0,		"DS:",
+	0,0,		"AAS",
+	0,0,		"INC%S	%OAX",
+	0,0,		"INC%S	%OCX",
+	0,0,		"INC%S	%ODX",
+	0,0,		"INC%S	%OBX",
+	0,0,		"INC%S	%OSP",
+	0,0,		"INC%S	%OBP",
+	0,0,		"INC%S	%OSI",
+	0,0,		"INC%S	%ODI",
+	0,0,		"DEC%S	%OAX",
+	0,0,		"DEC%S	%OCX",
+	0,0,		"DEC%S	%ODX",
+	0,0,		"DEC%S	%OBX",
+	0,0,		"DEC%S	%OSP",
+	0,0,		"DEC%S	%OBP",
+	0,0,		"DEC%S	%OSI",
+	0,0,		"DEC%S	%ODI",
+	0,0,		"PUSH%S	%OAX",
+	0,0,		"PUSH%S	%OCX",
+	0,0,		"PUSH%S	%ODX",
+	0,0,		"PUSH%S	%OBX",
+	0,0,		"PUSH%S	%OSP",
+	0,0,		"PUSH%S	%OBP",
+	0,0,		"PUSH%S	%OSI",
+	0,0,		"PUSH%S	%ODI",
+	0,0,		"POP%S	%OAX",
+	0,0,		"POP%S	%OCX",
+	0,0,		"POP%S	%ODX",
+	0,0,		"POP%S	%OBX",
+	0,0,		"POP%S	%OSP",
+	0,0,		"POP%S	%OBP",
+	0,0,		"POP%S	%OSI",
+	0,0,		"POP%S	%ODI",
+	0,0,		"PUSHA%S",
+	0,0,		"POPA%S",
+	RMM,0,		"BOUND	%e,%r",
+	RM,0,		"ARPL	%r,%e",
+	SEG,0,		"FS:",
+	SEG,0,		"GS:",
+	OPOVER,0,	"",
+	ADDOVER,0,	"",
+	Iwd,0,		"PUSH%S	%i",
+	RM,Iwd,		"IMUL%S	%e,%i,%r",
+	Ib,0,		"PUSH%S	%i",
+	RM,Ibs,		"IMUL%S	%e,%i,%r",
+	0,0,		"INSB	DX,(%ODI)",
+	0,0,		"INS%S	DX,(%ODI)",
+	0,0,		"OUTSB	(%ASI),DX",
+	0,0,		"OUTS%S	(%ASI),DX",
+	Jbs,0,		"JOS	%p",
+	Jbs,0,		"JOC	%p",
+	Jbs,0,		"JCS	%p",
+	Jbs,0,		"JCC	%p",
+	Jbs,0,		"JEQ	%p",
+	Jbs,0,		"JNE	%p",
+	Jbs,0,		"JLS	%p",
+	Jbs,0,		"JHI	%p",
+	Jbs,0,		"JMI	%p",
+	Jbs,0,		"JPL	%p",
+	Jbs,0,		"JPS	%p",
+	Jbs,0,		"JPC	%p",
+	Jbs,0,		"JLT	%p",
+	Jbs,0,		"JGE	%p",
+	Jbs,0,		"JLE	%p",
+	Jbs,0,		"JGT	%p",
+	RMOPB,0,	optab80,
+	RMOP,0,		optab81,
+	0,0,		nil,
+	RMOP,0,		optab83,
+	RMB,0,		"TESTB	%r,%e",
+	RM,0,		"TEST%S	%r,%e",
+	RMB,0,		"XCHGB	%r,%e",
+	RM,0,		"XCHG%S	%r,%e",
+	RMB,0,		"MOVB	%r,%e",
+	RM,0,		"MOV%S	%r,%e",
+	RMB,0,		"MOVB	%e,%r",
+	RM,0,		"MOV%S	%e,%r",
+	RM,0,		"MOVW	%g,%e",
+	RM,0,		"LEA	%e,%r",
+	RM,0,		"MOVW	%e,%g",
+	RM,0,		"POP%S	%e",
+	0,0,		"NOP",
+	0,0,		"XCHG	%OCX,%OAX",
+	0,0,		"XCHG	%ODX,%OAX",
+	0,0,		"XCHG	%OBX,%OAX",
+	0,0,		"XCHG	%OSP,%OAX",
+	0,0,		"XCHG	%OBP,%OAX",
+	0,0,		"XCHG	%OSI,%OAX",
+	0,0,		"XCHG	%ODI,%OAX",
+	0,0,		"%X",			/* miserable CBW or CWDE */
+	0,0,		"%x",			/* idiotic CWD or CDQ */
+	PTR,0,		"CALL%S	%d",
+	0,0,		"WAIT",
+	0,0,		"PUSH	FLAGS",
+	0,0,		"POP	FLAGS",
+	0,0,		"SAHF",
+	0,0,		"LAHF",
+	Awd,0,		"MOVB	%i,AL",
+	Awd,0,		"MOV%S	%i,%OAX",
+	Awd,0,		"MOVB	AL,%i",
+	Awd,0,		"MOV%S	%OAX,%i",
+	0,0,		"MOVSB	(%ASI),(%ADI)",
+	0,0,		"MOVS%S	(%ASI),(%ADI)",
+	0,0,		"CMPSB	(%ASI),(%ADI)",
+	0,0,		"CMPS%S	(%ASI),(%ADI)",
+	Ib,0,		"TESTB	%i,AL",
+	Iwd,0,		"TEST%S	%i,%OAX",
+	0,0,		"STOSB	AL,(%ADI)",
+	0,0,		"STOS%S	%OAX,(%ADI)",
+	0,0,		"LODSB	(%ASI),AL",
+	0,0,		"LODS%S	(%ASI),%OAX",
+	0,0,		"SCASB	(%ADI),AL",
+	0,0,		"SCAS%S	(%ADI),%OAX",
+	Ib,0,		"MOVB	%i,AL",
+	Ib,0,		"MOVB	%i,CL",
+	Ib,0,		"MOVB	%i,DL",
+	Ib,0,		"MOVB	%i,BL",
+	Ib,0,		"MOVB	%i,AH",
+	Ib,0,		"MOVB	%i,CH",
+	Ib,0,		"MOVB	%i,DH",
+	Ib,0,		"MOVB	%i,BH",
+	Iwd,0,		"MOV%S	%i,%OAX",
+	Iwd,0,		"MOV%S	%i,%OCX",
+	Iwd,0,		"MOV%S	%i,%ODX",
+	Iwd,0,		"MOV%S	%i,%OBX",
+	Iwd,0,		"MOV%S	%i,%OSP",
+	Iwd,0,		"MOV%S	%i,%OBP",
+	Iwd,0,		"MOV%S	%i,%OSI",
+	Iwd,0,		"MOV%S	%i,%ODI",
+	RMOPB,0,	optabC0,
+	RMOP,0,		optabC1,
+	Iw,0,		"RET	%i",
+	RET,0,		"RET",
+	RM,0,		"LES	%e,%r",
+	RM,0,		"LDS	%e,%r",
+	RMB,Ib,		"MOVB	%i,%e",
+	RM,Iwd,		"MOV%S	%i,%e",
+	Iw2,Ib,		"ENTER	%i,%I",		/* loony ENTER */
+	RET,0,		"LEAVE",		/* bizarre LEAVE */
+	Iw,0,		"RETF	%i",
+	RET,0,		"RETF",
+	0,0,		"INT	3",
+	Ib,0,		"INTB	%i",
+	0,0,		"INTO",
+	0,0,		"IRET",
+	RMOPB,0,	optabD0,
+	RMOP,0,		optabD1,
+	RMOPB,0,	optabD2,
+	RMOP,0,		optabD3,
+	OA,0,		"AAM",
+	OA,0,		"AAD",
+	0,0,		nil,
+	0,0,		"XLAT",
+	FRMOP,0,	optabD8,
+	FRMEX,0,	optabD9,
+	FRMOP,0,	optabDA,
+	FRMEX,0,	optabDB,
+	FRMOP,0,	optabDC,
+	FRMOP,0,	optabDD,
+	FRMOP,0,	optabDE,
+	FRMOP,0,	optabDF,
+	Jbs,0,		"LOOPNE	%p",
+	Jbs,0,		"LOOPE	%p",
+	Jbs,0,		"LOOP	%p",
+	Jbs,0,		"JCXZ	%p",
+	Ib,0,		"INB	%i,AL",
+	Ib,0,		"IN%S	%i,%OAX",
+	Ib,0,		"OUTB	AL,%i",
+	Ib,0,		"OUT%S	%OAX,%i",
+	Iwds,0,		"CALL	%p",
+	Iwds,0,		"JMP	%p",
+	PTR,0,		"JMP	%d",
+	Jbs,0,		"JMP	%p",
+	0,0,		"INB	DX,AL",
+	0,0,		"IN%S	DX,%OAX",
+	0,0,		"OUTB	AL,DX",
+	0,0,		"OUT%S	%OAX,DX",
+	PRE,0,		"LOCK",
+	0,0,		nil,
+	PRE,0,		"REPNE",
+	PRE,0,		"REP",
+	0,0,		"HALT",
+	0,0,		"CMC",
+	RMOPB,0,	optabF6,
+	RMOP,0,		optabF7,
+	0,0,		"CLC",
+	0,0,		"STC",
+	0,0,		"CLI",
+	0,0,		"STI",
+	0,0,		"CLD",
+	0,0,		"STD",
+	RMOPB,0,	optabFE,
+	RMOP,0,		optabFF,
+};
+
+/*
+ *  get a byte of the instruction
+ */
+static int
+igetc(Instr *ip, uchar *c)
+{
+	if(ip->n+1 > sizeof(ip->mem)){
+		kwerrstr("instruction too long");
+		return -1;
+	}
+	*c = dasdata[ip->addr+ip->n];
+	ip->mem[ip->n++] = *c;
+	return 1;
+}
+
+/*
+ *  get two bytes of the instruction
+ */
+static int
+igets(Instr *ip, ushort *sp)
+{
+	uchar	c;
+	ushort s;
+
+	if (igetc(ip, &c) < 0)
+		return -1;
+	s = c;
+	if (igetc(ip, &c) < 0)
+		return -1;
+	s |= (c<<8);
+	*sp = s;
+	return 1;
+}
+
+/*
+ *  get 4 bytes of the instruction
+ */
+static int
+igetl(Instr *ip, ulong *lp)
+{
+	ushort s;
+	long	l;
+
+	if (igets(ip, &s) < 0)
+		return -1;
+	l = s;
+	if (igets(ip, &s) < 0)
+		return -1;
+	l |= (s<<16);
+	*lp = l;
+	return 1;
+}
+
+static int
+getdisp(Instr *ip, int mod, int rm, int code)
+{
+	uchar c;
+	ushort s;
+
+	if (mod > 2)
+		return 1;
+	if (mod == 1) {
+		if (igetc(ip, &c) < 0)
+			return -1;
+		if (c&0x80)
+			ip->disp = c|0xffffff00;
+		else
+			ip->disp = c&0xff;
+	} else if (mod == 2 || rm == code) {
+		if (ip->asize == 'E') {
+			if (igetl(ip, &ip->disp) < 0)
+				return -1;
+		} else {
+			if (igets(ip, &s) < 0)
+				return -1;
+			if (s&0x8000)
+				ip->disp = s|0xffff0000;
+			else
+				ip->disp = s;
+		}
+		if (mod == 0)
+			ip->base = -1;
+	}
+	return 1;
+}
+
+static int
+modrm(Instr *ip, uchar c)
+{
+	uchar rm, mod;
+
+	mod = (c>>6)&3;
+	rm = c&7;
+	ip->mod = mod;
+	ip->base = rm;
+	ip->reg = (c>>3)&7;
+	if (mod == 3)			/* register */
+		return 1;
+	if (ip->asize == 0) {		/* 16-bit mode */
+		switch(rm)
+		{
+		case 0:
+			ip->base = BX; ip->index = SI;
+			break;
+		case 1:
+			ip->base = BX; ip->index = DI;
+			break;
+		case 2:
+			ip->base = BP; ip->index = SI;
+			break;
+		case 3:
+			ip->base = BP; ip->index = DI;
+			break;
+		case 4:
+			ip->base = SI;
+			break;
+		case 5:
+			ip->base = DI;
+			break;
+		case 6:
+			ip->base = BP;
+			break;
+		case 7:
+			ip->base = BX;
+			break;
+		default:
+			break;
+		}
+		return getdisp(ip, mod, rm, 6);
+	}
+	if (rm == 4) {	/* scummy sib byte */
+		if (igetc(ip, &c) < 0)
+			return -1;
+		ip->ss = (c>>6)&0x03;
+		ip->index = (c>>3)&0x07;
+		if (ip->index == 4)
+			ip->index = -1;
+		ip->base = c&0x07;
+		return getdisp(ip, mod, ip->base, 5);
+	}
+	return getdisp(ip, mod, rm, 5);
+}
+
+static Optable *
+mkinstr(Instr *ip, ulong pc)
+{
+	int i, n;
+	uchar c;
+	ushort s;
+	Optable *op, *obase;
+	char buf[128];
+
+	memset(ip, 0, sizeof(*ip));
+	ip->base = -1;
+	ip->index = -1;
+	ip->osize = 'L';
+	ip->asize = 'E';
+	ip->addr = pc;
+	if (igetc(ip, &c) < 0)
+		return 0;
+	obase = optable;
+newop:
+	op = &obase[c];
+	if (op->proto == 0) {
+badop:
+		n = snprint(buf, sizeof(buf), "opcode: ??");
+		for (i = 0; i < ip->n && n < sizeof(buf)-3; i++, n+=2)
+			_hexify(buf+n, ip->mem[i], 1);
+		strcpy(buf+n, "??");
+		kwerrstr(buf);
+		return 0;
+	}
+	for(i = 0; i < 2 && op->operand[i]; i++) {
+		switch(op->operand[i])
+		{
+		case Ib:	/* 8-bit immediate - (no sign extension)*/
+			if (igetc(ip, &c) < 0)
+				return 0;
+			ip->imm = c&0xff;
+			break;
+		case Jbs:	/* 8-bit jump immediate (sign extended) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (c&0x80)
+				ip->imm = c|0xffffff00;
+			else
+				ip->imm = c&0xff;
+			ip->jumptype = Jbs;
+			break;
+		case Ibs:	/* 8-bit immediate (sign extended) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (c&0x80)
+				if (ip->osize == 'L')
+					ip->imm = c|0xffffff00;
+				else
+					ip->imm = c|0xff00;
+			else
+				ip->imm = c&0xff;
+			break;
+		case Iw:	/* 16-bit immediate -> imm */
+			if (igets(ip, &s) < 0)
+				return 0;
+			ip->imm = s&0xffff;
+			ip->jumptype = Iw;
+			break;
+		case Iw2:	/* 16-bit immediate -> in imm2*/
+			if (igets(ip, &s) < 0)
+				return 0;
+			ip->imm2 = s&0xffff;
+			break;
+		case Iwd:	/* Operand-sized immediate (no sign extension)*/
+			if (ip->osize == 'L') {
+				if (igetl(ip, &ip->imm) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				ip->imm = s&0xffff;
+			}
+			break;
+		case Awd:	/* Address-sized immediate (no sign extension)*/
+			if (ip->asize == 'E') {
+				if (igetl(ip, &ip->imm) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				ip->imm = s&0xffff;
+			}
+			break;
+		case Iwds:	/* Operand-sized immediate (sign extended) */
+			if (ip->osize == 'L') {
+				if (igetl(ip, &ip->imm) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				if (s&0x8000)
+					ip->imm = s|0xffff0000;
+				else
+					ip->imm = s&0xffff;
+			}
+			ip->jumptype = Iwds;
+			break;
+		case OA:	/* literal 0x0a byte */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (c != 0x0a)
+				goto badop;
+			break;
+		case R0:	/* base register must be R0 */
+			if (ip->base != 0)
+				goto badop;
+			break;
+		case R1:	/* base register must be R1 */
+			if (ip->base != 1)
+				goto badop;
+			break;
+		case RMB:	/* R/M field with byte register (/r)*/
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			ip->osize = 'B';
+			break;
+		case RM:	/* R/M field with register (/r) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			break;
+		case RMOPB:	/* R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			c = ip->reg;		/* secondary op code */
+			obase = (Optable*)op->proto;
+			ip->osize = 'B';
+			goto newop;
+		case RMOP:	/* R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			c = ip->reg;
+			obase = (Optable*)op->proto;
+			goto newop;
+		case FRMOP:	/* FP R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			if ((c&0xc0) == 0xc0)
+				c = ip->reg+8;		/* 16 entry table */
+			else
+				c = ip->reg;
+			obase = (Optable*)op->proto;
+			goto newop;
+		case FRMEX:	/* Extended FP R/M field with op code (/digit) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if (modrm(ip, c) < 0)
+				return 0;
+			if ((c&0xc0) == 0xc0)
+				c = (c&0x3f)+8;		/* 64-entry table */
+			else
+				c = ip->reg;
+			obase = (Optable*)op->proto;
+			goto newop;
+		case RMR:	/* R/M register only (mod = 11) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if ((c&0xc0) != 0xc0) {
+				kwerrstr("invalid R/M register: %x", c);
+				return 0;
+			}
+			if (modrm(ip, c) < 0)
+				return 0;
+			break;
+		case RMM:	/* R/M register only (mod = 11) */
+			if (igetc(ip, &c) < 0)
+				return 0;
+			if ((c&0xc0) == 0xc0) {
+				kwerrstr("invalid R/M memory mode: %x", c);
+				return 0;
+			}
+			if (modrm(ip, c) < 0)
+				return 0;
+			break;
+		case PTR:	/* Seg:Displacement addr (ptr16:16 or ptr16:32) */
+			if (ip->osize == 'L') {
+				if (igetl(ip, &ip->disp) < 0)
+					return 0;
+			} else {
+				if (igets(ip, &s)< 0)
+					return 0;
+				ip->disp = s&0xffff;
+			}
+			if (igets(ip, (ushort*)&ip->seg) < 0)
+				return 0;
+			ip->jumptype = PTR;
+			break;
+		case AUX:	/* Multi-byte op code - Auxiliary table */
+			obase = (Optable*)op->proto;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case PRE:	/* Instr Prefix */
+			ip->prefix = (char*)op->proto;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case SEG:	/* Segment Prefix */
+			ip->segment = (char*)op->proto;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case OPOVER:	/* Operand size override */
+			ip->osize = 'W';
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case ADDOVER:	/* Address size override */
+			ip->asize = 0;
+			if (igetc(ip, &c) < 0)
+				return 0;
+			goto newop;
+		case JUMP:	/* mark instruction as JUMP or RET */
+		case RET:
+			ip->jumptype = op->operand[i];
+			break;
+		default:
+			kwerrstr("bad operand type %d", op->operand[i]);
+			return 0;
+		}
+	}
+	return op;
+}
+
+static void
+bprint(Instr *ip, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	ip->curr = vseprint(ip->curr, ip->end, fmt, arg);
+	va_end(arg);
+}
+
+/*
+ *  if we want to call 16 bit regs AX,BX,CX,...
+ *  and 32 bit regs EAX,EBX,ECX,... then
+ *  change the defs of ANAME and ONAME to:
+ *  #define	ANAME(ip)	((ip->asize == 'E' ? "E" : "")
+ *  #define	ONAME(ip)	((ip)->osize == 'L' ? "E" : "")
+ */
+#define	ANAME(ip)	""
+#define	ONAME(ip)	""
+
+static char *reg[] =  {
+	"AX",
+	"CX",
+	"DX",
+	"BX",
+	"SP",
+	"BP",
+	"SI",
+	"DI",
+};
+
+static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
+static char *sreg[] = { "ES", "CS", "SS", "DS", "FS", "GS" };
+
+static void
+plocal(Instr *ip)
+{
+	int offset;
+
+	offset = ip->disp;
+
+	bprint(ip, "%lux(SP)", offset);
+}
+
+static void
+pea(Instr *ip)
+{
+	if (ip->mod == 3) {
+		if (ip->osize == 'B')
+			bprint(ip, breg[ip->base]);
+		else
+			bprint(ip, "%s%s", ANAME(ip), reg[ip->base]);
+		return;
+	}
+	if (ip->segment)
+		bprint(ip, ip->segment);
+	if (ip->asize == 'E' && ip->base == SP)
+		plocal(ip);
+	else {
+		bprint(ip,"%lux", ip->disp);
+		if (ip->base >= 0)
+			bprint(ip,"(%s%s)", ANAME(ip), reg[ip->base]);
+	}
+	if (ip->index >= 0)
+		bprint(ip,"(%s%s*%d)", ANAME(ip), reg[ip->index], 1<<ip->ss);
+}
+
+static void
+immediate(Instr *ip, long val)
+{
+	bprint(ip, "%lux", val);
+}
+
+static void
+prinstr(Instr *ip, char *fmt)
+{
+	if (ip->prefix)
+		bprint(ip, "%s ", ip->prefix);
+	for (; *fmt && ip->curr < ip->end; fmt++) {
+		if (*fmt != '%')
+			*ip->curr++ = *fmt;
+		else switch(*++fmt)
+		{
+		case '%':
+			*ip->curr++ = '%';
+			break;
+		case 'A':
+			bprint(ip, "%s", ANAME(ip));
+			break;
+		case 'C':
+			bprint(ip, "CR%d", ip->reg);
+			break;
+		case 'D':
+			if (ip->reg < 4 || ip->reg == 6 || ip->reg == 7)
+				bprint(ip, "DR%d",ip->reg);
+			else
+				bprint(ip, "???");
+			break;
+		case 'I':
+			bprint(ip, "$");
+			immediate(ip, ip->imm2);
+			break;
+		case 'O':
+			bprint(ip,"%s", ONAME(ip));
+			break;
+		case 'i':
+			bprint(ip, "$");
+			immediate(ip,ip->imm);
+			break;
+		case 'R':
+			bprint(ip, "%s%s", ONAME(ip), reg[ip->reg]);
+			break;
+		case 'S':
+			bprint(ip, "%c", ip->osize);
+			break;
+		case 'T':
+			if (ip->reg == 6 || ip->reg == 7)
+				bprint(ip, "TR%d",ip->reg);
+			else
+				bprint(ip, "???");
+			break;
+		case 'X':
+			if (ip->osize == 'L')
+				bprint(ip,"CWDE");
+			else
+				bprint(ip, "CBW");
+			break;
+		case 'd':
+			bprint(ip,"%lux:%lux",ip->seg,ip->disp);
+			break;
+		case 'e':
+			pea(ip);
+			break;
+		case 'f':
+			bprint(ip, "F%d", ip->base);
+			break;
+		case 'g':
+			if (ip->reg < 6)
+				bprint(ip,"%s",sreg[ip->reg]);
+			else
+				bprint(ip,"???");
+			break;
+		case 'p':
+			immediate(ip, ip->imm+ip->addr+ip->n);
+			break;
+		case 'r':
+			if (ip->osize == 'B')
+				bprint(ip,"%s",breg[ip->reg]);
+			else
+				bprint(ip, reg[ip->reg]);
+			break;
+		case 'x':
+			if (ip->osize == 'L')
+				bprint(ip,"CDQ");
+			else
+				bprint(ip, "CWD");
+			break;
+		default:
+			bprint(ip, "%%%c", *fmt);
+			break;
+		}
+	}
+	*ip->curr = 0;		/* there's always room for 1 byte */
+}
+
+int
+i386inst(ulong pc, char modifier, char *buf, int n)
+{
+	Instr	instr;
+	Optable *op;
+
+	USED(modifier);
+	op = mkinstr(&instr, pc);
+	if (op == 0) {
+		kgerrstr(buf, n);
+		return -1;
+	}
+	instr.curr = buf;
+	instr.end = buf+n-1;
+	prinstr(&instr, op->proto);
+	return instr.n;
+}
+
+int
+i386das(ulong pc, char *buf, int n)
+{
+	Instr	instr;
+	int i;
+
+	if (mkinstr(&instr, pc) == 0) {
+		kgerrstr(buf, n);
+		return -1;
+	}
+	for(i = 0; i < instr.n && n > 2; i++) {
+		_hexify(buf, instr.mem[i], 1);
+		buf += 2;
+		n -= 2;
+	}
+	*buf = 0;
+	return instr.n;
+}
+
+int
+i386instlen(ulong pc)
+{
+	Instr i;
+
+	if (mkinstr(&i, pc))
+		return i.n;
+	return -1;
+}
+
+void
+das(uchar *x, int n)
+{
+	int l, pc;
+	char buf[128];
+/*
+	int i;
+	for(i = 0; i < n; i++)
+		print("%.2ux", x[i]);
+	print("\n");
+*/
+
+	dasdata = x;
+	pc = 0;
+	while(n > 0) {
+		i386das(pc, buf, sizeof(buf));
+		print("%.8lux %2x %-20s ", (ulong)(dasdata+pc), pc, buf);
+		l = i386inst(pc, 'i', buf, sizeof(buf));
+		print("\t%s\n", buf);
+
+		pc += l;
+		n -= l;
+	}
+}
--- /dev/null
+++ b/libinterp/das-arm.c
@@ -1,0 +1,535 @@
+#include <lib9.h>
+
+typedef struct	Instr	Instr;
+struct	Instr
+{
+	ulong	w;
+	ulong	addr;
+	uchar	op;			/* super opcode */
+
+	uchar	cond;			/* bits 28-31 */
+	uchar	store;			/* bit 20 */
+
+	uchar	rd;			/* bits 12-15 */
+	uchar	rn;			/* bits 16-19 */
+	uchar	rs;			/* bits 0-11 */
+
+	long	imm;			/* rotated imm */
+	char*	curr;			/* fill point in buffer */
+	char*	end;			/* end of buffer */
+	char*	err;			/* error message */
+};
+
+typedef struct Opcode Opcode;
+struct Opcode
+{
+	char*	o;
+	void	(*f)(Opcode*, Instr*);
+	char*	a;
+};
+
+static	void	format(char*, Instr*, char*);
+static	int	arminst(ulong, char, char*, int);
+static	int	armdas(ulong, char*, int);
+
+static
+char*	cond[16] =
+{
+	"EQ",	"NE",	"CS",	"CC",
+	"MI",	"PL",	"VS",	"VC",
+	"HI",	"LS",	"GE",	"LT",
+	"GT",	"LE",	0,	"NV"
+};
+
+static
+char*	shtype[4] =
+{
+	"<<",	">>",	"->",	"@>"
+};
+
+static int
+get4(ulong addr, long *v)
+{
+	*v = *(ulong*)addr;
+	return 1;	
+}
+
+static char *
+_hexify(char *buf, ulong p, int zeros)
+{
+	ulong d;
+
+	d = p/16;
+	if(d)
+		buf = _hexify(buf, d, zeros-1);
+	else
+		while(zeros--)
+			*buf++ = '0';
+	*buf++ = "0123456789abcdef"[p&0x0f];
+	return buf;
+}
+
+int
+armclass(long w)
+{
+	int op;
+
+	op = (w >> 25) & 0x7;
+	switch(op) {
+	case 0:	/* data processing r,r,r */
+		op = ((w >> 4) & 0xf);
+		if(op == 0x9) {
+			op = 48+16;		/* mul */
+			if(w & (1<<24)) {
+				op += 2;
+				if(w & (1<<22))
+					op++;	/* swap */
+				break;
+			}
+			if(w & (1<<21))
+				op++;		/* mla */
+			break;
+		}
+		op = (w >> 21) & 0xf;
+		if(w & (1<<4))
+			op += 32;
+		else
+		if(w & (31<<7))
+			op += 16;
+		break;
+	case 1:	/* data processing i,r,r */
+		op = (48) + ((w >> 21) & 0xf);
+		break;
+	case 2:	/* load/store byte/word i(r) */
+		op = (48+20) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+		break;
+	case 3:	/* load/store byte/word (r)(r) */
+		op = (48+20+4) + ((w >> 22) & 0x1) + ((w >> 19) & 0x2);
+		break;
+	case 4:	/* block data transfer (r)(r) */
+		op = (48+20+4+4) + ((w >> 20) & 0x1);
+		break;
+	case 5:	/* branch / branch link */
+		op = (48+20+4+4+2) + ((w >> 24) & 0x1);
+		break;
+	case 7:	/* coprocessor crap */
+		op = (48+20+4+4+2+2) + ((w >> 3) & 0x2) + ((w >> 20) & 0x1);
+		break;
+	default:
+		op = (48+20+4+4+2+2+4);
+		break;
+	}
+	return op;
+}
+
+static int
+decode(ulong pc, Instr *i)
+{
+	long w;
+
+	get4(pc, &w);
+	i->w = w;
+	i->addr = pc;
+	i->cond = (w >> 28) & 0xF;
+	i->op = armclass(w);
+	return 1;
+}
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	i->curr = vseprint(i->curr, i->end, fmt, arg);
+	va_end(arg);
+}
+
+static void
+armdps(Opcode *o, Instr *i)
+{
+	i->store = (i->w >> 20) & 1;
+	i->rn = (i->w >> 16) & 0xf;
+	i->rd = (i->w >> 12) & 0xf;
+	i->rs = (i->w >> 0) & 0xf;
+	if(i->rn == 15 && i->rs == 0) {
+		if(i->op == 8) {
+			format("MOVW", i,"CPSR, R%d");
+			return;
+		} else
+		if(i->op == 10) {
+			format("MOVW", i,"SPSR, R%d");
+			return;
+		}
+	} else
+	if(i->rn == 9 && i->rd == 15) {
+		if(i->op == 9) {
+			format("MOVW", i, "R%s, CPSR");
+			return;
+		} else
+		if(i->op == 11) {
+			format("MOVW", i, "R%s, SPSR");
+			return;
+		}
+	}
+	format(o->o, i, o->a);
+}
+
+static void
+armdpi(Opcode *o, Instr *i)
+{
+	ulong v;
+	int c;
+
+	v = (i->w >> 0) & 0xff;
+	c = (i->w >> 8) & 0xf;
+	while(c) {
+		v = (v<<30) | (v>>2);
+		c--;
+	}
+	i->imm = v;
+	i->store = (i->w >> 20) & 1;
+	i->rn = (i->w >> 16) & 0xf;
+	i->rd = (i->w >> 12) & 0xf;
+	i->rs = i->w&0x0f;
+
+		/* RET is encoded as ADD #0,R14,R15 */
+	if(i->w == 0xe282f000){
+		format("RET", i, "");
+		return;
+	} else
+	format(o->o, i, o->a);
+}
+
+static void
+armsdti(Opcode *o, Instr *i)
+{
+	ulong v;
+
+	v = (i->w >> 0) & 0xfff;
+	if(!(i->w & (1<<23)))
+		v = -v;
+	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+	i->imm = v;
+	i->rn = (i->w >> 16) & 0xf;
+	i->rd = (i->w >> 12) & 0xf;
+		/* convert load of offset(PC) to a load immediate */
+	if(i->rn == 15 && (i->w & (1<<20)) && get4(i->addr+v+8, &i->imm) > 0)
+		format(o->o, i, "$#%i,R%d");
+	else
+		format(o->o, i, o->a);
+}
+
+static void
+armsdts(Opcode *o, Instr *i)
+{
+	i->store = ((i->w >> 23) & 0x2) | ((i->w >>21) & 0x1);
+	i->rs = (i->w >> 0) & 0xf;
+	i->rn = (i->w >> 16) & 0xf;
+	i->rd = (i->w >> 12) & 0xf;
+	format(o->o, i, o->a);
+}
+
+static void
+armbdt(Opcode *o, Instr *i)
+{
+	i->store = (i->w >> 21) & 0x3;		/* S & W bits */
+	i->rn = (i->w >> 16) & 0xf;
+	i->imm = i->w & 0xffff;
+	if(i->w == 0xe8fd8000)
+		format("RFE", i, "");
+	else
+		format(o->o, i, o->a);
+}
+
+static void
+armund(Opcode *o, Instr *i)
+{
+	format(o->o, i, o->a);
+}
+
+static void
+armcdt(Opcode *o, Instr *i)
+{
+	format(o->o, i, o->a);
+}
+
+static void
+armunk(Opcode *o, Instr *i)
+{
+	format(o->o, i, o->a);
+}
+
+static void
+armb(Opcode *o, Instr *i)
+{
+	ulong v;
+
+	v = i->w & 0xffffff;
+	if(v & 0x800000)
+		v |= ~0xffffff;
+	i->imm = (v<<2) + i->addr + 8;
+	format(o->o, i, o->a);
+}
+
+static void
+armco(Opcode *o, Instr *i)		/* coprocessor instructions */
+{
+	int op, p, cp;
+
+	char buf[1024];
+
+	i->rn = (i->w >> 16) & 0xf;
+	i->rd = (i->w >> 12) & 0xf;
+	i->rs = i->w&0xf;
+	cp = (i->w >> 8) & 0xf;
+	p = (i->w >> 5) & 0x7;
+	if(i->w&0x10) {
+		op = (i->w >> 20) & 0x0f;
+		snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+	} else {
+		op = (i->w >> 21) & 0x07;
+		snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+	}
+	format(o->o, i, buf);
+}
+
+static Opcode opcodes[] =
+{
+	"AND%C%S",	armdps,	"R%s,R%n,R%d",
+	"EOR%C%S",	armdps,	"R%s,R%n,R%d",
+	"SUB%C%S",	armdps,	"R%s,R%n,R%d",
+	"RSB%C%S",	armdps,	"R%s,R%n,R%d",
+	"ADD%C%S",	armdps,	"R%s,R%n,R%d",
+	"ADC%C%S",	armdps,	"R%s,R%n,R%d",
+	"SBC%C%S",	armdps,	"R%s,R%n,R%d",
+	"RSC%C%S",	armdps,	"R%s,R%n,R%d",
+	"TST%C%S",	armdps,	"R%s,R%n,",
+	"TEQ%C%S",	armdps,	"R%s,R%n,",
+	"CMP%C%S",	armdps,	"R%s,R%n,",
+	"CMN%C%S",	armdps,	"R%s,R%n,",
+	"ORR%C%S",	armdps,	"R%s,R%n,R%d",
+	"MOVW%C%S",	armdps,	"R%s,R%d",
+	"BIC%C%S",	armdps,	"R%s,R%n,R%d",
+	"MVN%C%S",	armdps,	"R%s,R%d",
+
+	"AND%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"EOR%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"SUB%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"RSB%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"ADD%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"ADC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"SBC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"RSC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"TST%C%S",	armdps,	"(R%s%h#%m),R%n,",
+	"TEQ%C%S",	armdps,	"(R%s%h#%m),R%n,",
+	"CMP%C%S",	armdps,	"(R%s%h#%m),R%n,",
+	"CMN%C%S",	armdps,	"(R%s%h#%m),R%n,",
+	"ORR%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"MOVW%C%S",	armdps,	"(R%s%h#%m),R%d",
+	"BIC%C%S",	armdps,	"(R%s%h#%m),R%n,R%d",
+	"MVN%C%S",	armdps,	"(R%s%h#%m),R%d",
+
+	"AND%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"EOR%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"SUB%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"RSB%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"ADD%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"ADC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"SBC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"RSC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"TST%C%S",	armdps,	"(R%s%hR%m),R%n,",
+	"TEQ%C%S",	armdps,	"(R%s%hR%m),R%n,",
+	"CMP%C%S",	armdps,	"(R%s%hR%m),R%n,",
+	"CMN%C%S",	armdps,	"(R%s%hR%m),R%n,",
+	"ORR%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"MOVW%C%S",	armdps,	"(R%s%hR%m),R%d",
+	"BIC%C%S",	armdps,	"(R%s%hR%m),R%n,R%d",
+	"MVN%C%S",	armdps,	"(R%s%hR%m),R%d",
+
+	"AND%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"EOR%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"SUB%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"RSB%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"ADD%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"ADC%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"SBC%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"RSC%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"TST%C%S",	armdpi,	"$#%i,R%n,",
+	"TEQ%C%S",	armdpi,	"$#%i,R%n,",
+	"CMP%C%S",	armdpi,	"$#%i,R%n,",
+	"CMN%C%S",	armdpi,	"$#%i,R%n,",
+	"ORR%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"MOVW%C%S",	armdpi,	"$#%i,,R%d",
+	"BIC%C%S",	armdpi,	"$#%i,R%n,R%d",
+	"MVN%C%S",	armdpi,	"$#%i,,R%d",
+
+	"MUL%C%S",	armdpi,	"R%s,R%m,R%n",
+	"MULA%C%S",	armdpi,	"R%s,R%m,R%n,R%d",
+	"SWPW",		armdpi,	"R%s,(R%n),R%d",
+	"SWPB",		armdpi,	"R%s,(R%n),R%d",
+
+	"MOVW%C%p",	armsdti,"R%d,#%i(R%n)",
+	"MOVB%C%p",	armsdti,"R%d,#%i(R%n)",
+	"MOVW%C%p",	armsdti,"#%i(R%n),R%d",
+	"MOVB%C%p",	armsdti,"#%i(R%n),R%d",
+
+	"MOVW%C%p",	armsdts,"R%d,%D(R%s%h#%m)(R%n)",
+	"MOVB%C%p",	armsdts,"R%d,%D(R%s%h#%m)(R%n)",
+	"MOVW%C%p",	armsdts,"%D(R%s%h#%m)(R%n),R%d",
+	"MOVB%C%p",	armsdts,"%D(R%s%h#%m)(R%n),R%d",
+
+	"MOVM%C%P%a",	armbdt,	"R%n,[%r]",
+	"MOVM%C%P%a",	armbdt,	"[%r],R%n",
+
+	"B%C",		armb,	"%b",
+	"BL%C",		armb,	"%b",
+
+	"CDP%C",	armco,	"",
+	"CDP%C",	armco,	"",
+	"MCR%C",	armco,	"",
+	"MRC%C",	armco,	"",
+
+	"UNK",		armunk,	"",
+};
+
+static	char *mode[] = { 0, "IA", "DB", "IB" };
+static	char *pw[] = { "P", "PW", 0, "W" };
+static	char *sw[] = { 0, "W", "S", "SW" };
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+	int j, k, m, n;
+
+	if(mnemonic)
+		format(0, i, mnemonic);
+	if(f == 0)
+		return;
+	if(mnemonic)
+		if(i->curr < i->end)
+			*i->curr++ = '\t';
+	for ( ; *f && i->curr < i->end; f++) {
+		if(*f != '%') {
+			*i->curr++ = *f;
+			continue;
+		}
+		switch (*++f) {
+
+		case 'C':	/* .CONDITION */
+			if(cond[i->cond])
+				bprint(i, ".%s", cond[i->cond]);
+			break;
+
+		case 'S':	/* .STORE */
+			if(i->store)
+				bprint(i, ".S");
+			break;
+
+		case 'P':	/* P & U bits for block move */
+			n = (i->w >>23) & 0x3;
+			if (mode[n])
+				bprint(i, ".%s", mode[n]);
+			break;
+
+		case 'D':	/* ~U bit for single data xfer */
+			if((i->w & (1<<23)) == 0)
+				bprint(i, "-");
+			break;
+
+		case 'p':	/* P & W bits for single data xfer*/
+			if (pw[i->store])
+				bprint(i, ".%s", pw[i->store]);
+			break;
+
+		case 'a':	/* S & W bits for single data xfer*/
+			if (sw[i->store])
+				bprint(i, ".%s", sw[i->store]);
+			break;
+
+		case 's':
+			bprint(i, "%d", i->rs & 0xf);
+			break;
+				
+		case 'm':
+			bprint(i, "%d", (i->w>>7) & 0x1f);
+			break;
+
+		case 'h':
+			bprint(i, "%s", shtype[(i->w>>5) & 0x3]);
+			break;
+
+		case 'n':
+			bprint(i, "%d", i->rn);
+			break;
+
+		case 'd':
+			bprint(i, "%d", i->rd);
+			break;
+
+		case 'i':
+			bprint(i, "%lux", i->imm);
+			break;
+
+		case 'b':
+			bprint(i, "%lux", i->imm);
+			break;
+
+		case 'r':
+			n = i->imm&0xffff;
+			j = 0;
+			k = 0;
+			while(n) {
+				m = j;
+				while(n&0x1) {
+					j++;
+					n >>= 1;
+				}
+				if(j != m) {
+					if(k)
+						bprint(i, ",");
+					if(j == m+1)
+						bprint(i, "R%d", m);
+					else
+						bprint(i, "R%d-R%d", m, j-1);
+					k = 1;
+				}
+				j++;
+				n >>= 1;
+			}
+			break;
+
+		case '\0':
+			*i->curr++ = '%';
+			return;
+
+		default:
+			bprint(i, "%%%c", *f);
+			break;
+		}
+	}
+	*i->curr = 0;
+}
+
+void
+das(ulong *x, int n)
+{
+	ulong pc;
+	Instr i;
+	char buf[128];
+
+	pc = (ulong)x;
+	while(n > 0) {
+		i.curr = buf;
+		i.end = buf+sizeof(buf)-1;
+
+		if(decode(pc, &i) < 0)
+			sprint(buf, "???");
+		else
+			(*opcodes[i.op].f)(&opcodes[i.op], &i);
+
+		print("%.8lux %.8lux\t%s\n", pc, i.w, buf);
+		pc += 4;
+		n--;
+	}
+}
--- /dev/null
+++ b/libinterp/das-mips.c
@@ -1,0 +1,531 @@
+#include <lib9.h>
+
+/* mips native disassembler */
+
+typedef struct {
+	long addr;			/* pc of instr */
+	uchar op;			/* bits 31-26 */
+	uchar rs;			/* bits 25-21 */
+	uchar rt;			/* bits 20-16 */
+	uchar rd;			/* bits 15-11 */
+	uchar sa;			/* bits 10-6 */
+	uchar function;			/* bits 5-0 */
+	long immediate;			/* bits 15-0 */
+	ulong cofun;			/* bits 24-0 */
+	ulong target;			/* bits 25-0 */
+	long w0;
+	char *curr;			/* current fill point */
+	char *end;			/* end of buffer */
+	char *err;
+} Instr;
+
+typedef struct {
+	char *mnemonic;
+	char *mipsco;
+} Opcode;
+
+static char mipscoload[] = "r%t,%l";
+static char mipscoalui[] = "r%t,r%s,%i";
+static char mipscoalu3op[] = "r%d,r%s,r%t";
+static char mipscoboc[] = "r%s,r%t,%b";
+static char mipscoboc0[] = "r%s,%b";
+static char mipscorsrt[] = "r%s,r%t";
+static char mipscorsi[] = "r%s,%i";
+static char mipscoxxx[] = "%w";
+static char mipscofp3[] = "f%a,f%d,f%t";	/* fd,fs,ft */
+static char mipscofp2[] = "f%a,f%d";		/* fd,fs */
+static char mipscofpc[] = "f%d,f%t";		/* fs,ft */
+
+static Opcode opcodes[64] = {
+	0,		0,
+	0,		0,
+	"j",		"%j",
+	"jal",		"%j",
+	"beq",		mipscoboc,
+	"bne",		mipscoboc,
+	"blez",		mipscoboc0,
+	"bgtz",		mipscoboc0,
+	"addi",		mipscoalui,
+	"addiu",	mipscoalui,
+	"slti",		mipscoalui,
+	"sltiu",	mipscoalui,
+	"andi",		mipscoalui,
+	"ori",		mipscoalui,
+	"xori",		mipscoalui,
+	"lui",		"r%t,%u",
+	"cop0",		0,
+	"cop1",		0,
+	"cop2",		0,
+	"cop3",		0,
+	"beql",		mipscoboc,
+	"bnel",		mipscoboc,
+	"blezl",	mipscoboc0,
+	"bgtzl",	mipscoboc0,
+	"instr18",	mipscoxxx,
+	"instr19",	mipscoxxx,
+	"instr1A",	mipscoxxx,
+	"instr1B",	mipscoxxx,
+	"instr1C",	mipscoxxx,
+	"instr1D",	mipscoxxx,
+	"instr1E",	mipscoxxx,
+	"instr1F",	mipscoxxx,
+	"lb",		mipscoload,
+	"lh",		mipscoload,
+	"lwl",		mipscoload,
+	"lw",		mipscoload,
+	"lbu",		mipscoload,
+	"lhu",		mipscoload,
+	"lwr",		mipscoload,
+	"instr27",	mipscoxxx,
+	"sb",		mipscoload,
+	"sh",		mipscoload,
+	"swl",		mipscoload,
+	"sw",		mipscoload,
+	"instr2C",	mipscoxxx,
+	"instr2D",	mipscoxxx,
+	"swr",		mipscoload,
+	"cache",	"",
+	"ll",		mipscoload,
+	"lwc1",		mipscoload,
+	"lwc2",		mipscoload,
+	"lwc3",		mipscoload,
+	"instr34",	mipscoxxx,
+	"ld",		mipscoload,
+	"ld",		mipscoload,
+	"ld",		mipscoload,
+	"sc",		mipscoload,
+	"swc1",		mipscoload,
+	"swc2",		mipscoload,
+	"swc3",		mipscoload,
+	"instr3C",	mipscoxxx,
+	"sd",		mipscoload,
+	"sd",		mipscoload,
+	"sd",		mipscoload,
+};
+
+static Opcode sopcodes[64] = {
+	"sll",		"r%d,r%t,$%a",
+	"special01",	mipscoxxx,
+	"srl",		"r%d,r%t,$%a",
+	"sra",		"r%d,r%t,$%a",
+	"sllv",		"r%d,r%t,R%s",
+	"special05",	mipscoxxx,
+	"srlv",		"r%d,r%t,r%s",
+	"srav",		"r%d,r%t,r%s",
+	"jr",		"r%s",
+	"jalr",		"r%d,r%s",
+	"special0A",	mipscoxxx,
+	"special0B",	mipscoxxx,
+	"syscall",	"",
+	"break",	"",
+	"special0E",	mipscoxxx,
+	"sync",		"",
+	"mfhi",		"r%d",
+	"mthi",		"r%s",
+	"mflo",		"r%d",
+	"mtlo",		"r%s",
+	"special14",	mipscoxxx,
+	"special15",	mipscoxxx,
+	"special16",	mipscoxxx,
+	"special17",	mipscoxxx,
+	"mult",		mipscorsrt,
+	"multu",	mipscorsrt,
+	"div",		mipscorsrt,
+	"divu",		mipscorsrt,
+	"special1C",	mipscoxxx,
+	"special1D",	mipscoxxx,
+	"special1E",	mipscoxxx,
+	"special1F",	mipscoxxx,
+	"add",		mipscoalu3op,
+	"addu",		mipscoalu3op,
+	"sub",		mipscoalu3op,
+	"subu",		mipscoalu3op,
+	"and",		mipscoalu3op,
+	"or",		mipscoalu3op,
+	"xor",		mipscoalu3op,
+	"nor",		mipscoalu3op,
+	"special28",	mipscoxxx,
+	"special29",	mipscoxxx,
+	"slt",		mipscoalu3op,
+	"sltu",		mipscoalu3op,
+	"special2C",	mipscoxxx,
+	"special2D",	mipscoxxx,
+	"special2E",	mipscoxxx,
+	"special2F",	mipscoxxx,
+	"tge",		mipscorsrt,
+	"tgeu",		mipscorsrt,
+	"tlt",		mipscorsrt,
+	"tltu",		mipscorsrt,
+	"teq",		mipscorsrt,
+	"special35",	mipscoxxx,
+	"tne",		mipscorsrt,
+	"special37",	mipscoxxx,
+	"special38",	mipscoxxx,
+	"special39",	mipscoxxx,
+	"special3A",	mipscoxxx,
+	"special3B",	mipscoxxx,
+	"special3C",	mipscoxxx,
+	"special3D",	mipscoxxx,
+	"special3E",	mipscoxxx,
+	"special3F",	mipscoxxx,
+};
+
+static Opcode ropcodes[32] = {
+	"bltz",		mipscoboc0,
+	"bgez",		mipscoboc0,
+	"bltzl",	mipscoboc0,
+	"bgezl",	mipscoboc0,
+	"regimm04",	mipscoxxx,
+	"regimm05",	mipscoxxx,
+	"regimm06",	mipscoxxx,
+	"regimm07",	mipscoxxx,
+	"tgei",		mipscorsi,
+	"tgeiu",	mipscorsi,
+	"tlti",		mipscorsi,
+	"tltiu",	mipscorsi,
+	"teqi",		mipscorsi,
+	"regimm0D",	mipscoxxx,
+	"tnei",		mipscorsi,
+	"regimm0F",	mipscoxxx,
+	"bltzal",	mipscoboc0,
+	"bgezal",	mipscoboc0,
+	"bltzall",	mipscoboc0,
+	"bgezall",	mipscoboc0,
+	"regimm14",	mipscoxxx,
+	"regimm15",	mipscoxxx,
+	"regimm16",	mipscoxxx,
+	"regimm17",	mipscoxxx,
+	"regimm18",	mipscoxxx,
+	"regimm19",	mipscoxxx,
+	"regimm1A",	mipscoxxx,
+	"regimm1B",	mipscoxxx,
+	"regimm1C",	mipscoxxx,
+	"regimm1D",	mipscoxxx,
+	"regimm1E",	mipscoxxx,
+	"regimm1F",	mipscoxxx,
+};
+
+static Opcode fopcodes[64] = {
+	"add.%f",	mipscofp3,
+	"sub.%f",	mipscofp3,
+	"mul.%f",	mipscofp3,
+	"div.%f",	mipscofp3,
+	"sqrt.%f",	mipscofp2,
+	"abs.%f",	mipscofp2,
+	"mov.%f",	mipscofp2,
+	"neg.%f",	mipscofp2,
+	"finstr08",	mipscoxxx,
+	"finstr09",	mipscoxxx,
+	"finstr0A",	mipscoxxx,
+	"finstr0B",	mipscoxxx,
+	"round.w.%f",	mipscofp2,
+	"trunc.w%f",	mipscofp2,
+	"ceil.w%f",	mipscofp2,
+	"floor.w%f",	mipscofp2,
+	"finstr10",	mipscoxxx,
+	"finstr11",	mipscoxxx,
+	"finstr12",	mipscoxxx,
+	"finstr13",	mipscoxxx,
+	"finstr14",	mipscoxxx,
+	"finstr15",	mipscoxxx,
+	"finstr16",	mipscoxxx,
+	"finstr17",	mipscoxxx,
+	"finstr18",	mipscoxxx,
+	"finstr19",	mipscoxxx,
+	"finstr1A",	mipscoxxx,
+	"finstr1B",	mipscoxxx,
+	"finstr1C",	mipscoxxx,
+	"finstr1D",	mipscoxxx,
+	"finstr1E",	mipscoxxx,
+	"finstr1F",	mipscoxxx,
+	"cvt.s.%f",	mipscofp2,
+	"cvt.d.%f",	mipscofp2,
+	"cvt.e.%f",	mipscofp2,
+	"cvt.q.%f",	mipscofp2,
+	"cvt.w.%f",	mipscofp2,
+	"finstr25",	mipscoxxx,
+	"finstr26",	mipscoxxx,
+	"finstr27",	mipscoxxx,
+	"finstr28",	mipscoxxx,
+	"finstr29",	mipscoxxx,
+	"finstr2A",	mipscoxxx,
+	"finstr2B",	mipscoxxx,
+	"finstr2C",	mipscoxxx,
+	"finstr2D",	mipscoxxx,
+	"finstr2E",	mipscoxxx,
+	"finstr2F",	mipscoxxx,
+	"c.f.%f",	mipscofpc,
+	"c.un.%f",	mipscofpc,
+	"c.eq.%f",	mipscofpc,
+	"c.ueq.%f",	mipscofpc,
+	"c.olt.%f",	mipscofpc,
+	"c.ult.%f",	mipscofpc,
+	"c.ole.%f",	mipscofpc,
+	"c.ule.%f",	mipscofpc,
+	"c.sf.%f",	mipscofpc,
+	"c.ngle.%f",	mipscofpc,
+	"c.seq.%f",	mipscofpc,
+	"c.ngl.%f",	mipscofpc,
+	"c.lt.%f",	mipscofpc,
+	"c.nge.%f",	mipscofpc,
+	"c.le.%f",	mipscofpc,
+	"c.ngt.%f",	mipscofpc,
+};
+
+static char fsub[16] = {
+	's', 'd', 'e', 'q', 'w', '?', '?', '?',
+	'?', '?', '?', '?', '?', '?', '?', '?'
+};
+
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	i->curr = vseprint(i->curr, i->end, fmt, arg);
+	va_end(arg);
+}
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+	if (mnemonic)
+		format(0, i, mnemonic);
+	if (f == 0)
+		return;
+	if (i->curr < i->end)
+		*i->curr++ = '\t';
+	for ( ; *f && i->curr < i->end; f++) {
+		if (*f != '%') {
+			*i->curr++ = *f;
+			continue;
+		}
+		switch (*++f) {
+
+		case 's':
+			bprint(i, "%d", i->rs);
+			break;
+
+		case 't':
+			bprint(i, "%d", i->rt);
+			break;
+
+		case 'd':
+			bprint(i, "%d", i->rd);
+			break;
+
+		case 'a':
+			bprint(i, "%d", i->sa);
+			break;
+
+		case 'l':
+			bprint(i, "%d(r%d)", i->immediate, i->rs);
+			break;
+
+		case 'u':
+		case 'i':
+			bprint(i, "$%d", i->immediate);
+			break;
+
+		case 'j':
+			bprint(i, "0x%lux", (i->target<<2)|(i->addr & 0xF0000000));
+			break;
+
+		case 'b':
+			bprint(i, "0x%lux", (i->immediate<<2)+i->addr+4);
+			break;
+
+		case 'c':
+			bprint(i, "0x%lux", i->cofun);
+			break;
+
+		case 'w':
+			bprint(i, "[0x%lux]", i->w0);
+			break;
+
+		case 'f':
+			*i->curr++ = fsub[i->rs & 0x0F];
+			break;
+
+		case '\0':
+			*i->curr++ = '%';
+			return;
+
+		default:
+			bprint(i, "%%%c", *f);
+			break;
+		}
+	}
+}
+
+static void
+copz(int cop, Instr *i)
+{
+	char *f, *m, buf[16];
+
+	m = buf;
+	f = "%t,%d";
+	switch (i->rs) {
+
+	case 0:
+		sprint(buf, "mfc%d", cop);
+		break;
+
+	case 2:
+		sprint(buf, "cfc%d", cop);
+		break;
+
+	case 4:
+		sprint(buf, "mtc%d", cop);
+		break;
+
+	case 6:
+		sprint(buf, "ctc%d", cop);
+		break;
+
+	case 8:
+		f = "%b";
+		switch (i->rt) {
+
+		case 0:
+			sprint(buf, "bc%df", cop);
+			break;
+
+		case 1:
+			sprint(buf, "bc%dt", cop);
+			break;
+
+		case 2:
+			sprint(buf, "bc%dfl", cop);
+			break;
+
+		case 3:
+			sprint(buf, "bc%dtl", cop);
+			break;
+
+		default:
+			sprint(buf, "cop%d", cop);
+			f = mipscoxxx;
+			break;
+		}
+		break;
+
+	default:
+		sprint(buf, "cop%d", cop);
+		if (i->rs & 0x10)
+			f = "function %c";
+		else
+			f = mipscoxxx;
+		break;
+	}
+	format(m, i, f);
+}
+
+static void
+cop0(Instr *i)
+{
+	char *m = 0;
+
+	if (i->rs >= 0x10) {
+		switch (i->cofun) {
+	
+		case 1:
+			m = "tlbr";
+			break;
+	
+		case 2:
+			m = "tlbwi";
+			break;
+	
+		case 6:
+			m = "tlbwr";
+			break;
+	
+		case 8:
+			m = "tlbp";
+			break;
+	
+		case 16:
+			m = "rfe";
+			break;
+	
+		case 32:
+			m = "eret";
+			break;
+		}
+		if (m) {
+			format(m, i, 0);
+			if (i->curr < i->end)
+				*i->curr++ = 0;
+			return;
+		}
+	}
+	copz(0, i);
+}
+
+void
+das(ulong *pc)
+{
+	Instr i;
+	char buf[100];
+	Opcode *o;
+	uchar op;
+	ulong w;
+
+	w = *pc;
+
+	i.addr = (ulong)pc;
+	i.op = (w >> 26) & 0x3F;
+	i.rs = (w >> 21) & 0x1F;
+	i.rt = (w >> 16) & 0x1F;
+	i.rd = (w >> 11) & 0x1F;
+	i.sa = (w >> 6) & 0x1F;
+	i.function = w & 0x3F;
+	i.immediate = w & 0x0000FFFF;
+	if(i.immediate & 0x8000)
+		i.immediate |= ~0x0000FFFF;
+	i.cofun = w & 0x01FFFFFF;
+	i.target = w & 0x03FFFFFF;
+	i.w0 = w;
+	i.curr = buf;
+	i.end = buf+sizeof(buf)-1;
+
+	i.curr += sprint(i.curr, "	%.8p %.8lux", pc, w);
+
+	o = opcodes;
+	op = i.op;
+	switch (i.op) {
+
+	case 0x00:					/* SPECIAL */
+		o = sopcodes;
+		op = i.function;
+		break;
+
+	case 0x01:					/* REGIMM */
+		o = ropcodes;
+		op = i.rt;
+		break;
+
+	case 0x10:					/* COP0 */
+		cop0(&i);
+		break;
+
+	case 0x11:					/* COP1 */
+		if (i.rs & 0x10) {
+			o = fopcodes;
+			op = i.function;
+			break;
+		}
+		/*FALLTHROUGH*/
+	case 0x12:					/* COP2 */
+	case 0x13:					/* COP3 */
+		copz(i.op-0x10, &i);
+		break;
+	}
+	format(o[op].mnemonic, &i, o[op].mipsco);
+	*i.curr++ = '\n';
+	*i.curr = 0;
+	print("%s", buf);
+}
--- /dev/null
+++ b/libinterp/das-power.c
@@ -1,0 +1,961 @@
+#include <lib9.h>
+
+/*
+ * disassemble PowerPC opcodes in Plan9 format
+ * Copyright © 1997 C H Forsyth (forsyth@terzarima.net)
+ */
+
+/*
+ * ibm conventions for these: bit 0 is top bit
+ *	from table 10-1
+ */
+typedef struct {
+	uchar	aa;		/* bit 30 */
+	uchar	crba;		/* bits 11-15 */
+	uchar	crbb;		/* bits 16-20 */
+	long	bd;		/* bits 16-29 */
+	uchar	crfd;		/* bits 6-8 */
+	uchar	crfs;		/* bits 11-13 */
+	uchar	bi;		/* bits 11-15 */
+	uchar	bo;		/* bits 6-10 */
+	uchar	crbd;		/* bits 6-10 */
+	union {
+		short	d;	/* bits 16-31 */
+		short	simm;
+		ushort	uimm;
+	};
+	uchar	fm;		/* bits 7-14 */
+	uchar	fra;		/* bits 11-15 */
+	uchar	frb;		/* bits 16-20 */
+	uchar	frc;		/* bits 21-25 */
+	uchar	frs;		/* bits 6-10 */
+	uchar	frd;		/* bits 6-10 */
+	uchar	crm;		/* bits 12-19 */
+	long	li;		/* bits 6-29 || b'00' */
+	uchar	lk;		/* bit 31 */
+	uchar	mb;		/* bits 21-25 */
+	uchar	me;		/* bits 26-30 */
+	uchar	nb;		/* bits 16-20 */
+	uchar	op;		/* bits 0-5 */
+	uchar	oe;		/* bit 21 */
+	uchar	ra;		/* bits 11-15 */
+	uchar	rb;		/* bits 16-20 */
+	uchar	rc;		/* bit 31 */
+	union {
+		uchar	rs;	/* bits 6-10 */
+		uchar	rd;
+	};
+	uchar	sh;		/* bits 16-20 */
+	ushort	spr;		/* bits 11-20 */
+	uchar	to;		/* bits 6-10 */
+	uchar	imm;		/* bits 16-19 */
+	ushort	xo;		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
+	long	immediate;
+	long w0;
+	long w1;
+	ulong	addr;		/* pc of instruction */
+	short	target;
+	char	*curr;		/* current fill level in output buffer */
+	char	*end;		/* end of buffer */
+	int 	size;		/* number of longs in instr */
+	char	*err;		/* errmsg */
+} Instr;
+
+#define	IBF(v,a,b) (((ulong)(v)>>(32-(b)-1)) & ~(~0L<<(((b)-(a)+1))))
+#define	IB(v,b) IBF((v),(b),(b))
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	i->curr = vseprint(i->curr, i->end, fmt, arg);
+	va_end(arg);
+}
+
+static int
+decode(ulong *pc, Instr *i)
+{
+	ulong w;
+
+	w = *pc;
+	i->aa = IB(w, 30);
+	i->crba = IBF(w, 11, 15);
+	i->crbb = IBF(w, 16, 20);
+	i->bd = IBF(w, 16, 29)<<2;
+	if(i->bd & 0x8000)
+		i->bd |= ~0L<<16;
+	i->crfd = IBF(w, 6, 8);
+	i->crfs = IBF(w, 11, 13);
+	i->bi = IBF(w, 11, 15);
+	i->bo = IBF(w, 6, 10);
+	i->crbd = IBF(w, 6, 10);
+	i->uimm = IBF(w, 16, 31);	/* also d, simm */
+	i->fm = IBF(w, 7, 14);
+	i->fra = IBF(w, 11, 15);
+	i->frb = IBF(w, 16, 20);
+	i->frc = IBF(w, 21, 25);
+	i->frs = IBF(w, 6, 10);
+	i->frd = IBF(w, 6, 10);
+	i->crm = IBF(w, 12, 19);
+	i->li = IBF(w, 6, 29)<<2;
+	if(IB(w, 6))
+		i->li |= ~0<<25;
+	i->lk = IB(w, 31);
+	i->mb = IBF(w, 21, 25);
+	i->me = IBF(w, 26, 30);
+	i->nb = IBF(w, 16, 20);
+	i->op = IBF(w, 0, 5);
+	i->oe = IB(w, 21);
+	i->ra = IBF(w, 11, 15);
+	i->rb = IBF(w, 16, 20);
+	i->rc = IB(w, 31);
+	i->rs = IBF(w, 6, 10);	/* also rd */
+	i->sh = IBF(w, 16, 20);
+	i->spr = IBF(w, 11, 20);
+	i->to = IBF(w, 6, 10);
+	i->imm = IBF(w, 16, 19);
+	i->xo = IBF(w, 21, 30);		/* bits 21-30, 22-30, 26-30, or 30 (beware) */
+	i->immediate = i->simm;
+	if(i->op == 15)
+		i->immediate <<= 16;
+	i->w0 = w;
+	i->target = -1;
+	i->addr = (ulong)pc;
+	i->size = 1;
+	return 1;
+}
+
+static int
+mkinstr(ulong *pc, Instr *i)
+{
+	Instr x;
+
+	if(decode(pc, i) < 0)
+		return -1;
+	/*
+	 * combine ADDIS/ORI (CAU/ORIL) into MOVW
+	 */
+	if (i->op == 15 && i->ra==0) {
+		if(decode(pc+1, &x) < 0)
+			return -1;
+		if (x.op == 24 && x.rs == x.ra && x.ra == i->rd) {
+			i->immediate |= (x.immediate & 0xFFFF);
+			i->w1 = x.w0;
+			i->target = x.rd;
+			i->size++;
+			return 1;
+		}
+	}
+	return 1;
+}
+
+static void
+pglobal(Instr *i, long off, char *reg)
+{
+	bprint(i, "%lux%s", off, reg);
+}
+
+static void
+address(Instr *i)
+{
+	if(i->simm < 0)
+		bprint(i, "-%lx(R%d)", -i->simm, i->ra);
+	else
+		bprint(i, "%lux(R%d)", i->immediate, i->ra);
+}
+
+static	char	*tcrbits[] = {"LT", "GT", "EQ", "VS"};
+static	char	*fcrbits[] = {"GE", "LE", "NE", "VC"};
+
+typedef struct Opcode Opcode;
+
+struct Opcode {
+	uchar	op;
+	ushort	xo;
+	ushort	xomask;
+	char	*mnemonic;
+	void	(*f)(Opcode *, Instr *);
+	char	*ken;
+	int	flags;
+};
+
+static void format(char *, Instr *, char *);
+
+static void
+branch(Opcode *o, Instr *i)
+{
+	char buf[8];
+	int bo, bi;
+
+	bo = i->bo & ~1;	/* ignore prediction bit */
+	if(bo==4 || bo==12 || bo==20) {	/* simple forms */
+		if(bo != 20) {
+			bi = i->bi&3;
+			sprint(buf, "B%s%%L", bo==12? tcrbits[bi]: fcrbits[bi]);
+			format(buf, i, 0);
+			bprint(i, "\t");
+			if(i->bi > 4)
+				bprint(i, "CR(%d),", i->bi/4);
+		} else
+			format("BR%L\t", i, 0);
+		if(i->op == 16)
+			format(0, i, "%J");
+		else if(i->op == 19 && i->xo == 528)
+			format(0, i, "(CTR)");
+		else if(i->op == 19 && i->xo == 16)
+			format(0, i, "(LR)");
+	} else
+		format(o->mnemonic, i, o->ken);
+}
+
+static void
+addi(Opcode *o, Instr *i)
+{
+	if (i->op==14 && i->ra == 0)
+		format("MOVW", i, "%i,R%d");
+	else if(i->op==14 && i->simm < 0) {
+		bprint(i, "SUB\t$%d,R%d", -i->simm, i->ra);
+		if(i->rd != i->ra)
+			bprint(i, ",R%d", i->rd);
+	} else if(i->ra == i->rd) {
+		format(o->mnemonic, i, "%i");
+		bprint(i, ",R%d", i->rd);
+	} else
+		format(o->mnemonic, i, o->ken);
+}
+
+static void
+addis(Opcode *o, Instr *i)
+{
+	long v;
+
+	v = i->immediate;
+	if (i->op==15 && i->ra == 0)
+		bprint(i, "MOVW\t$%lux,R%d", v, i->rd);
+	else if(i->op==15 && v < 0) {
+		bprint(i, "SUB\t$%d,R%d", -v, i->ra);
+		if(i->rd != i->ra)
+			bprint(i, ",R%d", i->rd);
+	} else {
+		format(o->mnemonic, i, 0);
+		bprint(i, "\t$%ld,R%d", v, i->ra);
+		if(i->rd != i->ra)
+			bprint(i, ",R%d", i->rd);
+	}
+}
+
+static void
+andi(Opcode *o, Instr *i)
+{
+	if (i->ra == i->rs)
+		format(o->mnemonic, i, "%I,R%d");
+	else
+		format(o->mnemonic, i, o->ken);
+}
+
+static void
+gencc(Opcode *o, Instr *i)
+{
+	format(o->mnemonic, i, o->ken);
+}
+
+static void
+gen(Opcode *o, Instr *i)
+{
+	format(o->mnemonic, i, o->ken);
+	if (i->rc)
+		bprint(i, " [illegal Rc]");
+}
+
+static void
+ldx(Opcode *o, Instr *i)
+{
+	if(i->ra == 0)
+		format(o->mnemonic, i, "(R%b),R%d");
+	else
+		format(o->mnemonic, i, "(R%b+R%a),R%d");
+	if(i->rc)
+		bprint(i, " [illegal Rc]");
+}
+
+static void
+stx(Opcode *o, Instr *i)
+{
+	if(i->ra == 0)
+		format(o->mnemonic, i, "R%d,(R%b)");
+	else
+		format(o->mnemonic, i, "R%d,(R%b+R%a)");
+	if(i->rc && i->xo != 150)
+		bprint(i, " [illegal Rc]");
+}
+
+static void
+fldx(Opcode *o, Instr *i)
+{
+	if(i->ra == 0)
+		format(o->mnemonic, i, "(R%b),F%d");
+	else
+		format(o->mnemonic, i, "(R%b+R%a),F%d");
+	if(i->rc)
+		bprint(i, " [illegal Rc]");
+}
+
+static void
+fstx(Opcode *o, Instr *i)
+{
+	if(i->ra == 0)
+		format(o->mnemonic, i, "F%d,(R%b)");
+	else
+		format(o->mnemonic, i, "F%d,(R%b+R%a)");
+	if(i->rc)
+		bprint(i, " [illegal Rc]");
+}
+
+static void
+dcb(Opcode *o, Instr *i)
+{
+	if(i->ra == 0)
+		format(o->mnemonic, i, "(R%b)");
+	else
+		format(o->mnemonic, i, "(R%b+R%a)");
+	if(i->rd)
+		bprint(i, " [illegal Rd]");
+	if(i->rc)
+		bprint(i, " [illegal Rc]");
+}
+
+static void
+lw(Opcode *o, Instr *i, char r)
+{
+	bprint(i, "%s\t", o->mnemonic);
+	address(i);
+	bprint(i, ",%c%d", r, i->rd);
+}
+
+static void
+load(Opcode *o, Instr *i)
+{
+	lw(o, i, 'R');
+}
+
+static void
+fload(Opcode *o, Instr *i)
+{
+	lw(o, i, 'F');
+}
+
+static void
+sw(Opcode *o, Instr *i, char r)
+{
+	char *m;
+
+	m = o->mnemonic;
+	if (r == 'F')
+		format(m, i, "F%d,%l");
+	else
+		format(m, i, o->ken);
+}
+
+static void
+store(Opcode *o, Instr *i)
+{
+	sw(o, i, 'R');
+}
+
+static void
+fstore(Opcode *o, Instr *i)
+{
+	sw(o, i, 'F');
+}
+
+static void
+shifti(Opcode *o, Instr *i)
+{
+	if (i->ra == i->rs)
+		format(o->mnemonic, i, "$%k,R%a");
+	else
+		format(o->mnemonic, i, o->ken);
+}
+
+static void
+shift(Opcode *o, Instr *i)
+{
+	if (i->ra == i->rs)
+		format(o->mnemonic, i, "R%b,R%a");
+	else
+		format(o->mnemonic, i, o->ken);
+}
+
+static void
+add(Opcode *o, Instr *i)
+{
+	if (i->rd == i->ra)
+		format(o->mnemonic, i, "R%b,R%d");
+	else if (i->rd == i->rb)
+		format(o->mnemonic, i, "R%a,R%d");
+	else
+		format(o->mnemonic, i, o->ken);
+}
+
+static void
+sub(Opcode *o, Instr *i)
+{
+	format(o->mnemonic, i, 0);
+	bprint(i, "\t");
+	if(i->op == 31) {
+		bprint(i, "\tR%d,R%d", i->ra, i->rb);	/* subtract Ra from Rb */
+		if(i->rd != i->rb)
+			bprint(i, ",R%d", i->rd);
+	} else
+		bprint(i, "\tR%d,$%d,R%d", i->ra, i->simm, i->rd);
+}
+
+static void
+idiv(Opcode *o, Instr *i)
+{
+	format(o->mnemonic, i, 0);
+	if(i->op == 31)
+		bprint(i, "\tR%d,R%d", i->rb, i->ra);
+	else
+		bprint(i, "\t$%d,R%d", i->simm, i->ra);
+	if(i->ra != i->rd)
+		bprint(i, ",R%d", i->rd);
+}
+
+static void
+and(Opcode *o, Instr *i)
+{
+	if (i->op == 31) {
+		/* Rb,Rs,Ra */
+		if (i->ra == i->rs)
+			format(o->mnemonic, i, "R%b,R%a");
+		else if (i->ra == i->rb)
+			format(o->mnemonic, i, "R%s,R%a");
+		else
+			format(o->mnemonic, i, o->ken);
+	} else {
+		/* imm,Rs,Ra */
+		if (i->ra == i->rs)
+			format(o->mnemonic, i, "%I,R%a");
+		else
+			format(o->mnemonic, i, o->ken);
+	}
+}
+
+static void
+or(Opcode *o, Instr *i)
+{
+	if (i->op == 31) {
+		/* Rb,Rs,Ra */
+		if (i->rs == 0 && i->ra == 0 && i->rb == 0)
+			format("NOP", i, 0);
+		else if (i->rs == i->rb)
+			format("MOVW", i, "R%b,R%a");
+		else
+			and(o, i);
+	} else
+		and(o, i);
+}
+
+static void
+shifted(Opcode *o, Instr *i)
+{
+	format(o->mnemonic, i, 0);
+	bprint(i, "\t$%lux,", (ulong)i->uimm<<16);
+	if (i->rs == i->ra)
+		bprint(i, "R%d", i->ra);
+	else
+		bprint(i, "R%d,R%d", i->rs, i->ra);
+}
+
+static void
+neg(Opcode *o, Instr *i)
+{
+	if (i->rd == i->ra)
+		format(o->mnemonic, i, "R%d");
+	else
+		format(o->mnemonic, i, o->ken);
+}
+
+static	char	ir2[] = "R%a,R%d";		/* reverse of IBM order */
+static	char	ir3[] = "R%b,R%a,R%d";
+static	char	ir3r[] = "R%a,R%b,R%d";
+static	char	il3[] = "R%b,R%s,R%a";
+static	char	il2u[] = "%I,R%s,R%a";
+static	char	il3s[] = "$%k,R%s,R%a";
+static	char	il2[] = "R%s,R%a";
+static	char	icmp3[] = "R%a,R%b,%D";
+static	char	cr3op[] = "%b,%a,%d";
+static	char	ir2i[] = "%i,R%a,R%d";
+static	char	fp2[] = "F%b,F%d";
+static	char	fp3[] = "F%b,F%a,F%d";
+static	char	fp3c[] = "F%c,F%a,F%d";
+static	char	fp4[] = "F%a,F%c,F%b,F%d";
+static	char	fpcmp[] = "F%a,F%b,%D";
+static	char	ldop[] = "%l,R%d";
+static	char	stop[] = "R%d,%l";
+static	char	fldop[] = "%l,F%d";
+static	char	fstop[] = "F%d,%l";
+static	char	rlim[] = "R%b,R%s,$%z,R%a";
+static	char	rlimi[] = "$%k,R%s,$%z,R%a";
+
+#define	OEM	IBF(~0,22,30)
+#define	FP4	IBF(~0,26,30)
+#define	ALL	(~0)
+/*
+notes:
+	10-26: crfD = rD>>2; rD&3 mbz
+		also, L bit (bit 10) mbz or selects 64-bit operands
+*/
+
+static Opcode opcodes[] = {
+	{31,	266,	OEM,	"ADD%V%C",	add,	ir3},
+	{31,	 10,	OEM,	"ADDC%V%C",	add,	ir3},
+	{31,	138,	OEM,	"ADDE%V%C",	add,	ir3},
+	{14,	0,	0,	"ADD",		addi,	ir2i},
+	{12,	0,	0,	"ADDC",		addi,	ir2i},
+	{13,	0,	0,	"ADDCCC",	addi,	ir2i},
+	{15,	0,	0,	"ADD",		addis,	0},
+	{31,	234,	OEM,	"ADDME%V%C",	gencc,	ir2},
+	{31,	202,	OEM,	"ADDZE%V%C",	gencc,	ir2},
+
+	{31,	28,	ALL,	"AND%C",	and,	il3},
+	{31,	60,	ALL,	"ANDN%C",	and,	il3},
+	{28,	0,	0,	"ANDCC",		andi,	il2u},
+	{29,	0,	0,	"ANDCC",		shifted, 0},
+
+	{18,	0,	0,	"B%L",		gencc,	"%j"},
+	{16,	0,	0,	"BC%L",		branch,	"%d,%a,%J"},
+	{19,	528,	ALL,	"BC%L",		branch,	"%d,%a,(CTR)"},
+	{19,	16,	ALL,	"BC%L",		branch,	"%d,%a,(LR)"},
+
+	{31,	0,	ALL,	"CMP",		0,	icmp3},
+	{11,	0,	0,	"CMP",		0,	"R%a,%i,%D"},
+	{31,	32,	ALL,	"CMPU",		0,	icmp3},
+	{10,	0,	0,	"CMPU",		0,	"R%a,%I,%D"},
+
+	{31,	26,	ALL,	"CNTLZ%C",	gencc,	ir2},
+
+	{19,	257,	ALL,	"CRAND",	gen,	cr3op},
+	{19,	129,	ALL,	"CRANDN",	gen,	cr3op},
+	{19,	289,	ALL,	"CREQV",	gen,	cr3op},
+	{19,	225,	ALL,	"CRNAND",	gen,	cr3op},
+	{19,	33,	ALL,	"CRNOR",	gen,	cr3op},
+	{19,	449,	ALL,	"CROR",		gen,	cr3op},
+	{19,	417,	ALL,	"CRORN",	gen,	cr3op},
+	{19,	193,	ALL,	"CRXOR",	gen,	cr3op},
+
+	{31,	86,	ALL,	"DCBF",		dcb,	0},
+	{31,	470,	ALL,	"DCBI",		dcb,	0},
+	{31,	54,	ALL,	"DCBST",	dcb,	0},
+	{31,	278,	ALL,	"DCBT",		dcb,	0},
+	{31,	246,	ALL,	"DCBTST",	dcb,	0},
+	{31,	1014,	ALL,	"DCBZ",		dcb,	0},
+
+	{31,	491,	OEM,	"DIVW%V%C",	idiv,	ir3},
+	{31,	459,	OEM,	"DIVWU%V%C",	idiv,	ir3},
+
+	{31,	310,	ALL,	"ECIWX",	ldx,	0},
+	{31,	438,	ALL,	"ECOWX",	stx,	0},
+	{31,	854,	ALL,	"EIEIO",	gen,	0},
+
+	{31,	284,	ALL,	"EQV%C",	gencc,	il3},
+
+	{31,	954,	ALL,	"EXTSB%C",	gencc,	il2},
+	{31,	922,	ALL,	"EXTSH%C",	gencc,	il2},
+
+	{63,	264,	ALL,	"FABS%C",	gencc,	fp2},
+	{63,	21,	ALL,	"FADD%C",	gencc,	fp3},
+	{59,	21,	ALL,	"FADDS%C",	gencc,	fp3},
+	{63,	32,	ALL,	"FCMPO",	gen,	fpcmp},
+	{63,	0,	ALL,	"FCMPU",	gen,	fpcmp},
+	{63,	14,	ALL,	"FCTIW%C",	gencc,	fp2},
+	{63,	15,	ALL,	"FCTIWZ%C",	gencc,	fp2},
+	{63,	18,	ALL,	"FDIV%C",	gencc,	fp3},
+	{59,	18,	ALL,	"FDIVS%C",	gencc,	fp3},
+	{63,	29,	FP4,	"FMADD%C",	gencc,	fp4},
+	{59,	29,	FP4,	"FMADDS%C",	gencc,	fp4},
+	{63,	72,	ALL,	"FMOVD%C",	gencc,	fp2},
+	{63,	28,	FP4,	"FMSUB%C",	gencc,	fp4},
+	{59,	28,	FP4,	"FMSUBS%C",	gencc,	fp4},
+	{63,	25,	FP4,	"FMUL%C",	gencc,	fp3c},
+	{59,	25,	FP4,	"FMULS%C",	gencc,	fp3c},
+	{63,	136,	ALL,	"FNABS%C",	gencc,	fp2},
+	{63,	40,	ALL,	"FNEG%C",	gencc,	fp2},
+	{63,	31,	FP4,	"FNMADD%C",	gencc,	fp4},
+	{59,	31,	FP4,	"FNMADDS%C",	gencc,	fp4},
+	{63,	30,	FP4,	"FNMSUB%C",	gencc,	fp4},
+	{59,	30,	FP4,	"FNMSUBS%C",	gencc,	fp4},
+	{63,	12,	ALL,	"FRSP%C",	gencc,	fp2},
+	{63,	20,	FP4,	"FSUB%C",	gencc,	fp3},
+	{59,	20,	FP4,	"FSUBS%C",	gencc,	fp3},
+
+	{31,	982,	ALL,	"ICBI",		dcb,	0},
+	{19,	150,	ALL,	"ISYNC",	gen,	0},
+
+	{34,	0,	0,	"MOVBZ",	load,	ldop},
+	{35,	0,	0,	"MOVBZU",	load,	ldop},
+	{31,	119,	ALL,	"MOVBZU",	ldx,	0},
+	{31,	87,	ALL,	"MOVBZ",	ldx,	0},
+	{50,	0,	0,	"FMOVD",	fload,	fldop},
+	{51,	0,	0,	"FMOVDU",	fload,	fldop},
+	{31,	631,	ALL,	"FMOVDU",	fldx,	0},
+	{31,	599,	ALL,	"FMOVD",	fldx,	0},
+	{48,	0,	0,	"FMOVS",	load,	fldop},
+	{49,	0,	0,	"FMOVSU",	load,	fldop},
+	{31,	567,	ALL,	"FMOVSU",	fldx,	0},
+	{31,	535,	ALL,	"FMOVS",	fldx,	0},
+	{42,	0,	0,	"MOVH",		load,	ldop},
+	{43,	0,	0,	"MOVHU",	load,	ldop},
+	{31,	375,	ALL,	"MOVHU",	ldx,	0},
+	{31,	343,	ALL,	"MOVH",		ldx,	0},
+	{31,	790,	ALL,	"MOVHBR",	ldx,	0},
+	{40,	0,	0,	"MOVHZ",	load,	ldop},
+	{41,	0,	0,	"MOVHZU",	load,	ldop},
+	{31,	311,	ALL,	"MOVHZU",	ldx,	0},
+	{31,	279,	ALL,	"MOVHZ",	ldx,	0},
+	{46,	0,	0,	"MOVMW",		load,	ldop},
+	{31,	597,	ALL,	"LSW",		gen,	"(R%a),$%n,R%d"},
+	{31,	533,	ALL,	"LSW",		ldx,	0},
+	{31,	20,	ALL,	"LWAR",		ldx,	0},
+	{31,	534,	ALL,	"MOVWBR",		ldx,	0},
+	{32,	0,	0,	"MOVW",		load,	ldop},
+	{33,	0,	0,	"MOVWU",	load,	ldop},
+	{31,	55,	ALL,	"MOVWU",	ldx,	0},
+	{31,	23,	ALL,	"MOVW",		ldx,	0},
+
+	{19,	0,	ALL,	"MOVFL",	gen,	"%S,%D"},
+	{63,	64,	ALL,	"MOVCRFS",	gen,	"%S,%D"},
+	{31,	512,	ALL,	"MOVW",	gen,	"XER,%D"},
+	{31,	19,	ALL,	"MOVW",	gen,	"CR,R%d"},
+
+	{63,	583,	ALL,	"MOVW%C",	gen,	"FPSCR, F%d"},	/* mffs */
+	{31,	83,	ALL,	"MOVW",		gen,	"MSR,R%d"},
+	{31,	339,	ALL,	"MOVW",		gen,	"%P,R%d"},
+	{31,	595,	ALL,	"MOVW",		gen,	"SEG(%a),R%d"},
+	{31,	659,	ALL,	"MOVW",		gen,	"SEG(R%b),R%d"},
+	{31,	144,	ALL,	"MOVFL",	gen,	"R%s,%m,CR"},
+	{63,	70,	ALL,	"MTFSB0%C",	gencc,	"%D"},
+	{63,	38,	ALL,	"MTFSB1%C",	gencc,	"%D"},
+	{63,	711,	ALL,	"MOVFL%C",	gencc,	"F%b,%M,FPSCR"},	/* mtfsf */
+	{63,	134,	ALL,	"MOVFL%C",	gencc,	"%K,%D"},
+	{31,	146,	ALL,	"MOVW",		gen,	"R%s,MSR"},
+	{31,	467,	ALL,	"MOVW",		gen,	"R%s,%P"},
+	{31,	210,	ALL,	"MOVW",		gen,	"R%s,SEG(%a)"},
+	{31,	242,	ALL,	"MOVW",		gen,	"R%s,SEG(R%b)"},
+
+	{31,	235,	OEM,	"MULLW%V%C",	gencc,	ir3},
+	{7,	0,	0,	"MULLW",	idiv,	"%i,R%a,R%d"},
+
+	{31,	476,	ALL,	"NAND%C",	gencc,	il3},
+	{31,	104,	OEM,	"NEG%V%C",	neg,	ir2},
+	{31,	124,	ALL,	"NOR%C",	gencc,	il3},
+	{31,	444,	ALL,	"OR%C",	or,	il3},
+	{31,	412,	ALL,	"ORN%C",	or,	il3},
+	{24,	0,	0,	"OR",		and,	"%I,R%d,R%a"},
+	{25,	0,	0,	"OR",		shifted, 0},
+
+	{19,	50,	ALL,	"RFI",		gen,	0},
+
+	{20,	0,	0,	"RLWMI%C",	gencc,	rlimi},
+	{21,	0,	0,	"RLWNM%C",	gencc,	rlimi},
+	{23,	0,	0,	"RLWNM%C",	gencc,	rlim},
+
+	{17,	1,	ALL,	"SYSCALL",	gen,	0},
+
+	{31,	24,	ALL,	"SLW%C",	shift,	il3},
+
+	{31,	792,	ALL,	"SRAW%C",	shift,	il3},
+	{31,	824,	ALL,	"SRAW%C",	shifti,	il3s},
+
+	{31,	536,	ALL,	"SRW%C",	shift,	il3},
+
+	{38,	0,	0,	"MOVB",		store,	stop},
+	{39,	0,	0,	"MOVBU",	store,	stop},
+	{31,	247,	ALL,	"MOVBU",	stx,	0},
+	{31,	215,	ALL,	"MOVB",		stx,	0},
+	{54,	0,	0,	"FMOVD",	fstore,	fstop},
+	{55,	0,	0,	"FMOVDU",	fstore,	fstop},
+	{31,	759,	ALL,	"FMOVDU",	fstx,	0},
+	{31,	727,	ALL,	"FMOVD",	fstx,	0},
+	{52,	0,	0,	"FMOVS",	fstore,	fstop},
+	{53,	0,	0,	"FMOVSU",	fstore,	fstop},
+	{31,	695,	ALL,	"FMOVSU",	fstx,	0},
+	{31,	663,	ALL,	"FMOVS",	fstx,	0},
+	{44,	0,	0,	"MOVH",		store,	stop},
+	{31,	918,	ALL,	"MOVHBR",	stx,	0},
+	{45,	0,	0,	"MOVHU",	store,	stop},
+	{31,	439,	ALL,	"MOVHU",	stx,	0},
+	{31,	407,	ALL,	"MOVH",		stx,	0},
+	{47,	0,	0,	"MOVMW",		store,	stop},
+	{31,	725,	ALL,	"STSW",		gen,	"R%d,$%n,(R%a)"},
+	{31,	661,	ALL,	"STSW",		stx,	0},
+	{36,	0,	0,	"MOVW",		store,	stop},
+	{31,	662,	ALL,	"MOVWBR",	stx,	0},
+	{31,	150,	ALL,	"STWCCC",		stx,	0},
+	{37,	0,	0,	"MOVWU",	store,	stop},
+	{31,	183,	ALL,	"MOVWU",	stx,	0},
+	{31,	151,	ALL,	"MOVW",		stx,	0},
+
+	{31,	40,	OEM,	"SUB%V%C",	sub,	ir3},
+	{31,	8,	OEM,	"SUBC%V%C",	sub,	ir3},
+	{31,	136,	OEM,	"SUBE%V%C",	sub,	ir3},
+	{8,	0,	0,	"SUBC",		gen,	"R%a,%i,R%d"},
+	{31,	232,	OEM,	"SUBME%V%C",	sub,	ir2},
+	{31,	200,	OEM,	"SUBZE%V%C",	sub,	ir2},
+
+	{31,	598,	ALL,	"SYNC",		gen,	0},
+	{31,	306,	ALL,	"TLBIE",	gen,	"R%b"},
+	{31,	1010,	ALL,	"TLBLI",	gen,	"R%b"},
+	{31,	978,	ALL,	"TLBLD",	gen,	"R%b"},
+	{31,	4,	ALL,	"TW",		gen,	"%d,R%a,R%b"},
+	{3,	0,	0,	"TW",		gen,	"%d,R%a,%i"},
+
+	{31,	316,	ALL,	"XOR",		and,	il3},
+	{26,	0,	0,	"XOR",		and,	il2u},
+	{27,	0,	0,	"XOR",		shifted, 0},
+
+	{0},
+};
+
+typedef struct Spr Spr;
+struct Spr {
+	int	n;
+	char	*name;
+};
+
+static	Spr	sprname[] = {
+	{0, "MQ"},
+	{1, "XER"},
+	{268, "TBL"},
+	{269, "TBU"},
+	{8, "LR"},
+	{9, "CTR"},
+	{528, "IBAT0U"},
+	{529, "IBAT0L"},
+	{530, "IBAT1U"},
+	{531, "IBAT1L"},
+	{532, "IBAT2U"},
+	{533, "IBAT2L"},
+	{534, "IBAT3U"},
+	{535, "IBAT3L"},
+	{536, "DBAT0U"},
+	{537, "DBAT0L"},
+	{538, "DBAT1U"},
+	{539, "DBAT1L"},
+	{540, "DBAT2U"},
+	{541, "DBAT2L"},
+	{542, "DBAT3U"},
+	{543, "DBAT3L"},
+	{25, "SDR1"},
+	{19, "DAR"},
+	{272, "SPRG0"},
+	{273, "SPRG1"},
+	{274, "SPRG2"},
+	{275, "SPRG3"},
+	{18, "DSISR"},
+	{26, "SRR0"},
+	{27, "SRR1"},
+	{284, "TBLW"},
+	{285, "TBUW"},	
+	{22, "DEC"},
+	{282, "EAR"},
+	{1008, "HID0"},
+	{1009, "HID1"},
+	{976, "DMISS"},
+	{977, "DCMP"},
+	{978, "HASH1"},
+	{979, "HASH2"},
+	{980, "IMISS"},
+	{981, "ICMP"},
+	{982, "RPA"},
+	{1010, "IABR"},
+	{0,0},
+};
+
+static void
+format(char *mnemonic, Instr *i, char *f)
+{
+	int n, s;
+	ulong mask;
+
+	if (mnemonic)
+		format(0, i, mnemonic);
+	if (f == 0)
+		return;
+	if (mnemonic)
+		bprint(i, "\t");
+	for ( ; *f; f++) {
+		if (*f != '%') {
+			bprint(i, "%c", *f);
+			continue;
+		}
+		switch (*++f) {
+		case 'V':
+			if(i->oe)
+				bprint(i, "V");
+			break;
+
+		case 'C':
+			if(i->rc)
+				bprint(i, "CC");
+			break;
+
+		case 'a':
+			bprint(i, "%d", i->ra);
+			break;
+
+		case 'b':
+			bprint(i, "%d", i->rb);
+			break;
+
+		case 'c':
+			bprint(i, "%d", i->frc);
+			break;
+
+		case 'd':
+		case 's':
+			bprint(i, "%d", i->rd);
+			break;
+
+		case 'S':
+			if(i->ra & 3)
+				bprint(i, "CR(INVAL:%d)", i->ra);
+			else if(i->op == 63)
+				bprint(i, "FPSCR(%d)", i->crfs);
+			else
+				bprint(i, "CR(%d)", i->crfs);
+			break;
+
+		case 'D':
+			if(i->rd & 3)
+				bprint(i, "CR(INVAL:%d)", i->rd);
+			else if(i->op == 63)
+				bprint(i, "FPSCR(%d)", i->crfd);
+			else
+				bprint(i, "CR(%d)", i->crfd);
+			break;
+
+		case 'l':
+			if(i->simm < 0)
+				bprint(i, "-%lx(R%d)", -i->simm, i->ra);
+			else
+				bprint(i, "%lx(R%d)", i->simm, i->ra);
+			break;
+
+		case 'i':
+			bprint(i, "$%ld", i->simm);
+			break;
+
+		case 'I':
+			bprint(i, "$%lx", i->uimm);
+			break;
+
+		case 'w':
+			bprint(i, "[%lux]", i->w0);
+			break;
+
+		case 'P':
+			n = ((i->spr&0x1f)<<5)|((i->spr>>5)&0x1f);
+			for(s=0; sprname[s].name; s++)
+				if(sprname[s].n == n)
+					break;
+			if(sprname[s].name) {
+				if(n < 10)
+					bprint(i, sprname[s].name);
+				else
+					bprint(i, "SPR(%s)", sprname[s].name);
+			} else
+				bprint(i, "SPR(%d)", n);
+			break;
+
+		case 'n':
+			bprint(i, "%d", i->nb==0? 32: i->nb);	/* eg, pg 10-103 */
+			break;
+
+		case 'm':
+			bprint(i, "%lx", i->crm);
+			break;
+
+		case 'M':
+			bprint(i, "%lx", i->fm);
+			break;
+
+		case 'z':
+			if(i->mb <= i->me)
+				mask = ((ulong)~0L>>i->mb) & (~0L<<(31-i->me));
+			else
+				mask = ~(((ulong)~0L>>(i->me+1)) & (~0L<<(31-(i->mb-1))));
+			bprint(i, "%lux", mask);
+			break;
+
+		case 'k':
+			bprint(i, "%d", i->sh);
+			break;
+
+		case 'K':
+			bprint(i, "$%x", i->imm);
+			break;
+
+		case 'L':
+			if(i->lk)
+				bprint(i, "L");
+			break;
+
+		case 'j':
+			if(i->aa)
+				pglobal(i, i->li, "(ABS)");
+			else
+				pglobal(i, i->addr+i->li, "(REL)");
+			break;
+
+		case 'J':
+			if(i->aa)
+				pglobal(i, i->bd, "(ABS)");
+			else
+				pglobal(i, i->addr+i->bd, "(REL)");
+			break;
+
+		case '\0':
+			bprint(i, "%%");
+			return;
+
+		default:
+			bprint(i, "%%%c", *f);
+			break;
+		}
+	}
+}
+
+int
+das(ulong *pc)
+{
+	Instr i;
+	Opcode *o;
+	char buf[100];
+	int r;
+
+	memset(&i, 0, sizeof(i));
+	i.curr = buf;
+	i.end = buf+sizeof(buf)-1;
+	r = mkinstr(pc, &i);
+	i.curr += sprint(i.curr, "	%.8lux %.8lux ", (ulong)pc, i.w0);
+	if(r >= 0){
+		if(i.size == 2)
+			i.curr += sprint(i.curr, "%.8lux ", i.w1);
+		for(o = opcodes; o->mnemonic != 0; o++)
+			if(i.op == o->op && (i.xo & o->xomask) == o->xo) {
+				if (o->f)
+					(*o->f)(o, &i);
+				else
+					format(o->mnemonic, &i, o->ken);
+				print("%s\n", buf);
+				return i.size;
+			}
+	}
+	strcpy(i.curr, "ILLEGAL");
+	print("%s\n", buf);
+	return i.size;
+}
--- /dev/null
+++ b/libinterp/das-sparc.c
@@ -1,0 +1,833 @@
+#include <lib9.h>
+
+	/* Sparc disassembler and related functions */
+
+typedef struct instr Instr;
+
+struct opcode
+{
+	char	*mnemonic;
+	void	(*f)(Instr*, char*);
+	int	flag;
+};
+
+static	char FRAMENAME[] = ".frame";
+
+
+struct instr
+{
+	uchar	op;		/* bits 31-30 */
+	uchar	rd;		/* bits 29-25 */
+	uchar	op2;		/* bits 24-22 */
+	uchar	a;		/* bit  29    */
+	uchar	cond;		/* bits 28-25 */
+	uchar	op3;		/* bits 24-19 */
+	uchar	rs1;		/* bits 18-14 */
+	uchar	i;		/* bit  13    */
+	uchar	asi;		/* bits 12-05 */
+	uchar	rs2;		/* bits 04-00 */
+	short	simm13;		/* bits 12-00, signed */
+	ushort	opf;		/* bits 13-05 */
+	ulong	immdisp22;	/* bits 21-00 */
+	ulong	simmdisp22;	/* bits 21-00, signed */
+	ulong	disp30;		/* bits 30-00 */
+	ulong	imm32;		/* SETHI+ADD constant */
+	int	target;		/* SETHI+ADD dest reg */
+	long	w0;
+	long	w1;
+	ulong	addr;		/* pc of instruction */
+	char*	curr;		/* current fill level in output buffer */
+	char*	end;		/* end of buffer */
+	int 	size;		/* number of longs in instr */
+	char*	err;		/* errmsg */
+};
+
+static	int	dascase;
+
+static int	mkinstr(ulong*, Instr*);
+static void	bra1(Instr*, char*, char*[]);
+static void	bra(Instr*, char*);
+static void	fbra(Instr*, char*);
+static void	cbra(Instr*, char*);
+static void	unimp(Instr*, char*);
+static void	fpop(Instr*, char*);
+static void	shift(Instr*, char*);
+static void	sethi(Instr*, char*);
+static void	load(Instr*, char*);
+static void	loada(Instr*, char*);
+static void	store(Instr*, char*);
+static void	storea(Instr*, char*);
+static void	add(Instr*, char*);
+static void	cmp(Instr*, char*);
+static void	wr(Instr*, char*);
+static void	jmpl(Instr*, char*);
+static void	rd(Instr*, char*);
+static void	loadf(Instr*, char*);
+static void	storef(Instr*, char*);
+static void	loadc(Instr*, char*);
+static void	loadcsr(Instr*, char*);
+static void	trap(Instr*, char*);
+
+static struct opcode sparcop0[8] = {
+	/* [0] */	"UNIMP",	unimp,	0,	/* page 137 */
+		0,		0,	0,
+	/* [2] */	"B",		bra,	0,	/* page 119 */
+		0,		0,	0,
+	/* [4] */	"SETHI",	sethi,	0,	/* page 104 */
+		0,		0,	0,
+	/* [6] */	"FB",		fbra,	0,	/* page 121 */
+	/* [7] */	"CB",		cbra,	0,	/* page 123 */
+};
+
+static struct opcode sparcop2[64] = {
+	/* [0x00] */	"ADD",		add,	0,	/* page 108 */
+	/* [0x01] */	"AND",		add,	0,	/* page 106 */
+	/* [0x02] */	"OR",		add,	0,
+	/* [0x03] */	"XOR",		add,	0,
+	/* [0x04] */	"SUB",		add,	0,	/* page 110 */
+	/* [0x05] */	"ANDN",		add,	0,
+	/* [0x06] */	"ORN",		add,	0,
+	/* [0x07] */	"XORN",		add,	0,
+	/* [0x08] */	"ADDX",		add,	0,
+			0,		0,	0,
+	/* [0x0A] */	"UMUL",		add,	0,	/* page 113 */
+	/* [0x0B] */	"SMUL",		add,	0,
+	/* [0x0C] */	"SUBX",		add,	0,
+			0,		0,	0,
+	/* [0x0E] */	"UDIV",		add,	0,	/* page 115 */
+	/* [0x0F] */	"SDIV",		add,	0,
+	/* [0x10] */	"ADDCC",	add,	0,
+	/* [0x11] */	"ANDCC",	add,	0,
+	/* [0x12] */	"ORCC",		add,	0,
+	/* [0x13] */	"XORCC",	add,	0,
+	/* [0x14] */	"SUBCC",	cmp,	0,
+	/* [0x15] */	"ANDNCC",	add,	0,
+	/* [0x16] */	"ORNCC",	add,	0,
+	/* [0x17] */	"XORNCC",	add,	0,
+	/* [0x18] */	"ADDXCC",	add,	0,
+			0,		0,	0,
+	/* [0x1A] */	"UMULCC",	add,	0,
+	/* [0x1B] */	"SMULCC",	add,	0,
+	/* [0x1C] */	"SUBXCC",	add,	0,
+			0,		0,	0,
+	/* [0x1E] */	"UDIVCC",	add,	0,
+	/* [0x1F] */	"SDIVCC",	add,	0,
+	/* [0x20] */	"TADD",		add,	0,	/* page 109 */
+	/* [0x21] */	"TSUB",		add,	0,	/* page 111 */
+	/* [0x22] */	"TADDCCTV",	add,	0,
+	/* [0x23] */	"TSUBCCTV",	add,	0,
+	/* [0x24] */	"MULSCC",	add,	0,	/* page 112 */
+	/* [0x25] */	"SLL",		shift,	0,	/* page 107 */
+	/* [0x26] */	"SRL",		shift,	0,
+	/* [0x27] */	"SRA",		shift,	0,
+	/* [0x28] */	"rdy",		rd,	0,	/* page 131 */
+	/* [0x29] */	"rdpsr",	rd,	0,
+	/* [0x2A] */	"rdwim",	rd,	0,
+	/* [0x2B] */	"rdtbr",	rd,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+	/* [0x30] */	"wry",		wr,	0,	/* page 133 */
+	/* [0x31] */	"wrpsr",	wr,	0,
+	/* [0x32] */	"wrwim",	wr,	0,
+	/* [0x33] */	"wrtbr",	wr,	0,
+	/* [0x34] */	"FPOP",		fpop,	0,	/* page 140 */
+	/* [0x35] */	"FPOP",		fpop,	0,
+			0,		0,	0,
+			0,		0,	0,
+	/* [0x38] */	"JMPL",		jmpl,	0,	/* page 126 */
+	/* [0x39] */	"RETT",		add,	0,	/* page 127 */
+	/* [0x3A] */	"T",		trap,	0,	/* page 129 */
+	/* [0x3B] */	"flush",	add,	0,	/* page 138 */
+	/* [0x3C] */	"SAVE",		add,	0,	/* page 117 */
+	/* [0x3D] */	"RESTORE",	add,	0,
+};
+
+static struct opcode sparcop3[64]={
+	/* [0x00] */	"ld",		load,	0,
+	/* [0x01] */	"ldub",		load,	0,
+	/* [0x02] */	"lduh",		load,	0,
+	/* [0x03] */	"ldd",		load,	0,
+	/* [0x04] */	"st",		store,	0,
+	/* [0x05] */	"stb",		store,	0,	/* page 95 */
+	/* [0x06] */	"sth",		store,	0,
+	/* [0x07] */	"std",		store,	0,
+			0,		0,	0,
+	/* [0x09] */	"ldsb",		load,	0,	/* page 90 */
+	/* [0x0A] */	"ldsh",		load,	0,
+			0,		0,	0,
+			0,		0,	0,
+	/* [0x0D] */	"ldstub",	store,	0,	/* page 101 */
+			0,		0,	0,
+	/* [0x0F] */	"swap",		load,	0,	/* page 102 */
+	/* [0x10] */	"lda",		loada,	0,
+	/* [0x11] */	"lduba",	loada,	0,
+	/* [0x12] */	"lduha",	loada,	0,
+	/* [0x13] */	"ldda",		loada,	0,
+	/* [0x14] */	"sta",		storea,	0,
+	/* [0x15] */	"stba",		storea,	0,
+	/* [0x16] */	"stha",		storea,	0,
+	/* [0x17] */	"stda",		storea,	0,
+			0,		0,	0,
+	/* [0x19] */	"ldsba",	loada,	0,
+	/* [0x1A] */	"ldsha",	loada,	0,
+			0,		0,	0,
+			0,		0,	0,
+	/* [0x1D] */	"ldstuba",	storea,	0,
+			0,		0,	0,
+	/* [0x1F] */	"swapa",	loada,	0,
+	/* [0x20] */	"ldf",		loadf,	0,	/* page 92 */
+	/* [0x21] */	"ldfsr",	loadf,	0,
+			0,		0,	0,
+	/* [0x23] */	"lddf",		loadf,	0,
+	/* [0x24] */	"stf",		storef,	0,	/* page 97 */
+	/* [0x25] */	"stfsr",	storef,	0,
+	/* [0x26] */	"stdfq",	storef,	0,
+	/* [0x27] */	"stdf",		storef,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+			0,		0,	0,
+	/* [0x30] */	"ldc",		loadc,	0,	/* page 94 */
+	/* [0x31] */	"ldcsr",	loadcsr,0,
+			0,		0,	0,
+	/* [0x33] */	"lddc",		loadc,	0,
+	/* [0x34] */	"stc",		loadc,	0,	/* page 99 */
+	/* [0x35] */	"stcsr",	loadcsr,0,
+	/* [0x36] */	"stdcq",	loadcsr,0,
+	/* [0x37] */	"stdc",		loadc,	0,
+};
+
+static void
+bprint(Instr *i, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	i->curr = vseprint(i->curr, i->end, fmt, arg);
+	va_end(arg);
+}
+
+static int
+decode(ulong *pc, Instr *i)
+{
+	ulong w;
+
+	w = *pc;
+
+	i->op = (w >> 30) & 0x03;
+	i->rd = (w >> 25) & 0x1F;
+	i->op2 = (w >> 22) & 0x07;
+	i->a = (w >> 29) & 0x01;
+	i->cond = (w >> 25) & 0x0F;
+	i->op3 = (w >> 19) & 0x3F;
+	i->rs1 = (w >> 14) & 0x1F;
+	i->i = (w >> 13) & 0x01;
+	i->asi = (w >> 5) & 0xFF;
+	i->rs2 = (w >> 0) & 0x1F;
+	i->simm13 = (w >> 0) & 0x1FFF;
+	if(i->simm13 & (1<<12))
+		i->simm13 |= ~((1<<13)-1);
+	i->opf = (w >> 5) & 0x1FF;
+	i->immdisp22 = (w >> 0) & 0x3FFFFF;
+	i->simmdisp22 = i->immdisp22;
+	if(i->simmdisp22 & (1<<21))
+		i->simmdisp22 |= ~((1<<22)-1);
+	i->disp30 = (w >> 0) & 0x3FFFFFFF;
+	i->w0 = w;
+	i->target = -1;
+	i->addr = (ulong)pc;
+	i->size = 1;
+	return 1;
+}
+
+static int
+mkinstr(ulong *pc, Instr *i)
+{
+	Instr xi;
+
+	if (decode(pc, i) < 0)
+		return -1;
+	if(i->op==0 && i->op2==4 && !dascase){		/* SETHI */
+		if(decode(pc+1, &xi) < 0)
+			return -1;
+		if(xi.op == 2 && xi.op3 == 0)		/* ADD */
+		if(xi.i == 1 && xi.rs1 == i->rd){	/* immediate to same reg */
+			i->imm32 = xi.simm13 + (i->immdisp22<<10);
+			i->target = xi.rd;
+			i->w1 = xi.w0;
+			i->size++;
+			return 1;
+		}
+	}
+	if(i->op==2 && i->opf==1 && !dascase){		/* FMOVS */
+		if (decode(pc+1, &xi) < 0)
+			return -1;
+		if(i->op==2 && i->opf==1)		/* FMOVS */
+		if(xi.rd==i->rd+1 && xi.rs2==i->rs2+1){	/* next pair */
+			i->w1 = xi.w0;
+			i->size++;
+		}
+	}
+	return 1;
+}
+
+static int
+inst(ulong *pc)
+{
+	long disp;
+	Instr instr;
+	static char buf[128];
+	void (*f)(Instr*, char*);
+
+	memset(&instr, 0, sizeof(instr));
+	instr.curr = buf;
+	instr.end = buf+sizeof(buf)-1;
+	if(mkinstr(pc, &instr) < 0)
+		return 4;
+	switch(instr.op){
+	case 0:
+		f = sparcop0[instr.op2].f;
+		if(f)
+			(*f)(&instr, sparcop0[instr.op2].mnemonic);
+		else
+			bprint(&instr, "unknown 0x%lux", instr.w0);
+		break;
+
+	case 1:
+		disp = instr.disp30;
+		disp = (disp<<2)>>2;
+		bprint(&instr, "CALL\t0x%lux", pc+disp);
+		if (!dascase)
+			bprint(&instr, "(SB)");
+		break;
+
+	case 2:
+		f = sparcop2[instr.op3].f;
+		if(f)
+			(*f)(&instr, sparcop2[instr.op3].mnemonic);
+		else
+			bprint(&instr, "unknown 0x%lux", instr.w0);
+		break;
+
+	case 3:
+		f = sparcop3[instr.op3].f;
+		if(f)
+			(*f)(&instr, sparcop3[instr.op3].mnemonic);
+		else
+			bprint(&instr, "unknown 0x%lux", instr.w0);
+		break;
+	}
+	if (instr.err) {
+		if (instr.curr != buf)
+			bprint(&instr, "\t\t;");
+		bprint(&instr, instr.err);
+	}
+	print("\t%.8lux %s\n", (ulong)pc, buf);
+
+	return instr.size;
+}
+
+void
+das(ulong *pc, int n)
+{
+	ulong *e;
+
+	e = pc + n;
+	while(pc < e)
+		pc += inst(pc);
+}
+
+static void
+address(Instr *i)
+{
+	bprint(i, "0x%lux(R%d)", i->simm13, i->rs1);
+}
+
+static void
+unimp(Instr *i, char *m)
+{
+	bprint(i, "%s", m);
+}
+
+static char	*bratab[16] = {	/* page 91 */
+	/* [0x0] */	"N",
+	/* [0x1] */	"E",
+	/* [0x2] */	"LE",
+	/* [0x3] */	"L",
+	/* [0x4] */	"LEU",
+	/* [0x5] */	"CS",
+	/* [0x6] */	"NEG",
+	/* [0x7] */	"VS",
+	/* [0x8] */	"A",
+	/* [0x9] */	"NE",
+	/* [0xA] */	"G",
+	/* [0xB] */	"GE",
+	/* [0xC] */	"GU",
+	/* [0xD] */	"CC",
+	/* [0xE] */	"POS",
+	/* [0xF] */	"VC",
+};
+
+static char	*fbratab[16] = {	/* page 91 */
+	/* [0x0] */	"N",
+	/* [0x1] */	"NE",
+	/* [0x2] */	"LG",
+	/* [0x3] */	"UL",
+	/* [0x4] */	"L",
+	/* [0x5] */	"UG",
+	/* [0x6] */	"G",
+	/* [0x7] */	"U",
+	/* [0x8] */	"A",
+	/* [0x9] */	"E",
+	/* [0xA] */	"UE",
+	/* [0xB] */	"GE",
+	/* [0xC] */	"UGE",
+	/* [0xD] */	"LE",
+	/* [0xE] */	"ULE",
+	/* [0xF] */	"O",
+};
+
+static char	*cbratab[16] = {	/* page 91 */
+	/* [0x0] */	"N",
+	/* [0x1] */	"123",
+	/* [0x2] */	"12",
+	/* [0x3] */	"13",
+	/* [0x4] */	"1",
+	/* [0x5] */	"23",
+	/* [0x6] */	"2",
+	/* [0x7] */	"3",
+	/* [0x8] */	"A",
+	/* [0x9] */	"0",
+	/* [0xA] */	"03",
+	/* [0xB] */	"02",
+	/* [0xC] */	"023",
+	/* [0xD] */	"01",
+	/* [0xE] */	"013",
+	/* [0xF] */	"012",
+};
+
+static void
+bra1(Instr *i, char *m, char *tab[])
+{
+	long imm;
+
+	imm = i->simmdisp22;
+	if(i->a)
+		bprint(i, "%s%s.%c\t", m, tab[i->cond], 'A'+dascase);
+	else
+		bprint(i, "%s%s\t", m, tab[i->cond]);
+	bprint(i, "0x%lux", i->addr+4*imm);
+	if (!dascase)
+		bprint(i, "(SB)");
+}
+
+static void
+bra(Instr *i, char *m)			/* page 91 */
+{
+	bra1(i, m, bratab);
+}
+
+static void
+fbra(Instr *i, char *m)			/* page 93 */
+{
+	bra1(i, m, fbratab);
+}
+
+static void
+cbra(Instr *i, char *m)			/* page 95 */
+{
+	bra1(i, m, cbratab);
+}
+
+static void
+trap(Instr *i, char *m)			/* page 101 */
+{
+	if(i->i == 0)
+		bprint(i, "%s%s\tR%d+R%d", m, bratab[i->cond], i->rs2, i->rs1);
+	else
+		bprint(i, "%s%s\t$0x%lux+R%d", m, bratab[i->cond], i->simm13, i->rs1);
+}
+
+static void
+sethi(Instr *i, char *m)		/* page 89 */
+{
+	ulong imm;
+
+	imm = i->immdisp22<<10;
+	if(dascase){
+		bprint(i, "%s\t0x%lux, R%d", m, imm, i->rd);
+		return;
+	}
+	if(imm==0 && i->rd==0){
+		bprint(i, "NOP");
+		return;
+	}
+	if(i->target < 0){
+		bprint(i, "MOVW\t$0x%lux, R%d", imm, i->rd);
+		return;
+	}
+	bprint(i, "MOVW\t$0x%lux, R%d", i->imm32, i->target);
+}
+
+static char ldtab[] = {
+	'W',
+	'B',
+	'H',
+	'D',
+};
+
+static char*
+moveinstr(int op3, char *m)
+{
+	char *s;
+	int c;
+	static char buf[8];
+
+	if(!dascase){
+		/* batshit cases */
+		if(op3 == 0xF || op3 == 0x1F)
+			return "SWAP";
+		if(op3 == 0xD || op3 == 0x1D)
+			return "TAS";	/* really LDSTUB */
+		c = ldtab[op3&3];
+		s = "";
+		if((op3&11)==1 || (op3&11)==2)
+			s="U";
+		sprint(buf, "MOV%c%s", c, s);
+		return buf;
+	}
+	return m;
+}
+
+static void
+load(Instr *i, char *m)			/* page 68 */
+{
+	m = moveinstr(i->op3, m);
+	if(i->i == 0)
+		bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs1, i->rs2, i->rd);
+	else{
+		bprint(i, "%s\t", m);
+		address(i);
+		bprint(i, ", R%d", i->rd);
+	}
+}
+
+static void
+loada(Instr *i, char *m)		/* page 68 */
+{
+	m = moveinstr(i->op3, m);
+	if(i->i == 0)
+		bprint(i, "%s\t(R%d+R%d, %d), R%d", m, i->rs1, i->rs2, i->asi, i->rd);
+	else
+		bprint(i, "unknown ld asi 0x%lux", i->w0);
+}
+
+static void
+store(Instr *i, char *m)		/* page 74 */
+{
+	m = moveinstr(i->op3, m);
+	if(i->i == 0)
+		bprint(i, "%s\tR%d, (R%d+R%d)",
+				m, i->rd, i->rs1, i->rs2);
+	else{
+		bprint(i, "%s\tR%d, ", m, i->rd);
+		address(i);
+	}
+}
+
+static void
+storea(Instr *i, char *m)		/* page 74 */
+{
+	m = moveinstr(i->op3, m);
+	if(i->i == 0)
+		bprint(i, "%s\tR%d, (R%d+R%d, %d)", m, i->rd, i->rs1, i->rs2, i->asi);
+	else
+		bprint(i, "%s\tR%d, %d(R%d, %d), ???", m, i->rd, i->simm13, i->rs1, i->asi);
+}
+
+static void
+shift(Instr *i, char *m)	/* page 88 */
+{
+	if(i->i == 0){
+		if(i->rs1 == i->rd)
+			if(dascase)
+				bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+			else
+				bprint(i, "%s\tR%d, R%d", m, i->rs2, i->rs1);
+		else
+			if(dascase)
+				bprint(i, "%s\tR%d, R%d, R%d", m, i->rs1, i->rs2, i->rd);
+			else
+				bprint(i, "%s\tR%d, R%d, R%d", m, i->rs2, i->rs1, i->rd);
+	}else{
+		if(i->rs1 == i->rd)
+			if(dascase)
+				bprint(i, "%s\t$%d,R%d", m, i->simm13&0x1F, i->rs1);
+			else
+				bprint(i, "%s\tR%d, $%d", m,  i->rs1, i->simm13&0x1F);
+		else
+			if(dascase)
+				bprint(i, "%s\tR%d, $%d, R%d",m,i->rs1,i->simm13&0x1F,i->rd);
+			else
+				bprint(i, "%s\t$%d, R%d, R%d",m,i->simm13&0x1F,i->rs1,i->rd);
+	}
+}
+
+static void
+add(Instr *i, char *m)	/* page 82 */
+{
+	if(i->i == 0){
+		if(dascase)
+			bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+		else
+			if(i->op3==2 && i->rs1==0 && i->rd)  /* OR R2, R0, R1 */
+				bprint(i, "MOVW\tR%d", i->rs2);
+			else
+				bprint(i, "%s\tR%d, R%d", m, i->rs2, i->rs1);
+	}else{
+		if(dascase)
+			bprint(i, "%s\tR%d, $0x%lux", m, i->rs1, i->simm13);
+		else
+			if(i->op3==0 && i->rd && i->rs1==0)	/* ADD $x, R0, R1 */
+				bprint(i, "MOVW\t$0x%lux", i->simm13);
+			else if(i->op3==0 && i->rd && i->rs1==2){
+				/* ADD $x, R2, R1 -> MOVW $x(SB), R1 */
+				bprint(i, "MOVW\t$");
+				address(i);
+			} else
+				bprint(i, "%s\t$0x%lux, R%d", m, i->simm13, i->rs1);
+	}
+	if(i->rs1 != i->rd)
+		bprint(i, ", R%d", i->rd);
+}
+
+static void
+cmp(Instr *i, char *m)
+{
+	if(dascase || i->rd){
+		add(i, m);
+		return;
+	}
+	if(i->i == 0)
+		bprint(i, "CMP\tR%d, R%d", i->rs1, i->rs2);
+	else
+		bprint(i, "CMP\tR%d, $0x%lux", i->rs1, i->simm13);
+}
+
+static char *regtab[4] =
+{
+	"Y",
+	"PSR",
+	"WIM",
+	"TBR",
+};
+
+static void
+wr(Instr *i, char *m)		/* page 82 */
+{
+	if(dascase){
+		if(i->i == 0)
+			bprint(i, "%s\tR%d, R%d", m, i->rs1, i->rs2);
+		else
+			bprint(i, "%s\tR%d, $0x%lux", m, i->rs1, i->simm13);
+	}else{
+		if(i->i && i->simm13==0)
+			bprint(i, "MOVW\tR%d", i->rs1);
+		else if(i->i == 0)
+			bprint(i, "wr\tR%d, R%d", i->rs2, i->rs1);
+		else
+			bprint(i, "wr\t$0x%lux, R%d", i->simm13, i->rs1);
+	}
+	bprint(i, ", %s", regtab[i->op3&3]);
+}
+
+static void
+rd(Instr *i, char *m)		/* page 103 */
+{
+	if(i->rs1==15 && i->rd==0){
+		m = "stbar";
+		if(!dascase)
+			m = "STBAR";
+		bprint(i, "%s", m);
+	}else{
+		if(!dascase)
+			m = "MOVW";
+		bprint(i, "%s\t%s, R%d", m, regtab[i->op3&3], i->rd);
+	}
+}
+
+static void
+jmpl(Instr *i, char *m)		/* page 82 */
+{
+	if(i->i == 0){
+		if(i->rd == 15)
+			bprint(i, "CALL\t(R%d+R%d)", i->rs2, i->rs1);
+		else
+			bprint(i, "%s\t(R%d+R%d), R%d", m, i->rs2, i->rs1, i->rd);
+	}else{
+		if(!dascase && i->simm13==8 && i->rs1==15 && i->rd==0)
+			bprint(i, "RETURN");
+		else{
+			bprint(i, "%s\t", m);
+			address(i);
+			bprint(i, ", R%d", i->rd);
+		}
+	}
+}
+
+static void
+loadf(Instr *i, char *m)		/* page 70 */
+{
+	if(!dascase){
+		m = "FMOVD";
+		if(i->op3 == 0x20)
+			m = "FMOVF";
+		else if(i->op3 == 0x21)
+			m = "MOVW";
+	}
+	if(i->i == 0)
+		bprint(i, "%s\t(R%d+R%d)", m, i->rs1, i->rs2);
+	else{
+		bprint(i, "%s\t", m);
+		address(i);
+	}
+	if(i->op3 == 0x21)
+		bprint(i, ", FSR");
+	else
+		bprint(i, ", R%d", i->rd);
+}
+
+static
+void storef(Instr *i, char *m)		/* page 70 */
+{
+	if(!dascase){
+		m = "FMOVD";
+		if(i->op3 == 0x25 || i->op3 == 0x26)
+			m = "MOVW";
+		else if(i->op3 == 0x24)
+			m = "FMOVF";
+	}
+	bprint(i, "%s\t", m);
+	if(i->op3 == 0x25)
+		bprint(i, "FSR, ");
+	else if(i->op3 == 0x26)
+		bprint(i, "FQ, ");
+	else
+		bprint(i, "R%d, ", i->rd);
+	if(i->i == 0)
+		bprint(i, "(R%d+R%d)", i->rs1, i->rs2);
+	else
+		address(i);
+}
+
+static
+void loadc(Instr *i, char *m)			/* page 72 */
+{
+	if(i->i == 0)
+		bprint(i, "%s\t(R%d+R%d), C%d", m, i->rs1, i->rs2, i->rd);
+	else{
+		bprint(i, "%s\t", m);
+		address(i);
+		bprint(i, ", C%d", i->rd);
+	}
+}
+
+static
+void loadcsr(Instr *i, char *m)			/* page 72 */
+{
+	if(i->i == 0)
+		bprint(i, "%s\t(R%d+R%d), CSR", m, i->rs1, i->rs2);
+	else{
+		bprint(i, "%s\t", m);
+		address(i);
+		bprint(i, ", CSR");
+	}
+}
+
+static struct
+{
+	int	opf;
+	char	*name;
+} fptab1[] = {			/* ignores rs1 */
+	0xC4,	"FITOS",	/* page 109 */
+	0xC8,	"FITOD",
+	0xCC,	"FITOX",
+
+	0xD1,	"FSTOI",	/* page 110 */
+	0xD2,	"FDTOI",
+	0xD3,	"FXTOI",
+
+	0xC9,	"FSTOD",	/* page 111 */
+	0xCD,	"FSTOX",
+	0xC6,	"FDTOS",
+	0xCE,	"FDTOX",
+	0xC7,	"FXTOS",
+	0xCB,	"FXTOD",
+
+	0x01,	"FMOVS",	/* page 112 */
+	0x05,	"FNEGS",
+	0x09,	"FABSS",
+
+	0x29,	"FSQRTS", 	/* page 113 */
+	0x2A,	"FSQRTD",
+	0x2B,	"FSQRTX",
+
+	0,	0,
+};
+
+static struct{
+	int	opf;
+	char	*name;
+} fptab2[] = {			/* uses rs1 */
+
+	0x41,	"FADDS",	/* page 114 */
+	0x42,	"FADDD",
+	0x43,	"FADDX",
+	0x45,	"FSUBS",
+	0x46,	"FSUBD",
+	0x47,	"FSUBX",
+
+	0x49,	"FMULS",	/* page 115 */
+	0x4A,	"FMULD",
+	0x4B,	"FMULX",
+	0x4D,	"FDIVS",
+	0x4E,	"FDIVD",
+	0x4F,	"FDIVX",
+
+	0x51,	"FCMPS",	/* page 116 */
+	0x52,	"FCMPD",
+	0x53,	"FCMPX",
+	0x55,	"FCMPES",
+	0x56,	"FCMPED",
+	0x57,	"FCMPEX",
+
+	0, 0
+};
+
+static void
+fpop(Instr *i, char *m)	/* page 108-116 */
+{
+	int j;
+
+	if(dascase==0 && i->size==2){
+		bprint(i, "FMOVD\tF%d, F%d", i->rs2, i->rd);
+		return;
+	}
+	for(j=0; fptab1[j].name; j++)
+		if(fptab1[j].opf == i->opf){
+			bprint(i, "%s\tF%d, F%d", fptab1[j].name, i->rs2, i->rd);
+			return;
+		}
+	for(j=0; fptab2[j].name; j++)
+		if(fptab2[j].opf == i->opf){
+			bprint(i, "%s\tF%d, F%d, F%d", fptab2[j].name, i->rs1, i->rs2, i->rd);
+			return;
+		}
+	bprint(i, "%s%ux\tF%d, F%d, F%d", m, i->opf, i->rs1, i->rs2, i->rd);
+}
--- /dev/null
+++ b/libinterp/das-spim.c
@@ -1,0 +1,1 @@
+#include	"das-mips.c"
--- /dev/null
+++ b/libinterp/das-stub.c
@@ -1,0 +1,9 @@
+#include <lib9.h>
+#include <kernel.h>
+
+void
+das(uchar *x, int n)
+{
+	USED(x);
+	USED(n);
+}
--- /dev/null
+++ b/libinterp/dec.c
@@ -1,0 +1,1811 @@
+/* Machine generated by decgen.c */
+
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+#define DIND(reg, xxx) (uchar*)((*(ulong*)(R.reg+R.PC->xxx.i.f))+R.PC->xxx.i.s)
+static void
+D00(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D01(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D02(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D03(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D04(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D05(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D06(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D07(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D08(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D09(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D0A(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D0B(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D0C(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D0D(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D0E(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D0F(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D10(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D11(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D12(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D13(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D14(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D15(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D16(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D17(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D18(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D19(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D1A(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D1B(void)
+{
+}
+static void
+D1C(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D1D(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D1E(void)
+{
+}
+static void
+D1F(void)
+{
+}
+static void
+D20(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D21(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D22(void)
+{
+	R.s = DIND(MP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D23(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+D24(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D25(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D26(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+D27(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+D28(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D29(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D2A(void)
+{
+	R.s = DIND(FP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D2B(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+D2C(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D2D(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D2E(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+D2F(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+D30(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D31(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D32(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D33(void)
+{
+}
+static void
+D34(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D35(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D36(void)
+{
+}
+static void
+D37(void)
+{
+}
+static void
+D38(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D39(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.d;
+}
+static void
+D3A(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.d;
+}
+static void
+D3B(void)
+{
+}
+static void
+D3C(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.d;
+}
+static void
+D3D(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.d;
+}
+static void
+D3E(void)
+{
+}
+static void
+D3F(void)
+{
+}
+static void
+D40(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D41(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D42(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D43(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D44(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D45(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D46(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D47(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D48(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D49(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D4A(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D4B(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D4C(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D4D(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D4E(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D4F(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D50(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D51(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D52(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D53(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D54(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D55(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D56(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D57(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D58(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D59(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D5A(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D5B(void)
+{
+}
+static void
+D5C(void)
+{
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D5D(void)
+{
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D5E(void)
+{
+}
+static void
+D5F(void)
+{
+}
+static void
+D60(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D61(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D62(void)
+{
+	R.s = DIND(MP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D63(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+D64(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D65(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D66(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+D67(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+D68(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D69(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D6A(void)
+{
+	R.s = DIND(FP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D6B(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+D6C(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D6D(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D6E(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+D6F(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+D70(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D71(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D72(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D73(void)
+{
+}
+static void
+D74(void)
+{
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D75(void)
+{
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D76(void)
+{
+}
+static void
+D77(void)
+{
+}
+static void
+D78(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D79(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D7A(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D7B(void)
+{
+}
+static void
+D7C(void)
+{
+	R.d = DIND(MP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D7D(void)
+{
+	R.d = DIND(FP, d);
+	R.t = (short)R.PC->reg;
+	R.m = &R.t;
+}
+static void
+D7E(void)
+{
+}
+static void
+D7F(void)
+{
+}
+static void
+D80(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D81(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D82(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D83(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D84(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D85(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D86(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D87(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+D88(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D89(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D8A(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D8B(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D8C(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D8D(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D8E(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D8F(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+D90(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D91(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D92(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D93(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D94(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D95(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D96(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D97(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+D98(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D99(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D9A(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D9B(void)
+{
+}
+static void
+D9C(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D9D(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+D9E(void)
+{
+}
+static void
+D9F(void)
+{
+}
+static void
+DA0(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DA1(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DA2(void)
+{
+	R.s = DIND(MP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DA3(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+DA4(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DA5(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DA6(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+DA7(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+DA8(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DA9(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DAA(void)
+{
+	R.s = DIND(FP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DAB(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+DAC(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DAD(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DAE(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+DAF(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+DB0(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DB1(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DB2(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DB3(void)
+{
+}
+static void
+DB4(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DB5(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DB6(void)
+{
+}
+static void
+DB7(void)
+{
+}
+static void
+DB8(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DB9(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DBA(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DBB(void)
+{
+}
+static void
+DBC(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DBD(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.FP+R.PC->reg;
+}
+static void
+DBE(void)
+{
+}
+static void
+DBF(void)
+{
+}
+static void
+DC0(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DC1(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DC2(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DC3(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC4(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DC5(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DC6(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC7(void)
+{
+	R.s = R.MP+R.PC->s.ind;
+}
+static void
+DC8(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DC9(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DCA(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DCB(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+DCC(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DCD(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DCE(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+DCF(void)
+{
+	R.s = R.FP+R.PC->s.ind;
+}
+static void
+DD0(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DD1(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DD2(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DD3(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD4(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DD5(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DD6(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD7(void)
+{
+	R.s = (uchar*)&R.PC->s.imm;
+}
+static void
+DD8(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DD9(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DDA(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DDB(void)
+{
+}
+static void
+DDC(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DDD(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DDE(void)
+{
+}
+static void
+DDF(void)
+{
+}
+static void
+DE0(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DE1(void)
+{
+	R.s = DIND(MP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DE2(void)
+{
+	R.s = DIND(MP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DE3(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+DE4(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DE5(void)
+{
+	R.s = DIND(MP, s);
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DE6(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+DE7(void)
+{
+	R.s = DIND(MP, s);
+}
+static void
+DE8(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DE9(void)
+{
+	R.s = DIND(FP, s);
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DEA(void)
+{
+	R.s = DIND(FP, s);
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DEB(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+DEC(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DED(void)
+{
+	R.s = DIND(FP, s);
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DEE(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+DEF(void)
+{
+	R.s = DIND(FP, s);
+}
+static void
+DF0(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DF1(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DF2(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DF3(void)
+{
+}
+static void
+DF4(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DF5(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DF6(void)
+{
+}
+static void
+DF7(void)
+{
+}
+static void
+DF8(void)
+{
+	R.d = R.MP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DF9(void)
+{
+	R.d = R.FP+R.PC->d.ind;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DFA(void)
+{
+	R.d = (uchar*)&R.PC->d.imm;
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DFB(void)
+{
+}
+static void
+DFC(void)
+{
+	R.d = DIND(MP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DFD(void)
+{
+	R.d = DIND(FP, d);
+	R.m = R.MP+R.PC->reg;
+}
+static void
+DFE(void)
+{
+}
+static void
+DFF(void)
+{
+}
+
+void	(*dec[])(void) =
+{
+	D00,
+	D01,
+	D02,
+	D03,
+	D04,
+	D05,
+	D06,
+	D07,
+	D08,
+	D09,
+	D0A,
+	D0B,
+	D0C,
+	D0D,
+	D0E,
+	D0F,
+	D10,
+	D11,
+	D12,
+	D13,
+	D14,
+	D15,
+	D16,
+	D17,
+	D18,
+	D19,
+	D1A,
+	D1B,
+	D1C,
+	D1D,
+	D1E,
+	D1F,
+	D20,
+	D21,
+	D22,
+	D23,
+	D24,
+	D25,
+	D26,
+	D27,
+	D28,
+	D29,
+	D2A,
+	D2B,
+	D2C,
+	D2D,
+	D2E,
+	D2F,
+	D30,
+	D31,
+	D32,
+	D33,
+	D34,
+	D35,
+	D36,
+	D37,
+	D38,
+	D39,
+	D3A,
+	D3B,
+	D3C,
+	D3D,
+	D3E,
+	D3F,
+	D40,
+	D41,
+	D42,
+	D43,
+	D44,
+	D45,
+	D46,
+	D47,
+	D48,
+	D49,
+	D4A,
+	D4B,
+	D4C,
+	D4D,
+	D4E,
+	D4F,
+	D50,
+	D51,
+	D52,
+	D53,
+	D54,
+	D55,
+	D56,
+	D57,
+	D58,
+	D59,
+	D5A,
+	D5B,
+	D5C,
+	D5D,
+	D5E,
+	D5F,
+	D60,
+	D61,
+	D62,
+	D63,
+	D64,
+	D65,
+	D66,
+	D67,
+	D68,
+	D69,
+	D6A,
+	D6B,
+	D6C,
+	D6D,
+	D6E,
+	D6F,
+	D70,
+	D71,
+	D72,
+	D73,
+	D74,
+	D75,
+	D76,
+	D77,
+	D78,
+	D79,
+	D7A,
+	D7B,
+	D7C,
+	D7D,
+	D7E,
+	D7F,
+	D80,
+	D81,
+	D82,
+	D83,
+	D84,
+	D85,
+	D86,
+	D87,
+	D88,
+	D89,
+	D8A,
+	D8B,
+	D8C,
+	D8D,
+	D8E,
+	D8F,
+	D90,
+	D91,
+	D92,
+	D93,
+	D94,
+	D95,
+	D96,
+	D97,
+	D98,
+	D99,
+	D9A,
+	D9B,
+	D9C,
+	D9D,
+	D9E,
+	D9F,
+	DA0,
+	DA1,
+	DA2,
+	DA3,
+	DA4,
+	DA5,
+	DA6,
+	DA7,
+	DA8,
+	DA9,
+	DAA,
+	DAB,
+	DAC,
+	DAD,
+	DAE,
+	DAF,
+	DB0,
+	DB1,
+	DB2,
+	DB3,
+	DB4,
+	DB5,
+	DB6,
+	DB7,
+	DB8,
+	DB9,
+	DBA,
+	DBB,
+	DBC,
+	DBD,
+	DBE,
+	DBF,
+	DC0,
+	DC1,
+	DC2,
+	DC3,
+	DC4,
+	DC5,
+	DC6,
+	DC7,
+	DC8,
+	DC9,
+	DCA,
+	DCB,
+	DCC,
+	DCD,
+	DCE,
+	DCF,
+	DD0,
+	DD1,
+	DD2,
+	DD3,
+	DD4,
+	DD5,
+	DD6,
+	DD7,
+	DD8,
+	DD9,
+	DDA,
+	DDB,
+	DDC,
+	DDD,
+	DDE,
+	DDF,
+	DE0,
+	DE1,
+	DE2,
+	DE3,
+	DE4,
+	DE5,
+	DE6,
+	DE7,
+	DE8,
+	DE9,
+	DEA,
+	DEB,
+	DEC,
+	DED,
+	DEE,
+	DEF,
+	DF0,
+	DF1,
+	DF2,
+	DF3,
+	DF4,
+	DF5,
+	DF6,
+	DF7,
+	DF8,
+	DF9,
+	DFA,
+	DFB,
+	DFC,
+	DFD,
+	DFE,
+	DFF 
+};
--- /dev/null
+++ b/libinterp/decgen.c
@@ -1,0 +1,122 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+void	decgen(int);
+
+/*
+ * Force intermediate dereference of $o(o(reg)) modes to ensure intermediate
+ * pointer is valid. This is required if you want secure memory.
+ */
+#define	SOFTMMU		0
+
+void
+main(void)
+{
+	int i;
+
+	print("/* Machine generated by decgen.c */\n\n");
+
+	print("#include \"lib9.h\"\n");
+	print("#include \"isa.h\"\n");
+	print("#include \"interp.h\"\n\n");
+
+	print("#define DIND(reg, xxx) (uchar*)((*(ulong*)(R.reg+R.PC->xxx.i.f))+R.PC->xxx.i.s)\n");
+
+	for(i = 0; i < 256; i++)
+		decgen(i);
+
+	print("\nvoid	(*dec[])(void) =\n{\n");
+	for(i = 0; i < 256; i++)
+		print("\tD%.2uX%c\n", i, i != 255 ? ',' : ' ');
+	print("};\n");
+}
+
+void
+decgen(int addr)
+{
+	int nodst;
+
+	print("static void\nD%.2uX(void)\n{\n", addr);
+
+	switch(USRC(addr)) {
+	case AMP:
+		print("\tR.s = R.MP+R.PC->s.ind;\n");
+		break;
+	case AFP:
+		print("\tR.s = R.FP+R.PC->s.ind;\n");
+		break;
+	case AIMM:
+		print("\tR.s = (uchar*)&R.PC->s.imm;\n");
+		break;
+	case AMP|AIND:
+		if(SOFTMMU) {
+			print("R.s = R.MP+R.PC->s.i.f\n");
+			print("R.s = *(WORD**)R.s\n");
+			print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
+		}
+		else
+			print("\tR.s = DIND(MP, s);\n");
+		break;
+	case AFP|AIND:
+		if(SOFTMMU) {
+			print("R.s = R.FP+R.PC->s.i.f\n");
+			print("R.s = *(WORD**)R.s\n");
+			print("R.s = (uchar*)R.s + R.PC->s.i.s\n");
+		}
+		else
+			print("\tR.s = DIND(FP, s);\n");
+		break;
+	}
+	nodst = 0;
+	switch(UDST(addr)) {
+	default:
+		nodst = 1;
+		break;
+	case AMP:
+		print("\tR.d = R.MP+R.PC->d.ind;\n");
+		break;
+	case AFP:
+		print("\tR.d = R.FP+R.PC->d.ind;\n");
+		break;
+	case AIMM:
+		print("\tR.d = (uchar*)&R.PC->d.imm;\n");
+		break;
+	case AMP|AIND:
+		if(SOFTMMU) {
+			print("R.d = R.MP+R.PC->d.i.f\n");
+			print("R.d = *(WORD**)R.d\n");
+			print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
+		}
+		else
+			print("\tR.d = DIND(MP, d);\n");
+		break;
+	case AFP|AIND:
+		if(SOFTMMU) {
+			print("R.d = R.FP+R.PC->d.i.f\n");
+			print("R.d = *(WORD**)R.d\n");
+			print("R.d = (uchar*)R.d + R.PC->d.i.s\n");
+		}
+		else
+			print("\tR.d = DIND(FP, d);\n");
+		break;
+	}
+
+	if(nodst == 0)
+	switch(addr&ARM) {
+	case AXNON:
+		print("\tR.m = R.d;\n");
+		break;
+	case AXIMM:
+		print("\tR.t = (short)R.PC->reg;\n");
+		print("\tR.m = &R.t;\n");
+		break;
+	case AXINF:
+		print("\tR.m = R.FP+R.PC->reg;\n");
+		break;
+	case AXINM:
+		print("\tR.m = R.MP+R.PC->reg;\n");
+		break;
+	}
+	print("}\n");
+}
--- /dev/null
+++ b/libinterp/dlm-Inferno.c
@@ -1,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define	DBG	if(1) print
+
+extern Dynobj* dynld(int);
+extern char*	enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+	char buf[64];
+
+	if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+		return nil;
+	snprint(buf, sizeof(buf), "%s%s", pre, suf);
+	return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+	Module *m;
+	void *v;
+	Runtab *r;
+	Dynobj *o;
+	char *name;
+
+	DBG("module path is %s\n", path);
+	m = nil;
+	o = dynld(fd);
+	if(o == nil){
+		DBG("%s\n", enverror());
+		goto Error;
+	}
+	v = addr("XXX", "module", o, signof(char*));
+	if(v == nil)
+		goto Error;
+	name = *(char**)v;
+	DBG("module name is %s\n", name);
+	r = addr(name, "modtab", o, signof(Runtab[]));
+	if(r == nil)
+		goto Error;
+	m = builtinmod(name, r, 0);
+	m->rt = DYNMOD;
+	m->dev = dir->dev;
+	m->dtype = dir->type;
+	m->qid = dir->qid;
+	m->mtime = dir->mtime;
+	m->path = strdup(path);
+	if(m->path == nil)
+		goto Error;
+	m->dlm = o;
+	DBG("module base is 0x%p\n", o->base);
+	return m;
+Error:
+	if(o != nil)
+		dynobjfree(o);
+	if(m != nil)
+		freemod(m);
+	return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+	dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+	void *v, (*f)(void);
+
+	if(m->ref != 1)
+		return;
+	v = addr(m->name, fn, m->dlm, signof(*f));
+	if(v != nil){
+		f = v;
+		(*f)();
+	}
+}
+
+void
+newdyndata(Modlink *ml)
+{
+	callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+	callfn(ml->m, "end");
+}
--- /dev/null
+++ b/libinterp/dlm-Nt.c
@@ -1,0 +1,48 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+	USED(fd);
+	USED(path);
+	USED(dir);
+	return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+	USED(m);
+}
+
+void
+newdyndata(Modlink *ml)
+{
+	USED(ml);
+}
+
+void
+freedyndata(Modlink *ml)
+{
+	USED(ml);
+}
+
+Dynobj*
+dynld(int fd)
+{
+	USED(fd);
+	return nil;
+}
+
+int
+dynldable(int fd)
+{
+	USED(fd);
+	return 0;
+}
--- /dev/null
+++ b/libinterp/dlm-Plan9.c
@@ -1,0 +1,101 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+#define	DBG	if(1) print
+
+extern Dynobj* dynld(int);
+extern char*	enverror(void);
+
+typedef struct{char *name; long sig; void (*fn)(void*); int size; int np; uchar map[16];} Runtab;
+
+static void*
+addr(char *pre, char *suf, Dynobj *o, ulong sig)
+{
+	char buf[64];
+
+	if(o == nil || strlen(pre)+strlen(suf) > 64-1)
+		return nil;
+	snprint(buf, sizeof(buf), "%s%s", pre, suf);
+	return dynimport(o, buf, sig);
+}
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+	Module *m;
+	void *v;
+	Runtab *r;
+	Dynobj *o;
+	char *name;
+
+	DBG("module path is %s\n", path);
+	m = nil;
+	o = dynld(fd);
+	if(o == nil){
+		DBG("%s\n", enverror());
+		goto Error;
+	}
+	v = addr("XXX", "module", o, signof(char*));
+	if(v == nil)
+		goto Error;
+	name = *(char**)v;
+	DBG("module name is %s\n", name);
+	r = addr(name, "modtab", o, signof(Runtab[]));
+	if(r == nil)
+		goto Error;
+	m = builtinmod(name, r, 0);
+	m->rt = DYNMOD;
+	m->dev = dir->dev;
+	m->dtype = dir->type;
+	m->qid = dir->qid;
+	m->mtime = dir->mtime;
+	m->path = strdup(path);
+	if(m->path == nil)
+		goto Error;
+	m->dlm = o;
+	DBG("module base is 0x%p\n", o->base);
+	return m;
+Error:
+	if(o != nil)
+		dynobjfree(o);
+	if(m != nil)
+		freemod(m);
+	return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+	dynobjfree(m->dlm);
+}
+
+static void
+callfn(Module *m, char *fn)
+{
+	void *v, (*f)(void);
+
+	if(m->ref != 1)
+		return;
+	v = addr(m->name, fn, m->dlm, signof(*f));
+	if(v != nil){
+		f = v;
+		(*f)();
+	}
+}
+
+void
+newdyndata(Modlink *ml)
+{
+	callfn(ml->m, "init");
+}
+
+void
+freedyndata(Modlink *ml)
+{
+	callfn(ml->m, "end");
+}
--- /dev/null
+++ b/libinterp/dlm-Posix.c
@@ -1,0 +1,48 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+newdyncode(int fd, char *path, Dir *dir)
+{
+	USED(fd);
+	USED(path);
+	USED(dir);
+	return nil;
+}
+
+void
+freedyncode(Module *m)
+{
+	USED(m);
+}
+
+void
+newdyndata(Modlink *ml)
+{
+	USED(ml);
+}
+
+void
+freedyndata(Modlink *ml)
+{
+	USED(ml);
+}
+
+Dynobj*
+dynld(int fd)
+{
+	USED(fd);
+	return nil;
+}
+
+int
+dynldable(int fd)
+{
+	USED(fd);
+	return 0;
+}
--- /dev/null
+++ b/libinterp/draw.c
@@ -1,0 +1,2345 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "drawmod.h"
+#include "draw.h"
+#include "drawif.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * When a Display is remote, it must be locked to synchronize the
+ * outgoing message buffer with the refresh demon, which runs as a
+ * different process.  When it is local, the refresh demon does nothing
+ * and it is sufficient to use the interpreter's own acquire/release protection
+ * to lock the buffer.
+ *
+ * Most action to the buffer is caused by calls from Limbo, so locking at
+ * the top before going into the library is good enough.  However, the
+ * garbage collector can call the free routines at other times, so they
+ * need to protect themselves whether called through the Draw module
+ * or not; hence the need for check against recursive locking in lockdisplay().
+ * This also means that we needn't lock around calls to destroy if it's
+ * extra work to do so.
+ */
+
+typedef struct Cache Cache;
+typedef struct DRef DRef;
+typedef struct DDisplay DDisplay;
+typedef struct DImage DImage;
+typedef struct DScreen DScreen;
+typedef struct DFont DFont;
+
+struct Cache
+{
+	int	ref;
+	char*	name;
+	Display*display;
+	union{
+		Subfont*	sf;
+		Font*		f;
+		void*		ptr;
+	}u;
+	Cache*	next;
+};
+
+/* not visible to Limbo; used only for internal reference counting */
+struct DRef
+{
+	int		ref;
+	Display*	display;
+};
+
+struct DDisplay
+{
+	Draw_Display	drawdisplay;
+	Display*	display;
+	DRef*		dref;
+};
+
+struct DImage
+{
+	Draw_Image	drawimage;
+	Image*		image;
+	void*		refreshptr;
+	DRef*		dref;
+	int		flush;
+};
+
+struct DScreen
+{
+	Draw_Screen	drawscreen;
+	Screen*		screen;
+	DRef*		dref;
+};
+
+struct DFont
+{
+	Draw_Font	drawfont;
+	Font*		font;
+	DRef*		dref;
+};
+
+Cache*	sfcache[BIHASH];
+Cache*	fcache[BIHASH];
+void*	cacheqlock;
+
+static	Cache	*cachelookup(Cache**, Display*, char*);
+
+uchar fontmap[] = Draw_Font_map;
+uchar imagemap[] = Draw_Image_map;
+uchar screenmap[] = Draw_Screen_map;
+uchar displaymap[] = Draw_Display_map;
+
+Type*	TFont;
+Type*	TImage;
+Type*	TScreen;
+Type*	TDisplay;
+
+Draw_Image*	allocdrawimage(DDisplay*, Draw_Rect, ulong, Image*, int, int);
+Draw_Image*	color(DDisplay*, ulong);
+Draw_Screen	*mkdrawscreen(Screen*, Draw_Display*);
+
+char		deffontname[] = "*default*";
+void		refreshslave(Display*);
+void		subfont_close(Subfont*);
+void		freeallsubfonts(Display*);
+
+void
+drawmodinit(void)
+{
+	TFont = dtype(freedrawfont, sizeof(DFont), fontmap, sizeof(fontmap));
+	TImage = dtype(freedrawimage, sizeof(DImage), imagemap, sizeof(imagemap));
+	TScreen = dtype(freedrawscreen, sizeof(DScreen), screenmap, sizeof(screenmap));
+	TDisplay = dtype(freedrawdisplay, sizeof(DDisplay), displaymap, sizeof(displaymap));
+	builtinmod("$Draw", Drawmodtab, Drawmodlen);
+}
+
+static int
+drawhash(char *s)
+{
+	int h;
+
+	h = 0;
+	while(*s){
+		h += *s++;
+		h <<= 1;
+		if(h & (1<<8))
+			h |= 1;
+	}
+	return (h&0xFFFF)%BIHASH;
+}
+
+static Cache*
+cachelookup(Cache *cache[], Display *d, char *name)
+{
+	Cache *c;
+
+	libqlock(cacheqlock);
+	c = cache[drawhash(name)];
+	while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0))
+		c = c->next;
+	libqunlock(cacheqlock);
+	return c;
+}
+
+Cache*
+cacheinstall(Cache **cache, Display *d, char *name, void *ptr, char *type)
+{
+	Cache *c;
+	int hash;
+
+	USED(type);
+	c = cachelookup(cache, d, name);
+	if(c){
+/*		print("%s %s already in cache\n", type, name); /**/
+		return nil;
+	}
+	c = malloc(sizeof(Cache));
+	if(c == nil)
+		return nil;
+	hash = drawhash(name);
+	c->ref = 0;	/* will be incremented by caller */
+	c->display = d;
+	c->name = strdup(name);
+	c->u.ptr = ptr;
+	libqlock(cacheqlock);
+	c->next = cache[hash];
+	cache[hash] = c;
+	libqunlock(cacheqlock);
+	return c;
+}
+
+void
+cacheuninstall(Cache **cache, Display *d, char *name, char *type)
+{
+	Cache *c, *prev;
+	int hash;
+
+	hash = drawhash(name);
+	libqlock(cacheqlock);
+	c = cache[hash];
+	if(c == nil){
+   Notfound:
+		libqunlock(cacheqlock);
+		print("%s not in %s cache\n", name, type);
+		return;
+	}
+	prev = nil;
+	while(c!=nil && (d!=c->display || strcmp(name, c->name)!=0)){
+		prev = c;
+		c = c->next;
+	}
+	if(c == nil)
+		goto Notfound;
+	if(prev == 0)
+		cache[hash] = c->next;
+	else
+		prev->next = c->next;
+	libqunlock(cacheqlock);
+	free(c->name);
+	free(c);
+}
+
+Image*
+lookupimage(Draw_Image *di)
+{
+	Display *disp;
+	Image *i;
+	int locked;
+
+	if(di == H || D2H(di)->t != TImage)
+		return nil;
+	i = ((DImage*)di)->image;
+	if(i == nil)
+		return nil;
+	if(!eqrect(IRECT(di->clipr), i->clipr) || di->repl!=i->repl){
+		disp = i->display;
+		locked = lockdisplay(disp);
+		replclipr(i, di->repl, IRECT(di->clipr));
+		if(locked)
+			unlockdisplay(disp);
+	}
+	return i;
+}
+
+Screen*
+lookupscreen(Draw_Screen *ds)
+{
+	if(ds == H || D2H(ds)->t != TScreen)
+		return nil;
+	return ((DScreen*)ds)->screen;
+}
+
+Font*
+lookupfont(Draw_Font *df)
+{
+	if(df == H || D2H(df)->t != TFont)
+		return nil;
+	return ((DFont*)df)->font;
+}
+
+Display*
+lookupdisplay(Draw_Display *dd)
+{
+	if(dd == H || D2H(dd)->t != TDisplay)
+		return nil;
+	return ((DDisplay*)dd)->display;
+}
+
+Image*
+checkimage(Draw_Image *di)
+{
+	Image *i;
+
+	if(di == H)
+		error("nil Image");
+	i = lookupimage(di);
+	if(i == nil)
+		error(exType);
+	return i;
+}
+
+Screen*
+checkscreen(Draw_Screen *ds)
+{
+	Screen *s;
+
+	if(ds == H)
+		error("nil Screen");
+	s = lookupscreen(ds);
+	if(s == nil)
+		error(exType);
+	return s;
+}
+
+Font*
+checkfont(Draw_Font *df)
+{
+	Font *f;
+
+	if(df == H)
+		error("nil Font");
+	f = lookupfont(df);
+	if(f == nil)
+		error(exType);
+	return f;
+}
+
+Display*
+checkdisplay(Draw_Display *dd)
+{
+	Display *d;
+
+	if(dd == H)
+		error("nil Display");
+	d = lookupdisplay(dd);
+	if(d == nil)
+		error(exType);
+	return d;
+}
+
+void
+Display_allocate(void *fp)
+{
+	F_Display_allocate *f;
+	char buf[128], *dev;
+	Subfont *df;
+	Display *display;
+	DDisplay *dd;
+	Heap *h;
+	Draw_Rect r;
+	DRef *dr;
+	Cache *c;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	if(cacheqlock == nil){
+		cacheqlock = libqlalloc();
+		if(cacheqlock == nil)
+			return;
+	}
+	dev = string2c(f->dev);
+	if(dev[0] == 0)
+		dev = 0;
+	display = initdisplay(dev, dev, nil);	/* TO DO: win, error */
+	if(display == 0)
+		return;
+
+	dr = malloc(sizeof(DRef));
+	if(dr == nil)
+		return;
+	h = heap(TDisplay);
+	if(h == H){
+		closedisplay(display);
+		return;
+	}
+	dd = H2D(DDisplay*, h);
+	dd->display = display;
+	*f->ret = &dd->drawdisplay;
+	dd->dref = dr;
+	display->limbo = dr;
+	dr->display = display;
+	dr->ref = 1;
+	df = getdefont(display);
+	if(df){
+		display->defaultsubfont = df;
+		sprint(buf, "%d %d\n0 %d\t%s\n", df->height, df->ascent,
+			df->n-1, deffontname);
+		display->defaultfont = buildfont(display, buf, deffontname);
+		if(display->defaultfont){
+			c = cacheinstall(fcache, display, deffontname, display->defaultfont, "font");
+			if(c)
+				c->ref++;
+			/* else BUG? */
+		}
+	}
+
+	R2R(r, display->image->r);
+	dd->drawdisplay.image = allocdrawimage(dd, r, display->image->chan, display->image, 0, 0);
+	R2R(r, display->white->r);
+	dd->drawdisplay.black = allocdrawimage(dd, r, display->black->chan, display->black, 1, 0);
+	dd->drawdisplay.white = allocdrawimage(dd, r, display->white->chan, display->white, 1, 0);
+	dd->drawdisplay.opaque = allocdrawimage(dd, r, display->opaque->chan, display->opaque, 1, 0);
+	dd->drawdisplay.transparent = allocdrawimage(dd, r, display->transparent->chan, display->transparent, 1, 0);
+
+	/* don't call unlockdisplay because the qlock was left up by initdisplay */
+	libqunlock(display->qlock);
+}
+
+void
+Display_getwindow(void *fp)
+{
+	F_Display_getwindow *f;
+	Display *disp;
+	int locked;
+	Image *image;
+	Screen *screen;
+	char *wn;
+	void *r;
+
+	f = fp;
+	r = f->ret->t0;
+	f->ret->t0 = H;
+	destroy(r);
+	r = f->ret->t1;
+	f->ret->t1 = H;
+	destroy(r);
+	disp = checkdisplay(f->d);
+	if(f->winname == H)
+		wn = "/dev/winname";
+	else
+		wn = string2c(f->winname);
+	if(f->image == H)
+		image = nil;
+	else
+		image = checkimage(f->image);
+	if(f->screen == H)
+		screen = nil;
+	else
+		screen = checkscreen(f->screen);
+	locked = lockdisplay(disp);
+	if(gengetwindow(disp, wn, &image, &screen, f->backup) < 0){
+		/* TO DO: eliminate f->image and f->screen's references to Image and Screen */
+		goto Return;
+	}
+	if(screen != nil){
+		if(f->screen != H){
+			f->ret->t0 = f->screen;
+			D2H(f->screen)->ref++;
+		}else
+			f->ret->t0 = mkdrawscreen(screen, f->d);
+	}
+	if(image != nil){
+		if(f->image != H){
+			f->ret->t1 = f->image;
+			D2H(f->image)->ref++;
+		}else
+			f->ret->t1 = mkdrawimage(image, f->ret->t0, f->d, nil);
+	}
+
+Return:
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Display_startrefresh(void *fp)
+{
+	F_Display_startrefresh *f;
+	Display *disp;
+
+	f = fp;
+	disp = checkdisplay(f->d);
+	refreshslave(disp);
+}
+
+void
+display_dec(void *v)
+{
+	DRef *dr;
+	Display *d;
+	int locked;
+
+	dr = v;
+	if(dr->ref-- != 1)
+		return;
+
+	d = dr->display;
+	locked = lockdisplay(d);
+	font_close(d->defaultfont);
+	subfont_close(d->defaultsubfont);
+	if(locked)
+		unlockdisplay(d);
+	freeallsubfonts(d);
+	closedisplay(d);
+	free(dr);
+}
+
+void
+freedrawdisplay(Heap *h, int swept)
+{
+	DDisplay *dd;
+	Display *d;
+
+	dd = H2D(DDisplay*, h);
+
+	if(!swept) {
+		destroy(dd->drawdisplay.image);
+		destroy(dd->drawdisplay.black);
+		destroy(dd->drawdisplay.white);
+		destroy(dd->drawdisplay.opaque);
+		destroy(dd->drawdisplay.transparent);
+	}
+	/* we've now released dd->image etc.; make sure they're not freed again */
+	d = dd->display;
+	d->image = nil;
+	d->white = nil;
+	d->black = nil;
+	d->opaque = nil;
+	d->transparent = nil;
+	display_dec(dd->dref);
+	/* Draw_Display header will be freed by caller */
+}
+
+void
+Display_color(void *fp)
+{
+	F_Display_color *f;
+	Display *d;
+	int locked;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	d = checkdisplay(f->d);
+	locked = lockdisplay(d);
+	*f->ret = color((DDisplay*)f->d, f->color);
+	if(locked)
+		unlockdisplay(d);
+}
+
+void
+Image_flush(void *fp)
+{
+	F_Image_flush *f;
+	Image *d;
+	DImage *di;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->win);
+	di = (DImage*)f->win;
+	switch(f->func){
+	case 0:	/* Draw->Flushoff */
+		di->flush = 0;
+		break;
+	case 1:	/* Draw->Flushon */
+		di->flush = 1;
+		/* fall through */
+	case 2:	/* Draw->Flushnow */
+		locked = lockdisplay(d->display);
+		if(d->id==0 || d->screen!=0)
+			flushimage(d->display, 1);
+		if(locked)
+			unlockdisplay(d->display);
+		break;
+	default:
+		error(exInval);
+	}
+}
+
+void
+checkflush(Draw_Image *dst)
+{
+	DImage  *di;
+
+	di = (DImage*)dst;
+	if(di->flush && (di->image->id==0 || di->image->screen!=nil))
+		flushimage(di->image->display, 1);
+}
+
+static void
+imagedraw(void *fp, int op)
+{
+	F_Image_draw *f;
+	Image *d, *s, *m;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	if(f->src == H)
+		s = d->display->black;
+	else
+		s = checkimage(f->src);
+	if(f->matte == H)
+		m = d->display->white;	/* ones */
+	else
+		m = checkimage(f->matte);
+	if(d->display!=s->display || d->display!=m->display)
+		return;
+	locked = lockdisplay(d->display);
+	drawop(d, IRECT(f->r), s, m, IPOINT(f->p), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_draw(void *fp)
+{
+	imagedraw(fp, SoverD);
+}
+
+void
+Image_drawop(void *fp)
+{
+	F_Image_drawop *f;
+
+	f = fp;
+	imagedraw(fp, f->op);
+}
+
+static void
+imagegendraw(void *fp, int op)
+{
+	F_Image_gendraw *f;
+	Image *d, *s, *m;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	if(f->src == H)
+		s = d->display->black;
+	else
+		s = checkimage(f->src);
+	if(f->matte == H)
+		m = d->display->white;	/* ones */
+	else
+		m = checkimage(f->matte);
+	if(d->display!=s->display || d->display!=m->display)
+		return;
+	locked = lockdisplay(d->display);
+	gendrawop(d, IRECT(f->r), s, IPOINT(f->p0), m, IPOINT(f->p1), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_gendraw(void *fp)
+{
+	imagegendraw(fp, SoverD);
+}
+
+void
+Image_gendrawop(void *fp)
+{
+	F_Image_gendrawop *f;
+
+	f = fp;
+	imagegendraw(fp, f->op);
+}
+
+static void
+drawline(void *fp, int op)
+{
+	F_Image_line *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display || f->radius < 0)
+		return;
+	locked = lockdisplay(d->display);
+	lineop(d, IPOINT(f->p0), IPOINT(f->p1), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_line(void *fp)
+{
+	drawline(fp, SoverD);
+}
+
+void
+Image_lineop(void *fp)
+{
+	F_Image_lineop *f;
+
+	f = fp;
+	drawline(fp, f->op);
+}
+
+static void
+drawsplinepoly(void *fp, int smooth, int op)
+{
+	F_Image_poly *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display|| f->radius < 0)
+		return;
+	locked = lockdisplay(d->display);
+	/* sleazy: we know that Draw_Points have same shape as Points */
+	if(smooth)
+		bezsplineop(d, (Point*)f->p->data, f->p->len,
+			f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+	else
+		polyop(d, (Point*)f->p->data, f->p->len, f->end0,
+			f->end1, f->radius, s, IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_poly(void *fp)
+{
+	drawsplinepoly(fp, 0, SoverD);
+}
+
+void
+Image_polyop(void *fp)
+{
+	F_Image_polyop *f;
+
+	f = fp;
+	drawsplinepoly(fp, 0, f->op);
+}
+
+void
+Image_bezspline(void *fp)
+{
+	drawsplinepoly(fp, 1, SoverD);
+}
+
+void
+Image_bezsplineop(void *fp)
+{
+	F_Image_bezsplineop *f;
+
+	f = fp;
+	drawsplinepoly(fp, 1, f->op);
+}
+
+static void
+drawbezier(void *fp, int op)
+{
+	F_Image_bezier *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display || f->radius < 0)
+		return;
+	locked = lockdisplay(d->display);
+	bezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
+		  IPOINT(f->d), f->end0, f->end1, f->radius, s, IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_bezier(void *fp)
+{
+	drawbezier(fp, SoverD);
+}
+
+void
+Image_bezierop(void *fp)
+{
+	F_Image_bezierop *f;
+
+	f = fp;
+	drawbezier(fp, f->op);
+}
+
+static void
+drawfillbezier(void *fp, int op)
+{
+	F_Image_fillbezier *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display)
+		return;
+	locked = lockdisplay(d->display);
+	fillbezierop(d, IPOINT(f->a), IPOINT(f->b), IPOINT(f->c),
+			IPOINT(f->d), f->wind, s, IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_fillbezier(void *fp)
+{
+	drawfillbezier(fp, SoverD);
+}
+
+void
+Image_fillbezierop(void *fp)
+{
+	F_Image_fillbezierop *f;
+
+	f = fp;
+	drawfillbezier(fp, f->op);
+}
+
+static void
+drawfillsplinepoly(void *fp, int smooth, int op)
+{
+	F_Image_fillpoly *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display)
+		return;
+	locked = lockdisplay(d->display);
+	/* sleazy: we know that Draw_Points have same shape as Points */
+	if(smooth)
+		fillbezsplineop(d, (Point*)f->p->data, f->p->len,
+			f->wind, s, IPOINT(f->sp), op);
+	else
+		fillpolyop(d, (Point*)f->p->data, f->p->len,
+			f->wind, s, IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_fillpoly(void *fp)
+{
+	drawfillsplinepoly(fp, 0, SoverD);
+}
+
+void
+Image_fillpolyop(void *fp)
+{
+	F_Image_fillpolyop *f;
+
+	f = fp;
+	drawfillsplinepoly(fp, 0, f->op);
+}
+
+void
+Image_fillbezspline(void *fp)
+{
+	drawfillsplinepoly(fp, 1, SoverD);
+}
+
+void
+Image_fillbezsplineop(void *fp)
+{
+	F_Image_fillbezsplineop *f;
+
+	f = fp;
+	drawfillsplinepoly(fp, 1, f->op);
+}
+
+static void
+drawarcellipse(void *fp, int isarc, int alpha, int phi, int op)
+{
+	F_Image_arc *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display || f->thick < 0 || f->a<0 || f->b<0)
+		return;
+
+	locked = lockdisplay(d->display);
+	if(isarc)
+		arcop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
+			IPOINT(f->sp), alpha, phi, op);
+	else
+		ellipseop(d, IPOINT(f->c), f->a, f->b, f->thick, s,
+			IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_ellipse(void *fp)
+{
+	drawarcellipse(fp, 0, 0, 0, SoverD);
+}
+
+void
+Image_ellipseop(void *fp)
+{
+	F_Image_ellipseop *f;
+
+	f = fp;
+	drawarcellipse(fp, 0, 0, 0, f->op);
+}
+
+void
+Image_arc(void *fp)
+{
+	F_Image_arc *f;
+
+	f = fp;
+	drawarcellipse(fp, 1, f->alpha, f->phi, SoverD);
+}
+
+void
+Image_arcop(void *fp)
+{
+	F_Image_arcop *f;
+
+	f = fp;
+	drawarcellipse(fp, 1, f->alpha, f->phi, f->op);
+}
+
+static void
+drawfillarcellipse(void *fp, int isarc, int alpha, int phi, int op)
+{
+	F_Image_fillarc *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display || f->a<0 || f->b<0)
+		return;
+
+	locked = lockdisplay(d->display);
+	if(isarc)
+		fillarcop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), alpha, phi, op);
+	else
+		fillellipseop(d, IPOINT(f->c), f->a, f->b, s, IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_fillellipse(void *fp)
+{
+	drawfillarcellipse(fp, 0, 0, 0, SoverD);
+}
+
+void
+Image_fillellipseop(void *fp)
+{
+	F_Image_fillellipseop *f;
+
+	f = fp;
+	drawfillarcellipse(fp, 0, 0, 0, f->op);
+}
+
+void
+Image_fillarc(void *fp)
+{
+	F_Image_fillarc *f;
+
+	f = fp;
+	drawfillarcellipse(fp, 1, f->alpha, f->phi, SoverD);
+}
+
+void
+Image_fillarcop(void *fp)
+{
+	F_Image_fillarcop *f;
+
+	f = fp;
+	drawfillarcellipse(fp, 1, f->alpha, f->phi, f->op);
+}
+
+static void
+drawtext(void *fp, int op)
+{
+	F_Image_text *f;
+	Font *font;
+	Point pt;
+	Image *s, *d;
+	String *str;
+	int locked;
+
+	f = fp;
+	if(f->dst == H || f->src == H)
+		goto Return;
+	if(f->font == H || f->str == H)
+		goto Return;
+	str = f->str;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	font = checkfont(f->font);
+	if(d->display!=s->display || d->display!=font->display)
+		return;
+	locked = lockdisplay(d->display);
+	if(str->len >= 0)
+		pt = stringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, op);
+	else
+		pt = runestringnop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+    Return:
+	P2P(*f->ret, pt);
+}
+
+void
+Image_text(void *fp)
+{
+	drawtext(fp, SoverD);
+}
+
+void
+Image_textop(void *fp)
+{
+	F_Image_textop *f;
+
+	f = fp;
+	drawtext(fp, f->op);
+}
+
+static void
+drawtextbg(void *fp, int op)
+{
+	F_Image_textbg *f;
+	Font *font;
+	Point pt;
+	Image *s, *d, *bg;
+	String *str;
+	int locked;
+
+	f = fp;
+	if(f->dst == H || f->src == H)
+		goto Return;
+	if(f->font == H || f->str == H)
+		goto Return;
+	str = f->str;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	bg = checkimage(f->bg);
+	font = checkfont(f->font);
+	if(d->display!=s->display || d->display!=font->display)
+		return;
+	locked = lockdisplay(d->display);
+	if(str->len >= 0)
+		pt = stringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Sascii, str->len, bg, IPOINT(f->bgp), op);
+	else
+		pt = runestringnbgop(d, IPOINT(f->p), s, IPOINT(f->sp), font, str->Srune, -str->len, bg, IPOINT(f->bgp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+    Return:
+	P2P(*f->ret, pt);
+}
+
+void
+Image_textbg(void *fp)
+{
+	drawtextbg(fp, SoverD);
+}
+
+void
+Image_textbgop(void *fp)
+{
+	F_Image_textbgop *f;
+
+	f = fp;
+	drawtextbg(fp, f->op);
+}
+
+static void
+drawborder(void *fp, int op)
+{
+	F_Image_border *f;
+	Image *d, *s;
+	int locked;
+
+	f = fp;
+	d = checkimage(f->dst);
+	s = checkimage(f->src);
+	if(d->display != s->display)
+		return;
+	locked = lockdisplay(d->display);
+	borderop(d, IRECT(f->r), f->i, s, IPOINT(f->sp), op);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(d->display);
+}
+
+void
+Image_border(void *fp)
+{
+	drawborder(fp, SoverD);
+}
+
+void
+Display_newimage(void *fp)
+{
+	F_Display_newimage *f;
+	Display *d;
+	int locked;
+
+	f = fp;
+	d = checkdisplay(f->d);
+	destroy(*f->ret);
+	*f->ret = H;
+	locked = lockdisplay(d);
+	*f->ret = allocdrawimage((DDisplay*)f->d, f->r, f->chans.desc,
+				nil, f->repl, f->color);
+	if(locked)
+		unlockdisplay(d);
+}
+
+void
+Display_colormix(void *fp)
+{
+	F_Display_colormix *f;
+	Display *disp;
+	Image *i;
+	int locked;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	disp = checkdisplay(f->d);
+	locked = lockdisplay(disp);
+	i = allocimagemix(disp, f->c1, f->c2);
+	if(locked)
+		unlockdisplay(disp);
+	*f->ret = mkdrawimage(i, H, f->d, nil);
+}
+
+void
+Image_readpixels(void *fp)
+{
+	F_Image_readpixels *f;
+	Rectangle r;
+	Image *i;
+	int locked;
+
+	f = fp;
+	R2R(r, f->r);
+	i = checkimage(f->src);
+	locked = lockdisplay(i->display);
+	*f->ret = unloadimage(i, r, f->data->data, f->data->len);
+	if(locked)
+		unlockdisplay(i->display);
+}
+
+void
+Image_writepixels(void *fp)
+{
+	Rectangle r;
+	F_Image_writepixels *f;
+	Image *i;
+	int locked;
+
+	f = fp;
+	R2R(r, f->r);
+	i = checkimage(f->dst);
+	locked = lockdisplay(i->display);
+	*f->ret = loadimage(i, r, f->data->data, f->data->len);
+	checkflush(f->dst);
+	if(locked)
+		unlockdisplay(i->display);
+}
+
+void
+Image_arrow(void *fp)
+{
+	F_Image_arrow *f;
+
+	f = fp;
+	*f->ret = ARROW(f->a, f->b, f->c);
+}
+
+void
+Image_name(void *fp)
+{
+	F_Image_name *f;
+	Image *i;
+	int locked, ok;
+	char *name;
+
+	f = fp;
+	*f->ret = -1;
+	i = checkimage(f->src);
+	name = string2c(f->name);
+	locked = lockdisplay(i->display);
+	*f->ret = ok = nameimage(i, name, f->in);
+	if(locked)
+		unlockdisplay(i->display);
+	if(ok){
+		destroy(f->src->iname);
+		if(f->in){
+			f->src->iname = f->name;
+			D2H(f->name)->ref++;
+		}else
+			f->src->iname = H;
+	}
+}
+
+Image*
+display_open(Display *disp, char *name)
+{
+	Image *i;
+	int fd;
+
+	fd = libopen(name, OREAD);
+	if(fd < 0)
+		return nil;
+
+	i = readimage(disp, fd, 1);
+	libclose(fd);
+	return i;
+}
+
+void
+Display_open(void *fp)
+{
+	Image *i;
+	Display *disp;
+	F_Display_open *f;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	disp = lookupdisplay(f->d);
+	if(disp == nil)
+		return;
+	i = display_open(disp, string2c(f->name));
+	if(i == nil)
+		return;
+	*f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
+}
+
+void
+Display_namedimage(void *fp)
+{
+	F_Display_namedimage *f;
+	Display *d;
+	Image *i;
+	Draw_Image *di;
+	int locked;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	d = checkdisplay(f->d);
+	locked = lockdisplay(d);
+	i = namedimage(d, string2c(f->name));
+	if(locked)
+		unlockdisplay(d);
+	if(i == nil)
+		return;
+	di =  allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, i->repl, 0);
+	*f->ret = di;
+	if(di == H){
+		locked = lockdisplay(d);
+		freeimage(i);
+		if(locked)
+			unlockdisplay(d);
+	}else{
+		di->iname = f->name;
+		D2H(f->name)->ref++;
+	}
+}
+
+void
+Display_readimage(void *fp)
+{
+	Image *i;
+	Display *disp;
+	F_Display_readimage *f;
+	Sys_FD *fd;
+	int locked;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	fd = f->fd;
+	if(fd == H)
+		return;
+	disp = checkdisplay(f->d);
+	i = readimage(disp, fd->fd, 1);
+	if(i == nil)
+		return;
+	*f->ret = allocdrawimage((DDisplay*)f->d, DRECT(i->r), i->chan, i, 0, 0);
+	if(*f->ret == H){
+		locked = lockdisplay(disp);
+		freeimage(i);
+		if(locked)
+			unlockdisplay(disp);
+	}
+}
+
+void
+Display_writeimage(void *fp)
+{
+	Image *i;
+	F_Display_writeimage *f;
+	Sys_FD *fd;
+
+	f = fp;
+	*f->ret = -1;
+	fd = f->fd;
+	if(fd == H)
+		return;
+	i = checkimage(f->i);
+	if(checkdisplay(f->d) != i->display)
+		return;
+	*f->ret = writeimage(fd->fd, i, 1);	/* TO DO: dolock? */
+}
+
+Draw_Screen*
+mkdrawscreen(Screen *s, Draw_Display *display)
+{
+	Heap *h;
+	DScreen *ds;
+	Draw_Image *dimage, *dfill;
+
+	dimage = mkdrawimage(s->image, H, display, nil);
+	dfill = mkdrawimage(s->fill, H, display, nil);
+	h = heap(TScreen);
+	if(h == H)
+		return nil;
+	ds = H2D(DScreen*, h);
+	ds->screen = s;
+	ds->drawscreen.fill = dfill;
+	D2H(dfill)->ref++;
+	ds->drawscreen.image = dimage;
+	D2H(dimage)->ref++;
+	ds->drawscreen.display = dimage->display;
+	D2H(dimage->display)->ref++;
+	ds->drawscreen.id = s->id;
+	ds->dref = s->display->limbo;
+	ds->dref->ref++;
+	return &ds->drawscreen;
+}
+
+static DScreen*
+allocdrawscreen(Draw_Image *dimage, Draw_Image *dfill, int public)
+{
+	Heap *h;
+	Screen *s;
+	DScreen *ds;
+	Image *image, *fill;
+
+	image = ((DImage*)dimage)->image;
+	fill = ((DImage*)dfill)->image;
+	s = allocscreen(image, fill, public);
+	if(s == 0)
+		return nil;
+	h = heap(TScreen);
+	if(h == H)
+		return nil;
+	ds = H2D(DScreen*, h);
+	ds->screen = s;
+	ds->drawscreen.fill = dfill;
+	D2H(dfill)->ref++;
+	ds->drawscreen.image = dimage;
+	D2H(dimage)->ref++;
+	ds->drawscreen.display = dimage->display;
+	D2H(dimage->display)->ref++;
+	ds->drawscreen.id = s->id;
+	ds->dref = image->display->limbo;
+	ds->dref->ref++;
+	return ds;
+}
+
+void
+Screen_allocate(void *fp)
+{
+	F_Screen_allocate *f;
+	DScreen *ds;
+	Image *image;
+	int locked;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	image = checkimage(f->image);
+	checkimage(f->fill);
+	locked = lockdisplay(image->display);
+	ds = allocdrawscreen(f->image, f->fill, f->public);
+	if(ds != nil)
+		*f->ret = &ds->drawscreen;
+	if(locked)
+		unlockdisplay(image->display);
+}
+
+void
+Display_publicscreen(void *fp)
+{
+	F_Display_publicscreen *f;
+	Heap *h;
+	Screen *s;
+	DScreen *ds;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	disp = checkdisplay(f->d);
+	locked = lockdisplay(disp);
+	s = publicscreen(disp, f->id, disp->image->chan);
+	if(locked)
+		unlockdisplay(disp);
+	if(s == nil)
+		return;
+	h = heap(TScreen);
+	if(h == H)
+		return;
+	ds = H2D(DScreen*, h);
+	ds->screen = s;
+	ds->drawscreen.fill = H;
+	ds->drawscreen.image =H;
+	ds->drawscreen.id = s->id;
+	ds->drawscreen.display = f->d;
+	D2H(f->d)->ref++;
+	ds->dref = disp->limbo;
+	ds->dref->ref++;
+	*f->ret = &ds->drawscreen;
+}
+
+void
+freedrawscreen(Heap *h, int swept)
+{
+	DScreen *ds;
+	Screen *s;
+	Display *disp;
+	int locked;
+
+	ds = H2D(DScreen*, h);
+	if(!swept) {
+		destroy(ds->drawscreen.image);
+		destroy(ds->drawscreen.fill);
+		destroy(ds->drawscreen.display);
+	}
+	s = lookupscreen(&ds->drawscreen);
+	if(s == nil){
+		if(!swept)
+			freeptrs(ds, TScreen);
+		return;
+	}
+	disp = s->display;
+	locked = lockdisplay(disp);
+	freescreen(s);
+	if(locked)
+		unlockdisplay(disp);
+	display_dec(ds->dref);
+	/* screen header will be freed by caller */
+}
+
+void
+Font_build(void *fp)
+{
+	F_Font_build *f;
+	Font *font;
+	DFont *dfont;
+	Heap *h;
+	char buf[128];
+	char *name, *data;
+	Subfont *df;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	disp = checkdisplay(f->d);
+
+	name = string2c(f->name);
+	font = font_open(disp, name);
+	if(font == nil) {
+		if(strcmp(name, deffontname) == 0) {
+			df = disp->defaultsubfont;
+			sprint(buf, "%d %d\n0 %d\t%s\n",
+				df->height, df->ascent, df->n-1, name);
+			data = buf;
+		}
+		else
+		if(f->desc == H)
+			return;
+		else
+			data = string2c(f->desc);
+
+		locked = lockdisplay(disp);
+		font = buildfont(disp, data, name);
+		if(locked)
+			unlockdisplay(disp);
+		if(font == nil)
+			return;
+	}
+
+	h = heap(TFont);
+	if(h == H)
+		return;
+
+	dfont = H2D(DFont*, h);
+	dfont->font = font;
+	dfont->drawfont.name = f->name;
+	D2H(f->name)->ref++;
+	dfont->drawfont.height = font->height;
+	dfont->drawfont.ascent = font->ascent;
+	dfont->drawfont.display = f->d;
+	D2H(f->d)->ref++;
+	dfont->dref = disp->limbo;
+	dfont->dref->ref++;
+
+	*f->ret = &dfont->drawfont;
+}
+
+Font*
+font_open(Display *display, char *name)
+{
+	Cache *c;
+	Font *font;
+	int locked;
+
+	c = cachelookup(fcache, display, name);
+	if(c)
+		font = c->u.f;
+	else {
+		locked = lockdisplay(display);
+		font = openfont(display, name);
+		if(locked)
+			unlockdisplay(display);
+		if(font == nil)
+			return nil;
+		c = cacheinstall(fcache, display, name, font, "font");
+	}
+	if(c)
+		c->ref++;
+
+	return font;
+}
+
+void
+font_close(Font *f)
+{
+	Cache *c;
+	Display *disp;
+	int locked;
+	disp = f->display;
+	if(f->name == nil)
+		return;
+
+	/* fonts from Font_build() aren't always in fcache, but we still need to free them */
+	c = cachelookup(fcache, disp, f->name);
+	if(c != nil && f == c->u.f) {
+		if(c->ref <= 0)
+			return;
+		if(c->ref-- != 1)
+			return;
+		cacheuninstall(fcache, disp, f->name, "font");
+	}
+
+	locked = lockdisplay(disp);
+	freefont(f);
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+freecachedsubfont(Subfont *sf)
+{
+	Cache *c;
+	Display *disp;
+
+	disp = sf->bits->display;
+	c = cachelookup(sfcache, disp, sf->name);
+	if(c == nil){
+		fprint(2, "subfont %s not cached\n", sf->name);
+		return;
+	}
+	if(c->ref > 0)
+		c->ref--;
+	/* if ref is zero, we leave it around for later harvesting by freeallsubfonts */
+}
+
+void
+freeallsubfonts(Display *d)
+{
+	int i;
+	Cache *c, *prev, *o;
+	Subfont *sf;
+	int locked;
+	if(cacheqlock == nil)	/* may not have allocated anything yet */
+		return;
+	libqlock(cacheqlock);
+	for(i=0; i<BIHASH; i++){
+		c = sfcache[i];
+		prev = 0;
+		while(c != nil){
+			if(c->ref==0 && (d==nil || c->display==d)){
+				if(prev == 0)
+					sfcache[i] = c->next;
+				else
+					prev->next = c->next;
+				free(c->name);
+				sf = c->u.sf;
+				if(--sf->ref==0){
+					free(sf->info);
+					locked = lockdisplay(c->display);
+					freeimage(sf->bits);
+					if(locked)
+						unlockdisplay(c->display);
+					free(sf);
+				}
+				o = c;
+				c = c->next;
+				free(o);
+			}else{
+				prev = c;
+				c = c->next;
+			}
+		}
+	}
+	libqunlock(cacheqlock);
+}
+
+void
+subfont_close(Subfont *sf)
+{
+	freecachedsubfont(sf);
+}
+
+void
+freesubfont(Subfont *sf)
+{
+	freecachedsubfont(sf);
+}
+
+void
+Font_open(void *fp)
+{
+	Heap *h;
+	Font *font;
+	Display *disp;
+	DFont *df;
+	F_Font_open *f;
+
+	f = fp;
+
+	destroy(*f->ret);
+	*f->ret = H;
+	disp = checkdisplay(f->d);
+
+	font = font_open(disp, string2c(f->name));
+	if(font == 0)
+		return;
+
+	h = heap(TFont);
+	if(h == H)
+		return;
+
+	df = H2D(DFont*, h);
+	df->font = font;
+	df->drawfont.name = f->name;
+	D2H(f->name)->ref++;
+	df->drawfont.height = font->height;
+	df->drawfont.ascent = font->ascent;
+	df->drawfont.display = f->d;
+	D2H(f->d)->ref++;
+	df->dref = disp->limbo;
+	df->dref->ref++;
+	*f->ret = &df->drawfont;
+}
+
+void
+Font_width(void *fp)
+{
+	F_Font_width *f;
+	Font *font;
+	char *s;
+	int locked;
+
+	f = fp;
+	s = string2c(f->str);
+	if(f->f == H || s[0]=='\0')
+		*f->ret = 0;
+	else{
+		font = checkfont(f->f);
+		locked = lockdisplay(font->display);
+		*f->ret = stringwidth(font, s);
+		if(locked)
+			unlockdisplay(font->display);
+	}
+}
+
+void
+Font_bbox(void *fp)
+{
+	F_Font_bbox *f;
+	Draw_Rect *ret;
+
+	/* place holder for the real thing */
+	f = fp;
+	ret = f->ret;
+	ret->min.x = ret->min.y = 0;
+	ret->max.x = ret->max.y = 0;
+}
+
+/*
+ * BUG: would be nice if this cached the whole font.
+ * Instead only the subfonts are cached and the fonts are
+ * freed when released.
+ */
+void
+freedrawfont(Heap*h, int swept)
+{
+	Draw_Font *d;
+	Font *f;
+	d = H2D(Draw_Font*, h);
+	f = lookupfont(d);
+	if(!swept) {
+		destroy(d->name);
+		destroy(d->display);
+	}
+	font_close(f);
+	display_dec(((DFont*)d)->dref);
+}
+
+void
+Chans_text(void *fp)
+{
+	F_Chans_text *f;
+	char buf[16];
+
+	f = fp;
+	destroy(*f->ret);
+	*f->ret = H;
+	if(chantostr(buf, f->c.desc) != nil)
+		retstr(buf, f->ret);
+}
+
+void
+Chans_depth(void *fp)
+{
+	F_Chans_depth *f;
+
+	f = fp;
+	*f->ret = chantodepth(f->c.desc);
+}
+
+void
+Chans_eq(void *fp)
+{
+	F_Chans_eq *f;
+
+	f = fp;
+	*f->ret = f->c.desc == f->d.desc;
+}
+
+void
+Chans_mk(void *fp)
+{
+	F_Chans_mk *f;
+
+	f = fp;
+	f->ret->desc = strtochan(string2c(f->s));
+}
+
+void
+Display_rgb(void *fp)
+{
+	ulong c;
+	Display *disp;
+	F_Display_rgb *f;
+	int locked;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	disp = checkdisplay(f->d);
+
+	c = ((f->r&255)<<24)|((f->g&255)<<16)|((f->b&255)<<8)|0xFF;
+
+	locked = lockdisplay(disp);
+	*f->ret = color((DDisplay*)f->d, c);
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Display_rgb2cmap(void *fp)
+{
+	F_Display_rgb2cmap *f;
+
+	f = fp;
+	/* f->display is unused, but someday may have color map */
+	*f->ret = rgb2cmap(f->r, f->g, f->b);
+}
+
+void
+Display_cmap2rgb(void *fp)
+{
+	F_Display_cmap2rgb *f;
+	ulong c;
+
+	f = fp;
+	/* f->display is unused, but someday may have color map */
+	c = cmap2rgb(f->c);
+	f->ret->t0 = (c>>16)&0xFF;
+	f->ret->t1 = (c>>8)&0xFF;
+	f->ret->t2 = (c>>0)&0xFF;
+}
+
+void
+Display_cmap2rgba(void *fp)
+{
+	F_Display_cmap2rgba *f;
+
+	f = fp;
+	/* f->display is unused, but someday may have color map */
+	*f->ret = cmap2rgba(f->c);
+}
+
+void
+Draw_setalpha(void *fp)
+{
+	F_Draw_setalpha *f;
+
+	f = fp;
+	*f->ret = setalpha(f->c, f->a);
+}
+
+void
+Draw_icossin(void *fp)
+{
+	F_Draw_icossin *f;
+	int s, c;
+
+	f = fp;
+	icossin(f->deg, &s, &c);
+	f->ret->t0 = s;
+	f->ret->t1 = c;
+}
+
+void
+Draw_icossin2(void *fp)
+{
+	F_Draw_icossin2 *f;
+	int s, c;
+
+	f = fp;
+	icossin2(f->p.x, f->p.y, &s, &c);
+	f->ret->t0 = s;
+	f->ret->t1 = c;
+}
+
+void
+Draw_bytesperline(void *fp)
+{
+	F_Draw_bytesperline *f;
+
+	f = fp;
+	*f->ret = bytesperline(IRECT(f->r), f->d);
+}
+
+Draw_Image*
+color(DDisplay *dd, ulong color)
+{
+	int c;
+	Draw_Rect r;
+
+	r.min.x = 0;
+	r.min.y = 0;
+	r.max.x = 1;
+	r.max.y = 1;
+	c = (color&0xff) == 0xff ? RGB24: RGBA32;
+	return allocdrawimage(dd, r, c, nil, 1, color);
+}
+
+Draw_Image*
+mkdrawimage(Image *i, Draw_Screen *screen, Draw_Display *display, void *ref)
+{
+	Heap *h;
+	DImage *di;
+
+	h = heap(TImage);
+	if(h == H)
+		return H;
+
+	di = H2D(DImage*, h);
+	di->image = i;
+	di->drawimage.screen = screen;
+	if(screen != H)
+		D2H(screen)->ref++;
+	di->drawimage.display = display;
+	if(display != H)
+		D2H(display)->ref++;
+	di->refreshptr = ref;
+
+	R2R(di->drawimage.r, i->r);
+	R2R(di->drawimage.clipr, i->clipr);
+	di->drawimage.chans.desc = i->chan;
+	di->drawimage.depth = i->depth;
+	di->drawimage.repl = i->repl;
+	di->flush = 1;
+	di->dref = i->display->limbo;
+	di->dref->ref++;
+	return &di->drawimage;
+}
+
+void
+Screen_newwindow(void *fp)
+{
+	F_Screen_newwindow *f;
+	Image *i;
+	Screen *s;
+	Rectangle r;
+	int locked;
+	void *v;
+
+	f = fp;
+	s = checkscreen(f->screen);
+	R2R(r, f->r);
+
+	if(f->backing != Refnone && f->backing != Refbackup)
+		f->backing = Refbackup;
+
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	locked = lockdisplay(s->display);
+	i = allocwindow(s, r, f->backing, f->color);
+	if(locked)
+		unlockdisplay(s->display);
+	if(i == nil)
+		return;
+
+	*f->ret = mkdrawimage(i, f->screen, f->screen->display, 0);
+}
+
+static
+void
+screentopbot(Draw_Screen *screen, Array *array, void (*topbot)(Image **, int))
+{
+	Screen *s;
+	Draw_Image **di;
+	Image **ip;
+	int i, n, locked;
+
+	s = checkscreen(screen);
+	di = (Draw_Image**)array->data;
+	ip = malloc(array->len * sizeof(Image*));
+	if(ip == nil)
+		return;
+	n = 0;
+	for(i=0; i<array->len; i++)
+		if(di[i] != H){
+			ip[n] = lookupimage(di[i]);
+			if(ip[n]==nil || ip[n]->screen != s){
+				free(ip);
+				return;
+			}
+			n++;
+		}
+	if(n == 0){
+		free(ip);
+		return;
+	}
+	locked = lockdisplay(s->display);
+	(*topbot)(ip, n);
+	free(ip);
+	flushimage(s->display, 1);
+	if(locked)
+		unlockdisplay(s->display);
+}
+
+void
+Screen_top(void *fp)
+{
+	F_Screen_top *f;
+	f = fp;
+	screentopbot(f->screen, f->wins, topnwindows);
+}
+
+void
+Screen_bottom(void *fp)
+{
+	F_Screen_top *f;
+	f = fp;
+	screentopbot(f->screen, f->wins, bottomnwindows);
+}
+
+void
+freedrawimage(Heap *h, int swept)
+{
+	Image *i;
+	int locked;
+	Display *disp;
+	Draw_Image *d;
+
+	d = H2D(Draw_Image*, h);
+	i = lookupimage(d);
+	if(i == nil) {
+		if(!swept)
+			freeptrs(d, TImage);
+		return;
+	}
+	disp = i->display;
+	locked = lockdisplay(disp);
+	freeimage(i);
+	if(locked)
+		unlockdisplay(disp);
+	display_dec(((DImage*)d)->dref);
+	/* image/layer header will be freed by caller */
+}
+
+void
+Image_top(void *fp)
+{
+	F_Image_top *f;
+	Image *i;
+	int locked;
+
+	f = fp;
+	i = checkimage(f->win);
+	locked = lockdisplay(i->display);
+	topwindow(i);
+	flushimage(i->display, 1);
+	if(locked)
+		unlockdisplay(i->display);
+}
+
+void
+Image_origin(void *fp)
+{
+	F_Image_origin *f;
+	Image *i;
+	int locked;
+
+	f = fp;
+	i = checkimage(f->win);
+	locked = lockdisplay(i->display);
+	if(originwindow(i, IPOINT(f->log), IPOINT(f->scr)) < 0)
+		*f->ret = -1;
+	else{
+		f->win->r = DRECT(i->r);
+		f->win->clipr = DRECT(i->clipr);
+		*f->ret = 1;
+	}
+	if(locked)
+		unlockdisplay(i->display);
+}
+
+void
+Image_bottom(void *fp)
+{
+	F_Image_top *f;
+	Image *i;
+	int locked;
+
+	f = fp;
+	i = checkimage(f->win);
+	locked = lockdisplay(i->display);
+	bottomwindow(i);
+	flushimage(i->display, 1);
+	if(locked)
+		unlockdisplay(i->display);
+}
+
+Draw_Image*
+allocdrawimage(DDisplay *ddisplay, Draw_Rect r, ulong chan, Image *iimage, int repl, int color)
+{
+	Heap *h;
+	DImage *di;
+	Rectangle rr;
+	Image *image;
+
+	image = iimage;
+	if(iimage == nil){
+		R2R(rr, r);
+		image = allocimage(ddisplay->display, rr, chan, repl, color);
+		if(image == nil)
+			return H;
+	}
+
+	h = heap(TImage);
+	if(h == H){
+		if(iimage == nil)
+			freeimage(image);
+		return H;
+	}
+
+	di = H2D(DImage*, h);
+	di->drawimage.r = r;
+	R2R(di->drawimage.clipr, image->clipr);
+	di->drawimage.chans.desc = chan;
+	di->drawimage.depth = chantodepth(chan);
+	di->drawimage.repl = repl;
+	di->drawimage.display = (Draw_Display*)ddisplay;
+	D2H(di->drawimage.display)->ref++;
+	di->drawimage.screen = H;
+	di->dref = ddisplay->display->limbo;
+	di->dref->ref++;
+	di->image = image;
+	di->refreshptr = 0;
+	di->flush = 1;
+
+	return &di->drawimage;
+}
+
+/*
+ * Entry points called from the draw library
+ */
+Subfont*
+lookupsubfont(Display *d, char *name)
+{
+	Cache *c;
+
+	c = cachelookup(sfcache, d, name);
+	if(c == nil)
+		return nil;
+	/*c->u.sf->ref++;*/	/* TO DO: need to revisit the reference counting */
+	return c->u.sf;
+}
+
+void
+installsubfont(char *name, Subfont *subfont)
+{
+	Cache *c;
+
+	c = cacheinstall(sfcache, subfont->bits->display, name, subfont, "subfont");
+	if(c)
+		c->ref++;
+}
+
+/*
+ * BUG version
+ */
+char*
+subfontname(char *cfname, char *fname, int maxdepth)
+{
+	char *t, *u, tmp1[256], tmp2[256];
+	int i, fd;
+
+	if(strcmp(cfname, deffontname) == 0)
+		return strdup(cfname);
+	t = cfname;
+	if(t[0] != '/'){
+		strcpy(tmp2, fname);
+		u = utfrrune(tmp2, '/');
+		if(u)
+			u[0] = 0;
+		else
+			strcpy(tmp2, ".");
+		snprint(tmp1, sizeof tmp1, "%s/%s", tmp2, t);
+		t = tmp1;
+	}
+
+	if(maxdepth > 8)
+		maxdepth = 8;
+
+	for(i=3; i>=0; i--){
+		if((1<<i) > maxdepth)
+			continue;
+		/* try i-bit grey */
+		snprint(tmp2, sizeof tmp2, "%s.%d", t, i);
+		fd = libopen(tmp2, OREAD);
+		if(fd >= 0){
+			libclose(fd);
+			return strdup(tmp2);
+		}
+	}
+
+	return strdup(t);
+}
+
+void
+refreshslave(Display *d)
+{
+	int i, n, id;
+	uchar buf[5*(5*4)], *p;
+	Rectangle r;
+	Image *im;
+	int locked;
+
+	for(;;){
+		release();
+		n = kchanio(d->refchan, buf, sizeof buf, OREAD);
+		acquire();
+		if(n < 0)	/* probably caused by closedisplay() closing refchan */
+			return;	/* will fall off end of thread and close down */
+		locked = lockdisplay(d);
+		p = buf;
+		for(i=0; i<n; i+=5*4,p+=5*4){
+			id = BGLONG(p+0*4);
+			r.min.x = BGLONG(p+1*4);
+			r.min.y = BGLONG(p+2*4);
+			r.max.x = BGLONG(p+3*4);
+			r.max.y = BGLONG(p+4*4);
+			for(im=d->windows; im; im=im->next)
+				if(im->id == id)
+					break;
+			if(im && im->screen && im->reffn)
+				(*im->reffn)(im, r, im->refptr);
+		}
+		flushimage(d, 1);
+		if(locked)
+			unlockdisplay(d);
+	}
+}
+
+void
+startrefresh(Display *disp)
+{
+	USED(disp);
+}
+
+static
+int
+doflush(Display *d)
+{
+	int m, n;
+	char err[ERRMAX];
+	uchar *tp;
+
+	n = d->bufp-d->buf;
+	if(n <= 0)
+		return 1;
+
+	if(d->local == 0)
+		release();
+	if((m = kchanio(d->datachan, d->buf, n, OWRITE)) != n){
+		if(d->local == 0)
+			acquire();
+		kgerrstr(err, sizeof err);
+		if(_drawdebug || strcmp(err, "screen id in use") != 0 && strcmp(err, exImage) != 0){
+			print("flushimage fail: (%d not %d) d=%lux: %s\nbuffer: ", m, n, (ulong)d, err);
+			for(tp = d->buf; tp < d->bufp; tp++)
+				print("%.2x ", (int)*tp);
+			print("\n");
+		}
+		d->bufp = d->buf;	/* might as well; chance of continuing */
+		return -1;
+	}
+	d->bufp = d->buf;
+	if(d->local == 0)
+		acquire();
+	return 1;
+}
+
+int
+flushimage(Display *d, int visible)
+{
+	int ret;
+	Refreshq *r;
+
+	for(;;){
+		if(visible)
+			*d->bufp++ = 'v';	/* one byte always reserved for this */
+		ret = doflush(d);
+		if(d->refhead == nil)
+			break;
+		while(r = d->refhead){	/* assign = */
+			d->refhead = r->next;
+			if(d->refhead == nil)
+				d->reftail = nil;
+			r->reffn(nil, r->r, r->refptr);
+			free(r);
+		}
+	}
+	return ret;
+}
+
+/*
+ * Turn off refresh for this window and remove any pending refresh events for it.
+ */
+void
+delrefresh(Image *i)
+{
+	Refreshq *r, *prev, *next;
+	int locked;
+	Display *d;
+	void *refptr;
+
+	d = i->display;
+	/*
+	 * Any refresh function will do, because the data pointer is nil.
+	 * Can't use nil, though, because that turns backing store back on.
+	 */
+	if(d->local)
+		drawlsetrefresh(d->dataqid, i->id, memlnorefresh, nil);
+	refptr = i->refptr;
+	i->refptr = nil;
+	if(d->refhead==nil || refptr==nil)
+		return;
+	locked = lockdisplay(d);
+	prev = nil;
+	for(r=d->refhead; r; r=next){
+		next = r->next;
+		if(r->refptr == refptr){
+			if(prev)
+				prev->next = next;
+			else
+				d->refhead = next;
+			if(d->reftail == r)
+				d->reftail = prev;
+			free(r);
+		}else
+			prev = r;
+	}
+	if(locked)
+		unlockdisplay(d);
+}
+
+void
+queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr)
+{
+	Display *d;
+	Refreshq *rq;
+
+	d = i->display;
+	rq = malloc(sizeof(Refreshq));
+	if(rq == nil)
+		return;
+	if(d->reftail)
+		d->reftail->next = rq;
+	else
+		d->refhead = rq;
+	d->reftail = rq;
+	rq->reffn = reffn;
+	rq->refptr = refptr;
+	rq->r = r;
+}
+
+uchar*
+bufimage(Display *d, int n)
+{
+	uchar *p;
+
+	if(n<0 || n>Displaybufsize){
+		kwerrstr("bad count in bufimage");
+		return 0;
+	}
+	if(d->bufp+n > d->buf+Displaybufsize){
+		if(d->local==0 && currun()!=libqlowner(d->qlock)) {
+			print("bufimage: %lux %lux\n", (ulong)libqlowner(d->qlock), (ulong)currun());
+			abort();
+		}
+		if(doflush(d) < 0)
+			return 0;
+	}
+	p = d->bufp;
+	d->bufp += n;
+	/* return with buffer locked */
+	return p;
+}
+
+void
+drawerror(Display *d, char *s)
+{
+	USED(d);
+	fprint(2, "draw: %s: %r\n", s);
+}
--- /dev/null
+++ b/libinterp/freetype.c
@@ -1,0 +1,231 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "freetypemod.h"
+#include "freetype.h"
+
+
+typedef struct Face Face;
+struct Face {
+	Freetype_Face	freetypeface;		/* limbo part */
+	FTface		ftface;			/* private parts */
+};
+
+Type*	TMatrix;
+Type*	TVector;
+Type*	TFace;
+Type*	TGlyph;
+
+static uchar	Matrixmap[] = Freetype_Matrix_map;
+static uchar	Vectormap[] = Freetype_Vector_map;
+static uchar	Facemap[] = Freetype_Face_map;
+static uchar	Glyphmap[] = Freetype_Glyph_map;
+
+static void		freeface(Heap*, int);
+static Face*	ckface(Freetype_Face*);
+
+void
+freetypemodinit(void)
+{
+	builtinmod("$Freetype", Freetypemodtab, Freetypemodlen);
+	TMatrix = dtype(freeheap, sizeof(Freetype_Matrix), Matrixmap, sizeof(Matrixmap));
+	TVector = dtype(freeheap, sizeof(Freetype_Vector), Vectormap, sizeof(Vectormap));
+	TFace = dtype(freeface, sizeof(Face), Facemap, sizeof(Facemap));
+	TGlyph = dtype(freeheap, sizeof(Freetype_Glyph), Glyphmap, sizeof(Glyphmap));
+}
+
+void
+Face_haschar(void *fp)
+{
+	F_Face_haschar *f = fp;
+	Face *face;
+
+	*f->ret = 0;
+	face = ckface(f->face);
+	release();
+	*f->ret = fthaschar(face->ftface, f->c);
+	acquire();
+}
+
+void
+Face_loadglyph(void *fp)
+{
+	F_Face_loadglyph *f = fp;
+	Heap *h;
+	Face *face;
+	Freetype_Glyph *g;
+	FTglyph ftg;
+	int n, i, s1bpr, s2bpr;
+	char *err;
+
+	face = ckface(f->face);
+
+	destroy(*f->ret);
+	*f->ret = H;
+
+	release();
+	err = ftloadglyph(face->ftface, f->c, &ftg);
+	acquire();
+	if (err != nil) {
+		kwerrstr(err);
+		return;
+	}
+
+	h = heap(TGlyph);
+	if (h == H) {
+		kwerrstr(exNomem);
+		return;
+	}
+	g = H2D(Freetype_Glyph*, h);
+	n = ftg.width*ftg.height;
+	h = heaparray(&Tbyte, n);
+	if (h == H) {
+		destroy(g);
+		kwerrstr(exNomem);
+		return;
+	}
+	g->bitmap = H2D(Array*, h);
+	g->top = ftg.top;
+	g->left = ftg.left;
+	g->height = ftg.height;
+	g->width = ftg.width;
+	g->advance.x = ftg.advx;
+	g->advance.y = ftg.advy;
+
+	s1bpr = ftg.width;
+	s2bpr = ftg.bpr;
+	for (i = 0; i < ftg.height; i++)
+		memcpy(g->bitmap->data+(i*s1bpr), ftg.bitmap+(i*s2bpr), s1bpr);
+	*f->ret = g;
+}
+
+void
+Freetype_newface(void *fp)
+{
+	F_Freetype_newface *f = fp;
+	Heap *h;
+	Face *face;
+	Freetype_Face *limboface;
+	FTfaceinfo finfo;
+	char *path;
+	char *err;
+
+	destroy(*f->ret);
+	*f->ret = H;
+
+	h = heapz(TFace);
+	if (h == H) {
+		kwerrstr(exNomem);
+		return;
+	}
+
+	face = H2D(Face*, h);
+	limboface = (Freetype_Face*)face;
+	*f->ret = limboface;
+	path = strdup(string2c(f->path));	/* string2c() can call error() */
+	release();
+	err = ftnewface(path, f->index, &face->ftface, &finfo);
+	acquire();
+	free(path);
+	if (err != nil) {
+		*f->ret = H;
+		destroy(face);
+		kwerrstr(err);
+		return;
+	}
+	limboface->nfaces = finfo.nfaces;
+	limboface->index = finfo.index;
+	limboface->style = finfo.style;
+	limboface->height = finfo.height;
+	limboface->ascent = finfo.ascent;
+	limboface->familyname = c2string(finfo.familyname, strlen(finfo.familyname));
+	limboface->stylename = c2string(finfo.stylename, strlen(finfo.stylename));
+	*f->ret = limboface;
+}
+
+void
+Freetype_newmemface(void *fp)
+{
+	F_Freetype_newmemface *f = fp;
+
+	destroy(*f->ret);
+	*f->ret = H;
+
+	kwerrstr("not implemented");
+}
+
+void
+Face_setcharsize(void *fp)
+{
+	F_Face_setcharsize *f = fp;
+	Face *face;
+	Freetype_Face *limboface;
+	FTfaceinfo finfo;
+	char *err;
+
+	face = ckface(f->face);
+	limboface = (Freetype_Face*)face;
+	release();
+	err = ftsetcharsize(face->ftface, f->pts, f->hdpi, f->vdpi, &finfo);
+	acquire();
+	if (err == nil) {
+		limboface->height = finfo.height;
+		limboface->ascent = finfo.ascent;
+	}
+	retstr(err, f->ret);
+}
+
+void
+Face_settransform(void *fp)
+{
+	F_Face_settransform *f = fp;
+	FTmatrix *m = nil;
+	FTvector *v = nil;
+	Face *face;
+
+	face = ckface(f->face);
+
+	/*
+	 * ftsettransform() has no error return
+	 * we have one for consistency - but always nil for now
+	 */
+	destroy(*f->ret);
+	*f->ret = H;
+
+	if (f->m != H)
+		m = (FTmatrix*)(f->m);
+	if (f->v != H)
+		v = (FTvector*)(f->v);
+	release();
+	ftsettransform(face->ftface, m, v);
+	acquire();
+}
+
+static void
+freeface(Heap *h, int swept)
+{
+	Face *face = H2D(Face*, h);
+
+	if (!swept) {
+		destroy(face->freetypeface.familyname);
+		destroy(face->freetypeface.stylename);
+	}
+	release();
+	ftdoneface(face->ftface);
+	acquire();
+	memset(&face->ftface, 0, sizeof(face->ftface));
+}
+
+static Face*
+ckface(Freetype_Face *face)
+{
+	if (face == nil || face == H)
+		error("nil Face");
+	if (D2H(face)->t != TFace)
+		error(exType);
+	return (Face*)face;
+}
+
--- /dev/null
+++ b/libinterp/gc.c
@@ -1,0 +1,383 @@
+#include "lib9.h"
+#include "interp.h"
+#include "pool.h"
+
+enum
+{
+	Quanta		= 50,		/* Allocated blocks to sweep each time slice usually */
+	MaxQuanta	= 15*Quanta,
+	PTRHASH		= (1<<5)
+};
+
+static int quanta = Quanta;
+static int gce, gct = 1;
+
+typedef struct Ptrhash Ptrhash;
+struct Ptrhash
+{
+	Heap	*value;
+	Ptrhash	*next;
+};
+
+	int	nprop;
+	int	gchalt;
+	int	mflag;
+	int	mutator = 0;
+	int	gccolor = 3;
+
+	ulong	gcnruns;
+	ulong	gcsweeps;
+	ulong	gcbroken;
+	ulong	gchalted;
+	ulong	gcepochs;
+	uvlong	gcdestroys;
+	uvlong	gcinspects;
+
+static	int	marker  = 1;
+static	int	sweeper = 2;
+static	Bhdr*	base;
+static	Bhdr*	limit;
+Bhdr*	ptr;
+static	int	visit;
+extern	Pool*	heapmem;
+static	Ptrhash	*ptrtab[PTRHASH];
+static	Ptrhash	*ptrfree;
+
+#define	HASHPTR(p)	(((ulong)(p) >> 6) & (PTRHASH - 1))
+
+void
+ptradd(Heap *v)
+{
+	int h;
+	Ptrhash *p;
+
+	if ((p = ptrfree) != nil)
+		ptrfree = p->next;
+	else if ((p = malloc(sizeof (Ptrhash))) == nil)
+		error("ptradd malloc");
+	h = HASHPTR(v);
+	p->value = v;
+	p->next = ptrtab[h];
+	ptrtab[h] = p;
+}
+
+void
+ptrdel(Heap *v)
+{
+	Ptrhash	*p, **l;
+
+	for (l = &ptrtab[HASHPTR(v)]; (p = *l) != nil; l = &p->next) {
+		if (p->value == v) {
+			*l = p->next;
+			p->next = ptrfree;
+			ptrfree = p;
+			return;
+		}
+	}
+	/* ptradd must have failed */
+}
+
+static void
+ptrmark(void)
+{
+	int	i;
+	Heap	*h;
+	Ptrhash	*p;
+
+	for (i = 0; i < PTRHASH; i++) {
+		for (p = ptrtab[i]; p != nil; p = p->next) {
+			h = p->value;
+			Setmark(h);
+		}
+	}
+}
+
+void
+noptrs(Type *t, void *vw)
+{
+	USED(t);
+	USED(vw);
+}
+
+static int markdepth;
+
+/* code simpler with a depth search compared to a width search*/
+void
+markheap(Type *t, void *vw)
+{
+	Heap *h;
+	uchar *p;
+	int i, c, m;
+	WORD **w, **q;
+	Type *t1;
+
+	if(t == nil || t->np == 0)
+		return;
+
+	markdepth++;
+	w = (WORD**)vw;
+	p = t->map;
+	for(i = 0; i < t->np; i++) {
+		c = *p++;
+		if(c != 0) {
+			q = w;
+			for(m = 0x80; m != 0; m >>= 1) {
+				if((c & m) && *q != H) {
+					h = D2H(*q);
+					Setmark(h);
+					if(h->color == propagator && --visit >= 0 && markdepth < 64){
+						gce--;
+						h->color = mutator;
+						if((t1 = h->t) != nil)
+							t1->mark(t1, H2D(void*, h));
+					}
+				}
+				q++;
+			}
+		}
+		w += 8;
+	}
+	markdepth--;
+}
+
+/*
+ * This routine should be modified to be incremental, but how?
+ */
+void
+markarray(Type *t, void *vw)
+{
+	int i;
+	Heap *h;
+	uchar *v;
+	Array *a;
+
+	USED(t);
+
+	a = vw;
+	t = a->t;
+	if(a->root != H) {
+		h = D2H(a->root);
+		Setmark(h);
+	}
+
+	if(t->np == 0)
+		return;
+
+	v = a->data;
+	for(i = 0; i < a->len; i++) {
+		markheap(t, v);
+		v += t->size;
+	}
+	visit -= a->len;
+}
+
+void
+marklist(Type *t, void *vw)
+{
+	List *l;
+	Heap *h;
+
+	USED(t);
+	l = vw;
+	markheap(l->t, l->data);
+	while(visit > 0) {
+		l = l->tail;
+		if(l == H)
+			return;
+		h = D2H(l);
+		Setmark(h);
+		markheap(l->t, l->data);
+		visit--;
+	}
+	l = l->tail;
+	if(l != H) {
+		D2H(l)->color = propagator;
+		nprop = 1;
+	}
+}
+
+static void
+rootset(Prog *root)
+{
+	Heap *h;
+	Type *t;
+	Frame *f;
+	Module *m;
+	Stkext *sx;
+	Modlink *ml;
+	uchar *fp, *sp, *ex, *mp;
+
+	mutator = gccolor % 3;
+	marker = (gccolor-1)%3;
+	sweeper = (gccolor-2)%3;
+
+	while(root != nil) {
+		ml = root->R.M;
+		h = D2H(ml);
+		Setmark(h);
+		mp = ml->MP;
+		if(mp != H) {
+			h = D2H(mp);
+			Setmark(h);
+		}
+
+		sp = root->R.SP;
+		ex = root->R.EX;
+		while(ex != nil) {
+			sx = (Stkext*)ex;
+			fp = sx->reg.tos.fu;
+			while(fp != sp) {
+				f = (Frame*)fp;
+				t = f->t;
+				if(t == nil)
+					t = sx->reg.TR;
+				fp += t->size;
+				t->mark(t, f);
+				ml = f->mr;
+				if(ml != nil) {
+					h = D2H(ml);
+					Setmark(h);
+					mp = ml->MP;
+					if(mp != H) {
+						h = D2H(mp);
+						Setmark(h);
+					}
+				}
+			}
+			ex = sx->reg.EX;
+			sp = sx->reg.SP;
+		}
+
+		root = root->next;
+	}
+
+	for(m = modules; m != nil; m = m->link) {
+		if(m->origmp != H) {
+			h = D2H(m->origmp);
+			Setmark(h);
+		}
+	}
+
+	ptrmark();
+}
+
+static int
+okbhdr(Bhdr *b)
+{
+	if(b == nil)
+		return 0;
+	switch(b->magic) {
+	case MAGIC_A:
+	case MAGIC_F:
+	case MAGIC_E:
+	case MAGIC_I:
+		return 1;
+	}
+	return 0;
+}
+
+static void
+domflag(Heap *h)
+{
+	int i;
+	Module *m;
+
+	print("sweep h=0x%lux t=0x%lux c=%d", (ulong)h, (ulong)h->t, h->color);
+	for(m = modules; m != nil; m = m->link) {
+		for(i = 0; i < m->ntype; i++) {
+			if(m->type[i] == h->t) {
+				print(" module %s desc %d", m->name, i);
+				break;
+			}
+		}
+	}
+	print("\n");
+	if(mflag > 1)
+		abort();
+}
+
+void
+rungc(Prog *p)
+{
+	Type *t;
+	Heap *h;
+	Bhdr *b;
+
+	gcnruns++;
+	if(gchalt) {
+		gchalted++;
+		return;
+	}
+	if(base == nil) {
+		gcsweeps++;
+		b = poolchain(heapmem);
+		base = b;
+		ptr = b;
+		limit = B2LIMIT(b);
+	}
+
+	/* Chain broken ? */
+	if(!okbhdr(ptr)) {
+		base = nil;
+		gcbroken++;
+		return;
+	}
+
+	for(visit = quanta; visit > 0; ) {
+		if(ptr->magic == MAGIC_A) {
+			visit--;
+			gct++;
+			gcinspects++;
+			h = B2D(ptr);
+			t = h->t;
+			if(h->color == propagator) {
+				gce--;
+				h->color = mutator;
+				if(t != nil)
+					t->mark(t, H2D(void*, h));
+			}
+			else
+			if(h->color == sweeper) {
+				gce++;
+				if(0 && mflag)
+					domflag(h);
+				if(heapmonitor != nil)
+					heapmonitor(2, h, 0);
+				if(t != nil) {
+					gclock();
+					t->free(h, 1);
+					gcunlock();
+					freetype(t);
+				}
+				gcdestroys++;
+				poolfree(heapmem, h);
+			}
+		}
+		ptr = B2NB(ptr);
+		if(ptr >= limit) {
+			base = base->clink;
+			if(base == nil)
+				break;
+			ptr = base;
+			limit = B2LIMIT(base);
+		}
+	}
+
+	quanta = (MaxQuanta+Quanta)/2 + ((MaxQuanta-Quanta)/20)*((100*gce)/gct);
+	if(quanta < Quanta)
+		quanta = Quanta;
+	if(quanta > MaxQuanta)
+		quanta = MaxQuanta;
+
+	if(base != nil)		/* Completed this iteration ? */
+		return;
+	if(nprop == 0) {	/* Completed the epoch ? */
+		gcepochs++;
+		gccolor++;
+		rootset(p);
+		gce = 0;
+		gct = 1;
+		return;
+	}
+	nprop = 0;
+}
--- /dev/null
+++ b/libinterp/geom.c
@@ -1,0 +1,309 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "draw.h"
+#include "runt.h"
+#include "raise.h"
+
+void
+Point_add(void *fp)
+{
+	F_Point_add *f;
+	Draw_Point *ret;
+
+	f = fp;
+
+	ret = f->ret;
+	ret->x = f->p.x + f->q.x;
+	ret->y = f->p.y + f->q.y;
+}
+
+void
+Point_sub(void *fp)
+{
+	F_Point_sub *f;
+	Draw_Point *ret;
+
+	f = fp;
+
+	ret = f->ret;
+	ret->x = f->p.x - f->q.x;
+	ret->y = f->p.y - f->q.y;
+}
+
+void
+Point_mul(void *fp)
+{
+	F_Point_mul *f;
+	Draw_Point *ret;
+
+	f = fp;
+
+	ret = f->ret;
+	ret->x = f->p.x * f->i;
+	ret->y = f->p.y * f->i;
+}
+
+void
+Point_div(void *fp)
+{
+	F_Point_div *f;
+	Draw_Point *ret;
+
+	f = fp;
+
+	if(f->i == 0)
+		error(exZdiv);
+	ret = f->ret;
+	ret->x = f->p.x / f->i;
+	ret->y = f->p.y / f->i;
+}
+
+void
+Point_eq(void *fp)
+{
+	F_Point_eq *f;
+
+	f = fp;
+	*f->ret = f->p.x == f->q.x && f->p.y == f->q.y;
+}
+
+void
+Point_in(void *fp)
+{
+	F_Point_in *f;
+
+	f = fp;
+	*f->ret = f->p.x >= f->r.min.x && f->p.x < f->r.max.x &&
+	       f->p.y >= f->r.min.y && f->p.y < f->r.max.y;
+}
+
+void
+Rect_canon(void *fp)
+{
+	F_Rect_canon *f;
+	Draw_Rect *ret;
+	WORD t;
+
+	f = fp;
+
+	ret = f->ret;
+	if(f->r.max.x < f->r.min.x){
+		t = f->r.max.x;
+		ret->max.x = f->r.min.x;
+		ret->min.x = t;
+	}else{
+		t = f->r.max.x;
+		ret->min.x = f->r.min.x;
+		ret->max.x = t;
+	}
+	if(f->r.max.y < f->r.min.y){
+		t = f->r.max.y;
+		ret->max.y = f->r.min.y;
+		ret->min.y = t;
+	}else{
+		t = f->r.max.y;
+		ret->min.y = f->r.min.y;
+		ret->max.y = t;
+	}
+}
+
+void
+Rect_combine(void *fp)
+{
+	F_Rect_combine *f;
+	Draw_Rect *ret;
+
+	f = fp;
+	ret = f->ret;
+	*ret = f->r;
+	if(f->r.min.x > f->s.min.x)
+		ret->min.x = f->s.min.x;
+	if(f->r.min.y > f->s.min.y)
+		ret->min.y = f->s.min.y;
+	if(f->r.max.x < f->s.max.x)
+		ret->max.x = f->s.max.x;
+	if(f->r.max.y < f->s.max.y)
+		ret->max.y = f->s.max.y;
+}
+
+void
+Rect_eq(void *fp)
+{
+	F_Rect_eq *f;
+
+	f = fp;
+
+	*f->ret = f->r.min.x == f->s.min.x
+		&& f->r.max.x == f->s.max.x
+		&& f->r.min.y == f->s.min.y
+		&& f->r.max.y == f->s.max.y;
+}
+
+void
+Rect_Xrect(void *fp)
+{
+	F_Rect_Xrect *f;
+
+	f = fp;
+
+	*f->ret = f->r.min.x < f->s.max.x
+		&& f->s.min.x < f->r.max.x
+		&& f->r.min.y < f->s.max.y
+		&& f->s.min.y < f->r.max.y;
+}
+
+void
+Rect_clip(void *fp)
+{
+	F_Rect_clip *f;
+	Draw_Rect *r, *s, *ret;
+
+	f = fp;
+
+	r = &f->r;
+	s = &f->s;
+	ret = &f->ret->t0;
+
+	/*
+	 * Expand rectXrect() in line for speed
+	 */
+	if(!(r->min.x<s->max.x && s->min.x<r->max.x
+	&& r->min.y<s->max.y && s->min.y<r->max.y)){
+		*ret = *r;
+		f->ret->t1 = 0;
+		return;
+	}
+
+	/* They must overlap */
+	if(r->min.x < s->min.x)
+		ret->min.x = s->min.x;
+	else
+		ret->min.x = r->min.x;
+	if(r->min.y < s->min.y)
+		ret->min.y = s->min.y;
+	else
+		ret->min.y = r->min.y;
+	if(r->max.x > s->max.x)
+		ret->max.x = s->max.x;
+	else
+		ret->max.x = r->max.x;
+	if(r->max.y > s->max.y)
+		ret->max.y = s->max.y;
+	else
+		ret->max.y = r->max.y;
+	f->ret->t1 = 1;
+}
+
+void
+Rect_inrect(void *fp)
+{
+	F_Rect_inrect *f;
+
+	f = fp;
+
+	*f->ret = f->s.min.x <= f->r.min.x
+		&& f->r.max.x <= f->s.max.x
+		&& f->s.min.y <= f->r.min.y
+		&& f->r.max.y <= f->s.max.y;
+}
+
+void
+Rect_contains(void *fp)
+{
+	F_Rect_contains *f;
+	WORD x, y;
+
+	f = fp;
+
+	x = f->p.x;
+	y = f->p.y;
+	*f->ret = x >= f->r.min.x && x < f->r.max.x
+		&& y >= f->r.min.y && y < f->r.max.y;
+}
+
+void
+Rect_addpt(void *fp)
+{
+	F_Rect_addpt *f;
+	Draw_Rect *ret;
+	WORD n;
+
+	f = fp;
+
+	ret = f->ret;
+	n = f->p.x;
+	ret->min.x = f->r.min.x + n;
+	ret->max.x = f->r.max.x + n;
+	n = f->p.y;
+	ret->min.y = f->r.min.y + n;
+	ret->max.y = f->r.max.y + n;
+}
+
+void
+Rect_subpt(void *fp)
+{
+	WORD n;
+	F_Rect_subpt *f;
+	Draw_Rect *ret;
+
+	f = fp;
+
+	ret = f->ret;
+	n = f->p.x;
+	ret->min.x = f->r.min.x - n;
+	ret->max.x = f->r.max.x - n;
+	n = f->p.y;
+	ret->min.y = f->r.min.y - n;
+	ret->max.y = f->r.max.y - n;
+}
+
+void
+Rect_inset(void *fp)
+{
+	WORD n;
+	Draw_Rect *ret;
+	F_Rect_inset *f;
+
+	f = fp;
+
+	ret = f->ret;
+	n = f->n;
+	ret->min.x = f->r.min.x + n;
+	ret->min.y = f->r.min.y + n;
+	ret->max.x = f->r.max.x - n;
+	ret->max.y = f->r.max.y - n;
+}
+
+void
+Rect_dx(void *fp)
+{
+	F_Rect_dx *f;
+
+	f = fp;
+
+	*f->ret = f->r.max.x-f->r.min.x;
+}
+
+void
+Rect_dy(void *fp)
+{
+	F_Rect_dy *f;
+
+	f = fp;
+
+	*f->ret = f->r.max.y-f->r.min.y;
+}
+
+void
+Rect_size(void *fp)
+{
+	F_Rect_size *f;
+	Draw_Point *ret;
+
+	f = fp;
+
+	ret = f->ret;
+	ret->x = f->r.max.x-f->r.min.x;
+	ret->y = f->r.max.y-f->r.min.y;
+}
--- /dev/null
+++ b/libinterp/heap.c
@@ -1,0 +1,533 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "pool.h"
+#include "raise.h"
+
+void	freearray(Heap*, int);
+void	freelist(Heap*, int);
+void	freemodlink(Heap*, int);
+void	freechan(Heap*, int);
+Type	Tarray = { 1, freearray, markarray, sizeof(Array) };
+Type	Tstring = { 1, freestring, noptrs, sizeof(String) };
+Type	Tlist = { 1, freelist, marklist, sizeof(List) };
+Type	Tmodlink = { 1, freemodlink, markheap, -1, 1, 0, 0, { 0x80 } };
+Type	Tchannel = { 1, freechan, markheap, sizeof(Channel), 1,0,0,{0x80} };
+Type	Tptr = { 1, 0, markheap, sizeof(WORD*), 1, 0, 0, { 0x80 } };
+Type	Tbyte = { 1, 0, 0, 1 };
+Type Tword = { 1, 0, 0, sizeof(WORD) };
+Type Tlong = { 1, 0, 0, sizeof(LONG) };
+Type Treal = { 1, 0, 0, sizeof(REAL) };
+
+extern	Pool*	heapmem;
+extern	int	mutator;
+
+void	(*heapmonitor)(int, void*, ulong);
+
+#define	BIT(bt, nb)	(bt & (1<<nb))
+
+void
+freeptrs(void *v, Type *t)
+{
+	int c;
+	WORD **w, *x;
+	uchar *p, *ep;
+
+	if(t->np == 0)
+		return;
+
+	w = (WORD**)v;
+	p = t->map;
+	ep = p + t->np;
+	while(p < ep) {
+		c = *p;
+		if(c != 0) {
+ 			if(BIT(c, 0) && (x = w[7]) != H) destroy(x);
+			if(BIT(c, 1) && (x = w[6]) != H) destroy(x);
+ 			if(BIT(c, 2) && (x = w[5]) != H) destroy(x);
+			if(BIT(c, 3) && (x = w[4]) != H) destroy(x);
+			if(BIT(c, 4) && (x = w[3]) != H) destroy(x);
+			if(BIT(c, 5) && (x = w[2]) != H) destroy(x);
+			if(BIT(c, 6) && (x = w[1]) != H) destroy(x);
+			if(BIT(c, 7) && (x = w[0]) != H) destroy(x);
+		}
+		p++;
+		w += 8;
+	}
+}
+
+/*
+void
+nilptrs(void *v, Type *t)
+{
+	int c, i;
+	WORD **w;
+	uchar *p, *ep;
+
+	w = (WORD**)v;
+	p = t->map;
+	ep = p + t->np;
+	while(p < ep) {
+		c = *p;
+		for(i = 0; i < 8; i++){
+			if(BIT(c, 7)) *w = H;
+			c <<= 1;
+			w++;
+		}
+		p++;
+	}
+}
+*/
+
+void
+freechan(Heap *h, int swept)
+{
+	Channel *c;
+
+	USED(swept);
+	c = H2D(Channel*, h);
+	if(c->mover == movtmp)
+		freetype(c->mid.t);
+	killcomm(&c->send);
+	killcomm(&c->recv);
+	if (!swept && c->buf != H)
+		destroy(c->buf);
+}
+
+void
+freestring(Heap *h, int swept)
+{
+	String *s;
+
+	USED(swept);
+	s = H2D(String*, h);
+	if(s->tmp != nil)
+		free(s->tmp);
+}
+
+void
+freearray(Heap *h, int swept)
+{
+	int i;
+	Type *t;
+	uchar *v;
+	Array *a;
+
+	a = H2D(Array*, h);
+	t = a->t;
+
+	if(!swept) {
+		if(a->root != H)
+			destroy(a->root);
+		else
+		if(t->np != 0) {
+			v = a->data;
+			for(i = 0; i < a->len; i++) {
+				freeptrs(v, t);
+				v += t->size;
+			}
+		}
+	}
+	if(t->ref-- == 1) {
+		free(t->initialize);
+		free(t);
+	}
+}
+
+void
+freelist(Heap *h, int swept)
+{
+	Type *t;
+	List *l;
+	Heap *th;
+
+	l = H2D(List*, h);
+	t = l->t;
+
+	if(t != nil) {
+		if(!swept && t->np)
+			freeptrs(l->data, t);
+		t->ref--;
+		if(t->ref == 0) {
+			free(t->initialize);
+			free(t);
+		}
+	}
+	if(swept)
+		return;
+	l = l->tail;
+	while(l != (List*)H) {
+		t = l->t;
+		th = D2H(l);
+		if(th->ref-- != 1)
+			break;
+		th->t->ref--;	/* should be &Tlist and ref shouldn't go to 0 here nor be 0 already */
+		if(t != nil) {
+			if (t->np)
+				freeptrs(l->data, t);
+			t->ref--;
+			if(t->ref == 0) {
+				free(t->initialize);
+				free(t);
+			}
+		}
+		l = l->tail;
+		if(heapmonitor != nil)
+			heapmonitor(1, th, 0);
+		poolfree(heapmem, th);
+	}
+}
+
+void
+freemodlink(Heap *h, int swept)
+{
+	Modlink *ml;
+
+	ml = H2D(Modlink*, h);
+	if(ml->m->rt == DYNMOD)
+		freedyndata(ml);
+	else if(!swept)
+		destroy(ml->MP);
+	unload(ml->m);
+}
+
+int
+heapref(void *v)
+{
+	return D2H(v)->ref;
+}
+
+void
+freeheap(Heap *h, int swept)
+{
+	Type *t;
+
+	if(swept)
+		return;
+
+	t = h->t;
+	if (t->np)
+		freeptrs(H2D(void*, h), t);
+}
+
+void
+destroy(void *v)
+{
+	Heap *h;
+	Type *t;
+
+	if(v == H)
+		return;
+
+	h = D2H(v);
+	{ Bhdr *b; D2B(b, h); }		/* consistency check */
+
+	if(--h->ref > 0 || gchalt > 64) 	/* Protect 'C' thread stack */
+		return;
+
+	if(heapmonitor != nil)
+		heapmonitor(1, h, 0);
+	t = h->t;
+	if(t != nil) {
+		gclock();
+		t->free(h, 0);
+		gcunlock();
+		freetype(t);
+	}
+	poolfree(heapmem, h);
+}
+
+Type*
+dtype(void (*destroy)(Heap*, int), int size, uchar *map, int mapsize)
+{
+	Type *t;
+
+	t = malloc(sizeof(Type)-sizeof(t->map)+mapsize);
+	if(t != nil) {
+		t->ref = 1;
+		t->free = destroy;
+		t->mark = markheap;
+		t->size = size;
+		t->np = mapsize;
+		memmove(t->map, map, mapsize);
+	}
+	return t;
+}
+
+void*
+checktype(void *v, Type *t, char *name, int newref)
+{
+	Heap *h;
+
+	if(v == H || v == nil)
+		error(exNilref);
+	h = D2H(v);
+	if(t == nil || h->t != t)
+		errorf("%s: %s", exType, name);
+	if(newref){
+		h->ref++;
+		Setmark(h);
+	}
+	return v;
+}
+
+void
+freetype(Type *t)
+{
+	if(t == nil || --t->ref > 0)
+		return;
+
+	free(t->initialize);
+	free(t);
+}
+
+void
+incmem(void *vw, Type *t)
+{
+	Heap *h;
+	uchar *p;
+	int i, c, m;
+	WORD **w, **q, *wp;
+
+	w = (WORD**)vw;
+	p = t->map;
+	for(i = 0; i < t->np; i++) {
+		c = *p++;
+		if(c != 0) {
+			q = w;
+			for(m = 0x80; m != 0; m >>= 1) {
+				if((c & m) && (wp = *q) != H) {
+					h = D2H(wp);
+					h->ref++;
+					Setmark(h);
+				}
+				q++;
+			}
+		}
+		w += 8;
+	}
+}
+
+void
+scanptrs(void *vw, Type *t, void (*f)(void*))
+{
+	uchar *p;
+	int i, c, m;
+	WORD **w, **q, *wp;
+
+	w = (WORD**)vw;
+	p = t->map;
+	for(i = 0; i < t->np; i++) {
+		c = *p++;
+		if(c != 0) {
+			q = w;
+			for(m = 0x80; m != 0; m >>= 1) {
+				if((c & m) && (wp = *q) != H)
+					f(D2H(wp));
+				q++;
+			}
+		}
+		w += 8;
+	}
+}
+
+void
+initmem(Type *t, void *vw)
+{
+	int c;
+	WORD **w;
+	uchar *p, *ep;
+
+	w = (WORD**)vw;
+	p = t->map;
+	ep = p + t->np;
+	while(p < ep) {
+		c = *p;
+		if(c != 0) {
+ 			if(BIT(c, 0)) w[7] = H;
+			if(BIT(c, 1)) w[6] = H;
+			if(BIT(c, 2)) w[5] = H;
+			if(BIT(c, 3)) w[4] = H;
+			if(BIT(c, 4)) w[3] = H;
+			if(BIT(c, 5)) w[2] = H;
+			if(BIT(c, 6)) w[1] = H;
+			if(BIT(c, 7)) w[0] = H;
+		}
+		p++;
+		w += 8;
+	}
+}
+
+Heap*
+nheap(int n)
+{
+	Heap *h;
+
+	h = poolalloc(heapmem, sizeof(Heap)+n);
+	if(h == nil)
+		error(exHeap);
+
+	h->t = nil;
+	h->ref = 1;
+	h->color = mutator;
+	if(heapmonitor != nil)
+		heapmonitor(0, h, n);
+
+	return h;
+}
+
+Heap*
+heapz(Type *t)
+{
+	Heap *h;
+
+	h = poolalloc(heapmem, sizeof(Heap)+t->size);
+	if(h == nil)
+		error(exHeap);
+
+	h->t = t;
+	t->ref++;
+	h->ref = 1;
+	h->color = mutator;
+	memset(H2D(void*, h), 0, t->size);
+	if(t->np)
+		initmem(t, H2D(void*, h));
+	if(heapmonitor != nil)
+		heapmonitor(0, h, t->size);
+	return h;
+}
+
+Heap*
+heap(Type *t)
+{
+	Heap *h;
+
+	h = poolalloc(heapmem, sizeof(Heap)+t->size);
+	if(h == nil)
+		error(exHeap);
+
+	h->t = t;
+	t->ref++;
+	h->ref = 1;
+	h->color = mutator;
+	if(t->np)
+		initmem(t, H2D(void*, h));
+	if(heapmonitor != nil)
+		heapmonitor(0, h, t->size);
+	return h;
+}
+
+Heap*
+heaparray(Type *t, int sz)
+{
+	Heap *h;
+	Array *a;
+
+	h = nheap(sizeof(Array) + (t->size*sz));
+	h->t = &Tarray;
+	Tarray.ref++;
+	a = H2D(Array*, h);
+	a->t = t;
+	a->len = sz;
+	a->root = H;
+	a->data = (uchar*)a + sizeof(Array);
+	initarray(t, a);
+	return h;
+}
+
+int
+hmsize(void *v)
+{
+	return poolmsize(heapmem, v);
+}
+
+void
+initarray(Type *t, Array *a)
+{
+	int i;
+	uchar *p;
+
+	t->ref++;
+	if(t->np == 0)
+		return;
+
+	p = a->data;
+	for(i = 0; i < a->len; i++) {
+		initmem(t, p);
+		p += t->size;
+	}
+}
+
+void*
+arraycpy(Array *sa)
+{
+	int i;
+	Heap *dh;
+	Array *da;
+	uchar *elemp;
+	void **sp, **dp;
+
+	if(sa == H)
+		return H;
+
+	dh = nheap(sizeof(Array) + sa->t->size*sa->len);
+	dh->t = &Tarray;
+	Tarray.ref++;
+	da = H2D(Array*, dh);
+	da->t = sa->t;
+	da->t->ref++;
+	da->len = sa->len;
+	da->root = H;
+	da->data = (uchar*)da + sizeof(Array);
+	if(da->t == &Tarray) {
+		dp = (void**)da->data;
+		sp = (void**)sa->data;
+		/*
+		 * Maximum depth of this recursion is set by DADEPTH
+		 * in include/isa.h
+		 */
+		for(i = 0; i < sa->len; i++)
+			dp[i] = arraycpy(sp[i]);			
+	}
+	else {
+		memmove(da->data, sa->data, da->len*sa->t->size);
+		elemp = da->data;
+		for(i = 0; i < sa->len; i++) {
+			incmem(elemp, da->t);
+			elemp += da->t->size;
+		}
+	}
+	return da;
+}
+
+void
+newmp(void *dst, void *src, Type *t)
+{
+	Heap *h;
+	int c, i, m;
+	void **uld, *wp, **q;
+
+	memmove(dst, src, t->size);
+	uld = dst;
+	for(i = 0; i < t->np; i++) {
+		c = t->map[i];
+		if(c != 0) {
+			m = 0x80;
+			q = uld;
+			while(m != 0) {
+				if((m & c) && (wp = *q) != H) {
+					h = D2H(wp);
+					if(h->t == &Tarray)
+						*q = arraycpy(wp);
+					else {
+						h->ref++;
+						Setmark(h);
+					}
+				}
+				m >>= 1;
+				q++;
+			}
+		}
+		uld += 8;
+	}
+}
--- /dev/null
+++ b/libinterp/heapaudit.c
@@ -1,0 +1,198 @@
+#include "lib9.h"
+#include "interp.h"
+#include "pool.h"
+
+
+typedef struct Audit Audit;
+struct Audit
+{
+	Type*	t;
+	ulong	n;
+	ulong	size;
+	Audit*	hash;
+};
+Audit*	ahash[128];
+extern	Pool*	heapmem;
+extern void conslog(char*, ...);
+#define	conslog	print
+
+typedef struct Typed	Typed;
+typedef struct Ptyped	Ptyped;
+
+extern Type Trdchan;
+extern Type Twrchan;
+
+struct Typed
+{
+	char*	name;
+	Type*	ptr;
+} types[] =
+{
+	{"array",	&Tarray},
+	{"byte",	&Tbyte},
+	{"channel",	&Tchannel},
+	{"list",	&Tlist},
+	{"modlink",	&Tmodlink},
+	{"ptr",		&Tptr},
+	{"string",	&Tstring},
+
+	{"rdchan",	&Trdchan},
+	{"wrchan",	&Twrchan},
+	{"unspec",	nil},
+
+	0
+};
+
+extern Type* TDisplay;
+extern Type* TFont;
+extern Type* TImage;
+extern Type* TScreen;
+extern Type* TFD;
+extern Type* TFileIO;
+extern Type* Tread;
+extern Type* Twrite;
+extern Type* fakeTkTop;
+
+extern Type* TSigAlg;
+extern Type* TCertificate;
+extern Type* TSK;
+extern Type* TPK;
+extern Type* TDigestState;
+extern Type* TAuthinfo;
+extern Type* TDESstate;
+extern Type* TIPint;
+
+struct Ptyped
+{
+	char*	name;
+	Type**	ptr;
+} ptypes[] =
+{
+	{"Display",	&TDisplay},
+	{"Font",	&TFont},
+	{"Image",	&TImage},
+	{"Screen",	&TScreen},
+
+	{"SigAlg",	&TSigAlg},
+	{"Certificate",	&TCertificate},
+	{"SK",		&TSK},
+	{"PK",		&TPK},
+	{"DigestState",	&TDigestState},
+	{"Authinfo",	&TAuthinfo},
+	{"DESstate",	&TDESstate},
+	{"IPint",	&TIPint},
+
+	{"FD",		&TFD},
+	{"FileIO",	&TFileIO},
+
+/*	{"Fioread",	&Tread},	*/
+/*	{"Fiowrite",	&Twrite},	*/
+
+	{"TkTop",	&fakeTkTop},
+
+	0
+};
+
+static Audit **
+auditentry(Type *t)
+{
+	Audit **h, *a;
+
+	for(h = &ahash[((ulong)t>>2)%nelem(ahash)]; (a = *h) != nil; h = &a->hash)
+		if(a->t == t)
+			break;
+	return h;
+}
+
+void
+heapaudit(void)
+{
+	Type *t;
+	Heap *h;
+	List *l;
+	Array *r;
+	Module *m;
+	int i, ntype, n;
+	Bhdr *b, *base, *limit;
+	Audit *a, **hash;
+
+	acquire();
+
+	b = poolchain(heapmem);
+	base = b;
+	limit = B2LIMIT(b);
+
+	while(b != nil) {
+		if(b->magic == MAGIC_A) {
+			h = B2D(b);
+			t = h->t;
+			n = 1;
+			if(t == &Tlist) {
+				l = H2D(List*, h);
+				t = l->t;
+			} else if(t == &Tarray) {
+				r = H2D(Array*, h);
+				t = r->t;
+				n = r->len;
+			}
+			hash = auditentry(t);
+			if((a = *hash) == nil){
+				a = malloc(sizeof(Audit));
+				if(a == nil)
+					continue;
+				a->n = 1;
+				a->t = t;
+				a->hash = *hash;
+				*hash = a;
+			}else
+				a->n++;
+			if(t != nil && t != &Tmodlink && t != &Tstring)
+				a->size += t->size*n;
+			else
+				a->size += b->size;
+		}
+		b = B2NB(b);
+		if(b >= limit) {
+			base = base->clink;
+			if(base == nil)
+				break;
+			b = base;
+			limit = B2LIMIT(base);
+		}
+	}
+
+	for(m = modules; m != nil; m = m->link) {
+		for(i = 0; i < m->ntype; i++)
+			if((a = *auditentry(m->type[i])) != nil) {
+				conslog("%8ld %8lud %3d %s\n", a->n, a->size, i, m->path);
+				a->size = 0;
+				break;
+			}
+	}
+
+	for(i = 0; (t = types[i].ptr) != nil; i++)
+		if((a = *auditentry(t)) != nil){
+			conslog("%8ld %8lud %s\n", a->n, a->size, types[i].name);
+			a->size = 0;
+			break;
+		}
+
+	for(i = 0; ptypes[i].name != nil; i++)
+		if((a = *auditentry(*ptypes[i].ptr)) != nil){
+			conslog("%8ld %8lud %s\n", a->n, a->size, ptypes[i].name);
+			a->size = 0;
+			break;
+		}
+
+	ntype = 0;
+	for(i = 0; i < nelem(ahash); i++)
+		while((a = ahash[i]) != nil){
+			ahash[i] = a->hash;
+			if(a->size != 0)
+				conslog("%8ld %8lud %p\n", a->n, a->size, a->t);
+			free(a);
+			ntype++;
+		}
+
+	release();
+}
--- /dev/null
+++ b/libinterp/ipint.c
@@ -1,0 +1,848 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include "runt.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "ipint.h"
+#include "raise.h"
+
+#include "ipintsmod.h"
+
+enum
+{
+	MaxBigBytes = 1024
+};
+
+/* infinite precision integer */
+struct IPint
+{
+	IPints_IPint x;
+	mpint*	b;
+};
+
+Type	*TIPint;
+static uchar IPintmap[] = IPints_IPint_map;
+
+#define	MP(x)	checkIPint((x))
+
+void
+ipintsmodinit(void)
+{
+	/* can be called from modinit, Keyring or Crypt */
+	if(TIPint == nil)
+		TIPint = dtype(freeIPint, sizeof(IPint), IPintmap, sizeof(IPintmap));
+	builtinmod("$IPints", IPintsmodtab, IPintsmodlen);
+}
+
+//IPints_IPint*
+void*
+newIPint(mpint* b)
+{
+	Heap *h;
+	IPint *ip;
+
+	if(b == nil)
+		error(exHeap);
+	h = heap(TIPint);	/* TO DO: caller might lose other values if heap raises error here */
+	ip = H2D(IPint*, h);
+	ip->b = b;
+	return (IPints_IPint*)ip;
+}
+
+mpint*
+checkIPint(void *a)
+{
+	IPints_IPint *v;
+	IPint *ip;
+
+	v = a;
+	ip = (IPint*)v;
+	if(ip == H || ip == nil)
+		error(exNilref);
+	if(D2H(ip)->t != TIPint)
+		error(exType);
+	return ip->b;	/* non-nil by construction */
+}
+
+void
+freeIPint(Heap *h, int swept)
+{
+	IPint *ip;
+
+	USED(swept);
+	ip = H2D(IPint*, h);
+	if(ip->b)
+		mpfree(ip->b);
+	freeheap(h, 0);
+}
+
+void
+IPint_iptob64z(void *fp)
+{
+	F_IPint_iptob64 *f;
+	mpint *b;
+	char buf[MaxBigBytes];	/* TO DO: should allocate these */
+	uchar *p;
+	int n, o;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	b = MP(f->i);
+	n = (b->top+1)*Dbytes;
+	p = malloc(n+1);
+	if(p == nil)
+		error(exHeap);
+	n = mptobe(b, p+1, n, nil);
+	if(n < 0){
+		free(p);
+		return;
+	}
+	p[0] = 0;
+	if(n != 0 && (p[1]&0x80)){
+		/* force leading 0 byte for compatibility with older representation */
+		o = 0;
+		n++;
+	}else
+		o = 1;
+	enc64(buf, sizeof(buf), p+o, n);
+	retstr(buf, f->ret);
+	free(p);
+}
+
+void
+IPint_iptob64(void *fp)
+{
+	F_IPint_iptob64 *f;
+	char buf[MaxBigBytes];
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	mptoa(MP(f->i), 64, buf, sizeof(buf));
+	retstr(buf, f->ret);
+}
+
+void
+IPint_iptobytes(void *fp)
+{
+	F_IPint_iptobytes *f;
+	uchar buf[MaxBigBytes];
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	/* TO DO: two's complement or have ipmagtobe? */
+	*f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil));	/* for now we'll ignore sign */
+}
+
+void
+IPint_iptobebytes(void *fp)
+{
+	F_IPint_iptobebytes *f;
+	uchar buf[MaxBigBytes];
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	*f->ret = mem2array(buf, mptobe(MP(f->i), buf, sizeof(buf), nil));
+}
+
+void
+IPint_iptostr(void *fp)
+{
+	F_IPint_iptostr *f;
+	char buf[MaxBigBytes];
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	mptoa(MP(f->i), f->base, buf, sizeof(buf));
+	retstr(buf, f->ret);
+}
+
+static IPints_IPint*
+strtoipint(String *s, int base)
+{
+	char *p, *q;
+	mpint *b;
+
+	p = string2c(s);
+	b = strtomp(p, &q, base, nil);
+	if(b == nil)
+		return H;
+	while(*q == '=')
+		q++;
+	if(q == p || *q != 0){
+		mpfree(b);
+		return H;
+	}
+	return newIPint(b);
+}
+
+void
+IPint_b64toip(void *fp)
+{
+	F_IPint_b64toip *f;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	*f->ret = strtoipint(f->str, 64);
+}
+
+void
+IPint_bytestoip(void *fp)
+{
+	F_IPint_bytestoip *f;
+	mpint *b;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->buf == H)
+		error(exNilref);
+
+	b = betomp(f->buf->data, f->buf->len, nil);	/* for now we'll ignore sign */
+	*f->ret = newIPint(b);
+}
+
+void
+IPint_bebytestoip(void *fp)
+{
+	F_IPint_bebytestoip *f;
+	mpint *b;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	if(f->mag == H)
+		error(exNilref);
+
+	b = betomp(f->mag->data, f->mag->len, nil);
+	*f->ret = newIPint(b);
+}
+
+void
+IPint_strtoip(void *fp)
+{
+	F_IPint_strtoip *f;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	*f->ret = strtoipint(f->str, f->base);
+}
+
+/* create a random integer */
+void
+IPint_random(void *fp)
+{
+	F_IPint_random *f;
+	mpint *b;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	release();
+	b = mprand(f->nbits, genrandom, nil);
+	acquire();
+	*f->ret = newIPint(b);
+}
+
+/* number of bits in number */
+void
+IPint_bits(void *fp)
+{
+	F_IPint_bits *f;
+	int n;
+
+	f = fp;
+	*f->ret = 0;
+	if(f->i == H)
+		return;
+
+	n = mpsignif(MP(f->i));
+	if(n == 0)
+		n = 1;	/* compatibility */
+	*f->ret = n;
+}
+
+/* create a new IP from an int */
+void
+IPint_inttoip(void *fp)
+{
+	F_IPint_inttoip *f;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	*f->ret = newIPint(itomp(f->i, nil));
+}
+
+void
+IPint_iptoint(void *fp)
+{
+	F_IPint_iptoint *f;
+
+	f = fp;
+	*f->ret = 0;
+	if(f->i == H)
+		return;
+	*f->ret = mptoi(MP(f->i));
+}
+
+/* modular exponentiation */
+void
+IPint_expmod(void *fp)
+{
+	F_IPint_expmod *f;
+	mpint *ret, *mod, *base, *exp;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	base = MP(f->base);
+	exp = MP(f->exp);
+	if(f->mod != H)
+		mod = MP(f->mod);
+	else
+		mod = nil;
+	ret = mpnew(0);
+	if(ret != nil)
+		mpexp(base, exp, mod, ret);
+	*f->ret = newIPint(ret);
+}
+
+/* multiplicative inverse */
+void
+IPint_invert(void *fp)
+{
+	F_IPint_invert *f;
+	mpint *ret;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	ret = mpnew(0);
+	if(ret != nil)
+		mpinvert(MP(f->base), MP(f->mod), ret);
+	*f->ret = newIPint(ret);
+}
+
+/* basic math */
+void
+IPint_add(void *fp)
+{
+	F_IPint_add *f;
+	mpint *i1, *i2, *ret;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpadd(i1, i2, ret);
+
+	*f->ret = newIPint(ret);
+}
+void
+IPint_sub(void *fp)
+{
+	F_IPint_sub *f;
+	mpint *i1, *i2, *ret;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpsub(i1, i2, ret);
+
+	*f->ret = newIPint(ret);
+}
+void
+IPint_mul(void *fp)
+{
+	F_IPint_mul *f;
+	mpint *i1, *i2, *ret;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpmul(i1, i2, ret);
+
+	*f->ret = newIPint(ret);
+}
+void
+IPint_div(void *fp)
+{
+	F_IPint_div *f;
+	mpint *i1, *i2, *quo, *rem;
+	void *v;
+
+	f = fp;
+	v = f->ret->t0;
+	f->ret->t0 = H;
+	destroy(v);
+	v = f->ret->t1;
+	f->ret->t1 = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	quo = mpnew(0);
+	if(quo == nil)
+		error(exHeap);
+	rem = mpnew(0);
+	if(rem == nil){
+		mpfree(quo);
+		error(exHeap);
+	}
+	mpdiv(i1, i2, quo, rem);
+
+	f->ret->t0 = newIPint(quo);
+	f->ret->t1 = newIPint(rem);
+}
+void
+IPint_mod(void *fp)
+{
+	F_IPint_mod *f;
+	mpint *i1, *i2, *ret;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpmod(i1, i2, ret);
+
+	*f->ret = newIPint(ret);
+}
+void
+IPint_neg(void *fp)
+{
+	F_IPint_neg *f;
+	mpint *ret;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	ret = mpcopy(MP(f->i));
+	if(ret == nil)
+		error(exHeap);
+	ret->sign = -ret->sign;
+
+	*f->ret = newIPint(ret);
+}
+
+/* copy */
+void
+IPint_copy(void *fp)
+{
+	F_IPint_copy *f;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	*f->ret = newIPint(mpcopy(MP(f->i)));
+}
+
+
+/* equality */
+void
+IPint_eq(void *fp)
+{
+	F_IPint_eq *f;
+
+	f = fp;
+	*f->ret = mpcmp(MP(f->i1), MP(f->i2)) == 0;
+}
+
+/* compare */
+void
+IPint_cmp(void *fp)
+{
+	F_IPint_eq *f;
+
+	f = fp;
+	*f->ret = mpcmp(MP(f->i1), MP(f->i2));
+}
+
+/* shifts */
+void
+IPint_shl(void *fp)
+{
+	F_IPint_shl *f;
+	mpint *ret, *i;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i = MP(f->i);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpleft(i, f->n, ret);
+	*f->ret = newIPint(ret);
+}
+void
+IPint_shr(void *fp)
+{
+	F_IPint_shr *f;
+	mpint *ret, *i;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i = MP(f->i);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpright(i, f->n, ret);
+	*f->ret = newIPint(ret);
+}
+
+static void
+mpand(mpint *b, mpint *m, mpint *res)
+{
+	int i;
+
+	res->sign = b->sign;
+	if(b->top == 0 || m->top == 0){
+		res->top = 0;
+		return;
+	}
+	mpbits(res, b->top*Dbits);
+	res->top = b->top;
+	for(i = b->top; --i >= 0;){
+		if(i < m->top)
+			res->p[i] = b->p[i] & m->p[i];
+		else
+			res->p[i] = 0;
+	}
+	mpnorm(res);
+}
+
+static void
+mpor(mpint *b1, mpint *b2, mpint *res)
+{
+	mpint *t;
+	int i;
+
+	if(b2->top > b1->top){
+		t = b1;
+		b1 = b2;
+		b2 = t;
+	}
+	if(b1->top == 0){
+		mpassign(b2, res);
+		return;
+	}
+	if(b2->top == 0){
+		mpassign(b1, res);
+		return;
+	}
+	mpassign(b1, res);
+	for(i = b2->top; --i >= 0;)
+		res->p[i] |= b2->p[i];
+	mpnorm(res);
+}
+
+static void
+mpxor(mpint *b1, mpint *b2, mpint *res)
+{
+	mpint *t;
+	int i;
+
+	if(b2->top > b1->top){
+		t = b1;
+		b1 = b2;
+		b2 = t;
+	}
+	if(b1->top == 0){
+		mpassign(b2, res);
+		return;
+	}
+	if(b2->top == 0){
+		mpassign(b1, res);
+		return;
+	}
+	mpassign(b1, res);
+	for(i = b2->top; --i >= 0;)
+		res->p[i] ^= b2->p[i];
+	mpnorm(res);
+}
+
+static void
+mpnot(mpint *b1, mpint *res)
+{
+	int i;
+
+	mpbits(res, Dbits*b1->top);
+	res->sign = 1;
+	res->top = b1->top;
+	for(i = res->top; --i >= 0;)
+		res->p[i] = ~b1->p[i];
+	mpnorm(res);
+}
+
+/* bits */
+void
+IPint_and(void *fp)
+{
+	F_IPint_and *f;
+	mpint *ret, *i1, *i2;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpand(i1, i2, ret);
+	*f->ret = newIPint(ret);
+}
+
+void
+IPint_ori(void *fp)
+{
+	F_IPint_ori *f;
+	mpint *ret, *i1, *i2;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpor(i1, i2, ret);
+	*f->ret = newIPint(ret);
+}
+
+void
+IPint_xor(void *fp)
+{
+	F_IPint_xor *f;
+	mpint *ret, *i1, *i2;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	i2 = MP(f->i2);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpxor(i1, i2, ret);
+	*f->ret = newIPint(ret);
+}
+
+void
+IPint_not(void *fp)
+{
+	F_IPint_not *f;
+	mpint *ret, *i1;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	i1 = MP(f->i1);
+	ret = mpnew(0);
+	if(ret != nil)
+		mpnot(i1, ret);
+	*f->ret = newIPint(ret);
+}
+
+/*
+ * primes
+ */
+
+void
+IPints_probably_prime(void *fp)
+{
+	F_IPints_probably_prime *f;
+
+	f = fp;
+	release();
+	*f->ret = probably_prime(checkIPint(f->n), f->nrep);
+	acquire();
+}
+
+void
+IPints_genprime(void *fp)
+{
+	F_IPints_genprime *f;
+	mpint *p;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	p = mpnew(0);
+	release();
+	genprime(p, f->nbits, f->nrep);
+	acquire();
+	*f->ret = newIPint(p);
+}
+
+void
+IPints_genstrongprime(void *fp)
+{
+	F_IPints_genstrongprime *f;
+	mpint *p;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	p = mpnew(0);
+	release();
+	genstrongprime(p, f->nbits, f->nrep);
+	acquire();
+	*f->ret = newIPint(p);
+}
+
+void
+IPints_gensafeprime(void *fp)
+{
+	F_IPints_gensafeprime *f;
+	mpint *p, *alpha;
+	void *v;
+
+	f = fp;
+	v = f->ret->t0;
+	f->ret->t0 = H;
+	destroy(v);
+	v = f->ret->t1;
+	f->ret->t1 = H;
+	destroy(v);
+
+	p = mpnew(0);
+	alpha = mpnew(0);
+	release();
+	gensafeprime(p, alpha, f->nbits, f->nrep);
+	acquire();
+	f->ret->t0 = newIPint(p);
+	f->ret->t1 = newIPint(alpha);
+}
+
+void
+IPints_DSAprimes(void *fp)
+{
+	F_IPints_DSAprimes *f;
+	mpint *p, *q;
+	Heap *h;
+	void *v;
+
+	f = fp;
+	v = f->ret->t0;
+	f->ret->t0 = H;
+	destroy(v);
+	v = f->ret->t1;
+	f->ret->t1 = H;
+	destroy(v);
+	v = f->ret->t2;
+	f->ret->t2 = H;
+	destroy(v);
+
+	h = heaparray(&Tbyte, SHA1dlen);
+	f->ret->t2 = H2D(Array*, h);
+
+	p = mpnew(0);
+	q = mpnew(0);
+	release();
+	DSAprimes(q, p, f->ret->t2->data);
+	acquire();
+	f->ret->t0 = newIPint(q);
+	f->ret->t1 = newIPint(p);
+}
--- /dev/null
+++ b/libinterp/ipint.h
@@ -1,0 +1,12 @@
+typedef struct IPint IPint;
+
+#pragma incomplete IPint
+
+//Keyring_IPint*	newIPint(mpint*);
+void*	newIPint(mpint*);
+//mpint*	checkIPint(Keyring_IPint*);
+mpint*	checkIPint(void*);
+void	freeIPint(Heap*, int);
+void	ipintsmodinit(void);
+
+extern	Type*	TIPint;
--- /dev/null
+++ b/libinterp/keyring.c
@@ -1,0 +1,3083 @@
+#include "lib9.h"
+#include "kernel.h"
+#include <isa.h>
+#include "interp.h"
+#include <mp.h>
+#include <libsec.h>
+#include "pool.h"
+#include "raise.h"
+
+/* arguably limbo -t should qualify type name */
+#define	DigestState_copy Keyring_DigestState_copy
+#define	IPint_random Keyring_IPint_random
+#include "keyringif.h"
+#include "keyring.h"
+
+#include "ipint.h"
+#include "../libkeyring/keys.h"
+
+static Type*	TDigestState;
+static Type*	TAESstate;
+static Type*	TDESstate;
+static Type*	TIDEAstate;
+static Type*	TBFstate;
+static Type*	TRC4state;
+
+static Type*	TSigAlg;
+static Type*	TCertificate;
+static Type*	TSK;
+static Type*	TPK;
+static Type*	TAuthinfo;
+
+static Type*	TDSAsk;
+static Type*	TDSApk;
+static Type*	TDSAsig;
+static Type*	TEGsk;
+static Type*	TEGpk;
+static Type*	TEGsig;
+static Type*	TRSAsk;
+static Type*	TRSApk;
+static Type*	TRSAsig;
+
+enum {
+	Maxmsg=	4096
+};
+
+static uchar DigestStatemap[] = Keyring_DigestState_map;
+static uchar AESstatemap[] = Keyring_AESstate_map;
+static uchar DESstatemap[] = Keyring_DESstate_map;
+static uchar IDEAstatemap[] = Keyring_IDEAstate_map;
+static uchar BFstatemap[] = Keyring_BFstate_map;
+static uchar RC4statemap[] = Keyring_RC4state_map;
+
+static uchar SigAlgmap[] = Keyring_SigAlg_map;
+static uchar SKmap[] = Keyring_SK_map;
+static uchar PKmap[] = Keyring_PK_map;
+static uchar Certificatemap[] = Keyring_Certificate_map;
+static uchar Authinfomap[] = Keyring_Authinfo_map;
+static uchar DSAskmap[] = Keyring_DSAsk_map;
+static uchar DSApkmap[] = Keyring_DSApk_map;
+static uchar DSAsigmap[] = Keyring_DSAsig_map;
+static uchar EGskmap[] = Keyring_EGsk_map;
+static uchar EGpkmap[] = Keyring_EGpk_map;
+static uchar EGsigmap[] = Keyring_EGsig_map;
+static uchar RSAskmap[] = Keyring_RSAsk_map;
+static uchar RSApkmap[] = Keyring_RSApk_map;
+static uchar RSAsigmap[] = Keyring_RSAsig_map;
+
+static	PK*	checkPK(Keyring_PK *k);
+
+extern void		setid(char*, int);
+extern vlong		osusectime(void);
+extern void		freeIPint(Heap*, int);
+
+static char exBadSA[]	= "bad signature algorithm";
+static char exBadSK[]	= "bad secret key";
+static char exBadPK[]	= "bad public key";
+static char exBadCert[]	= "bad certificate";
+static char exBadBsize[]	= "data not multiple of block size";
+static char exBadKey[]	= "bad encryption key";
+static char exBadDigest[]	= "bad digest value";
+static char exBadIvec[]	= "bad ivec";
+static char exBadState[] = "bad encryption state";
+
+typedef struct XBFstate XBFstate;
+
+/* BF state */
+struct XBFstate
+{
+	Keyring_BFstate	x;
+	BFstate	state;
+};
+
+/* convert a Big to base64 ascii */
+int
+bigtobase64(mpint* b, char *buf, int len)
+{
+	uchar *p;
+	int n, rv, o;
+
+	n = (b->top+1)*Dbytes;
+	p = malloc(n+1);
+	if(p == nil)
+		goto Err;
+	n = mptobe(b, p+1, n, nil);
+	if(n < 0)
+		goto Err;
+	p[0] = 0;
+	if(n != 0 && (p[1]&0x80)){
+		/* force leading 0 byte for compatibility with older representation */
+		/* TO DO: if b->sign < 0, complement bits and add one */
+		o = 0;
+		n++;
+	}else
+		o = 1;
+	rv = enc64(buf, len, p+o, n);
+	free(p);
+	return rv;
+
+Err:
+	free(p);
+	if(len > 0){
+		*buf = '*';
+		return 1;
+	}
+	return 0;
+}
+
+/* convert a Big to base64 ascii for %U */
+int
+big64conv(Fmt *f)
+{
+	mpint *b;
+	char *buf;
+	int n;
+
+	b = va_arg(f->args, mpint*);
+	n = (b->top+1)*Dbytes + 1;
+	n = ((n+3)/3)*4 + 1;
+	buf = malloc(n);
+	bigtobase64(b, buf, n);
+	n = fmtstrcpy(f, buf);
+	free(buf);
+	return  n;
+}
+
+static void*
+newthing(Type *t, int add)
+{
+	Heap *h;
+
+	h = heap(t);
+	if(add)
+		ptradd(h);
+	return H2D(void*, h);
+}
+
+static Keyring_IPint*
+ipcopymp(mpint* b)
+{
+	if(b == nil)
+		return H;
+	return newIPint(mpcopy(b));
+}
+
+/* convert a base64 string to a big */
+mpint*
+base64tobig(char *str, char **strp)
+{
+	int n;
+	char *p;
+	mpint *b;
+	uchar hex[(MaxBigBytes*6 + 7)/8];
+
+	for(p = str; *p && *p != '\n'; p++)
+		;
+	if(p == str)
+		return nil;
+	n = dec64(hex, sizeof(hex), str, p - str);
+	b = betomp(hex, n, nil);
+	if(strp){
+		if(*p)
+			p++;
+		*strp = p;
+	}
+	return b;
+}
+
+/*
+ *  signature algorithms
+ */
+enum
+{
+	Maxalg = 8
+};
+static SigAlgVec	*algs[Maxalg];
+static int		nalg;
+
+static SigAlg*
+newSigAlg(SigAlgVec *vec)
+{
+	Heap *h;
+	SigAlg *sa;
+
+	h = heap(TSigAlg);
+	sa = H2D(SigAlg*, h);
+	retstr(vec->name, &sa->x.name);
+	sa->vec = vec;
+	return sa;
+}
+
+static void
+freeSigAlg(Heap *h, int swept)
+{
+	if(!swept)
+		freeheap(h, 0);
+}
+
+SigAlgVec*
+findsigalg(char *name)
+{
+	SigAlgVec **sap;
+
+	for(sap = algs; sap < &algs[nalg]; sap++)
+		if(strcmp(name, (*sap)->name) == 0)
+			return *sap;
+	return nil;
+}
+
+SigAlg*
+strtoalg(char *str, char **strp)
+{
+	int n;
+	char *p, name[20];
+	SigAlgVec *sa;
+
+
+	p = strchr(str, '\n');
+	if(p == 0){
+		p = str + strlen(str);
+		if(strp)
+			*strp = p;
+	} else {
+		if(strp)
+			*strp = p+1;
+	}
+
+	n = p - str;
+	if(n < sizeof(name)){
+		strncpy(name, str, n);
+		name[n] = 0;
+		sa = findsigalg(name);
+		if(sa != nil)
+			return newSigAlg(sa);
+	}
+	return nil;
+}
+
+static SigAlg*
+checkSigAlg(Keyring_SigAlg *ksa)
+{
+	SigAlgVec **sap;
+	SigAlg *sa;
+
+	sa = (SigAlg*)ksa;
+
+	for(sap = algs; sap < &algs[Maxalg]; sap++)
+		if(sa->vec == *sap)
+			return sa;
+	errorf("%s: %s", exType, exBadSA);
+	return nil;
+}
+
+/*
+ *  parse next new line terminated string into a String
+ */
+String*
+strtostring(char *str, char **strp)
+{
+	char *p;
+	String *s;
+
+	p = strchr(str, '\n');
+	if(p == 0)
+		p = str + strlen(str);
+	s = H;
+	retnstr(str, p - str, &s);
+
+	if(strp){
+		if(*p)
+			p++;
+		*strp = p;
+	}
+
+	return s;
+}
+
+/*
+ *  private part of a key
+ */
+static SK*
+newSK(SigAlg *sa, String *owner, int increfsa)
+{
+	Heap *h;
+	SK *k;
+
+	h = heap(TSK);
+	k = H2D(SK*, h);
+	k->x.sa = (Keyring_SigAlg*)sa;
+	if(increfsa) {
+		h = D2H(sa);
+		h->ref++;
+		Setmark(h);
+	}
+	k->x.owner = owner;
+	k->key = 0;
+	return k;
+}
+
+static void
+freeSK(Heap *h, int swept)
+{
+	SK *k;
+	SigAlg *sa;
+
+	k = H2D(SK*, h);
+	sa = checkSigAlg(k->x.sa);
+	if(k->key)
+		(*sa->vec->skfree)(k->key);
+	freeheap(h, swept);
+}
+
+static SK*
+checkSK(Keyring_SK *k)
+{
+	SK *sk;
+
+	sk = (SK*)k;
+	if(sk == H || sk == nil || sk->key == 0 || D2H(sk)->t != TSK){
+		errorf("%s: %s", exType, exBadSK);
+		return nil;
+	}
+	return sk;
+}
+
+void
+Keyring_genSK(void *fp)
+{
+	F_Keyring_genSK *f;
+	SK *sk;
+	SigAlg *sa;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sa = strtoalg(string2c(f->algname), 0);
+	if(sa == nil)
+		return;
+
+	sk = newSK(sa, stringdup(f->owner), 0);
+	*f->ret = (Keyring_SK*)sk;
+	release();
+	sk->key = (*sa->vec->gensk)(f->length);
+	acquire();
+}
+
+void
+Keyring_genSKfromPK(void *fp)
+{
+	F_Keyring_genSKfromPK *f;
+	SigAlg *sa;
+	PK *pk;
+	SK *sk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	pk = checkPK(f->pk);
+	sa = checkSigAlg(pk->x.sa);
+	sk = newSK(sa, stringdup(f->owner), 1);
+	*f->ret = (Keyring_SK*)sk;
+	release();
+	sk->key = (*sa->vec->genskfrompk)(pk->key);
+	acquire();
+}
+
+/* converts a sequence of newline-separated base64-encoded mpints to attr=hexval ... in f */
+static char*
+bigs2attr(Fmt *f, char *bigs, char **names)
+{
+	int i, n, nd;
+	char *b16, *vals[20];
+	uchar data[(MaxBigBytes*6 + 7)/8];
+
+	b16 = malloc(2*MaxBigBytes+1);
+	if(b16 == nil)
+		return nil;
+	n = getfields(bigs, vals, nelem(vals), 0, "\n");
+	for(i = 0; i < n-1; i++){
+		if(names == nil || names[i] == nil)
+			break;	/* shouldn't happen */
+		nd = dec64(data, sizeof(data), vals[i], strlen(vals[i]));
+		if(nd < 0)
+			break;
+		enc16(b16, 2*MaxBigBytes+1, data, nd);
+		fmtprint(f, " %s=%s", names[i], b16);
+	}
+	free(b16);
+	return fmtstrflush(f);
+}
+
+void
+Keyring_sktoattr(void *fp)
+{
+	F_Keyring_sktoattr *f;
+	char *val, *buf, *owner;
+	SigAlg *sa;
+	Fmt o;
+	SK *sk;
+
+	f = fp;
+	sk = checkSK(f->sk);
+	sa = checkSigAlg(sk->x.sa);
+	buf = malloc(Maxbuf);
+	if(buf == nil){
+		retstr(nil, f->ret);
+		return;
+	}
+	(*sa->vec->sk2str)(sk->key, buf, Maxbuf);
+	fmtstrinit(&o);
+	fmtprint(&o, "alg=%q", string2c(sa->x.name));
+	owner = string2c(sk->x.owner);
+	if(*owner)
+		fmtprint(&o, " owner=%q", owner);
+	val = bigs2attr(&o, buf, sa->vec->skattr);
+	free(buf);
+	retstr(val, f->ret);
+	free(val);
+}
+
+static int
+sktostr(SK *sk, char *buf, int len)
+{
+	int n;
+	SigAlg *sa;
+
+	sa = checkSigAlg(sk->x.sa);
+	n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name),
+			string2c(sk->x.owner));
+	return n + (*sa->vec->sk2str)(sk->key, buf+n, len - n);
+}
+
+void
+Keyring_sktostr(void *fp)
+{
+	F_Keyring_sktostr *f;
+	char *buf;
+
+	f = fp;
+	buf = malloc(Maxbuf);
+
+	if(buf)
+		sktostr(checkSK(f->sk), buf, Maxbuf);
+	retstr(buf, f->ret);
+
+	free(buf);
+}
+
+static SK*
+strtosk(char *buf)
+{
+	SK *sk;
+	char *p;
+	SigAlg *sa;
+	String *owner;
+	void *key;
+
+	sa = strtoalg(buf, &p);
+	if(sa == nil)
+		return H;
+	owner = strtostring(p, &p);
+	if(owner == H){
+		destroy(sa);
+		return H;
+	}
+
+	key = (*sa->vec->str2sk)(p, &p);
+	if(key == nil){
+		destroy(sa);
+		destroy(owner);
+		return H;
+	}
+	sk = newSK(sa, owner, 0);
+	sk->key = key;
+
+	return sk;
+}
+
+void
+Keyring_strtosk(void *fp)
+{
+	F_Keyring_strtosk *f;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+	*f->ret = (Keyring_SK*)strtosk(string2c(f->s));
+}
+
+/*
+ *  public part of a key
+ */
+PK*
+newPK(SigAlg *sa, String *owner, int increfsa)
+{
+	Heap *h;
+	PK *k;
+
+	h = heap(TPK);
+	k = H2D(PK*, h);
+	k->x.sa = (Keyring_SigAlg*)sa;
+	if(increfsa) {
+		h = D2H(sa);
+		h->ref++;
+		Setmark(h);
+	}
+	k->x.owner = owner;
+	k->key = 0;
+	return k;
+}
+
+void
+pkimmutable(PK *k)
+{
+	poolimmutable(D2H(k));
+	poolimmutable(D2H(k->x.sa));
+	poolimmutable(D2H(k->x.sa->name));
+	poolimmutable(D2H(k->x.owner));
+}
+
+void
+pkmutable(PK *k)
+{
+	poolmutable(D2H(k));
+	poolmutable(D2H(k->x.sa));
+	poolmutable(D2H(k->x.sa->name));
+	poolmutable(D2H(k->x.owner));
+}
+
+void
+freePK(Heap *h, int swept)
+{
+	PK *k;
+	SigAlg *sa;
+
+	k = H2D(PK*, h);
+	sa = checkSigAlg(k->x.sa);
+	if(k->key)
+		(*sa->vec->pkfree)(k->key);
+	freeheap(h, swept);
+}
+
+static PK*
+checkPK(Keyring_PK *k)
+{
+	PK *pk;
+
+	pk = (PK*)k;
+	if(pk == H || pk == nil || pk->key == 0 || D2H(pk)->t != TPK){
+		errorf("%s: %s", exType, exBadPK);
+		return nil;
+	}
+	return pk;
+}
+
+void
+Keyring_sktopk(void *fp)
+{
+	F_Keyring_sktopk *f;
+	PK *pk;
+	SigAlg *sa;
+	SK *sk;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	sk = checkSK(f->sk);
+	sa = checkSigAlg(sk->x.sa);
+	pk = newPK(sa, stringdup(sk->x.owner), 1);
+	pk->key = (*sa->vec->sk2pk)(sk->key);
+	*f->ret = (Keyring_PK*)pk;
+}
+
+static int
+pktostr(PK *pk, char *buf, int len)
+{
+	int n;
+	SigAlg *sa;
+
+	sa = checkSigAlg(pk->x.sa);
+	n = snprint(buf, len, "%s\n%s\n", string2c(sa->x.name), string2c(pk->x.owner));
+	return n + (*sa->vec->pk2str)(pk->key, buf+n, len - n);
+}
+
+void
+Keyring_pktostr(void *fp)
+{
+	F_Keyring_pktostr *f;
+	char *buf;
+
+	f = fp;
+	buf = malloc(Maxbuf);
+
+	if(buf)
+		pktostr(checkPK(f->pk), buf, Maxbuf);
+	retstr(buf, f->ret);
+
+	free(buf);
+}
+
+void
+Keyring_pktoattr(void *fp)
+{
+	F_Keyring_pktoattr *f;
+	char *val, *buf, *owner;
+	SigAlg *sa;
+	Fmt o;
+	PK *pk;
+
+	f = fp;
+	pk = checkPK(f->pk);
+	sa = checkSigAlg(pk->x.sa);
+	buf = malloc(Maxbuf);
+	if(buf == nil){
+		retstr(nil, f->ret);
+		return;
+	}
+	(*sa->vec->pk2str)(pk->key, buf, Maxbuf);
+	fmtstrinit(&o);
+	fmtprint(&o, "alg=%q", string2c(sa->x.name));
+	owner = string2c(pk->x.owner);
+	if(*owner)
+		fmtprint(&o, " owner=%q", owner);
+	val = bigs2attr(&o, buf, sa->vec->pkattr);
+	free(buf);
+	retstr(val, f->ret);
+	free(val);
+}
+
+static PK*
+strtopk(char *buf)
+{
+	PK *pk;
+	char *p;
+	SigAlg *sa;
+	String *owner;
+	void *key;
+
+	sa = strtoalg(buf, &p);
+	if(sa == nil)
+		return H;
+	owner = strtostring(p, &p);
+	if(owner == H){
+		destroy(sa);
+		return H;
+	}
+
+	key = (*sa->vec->str2pk)(p, &p);
+	if(key == nil){
+		destroy(sa);
+		destroy(owner);
+		return H;
+	}
+	pk = newPK(sa, owner, 0);
+	pk->key = key;
+
+	return pk;
+}
+
+void
+Keyring_strtopk(void *fp)
+{
+	F_Keyring_strtopk *f;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+	*f->ret = (Keyring_PK*)strtopk(string2c(f->s));
+}
+
+/*
+ *  Certificates/signatures
+ */
+
+void
+certimmutable(Certificate *c)
+{
+	poolimmutable(D2H(c));
+	poolimmutable(D2H(c->x.signer));
+	poolimmutable(D2H(c->x.ha));
+	poolimmutable(D2H(c->x.sa));
+	poolimmutable(D2H(c->x.sa->name));
+}
+
+void
+certmutable(Certificate *c)
+{
+	poolmutable(D2H(c));
+	poolmutable(D2H(c->x.signer));
+	poolmutable(D2H(c->x.ha));
+	Setmark(D2H(c->x.sa));
+	poolmutable(D2H(c->x.sa));
+	Setmark(D2H(c->x.sa->name));
+	poolmutable(D2H(c->x.sa->name));
+}
+
+Certificate*
+newCertificate(SigAlg *sa, String *ha, String *signer, long exp, int increfsa)
+{
+	Heap *h;
+	Certificate *c;
+
+	h = heap(TCertificate);
+	c = H2D(Certificate*, h);
+	c->x.sa = (Keyring_SigAlg*)sa;
+	if(increfsa) {
+		h = D2H(sa);
+		h->ref++;
+		Setmark(h);
+	}
+	c->x.signer = signer;
+	c->x.ha = ha;
+	c->x.exp = exp;
+	c->signa = 0;
+
+	return c;
+}
+
+void
+freeCertificate(Heap *h, int swept)
+{
+	Certificate *c;
+	SigAlg *sa;
+
+	c = H2D(Certificate*, h);
+	sa = checkSigAlg(c->x.sa);
+	if(c->signa)
+		(*sa->vec->sigfree)(c->signa);
+	freeheap(h, swept);
+}
+
+Certificate*
+checkCertificate(Keyring_Certificate *c)
+{
+	Certificate *cert;
+
+	cert = (Certificate*)c;
+	if(cert == H || cert == nil || cert->signa == 0 || D2H(cert)->t != TCertificate){
+		errorf("%s: %s", exType, exBadCert);
+		return nil;
+	}
+	return cert;
+}
+
+static int
+certtostr(Certificate *c, char *buf, int len)
+{
+	SigAlg *sa;
+	int n;
+
+	sa = checkSigAlg(c->x.sa);
+	n = snprint(buf, len, "%s\n%s\n%s\n%d\n", string2c(sa->x.name),
+		string2c(c->x.ha), string2c(c->x.signer), c->x.exp);
+	return n + (*sa->vec->sig2str)(c->signa, buf+n, len - n);
+}
+
+void
+Keyring_certtostr(void *fp)
+{
+	F_Keyring_certtostr *f;
+	char *buf;
+
+	f = fp;
+	buf = malloc(Maxbuf);
+
+	if(buf)
+		certtostr(checkCertificate(f->c), buf, Maxbuf);
+	retstr(buf, f->ret);
+
+	free(buf);
+}
+
+void
+Keyring_certtoattr(void *fp)
+{
+	F_Keyring_certtoattr *f;
+	char *val, *buf, *ha;
+	SigAlg *sa;
+	Fmt o;
+	Certificate *c;
+
+	f = fp;
+	c = checkCertificate(f->c);
+	sa = checkSigAlg(c->x.sa);
+	buf = malloc(Maxbuf);
+	if(buf == nil){
+		retstr(nil, f->ret);
+		return;
+	}
+	(*sa->vec->sig2str)(c->signa, buf, Maxbuf);
+	ha = string2c(c->x.ha);
+	if(strcmp(ha, "sha") == 0)
+		ha = "sha1";	/* normalise */
+	fmtstrinit(&o);
+	fmtprint(&o, "sigalg=%q-%q signer=%q expires=%ud", string2c(sa->x.name), ha,
+		string2c(c->x.signer), c->x.exp);
+	val = bigs2attr(&o, buf, sa->vec->sigattr);
+	free(buf);
+	retstr(val, f->ret);
+	free(val);
+}
+
+static Certificate*
+strtocert(char *buf)
+{
+	Certificate *c;
+	char *p;
+	SigAlg *sa;
+	String *signer, *ha;
+	long exp;
+	void *signa;
+
+	sa = strtoalg(buf, &p);
+	if(sa == 0)
+		return H;
+
+	ha = strtostring(p, &p);
+	if(ha == H){
+		destroy(sa);
+		return H;
+	}
+
+	signer = strtostring(p, &p);
+	if(signer == H){
+		destroy(sa);
+		destroy(ha);
+		return H;
+	}
+
+	exp = strtoul(p, &p, 10);
+	if(*p)
+		p++;
+	signa = (*sa->vec->str2sig)(p, &p);
+	if(signa == nil){
+		destroy(sa);
+		destroy(ha);
+		destroy(signer);
+		return H;
+	}
+
+	c = newCertificate(sa, ha, signer, exp, 0);
+	c->signa = signa;
+
+	return c;
+}
+
+void
+Keyring_strtocert(void *fp)
+{
+	F_Keyring_strtocert *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	*f->ret = (Keyring_Certificate*)strtocert(string2c(f->s));
+}
+
+static Certificate*
+sign(SK *sk, char *ha, ulong exp, uchar *a, int len)
+{
+	Certificate *c;
+	mpint *b;
+	int n;
+	SigAlg *sa;
+	DigestState *ds;
+	uchar digest[SHA1dlen];
+	char *buf;
+	String *hastr;
+
+	hastr = H;
+	sa = checkSigAlg(sk->x.sa);
+	buf = malloc(Maxbuf);
+	if(buf == nil)
+		return nil;
+
+	/* add signer name and expiration time to hash */
+	n = snprint(buf, Maxbuf, "%s %lud", string2c(sk->x.owner), exp);
+	if(strcmp(ha, "sha") == 0 || strcmp(ha, "sha1") == 0){
+		ds = sha1(a, len, 0, 0);
+		sha1((uchar*)buf, n, digest, ds);
+		n = Keyring_SHA1dlen;
+	} else if(strcmp(ha, "md5") == 0){
+		ds = md5(a, len, 0, 0);
+		md5((uchar*)buf, n, digest, ds);
+		n = Keyring_MD5dlen;
+	} else if(strcmp(ha, "md4") == 0){
+		ds = md4(a, len, 0, 0);
+		md4((uchar*)buf, n, digest, ds);
+		n = Keyring_MD5dlen;
+	} else {
+		free(buf);
+		return nil;
+	}
+	free(buf);
+
+	/* turn message into a big integer */
+	b = betomp(digest, n, nil);
+	if(b == nil)
+		return nil;
+
+	/* sign */
+	retstr(ha, &hastr);
+	c = newCertificate(sa, hastr, stringdup(sk->x.owner), exp, 1);
+	certimmutable(c);		/* hide from the garbage collector */
+	release();
+	c->signa = (*sa->vec->sign)(b, sk->key);
+	acquire();
+	mpfree(b);
+
+	return c;
+}
+
+void
+Keyring_sign(void *fp)
+{
+	F_Keyring_sign *f;
+	Certificate *c;
+	mpint *b;
+	int n;
+	SigAlg *sa;
+	SK *sk;
+	XDigestState *ds;
+	uchar digest[SHA1dlen];
+	char *buf;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sk = checkSK(f->sk);
+	sa = checkSigAlg(sk->x.sa);
+
+	/* add signer name and expiration time to hash */
+	if(f->state == H)
+		return;
+	buf = malloc(Maxbuf);
+	if(buf == nil)
+		return;
+	ds = (XDigestState*)f->state;
+	n = snprint(buf, Maxbuf, "%s %d", string2c(sk->x.owner), f->exp);
+	if(strcmp(string2c(f->ha), "sha") == 0 || strcmp(string2c(f->ha), "sha1") == 0){
+		sha1((uchar*)buf, n, digest, &ds->state);
+		n = Keyring_SHA1dlen;
+	} else if(strcmp(string2c(f->ha), "md5") == 0){
+		md5((uchar*)buf, n, digest, &ds->state);
+		n = Keyring_MD5dlen;
+	} else if(strcmp(string2c(f->ha), "md4") == 0){
+		md4((uchar*)buf, n, digest, &ds->state);
+		n = Keyring_MD5dlen;
+	} else {
+		free(buf);
+		return;
+	}
+	free(buf);
+
+	/* turn message into a big integer */
+	b = betomp(digest, n, nil);
+	if(b == nil)
+		return;
+
+	/* sign */
+	c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), f->exp, 1);
+	*f->ret = (Keyring_Certificate*)c;
+	release();
+	c->signa = (*sa->vec->sign)(b, sk->key);
+	acquire();
+	mpfree(b);
+}
+
+void
+Keyring_signm(void *fp)
+{
+	F_Keyring_signm *f;
+	Certificate *c;
+	mpint *b;
+	SigAlg *sa;
+	SK *sk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	sk = checkSK(f->sk);
+	sa = checkSigAlg(sk->x.sa);
+
+	if(f->m == H)
+		return;
+	b = checkIPint(f->m);
+
+	/* sign */
+	c = newCertificate(sa, stringdup(f->ha), stringdup(sk->x.owner), 0, 1);
+	*f->ret = (Keyring_Certificate*)c;
+	release();
+	c->signa = (*sa->vec->sign)(b, sk->key);
+	acquire();
+}
+
+static int
+verify(PK *pk, Certificate *c, char *a, int len)
+{
+	mpint *b;
+	int n;
+	SigAlg *sa, *pksa;
+	DigestState *ds;
+	uchar digest[SHA1dlen];
+	char *buf;
+
+	sa = checkSigAlg(c->x.sa);
+	pksa = checkSigAlg(pk->x.sa);
+	if(sa->vec != pksa->vec)
+		return 0;
+
+	/* add signer name and expiration time to hash */
+	buf = malloc(Maxbuf);
+	if(buf == nil)
+		return 0;
+	n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+	if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+		ds = sha1((uchar*)a, len, 0, 0);
+		sha1((uchar*)buf, n, digest, ds);
+		n = Keyring_SHA1dlen;
+	} else if(strcmp(string2c(c->x.ha), "md5") == 0){
+		ds = md5((uchar*)a, len, 0, 0);
+		md5((uchar*)buf, n, digest, ds);
+		n = Keyring_MD5dlen;
+	} else if(strcmp(string2c(c->x.ha), "md4") == 0){
+		ds = md4((uchar*)a, len, 0, 0);
+		md4((uchar*)buf, n, digest, ds);
+		n = Keyring_MD5dlen;
+	} else {
+		free(buf);
+		return 0;
+	}
+	free(buf);
+
+	/* turn message into a big integer */
+	b = betomp(digest, n, nil);
+	if(b == nil)
+		return 0;
+	/* verify */
+	release();
+	n = (*sa->vec->verify)(b, c->signa, pk->key);
+	acquire();
+
+	mpfree(b);
+	return n;
+}
+
+void
+Keyring_verify(void *fp)
+{
+	F_Keyring_verify *f;
+	Certificate *c;
+	mpint *b;
+	int n;
+	SigAlg *sa, *pksa;
+	PK *pk;
+	XDigestState *ds;
+	uchar digest[SHA1dlen];
+	char *buf;
+
+	f = fp;
+	*f->ret = 0;
+
+	c = checkCertificate(f->cert);
+	sa = checkSigAlg(c->x.sa);
+	pk = checkPK(f->pk);
+	pksa = checkSigAlg(pk->x.sa);
+	if(sa->vec != pksa->vec)
+		return;
+
+	/* add signer name and expiration time to hash */
+	if(f->state == H)
+		return;
+	buf = malloc(Maxbuf);
+	if(buf == nil)
+		return;
+	n = snprint(buf, Maxbuf, "%s %d", string2c(c->x.signer), c->x.exp);
+	ds = (XDigestState*)f->state;
+
+	if(strcmp(string2c(c->x.ha), "sha") == 0 || strcmp(string2c(c->x.ha), "sha1") == 0){
+		sha1((uchar*)buf, n, digest, &ds->state);
+		n = Keyring_SHA1dlen;
+	} else if(strcmp(string2c(c->x.ha), "md5") == 0){
+		md5((uchar*)buf, n, digest, &ds->state);
+		n = Keyring_MD5dlen;
+	} else if(strcmp(string2c(c->x.ha), "md4") == 0){
+		md4((uchar*)buf, n, digest, &ds->state);
+		n = Keyring_MD5dlen;
+	} else {
+		free(buf);
+		return;
+	}
+	free(buf);
+
+	/* turn message into a big integer */
+	b = betomp(digest, n, nil);
+	if(b == nil)
+		return;
+
+	/* verify */
+	release();
+	*f->ret = (*sa->vec->verify)(b, c->signa, pk->key);
+	acquire();
+
+	mpfree(b);
+}
+
+void
+Keyring_verifym(void *fp)
+{
+	F_Keyring_verifym *f;
+	Certificate *c;
+	SigAlg *sa, *pksa;
+	PK *pk;
+
+	f = fp;
+	*f->ret = 0;
+
+	c = checkCertificate(f->cert);
+	sa = checkSigAlg(c->x.sa);
+	pk = checkPK(f->pk);
+	pksa = checkSigAlg(pk->x.sa);
+	if(sa->vec != pksa->vec)
+		return;
+
+	if(f->m == H)
+		return;
+
+	release();
+	*f->ret = (*sa->vec->verify)(checkIPint(f->m), c->signa, pk->key);
+	acquire();
+}
+
+/*
+ *  digests
+ */
+void
+Keyring_DigestState_copy(void *fp)
+{
+	F_DigestState_copy *f;
+	Heap *h;
+	XDigestState *ds, *ods;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	if(f->d != H){
+		ods = checktype(f->d, TDigestState, "DigestState", 0);
+		h = heap(TDigestState);
+		ds = H2D(XDigestState*, h); 	
+		memmove(&ds->state, &ods->state, sizeof(ds->state)); 
+		*f->ret = (Keyring_DigestState*)ds;
+	}
+}
+
+static Keyring_DigestState*
+keyring_digest_x(Array *buf, int n, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, DigestState*))
+{
+	Heap *h;
+	XDigestState *ds;
+	uchar *cbuf, *cdigest;
+
+	if(buf != H){
+		if(n > buf->len)
+			n = buf->len;
+		cbuf = buf->data;
+	}else{
+		if(n != 0)
+			error(exInval);
+		cbuf = nil;
+	}
+
+	if(digest != H){
+		if(digest->len < dlen)
+			error(exBadDigest);
+		cdigest = digest->data;
+	} else
+		cdigest = nil;
+
+	if(state == H){
+		h = heap(TDigestState);
+		ds = H2D(XDigestState*, h);
+		memset(&ds->state, 0, sizeof(ds->state));
+	} else
+		ds = checktype(state, TDigestState, "DigestState", 1);
+
+	(*fn)(cbuf, n, cdigest, &ds->state);
+
+	return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_sha1(void *fp)
+{
+	F_Keyring_sha1 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA1dlen, f->state, sha1);
+}
+
+void
+Keyring_sha224(void *fp)
+{
+	F_Keyring_sha224 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA224dlen, f->state, sha224);
+}
+
+void
+Keyring_sha256(void *fp)
+{
+	F_Keyring_sha256 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA256dlen, f->state, sha256);
+}
+
+void
+Keyring_sha384(void *fp)
+{
+	F_Keyring_sha384 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA384dlen, f->state, sha384);
+}
+
+void
+Keyring_sha512(void *fp)
+{
+	F_Keyring_sha512 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = keyring_digest_x(f->buf, f->n, f->digest, SHA512dlen, f->state, sha512);
+}
+
+void
+Keyring_md5(void *fp)
+{
+	F_Keyring_md5 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD5dlen, f->state, md5);
+}
+
+void
+Keyring_md4(void *fp)
+{
+	F_Keyring_md4 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	*f->ret = keyring_digest_x(f->buf, f->n, f->digest, MD4dlen, f->state, md4);
+}
+
+static Keyring_DigestState*
+keyring_hmac_x(Array *data, int n, Array *key, Array *digest, int dlen, Keyring_DigestState *state, DigestState* (*fn)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*))
+{
+	Heap *h;
+	XDigestState *ds;
+	uchar *cdata, *cdigest;
+
+	if(data != H){
+		if(n > data->len)
+			n = data->len;
+		cdata = data->data;
+	}else{
+		if(n != 0)
+			error(exInval);
+		cdata = nil;
+	}
+
+	if(key == H || key->len > 64)
+		error(exBadKey);
+
+	if(digest != H){
+		if(digest->len < dlen)
+			error(exBadDigest);
+		cdigest = digest->data;
+	} else
+		cdigest = nil;
+
+	if(state == H){
+		h = heap(TDigestState);
+		ds = H2D(XDigestState*, h);
+		memset(&ds->state, 0, sizeof(ds->state));
+	} else
+		ds = checktype(state, TDigestState, "DigestState", 1);
+
+	(*fn)(cdata, n, key->data, key->len, cdigest, &ds->state);
+
+	return (Keyring_DigestState*)ds;
+}
+
+void
+Keyring_hmac_sha1(void *fp)
+{
+	F_Keyring_hmac_sha1 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	*f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, SHA1dlen, f->state, hmac_sha1);
+}
+
+void
+Keyring_hmac_md5(void *fp)
+{
+	F_Keyring_hmac_md5 *f;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	*f->ret = keyring_hmac_x(f->data, f->n, f->key, f->digest, MD5dlen, f->state, hmac_md5);
+}
+
+void
+Keyring_dhparams(void *fp)
+{
+	F_Keyring_dhparams *f;
+	mpint *p, *alpha;
+	void *v;
+
+	f = fp;
+	v = f->ret->t0;
+	f->ret->t0 = H;
+	destroy(v);
+	v = f->ret->t1;
+	f->ret->t1 = H;
+	destroy(v);
+
+	p = mpnew(0);
+	alpha = mpnew(0);
+	release();
+	if(f->nbits == 1024)
+		DSAprimes(alpha, p, nil);
+	else
+		gensafeprime(p, alpha, f->nbits, 0);
+	acquire();
+	f->ret->t0 = newIPint(alpha);
+	f->ret->t1 = newIPint(p);
+}
+
+static int
+sendmsg(int fd, void *buf, int n)
+{
+	char num[10];
+
+	release();
+	snprint(num, sizeof(num), "%4.4d\n", n);
+	if(kwrite(fd, num, 5) != 5){
+		acquire();
+		return -1;
+	}
+	n = kwrite(fd, buf, n);
+	acquire();
+	return n;
+}
+
+void
+Keyring_sendmsg(void *fp)
+{
+	F_Keyring_sendmsg *f;
+	int n;
+
+	f = fp;
+	*f->ret = -1;
+	if(f->fd == H || f->buf == H || f->n < 0)
+		return;
+	n = f->n;
+	if(n < 0 || n > f->buf->len)
+		error(exBounds);
+	*f->ret = sendmsg(f->fd->fd, f->buf->data, n);
+}
+
+static int
+senderr(int fd, char *err, int addrmt)
+{
+	char num[10];
+	int n, m;
+
+	release();
+	n = strlen(err);
+	m = 0;
+	if(addrmt)
+		m = strlen("remote: ");
+	snprint(num, sizeof(num), "!%3.3d\n", n+m);
+	if(kwrite(fd, num, 5) != 5){
+		acquire();
+		return -1;
+	}
+	if(addrmt)
+		kwrite(fd, "remote: ", m);
+	n = kwrite(fd, err, n);
+	acquire();
+	return n;
+}
+
+void
+Keyring_senderrmsg(void *fp)
+{
+	F_Keyring_senderrmsg *f;
+	char *s;
+
+	f = fp;
+	*f->ret = -1;
+	if(f->fd == H)
+		return;
+	s = string2c(f->s);
+	if(senderr(f->fd->fd, s, 0) > 0)
+		*f->ret = 0;
+}
+
+static int
+nreadn(int fd, void *av, int n)
+{
+
+	char *a;
+	long m, t;
+
+	a = av;
+	t = 0;
+	while(t < n){
+		m = kread(fd, a+t, n-t);
+		if(m <= 0){
+			if(t == 0)
+				return m;
+			break;
+		}
+		t += m;
+	}
+	return t;
+}
+
+#define MSG "input or format error"
+
+static void
+getmsgerr(char *buf, int n, int r)
+{
+	char *e;
+	int l;
+
+	e = r>0? MSG: "hungup";
+	l = strlen(e)+1;
+	if(n > l)
+		n = l;
+	memmove(buf, e, n-1);
+	buf[n-1] = 0;
+}
+
+static int
+getmsg(int fd, char *buf, int n)
+{
+	char num[6];
+	int len, r;
+
+	release();
+	if((r = nreadn(fd, num, 5)) != 5){
+		getmsgerr(buf, n, r);
+		acquire();
+		return -1;
+	}
+	num[5] = 0;
+
+	if(num[0] == '!')
+		len = strtoul(num+1, 0, 10);
+	else
+		len = strtoul(num, 0, 10);
+
+	r = -1;
+	if(len < 0 || len >= n || (r = nreadn(fd, buf, len)) != len){
+		getmsgerr(buf, n, r);
+		acquire();
+		return -1;
+	}
+
+	buf[len] = 0;
+	acquire();
+	if(num[0] == '!')
+		return -len;
+
+	return len;
+}
+
+void
+Keyring_getmsg(void *fp)
+{
+	F_Keyring_getmsg *f;
+	char *buf;
+	int n;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	if(f->fd == H){
+		kwerrstr("nil fd");
+		return;
+	}
+
+	buf = malloc(Maxmsg);
+	if(buf == nil){
+		kwerrstr(exNomem);
+		return;
+	}
+
+	n = getmsg(f->fd->fd, buf, Maxmsg);
+	if(n < 0){
+		kwerrstr("%s", buf);
+		free(buf);
+		return;
+	}
+
+	*f->ret = mem2array(buf, n);
+	free(buf);
+}
+
+void
+Keyring_auth(void *fp)
+{
+	F_Keyring_auth *f;
+	mpint *r0, *r1, *p, *alpha, *alphar0, *alphar1, *alphar0r1;
+	SK *mysk;
+	PK *mypk, *spk, *hispk;
+	Certificate *cert, *hiscert, *alphacert;
+	char *buf, *err;
+	uchar *cvb;
+	int n, fd, version;
+	long now;
+
+	hispk = H;
+	hiscert = H;
+	alphacert = H;
+	err = nil;
+
+	/* null out the return values */
+	f = fp;
+	destroy(f->ret->t0);
+	f->ret->t0 = H;
+	destroy(f->ret->t1);
+	f->ret->t1 = H;
+	r0 = r1 = alphar0 = alphar1 = alphar0r1 = nil;
+
+	/* check args */
+	if(f->fd == H || f->fd->fd < 0){
+		retstr("bad fd", &f->ret->t0);
+		return;
+	}
+	fd = f->fd->fd;
+
+	buf = malloc(Maxbuf);
+	if(buf == nil){
+		retstr(exNomem, &f->ret->t0);
+		return;
+	}
+
+	/* send auth protocol version number */
+	if(sendmsg(fd, "1", 1) <= 0){
+		err = MSG;
+		goto out;
+	}
+
+	/* get auth protocol version number */
+	n = getmsg(fd, buf, Maxbuf-1);
+	if(n < 0){
+		err = buf;
+		goto out;
+	}
+	buf[n] = 0;
+	version = atoi(buf);
+	if(version != 1 || n > 4){
+		err = "incompatible authentication protocol";
+		goto out;
+	}
+
+	if(f->info == H){
+		err = "no authentication information";
+		goto out;
+	}
+	if(f->info->p == H){
+		err = "missing diffie hellman mod";
+		goto out;
+	}
+	if(f->info->alpha == H){
+		err = "missing diffie hellman base";
+		goto out;
+	}
+	mysk = checkSK(f->info->mysk);
+	if(mysk == H){
+		err = "bad sk arg";
+		goto out;
+	}
+	mypk = checkPK(f->info->mypk);
+	if(mypk == H){
+		err = "bad pk arg";
+		goto out;
+	}
+	cert = checkCertificate(f->info->cert);
+	if(cert == H){
+		err = "bad certificate arg";
+		goto out;
+	}
+	spk = checkPK(f->info->spk);
+	if(spk == H){
+		err = "bad signer key arg";
+		goto out;
+	}
+
+	/* get alpha and p */
+	p = checkIPint(f->info->p);
+	alpha = checkIPint(f->info->alpha);
+
+	if(p->sign == -1) {
+		err = "-ve modulus";
+		goto out;
+	}
+
+	r0 = mpnew(0);
+	r1 = mpnew(0);
+	alphar0 = mpnew(0);
+	alphar0r1 = mpnew(0);
+
+	/* generate alpha**r0 */
+if(0)print("X");
+	release();
+	mprand(mpsignif(p), genrandom, r0);
+	mpexp(alpha, r0, p, alphar0);
+	acquire();
+if(0)print("Y");
+
+	/* send alpha**r0 mod p, mycert, and mypk */
+	n = bigtobase64(alphar0, buf, Maxbuf);
+	if(sendmsg(fd, buf, n) <= 0){
+		err = MSG;
+		goto out;
+	}
+
+	n = certtostr(cert, buf, Maxbuf);
+	if(sendmsg(fd, buf, n) <= 0){
+		err = MSG;
+		goto out;
+	}
+
+	n = pktostr(mypk, buf, Maxbuf);
+	if(sendmsg(fd, buf, n) <= 0){
+		err = MSG;
+		goto out;
+	}
+
+	/* get alpha**r1 mod p, hiscert, hispk */
+	n = getmsg(fd, buf, Maxbuf-1);
+	if(n < 0){
+		err = buf;
+		goto out;
+	}
+	buf[n] = 0;
+	alphar1 = strtomp(buf, nil, 64, nil);
+
+	/* trying a fast one */
+	if(mpcmp(p, alphar1) <= 0){
+		err = "implausible parameter value";
+		goto out;
+	}
+
+	/* if alpha**r1 == alpha**r0, someone may be trying a replay */
+	if(mpcmp(alphar0, alphar1) == 0){
+		err = "possible replay attack";
+		goto out;
+	}
+
+	n = getmsg(fd, buf, Maxbuf-1);
+	if(n < 0){
+		err = buf;
+		goto out;
+	}
+	buf[n] = 0;
+	hiscert = strtocert(buf);
+	if(hiscert == H){
+		err = "bad certificate syntax";
+		goto out;
+	}
+	certimmutable(hiscert);		/* hide from the garbage collector */
+
+	n = getmsg(fd, buf, Maxbuf-1);
+	if(n < 0){
+		err = buf;
+		goto out;
+	}
+	buf[n] = 0;
+	hispk = strtopk(buf);
+	if(hispk == H){
+		err = "bad public key";
+		goto out;
+	}
+	pkimmutable(hispk);		/* hide from the garbage collector */
+
+	/* verify his public key */
+	if(verify(spk, hiscert, buf, n) == 0){
+		err = "pk doesn't match certificate";
+		goto out;
+	}
+
+	/* check expiration date - in seconds of epoch */
+
+	now = osusectime()/1000000;
+	if(hiscert->x.exp != 0 && hiscert->x.exp <= now){
+		err = "certificate expired";
+		goto out;
+	}
+
+	/* sign alpha**r0 and alpha**r1 and send */
+	n = bigtobase64(alphar0, buf, Maxbuf);
+	n += bigtobase64(alphar1, buf+n, Maxbuf-n);
+	alphacert = sign(mysk, "sha1", 0, (uchar*)buf, n);
+	n = certtostr(alphacert, buf, Maxbuf);
+	if(sendmsg(fd, buf, n) <= 0){
+		err = MSG;
+		goto out;
+	}
+	certmutable(alphacert);
+	destroy(alphacert);
+	alphacert = H;
+
+	/* get signature of alpha**r1 and alpha**r0 and verify */
+	n = getmsg(fd, buf, Maxbuf-1);
+	if(n < 0){
+		err = buf;
+		goto out;
+	}
+	buf[n] = 0;
+	alphacert = strtocert(buf);
+	if(alphacert == H){
+		err = "alpha**r1 doesn't match certificate";
+		goto out;
+	}
+	certimmutable(alphacert);		/* hide from the garbage collector */
+	n = bigtobase64(alphar1, buf, Maxbuf);
+	n += bigtobase64(alphar0, buf+n, Maxbuf-n);
+	if(verify(hispk, alphacert, buf, n) == 0){
+		err = "bad certificate";
+		goto out;
+	}
+
+	/* we are now authenticated and have a common secret, alpha**(r0*r1) */
+	f->ret->t0 = stringdup(hispk->x.owner);
+	mpexp(alphar1, r0, p, alphar0r1);
+	n = mptobe(alphar0r1, nil, Maxbuf, &cvb);
+	if(n < 0){
+		err = "bad conversion";
+		goto out;
+	}
+	f->ret->t1 = mem2array(cvb, n);
+	free(cvb);
+
+out:
+	/* return status */
+	if(f->ret->t0 == H){
+		if(err == buf)
+			senderr(fd, "missing your authentication data", 1);
+		else
+			senderr(fd, err, 1);
+	}else
+		sendmsg(fd, "OK", 2);
+
+	/* read responses */
+	if(err != buf){
+		for(;;){
+			n = getmsg(fd, buf, Maxbuf-1);
+			if(n < 0){
+				destroy(f->ret->t0);
+				f->ret->t0 = H;
+				destroy(f->ret->t1);
+				f->ret->t1 = H;
+				if(err == nil){
+					if(n < -1)
+						err = buf;
+					else
+						err = MSG;
+				}
+				break;
+			}
+			if(n == 2 && buf[0] == 'O' && buf[1] == 'K')
+				break;
+		}
+	}
+
+	/* set error and id to nobody */
+	if(f->ret->t0 == H){
+		if(err == nil)
+			err = MSG;
+		retstr(err, &f->ret->t0);
+		if(f->setid)
+			setid("nobody", 1);
+	} else {
+		/* change user id */
+		if(f->setid)
+			setid(string2c(f->ret->t0), 1);
+	}
+	
+	/* free resources */
+	if(hispk != H){
+		pkmutable(hispk);
+		destroy(hispk);
+	}
+	if(hiscert != H){
+		certmutable(hiscert);
+		destroy(hiscert);
+	}
+	if(alphacert != H){
+		certmutable(alphacert);
+		destroy(alphacert);
+	}
+	free(buf);
+	if(r0 != nil){
+		mpfree(r0);
+		mpfree(r1);
+		mpfree(alphar0);
+		mpfree(alphar1);
+		mpfree(alphar0r1);
+	}
+}
+
+static Keyring_Authinfo*
+newAuthinfo(void)
+{
+	return H2D(Keyring_Authinfo*, heap(TAuthinfo));
+}
+
+void
+Keyring_writeauthinfo(void *fp)
+{
+	F_Keyring_writeauthinfo *f;
+	int n, fd;
+	char *buf;
+	PK *spk;
+	SK *mysk;
+	Certificate *c;
+	mpint *p, *alpha;
+
+	f = fp;
+	*f->ret = -1;
+
+	if(f->filename == H)
+		error(exNilref);
+	if(f->info == H)
+		error(exNilref);
+	alpha = checkIPint(f->info->alpha);
+	p = checkIPint(f->info->p);
+	spk = checkPK(f->info->spk);
+	mysk = checkSK(f->info->mysk);
+	c = checkCertificate(f->info->cert);
+
+	buf = malloc(Maxbuf);
+	if(buf == nil)
+		return;
+
+	/*
+	 *  The file may already exist or be a file2chan file so first
+	 *  try opening with truncation since create will change the
+	 *  permissions of the file and create doesn't work with a
+	 *  file2chan.
+	 */
+	release();
+	fd = kopen(string2c(f->filename), OTRUNC|OWRITE);
+	if(fd < 0)
+		fd = kcreate(string2c(f->filename), OWRITE, 0600);
+	if(fd < 0)
+		fd = kopen(string2c(f->filename), OWRITE);
+	acquire();
+	if(fd < 0)
+		goto out;
+
+	/* signer's public key */
+	n = pktostr(spk, buf, Maxmsg);
+	if(sendmsg(fd, buf, n) <= 0)
+		goto out;
+
+	/* certificate for my public key */
+	n = certtostr(c, buf, Maxmsg);
+	if(sendmsg(fd, buf, n) <= 0)
+		goto out;
+
+	/* my secret/public key */
+	n = sktostr(mysk, buf, Maxmsg);
+	if(sendmsg(fd, buf, n) <= 0)
+		goto out;
+
+	/* diffie hellman base */
+	n = bigtobase64(alpha, buf, Maxbuf);
+	if(sendmsg(fd, buf, n) <= 0)
+		goto out;
+
+	/* diffie hellman modulus */
+	n = bigtobase64(p, buf, Maxbuf);
+	if(sendmsg(fd, buf, n) <= 0)
+		goto out;
+
+	*f->ret = 0;
+out:
+	free(buf);
+	if(fd >= 0){
+		release();
+		kclose(fd);
+		acquire();
+	}
+}
+
+void
+Keyring_readauthinfo(void *fp)
+{
+	F_Keyring_readauthinfo *f;
+	int fd;
+	char *buf;
+	int n, ok;
+	PK *mypk;
+	SK *mysk;
+	SigAlg *sa;
+	Keyring_Authinfo *ai;
+	mpint *b;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	ok = 0;
+
+	if(f->filename == H)
+		return;
+
+	buf = malloc(Maxbuf);
+	if(buf == nil)
+		return;
+
+	ai = newAuthinfo();
+	*f->ret = ai;
+
+	release();
+	fd = kopen(string2c(f->filename), OREAD);
+	acquire();
+	if(fd < 0)
+		goto out;
+
+	/* signer's public key */
+	n = getmsg(fd, buf, Maxmsg);
+	if(n < 0)
+		goto out;
+
+	ai->spk = (Keyring_PK*)strtopk(buf);
+	if(ai->spk == H)
+		goto out;
+
+	/* certificate for my public key */
+	n = getmsg(fd, buf, Maxmsg);
+	if(n < 0)
+		goto out;
+	ai->cert = (Keyring_Certificate*)strtocert(buf);
+	if(ai->cert == H)
+		goto out;
+
+	/* my secret/public key */
+	n = getmsg(fd, buf, Maxmsg);
+	if(n < 0)
+		goto out;
+	mysk = strtosk(buf);
+	ai->mysk = (Keyring_SK*)mysk;
+	if(mysk == H)
+		goto out;
+	sa = checkSigAlg(mysk->x.sa);
+	mypk = newPK(sa, stringdup(mysk->x.owner), 1);
+	mypk->key = (*sa->vec->sk2pk)(mysk->key);
+	ai->mypk = (Keyring_PK*)mypk;
+
+	/* diffie hellman base */
+	n = getmsg(fd, buf, Maxmsg);
+	if(n < 0)
+		goto out;
+	b = strtomp(buf, nil, 64, nil);
+	ai->alpha = newIPint(b);
+
+	/* diffie hellman modulus */
+	n = getmsg(fd, buf, Maxmsg);
+	if(n < 0)
+		goto out;
+	b = strtomp(buf, nil, 64, nil);
+	ai->p = newIPint(b);
+	ok = 1;
+out:
+	if(!ok){
+		r = *f->ret;
+		*f->ret = H;
+		destroy(r);
+	}
+	free(buf);
+	if(fd >= 0){
+		release();
+		kclose(fd);
+		acquire();
+		kwerrstr("%q: %s", string2c(f->filename), MSG);
+	}
+}
+
+void
+keyringmodinit(void)
+{
+	SigAlgVec *sav;
+	extern SigAlgVec* elgamalinit(void);
+	extern SigAlgVec* rsainit(void);
+	extern SigAlgVec* dsainit(void);
+
+	ipintsmodinit();	/* in case only Keyring is configured */
+	TSigAlg = dtype(freeSigAlg, sizeof(SigAlg), SigAlgmap, sizeof(SigAlgmap));
+	TSK = dtype(freeSK, sizeof(SK), SKmap, sizeof(SKmap));
+	TPK = dtype(freePK, sizeof(PK), PKmap, sizeof(PKmap));
+	TCertificate = dtype(freeCertificate, sizeof(Certificate), Certificatemap,
+		sizeof(Certificatemap));
+	TDigestState = dtype(freeheap, sizeof(XDigestState), DigestStatemap,
+		sizeof(DigestStatemap));
+	TAESstate = dtype(freeheap, sizeof(XAESstate), AESstatemap,
+		sizeof(AESstatemap));
+	TDESstate = dtype(freeheap, sizeof(XDESstate), DESstatemap,
+		sizeof(DESstatemap));
+	TIDEAstate = dtype(freeheap, sizeof(XIDEAstate), IDEAstatemap,
+		sizeof(IDEAstatemap));
+	TBFstate = dtype(freeheap, sizeof(XBFstate), BFstatemap,
+		sizeof(BFstatemap));
+	TRC4state = dtype(freeheap, sizeof(XRC4state), RC4statemap,
+		sizeof(RC4statemap));
+	TAuthinfo = dtype(freeheap, sizeof(Keyring_Authinfo), Authinfomap, sizeof(Authinfomap));
+	TDSAsk = dtype(freeheap, sizeof(Keyring_DSAsk), DSAskmap, sizeof(DSAskmap));
+	TDSApk = dtype(freeheap, sizeof(Keyring_DSApk), DSApkmap, sizeof(DSApkmap));
+	TDSAsig = dtype(freeheap, sizeof(Keyring_DSAsig), DSAsigmap, sizeof(DSAsigmap));
+	TEGsk = dtype(freeheap, sizeof(Keyring_EGsk), EGskmap, sizeof(EGskmap));
+	TEGpk = dtype(freeheap, sizeof(Keyring_EGpk), EGpkmap, sizeof(EGpkmap));
+	TEGsig = dtype(freeheap, sizeof(Keyring_EGsig), EGsigmap, sizeof(EGsigmap));
+	TRSAsk = dtype(freeheap, sizeof(Keyring_RSAsk), RSAskmap, sizeof(RSAskmap));
+	TRSApk = dtype(freeheap, sizeof(Keyring_RSApk), RSApkmap, sizeof(RSApkmap));
+	TRSAsig = dtype(freeheap, sizeof(Keyring_RSAsig), RSAsigmap, sizeof(RSAsigmap));
+
+	if((sav = elgamalinit()) != nil)
+		algs[nalg++] = sav;
+	if((sav = rsainit()) != nil)
+		algs[nalg++] = sav;
+	if((sav = dsainit()) != nil)
+		algs[nalg++] = sav;
+
+	fmtinstall('U', big64conv);
+	builtinmod("$Keyring", Keyringmodtab, Keyringmodlen);
+}
+
+/*
+ *  IO on a delimited channel.  A message starting with 0x00 is a normal
+ *  message.  One starting with 0xff is an error string.
+ *
+ *  return negative number for error messages (including hangup)
+ */
+static int
+getbuf(int fd, uchar *buf, int n, char *err, int nerr)
+{
+	int len;
+
+	release();
+	len = kread(fd, buf, n);
+	acquire();
+	if(len <= 0){
+		strncpy(err, "hungup", nerr);
+		buf[nerr-1] = 0;
+		return -1;
+	}
+	if(buf[0] == 0)
+		return len-1;
+	if(buf[0] != 0xff){
+		/*
+		 * this happens when the client's password is wrong: both sides use a digest of the
+		 * password as a crypt key for devssl. When they don't match decryption garbles
+		 * messages
+		 */
+		strncpy(err, "failure", nerr);
+		err[nerr-1] = 0;
+		return -1;
+	}
+
+	/* error string */
+	len--;
+	if(len < 1){
+		strncpy(err, "unknown", nerr);
+		err[nerr-1] = 0;
+	} else {
+		if(len >= nerr)
+			len = nerr-1;
+		memmove(err, buf+1, len);
+		err[len] = 0;
+	}
+	return -1;
+}
+
+void
+Keyring_getstring(void *fp)
+{
+	F_Keyring_getstring *f;
+	uchar *buf;
+	char err[64];
+	int n;
+
+	f = fp;
+	destroy(f->ret->t0);
+	f->ret->t0 = H;
+	destroy(f->ret->t1);
+	f->ret->t1 = H;
+
+	if(f->fd == H)
+		return;
+
+	buf = malloc(Maxmsg);
+	if(buf == nil)
+		return;
+
+	n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+	if(n < 0)
+		retnstr(err, strlen(err), &f->ret->t1);
+	else
+		retnstr(((char*)buf)+1, n, &f->ret->t0);
+
+	free(buf);
+}
+
+void
+Keyring_getbytearray(void *fp)
+{
+	F_Keyring_getbytearray *f;
+	uchar *buf;
+	char err[64];
+	int n;
+
+	f = fp;
+	destroy(f->ret->t0);
+	f->ret->t0 = H;
+	destroy(f->ret->t1);
+	f->ret->t1 = H;
+
+	if(f->fd == H)
+		return;
+
+	buf = malloc(Maxmsg);
+	if(buf == nil)
+		return;
+
+	n = getbuf(f->fd->fd, buf, Maxmsg, err, sizeof(err));
+	if(n < 0)
+		retnstr(err, strlen(err), &f->ret->t1);
+	else
+		f->ret->t0 = mem2array(buf+1, n);
+
+	free(buf);
+}
+
+static int
+putbuf(int fd, void *p, int n)
+{
+	char *buf;
+
+	buf = malloc(Maxmsg);
+	if(buf == nil)
+		return -1;
+
+	release();
+	buf[0] = 0;
+	if(n < 0){
+		buf[0] = 0xff;
+		n = -n;
+	}
+	if(n >= Maxmsg)
+		n = Maxmsg - 1;
+	memmove(buf+1, p, n);
+	n = kwrite(fd, buf, n+1);
+	acquire();
+
+	free(buf);
+	return n;
+}
+
+void
+Keyring_putstring(void *fp)
+{
+	F_Keyring_putstring *f;
+
+	f = fp;
+	*f->ret = -1;
+	if(f->fd == H || f->s == H)
+		return;
+	*f->ret = putbuf(f->fd->fd, string2c(f->s), strlen(string2c(f->s)));
+}
+
+void
+Keyring_puterror(void *fp)
+{
+	F_Keyring_puterror *f;
+
+	f = fp;
+	*f->ret = -1;
+	if(f->fd == H || f->s == H)
+		return;
+	*f->ret = putbuf(f->fd->fd, string2c(f->s), -strlen(string2c(f->s)));
+}
+
+void
+Keyring_putbytearray(void *fp)
+{
+	F_Keyring_putbytearray *f;
+	int n;
+
+	f = fp;
+	*f->ret = -1;
+	if(f->fd == H || f->a == H)
+		return;
+	n = f->n;
+	if(n < 0 || n > f->a->len)
+		error(exBounds);
+	*f->ret = putbuf(f->fd->fd, f->a->data, n);
+}
+
+void
+Keyring_dessetup(void *fp)
+{
+	F_Keyring_dessetup *f;
+	Heap *h;
+	XDESstate *ds;
+	uchar *ivec;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	if(f->key == H || f->key->len < 8)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len < 8)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TDESstate);
+	ds = H2D(XDESstate*, h);
+	setupDESstate(&ds->state, f->key->data, ivec);
+
+	*f->ret = (Keyring_DESstate*)ds;
+}
+
+void
+Keyring_desecb(void *fp)
+{
+	F_Keyring_desecb *f;
+	XDESstate *ds;
+	int i;
+	uchar *p;
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	ds = checktype(f->state, TDESstate, exBadState, 0);
+	p = f->buf->data;
+
+	for(i = 8; i <= f->n; i += 8, p += 8)
+		block_cipher(ds->state.expanded, p, f->direction);
+}
+
+void
+Keyring_descbc(void *fp)
+{
+	F_Keyring_descbc *f;
+	XDESstate *ds;
+	uchar *p, *ep, *ip, *p2, *eip;
+	uchar tmp[8];
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	ds = checktype(f->state, TDESstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0){
+		for(ep = p + f->n; p < ep; p += 8){
+			p2 = p;
+			ip = ds->state.ivec;
+			for(eip = ip+8; ip < eip; )
+				*p2++ ^= *ip++;
+			block_cipher(ds->state.expanded, p, 0);
+			memmove(ds->state.ivec, p, 8);
+		}
+	} else {
+		for(ep = p + f->n; p < ep; ){
+			memmove(tmp, p, 8);
+			block_cipher(ds->state.expanded, p, 1);
+			p2 = tmp;
+			ip = ds->state.ivec;
+			for(eip = ip+8; ip < eip; ){
+				*p++ ^= *ip;
+				*ip++ = *p2++;
+			}
+		}
+	}
+}
+
+void
+Keyring_ideasetup(void *fp)
+{
+	F_Keyring_ideasetup *f;
+	Heap *h;
+	XIDEAstate *is;
+	uchar *ivec;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	if(f->key == H || f->key->len < 16)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len < 8)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TIDEAstate);
+	is = H2D(XIDEAstate*, h);
+
+	setupIDEAstate(&is->state, f->key->data, ivec);
+
+	*f->ret = (Keyring_IDEAstate*)is;
+}
+
+void
+Keyring_ideaecb(void *fp)
+{
+	F_Keyring_ideaecb *f;
+	XIDEAstate *is;
+	int i;
+	uchar *p;
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	is = checktype(f->state, TIDEAstate, exBadState, 0);
+	p = f->buf->data;
+
+	for(i = 8; i <= f->n; i += 8, p += 8)
+		idea_cipher(is->state.edkey, p, f->direction);
+}
+
+void
+Keyring_ideacbc(void *fp)
+{
+	F_Keyring_ideacbc *f;
+	XIDEAstate *is;
+	uchar *p, *ep, *ip, *p2, *eip;
+	uchar tmp[8];
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	is = checktype(f->state, TIDEAstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0){
+		for(ep = p + f->n; p < ep; p += 8){
+			p2 = p;
+			ip = is->state.ivec;
+			for(eip = ip+8; ip < eip; )
+				*p2++ ^= *ip++;
+			idea_cipher(is->state.edkey, p, 0);
+			memmove(is->state.ivec, p, 8);
+		}
+	} else {
+		for(ep = p + f->n; p < ep; ){
+			memmove(tmp, p, 8);
+			idea_cipher(is->state.edkey, p, 1);
+			p2 = tmp;
+			ip = is->state.ivec;
+			for(eip = ip+8; ip < eip; ){
+				*p++ ^= *ip;
+				*ip++ = *p2++;
+			}
+		}
+	}
+}
+
+void
+Keyring_aessetup(void *fp)
+{
+	F_Keyring_aessetup *f;
+	Heap *h;
+	XAESstate *is;
+	uchar *ivec;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	if(f->key == H ||
+	   f->key->len != 16 && f->key->len != 24 && f->key->len != 32)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len < AESbsize)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TAESstate);
+	is = H2D(XAESstate*, h);
+
+	setupAESstate(&is->state, f->key->data, f->key->len, ivec);
+
+	*f->ret = (Keyring_AESstate*)is;
+}
+
+void
+Keyring_aescbc(void *fp)
+{
+	F_Keyring_aescbc *f;
+	XAESstate *is;
+	uchar *p;
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+
+	is = checktype(f->state, TAESstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0)
+		aesCBCencrypt(p, f->n, &is->state);
+	else
+		aesCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Keyring_blowfishsetup(void *fp)
+{
+	F_Keyring_blowfishsetup *f;
+	Heap *h;
+	XBFstate *is;
+	uchar *ivec;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	if(f->key == H || f->key->len <= 0)
+		error(exBadKey);
+	if(f->ivec != H){
+		if(f->ivec->len != BFbsize)
+			error(exBadIvec);
+		ivec = f->ivec->data;
+	}else
+		ivec = nil;
+
+	h = heap(TBFstate);
+	is = H2D(XBFstate*, h);
+
+	setupBFstate(&is->state, f->key->data, f->key->len, ivec);
+
+	*f->ret = (Keyring_BFstate*)is;
+}
+
+void
+Keyring_blowfishcbc(void *fp)
+{
+	F_Keyring_blowfishcbc *f;
+	XBFstate *is;
+	uchar *p;
+
+	f = fp;
+
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	if(f->n & 7)
+		error(exBadBsize);
+
+	is = checktype(f->state, TBFstate, exBadState, 0);
+	p = f->buf->data;
+
+	if(f->direction == 0)
+		bfCBCencrypt(p, f->n, &is->state);
+	else
+		bfCBCdecrypt(p, f->n, &is->state);
+}
+
+void
+Keyring_rc4setup(void *fp)
+{
+	F_Keyring_rc4setup *f;
+	Heap *h;
+	XRC4state *is;
+	void *r;
+
+	f = fp;
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	if(f->seed == H)
+		return;
+
+	h = heap(TRC4state);
+	is = H2D(XRC4state*, h);
+
+	setupRC4state(&is->state, f->seed->data, f->seed->len);
+
+	*f->ret = (Keyring_RC4state*)is;
+}
+
+void
+Keyring_rc4(void *fp)
+{
+	F_Keyring_rc4 *f;
+	XRC4state *is;
+	uchar *p;
+
+	f = fp;
+	if(f->buf == H)
+		return;
+	if(f->n < 0 || f->n > f->buf->len)
+		error(exBounds);
+	is = checktype(f->state, TRC4state, exBadState, 0);
+	p = f->buf->data;
+	rc4(&is->state, p, f->n);
+}
+
+void
+Keyring_rc4skip(void *fp)
+{
+	F_Keyring_rc4skip *f;
+	XRC4state *is;
+
+	f = fp;
+	is = checktype(f->state, TRC4state, exBadState, 0);
+	rc4skip(&is->state, f->n);
+}
+
+void
+Keyring_rc4back(void *fp)
+{
+	F_Keyring_rc4back *f;
+	XRC4state *is;
+
+	f = fp;
+	is = checktype(f->state, TRC4state, exBadState, 0);
+	rc4back(&is->state, f->n);
+}
+
+/*
+ *  public/secret keys, signing and verifying
+ */
+
+static void
+dsapk2pub(DSApub* p, Keyring_DSApk* pk)
+{
+	if(pk == H)
+		error(exNilref);
+	p->p = checkIPint(pk->p);
+	p->q = checkIPint(pk->q);
+	p->alpha = checkIPint(pk->alpha);
+	p->key = checkIPint(pk->key);
+}
+
+static void
+dsask2priv(DSApriv* p, Keyring_DSAsk* sk)
+{
+	if(sk == H || sk->pk == H)
+		error(exNilref);
+	dsapk2pub(&p->pub, sk->pk);
+	p->secret = checkIPint(sk->secret);
+}
+
+static void
+dsapriv2sk(Keyring_DSAsk* sk, DSApriv* p)
+{
+	Keyring_DSApk* pk;
+
+	pk = sk->pk;
+	pk->p = ipcopymp(p->pub.p);
+	pk->q = ipcopymp(p->pub.q);
+	pk->alpha = ipcopymp(p->pub.alpha);
+	pk->key = ipcopymp(p->pub.key);
+	sk->secret = ipcopymp(p->secret);
+}
+
+void
+DSAsk_gen(void *fp)
+{
+	F_DSAsk_gen *f;
+	Keyring_DSAsk *sk;
+	DSApriv *p;
+	DSApub pub, *oldpk;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	sk = newthing(TDSAsk, 0);
+	sk->pk = newthing(TDSApk, 0);
+	*f->ret = sk;
+	destroy(v);
+	oldpk = nil;
+	if(f->oldpk != H){
+		dsapk2pub(&pub, f->oldpk);
+		oldpk = &pub;
+	}
+	release();
+	p = dsagen(oldpk);
+	acquire();
+	dsapriv2sk(sk, p);
+	dsaprivfree(p);
+}
+
+void
+DSAsk_sign(void *fp)
+{
+	F_DSAsk_sign *f;
+	Keyring_DSAsig *sig;
+	DSApriv p;
+	mpint *m;
+	DSAsig *s;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	sig = newthing(TDSAsig, 0);
+	*f->ret = sig;
+	destroy(v);
+
+	dsask2priv(&p, f->k);
+	m = checkIPint(f->m);
+	release();
+	s = dsasign(&p, m);
+	acquire();
+	sig->r = ipcopymp(s->r);
+	sig->s = ipcopymp(s->s);
+	dsasigfree(s);
+}
+
+void
+DSApk_verify(void *fp)
+{
+	F_DSApk_verify *f;
+	DSApub p;
+	DSAsig sig;
+	mpint *m;
+
+	f = fp;
+	*f->ret = 0;
+	if(f->m == H || f->sig == H)
+		return;
+	dsapk2pub(&p, f->k);
+	sig.r = checkIPint(f->sig->r);
+	sig.s = checkIPint(f->sig->s);
+	m = checkIPint(f->m);
+	release();
+	*f->ret = dsaverify(&p, &sig, m) == 0;
+	acquire();
+}
+
+static void
+egpk2pub(EGpub* p, Keyring_EGpk* pk)
+{
+	if(pk == H)
+		error(exNilref);
+	p->p = checkIPint(pk->p);
+	p->alpha = checkIPint(pk->alpha);
+	p->key = checkIPint(pk->key);
+}
+
+static void
+egsk2priv(EGpriv* p, Keyring_EGsk* sk)
+{
+	if(sk == H || sk->pk == H)
+		error(exNilref);
+	egpk2pub(&p->pub, sk->pk);
+	p->secret = checkIPint(sk->secret);
+}
+
+static void
+egpriv2sk(Keyring_EGsk* sk, EGpriv* p)
+{
+	Keyring_EGpk* pk;
+
+	pk = sk->pk;
+	pk->p = ipcopymp(p->pub.p);
+	pk->alpha = ipcopymp(p->pub.alpha);
+	pk->key = ipcopymp(p->pub.key);
+	sk->secret = ipcopymp(p->secret);
+}
+
+void
+EGsk_gen(void *fp)
+{
+	F_EGsk_gen *f;
+	Keyring_EGsk *sk;
+	EGpriv *p;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	sk = newthing(TEGsk, 0);
+	sk->pk = newthing(TEGpk, 0);
+	*f->ret = sk;
+	destroy(v);
+	release();
+	for(;;){
+		p = eggen(f->nlen, f->nrep);
+		if(mpsignif(p->pub.p) == f->nlen)
+			break;
+		egprivfree(p);
+	}
+	acquire();
+	egpriv2sk(sk, p);
+	egprivfree(p);
+}
+
+void
+EGsk_sign(void *fp)
+{
+	F_EGsk_sign *f;
+	Keyring_EGsig *sig;
+	EGpriv p;
+	mpint *m;
+	EGsig *s;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	sig = newthing(TEGsig, 0);
+	*f->ret = sig;
+	destroy(v);
+
+	egsk2priv(&p, f->k);
+	m = checkIPint(f->m);
+	release();
+	s = egsign(&p, m);
+	acquire();
+	sig->r = ipcopymp(s->r);
+	sig->s = ipcopymp(s->s);
+	egsigfree(s);
+}
+
+void
+EGpk_verify(void *fp)
+{
+	F_EGpk_verify *f;
+	EGpub p;
+	EGsig sig;
+	mpint *m;
+
+	f = fp;
+	*f->ret = 0;
+	if(f->m == H || f->sig == H)
+		return;
+	egpk2pub(&p, f->k);
+	sig.r = checkIPint(f->sig->r);
+	sig.s = checkIPint(f->sig->s);
+	m = checkIPint(f->m);
+	release();
+	*f->ret = egverify(&p, &sig, m) == 0;
+	acquire();
+}
+
+static void
+rsapk2pub(RSApub* p, Keyring_RSApk* pk)
+{
+	if(pk == H)
+		error(exNilref);
+	memset(p, 0, sizeof(*p));
+	p->n = checkIPint(pk->n);
+	p->ek = checkIPint(pk->ek);
+}
+
+static void
+rsask2priv(RSApriv* p, Keyring_RSAsk* sk)
+{
+	if(sk == H || sk->pk == H)
+		error(exNilref);
+	rsapk2pub(&p->pub, sk->pk);
+	p->dk = checkIPint(sk->dk);
+	p->p = checkIPint(sk->p);
+	p->q = checkIPint(sk->q);
+	p->kp = checkIPint(sk->kp);
+	p->kq = checkIPint(sk->kq);
+	p->c2 = checkIPint(sk->c2);
+}
+
+static void
+rsapriv2sk(Keyring_RSAsk* sk, RSApriv* p)
+{
+	Keyring_RSApk* pk;
+
+	pk = sk->pk;
+	pk->n = ipcopymp(p->pub.n);
+	pk->ek = ipcopymp(p->pub.ek);
+	sk->dk = ipcopymp(p->dk);
+	sk->p = ipcopymp(p->p);
+	sk->q = ipcopymp(p->q);
+	sk->kp = ipcopymp(p->kp);
+	sk->kq = ipcopymp(p->kq);
+	sk->c2 = ipcopymp(p->c2);
+}
+
+void
+RSApk_encrypt(void *fp)
+{
+	F_RSApk_encrypt *f;
+	RSApub p;
+	mpint *m, *o;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	rsapk2pub(&p, f->k);
+	m = checkIPint(f->m);
+	release();
+	o = rsaencrypt(&p, m, nil);
+	acquire();
+	*f->ret = newIPint(o);
+}
+
+void
+RSAsk_gen(void *fp)
+{
+	F_RSAsk_gen *f;
+	Keyring_RSAsk *sk;
+	RSApriv *p;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	sk = newthing(TRSAsk, 0);
+	sk->pk = newthing(TRSApk, 0);
+	*f->ret = sk;
+	destroy(v);
+	release();
+	for(;;){
+		p = rsagen(f->nlen, f->elen, f->nrep);
+		if(mpsignif(p->pub.n) == f->nlen)
+			break;
+		rsaprivfree(p);
+	}
+	acquire();
+	rsapriv2sk(sk, p);
+	rsaprivfree(p);
+}
+
+void
+RSAsk_fill(void *fp)
+{
+	F_RSAsk_fill *f;
+	Keyring_RSAsk *sk;
+	RSApriv *p;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	sk = newthing(TRSAsk, 0);
+	sk->pk = newthing(TRSApk, 0);
+	*f->ret = sk;
+	destroy(v);
+	release();
+	p = rsafill(checkIPint(f->n), checkIPint(f->e), checkIPint(f->d),
+			checkIPint(f->p), checkIPint(f->q));
+	acquire();
+	if(p == nil) {
+		*f->ret = H;
+		destroy(sk);
+	}else{
+		rsapriv2sk(sk, p);
+		rsaprivfree(p);
+	}
+}
+
+void
+RSAsk_decrypt(void *fp)
+{
+	F_RSAsk_decrypt *f;
+	RSApriv p;
+	mpint *m, *o;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	rsask2priv(&p, f->k);
+	m = checkIPint(f->m);
+	release();
+	o = rsadecrypt(&p, m, nil);
+	acquire();
+	*f->ret = newIPint(o);
+}
+
+void
+RSAsk_sign(void *fp)
+{
+	F_RSAsk_sign *f;
+	Keyring_RSAsig *sig;
+	RSApriv p;
+	mpint *m, *s;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	sig = newthing(TRSAsig, 0);
+	*f->ret = sig;
+	destroy(v);
+
+	rsask2priv(&p, f->k);
+	m = checkIPint(f->m);
+	release();
+	s = rsadecrypt(&p, m, nil);
+	acquire();
+	sig->n = newIPint(s);
+}
+
+void
+RSApk_verify(void *fp)
+{
+	F_RSApk_verify *f;
+	RSApub p;
+	mpint *sig, *m, *t;
+
+	f = fp;
+	*f->ret = 0;
+	if(f->m == H || f->sig == H)
+		return;
+	rsapk2pub(&p, f->k);
+	sig = checkIPint(f->sig->n);
+	m = checkIPint(f->m);
+	release();
+	t = rsaencrypt(&p, sig, nil);
+	*f->ret = mpcmp(t, m) == 0;
+	mpfree(t);
+	acquire();
+}
+
+void
+Keyring_IPint_random(void *fp)
+{
+	F_IPint_random *f;
+	mpint *b;
+	void *v;
+
+	f = fp;
+	v = *f->ret;
+	*f->ret = H;
+	destroy(v);
+
+	release();
+	b = mprand(f->maxbits, genrandom, nil);
+	acquire();
+	*f->ret = newIPint(b);
+}
--- /dev/null
+++ b/libinterp/keyringif.m
@@ -1,0 +1,4 @@
+# temporary hack to prevent clashes with DigestState
+include "sys.m";
+
+include "keyring.m";
--- /dev/null
+++ b/libinterp/link.c
@@ -1,0 +1,132 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <kernel.h>
+
+static void
+newlink(Link *l, char *fn, int sig, Type *t)
+{
+	l->name = malloc(strlen(fn)+1);
+	if(l->name == nil)
+		error(exNomem);
+	strcpy(l->name, fn);
+	l->sig = sig;
+	l->frame = t;
+}
+
+void
+runtime(Module *m, Link *l, char *fn, int sig, void (*runt)(void*), Type *t)
+{
+	USED(m);
+	newlink(l, fn, sig, t);
+	l->u.runt = runt;
+}
+
+void
+mlink(Module *m, Link* l, uchar *fn, int sig, int pc, Type *t)
+{
+	newlink(l, (char*)fn, sig, t);
+	l->u.pc = m->prog+pc;
+}
+
+static int
+linkm(Module *m, Modlink *ml, int i, Import *ldt)
+{
+	Link *l;
+	int sig;
+	char e[ERRMAX];
+
+	sig = ldt->sig;
+	for(l = m->ext; l->name; l++)
+		if(strcmp(ldt->name, l->name) == 0)
+			break;
+
+	if(l == nil) {
+		snprint(e, sizeof(e), "link failed fn %s->%s() not implemented", m->name, ldt->name);
+		goto bad;
+	}
+	if(l->sig != sig) {
+		snprint(e, sizeof(e), "link typecheck %s->%s() %ux/%ux",
+							m->name, ldt->name, l->sig, sig);
+		goto bad;
+	}
+
+	ml->links[i].u = l->u;
+	ml->links[i].frame = l->frame;
+	return 0;
+bad:
+	kwerrstr(e);
+	print("%s\n", e);
+	return -1;
+}
+
+Modlink*
+mklinkmod(Module *m, int n)
+{
+	Heap *h;
+	Modlink *ml;
+
+	h = nheap(sizeof(Modlink)+(n-1)*sizeof(ml->links[0]));
+	h->t = &Tmodlink;
+	Tmodlink.ref++;
+	ml = H2D(Modlink*, h);
+	ml->nlinks = n;
+	ml->m = m;
+	ml->prog = m->prog;
+	ml->type = m->type;
+	ml->compiled = m->compiled;
+	ml->MP = H;
+	ml->data = nil;
+
+	return ml;
+}
+
+Modlink*
+linkmod(Module *m, Import *ldt, int mkmp)
+{
+	Type *t;
+	Heap *h;
+	int i;
+	Modlink *ml;
+	Import *l;
+
+	if(m == nil)
+		return H;
+
+	for(i = 0, l = ldt; l->name != nil; i++, l++)
+		;
+	ml = mklinkmod(m, i);
+
+	if(mkmp){
+		if(m->rt == DYNMOD)
+			newdyndata(ml);
+		else if(mkmp && m->origmp != H && m->ntype > 0) {
+			t = m->type[0];
+			h = nheap(t->size);
+			h->t = t;
+			t->ref++;
+			ml->MP = H2D(uchar*, h);
+			newmp(ml->MP, m->origmp, t);
+		}
+	}
+
+	for(i = 0, l = ldt; l->name != nil; i++, l++) {
+		if(linkm(m, ml, i, l) < 0){
+			destroy(ml);
+			return H;
+		}
+	}
+
+	return ml;
+}
+
+void
+destroylinks(Module *m)
+{
+	Link *l;
+
+	for(l = m->ext; l->name; l++)
+		free(l->name);
+	free(m->ext);
+}
--- /dev/null
+++ b/libinterp/load.c
@@ -1,0 +1,621 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <kernel.h>
+
+#define	A(r)	*((Array**)(r))
+
+Module*	modules;
+int	dontcompile;
+
+static int
+operand(uchar **p)
+{
+	int c;
+	uchar *cp;
+
+	cp = *p;
+	c = cp[0];
+	switch(c & 0xC0) {
+	case 0x00:
+		*p = cp+1;
+		return c;
+	case 0x40:
+		*p = cp+1;
+		return c|~0x7F;
+	case 0x80:
+		*p = cp+2;
+		if(c & 0x20)
+			c |= ~0x3F;
+		else
+			c &= 0x3F;
+		return (c<<8)|cp[1];		
+	case 0xC0:
+		*p = cp+4;
+		if(c & 0x20)
+			c |= ~0x3F;
+		else
+			c &= 0x3F;
+		return (c<<24)|(cp[1]<<16)|(cp[2]<<8)|cp[3];		
+	}
+	return 0;	
+}
+
+static ulong
+disw(uchar **p)
+{
+	ulong v;
+	uchar *c;
+
+	c = *p;
+	v  = c[0] << 24;
+	v |= c[1] << 16;
+	v |= c[2] << 8;
+	v |= c[3];
+	*p = c + 4;
+	return v;
+}
+
+double
+canontod(ulong v[2])
+{
+	union { double d; unsigned long ul[2]; } a;
+	a.d = 1.;
+	if(a.ul[0]) {
+		a.ul[0] = v[0];
+		a.ul[1] = v[1];
+	}
+	else {
+		a.ul[1] = v[0];
+		a.ul[0] = v[1];
+	}
+	return a.d;
+}
+
+Module*
+load(char *path)
+{
+	return readmod(path, nil, 0);
+}
+
+int
+brpatch(Inst *ip, Module *m)
+{
+	switch(ip->op) {
+	case ICALL:
+	case IJMP:
+	case IBEQW:
+	case IBNEW:
+	case IBLTW:
+	case IBLEW:
+	case IBGTW:
+	case IBGEW:
+	case IBEQB:
+	case IBNEB:
+	case IBLTB:
+	case IBLEB:
+	case IBGTB:
+	case IBGEB:
+	case IBEQF:
+	case IBNEF:
+	case IBLTF:
+	case IBLEF:
+	case IBGTF:
+	case IBGEF:
+	case IBEQC:
+	case IBNEC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+	case IBEQL:
+	case IBNEL:
+	case IBLTL:
+	case IBLEL:
+	case IBGTL:
+	case IBGEL:
+	case ISPAWN:
+		if(ip->d.imm < 0 || ip->d.imm >= m->nprog)
+			return 0;
+		ip->d.imm = (WORD)&m->prog[ip->d.imm];
+		break;
+	}
+	return 1;
+}
+
+Module*
+parsemod(char *path, uchar *code, ulong length, Dir *dir)
+{
+	Heap *h;
+	Inst *ip;
+	Type *pt;
+	String *s;
+	Module *m;
+	Array *ary;
+	ulong ul[2];
+	WORD lo, hi;
+	int lsize, id, v, entry, entryt, tnp, tsz, siglen;
+	int de, pc, i, n, isize, dsize, hsize, dasp;
+	uchar *mod, sm, *istream, **isp, *si, *addr, *dastack[DADEPTH];
+	Link *l;
+
+	istream = code;
+	isp = &istream;
+
+	m = malloc(sizeof(Module));
+	if(m == nil)
+		return nil;
+
+	m->dev = dir->dev;
+	m->dtype = dir->type;
+	m->qid = dir->qid;
+	m->mtime = dir->mtime;
+	m->origmp = H;
+	m->pctab = nil;
+
+	switch(operand(isp)) {
+	default:
+		kwerrstr("bad magic");
+		goto bad;
+	case SMAGIC:
+		siglen = operand(isp);
+		n = length-(*isp-code);
+		if(n < 0 || siglen > n){
+			kwerrstr("corrupt signature");
+			goto bad;
+		}
+		if(verifysigner(*isp, siglen, *isp+siglen, n-siglen) == 0) {
+			kwerrstr("security violation");
+			goto bad;
+		}
+		*isp += siglen;
+		break;		
+	case XMAGIC:
+		if(mustbesigned(path, code, length, dir)){
+			kwerrstr("security violation: not signed");
+			goto bad;
+		}
+		break;
+	}
+
+	m->rt = operand(isp);
+	m->ss = operand(isp);
+	isize = operand(isp);
+	dsize = operand(isp);
+	hsize = operand(isp);
+	lsize = operand(isp);
+	entry = operand(isp);
+	entryt = operand(isp);
+
+	if(isize < 0 || dsize < 0 || hsize < 0 || lsize < 0) {
+		kwerrstr("implausible Dis file");
+		goto bad;
+	}
+
+	m->nprog = isize;
+	m->prog = mallocz(isize*sizeof(Inst), 0);
+	if(m->prog == nil) {
+		kwerrstr(exNomem);
+		goto bad;
+	}
+
+	m->ref = 1;
+
+	ip = m->prog;
+	for(i = 0; i < isize; i++) {
+		ip->op = *istream++;
+		ip->add = *istream++;
+		ip->reg = 0;
+		ip->s.imm = 0;
+		ip->d.imm = 0;
+		switch(ip->add & ARM) {
+		case AXIMM:
+		case AXINF:
+		case AXINM:
+			ip->reg = operand(isp);
+		 	break;
+		}
+		switch(UXSRC(ip->add)) {
+		case SRC(AFP):
+		case SRC(AMP):	
+		case SRC(AIMM):
+			ip->s.ind = operand(isp);
+			break;
+		case SRC(AIND|AFP):
+		case SRC(AIND|AMP):
+			ip->s.i.f = operand(isp);
+			ip->s.i.s = operand(isp);
+			break;
+		}
+		switch(UXDST(ip->add)) {
+		case DST(AFP):
+		case DST(AMP):	
+			ip->d.ind = operand(isp);
+			break;
+		case DST(AIMM):
+			ip->d.ind = operand(isp);
+			if(brpatch(ip, m) == 0) {
+				kwerrstr("bad branch addr");
+				goto bad;
+			}
+			break;
+		case DST(AIND|AFP):
+		case DST(AIND|AMP):
+			ip->d.i.f = operand(isp);
+			ip->d.i.s = operand(isp);
+			break;
+		}
+		ip++;		
+	}
+
+	m->ntype = hsize;
+	m->type = malloc(hsize*sizeof(Type*));
+	if(m->type == nil) {
+		kwerrstr(exNomem);
+		goto bad;
+	}
+	for(i = 0; i < hsize; i++) {
+		id = operand(isp);
+		if(id > hsize) {
+			kwerrstr("heap id range");
+			goto bad;
+		}
+		tsz = operand(isp);
+		tnp = operand(isp);
+		if(tsz < 0 || tnp < 0 || tnp > 128*1024){
+			kwerrstr("implausible Dis file");
+			goto bad;
+		}
+		pt = dtype(freeheap, tsz, istream, tnp);
+		if(pt == nil) {
+			kwerrstr(exNomem);
+			goto bad;
+		}
+		istream += tnp;
+		m->type[id] = pt;
+	}
+
+	if(dsize != 0) {
+		pt = m->type[0];
+		if(pt == 0 || pt->size != dsize) {
+			kwerrstr("bad desc for mp");
+			goto bad;
+		}
+		h = heapz(pt);
+		m->origmp = H2D(uchar*, h);
+	}
+	addr = m->origmp;
+	dasp = 0;
+	for(;;) {
+		sm = *istream++;
+		if(sm == 0)
+			break;
+		n = DLEN(sm);
+		if(n == 0)
+			n = operand(isp);
+		v = operand(isp);
+		si = addr + v;
+		switch(DTYPE(sm)) {
+		default:
+			kwerrstr("bad data item");
+			goto bad;
+		case DEFS:
+			s = c2string((char*)istream, n);
+			istream += n;
+			*(String**)si = s;
+			break;
+		case DEFB:
+			for(i = 0; i < n; i++)
+				*si++ = *istream++;
+			break;
+		case DEFW:
+			for(i = 0; i < n; i++) {
+				*(WORD*)si = disw(isp);
+				si += sizeof(WORD);
+			}
+			break;
+		case DEFL:
+			for(i = 0; i < n; i++) {
+				hi = disw(isp);
+				lo = disw(isp);
+				*(LONG*)si = (LONG)hi << 32 | (LONG)(ulong)lo;
+				si += sizeof(LONG);
+			}
+			break;
+		case DEFF:
+			for(i = 0; i < n; i++) {
+				ul[0] = disw(isp);
+				ul[1] = disw(isp);
+				*(REAL*)si = canontod(ul);
+				si += sizeof(REAL);
+			}
+			break;
+		case DEFA:			/* Array */
+			v = disw(isp);
+			if(v < 0 || v > m->ntype) {
+				kwerrstr("bad array type");
+				goto bad;
+			}
+			pt = m->type[v];
+			v = disw(isp);
+			h = nheap(sizeof(Array)+(pt->size*v));
+			h->t = &Tarray;
+			h->t->ref++;
+			ary = H2D(Array*, h);
+			ary->t = pt;
+			ary->len = v;
+			ary->root = H;
+			ary->data = (uchar*)ary+sizeof(Array);
+			memset((void*)ary->data, 0, pt->size*v);
+			initarray(pt, ary);
+			A(si) = ary;
+			break;			
+		case DIND:			/* Set index */
+			ary = A(si);
+			if(ary == H || D2H(ary)->t != &Tarray) {
+				kwerrstr("ind not array");
+				goto bad;
+			}
+			v = disw(isp);
+			if(v > ary->len || v < 0 || dasp >= DADEPTH) {
+				kwerrstr("array init range");
+				goto bad;
+			}
+			dastack[dasp++] = addr;
+			addr = ary->data+v*ary->t->size;
+			break;
+		case DAPOP:
+			if(dasp == 0) {
+				kwerrstr("pop range");
+				goto bad;
+			}
+			addr = dastack[--dasp];
+			break;
+		}
+	}
+	mod = istream;
+	if(memchr(mod, 0, 128) == 0) {
+		kwerrstr("bad module name");
+		goto bad;
+	}
+	m->name = strdup((char*)mod);
+	if(m->name == nil) {
+		kwerrstr(exNomem);
+		goto bad;
+	}
+	while(*istream++)
+		;
+
+	l = m->ext = (Link*)malloc((lsize+1)*sizeof(Link));
+	if(l == nil){
+		kwerrstr(exNomem);
+		goto bad;
+	}
+	for(i = 0; i < lsize; i++, l++) {
+		pc = operand(isp);
+		de = operand(isp);
+		v  = disw(isp);
+		pt = nil;
+		if(de != -1)
+			pt = m->type[de];
+		mlink(m, l, istream, v, pc, pt);
+		while(*istream++)
+			;
+	}
+	l->name = nil;
+
+	if(m->rt & HASLDT0){
+		kwerrstr("obsolete dis");
+		goto bad;
+	}
+
+	if(m->rt & HASLDT){
+		int j, nl;
+		Import *i1, **i2;
+
+		nl = operand(isp);
+		i2 = m->ldt = (Import**)malloc((nl+1)*sizeof(Import*));
+		if(i2 == nil){
+			kwerrstr(exNomem);
+			goto bad;
+		}
+		for(i = 0; i < nl; i++, i2++){
+			n = operand(isp);
+			i1 = *i2 = (Import*)malloc((n+1)*sizeof(Import));
+			if(i1 == nil){
+				kwerrstr(exNomem);
+				goto bad;
+			}
+			for(j = 0; j < n; j++, i1++){
+				i1->sig = disw(isp);
+				i1->name = strdup((char*)istream);
+				if(i1->name == nil){
+					kwerrstr(exNomem);
+					goto bad;
+				}
+				while(*istream++)
+					;
+			}
+		}
+		istream++;
+	}
+
+	if(m->rt & HASEXCEPT){
+		int j, nh;
+		Handler *h;
+		Except *e;
+
+		nh = operand(isp);
+		m->htab = malloc((nh+1)*sizeof(Handler));
+		if(m->htab == nil){
+			kwerrstr(exNomem);
+			goto bad;
+		}
+		h = m->htab;
+		for(i = 0; i < nh; i++, h++){
+			h->eoff = operand(isp);
+			h->pc1 = operand(isp);
+			h->pc2 = operand(isp);
+			n = operand(isp);
+			if(n != -1)
+				h->t = m->type[n];
+			n = operand(isp);
+			h->ne = n>>16;
+			n &= 0xffff;
+			h->etab = malloc((n+1)*sizeof(Except));
+			if(h->etab == nil){
+				kwerrstr(exNomem);
+				goto bad;
+			}
+			e = h->etab;
+			for(j = 0; j < n; j++, e++){
+				e->s = strdup((char*)istream);
+				if(e->s == nil){
+					kwerrstr(exNomem);
+					goto bad;
+				}
+				while(*istream++)
+					;
+				e->pc = operand(isp);
+			}
+			e->s = nil;
+			e->pc = operand(isp);
+		}
+		istream++;
+	}
+
+	m->entryt = nil;
+	m->entry = m->prog;
+	if((ulong)entry < isize && (ulong)entryt < hsize) {
+		m->entry = &m->prog[entry];
+		m->entryt = m->type[entryt];
+	}
+
+	if(cflag) {
+		if((m->rt&DONTCOMPILE) == 0 && !dontcompile)
+			compile(m, isize, nil);
+	}
+	else
+	if(m->rt & MUSTCOMPILE && !dontcompile) {
+		if(compile(m, isize, nil) == 0) {
+			kwerrstr("compiler required");
+			goto bad;
+		}
+	}
+
+	m->path = strdup(path);
+	if(m->path == nil) {
+		kwerrstr(exNomem);
+		goto bad;
+	}
+	m->link = modules;
+	modules = m;
+
+	return m;
+bad:
+	destroy(m->origmp);
+	freemod(m);
+	return nil;
+}
+
+Module*
+newmod(char *s)
+{
+	Module *m;
+
+	m = malloc(sizeof(Module));
+	if(m == nil)
+		error(exNomem);
+	m->ref = 1;
+	m->path = s;
+	m->origmp = H;
+	m->name = strdup(s);
+	if(m->name == nil) {
+		free(m);
+		error(exNomem);
+	}
+	m->link = modules;
+	modules = m;
+	m->pctab = nil;
+	return m;
+}
+
+Module*
+lookmod(char *s)
+{
+	Module *m;
+
+	for(m = modules; m != nil; m = m->link)
+		if(strcmp(s, m->path) == 0) {
+			m->ref++;
+			return m;
+		}
+	return nil;
+}
+
+void
+freemod(Module *m)
+{
+	int i;
+	Handler *h;
+	Except *e;
+	Import *i1, **i2;
+
+	if(m->type != nil) {
+		for(i = 0; i < m->ntype; i++)
+			freetype(m->type[i]);
+		free(m->type);
+	}
+	free(m->name);
+	free(m->prog);
+	free(m->path);
+	free(m->pctab);
+	if(m->ldt != nil){
+		for(i2 = m->ldt; *i2 != nil; i2++){
+			for(i1 = *i2; i1->name != nil; i1++)
+				free(i1->name);
+			free(*i2);
+		}
+		free(m->ldt);
+	}
+	if(m->htab != nil){
+		for(h = m->htab; h->etab != nil; h++){
+			for(e = h->etab; e->s != nil; e++)
+				free(e->s);
+			free(h->etab);
+		}
+		free(m->htab);
+	}
+	free(m);
+}
+
+void
+unload(Module *m)
+{
+	Module **last, *mm;
+
+	m->ref--;
+	if(m->ref > 0)
+		return;
+	if(m->ref == -1)
+		abort();
+
+	last = &modules;
+	for(mm = modules; mm != nil; mm = mm->link) {
+		if(mm == m) {
+			*last = m->link;
+			break;
+		}
+		last = &mm->link;
+	}
+
+	if(m->rt == DYNMOD)
+		freedyncode(m);
+	else
+		destroy(m->origmp);
+
+	destroylinks(m);
+
+	freemod(m);
+}
--- /dev/null
+++ b/libinterp/loader.c
@@ -1,0 +1,444 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "runt.h"
+#include "loadermod.h"
+#include "raise.h"
+#include <kernel.h>
+
+static uchar	Instmap[] = Loader_Inst_map;
+static Type*	Tinst;
+static uchar	Tdescmap[] = Loader_Typedesc_map;
+static Type*	Tdesc;
+static uchar	Tlinkmap[] = Loader_Link_map;
+static Type*	Tlink;
+
+void
+loadermodinit(void)
+{
+	sysinit();
+	builtinmod("$Loader", Loadermodtab, Loadermodlen);
+	Tinst = dtype(freeheap, sizeof(Loader_Inst), Instmap, sizeof(Instmap));
+	Tdesc = dtype(freeheap, sizeof(Loader_Typedesc), Tdescmap, sizeof(Tdescmap));
+	Tlink = dtype(freeheap, sizeof(Loader_Link), Tlinkmap, sizeof(Tlinkmap));
+}
+
+static void
+brunpatch(Loader_Inst *ip, Module *m)
+{
+	switch(ip->op) {
+	case ICALL:
+	case IJMP:
+	case IBEQW:
+	case IBNEW:
+	case IBLTW:
+	case IBLEW:
+	case IBGTW:
+	case IBGEW:
+	case IBEQB:
+	case IBNEB:
+	case IBLTB:
+	case IBLEB:
+	case IBGTB:
+	case IBGEB:
+	case IBEQF:
+	case IBNEF:
+	case IBLTF:
+	case IBLEF:
+	case IBGTF:
+	case IBGEF:
+	case IBEQC:
+	case IBNEC:
+	case IBLTC:
+	case IBLEC:
+	case IBGTC:
+	case IBGEC:
+	case IBEQL:
+	case IBNEL:
+	case IBLTL:
+	case IBLEL:
+	case IBGTL:
+	case IBGEL:
+	case ISPAWN:
+		ip->dst = (Inst*)ip->dst - m->prog;
+		break;
+	}
+}
+
+void
+Loader_ifetch(void *a)
+{
+	Heap *h;
+	Array *ar;
+	Module *m;
+	Inst *i, *ie;
+	Loader_Inst *li;
+	F_Loader_ifetch *f;
+
+	f = a;
+	destroy(*f->ret);
+	*f->ret = H;
+
+	if(f->mp == H)
+		return;
+	m = f->mp->m;
+	if(m == H)
+		return;
+	if(m->compiled) {
+		kwerrstr("compiled module");
+		return;
+	}
+
+	h = nheap(sizeof(Array)+m->nprog*sizeof(Loader_Inst));
+	h->t = &Tarray;
+	h->t->ref++;
+	ar = H2D(Array*, h);
+	ar->t = Tinst;
+	Tinst->ref++;
+	ar->len = m->nprog;
+	ar->root = H;
+	ar->data = (uchar*)ar+sizeof(Array);
+
+	li = (Loader_Inst*)ar->data;
+	i = m->prog;
+	ie = i + m->nprog;
+	while(i < ie) {
+		li->op = i->op;
+		li->addr = i->add;
+		li->src = i->s.imm;
+		li->dst = i->d.imm;
+		li->mid = i->reg;
+		if(UDST(i->add) == AIMM)
+			brunpatch(li, m);
+		li++;
+		i++;
+	}
+
+	*f->ret = ar;
+}
+
+void
+Loader_link(void *a)
+{
+	Link *p;
+	Heap *h;
+	Type **t;
+	int nlink;
+	Module *m;
+	Array *ar;
+	Loader_Link *ll;
+	F_Loader_link *f;
+	
+	f = a;
+	destroy(*f->ret);
+	*f->ret = H;
+
+	if(f->mp == H)
+		return;
+	m = f->mp->m;
+	if(m == H)
+		return;
+
+	nlink = 0;
+	for(p = m->ext; p->name; p++)
+		nlink++;
+
+	h = nheap(sizeof(Array)+nlink*sizeof(Loader_Link));
+	h->t = &Tarray;
+	h->t->ref++;
+	ar = H2D(Array*, h);
+	ar->t = Tlink;
+	Tlink->ref++;
+	ar->len = nlink;
+	ar->root = H;
+	ar->data = (uchar*)ar+sizeof(Array);
+
+	ll = (Loader_Link*)ar->data + nlink;
+	for(p = m->ext; p->name; p++) {
+		ll--;
+		ll->name = c2string(p->name, strlen(p->name));
+		ll->sig = p->sig;
+		if(m->prog == nil) {
+			ll->pc = -1;
+			ll->tdesc = -1;
+		} else {
+			ll->pc = p->u.pc - m->prog;
+			ll->tdesc = 0;
+			for(t = m->type; *t != p->frame; t++)
+				ll->tdesc++;
+		}
+	}
+
+	*f->ret = ar;
+}
+
+void
+Loader_tdesc(void *a)
+{
+	int i;
+	Heap *h;
+	Type *t;
+	Array *ar;
+	Module *m;
+	F_Loader_tdesc *f;
+	Loader_Typedesc *lt;
+
+	f = a;
+	destroy(*f->ret);
+	*f->ret = H;
+
+	if(f->mp == H)
+		return;
+	m = f->mp->m;
+	if(m == H)
+		return;
+
+	h = nheap(sizeof(Array)+m->ntype*sizeof(Loader_Typedesc));
+	h->t = &Tarray;
+	h->t->ref++;
+	ar = H2D(Array*, h);
+	ar->t = Tdesc;
+	Tdesc->ref++;
+	ar->len = m->ntype;
+	ar->root = H;
+	ar->data = (uchar*)ar+sizeof(Array);
+
+	lt = (Loader_Typedesc*)ar->data;
+	for(i = 0; i < m->ntype; i++) {
+		t = m->type[i];
+		lt->size = t->size;
+		lt->map = H;
+		if(t->np != 0)
+			lt->map = mem2array(t->map, t->np);
+		lt++;
+	}
+
+	*f->ret = ar;
+}
+
+void
+Loader_newmod(void *a)
+{
+	Heap *h;
+	Module *m;
+	Array *ia;
+	Modlink *ml;
+	Inst *i, *ie;
+	Loader_Inst *li;
+	F_Loader_newmod *f;
+
+	f = a;
+	destroy(*f->ret);
+	*f->ret = H;
+
+	if(f->inst == H || f->data == H) {
+		kwerrstr("nil parameters");
+		return;
+	}
+	if(f->nlink < 0) {
+		kwerrstr("bad nlink");
+		return;
+	}
+
+	m = malloc(sizeof(Module));
+	if(m == nil) {
+		kwerrstr(exNomem);
+		return;
+	}
+	m->origmp = H;
+	m->ref = 1;
+	m->ss = f->ss;
+	m->name = strdup(string2c(f->name));
+	m->path = strdup(m->name);
+	m->ntype = 1;
+	m->type = malloc(sizeof(Type*));
+	if(m->name == nil || m->path == nil || m->type == nil) {
+		kwerrstr(exNomem);
+		goto bad;
+	}
+	m->origmp = (uchar*)f->data;
+	h = D2H(f->data);
+	h->ref++;
+	Setmark(h);
+	m->type[0] = h->t;
+	h->t->ref++;
+
+	ia = f->inst;
+	m->nprog = ia->len;
+	m->prog = malloc(m->nprog*sizeof(Inst));
+	if(m->prog == nil)
+		goto bad;
+	i = m->prog;
+	ie = i + m->nprog;
+	li = (Loader_Inst*)ia->data;
+	while(i < ie) {
+		i->op = li->op;
+		i->add = li->addr;
+		i->reg = li->mid;
+		i->s.imm = li->src;
+		i->d.imm = li->dst;
+		if(brpatch(i, m) == 0) {
+			kwerrstr("bad branch addr");
+			goto bad;
+		}
+		i++;
+		li++;
+	}
+	m->entryt = nil;
+	m->entry = m->prog;
+
+	ml = mklinkmod(m, f->nlink);
+	ml->MP = m->origmp;
+	m->origmp = H;
+	m->pctab = nil;
+	*f->ret = ml;
+	return;
+bad:
+	destroy(m->origmp);
+	freemod(m);
+}
+
+void
+Loader_tnew(void *a)
+{
+	int mem;
+	Module *m;
+	Type *t, **nt;
+	Array *ar, az;
+	F_Loader_tnew *f;
+
+	f = a;
+	*f->ret = -1;
+	if(f->mp == H)
+		return;
+	m = f->mp->m;
+	if(m == H)
+		return;
+	if(m->origmp != H){
+		kwerrstr("need newmod");
+		return;
+	}
+
+	ar = f->map;
+	if(ar == H) {
+		ar = &az;
+		ar->len = 0;
+		ar->data = nil;
+	}
+
+	t = dtype(freeheap, f->size, ar->data, ar->len);
+	if(t == nil)
+		return;
+
+	mem = (m->ntype+1)*sizeof(Type*);
+	if(msize(m->type) > mem) {
+		*f->ret = m->ntype;
+		m->type[m->ntype++] = t;
+		return;
+	}
+	nt = realloc(m->type, mem);
+	if(nt == nil) {
+		kwerrstr(exNomem);
+		return;
+	}
+	m->type = nt;
+	f->mp->type = nt;
+	*f->ret = m->ntype;
+	m->type[m->ntype++] = t;
+}
+
+void
+Loader_ext(void *a)
+{
+	Modl *l;
+	Module *m;
+	Modlink *ml;
+	F_Loader_ext *f;
+
+	f = a;
+	*f->ret = -1;
+	if(f->mp == H) {
+		kwerrstr("nil mp");
+		return;
+	}
+	ml = f->mp;
+	m = ml->m;
+	if(f->tdesc < 0 || f->tdesc >= m->ntype) {
+		kwerrstr("bad tdesc");
+		return;
+	}
+	if(f->pc < 0 || f->pc >= m->nprog) {
+		kwerrstr("bad pc");
+		return;
+	}
+	if(f->idx < 0 || f->idx >= ml->nlinks) {
+		kwerrstr("bad idx");
+		return;
+	}
+	l = &ml->links[f->idx];
+	l->u.pc = m->prog + f->pc;
+	l->frame = m->type[f->tdesc];
+	*f->ret = 0;
+}
+
+void
+Loader_dnew(void *a)
+{
+	F_Loader_dnew *f;
+	Heap *h;
+	Array *ar, az;
+	Type *t;
+ 
+        f = a;
+        *f->ret = H;
+        if(f->map == H)
+                return;
+        ar = f->map;
+        if(ar == H) {
+                ar = &az;
+                ar->len = 0;
+                ar->data = nil;
+        }
+        t = dtype(freeheap, f->size, ar->data, ar->len);
+        if(t == nil) {
+                kwerrstr(exNomem);
+                return;
+        }
+
+	h=heapz(t);
+	if(h == nil) {
+		freetype(t);
+		kwerrstr(exNomem);
+		return;
+        }
+		
+	*f->ret=H2D(Loader_Niladt*, h);
+}
+
+void
+Loader_compile(void *a)
+{
+	Module *m;
+	F_Loader_compile *f;
+
+	f = a;
+	*f->ret = -1;
+	if(f->mp == H) {
+		kwerrstr("nil mp");
+		return;
+	}
+	m = f->mp->m;
+	if(m->compiled) {
+		kwerrstr("compiled module");
+		return;
+	}
+	*f->ret = 0;
+	m->origmp = f->mp->MP;
+	if(cflag || f->flag)
+	if(compile(m, m->nprog, f->mp)) {
+		f->mp->prog = m->prog;
+		f->mp->compiled = 1;
+	} else
+		*f->ret = -1;
+	m->origmp = H;
+}
--- /dev/null
+++ b/libinterp/math.c
@@ -1,0 +1,955 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "raise.h"
+#include "mathi.h"
+#include "mathmod.h"
+
+static union
+{
+	double x;
+	uvlong u;
+} bits64;
+
+static union{
+	float x;
+	unsigned int u;
+} bits32;
+
+void
+mathmodinit(void)
+{
+	builtinmod("$Math", Mathmodtab, Mathmodlen);
+	fmtinstall('g', gfltconv);
+	fmtinstall('G', gfltconv);
+	fmtinstall('e', gfltconv);
+	/* fmtinstall('E', gfltconv); */	/* avoid clash with ether address */
+	fmtinstall(0x00c9, gfltconv);	/* L'É' */
+	fmtinstall('f', gfltconv);
+}
+
+void
+Math_import_int(void *fp)
+{
+	F_Math_import_int *f;
+	int i, n;
+	unsigned int u;
+	unsigned char *bp;
+	int *x;
+
+	f = fp;
+	n = f->x->len;
+	if(f->b->len!=4*n)
+		error(exMathia);
+	bp = (unsigned char *)(f->b->data);
+	x = (int*)(f->x->data);
+	for(i=0; i<n; i++){
+		u = *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		x[i] = u;
+	}
+}
+
+void
+Math_import_real32(void *fp)
+{
+	F_Math_import_int *f;
+	int i, n;
+	unsigned int u;
+	unsigned char *bp;
+	double *x;
+
+	f = fp;
+	n = f->x->len;
+	if(f->b->len!=4*n)
+		error(exMathia);
+	bp = (unsigned char *)(f->b->data);
+	x = (double*)(f->x->data);
+	for(i=0; i<n; i++){
+		u = *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		bits32.u = u;
+		x[i] = bits32.x;
+	}
+}
+
+void
+Math_import_real(void *fp)
+{
+	F_Math_import_int *f;
+	int i, n;
+	uvlong u;
+	unsigned char *bp;
+	double *x;
+
+	f = fp;
+	n = f->x->len;
+	if(f->b->len!=8*n)
+		error(exMathia);
+	bp = f->b->data;
+	x = (double*)(f->x->data);
+	for(i=0; i<n; i++){
+		u = *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		u = (u<<8) | *bp++;
+		bits64.u = u;
+		x[i] = bits64.x;
+	}
+}
+
+void
+Math_export_int(void *fp)
+{
+	F_Math_export_int *f;
+	int i, n;
+	unsigned int u;
+	unsigned char *bp;
+	int *x;
+
+	f = fp;
+	n = f->x->len;
+	if(f->b->len!=4*n)
+		error(exMathia);
+	bp = (unsigned char *)(f->b->data);
+	x = (int*)(f->x->data);
+	for(i=0; i<n; i++){
+		u = x[i];
+		*bp++ = u>>24;
+		*bp++ = u>>16;
+		*bp++ = u>>8;
+		*bp++ = u;
+	}
+}
+
+void
+Math_export_real32(void *fp)
+{
+	F_Math_export_int *f;
+	int i, n;
+	unsigned int u;
+	unsigned char *bp;
+	double *x;
+
+	f = fp;
+	n = f->x->len;
+	if(f->b->len!=4*n)
+		error(exMathia);
+	bp = (unsigned char *)(f->b->data);
+	x = (double*)(f->x->data);
+	for(i=0; i<n; i++){
+		bits32.x = x[i];
+		u = bits32.u;
+		*bp++ = u>>24;
+		*bp++ = u>>16;
+		*bp++ = u>>8;
+		*bp++ = u;
+	}
+}
+
+void
+Math_export_real(void *fp)
+{
+	F_Math_export_int *f;
+	int i, n;
+	uvlong u;
+	unsigned char *bp;
+	double *x;
+
+	f = fp;
+	n = f->x->len;
+	if(f->b->len!=8*n)
+		error(exMathia);
+	bp = (unsigned char *)(f->b->data);
+	x = (double*)(f->x->data);
+	for(i=0; i<n; i++){
+		bits64.x = x[i];
+		u = bits64.u;
+		*bp++ = u>>56;
+		*bp++ = u>>48;
+		*bp++ = u>>40;
+		*bp++ = u>>32;
+		*bp++ = u>>24;
+		*bp++ = u>>16;
+		*bp++ = u>>8;
+		*bp++ = u;
+	}
+}
+
+
+void
+Math_bits32real(void *fp)
+{
+	F_Math_bits32real *f;
+
+	f = fp;
+	bits32.u = f->b;
+	*f->ret = bits32.x;
+}
+
+void
+Math_bits64real(void *fp)
+{
+	F_Math_bits64real *f;
+
+	f = fp;
+	bits64.u = f->b;
+	*f->ret = bits64.x;
+}
+
+void
+Math_realbits32(void *fp)
+{
+	F_Math_realbits32 *f;
+
+	f = fp;
+	bits32.x = f->x;
+	*f->ret = bits32.u;
+}
+
+void
+Math_realbits64(void *fp)
+{
+	F_Math_realbits64 *f;
+
+	f = fp;
+	bits64.x = f->x;
+	*f->ret = bits64.u;
+}
+
+
+void
+Math_getFPcontrol(void *fp)
+{
+	F_Math_getFPcontrol *f;
+
+	f = fp;
+
+	*f->ret = getFPcontrol();
+}
+
+void
+Math_getFPstatus(void *fp)
+{
+	F_Math_getFPstatus *f;
+
+	f = fp;
+
+	*f->ret = getFPstatus();
+}
+
+void
+Math_finite(void *fp)
+{
+	F_Math_finite *f;
+
+	f = fp;
+
+	*f->ret = finite(f->x);
+}
+
+void
+Math_ilogb(void *fp)
+{
+	F_Math_ilogb *f;
+
+	f = fp;
+
+	*f->ret = ilogb(f->x);
+}
+
+void
+Math_isnan(void *fp)
+{
+	F_Math_isnan *f;
+
+	f = fp;
+
+	*f->ret = isNaN(f->x);
+}
+
+void
+Math_acos(void *fp)
+{
+	F_Math_acos *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_acos(f->x);
+}
+
+void
+Math_acosh(void *fp)
+{
+	F_Math_acosh *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_acosh(f->x);
+}
+
+void
+Math_asin(void *fp)
+{
+	F_Math_asin *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_asin(f->x);
+}
+
+void
+Math_asinh(void *fp)
+{
+	F_Math_asinh *f;
+
+	f = fp;
+
+	*f->ret = asinh(f->x);
+}
+
+void
+Math_atan(void *fp)
+{
+	F_Math_atan *f;
+
+	f = fp;
+
+	*f->ret = atan(f->x);
+}
+
+void
+Math_atanh(void *fp)
+{
+	F_Math_atanh *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_atanh(f->x);
+}
+
+void
+Math_cbrt(void *fp)
+{
+	F_Math_cbrt *f;
+
+	f = fp;
+
+	*f->ret = cbrt(f->x);
+}
+
+void
+Math_ceil(void *fp)
+{
+	F_Math_ceil *f;
+
+	f = fp;
+
+	*f->ret = ceil(f->x);
+}
+
+void
+Math_cos(void *fp)
+{
+	F_Math_cos *f;
+
+	f = fp;
+
+	*f->ret = cos(f->x);
+}
+
+void
+Math_cosh(void *fp)
+{
+	F_Math_cosh *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_cosh(f->x);
+}
+
+void
+Math_erf(void *fp)
+{
+	F_Math_erf *f;
+
+	f = fp;
+
+	*f->ret = erf(f->x);
+}
+
+void
+Math_erfc(void *fp)
+{
+	F_Math_erfc *f;
+
+	f = fp;
+
+	*f->ret = erfc(f->x);
+}
+
+void
+Math_exp(void *fp)
+{
+	F_Math_exp *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_exp(f->x);
+}
+
+void
+Math_expm1(void *fp)
+{
+	F_Math_expm1 *f;
+
+	f = fp;
+
+	*f->ret = expm1(f->x);
+}
+
+void
+Math_fabs(void *fp)
+{
+	F_Math_fabs *f;
+
+	f = fp;
+
+	*f->ret = fabs(f->x);
+}
+
+void
+Math_floor(void *fp)
+{
+	F_Math_floor *f;
+
+	f = fp;
+
+	*f->ret = floor(f->x);
+}
+
+void
+Math_j0(void *fp)
+{
+	F_Math_j0 *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_j0(f->x);
+}
+
+void
+Math_j1(void *fp)
+{
+	F_Math_j1 *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_j1(f->x);
+}
+
+void
+Math_log(void *fp)
+{
+	F_Math_log *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_log(f->x);
+}
+
+void
+Math_log10(void *fp)
+{
+	F_Math_log10 *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_log10(f->x);
+}
+
+void
+Math_log1p(void *fp)
+{
+	F_Math_log1p *f;
+
+	f = fp;
+
+	*f->ret = log1p(f->x);
+}
+
+void
+Math_rint(void *fp)
+{
+	F_Math_rint *f;
+
+	f = fp;
+
+	*f->ret = rint(f->x);
+}
+
+void
+Math_sin(void *fp)
+{
+	F_Math_sin *f;
+
+	f = fp;
+
+	*f->ret = sin(f->x);
+}
+
+void
+Math_sinh(void *fp)
+{
+	F_Math_sinh *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_sinh(f->x);
+}
+
+void
+Math_sqrt(void *fp)
+{
+	F_Math_sqrt *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_sqrt(f->x);
+}
+
+void
+Math_tan(void *fp)
+{
+	F_Math_tan *f;
+
+	f = fp;
+
+	*f->ret = tan(f->x);
+}
+
+void
+Math_tanh(void *fp)
+{
+	F_Math_tanh *f;
+
+	f = fp;
+
+	*f->ret = tanh(f->x);
+}
+
+void
+Math_y0(void *fp)
+{
+	F_Math_y0 *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_y0(f->x);
+}
+
+void
+Math_y1(void *fp)
+{
+	F_Math_y1 *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_y1(f->x);
+}
+
+void
+Math_fdim(void *fp)
+{
+	F_Math_fdim *f;
+
+	f = fp;
+
+	*f->ret = fdim(f->x, f->y);
+}
+
+void
+Math_fmax(void *fp)
+{
+	F_Math_fmax *f;
+
+	f = fp;
+
+	*f->ret = fmax(f->x, f->y);
+}
+
+void
+Math_fmin(void *fp)
+{
+	F_Math_fmin *f;
+
+	f = fp;
+
+	*f->ret = fmin(f->x, f->y);
+}
+
+void
+Math_fmod(void *fp)
+{
+	F_Math_fmod *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_fmod(f->x, f->y);
+}
+
+void
+Math_hypot(void *fp)
+{
+	F_Math_hypot *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_hypot(f->x, f->y);
+}
+
+void
+Math_nextafter(void *fp)
+{
+	F_Math_nextafter *f;
+
+	f = fp;
+
+	*f->ret = nextafter(f->x, f->y);
+}
+
+void
+Math_pow(void *fp)
+{
+	F_Math_pow *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_pow(f->x, f->y);
+}
+
+
+
+void
+Math_FPcontrol(void *fp)
+{
+	F_Math_FPcontrol *f;
+
+	f = fp;
+
+	*f->ret = FPcontrol(f->r, f->mask);
+}
+
+void
+Math_FPstatus(void *fp)
+{
+	F_Math_FPstatus *f;
+
+	f = fp;
+
+	*f->ret = FPstatus(f->r, f->mask);
+}
+
+void
+Math_atan2(void *fp)
+{
+	F_Math_atan2 *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_atan2(f->y, f->x);
+}
+
+void
+Math_copysign(void *fp)
+{
+	F_Math_copysign *f;
+
+	f = fp;
+
+	*f->ret = copysign(f->x, f->s);
+}
+
+void
+Math_jn(void *fp)
+{
+	F_Math_jn *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_jn(f->n, f->x);
+}
+
+void
+Math_lgamma(void *fp)
+{
+	F_Math_lgamma *f;
+
+	f = fp;
+
+	f->ret->t1 = __ieee754_lgamma_r(f->x, &f->ret->t0);
+}
+
+void
+Math_modf(void *fp)
+{
+	F_Math_modf *f;
+	double ipart;
+
+	f = fp;
+
+	f->ret->t1 = modf(f->x, &ipart);
+	f->ret->t0 = ipart;
+}
+
+void
+Math_pow10(void *fp)
+{
+	F_Math_pow10 *f;
+
+	f = fp;
+
+	*f->ret = ipow10(f->p);
+}
+
+void
+Math_remainder(void *fp)
+{
+	F_Math_remainder *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_remainder(f->x, f->p);
+}
+
+void
+Math_scalbn(void *fp)
+{
+	F_Math_scalbn *f;
+
+	f = fp;
+
+	*f->ret = scalbn(f->x, f->n);
+}
+
+void
+Math_yn(void *fp)
+{
+	F_Math_yn *f;
+
+	f = fp;
+
+	*f->ret = __ieee754_yn(f->n, f->x);
+}
+
+
+/**** sorting real vectors through permutation vector ****/
+/* qsort from coma:/usr/jlb/qsort/qsort.dir/qsort.c on 28 Sep '92
+ char* has been changed to uchar*, static internal functions.
+ specialized to swapping ints (which are 32-bit anyway in limbo).
+ converted uchar* to int* (and substituted 1 for es).
+*/
+
+static int
+cmp(int *u, int *v, double *x)
+{
+	return ((x[*u]==x[*v])? 0 : ((x[*u]<x[*v])? -1 : 1));
+}
+
+#define swap(u, v) {int t = *(u); *(u) = *(v); *(v) = t;}
+
+#define vecswap(u, v, n) if(n>0){	\
+    int i = n;				\
+    register int *pi = u;		\
+    register int *pj = v;		\
+    do {				\
+        register int t = *pi;		\
+        *pi++ = *pj;			\
+        *pj++ = t;			\
+    } while (--i > 0);			\
+}
+
+#define minimum(x, y) ((x)<=(y) ? (x) : (y))
+
+static int *
+med3(int *a, int *b, int *c, double *x)
+{	return cmp(a, b, x) < 0 ?
+		  (cmp(b, c, x) < 0 ? b : (cmp(a, c, x) < 0 ? c : a ) )
+		: (cmp(b, c, x) > 0 ? b : (cmp(a, c, x) < 0 ? a : c ) );
+}
+
+void
+rqsort(int *a, int n, double *x)
+{
+	int *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+	int  d, r;
+
+	if (n < 7) { /* Insertion sort on small arrays */
+		for (pm = a + 1; pm < a + n; pm++)
+			for (pl = pm; pl > a && cmp(pl-1, pl, x) > 0; pl--)
+				swap(pl, pl-1);
+		return;
+	}
+	pm = a + (n/2);
+	if (n > 7) {
+		pl = a;
+		pn = a + (n-1);
+		if (n > 40) { /* On big arrays, pseudomedian of 9 */
+			d = (n/8);
+			pl = med3(pl, pl+d, pl+2*d, x);
+			pm = med3(pm-d, pm, pm+d, x);
+			pn = med3(pn-2*d, pn-d, pn, x);
+		}
+		pm = med3(pl, pm, pn, x); /* On mid arrays, med of 3 */
+	}
+	swap(a, pm); /* On tiny arrays, partition around middle */
+	pa = pb = a + 1;
+	pc = pd = a + (n-1);
+	for (;;) {
+		while (pb <= pc && (r = cmp(pb, a, x)) <= 0) {
+			if (r == 0) { swap(pa, pb); pa++; }
+			pb++;
+		}
+		while (pb <= pc && (r = cmp(pc, a, x)) >= 0) {
+			if (r == 0) { swap(pc, pd); pd--; }
+			pc--;
+		}
+		if (pb > pc) break;
+		swap(pb, pc);
+		pb++;
+		pc--;
+	}
+	pn = a + n;
+	r = minimum(pa-a,  pb-pa);   vecswap(a,  pb-r, r);
+	r = minimum(pd-pc, pn-pd-1); vecswap(pb, pn-r, r);
+	if ((r = pb-pa) > 1) rqsort(a, r, x);
+	if ((r = pd-pc) > 1) rqsort(pn-r, r, x);
+}
+
+void
+Math_sort(void*fp)
+{
+	F_Math_sort *f;
+	int	i, pilen, xlen, *p;
+
+	f = fp;
+
+	/* check that permutation contents are in [0,n-1] !!! */
+	p = (int*) (f->pi->data);
+	pilen = f->pi->len;
+	xlen = f->x->len - 1;
+
+	for(i = 0; i < pilen; i++) {
+		if((*p < 0) || (xlen < *p))
+			error(exMathia);
+		p++;
+	}
+
+	rqsort( (int*)(f->pi->data), f->pi->len, (double*)(f->x->data));
+}
+
+
+/************ BLAS ***************/
+
+void
+Math_dot(void *fp)
+{
+	F_Math_dot *f;
+
+	f = fp;
+	if(f->x->len!=f->y->len)
+		error(exMathia);	/* incompatible lengths */
+	*f->ret = dot(f->x->len, (double*)(f->x->data), (double*)(f->y->data));
+}
+
+void
+Math_iamax(void *fp)
+{
+	F_Math_iamax *f;
+
+	f = fp;
+
+	*f->ret = iamax(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_norm2(void *fp)
+{
+	F_Math_norm2 *f;
+
+	f = fp;
+
+	*f->ret = norm2(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_norm1(void *fp)
+{
+	F_Math_norm1 *f;
+
+	f = fp;
+
+	*f->ret = norm1(f->x->len, (double*)(f->x->data));
+}
+
+void
+Math_gemm(void *fp)
+{
+	F_Math_gemm *f = fp;
+	int nrowa, ncola, nrowb, ncolb, mn, ld, m, n;
+	double *adata = 0, *bdata = 0, *cdata;
+	int nota = f->transa=='N';
+	int notb = f->transb=='N';
+	if(nota){
+		nrowa = f->m;
+		ncola = f->k;
+	}else{
+		nrowa = f->k;
+		ncola = f->m;
+	}
+	if(notb){
+		nrowb = f->k;
+		ncolb = f->n;
+	}else{
+		nrowb = f->n;
+		ncolb = f->k;
+	}
+	if(     (!nota && f->transa!='C' && f->transa!='T') ||
+		(!notb && f->transb!='C' && f->transb!='T') ||
+		(f->m < 0 || f->n < 0 || f->k < 0) ){
+		error(exMathia);
+	}
+	if(f->a != H){
+		mn = f->a->len;
+		adata = (double*)(f->a->data);
+		ld = f->lda;
+		if(ld<nrowa || ld*(ncola-1)>mn)
+			error(exBounds);
+	}
+	if(f->b != H){
+		mn = f->b->len;
+		ld = f->ldb;
+		bdata = (double*)(f->b->data);
+		if(ld<nrowb || ld*(ncolb-1)>mn)
+			error(exBounds);
+	}
+	m = f->m;
+	n = f->n;
+	mn = f->c->len;
+	cdata = (double*)(f->c->data);
+	ld = f->ldc;
+	if(ld<m || ld*(n-1)>mn)
+		error(exBounds);
+
+	gemm(f->transa, f->transb, f->m, f->n, f->k, f->alpha,
+		adata, f->lda, bdata, f->ldb, f->beta, cdata, f->ldc);
+}
--- /dev/null
+++ b/libinterp/mkfile
@@ -1,0 +1,129 @@
+<../mkconfig
+
+LIB=libinterp.a
+
+OFILES=\
+	alt.$O\
+	comp-$OBJTYPE.$O\
+	conv.$O\
+	crypt.$O\
+	dec.$O\
+	dlm-$TARGMODEL.$O\
+	draw.$O\
+	freetype.$O\
+	gc.$O\
+	geom.$O\
+	heap.$O\
+	heapaudit.$O\
+	ipint.$O\
+	link.$O\
+	load.$O\
+	loader.$O\
+	math.$O\
+#	prefab.$O\
+	raise.$O\
+	readmod.$O\
+	runt.$O\
+	sign.$O\
+	stack.$O\
+	tk.$O\
+	validstk.$O\
+	xec.$O\
+	das-$OBJTYPE.$O\
+	keyring.$O\
+	string.$O\
+
+HFILES=\
+	$ROOT/include/interp.h\
+	$ROOT/include/isa.h\
+	runt.h\
+	tab.h\
+
+MODULES=\
+	../module/runt.m\
+	../module/sys.m\
+	../module/draw.m\
+	../module/prefab.m\
+	../module/math.m\
+	../module/tk.m\
+	../module/keyring.m\
+	../module/loader.m\
+	../module/freetype.m\
+	../module/ipints.m\
+	../module/crypt.m\
+	keyringif.m\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+runt.h:D: $MODULES
+	rm -f $target && limbo -a -I../module ../module/runt.m > $target
+
+sysmod.h:D: $MODULES
+	rm -f $target && limbo -t Sys -I../module ../module/runt.m > $target
+
+keyring.h:D: $MODULES
+	rm -f $target && limbo -t Keyring -I../module keyringif.m > $target
+
+drawmod.h:D: $MODULES
+	rm -f $target && limbo -t Draw -I../module ../module/runt.m > $target
+
+prefabmod.h:D: $MODULES
+	rm -f $target && limbo -t Prefab -I../module ../module/runt.m > $target
+
+tkmod.h:D: $MODULES
+	rm -f $target && limbo -t Tk -I../module ../module/runt.m > $target
+
+mathmod.h:D: $MODULES
+	rm -f $target && limbo -t Math -I../module ../module/runt.m > $target
+
+loadermod.h:D: $MODULES
+	rm -f $target && limbo -t Loader -I../module ../module/runt.m > $target
+
+freetypemod.h:D: $MODULES
+	rm -f $target && limbo -t Freetype -I../module ../module/runt.m > $target
+
+ipintsmod.h:D:	$MODULES
+	rm -f $target && limbo -t IPints -I../module ../module/ipints.m > $target
+
+benchmod.h:D: ../module/bench.m
+	rm -f $target && limbo -t Bench -I../module ../module/bench.m > $target
+
+cryptmod.h:D:	$MODULES
+	rm -f $target && limbo -t Crypt -I../module ../module/runt.m > $target
+
+keyringif.h:D:	$MODULES keyringif.m
+	rm -f $target && limbo -a -I../module keyringif.m > $target
+
+
+bench.h:D:../module/bench.m
+	rm -f $target && limbo -a -I../module ../module/bench.m > $target
+
+xec.$O:		optab.h  $ROOT/include/pool.h
+tk.$O:		$ROOT/include/tk.h  $ROOT/include/pool.h
+draw.$O: 	$ROOT/include/draw.h $ROOT/include/drawif.h
+prefab.$O: 	$ROOT/include/draw.h\
+		$ROOT/include/prefab.h
+
+runt.$O:	sysmod.h
+prefab.$O:	prefabmod.h
+draw.$O:	drawmod.h
+tk.$O:		$ROOT/include/draw.h tkmod.h
+math.$O:	mathmod.h
+keyring.$O:	keyring.h ipint.h keyringif.h
+crypt.$O:	ipint.h runt.h cryptmod.h
+ipint.$O:	ipint.h ipintsmod.h
+loader.$O:	loadermod.h
+freetype.$O:	freetypemod.h $ROOT/include/freetype.h
+math.$O:	$ROOT/include/mathi.h
+
+das-spim.c:N:	das-mips.c
+comp-spim.c:N:	comp-mips.c
+
+# optab.h:	$ROOT/include/isa.h mkoptab
+#	$SHELLNAME mkoptab > $target
+
+#	Do not remove optab.h, because the script that builds
+#	it works only on UNIX and Plan 9.
+
+nuke:EV:	nuke-std
+	rm -f runt.h sysmod.h drawmod.h prefabmod.h tkmod.h mathmod.h keyring.h readimagemod.h loadermod.h freetypemod.h cryptmod.h keyringif.h ipintsmod.h
--- /dev/null
+++ b/libinterp/mkoptab
@@ -1,0 +1,19 @@
+rm -f optab.h
+tr '[A-Z]' '[a-z]' <../include/isa.h >optab.h
+ed optab.h <<'HERE'
+1;/enum/c
+void	(*optab[256])(void) =
+.
+/}/+1,$ d
+,s/^[ 	]*i/	/g
+1;/nop/s//badop/
+1;/exit/s//i&/
+1;/goto/s//i&/
+1;/case/s//i&/
+1;/load/s//i&/
+1;/recv/s//i&/
+1;/send/s//i&/
+1;/raise/s//i&/
+w
+q
+HERE
--- /dev/null
+++ b/libinterp/optab.h
@@ -1,0 +1,179 @@
+void	(*optab[256])(void) =
+{
+	badop,
+	alt,
+	nbalt,
+	igoto,
+	call,
+	frame,
+	spawn,
+	runt,
+	iload,
+	mcall,
+	mspawn,
+	mframe,
+	ret,
+	jmp,
+	icase,
+	iexit,
+	new,
+	newa,
+	newcb,
+	newcw,
+	newcf,
+	newcp,
+	newcm,
+	newcmp,
+	isend,
+	irecv,
+	consb,
+	consw,
+	consp,
+	consf,
+	consm,
+	consmp,
+	headb,
+	headw,
+	headp,
+	headf,
+	headm,
+	headmp,
+	tail,
+	lea,
+	indx,
+	movp,
+	movm,
+	movmp,
+	movb,
+	movw,
+	movf,
+	cvtbw,
+	cvtwb,
+	cvtfw,
+	cvtwf,
+	cvtca,
+	cvtac,
+	cvtwc,
+	cvtcw,
+	cvtfc,
+	cvtcf,
+	addb,
+	addw,
+	addf,
+	subb,
+	subw,
+	subf,
+	mulb,
+	mulw,
+	mulf,
+	divb,
+	divw,
+	divf,
+	modw,
+	modb,
+	andb,
+	andw,
+	orb,
+	orw,
+	xorb,
+	xorw,
+	shlb,
+	shlw,
+	shrb,
+	shrw,
+	insc,
+	indc,
+	addc,
+	lenc,
+	lena,
+	lenl,
+	beqb,
+	bneb,
+	bltb,
+	bleb,
+	bgtb,
+	bgeb,
+	beqw,
+	bnew,
+	bltw,
+	blew,
+	bgtw,
+	bgew,
+	beqf,
+	bnef,
+	bltf,
+	blef,
+	bgtf,
+	bgef,
+	beqc,
+	bnec,
+	bltc,
+	blec,
+	bgtc,
+	bgec,
+	slicea,
+	slicela,
+	slicec,
+	indw,
+	indf,
+	indb,
+	negf,
+	movl,
+	addl,
+	subl,
+	divl,
+	modl,
+	mull,
+	andl,
+	orl,
+	xorl,
+	shll,
+	shrl,
+	bnel,
+	bltl,
+	blel,
+	bgtl,
+	bgel,
+	beql,
+	cvtlf,
+	cvtfl,
+	cvtlw,
+	cvtwl,
+	cvtlc,
+	cvtcl,
+	headl,
+	consl,
+	newcl,
+	casec,
+	indl,
+	movpc,
+	tcmp,
+	mnewz,
+	cvtrf,
+	cvtfr,
+	cvtws,
+	cvtsw,
+	lsrw,
+	lsrl,
+	eclr,		/* unused */
+	newz,
+	newaz,
+	iraise,
+	casel,
+	mulx,
+	divx,
+	cvtxx,
+	mulx0,
+	divx0,
+	cvtxx0,
+	mulx1,
+	divx1,
+	cvtxx1,
+	cvtfx,
+	cvtxf,
+	iexpw,
+	iexpl,
+	iexpf,
+	self,
+	/* fix maxdis if you add opcodes */
+};
--- /dev/null
+++ b/libinterp/prefab.c
@@ -1,0 +1,824 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "prefabmod.h"
+#include "draw.h"
+#include "drawif.h"
+#include "prefab.h"
+#include "raise.h"
+
+uchar elementmap[] = Prefab_Element_map;
+uchar compoundmap[] = Prefab_Compound_map;
+uchar layoutmap[] = Prefab_Layout_map;
+
+void	freeprefabcompound(Heap*, int);
+
+Type*	TCompound;
+Type*	TElement;
+Type*	TLayout;
+
+/* Infrared remote buttons known to Compound_select */
+enum
+{
+	IRFF		= 14,
+	IRRew		= 15,
+	IRUp		= 16,
+	IRDn		= 17,
+	IRSelect	= 18,
+	IREnter	= 20,
+};
+
+void
+prefabmodinit(void)
+{
+	TElement = dtype(freeheap, sizeof(PElement), elementmap, sizeof(elementmap));
+	TLayout = dtype(freeheap, Prefab_Layout_size, layoutmap, sizeof(layoutmap));
+	TCompound = dtype(freeprefabcompound, sizeof(PCompound), compoundmap, sizeof(compoundmap));
+	builtinmod("$Prefab", Prefabmodtab, Prefabmodlen);
+}
+
+PElement*
+checkelement(Prefab_Element *de)
+{
+	PElement *pe;
+
+	pe = lookupelement(de);
+	if(pe == H)
+		error(exType);
+	return pe;
+}
+
+PCompound*
+checkcompound(Prefab_Compound *de)
+{
+	PCompound *pe;
+
+	pe = lookupcompound(de);
+	if(pe == H)
+		error(exType);
+	return pe;
+}
+
+PElement*
+lookupelement(Prefab_Element *de)
+{
+	PElement *pe;
+	if(de == H)
+		return H;
+	if(D2H(de)->t != TElement)
+		return H;
+	pe = (PElement*)de;
+	if(de->kind!=pe->pkind || de->kids!=pe->first)
+		return H;
+	return pe;
+}
+
+PCompound*
+lookupcompound(Prefab_Compound *dc)
+{
+	if(dc == H)
+		return H;
+	if(D2H(dc)->t != TCompound)
+		return H;
+	return (PCompound*)dc;
+}
+
+void
+freeprefabcompound(Heap *h, int swept)
+{
+	Image *i;
+	Prefab_Compound *d;
+	PCompound *pc;
+
+	d = H2D(Prefab_Compound*, h);
+	pc = lookupcompound(d);
+	/* disconnect compound from image refresh daemon */
+	i = lookupimage(pc->c.image);
+	if(i != nil)
+		delrefresh(i);
+	if(!swept && TCompound->np)
+		freeptrs(d, TCompound);
+	/* header will be freed by caller */
+}
+
+static
+PElement*
+findtag(PElement *pelem, char *tag)
+{
+	PElement *pe, *t;
+	List *l;
+
+	if(pelem==H || tag[0]==0)
+		return pelem;
+	for(l=pelem->first; l!=H; l=l->tail){
+		pe = *(PElement**)l->data;
+		if(strcmp(tag, string2c(pe->e.tag)) == 0)
+			return pe;
+		else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
+			t = findtag(pe, tag);
+			if(t != H)
+				return t;
+		}
+	}
+	return H;
+}
+
+int
+badenviron(Prefab_Environ *env, int err)
+{
+	Prefab_Style *s;
+
+	if(env == H)
+		goto bad;
+	s = env->style;
+	if(s == H)
+		goto bad;
+	if(s->titlefont==H || s->textfont==H)
+		goto bad;
+	if(s->elemcolor==H || s->edgecolor==H)
+		goto bad;
+	if(s->titlecolor==H || s->textcolor==H || s->highlightcolor==H)
+		goto bad;
+	return 0;
+bad:
+	if(err)
+		error(exType);
+	return 1;
+}
+
+void
+Element_iconseparator(void *fp, int kind)
+{
+	F_Element_icon *f;
+	PElement *e;
+	Image *icon;
+	int locked;
+
+	f = fp;
+	badenviron(f->env, 1);
+	checkimage(f->mask);
+	icon = checkimage(f->icon);
+	locked = lockdisplay(icon->display);
+	destroy(*f->ret);
+	*f->ret = H;
+	if(kind == ESeparator)
+		e = separatorelement(f->env, f->r, f->icon, f->mask);
+	else
+		e = iconelement(f->env, f->r, f->icon, f->mask);
+	*f->ret = (Prefab_Element*)e;
+	if(locked)
+		unlockdisplay(icon->display);
+}
+
+void
+Element_icon(void *fp)
+{
+	Element_iconseparator(fp, EIcon);
+}
+
+void
+Element_separator(void *fp)
+{
+	Element_iconseparator(fp, ESeparator);
+}
+
+void
+Element_text(void *fp)
+{
+	F_Element_text *f;
+	PElement *pelem;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	badenviron(f->env, 1);
+	if(f->kind!=EText && f->kind!=ETitle)
+		return;
+
+	disp = checkscreen(f->env->screen)->display;
+	locked = lockdisplay(disp);
+	destroy(*f->ret);
+	*f->ret = H;
+	pelem = textelement(f->env, f->text, f->r, f->kind);
+	*f->ret = (Prefab_Element*)pelem;
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Element_layout(void *fp)
+{
+	F_Element_layout *f;
+	PElement *pelem;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	badenviron(f->env, 1);
+	if(f->kind!=EText && f->kind!=ETitle)
+		return;
+
+	disp = checkscreen(f->env->screen)->display;
+	locked = lockdisplay(disp);
+	destroy(*f->ret);
+	*f->ret = H;
+	pelem = layoutelement(f->env, f->lay, f->r, f->kind);
+	*f->ret = (Prefab_Element*)pelem;
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Element_elist(void *fp)
+{
+	F_Element_elist *f;
+	PElement *pelist;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	if(f->elem != H)
+		checkelement(f->elem);
+	badenviron(f->env, 1);
+	if(f->kind!=EHorizontal && f->kind!=EVertical)
+		return;
+
+	disp = checkscreen(f->env->screen)->display;
+	locked = lockdisplay(disp);
+	destroy(*f->ret);
+	*f->ret = H;
+	pelist = elistelement(f->env, f->elem, f->kind);
+	*f->ret = (Prefab_Element*)pelist;
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Element_append(void *fp)
+{
+	F_Element_append *f;
+
+	f = fp;
+	*f->ret = 0;
+	if(f->elist==H || f->elem==H)
+		return;
+
+	badenviron(f->elist->environ, 1);
+	checkelement(f->elist);
+	checkelement(f->elem);
+
+	if(f->elist->kind!=EHorizontal && f->elist->kind!=EVertical)
+		return;
+
+	if(appendelist(f->elist, f->elem) != H)
+		*f->ret = 1;
+}
+
+void
+Element_adjust(void *fp)
+{
+	F_Element_adjust *f;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	checkelement(f->elem);
+	badenviron(f->elem->environ, 1);
+	disp = checkscreen(f->elem->environ->screen)->display;
+	locked = lockdisplay(disp);
+	adjustelement(f->elem, f->equal, f->dir);
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Element_show(void *fp)
+{
+	F_Element_show *f;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	checkelement(f->elem);
+	checkelement(f->elist);
+	badenviron(f->elem->environ, 1);
+	disp = checkscreen(f->elem->environ->screen)->display;
+	locked = lockdisplay(disp);
+	*f->ret = showelement(f->elist, f->elem);
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Element_clip(void *fp)
+{
+	F_Element_clip *f;
+	Rectangle r;
+	Display *disp;
+	int locked;
+
+	f = fp;
+	checkelement(f->elem);
+	badenviron(f->elem->environ, 1);
+	R2R(r, f->r);
+	disp = checkscreen(f->elem->environ->screen)->display;
+	locked = lockdisplay(disp);
+	clipelement(f->elem, r);
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Element_translatescroll(void *fp, int trans)
+{
+	F_Element_scroll *f;
+	Point d;
+	Display *disp;
+	int locked, moved;
+
+	f = fp;
+	checkelement(f->elem);
+	badenviron(f->elem->environ, 1);
+	P2P(d, f->d);
+	disp = checkscreen(f->elem->environ->screen)->display;
+	locked = lockdisplay(disp);
+	if(trans)
+		translateelement(f->elem, d);
+	else{
+		moved = 0;
+		scrollelement(f->elem, d, &moved);
+	}
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Element_scroll(void *fp)
+{
+	Element_translatescroll(fp, 0);
+}
+
+void
+Element_translate(void *fp)
+{
+	Element_translatescroll(fp, 1);
+}
+
+void
+Compound_iconbox(void *fp)
+{
+	F_Compound_iconbox *f;
+	Image *icon;
+	int locked;
+	PCompound *pc;
+
+	f = fp;
+	badenviron(f->env, 1);
+	checkimage(f->mask);
+	icon = checkimage(f->icon);
+	locked = lockdisplay(icon->display);
+	destroy(*f->ret);
+	*f->ret = H;
+	pc = iconbox(f->env, f->p, f->title, f->icon, f->mask);
+	*f->ret = &pc->c;
+	if(locked)
+		unlockdisplay(icon->display);
+}
+
+void
+Compound_textbox(void *fp)
+{
+	F_Compound_textbox *f;
+	Display *disp;
+	int locked;
+	PCompound *pc;
+
+	f = fp;
+	badenviron(f->env, 1);
+	disp = checkscreen(f->env->screen)->display;
+	locked = lockdisplay(disp);
+	destroy(*f->ret);
+	*f->ret = H;
+	pc = textbox(f->env, f->r, f->title, f->text);
+	*f->ret = &pc->c;
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Compound_layoutbox(void *fp)
+{
+	F_Compound_layoutbox *f;
+	Display *disp;
+	int locked;
+	PCompound *pc;
+
+	f = fp;
+	badenviron(f->env, 1);
+	disp = checkscreen(f->env->screen)->display;
+	locked = lockdisplay(disp);
+	destroy(*f->ret);
+	*f->ret = H;
+	pc = layoutbox(f->env, f->r, f->title, f->lay);
+	*f->ret = &pc->c;
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Compound_box(void *fp)
+{
+	F_Compound_box *f;
+	Display *disp;
+	int locked;
+	PCompound *pc;
+
+	f = fp;
+	badenviron(f->env, 1);
+	if(f->title != H)
+		checkelement(f->title);
+	checkelement(f->elist);
+	disp = checkscreen(f->env->screen)->display;
+	locked = lockdisplay(disp);
+	destroy(*f->ret);
+	*f->ret = H;
+	pc = box(f->env, f->p, f->title, f->elist);
+	*f->ret = &pc->c;
+	if(locked)
+		unlockdisplay(disp);
+}
+
+void
+Compound_draw(void *fp)
+{
+	F_Compound_draw *f;
+	PCompound *pc;
+	int locked;
+
+	f = fp;
+	if(f->comp == H)
+		return;
+	pc = checkcompound(f->comp);
+	badenviron(pc->c.environ, 1);
+	locked = lockdisplay(pc->display);
+	drawcompound(&pc->c);
+	flushimage(pc->display, 1);
+	if(locked)
+		unlockdisplay(pc->display);
+}
+
+void
+Compound_redraw(void *fp)
+{
+	F_Compound_redraw *f;
+	PCompound *pc;
+	Image *i;
+	int locked;
+
+	f = fp;
+	if(f->comp == H)
+		return;
+	pc = checkcompound(f->comp);
+	badenviron(pc->c.environ, 1);
+	i = checkimage(pc->c.image);
+	locked = lockdisplay(pc->display);
+	redrawcompound(i, IRECT(f->r), &pc->c);
+	flushimage(pc->display, 1);
+	if(locked)
+		unlockdisplay(pc->display);
+}
+
+static
+PElement*
+pelement(Prefab_Compound *comp, Prefab_Element *elem)
+{
+	PElement *pe;
+
+	if(comp == H)
+		return H;
+	checkcompound(comp);
+	badenviron(comp->environ, 1);
+	pe = lookupelement(elem);
+	return pe;
+}
+
+void
+Compound_highlight(void *fp)
+{
+	F_Compound_highlight *f;
+	PCompound *pc;
+	PElement *pe;
+	Image *i;
+	int locked;
+
+	f = fp;
+	pe = pelement(f->comp, f->elem);
+	if(pe == H)
+		return;
+	pc = (PCompound*)f->comp;
+	i = checkimage(pc->c.image);
+	locked = lockdisplay(pc->display);
+	highlightelement(&pe->e, i, &pc->c, f->on);
+	flushimage(pc->display, 1);
+	if(locked)
+		unlockdisplay(pc->display);
+}
+
+void
+Compound_scroll(void *fp)
+{
+	F_Compound_scroll *f;
+	PCompound *pc;
+	PElement *pe;
+	int locked;
+	Image *i;
+	int moved;
+
+	f = fp;
+	pe = pelement(f->comp, f->elem);
+	if(pe == H)
+		return;
+	pc = (PCompound*)f->comp;
+	i = checkimage(pc->c.image);
+	locked = lockdisplay(pc->display);
+	moved = 0;
+	scrollelement(&pe->e, IPOINT(f->d), &moved);
+	if(moved){
+		drawelement(&pe->e, i, IRECT(pe->e.r), 0, 0);
+		flushimage(pc->display, 1);
+	}
+	if(locked)
+		unlockdisplay(pc->display);
+}
+
+void
+Compound_show(void *fp)
+{
+	F_Compound_show *f;
+	PCompound *pc;
+	PElement *pe;
+	int locked;
+
+	f = fp;
+	pe = pelement(f->comp, f->elem);
+	if(pe == H)
+		return;
+	pc = (PCompound*)f->comp;
+	locked = lockdisplay(pc->display);
+	*f->ret = showelement(pc->c.contents, &pe->e);
+	flushimage(pc->display, 1);
+	if(locked)
+		unlockdisplay(pc->display);
+}
+
+static
+PElement*
+element(PElement *plist, int index, int *ip)
+{
+	int i;
+	PElement *pe;
+	List *l;
+
+	i = 0;
+	pe = H;
+	for(l=plist->first; l!=H; l=l->tail){
+		pe = *(PElement**)l->data;
+		if(pe->pkind == ESeparator)
+			continue;
+		if(i == index)
+			break;
+		i++;
+	}
+	if(ip)
+		*ip = i;
+	if(l == H)
+		return H;
+	return pe;
+}
+
+static
+int
+wrapelement(PElement *plist, int index, int ntag)
+{
+	int i, wrap;
+
+	if(ntag > 0){
+		if(index < 0)
+			return ntag-1;
+		if(index >= ntag)
+			return 0;
+		return index;
+	}
+	wrap = 1;
+	if(index < 0){
+		index = 1000000;	/* will seek to end */
+		wrap = 0;
+	}
+	if(element(plist, index, &i)==H && index!=0){
+		if(wrap)	/* went off end; wrap to beginning */
+			return wrapelement(plist, 0, 0);
+		if(i > 0)
+			--i;
+	}
+	return i;
+}
+
+void
+dohighlight(PCompound *pc, PElement *list, PElement *pe, int on)
+{
+	Image *i;
+
+	/* see if we need to scroll */
+	i = lookupimage(pc->c.image);
+	if(i == nil)
+		return;
+	if(on && showelement(&list->e, &pe->e))
+		redrawcompound(i, IRECT(pc->c.contents->r), &pc->c);
+	highlightelement(&pe->e, i, &pc->c, on);
+}
+
+void
+highlight(PCompound *pc, PElement *list, int index, int on)
+{
+	dohighlight(pc, list, element(list, index, nil), on);
+}
+
+static
+PElement**
+tags(PElement *pelem, int *ntag)
+{
+	int n, nalloc, nn;
+	List *l;
+	PElement *pe, **tagged, **ntagged;
+
+	n = 0;
+	nalloc = 0;
+	tagged = nil;
+	*ntag = 0;
+	for(l=pelem->first; l!=H; l=l->tail){
+		pe = *(PElement**)l->data;
+		if(pe->e.tag != H){
+			if(nalloc == n){
+				nalloc += 10;
+				tagged = realloc(tagged, nalloc*sizeof(PElement*));
+				if(tagged == nil)
+					return nil;
+			}
+			tagged[n++] = pe;
+		}else if(pe->pkind==EHorizontal || pe->pkind==EVertical){
+			ntagged = tags(pe, &nn);
+			if(nn > 0){
+				if(nalloc < n+nn){
+					nalloc = n+nn+10;
+					tagged = realloc(tagged, nalloc*sizeof(PElement*));
+					if(tagged == nil){
+						free(ntagged);
+						return nil;
+					}
+				}
+				memmove(tagged+n, ntagged, nn*sizeof(PElement*));
+				free(ntagged);
+				n += nn;
+			}
+		}
+	}
+	*ntag = n;
+	return tagged;
+}
+
+void
+doselect(void *fp, int dotags)
+{
+	F_Compound_select *f;
+	PCompound *pc;
+	PElement *pe;
+	WORD *val;
+	List *l;
+	Prefab_Element *t;
+	int i, lasti, ntag;
+	PElement **tagged;
+	int locked;
+
+	f = fp;
+	pc = checkcompound(f->comp);
+	pe = lookupelement(f->elem);
+	if(pe->pkind!=EHorizontal && pe->pkind!=EVertical || pe->nkids == 0){
+    Bad:
+		destroy(f->ret->t2);
+		f->ret->t0 = 9999;
+		f->ret->t1 = 0;
+		f->ret->t2 = H;
+		return;
+	}
+	ntag = 0;
+	tagged = 0;
+	/* check at least one selectable item */
+	if(dotags){
+		tagged = tags(pe, &ntag);
+		if(ntag > 0)
+			goto OK;
+	}else
+		for(l=pe->first; l!=H; l=l->tail){
+			t = *(Prefab_Element**)l->data;
+			if(t->kind != ESeparator)
+				goto OK;
+		}
+	goto Bad;
+
+    OK:
+	i = f->i;
+	i = wrapelement(pe, i, ntag);
+	lasti = i;
+	locked = lockdisplay(pc->display);
+	if(dotags)
+		dohighlight(pc, pe, tagged[i], 1);
+	else
+		highlight(pc, pe, i, 1);
+	/* val must be in shared memory, but stacks not shared */
+	val = malloc(sizeof(WORD));
+	if(val == nil)
+		goto Bad;
+	for(;;){
+		if(lasti != i){
+			if(dotags){
+				dohighlight(pc, pe, tagged[lasti], 0);
+				dohighlight(pc, pe, tagged[i], 1);
+			}else{
+				highlight(pc, pe, lasti, 0);
+				highlight(pc, pe, i, 1);
+			}
+			lasti = i;
+		}
+		flushimage(pc->display, 1);
+		if(locked)
+			unlockdisplay(pc->display);
+		crecv(f->c, val);
+		locked = lockdisplay(pc->display);
+		switch(*val){
+		case IRUp:
+			if(pe->pkind != EVertical)
+				goto Default;
+			goto Up;
+		case IRRew:
+			if(pe->pkind != EHorizontal)
+				goto Default;
+		Up:
+			i = wrapelement(pe, i-1, ntag);
+			break;
+		case IRSelect:
+			if(dotags)
+				dohighlight(pc, pe, tagged[i], 0);
+			else
+				highlight(pc, pe, i, 0);
+			f->ret->t0 = *val;
+			f->ret->t1 = i;
+    Return:
+			flushimage(pc->display, 1);
+			if(dotags)
+				pe = tagged[i];
+			else
+				pe = element(pe, i, nil);
+			destroy(f->ret->t2);
+			D2H(pe)->ref++;
+			f->ret->t2 = &pe->e;
+			if(locked)
+				unlockdisplay(pc->display);
+			free(val);
+			free(tagged);
+			return;
+		case IRDn:
+			if(pe->pkind != EVertical)
+				goto Default;
+			goto Down;
+		case IRFF:
+			if(pe->pkind != EHorizontal)
+				goto Default;
+		Down:
+			i = wrapelement(pe, i+1, ntag);
+			break;
+		default:
+    Default:
+			if(dotags)
+				dohighlight(pc, pe, tagged[lasti], 0);
+			else
+				highlight(pc, pe, lasti, 0);
+			f->ret->t0 = *val;
+			f->ret->t1 = i;
+			goto Return;
+		}
+	}
+}
+
+void
+Compound_tagselect(void *fp)
+{
+	doselect(fp, 1);
+}
+
+void
+Compound_select(void *fp)
+{
+	doselect(fp, 0);
+}
--- /dev/null
+++ b/libinterp/raise.c
@@ -1,0 +1,25 @@
+/*
+ * Exceptions thrown by the interpreter
+ */	
+char exAlt[]		 = "alt send/recv on same chan";
+char exBusy[]		 = "channel busy";
+char exModule[]		 = "module not loaded";
+char exCompile[]	 = "compile failed";
+char exCrange[]		 = "constant range ";
+char exCctovflw[]	 = "constant table overflow";
+char exCphase[]		 = "compiler phase error";
+char exType[]		 = "type not constructed correctly";
+char exZdiv[]		 = "zero divide";
+char exHeap[]		 = "out of memory: heap";
+char	exImage[]		= "out of memory: image";
+char exItype[]		 = "inconsistent type";
+char exMathia[]		 = "invalid math argument";
+char exBounds[]		 = "array bounds error";
+char exNegsize[]	 = "negative array size";
+char exNomem[]		 = "out of memory: main";
+char exSpawn[]		 = "spawn a builtin module";
+char exOp[]		 = "illegal dis instruction";
+char exTcheck[]		 = "type check";
+char exInval[]		 = "invalid argument";
+char exNilref[]		 = "dereference of nil";
+char exRange[]		 = "value out of range";
--- /dev/null
+++ b/libinterp/readmod.c
@@ -1,0 +1,84 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "kernel.h"
+#include "dynld.h"
+
+Module*
+readmod(char *path, Module *m, int sync)
+{
+	Dir *d;
+	int fd, n, dynld;
+	uchar *code;
+	Module *ans;
+	ulong length;
+
+	if(path[0] == '$') {
+		if(m == nil)
+			kwerrstr("module not built-in");
+		return m;
+	}
+
+	ans = nil;
+	code = nil;
+	length = 0;
+	dynld = 0;
+
+	if(sync)
+		release();
+
+	d = nil;
+	fd = kopen(path, OREAD);
+	if(fd < 0)
+		goto done;
+
+	if((d = kdirfstat(fd)) == nil)
+		goto done;
+
+	if(m != nil) {
+		if(d->dev == m->dev && d->type == m->dtype &&
+		   d->mtime == m->mtime &&
+		   d->qid.type == m->qid.type && d->qid.path == m->qid.path && d->qid.vers == m->qid.vers) {
+			ans = m;
+			goto done;
+		}
+	}
+
+	if(d->length < 0 || d->length >= 8*1024*1024){
+		kwerrstr("implausible length");
+		goto done;
+	}
+	if((d->mode&0111) && dynldable(fd)){
+		dynld = 1;
+		goto done1;
+	}
+	length = d->length;
+	code = mallocz(length, 0);
+	if(code == nil)
+		goto done;
+
+	n = kread(fd, code, length);
+	if(n != length) {
+		free(code);
+		code = nil;
+	}
+done:
+	if(fd >= 0)
+		kclose(fd);
+done1:
+	if(sync)
+		acquire();
+	if(m != nil && ans == nil)
+		unload(m);
+	if(code != nil) {
+		ans = parsemod(path, code, length, d);
+		free(code);
+	}
+	else if(dynld){
+		kseek(fd, 0, 0);
+		ans = newdyncode(fd, path, d);
+		kclose(fd);
+	}
+	free(d);
+	return ans;
+}
--- /dev/null
+++ b/libinterp/runt.c
@@ -1,0 +1,496 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "runt.h"
+#include "sysmod.h"
+#include "raise.h"
+
+
+static	int		utfnleng(char*, int, int*);
+
+void
+sysmodinit(void)
+{
+	sysinit();
+	builtinmod("$Sys", Sysmodtab, Sysmodlen);
+}
+
+int
+xprint(Prog *xp, void *vfp, void *vva, String *s1, char *buf, int n)
+{
+	WORD i;
+	void *p;
+	LONG bg;
+	Type *t;
+	double d;
+	String *ss;
+	ulong *ptr;
+	uchar *fp, *va;
+	int nc, c, isbig, isr, sip;
+	char *b, *eb, *f, fmt[32];
+	Rune r;
+
+	fp = vfp;
+	va = vva;
+
+	sip = 0;
+	isr = 0;
+	if(s1 == H)
+		return 0;
+	nc = s1->len;
+	if(nc < 0) {
+		nc = -nc;
+		isr = 1;
+	}
+
+	b = buf;
+	eb = buf+n-1;
+	while(nc--) {
+		c = isr ? s1->Srune[sip] : s1->Sascii[sip];
+		sip++;
+		if(c != '%') {
+			if(b < eb) {
+				if(c < Runeself)
+					*b++ = c;
+				else
+					b += snprint(b, eb-b, "%C", c);
+			}
+			continue;
+		}
+		f = fmt;
+		*f++ = c;
+		isbig = 0;
+		while(nc--) {
+			c = isr ? s1->Srune[sip] : s1->Sascii[sip];
+			sip++;
+			*f++ = c;
+			*f = '\0';
+			switch(c) {
+			default:
+				continue;
+			case '*':
+				i = *(WORD*)va;
+				f--;
+				f += snprint(f, sizeof(fmt)-(f-fmt), "%d", i);
+				va += IBY2WD;
+				continue;
+			case 'b':
+				f[-1] = 'l';
+				*f++ = 'l';
+				*f = '\0';
+				isbig = 1;
+				continue;
+			case '%':
+				if(b < eb)
+					*b++ = '%';
+				break;
+			case 'q':
+			case 's':
+				ss = *(String**)va;
+				va += IBY2WD;
+				if(ss == H)
+					p = "";
+				else
+				if(ss->len < 0) {
+					f[-1] += 'A'-'a';
+					ss->Srune[-ss->len] = L'\0';
+					p = ss->Srune;
+				}
+				else {
+					ss->Sascii[ss->len] = '\0';
+					p = ss->Sascii;
+				}
+				b += snprint(b, eb-b, fmt, p);
+				break;
+			case 'E':
+				f--;
+				r = 0x00c9;	/* L'É' */
+				f += runetochar(f, &r);	/* avoid clash with ether address */
+				*f = '\0';
+				/* fall through */
+			case 'e':
+			case 'f':
+			case 'g':
+			case 'G':
+				while((va - fp) & (sizeof(REAL)-1))
+					va++;
+				d = *(REAL*)va;
+				b += snprint(b, eb-b, fmt, d);
+				va += sizeof(REAL);
+				break;
+			case 'd':
+			case 'o':
+			case 'x':
+			case 'X':
+			case 'c':
+				if(isbig) {
+					while((va - fp) & (IBY2LG-1))
+						va++;
+					bg = *(LONG*)va;
+					b += snprint(b, eb-b, fmt, bg);
+					va += IBY2LG;
+				}
+				else {
+					i = *(WORD*)va;
+					/* always a unicode character */
+					if(c == 'c')
+						f[-1] = 'C';
+					b += snprint(b, eb-b, fmt, i);
+					va += IBY2WD;
+				}
+				break;
+			case 'r':
+				b = syserr(b, eb, xp);
+				break;
+/* Debugging formats - may disappear */
+			case 'H':
+				ptr = *(ulong**)va;
+				c = -1;
+				t = nil;
+				if(ptr != H) {
+					c = D2H(ptr)->ref;
+					t = D2H(ptr)->t;
+				}
+				b += snprint(b, eb-b, "%d.%.8lux", c, (ulong)t);
+				va += IBY2WD;
+				break;
+			}
+			break;
+		}
+	}
+	return b - buf;
+}
+
+int
+bigxprint(Prog *xp, void *vfp, void *vva, String *s1, char **buf, int s)
+{
+	char *b;
+	int m, n;
+
+	m = s;
+	for (;;) {
+		m *= 2;
+		b = malloc(m);
+		if (b == nil)
+			error(exNomem);
+		n = xprint(xp, vfp, vva, s1, b, m);
+		if (n < m-UTFmax-2)
+			break;
+		free(b);
+	}
+	*buf = b;
+	return n;
+}
+
+void
+Sys_sprint(void *fp)
+{
+	int n;
+	char buf[256], *b = buf;
+	F_Sys_sprint *f;
+
+	f = fp;
+	n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
+	if (n >= sizeof(buf)-UTFmax-2)
+		n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
+	b[n] = '\0';
+	retstr(b, f->ret);
+	if (b != buf)
+		free(b);
+}
+
+void
+Sys_aprint(void *fp)
+{
+	int n;
+	char buf[256], *b = buf;
+	F_Sys_aprint *f;
+
+	f = fp;
+	n = xprint(currun(), f, &f->vargs, f->s, buf, sizeof(buf));
+	if (n >= sizeof(buf)-UTFmax-2)
+		n = bigxprint(currun(), f, &f->vargs, f->s, &b, sizeof(buf));
+	destroy(*f->ret);
+	*f->ret = mem2array(b, n);
+	if (b != buf)
+		free(b);
+}
+
+static int
+tokdelim(int c, String *d)
+{
+	int l;
+	char *p;
+	Rune *r;
+
+	l = d->len;
+	if(l < 0) {
+		l = -l;
+		for(r = d->Srune; l != 0; l--)
+			if(*r++ == c)
+				return 1;
+		return 0;
+	}
+	for(p = d->Sascii; l != 0; l--)
+		if(*p++ == c)
+			return 1;
+	return 0;
+}
+
+void
+Sys_tokenize(void *fp)
+{
+	String *s, *d;
+	List **h, *l, *nl;
+	F_Sys_tokenize *f;
+	int n, c, nc, first, last, srune;
+
+	f = fp;
+	s = f->s;
+	d = f->delim;
+
+	if(s == H || d == H) {
+		f->ret->t0 = 0;
+		destroy(f->ret->t1);
+		f->ret->t1 = H;
+		return;
+	}
+
+	n = 0;
+	l = H;
+	h = &l;
+	first = 0;
+	srune = 0;
+
+	nc = s->len;
+	if(nc < 0) {
+		nc = -nc;
+		srune = 1;
+	}
+
+	while(first < nc) {
+		while(first < nc) {
+			c = srune ? s->Srune[first] : s->Sascii[first];
+			if(tokdelim(c, d) == 0)
+				break;	
+			first++;
+		}
+
+		last = first;
+
+		while(last < nc) {
+			c = srune ? s->Srune[last] : s->Sascii[last];
+			if(tokdelim(c, d) != 0)
+				break;	
+			last++;
+		}
+
+		if(first == last)
+			break;
+
+		nl = cons(IBY2WD, h);
+		nl->tail = H;
+		nl->t = &Tptr;
+		Tptr.ref++;
+		*(String**)nl->data = slicer(first, last, s);
+		h = &nl->tail;
+
+		first = last;
+		n++;
+	}
+
+	f->ret->t0 = n;
+	destroy(f->ret->t1);
+	f->ret->t1 = l;
+}
+
+void
+Sys_utfbytes(void *fp)
+{
+	Array *a;
+	int nbyte;
+	F_Sys_utfbytes *f;
+
+	f = fp;
+	a = f->buf;
+	if(a == H || (UWORD)f->n > a->len)
+		error(exBounds);
+
+	utfnleng((char*)a->data, f->n, &nbyte);
+	*f->ret = nbyte;
+}
+
+void
+Sys_byte2char(void *fp)
+{
+	Rune r;
+	char *p;
+	int n, w;
+	Array *a;
+	F_Sys_byte2char *f;
+
+	f = fp;
+	a = f->buf;
+	n = f->n;
+	if(a == H || (UWORD)n >= a->len)
+		error(exBounds);
+	r = a->data[n];
+	if(r < Runeself){
+		f->ret->t0 = r;
+		f->ret->t1 = 1;
+		f->ret->t2 = 1;
+		return;
+	}
+	p = (char*)a->data+n;
+	if(n+UTFmax <= a->len || fullrune(p, a->len-n))
+		w = chartorune(&r, p);
+	else {
+		/* insufficient data */
+		f->ret->t0 = Runeerror;
+		f->ret->t1 = 0;
+		f->ret->t2 = 0;
+		return;
+	}
+	if(r == Runeerror && w==1){	/* encoding error */
+		f->ret->t0 = Runeerror;
+		f->ret->t1 = 1;
+		f->ret->t2 = 0;
+		return;
+	}
+	f->ret->t0 = r;
+	f->ret->t1 = w;
+	f->ret->t2 = 1;
+}
+
+void
+Sys_char2byte(void *fp)
+{
+	F_Sys_char2byte *f;
+	Array *a;
+	int n, c;
+	Rune r;
+
+	f = fp;
+	a = f->buf;
+	n = f->n;
+	c = f->c;
+	if(a == H || (UWORD)n>=a->len)
+		error(exBounds);
+	if(c<0 || c>=Runemax)
+		c = Runeerror;
+	if(c < Runeself){
+		a->data[n] = c;
+		*f->ret = 1;
+		return;
+	}
+	r = c;
+	if(n+UTFmax<=a->len || runelen(c)<=a->len-n){
+		*f->ret = runetochar((char*)a->data+n, &r);
+		return;
+	}
+	*f->ret = 0;
+}
+
+Module *
+builtinmod(char *name, void *vr, int rlen)
+{
+	Runtab *r = vr;
+	Type *t;
+	Module *m;
+	Link *l;
+
+	m = newmod(name);
+	if(rlen == 0){
+		while(r->name){
+			rlen++;
+			r++;
+		}
+		r = vr;
+	}
+	l = m->ext = (Link*)malloc((rlen+1)*sizeof(Link));
+	if(l == nil){
+		freemod(m);
+		return nil;
+	}
+	while(r->name) {
+		t = dtype(freeheap, r->size, r->map, r->np);
+		runtime(m, l, r->name, r->sig, r->fn, t);
+		r++;
+		l++;
+	}
+	l->name = nil;
+	return m;
+}
+
+void
+retnstr(char *s, int n, String **d)
+{
+	String *s1;
+
+	s1 = H;
+	if(n != 0)
+		s1 = c2string(s, n);
+	destroy(*d);
+	*d = s1;
+}
+
+void
+retstr(char *s, String **d)
+{
+	String *s1;
+
+	s1 = H;
+	if(s != nil)
+		s1 = c2string(s, strlen(s));
+	destroy(*d);
+	*d = s1;
+}
+
+Array*
+mem2array(void *va, int n)
+{
+	Heap *h;
+	Array *a;
+
+	if(n < 0)
+		n = 0;
+	h = nheap(sizeof(Array)+n);
+	h->t = &Tarray;
+	h->t->ref++;
+	a = H2D(Array*, h);
+	a->t = &Tbyte;
+	Tbyte.ref++;
+	a->len = n;
+	a->root = H;
+	a->data = (uchar*)a+sizeof(Array);
+	if(va != 0)
+		memmove(a->data, va, n);
+
+	return a;
+}
+
+static int
+utfnleng(char *s, int nb, int *ngood)
+{
+	int c;
+	long n;
+	Rune rune;
+	char *es, *starts;
+
+	starts = s;
+	es = s+nb;
+	for(n = 0; s < es; n++) {
+		c = *(uchar*)s;
+		if(c < Runeself)
+			s++;
+		else {
+			if(s+UTFmax<=es || fullrune(s, es-s))
+				s += chartorune(&rune, s);
+			else
+				break;
+		}
+	}
+	if(ngood)
+		*ngood = s-starts;
+	return n;
+}
--- /dev/null
+++ b/libinterp/sign.c
@@ -1,0 +1,29 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include <kernel.h>
+
+/*
+ * these stubs are used when devsign isn't configured
+ */
+
+int
+verifysigner(uchar *sign, int len, uchar *data, ulong ndata)
+{
+	USED(sign);
+	USED(len);
+	USED(data);
+	USED(ndata);
+
+	return 1;
+}
+
+int
+mustbesigned(char *path, uchar *code, ulong length, Dir *dir)
+{
+	USED(path);
+	USED(code);
+	USED(length);
+	USED(dir);
+	return 0;
+}
--- /dev/null
+++ b/libinterp/stack.c
@@ -1,0 +1,118 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include <pool.h>
+
+#define T(r)	*((void**)(R.r))
+
+void
+newstack(Prog *p)
+{
+	int l;
+	Type *t;
+	Frame *f;
+	Stkext *ns;
+
+	f = T(s);
+
+	t = f->t;
+	if(t == nil)
+		t = SEXTYPE(f)->reg.TR;
+
+	f->lr = nil;
+	f->mr = nil;
+	f->fp = nil;
+	l = p->R.M->m->ss;
+	/* 16 bytes for Stkext record keeping */
+	if(l < t->size+16)
+		l = t->size+16;
+	ns = mallocz(l, 0);
+	if(ns == nil)
+		error(exNomem);
+
+	ns->reg.TR = t;
+	ns->reg.SP = nil;
+	ns->reg.TS = nil;
+	ns->reg.EX = nil;
+	p->R.EX = ns->stack;
+	p->R.TS = ns->stack + l;
+	p->R.SP = ns->reg.tos.fu + t->size;
+	p->R.FP = ns->reg.tos.fu;
+
+	memmove(p->R.FP, f, t->size);
+	f = (Frame*)p->R.FP;
+	f->t = nil;
+}
+
+void
+extend(void)
+{
+	int l;
+	Type *t;
+	Frame *f;
+	Stkext *ns;
+
+	t = R.s;
+	l = R.M->m->ss;
+	/* 16 bytes for Stkext record keeping */
+	if(l < t->size+16)
+		l = 2*t->size+16;
+	ns = mallocz(l, 0);
+	if(ns == nil)
+		error(exNomem);
+
+	ns->reg.TR = t;
+	ns->reg.SP = R.SP;
+	ns->reg.TS = R.TS;
+	ns->reg.EX = R.EX;
+	f = ns->reg.tos.fr;
+	f->t  = nil;
+	f->mr = nil;
+	R.s = f;
+	R.EX = ns->stack;
+	R.TS = ns->stack + l;
+	R.SP = ns->reg.tos.fu + t->size;
+
+	if (t->np)
+		initmem(t, f);
+}
+
+void
+unextend(Frame *f)
+{
+	Stkext *sx;
+	Type *t;
+
+	sx = SEXTYPE(f);
+	R.SP = sx->reg.SP;
+	R.TS = sx->reg.TS;
+	R.EX = sx->reg.EX;
+	t = sx->reg.TR;
+	if (t->np)
+		freeptrs(f, t);
+	free(sx);
+}
+
+void
+unframe(void)
+{
+	Type *t;
+	Frame *f;
+	Stkext *sx;
+
+	f = (Frame*)R.FP;
+	t = f->t;
+	if(t == nil)
+		t = SEXTYPE(f)->reg.TR;
+
+	R.SP = R.FP+t->size;
+
+	f = T(s);
+	if(f->t == nil) {
+		sx = SEXTYPE(f);
+		R.TS = sx->reg.TS;
+		R.EX = sx->reg.EX;
+		free(sx);
+	}
+}
--- /dev/null
+++ b/libinterp/string.c
@@ -1,0 +1,616 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+
+#define OP(fn)	void fn(void)
+#define B(r)	*((BYTE*)(R.r))
+#define W(r)	*((WORD*)(R.r))
+#define F(r)	*((REAL*)(R.r))
+#define V(r)	*((LONG*)(R.r))
+#define	S(r)	*((String**)(R.r))
+#define	A(r)	*((Array**)(R.r))
+#define	L(r)	*((List**)(R.r))
+#define P(r)	*((WORD**)(R.r))
+#define C(r)	*((Channel**)(R.r))
+#define T(r)	*((void**)(R.r))
+
+OP(indc)
+{
+	int l;
+	ulong v;
+	String *ss;
+
+	v = W(m);
+	ss = S(s);
+
+	if(ss == H)
+		error(exNilref);
+
+	l = ss->len;
+	if(l < 0) {
+		if(v >= -l)
+e:			error(exBounds);
+		l = ss->Srune[v];			
+	}
+	else {
+		if(v >= l)
+			goto e;
+		l = ss->Sascii[v];			
+	}
+	W(d) = l;
+}
+
+OP(insc)
+{
+	ulong v;
+	int l, r, expand;
+	String *ss, *ns, **sp;
+
+	r = W(s);
+	v = W(m);
+	ss = S(d);
+
+	expand = r >= Runeself;
+
+	if(ss == H) {
+		ss = newstring(0);
+		if(expand) {
+			l = 0;
+			ss->max /= sizeof(Rune);
+			goto r;
+		}
+	}
+	else
+	if(D2H(ss)->ref > 1 || (expand && ss->len > 0))
+		ss = splitc(R.d, expand);
+
+	l = ss->len;
+	if(l < 0 || expand) {
+		l = -l;
+r:
+		if(v < l)
+			ss->Srune[v] = r;
+		else
+		if(v == l && v < ss->max) {
+			ss->len = -(v+1);
+			ss->Srune[v] = r;
+		}
+		else {
+			if(v != l)
+				error(exBounds);
+			ns = newstring((v + 1 + v/4)*sizeof(Rune));
+			memmove(ns->Srune, ss->Srune, -ss->len*sizeof(Rune));
+			ns->Srune[v] = r;
+			ns->len = -(v+1);
+			ns->max /= sizeof(Rune);
+			ss = ns;
+		}
+	}
+	else {
+		if(v < l)
+			ss->Sascii[v] = r;
+		else
+		if(v == l && v < ss->max) {
+			ss->len = v+1;
+			ss->Sascii[v] = r;
+		}
+		else {
+			if(v != l)
+				error(exBounds);
+			ns = newstring(v + 1 + v/4);
+			memmove(ns->Sascii, ss->Sascii, l);
+			ns->Sascii[v] = r;
+			ns->len = v+1;
+			ss = ns;
+		}
+	}
+	if(ss != S(d)) {
+		sp = R.d;
+		destroy(*sp);
+		*sp = ss;
+	}
+}
+
+String*
+slicer(ulong start, ulong v, String *ds)
+{
+	String *ns;
+	int l, nc;
+
+	if(ds == H) {
+		if(start == 0 && v == 0)
+			return H;
+
+		error(exBounds);
+	}
+
+	nc = v - start;
+	if(ds->len < 0) {
+		l = -ds->len;
+		if(v < start || v > l)
+			error(exBounds);
+		if(nc == 0)
+			return H;
+		ns = newrunes(nc);
+		memmove(ns->Srune, &ds->Srune[start], nc*sizeof(Rune));
+	}
+	else {
+		l = ds->len;
+		if(v < start || v > l)
+			error(exBounds);
+		if(nc == 0)
+			return H;
+		ns = newstring(nc);
+		memmove(ns->Sascii, &ds->Sascii[start], nc);
+	}
+
+	return ns;
+}
+
+OP(slicec)
+{
+	String *ns, **sp;
+
+	ns = slicer(W(s), W(m), S(d));
+	sp = R.d;
+	destroy(*sp);
+	*sp = ns;
+}
+
+void
+cvtup(Rune *r, String *s)
+{
+	uchar *bp, *ep;
+
+	bp = (uchar*)s->Sascii;
+	ep = bp + s->len;
+	while(bp < ep)
+		*r++ = *bp++;
+}
+
+String*
+addstring(String *s1, String *s2, int append)
+{
+	Rune *r;
+	String *ns;
+	int l, l1, l2;
+
+	if(s1 == H) {
+		if(s2 == H)
+			return H;
+		return stringdup(s2);
+	}
+	if(D2H(s1)->ref > 1)
+		append = 0;
+	if(s2 == H) {
+		if(append)
+			return s1;
+		return stringdup(s1);
+	}
+
+	if(s1->len < 0) {
+		l1 = -s1->len;
+		if(s2->len < 0) 
+			l = l1 - s2->len;
+		else
+			l = l1 + s2->len;
+		if(append && l <= s1->max)
+			ns = s1;
+		else {
+			ns = newrunes(append? (l+l/4): l);
+			memmove(ns->Srune, s1->Srune, l1*sizeof(Rune));
+		}
+		ns->len = -l;
+		r = &ns->Srune[l1];
+		if(s2->len < 0)
+			memmove(r, s2->Srune, -s2->len*sizeof(Rune));
+		else
+			cvtup(r, s2);
+
+		return ns;
+	}
+
+	if(s2->len < 0) {
+		l2 = -s2->len;
+		l = s1->len + l2;
+		ns = newrunes(append? (l+l/4): l);
+		ns->len = -l;
+		cvtup(ns->Srune, s1);
+		memmove(&ns->Srune[s1->len], s2->Srune, l2*sizeof(Rune));
+		return ns;
+	}
+
+	l1 = s1->len;
+	l = l1 + s2->len;
+	if(append && l <= s1->max)
+		ns = s1;
+	else {
+		ns = newstring(append? (l+l/4): l);
+		memmove(ns->Sascii, s1->Sascii, l1);
+	}
+	ns->len = l;
+	memmove(ns->Sascii+l1, s2->Sascii, s2->len);
+
+	return ns;
+}
+
+OP(addc)
+{
+	String *ns, **sp;
+
+	ns = addstring(S(m), S(s), R.m == R.d);
+
+	sp = R.d;
+	if(ns != *sp) {
+		destroy(*sp);
+		*sp = ns;
+	}
+}
+
+OP(cvtca)
+{
+	int l;
+	Rune *r;
+	char *p;
+	String *ss;
+ 	Array *a, **ap;
+
+	ss = S(s);
+	if(ss == H) {
+		a = mem2array(nil, 0);
+		goto r;
+	}
+	if(ss->len < 0) {
+		l = -ss->len;
+		a = mem2array(nil, runenlen(ss->Srune, l));
+		p = (char*)a->data;
+		r = ss->Srune;
+		while(l--)
+			p += runetochar(p, r++);	
+		goto r;
+	}
+	a = mem2array(ss->Sascii, ss->len);
+
+r:	ap = R.d;
+	destroy(*ap);
+	*ap = a;
+}
+
+OP(cvtac)
+{
+	Array *a;
+	String *ds, **dp;
+
+	ds = H;
+	a = A(s);
+	if(a != H)
+		ds = c2string((char*)a->data, a->len);
+
+	dp = R.d;
+	destroy(*dp);
+	*dp = ds;
+}
+
+OP(lenc)
+{
+	int l;
+	String *ss;
+
+	l = 0;
+	ss = S(s);
+	if(ss != H) {
+		l = ss->len;
+		if(l < 0)
+			l = -l;
+	}
+	W(d) = l;
+}
+
+OP(cvtcw)
+{
+	String *s;
+
+	s = S(s);
+	if(s == H)
+		W(d) = 0;
+	else
+	if(s->len < 0)
+		W(d) = strtol(string2c(s), nil, 10);
+	else {
+		s->Sascii[s->len] = '\0';
+		W(d) = strtol(s->Sascii, nil, 10);
+	}
+}
+
+OP(cvtcf)
+{
+	String *s;
+
+	s = S(s);
+	if(s == H)
+		F(d) = 0.0;
+	else
+	if(s->len < 0)
+		F(d) = strtod(string2c(s), nil);
+	else {
+		s->Sascii[s->len] = '\0';
+		F(d) = strtod(s->Sascii, nil);
+	}
+}
+
+OP(cvtwc)
+{
+	String *ds, **dp;
+
+	ds = newstring(16);
+	ds->len = sprint(ds->Sascii, "%d", W(s));
+
+	dp = R.d;
+	destroy(*dp);
+	*dp = ds;
+}
+
+OP(cvtlc)
+{
+	String *ds, **dp;
+
+	ds = newstring(16);
+	ds->len = sprint(ds->Sascii, "%lld", V(s));
+	
+	dp = R.d;
+	destroy(*dp);
+	*dp = ds;
+}
+
+OP(cvtfc)
+{
+	String *ds, **dp;
+
+	ds = newstring(32);
+	ds->len = sprint(ds->Sascii, "%g", F(s));	
+	dp = R.d;
+	destroy(*dp);
+	*dp = ds;
+}
+
+char*
+string2c(String *s)
+{
+	char *p;
+	int c, l, nc;
+	Rune *r, *er;
+
+	if(s == H)
+		return "";
+
+	if(s->len >= 0) {
+		s->Sascii[s->len] = '\0';
+		return s->Sascii;
+	}
+
+	nc = -s->len;
+	l = (nc * UTFmax) + UTFmax;
+	if(s->tmp == nil || msize(s->tmp) < l) {
+		free(s->tmp);
+		s->tmp = malloc(l);
+		if(s->tmp == nil)
+			error(exNomem);
+	}
+
+	p = s->tmp;
+	r = s->Srune;
+	er = r + nc;
+	while(r < er) {
+		c = *r++;
+		if(c < Runeself)
+			*p++ = c;
+		else
+			p += runetochar(p, r-1);
+	}
+
+	*p = 0;
+
+	return s->tmp;
+}
+
+String*
+c2string(char *cs, int len)
+{
+	uchar *p;
+	char *ecs;
+	String *s;
+	Rune *r, junk;
+	int c, nc, isrune;
+
+	isrune = 0;
+	ecs = cs+len;
+	p = (uchar*)cs;
+	while(len--) {
+		c = *p++;
+		if(c >= Runeself) {
+			isrune = 1;
+			break;
+		}
+	}
+
+	if(isrune == 0) {
+		nc = ecs - cs;
+		s = newstring(nc);
+		memmove(s->Sascii, cs, nc);
+		return s;
+	}
+
+	p--;
+	nc = p - (uchar*)cs;
+	while(p < (uchar*)ecs) {
+		c = *p;
+		if(c < Runeself)
+			p++;
+		else if(p+UTFmax<=(uchar*)ecs || fullrune((char*)p, (uchar*)ecs-p))
+			p += chartorune(&junk, (char*)p);
+		else
+			break;
+		nc++;
+	}
+	s = newrunes(nc);
+	r = s->Srune;
+	while(nc--)
+		cs += chartorune(r++, cs);
+
+	return s;
+}
+
+String*
+newstring(int nb)
+{
+	Heap *h;
+	String *s;
+
+	h = nheap(sizeof(String)+nb);
+	h->t = &Tstring;
+	Tstring.ref++;
+	s = H2D(String*, h);
+	s->tmp = nil;
+	s->len = nb;
+	s->max = hmsize(h) - (sizeof(String)+sizeof(Heap));
+	return s;
+}
+
+String*
+newrunes(int nr)
+{
+	Heap *h;
+	String *s;
+
+	if(nr == 0)
+		return newstring(nr);
+	if(nr < 0)
+		nr = -nr;
+	h = nheap(sizeof(String)+nr*sizeof(Rune));
+	h->t = &Tstring;
+	Tstring.ref++;
+	s = H2D(String*, h);
+	s->tmp = nil;
+	s->len = -nr;
+	s->max = (hmsize(h) - (sizeof(String)+sizeof(Heap)))/sizeof(Rune);
+	return s;
+}
+
+String*
+stringdup(String *s)
+{
+	String *ns;
+
+	if(s == H)
+		return H;
+
+	if(s->len >= 0) {
+		ns = newstring(s->len);
+		memmove(ns->Sascii, s->Sascii, s->len);
+		return ns;
+	}
+
+	ns = newrunes(-s->len);
+	memmove(ns->Srune, s->Srune,-s->len*sizeof(Rune));
+
+	return ns;
+}
+
+int
+stringcmp(String *s1, String *s2)
+{
+	Rune *r1, *r2;
+	char *a1, *a2;
+	int v, n, n1, n2, c1, c2;
+	static String snil = { 0, 0, nil };
+
+	if(s1 == H)
+		s1 = &snil;
+	if(s2 == H)
+		s2 = &snil;
+
+	if(s1 == s2)
+		return 0;
+
+	v = 0;
+	n1 = s1->len;
+	if(n1 < 0) {
+		n1 = -n1;
+		v |= 1;
+	}
+	n2 = s2->len;
+	if(n2 < 0) {
+		n2 = -n2;
+		v |= 2;
+	}
+
+	n = n1;
+	if(n2 < n)
+		n = n2;
+
+	switch(v) {
+	case 0:		/* Ascii Ascii */
+		n = memcmp(s1->Sascii, s2->Sascii, n);
+		if(n == 0)
+			n = n1 - n2;
+		return n;
+	case 1:		/* Rune Ascii */
+		r1 = s1->Srune;
+		a2 = s2->Sascii;
+		while(n > 0) {
+			c1 = *r1++;
+			c2 = *a2++;
+			if(c1 != c2)
+				goto ne;
+			n--;
+		}
+		break;
+	case 2:		/* Ascii Rune */
+		a1 = s1->Sascii;
+		r2 = s2->Srune;
+		while(n > 0) {
+			c1 = *a1++;
+			c2 = *r2++;
+			if(c1 != c2)
+				goto ne;
+			n--;
+		}
+		break;
+	case 3:		/* Rune Rune */
+		r1 = s1->Srune;
+		r2 = s2->Srune;
+		while(n > 0) {
+			c1 = *r1++;
+			c2 = *r2++;
+			if(c1 != c2)
+				goto ne;
+			n--;
+		}
+		break;
+	}
+	return n1 - n2;
+
+ne:	if(c1 < c2)
+		return -1;
+	return 1;
+}
+
+String*
+splitc(String **s, int expand)
+{
+	String *ss, *ns;
+
+	ss = *s;
+	if(expand && ss->len > 0) {
+		ns = newrunes(ss->len);
+		cvtup(ns->Srune, ss);
+	}
+	else
+		ns = stringdup(ss);
+
+	destroy(ss);
+	*s = ns;
+	return ns;
+}
--- /dev/null
+++ b/libinterp/tab.h
@@ -1,0 +1,184 @@
+struct
+{
+	char*	name;
+	int	op;
+	int	terminal;
+}keywds[] =
+{
+	"nop",		INOP,		TOKI0,
+	"alt",		IALT,		TOKI3,
+	"nbalt",	INBALT,		TOKI3,
+	"goto",		IGOTO,		TOKI2,
+	"call",		ICALL,		TOKI2,
+	"frame",	IFRAME,		TOKI2,
+	"spawn",	ISPAWN,		TOKI2,
+	"runt",		IRUNT,		TOKI2,
+	"load",		ILOAD,		TOKI3,
+	"mcall",	IMCALL,		TOKI3,
+	"mspawn",	IMSPAWN,	TOKI3,
+	"mframe",	IMFRAME,	TOKI3,
+	"ret",		IRET,		TOKI0,
+	"jmp",		IJMP,		TOKI1,
+	"case",		ICASE,		TOKI2,
+	"exit",		IEXIT,		TOKI0,
+	"new",		INEW,		TOKI2,
+	"newa",		INEWA,		TOKI3,
+	"newcb",	INEWCB,		TOKI1,
+	"newcw",	INEWCW,		TOKI1,
+	"newcf",	INEWCF,		TOKI1,
+	"newcp",	INEWCP,		TOKI1,
+	"newcm",	INEWCM,		TOKI2,
+	"newcmp",	INEWCMP,	TOKI2,
+	"send",		ISEND,		TOKI2,
+	"recv",		IRECV,		TOKI2,
+	"consb",	ICONSB,		TOKI2,
+	"consw",	ICONSW,		TOKI2,
+	"consp",	ICONSP,		TOKI2,
+	"consf",	ICONSF,		TOKI2,
+	"consm",	ICONSM,		TOKI3,
+	"consmp",	ICONSMP,	TOKI3,
+	"headb",	IHEADB,		TOKI2,
+	"headw",	IHEADW,		TOKI2,
+	"headp",	IHEADP,		TOKI2,
+	"headf",	IHEADF,		TOKI2,
+	"headm",	IHEADM,		TOKI3,
+	"headmp",	IHEADMP,	TOKI3,
+	"tail",		ITAIL,		TOKI2,
+	"lea",		ILEA,		TOKI2,
+	"indx",		IINDX,		TOKI3,
+	"movp",		IMOVP,		TOKI2,
+	"movm",		IMOVM,		TOKI3,
+	"movmp",	IMOVMP,		TOKI3,
+	"movb",		IMOVB,		TOKI2,
+	"movw",		IMOVW,		TOKI2,
+	"movf",		IMOVF,		TOKI2,
+	"cvtbw",	ICVTBW,		TOKI2,
+	"cvtwb",	ICVTWB,		TOKI2,
+	"cvtfw",	ICVTFW,		TOKI2,
+	"cvtwf",	ICVTWF,		TOKI2,
+	"cvtca",	ICVTCA,		TOKI2,
+	"cvtac",	ICVTAC,		TOKI2,
+	"cvtwc",	ICVTWC,		TOKI2,
+	"cvtcw",	ICVTCW,		TOKI2,
+	"cvtfc",	ICVTFC,		TOKI2,
+	"cvtcf",	ICVTCF,		TOKI2,
+	"addb",		IADDB,		TOKI3,
+	"addw",		IADDW,		TOKI3,
+	"addf",		IADDF,		TOKI3,
+	"subb",		ISUBB,		TOKI3,
+	"subw",		ISUBW,		TOKI3,
+	"subf",		ISUBF,		TOKI3,
+	"mulb",		IMULB,		TOKI3,
+	"mulw",		IMULW,		TOKI3,
+	"mulf",		IMULF,		TOKI3,
+	"divb",		IDIVB,		TOKI3,
+	"divw",		IDIVW,		TOKI3,
+	"divf",		IDIVF,		TOKI3,
+	"modw",		IMODW,		TOKI3,
+	"modb",		IMODB,		TOKI3,
+	"andb",		IANDB,		TOKI3,
+	"andw",		IANDW,		TOKI3,
+	"orb",		IORB,		TOKI3,
+	"orw",		IORW,		TOKI3,
+	"xorb",		IXORB,		TOKI3,
+	"xorw",		IXORW,		TOKI3,
+	"shlb",		ISHLB,		TOKI3,
+	"shlw",		ISHLW,		TOKI3,
+	"shrb",		ISHRB,		TOKI3,
+	"shrw",		ISHRW,		TOKI3,
+	"insc",		IINSC,		TOKI3,
+	"indc",		IINDC,		TOKI3,
+	"addc",		IADDC,		TOKI3,
+	"lenc",		ILENC,		TOKI2,
+	"lena",		ILENA,		TOKI2,
+	"lenl",		ILENL,		TOKI2,
+	"beqb",		IBEQB,		TOKI3,
+	"bneb",		IBNEB,		TOKI3,
+	"bltb",		IBLTB,		TOKI3,
+	"bleb",		IBLEB,		TOKI3,
+	"bgtb",		IBGTB,		TOKI3,
+	"bgeb",		IBGEB,		TOKI3,
+	"beqw",		IBEQW,		TOKI3,
+	"bnew",		IBNEW,		TOKI3,
+	"bltw",		IBLTW,		TOKI3,
+	"blew",		IBLEW,		TOKI3,
+	"bgtw",		IBGTW,		TOKI3,
+	"bgew",		IBGEW,		TOKI3,
+	"beqf",		IBEQF,		TOKI3,
+	"bnef",		IBNEF,		TOKI3,
+	"bltf",		IBLTF,		TOKI3,
+	"blef",		IBLEF,		TOKI3,
+	"bgtf",		IBGTF,		TOKI3,
+	"bgef",		IBGEF,		TOKI3,
+	"beqc",		IBEQC,		TOKI3,
+	"bnec",		IBNEC,		TOKI3,
+	"bltc",		IBLTC,		TOKI3,
+	"blec",		IBLEC,		TOKI3,
+	"bgtc",		IBGTC,		TOKI3,
+	"bgec",		IBGEC,		TOKI3,
+	"slicea",	ISLICEA,	TOKI3,
+	"slicela",	ISLICELA,	TOKI3,
+	"slicec",	ISLICEC,	TOKI3,
+	"indw",		IINDW,		TOKI3,
+	"indf",		IINDF,		TOKI3,
+	"indb",		IINDB,		TOKI3,
+	"negf",		INEGF,		TOKI2,
+	"movl",		IMOVL,		TOKI2,
+	"addl",		IADDL,		TOKI3,
+	"subl",		ISUBL,		TOKI3,
+	"divl",		IDIVL,		TOKI3,
+	"modl",		IMODL,		TOKI3,
+	"mull",		IMULL,		TOKI3,
+	"andl",		IANDL,		TOKI3,
+	"orl",		IORL,		TOKI3,
+	"xorl",		IXORL,		TOKI3,
+	"shll",		ISHLL,		TOKI3,
+	"shrl",		ISHRL,		TOKI3,
+	"bnel",		IBNEL,		TOKI3,
+	"bltl",		IBLTL,		TOKI3,
+	"blel",		IBLEL,		TOKI3,
+	"bgtl",		IBGTL,		TOKI3,
+	"bgel",		IBGEL,		TOKI3,
+	"beql",		IBEQL,		TOKI3,
+	"cvtlf",	ICVTLF,		TOKI2,
+	"cvtfl",	ICVTFL,		TOKI2,
+	"cvtlw",	ICVTLW,		TOKI2,
+	"cvtwl",	ICVTWL,		TOKI2,
+	"cvtlc",	ICVTLC,		TOKI2,
+	"cvtcl",	ICVTCL,		TOKI2,
+	"headl",	IHEADL,		TOKI2,
+	"consl",	ICONSL,		TOKI2,
+	"newcl",	INEWCL,		TOKI1,
+	"casec",	ICASEC,		TOKI2,
+	"indl",		IINDL,		TOKI3,
+	"movpc",	IMOVPC,		TOKI2,
+	"tcmp",		ITCMP,		TOKI2,
+	"mnewz",	IMNEWZ,		TOKI3,
+	"cvtrf",	ICVTRF,		TOKI2,
+	"cvtfr",	ICVTFR,		TOKI2,
+	"cvtws",	ICVTWS,		TOKI2,
+	"cvtsw",	ICVTSW,		TOKI2,
+	"lsrw",		ILSRW,		TOKI3,
+	"lsrl",		ILSRL,		TOKI3,
+	"eclr",		IECLR,		TOKI0,
+	"newz",		INEWZ,		TOKI2,
+	"newaz",	INEWAZ,		TOKI3,
+	"raise",	IRAISE,	TOKI1,
+	"casel",	ICASEL,	TOKI2,
+	"mulx",	IMULX,	TOKI3,
+	"divx",	IDIVX,	TOKI3,
+	"cvtxx",	ICVTXX,	TOKI3,
+	"mulx0",	IMULX0,	TOKI3,
+	"divx0",	IDIVX0,	TOKI3,
+	"cvtxx0",	ICVTXX0,	TOKI3,
+	"mulx1",	IMULX1,	TOKI3,
+	"divx1",	IDIVX1,	TOKI3,
+	"cvtxx1",	ICVTXX1,	TOKI3,
+	"cvtfx",	ICVTFX,	TOKI3,
+	"cvtxf",	ICVTXF,	TOKI3,
+	"expw",	IEXPW,	TOKI3,
+	"expl",	IEXPL,	TOKI3,
+	"expf",	IEXPF,	TOKI3,
+	"self",	ISELF,	TOKI1,
+	0,
+};
--- /dev/null
+++ b/libinterp/tk.c
@@ -1,0 +1,1305 @@
+#include "lib9.h"
+#include "interp.h"
+#include "isa.h"
+#include "runt.h"
+#include "draw.h"
+#include "tk.h"
+#include "tkmod.h"
+#include "pool.h"
+#include "drawif.h"
+#include "keyboard.h"
+#include "raise.h"
+#include "kernel.h"
+
+extern	void	tkfreetop(Heap*, int);
+Type*	fakeTkTop;
+static	uchar	TktypeMap[] = Tk_Toplevel_map;
+int	tkstylus;
+void	(*tkwiretap)(void*, char*, char*, void*, Rectangle*);
+
+static void tktopimagedptr(TkTop*, Draw_Image*);
+static char*tkputwinimage(Tk*, Draw_Image*, int);
+
+static void
+lockctxt(TkCtxt *ctxt)
+{
+	libqlock(ctxt->lock);
+}
+
+static void
+unlockctxt(TkCtxt *ctxt)
+{
+	libqunlock(ctxt->lock);
+}
+
+static void
+tkmarktop(Type *t, void *vw)
+{
+	Heap *h;
+	TkVar *v;
+	TkPanelimage *di;
+	TkTop *top;
+	Tk *w, *next;
+	TkWin *tkw;
+
+	markheap(t, vw);
+	top = vw;
+	// XXX do we need to lock context here??
+	for(v = top->vars; v; v = v->link) {
+		if(v->type == TkVchan) {
+			h = D2H(v->value);
+			Setmark(h);
+		}
+	}
+	for (di = top->panelimages; di != nil; di = di->link) {
+		h = D2H(di->image);
+		Setmark(h);
+	}
+	for(w = top->windows; w != nil; w = next){
+		tkw = TKobj(TkWin, w);
+		if(tkw->image != nil){
+			h = D2H(tkw->di);
+			Setmark(h);
+		}
+		next = tkw->next;
+	}
+}
+
+void
+tkmodinit(void)
+{
+	builtinmod("$Tk", Tkmodtab, Tkmodlen);
+	fmtinstall('v', tkeventfmt);			/* XXX */
+
+	fakeTkTop = dtype(tkfreetop, sizeof(TkTop), TktypeMap, sizeof(TktypeMap));
+	fakeTkTop->mark = tkmarktop;
+
+	tksorttable();
+}
+
+void
+Tk_toplevel(void *a)
+{
+	Tk *tk;
+	Heap *h;
+	TkTop *t;
+	TkWin *tkw;
+	TkCtxt *ctxt;
+	Display *disp;
+	F_Tk_toplevel *f = a;
+	void *r;
+
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+	disp = checkdisplay(f->d);
+
+	h = heapz(fakeTkTop);
+	t = H2D(TkTop*, h);
+	poolimmutable(h);
+
+	t->dd = f->d;
+	D2H(t->dd)->ref++;
+
+	t->execdepth = -1;
+	t->display = disp;
+
+	tk = tknewobj(t, TKframe, sizeof(Tk)+sizeof(TkWin));
+	if(tk == nil) {
+		destroy(t);
+		return;
+	}
+
+	tk->act.x = 0;
+	tk->act.y = 0;
+	tk->act.width = 1;		/* XXX why not zero? */
+	tk->act.height = 1;
+	tk->flag |= Tkwindow;
+
+	tkw = TKobj(TkWin, tk);
+	tkw->di = H;
+
+	tktopopt(tk, string2c(f->arg));
+	
+	tk->geom = tkmoveresize;
+	tk->name = tkmkname(".");
+	if(tk->name == nil) {
+		tkfreeobj(tk);
+		destroy(t);
+		return;
+	}
+
+	ctxt = tknewctxt(disp);
+	if(ctxt == nil) {
+		tkfreeobj(tk);
+		destroy(t);
+		return;
+	}
+	t->ctxt = ctxt;
+	t->screenr = disp->image->r;
+
+	tkw->next = t->windows;
+	t->windows = tk;
+	t->root = tk;
+	Setmark(h);
+	poolmutable(h);
+	t->wreq = cnewc(&Tptr, movp, 8);
+	*f->ret = (Tk_Toplevel*)t;
+}
+
+void
+Tk_cmd(void *a)
+{
+	TkTop *t;
+	char *val, *e;
+	F_Tk_cmd *f = a;
+
+	t = (TkTop*)f->t;
+	if(t == H || D2H(t)->t != fakeTkTop) {
+		retstr(TkNotop, f->ret);
+		return;
+	}
+	lockctxt(t->ctxt);
+	val = nil;
+	e = tkexec(t, string2c(f->arg), &val);
+	unlockctxt(t->ctxt);
+	if(e == TkNomem){
+		free(val);
+		error(exNomem);		/* what about f->ret? */
+	}
+	if(e != nil && t->errx[0] != '\0'){
+		char *s = tkerrstr(t, e);
+
+		retstr(s, f->ret);
+		free(s);
+	}
+	else
+		retstr(e == nil ? val : e, f->ret);
+	if(tkwiretap != nil)
+		tkwiretap(t, string2c(f->arg), val, nil, nil);
+	free(val);
+}
+
+void
+Tk_color(void *fp)
+{
+	ulong rgba;
+	F_Tk_color *f = fp;
+	if(tkparsecolor(string2c(f->col), &rgba) != nil)
+		*f->ret = DNotacolor;
+	else
+		*f->ret = rgba;
+}
+
+void
+Tk_rect(void *fp)
+{
+	F_Tk_rect *f = fp;
+	Tk *tk;
+	TkTop *t;
+	Rectangle r;
+	Point o;
+	int bd, flags, w, h;
+
+	t = (TkTop*)f->t;
+	if(t == H || D2H(t)->t != fakeTkTop){
+		*(Rectangle*)f->ret = ZR;
+		return;
+	}
+	lockctxt(t->ctxt);
+	tk = tklook(t, string2c(f->name), 0);
+	if(tk == nil){
+		*(Rectangle*)f->ret = ZR;
+		unlockctxt(t->ctxt);
+		return;
+	}
+	o = tkposn(tk);
+	flags = f->flags;
+	if(flags & Tk_Local)
+		o = subpt(o, tkposn(tk->env->top->root));
+	if(flags & Tk_Required){
+		h = tk->req.height;
+		w = tk->req.width;
+	}else{
+		h = tk->act.height;
+		w = tk->act.width;
+	}
+	unlockctxt(t->ctxt);
+	if(w < 0)
+		w = 0;
+	if(h < 0)
+		h = 0;
+	bd = tk->borderwidth;
+	if(bd < 0)
+		bd = 0;
+	if(flags & Tk_Border){
+		r.min = o;
+		r.max.x = r.min.x + w + bd + bd;
+		r.max.y = r.min.y + h + bd + bd;
+	}else{
+		r.min.x = o.x + bd;
+		r.min.y = o.y + bd;
+		r.max.x = r.min.x + w;
+		r.max.y = r.min.y + h;
+	}
+	*(Rectangle*)f->ret = r;
+}
+
+int
+tkdescendant(Tk *p, Tk *c)
+{
+	int n;
+
+	if(c == nil || p->env->top != c->env->top)
+		return 0;
+
+	if (p->name != nil && c->name != nil) {
+ 		n = strlen(p->name->name);
+		if(strncmp(p->name->name, c->name->name, n) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+void
+tkenterleave(TkTop *t)
+{
+	Tk *fw, *ent;
+	TkMouse m;
+	TkTop *t1, *t2;
+	TkCtxt *c;
+
+	c = t->ctxt;
+	m = c->mstate;
+
+	if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
+		fw = tkfindfocus(t, m.x, m.y, 1);
+		if (fw != c->mgrab && fw != nil && (fw->flag & Tknograb) == 0)
+			fw = nil;
+	} else if (c->focused) {
+		fw = tkfindfocus(t, m.x, m.y, 1);
+		if (fw != c->mfocus)
+			fw = nil;
+	} else if (c->mgrab != nil) {
+		fw = tkfindfocus(t, m.x, m.y, 1);
+		if (fw != nil) {
+			if (!tkdescendant(c->mgrab, fw) && !(fw->flag & c->mgrab->flag & Tknograb))
+				fw = nil;
+		}
+	} else if (m.b == 0)
+		fw = tkfindfocus(t, m.x, m.y, 0);
+	else if (tkfindfocus(t, m.x, m.y, 1) == c->entered)
+		return;
+	else
+		fw = nil;
+
+ 	if (c->entered == fw)
+		return;
+
+	t1 = t2 = nil;
+	if (c->entered != nil) {
+		ent = c->entered;
+		t1 = ent->env->top;
+		c->entered = nil;
+		tkdeliver(ent, TkLeave, nil);
+	}
+
+	if (fw != nil) {
+		t2 = fw->env->top;
+		c->entered = fw;
+		tkdeliver(fw, TkEnter, &m);
+	}
+	if (t1 != nil)
+		tkupdate(t1);
+	if (t2 != nil && t1 != t2)
+		tkupdate(t2);
+}
+
+void
+Tk_pointer(void *a)
+{
+	static int buttonr[] = {TkButton1R, TkButton2R, TkButton3R, TkButton4R, TkButton5R, TkButton6R};
+	static int buttonp[] = {TkButton1P, TkButton2P, TkButton3P, TkButton4P, TkButton5P, TkButton6P};
+	Tk *fw, *target, *dest, *ent;
+	TkMouse m;
+	TkCtxt *c;
+	TkTop *t, *ot;
+	int d, dtype, etype;
+	F_Tk_pointer *f = a;
+	int b, lastb, inside;
+
+	t = (TkTop*)f->t;
+	if(t == H || D2H(t)->t != fakeTkTop)
+		return;
+
+	c = t->ctxt;
+
+	/* ignore no-button-motion for emulated stylus input */
+	if(tkstylus && c->mstate.b == 0 && (f->p.buttons&0x1f)==0)
+		return;
+
+	lockctxt(c);
+//if (f->p.buttons != 0 || c->mstate.b != 0)
+//print("tkmouse %d [%d %d], focused %d[%s], grab %s, entered %s\n",
+//	f->p.buttons, f->p.xy.x, f->p.xy.y, c->focused, tkname(c->mfocus), tkname(c->mgrab), tkname(c->entered));
+	/*
+	 * target is the widget that we're deliver the mouse event to.
+	 * inside is true if the mouse point is located inside target.
+	 */
+	inside = 1;
+	if (c->mgrab != nil && (c->mgrab->flag & Tknograb)) {
+		fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+		if (fw != nil && (fw->flag & Tknograb))
+			target = fw;
+		else {
+			target = c->mgrab;
+			inside = 0;
+		}
+	} else if (c->focused) {
+		if (c->mfocus != nil) {
+			fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+			if (fw != c->mfocus)
+				inside = 0;
+		}
+		target = c->mfocus;
+	} else if (c->mgrab != nil && (c->mgrab->flag & Tkdisabled) == 0) {
+		/*
+		 * XXX this isn't quite right, as perhaps we should do a tkinwindow()
+		 * (below the grab).
+		 * so that events to containers underneath the grab arrive
+		 * via the containers (as is usual)
+		 */
+		fw = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 1);
+		if (fw != nil && tkdescendant(c->mgrab, fw))
+			target = fw;
+		else {
+			target = c->mgrab;
+			inside = 0;
+		}
+	} else
+		target = tkfindfocus(t, f->p.xy.x, f->p.xy.y, 0);
+
+	lastb = c->mstate.b;
+	c->mstate.x = f->p.xy.x;
+	c->mstate.y = f->p.xy.y;
+	c->mstate.b = f->p.buttons & 0x1f;		/* Just the buttons */
+	m = c->mstate;
+
+	/* XXX if the mouse is being moved with the buttons held down
+	 * and we've no mfocus and no mgrab then ignore
+	 * the event as our original target has gone away (or never existed)
+	 */
+	if (lastb && m.b && !c->focused && c->mgrab == nil)
+		target = nil;
+
+	if (target != c->entered || (c->entered != nil && !inside)) {
+		if (c->entered != nil) {
+			fw = c->entered;
+			c->entered =  nil;
+			tkdeliver(fw, TkLeave, nil);
+			if (target == nil || fw->env->top != target->env->top)
+				tkupdate(fw->env->top);
+		}
+		if (inside) {
+			c->entered = target;
+			tkdeliver(target, TkEnter, &m);
+		}
+	}
+
+	dest = nil;
+	if (target != nil) {
+		etype = 0;
+		dtype = 0;
+		if(f->p.buttons & (1<<8))		/* Double */
+			dtype = TkDouble;
+	
+		d = lastb ^ m.b;
+		if (d)	{
+			/* cancel any autorepeat, notifying existing client */
+			tkrepeat(nil, nil, nil, 0, 0);
+			if (d & ~lastb & 1)		/* button 1 potentially takes the focus */
+				tkdeliver(target, TkTakefocus|TkButton1P, &m);
+		}
+		for(b=0; b<nelem(buttonp); b++){
+			if(d & (1<<b)){
+				etype = buttonr[b];
+				if(m.b & (1<<b))
+					etype = buttonp[b]|dtype;
+				dest = tkdeliver(target, etype, &m);
+			}
+		}
+		if(tkstylus && m.b==0) {
+			if ((ent = c->entered) != nil) {
+				c->entered = nil;
+				ot = ent->env->top;
+				tkdeliver(ent, TkLeave, nil);
+				if (ot != target->env->top)
+					tkupdate(ot);
+			}
+		} else if(etype == 0) {
+			etype = TkMotion;
+			for(b = 0; b<nelem(buttonp); b++)
+				if (m.b & (1<<b))
+					etype |= buttonp[b];
+			tkdeliver(target, etype, &m);
+		}
+		if (m.b != 0) {
+			if (lastb == 0 && !c->focused) {		/* (some deliver might have grabbed it...) */
+				if (dest == nil)
+					dest = target;
+				if ((dest->flag & Tknograb) == 0) {
+					c->focused = 1;
+					c->mfocus = dest;
+				}
+			}
+		} else {
+			c->focused = 0;
+			c->mfocus = nil;
+			if (lastb != 0)
+				tkenterleave(t);
+		}
+		tkupdate(target->env->top);
+	} else if (c->focused && m.b == 0) {
+		c->focused = 0;
+		tkenterleave(t);
+	}
+	unlockctxt(c);
+}
+
+void
+Tk_keyboard(void *a)
+{
+	Tk *grab;
+	TkTop *t;
+	TkCtxt *c;
+	F_Tk_keyboard *f = a;
+
+	t = (TkTop*)f->t;
+	if(t == H || D2H(t)->t != fakeTkTop)
+		return;
+	c = t->ctxt;
+	if (c == nil)
+		return;
+	lockctxt(c);
+	if (c->tkmenu != nil)
+		grab = c->tkmenu;
+	else
+		grab = c->tkkeygrab;
+	if(grab == nil){
+		unlockctxt(c);
+		return;
+	}
+
+	t = grab->env->top;
+	tkdeliver(grab, TkKey|TKKEY(f->key), nil);
+	tkupdate(t);
+	unlockctxt(c);
+}
+
+TkVar*
+tkmkvar(TkTop *t, char *name, int type)
+{
+	TkVar *v;
+
+	for(v = t->vars; v; v = v->link)
+		if(strcmp(v->name, name) == 0)
+			return v;
+
+	if(type == 0)
+		return nil;
+
+	v = malloc(sizeof(TkVar)+strlen(name)+1);
+	if(v == nil)
+		return nil;
+	strcpy(v->name, name);
+	v->link = t->vars;
+	t->vars = v;
+	v->type = type;
+	v->value = nil;
+	if(type == TkVchan)
+		v->value = H;
+	return v;
+}
+
+void
+tkfreevar(TkTop *t, char *name, int swept)
+{
+	TkVar **l, *p;
+
+	if(name == nil)
+		return;
+	l = &t->vars;
+	for(p = *l; p != nil; p = p->link) {
+		if(strcmp(p->name, name) == 0) {
+			*l = p->link;
+			switch(p->type) {
+			default:
+				free(p->value);
+				break;
+			case TkVchan:
+				if(!swept)
+					destroy(p->value);
+				break;
+			}
+			free(p);
+			return;
+		}
+		l = &p->link;
+	}
+}
+
+void
+Tk_namechan(void *a)
+{
+	Heap *h;
+	TkVar *v;
+	TkTop *t;
+	char *name;
+	F_Tk_namechan *f = a;
+
+	t = (TkTop*)f->t;
+	if(t == H || D2H(t)->t != fakeTkTop) {
+		retstr(TkNotop, f->ret);
+		return;
+	}
+	if(f->c == H) {
+		retstr("nil channel", f->ret);
+		return;
+	}
+	name = string2c(f->n);
+	if(name[0] == '\0') {
+		retstr(TkBadvl, f->ret);
+		return;
+	}
+
+	lockctxt(t->ctxt);
+	v = tkmkvar(t, name, TkVchan);
+	if(v == nil) {
+		unlockctxt(t->ctxt);
+		retstr(TkNomem, f->ret);
+		return;
+	}
+	if(v->type != TkVchan) {
+		unlockctxt(t->ctxt);
+		retstr(TkNotvt, f->ret);
+		return;
+	}
+	destroy(v->value);
+	v->value = f->c;
+	unlockctxt(t->ctxt);
+	h = D2H(v->value);
+	h->ref++;
+	Setmark(h);
+	retstr("", f->ret);
+}
+
+void
+Tk_quote(void *a)
+{
+	String *s, *ns;
+	F_Tk_quote *f;
+	void *r;
+	int c, i, need, len, userune, last, n;
+	Rune *sr;
+	char *sc;
+
+	f = a;
+
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	s = f->s;
+	if(s == H){
+		retstr("{}", f->ret);
+		return;
+	}
+	len = s->len;
+	userune = 0;
+	if(len < 0) {
+		len = -len;
+		userune = 1;
+	}
+	need = len+2;
+	for(i = 0; i < len; i++) {
+		c = userune? s->Srune[i]: s->Sascii[i];
+		if(c == '{' || c == '}' || c == '\\')
+			need++;
+	}
+	if(userune) {
+		ns = newrunes(need);
+		sr = ns->Srune;
+		*sr++ = '{';
+		last = 0;
+		for(i = 0;; i++) {
+			if(i >= len || (c = s->Srune[i]) == '{' || c == '}' || c == '\\'){
+				n = i-last;
+				if(n) {
+					memmove(sr, &s->Srune[last], n*sizeof(Rune));
+					sr += n;
+				}
+				if(i >= len)
+					break;
+				*sr++ = '\\';
+				last = i;
+			}
+		}
+		*sr = '}';
+	} else {
+		ns = newstring(need);
+		sc = ns->Sascii;
+		*sc++ = '{';
+		last = 0;
+		for(i = 0;; i++) {
+			if(i >= len || (c = s->Sascii[i]) == '{' || c == '}' || c == '\\'){
+				n = i-last;
+				if(n) {
+					memmove(sc, &s->Sascii[last], n);
+					sc += n;
+				}
+				if(i >= len)
+					break;
+				*sc++ = '\\';
+				last = i;
+			}
+		}
+		*sc= '}';
+	}
+	*f->ret = ns;
+}
+
+static void
+tkreplimg(TkTop *t, Draw_Image *f, Draw_Image *m, Image **ximg)
+{
+	Display *d;
+	Image *cimg, *cmask, *new;
+
+	cimg = lookupimage(f);
+	d = t->display;
+	if(cimg == nil || cimg->screen != nil || cimg->display != d)
+		return;
+	cmask = lookupimage(m);
+	if(cmask != nil && (cmask->screen != nil || cmask->display != d))
+		return;
+
+	if (cmask == nil)
+		new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), cimg->chan, 0, DNofill);
+	else {
+		if(cmask->screen != nil || cmask->display != d)
+			return;
+		new = allocimage(d, Rect(0, 0, Dx(cimg->r), Dy(cimg->r)), RGBA32, 0, DTransparent);
+	}
+	if(new == nil)
+		return;
+	draw(new, new->r, cimg, cmask, cimg->r.min);
+	if(tkwiretap != nil)
+		tkwiretap(t, "replimg", nil, cimg, &cimg->r);
+	if(*ximg != nil)
+		freeimage(*ximg);
+	*ximg = new;
+}
+
+static char*
+tkaddpanelimage(TkTop *t, Draw_Image *di, Image **i)
+{
+	TkPanelimage *pi;
+
+	if (di == H) {
+		*i = 0;
+		return nil;
+	}
+
+	*i = lookupimage(di);
+	if (*i == nil || (*i)->display != t->display)
+		return TkNotwm;
+
+	for (pi = t->panelimages; pi != nil; pi = pi->link) {
+		if (pi->image == di) {
+			pi->ref++;
+			return nil;
+		}
+	}
+
+	pi = malloc(sizeof(TkPanelimage));
+	if (pi == nil)
+		return TkNomem;
+	pi->image = di;
+	D2H(di)->ref++;
+	pi->ref = 1;
+	pi->link = t->panelimages;
+	t->panelimages = pi;
+	return nil;
+}
+
+void
+tkdelpanelimage(TkTop *t, Image *i)
+{
+	TkPanelimage *pi, *prev;
+	int locked;
+
+	if (i == nil)
+		return;
+
+	prev = nil;
+	for (pi = t->panelimages; pi != nil; pi = pi->link) {
+		if (lookupimage(pi->image) == i)
+			break;
+		prev = pi;
+	}
+	if (pi == nil || --pi->ref > 0)
+		return;
+	if (prev)
+		prev->link = pi->link;
+	else
+		t->panelimages = pi->link;
+	if (D2H(pi->image)->ref == 1) {		/* don't bother locking if it's not going away */
+		locked = lockdisplay(t->display);
+		destroy(pi->image);
+		if (locked)
+			unlockdisplay(t->display);
+	}
+		
+	free(pi);
+}
+
+void
+Tk_putimage(void *a)
+{
+	TkTop *t;
+	TkImg *tki;
+	Image *i, *m, *oldi, *oldm;
+	int locked, found, reqid, n;
+	char *words[2];
+	Display *d;
+	F_Tk_putimage *f;
+	void *r;
+	char *name, *e;
+	Tk *tk;
+
+	f = a;
+
+	r = *f->ret;
+	*f->ret = H;
+	destroy(r);
+
+	t = (TkTop*)f->t;
+	if(t == H || D2H(t)->t != fakeTkTop) {
+		retstr(TkNotop, f->ret);
+		return;
+	}
+
+	if(f->i == H) {
+		retstr(TkBadvl, f->ret);
+		return;
+	}
+
+	name = string2c(f->name);
+	lockctxt(t->ctxt);
+	e = nil;
+	found = 0;
+	if(name[0] == '.'){
+		n = getfields(name, words, nelem(words), 1, " ");
+		reqid = -1;
+		if(n > 1){
+			reqid = atoi(words[1]);
+			name = words[0];
+		}
+		if((tk = tklook(t, name, 0)) != nil){
+			if(tk->type == TKchoicebutton){
+				tk = tkfindchoicemenu(tk);
+				if(tk == nil)
+					goto Error;
+			}
+			if(tk->type == TKframe || tk->type == TKmenu){
+				if((tk->flag & Tkwindow) == 0){
+					e = TkNotwm;
+					goto Error;
+				}
+				e = tkputwinimage(tk, f->i, reqid);
+				found = 1;
+			} else
+			if(tk->type == TKpanel){
+				if(n > 1){
+					e = TkBadvl;
+					goto Error;
+				}
+				e = tkaddpanelimage(t, f->i, &i);
+				if(e != nil)
+					goto Error;
+				e = tkaddpanelimage(t, f->m, &m);
+				if(e != nil){
+					tkdelpanelimage(t, i);
+					goto Error;
+				}
+				tkgetpanelimage(tk, &oldi, &oldm);
+				tkdelpanelimage(t, oldi);
+				tkdelpanelimage(t, oldm);
+				tksetpanelimage(tk, i, m);
+				tkdirty(tk);
+				found = 1;
+			}
+		}
+	}
+	if(!found){
+		/* XXX perhaps we shouldn't ever do this if name begins with '.'? */
+		tki = tkname2img(t, name);
+		if(tki == nil) {
+			e = TkBadvl;
+			goto Error;
+		}
+	
+		d = t->display;
+		locked = lockdisplay(d);
+		tkreplimg(t, f->i, f->m, &tki->img);
+		if(locked)
+			unlockdisplay(d);
+	
+		tksizeimage(t->root, tki);
+	}
+Error:
+	unlockctxt(t->ctxt);
+	if(e != nil)
+		retstr(e, f->ret);
+	return;
+}
+
+Draw_Image*
+tkimgcopy(TkTop *t, Image *cimg)
+{
+	Image *new;
+	Display *dp;
+	Draw_Image *i;
+
+	if(cimg == nil)
+		return H;
+
+	dp = t->display;
+	new = allocimage(dp, cimg->r, cimg->chan, cimg->repl, DNofill);
+	if(new == nil)
+		return H;
+	new->clipr = cimg->clipr;
+
+	drawop(new, new->r, cimg, nil, cimg->r.min, S);
+	if(tkwiretap != nil)
+		tkwiretap(t, "imgcopy", nil, cimg, &cimg->r);
+
+	i = mkdrawimage(new, H, t->dd, nil);
+	if(i == H)
+		freeimage(new);
+
+	return i;
+}
+
+void
+Tk_getimage(void *a)
+{
+	Tk *tk;
+	char *n;
+	TkImg *i;
+	TkTop *t;
+	int locked;
+	Display *d;
+	F_Tk_getimage *f;
+	void *r;
+	void (*getimgs)(Tk*, Image**, Image**);
+	Image *image, *mask;
+
+	f = a;
+
+	r = f->ret->t0;
+	f->ret->t0 = H;
+	destroy(r);
+	r = f->ret->t1;
+	f->ret->t1 = H;
+	destroy(r);
+	r = f->ret->t2;
+	f->ret->t2 = H;
+	destroy(r);
+
+	t = (TkTop*)f->t;
+	if(t == H || D2H(t)->t != fakeTkTop) {
+		retstr(TkNotop, &f->ret->t2);
+		return;
+	}
+	d = t->ctxt->display;
+	n = string2c(f->name);
+	lockctxt(t->ctxt);
+	i = tkname2img(t, n);
+	if (i != nil) {
+		image = i->img;
+		mask = nil;
+	} else {
+		tk = tklook(t, n, 0);
+		if (tk == nil || (getimgs = tkmethod[tk->type]->getimgs) == nil) {
+			unlockctxt(t->ctxt);
+			retstr(TkBadvl, &f->ret->t2);
+			return;
+		}
+		getimgs(tk, &image, &mask);
+	}
+	locked = lockdisplay(d);
+	f->ret->t0 = tkimgcopy(t, image);
+	if (mask != nil)
+		f->ret->t1 = tkimgcopy(t, mask);
+	if (locked)
+		unlockdisplay(d);
+	unlockctxt(t->ctxt);
+}
+
+void
+tkfreetop(Heap *h, int swept)
+{
+	TkTop *t;
+	Tk *f;
+	TkImg *i, *nexti;
+	TkVar *v, *nextv;
+	int wgtype;
+	void *r;
+	TkPanelimage *pi, *nextpi;
+
+	t = H2D(TkTop*, h);
+	lockctxt(t->ctxt);
+
+	if(swept) {
+		t->di = H;
+		t->dd = H;
+		t->wreq = H;
+		t->wmctxt = H;
+	}
+
+	t->windows = nil;
+
+	for(f = t->root; f; f = f->siblings) {
+		f->flag |= Tkdestroy;
+		tkdeliver(f, TkDestroy, nil);
+		if(f->destroyed != nil)
+			f->destroyed(f);
+	}
+
+	for(f = t->root; f; f = t->root) {
+		t->root = f->siblings;
+		if(swept)
+			f->flag |= Tkswept;
+		tkfreeobj(f);
+	}
+
+	for(v = t->vars; v; v = nextv) {
+		nextv = v->link;
+		switch(v->type) {
+		default:
+			free(v->value);
+			break;
+		case TkVchan:
+			if(!swept)
+				destroy(v->value);
+			break;
+		}
+		free(v);
+	}
+
+	for (pi = t->panelimages; pi; pi = nextpi) {
+		if (!swept)
+			destroy(pi->image);
+		nextpi = pi->link;
+		free(pi);
+	}
+
+	for(i = t->imgs; i; i = nexti) {
+		if(i->ref != 1)
+			abort();
+		nexti = i->link;
+		tkimgput(i);
+	}
+	/* XXX free images inside widgets */
+
+	for(wgtype = 0; wgtype < TKwidgets; wgtype++)
+		if(t->binds[wgtype])
+			tkfreebind(t->binds[wgtype]);
+
+	unlockctxt(t->ctxt);
+	/* XXX should we leave it locked for this bit? */
+	tkfreectxt(t->ctxt);
+	if(!swept) {
+		r = t->di;
+		t->di = H;
+		destroy(r);
+
+		r = t->dd;
+		t->dd = H;
+		destroy(r);
+
+		r = t->wreq;
+		t->wreq = H;
+		destroy(r);
+
+		r = t->wmctxt;
+		t->wmctxt = H;
+		destroy(r);
+	}
+}
+
+static void
+tktopimagedptr(TkTop *top, Draw_Image *di)
+{
+	if(top->di != H){
+		destroy(top->di);
+		top->di = H;
+	}
+	if(di == H)
+		return;
+	D2H(di)->ref++;
+	top->di = di;
+}
+
+static void
+tkfreewinimage(TkWin *w)
+{
+	destroy(w->di);
+	w->image = nil;
+	w->di = H;
+}
+
+static int
+tksetwindrawimage(Tk *tk, Draw_Image *di)
+{
+	TkWin *tkw;
+	char *name;
+	Image *i;
+	int locked;
+	int same;
+
+	tkw = TKobj(TkWin, tk);
+
+	same = tkw->di == di;
+	if(!same)
+		if(tkw->image != nil)
+			destroy(tkw->di);
+	if(di == H){
+		tkw->di = H;
+		tkw->image = nil;
+		return same;
+	}
+	tkw->di = di;
+	i = lookupimage(di);
+	tkw->image = i;
+
+	locked = lockdisplay(i->display);
+	if(originwindow(i, ZP, i->r.min) == -1)
+		print("tk originwindow failed: %r\n");
+	di->r = DRECT(i->r);
+	di->clipr = DRECT(i->clipr);
+	if(locked)
+		unlockdisplay(i->display);
+
+	if(!same){
+		D2H(di)->ref++;
+		if(tk->name){
+			name = tk->name->name;
+			if(name[0] == '.' && name[1] == '\0')
+				tktopimagedptr(tk->env->top, tkw->di);
+		}
+	}
+	return same;
+}
+
+void
+tkdestroywinimage(Tk *tk)
+{
+	TkWin *tkw;
+	TkTop *top;
+	char *name;
+
+	assert(tk->flag & Tkwindow);
+	tkw = TKobj(TkWin, tk);
+	top = tk->env->top;
+
+	if(tkw->image != nil && !(tk->flag & Tkswept))
+		destroy(tkw->di);
+	tkw->di = H;
+	tkw->image = nil;
+	if(tk->name == nil)
+		name = tkw->cbname;
+	else
+		name = tk->name->name;
+	if(name[0] == '.' && name[1] == '\0' && !(tk->flag & Tkswept))
+		tktopimagedptr(top, H);
+	tkw->reqid++;
+	tkwreq(top, "delete %s", name);
+}
+
+static char*
+tkputwinimage(Tk *tk, Draw_Image *di, int reqid)
+{
+	TkWin *tkw;
+	TkTop *top;
+	Image *i;
+	int bw2, prop, resize;
+	Rectangle req;
+
+	top = tk->env->top;
+	tkw = TKobj(TkWin, tk);
+	i = lookupimage(di);
+	if (i == nil || i->display != top->display)
+		return TkNotwm;
+
+	if(reqid != -1 && reqid < tkw->reqid)
+		return "!request out of date";
+
+	bw2 = 2*tk->borderwidth;
+	req.min.x = tkw->req.x;
+	req.min.y = tkw->req.y;
+	req.max.x = req.min.x + tk->act.width + bw2;
+	req.max.y = req.min.y + tk->act.height + bw2;
+
+	resize = 0;
+	if(eqrect(req, i->r) == 0){
+		/*
+		 * if we'd sent a request and our requested rect has now changed,
+		 * then resend the request (via tkupdatewinsize),
+		 * otherwise accept the new size and repack if necessary
+		 */
+		if(reqid != -1 && tkw->changed){
+			if(tkupdatewinsize(tk))
+				return "!requested size has changed";
+
+		} else if(Dx(req) != Dx(i->r) || Dy(req) != Dy(i->r)){
+			tk->flag |= Tksuspended;
+			tk->act.width = Dx(i->r) - bw2;
+			tk->act.height = Dy(i->r) - bw2;
+			tk->req = tk->act;
+			prop = tk->flag & Tknoprop;
+			tk->flag |= Tknoprop;
+			tkpackqit(tk);
+			tkrunpack(top);
+			tk->flag = (tk->flag & ~Tknoprop) | prop;
+			resize = 1;
+		}
+	}
+	if(reqid == -1)
+		tkw->reqid++;		/* invalidate all buffered requests. */
+	tkw->act = i->r.min;
+	tkw->req = tkw->act;
+	tkw->changed = 0;
+	tk->req.width = Dx(i->r) - bw2;
+	tk->req.height = Dy(i->r) - bw2;
+	tk->act = tk->req;
+	if((tk->flag & Tkmapped) == 0){
+		tk->flag |= Tkmapped;
+		tkdeliver(tk, TkMap, nil);
+	}
+	if(tksetwindrawimage(tk, di) == 0 || resize){
+		tk->dirty = tkrect(tk, 1);
+		tk->flag |= Tkrefresh;
+	}
+	tk->flag &= ~Tksuspended;
+
+	lookupimage(di);			/* make sure limbo image coords correspond correctly */
+	tkupdate(top);
+	return nil;
+}
+
+void
+tkwreq(TkTop *top, char *fmt, ...)
+{
+	char *buf;
+	va_list arg;
+
+	va_start(arg, fmt);
+	buf = vsmprint(fmt, arg);
+	va_end(arg);
+	tktolimbo(top->wreq, buf);
+	free(buf);
+}
+
+int
+tktolimbo(void *var, char *msg)
+{
+	void *ptrs[1];
+	int r;
+
+	if(var==H)
+		return 0;
+	ptrs[0] = H;
+	retstr(msg, (String**) &ptrs[0]);
+	r = csendalt((Channel *)var, ptrs, &Tptr, TkMaxmsgs);
+	return r;
+}
+
+static void
+hexify(char *buf, int n)
+{
+	static char hex[] = "0123456789abcdef";
+	uchar b;
+	char *dp, *fp;
+	fp = buf+n;
+	dp = buf+n*2;
+	*dp-- = '\0';
+	while(fp-- > buf){
+		b = (uchar)*fp;
+		*dp-- = hex[b & 0xf];
+		*dp-- = hex[b >> 4];
+	}
+}
+
+char*
+tkcursorswitch(TkTop *top, Image *i, TkImg *img)
+{
+	Image *ci, *scratch;
+	char *buf;
+	Rectangle r;
+	int n, maxb, nb;
+
+	if(i == nil && img == nil){
+		tktolimbo(top->wreq, "cursor");
+		return nil;
+	}
+
+	if(img != nil){
+		if(img->cursor){
+			tktolimbo(top->wreq, img->cursor);
+			return nil;
+		}
+		i = img->img;
+	}
+	if(i->depth != 1 || Dx(i->r)*Dy(i->r) > 16000 || Dy(i->r)%8 != 0 || Dy(i->r)%2 != 0)
+		return TkBadcursor;
+	/*
+	 * readjust image, inferring hotspot from origin.
+	 */
+	if(i->r.min.x != 0 || i->r.min.y != 0){
+		r.min.x = 0;
+		r.min.y = 0;
+		r.max.x = Dx(i->r);
+		r.max.y = Dy(i->r);
+		scratch = allocimage(i->display, r, GREY1, 0, DNofill);
+		if(scratch == nil)
+			return TkNomem;
+		draw(scratch, r, i, nil, i->r.min);
+		ci = scratch;
+	}else{
+		scratch = nil;
+		ci = i;
+	}
+	nb = ci->r.max.x/8 * ci->r.max.y;
+	maxb = 7 + 12*4 + 2*nb + 1;
+	buf = mallocz(maxb, 0);
+	if(buf == nil)
+		return TkNomem;
+	n = sprint(buf, "cursor %d %d %d %d ", i->r.min.x, i->r.min.y, ci->r.max.x, ci->r.max.y);
+	unloadimage(ci, ci->r, (uchar*)buf+n, maxb-n);
+	hexify(buf+n, nb);
+	tktolimbo(top->wreq, buf);
+	if(img != nil){
+		free(img->cursor);
+		img->cursor = buf;
+	}
+	freeimage(scratch);
+	return nil;
+}
+
+void
+tkcursorset(TkTop *t, Point p)
+{
+	tkwreq(t, "ptr %d %d", p.x, p.y);
+}
--- /dev/null
+++ b/libinterp/validstk.c
@@ -1,0 +1,53 @@
+#include "lib9.h"
+#include "isa.h"
+#include "interp.h"
+
+static int depth;
+
+void
+memchk(void *p, Type *t)
+{
+	Heap *h;
+	int i, j;
+	ulong *v, **base;
+
+	if(depth > 100)
+		return;
+	depth++;
+	base = p;
+	for(i = 0; i < t->np; i++) {
+		for(j = 0; j < 8; j++) {
+			if(t->map[i] & (1<<(7-j))) {
+				v = base[(i*8)+j];
+				if(v != H) {
+					h = D2H(v);
+					hmsize(h);
+					if(h->ref <= 0)
+						abort();
+					if(h->t != nil)
+						memchk(v, h->t);
+				}
+			}
+		}
+	}
+	depth--;
+}
+
+void
+validstk(void)
+{
+	Type *t;
+	Frame *f;
+	uchar *fp;
+
+	fp = R.FP;
+	while(fp != nil) {
+		f = (Frame*)fp;
+		t = f->t;
+		if(t == nil)
+			t = SEXTYPE(f)->reg.TR;
+
+		memchk(f, t);
+		fp = f->fp;
+	}
+}
--- /dev/null
+++ b/libinterp/xec.c
@@ -1,0 +1,1698 @@
+#include <lib9.h>
+#include "isa.h"
+#include "interp.h"
+#include "raise.h"
+#include "pool.h"
+
+REG	R;			/* Virtual Machine registers */
+String	snil;			/* String known to be zero length */
+
+#define Stmp	*((WORD*)(R.FP+NREG*IBY2WD))
+#define Dtmp	*((WORD*)(R.FP+(NREG+2)*IBY2WD))
+
+#define OP(fn)	void fn(void)
+#define B(r)	*((BYTE*)(R.r))
+#define W(r)	*((WORD*)(R.r))
+#define UW(r)	*((UWORD*)(R.r))
+#define F(r)	*((REAL*)(R.r))
+#define V(r)	*((LONG*)(R.r))	
+#define UV(r)	*((ULONG*)(R.r))	
+#define	S(r)	*((String**)(R.r))
+#define	A(r)	*((Array**)(R.r))
+#define	L(r)	*((List**)(R.r))
+#define P(r)	*((WORD**)(R.r))
+#define C(r)	*((Channel**)(R.r))
+#define T(r)	*((void**)(R.r))
+#define JMP(r)	R.PC = *(Inst**)(R.r)
+#define SH(r)	*((SHORT*)(R.r))
+#define SR(r)	*((SREAL*)(R.r))
+
+OP(runt) {}
+OP(negf) { F(d) = -F(s); }
+OP(jmp)  { JMP(d); }
+OP(movpc){ T(d) = &R.M->prog[W(s)]; }
+OP(movm) { memmove(R.d, R.s, W(m)); }
+OP(lea)  { W(d) = (WORD)R.s; }
+OP(movb) { B(d) = B(s); }
+OP(movw) { W(d) = W(s); }
+OP(movf) { F(d) = F(s); }
+OP(movl) { V(d) = V(s); }
+OP(cvtbw){ W(d) = B(s); }
+OP(cvtwb){ B(d) = W(s); }
+OP(cvtrf){ F(d) = SR(s); }
+OP(cvtfr){ SR(d) = F(s); }
+OP(cvtws){ SH(d) = W(s); }
+OP(cvtsw){ W(d) = SH(s); }
+OP(cvtwf){ F(d) = W(s); }
+OP(addb) { B(d) = B(m) + B(s); }
+OP(addw) { W(d) = W(m) + W(s); }
+OP(addl) { V(d) = V(m) + V(s); }
+OP(addf) { F(d) = F(m) + F(s); }
+OP(subb) { B(d) = B(m) - B(s); }
+OP(subw) { W(d) = W(m) - W(s); }
+OP(subl) { V(d) = V(m) - V(s); }
+OP(subf) { F(d) = F(m) - F(s); }
+OP(divb) { B(d) = B(m) / B(s); }
+OP(divw) { W(d) = W(m) / W(s); }
+OP(divl) { V(d) = V(m) / V(s); }
+OP(divf) { F(d) = F(m) / F(s); }
+OP(modb) { B(d) = B(m) % B(s); }
+OP(modw) { W(d) = W(m) % W(s); }
+OP(modl) { V(d) = V(m) % V(s); }
+OP(mulb) { B(d) = B(m) * B(s); }
+OP(mulw) { W(d) = W(m) * W(s); }
+OP(mull) { V(d) = V(m) * V(s); }
+OP(mulf) { F(d) = F(m) * F(s); }
+OP(andb) { B(d) = B(m) & B(s); }
+OP(andw) { W(d) = W(m) & W(s); }
+OP(andl) { V(d) = V(m) & V(s); }
+OP(xorb) { B(d) = B(m) ^ B(s); }
+OP(xorw) { W(d) = W(m) ^ W(s); }
+OP(xorl) { V(d) = V(m) ^ V(s); }
+OP(orb)  { B(d) = B(m) | B(s); }
+OP(orw)  { W(d) = W(m) | W(s); }
+OP(orl)  { V(d) = V(m) | V(s); }
+OP(shlb) { B(d) = B(m) << W(s); }
+OP(shlw) { W(d) = W(m) << W(s); }
+OP(shll) { V(d) = V(m) << W(s); }
+OP(shrb) { B(d) = B(m) >> W(s); }
+OP(shrw) { W(d) = W(m) >> W(s); }
+OP(shrl) { V(d) = V(m) >> W(s); }
+OP(lsrw) { W(d) = UW(m) >> W(s); }
+OP(lsrl) { V(d) = UV(m) >> W(s); }
+OP(beqb) { if(B(s) == B(m)) JMP(d); }
+OP(bneb) { if(B(s) != B(m)) JMP(d); }
+OP(bltb) { if(B(s) <  B(m)) JMP(d); }
+OP(bleb) { if(B(s) <= B(m)) JMP(d); }
+OP(bgtb) { if(B(s) >  B(m)) JMP(d); }
+OP(bgeb) { if(B(s) >= B(m)) JMP(d); }
+OP(beqw) { if(W(s) == W(m)) JMP(d); }
+OP(bnew) { if(W(s) != W(m)) JMP(d); }
+OP(bltw) { if(W(s) <  W(m)) JMP(d); }
+OP(blew) { if(W(s) <= W(m)) JMP(d); }
+OP(bgtw) { if(W(s) >  W(m)) JMP(d); }
+OP(bgew) { if(W(s) >= W(m)) JMP(d); }
+OP(beql) { if(V(s) == V(m)) JMP(d); }
+OP(bnel) { if(V(s) != V(m)) JMP(d); }
+OP(bltl) { if(V(s) <  V(m)) JMP(d); }
+OP(blel) { if(V(s) <= V(m)) JMP(d); }
+OP(bgtl) { if(V(s) >  V(m)) JMP(d); }
+OP(bgel) { if(V(s) >= V(m)) JMP(d); }
+OP(beqf) { if(F(s) == F(m)) JMP(d); }
+OP(bnef) { if(F(s) != F(m)) JMP(d); }
+OP(bltf) { if(F(s) <  F(m)) JMP(d); }
+OP(blef) { if(F(s) <= F(m)) JMP(d); }
+OP(bgtf) { if(F(s) >  F(m)) JMP(d); }
+OP(bgef) { if(F(s) >= F(m)) JMP(d); }
+OP(beqc) { if(stringcmp(S(s), S(m)) == 0) JMP(d); }
+OP(bnec) { if(stringcmp(S(s), S(m)) != 0) JMP(d); }
+OP(bltc) { if(stringcmp(S(s), S(m)) <  0) JMP(d); }
+OP(blec) { if(stringcmp(S(s), S(m)) <= 0) JMP(d); }
+OP(bgtc) { if(stringcmp(S(s), S(m)) >  0) JMP(d); }
+OP(bgec) { if(stringcmp(S(s), S(m)) >= 0) JMP(d); }
+OP(iexit){ error(""); }
+OP(cvtwl){ V(d) = W(s); }
+OP(cvtlw){ W(d) = V(s); }
+OP(cvtlf){ F(d) = V(s); }
+OP(cvtfl)
+{
+	REAL f;
+
+	f = F(s);
+	V(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtfw)
+{
+	REAL f;
+
+	f = F(s);
+	W(d) = f < 0 ? f - .5 : f + .5;
+}
+OP(cvtcl)
+{
+	String *s;
+
+	s = S(s);
+	if(s == H)
+		V(d) = 0;
+	else
+		V(d) = strtoll(string2c(s), nil, 10);
+}
+OP(iexpw)
+{
+	int inv;
+	WORD x, n, r;
+
+	x = W(m);
+	n = W(s);
+	inv = 0;
+	if(n < 0){
+		n = -n;
+		inv = 1;
+	}
+	r = 1;
+	for(;;){
+		if(n&1)
+			r *= x;
+		if((n >>= 1) == 0)
+			break;
+		x *= x;
+	}
+	if(inv)
+		r = 1/r;
+	W(d) = r;
+}
+OP(iexpl)
+{
+	int inv;
+	WORD n;
+	LONG x, r;
+
+	x = V(m);
+	n = W(s);
+	inv = 0;
+	if(n < 0){
+		n = -n;
+		inv = 1;
+	}
+	r = 1;
+	for(;;){
+		if(n&1)
+			r *= x;
+		if((n >>= 1) == 0)
+			break;
+		x *= x;
+	}
+	if(inv)
+		r = 1/r;
+	V(d) = r;
+}
+OP(iexpf)
+{
+	int inv;
+	WORD n;
+	REAL x, r;
+
+	x = F(m);
+	n = W(s);
+	inv = 0;
+	if(n < 0){
+		n = -n;
+		inv = 1;
+	}
+	r = 1;
+	for(;;){
+		if(n&1)
+			r *= x;
+		if((n >>= 1) == 0)
+			break;
+		x *= x;
+	}
+	if(inv)
+		r = 1/r;
+	F(d) = r;
+}
+OP(indx)
+{
+	ulong i;
+	Array *a;
+
+	a = A(s);
+	i = W(d);
+	if(a == H || i >= a->len)
+		error(exBounds);
+	W(m) = (WORD)(a->data+i*a->t->size);
+}
+OP(indw)
+{
+	ulong i;
+	Array *a;
+
+	a = A(s);
+	i = W(d);
+	if(a == H || i >= a->len)
+		error(exBounds);
+	W(m) = (WORD)(a->data+i*sizeof(WORD));
+}
+OP(indf)
+{
+	ulong i;
+	Array *a;
+
+	a = A(s);
+	i = W(d);
+	if(a == H || i >= a->len)
+		error(exBounds);
+	W(m) = (WORD)(a->data+i*sizeof(REAL));
+}
+OP(indl)
+{
+	ulong i;
+	Array *a;
+
+	a = A(s);
+	i = W(d);
+	if(a == H || i >= a->len)
+		error(exBounds);
+	W(m) = (WORD)(a->data+i*sizeof(LONG));
+}
+OP(indb)
+{
+	ulong i;
+	Array *a;
+
+	a = A(s);
+	i = W(d);
+	if(a == H || i >= a->len)
+		error(exBounds);
+	W(m) = (WORD)(a->data+i*sizeof(BYTE));
+}
+OP(movp)
+{
+	Heap *h;
+	WORD *dv, *sv;
+
+	sv = P(s);
+	if(sv != H) {
+		h = D2H(sv);
+		h->ref++;
+		Setmark(h);
+	}
+	dv = P(d);
+	P(d) = sv;
+	destroy(dv);
+}
+OP(movmp)
+{
+	Type *t;
+
+	t = R.M->type[W(m)];
+
+	incmem(R.s, t);
+	if (t->np)
+		freeptrs(R.d, t);
+	memmove(R.d, R.s, t->size);
+}
+OP(new)
+{
+	Heap *h;
+	WORD **wp, *t;
+
+	h = heap(R.M->type[W(s)]);
+	wp = R.d;
+	t = *wp;
+	*wp = H2D(WORD*, h);
+	destroy(t);
+}
+OP(newz)
+{
+	Heap *h;
+	WORD **wp, *t;
+
+	h = heapz(R.M->type[W(s)]);
+	wp = R.d;
+	t = *wp;
+	*wp = H2D(WORD*, h);
+	destroy(t);
+}
+OP(mnewz)
+{
+	Heap *h;
+	WORD **wp, *t;
+	Modlink *ml;
+
+	ml = *(Modlink**)R.s;
+	if(ml == H)
+		error(exModule);
+	h = heapz(ml->type[W(m)]);
+	wp = R.d;
+	t = *wp;
+	*wp = H2D(WORD*, h);
+	destroy(t);
+}
+OP(frame)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+
+	t = R.M->type[W(s)];
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP  = nsp;
+	f->t  = t;
+	f->mr = nil;
+	if (t->np)
+		initmem(t, f);
+	T(d) = f;
+}
+OP(mframe)
+{
+	Type *t;
+	Frame *f;
+	uchar *nsp;
+	Modlink *ml;
+	int o;
+
+	ml = *(Modlink**)R.s;
+	if(ml == H)
+		error(exModule);
+
+	o = W(m);
+	if(o >= 0){
+		if(o >= ml->nlinks)
+			error("invalid mframe");
+		t = ml->links[o].frame;
+	}
+	else
+		t = ml->m->ext[-o-1].frame;
+	nsp = R.SP + t->size;
+	if(nsp >= R.TS) {
+		R.s = t;
+		extend();
+		T(d) = R.s;
+		return;
+	}
+	f = (Frame*)R.SP;
+	R.SP = nsp;
+	f->t = t;
+	f->mr = nil;
+	if (t->np)
+		initmem(t, f);
+	T(d) = f;
+}
+void
+acheck(int tsz, int sz)
+{
+	if(sz < 0)
+		error(exNegsize);
+	/* test for overflow; assumes sz >>> tsz */
+	if((int)(sizeof(Array) + sizeof(Heap) + tsz*sz) < sz && tsz != 0)
+		error(exHeap);
+}
+OP(newa)
+{
+	int sz;
+	Type *t;
+	Heap *h;
+	Array *a, *at, **ap;
+
+	t = R.M->type[W(m)];
+	sz = W(s);
+	acheck(t->size, sz);
+	h = nheap(sizeof(Array) + (t->size*sz));
+	h->t = &Tarray;
+	Tarray.ref++;
+	a = H2D(Array*, h);
+	a->t = t;
+	a->len = sz;
+	a->root = H;
+	a->data = (uchar*)a + sizeof(Array);
+	initarray(t, a);
+
+	ap = R.d;
+	at = *ap;
+	*ap = a;
+	destroy(at);
+}
+OP(newaz)
+{
+	int sz;
+	Type *t;
+	Heap *h;
+	Array *a, *at, **ap;
+
+	t = R.M->type[W(m)];
+	sz = W(s);
+	acheck(t->size, sz);
+	h = nheap(sizeof(Array) + (t->size*sz));
+	h->t = &Tarray;
+	Tarray.ref++;
+	a = H2D(Array*, h);
+	a->t = t;
+	a->len = sz;
+	a->root = H;
+	a->data = (uchar*)a + sizeof(Array);
+	memset(a->data, 0, t->size*sz);
+	initarray(t, a);
+
+	ap = R.d;
+	at = *ap;
+	*ap = a;
+	destroy(at);
+}
+Channel*
+cnewc(Type *t, void (*mover)(void), int len)
+{
+	Heap *h;
+	Channel *c;
+
+	h = heap(&Tchannel);
+	c = H2D(Channel*, h);
+	c->send = malloc(sizeof(Progq));
+	c->recv = malloc(sizeof(Progq));
+	if(c->send == nil || c->recv == nil){
+		free(c->send);
+		free(c->recv);
+		error(exNomem);
+	}
+	c->send->prog = c->recv->prog = nil;
+	c->send->next = c->recv->next = nil;
+	c->mover = mover;
+	c->buf = H;
+	if(len > 0)
+		c->buf = H2D(Array*, heaparray(t, len));
+	c->front = 0;
+	c->size = 0;
+	if(mover == movtmp){
+		c->mid.t = t;
+		t->ref++;
+	}
+	return c;
+}
+Channel*
+newc(Type *t, void (*mover)(void))
+{
+	Channel **cp, *oldc;
+	WORD len;
+
+	len = 0;
+	if(R.m != R.d){
+		len = W(m);
+		if(len < 0)
+			error(exNegsize);
+	}
+	cp = R.d;
+	oldc = *cp;
+	*cp = cnewc(t, mover, len);
+	destroy(oldc);
+	return *cp;
+}
+OP(newcl)  { newc(&Tlong, movl);  }
+OP(newcb)  { newc(&Tbyte, movb);  }
+OP(newcw)  { newc(&Tword, movw);  }
+OP(newcf)  { newc(&Treal, movf);  }
+OP(newcp)  { newc(&Tptr, movp);  }
+OP(newcm)
+{
+	Channel *c;
+	Type *t;
+
+	t = nil;
+	if(R.m != R.d && W(m) > 0)
+		t = dtype(nil, W(s), nil, 0);
+	c = newc(t, movm);
+	c->mid.w = W(s);
+	if(t != nil)
+		freetype(t);
+}
+OP(newcmp)
+{
+	newc(R.M->type[W(s)], movtmp);
+}
+OP(icase)
+{
+	WORD v, *t, *l, d, n, n2;
+
+	v = W(s);
+	t = (WORD*)((WORD)R.d + IBY2WD);
+	n = t[-1];
+	d = t[n*3];
+
+	while(n > 0) {
+		n2 = n >> 1;
+		l = t + n2*3;
+		if(v < l[0]) {
+			n = n2;
+			continue;
+		}
+		if(v >= l[1]) {
+			t = l+3;
+			n -= n2 + 1;
+			continue;
+		}
+		d = l[2];
+		break;
+	}
+	if(R.M->compiled) {
+		R.PC = (Inst*)d;
+		return;
+	}
+	R.PC = R.M->prog + d;
+}
+OP(casel)
+{
+	WORD *t, *l, d, n, n2;
+	LONG v;
+
+	v = V(s);
+	t = (WORD*)((WORD)R.d + 2*IBY2WD);
+	n = t[-2];
+	d = t[n*6];
+
+	while(n > 0) {
+		n2 = n >> 1;
+		l = t + n2*6;
+		if(v < ((LONG*)l)[0]) {
+			n = n2;
+			continue;
+		}
+		if(v >= ((LONG*)l)[1]) {
+			t = l+6;
+			n -= n2 + 1;
+			continue;
+		}
+		d = l[4];
+		break;
+	}
+	if(R.M->compiled) {
+		R.PC = (Inst*)d;
+		return;
+	}
+	R.PC = R.M->prog + d;
+}
+OP(casec)
+{
+	WORD *l, *t, *e, n, n2, r;
+	String *sl, *sh, *sv;
+	
+	sv = S(s);
+	t = (WORD*)((WORD)R.d + IBY2WD);
+	n = t[-1];
+	e = t + n*3;
+	if(n > 2){
+		while(n > 0){
+			n2 = n>>1;
+			l = t + n2*3;
+			sl = (String*)l[0];
+			r = stringcmp(sv, sl);
+			if(r == 0){
+				e = &l[2];
+				break;
+			}
+			if(r < 0){
+				n = n2;
+				continue;
+			}
+			sh = (String*)l[1];
+			if(sh == H || stringcmp(sv, sh) > 0){
+				t = l+3;
+				n -= n2+1;
+				continue;
+			}
+			e = &l[2];
+			break;
+		}
+		t = e;
+	}
+	else{
+		while(t < e) {
+			sl = (String*)t[0];
+			sh = (String*)t[1];
+			if(sh == H) {
+				if(stringcmp(sl, sv) == 0) {
+					t = &t[2];
+					goto found;
+				}
+			}
+			else
+			if(stringcmp(sl, sv) <= 0 && stringcmp(sh, sv) >= 0) {
+				t = &t[2];
+				goto found;
+			}
+			t += 3;
+		}
+	}
+found:
+	if(R.M->compiled) {
+		R.PC = (Inst*)*t;
+		return;
+	}
+	R.PC = R.M->prog + t[0];
+}
+OP(igoto)
+{
+	WORD *t;
+
+	t = (WORD*)((WORD)R.d + (W(s) * IBY2WD));
+	if(R.M->compiled) {
+		R.PC = (Inst*)t[0];
+		return;
+	}
+	R.PC = R.M->prog + t[0];
+}
+OP(call)
+{
+	Frame *f;
+
+	f = T(s);
+	f->lr = R.PC;
+	f->fp = R.FP;
+	R.FP = (uchar*)f;
+	JMP(d);
+}
+OP(spawn)
+{
+	Prog *p;
+
+	p = newprog(currun(), R.M);
+	p->R.PC = *(Inst**)R.d;
+	newstack(p);
+	unframe();
+}
+OP(mspawn)
+{
+	Prog *p;
+	Modlink *ml;
+	int o;
+
+	ml = *(Modlink**)R.d;
+	if(ml == H)
+		error(exModule);
+	if(ml->prog == nil)
+		error(exSpawn);
+	p = newprog(currun(), ml);
+	o = W(m);
+	if(o >= 0)
+		p->R.PC = ml->links[o].u.pc;
+	else
+		p->R.PC = ml->m->ext[-o-1].u.pc;
+	newstack(p);
+	unframe();
+}
+OP(ret)
+{
+	Frame *f;
+	Modlink *m;
+
+	f = (Frame*)R.FP;
+	R.FP = f->fp;
+	if(R.FP == nil) {
+		R.FP = (uchar*)f;
+		error("");
+	}
+	R.SP = (uchar*)f;
+	R.PC = f->lr;
+	m = f->mr;
+
+	if(f->t == nil)
+		unextend(f);
+	else if (f->t->np)
+		freeptrs(f, f->t);
+
+	if(m != nil) {
+		if(R.M->compiled != m->compiled) {
+			R.IC = 1;
+			R.t = 1;
+		}
+		destroy(R.M);
+		R.M = m;
+		R.MP = m->MP;
+	}
+}
+OP(iload)
+{
+	char *n;
+	Import *ldt;
+	Module *m;
+	Modlink *ml, **mp, *t;
+	Heap *h;
+
+	n = string2c(S(s));
+	m = R.M->m;
+	if(m->rt & HASLDT)
+		ldt = m->ldt[W(m)];
+	else{
+		ldt = nil;
+		error("obsolete dis");
+	}
+
+	if(strcmp(n, "$self") == 0) {
+		m->ref++;
+		ml = linkmod(m, ldt, 0);
+		if(ml != H) {
+			ml->MP = R.M->MP;
+			h = D2H(ml->MP);
+			h->ref++;
+			Setmark(h);
+		}
+	}
+	else {
+		m = readmod(n, lookmod(n), 1);
+		ml = linkmod(m, ldt, 1);
+	}
+
+	mp = R.d;
+	t = *mp;
+	*mp = ml;
+	destroy(t);
+}
+OP(mcall)
+{
+	Heap *h;
+	Prog *p;
+	Frame *f;
+	Linkpc *l;
+	Modlink *ml;
+	int o;
+
+	ml = *(Modlink**)R.d;
+	if(ml == H)
+		error(exModule);
+	f = T(s);
+	f->lr = R.PC;
+	f->fp = R.FP;
+	f->mr = R.M;
+
+	R.FP = (uchar*)f;
+	R.M = ml;
+	h = D2H(ml);
+	h->ref++;
+
+	o = W(m);
+	if(o >= 0)
+		l = &ml->links[o].u;
+	else
+		l = &ml->m->ext[-o-1].u;
+	if(ml->prog == nil) {
+		l->runt(f);
+		h->ref--;
+		R.M = f->mr;
+		R.SP = R.FP;
+		R.FP = f->fp;
+		if(f->t == nil)
+			unextend(f);
+		else if (f->t->np)
+			freeptrs(f, f->t);
+		p = currun();
+		if(p->kill != nil)
+			error(p->kill);
+		R.t = 0;
+		return;
+	}
+	R.MP = R.M->MP;
+	R.PC = l->pc;
+	R.t = 1;
+
+	if(f->mr->compiled != R.M->compiled)
+		R.IC = 1;
+}
+OP(lena)
+{
+	WORD l;
+	Array *a;
+
+	a = A(s);
+	l = 0;
+	if(a != H)
+		l = a->len;
+	W(d) = l;
+}
+OP(lenl)
+{
+	WORD l;
+	List *a;
+
+	a = L(s);
+	l = 0;
+	while(a != H) {
+		l++;
+		a = a->tail;
+	}
+	W(d) = l;
+}
+static int
+cgetb(Channel *c, void *v)
+{
+	Array *a;
+	void *w;
+
+	if((a = c->buf) == H)
+		return 0;
+	if(c->size > 0){
+		w = a->data+c->front*a->t->size;
+		c->front++;
+		if(c->front == c->buf->len)
+			c->front = 0;
+		c->size--;
+		R.s = w;
+		R.m = &c->mid;
+		R.d = v;
+		c->mover();
+		if(a->t->np){
+			freeptrs(w, a->t);
+			initmem(a->t, w);
+		}
+		return 1;
+	}
+	return 0;
+}
+static int
+cputb(Channel *c, void *v)
+{
+	Array *a;
+	WORD len, r;
+
+	if((a = c->buf) == H)
+		return 0;
+	len = c->buf->len;
+	if(c->size < len){
+		r = c->front+c->size;
+		if(r >= len)
+			r -= len;
+		c->size++;
+		R.s = v;
+		R.m = &c->mid;
+		R.d = a->data+r*a->t->size;
+		c->mover();
+		return 1;
+	}
+	return 0;
+}
+/*
+int
+cqsize(Progq *q)
+{
+	int n;
+
+	n = 0;
+	for( ; q != nil; q = q->next)
+		if(q->prog != nil)
+			n++;
+	return n;
+}
+*/
+void
+cqadd(Progq **q, Prog *p)
+{
+	Progq *n;
+
+	if((*q)->prog == nil){
+		(*q)->prog = p;
+		return;
+	}
+	n = (Progq*)malloc(sizeof(Progq));
+	if(n == nil)
+		error(exNomem);
+	n->prog = p;
+	n->next = nil;
+	for( ; *q != nil; q = &(*q)->next)
+		;
+	*q = n;
+}
+void
+cqdel(Progq **q)
+{
+	Progq *f;
+
+	if((*q)->next == nil){
+		(*q)->prog = nil;
+		return;
+	}
+	f = *q;
+	*q = f->next;
+	free(f);
+}
+void
+cqdelp(Progq **q, Prog *p)
+{
+	Progq *f;
+
+	if((*q)->next == nil){
+		if((*q)->prog == p)
+			(*q)->prog = nil;
+		return;
+	}
+	for( ; *q != nil; ){
+		if((*q)->prog == p){
+			f = *q;
+			*q = (*q)->next;
+			free(f);
+		}
+		else
+			q = &(*q)->next;
+	}
+}	
+OP(isend)
+{
+	Channel *c;
+ 	Prog *p;
+
+	c = C(d);
+	if(c == H)
+		error(exNilref);
+
+	if((p = c->recv->prog) == nil) {
+		if(c->buf != H && cputb(c, R.s))
+			return;
+		p = delrun(Psend);
+		p->ptr = R.s;
+		p->chan = c;	/* for killprog */
+		R.IC = 1;	
+		R.t = 1;
+		cqadd(&c->send, p);
+		return;
+	}
+
+	if(c->buf != H && c->size > 0)
+		print("non-empty buffer in isend\n");
+
+	cqdel(&c->recv);
+	if(p->state == Palt)
+		altdone(p->R.s, p, c, 1);
+
+	R.m = &c->mid;
+	R.d = p->ptr;
+	p->ptr = nil;
+	c->mover();
+	addrun(p);
+	R.t = 0;
+}
+OP(irecv)
+{
+	Channel *c;
+	Prog *p;
+
+	c = C(s);
+	if(c == H)
+		error(exNilref);
+
+	if((p = c->send->prog) == nil) {
+		if(c->buf != H && cgetb(c, R.d))
+			return;
+		p = delrun(Precv);
+		p->ptr = R.d;
+		p->chan = c;	/* for killprog */
+		R.IC = 1;
+		R.t = 1;
+		cqadd(&c->recv, p);
+		return;
+	}
+
+	if(c->buf != H && c->size != c->buf->len)
+		print("non-full buffer in irecv\n");
+
+	cqdel(&c->send);
+	if(p->state == Palt)
+		altdone(p->R.s, p, c, 0);
+
+	if(c->buf != H){
+		cgetb(c, R.d);
+		cputb(c, p->ptr);
+		p->ptr = nil;
+	}
+	else{
+		R.m = &c->mid;
+		R.s = p->ptr;
+		p->ptr = nil;
+		c->mover();
+	}
+	addrun(p);
+	R.t = 0;
+}
+int
+csendalt(Channel *c, void *ip, Type *t, int len)
+{
+	REG rsav;
+
+	if(c == H)
+		error(exNilref);
+
+	if(c->recv->prog == nil && (c->buf == H || c->size == c->buf->len)){
+		if(c->buf != H){
+			print("csendalt failed\n");
+			freeptrs(ip, t);
+			return 0;
+		}
+		c->buf = H2D(Array*, heaparray(t, len));
+	}
+
+	rsav = R;
+	R.s = ip;
+	R.d = &c;
+	isend();
+	R = rsav;
+	freeptrs(ip, t);
+	return 1;
+}
+
+List*
+cons(ulong size, List **lp)
+{
+	Heap *h;
+	List *lv, *l;
+
+	h = nheap(sizeof(List) + size - sizeof(((List*)0)->data));
+	h->t = &Tlist;
+	Tlist.ref++;
+	l = H2D(List*, h);
+	l->t = nil;
+
+	lv = *lp;
+	if(lv != H) {
+		h = D2H(lv);
+		Setmark(h);
+	}
+	l->tail = lv;
+	*lp = l;
+	return l;
+}
+OP(consb)
+{
+	List *l;
+
+	l = cons(IBY2WD, R.d);
+	*(BYTE*)l->data = B(s);
+}
+OP(consw)
+{
+	List *l;
+
+	l = cons(IBY2WD, R.d);
+	*(WORD*)l->data = W(s);
+}
+OP(consl)
+{
+	List *l;
+
+	l = cons(IBY2LG, R.d);
+	*(LONG*)l->data = V(s);
+}
+OP(consp)
+{
+	List *l;
+	Heap *h;
+	WORD *sv;
+
+	l = cons(IBY2WD, R.d);
+	sv = P(s);
+	if(sv != H) {
+		h = D2H(sv);
+		h->ref++;
+		Setmark(h);
+	}
+	l->t = &Tptr;
+	Tptr.ref++;
+	*(WORD**)l->data = sv;
+}
+OP(consf)
+{
+	List *l;
+
+	l = cons(sizeof(REAL), R.d);
+	*(REAL*)l->data = F(s);
+}
+OP(consm)
+{
+	int v;
+	List *l;
+
+	v = W(m);
+	l = cons(v, R.d);
+	memmove(l->data, R.s, v);
+}
+OP(consmp)
+{
+	List *l;
+	Type *t;
+
+	t = R.M->type[W(m)];
+	l = cons(t->size, R.d);
+	incmem(R.s, t);
+	memmove(l->data, R.s, t->size);
+	l->t = t;
+	t->ref++;
+}
+OP(headb)
+{
+	List *l;
+
+	l = L(s);
+	B(d) = *(BYTE*)l->data;
+}
+OP(headw)
+{
+	List *l;
+
+	l = L(s);
+	W(d) = *(WORD*)l->data;
+}
+OP(headl)
+{
+	List *l;
+
+	l = L(s);
+	V(d) = *(LONG*)l->data;
+}
+OP(headp)
+{
+	List *l;
+
+	l = L(s);
+	R.s = l->data;
+	movp();
+}
+OP(headf)
+{
+	List *l;
+
+	l = L(s);
+	F(d) = *(REAL*)l->data;
+}
+OP(headm)
+{
+	List *l;
+
+	l = L(s);
+	memmove(R.d, l->data, W(m));
+}
+OP(headmp)
+{
+	List *l;
+
+	l = L(s);
+	R.s = l->data;
+	movmp();
+}
+OP(tail)
+{
+	List *l;
+
+	l = L(s);
+	R.s = &l->tail;
+	movp();
+}
+OP(slicea)
+{
+	Type *t;
+	Heap *h;
+	Array *at, *ss, *ds;
+	int v, n, start;
+
+	v = W(m);
+	start = W(s);
+	n = v - start;
+	ds = A(d);
+
+	if(ds == H) {
+		if(n == 0)
+			return;
+		error(exNilref);
+	}
+	if(n < 0 || (ulong)start > ds->len || (ulong)v > ds->len)
+		error(exBounds);
+
+	t = ds->t;
+	h = heap(&Tarray);
+	ss = H2D(Array*, h);
+	ss->len = n;
+	ss->data = ds->data + start*t->size;
+	ss->t = t;
+	t->ref++;
+
+	if(ds->root != H) {			/* slicing a slice */
+		ds = ds->root;
+		h = D2H(ds);
+		h->ref++;
+		at = A(d);
+		A(d) = ss;
+		ss->root = ds;
+		destroy(at);
+	}
+	else {
+		h = D2H(ds);
+		ss->root = ds;
+		A(d) = ss;
+	}
+	Setmark(h);
+}
+OP(slicela)
+{
+	Type *t;
+	int l, dl;
+	Array *ss, *ds;
+	uchar *sp, *dp, *ep;
+
+	ss = A(s);
+	dl = W(m);
+	ds = A(d);
+	if(ss == H)
+		return;
+	if(ds == H)
+		error(exNilref);
+	if(dl < 0 || dl+ss->len > ds->len)
+		error(exBounds);
+
+	t = ds->t;
+	if(t->np == 0) {
+		memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+		return;
+	}
+	sp = ss->data;
+	dp = ds->data+dl*t->size;
+
+	if(dp > sp) {
+		l = ss->len * t->size;
+		sp = ss->data + l;
+		ep = dp + l;
+		while(ep > dp) {
+			ep -= t->size;
+			sp -= t->size;
+			incmem(sp, t);
+			if (t->np)
+				freeptrs(ep, t);
+		}
+	}
+	else {
+		ep = dp + ss->len*t->size;
+		while(dp < ep) {
+			incmem(sp, t);
+			if (t->np)
+				freeptrs(dp, t);
+			dp += t->size;
+			sp += t->size;
+		}
+	}
+	memmove(ds->data+dl*t->size, ss->data, ss->len*t->size);
+}
+OP(alt)
+{
+	R.t = 0;
+	xecalt(1);
+}
+OP(nbalt)
+{
+	xecalt(0);
+}
+OP(tcmp)
+{
+	void *s, *d;
+
+	s = T(s);
+	d = T(d);
+	if(s != H && (d == H || D2H(s)->t != D2H(d)->t))
+		error(exTcheck);
+}
+OP(eclr)
+{
+	/* spare slot */
+}
+OP(badop)
+{
+	error(exOp);
+}
+OP(iraise)
+{
+	void *v;
+	Heap *h;
+	Prog *p;
+
+	p = currun();
+	v = T(s);
+	if(v == H)
+		error(exNilref);
+	p->exval = v;
+	h = D2H(v);
+	h->ref++;
+	if(h->t == &Tstring)
+		error(string2c((String*)v));
+	else
+		error(string2c(*(String**)v));
+}
+OP(mulx)
+{
+	WORD p;
+	LONG r;
+
+	p = Dtmp;
+	r = (LONG)W(m)*(LONG)W(s);
+	if(p >= 0)
+		r <<= p;
+	else
+		r >>= (-p);
+	W(d) = (WORD)r;
+}
+OP(divx)
+{
+	WORD p;
+	LONG s;
+
+	p = Dtmp;
+	s = (LONG)W(m);
+	if(p >= 0)
+		s <<= p;
+	else
+		s >>= (-p);
+	s /= (LONG)W(s);
+	W(d) = (WORD)s;
+}
+OP(cvtxx)
+{
+	WORD p;
+	LONG r;
+
+	p = W(m);
+	r = (LONG)W(s);
+	if(p >= 0)
+		r <<= p;
+	else
+		r >>= (-p);
+	W(d) = (WORD)r;
+}
+OP(mulx0)
+{
+	WORD x, y, p, a;
+	LONG r;
+
+	x = W(m);
+	y = W(s);
+	p = Dtmp;
+	a = Stmp;
+	if(x == 0 || y == 0){
+		W(d) = 0;
+		return;
+	}
+	r = (LONG)x*(LONG)y;
+	if(p >= 0)
+		r <<= p;
+	else
+		r >>= (-p);
+	r /= (LONG)a;
+	W(d) = (WORD)r;
+}
+OP(divx0)
+{
+	WORD x, y, p, b;
+	LONG s;
+
+	x = W(m);
+	y = W(s);
+	p = Dtmp;
+	b = Stmp;
+	if(x == 0){
+		W(d) = 0;
+		return;
+	}
+	s = (LONG)b*(LONG)x;
+	if(p >= 0)
+		s <<= p;
+	else
+		s >>= (-p);
+	s /= (LONG)y;
+	W(d) = (WORD)s;
+}
+OP(cvtxx0)
+{
+	WORD x, p, a;
+	LONG r;
+
+	x = W(s);
+	p = W(m);
+	a = Stmp;
+	if(x == 0){
+		W(d) = 0;
+		return;
+	}
+	r = (LONG)x;
+	if(p >= 0)
+		r <<= p;
+	else
+		r >>= (-p);
+	r /= (LONG)a;
+	W(d) = (WORD)r;
+}
+OP(mulx1)
+{
+	WORD x, y, p, a, v;
+	int vnz, wnz;
+	LONG w, r;
+
+	x = W(m);
+	y = W(s);
+	p = Dtmp;
+	a = Stmp;
+	if(x == 0 || y == 0){
+		W(d) = 0;
+		return;
+	}
+	vnz = p&2;
+	wnz = p&1;
+	p >>= 2;
+	v = 0;
+	w = 0;
+	if(vnz){
+		v = a-1;
+		if(x >= 0 && y < 0 || x < 0 && y >= 0)
+			v = -v;
+	}
+	if(wnz){
+		if((!vnz && (x > 0 && y < 0 || x < 0 && y > 0)) ||
+		(vnz && (x > 0 && y > 0 || x < 0 && y < 0)))
+			w = ((LONG)1<<(-p)) - 1;
+	}
+	r = (LONG)x*(LONG)y + w;
+	if(p >= 0)
+		r <<= p;
+	else
+		r >>= (-p);
+	r += (LONG)v;
+	r /= (LONG)a;
+	W(d) = (WORD)r;
+}
+OP(divx1)
+{
+	WORD x, y, p, b, v;
+	int vnz, wnz;
+	LONG w, s;
+
+	x = W(m);
+	y = W(s);
+	p = Dtmp;
+	b = Stmp;
+	if(x == 0){
+		W(d) = 0;
+		return;
+	}
+	vnz = p&2;
+	wnz = p&1;
+	p >>= 2;
+	v = 0;
+	w = 0;
+	if(vnz){
+		v = 1;
+		if(x >= 0 && y < 0 || x < 0 && y >= 0)
+			v = -v;
+	}
+	if(wnz){
+		if(x <= 0)
+			w = ((LONG)1<<(-p)) - 1;
+	}
+	s = (LONG)b*(LONG)x + w;
+	if(p >= 0)
+		s <<= p;
+	else
+		s >>= (-p);
+	s /= (LONG)y;
+	W(d) = (WORD)s + v;
+}
+OP(cvtxx1)
+{
+	WORD x, p, a, v;
+	int vnz, wnz;
+	LONG w, r;
+
+	x = W(s);
+	p = W(m);
+	a = Stmp;
+	if(x == 0){
+		W(d) = 0;
+		return;
+	}
+	vnz = p&2;
+	wnz = p&1;
+	p >>= 2;
+	v = 0;
+	w = 0;
+	if(vnz){
+		v = a-1;
+		if(x < 0)
+			v = -v;
+	}
+	if(wnz){
+		if(!vnz && x < 0 || vnz && x > 0)
+			w = ((LONG)1<<(-p)) - 1;
+	}
+	r = (LONG)x + w;
+	if(p >= 0)
+		r <<= p;
+	else
+		r >>= (-p);
+	r += (LONG)v;
+	r /= (LONG)a;
+	W(d) = (WORD)r;
+}
+/*
+OP(cvtxx)
+{
+	REAL v;
+
+	v = (REAL)W(s)*F(m);
+	v = v < 0 ? v-0.5: v+0.5;
+	W(d) = (WORD)v;
+}
+*/
+OP(cvtfx)
+{
+	REAL v;
+
+	v = F(s)*F(m);
+	v = v < 0 ? v-0.5: v+0.5;
+	W(d) = (WORD)v;
+}
+OP(cvtxf)
+{
+	F(d) = (REAL)W(s)*F(m);
+}
+
+OP(self)
+{
+	Modlink *ml, **mp, *t;
+	Heap *h;
+
+	ml = R.M;
+	h = D2H(ml);
+	h->ref++;
+	Setmark(h);
+	mp = R.d;
+	t = *mp;
+	*mp = ml;
+	destroy(t);
+}
+
+void
+destroystack(REG *reg)
+{
+	Type *t;
+	Frame *f, *fp;
+	Modlink *m;
+	Stkext *sx;
+	uchar *ex;
+
+	ex = reg->EX;
+	reg->EX = nil;
+	while(ex != nil) {
+		sx = (Stkext*)ex;
+		fp = sx->reg.tos.fr;
+		do {
+			f = (Frame*)reg->FP;
+			if(f == nil)
+				break;
+			reg->FP = f->fp;
+			t = f->t;
+			if(t == nil)
+				t = sx->reg.TR;
+			m = f->mr;
+			if (t->np)
+				freeptrs(f, t);
+			if(m != nil) {
+				destroy(reg->M);
+				reg->M = m;
+			}
+		} while(f != fp);
+		ex = sx->reg.EX;
+		free(sx);
+	}
+	destroy(reg->M);
+	reg->M = H;	/* for devprof */
+}
+
+Prog*
+isave(void)
+{
+	Prog *p;
+
+	p = delrun(Prelease);
+	p->R = R;
+	return p;
+}
+
+void
+irestore(Prog *p)
+{
+	R = p->R;
+	R.IC = 1;
+}
+
+void
+movtmp(void)		/* Used by send & receive */
+{
+	Type *t;
+
+	t = (Type*)W(m);
+
+	incmem(R.s, t);
+	if (t->np)
+		freeptrs(R.d, t);
+	memmove(R.d, R.s, t->size);
+}
+
+extern OP(cvtca);
+extern OP(cvtac);
+extern OP(cvtwc);
+extern OP(cvtcw);
+extern OP(cvtfc);
+extern OP(cvtcf);
+extern OP(insc);
+extern OP(indc);
+extern OP(addc);
+extern OP(lenc);
+extern OP(slicec);
+extern OP(cvtlc);
+
+#include "optab.h"
+
+void
+opinit(void)
+{
+	int i;
+
+	for(i = 0; i < 256; i++)
+		if(optab[i] == nil)
+			optab[i] = badop;
+}
+
+void
+xec(Prog *p)
+{
+	int op;
+
+	R = p->R;
+	R.MP = R.M->MP;
+	R.IC = p->quanta;
+
+	if(p->kill != nil) {
+		char *m;
+		m = p->kill;
+		p->kill = nil;
+		error(m);
+	}
+
+// print("%lux %lux %lux %lux %lux\n", (ulong)&R, R.xpc, R.FP, R.MP, R.PC);
+
+	if(R.M->compiled)
+		comvec();
+	else do {
+		dec[R.PC->add]();
+		op = R.PC->op;
+		R.PC++;
+		optab[op]();
+	} while(--R.IC != 0);
+
+	p->R = R;
+}
--- /dev/null
+++ b/libkern/NOTICE
@@ -1,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/libkern/abort.c
@@ -1,0 +1,7 @@
+#include <lib9.h>
+void
+abort(void)
+{
+	while(*(int*)0)
+		;
+}
--- /dev/null
+++ b/libkern/abs.c
@@ -1,0 +1,17 @@
+#include <lib9.h>
+
+int
+abs(int a)
+{
+	if(a < 0)
+		return -a;
+	return a;
+}
+
+long
+labs(long a)
+{
+	if(a < 0)
+		return -a;
+	return a;
+}
--- /dev/null
+++ b/libkern/atol.c
@@ -1,0 +1,47 @@
+#include <lib9.h>
+
+long
+atol(char *s)
+{
+	long n;
+	int f;
+
+	n = 0;
+	f = 0;
+	while(*s == ' ' || *s == '\t')
+		s++;
+	if(*s == '-' || *s == '+') {
+		if(*s++ == '-')
+			f = 1;
+		while(*s == ' ' || *s == '\t')
+			s++;
+	}
+	if(s[0]=='0' && s[1]){
+		if(s[1]=='x' || s[1]=='X'){
+			s += 2;
+			for(;;){
+				if(*s >= '0' && *s <= '9')
+					n = n*16 + *s++ - '0';
+				else if(*s >= 'a' && *s <= 'f')
+					n = n*16 + *s++ - 'a' + 10;
+				else if(*s >= 'A' && *s <= 'F')
+					n = n*16 + *s++ - 'A' + 10;
+				else
+					break;
+			}
+		} else
+			while(*s >= '0' && *s <= '7')
+				n = n*8 + *s++ - '0';
+	} else
+		while(*s >= '0' && *s <= '9')
+			n = n*10 + *s++ - '0';
+	if(f)
+		n = -n;
+	return n;
+}
+
+atoi(char *s)
+{
+
+	return atol(s);
+}
--- /dev/null
+++ b/libkern/charstod.c
@@ -1,0 +1,80 @@
+#include "lib9.h"
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp).  The last call it makes to f terminates the
+ * scan, so is not a character in the number.  It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+#define ADVANCE *s++ = c; if(s>=e) return NaN(); c = (*f)(vp)
+
+double
+charstod(int(*f)(void*), void *vp)
+{
+	char str[400], *s, *e, *start;
+	int c;
+
+	s = str;
+	e = str + sizeof str - 1;
+	c = (*f)(vp);
+	while(c == ' ' || c == '\t')
+		c = (*f)(vp);
+	if(c == '-' || c == '+'){
+		ADVANCE;
+	}
+	start = s;
+	while(c >= '0' && c <= '9'){
+		ADVANCE;
+	}
+	if(c == '.'){
+		ADVANCE;
+		while(c >= '0' && c <= '9'){
+			ADVANCE;
+		}
+	}
+	if(s > start && (c == 'e' || c == 'E')){
+		ADVANCE;
+		if(c == '-' || c == '+'){
+			ADVANCE;
+		}
+		while(c >= '0' && c <= '9'){
+			ADVANCE;
+		}
+	}else if(s == start && (c == 'i' || c == 'I')){
+		ADVANCE;
+		if(c != 'n' && c != 'N')
+			return NaN();
+		ADVANCE;
+		if(c != 'f' && c != 'F')
+			return NaN();
+		ADVANCE;
+		if(c != 'i' && c != 'I')
+			return NaN();
+		ADVANCE;
+		if(c != 'n' && c != 'N')
+			return NaN();
+		ADVANCE;
+		if(c != 'i' && c != 'I')
+			return NaN();
+		ADVANCE;
+		if(c != 't' && c != 'T')
+			return NaN();
+		ADVANCE;
+		if(c != 'y' && c != 'Y')
+			return NaN();
+		ADVANCE;  /* so caller can back up uniformly */
+		USED(c);
+	}else if(s == str && (c == 'n' || c == 'N')){
+		ADVANCE;
+		if(c != 'a' && c != 'A')
+			return NaN();
+		ADVANCE;
+		if(c != 'n' && c != 'N')
+			return NaN();
+		ADVANCE;  /* so caller can back up uniformly */
+		USED(c);
+	}
+	*s = 0;
+	return strtod(str, &s);
+}
--- /dev/null
+++ b/libkern/cistrcmp.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+int
+cistrcmp(char *s1, char *s2)
+{
+	int c1, c2;
+
+	while(*s1){
+		c1 = *(uchar*)s1++;
+		c2 = *(uchar*)s2++;
+
+		if(c1 == c2)
+			continue;
+
+		if(c1 >= 'A' && c1 <= 'Z')
+			c1 -= 'A' - 'a';
+
+		if(c2 >= 'A' && c2 <= 'Z')
+			c2 -= 'A' - 'a';
+
+		if(c1 != c2)
+			return c1 - c2;
+	}
+	return -*s2;
+}
--- /dev/null
+++ b/libkern/cistrncmp.c
@@ -1,0 +1,27 @@
+#include "lib9.h"
+
+int
+cistrncmp(char *s1, char *s2, int n)
+{
+	int c1, c2;
+
+	while(*s1 && n-- > 0){
+		c1 = *(uchar*)s1++;
+		c2 = *(uchar*)s2++;
+
+		if(c1 == c2)
+			continue;
+
+		if(c1 >= 'A' && c1 <= 'Z')
+			c1 -= 'A' - 'a';
+
+		if(c2 >= 'A' && c2 <= 'Z')
+			c2 -= 'A' - 'a';
+
+		if(c1 != c2)
+			return c1 - c2;
+	}
+	if(n <= 0)
+		return 0;
+	return -*s2;
+}
--- /dev/null
+++ b/libkern/cistrstr.c
@@ -1,0 +1,22 @@
+#include "lib9.h"
+
+char*
+cistrstr(char *s, char *sub)
+{
+	int c, csub, n;
+
+	csub = *sub;
+	if(csub == '\0')
+		return s;
+	if(csub >= 'A' && csub <= 'Z')
+		csub -= 'A' - 'a';
+	sub++;
+	n = strlen(sub);
+	for(; c = *s; s++){
+		if(c >= 'A' && c <= 'Z')
+			c -= 'A' - 'a';
+		if(c == csub && cistrncmp(s+1, sub, n) == 0)
+			return s;
+	}
+	return nil;
+}
--- /dev/null
+++ b/libkern/cleanname.c
@@ -1,0 +1,62 @@
+#include "lib9.h"
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x)	((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+	char *p, *q, *dotdot;
+	int rooted, erasedprefix;
+
+	rooted = name[0] == '/';
+	erasedprefix = 0;
+
+	/*
+	 * invariants:
+	 *	p points at beginning of path element we're considering.
+	 *	q points just past the last path element we wrote (no slash).
+	 *	dotdot points just past the point where .. cannot backtrack
+	 *		any further (no slash).
+	 */
+	p = q = dotdot = name+rooted;
+	while(*p) {
+		if(p[0] == '/')	/* null element */
+			p++;
+		else if(p[0] == '.' && SEP(p[1])) {
+			if(p == name)
+				erasedprefix = 1;
+			p += 1;	/* don't count the separator in case it is nul */
+		} else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+			p += 2;
+			if(q > dotdot) {	/* can backtrack */
+				while(--q > dotdot && *q != '/')
+					;
+			} else if(!rooted) {	/* /.. is / but ./../ is .. */
+				if(q != name)
+					*q++ = '/';
+				*q++ = '.';
+				*q++ = '.';
+				dotdot = q;
+			}
+			if(q == name)
+				erasedprefix = 1;	/* erased entire path via dotdot */
+		} else {	/* real path element */
+			if(q != name+rooted)
+				*q++ = '/';
+			while((*q = *p) != '/' && *q != 0)
+				p++, q++;
+		}
+	}
+	if(q == name)	/* empty string is really ``.'' */
+		*q++ = '.';
+	*q = '\0';
+	if(erasedprefix && name[0] == '#'){	
+		/* this was not a #x device path originally - make it not one now */
+		memmove(name+2, name, strlen(name)+1);
+		name[0] = '.';
+		name[1] = '/';
+	}
+	return name;
+}
--- /dev/null
+++ b/libkern/convD2M.c
@@ -1,0 +1,94 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+uint
+sizeD2M(Dir *d)
+{
+	char *sv[4];
+	int i, ns;
+
+	sv[0] = d->name;
+	sv[1] = d->uid;
+	sv[2] = d->gid;
+	sv[3] = d->muid;
+
+	ns = 0;
+	for(i = 0; i < 4; i++)
+		if(sv[i])
+			ns += strlen(sv[i]);
+
+	return STATFIXLEN + ns;
+}
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+	uchar *p, *ebuf;
+	char *sv[4];
+	int i, ns, nsv[4], ss;
+
+	if(nbuf < BIT16SZ)
+		return 0;
+
+	p = buf;
+	ebuf = buf + nbuf;
+
+	sv[0] = d->name;
+	sv[1] = d->uid;
+	sv[2] = d->gid;
+	sv[3] = d->muid;
+
+	ns = 0;
+	for(i = 0; i < 4; i++){
+		if(sv[i])
+			nsv[i] = strlen(sv[i]);
+		else
+			nsv[i] = 0;
+		ns += nsv[i];
+	}
+
+	ss = STATFIXLEN + ns;
+
+	/* set size befor erroring, so user can know how much is needed */
+	/* note that length excludes count field itself */
+	PBIT16(p, ss-BIT16SZ);
+	p += BIT16SZ;
+
+	if(ss > nbuf)
+		return BIT16SZ;
+
+	PBIT16(p, d->type);
+	p += BIT16SZ;
+	PBIT32(p, d->dev);
+	p += BIT32SZ;
+	PBIT8(p, d->qid.type);
+	p += BIT8SZ;
+	PBIT32(p, d->qid.vers);
+	p += BIT32SZ;
+	PBIT64(p, d->qid.path);
+	p += BIT64SZ;
+	PBIT32(p, d->mode);
+	p += BIT32SZ;
+	PBIT32(p, d->atime);
+	p += BIT32SZ;
+	PBIT32(p, d->mtime);
+	p += BIT32SZ;
+	PBIT64(p, d->length);
+	p += BIT64SZ;
+
+	for(i = 0; i < 4; i++){
+		ns = nsv[i];
+		if(p + ns + BIT16SZ > ebuf)
+			return 0;
+		PBIT16(p, ns);
+		p += BIT16SZ;
+		if(ns)
+			memmove(p, sv[i], ns);
+		p += ns;
+	}
+
+	if(ss != p - buf)
+		return 0;
+
+	return p - buf;
+}
--- /dev/null
+++ b/libkern/convM2D.c
@@ -1,0 +1,93 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+int
+statcheck(uchar *buf, uint nbuf)
+{
+	uchar *ebuf;
+	int i;
+
+	ebuf = buf + nbuf;
+
+	if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
+		return -1;
+
+	buf += STATFIXLEN - 4 * BIT16SZ;
+
+	for(i = 0; i < 4; i++){
+		if(buf + BIT16SZ > ebuf)
+			return -1;
+		buf += BIT16SZ + GBIT16(buf);
+	}
+
+	if(buf != ebuf)
+		return -1;
+
+	return 0;
+}
+
+static char nullstring[] = "";
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+	uchar *p, *ebuf;
+	char *sv[4];
+	int i, ns;
+
+	if(nbuf < STATFIXLEN)
+		return 0; 
+
+	p = buf;
+	ebuf = buf + nbuf;
+
+	p += BIT16SZ;	/* ignore size */
+	d->type = GBIT16(p);
+	p += BIT16SZ;
+	d->dev = GBIT32(p);
+	p += BIT32SZ;
+	d->qid.type = GBIT8(p);
+	p += BIT8SZ;
+	d->qid.vers = GBIT32(p);
+	p += BIT32SZ;
+	d->qid.path = GBIT64(p);
+	p += BIT64SZ;
+	d->mode = GBIT32(p);
+	p += BIT32SZ;
+	d->atime = GBIT32(p);
+	p += BIT32SZ;
+	d->mtime = GBIT32(p);
+	p += BIT32SZ;
+	d->length = GBIT64(p);
+	p += BIT64SZ;
+
+	for(i = 0; i < 4; i++){
+		if(p + BIT16SZ > ebuf)
+			return 0;
+		ns = GBIT16(p);
+		p += BIT16SZ;
+		if(p + ns > ebuf)
+			return 0;
+		if(strs){
+			sv[i] = strs;
+			memmove(strs, p, ns);
+			strs += ns;
+			*strs++ = '\0';
+		}
+		p += ns;
+	}
+
+	if(strs){
+		d->name = sv[0];
+		d->uid = sv[1];
+		d->gid = sv[2];
+		d->muid = sv[3];
+	}else{
+		d->name = nullstring;
+		d->uid = nullstring;
+		d->gid = nullstring;
+		d->muid = nullstring;
+	}
+	
+	return p - buf;
+}
--- /dev/null
+++ b/libkern/convM2S.c
@@ -1,0 +1,314 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+static
+uchar*
+gstring(uchar *p, uchar *ep, char **s)
+{
+	uint n;
+
+	if(p+BIT16SZ > ep)
+		return nil;
+	n = GBIT16(p);
+	p += BIT16SZ - 1;
+	if(p+n+1 > ep)
+		return nil;
+	/* move it down, on top of count, to make room for '\0' */
+	memmove(p, p + 1, n);
+	p[n] = '\0';
+	*s = (char*)p;
+	p += n+1;
+	return p;
+}
+
+static
+uchar*
+gqid(uchar *p, uchar *ep, Qid *q)
+{
+	if(p+QIDSZ > ep)
+		return nil;
+	q->type = GBIT8(p);
+	p += BIT8SZ;
+	q->vers = GBIT32(p);
+	p += BIT32SZ;
+	q->path = GBIT64(p);
+	p += BIT64SZ;
+	return p;
+}
+
+/*
+ * no syntactic checks.
+ * three causes for error:
+ *  1. message size field is incorrect
+ *  2. input buffer too short for its own data (counts too long, etc.)
+ *  3. too many names or qids
+ * gqid() and gstring() return nil if they would reach beyond buffer.
+ * main switch statement checks range and also can fall through
+ * to test at end of routine.
+ */
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+	uchar *p, *ep;
+	uint i, size;
+
+	p = ap;
+	ep = p + nap;
+
+	if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
+		return 0;
+	size = GBIT32(p);
+	p += BIT32SZ;
+
+	if(size < BIT32SZ+BIT8SZ+BIT16SZ)
+		return 0;
+
+	f->type = GBIT8(p);
+	p += BIT8SZ;
+	f->tag = GBIT16(p);
+	p += BIT16SZ;
+
+	switch(f->type)
+	{
+	default:
+		return 0;
+
+	case Tversion:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->msize = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->version);
+		break;
+
+	case Tflush:
+		if(p+BIT16SZ > ep)
+			return 0;
+		f->oldtag = GBIT16(p);
+		p += BIT16SZ;
+		break;
+
+	case Tauth:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->afid = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->uname);
+		if(p == nil)
+			break;
+		p = gstring(p, ep, &f->aname);
+		if(p == nil)
+			break;
+		break;
+
+	case Tattach:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->afid = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->uname);
+		if(p == nil)
+			break;
+		p = gstring(p, ep, &f->aname);
+		if(p == nil)
+			break;
+		break;
+
+	case Twalk:
+		if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->newfid = GBIT32(p);
+		p += BIT32SZ;
+		f->nwname = GBIT16(p);
+		p += BIT16SZ;
+		if(f->nwname > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwname; i++){
+			p = gstring(p, ep, &f->wname[i]);
+			if(p == nil)
+				break;
+		}
+		break;
+
+	case Topen:
+		if(p+BIT32SZ+BIT8SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->mode = GBIT8(p);
+		p += BIT8SZ;
+		break;
+
+	case Tcreate:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->name);
+		if(p == nil)
+			break;
+		if(p+BIT32SZ+BIT8SZ > ep)
+			return 0;
+		f->perm = GBIT32(p);
+		p += BIT32SZ;
+		f->mode = GBIT8(p);
+		p += BIT8SZ;
+		break;
+
+	case Tread:
+		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->offset = GBIT64(p);
+		p += BIT64SZ;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Twrite:
+		if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->offset = GBIT64(p);
+		p += BIT64SZ;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		if(p+f->count > ep)
+			return 0;
+		f->data = (char*)p;
+		p += f->count;
+		break;
+
+	case Tclunk:
+	case Tremove:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Tstat:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Twstat:
+		if(p+BIT32SZ+BIT16SZ > ep)
+			return 0;
+		f->fid = GBIT32(p);
+		p += BIT32SZ;
+		f->nstat = GBIT16(p);
+		p += BIT16SZ;
+		if(p+f->nstat > ep)
+			return 0;
+		f->stat = p;
+		p += f->nstat;
+		break;
+
+/*
+ */
+	case Rversion:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->msize = GBIT32(p);
+		p += BIT32SZ;
+		p = gstring(p, ep, &f->version);
+		break;
+
+	case Rerror:
+		p = gstring(p, ep, &f->ename);
+		break;
+
+	case Rflush:
+		break;
+
+	case Rauth:
+		p = gqid(p, ep, &f->aqid);
+		if(p == nil)
+			break;
+		break;
+
+	case Rattach:
+		p = gqid(p, ep, &f->qid);
+		if(p == nil)
+			break;
+		break;
+
+	case Rwalk:
+		if(p+BIT16SZ > ep)
+			return 0;
+		f->nwqid = GBIT16(p);
+		p += BIT16SZ;
+		if(f->nwqid > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwqid; i++){
+			p = gqid(p, ep, &f->wqid[i]);
+			if(p == nil)
+				break;
+		}
+		break;
+
+	case Ropen:
+	case Rcreate:
+		p = gqid(p, ep, &f->qid);
+		if(p == nil)
+			break;
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->iounit = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Rread:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		if(p+f->count > ep)
+			return 0;
+		f->data = (char*)p;
+		p += f->count;
+		break;
+
+	case Rwrite:
+		if(p+BIT32SZ > ep)
+			return 0;
+		f->count = GBIT32(p);
+		p += BIT32SZ;
+		break;
+
+	case Rclunk:
+	case Rremove:
+		break;
+
+	case Rstat:
+		if(p+BIT16SZ > ep)
+			return 0;
+		f->nstat = GBIT16(p);
+		p += BIT16SZ;
+		if(p+f->nstat > ep)
+			return 0;
+		f->stat = p;
+		p += f->nstat;
+		break;
+
+	case Rwstat:
+		break;
+	}
+
+	if(p==nil || p>ep)
+		return 0;
+	if(ap+size == p)
+		return size;
+	return 0;
+}
--- /dev/null
+++ b/libkern/convS2M.c
@@ -1,0 +1,385 @@
+#include	"lib9.h"
+#include	"fcall.h"
+
+static
+uchar*
+pstring(uchar *p, char *s)
+{
+	uint n;
+
+	if(s == nil){
+		PBIT16(p, 0);
+		p += BIT16SZ;
+		return p;
+	}
+
+	n = strlen(s);
+	PBIT16(p, n);
+	p += BIT16SZ;
+	memmove(p, s, n);
+	p += n;
+	return p;
+}
+
+static
+uchar*
+pqid(uchar *p, Qid *q)
+{
+	PBIT8(p, q->type);
+	p += BIT8SZ;
+	PBIT32(p, q->vers);
+	p += BIT32SZ;
+	PBIT64(p, q->path);
+	p += BIT64SZ;
+	return p;
+}
+
+static
+uint
+stringsz(char *s)
+{
+	if(s == nil)
+		return BIT16SZ;
+
+	return BIT16SZ+strlen(s);
+}
+
+uint
+sizeS2M(Fcall *f)
+{
+	uint n;
+	int i;
+
+	n = 0;
+	n += BIT32SZ;	/* size */
+	n += BIT8SZ;	/* type */
+	n += BIT16SZ;	/* tag */
+
+	switch(f->type)
+	{
+	default:
+		return 0;
+
+	case Tversion:
+		n += BIT32SZ;
+		n += stringsz(f->version);
+		break;
+
+	case Tflush:
+		n += BIT16SZ;
+		break;
+
+	case Tauth:
+		n += BIT32SZ;
+		n += stringsz(f->uname);
+		n += stringsz(f->aname);
+		break;
+
+	case Tattach:
+		n += BIT32SZ;
+		n += BIT32SZ;
+		n += stringsz(f->uname);
+		n += stringsz(f->aname);
+		break;
+
+	case Twalk:
+		n += BIT32SZ;
+		n += BIT32SZ;
+		n += BIT16SZ;
+		for(i=0; i<f->nwname; i++)
+			n += stringsz(f->wname[i]);
+		break;
+
+	case Topen:
+		n += BIT32SZ;
+		n += BIT8SZ;
+		break;
+
+	case Tcreate:
+		n += BIT32SZ;
+		n += stringsz(f->name);
+		n += BIT32SZ;
+		n += BIT8SZ;
+		break;
+
+	case Tread:
+		n += BIT32SZ;
+		n += BIT64SZ;
+		n += BIT32SZ;
+		break;
+
+	case Twrite:
+		n += BIT32SZ;
+		n += BIT64SZ;
+		n += BIT32SZ;
+		n += f->count;
+		break;
+
+	case Tclunk:
+	case Tremove:
+		n += BIT32SZ;
+		break;
+
+	case Tstat:
+		n += BIT32SZ;
+		break;
+
+	case Twstat:
+		n += BIT32SZ;
+		n += BIT16SZ;
+		n += f->nstat;
+		break;
+/*
+ */
+
+	case Rversion:
+		n += BIT32SZ;
+		n += stringsz(f->version);
+		break;
+
+	case Rerror:
+		n += stringsz(f->ename);
+		break;
+
+	case Rflush:
+		break;
+
+	case Rauth:
+		n += QIDSZ;
+		break;
+
+	case Rattach:
+		n += QIDSZ;
+		break;
+
+	case Rwalk:
+		n += BIT16SZ;
+		n += f->nwqid*QIDSZ;
+		break;
+
+	case Ropen:
+	case Rcreate:
+		n += QIDSZ;
+		n += BIT32SZ;
+		break;
+
+	case Rread:
+		n += BIT32SZ;
+		n += f->count;
+		break;
+
+	case Rwrite:
+		n += BIT32SZ;
+		break;
+
+	case Rclunk:
+		break;
+
+	case Rremove:
+		break;
+
+	case Rstat:
+		n += BIT16SZ;
+		n += f->nstat;
+		break;
+
+	case Rwstat:
+		break;
+	}
+	return n;
+}
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+	uchar *p;
+	uint i, size;
+
+	size = sizeS2M(f);
+	if(size == 0)
+		return 0;
+	if(size > nap)
+		return 0;
+
+	p = (uchar*)ap;
+
+	PBIT32(p, size);
+	p += BIT32SZ;
+	PBIT8(p, f->type);
+	p += BIT8SZ;
+	PBIT16(p, f->tag);
+	p += BIT16SZ;
+
+	switch(f->type)
+	{
+	default:
+		return 0;
+
+	case Tversion:
+		PBIT32(p, f->msize);
+		p += BIT32SZ;
+		p = pstring(p, f->version);
+		break;
+
+	case Tflush:
+		PBIT16(p, f->oldtag);
+		p += BIT16SZ;
+		break;
+
+	case Tauth:
+		PBIT32(p, f->afid);
+		p += BIT32SZ;
+		p  = pstring(p, f->uname);
+		p  = pstring(p, f->aname);
+		break;
+
+	case Tattach:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT32(p, f->afid);
+		p += BIT32SZ;
+		p  = pstring(p, f->uname);
+		p  = pstring(p, f->aname);
+		break;
+
+	case Twalk:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT32(p, f->newfid);
+		p += BIT32SZ;
+		PBIT16(p, f->nwname);
+		p += BIT16SZ;
+		if(f->nwname > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwname; i++)
+			p = pstring(p, f->wname[i]);
+		break;
+
+	case Topen:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT8(p, f->mode);
+		p += BIT8SZ;
+		break;
+
+	case Tcreate:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		p = pstring(p, f->name);
+		PBIT32(p, f->perm);
+		p += BIT32SZ;
+		PBIT8(p, f->mode);
+		p += BIT8SZ;
+		break;
+
+	case Tread:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT64(p, f->offset);
+		p += BIT64SZ;
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		break;
+
+	case Twrite:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT64(p, f->offset);
+		p += BIT64SZ;
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		memmove(p, f->data, f->count);
+		p += f->count;
+		break;
+
+	case Tclunk:
+	case Tremove:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		break;
+
+	case Tstat:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		break;
+
+	case Twstat:
+		PBIT32(p, f->fid);
+		p += BIT32SZ;
+		PBIT16(p, f->nstat);
+		p += BIT16SZ;
+		memmove(p, f->stat, f->nstat);
+		p += f->nstat;
+		break;
+/*
+ */
+
+	case Rversion:
+		PBIT32(p, f->msize);
+		p += BIT32SZ;
+		p = pstring(p, f->version);
+		break;
+
+	case Rerror:
+		p = pstring(p, f->ename);
+		break;
+
+	case Rflush:
+		break;
+
+	case Rauth:
+		p = pqid(p, &f->aqid);
+		break;
+
+	case Rattach:
+		p = pqid(p, &f->qid);
+		break;
+
+	case Rwalk:
+		PBIT16(p, f->nwqid);
+		p += BIT16SZ;
+		if(f->nwqid > MAXWELEM)
+			return 0;
+		for(i=0; i<f->nwqid; i++)
+			p = pqid(p, &f->wqid[i]);
+		break;
+
+	case Ropen:
+	case Rcreate:
+		p = pqid(p, &f->qid);
+		PBIT32(p, f->iounit);
+		p += BIT32SZ;
+		break;
+
+	case Rread:
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		memmove(p, f->data, f->count);
+		p += f->count;
+		break;
+
+	case Rwrite:
+		PBIT32(p, f->count);
+		p += BIT32SZ;
+		break;
+
+	case Rclunk:
+		break;
+
+	case Rremove:
+		break;
+
+	case Rstat:
+		PBIT16(p, f->nstat);
+		p += BIT16SZ;
+		memmove(p, f->stat, f->nstat);
+		p += f->nstat;
+		break;
+
+	case Rwstat:
+		break;
+	}
+	if(size != p-ap)
+		return 0;
+	return size;
+}
--- /dev/null
+++ b/libkern/div-arm.s
@@ -1,0 +1,119 @@
+Q	= 0
+N	= 1
+D	= 2
+CC	= 3
+TMP	= 11
+
+TEXT	save<>(SB), 1, $0
+	MOVW	R(Q), 0(FP)
+	MOVW	R(N), 4(FP)
+	MOVW	R(D), 8(FP)
+	MOVW	R(CC), 12(FP)
+
+	MOVW	R(TMP), R(Q)		/* numerator */
+	MOVW	20(FP), R(D)		/* denominator */
+	CMP	$0, R(D)
+	BNE	s1
+	SWI		0
+/*	MOVW	-1(R(D)), R(TMP)	/* divide by zero fault */
+s1:	RET
+
+TEXT	rest<>(SB), 1, $0
+	MOVW	0(FP), R(Q)
+	MOVW	4(FP), R(N)
+	MOVW	8(FP), R(D)
+	MOVW	12(FP), R(CC)
+/*
+ * return to caller
+ * of rest<>
+ */
+	MOVW	0(R13), R14
+	ADD	$20, R13
+	B	(R14)
+
+TEXT	div<>(SB), 1, $0
+	MOVW	$32, R(CC)
+/*
+ * skip zeros 8-at-a-time
+ */
+e1:
+	AND.S	$(0xff<<24),R(Q), R(N)
+	BNE	e2
+	SLL	$8, R(Q)
+	SUB.S	$8, R(CC)
+	BNE	e1
+	RET
+e2:
+	MOVW	$0, R(N)
+
+loop:
+/*
+ * shift R(N||Q) left one
+ */
+	SLL	$1, R(N)
+	CMP	$0, R(Q)
+	ORR.LT	$1, R(N)
+	SLL	$1, R(Q)
+
+/*
+ * compare numerator to denominator
+ * if less, subtract and set quotent bit
+ */
+	CMP	R(D), R(N)
+	ORR.HS	$1, R(Q)
+	SUB.HS	R(D), R(N)
+	SUB.S	$1, R(CC)
+	BNE	loop
+	RET
+
+TEXT	_div(SB), 1, $16
+	BL	save<>(SB)
+	CMP	$0, R(Q)
+	BGE	d1
+	RSB	$0, R(Q), R(Q)
+	CMP	$0, R(D)
+	BGE	d2
+	RSB	$0, R(D), R(D)
+d0:
+	BL	div<>(SB)		/* none/both neg */
+	MOVW	R(Q), R(TMP)
+	B	out
+d1:
+	CMP	$0, R(D)
+	BGE	d0
+	RSB	$0, R(D), R(D)
+d2:
+	BL	div<>(SB)		/* one neg */
+	RSB	$0, R(Q), R(TMP)
+	B	out
+
+TEXT	_mod(SB), 1, $16
+	BL	save<>(SB)
+	CMP	$0, R(D)
+	RSB.LT	$0, R(D), R(D)
+	CMP	$0, R(Q)
+	BGE	m1
+	RSB	$0, R(Q), R(Q)
+	BL	div<>(SB)		/* neg numerator */
+	RSB	$0, R(N), R(TMP)
+	B	out
+m1:
+	BL	div<>(SB)		/* pos numerator */
+	MOVW	R(N), R(TMP)
+	B	out
+
+TEXT	_divu(SB), 1, $16
+	BL	save<>(SB)
+	BL	div<>(SB)
+	MOVW	R(Q), R(TMP)
+	B	out
+
+TEXT	_modu(SB), 1, $16
+	BL	save<>(SB)
+	BL	div<>(SB)
+	MOVW	R(N), R(TMP)
+	B	out
+
+out:
+	BL	rest<>(SB)
+	B	out
--- /dev/null
+++ b/libkern/div-thumb.s
@@ -1,0 +1,119 @@
+Q	= 0
+N	= 1
+D	= 2
+CC	= 3
+TMP	= 11
+
+TEXT	save<>(SB), 1, $0
+	MOVW	R(Q), 0(FP)
+	MOVW	R(N), 4(FP)
+	MOVW	R(D), 8(FP)
+	MOVW	R(CC), 12(FP)
+
+	MOVW	R(TMP), R(Q)		/* numerator */
+	MOVW	20(FP), R(D)		/* denominator */
+	CMP	$0, R(D)
+	BNE	s1
+	SWI		0
+/*	MOVW	-1(R(D)), R(TMP)	/* divide by zero fault */
+s1:	RET
+
+TEXT	rest<>(SB), 1, $0
+	MOVW	0(FP), R(Q)
+	MOVW	4(FP), R(N)
+	MOVW	8(FP), R(D)
+	MOVW	12(FP), R(CC)
+/*
+ * return to caller
+ * of rest<>
+ */
+	MOVW	0(R13), R14
+	ADD	$20, R13
+	B	(R14)
+
+TEXT	div<>(SB), 1, $0
+	MOVW	$32, R(CC)
+/*
+ * skip zeros 8-at-a-time
+ */
+e1:
+	AND.S	$(0xff<<24),R(Q), R(N)
+	BNE	e2
+	SLL	$8, R(Q)
+	SUB.S	$8, R(CC)
+	BNE	e1
+	RET
+e2:
+	MOVW	$0, R(N)
+
+loop:
+/*
+ * shift R(N||Q) left one
+ */
+	SLL	$1, R(N)
+	CMP	$0, R(Q)
+	ORR.LT	$1, R(N)
+	SLL	$1, R(Q)
+
+/*
+ * compare numerator to denominator
+ * if less, subtract and set quotent bit
+ */
+	CMP	R(D), R(N)
+	ORR.HS	$1, R(Q)
+	SUB.HS	R(D), R(N)
+	SUB.S	$1, R(CC)
+	BNE	loop
+	RET
+
+TEXT	_div(SB), 1, $16
+	BL	save<>(SB)
+	CMP	$0, R(Q)
+	BGE	d1
+	RSB	$0, R(Q), R(Q)
+	CMP	$0, R(D)
+	BGE	d2
+	RSB	$0, R(D), R(D)
+d0:
+	BL	div<>(SB)		/* none/both neg */
+	MOVW	R(Q), R(TMP)
+	B	out
+d1:
+	CMP	$0, R(D)
+	BGE	d0
+	RSB	$0, R(D), R(D)
+d2:
+	BL	div<>(SB)		/* one neg */
+	RSB	$0, R(Q), R(TMP)
+	B	out
+
+TEXT	_mod(SB), 1, $16
+	BL	save<>(SB)
+	CMP	$0, R(D)
+	RSB.LT	$0, R(D), R(D)
+	CMP	$0, R(Q)
+	BGE	m1
+	RSB	$0, R(Q), R(Q)
+	BL	div<>(SB)		/* neg numerator */
+	RSB	$0, R(N), R(TMP)
+	B	out
+m1:
+	BL	div<>(SB)		/* pos numerator */
+	MOVW	R(N), R(TMP)
+	B	out
+
+TEXT	_divu(SB), 1, $16
+	BL	save<>(SB)
+	BL	div<>(SB)
+	MOVW	R(Q), R(TMP)
+	B	out
+
+TEXT	_modu(SB), 1, $16
+	BL	save<>(SB)
+	BL	div<>(SB)
+	MOVW	R(N), R(TMP)
+	B	out
+
+out:
+	BL	rest<>(SB)
+	B	out
--- /dev/null
+++ b/libkern/dofmt.c
@@ -1,0 +1,531 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted  */
+int
+dofmt(Fmt *f, char *fmt)
+{
+	Rune rune, *rt, *rs;
+	int r;
+	char *t, *s;
+	int n, nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = f->to;
+			rs = f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself)
+					fmt++;
+				else{
+					fmt += chartorune(&rune, fmt);
+					r = rune;
+				}
+				FMTRCHAR(f, rt, rs, r);
+			}
+			fmt++;
+			f->nfmt += rt - (Rune *)f->to;
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = f->to;
+			s = f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself){
+					FMTCHAR(f, t, s, r);
+					fmt++;
+				}else{
+					n = chartorune(&rune, fmt);
+					if(t + n > s){
+						t = _fmtflush(f, t, n);
+						if(t != nil)
+							s = f->stop;
+						else
+							return -1;
+					}
+					while(n--)
+						*t++ = *fmt++;
+				}
+			}
+			fmt++;
+			f->nfmt += t - (char *)f->to;
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = _fmtdispatch(f, fmt, 0);
+		if(fmt == nil)
+			return -1;
+	}
+}
+
+void *
+_fmtflush(Fmt *f, void *t, int len)
+{
+	if(f->runes)
+		f->nfmt += (Rune*)t - (Rune*)f->to;
+	else
+		f->nfmt += (char*)t - (char *)f->to;
+	f->to = t;
+	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+		f->stop = f->to;
+		return nil;
+	}
+	return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width charactes
+ */
+int
+_fmtpad(Fmt *f, int n)
+{
+	char *t, *s;
+	int i;
+
+	t = f->to;
+	s = f->stop;
+	for(i = 0; i < n; i++)
+		FMTCHAR(f, t, s, ' ');
+	f->nfmt += t - (char *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+_rfmtpad(Fmt *f, int n)
+{
+	Rune *t, *s;
+	int i;
+
+	t = f->to;
+	s = f->stop;
+	for(i = 0; i < n; i++)
+		FMTRCHAR(f, t, s, ' ');
+	f->nfmt += t - (Rune *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+_fmtcpy(Fmt *f, void *vm, int n, int sz)
+{
+	Rune *rt, *rs, r;
+	char *t, *s, *m, *me;
+	ulong fl;
+	int nc, w;
+
+	m = vm;
+	me = m + sz;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = f->to;
+		rs = f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRCHAR(f, rt, rs, r);
+		}
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(m < me)
+			return -1;
+		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+			return -1;
+		t = f->to;
+		s = f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+_fmtrcpy(Fmt *f, void *vm, int n)
+{
+	Rune r, *m, *me, *rt, *rs;
+	char *t, *s;
+	ulong fl;
+	int w;
+
+	m = vm;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = f->to;
+		rs = f->stop;
+		for(me = m + n; m < me; m++)
+			FMTRCHAR(f, rt, rs, *m);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
+			return -1;
+		t = f->to;
+		s = f->stop;
+		for(me = m + n; m < me; m++){
+			r = *m;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+/* fmt out one character */
+int
+_charfmt(Fmt *f)
+{
+	char x[1];
+
+	x[0] = va_arg(f->args, int);
+	f->prec = 1;
+	return _fmtcpy(f, x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+_runefmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = va_arg(f->args, int);
+	return _fmtrcpy(f, x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+	int p, i;
+	if(!s)
+		return _fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(i = 0; i < p; i++)
+			if(s[i] == 0)
+				break;
+		return _fmtcpy(f, s, utfnlen(s, i), i);	/* BUG?: won't print a partial rune at end */
+	}
+
+	return _fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+_strfmt(Fmt *f)
+{
+	char *s;
+
+	s = va_arg(f->args, char *);
+	return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+	Rune *e;
+	int n, p;
+
+	if(!s)
+		return _fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(n = 0; n < p; n++)
+			if(s[n] == 0)
+				break;
+	}else{
+		for(e = s; *e; e++)
+			;
+		n = e - s;
+	}
+	return _fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+_runesfmt(Fmt *f)
+{
+	Rune *s;
+
+	s = va_arg(f->args, Rune *);
+	return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+_percentfmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = f->r;
+	f->prec = 1;
+	return _fmtrcpy(f, x, 1);
+}
+
+/* fmt an integer */
+int
+_ifmt(Fmt *f)
+{
+	char buf[70], *p, *conv;
+	uvlong vu;
+	ulong u;
+	int neg, base, i, n, fl, w, isv;
+
+	neg = 0;
+	fl = f->flags;
+	isv = 0;
+	vu = 0;
+	u = 0;
+	if(f->r == 'p'){
+		u = (ulong)va_arg(f->args, void*);
+		f->r = 'x';
+		fl |= FmtUnsigned;
+	}else if(fl & FmtVLong){
+		isv = 1;
+		if(fl & FmtUnsigned)
+			vu = va_arg(f->args, uvlong);
+		else
+			vu = va_arg(f->args, vlong);
+	}else if(fl & FmtLong){
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, ulong);
+		else
+			u = va_arg(f->args, long);
+	}else if(fl & FmtByte){
+		if(fl & FmtUnsigned)
+			u = (uchar)va_arg(f->args, int);
+		else
+			u = (char)va_arg(f->args, int);
+	}else if(fl & FmtShort){
+		if(fl & FmtUnsigned)
+			u = (ushort)va_arg(f->args, int);
+		else
+			u = (short)va_arg(f->args, int);
+	}else{
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, uint);
+		else
+			u = va_arg(f->args, int);
+	}
+	conv = "0123456789abcdef";
+	switch(f->r){
+	case 'd':
+		base = 10;
+		break;
+	case 'x':
+		base = 16;
+		break;
+	case 'X':
+		base = 16;
+		conv = "0123456789ABCDEF";
+		break;
+	case 'b':
+		base = 2;
+		break;
+	case 'o':
+		base = 8;
+		break;
+	default:
+		return -1;
+	}
+	if(!(fl & FmtUnsigned)){
+		if(isv && (vlong)vu < 0){
+			vu = -(vlong)vu;
+			neg = 1;
+		}else if(!isv && (long)u < 0){
+			u = -(long)u;
+			neg = 1;
+		}
+	}
+	p = buf + sizeof buf - 1;
+	n = 0;
+	if(isv){
+		while(vu){
+			i = vu % base;
+			vu /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}else{
+		while(u){
+			i = u % base;
+			u /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}
+	if(n == 0){
+		*p-- = '0';
+		n = 1;
+	}
+	for(w = f->prec; n < w && p > buf+3; n++)
+		*p-- = '0';
+	if(neg || (fl & (FmtSign|FmtSpace)))
+		n++;
+	if(fl & FmtSharp){
+		if(base == 16)
+			n += 2;
+		else if(base == 8){
+			if(p[1] == '0')
+				fl &= ~FmtSharp;
+			else
+				n++;
+		}
+	}
+	if((fl & FmtZero) && !(fl & FmtLeft)){
+		for(w = f->width; n < w && p > buf+3; n++)
+			*p-- = '0';
+		f->width = 0;
+	}
+	if(fl & FmtSharp){
+		if(base == 16)
+			*p-- = f->r;
+		if(base == 16 || base == 8)
+			*p-- = '0';
+	}
+	if(neg)
+		*p-- = '-';
+	else if(fl & FmtSign)
+		*p-- = '+';
+	else if(fl & FmtSpace)
+		*p-- = ' ';
+	f->flags &= ~FmtPrec;
+	return _fmtcpy(f, p + 1, n, n);
+}
+
+int
+_countfmt(Fmt *f)
+{
+	void *p;
+	ulong fl;
+
+	fl = f->flags;
+	p = va_arg(f->args, void*);
+	if(fl & FmtVLong){
+		*(vlong*)p = f->nfmt;
+	}else if(fl & FmtLong){
+		*(long*)p = f->nfmt;
+	}else if(fl & FmtByte){
+		*(char*)p = f->nfmt;
+	}else if(fl & FmtShort){
+		*(short*)p = f->nfmt;
+	}else{
+		*(int*)p = f->nfmt;
+	}
+	return 0;
+}
+
+int
+_flagfmt(Fmt *f)
+{
+	switch(f->r){
+	case ',':
+		f->flags |= FmtComma;
+		break;
+	case '-':
+		f->flags |= FmtLeft;
+		break;
+	case '+':
+		f->flags |= FmtSign;
+		break;
+	case '#':
+		f->flags |= FmtSharp;
+		break;
+	case ' ':
+		f->flags |= FmtSpace;
+		break;
+	case 'u':
+		f->flags |= FmtUnsigned;
+		break;
+	case 'h':
+		if(f->flags & FmtShort)
+			f->flags |= FmtByte;
+		f->flags |= FmtShort;
+		break;
+	case 'l':
+		if(f->flags & FmtLong)
+			f->flags |= FmtVLong;
+		f->flags |= FmtLong;
+		break;
+	}
+	return 1;
+}
+
+/* default error format */
+int
+_badfmt(Fmt *f)
+{
+	char x[3];
+
+	x[0] = '%';
+	x[1] = f->r;
+	x[2] = '%';
+	f->prec = 3;
+	_fmtcpy(f, x, 3, 3);
+	return 0;
+}
--- /dev/null
+++ b/libkern/exp.c
@@ -1,0 +1,39 @@
+/*
+	exp returns the exponential function of its
+	floating-point argument.
+
+	The coefficients are #1069 from Hart and Cheney. (22.35D)
+*/
+
+#include <lib9.h>
+
+#define	p0  .2080384346694663001443843411e7
+#define	p1  .3028697169744036299076048876e5
+#define	p2  .6061485330061080841615584556e2
+#define	q0  .6002720360238832528230907598e7
+#define	q1  .3277251518082914423057964422e6
+#define	q2  .1749287689093076403844945335e4
+#define	log2e  1.4426950408889634073599247
+#define	sqrt2  1.4142135623730950488016887
+#define	maxf  10000
+
+double
+exp(double arg)
+{
+	double fract, temp1, temp2, xsq;
+	int ent;
+
+	if(arg == 0)
+		return 1;
+	if(arg < -maxf)
+		return 0;
+	if(arg > maxf)
+		return Inf(1);
+	arg *= log2e;
+	ent = floor(arg);
+	fract = (arg-ent) - 0.5;
+	xsq = fract*fract;
+	temp1 = ((p2*xsq+p1)*xsq+p0)*fract;
+	temp2 = ((xsq+q2)*xsq+q1)*xsq + q0;
+	return ldexp(sqrt2*(temp2+temp1)/(temp2-temp1), ent);
+}
--- /dev/null
+++ b/libkern/fcallfmt.c
@@ -1,0 +1,246 @@
+/*
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <lib9.h>
+#include "fcall.h"
+
+static uint dumpsome(char*, char*, char*, long);
+static void fdirconv(char*, char*, Dir*);
+static char *qidtype(char*, uchar);
+
+#define	QIDFMT	"(%.16llux %lud %s)"
+
+int
+fcallfmt(Fmt *fmt)
+{
+	Fcall *f;
+	int fid, type, tag, i;
+	char buf[512], tmp[200];
+	char *p, *e;
+	Dir *d;
+	Qid *q;
+
+	e = buf+sizeof(buf);
+	f = va_arg(fmt->args, Fcall*);
+	type = f->type;
+	fid = f->fid;
+	tag = f->tag;
+	switch(type){
+	case Tversion:	/* 100 */
+		seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+		break;
+	case Rversion:
+		seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
+		break;
+	case Tauth:	/* 102 */
+		seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
+			f->afid, f->uname, f->aname);
+		break;
+	case Rauth:
+		seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
+			f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
+		break;
+	case Tattach:	/* 104 */
+		seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
+			fid, f->afid, f->uname, f->aname);
+		break;
+	case Rattach:
+		seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
+			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
+		break;
+	case Rerror:	/* 107; 106 (Terror) illegal */
+		seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
+		break;
+	case Tflush:	/* 108 */
+		seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
+		break;
+	case Rflush:
+		seprint(buf, e, "Rflush tag %ud", tag);
+		break;
+	case Twalk:	/* 110 */
+		p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
+		if(f->nwname <= MAXWELEM)
+			for(i=0; i<f->nwname; i++)
+				p = seprint(p, e, "%d:%s ", i, f->wname[i]);
+		break;
+	case Rwalk:
+		p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
+		if(f->nwqid <= MAXWELEM)
+			for(i=0; i<f->nwqid; i++){
+				q = &f->wqid[i];
+				p = seprint(p, e, "%d:" QIDFMT " ", i,
+					q->path, q->vers, qidtype(tmp, q->type));
+			}
+		break;
+	case Topen:	/* 112 */
+		seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
+		break;
+	case Ropen:
+		seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud ", tag,
+			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+		break;
+	case Tcreate:	/* 114 */
+		seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode);
+		break;
+	case Rcreate:
+		seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
+			f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
+		break;
+	case Tread:	/* 116 */
+		seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
+			tag, fid, f->offset, f->count);
+		break;
+	case Rread:
+		p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
+			dumpsome(p, e, f->data, f->count);
+		break;
+	case Twrite:	/* 118 */
+		p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
+			tag, fid, f->offset, f->count);
+		dumpsome(p, e, f->data, f->count);
+		break;
+	case Rwrite:
+		seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
+		break;
+	case Tclunk:	/* 120 */
+		seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
+		break;
+	case Rclunk:
+		seprint(buf, e, "Rclunk tag %ud", tag);
+		break;
+	case Tremove:	/* 122 */
+		seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
+		break;
+	case Rremove:
+		seprint(buf, e, "Rremove tag %ud", tag);
+		break;
+	case Tstat:	/* 124 */
+		seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
+		break;
+	case Rstat:
+		p = seprint(buf, e, "Rstat tag %ud ", tag);
+		if(f->nstat > sizeof tmp)
+			seprint(p, e, " stat(%d bytes)", f->nstat);
+		else{
+			d = (Dir*)tmp;
+			convM2D(f->stat, f->nstat, d, (char*)(d+1));
+			seprint(p, e, " stat ");
+			fdirconv(p+6, e, d);
+		}
+		break;
+	case Twstat:	/* 126 */
+		p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
+		if(f->nstat > sizeof tmp)
+			seprint(p, e, " stat(%d bytes)", f->nstat);
+		else{
+			d = (Dir*)tmp;
+			convM2D(f->stat, f->nstat, d, (char*)(d+1));
+			seprint(p, e, " stat ");
+			fdirconv(p+6, e, d);
+		}
+		break;
+	case Rwstat:
+		seprint(buf, e, "Rwstat tag %ud", tag);
+		break;
+	default:
+		seprint(buf, e,  "unknown type %d", type);
+	}
+	return fmtstrcpy(fmt, buf);
+}
+
+static char*
+qidtype(char *s, uchar t)
+{
+	char *p;
+
+	p = s;
+	if(t & QTDIR)
+		*p++ = 'd';
+	if(t & QTAPPEND)
+		*p++ = 'a';
+	if(t & QTEXCL)
+		*p++ = 'l';
+	if(t & QTAUTH)
+		*p++ = 'A';
+	*p = '\0';
+	return s;
+}
+
+int
+dirfmt(Fmt *fmt)
+{
+	char buf[160];
+
+	fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
+	return fmtstrcpy(fmt, buf);
+}
+
+static void
+fdirconv(char *buf, char *e, Dir *d)
+{
+	char tmp[16];
+
+	seprint(buf, e, "'%s' '%s' '%s' '%s' "
+		"q " QIDFMT " m %#luo "
+		"at %ld mt %ld l %lld "
+		"t %d d %d",
+			d->name, d->uid, d->gid, d->muid,
+			d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
+			d->atime, d->mtime, d->length,
+			d->type, d->dev);
+}
+
+/*
+ * dump out count (or DUMPL, if count is bigger) bytes from
+ * buf to ans, as a string if they are all printable,
+ * else as a series of hex bytes
+ */
+#define DUMPL 64
+
+static uint
+dumpsome(char *ans, char *e, char *buf, long count)
+{
+	int i, printable;
+	char *p;
+
+	if(buf == nil){
+		seprint(ans, e, "<no data>");
+		return strlen(ans);
+	}
+	printable = 1;
+	if(count > DUMPL)
+		count = DUMPL;
+	for(i=0; i<count && printable; i++)
+		if((buf[i]<32 && buf[i] !='\n' && buf[i] !='\t') || (uchar)buf[i]>127)
+			printable = 0;
+	p = ans;
+	*p++ = '\'';
+	if(printable){
+		if(count > e-p-2)
+			count = e-p-2;
+		memmove(p, buf, count);
+		p += count;
+	}else{
+		if(2*count > e-p-2)
+			count = (e-p-2)/2;
+		for(i=0; i<count; i++){
+			if(i>0 && i%4==0)
+				*p++ = ' ';
+			sprint(p, "%2.2ux", buf[i]);
+			p += 2;
+		}
+	}
+	*p++ = '\'';
+	*p = 0;
+	return p - ans;
+}
--- /dev/null
+++ b/libkern/floor.c
@@ -1,0 +1,26 @@
+#include <lib9.h>
+/*
+ * floor and ceil-- greatest integer <= arg
+ * (resp least >=)
+ */
+
+double
+floor(double d)
+{
+	double fract;
+
+	if(d < 0) {
+		fract = modf(-d, &d);
+		if(fract != 0.0)
+			d += 1;
+		d = -d;
+	} else
+		modf(d, &d);
+	return d;
+}
+
+double
+ceil(double d)
+{
+	return -floor(-d);
+}
--- /dev/null
+++ b/libkern/fmt.c
@@ -1,0 +1,188 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+enum
+{
+	Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+	int	c;
+	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+struct
+{
+	/* lock by calling _fmtlock, _fmtunlock */
+	int	nfmt;
+	Convfmt	fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+	' ',	_flagfmt,
+	'#',	_flagfmt,
+	'%',	_percentfmt,
+	'+',	_flagfmt,
+	',',	_flagfmt,
+	'-',	_flagfmt,
+	'C',	_runefmt,
+	'S',	_runesfmt,
+	'X',	_ifmt,
+	'b',	_ifmt,
+	'c',	_charfmt,
+	'd',	_ifmt,
+	'h',	_flagfmt,
+	'l',	_flagfmt,
+	'n',	_countfmt,
+	'o',	_ifmt,
+	'p',	_ifmt,
+	'r',	errfmt,
+	's',	_strfmt,
+	'u',	_flagfmt,
+	'x',	_ifmt,
+	0,	nil,
+};
+
+int	(*doquote)(int);
+
+static Fmts
+fmtfmt(int c)
+{
+	Convfmt *p, *ep;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c)
+			return p->fmt;
+
+	/* is this a predefined format char? */
+	for(p=knownfmt; p->c; p++)
+		if(p->c == c){
+			/* no need to lock; fmtinstall is idempotent */
+			fmtinstall(p->c, p->fmt);
+			while(p->fmt == nil)	/* loop until value is updated */
+				;
+			return p->fmt;
+		}
+
+	return _badfmt;
+}
+
+int
+fmtinstall(int c, Fmts f)
+{
+	Convfmt *p, *ep;
+
+	if(c<=0 || c>=65536)
+		return -1;
+	if(!f)
+		f = _badfmt;
+
+	_fmtlock();
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c)
+			break;
+
+	if(p == &fmtalloc.fmt[Maxfmt]){
+		_fmtunlock();
+		return -1;
+	}
+
+	p->fmt = f;
+	if(p == ep){	/* installing a new format character */
+		fmtalloc.nfmt++;
+		p->c = c;
+	}
+
+	_fmtunlock();
+	return 0;
+}
+
+void*
+_fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+	Rune rune, r;
+	int i, n;
+
+	f->flags = 0;
+	f->width = f->prec = 0;
+
+	for(;;){
+		if(isrunes){
+			r = *(Rune*)fmt;
+			fmt = (Rune*)fmt + 1;
+		}else{
+			fmt = (char*)fmt + chartorune(&rune, fmt);
+			r = rune;
+		}
+		f->r = r;
+		switch(r){
+		case '\0':
+			return nil;
+		case '.':
+			f->flags |= FmtWidth|FmtPrec;
+			continue;
+		case '0':
+			if(!(f->flags & FmtWidth)){
+				f->flags |= FmtZero;
+				continue;
+			}
+			/* fall through */
+		case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			i = 0;
+			while(r >= '0' && r <= '9'){
+				i = i * 10 + r - '0';
+				if(isrunes){
+					r = *(Rune*)fmt;
+					fmt = (Rune*)fmt + 1;
+				}else{
+					r = *(char*)fmt;
+					fmt = (char*)fmt + 1;
+				}
+			}
+			if(isrunes)
+				fmt = (Rune*)fmt - 1;
+			else
+				fmt = (char*)fmt - 1;
+		numflag:
+			if(f->flags & FmtWidth){
+				f->flags |= FmtPrec;
+				f->prec = i;
+			}else{
+				f->flags |= FmtWidth;
+				f->width = i;
+			}
+			continue;
+		case '*':
+			i = va_arg(f->args, int);
+			if(i < 0){
+				i = -i;
+				f->flags |= FmtLeft;
+			}
+			goto numflag;
+		}
+		n = (*fmtfmt(r))(f);
+		if(n < 0)
+			return nil;
+		if(n == 0)
+			return fmt;
+	}
+}
--- /dev/null
+++ b/libkern/fmtdef.h
@@ -1,0 +1,102 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+	int	quoted;		/* if set, string must be quoted */
+	int	nrunesin;	/* number of input runes that can be accepted */
+	int	nbytesin;	/* number of input bytes that can be accepted */
+	int	nrunesout;	/* number of runes that will be generated */
+	int	nbytesout;	/* number of bytes that will be generated */
+};
+
+void	*_fmtflush(Fmt*, void*, int);
+void	*_fmtdispatch(Fmt*, void*, int);
+int	_floatfmt(Fmt*, double);
+int	_fmtpad(Fmt*, int);
+int	_rfmtpad(Fmt*, int);
+int	_fmtFdFlush(Fmt*);
+
+int	_efgfmt(Fmt*);
+int	_charfmt(Fmt*);
+int	_countfmt(Fmt*);
+int	_flagfmt(Fmt*);
+int	_percentfmt(Fmt*);
+int	_ifmt(Fmt*);
+int	_runefmt(Fmt*);
+int	_runesfmt(Fmt*);
+int	_strfmt(Fmt*);
+int	_badfmt(Fmt*);
+int	_fmtcpy(Fmt*, void*, int, int);
+int	_fmtrcpy(Fmt*, void*, int n);
+
+void	_fmtlock(void);
+void	_fmtunlock(void);
+
+#define FMTCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (char*)s){\
+		t = _fmtflush(f, t, 1);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (Rune*)s){\
+		t = _fmtflush(f, t, sizeof(Rune));\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRUNE(f, t, s, r)\
+	do{\
+	Rune _rune;\
+	int _runelen;\
+	if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+		t = _fmtflush(f, t, _runelen);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	if(r < Runeself)\
+		*t++ = r;\
+	else{\
+		_rune = r;\
+		t += runetochar(t, &_rune);\
+	}\
+	}while(0)
+
+#ifndef va_copy
+#define	va_copy(a, b) ((a) = (b))
+#endif
--- /dev/null
+++ b/libkern/fmtprint.c
@@ -1,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_copy(va, f->args);
+	va_end(f->args);
+	va_start(f->args, fmt);
+	n = dofmt(f, fmt);
+	va_end(f->args);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_copy(f->args, va);
+	va_end(va);
+	if(n >= 0)
+		return 0;
+	return n;
+}
+
--- /dev/null
+++ b/libkern/fmtquote.c
@@ -1,0 +1,259 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by _quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ *	NUL in input
+ *	count exceeded in input
+ *	count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+_quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+	int w;
+	Rune c;
+
+	q->quoted = 0;
+	q->nbytesout = 0;
+	q->nrunesout = 0;
+	q->nbytesin = 0;
+	q->nrunesin = 0;
+	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+		if(nout < 2)
+			return;
+		q->quoted = 1;
+		q->nbytesout = 2;
+		q->nrunesout = 2;
+	}
+	for(; nin!=0; nin-=w){
+		if(s)
+			w = chartorune(&c, s);
+		else{
+			c = *r;
+			w = runelen(c);
+		}
+
+		if(c == '\0')
+			break;
+		if(runesout){
+			if(q->nrunesout+1 > nout)
+				break;
+		}else{
+			if(q->nbytesout+w > nout)
+				break;
+		}
+
+		if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
+			if(!q->quoted){
+				if(runesout){
+					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
+						break;
+				}
+				q->nrunesout += 2;	/* include quotes */
+				q->nbytesout += 2;	/* include quotes */
+				q->quoted = 1;
+			}
+			if(c == '\'')	{
+				if(runesout){
+					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w > nout)	/* no room for quotes */
+						break;
+				}
+				q->nbytesout++;
+				q->nrunesout++;	/* quotes reproduce as two characters */
+			}
+		}
+
+		/* advance input */
+		if(s)
+			s += w;
+		else
+			r++;
+		q->nbytesin += w;
+		q->nrunesin++;
+
+		/* advance output */
+		q->nbytesout += w;
+		q->nrunesout++;
+	}
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+	Rune r, *rm, *rme;
+	char *t, *s, *m, *me;
+	Rune *rt, *rs;
+	ulong fl;
+	int nc, w;
+
+	m = sin;
+	me = m + q->nbytesin;
+	rm = rin;
+	rme = rm + q->nrunesin;
+
+	w = f->width;
+	fl = f->flags;
+	if(f->runes){
+		if(!(fl & FmtLeft) && _rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && _fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	t = f->to;
+	s = f->stop;
+	rt = f->to;
+	rs = f->stop;
+	if(f->runes)
+		FMTRCHAR(f, rt, rs, '\'');
+	else
+		FMTRUNE(f, t, s, '\'');
+	for(nc = q->nrunesin; nc > 0; nc--){
+		if(sin){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+		}else{
+			if(rm >= rme)
+				break;
+			r = *rm++;
+		}
+		if(f->runes){
+			FMTRCHAR(f, rt, rs, r);
+			if(r == '\'')
+				FMTRCHAR(f, rt, rs, r);
+		}else{
+			FMTRUNE(f, t, s, r);
+			if(r == '\'')
+				FMTRUNE(f, t, s, r);
+		}
+	}
+
+	if(f->runes){
+		FMTRCHAR(f, rt, rs, '\'');
+		USED(rs);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && _rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		FMTRUNE(f, t, s, '\'');
+		USED(s);
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && _fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+_quotestrfmt(int runesin, Fmt *f)
+{
+	int outlen;
+	Rune *r;
+	char *s;
+	Quoteinfo q;
+
+	f->flags &= ~FmtPrec;	/* ignored for %q %Q, so disable for %s %S in easy case */
+	if(runesin){
+		r = va_arg(f->args, Rune *);
+		s = nil;
+	}else{
+		s = va_arg(f->args, char *);
+		r = nil;
+	}
+	if(!s && !r)
+		return _fmtcpy(f, "<nil>", 5, 5);
+
+	if(f->flush)
+		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
+	else if(f->runes)
+		outlen = (Rune*)f->stop - (Rune*)f->to;
+	else
+		outlen = (char*)f->stop - (char*)f->to;
+
+	_quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
+//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+
+	if(runesin){
+		if(!q.quoted)
+			return _fmtrcpy(f, r, q.nrunesin);
+		return qstrfmt(nil, r, &q, f);
+	}
+
+	if(!q.quoted)
+		return _fmtcpy(f, s, q.nrunesin, q.nbytesin);
+	return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+	return _quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+	return _quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+	fmtinstall('q', quotestrfmt);
+	fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+_needsquotes(char *s, int *quotelenp)
+{
+	Quoteinfo q;
+
+	_quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nbytesout;
+
+	return q.quoted;
+}
+
+int
+_runeneedsquotes(Rune *r, int *quotelenp)
+{
+	Quoteinfo q;
+
+	_quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nrunesout;
+
+	return q.quoted;
+}
--- /dev/null
+++ b/libkern/fmtstr.c
@@ -1,0 +1,23 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+fmtstrflush(Fmt *f)
+{
+	if(f->start == nil)
+		return nil;
+	*(char*)f->to = '\0';
+	return f->start;
+}
--- /dev/null
+++ b/libkern/fmtvprint.c
@@ -1,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_copy(va, f->args);
+	va_end(f->args);
+	va_copy(f->args, args);
+	n = dofmt(f, fmt);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va_end(f->args);
+	va_copy(f->args, va);
+	va_end(va);
+	if(n >= 0)
+		return 0;
+	return n;
+}
+
--- /dev/null
+++ b/libkern/frexp-386.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define	MASK	0x7ffL
+#define	SHIFT	20
+#define	BIAS	1022L
+
+typedef	union
+{
+	double	d;
+	struct
+	{
+		long	ls;
+		long	ms;
+	};
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+	Cheat x;
+
+	if(d == 0) {
+		*ep = 0;
+		return 0;
+	}
+	x.d = d;
+	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= BIAS << SHIFT;
+	return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+	Cheat x;
+
+	if(d == 0)
+		return 0;
+	x.d = d;
+	e += (x.ms >> SHIFT) & MASK;
+	if(e <= 0)
+		return 0;	/* underflow */
+	if(e >= MASK){		/* overflow */
+		if(d < 0)
+			return Inf(-1);
+		return Inf(1);
+	}
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= (long)e << SHIFT;
+	return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+	Cheat x;
+	int e;
+
+	if(d < 1) {
+		if(d < 0) {
+			x.d = modf(-d, ip);
+			*ip = -*ip;
+			return -x.d;
+		}
+		*ip = 0;
+		return d;
+	}
+	x.d = d;
+	e = ((x.ms >> SHIFT) & MASK) - BIAS;
+	if(e <= SHIFT+1) {
+		x.ms &= ~(0x1fffffL >> e);
+		x.ls = 0;
+	} else
+	if(e <= SHIFT+33)
+		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+	*ip = x.d;
+	return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-arm.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define	MASK	0x7ffL
+#define	SHIFT	20
+#define	BIAS	1022L
+
+typedef	union
+{
+	double	d;
+	struct
+	{
+		long	ls;
+		long	ms;
+	};
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+	Cheat x;
+
+	if(d == 0) {
+		*ep = 0;
+		return 0;
+	}
+	x.d = d;
+	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= BIAS << SHIFT;
+	return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+	Cheat x;
+
+	if(d == 0)
+		return 0;
+	x.d = d;
+	e += (x.ms >> SHIFT) & MASK;
+	if(e <= 0)
+		return 0;	/* underflow */
+	if(e >= MASK){		/* overflow */
+		if(d < 0)
+			return Inf(-1);
+		return Inf(1);
+	}
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= (long)e << SHIFT;
+	return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+	Cheat x;
+	int e;
+
+	if(d < 1) {
+		if(d < 0) {
+			x.d = modf(-d, ip);
+			*ip = -*ip;
+			return -x.d;
+		}
+		*ip = 0;
+		return d;
+	}
+	x.d = d;
+	e = ((x.ms >> SHIFT) & MASK) - BIAS;
+	if(e <= SHIFT+1) {
+		x.ms &= ~(0x1fffffL >> e);
+		x.ls = 0;
+	} else
+	if(e <= SHIFT+33)
+		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+	*ip = x.d;
+	return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-mips.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define	MASK	0x7ffL
+#define	SHIFT	20
+#define	BIAS	1022L
+
+typedef	union
+{
+	double	d;
+	struct
+	{
+		long	ms;
+		long	ls;
+	};
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+	Cheat x;
+
+	if(d == 0) {
+		*ep = 0;
+		return 0;
+	}
+	x.d = d;
+	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= BIAS << SHIFT;
+	return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+	Cheat x;
+
+	if(d == 0)
+		return 0;
+	x.d = d;
+	e += (x.ms >> SHIFT) & MASK;
+	if(e <= 0)
+		return 0;	/* underflow */
+	if(e >= MASK){		/* overflow */
+		if(d < 0)
+			return Inf(-1);
+		return Inf(1);
+	}
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= (long)e << SHIFT;
+	return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+	Cheat x;
+	int e;
+
+	if(d < 1) {
+		if(d < 0) {
+			x.d = modf(-d, ip);
+			*ip = -*ip;
+			return -x.d;
+		}
+		*ip = 0;
+		return d;
+	}
+	x.d = d;
+	e = ((x.ms >> SHIFT) & MASK) - BIAS;
+	if(e <= SHIFT+1) {
+		x.ms &= ~(0x1fffffL >> e);
+		x.ls = 0;
+	} else
+	if(e <= SHIFT+33)
+		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+	*ip = x.d;
+	return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-power.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define	MASK	0x7ffL
+#define	SHIFT	20
+#define	BIAS	1022L
+
+typedef	union
+{
+	double	d;
+	struct
+	{
+		long	ms;
+		long	ls;
+	};
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+	Cheat x;
+
+	if(d == 0) {
+		*ep = 0;
+		return 0;
+	}
+	x.d = d;
+	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= BIAS << SHIFT;
+	return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+	Cheat x;
+
+	if(d == 0)
+		return 0;
+	x.d = d;
+	e += (x.ms >> SHIFT) & MASK;
+	if(e <= 0)
+		return 0;	/* underflow */
+	if(e >= MASK){		/* overflow */
+		if(d < 0)
+			return Inf(-1);
+		return Inf(1);
+	}
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= (long)e << SHIFT;
+	return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+	Cheat x;
+	int e;
+
+	if(d < 1) {
+		if(d < 0) {
+			x.d = modf(-d, ip);
+			*ip = -*ip;
+			return -x.d;
+		}
+		*ip = 0;
+		return d;
+	}
+	x.d = d;
+	e = ((x.ms >> SHIFT) & MASK) - BIAS;
+	if(e <= SHIFT+1) {
+		x.ms &= ~(0x1fffffL >> e);
+		x.ls = 0;
+	} else
+	if(e <= SHIFT+33)
+		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+	*ip = x.d;
+	return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-sparc.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define	MASK	0x7ffL
+#define	SHIFT	20
+#define	BIAS	1022L
+
+typedef	union
+{
+	double	d;
+	struct
+	{
+		long	ms;
+		long	ls;
+	};
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+	Cheat x;
+
+	if(d == 0) {
+		*ep = 0;
+		return 0;
+	}
+	x.d = d;
+	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= BIAS << SHIFT;
+	return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+	Cheat x;
+
+	if(d == 0)
+		return 0;
+	x.d = d;
+	e += (x.ms >> SHIFT) & MASK;
+	if(e <= 0)
+		return 0;	/* underflow */
+	if(e >= MASK){		/* overflow */
+		if(d < 0)
+			return Inf(-1);
+		return Inf(1);
+	}
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= (long)e << SHIFT;
+	return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+	Cheat x;
+	int e;
+
+	if(d < 1) {
+		if(d < 0) {
+			x.d = modf(-d, ip);
+			*ip = -*ip;
+			return -x.d;
+		}
+		*ip = 0;
+		return d;
+	}
+	x.d = d;
+	e = ((x.ms >> SHIFT) & MASK) - BIAS;
+	if(e <= SHIFT+1) {
+		x.ms &= ~(0x1fffffL >> e);
+		x.ls = 0;
+	} else
+	if(e <= SHIFT+33)
+		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+	*ip = x.d;
+	return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-spim.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define	MASK	0x7ffL
+#define	SHIFT	20
+#define	BIAS	1022L
+
+typedef	union
+{
+	double	d;
+	struct
+	{
+		long	ls;
+		long	ms;
+	};
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+	Cheat x;
+
+	if(d == 0) {
+		*ep = 0;
+		return 0;
+	}
+	x.d = d;
+	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= BIAS << SHIFT;
+	return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+	Cheat x;
+
+	if(d == 0)
+		return 0;
+	x.d = d;
+	e += (x.ms >> SHIFT) & MASK;
+	if(e <= 0)
+		return 0;	/* underflow */
+	if(e >= MASK){		/* overflow */
+		if(d < 0)
+			return Inf(-1);
+		return Inf(1);
+	}
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= (long)e << SHIFT;
+	return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+	Cheat x;
+	int e;
+
+	if(d < 1) {
+		if(d < 0) {
+			x.d = modf(-d, ip);
+			*ip = -*ip;
+			return -x.d;
+		}
+		*ip = 0;
+		return d;
+	}
+	x.d = d;
+	e = ((x.ms >> SHIFT) & MASK) - BIAS;
+	if(e <= SHIFT+1) {
+		x.ms &= ~(0x1fffffL >> e);
+		x.ls = 0;
+	} else
+	if(e <= SHIFT+33)
+		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+	*ip = x.d;
+	return d - x.d;
+}
--- /dev/null
+++ b/libkern/frexp-thumb.c
@@ -1,0 +1,79 @@
+#include <lib9.h>
+
+#define	MASK	0x7ffL
+#define	SHIFT	20
+#define	BIAS	1022L
+
+typedef	union
+{
+	double	d;
+	struct
+	{
+		long	ls;
+		long	ms;
+	};
+} Cheat;
+
+double
+frexp(double d, int *ep)
+{
+	Cheat x;
+
+	if(d == 0) {
+		*ep = 0;
+		return 0;
+	}
+	x.d = d;
+	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= BIAS << SHIFT;
+	return x.d;
+}
+
+double
+ldexp(double d, int e)
+{
+	Cheat x;
+
+	if(d == 0)
+		return 0;
+	x.d = d;
+	e += (x.ms >> SHIFT) & MASK;
+	if(e <= 0)
+		return 0;	/* underflow */
+	if(e >= MASK){		/* overflow */
+		if(d < 0)
+			return Inf(-1);
+		return Inf(1);
+	}
+	x.ms &= ~(MASK << SHIFT);
+	x.ms |= (long)e << SHIFT;
+	return x.d;
+}
+
+double
+modf(double d, double *ip)
+{
+	Cheat x;
+	int e;
+
+	if(d < 1) {
+		if(d < 0) {
+			x.d = modf(-d, ip);
+			*ip = -*ip;
+			return -x.d;
+		}
+		*ip = 0;
+		return d;
+	}
+	x.d = d;
+	e = ((x.ms >> SHIFT) & MASK) - BIAS;
+	if(e <= SHIFT+1) {
+		x.ms &= ~(0x1fffffL >> e);
+		x.ls = 0;
+	} else
+	if(e <= SHIFT+33)
+		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
+	*ip = x.d;
+	return d - x.d;
+}
--- /dev/null
+++ b/libkern/getfcr-386.s
@@ -1,0 +1,27 @@
+TEXT	setfcr(SB), $0
+	MOVL	p+0(FP),AX
+	XORB	$0x3f,AX
+	PUSHW	AX
+	WAIT
+	FLDCW	0(SP)
+	POPW	AX
+	RET
+
+TEXT	getfcr(SB), $0
+	PUSHW	AX
+	WAIT
+	FSTCW	0(SP)
+	POPW	AX
+	XORB	$0x3f,AX
+	RET
+
+TEXT	getfsr(SB), $0
+	WAIT
+	FSTSW	AX
+	RET
+
+TEXT	setfsr(SB), $0
+	WAIT
+	FCLEX
+	RET
+
--- /dev/null
+++ b/libkern/getfcr-arm.s
@@ -1,0 +1,12 @@
+TEXT	setfcr(SB), $0
+	RET
+
+TEXT	getfcr(SB), $0
+	RET
+
+TEXT	getfsr(SB), $0
+	RET
+
+TEXT	setfsr(SB), $0
+	RET
+
--- /dev/null
+++ b/libkern/getfcr-mips.s
@@ -1,0 +1,15 @@
+TEXT	getfsr(SB), $0
+	MOVW	FCR31, R1
+	RET
+
+TEXT	setfsr(SB), $0
+	MOVW	R1, FCR31
+	RET
+
+TEXT	getfcr(SB), $0
+	MOVW	FCR31, R1
+	RET
+
+TEXT	setfcr(SB), $0
+	MOVW	R1, FCR31
+	RET
--- /dev/null
+++ b/libkern/getfcr-power.s
@@ -1,0 +1,28 @@
+TEXT	getfcr(SB), $8
+	MOVFL	FPSCR, F3
+	FMOVD	F3, f-8(SP)
+	MOVW	-4(SP), R3
+	RETURN
+
+TEXT	getfsr(SB), $8
+	MOVFL	FPSCR, F3
+	FMOVD	F3, f-8(SP)
+	MOVW	-4(SP), R3
+	RETURN
+
+TEXT	setfcr(SB), $8
+	SYNC
+	MOVW	R3, -4(SP)
+	FMOVD	-8(SP), F3
+	MOVFL	F3, FPSCR
+	ISYNC
+	RETURN
+
+TEXT	setfsr(SB), $8
+	SYNC
+	MOVW	R3, -4(SP)
+	FMOVD	-8(SP), F3
+	MOVFL	F3, FPSCR
+	ISYNC
+	RETURN
+
--- /dev/null
+++ b/libkern/getfcr-sparc.s
@@ -1,0 +1,27 @@
+TEXT	getfsr(SB), $0
+	SUB	$4, R1
+	MOVW	FSR, (R1)
+	MOVW	(R1), R7
+	ADD	$4, R1
+	RETURN
+
+TEXT	setfsr(SB), $0
+	SUB	$4, R1
+	MOVW	R7, (R1)
+	MOVW	(R1), FSR
+	ADD	$4, R1
+	RETURN
+
+TEXT	setfcr(SB), $0
+	SUB	$4, R1
+	MOVW	R7, (R1)
+	MOVW	(R1), FSR
+	ADD	$4, R1
+	RETURN
+
+TEXT	getfcr(SB), $0
+	SUB	$4, R1
+	MOVW	FSR, (R1)
+	MOVW	(R1), R7
+	ADD	$4, R1
+	RETURN
--- /dev/null
+++ b/libkern/getfcr-spim.s
@@ -1,0 +1,1 @@
+#include "getfcr-mips.s"
--- /dev/null
+++ b/libkern/getfcr-thumb.s
@@ -1,0 +1,12 @@
+TEXT	setfcr(SB), $0
+	RET
+
+TEXT	getfcr(SB), $0
+	RET
+
+TEXT	getfsr(SB), $0
+	RET
+
+TEXT	setfsr(SB), $0
+	RET
+
--- /dev/null
+++ b/libkern/getfields.c
@@ -1,0 +1,35 @@
+#include	"lib9.h"
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+	Rune r;
+	int nr, intok, narg;
+
+	if(max <= 0)
+		return 0;
+
+	narg = 0;
+	args[narg] = str;
+	if(!mflag)
+		narg++;
+	intok = 0;
+	for(;; str += nr) {
+		nr = chartorune(&r, str);
+		if(r == 0)
+			break;
+		if(utfrune(set, r)) {
+			if(narg >= max)
+				break;
+			*str = 0;
+			intok = 0;
+			args[narg] = str + nr;
+			if(!mflag)
+				narg++;
+		} else {
+			if(!intok && mflag)
+				narg++;
+			intok = 1;
+		}
+	}
+	return narg;
+}
--- /dev/null
+++ b/libkern/log.c
@@ -1,0 +1,57 @@
+/*
+	log returns the natural logarithm of its floating
+	point argument.
+
+	The coefficients are #2705 from Hart & Cheney. (19.38D)
+
+	It calls frexp.
+*/
+
+#include <lib9.h>
+
+#define	log2    0.693147180559945309e0
+#define	ln10o1  .4342944819032518276511
+#define	sqrto2  0.707106781186547524e0
+#define	p0      -.240139179559210510e2
+#define	p1      0.309572928215376501e2
+#define	p2      -.963769093377840513e1
+#define	p3      0.421087371217979714e0
+#define	q0      -.120069589779605255e2
+#define	q1      0.194809660700889731e2
+#define	q2      -.891110902798312337e1
+
+double
+log(double arg)
+{
+	double x, z, zsq, temp;
+	int exp;
+
+	if(arg <= 0)
+		return NaN();
+	x = frexp(arg, &exp);
+	while(x < 0.5) {
+		x *= 2;
+		exp--;
+	}
+	if(x < sqrto2) {
+		x *= 2;
+		exp--;
+	}
+
+	z = (x-1) / (x+1);
+	zsq = z*z;
+
+	temp = ((p3*zsq + p2)*zsq + p1)*zsq + p0;
+	temp = temp/(((zsq + q2)*zsq + q1)*zsq + q0);
+	temp = temp*z + exp*log2;
+	return temp;
+}
+
+double
+log10(double arg)
+{
+
+	if(arg <= 0)
+		return NaN();
+	return log(arg) * ln10o1;
+}
--- /dev/null
+++ b/libkern/memccpy-power.s
@@ -1,0 +1,23 @@
+	TEXT	memccpy(SB), $0
+#define	BDNZ	BC	16,0,
+MOVW R3, s1+0(FP)
+	MOVW	n+12(FP), R7
+	MOVW	s2+4(FP), R4
+	MOVBZ	c+11(FP), R5
+	CMP	R7, $0
+	BEQ	nf
+	MOVW	R7, CTR
+	SUB	$1, R3
+	SUB	$1, R4
+l1:
+	MOVBZU	1(R4), R6
+	CMP	R6, R5
+	MOVBZU	R6, 1(R3)
+	BEQ	eq
+	BDNZ	l1
+nf:
+	MOVW	$0, R3
+	RETURN
+eq:
+	ADD	$1, R3
+	RETURN
--- /dev/null
+++ b/libkern/memccpy.c
@@ -1,0 +1,17 @@
+#include	<lib9.h>
+
+void*
+memccpy(void *a1, void *a2, int c, ulong n)
+{
+	uchar *s1, *s2;
+
+	s1 = a1;
+	s2 = a2;
+	c &= 0xFF;
+	while(n > 0) {
+		if((*s1++ = *s2++) == c)
+			return s1;
+		n--;
+	}
+	return 0;
+}
--- /dev/null
+++ b/libkern/memchr.c
@@ -1,0 +1,16 @@
+#include	<lib9.h>
+
+void*
+memchr(void *ap, int c, ulong n)
+{
+	uchar *sp;
+
+	sp = ap;
+	c &= 0xFF;
+	while(n > 0) {
+		if(*sp++ == c)
+			return sp-1;
+		n--;
+	}
+	return 0;
+}
--- /dev/null
+++ b/libkern/memcmp-power.s
@@ -1,0 +1,110 @@
+	TEXT	memcmp(SB), $0
+#define	BDNZ	BC	16,0,
+	MOVW R3, s1+0(FP)		/* R3 is pointer1 */
+
+/*
+ * performance:
+ *	67mb/sec aligned; 16mb/sec unaligned
+ */
+
+	MOVW	n+8(FP), R4		/* R4 is count */
+	MOVW	s2+4(FP), R5		/* R5 is pointer2 */
+
+/*
+ * let LSW do the work for 4 characters or less; aligned and unaligned
+ */
+	CMP	R4, $0
+	BLE	eq
+	CMP	R4, $4
+	BLE	out
+
+	XOR	R3, R5, R9
+	ANDCC	$3, R9
+	BNE	l4	/* pointers misaligned; use LSW loop */
+
+/*
+ * do enough bytes to align pointers
+ */
+	ANDCC	$3,R3, R9
+	BEQ	l2
+	SUBC	R9, $4, R9
+	MOVW	R9, XER
+	LSW	(R3), R10
+	ADD	R9, R3
+	LSW	(R5), R14
+	ADD	R9, R5
+	SUB	R9, R4
+	CMPU	R10, R14
+	BNE	ne
+
+/*
+ * compare 16 at a time
+ */
+l2:
+	SRAWCC	$4, R4, R9
+	BLE	l4
+	MOVW	R9, CTR
+	SUB	$4, R3
+	SUB	$4, R5
+l3:
+	MOVWU	4(R3), R10
+	MOVWU	4(R5), R12
+	MOVWU	4(R3), R11
+	MOVWU	4(R5), R13
+	CMPU	R10, R12
+	BNE	ne
+	MOVWU	4(R3), R10
+	MOVWU	4(R5), R12
+	CMPU	R11, R13
+	BNE	ne
+	MOVWU	4(R3), R11
+	MOVWU	4(R5), R13
+	CMPU	R10, R12
+	BNE	ne
+	CMPU	R11, R13
+	BNE	ne
+	BDNZ	l3
+	ADD	$4, R3
+	ADD	$4, R5
+	RLWNMCC	$0, R4, $15, R4	/* residue */
+	BEQ	eq
+
+/*
+ * do remaining words with LSW; also does unaligned case
+ */
+l4:
+	SRAWCC	$2, R4, R9
+	BLE	out
+	MOVW	R9, CTR
+l5:
+	LSW	(R3), $4, R10
+	ADD	$4, R3
+	LSW	(R5), $4, R11
+	ADD	$4, R5
+	CMPU	R10, R11
+	BNE	ne
+	BDNZ	l5
+	RLWNMCC	$0, R4, $3, R4	/* residue */
+	BEQ	eq
+
+/*
+ * do remaining bytes with final LSW
+ */
+out:
+	MOVW	R4, XER
+	LSW	(R3), R10
+	LSW	(R5), R11
+	CMPU	R10, R11
+	BNE	ne
+
+eq:
+	MOVW	$0, R3
+	RETURN
+
+ne:
+	MOVW	$1, R3
+	BGE	ret
+	MOVW	$-1,R3
+ret:
+	RETURN
+	END
--- /dev/null
+++ b/libkern/memcmp.c
@@ -1,0 +1,22 @@
+#include	<lib9.h>
+
+int
+memcmp(void *a1, void *a2, ulong n)
+{
+	uchar *s1, *s2;
+	uint c1, c2;
+
+	s1 = a1;
+	s2 = a2;
+	while(n > 0) {
+		c1 = *s1++;
+		c2 = *s2++;
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		n--;
+	}
+	return 0;
+}
--- /dev/null
+++ b/libkern/memmove-386.s
@@ -1,0 +1,58 @@
+	TEXT	memmove(SB), $0
+	TEXT	memcpy(SB), $0
+
+	MOVL	p1+0(FP), DI
+	MOVL	p2+4(FP), SI
+	MOVL	n+8(FP), BX
+	CMPL	BX, $0
+	JGE	ok
+	MOVL	$0, SI
+ok:
+	CLD
+/*
+ * check and set for backwards
+ */
+	CMPL	SI, DI
+	JLS	back
+/*
+ * copy whole longs
+ */
+	MOVL	BX, CX
+	SHRL	$2, CX
+	REP;	MOVSL
+/*
+ * copy the rest, by bytes
+ */
+	ANDL	$3, BX
+	MOVL	BX, CX
+	REP;	MOVSB
+
+	MOVL	p+0(FP),AX
+	RET
+/*
+ * whole thing backwards has
+ * adjusted addresses
+ */
+back:
+	ADDL	BX, DI
+	ADDL	BX, SI
+	SUBL	$4, DI
+	SUBL	$4, SI
+	STD
+/*
+ * copy whole longs
+ */
+	MOVL	BX, CX
+	SHRL	$2, CX
+	ANDL	$3, BX
+	REP;	MOVSL
+/*
+ * copy the rest, by bytes
+ */
+	ADDL	$3, DI
+	ADDL	$3, SI
+	MOVL	BX, CX
+	REP;	MOVSB
+
+	MOVL	p+0(FP),AX
+	RET
--- /dev/null
+++ b/libkern/memmove-arm.s
@@ -1,0 +1,223 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3					/* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT	memcpy(SB), $0
+TEXT memmove(SB), $-4
+_memmove:
+	MOVW	R(TS), to+0(FP)		/* need to save for return value */
+	MOVW	from+4(FP), R(FROM)
+	MOVW	n+8(FP), R(N)
+
+	ADD	R(N), R(TS), R(TE)	/* to end pointer */
+
+	CMP	R(FROM), R(TS)
+	BLS	_forward
+
+_back:
+	ADD	R(N), R(FROM)		/* from end pointer */
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	BLT	_b1tail
+
+_b4align:				/* align destination on 4 */
+	AND.S	$3, R(TE), R(TMP)
+	BEQ	_b4aligned
+
+	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
+	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
+	B	_b4align
+
+_b4aligned:				/* is source now aligned? */
+	AND.S	$3, R(FROM), R(TMP)
+	BNE	_bunaligned
+
+	ADD	$31, R(TS), R(TMP)	/* do 32-byte chunks if possible */
+_b32loop:
+	CMP	R(TMP), R(TE)
+	BLS	_b4tail
+
+	MOVM.DB.W (R(FROM)), [R4-R11]
+	MOVM.DB.W [R4-R11], (R(TE))
+	B	_b32loop
+
+_b4tail:				/* do remaining words if possible */
+	ADD	$3, R(TS), R(TMP)
+_b4loop:
+	CMP	R(TMP), R(TE)
+	BLS	_b1tail
+
+	MOVW.W	-4(R(FROM)), R(TMP1)	/* pre-indexed */
+	MOVW.W	R(TMP1), -4(R(TE))	/* pre-indexed */
+	B	_b4loop
+
+_b1tail:				/* remaining bytes */
+	CMP	R(TE), R(TS)
+	BEQ	_return
+
+	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
+	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
+	B	_b1tail
+
+_forward:
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	BLT	_f1tail
+
+_f4align:				/* align destination on 4 */
+	AND.S	$3, R(TS), R(TMP)
+	BEQ	_f4aligned
+
+	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
+	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
+	B	_f4align
+
+_f4aligned:				/* is source now aligned? */
+	AND.S	$3, R(FROM), R(TMP)
+	BNE	_funaligned
+
+	SUB	$31, R(TE), R(TMP)	/* do 32-byte chunks if possible */
+_f32loop:
+	CMP	R(TMP), R(TS)
+	BHS	_f4tail
+
+	MOVM.IA.W (R(FROM)), [R4-R11] 
+	MOVM.IA.W [R4-R11], (R(TS))
+	B	_f32loop
+
+_f4tail:
+	SUB	$3, R(TE), R(TMP)	/* do remaining words if possible */
+_f4loop:
+	CMP	R(TMP), R(TS)
+	BHS	_f1tail
+
+	MOVW.P	4(R(FROM)), R(TMP1)	/* implicit write back */
+	MOVW.P	R4, 4(R(TS))		/* implicit write back */
+	B	_f4loop
+
+_f1tail:
+	CMP	R(TS), R(TE)
+	BEQ	_return
+
+	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
+	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
+	B	_f1tail
+
+_return:
+	MOVW	to+0(FP), R0
+	RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 6
+
+BR0 = 7
+BW0 = 8
+BR1 = 8
+BW1 = 9
+BR2 = 9
+BW2 = 10
+BR3 = 10
+BW3 = 11
+
+_bunaligned:
+	CMP	$2, R(TMP)		/* is R(TMP) < 2 ? */
+
+	MOVW.LT	$8, R(RSHIFT)		/* (R(n)<<24)|(R(n-1)>>8) */
+	MOVW.LT	$24, R(LSHIFT)
+	MOVW.LT	$1, R(OFFSET)
+
+	MOVW.EQ	$16, R(RSHIFT)		/* (R(n)<<16)|(R(n-1)>>16) */
+	MOVW.EQ	$16, R(LSHIFT)
+	MOVW.EQ	$2, R(OFFSET)
+
+	MOVW.GT	$24, R(RSHIFT)		/* (R(n)<<8)|(R(n-1)>>24) */
+	MOVW.GT	$8, R(LSHIFT)
+	MOVW.GT	$3, R(OFFSET)
+
+	ADD	$16, R(TS), R(TMP)	/* do 16-byte chunks if possible */
+	CMP	R(TMP), R(TE)
+	BLS	_b1tail
+
+	AND	$~0x03, R(FROM)		/* align source */
+	MOVW	(R(FROM)), R(BR0)	/* prime first block register */
+
+_bu16loop:
+	CMP	R(TMP), R(TE)
+	BLS	_bu1tail
+
+	MOVW	R(BR0)<<R(LSHIFT), R(BW3)
+	MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+	ORR	R(BR3)>>R(RSHIFT), R(BW3)
+
+	MOVW	R(BR3)<<R(LSHIFT), R(BW2)
+	ORR	R(BR2)>>R(RSHIFT), R(BW2)
+
+	MOVW	R(BR2)<<R(LSHIFT), R(BW1)
+	ORR	R(BR1)>>R(RSHIFT), R(BW1)
+
+	MOVW	R(BR1)<<R(LSHIFT), R(BW0)
+	ORR	R(BR0)>>R(RSHIFT), R(BW0)
+
+	MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+	B	_bu16loop
+
+_bu1tail:
+	ADD	R(OFFSET), R(FROM)
+	B	_b1tail
+
+FW0 = 7
+FR0 = 8
+FW1 = 8
+FR1 = 9
+FW2 = 9
+FR2 = 10
+FW3 = 10
+FR3 = 11
+
+_funaligned:
+	CMP	$2, R(TMP)
+
+	MOVW.LT	$8, R(RSHIFT)		/* (R(n+1)<<24)|(R(n)>>8) */
+	MOVW.LT	$24, R(LSHIFT)
+	MOVW.LT	$3, R(OFFSET)
+
+	MOVW.EQ	$16, R(RSHIFT)		/* (R(n+1)<<16)|(R(n)>>16) */
+	MOVW.EQ	$16, R(LSHIFT)
+	MOVW.EQ	$2, R(OFFSET)
+
+	MOVW.GT	$24, R(RSHIFT)		/* (R(n+1)<<8)|(R(n)>>24) */
+	MOVW.GT	$8, R(LSHIFT)
+	MOVW.GT	$1, R(OFFSET)
+
+	SUB	$16, R(TE), R(TMP)	/* do 16-byte chunks if possible */
+	CMP	R(TMP), R(TS)
+	BHS	_f1tail
+
+	AND	$~0x03, R(FROM)		/* align source */
+	MOVW.P	4(R(FROM)), R(FR3)	/* prime last block register, implicit write back */
+
+_fu16loop:
+	CMP	R(TMP), R(TS)
+	BHS	_fu1tail
+
+	MOVW	R(FR3)>>R(RSHIFT), R(FW0)
+	MOVM.IA.W (R(FROM)), [R(FR0)-R(FR3)]
+	ORR	R(FR0)<<R(LSHIFT), R(FW0)
+
+	MOVW	R(FR0)>>R(RSHIFT), R(FW1)
+	ORR	R(FR1)<<R(LSHIFT), R(FW1)
+
+	MOVW	R(FR1)>>R(RSHIFT), R(FW2)
+	ORR	R(FR2)<<R(LSHIFT), R(FW2)
+
+	MOVW	R(FR2)>>R(RSHIFT), R(FW3)
+	ORR	R(FR3)<<R(LSHIFT), R(FW3)
+
+	MOVM.IA.W [R(FW0)-R(FW3)], (R(TS))
+	B	_fu16loop
+
+_fu1tail:
+	SUB	R(OFFSET), R(FROM)
+	B	_f1tail
--- /dev/null
+++ b/libkern/memmove-mips.s
@@ -1,0 +1,237 @@
+	TEXT	memmove(SB), $0
+
+	JMP	move
+
+	TEXT	memcpy(SB), $0
+move:
+	MOVW	R1, s1+0(FP)
+
+	MOVW	n+8(FP), R3		/* R3 is count */
+	MOVW	R1, R4			/* R4 is to-pointer */
+	SGT	R0, R3, R5
+	BEQ	R5, ok
+	MOVW	(R0), R0		/* abort if negative count */
+ok:
+	MOVW	s2+4(FP), R5		/* R5 is from-pointer */
+	ADDU	R3,R5, R7		/* R7 is end from-pointer */
+	ADDU	R3,R4, R6		/* R6 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+	SGT	$4,R3, R2
+	SGTU	R4,R5, R1
+	BNE	R1, back
+
+/*
+ * if not at least 4 chars,
+ * don't even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+	BNE	R2, fout
+
+
+/*
+ * byte at a time to word align destination
+ */
+f1:
+	AND	$3,R4, R1
+	BEQ	R1, f2
+	MOVB	0(R5), R8
+	ADDU	$1, R5
+	MOVB	R8, 0(R4)
+	ADDU	$1, R4
+	JMP	f1
+
+/*
+ * test if source is now word aligned
+ */
+f2:
+	AND	$3, R5, R1
+	BNE	R1, fun2
+/*
+ * turn R3 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R6 is smaller than R7 --
+ * there are problems if R7 is 0.
+ */
+	ADDU	$-15,R6, R3
+f3:
+	SGTU	R3,R4, R1
+	BEQ	R1, f4
+	MOVW	0(R5), R8
+	MOVW	4(R5), R9
+	MOVW	R8, 0(R4)
+	MOVW	8(R5), R8
+	MOVW	R9, 4(R4)
+	MOVW	12(R5), R9
+	ADDU	$16, R5
+	MOVW	R8, 8(R4)
+	MOVW	R9, 12(R4)
+	ADDU	$16, R4
+	JMP	f3
+
+/*
+ * turn R3 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+	ADDU	$-3,R6, R3
+f5:
+	SGTU	R3,R4, R1
+	BEQ	R1, fout
+	MOVW	0(R5), R8
+	ADDU	$4, R5
+	MOVW	R8, 0(R4)
+	ADDU	$4, R4
+	JMP	f5
+
+/*
+ * forward copy, unaligned
+ * turn R3 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R6 is smaller than R7 --
+ * there are problems if R7 is 0.
+ */
+fun2:
+	ADDU	$-15,R6, R3
+fun3:
+	SGTU	R3,R4, R1
+	BEQ	R1, fun4
+	MOVWL	0(R5), R8
+	MOVWR	3(R5), R8
+	MOVWL	4(R5), R9
+	MOVWR	7(R5), R9
+	MOVW	R8, 0(R4)
+	MOVWL	8(R5), R8
+	MOVWR	11(R5), R8
+	MOVW	R9, 4(R4)
+	MOVWL	12(R5), R9
+	MOVWR	15(R5), R9
+	ADDU	$16, R5
+	MOVW	R8, 8(R4)
+	MOVW	R9, 12(R4)
+	ADDU	$16, R4
+	JMP	fun3
+
+/*
+ * turn R3 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+fun4:
+	ADDU	$-3,R6, R3
+fun5:
+	SGTU	R3,R4, R1
+	BEQ	R1, fout
+	MOVWL	0(R5), R8
+	MOVWR	3(R5), R8
+	ADDU	$4, R5
+	MOVW	R8, 0(R4)
+	ADDU	$4, R4
+	JMP	fun5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+	BEQ	R7,R5, ret
+	MOVB	0(R5), R8
+	ADDU	$1, R5
+	MOVB	R8, 0(R4)
+	ADDU	$1, R4
+	JMP	fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+	BNE	R2, bout
+b1:
+	AND	$3,R6, R1
+	BEQ	R1, b2
+	MOVB	-1(R7), R8
+	ADDU	$-1, R7
+	MOVB	R8, -1(R6)
+	ADDU	$-1, R6
+	JMP	b1
+
+b2:
+	AND	$3, R7, R1
+	BNE	R1, bun2
+
+	ADDU	$15,R5, R3
+b3:
+	SGTU	R7,R3, R1
+	BEQ	R1, b4
+	MOVW	-4(R7), R8
+	MOVW	-8(R7), R9
+	MOVW	R8, -4(R6)
+	MOVW	-12(R7), R8
+	MOVW	R9, -8(R6)
+	MOVW	-16(R7), R9
+	ADDU	$-16, R7
+	MOVW	R8, -12(R6)
+	MOVW	R9, -16(R6)
+	ADDU	$-16, R6
+	JMP	b3
+b4:
+	ADDU	$3,R5, R3
+b5:
+	SGTU	R7,R3, R1
+	BEQ	R1, bout
+	MOVW	-4(R7), R8
+	ADDU	$-4, R7
+	MOVW	R8, -4(R6)
+	ADDU	$-4, R6
+	JMP	b5
+
+bun2:
+	ADDU	$15,R5, R3
+bun3:
+	SGTU	R7,R3, R1
+	BEQ	R1, bun4
+	MOVWL	-4(R7), R8
+	MOVWR	-1(R7), R8
+	MOVWL	-8(R7), R9
+	MOVWR	-5(R7), R9
+	MOVW	R8, -4(R6)
+	MOVWL	-12(R7), R8
+	MOVWR	-9(R7), R8
+	MOVW	R9, -8(R6)
+	MOVWL	-16(R7), R9
+	MOVWR	-13(R7), R9
+	ADDU	$-16, R7
+	MOVW	R8, -12(R6)
+	MOVW	R9, -16(R6)
+	ADDU	$-16, R6
+	JMP	bun3
+
+bun4:
+	ADDU	$3,R5, R3
+bun5:
+	SGTU	R7,R3, R1
+	BEQ	R1, bout
+	MOVWL	-4(R7), R8
+	MOVWR	-1(R7), R8
+	ADDU	$-4, R7
+	MOVW	R8, -4(R6)
+	ADDU	$-4, R6
+	JMP	bun5
+
+bout:
+	BEQ	R7,R5, ret
+	MOVB	-1(R7), R8
+	ADDU	$-1, R7
+	MOVB	R8, -1(R6)
+	ADDU	$-1, R6
+	JMP	bout
+
+ret:
+	MOVW	s1+0(FP), R1
+	RET
+	END
--- /dev/null
+++ b/libkern/memmove-power.s
@@ -1,0 +1,170 @@
+#define	BDNZ	BC	16,0,
+	TEXT	memcpy(SB), $0
+	BR	move
+
+	TEXT	memmove(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+	MOVW	R3, s1+0(FP)
+	MOVW	n+8(FP), R9		/* R9 is count */
+	MOVW	R3, R10			/* R10 is to-pointer */
+	CMP	R9, $0
+	BEQ	ret
+	BLT	trap
+	MOVW	s2+4(FP), R11		/* R11 is from-pointer */
+
+/*
+ * if no more than 16 bytes, just use one lsw/stsw
+ */
+	CMP	R9, $16
+	BLE	fout
+
+	ADD	R9,R11, R13		/* R13 is end from-pointer */
+	ADD	R9,R10, R12		/* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+	CMPU	R10, R11
+	BGT	back
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+	XOR	R10,R11, R7
+	ANDCC	$3,R7
+	BNE	fbad
+
+/*
+ * move a few bytes to align pointers
+ */
+	ANDCC	$3,R10,R7
+	BEQ	f2
+	SUBC	R7, $4, R7
+	SUB	R7, R9
+	MOVW	R7, XER
+	LSW	(R11), R16
+	ADD	R7, R11
+	STSW	R16, (R10)
+	ADD	R7, R10
+
+/*
+ * turn R14 into doubleword count
+ * copy 16 bytes at a time while there's room.
+ */
+f2:
+	SRAWCC	$4, R9, R14
+	BLE	fout
+	MOVW	R14, CTR
+	SUB	$4, R11
+	SUB	$4, R10
+f3:
+	MOVWU	4(R11), R16
+	MOVWU	R16, 4(R10)
+	MOVWU	4(R11), R17
+	MOVWU	R17, 4(R10)
+	MOVWU	4(R11), R16
+	MOVWU	R16, 4(R10)
+	MOVWU	4(R11), R17
+	MOVWU	R17, 4(R10)
+	BDNZ	f3
+	RLWNMCC	$0, R9, $15, R9	/* residue */
+	BEQ	ret
+	ADD	$4, R11
+	ADD	$4, R10
+
+/*
+ * move up to 16 bytes through R16 .. R19; aligned and unaligned
+ */
+fout:
+	MOVW	R9, XER
+	LSW	(R11), R16
+	STSW	R16, (R10)
+	BR	ret
+
+/*
+ * loop for unaligned copy, then copy up to 15 remaining bytes
+ */
+fbad:
+	SRAWCC	$4, R9, R14
+	BLE	f6
+	MOVW	R14, CTR
+f5:
+	LSW	(R11), $16, R16
+	ADD	$16, R11
+	STSW	R16, $16, (R10)
+	ADD	$16, R10
+	BDNZ	f5
+	RLWNMCC	$0, R9, $15, R9	/* residue */
+	BEQ	ret
+f6:
+	MOVW	R9, XER
+	LSW	(R11), R16
+	STSW	R16, (R10)
+	BR	ret
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+	CMP	R9, $4
+	BLT	bout
+
+	XOR	R12,R13, R7
+	ANDCC	$3,R7
+	BNE	bout
+b1:
+	ANDCC	$3,R13, R7
+	BEQ	b2
+	MOVBZU	-1(R13), R16
+	MOVBZU	R16, -1(R12)
+	SUB	$1, R9
+	BR	b1
+b2:
+	SRAWCC	$4, R9, R14
+	BLE	b4
+	MOVW	R14, CTR
+b3:
+	MOVWU	-4(R13), R16
+	MOVWU	R16, -4(R12)
+	MOVWU	-4(R13), R17
+	MOVWU	R17, -4(R12)
+	MOVWU	-4(R13), R16
+	MOVWU	R16, -4(R12)
+	MOVWU	-4(R13), R17
+	MOVWU	R17, -4(R12)
+	BDNZ	b3
+	RLWNMCC	$0, R9, $15, R9	/* residue */
+	BEQ	ret
+b4:
+	SRAWCC	$2, R9, R14
+	BLE	bout
+	MOVW	R14, CTR
+b5:
+	MOVWU	-4(R13), R16
+	MOVWU	R16, -4(R12)
+	BDNZ	b5
+	RLWNMCC	$0, R9, $3, R9	/* residue */
+	BEQ	ret
+
+bout:
+	CMPU	R13, R11
+	BLE	ret
+	MOVBZU	-1(R13), R16
+	MOVBZU	R16, -1(R12)
+	BR	bout
+
+trap:
+/*	MOVW	$0, R0	*/
+	MOVW	R0, 0(R0)
+
+ret:
+	MOVW	s1+0(FP), R3
+	RETURN
--- /dev/null
+++ b/libkern/memmove-sparc.s
@@ -1,0 +1,162 @@
+	TEXT	memmove(SB), $0
+	JMP	move
+
+	TEXT	memcpy(SB), $0
+move:
+
+/*
+ * performance:
+ * (tba)
+ */
+
+	MOVW	R7, s1+0(FP)
+	MOVW	n+8(FP), R9		/* R9 is count */
+	MOVW	R7, R10			/* R10 is to-pointer */
+	SUBCC	R0,R9, R0
+	BGE	ok
+	MOVW	0(R0), R0
+
+ok:
+	MOVW	s2+4(FP), R11		/* R11 is from-pointer */
+	ADD	R9,R11, R13		/* R13 is end from-pointer */
+	ADD	R9,R10, R12		/* R12 is end to-pointer */
+
+/*
+ * easiest test is copy backwards if
+ * destination string has higher mem address
+ */
+	SUBCC	R11,R10, R0
+	BGU	back
+
+/*
+ * if not at least 8 chars,
+ * dont even mess around.
+ * 7 chars to guarantee any
+ * rounding up to a word
+ * boundary and 8 characters
+ * to get at least maybe one
+ * full word store.
+ */
+	SUBCC	$8,R9, R0
+	BL	fout
+
+/*
+ * test if both pointers
+ * are similarly word aligned
+ */
+	XOR	R10,R11, R7
+	ANDCC	$7,R7, R0
+	BNE	fout
+
+/*
+ * byte at a time to double align
+ */
+f1:
+	ANDCC	$7,R10, R0
+	BE	f2
+	MOVB	0(R11), R16
+	ADD	$1, R11
+	MOVB	R16, 0(R10)
+	ADD	$1, R10
+	JMP	f1
+
+/*
+ * turn R9 into to-end pointer-15
+ * copy 16 at a time while theres room.
+ * R12 is smaller than R13 --
+ * there are problems if R13 is 0.
+ */
+f2:
+	SUB	$15,R12, R9
+f3:
+	SUBCC	R10,R9, R0
+	BLEU	f4
+	MOVD	0(R11), R16
+	MOVD	R16, 0(R10)
+	MOVD	8(R11), R16
+	ADD	$16, R11
+	MOVD	R16, 8(R10)
+	ADD	$16, R10
+	JMP	f3
+
+/*
+ * turn R9 into to-end pointer-3
+ * copy 4 at a time while theres room
+ */
+f4:
+	SUB	$3,R12, R9
+f5:
+	SUBCC	R10,R9, R0
+	BLEU	fout
+	MOVW	0(R11), R16
+	ADD	$4, R11
+	MOVW	R16, 0(R10)
+	ADD	$4, R10
+	JMP	f5
+
+/*
+ * last loop, copy byte at a time
+ */
+fout:
+	SUBCC	R11,R13, R0
+	BLEU	ret
+	MOVB	0(R11), R16
+	ADD	$1, R11
+	MOVB	R16, 0(R10)
+	ADD	$1, R10
+	JMP	fout
+
+/*
+ * whole thing repeated for backwards
+ */
+back:
+	SUBCC	$8,R9, R0 
+	BL	bout
+
+	XOR	R12,R13, R7
+	ANDCC	$7,R7, R0
+	BNE	bout
+b1:
+	ANDCC	$7,R13, R0
+	BE	b2
+	MOVB	-1(R13), R16
+	SUB	$1, R13
+	MOVB	R16, -1(R12)
+	SUB	$1, R12
+	JMP	b1
+b2:
+	ADD	$15,R11, R9
+b3:
+	SUBCC	R9,R13, R0
+	BLEU	b4
+
+	MOVD	-8(R13), R16
+	MOVD	R16, -8(R12)
+	MOVD	-16(R13), R16
+	SUB	$16, R13
+	MOVD	R16, -16(R12);
+	SUB	$16, R12
+	JMP	b3
+b4:
+	ADD	$3,R11, R9
+b5:
+	SUBCC	R9,R13, R0
+	BLEU	bout
+	MOVW	-4(R13), R16
+	SUB	$4, R13
+	MOVW	R16, -4(R12)
+	SUB	$4, R12
+	JMP	b5
+
+bout:
+	SUBCC	R11,R13, R0
+	BLEU	ret
+	MOVB	-1(R13), R16
+	SUB	$1, R13
+	MOVB	R16, -1(R12)
+	SUB	$1, R12
+	JMP	bout
+
+ret:
+	MOVW	s1+0(FP), R7
+	RETURN
--- /dev/null
+++ b/libkern/memmove-spim.s
@@ -1,0 +1,1 @@
+#include "memmove-mips.s"
--- /dev/null
+++ b/libkern/memmove-thumb.s
@@ -1,0 +1,223 @@
+TS = 0
+TE = 1
+FROM = 2
+N = 3
+TMP = 3					/* N and TMP don't overlap */
+TMP1 = 4
+
+TEXT	memcpy(SB), $0
+TEXT memmove(SB), $-4
+_memmove:
+	MOVW	R(TS), to+0(FP)		/* need to save for return value */
+	MOVW	from+4(FP), R(FROM)
+	MOVW	n+8(FP), R(N)
+
+	ADD	R(N), R(TS), R(TE)	/* to end pointer */
+
+	CMP	R(FROM), R(TS)
+	BLS	_forward
+
+_back:
+	ADD	R(N), R(FROM)		/* from end pointer */
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	BLT	_b1tail
+
+_b4align:				/* align destination on 4 */
+	AND.S	$3, R(TE), R(TMP)
+	BEQ	_b4aligned
+
+	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
+	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
+	B	_b4align
+
+_b4aligned:				/* is source now aligned? */
+	AND.S	$3, R(FROM), R(TMP)
+	BNE	_bunaligned
+
+	ADD	$31, R(TS), R(TMP)	/* do 32-byte chunks if possible */
+_b32loop:
+	CMP	R(TMP), R(TE)
+	BLS	_b4tail
+
+	MOVM.DB.W (R(FROM)), [R4-R11]
+	MOVM.DB.W [R4-R11], (R(TE))
+	B	_b32loop
+
+_b4tail:				/* do remaining words if possible */
+	ADD	$3, R(TS), R(TMP)
+_b4loop:
+	CMP	R(TMP), R(TE)
+	BLS	_b1tail
+
+	MOVW.W	-4(R(FROM)), R(TMP1)	/* pre-indexed */
+	MOVW.W	R(TMP1), -4(R(TE))	/* pre-indexed */
+	B	_b4loop
+
+_b1tail:				/* remaining bytes */
+	CMP	R(TE), R(TS)
+	BEQ	_return
+
+	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
+	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
+	B	_b1tail
+
+_forward:
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	BLT	_f1tail
+
+_f4align:				/* align destination on 4 */
+	AND.S	$3, R(TS), R(TMP)
+	BEQ	_f4aligned
+
+	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
+	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
+	B	_f4align
+
+_f4aligned:				/* is source now aligned? */
+	AND.S	$3, R(FROM), R(TMP)
+	BNE	_funaligned
+
+	SUB	$31, R(TE), R(TMP)	/* do 32-byte chunks if possible */
+_f32loop:
+	CMP	R(TMP), R(TS)
+	BHS	_f4tail
+
+	MOVM.IA.W (R(FROM)), [R4-R11] 
+	MOVM.IA.W [R4-R11], (R(TS))
+	B	_f32loop
+
+_f4tail:
+	SUB	$3, R(TE), R(TMP)	/* do remaining words if possible */
+_f4loop:
+	CMP	R(TMP), R(TS)
+	BHS	_f1tail
+
+	MOVW.P	4(R(FROM)), R(TMP1)	/* implicit write back */
+	MOVW.P	R4, 4(R(TS))		/* implicit write back */
+	B	_f4loop
+
+_f1tail:
+	CMP	R(TS), R(TE)
+	BEQ	_return
+
+	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
+	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
+	B	_f1tail
+
+_return:
+	MOVW	to+0(FP), R0
+	RET
+
+RSHIFT = 4
+LSHIFT = 5
+OFFSET = 6
+
+BR0 = 7
+BW0 = 8
+BR1 = 8
+BW1 = 9
+BR2 = 9
+BW2 = 10
+BR3 = 10
+BW3 = 11
+
+_bunaligned:
+	CMP	$2, R(TMP)		/* is R(TMP) < 2 ? */
+
+	MOVW.LT	$8, R(RSHIFT)		/* (R(n)<<24)|(R(n-1)>>8) */
+	MOVW.LT	$24, R(LSHIFT)
+	MOVW.LT	$1, R(OFFSET)
+
+	MOVW.EQ	$16, R(RSHIFT)		/* (R(n)<<16)|(R(n-1)>>16) */
+	MOVW.EQ	$16, R(LSHIFT)
+	MOVW.EQ	$2, R(OFFSET)
+
+	MOVW.GT	$24, R(RSHIFT)		/* (R(n)<<8)|(R(n-1)>>24) */
+	MOVW.GT	$8, R(LSHIFT)
+	MOVW.GT	$3, R(OFFSET)
+
+	ADD	$16, R(TS), R(TMP)	/* do 16-byte chunks if possible */
+	CMP	R(TMP), R(TE)
+	BLS	_b1tail
+
+	AND	$~0x03, R(FROM)		/* align source */
+	MOVW	(R(FROM)), R(BR0)	/* prime first block register */
+
+_bu16loop:
+	CMP	R(TMP), R(TE)
+	BLS	_bu1tail
+
+	MOVW	R(BR0)<<R(LSHIFT), R(BW3)
+	MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+	ORR	R(BR3)>>R(RSHIFT), R(BW3)
+
+	MOVW	R(BR3)<<R(LSHIFT), R(BW2)
+	ORR	R(BR2)>>R(RSHIFT), R(BW2)
+
+	MOVW	R(BR2)<<R(LSHIFT), R(BW1)
+	ORR	R(BR1)>>R(RSHIFT), R(BW1)
+
+	MOVW	R(BR1)<<R(LSHIFT), R(BW0)
+	ORR	R(BR0)>>R(RSHIFT), R(BW0)
+
+	MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+	B	_bu16loop
+
+_bu1tail:
+	ADD	R(OFFSET), R(FROM)
+	B	_b1tail
+
+FW0 = 7
+FR0 = 8
+FW1 = 8
+FR1 = 9
+FW2 = 9
+FR2 = 10
+FW3 = 10
+FR3 = 11
+
+_funaligned:
+	CMP	$2, R(TMP)
+
+	MOVW.LT	$8, R(RSHIFT)		/* (R(n+1)<<24)|(R(n)>>8) */
+	MOVW.LT	$24, R(LSHIFT)
+	MOVW.LT	$3, R(OFFSET)
+
+	MOVW.EQ	$16, R(RSHIFT)		/* (R(n+1)<<16)|(R(n)>>16) */
+	MOVW.EQ	$16, R(LSHIFT)
+	MOVW.EQ	$2, R(OFFSET)
+
+	MOVW.GT	$24, R(RSHIFT)		/* (R(n+1)<<8)|(R(n)>>24) */
+	MOVW.GT	$8, R(LSHIFT)
+	MOVW.GT	$1, R(OFFSET)
+
+	SUB	$16, R(TE), R(TMP)	/* do 16-byte chunks if possible */
+	CMP	R(TMP), R(TS)
+	BHS	_f1tail
+
+	AND	$~0x03, R(FROM)		/* align source */
+	MOVW.P	4(R(FROM)), R(FR3)	/* prime last block register, implicit write back */
+
+_fu16loop:
+	CMP	R(TMP), R(TS)
+	BHS	_fu1tail
+
+	MOVW	R(FR3)>>R(RSHIFT), R(FW0)
+	MOVM.IA.W (R(FROM)), [R(FR0)-R(FR3)]
+	ORR	R(FR0)<<R(LSHIFT), R(FW0)
+
+	MOVW	R(FR0)>>R(RSHIFT), R(FW1)
+	ORR	R(FR1)<<R(LSHIFT), R(FW1)
+
+	MOVW	R(FR1)>>R(RSHIFT), R(FW2)
+	ORR	R(FR2)<<R(LSHIFT), R(FW2)
+
+	MOVW	R(FR2)>>R(RSHIFT), R(FW3)
+	ORR	R(FR3)<<R(LSHIFT), R(FW3)
+
+	MOVM.IA.W [R(FW0)-R(FW3)], (R(TS))
+	B	_fu16loop
+
+_fu1tail:
+	SUB	R(OFFSET), R(FROM)
+	B	_f1tail
--- /dev/null
+++ b/libkern/memmove.c
@@ -1,0 +1,29 @@
+#include	<lib9.h>
+
+/* for testing only */
+void*
+memcpy(void *a1, void *a2, ulong n)
+{
+	return memmove(a1, a2, n);
+}
+
+void*
+memmove(void *a1, void *a2, ulong n)
+{
+	int m = (int)n;
+	uchar *s, *d;
+	
+	d = a1;
+	s = a2;
+	if(d > s){
+		s += m;
+		d += m;
+		while(--m >= 0)
+			*--d = *--s;
+	}
+	else{
+		while(--m >= 0)
+			*d++ = *s++;
+	}
+	return a1;
+}
--- /dev/null
+++ b/libkern/memset-386.s
@@ -1,0 +1,35 @@
+	TEXT	memset(SB),$0
+
+	CLD
+	MOVL	p+0(FP), DI
+	MOVBLZX	c+4(FP), AX
+	MOVL	n+8(FP), BX
+/*
+ * if not enough bytes, just copy
+ */
+	CMPL	BX, $9
+	JLS	c3
+/*
+ * build word in AX
+ */
+	MOVB	AL, AH
+	MOVL	AX, CX
+	SHLL	$16, CX
+	ORL	CX, AX
+/*
+ * copy whole longs
+ */
+c1:
+	MOVL	BX, CX
+	SHRL	$2, CX
+	ANDL	$3, BX
+	REP;	STOSL
+/*
+ * copy the rest, by bytes
+ */
+c3:
+	MOVL	BX, CX
+	REP;	STOSB
+ret:
+	MOVL	p+0(FP),AX
+	RET
--- /dev/null
+++ b/libkern/memset-arm.s
@@ -1,0 +1,66 @@
+TO = 1
+TOE = 2
+N = 3
+TMP = 3					/* N and TMP don't overlap */
+
+TEXT memset(SB), $0
+	MOVW	R0, R(TO)
+	MOVW	data+4(FP), R(4)
+	MOVW	n+8(FP), R(N)
+
+	ADD	R(N), R(TO), R(TOE)	/* to end pointer */
+
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	BLT	_1tail
+
+	AND	$0xFF, R(4)		/* it's a byte */
+	SLL	$8, R(4), R(TMP)	/* replicate to a word */
+	ORR	R(TMP), R(4)
+	SLL	$16, R(4), R(TMP)
+	ORR	R(TMP), R(4)
+
+_4align:				/* align on 4 */
+	AND.S	$3, R(TO), R(TMP)
+	BEQ	_4aligned
+
+	MOVBU.P	R(4), 1(R(TO))		/* implicit write back */
+	B	_4align
+
+_4aligned:
+	SUB	$31, R(TOE), R(TMP)	/* do 32-byte chunks if possible */
+	CMP	R(TMP), R(TO)
+	BHS	_4tail
+
+	MOVW	R4, R5			/* replicate */
+	MOVW	R4, R6
+	MOVW	R4, R7
+	MOVW	R4, R8
+	MOVW	R4, R9
+	MOVW	R4, R10
+	MOVW	R4, R11
+
+_f32loop:
+	CMP	R(TMP), R(TO)
+	BHS	_4tail
+
+	MOVM.IA.W [R4-R11], (R(TO))
+	B	_f32loop
+
+_4tail:
+	SUB	$3, R(TOE), R(TMP)	/* do remaining words if possible */
+_4loop:
+	CMP	R(TMP), R(TO)
+	BHS	_1tail
+
+	MOVW.P	R(4), 4(R(TO))		/* implicit write back */
+	B	_4loop
+
+_1tail:
+	CMP	R(TO), R(TOE)
+	BEQ	_return
+
+	MOVBU.P	R(4), 1(R(TO))		/* implicit write back */
+	B	_1tail
+
+_return:
+	RET
--- /dev/null
+++ b/libkern/memset-mips.s
@@ -1,0 +1,88 @@
+	TEXT	memset(SB),$12
+MOVW R1, 0(FP)
+
+/*
+ * performance:
+ *	about 1us/call and 28mb/sec
+ */
+
+	MOVW	n+8(FP), R3		/* R3 is count */
+	MOVW	p+0(FP), R4		/* R4 is pointer */
+	MOVW	c+4(FP), R5		/* R5 is char */
+	ADDU	R3,R4, R6		/* R6 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+	SGT	$4,R3, R1
+	BNE	R1, out
+
+/*
+ * turn R5 into a word of characters
+ */
+	AND	$0xff, R5
+	SLL	$8,R5, R1
+	OR	R1, R5
+	SLL	$16,R5, R1
+	OR	R1, R5
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+	AND	$3,R4, R1
+	BEQ	R1, l2
+	MOVB	R5, 0(R4)
+	ADDU	$1, R4
+	JMP	l1
+
+/*
+ * turn R3 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+	ADDU	$-15,R6, R3
+l3:
+	SGTU	R3,R4, R1
+	BEQ	R1, l4
+	MOVW	R5, 0(R4)
+	MOVW	R5, 4(R4)
+	ADDU	$16, R4
+	MOVW	R5, -8(R4)
+	MOVW	R5, -4(R4)
+	JMP	l3
+
+/*
+ * turn R3 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+	ADDU	$-3,R6, R3
+l5:
+	SGTU	R3,R4, R1
+	BEQ	R1, out
+	MOVW	R5, 0(R4)
+	ADDU	$4, R4
+	JMP	l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+	SGTU	R6,R4 ,R1
+	BEQ	R1, ret
+	MOVB	R5, 0(R4)
+	ADDU	$1, R4
+	JMP	out
+
+ret:
+	MOVW	s1+0(FP), R1
+	RET
+	END
--- /dev/null
+++ b/libkern/memset-power.s
@@ -1,0 +1,73 @@
+	TEXT	memset(SB),$0
+#define	BDNZ	BC	16,0,
+	MOVW R3, p+0(FP)		/* R3 is pointer */
+
+/*
+ * performance:
+ *	about 100mbytes/sec (8k blocks) on a 603/105 without L2 cache
+ *	drops to 40mbytes/sec (10k blocks) and 28mbytes/sec with 32k blocks
+ */
+
+	MOVW	n+8(FP), R4		/* R4 is count */
+	CMP	R4, $0
+	BLE	ret
+	MOVW	c+4(FP), R5		/* R5 is char */
+
+/*
+ * create 16 copies of c in R5 .. R8
+ */
+	RLWNM	$0, R5, $0xff, R5
+	RLWMI	$8, R5, $0xff00, R5
+	RLWMI	$16, R5, $0xffff0000, R5
+	MOVW	R5, R6
+	MOVW	R5, R7
+	MOVW	R5, R8
+
+/*
+ * let STSW do the work for 16 characters or less; aligned and unaligned
+ */
+	CMP	R4, $16
+	BLE	out
+
+/*
+ * store enough bytes to align pointer
+ */
+	ANDCC	$7,R3, R9
+	BEQ	l2
+	SUBC	R9, $8, R9
+	MOVW	R9, XER
+	STSW	R5, (R3)
+	ADD	R9, R3
+	SUB	R9, R4
+
+/*
+ * store 16 at a time while there's room
+ * STSW was used here originally, but it's `completion serialised'
+ */
+l2:
+	SRAWCC	$4, R4, R9
+	BLE	out
+	MOVW	R9, CTR
+l3:
+	MOVW	R5, 0(R3)
+	ADD	$8, R3, R10
+	MOVW	R6, 4(R3)
+	MOVW	R7, 0(R10)
+	ADD	$8, R10, R3
+	MOVW	R8, 4(R10)
+	BDNZ	l3
+	RLWNMCC	$0, R4, $15, R4	/* residue */
+	BEQ	ret
+
+/*
+ * store up to 16 bytes from R5 .. R8; aligned and unaligned
+ */
+
+out:
+	MOVW	R4, XER
+	STSW	R5, (R3)
+
+ret:
+	MOVW	0(FP), R3
+	RETURN
+	END
--- /dev/null
+++ b/libkern/memset-sparc.s
@@ -1,0 +1,88 @@
+	TEXT	memset(SB),$0
+
+/*
+ * performance:
+ *	(tba)
+ */
+
+MOVW	R7, 0(FP)
+	MOVW	n+8(FP), R9		/* R9 is count */
+	MOVW	p+0(FP), R10		/* R10 is pointer */
+	MOVW	c+4(FP), R11		/* R11 is char */
+	ADD	R9,R10, R12		/* R12 is end pointer */
+
+/*
+ * if not at least 4 chars,
+ * dont even mess around.
+ * 3 chars to guarantee any
+ * rounding up to a word
+ * boundary and 4 characters
+ * to get at least maybe one
+ * full word store.
+ */
+	SUBCC	$4,R9, R0
+	BL	out
+
+/*
+ * turn R11 into a word of characters
+ */
+	AND	$0xff, R11
+	SLL	$8,R11, R7
+	OR	R7, R11
+	SLL	$16,R11, R7
+	OR	R7, R11
+
+/*
+ * store one byte at a time until pointer
+ * is alligned on a word boundary
+ */
+l1:
+	ANDCC	$3,R10, R0
+	BE	l2
+	MOVB	R11, 0(R10)
+	ADD	$1, R10
+	JMP	l1
+
+/*
+ * turn R9 into end pointer-15
+ * store 16 at a time while theres room
+ */
+l2:
+	ADD	$-15,R12, R9
+	SUBCC	R10,R9, R0
+	BLEU	l4
+l3:
+	MOVW	R11, 0(R10)
+	MOVW	R11, 4(R10)
+	ADD	$16, R10
+	SUBCC	R10,R9, R0
+	MOVW	R11, -8(R10)
+	MOVW	R11, -4(R10)
+	BGU	l3
+
+/*
+ * turn R9 into end pointer-3
+ * store 4 at a time while theres room
+ */
+l4:
+	ADD	$-3,R12, R9
+l5:
+	SUBCC	R10,R9, R0
+	BLEU	out
+	MOVW	R11, 0(R10)
+	ADD	$4, R10
+	JMP	l5
+
+/*
+ * last loop, store byte at a time
+ */
+out:
+	SUBCC	R10,R12, R0
+	BLEU	ret
+	MOVB	R11, 0(R10)
+	ADD	$1, R10
+	JMP	out
+
+ret:
+	MOVW	s1+0(FP), R7
+	RETURN
--- /dev/null
+++ b/libkern/memset-spim.s
@@ -1,0 +1,1 @@
+#include "memset-mips.s"
--- /dev/null
+++ b/libkern/memset-thumb.s
@@ -1,0 +1,66 @@
+TO = 1
+TOE = 2
+N = 3
+TMP = 3					/* N and TMP don't overlap */
+
+TEXT memset(SB), $0
+	MOVW	R0, R(TO)
+	MOVW	data+4(FP), R(4)
+	MOVW	n+8(FP), R(N)
+
+	ADD	R(N), R(TO), R(TOE)	/* to end pointer */
+
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	BLT	_1tail
+
+	AND	$0xFF, R(4)		/* it's a byte */
+	SLL	$8, R(4), R(TMP)	/* replicate to a word */
+	ORR	R(TMP), R(4)
+	SLL	$16, R(4), R(TMP)
+	ORR	R(TMP), R(4)
+
+_4align:				/* align on 4 */
+	AND.S	$3, R(TO), R(TMP)
+	BEQ	_4aligned
+
+	MOVBU.P	R(4), 1(R(TO))		/* implicit write back */
+	B	_4align
+
+_4aligned:
+	SUB	$31, R(TOE), R(TMP)	/* do 32-byte chunks if possible */
+	CMP	R(TMP), R(TO)
+	BHS	_4tail
+
+	MOVW	R4, R5			/* replicate */
+	MOVW	R4, R6
+	MOVW	R4, R7
+	MOVW	R4, R8
+	MOVW	R4, R9
+	MOVW	R4, R10
+	MOVW	R4, R11
+
+_f32loop:
+	CMP	R(TMP), R(TO)
+	BHS	_4tail
+
+	MOVM.IA.W [R4-R11], (R(TO))
+	B	_f32loop
+
+_4tail:
+	SUB	$3, R(TOE), R(TMP)	/* do remaining words if possible */
+_4loop:
+	CMP	R(TMP), R(TO)
+	BHS	_1tail
+
+	MOVW.P	R(4), 4(R(TO))		/* implicit write back */
+	B	_4loop
+
+_1tail:
+	CMP	R(TO), R(TOE)
+	BEQ	_return
+
+	MOVBU.P	R(4), 1(R(TO))		/* implicit write back */
+	B	_1tail
+
+_return:
+	RET
--- /dev/null
+++ b/libkern/memset.c
@@ -1,0 +1,15 @@
+#include	<lib9.h>
+
+void*
+memset(void *ap, int c, ulong n)
+{
+	char *p;
+	int m = (int)n;
+
+	p = ap;
+	while(m > 0) {
+		*p++ = c;
+		m--;
+	}
+	return ap;
+}
--- /dev/null
+++ b/libkern/mkfile
@@ -1,0 +1,83 @@
+<../mkconfig
+
+LIB=libkern.a
+
+COMMONFILES=\
+	abort.$O\
+	abs.$O\
+	atol.$O\
+	charstod.$O\
+	cistrcmp.$O\
+	cistrncmp.$O\
+	cistrstr.$O\
+	cleanname.$O\
+	convD2M.$O\
+	convM2D.$O\
+	convM2S.$O\
+	convS2M.$O\
+	dofmt.$O\
+	exp.$O\
+	fcallfmt.$O\
+	floor.$O\
+	fmt.$O\
+	fmtprint.$O\
+	fmtquote.$O\
+	fmtstr.$O\
+	fmtvprint.$O\
+	getfields.$O\
+	log.$O\
+	memccpy.$O\
+	memchr.$O\
+	memcmp.$O\
+#	netmkaddr.$O\
+	pow.$O\
+	pow10.$O\
+	qsort.$O\
+	rune.$O\
+	runestrlen.$O\
+	sin.$O\
+	seprint.$O\
+	smprint.$O\
+	snprint.$O\
+	sqrt.$O\
+	strcat.$O\
+	strcmp.$O\
+	strcpy.$O\
+	strdup.$O\
+	strecpy.$O\
+	strlen.$O\
+	strncmp.$O\
+	strncpy.$O\
+	strrchr.$O\
+	strstr.$O\
+	strtod.$O\
+	strtol.$O\
+	strtoll.$O\
+	strtoul.$O\
+	strtoull.$O\
+	tokenize.$O\
+	toupper.$O\
+	u16.$O\
+	u32.$O\
+	u64.$O\
+	utfecpy.$O\
+	utflen.$O\
+	utfnlen.$O\
+	utfrrune.$O\
+	utfrune.$O\
+	vseprint.$O\
+	vsmprint.$O\
+	vsnprint.$O\
+
+<mkfile-$OBJTYPE		#sets $TARGFILES
+
+OFILES=	$COMMONFILES $TARGFILES
+HFILES=	fmtdef.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+convD2M.$O: $ROOT/include/fcall.h
+convM2D.$O: $ROOT/include/fcall.h
+convM2S.$O: $ROOT/include/fcall.h
+convS2M.$O: $ROOT/include/fcall.h
+fcallfmt.$O: $ROOT/include/fcall.h
--- /dev/null
+++ b/libkern/mkfile-386
@@ -1,0 +1,12 @@
+#
+#	386-specific files
+#
+TARGFILES=\
+	frexp-386.$O\
+	getfcr-386.$O\
+	memmove-386.$O\
+	memset-386.$O\
+	nan-386.$O\
+	strchr-386.$O\
+	vlop-386.$O\
+	vlrt-386.$O\
--- /dev/null
+++ b/libkern/mkfile-arm
@@ -1,0 +1,13 @@
+#
+#	arm-specific files
+#
+TARGFILES=\
+	frexp-arm.$O\
+	getfcr-arm.$O\
+	memmove-arm.$O\
+	memset-arm.$O\
+	nan-arm.$O\
+	strchr-arm.$O\
+	vlop-arm.$O\
+	vlrt-arm.$O\
+	div-arm.$O\
--- /dev/null
+++ b/libkern/mkfile-mips
@@ -1,0 +1,13 @@
+#
+#	mips-specific files
+#
+TARGFILES=\
+	frexp-mips.$O\
+	getfcr-mips.$O\
+	memmove-mips.$O\
+	memset-mips.$O\
+	nan-mips.$O\
+	strchr-mips.$O\
+	vlop-mips.$O\
+	vlrt-mips.$O\
+
--- /dev/null
+++ b/libkern/mkfile-power
@@ -1,0 +1,13 @@
+#
+#	power-specific files
+#
+TARGFILES=\
+	frexp-power.$O\
+	getfcr-power.$O\
+	memmove-power.$O\
+	memset-power.$O\
+	nan-power.$O\
+	strchr-power.$O\
+	vlop-power.$O\
+	vlrt-power.$O\
+
--- /dev/null
+++ b/libkern/mkfile-sparc
@@ -1,0 +1,13 @@
+#
+#	sparc-specific files
+#
+TARGFILES=\
+	frexp-sparc.$O\
+	getfcr-sparc.$O\
+	memmove-sparc.$O\
+	memset-sparc.$O\
+	nan-sparc.$O\
+	strchr-sparc.$O\
+	vlop-sparc.$O\
+	vlrt-sparc.$O\
+
--- /dev/null
+++ b/libkern/mkfile-spim
@@ -1,0 +1,8 @@
+#
+#	spim-specific files
+#
+TARGFILES=\
+	getfcr-spim.$O\
+	memmove-spim.$O\
+	memset-spim.$O\
+	strchr-spim.$O\
--- /dev/null
+++ b/libkern/mkfile-thumb
@@ -1,0 +1,13 @@
+#
+#	thumb-specific files
+#
+TARGFILES=\
+	frexp-thumb.$O\
+	getfcr-thumb.$O\
+	memmove-thumb.$O\
+	memset-thumb.$O\
+	nan-thumb.$O\
+	strchr-thumb.$O\
+	vlop-thumb.$O\
+	vlrt-thumb.$O\
+	div-thumb.$O\
--- /dev/null
+++ b/libkern/nan-386.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define	NANEXP	(2047<<20)
+#define	NANMASK	(2047<<20)
+#define	NANSIGN	(1<<31)
+
+double
+NaN(void)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[1] = NANEXP;
+	a.x[0] = 1;
+	return a.d;
+}
+
+int
+isNaN(double d)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if((a.x[1] & NANMASK) != NANEXP)
+		return 0;
+	return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[1] = NANEXP;
+	a.x[0] = 0;
+	if(sign < 0)
+		a.x[1] |= NANSIGN;
+	return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if(a.x[0] != 0)
+		return 0;
+	if(a.x[1] == NANEXP)
+		return sign >= 0;
+	if(a.x[1] == (NANEXP|NANSIGN))
+		return sign <= 0;
+	return 0;
+}
--- /dev/null
+++ b/libkern/nan-arm.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define	NANEXP	(2047<<20)
+#define	NANMASK	(2047<<20)
+#define	NANSIGN	(1<<31)
+
+double
+NaN(void)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[1] = NANEXP;
+	a.x[0] = 1;
+	return a.d;
+}
+
+int
+isNaN(double d)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if((a.x[1] & NANMASK) != NANEXP)
+		return 0;
+	return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[1] = NANEXP;
+	a.x[0] = 0;
+	if(sign < 0)
+		a.x[1] |= NANSIGN;
+	return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if(a.x[0] != 0)
+		return 0;
+	if(a.x[1] == NANEXP)
+		return sign >= 0;
+	if(a.x[1] == (NANEXP|NANSIGN))
+		return sign <= 0;
+	return 0;
+}
--- /dev/null
+++ b/libkern/nan-mips.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define	NANEXP	(2047<<20)
+#define	NANMASK	(2047<<20)
+#define	NANSIGN	(1<<31)
+
+double
+NaN(void)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 1;
+	return a.d;
+}
+
+int
+isNaN(double d)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if((a.x[0] & NANMASK) != NANEXP)
+		return 0;
+	return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 0;
+	if(sign < 0)
+		a.x[0] |= NANSIGN;
+	return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if(a.x[1] != 0)
+		return 0;
+	if(a.x[0] == NANEXP)
+		return sign >= 0;
+	if(a.x[0] == (NANEXP|NANSIGN))
+		return sign <= 0;
+	return 0;
+}
--- /dev/null
+++ b/libkern/nan-power.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define	NANEXP	(2047<<20)
+#define	NANMASK	(2047<<20)
+#define	NANSIGN	(1<<31)
+
+double
+NaN(void)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 1;
+	return a.d;
+}
+
+int
+isNaN(double d)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if((a.x[0] & NANMASK) != NANEXP)
+		return 0;
+	return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 0;
+	if(sign < 0)
+		a.x[0] |= NANSIGN;
+	return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if(a.x[1] != 0)
+		return 0;
+	if(a.x[0] == NANEXP)
+		return sign >= 0;
+	if(a.x[0] == (NANEXP|NANSIGN))
+		return sign <= 0;
+	return 0;
+}
--- /dev/null
+++ b/libkern/nan-sparc.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define	NANEXP	(2047<<20)
+#define	NANMASK	(2047<<20)
+#define	NANSIGN	(1<<31)
+
+double
+NaN(void)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 1;
+	return a.d;
+}
+
+int
+isNaN(double d)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if((a.x[0] & NANMASK) != NANEXP)
+		return 0;
+	return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 0;
+	if(sign < 0)
+		a.x[0] |= NANSIGN;
+	return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if(a.x[1] != 0)
+		return 0;
+	if(a.x[0] == NANEXP)
+		return sign >= 0;
+	if(a.x[0] == (NANEXP|NANSIGN))
+		return sign <= 0;
+	return 0;
+}
--- /dev/null
+++ b/libkern/nan-spim.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define	NANEXP	(2047<<20)
+#define	NANMASK	(2047<<20)
+#define	NANSIGN	(1<<31)
+
+double
+NaN(void)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[1] = NANEXP;
+	a.x[0] = 1;
+	return a.d;
+}
+
+int
+isNaN(double d)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if((a.x[1] & NANMASK) != NANEXP)
+		return 0;
+	return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[1] = NANEXP;
+	a.x[0] = 0;
+	if(sign < 0)
+		a.x[1] |= NANSIGN;
+	return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if(a.x[0] != 0)
+		return 0;
+	if(a.x[1] == NANEXP)
+		return sign >= 0;
+	if(a.x[1] == (NANEXP|NANSIGN))
+		return sign <= 0;
+	return 0;
+}
--- /dev/null
+++ b/libkern/nan-thumb.c
@@ -1,0 +1,69 @@
+#include <lib9.h>
+
+#define	NANEXP	(2047<<20)
+#define	NANMASK	(2047<<20)
+#define	NANSIGN	(1<<31)
+
+double
+NaN(void)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 1;
+	return a.d;
+}
+
+int
+isNaN(double d)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if((a.x[0] & NANMASK) != NANEXP)
+		return 0;
+	return !isInf(d, 0);
+}
+
+double
+Inf(int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.x[0] = NANEXP;
+	a.x[1] = 0;
+	if(sign < 0)
+		a.x[0] |= NANSIGN;
+	return a.d;
+}
+
+int
+isInf(double d, int sign)
+{
+	union
+	{
+		double	d;
+		long	x[2];
+	} a;
+
+	a.d = d;
+	if(a.x[1] != 0)
+		return 0;
+	if(a.x[0] == NANEXP)
+		return sign >= 0;
+	if(a.x[0] == (NANEXP|NANSIGN))
+		return sign <= 0;
+	return 0;
+}
--- /dev/null
+++ b/libkern/netmkaddr.c
@@ -1,0 +1,50 @@
+#include <lib9.h>
+
+/*
+ *  make an address, add the defaults
+ */
+char *
+netmkaddr(char *linear, char *defnet, char *defsrv)
+{
+	static char addr[4*(NAMELEN+1)];
+	char *cp;
+
+	/*
+	 *  dump network name
+	 */
+	cp = strchr(linear, '!');
+	if(cp == 0){
+		if(defnet==0){
+			if(defsrv)
+				sprint(addr, "net!%.*s!%.*s", 2*NAMELEN, linear,
+					NAMELEN, defsrv);
+			else
+				sprint(addr, "net!%.*s", 2*NAMELEN, linear);
+		} else {
+			if(defsrv)
+				sprint(addr, "%.*s!%.*s!%.*s", NAMELEN, defnet,
+					2*NAMELEN, linear, NAMELEN, defsrv);
+			else
+				sprint(addr, "%.*s!%.*s", NAMELEN, defnet,
+					2*NAMELEN, linear);
+		}
+		return addr;
+	}
+
+	/*
+	 *  if there is already a service, use it
+	 */
+	cp = strchr(cp+1, '!');
+	if(cp)
+		return linear;
+
+	/*
+	 *  add default service
+	 */
+	if(defsrv == 0)
+		return linear;
+	sprint(addr, "%.*s!%.*s", 3*NAMELEN, linear,
+		NAMELEN, defsrv);
+
+	return addr;
+}
--- /dev/null
+++ b/libkern/pow.c
@@ -1,0 +1,68 @@
+#include <lib9.h>
+
+double
+pow(double x, double y) /* return x ^ y (exponentiation) */
+{
+	double xy, y1, ye;
+	long i;
+	int ex, ey, flip;
+
+	if(y == 0.0)
+		return 1.0;
+
+	flip = 0;
+	if(y < 0.){
+		y = -y;
+		flip = 1;
+	}
+	y1 = modf(y, &ye);
+	if(y1 != 0.0){
+		if(x <= 0.)
+			goto zreturn;
+		if(y1 > 0.5) {
+			y1 -= 1.;
+			ye += 1.;
+		}
+		xy = exp(y1 * log(x));
+	}else
+		xy = 1.0;
+	if(ye > 0x7FFFFFFF){	/* should be ~0UL but compiler can't convert double to ulong */
+		if(x <= 0.){
+ zreturn:
+			if(x==0. && !flip)
+				return 0.;
+			return NaN();
+		}
+		if(flip){
+			if(y == .5)
+				return 1./sqrt(x);
+			y = -y;
+		}else if(y == .5)
+			return sqrt(x);
+		return exp(y * log(x));
+	}
+	x = frexp(x, &ex);
+	ey = 0;
+	i = ye;
+	if(i)
+		for(;;){
+			if(i & 1){
+				xy *= x;
+				ey += ex;
+			}
+			i >>= 1;
+			if(i == 0)
+				break;
+			x *= x;
+			ex <<= 1;
+			if(x < .5){
+				x += x;
+				ex -= 1;
+			}
+		}
+	if(flip){
+		xy = 1. / xy;
+		ey = -ey;
+	}
+	return ldexp(xy, ey);
+}
--- /dev/null
+++ b/libkern/pow10.c
@@ -1,0 +1,51 @@
+#ifdef	LINUX_386
+#define	_MATH_H
+#endif
+#include	"lib9.h"
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+static
+double	tab[] =
+{
+	1.0e0,  1.0e1,  1.0e2,  1.0e3,  1.0e4,  1.0e5,  1.0e6,  1.0e7,  1.0e8,  1.0e9, 
+	1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19, 
+	1.0e20, 1.0e21, 1.0e22, 1.0e23, 1.0e24, 1.0e25, 1.0e26, 1.0e27, 1.0e28, 1.0e29, 
+	1.0e30, 1.0e31, 1.0e32, 1.0e33, 1.0e34, 1.0e35, 1.0e36, 1.0e37, 1.0e38, 1.0e39, 
+	1.0e40, 1.0e41, 1.0e42, 1.0e43, 1.0e44, 1.0e45, 1.0e46, 1.0e47, 1.0e48, 1.0e49, 
+	1.0e50, 1.0e51, 1.0e52, 1.0e53, 1.0e54, 1.0e55, 1.0e56, 1.0e57, 1.0e58, 1.0e59, 
+	1.0e60, 1.0e61, 1.0e62, 1.0e63, 1.0e64, 1.0e65, 1.0e66, 1.0e67, 1.0e68, 1.0e69, 
+	1.0e70, 1.0e71, 1.0e72, 1.0e73, 1.0e74, 1.0e75, 1.0e76, 1.0e77, 1.0e78, 1.0e79, 
+	1.0e80, 1.0e81, 1.0e82, 1.0e83, 1.0e84, 1.0e85, 1.0e86, 1.0e87, 1.0e88, 1.0e89, 
+	1.0e90, 1.0e91, 1.0e92, 1.0e93, 1.0e94, 1.0e95, 1.0e96, 1.0e97, 1.0e98, 1.0e99, 
+	1.0e100,1.0e101,1.0e102,1.0e103,1.0e104,1.0e105,1.0e106,1.0e107,1.0e108,1.0e109,
+	1.0e110,1.0e111,1.0e112,1.0e113,1.0e114,1.0e115,1.0e116,1.0e117,1.0e118,1.0e119,
+	1.0e120,1.0e121,1.0e122,1.0e123,1.0e124,1.0e125,1.0e126,1.0e127,1.0e128,1.0e129,
+	1.0e130,1.0e131,1.0e132,1.0e133,1.0e134,1.0e135,1.0e136,1.0e137,1.0e138,1.0e139,
+	1.0e140,1.0e141,1.0e142,1.0e143,1.0e144,1.0e145,1.0e146,1.0e147,1.0e148,1.0e149,
+	1.0e150,1.0e151,1.0e152,1.0e153,1.0e154,1.0e155,1.0e156,1.0e157,1.0e158,1.0e159,
+};
+
+double
+pow10(int n)
+{
+	int m;
+
+	if(n < 0) {
+		n = -n;
+		if(n < sizeof(tab)/sizeof(tab[0]))
+			return 1/tab[n];
+		m = n/2;
+		return 1/(pow10(m) * pow10(n-m));
+	}
+	if(n < sizeof(tab)/sizeof(tab[0]))
+		return tab[n];
+	m = n/2;
+	return pow10(m) * pow10(n-m);
+}
--- /dev/null
+++ b/libkern/qsort.c
@@ -1,0 +1,123 @@
+/*
+ * qsort -- simple quicksort
+ */
+
+#include "lib9.h"
+typedef
+struct
+{
+	int	(*cmp)(void*, void*);
+	void	(*swap)(char*, char*, long);
+	long	es;
+} Sort;
+
+static	void
+swapb(char *i, char *j, long es)
+{
+	char c;
+
+	do {
+		c = *i;
+		*i++ = *j;
+		*j++ = c;
+		es--;
+	} while(es != 0);
+
+}
+
+static	void
+swapi(char *ii, char *ij, long es)
+{
+	long *i, *j, c;
+
+	i = (long*)ii;
+	j = (long*)ij;
+	do {
+		c = *i;
+		*i++ = *j;
+		*j++ = c;
+		es -= sizeof(long);
+	} while(es != 0);
+}
+
+static	char*
+pivot(char *a, long n, Sort *p)
+{
+	long j;
+	char *pi, *pj, *pk;
+
+	j = n/6 * p->es;
+	pi = a + j;	/* 1/6 */
+	j += j;
+	pj = pi + j;	/* 1/2 */
+	pk = pj + j;	/* 5/6 */
+	if(p->cmp(pi, pj) < 0) {
+		if(p->cmp(pi, pk) < 0) {
+			if(p->cmp(pj, pk) < 0)
+				return pj;
+			return pk;
+		}
+		return pi;
+	}
+	if(p->cmp(pj, pk) < 0) {
+		if(p->cmp(pi, pk) < 0)
+			return pi;
+		return pk;
+	}
+	return pj;
+}
+
+static	void
+qsorts(char *a, long n, Sort *p)
+{
+	long j, es;
+	char *pi, *pj, *pn;
+
+	es = p->es;
+	while(n > 1) {
+		if(n > 10) {
+			pi = pivot(a, n, p);
+		} else
+			pi = a + (n>>1)*es;
+
+		p->swap(a, pi, es);
+		pi = a;
+		pn = a + n*es;
+		pj = pn;
+		for(;;) {
+			do
+				pi += es;
+			while(pi < pn && p->cmp(pi, a) < 0);
+			do
+				pj -= es;
+			while(pj > a && p->cmp(pj, a) > 0);
+			if(pj < pi)
+				break;
+			p->swap(pi, pj, es);
+		}
+		p->swap(a, pj, es);
+		j = (pj - a) / es;
+
+		n = n-j-1;
+		if(j >= n) {
+			qsorts(a, j, p);
+			a += (j+1)*es;
+		} else {
+			qsorts(a + (j+1)*es, n, p);
+			n = j;
+		}
+	}
+}
+
+void
+qsort(void *va, long n, long es, int (*cmp)(void*, void*))
+{
+	Sort s;
+
+	s.cmp = cmp;
+	s.es = es;
+	s.swap = swapi;
+	if(((uintptr)va | es) % sizeof(long))
+		s.swap = swapb;
+	qsorts((char*)va, n, &s);
+}
--- /dev/null
+++ b/libkern/rune.c
@@ -1,0 +1,165 @@
+#include	"lib9.h"
+
+#define Bit(i) (7-(i))
+/* N 0's preceded by i 1's, T(Bit(2)) is 1100 0000 */
+#define T(i) (((1 << (Bit(i)+1))-1) ^ 0xFF)
+/* 0000 0000 0000 0111 1111 1111 */
+#define	RuneX(i) ((1 << (Bit(i) + ((i)-1)*Bitx))-1)
+
+enum
+{
+	Bitx	= Bit(1),
+
+	Tx	= T(1),			/* 1000 0000 */
+	Rune1 = (1<<(Bit(0)+0*Bitx))-1,	/* 0000 0000 0000 0000 0111 1111 */
+
+	Maskx	= (1<<Bitx)-1,		/* 0011 1111 */
+	Testx	= Maskx ^ 0xFF,		/* 1100 0000 */
+
+	SurrogateMin	= 0xD800,
+	SurrogateMax	= 0xDFFF,
+
+	Bad	= Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+	int c[UTFmax], i;
+	Rune l;
+
+	/*
+	 * N character sequence
+	 *	00000-0007F => T1
+	 *	00080-007FF => T2 Tx
+	 *	00800-0FFFF => T3 Tx Tx
+	 *	10000-10FFFF => T4 Tx Tx Tx
+	 */
+
+	c[0] = *(uchar*)(str);
+	if(c[0] < Tx){
+		*rune = c[0];
+		return 1;
+	}
+	l = c[0];
+
+	for(i = 1; i < UTFmax; i++) {
+		c[i] = *(uchar*)(str+i);
+		c[i] ^= Tx;
+		if(c[i] & Testx)
+			goto bad;
+		l = (l << Bitx) | c[i];
+		if(c[0] < T(i + 2)) {
+			l &= RuneX(i + 1);
+			if(i == 1) {
+				if(c[0] < T(2) || l <= Rune1)
+					goto bad;
+			} else if(l <= RuneX(i) || l > Runemax)
+				goto bad;
+			if (i == 2 && SurrogateMin <= l && l <= SurrogateMax)
+				goto bad;
+			*rune = l;
+			return i + 1;
+		}
+	}
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	*rune = Bad;
+	return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+	int i, j;
+	Rune c;
+
+	c = *rune;
+	if(c <= Rune1) {
+		str[0] = c;
+		return 1;
+	}
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => 00-7F
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 * four character sequence (21-bit value)
+	 *     10000-1FFFFF => T4 Tx Tx Tx
+	 * If the Rune is out of range or a surrogate half,
+	 * convert it to the error rune.
+	 * Do this test when i==3 because the error rune encodes to three bytes.
+	 * Doing it earlier would duplicate work, since an out of range
+	 * Rune wouldn't have fit in one or two bytes.
+	 */
+	for(i = 2; i < UTFmax + 1; i++){
+		if(i == 3){
+			if(c > Runemax)
+				c = Runeerror;
+			if(SurrogateMin <= c && c <= SurrogateMax)
+				c = Runeerror;
+		}
+		if (c <= RuneX(i) || i == UTFmax ) {
+			str[0] = T(i) |  (c >> (i - 1)*Bitx);
+			for(j = 1; j < i; j++)
+				str[j] = Tx | ((c >> (i - j - 1)*Bitx) & Maskx);
+			return i;
+		}
+	}
+	return UTFmax;
+}
+
+int
+runelen(long c)
+{
+	Rune rune;
+	char str[10];
+
+	rune = c;
+	return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+	int nb, i;
+	Rune c;
+
+	nb = 0;
+	while(nrune--) {
+		c = *r++;
+		if(c <= Rune1){
+			nb++;
+		} else {
+			for(i = 2; i < UTFmax + 1; i++)
+				if(c <= RuneX(i) || i == UTFmax){
+					nb += i;
+					break;
+				}
+		}
+	}
+	return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+	int  i;
+	Rune c;
+
+	if(n <= 0)
+		return 0;
+	c = *(uchar*)str;
+	if(c < Tx)
+		return 1;
+	for(i = 3; i < UTFmax + 1; i++)
+		if(c < T(i))
+			return n >= i - 1;
+	return n >= UTFmax;
+}
--- /dev/null
+++ b/libkern/runestrlen.c
@@ -1,0 +1,13 @@
+#include "lib9.h"
+
+
+long
+runestrlen(Rune *s)
+{
+	int i;
+
+	i = 0;
+	while(*s++)
+		i++;
+	return i;
+}
--- /dev/null
+++ b/libkern/seprint.c
@@ -1,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+	char *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = vseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}
--- /dev/null
+++ b/libkern/sin.c
@@ -1,0 +1,67 @@
+/*
+	C program for floating point sin/cos.
+	Calls modf.
+	There are no error exits.
+	Coefficients are #3370 from Hart & Cheney (18.80D).
+*/
+
+#include <lib9.h>
+
+#define p0      .1357884097877375669092680e8
+#define p1     -.4942908100902844161158627e7
+#define p2      .4401030535375266501944918e6
+#define p3     -.1384727249982452873054457e5
+#define p4      .1459688406665768722226959e3
+#define q0      .8644558652922534429915149e7
+#define q1      .4081792252343299749395779e6
+#define q2      .9463096101538208180571257e4
+#define q3      .1326534908786136358911494e3
+
+static
+double
+sinus(double arg, int quad)
+{
+	double e, f, ysq, x, y, temp1, temp2;
+	int k;
+
+	x = arg;
+	if(x < 0) {
+		x = -x;
+		quad += 2;
+	}
+	x *= 1/PIO2;	/* underflow? */
+	if(x > 32764) {
+		y = modf(x, &e);
+		e += quad;
+		modf(0.25*e, &f);
+		quad = e - 4*f;
+	} else {
+		k = x;
+		y = x - k;
+		quad += k;
+		quad &= 3;
+	}
+	if(quad & 1)
+		y = 1-y;
+	if(quad > 1)
+		y = -y;
+
+	ysq = y*y;
+	temp1 = ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y;
+	temp2 = ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0);
+	return temp1/temp2;
+}
+
+double
+cos(double arg)
+{
+	if(arg < 0)
+		arg = -arg;
+	return sinus(arg, 1);
+}
+
+double
+sin(double arg)
+{
+	return sinus(arg, 0);
+}
--- /dev/null
+++ b/libkern/smprint.c
@@ -1,0 +1,26 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+char*
+smprint(char *fmt, ...)
+{
+	va_list args;
+	char *p;
+
+	va_start(args, fmt);
+	p = vsmprint(fmt, args);
+	va_end(args);
+	return p;
+}
--- /dev/null
+++ b/libkern/snprint.c
@@ -1,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+
--- /dev/null
+++ b/libkern/sqrt.c
@@ -1,0 +1,53 @@
+/*
+	sqrt returns the square root of its floating
+	point argument. Newton's method.
+
+	calls frexp
+*/
+
+#include <lib9.h>
+
+double
+sqrt(double arg)
+{
+	double x, temp;
+	int exp, i;
+
+	if(arg <= 0) {
+		if(arg < 0)
+			return NaN();
+		return 0;
+	}
+	if(isInf(arg, 1))
+		return arg;
+	x = frexp(arg, &exp);
+	while(x < 0.5) {
+		x *= 2;
+		exp--;
+	}
+	/*
+	 * NOTE
+	 * this wont work on 1's comp
+	 */
+	if(exp & 1) {
+		x *= 2;
+		exp--;
+	}
+	temp = 0.5 * (1.0+x);
+
+	while(exp > 60) {
+		temp *= (1L<<30);
+		exp -= 60;
+	}
+	while(exp < -60) {
+		temp /= (1L<<30);
+		exp += 60;
+	}
+	if(exp >= 0)
+		temp *= 1L << (exp/2);
+	else
+		temp /= 1L << (-exp/2);
+	for(i=0; i<=4; i++)
+		temp = 0.5*(temp + arg/temp);
+	return temp;
+}
--- /dev/null
+++ b/libkern/strcat.c
@@ -1,0 +1,9 @@
+#include <lib9.h>
+
+char*
+strcat(char *s1, char *s2)
+{
+
+	strcpy(strchr(s1, 0), s2);
+	return s1;
+}
--- /dev/null
+++ b/libkern/strchr-386.s
@@ -1,0 +1,29 @@
+	TEXT	strchr(SB),$0
+/*
+ * look for null
+ */
+	MOVL	p+0(FP), DI
+	MOVL	$-1, CX
+	MOVL	$0, AX
+	CLD
+
+	REPN;	SCASB
+
+/*
+ * look for real char
+ */
+	MOVL	DI, CX
+	MOVL	p+0(FP), DI
+	SUBL	DI, CX
+	MOVBLZX	c+4(FP), AX
+
+	REPN;	SCASB
+
+	JEQ	found
+	MOVL	$0, AX
+	RET
+
+found:
+	MOVL	DI, AX
+	SUBL	$1, AX
+	RET
--- /dev/null
+++ b/libkern/strchr-arm.s
@@ -1,0 +1,52 @@
+TEXT strchr(SB), $-4
+	MOVBU	c+4(FP), R1
+	CMP	$0, R1
+	BEQ	_null
+
+_strchr:				/* not looking for a null, byte at a time */
+	MOVBU.P	1(R0), R2
+	CMP	R1, R2
+	BEQ	_sub1
+
+	CMP	$0, R2
+	BNE	_strchr
+
+_return0:				/* character not found in string, return 0 */
+	MOVW	$0, R0
+	RET
+
+_null:					/* looking for null, align */
+	AND.S	$3, R0, R2
+	BEQ	_aligned
+
+	MOVBU.P	1(R0), R4
+	CMP	$0, R4
+	BEQ	_sub1
+	B	_null
+
+_aligned:
+	MOVW	$0xFF, R3		/* mask */
+
+_loop:
+	MOVW.P	4(R0), R4		/* 4 at a time */
+	TST	R4, R3			/* AND.S R2, R3, Rx */
+	BEQ	_sub4
+	TST	R4>>8, R3
+	BEQ	_sub3
+	TST	R4>>16, R3
+	BEQ	_sub2
+	TST	R4>>24, R3
+	BNE	_loop
+
+_sub1:					/* compensate for pointer increment */
+	SUB	$1, R0
+	RET
+_sub2:
+	SUB	$2, R0
+	RET
+_sub3:
+	SUB	$3, R0
+	RET
+_sub4:
+	SUB	$4, R0
+	RET
--- /dev/null
+++ b/libkern/strchr-mips.s
@@ -1,0 +1,63 @@
+	TEXT	strchr(SB), $0
+MOVW R1, 0(FP)
+	MOVB	c+7(FP), R4
+	MOVW	s+0(FP), R3
+
+	BEQ	R4, l2
+
+/*
+ * char is not null
+ */
+l1:
+	MOVB	(R3), R1
+	ADDU	$1, R3
+	BEQ	R1, ret
+	BNE	R1,R4, l1
+	JMP	rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+	AND	$3,R3, R1
+	BEQ	R1, l3
+	MOVB	(R3), R1
+	ADDU	$1, R3
+	BNE	R1, l2
+	JMP	rm1
+
+l3:
+	MOVW	$0xff000000, R6
+	MOVW	$0x00ff0000, R7
+
+l4:
+	MOVW	(R3), R5
+	ADDU	$4, R3
+	AND	R6,R5, R1
+	AND	R7,R5, R2
+	BEQ	R1, b0
+	AND	$0xff00,R5, R1
+	BEQ	R2, b1
+	AND	$0xff,R5, R2
+	BEQ	R1, b2
+	BNE	R2, l4
+
+rm1:
+	ADDU	$-1,R3, R1
+	JMP	ret
+
+b2:
+	ADDU	$-2,R3, R1
+	JMP	ret
+
+b1:
+	ADDU	$-3,R3, R1
+	JMP	ret
+
+b0:
+	ADDU	$-4,R3, R1
+	JMP	ret
+
+ret:
+	RET
--- /dev/null
+++ b/libkern/strchr-power.s
@@ -1,0 +1,16 @@
+/*
+ * BUG: it's slow
+ */
+	TEXT	strchr(SB), $0
+	MOVBZ	c+7(FP), R4
+	SUB	$1, R3
+l1:
+	MOVBZU	1(R3), R6
+	CMP	R6, R4
+	BEQ	eq
+	CMP	R6, $0
+	BNE	l1
+nf:
+	MOVW	$0, R3
+eq:
+	RETURN
--- /dev/null
+++ b/libkern/strchr-sparc.s
@@ -1,0 +1,73 @@
+	TEXT	strchr(SB), $0
+
+MOVW	R7, 0(FP)
+	MOVB	c+7(FP), R10
+	MOVW	s+0(FP), R9
+
+	SUBCC	R0,R10, R0
+	BE	l2
+
+/*
+ * char is not null
+ */
+l1:
+	MOVB	(R9), R7
+	ADD	$1, R9
+	SUBCC	R0,R7, R0
+	BE	ret
+	SUBCC	R7,R10, R0
+	BNE	l1
+	JMP	rm1
+
+/*
+ * char is null
+ * align to word
+ */
+l2:
+	ANDCC	$3,R9, R0
+	BE	l3
+	MOVB	(R9), R7
+	ADD	$1, R9
+	SUBCC	R0,R7, R0
+	BNE	l2
+	JMP	rm1
+
+/*
+ * develop byte masks
+ */
+l3:
+	MOVW	$0xff, R17
+	SLL	$8,R17, R16
+	SLL	$16,R17, R13
+	SLL	$24,R17, R12
+
+l4:
+	MOVW	(R9), R11
+	ADD	$4, R9
+	ANDCC	R12,R11, R0
+	BE	b0
+	ANDCC	R13,R11, R0
+	BE	b1
+	ANDCC	R16,R11, R0
+	BE	b2
+	ANDCC	R17,R11, R0
+	BNE	l4
+
+rm1:
+	SUB	$1,R9, R7
+	JMP	ret
+
+b2:
+	SUB	$2,R9, R7
+	JMP	ret
+
+b1:
+	SUB	$3,R9, R7
+	JMP	ret
+
+b0:
+	SUB	$4,R9, R7
+	JMP	ret
+
+ret:
+	RETURN
--- /dev/null
+++ b/libkern/strchr-spim.c
@@ -1,0 +1,18 @@
+#include <lib9.h>
+
+char*
+strchr(char *s, int c)
+{
+	char c1;
+
+	if(c == 0) {
+		while(*s++)
+			;
+		return s-1;
+	}
+
+	while(c1 = *s++)
+		if(c1 == c)
+			return s-1;
+	return 0;
+}
--- /dev/null
+++ b/libkern/strchr-spim.s
@@ -1,0 +1,1 @@
+#include "strchr-mips.s"
--- /dev/null
+++ b/libkern/strchr-thumb.s
@@ -1,0 +1,52 @@
+TEXT strchr(SB), $-4
+	MOVBU	c+4(FP), R1
+	CMP	$0, R1
+	BEQ	_null
+
+_strchr:				/* not looking for a null, byte at a time */
+	MOVBU.P	1(R0), R2
+	CMP	R1, R2
+	BEQ	_sub1
+
+	CMP	$0, R2
+	BNE	_strchr
+
+_return0:				/* character not found in string, return 0 */
+	MOVW	$0, R0
+	RET
+
+_null:					/* looking for null, align */
+	AND.S	$3, R0, R2
+	BEQ	_aligned
+
+	MOVBU.P	1(R0), R4
+	CMP	$0, R4
+	BEQ	_sub1
+	B	_null
+
+_aligned:
+	MOVW	$0xFF, R3		/* mask */
+
+_loop:
+	MOVW.P	4(R0), R4		/* 4 at a time */
+	TST	R4, R3			/* AND.S R2, R3, Rx */
+	BEQ	_sub4
+	TST	R4>>8, R3
+	BEQ	_sub3
+	TST	R4>>16, R3
+	BEQ	_sub2
+	TST	R4>>24, R3
+	BNE	_loop
+
+_sub1:					/* compensate for pointer increment */
+	SUB	$1, R0
+	RET
+_sub2:
+	SUB	$2, R0
+	RET
+_sub3:
+	SUB	$3, R0
+	RET
+_sub4:
+	SUB	$4, R0
+	RET
--- /dev/null
+++ b/libkern/strchr.c
@@ -1,0 +1,18 @@
+#include <lib9.h>
+
+char*
+strchr(char *s, int c)
+{
+	char c1;
+
+	if(c == 0) {
+		while(*s++)
+			;
+		return s-1;
+	}
+
+	while(c1 = *s++)
+		if(c1 == c)
+			return s-1;
+	return 0;
+}
--- /dev/null
+++ b/libkern/strcmp-power.s
@@ -1,0 +1,21 @@
+TEXT	strcmp(SB), $0
+
+	MOVW	s2+4(FP), R4
+
+	SUB	$1, R3
+	SUB	$1, R4
+l1:
+	MOVBZU	1(R3), R5
+	MOVBZU	1(R4), R6
+	CMP	R5, R6
+	BNE	ne
+	CMP	R5, $0
+	BNE	l1
+	MOVW	$0, R3
+	RETURN
+ne:
+	MOVW	$1, R3
+	BGT	ret
+	MOVW	$-1, R3
+ret:
+	RETURN
--- /dev/null
+++ b/libkern/strcmp.c
@@ -1,0 +1,19 @@
+#include <lib9.h>
+
+int
+strcmp(char *s1, char *s2)
+{
+	unsigned c1, c2;
+
+	for(;;) {
+		c1 = *s1++;
+		c2 = *s2++;
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		if(c1 == 0)
+			return 0;
+	}
+}
--- /dev/null
+++ b/libkern/strcpy.c
@@ -1,0 +1,15 @@
+#include <lib9.h>
+#define	N	10000
+
+char*
+strcpy(char *s1, char *s2)
+{
+	char *os1;
+
+	os1 = s1;
+	while(!memccpy(s1, s2, 0, N)) {
+		s1 += N;
+		s2 += N;
+	}
+	return os1;
+}
--- /dev/null
+++ b/libkern/strdup.c
@@ -1,0 +1,12 @@
+#include <lib9.h>
+
+char*
+strdup(char *s) 
+{  
+	char *os;
+
+	os = malloc(strlen(s) + 1);
+	if(os == 0)
+		return 0;
+	return strcpy(os, s);
+}
--- /dev/null
+++ b/libkern/strecpy.c
@@ -1,0 +1,16 @@
+#include <lib9.h>
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+	if(to >= e)
+		return to;
+	to = memccpy(to, from, '\0', e - to);
+	if(to == nil){
+		to = e - 1;
+		*to = '\0';
+	}else{
+		to--;
+	}
+	return to;
+}
--- /dev/null
+++ b/libkern/strlen.c
@@ -1,0 +1,8 @@
+#include <lib9.h>
+
+long
+strlen(char *s)
+{
+
+	return strchr(s, 0) - s;
+}
--- /dev/null
+++ b/libkern/strncmp-power.s
@@ -1,0 +1,29 @@
+TEXT	strncmp(SB), $0
+#define	BDNZ	BC	16,0,
+
+	MOVW	s2+4(FP), R4
+	MOVW	n+8(FP), R7
+
+	CMP	R7, $0
+	MOVW	R7, CTR
+	BLE	eq
+
+	SUB	$1, R3
+	SUB	$1, R4
+l1:
+	MOVBZU	1(R3), R5
+	MOVBZU	1(R4), R6
+	CMP	R5, R6
+	BNE	ne
+	CMP	R5, $0
+	BEQ	eq
+	BDNZ	l1
+eq:
+	MOVW	$0, R3
+	RETURN
+ne:
+	MOVW	$1, R3
+	BGT	ret
+	MOVW	$-1, R3
+ret:
+	RETURN
--- /dev/null
+++ b/libkern/strncmp.c
@@ -1,0 +1,21 @@
+#include <lib9.h>
+
+int
+strncmp(char *s1, char *s2, long n)
+{
+	unsigned c1, c2;
+
+	while(n > 0) {
+		c1 = *s1++;
+		c2 = *s2++;
+		n--;
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		if(c1 == 0)
+			break;
+	}
+	return 0;
+}
--- /dev/null
+++ b/libkern/strncpy.c
@@ -1,0 +1,17 @@
+#include <lib9.h>
+
+char*
+strncpy(char *s1, char *s2, long n)
+{
+	int i;
+	char *os1;
+
+	os1 = s1;
+	for(i = 0; i < n; i++)
+		if((*s1++ = *s2++) == 0) {
+			while(++i < n)
+				*s1++ = 0;
+			return os1;
+		}
+	return os1;
+}
--- /dev/null
+++ b/libkern/strrchr.c
@@ -1,0 +1,14 @@
+#include <lib9.h>
+
+char*
+strrchr(char *s, int c)
+{
+	char *r;
+
+	if(c == 0)
+		return strchr(s, 0);
+	r = 0;
+	while(s = strchr(s, c))
+		r = s++;
+	return r;
+}
--- /dev/null
+++ b/libkern/strstr.c
@@ -1,0 +1,21 @@
+#include <lib9.h>
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+strstr(char *s1, char *s2)
+{
+	char *p;
+	int f, n;
+
+	f = s2[0];
+	if(f == 0)
+		return s1;
+	n = strlen(s2);
+	for(p=strchr(s1, f); p; p=strchr(p+1, f))
+		if(strncmp(p, s2, n) == 0)
+			return p;
+	return 0;
+}
--- /dev/null
+++ b/libkern/strtod.c
@@ -1,0 +1,31 @@
+#include <lib9.h>
+
+static int
+strtodf(void *vp)
+{
+	return *(*((char**)vp))++;
+}
+
+double
+strtod(char *s, char **end)
+{
+	double d;
+	char *ss;
+	int c;
+
+	ss = s;
+	d = charstod(strtodf, &s);
+	/*
+	 * Fix cases like 2.3e+ , which charstod will consume
+	 */
+	if(end){
+		*end = --s;
+		while(s > ss){
+			c = *--s;
+			if(c!='-' && c!='+' && c!='e' && c!='E')
+				break;
+			(*end)--;
+		}
+	}
+	return d;
+}
--- /dev/null
+++ b/libkern/strtol.c
@@ -1,0 +1,94 @@
+#include <lib9.h>
+
+#define LONG_MAX	2147483647L
+#define LONG_MIN	-2147483648L
+
+long
+strtol(char *nptr, char **endptr, int base)
+{
+	char *p;
+	long n, nn;
+	int c, ovfl, v, neg, ndig;
+
+	p = nptr;
+	neg = 0;
+	n = 0;
+	ndig = 0;
+	ovfl = 0;
+
+	/*
+	 * White space
+	 */
+	for(;;p++){
+		switch(*p){
+		case ' ':
+		case '\t':
+		case '\n':
+		case '\f':
+		case '\r':
+		case '\v':
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * Sign
+	 */
+	if(*p=='-' || *p=='+')
+		if(*p++ == '-')
+			neg = 1;
+
+	/*
+	 * Base
+	 */
+	if(base==0){
+		if(*p != '0')
+			base = 10;
+		else{
+			base = 8;
+			if(p[1]=='x' || p[1]=='X'){
+				p += 2;
+				base = 16;
+			}
+		}
+	}else if(base==16 && *p=='0'){
+		if(p[1]=='x' || p[1]=='X')
+			p += 2;
+	}else if(base<0 || 36<base)
+		goto Return;
+
+	/*
+	 * Non-empty sequence of digits
+	 */
+	for(;; p++,ndig++){
+		c = *p;
+		v = base;
+		if('0'<=c && c<='9')
+			v = c - '0';
+		else if('a'<=c && c<='z')
+			v = c - 'a' + 10;
+		else if('A'<=c && c<='Z')
+			v = c - 'A' + 10;
+		if(v >= base)
+			break;
+		nn = n*base + v;
+		if(nn < n)
+			ovfl = 1;
+		n = nn;
+	}
+
+    Return:
+	if(ndig == 0)
+		p = nptr;
+	if(endptr)
+		*endptr = p;
+	if(ovfl){
+		if(neg)
+			return LONG_MIN;
+		return LONG_MAX;
+	}
+	if(neg)
+		return -n;
+	return n;
+}
--- /dev/null
+++ b/libkern/strtoll.c
@@ -1,0 +1,81 @@
+#include "lib9.h"
+
+vlong
+strtoll(const char *nptr, char **endptr, int base)
+{
+	const char *p;
+	vlong n;
+	int c, v, neg, ndig;
+
+	p = nptr;
+	neg = 0;
+	n = 0;
+	ndig = 0;
+
+	/*
+	 * White space
+	 */
+	for(;;p++){
+		switch(*p){
+		case ' ':
+		case '\t':
+		case '\n':
+		case '\f':
+		case '\r':
+		case '\v':
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * Sign
+	 */
+	if(*p=='-' || *p=='+')
+		if(*p++ == '-')
+			neg = 1;
+
+	/*
+	 * Base
+	 */
+	if(base==0){
+		if(*p != '0')
+			base = 10;
+		else{
+			base = 8;
+			if(p[1]=='x' || p[1]=='X'){
+				p += 2;
+				base = 16;
+			}
+		}
+	}else if(base==16 && *p=='0'){
+		if(p[1]=='x' || p[1]=='X')
+			p += 2;
+	}else if(base<0 || 36<base)
+		goto Return;
+
+	/*
+	 * Non-empty sequence of digits
+	 */
+	for(;; p++,ndig++){
+		c = *p;
+		v = base;
+		if('0'<=c && c<='9')
+			v = c - '0';
+		else if('a'<=c && c<='z')
+			v = c - 'a' + 10;
+		else if('A'<=c && c<='Z')
+			v = c - 'A' + 10;
+		if(v >= base)
+			break;
+		n = n*base + v;
+	}
+    Return:
+	if(ndig == 0)
+		p = nptr;
+	if(endptr)
+		*endptr = (char*) p;
+	if(neg)
+		return -n;
+	return n;
+}
--- /dev/null
+++ b/libkern/strtoul.c
@@ -1,0 +1,96 @@
+#include <lib9.h>
+
+#define ULONG_MAX	4294967295UL
+
+ulong
+strtoul(char *nptr, char **endptr, int base)
+{
+	char *p;
+	ulong n, nn, m;
+	int c, ovfl, neg, v, ndig;
+
+	p = (char*)nptr;
+	neg = 0;
+	n = 0;
+	ndig = 0;
+	ovfl = 0;
+
+	/*
+	 * White space
+	 */
+	for(;;p++){
+		switch(*p){
+		case ' ':
+		case '\t':
+		case '\n':
+		case '\f':
+		case '\r':
+		case '\v':
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * Sign
+	 */
+	if(*p=='-' || *p=='+')
+		if(*p++ == '-')
+			neg = 1;
+
+	/*
+	 * Base
+	 */
+	if(base==0){
+		if(*p != '0')
+			base = 10;
+		else{
+			base = 8;
+			if(p[1]=='x' || p[1]=='X')
+				base = 16;
+		}
+	}
+ 	if(base<2 || 36<base)
+		goto Return;
+	if(base==16 && *p=='0'){
+		if(p[1]=='x' || p[1]=='X')
+			if(('0' <= p[2] && p[2] <= '9')
+			 ||('a' <= p[2] && p[2] <= 'f')
+			 ||('A' <= p[2] && p[2] <= 'F'))
+				p += 2;
+	}
+	/*
+	 * Non-empty sequence of digits
+	 */
+	n = 0;
+	m = ULONG_MAX/base;
+	for(;; p++,ndig++){
+		c = *p;
+		v = base;
+		if('0'<=c && c<='9')
+			v = c - '0';
+		else if('a'<=c && c<='z')
+			v = c - 'a' + 10;
+		else if('A'<=c && c<='Z')
+			v = c - 'A' + 10;
+		if(v >= base)
+			break;
+		if(n > m)
+			ovfl = 1;
+		nn = n*base + v;
+		if(nn < n)
+			ovfl = 1;
+		n = nn;
+	}
+
+    Return:
+	if(ndig == 0)
+		p = nptr;
+	if(endptr)
+		*endptr = p;
+	if(ovfl)
+		return ULONG_MAX;
+	if(neg)
+		return -n;
+	return n;
+}
--- /dev/null
+++ b/libkern/strtoull.c
@@ -1,0 +1,96 @@
+#include <lib9.h>
+
+#define UVLONG_MAX	(1LL<<63)
+
+uvlong
+strtoull(char *nptr, char **endptr, int base)
+{
+	char *p;
+	uvlong n, nn, m;
+	int c, ovfl, v, neg, ndig;
+
+	p = nptr;
+	neg = 0;
+	n = 0;
+	ndig = 0;
+	ovfl = 0;
+
+	/*
+	 * White space
+	 */
+	for(;; p++) {
+		switch(*p) {
+		case ' ':
+		case '\t':
+		case '\n':
+		case '\f':
+		case '\r':
+		case '\v':
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * Sign
+	 */
+	if(*p == '-' || *p == '+')
+		if(*p++ == '-')
+			neg = 1;
+
+	/*
+	 * Base
+	 */
+	if(base == 0) {
+		base = 10;
+		if(*p == '0') {
+			base = 8;
+			if(p[1] == 'x' || p[1] == 'X'){
+				p += 2;
+				base = 16;
+			}
+		}
+	} else
+	if(base == 16 && *p == '0') {
+		if(p[1] == 'x' || p[1] == 'X')
+			p += 2;
+	} else
+	if(base < 0 || 36 < base)
+		goto Return;
+
+	/*
+	 * Non-empty sequence of digits
+	 */
+	m = UVLONG_MAX/base;
+	for(;; p++,ndig++) {
+		c = *p;
+		v = base;
+		if('0' <= c && c <= '9')
+			v = c - '0';
+		else
+		if('a' <= c && c <= 'z')
+			v = c - 'a' + 10;
+		else
+		if('A' <= c && c <= 'Z')
+			v = c - 'A' + 10;
+		if(v >= base)
+			break;
+		if(n > m)
+			ovfl = 1;
+		nn = n*base + v;
+		if(nn < n)
+			ovfl = 1;
+		n = nn;
+	}
+
+Return:
+	if(ndig == 0)
+		p = nptr;
+	if(endptr)
+		*endptr = p;
+	if(ovfl)
+		return UVLONG_MAX;
+	if(neg)
+		return -n;
+	return n;
+}
--- /dev/null
+++ b/libkern/tokenize.c
@@ -1,0 +1,106 @@
+#include "lib9.h"
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+	int quoting;
+	char *t;
+
+	quoting = 0;
+	t = s;	/* s is output string, t is input string */
+	while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+		if(*t != '\''){
+			*s++ = *t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t++;
+		*s++ = *t++;
+	}
+	if(*s != '\0'){
+		*s = '\0';
+		if(t == s)
+			t++;
+	}
+	return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+	int quoting;
+
+	/* move to end of next token */
+	quoting = 0;
+	while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+		if(*t != '\''){
+			t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t += 2;
+	}
+	return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(sep, *s)!=nil)
+			*s++ = '\0';
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = etoken(s, sep);
+	}
+
+	return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(qsep, *s)!=nil)
+			s++;
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = qtoken(s, qsep);
+	}
+
+	return nargs;
+}
--- /dev/null
+++ b/libkern/toupper.c
@@ -1,0 +1,16 @@
+toupper(int c)
+{
+
+	if(c < 'a' || c > 'z')
+		return c;
+	return (c-'a'+'A');
+}
+
+tolower(int c)
+{
+
+	if(c < 'A' || c > 'Z')
+		return c;
+	return (c-'A'+'a');
+}
+
--- /dev/null
+++ b/libkern/u16.c
@@ -1,0 +1,52 @@
+#include <lib9.h>
+static char t16e[] = "0123456789ABCDEF";
+
+int
+dec16(uchar *out, int lim, char *in, int n)
+{
+	int c, w = 0, i = 0;
+	uchar *start = out;
+	uchar *eout = out + lim;
+
+	while(n-- > 0){
+		c = *in++;
+		if('0' <= c && c <= '9')
+			c = c - '0';
+		else if('a' <= c && c <= 'z')
+			c = c - 'a' + 10;
+		else if('A' <= c && c <= 'Z')
+			c = c - 'A' + 10;
+		else
+			continue;
+		w = (w<<4) + c;
+		i++;
+		if(i == 2){
+			if(out + 1 > eout)
+				goto exhausted;
+			*out++ = w;
+			w = 0;
+			i = 0;
+		}
+	}
+exhausted:
+	return out - start;
+}
+
+int
+enc16(char *out, int lim, uchar *in, int n)
+{
+	uint c;
+	char *eout = out + lim;
+	char *start = out;
+
+	while(n-- > 0){
+		c = *in++;
+		if(out + 2 >= eout)
+			goto exhausted;
+		*out++ = t16e[c>>4];
+		*out++ = t16e[c&0xf];
+	}
+exhausted:
+	*out = 0;
+	return out - start;
+}
--- /dev/null
+++ b/libkern/u32.c
@@ -1,0 +1,109 @@
+#include <lib9.h>
+
+int
+dec32(uchar *dest, int ndest, char *src, int nsrc)
+{
+	char *s, *tab;
+	uchar *start;
+	int i, u[8];
+
+	if(ndest+1 < (5*nsrc+7)/8)
+		return -1;
+	start = dest;
+	tab = "23456789abcdefghijkmnpqrstuvwxyz";
+	while(nsrc>=8){
+		for(i=0; i<8; i++){
+			s = strchr(tab,(int)src[i]);
+			u[i] = s ? s-tab : 0;
+		}
+		*dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+		*dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+		*dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+		*dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+		*dest++ = ((0x7 & u[6])<<5) | u[7];
+		src  += 8;
+		nsrc -= 8;
+	}
+	if(nsrc > 0){
+		if(nsrc == 1 || nsrc == 3 || nsrc == 6)
+			return -1;
+		for(i=0; i<nsrc; i++){
+			s = strchr(tab,(int)src[i]);
+			u[i] = s ? s-tab : 0;
+		}
+		*dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+		if(nsrc == 2)
+			goto out;
+		*dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+		if(nsrc == 4)
+			goto out;
+		*dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+		if(nsrc == 5)
+			goto out;
+		*dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+	}
+out:
+	return dest-start;
+}
+
+int
+enc32(char *dest, int ndest, uchar *src, int nsrc)
+{
+	char *tab, *start;
+	int j;
+
+	if(ndest <= (8*nsrc+4)/5 )
+		return -1;
+	start = dest;
+	tab = "23456789abcdefghijkmnpqrstuvwxyz";
+	while(nsrc>=5){
+		j = (0x1f & (src[0]>>3));
+		*dest++ = tab[j];
+		j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
+		*dest++ = tab[j];
+		j = (0x1f & (src[1]>>1));
+		*dest++ = tab[j];
+		j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
+		*dest++ = tab[j];
+		j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
+		*dest++ = tab[j];
+		j = (0x1f & (src[3]>>2));
+		*dest++ = tab[j];
+		j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
+		*dest++ = tab[j];
+		j = (0x1f & (src[4]));
+		*dest++ = tab[j];
+		src  += 5;
+		nsrc -= 5;
+	}
+	if(nsrc){
+		j = (0x1f & (src[0]>>3));
+		*dest++ = tab[j];
+		j = (0x1c & (src[0]<<2));
+		if(nsrc == 1)
+			goto out;
+		j |= (0x03 & (src[1]>>6));
+		*dest++ = tab[j];
+		j = (0x1f & (src[1]>>1));
+		if(nsrc == 2)
+			goto out;
+		*dest++ = tab[j];
+		j = (0x10 & (src[1]<<4));
+		if(nsrc == 3)
+			goto out;
+		j |= (0x0f & (src[2]>>4));
+		*dest++ = tab[j];
+		j = (0x1e & (src[2]<<1));
+		if(nsrc == 4)
+			goto out;
+		j |= (0x01 & (src[3]>>7));
+		*dest++ = tab[j];
+		j = (0x1f & (src[3]>>2));
+		*dest++ = tab[j];
+		j = (0x18 & (src[3]<<3));
+out:
+		*dest++ = tab[j];
+	}
+	*dest = 0;
+	return dest-start;
+}
--- /dev/null
+++ b/libkern/u64.c
@@ -1,0 +1,126 @@
+#include <lib9.h>
+
+enum {
+	INVAL=	255
+};
+
+static uchar t64d[256] = {
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,   62,INVAL,INVAL,INVAL,   63,
+      52,   53,   54,   55,   56,   57,   58,   59,   60,   61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,    0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,
+      15,   16,   17,   18,   19,   20,   21,   22,   23,   24,   25,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,   37,   38,   39,   40,
+      41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL
+};
+static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int
+dec64(uchar *out, int lim, char *in, int n)
+{
+	ulong b24;
+	uchar *start = out;
+	uchar *e = out + lim;
+	int i, c;
+
+	b24 = 0;
+	i = 0;
+	while(n-- > 0){
+ 
+		c = t64d[*(uchar*)in++];
+		if(c == INVAL)
+			continue;
+		switch(i){
+		case 0:
+			b24 = c<<18;
+			break;
+		case 1:
+			b24 |= c<<12;
+			break;
+		case 2:
+			b24 |= c<<6;
+			break;
+		case 3:
+			if(out + 3 > e)
+				goto exhausted;
+
+			b24 |= c;
+			*out++ = b24>>16;
+			*out++ = b24>>8;
+			*out++ = b24;
+			i = -1;
+			break;
+		}
+		i++;
+	}
+	switch(i){
+	case 2:
+		if(out + 1 > e)
+			goto exhausted;
+		*out++ = b24>>16;
+		break;
+	case 3:
+		if(out + 2 > e)
+			goto exhausted;
+		*out++ = b24>>16;
+		*out++ = b24>>8;
+		break;
+	}
+exhausted:
+	return out - start;
+}
+
+int
+enc64(char *out, int lim, uchar *in, int n)
+{
+	int i;
+	ulong b24;
+	char *start = out;
+	char *e = out + lim;
+
+	for(i = n/3; i > 0; i--){
+		b24 = (*in++)<<16;
+		b24 |= (*in++)<<8;
+		b24 |= *in++;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = t64e[(b24>>6)&0x3f];
+		*out++ = t64e[(b24)&0x3f];
+	}
+
+	switch(n%3){
+	case 2:
+		b24 = (*in++)<<16;
+		b24 |= (*in)<<8;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = t64e[(b24>>6)&0x3f];
+		*out++ = '=';
+		break;
+	case 1:
+		b24 = (*in)<<16;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = '=';
+		*out++ = '=';
+		break;
+	}
+exhausted:
+	*out = 0;
+	return out - start;
+}
--- /dev/null
+++ b/libkern/utfecpy.c
@@ -1,0 +1,20 @@
+#include "lib9.h"
+
+char*
+utfecpy(char *to, char *e, char *from)
+{
+	char *end;
+
+	if(to >= e)
+		return to;
+	end = memccpy(to, from, '\0', e - to);
+	if(end == nil){
+		end = e;
+		while(end>to && (*--end&0xC0)==0x80)
+			;
+		*end = '\0';
+	}else{
+		end--;
+	}
+	return end;
+}
--- /dev/null
+++ b/libkern/utflen.c
@@ -1,0 +1,21 @@
+#include "lib9.h"
+
+int
+utflen(char *s)
+{
+	int c;
+	long n;
+	Rune rune;
+
+	n = 0;
+	for(;;) {
+		c = *(uchar*)s;
+		if(c < Runeself) {
+			if(c == 0)
+				return n;
+			s++;
+		} else
+			s += chartorune(&rune, s);
+		n++;
+	}
+}
--- /dev/null
+++ b/libkern/utfnlen.c
@@ -1,0 +1,25 @@
+#include "lib9.h"
+
+int
+utfnlen(char *s, long m)
+{
+	int c;
+	long n;
+	Rune rune;
+	char *es;
+
+	es = s + m;
+	for(n = 0; s < es; n++) {
+		c = *(uchar*)s;
+		if(c < Runeself){
+			if(c == '\0')
+				break;
+			s++;
+			continue;
+		}
+		if(!fullrune(s, es-s))
+			break;
+		s += chartorune(&rune, s);
+	}
+	return n;
+}
--- /dev/null
+++ b/libkern/utfrrune.c
@@ -1,0 +1,29 @@
+#include "lib9.h"
+
+char*
+utfrrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	char *s1;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strrchr(s, c);
+
+	s1 = 0;
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return s1;
+			if(c1 == c)
+				s1 = s;
+			s++;
+			continue;
+		}
+		c1 = chartorune(&r, s);
+		if(r == c)
+			s1 = s;
+		s += c1;
+	}
+}
--- /dev/null
+++ b/libkern/utfrune.c
@@ -1,0 +1,28 @@
+#include "lib9.h"
+
+char*
+utfrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	int n;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strchr(s, c);
+
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return 0;
+			if(c1 == c)
+				return s;
+			s++;
+			continue;
+		}
+		n = chartorune(&r, s);
+		if(r == c)
+			return s;
+		s += n;
+	}
+}
--- /dev/null
+++ b/libkern/vlop-386.s
@@ -1,0 +1,44 @@
+TEXT	_mulv(SB), $0
+	MOVL	r+0(FP), CX
+	MOVL	a+4(FP), AX
+	MULL	b+12(FP)
+	MOVL	AX, 0(CX)
+	MOVL	DX, BX
+	MOVL	a+4(FP), AX
+	MULL	b+16(FP)
+	ADDL	AX, BX
+	MOVL	a+8(FP), AX
+	MULL	b+12(FP)
+	ADDL	AX, BX
+	MOVL	BX, 4(CX)
+	RET
+
+TEXT	_mul64by32(SB), $0
+	MOVL	r+0(FP), CX
+	MOVL	a+4(FP), AX
+	MULL	b+12(FP)
+	MOVL	AX, 0(CX)
+	MOVL	DX, BX
+	MOVL	a+8(FP), AX
+	MULL	b+12(FP)
+	ADDL	AX, BX
+	MOVL	BX, 4(CX)
+	RET
+
+TEXT	_div64by32(SB), $0
+	MOVL	r+12(FP), CX
+	MOVL	a+0(FP), AX
+	MOVL	a+4(FP), DX
+	DIVL	b+8(FP)
+	MOVL	DX, 0(CX)
+	RET
+
+TEXT	_addv(SB), $0
+	MOVL	r+0(FP), CX
+	MOVL	a+4(FP), AX
+	MOVL	a+8(FP), BX
+	ADDL	b+12(FP), AX
+	ADCL	b+16(FP), BX
+	MOVL	AX, 0(CX)
+	MOVL	BX, 4(CX)
+	RET
--- /dev/null
+++ b/libkern/vlop-arm.s
@@ -1,0 +1,34 @@
+#define	UMULL(Rs,Rm,Rhi,Rlo,S)	WORD	$((14<<28)|(4<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define UMLAL(Rs,Rm,Rhi,Rlo,S)	WORD	$((14<<28)|(5<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define	MUL(Rs,Rm,Rd,S)	WORD	$((14<<28)|(0<<21)|(S<<20)|(Rd<<16)|(Rs<<8)|(9<<4)|Rm)
+arg=0
+
+/* replaced use of R10 by R11 because the former can be the data segment base register */
+
+TEXT	_mulv(SB), $0
+	MOVW	4(FP), R9	/* l0 */
+	MOVW	8(FP), R11	/* h0 */
+	MOVW	12(FP), R4	/* l1 */
+	MOVW	16(FP), R5	/* h1 */
+	UMULL(4, 9, 7, 6, 0)
+	MUL(11, 4, 8, 0)
+	ADD	R8, R7
+	MUL(9, 5, 8, 0)
+	ADD	R8, R7
+	MOVW	R6, 0(R(arg))
+	MOVW	R7, 4(R(arg))
+	RET
+
+/* multiply, add, and right-shift, yielding a 32-bit result, while
+   using 64-bit accuracy for the multiply -- for fast fixed-point math */
+TEXT	_mularsv(SB), $0
+	MOVW	4(FP), R11	/* m1 */
+	MOVW	8(FP),	R8	/* a */
+	MOVW	12(FP), R4	/* rs */
+	MOVW	$0, R9
+	UMLAL(0, 11, 9, 8, 0)
+	MOVW	R8>>R4, R8
+	RSB	$32, R4, R4
+	ORR	R9<<R4, R8, R0
+	RET
+
--- /dev/null
+++ b/libkern/vlop-mips.s
@@ -1,0 +1,17 @@
+TEXT	_mulv(SB), $0
+	MOVW	8(FP), R2
+	MOVW	4(FP), R3
+	MOVW	16(FP), R4
+	MOVW	12(FP), R5
+	MULU	R4, R2
+	MOVW	LO, R6
+	MOVW	HI, R7
+	MULU	R3, R4
+	MOVW	LO, R8
+	ADDU	R8, R7
+	MULU	R2, R5
+	MOVW	LO, R8
+	ADDU	R8, R7
+	MOVW	R6, 4(R1)
+	MOVW	R7, 0(R1)
+	RET
--- /dev/null
+++ b/libkern/vlop-power.s
@@ -1,0 +1,14 @@
+TEXT	_mulv(SB), $0
+	MOVW	8(FP), R9
+	MOVW	4(FP), R10
+	MOVW	16(FP), R4
+	MOVW	12(FP), R5
+	MULLW	R4, R9, R6
+	MULHWU	R4, R9, R7
+	MULLW	R10, R4, R8
+	ADD	R8, R7
+	MULLW	R9, R5, R8
+	ADD	R8, R7
+	MOVW	R6, 4(R3)
+	MOVW	R7, 0(R3)
+	RETURN
--- /dev/null
+++ b/libkern/vlop-sparc.s
@@ -1,0 +1,112 @@
+TEXT	_mulv(SB), $0
+	MOVW	u1+8(FP), R8
+	MOVW	u2+16(FP), R13
+
+	MOVW	R13, R16		/* save low parts for later */
+	MOVW	R8, R12
+
+	/*
+	 * unsigned 32x32 => 64 multiply
+	 */
+	CMP	R13, R8
+	BLE	mul1
+	MOVW	R12, R13
+	MOVW	R16, R8
+mul1:
+	MOVW	R13, Y
+	ANDNCC	$0xFFF, R13, R0
+	BE	mul_shortway
+	ANDCC	R0, R0, R9		/* zero partial product and clear N and V cond's */
+
+	/* long multiply */
+	MULSCC	R8, R9, R9		/* 0 */
+	MULSCC	R8, R9, R9		/* 1 */
+	MULSCC	R8, R9, R9		/* 2 */
+	MULSCC	R8, R9, R9		/* 3 */
+	MULSCC	R8, R9, R9		/* 4 */
+	MULSCC	R8, R9, R9		/* 5 */
+	MULSCC	R8, R9, R9		/* 6 */
+	MULSCC	R8, R9, R9		/* 7 */
+	MULSCC	R8, R9, R9		/* 8 */
+	MULSCC	R8, R9, R9		/* 9 */
+	MULSCC	R8, R9, R9		/* 10 */
+	MULSCC	R8, R9, R9		/* 11 */
+	MULSCC	R8, R9, R9		/* 12 */
+	MULSCC	R8, R9, R9		/* 13 */
+	MULSCC	R8, R9, R9		/* 14 */
+	MULSCC	R8, R9, R9		/* 15 */
+	MULSCC	R8, R9, R9		/* 16 */
+	MULSCC	R8, R9, R9		/* 17 */
+	MULSCC	R8, R9, R9		/* 18 */
+	MULSCC	R8, R9, R9		/* 19 */
+	MULSCC	R8, R9, R9		/* 20 */
+	MULSCC	R8, R9, R9		/* 21 */
+	MULSCC	R8, R9, R9		/* 22 */
+	MULSCC	R8, R9, R9		/* 23 */
+	MULSCC	R8, R9, R9		/* 24 */
+	MULSCC	R8, R9, R9		/* 25 */
+	MULSCC	R8, R9, R9		/* 26 */
+	MULSCC	R8, R9, R9		/* 27 */
+	MULSCC	R8, R9, R9		/* 28 */
+	MULSCC	R8, R9, R9		/* 29 */
+	MULSCC	R8, R9, R9		/* 30 */
+	MULSCC	R8, R9, R9		/* 31 */
+	MULSCC	R0, R9, R9		/* 32; shift only; r9 is high part */
+
+	/*
+	 * need to correct top word if top bit set
+	 */
+	CMP	R8, R0
+	BGE	mul_tstlow
+	ADD	R13, R9			/* adjust the high parts */
+
+mul_tstlow:
+	MOVW	Y, R13			/* get low part */
+	BA	mul_done
+
+mul_shortway:
+	ANDCC	R0, R0, R9		/* zero partial product and clear N and V cond's */
+	MULSCC	R8, R9, R9		/*  0 */
+	MULSCC	R8, R9, R9		/*  1 */
+	MULSCC	R8, R9, R9		/*  2 */
+	MULSCC	R8, R9, R9		/*  3 */
+	MULSCC	R8, R9, R9		/*  4 */
+	MULSCC	R8, R9, R9		/*  5 */
+	MULSCC	R8, R9, R9		/*  6 */
+	MULSCC	R8, R9, R9		/*  7 */
+	MULSCC	R8, R9, R9		/*  8 */
+	MULSCC	R8, R9, R9		/*  9 */
+	MULSCC	R8, R9, R9		/* 10 */
+	MULSCC	R8, R9, R9		/* 11 */
+	MULSCC	R0, R9, R9		/* 12; shift only; r9 is high part */
+
+	MOVW	Y, R8			/* make low part of partial low part & high part */
+	SLL	$12, R9, R13
+	SRL	$20, R8
+	OR	R8, R13
+
+	SRA	$20, R9			/* high part */
+
+mul_done:
+
+	/*
+	 * mul by high halves if needed
+	 */
+	MOVW	R13, 4(R7)
+	MOVW	u2+12(FP), R11
+	CMP	R11, R0
+	BE	nomul1
+	MUL	R11, R12
+	ADD	R12, R9
+
+nomul1:
+	MOVW	u1+4(FP), R11
+	CMP	R11, R0
+	BE	nomul2
+	MUL	R11, R16
+	ADD	R16, R9
+
+nomul2:
+
+	MOVW	R9, 0(R7)
+	RETURN	
--- /dev/null
+++ b/libkern/vlop-spim.s
@@ -1,0 +1,17 @@
+TEXT	_mulv(SB), $0
+	MOVW	4(FP), R2
+	MOVW	8(FP), R3
+	MOVW	12(FP), R4
+	MOVW	16(FP), R5
+	MULU	R4, R2
+	MOVW	LO, R6
+	MOVW	HI, R7
+	MULU	R3, R4
+	MOVW	LO, R8
+	ADDU	R8, R7
+	MULU	R2, R5
+	MOVW	LO, R8
+	ADDU	R8, R7
+	MOVW	R6, 0(R1)
+	MOVW	R7, 4(R1)
+	RET
--- /dev/null
+++ b/libkern/vlop-thumb.s
@@ -1,0 +1,34 @@
+#define	UMULL(Rs,Rm,Rhi,Rlo,S)	WORD	$((14<<28)|(4<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define UMLAL(Rs,Rm,Rhi,Rlo,S)	WORD	$((14<<28)|(5<<21)|(S<<20)|(Rhi<<16)|(Rlo<<12)|(Rs<<8)|(9<<4)|Rm)
+#define	MUL(Rs,Rm,Rd,S)	WORD	$((14<<28)|(0<<21)|(S<<20)|(Rd<<16)|(Rs<<8)|(9<<4)|Rm)
+arg=0
+
+/* replaced use of R10 by R11 because the former can be the data segment base register */
+
+TEXT	_mulv(SB), $0
+	MOVW	4(FP), R9	/* l0 */
+	MOVW	8(FP), R11	/* h0 */
+	MOVW	12(FP), R4	/* l1 */
+	MOVW	16(FP), R5	/* h1 */
+	UMULL(4, 9, 7, 6, 0)
+	MUL(11, 4, 8, 0)
+	ADD	R8, R7
+	MUL(9, 5, 8, 0)
+	ADD	R8, R7
+	MOVW	R6, 0(R(arg))
+	MOVW	R7, 4(R(arg))
+	RET
+
+/* multiply, add, and right-shift, yielding a 32-bit result, while
+   using 64-bit accuracy for the multiply -- for fast fixed-point math */
+TEXT	_mularsv(SB), $0
+	MOVW	4(FP), R11	/* m1 */
+	MOVW	8(FP),	R8	/* a */
+	MOVW	12(FP), R4	/* rs */
+	MOVW	$0, R9
+	UMLAL(0, 11, 9, 8, 0)
+	MOVW	R8>>R4, R8
+	RSB	$32, R4, R4
+	ORR	R9<<R4, R8, R0
+	RET
+
--- /dev/null
+++ b/libkern/vlrt-386.c
@@ -1,0 +1,695 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	lo;
+			ulong	hi;
+		};
+		struct
+		{
+			ushort	lols;
+			ushort	loms;
+			ushort	hils;
+			ushort	hims;
+		};
+	};
+};
+
+void	abort(void);
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+ulong	_div64by32(Vlong, ulong, ulong*);
+void	_mul64by32(Vlong*, Vlong, ulong);
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+	ulong n;
+	Vlong x, q, r;
+
+	if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+		if(qp) {
+			qp->hi = 0;
+			qp->lo = 0;
+		}
+		if(rp) {
+			rp->hi = num.hi;
+			rp->lo = num.lo;
+		}
+		return;
+	}
+
+	if(den.hi != 0){
+		q.hi = 0;
+		n = num.hi/den.hi;
+		_mul64by32(&x, den, n);
+		if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)){
+			n--;
+			_mul64by32(&x, den, n);
+		}
+		q.lo = n;
+		_subv(&r, num, x);
+	} else {
+		if(num.hi >= den.lo){
+			q.hi = n = num.hi/den.lo;
+			num.hi -= den.lo*n;
+		} else {
+			q.hi = 0;
+		}
+		q.lo = _div64by32(num, den.lo, &r.lo);
+		r.hi = 0;
+	}
+	if(qp) {
+		qp->lo = q.lo;
+		qp->hi = q.hi;
+	}
+	if(rp) {
+		rp->lo = r.lo;
+		rp->hi = r.hi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u.lo = 0;
+	u.hi = 0;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-arm.c
@@ -1,0 +1,711 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	lo;
+			ulong	hi;
+		};
+	};
+};
+
+void	abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo + b.lo;
+	hi = a.hi + b.hi;
+	if(lo < a.lo)
+		hi++;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		numlo = numlo / denlo;
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(q) {
+		q->lo = quolo;
+		q->hi = quohi;
+	}
+	if(r) {
+		r->lo = numlo;
+		r->hi = numhi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u = *ret;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-mips.c
@@ -1,0 +1,712 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	hi;
+			ulong	lo;
+		};
+	};
+};
+
+void	abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo + b.lo;
+	hi = a.hi + b.hi;
+	if(lo < a.lo)
+		hi++;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		numlo = numlo / denlo;
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(qp) {
+		qp->lo = quolo;
+		qp->hi = quohi;
+	}
+	if(rp) {
+		rp->lo = numlo;
+		rp->hi = numhi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u.lo = 0;
+	u.hi = 0;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-power.c
@@ -1,0 +1,718 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	hi;
+			ulong	lo;
+		};
+		struct
+		{
+			ushort	hims;
+			ushort	hils;
+			ushort	loms;
+			ushort	lols;
+		};
+	};
+};
+
+void	abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo + b.lo;
+	hi = a.hi + b.hi;
+	if(lo < a.lo)
+		hi++;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		numlo = numlo / denlo;
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(q) {
+		q->lo = quolo;
+		q->hi = quohi;
+	}
+	if(r) {
+		r->lo = numlo;
+		r->hi = numhi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u = *ret;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-sparc.c
@@ -1,0 +1,718 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	hi;
+			ulong	lo;
+		};
+		struct
+		{
+			ushort	hims;
+			ushort	hils;
+			ushort	loms;
+			ushort	lols;
+		};
+	};
+};
+
+void	abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo + b.lo;
+	hi = a.hi + b.hi;
+	if(lo < a.lo)
+		hi++;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		numlo = numlo / denlo;
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(q) {
+		q->lo = quolo;
+		q->hi = quohi;
+	}
+	if(r) {
+		r->lo = numlo;
+		r->hi = numhi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u = *ret;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-spim.c
@@ -1,0 +1,711 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	lo;
+			ulong	hi;
+		};
+	};
+};
+
+void	abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo + b.lo;
+	hi = a.hi + b.hi;
+	if(lo < a.lo)
+		hi++;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		numlo = numlo / denlo;
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(q) {
+		q->lo = quolo;
+		q->hi = quohi;
+	}
+	if(r) {
+		r->lo = numlo;
+		r->hi = numhi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u = *ret;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vlrt-thumb.c
@@ -1,0 +1,718 @@
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	union
+	{
+		struct
+		{
+			ulong	hi;
+			ulong	lo;
+		};
+		struct
+		{
+			ushort	hims;
+			ushort	hils;
+			ushort	loms;
+			ushort	lols;
+		};
+	};
+};
+
+void	abort(void);
+
+void
+_addv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo + b.lo;
+	hi = a.hi + b.hi;
+	if(lo < a.lo)
+		hi++;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+void
+_subv(Vlong *r, Vlong a, Vlong b)
+{
+	ulong lo, hi;
+
+	lo = a.lo - b.lo;
+	hi = a.hi - b.hi;
+	if(lo > a.lo)
+		hi--;
+	r->lo = lo;
+	r->hi = hi;
+}
+
+
+void
+_d2v(Vlong *y, double d)
+{
+	union { double d; struct Vlong; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+
+	x.d = d;
+
+	xhi = (x.hi & 0xfffff) | 0x100000;
+	xlo = x.lo;
+	sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) {
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y->hi = yhi;
+	y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+	_d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -((long)x.hi*4294967296. + x.lo);
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		numlo = numlo / denlo;
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(q) {
+		q->lo = quolo;
+		q->hi = quohi;
+	}
+	if(r) {
+		r->lo = numlo;
+		r->hi = numhi;
+	}
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		q->hi = 0;
+		q->lo = n.lo / d.lo;
+		return;
+	}
+	dodiv(n, d, q, 0);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+	if(n.hi == 0 && d.hi == 0) {
+		r->hi = 0;
+		r->lo = n.lo % d.lo;
+		return;
+	}
+	dodiv(n, d, 0, r);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		q->lo = (long)n.lo / (long)d.lo;
+		q->hi = ((long)q->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, q, 0);
+	if(nneg != dneg)
+		vneg(q);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+	long nneg, dneg;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		r->lo = (long)n.lo % (long)d.lo;
+		r->hi = ((long)r->lo) >> 31;
+		return;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, r);
+	if(nneg)
+		vneg(r);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+	long t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = t>>31;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.hi;
+	if(b >= 32) {
+		r->hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->lo = 0;
+			return;
+		}
+		r->lo = t >> (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->hi = t;
+		r->lo = a.lo;
+		return;
+	}
+	r->hi = t >> b;
+	r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		r->lo = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r->hi = 0;
+			return;
+		}
+		r->hi = t << (b-32);
+		return;
+	}
+	if(b <= 0) {
+		r->lo = t;
+		r->hi = a.hi;
+		return;
+	}
+	r->lo = t << b;
+	r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi & b.hi;
+	r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi | b.hi;
+	r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+	r->hi = a.hi ^ b.hi;
+	r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+	l->hi = r->hi;
+	l->lo = r->lo;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	l->hi = r->hi;
+	l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u = *ret;
+	switch(type) {
+	default:
+		abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		fn(&u, t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		fn(&u, t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		fn(&u, *(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	*ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+	long t;
+
+	t = (ulong)p;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+	long t;
+
+	t = sl;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+	long t;
+
+	t = si;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+	long t;
+
+	t = ui;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+	long t;
+
+	t = (sh << 16) >> 16;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xffff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+	long t;
+
+	t = (uc << 24) >> 24;
+	ret->lo = t;
+	ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+	long t;
+
+	t = ul & 0xff;
+	ret->lo = t;
+	ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi || 
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi || 
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
--- /dev/null
+++ b/libkern/vseprint.c
@@ -1,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	va_copy(f.args, args);
+	dofmt(&f, fmt);
+	va_end(f.args);
+	*(char*)f.to = '\0';
+	return f.to;
+}
+
--- /dev/null
+++ b/libkern/vsmprint.c
@@ -1,0 +1,79 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+	char *s;
+	int n;
+
+	if(f->start == nil)
+		return 0;
+	n = (int)f->farg;
+	n += 256;
+	f->farg = (void*)n;
+	s = f->start;
+	f->start = realloc(s, n);
+	if(f->start == nil){
+		free(s);
+		f->to = nil;
+		f->stop = nil;
+		return 0;
+	}
+	f->to = (char*)f->start + ((char*)f->to - s);
+	f->stop = (char*)f->start + n - 1;
+	return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+	int n;
+
+	memset(f, 0, sizeof(*f));
+	n = 32;
+	f->start = malloc(n);
+	if(f->start == nil)
+		return -1;
+	f->to = f->start;
+	f->stop = (char*)f->start + n - 1;
+	f->flush = fmtStrFlush;
+	f->farg = (void*)n;
+	f->nfmt = 0;
+	return 0;
+}
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+	Fmt f;
+	int n;
+
+	if(fmtstrinit(&f) < 0)
+		return nil;
+	va_copy(f.args, args);
+	n = dofmt(&f, fmt);
+	va_end(f.args);
+	if(n < 0){
+		free(f.start);
+		f.start = nil;
+		return nil;
+	}
+	return fmtstrflush(&f);
+}
--- /dev/null
+++ b/libkern/vsnprint.c
@@ -1,0 +1,36 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "lib9.h"
+#include "fmtdef.h"
+
+int
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(len <= 0)
+		return -1;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = buf + len - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	va_copy(f.args, args);
+	dofmt(&f, fmt);
+	va_end(f.args);
+	*(char*)f.to = '\0';
+	return (char*)f.to - buf;
+}
--- /dev/null
+++ b/libkeyring/NOTICE
@@ -1,0 +1,25 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libkeyring/dsaalg.c
@@ -1,0 +1,216 @@
+#include <lib9.h>
+#include <kernel.h>
+#include <isa.h>
+#include "interp.h"
+#include "../libinterp/keyringif.h"
+#include "mp.h"
+#include "libsec.h"
+#include "keys.h"
+
+static char*	pkattr[] = { "p", "q", "alpha", "key", nil };
+static char*	skattr[] = { "p", "q", "alpha", "key", "!secret", nil };
+static char*	sigattr[] = { "r", "s", nil };
+
+static void*
+dsa_str2sk(char *str, char **strp)
+{
+	DSApriv *dsa;
+	char *p;
+
+	dsa = dsaprivalloc();
+	dsa->pub.p = base64tobig(str, &p);
+	dsa->pub.q = base64tobig(str, &p);
+	dsa->pub.alpha = base64tobig(p, &p);
+	dsa->pub.key = base64tobig(p, &p);
+	dsa->secret = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(dsa->pub.p == nil || dsa->pub.q == nil ||
+	   dsa->pub.alpha == nil || dsa->pub.key == nil || dsa->secret == nil){
+		dsaprivfree(dsa);
+		return nil;
+	}
+	return dsa;
+}
+
+static void*
+dsa_str2pk(char *str, char **strp)
+{
+	DSApub *dsa;
+	char *p;
+
+	dsa = dsapuballoc();
+	dsa->p = base64tobig(str, &p);
+	dsa->q = base64tobig(str, &p);
+	dsa->alpha = base64tobig(p, &p);
+	dsa->key = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(dsa->p == nil || dsa->q == nil || dsa->alpha == nil || dsa->key == nil){
+		dsapubfree(dsa);
+		return nil;
+	}
+	return dsa;
+}
+
+static void*
+dsa_str2sig(char *str, char **strp)
+{
+	DSAsig *dsa;
+	char *p;
+
+	dsa = dsasigalloc();
+	dsa->r = base64tobig(str, &p);
+	dsa->s = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(dsa->r == nil || dsa->s == nil){
+		dsasigfree(dsa);
+		return nil;
+	}
+	return dsa;
+}
+
+static int
+dsa_sk2str(void *veg, char *buf, int len)
+{
+	DSApriv *dsa;
+	char *cp, *ep;
+
+	dsa = veg;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", dsa->pub.p);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->pub.q);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->pub.alpha);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->pub.key);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->secret);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static int
+dsa_pk2str(void *veg, char *buf, int len)
+{
+	DSApub *dsa;
+	char *cp, *ep;
+
+	dsa = veg;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", dsa->p);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->q);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->alpha);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->key);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static int
+dsa_sig2str(void *veg, char *buf, int len)
+{
+	DSAsig *dsa;
+	char *cp, *ep;
+
+	dsa = veg;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", dsa->r);
+	cp += snprint(cp, ep - cp, "%U\n", dsa->s);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static void*
+dsa_sk2pk(void *vs)
+{
+	return dsaprivtopub((DSApriv*)vs);
+}
+
+/* generate a dsa secret key with new params */
+static void*
+dsa_gen(int len)
+{
+	USED(len);
+	return dsagen(nil);
+}
+
+/* generate a dsa secret key with same params as a public key */
+static void*
+dsa_genfrompk(void *vpub)
+{
+	return dsagen((DSApub*)vpub);
+}
+
+static void
+dsa_freepub(void *a)
+{
+	dsapubfree((DSApub*)a);
+}
+
+static void
+dsa_freepriv(void *a)
+{
+	dsaprivfree((DSApriv*)a);
+}
+
+static void
+dsa_freesig(void *a)
+{
+	dsasigfree((DSAsig*)a);
+}
+
+static void*
+dsa_sign(mpint* md, void *key)
+{
+	return dsasign((DSApriv*)key, md);
+}
+
+static int
+dsa_verify(mpint* md, void *sig, void *key)
+{
+	return dsaverify((DSApub*)key, (DSAsig*)sig, md) == 0;
+}
+
+SigAlgVec*
+dsainit(void)
+{
+	SigAlgVec *vec;
+
+	vec = malloc(sizeof(SigAlgVec));
+	if(vec == nil)
+		return nil;
+
+	vec->name = "dsa";
+
+	vec->pkattr = pkattr;
+	vec->skattr = skattr;
+	vec->sigattr = sigattr;
+
+	vec->str2sk = dsa_str2sk;
+	vec->str2pk = dsa_str2pk;
+	vec->str2sig = dsa_str2sig;
+
+	vec->sk2str = dsa_sk2str;
+	vec->pk2str = dsa_pk2str;
+	vec->sig2str = dsa_sig2str;
+
+	vec->sk2pk = dsa_sk2pk;
+
+	vec->gensk = dsa_gen;
+	vec->genskfrompk = dsa_genfrompk;
+	vec->sign = dsa_sign;
+	vec->verify = dsa_verify;
+
+	vec->skfree = dsa_freepriv;
+	vec->pkfree = dsa_freepub;
+	vec->sigfree = dsa_freesig;
+
+	return vec;
+}
--- /dev/null
+++ b/libkeyring/egalg.c
@@ -1,0 +1,224 @@
+#include <lib9.h>
+#include <kernel.h>
+#include <isa.h>
+#include "interp.h"
+#include "../libinterp/keyringif.h"
+#include "mp.h"
+#include "libsec.h"
+#include "keys.h"
+
+static char*	pkattr[] = { "p", "alpha", "key", nil };
+static char*	skattr[] = { "p", "alpha", "key", "!secret", nil };
+static char*	sigattr[] = { "r", "s", nil };
+
+static void*
+eg_str2sk(char *str, char **strp)
+{
+	EGpriv *eg;
+	char *p;
+
+	eg = egprivalloc();
+	eg->pub.p = base64tobig(str, &p);
+	eg->pub.alpha = base64tobig(p, &p);
+	eg->pub.key = base64tobig(p, &p);
+	eg->secret = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(eg->pub.p == nil || eg->pub.alpha == nil || eg->pub.key == nil || eg->secret == nil){
+		egprivfree(eg);
+		return nil;
+	}
+	return eg;
+}
+
+static void*
+eg_str2pk(char *str, char **strp)
+{
+	EGpub *eg;
+	char *p;
+
+	eg = egpuballoc();
+	eg->p = base64tobig(str, &p);
+	eg->alpha = base64tobig(p, &p);
+	eg->key = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(eg->p == nil || eg->alpha == nil || eg->key == nil){
+		egpubfree(eg);
+		return nil;
+	}
+	return eg;
+}
+
+static void*
+eg_str2sig(char *str, char **strp)
+{
+	EGsig *eg;
+	char *p;
+
+	eg = egsigalloc();
+	eg->r = base64tobig(str, &p);
+	eg->s = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(eg->r == nil || eg->s == nil){
+		egsigfree(eg);
+		return nil;
+	}
+	return eg;
+}
+
+static int
+eg_sk2str(void *veg, char *buf, int len)
+{
+	EGpriv *eg;
+	char *cp, *ep;
+
+	eg = (EGpriv*)veg;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", eg->pub.p);
+	cp += snprint(cp, ep - cp, "%U\n", eg->pub.alpha);
+	cp += snprint(cp, ep - cp, "%U\n", eg->pub.key);
+	cp += snprint(cp, ep - cp, "%U\n", eg->secret);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static int
+eg_pk2str(void *veg, char *buf, int len)
+{
+	EGpub *eg;
+	char *cp, *ep;
+
+	eg = (EGpub*)veg;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", eg->p);
+	cp += snprint(cp, ep - cp, "%U\n", eg->alpha);
+	cp += snprint(cp, ep - cp, "%U\n", eg->key);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static int
+eg_sig2str(void *veg, char *buf, int len)
+{
+	EGsig *eg;
+	char *cp, *ep;
+
+	eg = veg;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", eg->r);
+	cp += snprint(cp, ep - cp, "%U\n", eg->s);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static void*
+eg_sk2pk(void *vs)
+{
+	return egprivtopub((EGpriv*)vs);
+}
+
+/* generate an el gamal secret key with new params */
+static void*
+eg_gen(int len)
+{
+	return eggen(len, 0);
+}
+
+/* generate an el gamal secret key with same params as a public key */
+static void*
+eg_genfrompk(void *vpub)
+{
+	EGpub *pub;
+	EGpriv *priv;
+	int nlen;
+
+	pub = vpub;
+	priv = egprivalloc();
+	priv->pub.p = mpcopy(pub->p);
+	priv->pub.alpha = mpcopy(pub->alpha);
+	nlen = mpsignif(pub->p);
+	pub = &priv->pub;
+	pub->key = mpnew(0);
+	priv->secret = mpnew(0);
+	mprand(nlen-1, genrandom, priv->secret);
+	mpexp(pub->alpha, priv->secret, pub->p, pub->key);
+	return priv;
+}
+
+static void*
+eg_sign(mpint* mp, void *key)
+{
+	return egsign((EGpriv*)key, mp);
+}
+
+static int
+eg_verify(mpint* mp, void *sig, void *key)
+{
+	return egverify((EGpub*)key, (EGsig*)sig, mp) == 0;
+}
+
+static void
+eg_freepub(void *a)
+{
+	egpubfree((EGpub*)a);
+}
+
+static void
+eg_freepriv(void *a)
+{
+	egprivfree((EGpriv*)a);
+}
+
+static void
+eg_freesig(void *a)
+{
+	egsigfree((EGsig*)a);
+}
+
+SigAlgVec*
+elgamalinit(void)
+{
+	SigAlgVec *vec;
+
+	vec = malloc(sizeof(SigAlgVec));
+	if(vec == nil)
+		return nil;
+
+	vec->name = "elgamal";
+
+	vec->pkattr = pkattr;
+	vec->skattr = skattr;
+	vec->sigattr = sigattr;
+
+	vec->str2sk = eg_str2sk;
+	vec->str2pk = eg_str2pk;
+	vec->str2sig = eg_str2sig;
+
+	vec->sk2str = eg_sk2str;
+	vec->pk2str = eg_pk2str;
+	vec->sig2str = eg_sig2str;
+
+	vec->sk2pk = eg_sk2pk;
+
+	vec->gensk = eg_gen;
+	vec->genskfrompk = eg_genfrompk;
+	vec->sign = eg_sign;
+	vec->verify = eg_verify;
+
+	vec->skfree = eg_freepriv;
+	vec->pkfree = eg_freepub;
+	vec->sigfree = eg_freesig;
+
+	return vec;
+}
--- /dev/null
+++ b/libkeyring/keys.h
@@ -1,0 +1,111 @@
+typedef struct SigAlg SigAlg;
+typedef struct SigAlgVec SigAlgVec;
+typedef struct SK SK;
+typedef struct PK PK;
+typedef struct Certificate Certificate;
+typedef struct XDigestState XDigestState;
+typedef struct XAESstate XAESstate;
+typedef struct XDESstate XDESstate;
+typedef struct XIDEAstate XIDEAstate;
+typedef struct XRC4state XRC4state;
+
+enum
+{
+	Maxbuf=	4096,
+	MaxBigBytes = 1024
+};
+
+/* generic certificate */
+struct Certificate
+{
+	Keyring_Certificate x;
+	void		*signa;	/* actual signature */
+};
+
+/* generic public key */
+struct PK
+{
+	Keyring_PK	x;
+	void		*key;	/* key and system parameters */
+};
+
+/* digest state */
+struct XDigestState
+{
+	Keyring_DigestState	x;
+	DigestState	state;
+};
+
+/* AES state */
+struct XAESstate
+{
+	Keyring_AESstate	x;
+	AESstate	state;
+};
+
+/* DES state */
+struct XDESstate
+{
+	Keyring_DESstate	x;
+	DESstate	state;
+};
+
+/* IDEA state */
+struct XIDEAstate
+{
+	Keyring_IDEAstate	x;
+	IDEAstate	state;
+};
+
+/* RC4 state */
+struct XRC4state
+{
+	Keyring_RC4state	x;
+	RC4state	state;
+};
+
+/* generic secret key */
+struct SK
+{
+	Keyring_SK	x;
+	void		*key;	/* key and system parameters */
+};
+
+struct SigAlgVec {
+	char	*name;
+
+	char**	skattr;
+	char**	pkattr;
+	char**	sigattr;
+
+	void*	(*str2sk)(char*, char**);
+	void*	(*str2pk)(char*, char**);
+	void*	(*str2sig)(char*, char**);
+
+	int	(*sk2str)(void*, char*, int);
+	int	(*pk2str)(void*, char*, int);
+	int	(*sig2str)(void*, char*, int);
+
+	void*	(*sk2pk)(void*);
+
+	void*	(*gensk)(int);
+	void*	(*genskfrompk)(void*);
+	void*	(*sign)(mpint*, void*);
+	int	(*verify)(mpint*, void*, void*);
+
+	void	(*skfree)(void*);
+	void	(*pkfree)(void*);
+	void	(*sigfree)(void*);
+};
+
+struct SigAlg
+{
+	Keyring_SigAlg	x;
+	SigAlgVec	*vec;
+};
+
+int	bigtobase64(mpint* b, char *buf, int blen);
+mpint*	base64tobig(char *str, char **strp);
+SigAlgVec*	findsigalg(char*);
+//Keyring_IPint*	newIPint(mpint*);
+void*	newIPint(mpint*);
--- /dev/null
+++ b/libkeyring/mkfile
@@ -1,0 +1,17 @@
+<../mkconfig
+
+LIB=libkeyring.a
+
+OFILES=\
+	dsaalg.$O\
+	egalg.$O\
+	rsaalg.$O
+
+HFILES=\
+	$ROOT/include/mp.h\
+	$ROOT/include/libsec.h\
+	$ROOT/libinterp/runt.h\
+	$ROOT/include/interp.h\
+	keys.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libkeyring/rsaalg.c
@@ -1,0 +1,230 @@
+#include <lib9.h>
+#include <kernel.h>
+#include <isa.h>
+#include "interp.h"
+#include "../libinterp/keyringif.h"
+#include "mp.h"
+#include "libsec.h"
+#include "keys.h"
+
+static char*	pkattr[] = { "n", "ek", nil };
+static char*	skattr[] = { "n", "ek", "!dk", "!p", "!q", "!kp", "!kq", "!c2", nil };
+static char*	sigattr[] = { "val", nil };
+
+static void*
+rsa_str2sk(char *str, char **strp)
+{
+	RSApriv *rsa;
+	char *p;
+
+	rsa = rsaprivalloc();
+	rsa->pub.n = base64tobig(str, &p);
+	rsa->pub.ek = base64tobig(p, &p);
+	rsa->dk = base64tobig(p, &p);
+	rsa->p = base64tobig(p, &p);
+	rsa->q = base64tobig(p, &p);
+	rsa->kp = base64tobig(p, &p);
+	rsa->kq = base64tobig(p, &p);
+	rsa->c2 = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(rsa->pub.n == nil || rsa->pub.ek == nil ||
+	   rsa->dk == nil || rsa->p == nil || rsa->q == nil ||
+	   rsa->kp == nil || rsa->kq == nil || rsa->c2 == nil){
+		rsaprivfree(rsa);
+		return nil;
+	}
+
+	return rsa;
+}
+
+static void*
+rsa_str2pk(char *str, char **strp)
+{
+	RSApub *rsa;
+	char *p;
+
+	rsa = rsapuballoc();
+	rsa->n = base64tobig(str, &p);
+	rsa->ek = base64tobig(p, &p);
+	if(strp)
+		*strp = p;
+	if(rsa->n == nil || rsa->ek == nil){
+		rsapubfree(rsa);
+		return nil;
+	}
+
+	return rsa;
+}
+
+static void*
+rsa_str2sig(char *str, char **strp)
+{
+	mpint *rsa;
+	char *p;
+
+	rsa = base64tobig(str, &p);
+	if(rsa == nil)
+		return nil;
+	if(strp)
+		*strp = p;
+	return rsa;
+}
+
+static int
+rsa_sk2str(void *vrsa, char *buf, int len)
+{
+	RSApriv *rsa;
+	char *cp, *ep;
+
+	rsa = vrsa;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", rsa->pub.n);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->pub.ek);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->dk);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->p);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->q);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->kp);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->kq);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->c2);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static int
+rsa_pk2str(void *vrsa, char *buf, int len)
+{
+	RSApub *rsa;
+	char *cp, *ep;
+
+	rsa = vrsa;
+	ep = buf + len - 1;
+	cp = buf;
+	cp += snprint(cp, ep - cp, "%U\n", rsa->n);
+	cp += snprint(cp, ep - cp, "%U\n", rsa->ek);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static int
+rsa_sig2str(void *vrsa, char *buf, int len)
+{
+	mpint *rsa;
+	char *cp, *ep;
+
+	rsa = vrsa;
+	ep = buf + len - 1;
+	cp = buf;
+
+	cp += snprint(cp, ep - cp, "%U\n", rsa);
+	*cp = 0;
+
+	return cp - buf;
+}
+
+static void*
+rsa_sk2pk(void *vs)
+{
+	return rsaprivtopub((RSApriv*)vs);
+}
+
+/* generate an rsa secret key */
+static void*
+rsa_gen(int len)
+{
+	RSApriv *key;
+
+	for(;;){
+		key = rsagen(len, 6, 0);
+		if(mpsignif(key->pub.n) == len)
+			return key;
+		rsaprivfree(key);
+	}
+}
+
+/* generate an rsa secret key with same params as a public key */
+static void*
+rsa_genfrompk(void *vpub)
+{
+	RSApub *pub;
+
+	pub = vpub;
+	return rsagen(mpsignif(pub->n), mpsignif(pub->ek), 0);
+}
+
+static void*
+rsa_sign(mpint* m, void *key)
+{
+	return rsadecrypt((RSApriv*)key, m, nil);
+}
+
+static int
+rsa_verify(mpint* m, void *sig, void *key)
+{
+	mpint *t;
+	int r;
+
+	t = rsaencrypt((RSApub*)key, (mpint*)sig, nil);
+	r = mpcmp(t, m) == 0;
+	mpfree(t);
+	return r;
+}
+
+static void
+rsa_freepriv(void *a)
+{
+	rsaprivfree((RSApriv*)a);
+}
+
+static void
+rsa_freepub(void *a)
+{
+	rsapubfree((RSApub*)a);
+}
+
+static void
+rsa_freesig(void *a)
+{
+	mpfree(a);
+}
+
+SigAlgVec*
+rsainit(void)
+{
+	SigAlgVec *vec;
+
+	vec = malloc(sizeof(SigAlgVec));
+	if(vec == nil)
+		return nil;
+
+	vec->name = "rsa";
+
+	vec->pkattr = pkattr;
+	vec->skattr = skattr;
+	vec->sigattr = sigattr;
+
+	vec->str2sk = rsa_str2sk;
+	vec->str2pk = rsa_str2pk;
+	vec->str2sig = rsa_str2sig;
+
+	vec->sk2str = rsa_sk2str;
+	vec->pk2str = rsa_pk2str;
+	vec->sig2str = rsa_sig2str;
+
+	vec->sk2pk = rsa_sk2pk;
+
+	vec->gensk = rsa_gen;
+	vec->genskfrompk = rsa_genfrompk;
+	vec->sign = rsa_sign;
+	vec->verify = rsa_verify;
+
+	vec->skfree = rsa_freepriv;
+	vec->pkfree = rsa_freepub;
+	vec->sigfree = rsa_freesig;
+
+	return vec;
+}
--- /dev/null
+++ b/liblogfs/NOTICE
@@ -1,0 +1,23 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 2002, 2003 Vita Nuova Holdings Limited.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/liblogfs/boot.c
@@ -1,0 +1,496 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+struct LogfsBoot {
+	LogfsLowLevel *ll;
+	long bootblocks;
+	long blocksize;
+	long size;
+	long *map;
+	int trace;
+	int printbad;
+//	ulong bootpathmask;
+//	int bootgenshift;
+};
+
+typedef struct LogfsBootPath LogfsBootPath;
+
+//#define LogfsBootGenBits 2
+//#define LogfsBootGenMask ((1 << LogfsBootGenBits) - 1)
+#define LogfsBootGenMask ((1 << L2BlockCopies) - 1)
+
+struct LogfsBootPath {
+	ulong path;
+	uchar gen;
+};
+
+#define LOGFSMKBOOTPATH(lb, p) mkdatapath((p)->path, (p)->gen)
+#define LOGFSSPLITBOOTPATHEX(bgs, bpm, p, v) ((p)->path = dataseqof(v), (p)->gen = copygenof(v))
+#define LOGFSSPLITBOOTPATH(lb, p, v) LOGFSSPLITBOOTPATHEX(0, 0, p, v)
+
+//#define LOGFSMKBOOTPATH(lb, p) (((p)->path & (lb)->bootpathmask) | (((p)->gen & LogfsBootGenMask) << (lb)->bootgenshift))
+//#define LOGFSSPLITBOOTPATHEX(bgs, bpm, p, v) ((p)->path = (v) & (bpm), (p)->gen = ((v) >> (bgs)) & LogfsBootGenMask) 
+//#define LOGFSSPLITBOOTPATH(lb, p, v) LOGFSSPLITBOOTPATHEX((lb)->bootgenshift, (lb)->bootpathmask, p, v)
+
+extern LogfsBootPath logfsbooterasedpath;
+
+static char Ecorrupt[] = "filesystem corrupt";
+static char Enospc[] = "no free blocks";
+static char Eaddress[] = "address out of range";
+
+static char *
+logfsbootblockupdate(LogfsBoot *lb, void *buf, LogfsBootPath *path, uchar tag, ulong block)
+{
+	LogfsLowLevel *ll =  lb->ll;
+	char *errmsg;
+	ulong packedpath;
+
+	if(lb->trace > 1)
+		print("logfsbootblockupdate: path 0x%.8lux(%d) tag %s block %lud\n",
+		    path->path, path->gen, logfstagname(tag), block);
+
+	packedpath = LOGFSMKBOOTPATH(lb, path);
+	errmsg = (*ll->writeblock)(ll, buf, tag, packedpath, 1, &lb->bootblocks, block);
+
+	if(errmsg) {
+		/*
+		 * ensure block never used again until file system reinitialised
+		 * We have absolutely no idea what state it's in. This is most
+		 * likely if someone turns off the power (or at least threatens
+		 * the power supply), during a block update. This way the block
+		 * is protected until the file system in reinitialised. An alternative
+		 * would be check the file system after a power fail false alarm,
+		 * and erase any Tworse blocks
+		 */
+		(*ll->setblocktag)(ll, block, LogfsTworse);
+		return errmsg;
+	}
+		
+	(*ll->setblocktag)(ll, block, tag);
+	(*ll->setblockpath)(ll, block, packedpath);
+
+	return nil;
+}
+
+char *
+logfsbootfettleblock(LogfsBoot *lb, long block, uchar tag, long path, int *markedbad)
+{
+	LogfsLowLevel *ll = lb->ll;
+	char *errmsg;
+	void *llsave;
+
+	errmsg = (*ll->eraseblock)(ll, block, &llsave, markedbad);
+	if(errmsg || (markedbad && *markedbad)) {
+		logfsfreemem(llsave);
+		return errmsg;
+	}
+	errmsg = (*ll->reformatblock)(ll, block, tag, path, 1, &lb->bootblocks, llsave, markedbad);
+	logfsfreemem(llsave);
+	return errmsg;
+}
+
+/*
+ * block transfer is the critical unit of update
+ * we are going to assume that page writes and block erases are atomic
+ * this can pretty much be assured by not starting a page write or block erase
+ * if the device feels it is in power fail
+ */
+
+static char *
+logfsbootblocktransfer(LogfsBoot *lb, void *buf, ulong oldblock, int markbad)
+{
+	LogfsLowLevel *ll = lb->ll;
+	long bestnewblock;
+	ulong oldpackedpath;
+	LogfsBootPath oldpath;
+	short oldtag;
+	char *errmsg;
+	int markedbad;
+
+	oldpackedpath = (*ll->getblockpath)(ll, oldblock);
+	oldtag = (*ll->getblocktag)(ll, oldblock);
+
+	LOGFSSPLITBOOTPATH(lb, &oldpath, oldpackedpath);
+
+	for(;;) {
+		LogfsBootPath newpath;
+
+		bestnewblock = logfsfindfreeblock(ll, markbad ? AllocReasonReplace : AllocReasonTransfer);
+		if(lb->trace > 0 && markbad)
+			print("logfsbootblocktransfer: block %lud is bad, copying to %ld\n",
+				oldblock, bestnewblock);
+		if(lb->trace > 1 && !markbad)
+			print("logfsbootblocktransfer: copying block %lud to %ld\n",
+				oldblock, bestnewblock);
+		if(bestnewblock == -1)
+			return Enospc;
+		newpath = oldpath;
+//		newpath.gen = (newpath.gen + 1) & LogfsBootGenMask;
+		newpath.gen = copygensucc(newpath.gen);
+		errmsg = logfsbootblockupdate(lb, buf, &newpath, oldtag, bestnewblock);
+		if(errmsg == nil)
+			break;
+		if(strcmp(errmsg, Eio) != 0)
+			return errmsg;
+		(*ll->markblockbad)(ll, bestnewblock);
+	}
+
+#ifdef LOGFSTEST
+	if(logfstest.partialupdate) {
+		print("skipping erase\n");
+		logfstest.partialupdate = 0;
+		return nil;
+	}
+	if(logfstest.updatenoerase) {
+		print("skipping erase\n");
+		logfstest.updatenoerase = 0;
+		return nil;
+	}
+#endif
+
+	if(oldtag == LogfsTboot)
+		lb->map[oldpath.path] = bestnewblock;
+
+	return logfsbootfettleblock(lb, oldblock, LogfsTnone, ~0, &markedbad);
+}
+
+static char *
+logfsbootblockread(LogfsBoot *lb, void *buf, long block, LogfsLowLevelReadResult *blocke)
+{
+	LogfsLowLevel *ll = lb->ll;
+	char *errmsg;
+
+	*blocke = LogfsLowLevelReadResultOk;
+	errmsg = (*ll->readblock)(ll, buf, block, blocke);
+	if(errmsg)
+		return errmsg;
+
+	if(*blocke != LogfsLowLevelReadResultOk) {
+		char *errmsg = logfsbootblocktransfer(lb, buf, block, 1);
+		if(errmsg)
+			return errmsg;
+	}
+
+	if(*blocke == LogfsLowLevelReadResultHardError)
+		return Eio;
+
+	return nil;
+}
+
+char *
+logfsbootread(LogfsBoot *lb, void *buf, long n, ulong offset)
+{
+	int i;
+
+	if(lb->trace > 0)
+		print("logfsbootread(0x%.8lux, 0x%lx, 0x%lux)\n", (ulong)buf, n, offset);
+	if(offset % lb->blocksize || n % lb->blocksize)
+		return Eio;
+	n /= lb->blocksize;
+	offset /= lb->blocksize;
+	if(offset + n > lb->bootblocks)
+		return Eio;
+	for(i = 0; i < n; i++) {
+		LogfsLowLevelReadResult result;
+		char *errmsg = logfsbootblockread(lb, buf, lb->map[offset + i], &result);
+		if(errmsg)
+			return errmsg;
+		buf = (uchar *)buf + lb->blocksize;
+	}
+	return nil;
+}
+
+static char *
+logfsbootblockreplace(LogfsBoot *lb, void *buf, ulong logicalblock)
+{
+	uchar *oldblockbuf;
+	ulong oldblock;
+	char *errmsg;
+	LogfsLowLevelReadResult result;
+
+	oldblock = lb->map[logicalblock];
+	oldblockbuf = logfsrealloc(nil, lb->blocksize);
+	if(oldblockbuf == nil)
+		return Enomem;
+
+	errmsg = logfsbootblockread(lb, oldblockbuf, oldblock, &result);
+	if(errmsg == nil && memcmp(oldblockbuf, buf, lb->blocksize) != 0)
+		errmsg = logfsbootblocktransfer(lb, buf, oldblock, 0);
+
+	logfsfreemem(oldblockbuf);
+	return errmsg;
+}
+
+char *
+logfsbootwrite(LogfsBoot *lb, void *buf, long n, ulong offset)
+{
+	int i;
+
+	if(lb->trace > 0)
+		print("logfsbootwrite(0x%.8lux, 0x%lux, 0x%lux)\n", (ulong)buf, n, offset);
+	/*
+	 * don't even get started on a write if the power has failed
+	 */
+	if(offset % lb->blocksize || n % lb->blocksize)
+		return Eio;
+	n /= lb->blocksize;
+	offset /= lb->blocksize;
+	if(offset + n > lb->bootblocks)
+		return Eio;
+	for(i = 0; i < n; i++) {
+		logfsbootblockreplace(lb, buf, offset + i);
+		buf = (uchar *)buf + lb->blocksize;
+	}
+	return nil;
+}
+
+char *
+logfsbootio(LogfsBoot *lb, void *buf, long n, ulong offset, int write)
+{
+	return (write ? logfsbootwrite : logfsbootread)(lb, buf, n, offset);
+}
+
+static char *
+eraseandformatblock(LogfsBoot *lb, long block, int trace)
+{
+	char *errmsg;
+	int markedbad;
+
+	errmsg = logfsbootfettleblock(lb, block, LogfsTnone, ~0, &markedbad);
+	if(errmsg)
+		return errmsg;
+	if(markedbad && trace > 1)
+		print("erase/format failed - marked bad\n");
+	return nil;
+}
+
+char *
+logfsbootopen(LogfsLowLevel *ll, long base, long limit, int trace, int printbad, LogfsBoot **lbp)
+{
+	long *reversemap;
+	ulong blocksize;
+	ulong blocks;
+	long i;
+	long bootblockmax;
+	LogfsBoot *lb = nil;
+	ulong baseblock;
+	char *errmsg;
+//	int bootgenshift = ll->pathbits- LogfsBootGenBits;
+//	ulong bootpathmask = (1 << (ll->pathbits - LogfsBootGenBits)) - 1;
+	long expectedbootblocks;
+
+	errmsg = (*ll->open)(ll, base, limit, trace, 1, &expectedbootblocks);
+	if(errmsg)
+		return errmsg;
+
+	bootblockmax = -1;
+	blocks = ll->blocks;
+	baseblock = (*ll->getbaseblock)(ll);
+	blocksize = (*ll->getblocksize)(ll);
+
+	for(i = 0; i < blocks; i++) {
+		if((*ll->getblocktag)(ll, i) == LogfsTboot) {
+			long path = (*ll->getblockpath)(ll, i);
+			LogfsBootPath lp;
+			LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &lp, path);
+			if((long)lp.path > bootblockmax)
+				bootblockmax = lp.path;
+		}
+	}
+	if(bootblockmax + 1 >= blocks) {
+		if(printbad)
+			print("logfsbootinit: bootblockmax %ld exceeds number of blocks\n", bootblockmax);
+		return Ecorrupt;
+	}
+	if(bootblockmax < 0) {
+		if(printbad)
+			print("logfsbootopen: no boot area\n");
+		return Ecorrupt;
+	}
+	if(bootblockmax + 1 != expectedbootblocks) {
+		if(printbad)
+			print("logfsbootopen: wrong number of bootblocks (found %lud, expected %lud)\n",
+				bootblockmax + 1, expectedbootblocks);
+	}
+		
+	reversemap = logfsrealloc(nil, sizeof(*reversemap) * (bootblockmax + 1));
+	if(reversemap == nil)
+		return Enomem;
+
+	for(i = 0; i <= bootblockmax; i++)
+		reversemap[i] = -1;
+	for(i = 0; i < blocks; i++) {
+		LogfsBootPath ipath;
+		long rm;
+		ulong ip;
+
+		if((*ll->getblocktag)(ll, i) != LogfsTboot)
+			continue;
+		ip = (*ll->getblockpath)(ll, i);
+		LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &ipath, ip);
+		rm = reversemap[ipath.path];
+		if(rm != -1) {
+			if(printbad)
+				print("logfsbootopen: blockaddr 0x%.8lux: path %ld(%d): duplicate\n",
+					blocksize * (baseblock + i), ipath.path, ipath.gen);
+			/*
+			 * resolve collision
+			 * if this one is partial, then erase it
+			 * if the existing one is partial, erase that
+			 * if both valid, give up
+			 */
+			if((*ll->getblockpartialformatstatus)(ll, i)) {
+				errmsg = eraseandformatblock(lb, i, trace);
+				if(errmsg)
+					goto error;
+			}
+			else if((*ll->getblockpartialformatstatus)(ll, rm)) {
+				errmsg = eraseandformatblock(lb, rm, trace);
+				if(errmsg)
+					goto error;
+				reversemap[ipath.path] = i;
+			}
+			else {
+				int d;
+				ulong rmp;
+				LogfsBootPath rmpath;
+				rmp = (*ll->getblockpath)(ll, rm);
+				LOGFSSPLITBOOTPATHEX(bootgenshift, bootpathmask, &rmpath, rmp);
+				d = (ipath.gen - rmpath.gen) & LogfsBootGenMask;
+				if(printbad)
+					print("i.gen = %d rm.gen = %d d = %d\n", ipath.gen, rmpath.gen, d);
+				if(d == 1) {
+					/* i is newer;
+					 * keep the OLDER one because
+					 * we might have had a write failure on the last page, but lost the
+					 * power before being able to mark the first page bad
+					 * if, worse, the auxiliary area's tag is the same for first and last page,
+					 * this looks like a successfully written page. so, we cannot believe the
+					 * data in the newer block unless we erased the old one, and then of
+					 * course, we wouldn't have a duplicate.
+					 */
+					errmsg = eraseandformatblock(lb, i, trace);
+					if(errmsg)
+						goto error;
+				}
+				else if(d == LogfsBootGenMask) {
+					/* rm is newer */
+					errmsg = eraseandformatblock(lb, rm, trace);
+					if(errmsg)
+						goto error;
+					reversemap[ipath.path] = i;
+				}
+				else {
+					errmsg = Ecorrupt;
+					goto error;
+				}
+			}
+		}
+		else
+			reversemap[ipath.path] = i;
+	}
+	/*
+	 * final checks; not partial blocks, and no holes
+	 */
+	for(i = 0; i <= bootblockmax; i++) {
+		long rm;
+		rm = reversemap[i];
+		if(rm == -1) {
+			if(printbad)
+				print("logfsbootopen: missing boot block %ld\n", i);
+			errmsg = Ecorrupt;
+			goto error;
+		}
+		if((*ll->getblockpartialformatstatus)(ll, rm)) {
+			if(printbad)
+				print("logfsbootopen: boot block %ld partially written\n", rm);
+			errmsg = Ecorrupt;
+			goto error;
+		}
+	}
+	/* the reverse map is consistent */
+	lb = logfsrealloc(nil, sizeof(*lb));
+	if(lb == nil) {
+		errmsg = Enomem;
+		goto error;
+	}
+
+	lb->blocksize = blocksize;
+	lb->bootblocks = bootblockmax + 1;
+	lb->map = reversemap;
+	lb->trace = trace;
+	lb->printbad = printbad;
+	lb->ll = ll;
+	lb->size = blocksize * lb->bootblocks;
+//	lb->bootgenshift = bootgenshift;
+//	lb->bootpathmask = bootpathmask;
+	*lbp = lb;
+	if(trace)
+		print("logfsbootopen: success\n");
+	return nil;
+
+error:
+	logfsfreemem(reversemap);
+	logfsfreemem(lb);
+	return errmsg;
+}
+
+void
+logfsbootfree(LogfsBoot *lb)
+{
+	if(lb) {
+		logfsfreemem(lb->map);
+		logfsfreemem(lb);
+	}
+}
+
+char *
+logfsbootmap(LogfsBoot *lb, ulong laddress, ulong *lblockp, int *lboffsetp, int *lpagep, int *lpageoffsetp, ulong *pblockp, ulong *paddressp)
+{
+	LogfsLowLevel *ll = lb->ll;
+	ulong lblock;
+	ulong lboffset, lpageoffset, lpage;
+	ulong pblock;
+	ulong paddress;
+
+	lblock = laddress / lb->blocksize;
+	if(lblock >= lb->bootblocks)
+		return Eaddress;
+	lboffset = laddress % lb->blocksize;
+	pblock = lb->map[lblock];
+	paddress = (*ll->calcrawaddress)(ll, pblock, lboffset);
+	lpage = lboffset >>  ll->l2pagesize;
+	lpageoffset = lboffset & ((1 << ll->l2pagesize) - 1);
+	if(lblockp)
+		*lblockp = lblock;
+	if(lboffsetp)
+		*lboffsetp = lboffset;
+	if(lpagep)
+		*lpagep = lpage;
+	if(lpageoffsetp)
+		*lpageoffsetp = lpageoffset;
+	if(pblockp)
+		*pblockp = pblock;
+	if(paddressp)
+		*paddressp = paddress;
+	return nil;
+}
+
+long
+logfsbootgetiosize(LogfsBoot *lb)
+{
+	return lb->blocksize;
+}
+
+long
+logfsbootgetsize(LogfsBoot *lb)
+{
+	return lb->size;
+}
+
+void
+logfsboottrace(LogfsBoot *lb, int level)
+{
+	lb->trace = level;
+}
--- /dev/null
+++ b/liblogfs/clunk.c
@@ -1,0 +1,19 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverclunk(LogfsServer *server, u32int fid)
+{
+	Fid *f;
+	if(server->trace > 1)
+		print("logfsserverclunk(%ud)\n", fid);
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsebadfid;
+	if(f->openmode >= 0 && (f->openmode & ORCLOSE) != 0)
+		return logfsserverremove(server, fid);
+	logfsfidmapclunk(server->fidmap, fid);
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/conv.c
@@ -1,0 +1,285 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+static void
+pn(uchar **pp, char *v)
+{
+	uchar *p = *pp;
+	int l;
+	l = v ? strlen(v) : 0;
+	PBIT16(p, l); p += BIT16SZ;
+	memmove(p, v, l);
+	p += l;
+	*pp = p;
+}
+
+static uint
+sn(char *p)
+{
+	if(p == nil)
+		return BIT16SZ;
+	return strlen(p) + BIT16SZ;
+}
+
+uint
+logfsconvM2S(uchar *ap, uint nap, LogMessage *f)
+{
+	uchar *p = ap;
+	uchar *ep = p + nap;
+	uchar *mep;
+	uint size;
+//print("conv(%d)\n", nap);
+	if(p + 1 > ep)
+		return 0;
+	f->type = *p++;
+//print("type %c\n", f->type);
+	switch(f->type) {
+	case LogfsLogTstart:
+	case LogfsLogTcreate:
+	case LogfsLogTtrunc:
+	case LogfsLogTremove:
+	case LogfsLogTwrite:
+	case LogfsLogTwstat:
+		break;
+	case LogfsLogTend:
+		return 1;
+	default:	
+		return 0;
+	}
+	if(p + BIT16SZ > ep)
+		return 0;
+	size = GBIT16(p); p += BIT16SZ;
+//print("size %ud\n", size);
+	if(p + size > ep)
+		return 0;
+	mep = p + size;
+	if(p + BIT32SZ > mep)
+		return 0;
+	f->path = GBIT32(p); p += BIT32SZ;
+	switch(f->type) {
+	case LogfsLogTstart:
+		/* 's' size[2] path[4] nerase[4] */
+		if(p + BIT32SZ > ep)
+			return 0;
+		f->u.start.nerase = GBIT32(p); p += BIT32SZ;
+		break;
+	case LogfsLogTcreate:
+		/* 'c' size[2] path[4] perm[4] newpath[4] mtime[4] cvers[4] name[s] uid[s] gid[s] */
+		if(p + 4 * BIT32SZ > mep)
+			return 0;
+		f->u.create.perm = GBIT32(p); p+= BIT32SZ;
+		f->u.create.newpath = GBIT32(p); p+= BIT32SZ;
+		f->u.create.mtime = GBIT32(p); p+= BIT32SZ;
+		f->u.create.cvers = GBIT32(p); p+= BIT32SZ;
+		if(!logfsgn(&p, mep, &f->u.create.name)
+			|| !logfsgn(&p, mep, &f->u.create.uid)
+			|| !logfsgn(&p, mep, &f->u.create.gid))
+			return 0;
+		break;
+	case LogfsLogTremove:
+		/* 'r' size[2] path[4] mtime[4] muid[s] */
+		if(p + BIT32SZ > mep)
+			return 0;
+		f->u.remove.mtime = GBIT32(p); p += BIT32SZ;
+		if(!logfsgn(&p, mep, &f->u.remove.muid))
+			return 0;
+		break;
+	case LogfsLogTtrunc:
+		/* 't' size[2] path[4] mtime[4] cvers[4] muid[s] */
+		if(p + 2 * BIT32SZ > mep)
+			return 0;
+		f->u.trunc.mtime = GBIT32(p); p += BIT32SZ;
+		f->u.trunc.cvers = GBIT32(p); p += BIT32SZ;
+		if(!logfsgn(&p, mep, &f->u.trunc.muid))
+			return 0;
+		break;
+	case LogfsLogTwrite:
+		/* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+		if(p + BIT32SZ + BIT16SZ + 2 * BIT32SZ > mep)
+			return 0;
+		f->u.write.offset = GBIT32(p); p += BIT32SZ;
+		f->u.write.count = GBIT16(p); p += BIT16SZ;
+		f->u.write.mtime = GBIT32(p); p += BIT32SZ;
+		f->u.write.cvers = GBIT32(p); p += BIT32SZ;
+		if(!logfsgn(&p, mep, &f->u.write.muid))
+			return 0;
+		if(p + BIT32SZ > mep)
+			return 0;
+		f->u.write.flashaddr = GBIT32(p); p += BIT32SZ;
+		if(f->u.write.flashaddr & LogAddr) {
+			if(p + f->u.write.count > mep)
+				return 0;
+			f->u.write.data = p;
+			p += f->u.write.count;
+		}
+		else
+			f->u.write.data = nil;
+		break;
+	case LogfsLogTwstat:
+		/* 'W' size[2] path[4] name[s] perm[4] uid[s] gid[s] mtime[4] muid[s] or */
+		/* 'W' size[2] path[4] name[s] perm[4] gid[s] mtime[4] muid[s] */
+		if(!logfsgn(&p, mep, &f->u.wstat.name))
+			return 0;
+		if(p + BIT32SZ > mep)
+			return 0;
+		f->u.wstat.perm = GBIT32(p); p += BIT32SZ;
+		if(!logfsgn(&p, mep, &f->u.wstat.uid))
+			return 0;
+		if(!logfsgn(&p, mep, &f->u.wstat.gid))
+			return 0;
+		if(p + BIT32SZ > mep)
+			return 0;
+		f->u.wstat.mtime = GBIT32(p); p += BIT32SZ;
+		if(!logfsgn(&p, mep, &f->u.wstat.muid))
+			return 0;
+		break;
+	default:
+		return 0;
+	}
+	if(p != mep)
+		return 0;
+	return p - ap;
+}
+
+uint
+logfssizeS2M(LogMessage *m)
+{
+	switch(m->type) {
+	case LogfsLogTend:
+		return 1;
+	case LogfsLogTstart:
+		return 11;
+	case LogfsLogTcreate:
+		/* 'c' size[2] path[4] perm[4] newpath[4] mtime[4] cvers[4] name[s] uid[s] gid[s] */
+		return 1 + BIT16SZ + 5 * BIT32SZ
+			+ sn(m->u.create.name) + sn(m->u.create.uid) + sn(m->u.create.gid);
+	case LogfsLogTremove:
+		/* 'r' size[2] path[4] mtime[4] muid[s] */
+		return 1 + BIT16SZ + 2 * BIT32SZ + sn(m->u.remove.muid);
+	case LogfsLogTtrunc:
+		/* 't' size[2] path[4] mtime[4] cvers[4] muid[s] */
+		return 1 + BIT16SZ + 3 * BIT32SZ + sn(m->u.trunc.muid);
+	case LogfsLogTwrite:
+		/* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+		return 1 + BIT16SZ + 2 * BIT32SZ + BIT16SZ + 2 * BIT32SZ + sn(m->u.write.muid)
+			+ BIT32SZ + (m->u.write.data ? m->u.write.count : 0);
+	case LogfsLogTwstat:
+		/* 'W' size[2] path[4] name[s] perm[4] uid[s] gid[s] mtime[4] muid[s] */
+		/* 'W' size[2] path[4] name[s] perm[4] gid[s] mtime[4] muid[s] */
+		return 1 + BIT16SZ + BIT32SZ + sn(m->u.wstat.name) + BIT32SZ
+			+ sn(m->u.wstat.uid)
+			+ sn(m->u.wstat.gid) + BIT32SZ + sn(m->u.wstat.muid);
+	default:
+		return 0;
+	}
+}
+
+uint
+logfsconvS2M(LogMessage *s, uchar *ap, uint nap)
+{
+	uint size;
+	uchar *p;
+	size = logfssizeS2M(s);
+	if(size == 0 || size > nap)
+		return 0;
+	p = ap;
+	*p++ = s->type;
+	if(s->type == LogfsLogTend)
+		return 1;
+	size -= 1 + BIT16SZ;
+	PBIT16(p, size); p += BIT16SZ;
+	PBIT32(p, s->path); p += BIT32SZ;
+	switch(s->type) {
+	case LogfsLogTstart:
+		PBIT32(p, s->u.start.nerase); p += BIT32SZ;
+		break;
+	case LogfsLogTcreate:
+		/* 'c' size[2] path[4] perm[4] newpath[4] mtime[4] cvers[4] name[s] uid[s] gid[s] */
+		PBIT32(p, s->u.create.perm); p += BIT32SZ;
+		PBIT32(p, s->u.create.newpath); p += BIT32SZ;
+		PBIT32(p, s->u.create.mtime); p += BIT32SZ;
+		PBIT32(p, s->u.create.cvers); p += BIT32SZ;
+		pn(&p, s->u.create.name);
+		pn(&p, s->u.create.uid);
+		pn(&p, s->u.create.gid);
+		break;
+	case LogfsLogTremove:
+		/* 'r' size[2] path[4] mtime[4] muid[s] */
+		PBIT32(p, s->u.remove.mtime); p += BIT32SZ;
+		pn(&p, s->u.remove.muid);
+		break;
+	case LogfsLogTtrunc:
+		/* 't' size[2] path[4] mtime[4] cvers[4] muid[s] */
+		PBIT32(p, s->u.trunc.mtime); p += BIT32SZ;
+		PBIT32(p, s->u.trunc.cvers); p += BIT32SZ;
+		pn(&p, s->u.trunc.muid);
+		break;
+	case LogfsLogTwrite:
+		/* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+		PBIT32(p, s->u.write.offset); p += BIT32SZ;
+		PBIT16(p, s->u.write.count); p += BIT16SZ;
+		PBIT32(p, s->u.write.mtime); p += BIT32SZ;
+		PBIT32(p, s->u.write.cvers); p += BIT32SZ;
+		pn(&p, s->u.write.muid);
+		PBIT32(p, s->u.write.flashaddr); p += BIT32SZ;
+		if(s->u.write.data) {
+			memmove(p, s->u.write.data, s->u.write.count);
+			p += s->u.write.count;
+		}
+		break;
+	case LogfsLogTwstat:
+		/* 'W' size[2] path[4] name[s] perm[4] uid[s] gid[s] mtime[4] muid[s] */
+		/* 'W' size[2] path[4] name[s] perm[4] gid[s] mtime[4] muid[s] */
+		pn(&p, s->u.wstat.name);
+		PBIT32(p, s->u.wstat.perm); p += BIT32SZ;
+		pn(&p, s->u.wstat.uid);
+		pn(&p, s->u.wstat.gid);
+		PBIT32(p, s->u.wstat.mtime); p+= BIT32SZ;
+		pn(&p, s->u.wstat.muid);
+		break;
+	default:
+		return 0;
+	}
+	return p - ap;
+}
+		
+void
+logfsdumpS(LogMessage *m)
+{
+	switch(m->type) {
+	case LogfsLogTend:
+		print("LogfsLogTend()");
+		break;
+	case LogfsLogTstart:
+		print("LogfsLogTstart(path=%ud, nerase=%ud)", m->path, m->u.start.nerase);
+		break;
+	case LogfsLogTcreate:
+		print("LogfsLogTcreate(path=%ud, perm=0%uo, newpath=%ud, mtime=%ud, cvers=%ud, name=%s, uid=%s, gid=%s)",
+			m->path, m->u.create.perm, m->u.create.newpath, m->u.create.mtime, m->u.create.cvers,
+			m->u.create.name, m->u.create.uid, m->u.create.gid);
+		break;
+	case LogfsLogTremove:
+		print("LogfsLogTremove(path=%ud, mtime=%ud, muid=%s)",
+			m->path, m->u.remove.mtime, m->u.remove.muid);
+		break;
+	case LogfsLogTtrunc:
+		print("LogfsLogTtrunc(path=%ud, mtime=%ud, cvers=%ud, muid=%s)",
+			m->path, m->u.trunc.mtime, m->u.trunc.cvers, m->u.trunc.muid);
+		break;
+	case LogfsLogTwrite:
+		print("LogfsLogTwrite(path=%ud, offset=%ud, count=%ud, mtime=%ud, cvers=%ud, muid=%s, flashaddr=0x%.8ux)",
+			m->path, m->u.write.offset, m->u.write.count, m->u.write.mtime, m->u.write.cvers, m->u.write.muid,
+			m->u.write.flashaddr);
+		break;
+	case LogfsLogTwstat:
+		print("LogfsLogTwstat(path=%ud, name=%s, perm=0%uo, uid=%s, gid=%s, mtime=%ud, muid=%s)",
+			m->path, m->u.wstat.name, m->u.wstat.perm, m->u.wstat.uid, m->u.wstat.gid,
+			m->u.wstat.mtime, m->u.wstat.muid);
+		break;
+	default:
+		print("LogfsLogTother(%c)", m->type);
+		break;
+	}
+}
--- /dev/null
+++ b/liblogfs/create.c
@@ -1,0 +1,82 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsservercreate(LogfsServer *server, u32int fid, char *name, u32int perm, uchar mode, Qid *qid)
+{
+	Fid *f;
+	char *uid;
+	ulong newpath;
+	char *errmsg;
+	Entry *e, *xe, *pe;
+	Path *pp;
+	LogMessage s;
+
+	if(server->trace > 1)
+		print("logfsservercreate(%ud, %s, 0%uo, %.2ux)\n", fid, name, perm, mode);
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsebadfid;
+	if(f->openmode >= 0)
+		return logfsefidopen;
+	pe = f->entry;
+	if((pe->qid.type & QTDIR) == 0)
+		return Enotdir;
+	if((perm & DMDIR) != 0 && ((mode & OTRUNC) != 0 || (mode &  3) != OREAD))
+		return Eperm;
+	if(!logfsuserpermcheck(server, pe, f, DMWRITE))
+		return Eperm;
+	/*
+	 * illegal names
+	 */
+	if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+		return Eperm;
+	for(xe = pe->u.dir.list; xe; xe = xe->next)
+		if(strcmp(xe->name, name) == 0)
+			return Eexist;
+	newpath = ++server->path;
+	while(logfspathmapfindentry(server->pathmap, newpath))
+		newpath++;	/* shouldn't happen */
+	uid = logfsisfindidfromname(server->is, f->uname);
+	errmsg = logfsentrynew(server, 1, newpath,
+		pe, name, uid, f->entry->gid, logfsnow(), uid, perm, 0, 0, &e);
+	if(errmsg)
+		return errmsg;
+	errmsg = logfspathmapnewentry(server->pathmap, newpath, e, &pp);
+	/* pp is guaranteed to be non-null */
+	if(errmsg) {
+		logfsfreemem(e);
+		return errmsg;
+	}
+	s.type = LogfsLogTcreate;
+	s.path = e->parent->qid.path;	
+	s.u.create.perm = e->perm;
+	s.u.create.newpath = e->qid.path;
+	s.u.create.mtime = e->mtime;
+	/* TODO - check with forsyth whether cvers is needed in dirs */
+	s.u.create.cvers = (e->qid.type & QTDIR) ? 0 : e->u.file.cvers;
+	s.u.create.name = e->name;
+	s.u.create.uid = e->uid;
+	s.u.create.gid = e->gid;
+	errmsg = logfslog(server, 1, &s);
+	if(errmsg) {
+		logfsfreemem(e);
+		logfspathmapdeleteentry(server->pathmap, newpath);
+		return errmsg;
+	}
+	server->path = newpath;
+	e->inuse++;
+	e->qid.vers++;
+	e->next = pe->u.dir.list;
+	pe->u.dir.list = e;
+	f->openmode = mode;
+	/*
+	 * TODO why does forsyth increment inuse for dir? - we're moving the fid onto the new file
+	 * so a decrement seems better
+	 */
+	logfsentryclunk(pe);
+	f->entry = e;
+	*qid = e->qid;
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/dump.c
@@ -1,0 +1,71 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+typedef struct WalkState {
+	u32int *flashaddrp;
+	u32int *lengthp;
+	int i;
+	int nth;
+} WalkState;
+
+static int
+walk(void *magic, Extent *e, int hole)
+{
+	WalkState *s = magic;
+	USED(hole);
+	if(s->i == s->nth) {
+		*s->flashaddrp = e->flashaddr;
+		*s->lengthp = e->max - e->min;
+		return 0;
+	}
+	s->i++;
+	return 1;
+}
+
+char *
+logfsserverreadpathextent(LogfsServer *server, u32int path, int nth, u32int *flashaddrp, u32int *lengthp,
+	long *blockp, int *pagep, int *offsetp)
+{
+	Entry *e;
+	WalkState s;
+	long index;
+	e = logfspathmapfinde(server->pathmap, path);
+	if(e == nil)
+		return logfseunknownpath;
+	if(e->perm & DMDIR)
+		return Eisdir;
+	s.flashaddrp = flashaddrp;
+	s.lengthp = lengthp;
+	s.i = 0;
+	s.nth = nth;
+	*lengthp = 0;
+	logfsextentlistwalk(e->u.file.extent, walk, &s);
+	if(*lengthp) {
+		logfsflashaddr2spo(server, *flashaddrp, &index, pagep, offsetp);
+		if(*flashaddrp & LogAddr)
+			if(index >= server->activelog->unsweptblockindex)
+				if(index <= server->activelog->curblockindex)
+					*blockp = server->activelog->blockmap[index];
+				else
+					*blockp = -1;
+			else if(server->sweptlog)
+				if(index <= server->sweptlog->curblockindex)
+					*blockp = server->sweptlog->blockmap[index];
+				else
+					*blockp = -1;
+			else
+				*blockp = -1;
+		else if(index < server->ndatablocks)
+			*blockp = server->datablock[index].block;
+		else
+			*blockp = -1;
+	}
+	else {
+		*blockp = 0;
+		*pagep = 0;
+		*offsetp = 0;
+	}
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/error.c
@@ -1,0 +1,17 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char logfsebadfid[] = "fid not in use";
+char logfsefidnotopen[] = "fid is not open for I/O";
+char logfsefidopen[] = "fid is open for I/O";
+char logfsenotadir[]  = "fid not a dir";
+char logfsefidinuse[] = "fid in use";
+char logfseopen[] = "fid not open";
+char logfseaccess[] = "fid open in wrong mode";
+char logfselogfull[] = "log filled";
+char logfselogmsgtoobig[] = "message too big for log";
+char logfseinternal[] = "internal error";
+char logfsenotempty[] = "directory not empty";
+char logfsefullreplacing[] = "out of space trying to replace block";
+char logfseunknownpath[] = "unknown path";
--- /dev/null
+++ b/liblogfs/extentlist.c
@@ -1,0 +1,279 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+typedef struct ExtentNode ExtentNode;
+
+struct ExtentNode {
+	Extent e;
+	ExtentNode *next;
+};
+
+struct ExtentList {
+	ExtentNode *head;
+};
+
+char *
+logfsextentlistnew(ExtentList **ep)
+{
+	ExtentList *l;
+	l = logfsrealloc(nil, sizeof(*l));
+	if(l == nil)
+		return Enomem;
+	*ep = l;
+	return  nil;
+}
+
+void
+logfsextentlistreset(ExtentList *l)
+{
+	ExtentNode *n;
+	n = l->head;
+	while(n) {
+		ExtentNode *next;
+		next = n->next;
+		logfsfreemem(n);
+		n = next;
+	}
+	l->head = nil;
+}
+
+void
+logfsextentlistfree(ExtentList **lp)
+{
+	ExtentList *l;
+	if(lp == nil || (l = *lp) == nil)
+		return;
+	logfsextentlistreset(l);
+	logfsfreemem(l);
+	*lp = nil;
+}
+
+char *
+logfsextentlistinsert(ExtentList *l, Extent *add, Extent **new)
+{
+	ExtentNode *old, *prev;
+	ExtentNode *saved = nil;
+
+	if(l == nil)
+		return "nil extentlist";
+
+	/* initially a's extents are non-empty, disjoint and sorted */
+	old = l->head;
+	prev = nil;
+	while(old) {
+		ExtentNode *next = old->next;
+		if(add->max <= old->e.min)
+			break;
+		if(old->e.min < add->max && add->min < old->e.max) {	/* they intersect */
+			if(add->min <= old->e.min) {
+				/* add overlaps front of old */
+				if(add->max < old->e.max) {
+					int trimmed;
+					/* but doesn't overlap end */
+					/* retain tail of old */
+					if(saved == nil){
+						saved = logfsrealloc(nil, sizeof(*saved));
+						if(saved == nil)
+							return Enomem;
+					}
+					trimmed = add->max - old->e.min;
+					old->e.min += trimmed;
+					old->e.flashaddr += trimmed;
+					/* can't touch any further extents, so... */
+					break;
+				}
+				/* add.min ≤ old.min < old.max ≤ add.max ⇒ add completely covers old */
+				/* delete old */
+				if(prev)
+					prev->next = next;
+				else
+					l->head = next;
+				/* stash the deleted extent, so we can reuse it */
+				if(saved == nil)
+					saved = old;
+				else
+					logfsfreemem(old);
+				old = next;
+				continue;
+			}
+			else {
+				/* add.min > old.min, so overlaps end of old or splits it */
+				if(add->max < old->e.max) {	/* add inside old, splitting it */
+					ExtentNode *frag;
+					/*
+					 * will need at most two add extents, so ensure
+					 * enough store exists before changing data structures
+					 */
+					if(saved == nil)
+						saved = logfsrealloc(nil, sizeof(*saved));
+					frag = logfsrealloc(nil, sizeof(*frag));
+					if(saved == nil || frag == nil)
+						return Enomem;
+					frag->next = next;
+					old->next = frag;
+					frag->e.min = add->max;
+					frag->e.max = old->e.max;
+					frag->e.flashaddr = old->e.flashaddr + (add->max - old->e.min);
+					old->e.max = add->min;
+					prev = old;
+					break;
+				}
+				else {
+					/*
+					 * will need at most one add extent, so create one
+					 * now before changing data structures
+					 */
+					if(saved == nil){
+						saved = logfsrealloc(nil, sizeof(*saved));
+						if(saved == nil)
+							return Enomem;
+					}
+					old->e.max = add->min;		/* retain start of old */
+				}
+				/* old.max <= add.max ⇒ add covers tail of old */
+			}
+		}
+		prev = old;
+		old = next;
+	}
+	/*
+	 * if here, and saved == nil, then there was no overlap
+	 */
+	if(saved == nil){
+		saved = logfsrealloc(nil, sizeof(*saved));
+		if(saved == nil)
+			return Enomem;
+	}
+	saved->e = *add;
+	if(prev) {
+		saved->next = prev->next;
+		prev->next = saved;
+	}
+	else {
+		saved->next = l->head;
+		l->head = saved;
+	}
+	if(new)
+		*new = &saved->e;
+	return nil;
+}
+
+Extent *
+logfsextentlistmatch(ExtentList *l, Extent *e)
+{
+	ExtentNode *m;
+	u32int flashmax;
+
+	if(l == nil)
+		return nil;
+
+	flashmax = e->flashaddr + (e->max - e->min);
+
+	for(m = l->head; m; m = m->next) {
+		u32int l = m->e.max - m->e.min;
+		if(e->min < m->e.max && m->e.min < e->max	/* they intersect */
+			&& m->e.flashaddr < flashmax && e->flashaddr < m->e.flashaddr + l) /* the store intersects */
+			return &(m->e);
+	}
+	return nil;
+}
+
+int
+logfsextentlistmatchall(ExtentList *l, int (*func)(void *magic, Extent *), void *magic, Extent *e)
+{
+	ExtentNode *m;
+	u32int flashmax;
+
+	if(l == nil)
+		return 1;
+
+	flashmax = e->flashaddr + (e->max - e->min);
+
+	for(m = l->head; m; m = m->next) {
+		u32int l;
+		if(m->e.min >= e->max)
+			return 1;
+		l = m->e.max - m->e.min;
+		if(e->min < m->e.max	/* they intersect */
+			&& m->e.flashaddr < flashmax && e->flashaddr < m->e.flashaddr + l) {
+			/* the store intersects */
+			int rv = (*func)(magic, &(m->e));
+			if(rv <= 0)
+				return rv;
+		}
+	}
+	return 1;
+}
+
+int
+logfsextentlistwalk(ExtentList *l, int (*func)(void *magic, Extent *, int hole), void *magic)
+{
+	ExtentNode *n;
+	u32int last = 0;
+	if(l == nil)
+		return 1;
+	for(n = l->head; n; n = n->next) {
+		int rv;
+		if(last < n->e.min) {
+			Extent hole;
+			hole.min = last;
+			hole.max = n->e.min;
+			hole.flashaddr = ~0;
+			rv = (*func)(magic, &hole, 1);
+			if(rv <= 0)
+				return rv;
+		}
+		rv = (*func)(magic, &n->e, 0);
+		if(rv <= 0)
+			return rv;
+		last = n->e.max;
+	}
+	return 1;
+}
+
+int
+logfsextentlistwalkrange(ExtentList *l, int (*func)(void *magic, u32int baseoffset, u32int limitoffset, Extent *, u32int extentoffset), void *magic, u32int base, u32int limit)
+{
+	ExtentNode *n;
+	u32int last = 0;
+	if(l == nil)
+		return 1;
+	for(n = l->head; n; n = n->next) {
+		Extent hole;
+		Extent *e;
+		if(last < n->e.min) {
+			hole.min = last;
+			hole.max = n->e.min;
+			e = &hole;
+		}
+		else {
+		again:
+			e = &n->e;
+		}
+		if(e->min >= limit)
+			return 1;
+//print("walkrange %ud .. %ud\n", e->min, e->max);
+		if(e->max > base) {
+			ulong rangebase, rangelimit, extentoffset;
+			int rv;
+			rangebase = e->min;
+			if(rangebase < base) {
+				extentoffset = base - rangebase;
+				rangebase += extentoffset;
+			}
+			else
+				extentoffset = 0;
+			rangelimit = e->max;
+			if(rangelimit > limit)
+				rangelimit = limit;
+			rv = (*func)(magic, rangebase - base, rangelimit - base, e == &hole ? nil : e, extentoffset);
+			if(rv <= 0)
+				return rv;
+		}
+		last = e->max;
+		if(e == &hole)
+			goto again;
+	}
+	return 1;
+}
--- /dev/null
+++ b/liblogfs/fidmap.c
@@ -1,0 +1,71 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+	FIDMOD = 127
+};
+
+int
+logfshashulong(void *v, int size)
+{
+	return (ulong)v % size;
+}
+
+/*
+ * TO DO: assumes map.c always passes sought key value as b, and value in map as a
+ */
+static int
+compare(void *a, void *b)
+{
+	Fid *f = a;
+	ulong fid = (ulong)b;	/* sic */
+//print("fidcompare(%ld, %ld)\n", f->fid, fid);
+	return f->fid == fid;
+}
+
+static int
+allocsize(void *key)
+{
+	USED(key);
+	return sizeof(Fid);
+}
+
+static void
+fidfree(void *a)
+{
+	Fid *f = a;
+	logfsdrsfree(&f->drs);
+}
+
+char *
+logfsfidmapnew(FidMap **fidmapp)
+{
+	return logfsmapnew(FIDMOD, logfshashulong, compare, allocsize, fidfree, fidmapp);
+}
+
+int
+logfsfidmapclunk(FidMap *m, ulong fid)
+{
+	Fid *f = logfsfidmapfindentry(m, fid);
+	if(f != nil){
+		logfsentryclunk(f->entry);
+		logfsmapdeleteentry(m, (void *)fid);
+		return 1;
+	}
+	return 0;
+}
+
+char *
+logfsfidmapnewentry(FidMap *m, ulong fid, Fid **fidmapp)
+{
+	char *errmsg;
+	errmsg = logfsmapnewentry(m, (void*)fid, fidmapp);
+	if(errmsg)
+		return errmsg;
+	if(*fidmapp == nil)
+		return nil;
+	(*fidmapp)->fid = fid;
+	(*fidmapp)->openmode = -1;
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/findfreeblock.c
@@ -1,0 +1,31 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+long
+logfsfindfreeblock(LogfsLowLevel *ll, AllocReason reason)
+{
+	long b;
+	long total;
+	b = (*ll->findfreeblock)(ll, &total);
+	if(b < 0)
+		return b;
+	switch(reason) {
+	case AllocReasonReplace:
+		break;
+	case AllocReasonTransfer:
+		if(total <= Replacements)
+			return -1;
+		break;
+	case AllocReasonLogExtend:
+		if(total <= Replacements + Transfers)
+			return -1;
+		break;
+	case AllocReasonDataExtend:
+		if(total <= Replacements + Transfers + LogSlack)
+			return -1;
+		break;
+	}
+//print("allocated free block %ld\n", b);
+	return b;
+}
--- /dev/null
+++ b/liblogfs/flush.c
@@ -1,0 +1,17 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverflush(LogfsServer *server)
+{
+	char *errmsg = logfslogsegmentflush(server, 1);
+	if(errmsg == nil)
+		errmsg = logfslogsegmentflush(server, 0);
+	if(errmsg == nil)
+		errmsg = (*server->ll->sync)(server->ll);
+	if(server->trace > 1)
+		print("logfsserverflush\n");
+	return errmsg;
+}
--- /dev/null
+++ b/liblogfs/format.c
@@ -1,0 +1,107 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsformat(LogfsLowLevel *ll, long base, long limit, long bootsize, int trace)
+{
+	long bootblocksdone, logblocksdone;
+	long u;
+	long baseblock, limitblock, bootblocks, sizeinblocks;
+	int magicfound;
+	void *llsave;
+
+	if(trace > 1)
+		print("logfsformat: base %ld limit %ld bootsize %lud\n", base, limit, bootsize);
+
+	if((*ll->getopenstatus)(ll))
+		return Eperm;
+
+	if(!(*ll->calcformat)(ll, base, limit, bootsize, &baseblock, &limitblock, &bootblocks))
+		return Ebadarg;
+
+	if(trace > 0)
+		print("logfsformat: baseblock %ld limitblock %ld bootblocks %ld\n", baseblock, limitblock, bootblocks);
+
+	bootblocksdone = 0;
+	logblocksdone = 0;
+	/*
+	 * we need to create some fs blocks, and some boot blocks
+	 * the number of boot blocks is fixed; the number of fs blocks
+	 * occupies the remainder
+	 * the layout is randomised to:
+	 * 1) test the software
+	 * 2) spread wear around if a lot of format commands are issued by
+	 *     the bootloader
+	 */
+
+	sizeinblocks = limitblock - baseblock;
+
+	for(u = 0; u < sizeinblocks; u++) {
+		int r;
+		uchar tag;
+		long path;
+		LogfsLowLevelReadResult e;
+		char *errmsg;
+		int markedbad;
+
+		if(trace > 1)
+			print("block %lud:", u);
+		llsave = nil;
+		errmsg = (*ll->getblockstatus)(ll, u + baseblock, &magicfound, &llsave, &e);
+		if(errmsg)
+			return errmsg;
+		if(e == LogfsLowLevelReadResultBad) {
+			if(trace > 1)
+				print(" marked bad\n");
+			continue;
+		}
+		errmsg = (*ll->eraseblock)(ll, u + baseblock, nil, &markedbad);
+		if(errmsg)
+			return errmsg;
+		if(markedbad) {
+			if(trace > 1)
+				print(" marked bad\n");
+			continue;
+		}
+		if(e != LogfsLowLevelReadResultHardError && magicfound) {
+			if(trace > 1)
+				print(" previously formatted");
+		}
+		r = nrand(sizeinblocks - u);
+		if(bootblocksdone < bootblocks && r < (bootblocks - bootblocksdone)) {
+			tag = LogfsTboot;
+			path = mkdatapath(bootblocksdone, 0);
+		}
+		else {
+			tag = LogfsTnone;
+			path = ~0;
+		}
+		if(trace > 1)
+			print(" tag %s path %ld", logfstagname(tag), path);
+		errmsg = (*ll->formatblock)(ll, u + baseblock, tag, path, baseblock, sizeinblocks, 1, &bootblocks, llsave, &markedbad);
+		logfsfreemem(llsave);
+		if(errmsg)
+			return errmsg;
+		if(markedbad) {
+			if(trace > 1)
+				print(" marked bad\n");
+			continue;
+		}
+		switch(tag) {
+		case LogfsTboot:
+			bootblocksdone++;
+			break;
+		case LogfsTnone:
+			logblocksdone++;
+			break;
+		}
+		if(trace > 1)
+			print("\n");
+	}
+	if(bootblocksdone < bootblocks)
+		return "not enough capacity left for boot";
+	if(trace > 0)
+		print("log blocks %lud\n", logblocksdone);
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/gn.c
@@ -1,0 +1,26 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+int
+logfsgn(uchar **pp, uchar *mep, char **v)
+{
+	uchar *p = *pp;
+	int l;
+	if(p + BIT16SZ > mep)
+		return 0;
+	l = GBIT16(p); p += BIT16SZ;
+	if(p + l > mep)
+		return 0;
+	*pp = p + l;
+	if(l == 0) {
+		*v = 0;
+		return 1;
+	}
+	*v = (char *)(p - 1);
+	memmove(p - 1, p, l);
+	p[l - 1] = 0;
+	return 1;
+}
+
--- /dev/null
+++ b/liblogfs/group.c
@@ -1,0 +1,99 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+	GROUPMOD = 127
+};
+
+static int
+groupcompare(void *a, void *b)
+{
+	Group *g = a;
+	char *uid = b;
+	return g->uid == uid;
+}
+
+static int
+unamecompare(void *a, void *b)
+{
+	Uname *u = a;
+	char *uname = b;
+	return u->uname == uname;
+}
+
+static int
+groupallocsize(void *key)
+{
+	USED(key);
+	return sizeof(Group);
+}
+
+static int
+unameallocsize(void *key)
+{
+	USED(key);
+	return sizeof(Uname);
+}
+
+char *
+logfsgroupmapnew(GroupMap **groupmapp, UnameMap **unamemapp)
+{
+	char *errmsg;
+	errmsg = logfsmapnew(GROUPMOD, logfshashulong, groupcompare, groupallocsize, nil, groupmapp);
+	if(errmsg)
+		return errmsg;
+	errmsg = logfsmapnew(GROUPMOD, logfshashulong, unamecompare, unameallocsize, nil, unamemapp);
+	if(errmsg)
+		logfsmapfree(groupmapp);
+	return errmsg;
+}
+
+char *
+logfsgroupmapnewentry(GroupMap *gm, UnameMap *um, char *uid, char *uname, Group **groupp, Uname **unamep)
+{
+	char *errmsg;
+	errmsg = logfsmapnewentry(gm, uid, groupp);
+	if(errmsg)
+		return errmsg;
+	if(*groupp == nil)
+		return "uid already exists";
+	(*groupp)->uid = uid;
+	errmsg = logfsgroupsetnew(&(*groupp)->members);
+	if(errmsg) {
+		logfsmapdeleteentry(gm, uid);
+		return errmsg;
+	}
+	errmsg = logfsmapnewentry(um, uname, unamep);
+	if(errmsg == nil && *unamep == nil)
+		errmsg = "uname already exists";
+	if(errmsg) {
+		logfsgroupsetfree(&(*groupp)->members);
+		logfsmapdeleteentry(gm, uid);
+		return errmsg;
+	}
+	(*groupp)->uname = uname;
+	(*unamep)->uname = uname;
+	(*unamep)->g = *groupp;
+	return nil;
+}
+
+char *
+logfsgroupmapfinduname(GroupMap *m, char *uid)
+{
+	Group *g;
+	g = logfsgroupmapfindentry(m, uid);
+	if(g)
+		return g->uname;
+	return nil;
+}
+
+char *
+logfsunamemapfinduid(UnameMap *m, char *uname)
+{
+	Uname *u;
+	u = logfsunamemapfindentry(m, uname);
+	if(u)
+		return u->g->uid;
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/groupset.c
@@ -1,0 +1,91 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+struct GroupSet {
+	int maxentries;
+	int nentries;
+	Group **entry;
+};
+
+char *
+logfsgroupsetnew(GroupSet **gsp)
+{
+	GroupSet *gs = logfsrealloc(nil, sizeof(*gs));
+	if(gs == nil)
+		return Enomem;
+	gs->entry = logfsrealloc(nil, sizeof(Group *));
+	if(gs->entry == nil) {
+		logfsfreemem(gs);
+		return Enomem;
+	}
+	gs->maxentries = 1;		/* most groups have one member */
+	gs->nentries = 0;
+	*gsp = gs;
+	return nil;
+}
+
+void
+logfsgroupsetfree(GroupSet **gsp)
+{
+	GroupSet *gs = *gsp;
+	if(gs) {
+		logfsfreemem(gs->entry);
+		logfsfreemem(gs);
+		*gsp = nil;
+	}
+}
+
+int
+logfsgroupsetadd(GroupSet *gs, Group *g)
+{
+	int x;
+	for(x = 0; x < gs->nentries; x++)
+		if(gs->entry[x] == g)
+			return 1;
+	if(gs->nentries >= gs->maxentries) {
+		Group **ne = logfsrealloc(gs->entry, sizeof(Group*)*(gs->maxentries * 2));
+		if(ne == nil)
+			return 0;
+		gs->entry = ne;
+		gs->maxentries *= 2;
+	}
+	gs->entry[gs->nentries++] = g;
+	return 1;
+}
+
+int
+logfsgroupsetremove(GroupSet *gs, Group *g)
+{
+	int x;
+	for(x = 0; x < gs->nentries; x++)
+		if(gs->entry[x] == g)
+			break;
+	if(x == gs->nentries)
+		return 0;
+	gs->nentries--;
+	memmove(&gs->entry[x], &gs->entry[x + 1], sizeof(Group *) * (gs->nentries - x));
+	return 1;
+}
+
+int
+logfsgroupsetwalk(GroupSet *gs, LOGFSGROUPSETWALKFN *func, void *magic)
+{
+	int x;
+	for(x = 0; x < gs->nentries; x++) {
+		int rv = (*func)(magic, gs->entry[x]);
+		if(rv <= 0)
+			return rv;
+	}
+	return 1;
+}
+
+int
+logfsgroupsetismember(GroupSet *gs, Group *g)
+{
+	int x;
+	for(x = 0; x < gs->nentries; x++)
+		if(gs->entry[x] == g)
+			return 1;
+	return 0;
+}
--- /dev/null
+++ b/liblogfs/is.c
@@ -1,0 +1,305 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *logfsisgroupnonename = "none";
+
+char *
+logfsisnew(LogfsIdentityStore **isp)
+{
+	LogfsIdentityStore *is;
+	char *errmsg;
+
+	is = logfsrealloc(nil, sizeof(*is));
+	if(is == nil) {
+	memerror:
+		logfsisfree(&is);
+		return Enomem;
+	}
+	errmsg = logfsustnew(&is->ids);
+	if(errmsg)
+		goto memerror;
+	errmsg = logfsgroupmapnew(&is->groupmap, &is->unamemap);
+	if(errmsg)
+		goto memerror;
+	logfsisgroupnonename = logfsustadd(is->ids, logfsisgroupnonename);
+	*isp = is;
+	return nil;
+}
+
+void
+logfsisfree(LogfsIdentityStore **isp)
+{
+	LogfsIdentityStore *is = *isp;
+	if(is) {
+		logfsustfree(&is->ids);
+		logfsgroupmapfree(&is->groupmap);
+		logfsunamemapfree(&is->unamemap);
+		logfsfreemem(is);
+		*isp = nil;
+	}
+}
+
+char *
+logfsisgroupcreate(LogfsIdentityStore *is, char *groupname, char *groupid)
+{
+	Group *group;
+	Uname *uname;
+
+	if(strcmp(groupname, logfsisgroupnonename) == 0 || groupname[0] == '(')
+		return "group name reserved";
+	groupname = logfsisustadd(is, groupname);
+	groupid = logfsisustadd(is, groupid);
+	if(groupname == nil || groupid == nil)
+		return Enomem;
+	return logfsgroupmapnewentry(is->groupmap, is->unamemap, groupid, groupname, &group, &uname);
+}
+
+static Group *
+findgroupfromuname(LogfsIdentityStore *is, char *groupname)
+{
+	Uname *u = logfsunamemapfindentry(is->unamemap, groupname);
+	if(u == nil)
+		return nil;
+	return u->g;
+}
+
+char *
+logfsisgrouprename(LogfsIdentityStore *is, char *oldgroupname, char *newgroupname)
+{
+	Group *og, *ng;
+	oldgroupname = logfsisustadd(is, oldgroupname);
+	if(oldgroupname == nil)
+		return Enomem;
+	og =findgroupfromuname(is, oldgroupname);
+	if(og == nil)
+		return Enonexist;
+	newgroupname = logfsisustadd(is, newgroupname);
+	if(newgroupname == nil)
+		return Enomem;
+	ng = findgroupfromuname(is, newgroupname);
+	if(ng != nil)
+		return Eexist;
+	og->uname = newgroupname;
+	return nil;
+}
+
+char *
+logfsisgroupsetleader(LogfsIdentityStore *is, char *groupname, char *leadername)
+{
+	Group *g, *lg;
+	groupname = logfsisustadd(is, groupname);
+	if(groupname == nil)
+		return Enomem;
+	g = findgroupfromuname(is, groupname);
+	if(g == nil)
+		return Enonexist;
+	if(leadername && leadername[0]) {
+		leadername = logfsisustadd(is, leadername);
+		if(leadername == nil)
+			return Enomem;
+		lg = findgroupfromuname(is, leadername);
+		if(lg == nil)
+			return Enonexist;
+		if(!logfsgroupsetismember(g->members, lg))
+			return "not a member of the group";
+		g->leader = lg;
+	}
+	else
+		g->leader = nil;
+	return nil;
+}
+
+char *
+logfsisgroupaddmember(LogfsIdentityStore *is, char *groupname, char *membername)
+{
+	Group *g, *mg;
+	groupname = logfsisustadd(is, groupname);
+	if(groupname == nil)
+		return Enomem;
+	g =findgroupfromuname(is, groupname);
+	if(g == nil)
+		return Enonexist;
+	membername = logfsisustadd(is, membername);
+	if(membername == nil)
+		return Enomem;
+	mg = findgroupfromuname(is, membername);
+	if(mg == nil)
+		return Enonexist;
+	if(!logfsgroupsetadd(g->members, mg))
+		return Enomem;
+	return nil;
+}
+
+char *
+logfsisgroupremovemember(LogfsIdentityStore *is, char *groupname, char *nonmembername)
+{
+	Group *g, *nonmg;
+	groupname = logfsisustadd(is, groupname);
+	if(groupname == nil)
+		return Enomem;
+	g =findgroupfromuname(is, groupname);
+	if(g == nil)
+		return Enonexist;
+	nonmembername = logfsisustadd(is, nonmembername);
+	if(nonmembername == nil)
+		return Enomem;
+	nonmg = findgroupfromuname(is, nonmembername);
+	if(nonmg == nil)
+		return Enonexist;
+	if(!logfsgroupsetremove(g->members, nonmg))
+		return Enonexist;
+	if(g->leader == nonmg)
+		g->leader = nil;
+	return nil;
+}
+
+typedef struct DS {
+	char *printbuf;
+	long printbufsize;
+	void *buf;
+	ulong offset;
+	long n;
+	ulong printoffset;
+	int printn;
+	int comma;
+} DS;
+
+static int
+printmember(void *magic, Group *member)
+{
+	DS *ds = magic;
+	if(ds->comma) {
+		if(ds->printn < ds->printbufsize)
+			ds->printbuf[ds->printn++] = ',';
+	}
+	else
+		ds->comma = 1;
+	ds->printn += snprint(ds->printbuf + ds->printn, ds->printbufsize - ds->printn, "%s", member->uname);
+	return 1;
+}
+
+static int
+printgroup(void *magic, Group *g)
+{
+	DS *ds = magic;
+	ds->printn = snprint(ds->printbuf, ds->printbufsize, "%s:%s:%s:",
+		g->uid, g->uname, g->leader ? g->leader->uname : "");
+	/* do members */
+	ds->comma = 0;
+	logfsgroupsetwalk(g->members, printmember, ds);
+	if(ds->printn < ds->printbufsize)
+		ds->printbuf[ds->printn++] = '\n';
+	/*
+	 * copy the appropriate part of the buffer
+	 */
+	if(ds->printoffset < ds->offset + ds->n && ds->printoffset + ds->printn > ds->offset) {
+		char *printbuf = ds->printbuf;
+		uchar *buf = ds->buf;
+		long trim = ds->offset - ds->printoffset;
+		if(trim >= 0) {
+			printbuf += trim;
+			ds->printn -= trim;
+		}
+		else
+			buf -= trim;
+		if(ds->printoffset + ds->printn > ds->offset + ds->n)
+			ds->printn = ds->offset + ds->n - ds->printoffset;
+		memmove(buf, printbuf, ds->printn);
+	}
+	/*
+	 * advance print position
+	 */
+	ds->printoffset += ds->printn;
+	/*
+	 * stop if exceeding the buffer
+	 */
+	if(ds->printoffset >= ds->offset + ds->n)
+		return 0;
+	return 1;
+}
+
+char *
+logfsisusersread(LogfsIdentityStore *is, void *buf, long n, ulong offset, long *nr)
+{
+	DS ds;
+	ds.buf = buf;
+	ds.n = n;
+	ds.printoffset = 0;
+	ds.offset = offset;
+	ds.printbufsize = 1024;
+	ds.printbuf = logfsrealloc(nil, ds.printbufsize);
+	if(ds.printbuf == nil)
+		return Enomem;
+	logfsmapwalk(is->groupmap, (LOGFSMAPWALKFN *)printgroup, &ds);
+	*nr = ds.printoffset - ds.offset;
+	logfsfreemem(ds.printbuf);
+	return nil;
+}
+
+int
+logfsisgroupunameismember(LogfsIdentityStore *is, Group *g, char *uname)
+{
+	Group *ug;
+	if(g == nil)
+		return 0;
+	if(g->uname == uname)
+		return 1;
+	ug = logfsisfindgroupfromname(is, uname);
+	if(ug == nil)
+		return 0;
+	return logfsgroupsetismember(g->members, ug);
+}
+
+int
+logfsisgroupuidismember(LogfsIdentityStore *is, Group *g, char *uid)
+{
+	Group *ug;
+	if(g == nil)
+		return 0;
+	if(g->uid == uid)
+		return 1;
+	ug = logfsisfindgroupfromid(is, uid);
+	if(ug == nil)
+		return 0;
+	return logfsgroupsetismember(g->members, ug);
+}
+
+int
+logfsisgroupuidisleader(LogfsIdentityStore *is, Group *g, char *id)
+{
+	if(g->leader)
+		return g->leader->uid == id;
+	return logfsisgroupuidismember(is, g, id);
+}
+
+Group *
+logfsisfindgroupfromname(LogfsIdentityStore *is, char *name)
+{
+	Uname *u;
+	u = logfsunamemapfindentry(is->unamemap, name);
+	if(u == nil)
+		return nil;
+	return u->g;
+}
+
+char *
+logfsisfindidfromname(LogfsIdentityStore *is, char *name)
+{
+	char *id;
+	id = logfsunamemapfinduid(is->unamemap, name);
+	if(id == nil)
+		return logfsisgroupnonename;
+	return id;
+}
+
+char *
+logfsisfindnamefromid(LogfsIdentityStore *is, char *id)
+{
+	Group *g;
+	g = logfsgroupmapfindentry(is->groupmap, id);
+	if(g == nil)
+		return nil;
+	return g->uname;
+}
--- /dev/null
+++ b/liblogfs/local.h
@@ -1,0 +1,335 @@
+typedef struct DataBlock DataBlock;
+typedef struct Extent Extent;
+typedef struct Entry Entry;
+typedef struct ExtentList ExtentList;
+typedef struct Fid Fid;
+typedef struct Map Map;
+typedef struct GroupSet GroupSet;
+typedef struct Group Group;
+typedef struct Uname Uname;
+typedef struct LogMessage LogMessage;
+typedef struct LogSegment LogSegment;
+typedef struct Path Path;
+typedef struct DirReadState DirReadState;
+
+typedef struct Map PathMap;
+typedef struct Map FidMap;
+typedef struct Map GroupMap;
+typedef struct Map UnameMap;
+typedef struct Map Ust;
+
+#pragma incomplete Extent
+#pragma incomplete ExtentList
+#pragma incomplete Map
+#pragma incomplete DirReadState
+
+enum {
+	L2LogSweeps = 2,
+	L2BlockCopies = 2,
+	LogDataLimit = 128,
+	LogAddr = (1 << 31),
+	Replacements = 2,		/* extra space for replacements */
+	Transfers = 2,			/* extra space available for transfers */
+	LogSlack = 1,			/* extra space for data allocation */
+};
+
+struct Extent {
+	u32int min, max;
+	u32int flashaddr;		/* encode block index, page number, and offset within page to min */
+};
+
+char *logfsextentlistnew(ExtentList **);
+void logfsextentlistfree(ExtentList **);
+char *logfsextentlistinsert(ExtentList *, Extent *, Extent **);
+int logfsextentlistwalk(ExtentList *, int (*)(void *, Extent *, int),void *);
+Extent *logfsextentlistmatch(ExtentList *, Extent *);
+int logfsextentlistwalkrange(ExtentList *,
+	int (*)(void *, u32int, u32int, Extent *, u32int),
+	void *, u32int, u32int);
+int logfsextentlistmatchall(ExtentList *, int (*)(void *, Extent *), void *, Extent *);
+void logfsextentlistreset(ExtentList *);
+
+struct Entry {
+	int inuse;
+	int deadandgone;	/* removed */
+	Qid qid;
+	struct Entry *parent;
+	char *name;
+	char *uid;
+	char *gid;
+	ulong mtime;
+	char *muid;
+	u32int perm;
+	struct Entry *next;
+	struct {
+		struct {
+			ulong cvers;
+			ulong length;
+			ExtentList *extent;
+		} file;
+		struct {
+			struct Entry *list;
+		} dir;
+	} u;
+};
+
+char *logfsentrynew(LogfsServer *, int, u32int, Entry *,
+	char *, char *, char *,
+	u32int, char *, u32int, ulong, ulong, Entry **);
+void logfsentryclunk(Entry *);
+
+void logfsdrsfree(DirReadState **);
+
+struct Fid {
+	ulong fid;
+	int openmode;
+	Entry *entry;
+	char *uname;
+	DirReadState *drs;
+};
+
+typedef int LOGFSMAPWALKFN(void*, void*);
+char *logfsmapnew(int, int (*)(void*, int), int (*)(void*, void*), int (*)(void*), void (*)(void*), Map **);
+void logfsmapfree(Map **);
+char *logfsmapnewentry(Map*, void*, void **);
+void *logfsmapfindentry(Map*, void*);
+int logfsmapdeleteentry(Map*, void*);
+int logfsmapwalk(Map*, LOGFSMAPWALKFN*, void*);
+
+char *logfsfidmapnew(FidMap **);
+#define logfsfidmapfree(mp) logfsmapfree(mp)
+char *logfsfidmapnewentry(FidMap *, ulong, Fid **);
+#define logfsfidmapfindentry(m, fid) logfsmapfindentry(m, (void *)fid)
+int logfsfidmapclunk(FidMap *, ulong);
+
+struct Logfs {
+	int trace;
+};
+
+char *logfsustnew(Ust**);
+#define logfsustfree(m) logfsmapfree((m))
+char *logfsustadd(Ust*, char*);
+
+struct Group {
+	char *uid;
+	char *uname;
+	Group *leader;
+	GroupSet *members;
+};
+
+struct Uname {
+	char *uname;
+	Group *g;
+};
+
+struct LogfsIdentityStore {
+	Ust *ids;
+	GroupMap *groupmap;
+	UnameMap *unamemap;
+};
+
+char *logfsgroupmapnew(GroupMap **, UnameMap **);
+#define logfsgroupmapfree(mp) logfsmapfree(mp)
+#define logfsunamemapfree(mp) logfsmapfree(mp)
+char *logfsgroupmapnewentry(GroupMap *, UnameMap *, char *, char *, Group **, Uname **);
+#define logfsgroupmapdeleteentry(m, uid) logfsmapdeleteentry(m, (void *)uid)
+#define logfsgroupmapfindentry(m, uid) logfsmapfindentry(m, uid)
+#define logfsunamemapfindentry(m, uname) logfsmapfindentry(m, uname)
+char *logfsgroupmapfinduname(GroupMap *, char *);
+char *logfsunamemapfinduid(UnameMap *, char *);
+#define logfsunamemapdeleteentry(m, uname) logfsmapdeleteentry(m, (void *)uname)
+
+typedef int LOGFSGROUPSETWALKFN(void *, Group *);
+char *logfsgroupsetnew(GroupSet **);
+void logfsgroupsetfree(GroupSet **);
+int logfsgroupsetadd(GroupSet *, Group *);
+int logfsgroupsetremove(GroupSet *, Group *);
+int logfsgroupsetwalk(GroupSet *, LOGFSGROUPSETWALKFN *, void *);
+int logfsgroupsetismember(GroupSet *, Group *);
+char *logfsisfindidfromname(LogfsIdentityStore *, char *);
+char *logfsisfindnamefromid(LogfsIdentityStore *, char *);
+#define logfsisfindgroupfromid(is, id) logfsgroupmapfindentry((is)->groupmap, id)
+Group *logfsisfindgroupfromname(LogfsIdentityStore *, char *);
+#define logfsisustadd(is, s) logfsustadd((is)->ids, s)
+int logfsisgroupunameismember(LogfsIdentityStore *, Group *, char *);
+int logfsisgroupuidismember(LogfsIdentityStore *, Group *, char *);
+int logfsisgroupuidisleader(LogfsIdentityStore *, Group *, char *);
+extern char *logfsisgroupnonename;
+
+struct LogMessage {
+	uchar type;
+	u32int path;
+	union {
+		struct {
+			u32int nerase;
+		} start;
+		struct {
+			u32int perm;
+			u32int newpath;
+			u32int mtime;
+			u32int cvers;
+			char *name;
+			char *uid;
+			char *gid;
+		} create;
+		struct {
+			u32int mtime;
+			char *muid;
+		} remove;
+		struct {
+			u32int mtime;
+			u32int cvers;
+			char *muid;
+		} trunc;
+		struct {
+			u32int offset;
+			u32int count;
+			u32int mtime;
+			u32int cvers;
+			char *muid;
+			u32int flashaddr;
+			uchar *data;
+		} write;
+		struct {
+			char *name;
+			u32int perm;
+			char *uid;
+			char *gid;
+			u32int mtime;
+			char *muid;
+		} wstat;
+	} u;
+};
+
+uint logfsconvM2S(uchar *, uint, LogMessage *);
+uint logfssizeS2M(LogMessage *);
+uint logfsconvS2M(LogMessage *, uchar *, uint);
+void logfsdumpS(LogMessage *);
+
+struct LogSegment {
+	int gen;				/* generation number of this log */
+	int dirty;				/* written to since last sweep */
+	long curblockindex;		/* index of block being filled, or -1 */
+	long unsweptblockindex;	/* next block to sweep */
+	int curpage;			/* page within block */
+	uchar *pagebuf;		/* page buffer */
+	int nbytes;			/* bytes used in page buffer */
+	long blockmap[1];		/* there are ll->blocks of these */
+};
+
+char *logfslogsegmentnew(LogfsServer *, int, LogSegment **);
+void logfslogsegmentfree(LogSegment **);
+char *logfslogbytes(LogfsServer *, int, uchar *, uint);
+char *logfslog(LogfsServer *, int, LogMessage *);
+char *logfslogwrite(LogfsServer *, int, u32int, u32int, int, u32int,
+	u32int, char *, uchar *, u32int *);
+char *logfslogsegmentflush(LogfsServer *, int);
+int lognicesizeforwrite(LogfsServer *, int, u32int, int);
+char *logfsscan(LogfsServer *);
+
+struct DataBlock {
+	Pageset free;
+	Pageset dirty;
+	long path;			/* includes generation */
+	long block;
+};
+
+Pageset logfsdatapagemask(int, int);
+
+struct Path {
+	ulong path;
+	Entry *entry;
+};
+
+char *logfspathmapnew(PathMap **);
+#define logfspathmapfree(mp) logfsmapfree(mp)
+char *logfspathmapnewentry(PathMap *, ulong, Entry *, Path **);
+#define logfspathmapfindentry(m, path) (Path *)logfsmapfindentry(m, (void *)path)
+#define logfspathmapdeleteentry(m, path) logfsmapdeleteentry(m, (void *)path)
+Entry *logfspathmapfinde(PathMap *, ulong);
+
+enum {
+	LogfsTestDontFettleDataBlock = 1,
+};
+
+struct LogfsServer {
+	LogfsLowLevel *ll;
+	LogfsBoot *lb;
+	FidMap *fidmap;
+	LogfsIdentityStore *is;
+	PathMap *pathmap;
+	LogSegment *activelog;
+	LogSegment *sweptlog;
+	long ndatablocks;
+	DataBlock *datablock;
+	ulong path;
+	Entry root;
+	int trace;
+	ulong openflags;
+	ulong testflags;
+};
+
+int logfshashulong(void *, int);
+
+int logfsuserpermcheck(LogfsServer *, Entry *, Fid *, ulong);
+u32int logfsflattenentry(LogfsIdentityStore *, uchar *, u32int, Entry *);
+char *logfsreplay(LogfsServer *, LogSegment *, int);
+void logfsreplayfinddata(LogfsServer *);
+
+#define dataseqof(path) ((path) >> L2BlockCopies)
+#define copygenof(path) ((path) & ((1 << L2BlockCopies) -1))
+#define mkdatapath(seq, gen) (((seq) << L2BlockCopies) | (gen))
+#define gensucc(g, l2) (((g) + 1) & ((1 << (l2)) - 1))
+#define copygensucc(g) gensucc((g), L2BlockCopies)
+#define loggenof(path) ((path >> L2BlockCopies) & ((1 << L2LogSweeps) - 1))
+#define logseqof(path) ((path) >> (L2BlockCopies + L2LogSweeps))
+#define mklogpath(seq, gen, copygen) (((((seq) << L2LogSweeps) | (gen)) << L2BlockCopies) | (copygen))
+#define loggensucc(g) gensucc((g), L2LogSweeps)
+
+int logfsunconditionallymarkfreeanddirty(void *, Extent *, int);
+void logfsflashaddr2spo(LogfsServer *, u32int, long *, int *, int *);
+int logfsgn(uchar **, uchar *, char **);
+u32int logfsspo2flashaddr(LogfsServer *, long, int, int);
+int logfsgn(uchar **, uchar *, char **);
+void logfsflashaddr2o(LogfsServer *, u32int, int *);
+void logfsfreedatapages(LogfsServer *, long, Pageset);
+void logfsfreeanddirtydatablockcheck(LogfsServer *, long);
+
+typedef enum AllocReason {
+	AllocReasonReplace,
+	AllocReasonTransfer,
+	AllocReasonLogExtend,
+	AllocReasonDataExtend,
+} AllocReason;
+
+long logfsfindfreeblock(LogfsLowLevel *, AllocReason);
+char *logfsbootfettleblock(LogfsBoot *, long, uchar tag, long, int *);
+char *logfsserverreplacedatablock(LogfsServer *, long);
+char *logfsserverreplacelogblock(LogfsServer *, LogSegment *, long);
+char *logfsserverreplaceblock(LogfsServer *, LogSegment *, long);
+char *logfsservercopyactivedata(LogfsServer *, long, long, int,
+	LogfsLowLevelReadResult *, int *);
+
+char *logfsstrdup(char*);
+
+extern char Enomem[];
+extern char Eshortstat[];
+extern char Enonexist[];
+extern char Etoobig[];
+extern char Eexist[];
+extern char Eunknown[];
+extern char Enotdir[];
+extern char Eisdir[];
+extern char logfsebadfid[];
+extern char logfsefidopen[];
+extern char logfsefidnotopen[];
+extern char logfsefidinuse[];
+extern char logfseopen[];
+extern char logfseaccess[];
+extern char logfselogmsgtoobig[];
+extern char logfselogfull[];
+extern char logfseinternal[];
+extern char logfsenotempty[];
+extern char logfseexcl[];
+extern char logfsefullreplacing[];
+extern char logfseunknownpath[];
--- /dev/null
+++ b/liblogfs/log.c
@@ -1,0 +1,270 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+void
+logfsflashaddr2spo(LogfsServer *server, u32int flashaddr, long *seq, int *page, int *offset)
+{
+	LogfsLowLevel *ll = server->ll;
+	flashaddr &= ~LogAddr;
+	*offset = flashaddr & ((1 << ll->l2pagesize) - 1);
+	flashaddr >>= ll->l2pagesize;
+	*page = flashaddr & ((1 << ll->l2pagesperblock) - 1);
+	flashaddr >>= ll->l2pagesperblock;
+	*seq = flashaddr;
+}
+
+u32int
+logfsspo2flashaddr(LogfsServer *server, long seq, int page, int offset)
+{
+//print("logfsspo2flashaddr(%ld, %d, %d)\n", seq, page, offset);
+	return (((seq << server->ll->l2pagesperblock) + page) << server->ll->l2pagesize) + offset;
+}
+
+void
+logfsflashaddr2o(LogfsServer *server, u32int flashaddr, int *offset)
+{
+	LogfsLowLevel *ll = server->ll;
+	flashaddr &= ~LogAddr;
+	*offset = flashaddr & ((1 << ll->l2pagesize) - 1);
+}
+
+char *
+logfslogsegmentnew(LogfsServer *server, int gen, LogSegment **segp)
+{
+	LogSegment *seg;
+	seg = logfsrealloc(nil, sizeof(LogSegment) + (server->ll->blocks - 1) * sizeof(long));
+	if(seg == nil)
+		return Enomem;
+	seg->pagebuf = logfsrealloc(nil, 1 << server->ll->l2pagesize);
+	if(seg->pagebuf == nil) {
+		logfsfreemem(seg);
+		return Enomem;
+	}
+	seg->curpage = -1;
+	seg->curblockindex = -1;
+	seg->gen = gen;
+	*segp = seg;
+	return nil;
+}
+
+void
+logfslogsegmentfree(LogSegment **segp)
+{
+	LogSegment *seg = *segp;
+	if(seg) {
+		logfsfreemem(seg->pagebuf);
+		logfsfreemem(seg);
+		*segp = nil;
+	}
+}
+
+char *
+logfslogsegmentflush(LogfsServer *server, int active)
+{
+	LogSegment *seg;
+	seg = active ? server->activelog : server->sweptlog;
+	if(seg == nil)
+		return nil;
+	if(seg->curpage >= 0 && seg->nbytes) {
+		char *errmsg;
+		LogfsLowLevel *ll = server->ll;
+		int pagesize = 1 << ll->l2pagesize;
+//print("curblockindex %ld curpage %d nbytes %d\n", seg->curblockindex, seg->curpage, seg->nbytes);
+		if(seg->nbytes < pagesize)
+			seg->pagebuf[seg->nbytes++] = LogfsLogTend;
+		memset(seg->pagebuf + seg->nbytes, 0xff, pagesize - seg->nbytes);
+		for(;;) {
+			errmsg = (*ll->writepage)(ll, seg->pagebuf,
+				seg->blockmap[seg->curblockindex], seg->curpage);
+			if(errmsg == nil)
+				break;
+			if(strcmp(errmsg, Eio) != 0)
+				return errmsg;
+			errmsg = logfsserverreplacelogblock(server, seg, seg->curblockindex);
+			if(errmsg)
+				return errmsg;
+		}
+		seg->curpage++;
+		if(seg->curpage == (1 << ll->l2pagesperblock))
+			seg->curpage = -1;
+		seg->nbytes = 0;
+	}
+	return nil;
+}
+
+static char *
+logspace(LogfsServer *server, int active, int takearisk, int nbytes, uchar **where, u32int *flashaddr)
+{
+	char *errmsg;
+	LogfsLowLevel *ll = server->ll;
+	int pagesize = 1 << ll->l2pagesize;
+	LogSegment *seg;
+
+	if(nbytes > pagesize)
+		return logfselogmsgtoobig;
+retry:
+	seg = active ? server->activelog : server->sweptlog;
+	for(;;) {
+//print("curpage %d nbytes %d\n", seg->curpage, seg->nbytes);
+		if(seg->curpage >= 0) {
+			if(seg->nbytes + nbytes < pagesize)
+				break;
+			errmsg = logfslogsegmentflush(server, active);
+			if(errmsg)
+				return errmsg;
+		}
+		if(seg->curpage < 0) {
+			long block;
+			long path;
+			block = logfsfindfreeblock(ll,
+				active ? (takearisk ? AllocReasonLogExtend : AllocReasonDataExtend) : AllocReasonTransfer);
+			if(block < 0) {
+				if(active) {
+					int didsomething;
+					errmsg = logfsserverlogsweep(server, 0, &didsomething);
+					if(errmsg)
+						return errmsg;
+					if(didsomething)
+						goto retry;
+				}
+				return logfselogfull;
+			}
+			seg->blockmap[++seg->curblockindex] = block;
+			path = mklogpath(seg->curblockindex, seg->gen, 0);
+			(*ll->setblocktag)(ll, block, LogfsTlog);
+			(*ll->setblockpath)(ll, block, path);
+			seg->curpage = 0;
+#ifdef FUTURE
+			/* TODO - do we need one of these if the underlying system supports erase counting? */
+			seg->pagebuf[0] = LogfsLogTstart;
+			PBIT16(seg->pagebuf + 1, 8);
+			PBIT32(seg->pagebuf + 3, path);	/* TODO duplicate information */
+			PBIT32(seg->pagebuf + 7, 0);		/* TODO don't have this - discuss with forsyth */
+			seg->nbytes = 11;
+#else
+			seg->nbytes = 0;
+#endif
+		}
+	}
+	*where = seg->pagebuf + seg->nbytes;
+	if(flashaddr)
+		*flashaddr = logfsspo2flashaddr(server, seg->curblockindex, seg->curpage, seg->nbytes);
+	seg->nbytes += nbytes;
+	return nil;
+}
+
+static void
+logdirty(LogfsServer *server, int active)
+{
+	if(active)
+		server->activelog->dirty = 1;
+	else
+		server->sweptlog->dirty = 1;
+}
+
+char *
+logfslogbytes(LogfsServer *server, int active, uchar *msg, uint size)
+{
+	char *errmsg;
+	uchar *p;
+
+	errmsg = logspace(server, active, 0, size, &p, nil);
+	if(errmsg)
+		return errmsg;
+	memmove(p, msg, size);
+	logdirty(server, active);
+	return nil;
+}
+
+char *
+logfslog(LogfsServer *server, int active, LogMessage *s)
+{
+	uint size = logfssizeS2M(s);
+	char *errmsg;
+	uchar *p;
+	int takearisk;
+
+	if(server->trace > 1) {
+		print("%c<< ", active ? 'A' : 'S');
+		logfsdumpS(s);
+		print("\n");
+	}
+	if(active) {
+		switch(s->type) {
+		case LogfsLogTremove:
+		case LogfsLogTtrunc:
+			takearisk = 1;
+			break;
+		default:
+			takearisk = 0;
+		}
+	}
+	else
+		takearisk = 0;
+	errmsg = logspace(server, active, takearisk, size, &p, nil);
+	if(errmsg)
+		return errmsg;
+	if(logfsconvS2M(s, p, size) != size)
+		return "bad conversion";
+	logdirty(server, active);
+	return nil;
+}
+
+int
+lognicesizeforwrite(LogfsServer *server, int active, u32int count, int muidlen)
+{
+	int rawspace;
+	LogSegment *seg;
+	if(count > LogDataLimit)
+		return 0;
+	seg = active ? server->activelog : server->sweptlog;
+	if(seg->curpage < 0)
+		return LogDataLimit;
+	rawspace = (1 << server->ll->l2pagesize) - seg->nbytes;
+	if(rawspace < 5 * 4 + 2 + muidlen + 1)
+		return LogDataLimit;
+	return 5 * 4 + 2 + muidlen - rawspace;
+}
+
+char *
+logfslogwrite(LogfsServer *server, int active, u32int path, u32int offset, int count, u32int mtime, u32int cvers,
+	char *muid, uchar *data, u32int *flashaddr)
+{
+	/* 'w' size[2] path[4] offset[4] count[2] mtime[4] cvers[4] muid[s] flashaddr[4] [data[n]] */
+	LogMessage s;
+	uint size;
+	char *errmsg;
+	uchar *p;
+	u32int faddr;
+	uint asize;
+
+	s.type = LogfsLogTwrite;
+	s.path = path;
+	s.u.write.offset = offset;
+	s.u.write.count = count;
+	s.u.write.mtime = mtime;
+	s.u.write.cvers = cvers;
+	s.u.write.muid = muid;
+	s.u.write.data = data;
+	size = logfssizeS2M(&s);
+	errmsg = logspace(server, active, 0, size, &p, &faddr);
+	if(errmsg)
+		return errmsg;
+	if(data)
+		*flashaddr = (faddr + size - count) | LogAddr;
+	s.u.write.flashaddr = *flashaddr;
+	if(server->trace > 1) {
+		print("%c<< ", active ? 'A' : 'S');
+		logfsdumpS(&s);
+		print("\n");
+	}
+	if((asize = logfsconvS2M(&s, p, size)) != size) {
+		print("expected %d actual %d\n", size, asize);
+		return "bad conversion";
+	}
+	logdirty(server, active);
+	return nil;
+}
+
--- /dev/null
+++ b/liblogfs/map.c
@@ -1,0 +1,139 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+typedef struct MapNode MapNode;
+
+struct MapNode {
+	MapNode *next;
+	uchar e[1];	// entry goes here, inline
+};
+
+struct Map {
+	int size;
+	int (*hash)(void *key, int size);
+	int (*compare)(void *entry, void *key);
+	int (*allocsize)(void *key);
+	void (*free)(void *entry);
+	MapNode *head[1];
+};
+
+char *
+logfsmapnew(int size, int (*hash)(void *key, int size), int (*compare)(void *entry, void *key), int (*allocsize)(void *key), void (*free)(void *), Map **mapp)
+{
+	Map *p;
+	*mapp = p = logfsrealloc(nil, sizeof(Map) + (size - 1) * sizeof(MapNode *));
+	if(p == nil)
+		return Enomem;
+	p->size = size;
+	p->hash = hash;
+	p->compare = compare;
+	p->allocsize = allocsize;
+	p->free = free;
+	return nil;
+}
+
+void
+logfsmapfree(FidMap **mp)
+{
+	FidMap *m;
+	int i;
+
+	m = *mp;
+	if(m == nil)
+		return;
+
+	for(i = 0; i < m->size; i++) {
+		MapNode *n, *next;
+		n = m->head[i];
+		while(n) {
+			next = n->next;
+			if(m->free)
+				(*m->free)(n->e);
+			logfsfreemem(n);
+			n = next;
+		}
+	}
+	logfsfreemem(m);
+	*mp = nil;
+}
+
+static char *
+find(FidMap *m, void *key, int create, void **ep)
+{
+	MapNode *n;
+	int i;
+
+	i = (*m->hash)(key, m->size);
+	n = m->head[i];
+	while(n && !(*m->compare)(n->e, key))
+		n = n->next;
+	if(n) {
+		if(create) {
+			*ep = nil;
+			return nil;
+		}
+		*ep = n->e;
+		return nil;
+	}
+	if(!create) {
+		*ep = nil;
+		return nil;
+	}
+	n = logfsrealloc(nil, (*m->allocsize)(key) + sizeof(MapNode *));
+	if(n == nil) {
+		*ep = nil;
+		return Enomem;
+	}
+	n->next = m->head[i];
+	m->head[i] = n;
+	*ep = n->e;
+	return nil;
+}
+
+void *
+logfsmapfindentry(Map *m, void *key)
+{
+	void *rv;
+	find(m, key, 0, &rv);
+	return rv;
+}
+
+char *
+logfsmapnewentry(Map *m, void *key, void **entryp)
+{
+	return find(m, key, 1, entryp);
+}
+
+int
+logfsmapdeleteentry(Map *m, void *key)
+{
+	MapNode **np, *n;
+	np = &m->head[(*m->hash)(key, m->size)];
+	while((n = *np) && !(*m->compare)(n->e, key))
+		np = &n->next;
+	if(n) {
+		*np = n->next;
+		if(m->free)
+			(*m->free)(n->e);
+		logfsfreemem(n);
+		return 1;
+	}
+	return 0;		// not there
+}
+
+int
+logfsmapwalk(Map *m, int (*func)(void *magic, void *), void *magic)
+{
+	int x;
+	MapNode *n;
+
+	for(x = 0; x < m->size; x++)
+		for(n = m->head[x]; n; n = n->next) {
+			int rv = (*func)(magic, n->e);
+			if(rv <= 0)
+				return rv;
+		}
+	return 1;
+}
+
--- /dev/null
+++ b/liblogfs/mkfile
@@ -1,0 +1,45 @@
+<../mkconfig
+
+LIB=liblogfs.a
+
+OFILES=	\
+		boot.$O\
+		clunk.$O\
+		conv.$O\
+		create.$O\
+		dump.$O\
+		error.$O\
+		extentlist.$O\
+		fidmap.$O\
+		findfreeblock.$O\
+		flush.$O\
+		format.$O\
+		gn.$O\
+		group.$O\
+		groupset.$O\
+		is.$O\
+		log.$O\
+		map.$O\
+		open.$O\
+		path.$O\
+		perm.$O\
+		read.$O\
+		remove.$O\
+		replace.$O\
+		replay.$O\
+		scan.$O\
+		srv.$O\
+		sweep.$O\
+		tagname.$O\
+		test.$O\
+		ust.$O\
+		walk.$O\
+		write.$O\
+		wstat.$O\
+
+HFILES=\
+	local.h \
+	$ROOT/include/logfs.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
--- /dev/null
+++ b/liblogfs/open.c
@@ -1,0 +1,72 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsserveropen(LogfsServer *server, u32int fid, uchar mode, Qid *qid)
+{
+	Fid *f;
+	Entry *e;
+	ulong modemask;
+
+	if(server->trace > 1)
+		print("logfsserveropen(%ud, %d)\n",  fid, mode);
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsebadfid;
+	if(f->openmode >= 0)
+		return logfsefidopen;
+	e = f->entry;
+	SET(modemask);
+	switch(mode & 3) {
+	case OEXEC:
+		modemask = DMEXEC;
+		break;
+	case OREAD:
+		modemask = DMREAD;
+		break;
+	case OWRITE:
+		modemask = DMWRITE;
+		break;
+	case ORDWR:
+		modemask = DMWRITE | DMREAD;
+		break;
+	}
+	if(e->qid.type & QTDIR) {
+		if((modemask & DMWRITE) != 0 || (mode & (ORCLOSE | OTRUNC)) != 0)
+			return Eperm;
+	}
+	else {
+		if(mode & OTRUNC)
+			modemask |= DMWRITE;
+		if((mode & ORCLOSE) != 0 && !logfsuserpermcheck(server, e->parent, f, DMWRITE))
+			return Eperm;
+	}
+	if(!logfsuserpermcheck(server, e, f, modemask))
+		return Eperm;
+	if((e->qid.type & QTDIR) == 0 && (mode & OTRUNC) != 0 && (e->perm & DMAPPEND) == 0 && e->u.file.length != 0) {
+		LogMessage s;
+		char *errmsg;
+		s.type = LogfsLogTtrunc;
+		s.path = e->qid.path;
+		s.u.trunc.mtime = logfsnow();
+		s.u.trunc.cvers = e->u.file.cvers + 1;
+		s.u.trunc.muid = logfsisfindidfromname(server->is, f->uname);
+		errmsg = logfslog(server, 1, &s);
+		if(errmsg)
+			return errmsg;
+		e->muid = s.u.trunc.muid;
+		e->mtime = s.u.trunc.mtime;
+		e->qid.vers++;
+		e->u.file.cvers = s.u.trunc.cvers;
+		/*
+		 * zap all data and extents
+		 */
+		logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
+		logfsextentlistreset(e->u.file.extent);
+		e->u.file.length = 0;
+	}
+	f->openmode = mode;
+	*qid = e->qid;
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/path.c
@@ -1,0 +1,50 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+	PATHMOD = 127
+};
+
+static int
+compare(void *a, void *b)
+{
+	Path *f = a;
+	ulong path = (ulong)b;	/* sic */
+	return f->path == path;
+}
+
+static int
+allocsize(void *key)
+{
+	USED(key);
+	return sizeof(Path);
+}
+
+char *
+logfspathmapnew(PathMap **pathmapp)
+{
+	return logfsmapnew(PATHMOD, logfshashulong, compare, allocsize, nil, pathmapp);
+}
+
+char *
+logfspathmapnewentry(PathMap *m, ulong path, Entry *e, Path **pathmapp)
+{
+	char *errmsg;
+	errmsg = logfsmapnewentry(m, (void*)path, pathmapp);
+	if(errmsg)
+		return errmsg;
+	if(*pathmapp == nil)
+		return nil;
+	(*pathmapp)->path = path;
+	(*pathmapp)->entry = e;
+	return nil;
+}
+
+Entry *
+logfspathmapfinde(PathMap *m, ulong path)
+{
+	Path *p;
+	p = logfspathmapfindentry(m, path);
+	return p ? p->entry : nil;
+}
--- /dev/null
+++ b/liblogfs/perm.c
@@ -1,0 +1,25 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+int
+logfsuserpermcheck(LogfsServer *s, Entry *e, Fid *f, ulong permmask)
+{
+	if(s->openflags & LogfsOpenFlagNoPerm)
+		return 1;
+	if((e->perm & permmask) == permmask)
+		/* the whole world can do this */
+		return 1;
+	if(((e->perm >> 6) & permmask) == permmask) {
+		/* maybe we're the owner */
+		char *uname = logfsisfindnamefromid(s->is, e->uid);
+		if(uname == f->uname)
+			return 1;
+	}
+	if(((e->perm >> 3) & permmask) == permmask) {
+		/* maybe we're in the group */
+		Group *g = logfsisfindgroupfromid(s->is, e->gid);
+		return g && logfsisgroupunameismember(s->is, g, f->uname);
+	}
+	return 0;
+}
--- /dev/null
+++ b/liblogfs/read.c
@@ -1,0 +1,253 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+struct DirReadState {
+	u32int offset;
+	u32int lastoffset;
+	u32int limit;
+	uchar *data;
+};
+
+typedef struct ReaderState {
+	uchar *buf;
+	u32int maxoffset;
+	LogfsServer *server;
+	char *errmsg;
+} ReaderState;
+
+static DirReadState *
+drsinit(LogfsIdentityStore *is, Entry *list, uchar *buf, u32int buflen, u32int *rcount)
+{
+	Entry *p, *q;
+	DirReadState *drs;
+	u32int k;
+	/*
+	 * stash as many entries as will fit in the read buffer
+	 */
+	*rcount = 0;
+	for(p = list; p; p = p->next) {
+		uint len = logfsflattenentry(is, buf, buflen, p);
+		if(len == 0)
+			break;
+		*rcount += len;
+		buf += len;
+		buflen -= len;
+	}
+	drs = logfsrealloc(nil, sizeof(*drs));
+	if(drs == nil)
+		return nil;
+	drs->offset = *rcount;
+	drs->lastoffset = drs->offset;
+	k = 0;
+	for(q = p; q; q = q->next)
+		k += logfsflattenentry(is, nil, 0, q);
+	if(k) {
+		u32int k2;
+//		print("drsinit: %ud bytes extra\n", k);
+		drs->data = logfsrealloc(nil, k);
+		if(drs->data == nil) {
+			logfsfreemem(drs);
+			return nil;
+		}
+		k2 = 0;
+		for(q = p; q; q = q->next)
+			k2 += logfsflattenentry(is, drs->data + k2, k - k2, q);
+		drs->limit = drs->offset + k;
+	}
+//	print("drsinit: rcount %ud\n", *rcount);
+	return drs;
+}
+
+static void
+drsread(DirReadState *drs, uchar *buf, u32int buflen, u32int *rcount)
+{
+	uchar *p;
+	*rcount = 0;
+	p = drs->data + drs->lastoffset - drs->offset;
+	while(drs->lastoffset < drs->limit) {
+		/*
+		 * copy an entry, if it fits
+		 */
+		uint len = GBIT16(p) + BIT16SZ;
+		if(len > buflen)
+			break;
+		memmove(buf, p, len);
+		drs->lastoffset += len;
+		*rcount += len;
+		buf += len;
+		buflen -= len;
+		p += len;
+	}
+	if(drs->lastoffset >= drs->limit) {
+		logfsfreemem(drs->data);
+		drs->data = nil;
+	}
+}
+
+void
+logfsdrsfree(DirReadState **drsp)
+{
+	DirReadState *drs = *drsp;
+	if(drs) {
+		logfsfreemem(drs->data);
+		logfsfreemem(drs);
+		*drsp = nil;
+	}
+}
+
+static int
+reader(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset)
+{
+	ReaderState *s = magic;
+	LogfsServer *server;
+	LogfsLowLevel *ll;
+	LogfsLowLevelReadResult llrr;
+	long seq;
+	int page;
+	int offset;
+	long block;
+	int pagesize;
+	LogSegment *seg;
+	int replace;
+
+	if(e == nil) {
+//print("fill(%d, %d)\n", baseoffset, limitoffset);
+		memset(s->buf + baseoffset, 0, limitoffset - baseoffset);
+		if(limitoffset > s->maxoffset)
+			s->maxoffset = limitoffset;
+		return 1;
+	}
+	server = s->server;
+	ll = server->ll;
+	/*
+	 * extentoffset is how much to trim off the front of the extent
+	 */
+	logfsflashaddr2spo(server, e->flashaddr + extentoffset, &seq, &page, &offset);
+	/*
+	 * offset is the offset within the page to where e->min is stored
+	 */
+//print("read(%d, %d, %c%ld/%ud/%ud)\n",
+//	baseoffset, limitoffset, (e->flashaddr & LogAddr) ? 'L' :  'D', seq, page, offset);
+	if(e->flashaddr & LogAddr) {
+		if(seq >= server->activelog->unsweptblockindex && seq <= server->activelog->curblockindex)
+			seg = server->activelog;
+		else if(server->sweptlog && seq <= server->sweptlog->curblockindex)
+			seg = server->sweptlog;
+		else {
+			print("logfsserverread: illegal log sequence number %ld (active=[%ld, %ld], swept=[%ld, %ld])\n",
+				seq, server->activelog->unsweptblockindex, server->activelog->curblockindex,
+				server->sweptlog ? 0L : -1L, server->sweptlog ? server->sweptlog->curblockindex : -1L);
+			s->errmsg = logfseinternal;
+			return -1;
+		}
+		if(seg->curpage == page && seg->curblockindex == seq) {
+			/*
+			 * it hasn't made it to disk yet
+			 */
+			memmove(s->buf + baseoffset, seg->pagebuf + offset, limitoffset - baseoffset);
+			goto done;
+		}
+		if(seq < seg->unsweptblockindex) {
+			/* data already swept */
+			print("logfsserverread: log address has been swept\n");
+			s->errmsg = logfseinternal;
+			return -1;
+		}
+		block = seg->blockmap[seq];
+	}
+	else {
+		seg = nil;
+		if(seq >= server->ndatablocks)
+			block = -1;
+		else
+			block = server->datablock[seq].block;
+		if(block < 0) {
+			print("logfsserveread: data address does not exist\n");
+			s->errmsg = logfseinternal;
+			return -1;
+		}
+	}
+	/*
+	 * read as many pages as necessary to get to the limitoffset
+	 */
+	pagesize = 1 << ll->l2pagesize;
+	replace = 0;
+	while(baseoffset < limitoffset) {
+		u32int thistime;
+		thistime = pagesize - offset;
+		if(thistime > (limitoffset - baseoffset))
+			thistime = limitoffset - baseoffset;
+		s->errmsg = (*ll->readpagerange)(ll, s->buf + baseoffset, block, page,
+			offset, thistime, &llrr);
+		if(s->errmsg)
+			return -1;
+		if(llrr != LogfsLowLevelReadResultOk) {
+			replace = 1;
+		}
+		baseoffset += thistime;
+		page++;
+		offset = 0;
+	}
+	if(replace) {
+		s->errmsg = logfsserverreplaceblock(server, seg, seq);
+		if(s->errmsg)
+			return -1;
+	}
+done:
+	if(limitoffset > s->maxoffset)
+		s->maxoffset = limitoffset;
+	return 1;
+}
+
+char *
+logfsserverread(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int buflen, u32int *rcount)
+{
+	Fid *f;
+	Entry *e;
+	ReaderState s;
+	int rv;
+
+	if(server->trace > 1)
+		print("logfsserverread(%ud, %ud, %ud)\n", fid, offset, count);
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsebadfid;
+	if(f->openmode < 0)
+		return logfsefidnotopen;
+	if((f->openmode & 3) == OWRITE)
+		return logfseaccess;
+	if(count > buflen)
+		return Etoobig;
+	e = f->entry;
+	if(e->deadandgone)
+		return Eio;
+	if(e->qid.type & QTDIR) {
+		if(offset != 0) {
+			if(f->drs == nil || f->drs->lastoffset != offset)
+				return Eio;
+			drsread(f->drs, buf, count, rcount);
+		}
+		else {
+			logfsdrsfree(&f->drs);
+			f->drs = drsinit(server->is, e->u.dir.list, buf, count, rcount);
+			if(f->drs == nil)
+				return Enomem;
+		}
+		return nil;
+	}
+	if(offset >= e->u.file.length) {
+		*rcount = 0;
+		return nil;
+	}
+	s.buf = buf;
+	s.server = server;
+	s.maxoffset = 0;
+	rv = logfsextentlistwalkrange(e->u.file.extent, reader, &s, offset, offset + count);
+	if(rv < 0)
+		return s.errmsg;
+	*rcount = s.maxoffset;
+	return nil;
+}
+
--- /dev/null
+++ b/liblogfs/remove.c
@@ -1,0 +1,148 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+void
+logfsfreeanddirtydatablockcheck(LogfsServer *server, long seq)
+{
+	DataBlock *db;
+	Pageset mask, allpages;
+
+	if(seq >= server->ndatablocks)
+		return;
+	db = server->datablock + seq;
+	if(db->block < 0)
+		return;
+
+	mask = db->dirty & db->free;
+	if(mask) {
+		allpages = logfsdatapagemask(1 << server->ll->l2pagesperblock, 0);
+		if((mask & allpages) == allpages) {
+//print("logfsfreedatapages: returning block to the wild\n");
+			logfsbootfettleblock(server->lb, db->block, LogfsTnone, ~0, nil);
+			db->block = -1;
+			if(seq == server->ndatablocks - 1)
+				server->ndatablocks--;
+		}
+	}
+}
+
+void
+logfsfreedatapages(LogfsServer *server, long seq, Pageset mask)
+{
+	DataBlock *db;
+	if(seq >= server->ndatablocks)
+		return;
+	db = server->datablock + seq;
+	if(db->block < 0)
+		return;
+//print("logfsfreedatapages: index %ld mask 0x%.8ux\n", seq, mask);
+	db->dirty |= mask;
+	db->free |= mask;
+	logfsfreeanddirtydatablockcheck(server, seq);
+}
+
+int
+logfsunconditionallymarkfreeanddirty(void *magic, Extent *e, int hole)
+{
+	if(!hole && (e->flashaddr & LogAddr) == 0) {
+		LogfsServer *server = magic;
+		LogfsLowLevel *ll = server->ll;
+		DataBlock *db;
+		long blockindex;
+		int page, offset, npages;
+		Pageset mask;
+
+		logfsflashaddr2spo(server, e->flashaddr, &blockindex, &page, &offset);
+		if(blockindex < server->ndatablocks && (db = server->datablock + blockindex)->block >= 0) {
+			npages = ((offset + e->max - e->min) + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
+			mask = logfsdatapagemask(npages, page);
+			if((db->dirty & mask) != mask)
+				print("markfreeandirty: not all pages dirty\n");
+//print("markfreeanddirty: datablock %ld mask 0x%.8ux\n", blockindex, mask);
+			logfsfreedatapages(server, blockindex, mask);
+		}
+		else
+			print("markfreeanddirty: data block index %ld invalid\n", blockindex);
+	}
+	return 1;
+}
+
+char *
+logfsserverremove(LogfsServer *server, u32int fid)
+{
+	Fid *f;
+	char *errmsg;
+	Entry *parent;
+	Entry *e, **ep;
+	ulong now;
+	char *uid;
+	LogMessage s;
+
+	if(server->trace > 1)
+		print("logfsserverremove(%ud)\n", fid);
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil) {
+		errmsg = logfsebadfid;
+		goto clunk;
+	}
+	if((f->openmode & 3) == OWRITE) {
+		errmsg = logfseaccess;
+		goto clunk;
+	}
+	parent = f->entry->parent;
+	if(parent == f->entry) {
+		errmsg = Eperm;
+		goto clunk;
+	}
+	if((parent->qid.type & QTDIR) == 0) {
+		errmsg = logfseinternal;
+		goto clunk;
+	}
+	if(!logfsuserpermcheck(server, parent, f, DMWRITE)) {
+		errmsg = Eperm;
+		goto clunk;
+	}
+	if((f->entry->qid.type & QTDIR) != 0 && f->entry->u.dir.list) {
+		errmsg = logfsenotempty;
+		goto clunk;
+	}
+	if(f->entry->deadandgone) {
+		errmsg = Eio;
+		goto clunk;
+	}
+	for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
+		if(e == f->entry)
+			break;
+	if(e == nil) {
+		errmsg = logfseinternal;
+		goto clunk;
+	}
+	now = logfsnow();
+	uid = logfsisfindidfromname(server->is, f->uname);
+	/* log it */
+	s.type = LogfsLogTremove;
+	s.path = e->qid.path;
+	s.u.remove.mtime = e->mtime;
+	s.u.remove.muid = e->muid;
+	errmsg = logfslog(server, 1, &s);
+	if(errmsg)
+		goto clunk;
+	parent->mtime = now;
+	parent->muid = uid;
+	logfspathmapdeleteentry(server->pathmap, e->qid.path);
+	*ep = e->next;				/* so open can't find it */
+	e->deadandgone = 1;		/* so that other fids don't work any more */
+	/*
+	 * lose the storage now, as deadandgone will prevent access
+	 */
+	if((e->qid.type & QTDIR) == 0) {
+		logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
+		logfsextentlistfree(&e->u.file.extent);
+	}
+	e->inuse--;				/* so that the entryclunk removes the storage */
+	errmsg = nil;
+clunk:
+	logfsfidmapclunk(server->fidmap, fid);
+	return errmsg;
+}
--- /dev/null
+++ b/liblogfs/replace.c
@@ -1,0 +1,171 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+static char *
+copypages(LogfsServer *server, long newb, long oldb, Pageset copymask, LogfsLowLevelReadResult *llrrp, int *markedbadp)
+{
+	char *errmsg;
+	int page;
+	LogfsLowLevel *ll;
+	int ppb;
+	int pagesize;
+	uchar *buf;
+
+	if(copymask == 0)
+		return nil;
+
+	ll = server->ll;
+	ppb = 1 << ll->l2pagesperblock;
+	pagesize = 1 << ll->l2pagesize;
+	*markedbadp = 0;
+	*llrrp = LogfsLowLevelReadResultOk;
+	errmsg = nil;
+
+	buf = logfsrealloc(nil, 1 << ll->l2pagesize);
+	if(buf == nil)
+		return Enomem;
+
+	for(page = ppb - 1; page >= 0; page--) {
+		Pageset m;
+
+		m = logfsdatapagemask(1, page);
+
+		if(copymask & m) {
+			LogfsLowLevelReadResult llrr;
+			if(server->trace > 1)
+				print("copypages read page %d\n", page);
+			errmsg = (*ll->readpagerange)(ll, buf, oldb, page, 0, pagesize, &llrr);
+			if(errmsg != nil)
+				break;
+			if(llrr > *llrrp)
+				*llrrp = llrr;
+			if(server->trace > 1)
+				print("copypages write page %d\n", page);
+			errmsg = (*ll->writepage)(ll, buf, newb, page);
+			if(errmsg) {
+				if(strcmp(errmsg, Eio) == 0) {
+					(*ll->markblockbad)(ll, newb);
+					*markedbadp = 1;
+				}
+				break;
+			}
+			if(server->trace > 1)
+				print("copypages end page %d\n", page);
+		}
+	}
+	logfsfreemem(buf);
+	return errmsg;
+}
+
+char *
+logfsservercopyactivedata(LogfsServer *server, long newb, long oldblockindex, int forcepage0, LogfsLowLevelReadResult *llrrp, int *markedbadp)
+{
+	LogfsLowLevel *ll = server->ll;
+	ulong newpath;
+	DataBlock *ob;
+	char *errmsg;
+	Pageset copymask;
+
+	ob = server->datablock + oldblockindex;
+	copymask = ~ob->free;
+	if(forcepage0)
+		copymask |= logfsdatapagemask(1, 0);
+	if(server->trace > 1)
+		print("copyactivedata %ld: (%ld -> %ld)\n", oldblockindex, ob->block, newb);
+	newpath = mkdatapath(dataseqof(ob->path), copygensucc(copygenof(ob->path)));
+	(*ll->setblocktag)(ll, newb, LogfsTdata);
+	(*ll->setblockpath)(ll, newb, newpath);
+	errmsg = copypages(server, newb, ob->block, copymask, llrrp, markedbadp);
+	if(errmsg)
+		return errmsg;
+	/*
+	 * anything not copied is now not dirty
+	 */
+	ob->dirty &= copymask;
+	ob->block = newb;
+	ob->path = newpath;
+	return nil;
+}
+
+/*
+ * unconditionally replace a datablock, and mark the old one bad
+ * NB: if page 0 is apparently unused, force it to be copied, and mark
+ * it free and dirty afterwards
+ */
+char *
+logfsserverreplacedatablock(LogfsServer *server, long index)
+{
+	long newb;
+	LogfsLowLevel *ll = server->ll;
+
+	newb = logfsfindfreeblock(ll, AllocReasonReplace);
+	/* TODO - recover space by scavenging other blocks, or recycling the log */
+	while(newb >= 0) {
+		char *errmsg;
+		LogfsLowLevelReadResult llrr;
+		long oldblock;
+		int markedbad;
+		DataBlock *db;
+
+		db = server->datablock + index;
+		oldblock = db->block;
+		errmsg = logfsservercopyactivedata(server, newb, index, 1, &llrr, &markedbad);
+		if(errmsg) {
+			if(!markedbad)
+				return errmsg;
+			newb = logfsfindfreeblock(ll, AllocReasonReplace);
+			continue;
+		}
+		(*ll->markblockbad)(ll, oldblock);
+		return nil;
+	}
+	return logfsefullreplacing;
+}
+
+char *
+logfsserverreplacelogblock(LogfsServer *server, LogSegment *seg, long index)
+{
+	ulong opath;
+	LogfsLowLevel *ll = server->ll;
+	long oldb = seg->blockmap[index];
+
+	opath = (*ll->getblockpath)(ll, oldb);
+
+	for(;;) {
+		long newb;
+		int pages;
+		char *errmsg;
+		LogfsLowLevelReadResult llrr;
+		int markedbad;
+
+		newb  = logfsfindfreeblock(ll, AllocReasonReplace);
+		if(newb < 0)
+			return "full replacing log block";
+		/* TODO - scavenge data space for a spare block */
+		(*ll->setblocktag)(ll, newb, LogfsTlog);
+		(*ll->setblockpath)(ll, newb, mklogpath(seg->gen, index, copygensucc(copygenof(opath))));
+		if(index == seg->curblockindex)
+			pages = seg->curpage;
+		else
+			pages = 1 << server->ll->l2pagesperblock;
+		errmsg = copypages(server, newb, oldb, logfsdatapagemask(pages, 0), &llrr, &markedbad);
+		if(errmsg == nil) {
+			(*ll->markblockbad)(ll, seg->blockmap[index]);
+			seg->blockmap[index] = newb;
+			return nil;
+		}
+		if(!markedbad)
+			return errmsg;
+	}
+}
+
+char *
+logfsserverreplaceblock(LogfsServer *server, LogSegment *seg, long index)
+{
+	if(seg)
+		return logfsserverreplacelogblock(server, seg, index);
+	else
+		return logfsserverreplacedatablock(server, index);
+}
--- /dev/null
+++ b/liblogfs/replay.c
@@ -1,0 +1,386 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+static void
+maxpath(LogfsServer *server, ulong p)
+{
+	if(p > server->path)
+		server->path = p;
+}
+
+static char *
+recreate(LogfsServer *server, LogMessage *s, int *ok)
+{
+	Entry *parent;
+	char *errmsg;
+	Entry *e;
+	Path *p;
+
+	parent = logfspathmapfinde(server->pathmap, s->path);
+	if(parent == nil)
+		return "can't find parent";
+	if(logfspathmapfindentry(server->pathmap, s->u.create.newpath) != nil){
+		Entry *d = logfspathmapfinde(server->pathmap, s->u.create.newpath);
+		if(d == nil)
+			print("existing was nil\n");
+		else{
+			print("existing: name=%q d=%d path=%8.8llux uid=%q gid=%q perm=%#uo\n",
+				d->name, d->deadandgone, d->qid.path, d->uid, d->gid, d->perm);
+		}
+		return "duplicate path";
+	}
+	if((parent->qid.type & QTDIR) == 0)
+		return Enotdir;
+	errmsg = logfsentrynew(server, 1, s->u.create.newpath, parent,
+		s->u.create.name, s->u.create.uid, s->u.create.gid, s->u.create.mtime, s->u.create.uid,
+		s->u.create.perm, s->u.create.cvers, 0, &e);
+	if(errmsg) {
+		*ok = 0;
+		return errmsg;
+	}
+	/* p guaranteed to be non null */
+	errmsg = logfspathmapnewentry(server->pathmap, s->u.create.newpath, e, &p);
+	if(errmsg) {
+		logfsfreemem(e);
+		*ok = 0;
+		return errmsg;
+	}
+	e->next = parent->u.dir.list;
+	parent->u.dir.list = e;
+	return nil;
+}
+
+static char *
+reremove(LogfsServer *server, LogMessage *s, int *ok)
+{
+	Entry *oe;
+	Entry *parent;
+	Entry **ep;
+	Entry *e;
+	char *ustmuid;
+
+	USED(ok);
+	oe = logfspathmapfinde(server->pathmap, s->path);
+	if(oe == nil)
+		return logfseunknownpath;
+	parent = oe->parent;
+	if(parent == oe)
+		return "tried to remove root";
+	if((parent->qid.type & QTDIR) == 0)
+		return Enotdir;
+	if((oe->qid.type & QTDIR) != 0 && oe->u.dir.list)
+		return logfsenotempty;
+	for(ep = &parent->u.dir.list; e = *ep; ep = &e->next)
+		if(e == oe)
+			break;
+	if(e == nil)
+		return logfseinternal;
+	ustmuid = logfsisustadd(server->is, s->u.remove.muid);
+	if(ustmuid == nil)
+		return Enomem;
+	parent->mtime = s->u.remove.mtime;
+	parent->muid = ustmuid;
+	logfspathmapdeleteentry(server->pathmap, s->path);
+	*ep = e->next;
+	if(e->inuse > 1) {
+		print("replay: entry inuse > 1\n");
+		e->inuse = 1;
+	}
+	logfsentryclunk(e);
+	return nil;
+}
+
+static char *
+retrunc(LogfsServer *server, LogMessage *s, int *ok)
+{
+	Entry *e;
+	char *ustmuid;
+
+	USED(ok);
+	e = logfspathmapfinde(server->pathmap, s->path);
+	if(e == nil)
+		return logfseunknownpath;
+	if((e->qid.type & QTDIR) != 0)
+		return Eperm;
+	if(e->u.file.cvers >= s->u.trunc.cvers)
+		return "old news";
+	ustmuid = logfsisustadd(server->is, s->u.trunc.muid);
+	if(ustmuid == nil)
+		return Enomem;
+	e->muid = ustmuid;
+	e->mtime = s->u.trunc.mtime;
+	e->qid.vers++;
+	e->u.file.cvers = s->u.trunc.cvers;
+	/*
+	 * zap all extents
+	 */
+	logfsextentlistreset(e->u.file.extent);
+	e->u.file.length = 0;
+	return nil;
+}
+
+static char *
+rewrite(LogfsServer *server, LogMessage *s, int *ok)
+{
+	Entry *e;
+	char *ustmuid;
+	Extent extent;
+	char *errmsg;
+
+	USED(ok);
+	e = logfspathmapfinde(server->pathmap, s->path);
+	if(e == nil)
+		return logfseunknownpath;
+	if((e->qid.type & QTDIR) != 0)
+		return Eperm;
+	if(e->u.file.cvers != s->u.write.cvers)
+		return nil;
+	ustmuid = logfsisustadd(server->is, s->u.write.muid);
+	if(ustmuid == nil)
+		return Enomem;
+	extent.min = s->u.write.offset;
+	extent.max = s->u.write.offset + s->u.write.count;
+	extent.flashaddr = s->u.write.flashaddr;
+	errmsg = logfsextentlistinsert(e->u.file.extent, &extent, nil);
+	if(errmsg)
+		return errmsg;
+	e->mtime = s->u.write.mtime;
+	e->muid = ustmuid;
+	if(extent.max > e->u.file.length)
+		e->u.file.length = extent.max;
+	/* TODO forsyth increments vers here; not sure whether necessary */
+	return nil;
+}
+
+static char *
+rewstat(LogfsServer *server, LogMessage *s, int *ok)
+{
+	Entry *e;
+	char *errmsg;
+	char *cname, *ustgid, *ustmuid;
+	char *ustuid;
+
+	USED(ok);
+	e = logfspathmapfinde(server->pathmap, s->path);
+	if(e == nil)
+		return logfseunknownpath;
+	cname = nil;
+	ustuid = nil;
+	ustgid = nil;
+	ustmuid = nil;
+	if(s->u.wstat.name) {
+		cname = logfsstrdup(s->u.wstat.name);
+		if(cname == nil) {
+		memerror:
+			errmsg = Enomem;
+			goto fail;
+		}
+	}
+	if(s->u.wstat.uid) {
+		ustuid = logfsisustadd(server->is, s->u.wstat.uid);
+		if(ustuid == nil)
+			goto memerror;
+	}
+	if(s->u.wstat.gid) {
+		ustgid = logfsisustadd(server->is, s->u.wstat.gid);
+		if(ustgid == nil)
+			goto memerror;
+	}
+	if(s->u.wstat.muid) {
+		ustmuid = logfsisustadd(server->is, s->u.wstat.muid);
+		if(ustmuid == nil)
+			goto memerror;
+	}
+	if(cname) {
+		logfsfreemem(e->name);
+		e->name = cname;
+		cname = nil;
+	}
+	if(ustuid)
+		e->uid = ustuid;
+	if(ustgid)
+		e->gid = ustgid;
+	if(ustmuid)
+		e->muid = ustmuid;
+	if(s->u.wstat.perm != ~0)
+		e->perm = (e->perm & DMDIR) | (s->u.wstat.perm & ~DMDIR);
+	if(s->u.wstat.mtime != ~0)
+		e->mtime = s->u.wstat.mtime;
+	errmsg = nil;
+fail:
+	logfsfreemem(cname);
+	return errmsg;
+}
+
+static char *
+replayblock(LogfsServer *server, LogSegment *seg, uchar *buf, long i, int *pagep, int disableerrors)
+{
+	int page;
+	LogfsLowLevel *ll = server->ll;
+	LogfsLowLevelReadResult llrr;
+	ushort size;
+	LogMessage s;
+	int ppb = 1 << ll->l2pagesperblock;
+	int pagesize = 1 << ll->l2pagesize;
+
+	for(page = 0; page < ppb; page++) {
+		uchar *p, *bufend;
+		char *errmsg = (*ll->readpagerange)(ll, buf, seg->blockmap[i], page, 0,  pagesize, &llrr);
+		if(errmsg)
+			return errmsg;
+		if(llrr != LogfsLowLevelReadResultOk)
+			logfsserverreplacelogblock(server, seg, i);
+			/* ignore failure to replace block */
+		if(server->trace > 1)
+			print("replaying seq %ld block %ld page %d\n", i, seg->blockmap[i], page);
+		p = buf;
+		if(*p == 0xff)
+			break;
+		bufend = p + pagesize;
+		while(p < bufend) {
+			int ok = 1;
+			size = logfsconvM2S(p, bufend - p, &s);
+			if(size == 0)
+				return "parse failure";
+			if(server->trace > 1) {
+				print(">> ");
+				logfsdumpS(&s);
+				print("\n");
+			}
+			if(s.type == LogfsLogTend)
+				break;
+			switch(s.type) {
+			case LogfsLogTstart:
+				break;
+			case LogfsLogTcreate:
+				maxpath(server, s.path);
+				maxpath(server, s.u.create.newpath);
+				errmsg = recreate(server, &s, &ok);
+				break;
+			case LogfsLogTtrunc:
+				maxpath(server, s.path);
+				errmsg = retrunc(server, &s, &ok);
+				break;
+			case LogfsLogTremove:
+				maxpath(server, s.path);
+				errmsg = reremove(server, &s, &ok);
+				break;
+			case LogfsLogTwrite:
+				maxpath(server, s.path);
+				errmsg = rewrite(server, &s, &ok);
+				break;
+			case LogfsLogTwstat:
+				maxpath(server, s.path);
+				errmsg = rewstat(server, &s, &ok);
+				break;
+			default:
+				return "bad tag in log page";
+			}
+			if(!ok)
+				return errmsg;
+			if(errmsg && !disableerrors){
+				print("bad replay: %s\n", errmsg);
+				print("on: "); logfsdumpS(&s); print("\n");
+			}
+			p += size;
+		}
+	}
+	*pagep = page;
+	return nil;
+}
+
+static int
+map(void *magic, Extent *x, int hole)
+{
+	LogfsServer *server;
+	LogfsLowLevel *ll;
+	long seq;
+	int page;
+	int offset;
+	Pageset mask;
+	DataBlock *db;
+
+	if(hole || (x->flashaddr & LogAddr) != 0)
+		return 1;
+	server = magic;
+	ll = server->ll;
+	logfsflashaddr2spo(server, x->flashaddr, &seq, &page, &offset);
+	if(seq >= server->ndatablocks || (db = server->datablock + seq)->block < 0) {
+		print("huntfordata: seq %ld invalid\n", seq);
+		return 1;
+	}
+	mask = logfsdatapagemask((x->max - x->min + offset + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize, page);
+//print("mask 0x%.8ux free 0x%.8ux dirty 0x%.8ux\n", mask, db->free, db->dirty);
+	if((db->free & mask) != mask)
+		print("huntfordata: data referenced more than once: block %ld(%ld) free 0x%.8llux mask 0x%.8llux\n",
+			seq, db->block, (u64int)db->free, (u64int)mask);
+	db->free &= ~mask;
+	db->dirty |= mask;
+	return 1;
+}
+
+static void
+huntfordatainfile(LogfsServer *server, Entry *e)
+{
+	logfsextentlistwalk(e->u.file.extent, map, server);
+}
+
+static void
+huntfordataindir(LogfsServer *server, Entry *pe)
+{
+	Entry *e;
+	for(e = pe->u.dir.list; e; e = e->next)
+		if(e->qid.type & QTDIR)
+			huntfordataindir(server, e);
+		else
+			huntfordatainfile(server, e);
+}
+
+char *
+logfsreplay(LogfsServer *server, LogSegment *seg, int disableerrorsforfirstblock)
+{
+	uchar *buf;
+	long i;
+	int page;
+	char *errmsg;
+
+	if(seg == nil || seg->curblockindex < 0)
+		return nil;
+	buf = logfsrealloc(nil, 1 << server->ll->l2pagesize);
+	if(buf == nil)
+		return Enomem;
+	for(i = 0; i <= seg->curblockindex; i++) {
+		errmsg = replayblock(server, seg, buf,  i, &page, disableerrorsforfirstblock);
+		disableerrorsforfirstblock = 0;
+		if(errmsg) {
+			print("logfsreplay: error: %s\n", errmsg);
+			goto fail;
+		}
+	}
+	/*
+	 * if the last block ended early, restart at the first free page
+	 */
+	if(page < (1 << server->ll->l2pagesperblock))
+		seg->curpage = page;
+	errmsg = nil;
+fail:
+	logfsfreemem(buf);
+	return errmsg;
+}
+
+void
+logfsreplayfinddata(LogfsServer *server)
+{
+	huntfordataindir(server, &server->root);
+	if(server->trace > 0) {
+		long i;
+		DataBlock *db;
+		for(i = 0, db = server->datablock; i < server->ndatablocks; i++, db++) {
+			logfsfreeanddirtydatablockcheck(server, i);
+			if(db->block >= 0)
+				print("%4ld: free 0x%.8llux dirty 0x%.8llux\n", i, (u64int)server->datablock[i].free, (u64int)server->datablock[i].dirty);
+		}
+	}
+}
--- /dev/null
+++ b/liblogfs/scan.c
@@ -1,0 +1,293 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+#include "fcall.h"
+
+typedef struct PathEnt {
+	ulong path;	
+	long block;
+} PathEnt;
+
+typedef struct GenInfo {
+	long start;
+	long end;
+	int gaps;
+} GenInfo;
+
+static int
+dataorder(ulong p1, ulong p2)
+{
+	int o;
+	o = dataseqof(p1) - dataseqof(p2);
+	if(o != 0)
+		return o;
+	return copygenof(p1) - copygenof(p2);
+}
+
+static int
+logorder(ulong p1, ulong p2)
+{
+	int o;
+	o = loggenof(p1) - loggenof(p2);
+	if(o != 0)
+		return o;
+	o = logseqof(p1) - logseqof(p2);
+	if(o != 0)
+		return o;
+	return copygenof(p1) - copygenof(p2);
+}
+
+static void
+insert(PathEnt *pathmap, long entries, ulong path, long block, int (*order)(ulong p1, ulong p2))
+{
+	long i;
+	for(i = 0; i < entries; i++)
+		if((*order)(path, pathmap[i].path) < 0)
+			break;
+	memmove(&pathmap[i + 1], &pathmap[i], (entries - i) * sizeof(PathEnt));
+	pathmap[i].path = path;
+	pathmap[i].block = block;
+}
+
+static void
+populate(LogSegment *seg, int gen, long unsweptblockindex, long curblockindex, PathEnt *pathent)
+{
+	long i;
+	seg->gen = gen;
+	seg->unsweptblockindex = unsweptblockindex;
+	seg->curblockindex = curblockindex;
+	for(i = unsweptblockindex; i <= curblockindex; i++) {
+//		print("populate %d: %d\n", i, pathent[i - unsweptblockindex].block);
+		seg->blockmap[i] = pathent->block;
+		pathent++;
+	}
+}
+
+static int
+dataduplicate(PathEnt *p1, PathEnt *p2)
+{
+	return dataseqof(p2->path) == dataseqof(p1->path)
+		&& copygenof(p2->path) == copygensucc(copygenof(p1->path));
+}
+
+static char *
+eliminateduplicates(LogfsServer *server, char *name, PathEnt *map, long *entriesp)
+{
+	long i;
+	long k = *entriesp;
+	for(i = 0; i < k;) {
+		PathEnt *prev = &map[i - 1];
+		PathEnt *this = &map[i];
+		if(i > 0 && dataduplicate(prev, this)) {
+			print("%s duplicate detected\n", name);
+			if(i + 1 < k && dataduplicate(this, &map[i + 1]))
+				return "three or more copies of same block";
+			/*
+			 * check that the copy generations are in order
+			 */
+			if(copygensucc(copygenof(this->path)) == copygenof(prev->path)) {
+				PathEnt m;
+				/*
+				 * previous entry is newer, so swap
+				 */
+				m = *this;
+				*this = *prev;
+				*prev = m;
+			}
+			else if(copygensucc(copygenof(prev->path)) != copygenof(this->path))
+				return "duplicate blocks but copy generations not sequential";
+			/* erase and format previous block */
+			logfsbootfettleblock(server->lb, prev->block, LogfsTnone, ~0, nil);
+			/*
+			 * remove entry from table
+			 */
+			memmove(prev, this, sizeof(PathEnt) * (k - i));
+			k--;
+			continue;
+		}
+		i++;
+	}
+	*entriesp = k;
+	return nil;
+}
+
+char *
+logfsscan(LogfsServer *server)
+{
+	LogfsLowLevel *ll = server->ll;
+	long b;
+	long i;
+	long logfound = 0;
+	long datafound = 0;
+	PathEnt *logpathmap, *datapathmap;
+	GenInfo geninfo[1 << L2LogSweeps];
+	int gensfound, lastgenfound;
+	int g0, g1;
+	char *errmsg;
+//print("logfsscan %ld blocks\n", server->ll->blocks);
+	logpathmap = logfsrealloc(nil, sizeof(PathEnt) * server->ll->blocks);
+	datapathmap = logfsrealloc(nil, sizeof(PathEnt) * server->ll->blocks);
+	if(logpathmap == nil || datapathmap == nil)
+		return Enomem;
+	for(b = 0; b < ll->blocks; b++) {
+		short tag = (*ll->getblocktag)(ll, b);
+		ulong path = (*ll->getblockpath)(ll, b);
+//print("scan: %ld: %d %ld\n", b, tag, path);
+		switch(tag) {
+		case LogfsTlog:
+			insert(logpathmap, logfound++, path, b, logorder);
+			break;
+		case LogfsTdata:
+			insert(datapathmap, datafound++, path, b, dataorder);
+			break;
+		}
+	}
+	if(server->trace > 1) {
+		for(i = 0; i < logfound; i++)
+			print("log gen %lud seq %lud copygen %lud block %ld\n",
+				loggenof(logpathmap[i].path), logseqof(logpathmap[i].path), copygenof(datapathmap[i].path), logpathmap[i].block);
+		for(i = 0; i < datafound; i++)
+			print("data seq %lud copygen %lud block %ld\n",
+				dataseqof(datapathmap[i].path), copygenof(datapathmap[i].path), datapathmap[i].block);
+	}
+	/*
+	 * sort out data first
+	 */
+	errmsg = eliminateduplicates(server, "data", datapathmap, &datafound);
+	if(errmsg)
+		goto fail;
+	/*
+	 * data blocks guaranteed to be ordered
+	 */
+	if(datafound)
+		server->ndatablocks = dataseqof(datapathmap[datafound - 1].path) + 1;
+	else
+		server->ndatablocks = 0;
+	for(i = 0; i < server->ndatablocks; i++)
+		server->datablock[i].block = -1;
+	for(i = 0; i < datafound; i++) {
+		long j;
+		j = dataseqof(datapathmap[i].path);
+		server->datablock[j].path = datapathmap[i].path;
+		server->datablock[j].block = datapathmap[i].block;
+		/*
+		 * mark pages as free and dirty, which indicates they cannot be used
+	 	*/
+		server->datablock[j].dirty = server->datablock[j].free = logfsdatapagemask(1 << ll->l2pagesperblock, 0);
+	}
+	/*
+	 * find how many generations are present, and whether there are any gaps
+	 */
+	errmsg = eliminateduplicates(server, "log", logpathmap, &logfound);
+	if(errmsg)
+		goto fail;
+	gensfound = 0;
+	lastgenfound = -1;
+	for(i = 0; i < nelem(geninfo); i++)
+		geninfo[i].start = -1;
+	for(i = 0; i < logfound; i++) {
+		int gen;
+		gen = loggenof(logpathmap[i].path);
+		if(geninfo[gen].start < 0) {
+			if(lastgenfound >= 0)
+				geninfo[lastgenfound].end = i;
+			geninfo[gen].start = i;
+			lastgenfound = gen;
+			geninfo[gen].gaps = 0;
+			gensfound++;
+		}
+		else if(!geninfo[lastgenfound].gaps && logseqof(logpathmap[i - 1].path) + 1 != logseqof(logpathmap[i].path)) {
+			geninfo[lastgenfound].gaps = 1;
+			print("generation %d has gaps (%lud, %lud)\n", lastgenfound,
+				logseqof(logpathmap[i - 1].path), logseqof(logpathmap[i].path));
+		}
+	}
+	if(lastgenfound >= 0)
+		geninfo[lastgenfound].end = i;
+	if(server->trace > 1) {
+		for(i = 0; i < nelem(geninfo); i++)
+			print("geninfo: %ld: start %ld end %ld gaps %d\n", i, geninfo[i].start, geninfo[i].end, geninfo[i].gaps);
+	}
+	switch(gensfound) {
+	case 0:
+		/* active log - empty */
+		break;
+	case 1:
+		/*
+		 * one log, active
+		 */
+		for(g0 = 0; g0 < nelem(geninfo); g0++)
+			if(geninfo[g0].start >= 0)
+				break;
+		if(geninfo[g0].gaps || geninfo[g0].start != 0) {
+			errmsg = "missing log blocks";
+			goto fail;
+		}
+		populate(server->activelog, g0, 0, geninfo[g0].end - geninfo[g0].start - 1, logpathmap + geninfo[g0].start);
+		break;
+	case 2:
+		/*
+		 * two logs, active, swept
+		 */
+		g0 = -1;
+		for(g1 = 0; g1 < nelem(geninfo); g1++)
+			if(geninfo[g1].start >= 0) {
+				if(g0 < 0)
+					g0 = g1;
+				else 
+					break;
+			}
+		if(geninfo[g0].gaps || geninfo[g1].gaps) {
+			errmsg = "missing log blocks";
+			goto fail;
+		}
+		if(g0 == loggensucc(g1)) {
+			int tmp = g0;
+			g0 = g1;
+			g1 = tmp;
+		}
+		else if(g1 != loggensucc(g0)) {
+			errmsg = "nonsequential generations in log";
+			goto fail;
+		}
+		if(logseqof(logpathmap[geninfo[g1].start].path) != 0) {
+			errmsg = "swept log does not start at 0";
+			goto fail;
+		}
+		if(logseqof(logpathmap[geninfo[g0].start].path) == logseqof(logpathmap[geninfo[g1].end - 1].path)) {
+			/*
+			 * duplicate block
+			 * as the log never gets bigger, information from active[n] is either entirely in swept[n],
+			 * or split between swept[n-1] and swept[n]. we can safely remove swept[n]. this might
+			 * leave some duplication between swept[n - 1] and active[n], but this is always true
+			 * for a partially swept log
+			 */
+			logfsbootfettleblock(server->lb, logpathmap[geninfo[g1].end - 1].block, LogfsTnone, ~0, nil);
+			geninfo[g1].end--;
+		}
+		if(logseqof(logpathmap[geninfo[g0].start].path) < logseqof(logpathmap[geninfo[g1].end - 1].path)) {
+			errmsg = "active log overlaps end of swept log";
+			goto fail;
+		}
+		populate(server->activelog, g0, logseqof(logpathmap[geninfo[g0].start].path),
+			logseqof(logpathmap[geninfo[g0].end - 1].path), logpathmap + geninfo[g0].start);
+		if(server->sweptlog == nil) {
+			errmsg = logfslogsegmentnew(server, g1, &server->sweptlog);
+			if(errmsg)
+				goto fail;
+		}
+		populate(server->sweptlog, g1, logseqof(logpathmap[geninfo[g1].start].path),
+			logseqof(logpathmap[geninfo[g1].end - 1].path), logpathmap + geninfo[g1].start);
+		break;
+	default:	
+		errmsg = "more than two generations in log";
+		goto fail;
+	}
+	goto ok;
+fail:
+	logfslogsegmentfree(&server->sweptlog);
+ok:
+	logfsfreemem(logpathmap);
+	logfsfreemem(datapathmap);
+	return errmsg;
+}
--- /dev/null
+++ b/liblogfs/srv.c
@@ -1,0 +1,308 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+static char *unimp = "unimplemented";
+char *logfsbadfid = "invalid fid";
+
+char *
+logfsstrdup(char *p)
+{
+	int l;
+	char *q;
+	if(p == nil)
+		return nil;
+	l = strlen(p);
+	q = logfsrealloc(nil, l + 1);
+	if(q == nil)
+		return nil;
+	return strcpy(q, p);
+}
+
+static
+mkdirentry(LogfsServer *server, Entry *e, int inuse, ulong path, Entry *parent, char *name, char *uid, char *gid,
+	ulong mtime, char *muid, ulong perm)
+{
+//print("mkdirentry 0x%.8lux\n", e);
+	e->inuse = inuse;
+	e->qid.path = path;
+	e->qid.vers = 0;
+	e->qid.type = QTDIR;
+	e->parent = parent;
+	e->name = name;
+	e->uid = logfsisustadd(server->is, uid);
+	e->gid = logfsisustadd(server->is, gid);
+	e->mtime = mtime;
+	e->muid = logfsisustadd(server->is, muid);
+	e->perm = perm | DMDIR;
+	e->next = nil;
+	return e->uid != nil && e->muid != nil && e->name != nil;
+}
+
+void
+logfsentryfree(Entry *e)
+{
+	logfsfreemem(e->name);
+	if((e->qid.type & QTDIR) == 0)
+		logfsextentlistfree(&e->u.file.extent);
+	logfsfreemem(e);
+}
+
+char *
+logfsentrynew(LogfsServer *server, int inuse, u32int path, Entry *parent, char *name, char *uid, char *gid,
+u32int mtime, char *muid, u32int perm, ulong cvers, ulong length, Entry **ep)
+{
+	Entry *e;
+	char *errmsg;
+	e = logfsrealloc(nil, sizeof(*e));
+	if(e == nil)
+		return Enomem;
+	e->inuse = inuse;
+	e->qid.path = path;
+	e->qid.vers = 0;
+	e->qid.type = perm >> 24;
+	e->parent = parent;
+	e->name = logfsstrdup(name);
+	e->uid = logfsisustadd(server->is, uid);
+	e->gid = logfsisustadd(server->is, gid);
+	e->muid = logfsisustadd(server->is, muid);
+	if(e->uid == nil || e->gid == nil || e->muid == nil || e->name == nil) {
+		logfsentryfree(e);
+		return Enomem;
+	}
+	e->mtime = mtime;
+	if(perm & DMDIR)
+		e->perm = perm & (~0777 | (parent->perm & 0777));
+	else {
+		e->perm = perm & (~0666 | (parent->perm & 0666));
+		e->u.file.cvers = cvers;
+		e->u.file.length = length;
+		errmsg = logfsextentlistnew(&e->u.file.extent);
+		if(errmsg) {
+			logfsentryfree(e);
+			return errmsg;
+		}
+	}
+//print("e 0x%.8lux perm 0%.uo\n", e, e->perm);
+	*ep = e;
+	return nil;
+	
+}
+
+void
+logfsentryclunk(Entry *e)
+{
+	e->inuse--;
+	if(e->inuse <= 0)
+		logfsentryfree(e);
+}
+
+char *
+logfsservernew(LogfsBoot *lb, LogfsLowLevel *ll, LogfsIdentityStore *is, ulong openflags, int trace, LogfsServer **srvp)
+{
+	LogfsServer *srv;
+	char *errmsg;
+	Path *p;
+
+	if(trace > 1)
+		print("logfsservernew()\n");
+	if(ll->l2pagesperblock > 5)
+		return "more than 32 pages per block";
+	if((1 << (ll->pathbits - L2LogSweeps - L2BlockCopies)) < ll->blocks)
+		return "too many blocks";
+	srv = logfsrealloc(nil, sizeof(*srv));
+	if(srv == nil) {
+	memerror:
+		errmsg = Enomem;
+	err:
+		logfsserverfree(&srv);
+		return errmsg;
+	}
+	errmsg = logfsfidmapnew(&srv->fidmap);
+	if(errmsg)
+		goto memerror;
+	errmsg = logfspathmapnew(&srv->pathmap);
+	if(errmsg)
+		goto memerror;
+	srv->is = is;
+	srv->ll = ll;
+	srv->trace = trace;
+	srv->lb = lb;
+	srv->openflags = openflags;
+	if(!mkdirentry(srv, &srv->root, 1, 0, &srv->root, "", "inferno", "sys", logfsnow(), "inferno", 0777))
+		goto memerror;
+	errmsg = logfspathmapnewentry(srv->pathmap, 0, &srv->root, &p);
+	/* p is guaranteed to be non null */
+	if(errmsg)
+		goto memerror;
+	errmsg = logfslogsegmentnew(srv, 0, &srv->activelog);
+	if(errmsg)
+		goto memerror;
+	srv->ndatablocks = 0;
+	srv->datablock = logfsrealloc(nil, sizeof(DataBlock) * ll->blocks);
+	if(srv->datablock == nil)
+		goto memerror;
+	errmsg = logfsscan(srv);
+	if(errmsg)
+		goto err;
+	errmsg = logfsreplay(srv, srv->sweptlog, 0);
+	if(errmsg)
+		goto err;
+	errmsg = logfsreplay(srv, srv->activelog, srv->sweptlog != nil);
+	if(errmsg)
+		goto err;
+	logfsreplayfinddata(srv);
+	*srvp = srv;
+	return nil;
+}
+
+static void
+freeentrylist(Entry *e)
+{
+	Entry *next;
+	while(e) {
+		next = e->next;
+		if(e->qid.type & QTDIR)
+			freeentrylist(e->u.dir.list);
+		logfsentryfree(e);
+		e = next;
+	}
+}
+
+void
+logfsserverfree(LogfsServer **serverp)
+{
+	LogfsServer *server = *serverp;
+	if(server) {
+		logfsfidmapfree(&server->fidmap);
+		logfslogsegmentfree(&server->activelog);
+		logfslogsegmentfree(&server->sweptlog);
+		logfspathmapfree(&server->pathmap);
+		logfsfreemem(server->datablock);
+		logfsfreemem(server);
+		freeentrylist(server->root.u.dir.list);
+		*serverp = nil;
+	}
+}
+
+char *
+logfsserverattach(LogfsServer *server, u32int fid, char *uname, Qid *qid)
+{
+	char *errmsg;
+	Fid *f;
+	if(server->trace > 1)
+		print("logfsserverattach(%ud, %s)\n", fid, uname);
+	errmsg = logfsfidmapnewentry(server->fidmap, fid, &f);
+	if(errmsg)
+		return errmsg;
+	f->uname = logfsisustadd(server->is, uname);
+	if(f->uname == nil) {
+		logfsfidmapclunk(server->fidmap, fid);
+		return Enomem;
+	}
+	f->entry = &server->root;
+	f->entry->inuse++;
+	*qid = f->entry->qid;
+	return nil;
+}
+
+static void
+id2name(LogfsIdentityStore *is, char *id, char **namep, int *badp, int *lenp)
+{
+	char *name;
+	if(id == logfsisgroupnonename)
+		name = id;
+	else {
+		name = logfsisfindnamefromid(is, id);
+		if(name == nil) {
+			*badp = 2;
+			name = id;
+		}
+	}
+	*lenp = strlen(name);
+	*namep = name;
+}
+
+u32int
+logfsflattenentry(LogfsIdentityStore *is, uchar *buf, u32int limit, Entry *e)
+{
+	int unamelen, gnamelen, munamelen, namelen;
+	uint len;
+	uchar *p;
+	int unamebad = 0, gnamebad = 0, munamebad = 0;
+	char *uname, *gname, *muname;
+
+	id2name(is, e->uid, &uname, &unamebad, &unamelen);
+	id2name(is, e->gid, &gname, &gnamebad, &gnamelen);
+	id2name(is, e->muid, &muname, &munamebad, &munamelen);
+	namelen = strlen(e->name);
+	len = 49 + unamelen + unamebad + gnamelen + gnamebad + munamelen + munamebad + namelen;
+	if(buf == nil)
+		return len;
+	if(len > limit)
+		return 0;
+	p = buf;
+	/* size */		PBIT16(p, len - BIT16SZ); p += BIT16SZ;
+	/* type */		p += BIT16SZ;
+	/* dev */		p += BIT32SZ;
+	/* qid.type */	*p++ = e->qid.type;
+	/* qid.vers */	PBIT32(p, e->qid.vers); p += BIT32SZ;
+	/* qid.path */	PBIT64(p, e->qid.path); p+= 8;
+	/* mode */	PBIT32(p, e->perm); p+= BIT32SZ;
+	/* atime */	PBIT32(p, e->mtime); p+= BIT32SZ;
+	/* mtime */	PBIT32(p, e->mtime); p+= BIT32SZ;
+	/* length */	if(e->qid.type & QTDIR) {
+					PBIT64(p, 0);
+					p += 8;
+				}
+				else {
+					PBIT32(p, e->u.file.length); p += BIT32SZ;
+					PBIT32(p, 0); p += BIT32SZ;
+				}
+	/* name */	PBIT16(p, namelen); p += BIT16SZ; memmove(p, e->name, namelen); p+= namelen;
+	/* uid */		PBIT16(p, unamelen + unamebad); p += BIT16SZ;
+				if(unamebad)
+					*p++ = '(';
+				memmove(p, uname, unamelen + unamebad); p+= unamelen;
+				if(unamebad)
+					*p++ = ')';
+	/* gid */		PBIT16(p, gnamelen + gnamebad); p += BIT16SZ;
+				if(gnamebad)
+					*p++ = '(';
+				memmove(p, gname, gnamelen); p+= gnamelen;
+				if(gnamebad)
+					*p++ = ')';
+	/* muid */	PBIT16(p, munamelen + munamebad); p += BIT16SZ;
+				if(munamebad)
+					*p++ = '(';
+				memmove(p, muname, munamelen); p+= munamelen;
+				if(munamebad)
+					*p = ')';
+//print("len %ud p - buf %ld\n", len, p - buf);
+	return len;
+}
+
+char *
+logfsserverstat(LogfsServer *server, u32int fid, uchar *buf, u32int bufsize, ushort *nstat)
+{
+	Fid *f;
+	if(server->trace > 1)
+		print("logfsserverstat(%ud)\n", fid);
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsbadfid;
+	if(f->entry->deadandgone)
+		return Eio;
+	*nstat = logfsflattenentry(server->is, buf, bufsize, f->entry);
+	if(*nstat == 0)
+		return Eshortstat;
+	return nil;
+}
+
+
+void
+logfsservertrace(LogfsServer *server, int level)
+{
+	server->trace = level;
+}
--- /dev/null
+++ b/liblogfs/sweep.c
@@ -1,0 +1,272 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+	ThrowAway,
+	Keep,
+	Repack,
+	Error,
+};
+
+#define setaction(a) if(*actionp < (a)) *actionp = a
+#define REPACK setaction(Repack)
+#define KEEP setaction(Keep)
+#define OPTCOPYEX(name, etag, stag) \
+	if(e->etag != s->stag) { \
+		s->stag = e->etag; \
+		REPACK; \
+	}
+#define OPTSTRCOPYEX(name, etag, stag) \
+	if(strcmp(e->etag, s->stag) != 0) { \
+		s->stag = e->etag; \
+		REPACK; \
+	}
+
+#define OPTCOPY(name, tag, sunion) OPTCOPYEX(name, tag, u.sunion.tag)
+#define OPTSTRCOPY(name, tag, sunion) OPTSTRCOPYEX(name, tag, u.sunion.tag)
+
+static char *
+sweepcreate(LogfsServer *server, LogMessage *s, int *actionp)
+{
+	Entry *pe, *e;
+	e = logfspathmapfinde(server->pathmap, s->u.create.newpath);
+	if(e == nil)
+		/* file no longer exists */
+		return nil;
+	pe = logfspathmapfinde(server->pathmap, s->path);
+	if(pe == nil)
+		/* file exists but parent doesn't - not good, but can continue */
+		return "parent missing";
+	if((pe->perm & DMDIR) == 0 || (e->perm & DMDIR) != (s->u.create.perm & DMDIR))
+		/* parent must be a directory, and
+		 * the directory mode cannot change
+		 */
+		return logfseinternal;
+	if((e->perm & DMDIR) == 0) {
+		OPTCOPYEX("cvers", u.file.cvers, u.create.cvers);
+	}
+	OPTSTRCOPY("name", name, create);
+	OPTCOPY("mtime", mtime, create);
+	OPTCOPY("perm", perm, create);
+	OPTSTRCOPY("uid", uid, create);
+	OPTSTRCOPY("gid", gid, create);
+	KEEP;
+	return nil;
+}
+
+static char *
+sweepwrite(LogfsServer *server, LogMessage *s, int readoffset, Entry **ep, int *trimp, int *actionp)
+{
+	Entry *e;
+	Extent extent;
+	Extent *ext;
+	*ep = nil;
+	e = logfspathmapfinde(server->pathmap, s->path);
+	if(e == nil)
+		/* gone, gone */
+		return nil;
+	if(e->perm & DMDIR)
+		return logfseinternal;
+	if(e->u.file.cvers != s->u.write.cvers)
+		/* trunced more recently */
+		return nil;
+	extent.min = s->u.write.offset;
+	extent.max = extent.min + s->u.write.count;
+	extent.flashaddr = s->u.write.flashaddr;
+	ext = logfsextentlistmatch(e->u.file.extent, &extent);
+	if(ext == nil)
+		return nil;
+	if(s->u.write.data) {
+		/*
+		 * trim the front of the data so that when fixing up extents,
+		 * flashaddr refers to the first byte
+		 */
+		int offset;	
+		logfsflashaddr2o(server, ext->flashaddr, &offset);
+		*trimp = offset - readoffset;
+		*ep = e;
+	}
+	KEEP;
+	return nil;
+}
+
+typedef struct FixupState {
+	LogfsServer *server;
+	int oldoffset;
+	u32int newflashaddr;
+} FixupState;
+
+static int
+fixup(void *magic, Extent *e)
+{
+	FixupState *state = magic;
+	int offset;
+	logfsflashaddr2o(state->server, e->flashaddr, &offset);
+	e->flashaddr = state->newflashaddr + (offset - state->oldoffset);
+	return 1;
+}
+
+static char *
+sweepblock(LogfsServer *server, uchar *buf)
+{
+	char *errmsg;
+	LogSegment *active = server->activelog;
+	LogSegment *swept = server->sweptlog;
+	int pagesize, ppb, page;
+	LogfsLowLevel *ll = server->ll;
+	LogfsLowLevelReadResult llrr;
+	int markedbad;
+	long oblock;
+
+	if(active == nil)
+		return nil;
+	if(swept == nil) {
+		errmsg = logfslogsegmentnew(server, loggensucc(active->gen), &server->sweptlog);
+		if(errmsg)
+			return errmsg;
+		swept = server->sweptlog;
+	}
+	/*
+	 * if this is last block in the active log, flush it, so that the read of the last page works
+	 */
+	if(active->unsweptblockindex	== active->curblockindex)
+		logfslogsegmentflush(server, 1);
+	ppb = (1 << ll->l2pagesperblock);
+	pagesize = (1 << ll->l2pagesize);
+	for(page = 0; page < ppb; page++) {
+		uchar *p, *bufend;
+		errmsg = (*ll->readpagerange)(ll, buf, active->blockmap[active->unsweptblockindex], page, 0,  pagesize, &llrr);
+		if(errmsg)
+			goto fail;
+		if(llrr != LogfsLowLevelReadResultOk)
+			logfsserverreplacelogblock(server, active, active->unsweptblockindex);
+		p = buf;
+		if(*p == 0xff)
+			break;
+		bufend = p + pagesize;
+		while(p < bufend) {
+			int action;
+			uint size;
+			LogMessage s;
+			Entry *e;
+			int trim;
+
+			size = logfsconvM2S(p, bufend - p, &s);
+			if(size == 0)
+				return "parse failure";
+			if(server->trace > 1) {
+				print("A>> ");
+				logfsdumpS(&s);
+				print("\n");
+			}
+			if(s.type == LogfsLogTend)
+				break;
+			action = ThrowAway;
+			switch(s.type) {
+			case LogfsLogTstart:
+				break;
+			case LogfsLogTcreate:
+				errmsg = sweepcreate(server, &s, &action);
+				break;
+			case LogfsLogTremove:
+				/* always obsolete; might check that path really doesn't exist */
+				break;
+			case LogfsLogTtrunc:
+				/* always obsolete, unless collecting out of order */
+				break;
+			case LogfsLogTwrite:
+				errmsg = sweepwrite(server, &s, s.u.write.data ? s.u.write.data - buf : 0, &e, &trim, &action);
+				break;
+			case LogfsLogTwstat:
+				/* always obsolete, unless collecting out of order */
+				break;
+			default:
+				return "bad tag in log page";
+			}
+			if(action == Error)
+				return errmsg;
+			if(errmsg)
+				print("bad sweep: %s\n", errmsg);
+			if(action == Keep)
+				action = Repack;		/* input buffer has been wrecked, so can't just copy it */
+			if(action == Keep) {
+				/* write 'size' bytes to log */
+				errmsg = logfslogbytes(server, 0, p, size);
+				if(errmsg)
+					goto fail;
+			}
+			else if(action == Repack) {
+				/* TODO - handle writes */
+				if(s.type == LogfsLogTwrite && s.u.write.data) {
+					FixupState state;
+					errmsg = logfslogwrite(server, 0, s.path, s.u.write.offset + trim, s.u.write.count - trim,
+						s.u.write.mtime, s.u.write.cvers,
+						s.u.write.muid, s.u.write.data + trim, &state.newflashaddr);
+					if(errmsg == nil && s.u.write.data != nil) {
+						Extent extent;
+						/* TODO - deal with a failure to write the changes */
+						state.oldoffset = s.u.write.data - buf + trim;
+						state.server = server;
+						extent.min = s.u.write.offset;
+						extent.max = extent.min + s.u.write.count;
+						extent.flashaddr = s.u.write.flashaddr;
+						logfsextentlistmatchall(e->u.file.extent, fixup, &state, &extent);
+					}
+				}
+				else
+					errmsg = logfslog(server, 0, &s);
+				if(errmsg)
+					goto fail;
+			}
+			p += size;
+		}
+	}
+	/*
+	 * this log block is no longer needed
+	 */
+	oblock = active->blockmap[active->unsweptblockindex++];
+	errmsg = logfsbootfettleblock(server->lb, oblock, LogfsTnone, ~0, &markedbad);
+	if(errmsg)
+		goto fail;
+	if(active->unsweptblockindex  > active->curblockindex) {
+		/*
+		 * the activelog is now empty, so make the sweptlog the active one
+		 */
+		logfslogsegmentfree(&active);
+		server->activelog = swept;
+		server->sweptlog = nil;
+		swept->dirty = 0;
+	}
+	return nil;
+fail:
+	return errmsg;
+}
+
+char *
+logfsserverlogsweep(LogfsServer *server, int justone, int *didsomething)
+{
+	uchar *buf;
+	char *errmsg;
+
+	/*
+	 * TODO - is it even worth doing?
+	 */
+	*didsomething = 0;
+	if(!server->activelog->dirty)
+		return nil;
+	buf = logfsrealloc(nil, (1 << server->ll->l2pagesize));
+	if(buf == nil)
+		return Enomem;
+	errmsg = nil;
+	while(server->activelog->unsweptblockindex <= server->activelog->curblockindex) {
+		errmsg = sweepblock(server, buf);
+		if(errmsg)
+			break;
+		if(server->sweptlog == nil || justone)
+			break;
+	}
+	logfsfreemem(buf);
+	*didsomething = 1;
+	return errmsg;
+}
--- /dev/null
+++ b/liblogfs/tagname.c
@@ -1,0 +1,20 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfstagname(uchar tag)
+{
+	switch(tag) {
+	case LogfsTboot:
+		return "boot";
+	case LogfsTnone:
+		return "free";
+	case LogfsTlog:
+		return "log";
+	case LogfsTdata:
+		return "data";
+	}
+	return "???";
+}
+
--- /dev/null
+++ b/liblogfs/test.c
@@ -1,0 +1,13 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+char *
+logfsservertestcmd(LogfsServer *s, int argc, char **argv)
+{
+	if(argc == 1 && strcmp(argv[0], "dontfettledatablock") == 0)
+		s->testflags |= LogfsTestDontFettleDataBlock;
+	else
+		return Ebadarg;
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/ust.c
@@ -1,0 +1,65 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+enum {
+	USTMOD = 127
+};
+
+typedef struct UstNode {
+	char s[1];
+} UstNode;
+
+struct Ust {
+	UstNode *head[USTMOD];
+};
+
+int
+logfshashstring(void *s, int n)
+{
+	int h = 0;
+	char *p;
+	for(p = s; *p; p++) {
+		ulong g;
+		h = (h << 4) + *p;
+		g = h & 0xf0000000;
+		if(g != 0)
+			h ^= ((g >> 24) & 0xff) | g;
+	}
+	return (h & ~(1 << 31)) % n;
+}
+
+static int
+compare(void *entry, void *key)
+{
+	return strcmp((char*)entry, (char*)key) == 0;
+}
+
+static int
+allocsize(void *key)
+{
+	return strlen(key) + 1;
+}
+
+char *
+logfsustnew(Ust **ustp)
+{
+	return logfsmapnew(USTMOD, logfshashstring, compare, allocsize, nil, ustp);
+}
+
+char *
+logfsustadd(Ust *ust, char *s)
+{
+	char *errmsg;
+	char *ep;
+	ep = logfsmapfindentry(ust, s);
+	if(ep != nil) {
+//		print("ust: found %s\n", s);
+		return ep;
+	}
+	errmsg = logfsmapnewentry(ust, s, &ep);
+	if(errmsg != nil)
+		return errmsg;
+//	print("ust: new %s\n", s);
+	return strcpy(ep, s);
+}
--- /dev/null
+++ b/liblogfs/walk.c
@@ -1,0 +1,108 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverwalk(LogfsServer *server, u32int fid, u32int newfid, ushort nwname, char **wname, ushort *nwqid, Qid *wqid)
+{
+	ushort i;
+	Entry *e;
+	char *errmsg;
+	Fid *f;
+	if(server->trace > 1) {
+		print("logfsserverwalk(%ud, %ud, %ud, \"", fid, newfid, nwname);
+		for(i = 0; i < nwname; i++) {
+			if(i > 0)
+				print("/");
+			print("%s", wname[i]);
+		}
+		print("\")\n");
+	}
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsebadfid;
+	if(f->openmode >= 0)
+		return logfsefidopen;
+	errmsg = nil;
+	e = f->entry;
+	if(e->deadandgone)
+		return Eio;
+	for(i = 0; i < nwname; i++) {
+		Entry *se;
+		/*
+		 * deal with ..
+		 */
+		if(strcmp(wname[i], "..") == 0)
+			se = e->parent;
+		else if(strcmp(wname[i], ".") == 0)
+			se = e;
+		else {
+			/*
+			 * is it a directory?
+			 */
+			if((e->qid.type & QTDIR) == 0) {
+				errmsg = Enotdir;
+				break;
+			}
+			/*
+			 * can we walk the walk, or just talk the protocol?
+			 */
+			if(!logfsuserpermcheck(server, e, f, DMEXEC)) {
+				errmsg = Eperm;
+				break;
+			}
+			/*
+			 * search current entry for nwname[i]
+			 */
+			for(se = e->u.dir.list; se; se = se->next)
+				if(strcmp(se->name, wname[i]) == 0)
+					break;
+			if(se == nil) {
+				errmsg = Enonexist;
+				break;
+			}
+		}
+		wqid[i] = se->qid;
+		e = se;
+	}
+	if(nwname > 0 && i == 0) {
+		/*
+		 * fell at the first fence
+		 */
+		return errmsg;
+	}
+	*nwqid = i;
+	if(i < nwname)
+		return nil;
+	/*
+	 * new fid required?
+	 */
+	if(fid != newfid) {
+		Fid *newf;
+		char *errmsg;
+		errmsg = logfsfidmapnewentry(server->fidmap, newfid, &newf);
+		if(errmsg)
+			return errmsg;
+		if(newf == nil)
+			return logfsefidinuse;
+		newf->entry = e;
+		newf->uname = f->uname;
+		e->inuse++;
+	}
+	else {
+		/*
+		 * this may now be right
+		 * 1. increment reference on new entry first in case e and f->entry are the same
+		 * 2. clunk the old one in case this has the effect of removing an old entry
+		 * 3. dump the directory read state if the entry has changed
+		 */
+		e->inuse++;
+		logfsentryclunk(f->entry);
+		if(e != f->entry)
+			logfsdrsfree(&f->drs);
+		f->entry = e;
+	}
+	return nil;
+}
+
--- /dev/null
+++ b/liblogfs/write.c
@@ -1,0 +1,595 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "local.h"
+
+typedef struct AllocState AllocState;
+struct AllocState {
+	long oldblock;
+	int markbad;
+};
+
+Pageset
+logfsdatapagemask(int pages, int base)
+{
+	if(pages == BITSPERSET)
+		return ~(Pageset)0;
+	return (((Pageset)1 << pages) - 1) << (BITSPERSET - base - pages);
+}
+
+static Pageset
+fastgap(Pageset w, uint n)
+{
+	Pageset s;
+//print("fastgap(0x%.8ux, %d)\n", w, n);
+	if(w == 0 || n < 1 || n > BITSPERSET)
+		return 0;
+/*
+#	unroll the following loop 5 times:
+#		while(n > 1){
+#			s := n >> 1;
+#			w &= w<<s;
+#			n -= s;
+#		}
+*/
+	s = n >> 1;
+	w &= w << s;
+	n -= s;
+	s = n >> 1;
+	w &= w << s;
+	n -= s;
+	s = n >> 1;
+	w &= w << s;
+	n -= s;
+	s = n >> 1;
+	w &= w << s;
+	n -= s;
+	s = n >> 1;
+	if(BITSPERSET == 64){	/* extra time if 64 bits */
+		w &= w << s;
+		n -= s;
+		s = n >> 1;
+	}
+	return w & (w << s);
+}
+
+static int
+nlz(Pageset x)
+{
+	int n, c;
+
+	if(x == 0)
+		return BITSPERSET;
+	if(x & PAGETOP)
+		return 0;
+	n = BITSPERSET;
+	c = BITSPERSET/2;
+	do {
+		Pageset y;
+		y = x >> c;
+		if(y != 0) {
+			n -= c;
+			x = y;
+		}
+	} while((c >>= 1) != 0);
+	return n - x;
+}
+
+static Pageset
+findgap(Pageset w, uint n)
+{
+	Pageset m;
+
+	do {
+		m  = fastgap(w, n);
+		if(m)
+			break;
+		n--;
+	} while(n);
+	if(n == 0)
+		return 0;
+	return logfsdatapagemask(n, nlz(m));
+}
+
+static int
+bitcount(Pageset mask)
+{
+	Pageset m;
+	int rv;
+
+	rv = 0;
+	for(m = PAGETOP; m != 0; m >>= 1)
+		if(mask & m)
+			rv++;
+	return rv;
+}
+
+static char *
+allocdatapages(LogfsServer *server, u32int count, int *countp, long *blockindexp, int *pagep, u32int *flashaddr, AllocState *state)
+{
+	LogfsLowLevel *ll = server->ll;
+	long b, blockindex;
+	DataBlock *db;
+	int pagebase;
+	u32int pages = (count + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
+	u32int gapmask;
+	long bestfreeblockindex;
+	int bestfree;
+	int pagesperblock = 1 << ll->l2pagesperblock;
+	int apages;
+	char *errmsg;
+	int didsomething;
+
+	state->oldblock = -1;
+	state->markbad = 0;
+	if(pages > pagesperblock)
+		pages = pagesperblock;
+	/*
+	 * fill in gaps first
+	 */
+	bestfreeblockindex = -1;
+	bestfree = 0;
+	for(blockindex = 0; blockindex < server->ndatablocks; blockindex++) {
+		db = server->datablock + blockindex;
+		if(db->block < 0)
+			continue;
+		gapmask = findgap(db->free & ~db->dirty, pages);
+//print("blockindex %ld free 0x%.8ux dirty 0x%.8ux gapmask %.8ux\n", blockindex, db->free, db->dirty, gapmask);
+		if(gapmask != 0) {
+			/*
+			 * this is free and !dirty
+			 */
+			b = db->block;
+			USED(b);
+			goto done;
+		}
+		else {
+			int free = bitcount(db->free & logfsdatapagemask(pagesperblock, 0));
+			if(free > 0 && (bestfreeblockindex < 0 || free > bestfree)) {
+				bestfreeblockindex = blockindex;
+				bestfree = free;
+			}
+		}
+	}
+//print("out of space - need to clean up a data block\n");
+	if(bestfreeblockindex >= 0) {
+//print("best block index %ld (%ld) %d bits\n", bestfreeblockindex, server->datablock[bestfreeblockindex].block, bestfree);
+		/*
+		 * clean up data block
+		 */
+		b = logfsfindfreeblock(ll, AllocReasonTransfer);
+		while(b >= 0) {
+			char *errmsg;
+			LogfsLowLevelReadResult llrr;
+			long oldblock;
+			int markedbad;
+
+			db = server->datablock + bestfreeblockindex;
+			oldblock = db->block;
+			errmsg = logfsservercopyactivedata(server, b, bestfreeblockindex, 0, &llrr, &markedbad);
+			if(errmsg) {
+				if(!markedbad)
+					return errmsg;
+				b = logfsfindfreeblock(ll, AllocReasonTransfer);
+			}
+			else {
+				Pageset available;
+				/*
+				 * if page0 is free, then we must ensure that we use it otherwise
+				 * in tagged storage such as nand, the block tag is not written
+				 * in all cases, it is safer to erase the block afterwards to
+				 * preserve the data for as long as possible (we could choose
+				 * to erase the old block now if page0 has already been copied)
+				 */
+				blockindex = bestfreeblockindex;
+				state->oldblock = oldblock;
+				state->markbad = llrr != LogfsLowLevelReadResultOk;
+				available = db->free & ~db->dirty;
+				if(available & PAGETOP)
+					available = logfsdatapagemask(nlz(~available), 0);
+				gapmask = findgap(available, pages);
+				goto done;
+			}
+		}
+	}
+	/*
+	 * use already erased blocks, so long as there are a few free
+	 */
+	b = logfsfindfreeblock(ll, AllocReasonDataExtend);
+	if(b >= 0) {
+useerased:
+		for(blockindex = 0, db = server->datablock; blockindex < server->ndatablocks; blockindex++, db++)
+			if(db->block < 0)
+				break;
+		if(blockindex == server->ndatablocks)
+			server->ndatablocks++;
+		db->path = mkdatapath(blockindex, 0);
+		db->block = b;
+		(*ll->setblocktag)(ll, b, LogfsTdata);
+		(*ll->setblockpath)(ll, b, db->path);
+		db->free = logfsdatapagemask(pagesperblock, 0);
+		db->dirty = 0;
+		gapmask = db->free;
+		goto done;
+	}
+	/*
+	 * last resort; try to steal from log
+	 */
+//print("last resort\n");
+	errmsg = logfsserverlogsweep(server, 0, &didsomething);
+	if(errmsg)
+		return errmsg;
+	if(didsomething) {
+		/*
+		 * this can only create whole free blocks, so...
+		 */
+//print("findfree after last resort\n");
+		b = logfsfindfreeblock(ll, AllocReasonDataExtend);
+		if(b >= 0) {
+//print("*********************************************************\n");
+			goto useerased;
+		}
+	}
+	*countp = 0;
+	return nil;
+done:
+	/*
+	 * common finish - needs gapmask, blockindex, db
+	 */
+	apages = bitcount(gapmask);
+	pagebase = nlz(gapmask);
+	if(apages > pages)
+		apages = pages;
+	gapmask = logfsdatapagemask(apages, pagebase);
+	if(server->trace > 1)
+		print("allocdatapages: block %ld(%ld) pages %d mask 0x%.8ux pagebase %d apages %d\n",
+			blockindex, db->block, pages, gapmask, pagebase, apages);
+	db->free &= ~gapmask;
+	db->dirty |= gapmask;
+	*pagep = pagebase;
+	*blockindexp = blockindex;
+	*flashaddr = logfsspo2flashaddr(server, blockindex, pagebase, 0);
+	*countp = apages << ll->l2pagesize;
+	if(*countp > count)
+		*countp = count;
+	return nil;
+}
+
+typedef struct Page {
+	u32int pageaddr;
+	int ref;
+} Page;
+
+typedef struct DataStructure {
+	LogfsServer *server;
+	int nentries;
+	int maxentries;
+	Page *array;
+} DataStructure;
+
+static int
+deltapage(DataStructure *ds, u32int pageaddr, int add, int delta)
+{
+	int i;
+	for(i = 0; i < ds->nentries; i++)
+		if(ds->array[i].pageaddr == pageaddr) {
+			ds->array[i].ref += delta;
+			return 1;
+		}
+	if(!add)
+		return 1;
+	if(ds->maxentries == 0) {
+		ds->array = logfsrealloc(nil, sizeof(Page) * 100);
+		if(ds->array == nil)
+			return 0;
+		ds->maxentries = 100;
+	}
+	else if(ds->nentries >= ds->maxentries) {
+		void *a = logfsrealloc(ds->array, ds->maxentries * 2 * sizeof(Page));
+		if(a == nil)
+			return 0;
+		ds->array = a;
+		ds->maxentries *= 2;
+	}
+	ds->array[ds->nentries].pageaddr = pageaddr;
+	ds->array[ds->nentries++].ref = delta;
+	return 1;
+}
+
+/*
+ * only called for data addresses
+ */
+static int
+deltapages(DataStructure *ds, LogfsLowLevel *ll, u32int baseflashaddr, int range, int add, int delta)
+{
+	long seq;
+	int page, offset;
+	int pages;
+	u32int pageaddr;
+	int x;
+
+//print("deltapages(%ud, %ud, %d, %d)\n", baseflashaddr, limitflashaddr, add, delta);
+	logfsflashaddr2spo(ds->server, baseflashaddr, &seq, &page, &offset);
+	pages = (offset + range + (1 << ll->l2pagesize) - 1) >> ll->l2pagesize;
+	pageaddr = (seq << ll->l2pagesperblock) + page;
+ 	for(x = 0; x < pages; x++, pageaddr++)
+		if(!deltapage(ds, pageaddr, add, delta))
+			return 0;
+	return 1;
+}
+
+static int
+findpageset(void *magic, u32int baseoffset, u32int limitoffset, Extent *e, u32int extentoffset)
+{
+	DataStructure *ds = magic;
+	LogfsLowLevel *ll;
+	u32int flashaddr;
+	u32int range;
+	u32int residue;
+
+	if(e == nil || (e->flashaddr & LogAddr) != 0)
+		return 1;
+	ll = ds->server->ll;
+//print("baseoffset %ud limitoffset %ud min %ud max %ud\n", baseoffset, limitoffset, e->min, e->max);
+	flashaddr = e->flashaddr;
+	if(extentoffset)
+		if(!deltapages(ds, ll, flashaddr, extentoffset, 1, 1))
+			return -1;
+	flashaddr += extentoffset;
+	range = limitoffset - baseoffset;
+	if(!deltapages(ds, ll, flashaddr, range, 1, -1))
+		return -1;
+	flashaddr += range;
+	residue = e->max - e->min - (extentoffset + range);
+	if(residue)
+		if(!deltapages(ds, ll, flashaddr, residue, 1, 1))
+			return -1;
+	return 1;
+}
+
+static int
+addpagereferences(void *magic, Extent *e, int hole)
+{
+	DataStructure *ds = magic;
+
+	if(hole || (e->flashaddr & LogAddr) != 0)
+		return 1;
+	return deltapages(ds, ds->server->ll, e->flashaddr, e->max - e->min, 0, 1) ? 1 : -1;
+}
+
+static char *
+zappages(LogfsServer *server, Entry *e, u32int min, u32int max)
+{
+	DataStructure ds;
+	long seq;
+	int x, rv, page;
+	Page *p;
+
+	if(min >= e->u.file.length)
+		return nil;		/* no checks necessary */
+	if(min == 0 && max >= e->u.file.length) {
+		/* replacing entire file */
+		logfsextentlistwalk(e->u.file.extent, logfsunconditionallymarkfreeanddirty, server);
+		return nil;
+	}
+	/* hard after that - this will need to be improved */
+	/*
+	 * current algorithm
+	 * build a list of all pages referenced by the extents being removed, and count the
+ 	 * number of references
+	 * then subtract the number of references to each page in entire file
+	 * any pages with a reference count == 0 can be removed
+	 */
+	ds.server = server;
+	ds.nentries = 0;
+	ds.maxentries = 0;
+	ds.array = nil;
+	rv = logfsextentlistwalkrange(e->u.file.extent, findpageset, &ds, min, max);
+	if(rv < 0 || ds.nentries == 0)
+		goto Out;
+	if(server->trace > 1){
+		print("pass 1\n");
+		for(x = 0; x < ds.nentries; x++){
+			p = &ds.array[x];
+			seq = p->pageaddr >> server->ll->l2pagesperblock;
+			page = p->pageaddr & ((1 << server->ll->l2pagesperblock) - 1);
+			print("block %lud page %ud ref %d\n", seq, page, p->ref);
+		}
+		print("pass 2\n");
+	}
+	rv = logfsextentlistwalk(e->u.file.extent, addpagereferences, &ds);
+	if(rv >= 0){
+		for(x = 0; x < ds.nentries; x++){
+			p = &ds.array[x];
+			seq = p->pageaddr >> server->ll->l2pagesperblock;
+			page = p->pageaddr & ((1 << server->ll->l2pagesperblock) - 1);
+			if(server->trace > 1)
+				print("block %lud page %ud ref %d\n", seq, page, p->ref);
+			if(p->ref == 0)
+				logfsfreedatapages(server, seq, logfsdatapagemask(1, page));
+		}
+	}
+Out:
+	logfsfreemem(ds.array);
+	return rv < 0 ? Enomem : nil;
+}
+
+static void
+disposeofoldblock(LogfsServer *server, AllocState *state)
+{
+	if(state->oldblock >= 0) {
+		if(server->testflags & LogfsTestDontFettleDataBlock) {
+			/* take the block out of commission */
+			(*server->ll->setblocktag)(server->ll, state->oldblock, LogfsTworse);
+			server->testflags &= ~LogfsTestDontFettleDataBlock;
+		}
+		else {
+			if(state->markbad)
+				(*server->ll->markblockbad)(server->ll, state->oldblock);
+			else
+				logfsbootfettleblock(server->lb, state->oldblock, LogfsTnone, ~0, nil);
+		}
+		state->oldblock = -1;
+	}
+}
+
+char *
+logfsserverwrite(LogfsServer *server, u32int fid, u32int offset, u32int count, uchar *buf, u32int *rcount)
+{
+	Fid *f;
+	Entry *e;
+	u32int now;
+	char *muid;
+	int muidlen;
+	LogfsLowLevel *ll = server->ll;
+
+	if(server->trace > 1)
+		print("logfsserverwrite(%ud, %ud, %ud)\n", fid, offset, count);
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsebadfid;
+	if(f->openmode < 0)
+		return logfsefidnotopen;
+	if((f->openmode & 3) == OREAD)
+		return logfseaccess;
+	e = f->entry;
+	if(e->deadandgone)
+		return Eio;
+	if(e->qid.type & QTDIR)
+		return Eperm;
+	if(e->perm & DMAPPEND)
+		offset = e->u.file.length;
+	now = logfsnow();
+	*rcount = count;
+	muid = logfsisfindidfromname(server->is, f->uname);
+	muidlen = strlen(muid);
+	while(count) {
+		Extent extent;
+		int thistime;
+		char *errmsg;
+		thistime = lognicesizeforwrite(server, 1, count, muidlen);
+		if(thistime == 0) {
+			int p;
+			u32int n;
+			long blockindex;
+			int pagebase;
+			AllocState state;
+			int pagesize = 1 << ll->l2pagesize;
+		reallocate:
+			errmsg = allocdatapages(server, count, &thistime, &blockindex, &pagebase, &extent.flashaddr, &state);
+			if(errmsg)
+				return errmsg;
+			if(thistime == 0)
+				return logfselogfull;
+			for(p = pagebase, n = 0; n < thistime; p++, n += pagesize) {
+				u32int mask;
+				DataBlock *db = server->datablock + blockindex;
+				errmsg = (*ll->writepage)(ll, buf + n, db->block, p);
+				if(errmsg) {
+					if(strcmp(errmsg, Eio) != 0) {
+						/*
+						 * something horrid happened down below
+						 * recover without writing any more than we have to
+						 */
+						if(p != 0) {
+							/*
+							 * page 0 was either written already, or has been written in this loop
+							 * thus the block referenced is valid on the media. all we need to do
+							 * is lose the old block, mark the written pages as free (so they can
+							 * be scavenged), and don't bother with the log message
+							 */
+							disposeofoldblock(server, &state);
+							mask = logfsdatapagemask(p - pagebase - 1, pagebase);
+							db->free |= mask;
+							db->dirty |= mask;
+							return errmsg;
+						}
+						/*
+						 * page 0 failed to write (so nothing written at all)
+						 * this is either an entirely free block (no erased block in savestate),
+						 * or a copy of a scavenged block (erased block in savestate)
+						 */
+						if(state.oldblock < 0) {
+							/*
+							 * newly selected erased block (blockindex == server->ndatablocks - 1)
+							 * mark it bad, lose it from the datablock table
+							 */
+							(*ll->markblockbad)(ll, db->block);
+							db->block = -1;
+							if(blockindex == server->ndatablocks - 1)
+								server->ndatablocks--;
+							return errmsg;
+						}
+						/*
+						 * page 0 of a data scavenge copy
+						 * mark it bad, restore state (old block)
+						 */
+						(*ll->markblockbad)(ll, db->block);
+						db->block = state.oldblock;
+						return errmsg;
+					}
+					/*
+					 * write error on target block
+					 *
+					 * if it is a replacement (state saved)
+					 *	mark the new block bad, restore state and try again
+					 *
+					 * if it is not replaced (no state saved)
+					 *	replace block, and try again
+					 */
+					if(state.oldblock >= 0) {
+						(*ll->markblockbad)(ll, db->block);
+						db->block = state.oldblock;
+					}
+					else {
+						errmsg = logfsserverreplacedatablock(server, blockindex);
+						if(errmsg)
+							return errmsg;
+					}
+					goto reallocate;
+				}
+				mask = logfsdatapagemask(1, p);
+				db->free &= ~mask;
+				db->dirty |= mask;
+			}
+			/* well, we managed to write the data out */
+			errmsg = logfslogwrite(server, 1, e->qid.path, offset, thistime, now, e->u.file.cvers,
+				muid, nil, &extent.flashaddr);
+			/*
+			 * now we can dispose of the original data block, if any
+			 * this is regardless of whether we succeeded in writing a log message, as
+			 * if this block is not erased, there will be a duplicate
+			 */
+			disposeofoldblock(server, &state);
+		}
+		else {
+			if(thistime > count)
+				thistime = count;
+			errmsg = logfslogwrite(server, 1, e->qid.path, offset, thistime, now, e->u.file.cvers,
+				muid, buf, &extent.flashaddr);
+		}
+		/*
+		 * here if we failed to write the log message
+		 */
+		if(errmsg)
+			return errmsg;
+		if(server->trace > 1)
+			print("logfsserverwrite: %d bytes at flashaddr 0x%.8ux\n", thistime, extent.flashaddr);
+		extent.min = offset;
+		extent.max = offset + thistime;
+		errmsg = zappages(server, e, extent.min, extent.max);
+		if(errmsg)
+			return errmsg;
+		errmsg = logfsextentlistinsert(e->u.file.extent, &extent, nil);
+		if(errmsg)
+			return errmsg;
+		e->muid = muid;
+		e->mtime = now;
+		offset += thistime;	
+		if(e->u.file.length < offset)
+			e->u.file.length = offset;
+		count -= thistime;
+		buf += thistime;
+		e->qid.vers++;
+	}
+	return nil;
+}
--- /dev/null
+++ b/liblogfs/wstat.c
@@ -1,0 +1,245 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "fcall.h"
+#include "local.h"
+
+char *
+logfsserverwstat(LogfsServer *server, u32int fid, uchar *stat, ushort nstat)
+{
+	Fid *f;
+	uchar *p;
+	ushort len;
+	uchar *mep;
+	Qid qid;
+	u32int perm, mtime;
+	uvlong length;
+	char *name, *uname, *gname, *muname;
+	int qiddonttouch, permdonttouch, mtimedonttouch, lengthdonttouch;
+	Entry *e, *parent;
+	LogMessage s;
+	char *cuid, *ngid;
+	Group *eg, *ng;
+	char *cname;
+	char *errmsg;
+	char *nuid;
+
+	if(server->trace > 1)
+		print("logfsserverwstat(%ud, %ud)\n", fid, nstat);
+	if(nstat < 49)
+		return Eshortstat;
+	p  = stat;
+	len = GBIT16(p); p += BIT16SZ;
+	if(len + BIT16SZ  != nstat)
+		return Eshortstat;
+	mep = p + len;
+	p += BIT16SZ + BIT32SZ;		/* skip type and dev */
+	qid.type = *p++;
+	qid.vers = GBIT32(p); p += BIT32SZ;
+	qid.path = GBIT64(p); p += BIT64SZ;
+	perm = GBIT32(p); p += BIT32SZ;
+	p += BIT32SZ;				/* skip atime */
+	mtime = GBIT32(p); p += BIT32SZ;
+	length = GBIT64(p); p+= BIT64SZ;
+	if(!logfsgn(&p, mep, &name) || !logfsgn(&p, mep, &uname)
+		|| !logfsgn(&p, mep, &gname) || !logfsgn(&p, mep, &muname))
+		return Eshortstat;
+	if(p != mep)
+		return Eshortstat;
+	qiddonttouch = qid.type == (uchar)~0 && qid.vers == ~0 && qid.path == ~(uvlong)0;
+	permdonttouch = perm == ~0;
+	mtimedonttouch = mtime == ~0;
+	lengthdonttouch = length == ~(uvlong)0;
+	if(server->trace > 1) {
+		int comma = 0;
+		print("logfsserverwstat(");
+		if(!qiddonttouch) {
+			comma = 1;
+			print("qid=0x%.2ux/%lud/%llud", qid.type, qid.vers, qid.path);
+		}
+		if(!permdonttouch) {
+			if(comma)
+				print(", ");
+			print("perm=0%uo", perm);
+			comma = 1;
+		}
+		if(!mtimedonttouch) {
+			if(comma)
+				print(", ");
+			print("mtime=%ud", mtime);
+			comma = 1;
+		}
+		if(!lengthdonttouch) {
+			if(comma)
+				print(", ");
+			print("length=%llud", length);
+			comma = 1;
+		}
+		if(name != nil) {
+			if(comma)
+				print(", ");
+			print("name=%s", name);
+			comma = 1;
+		}
+		if(uname != nil) {
+			if(comma)
+				print(", ");
+			print("uid=%s", uname);
+			comma = 1;
+		}
+		if(gname != nil) {
+			if(comma)
+				print(", ");
+			print("gid=%s", gname);
+			comma = 1;
+		}
+		if(muname != nil) {
+			if(comma)
+				print(", ");
+			print("muname=%s", muname);
+			comma = 1;
+		}
+		USED(comma);
+		print(")\n");
+	}
+	f = logfsfidmapfindentry(server->fidmap, fid);
+	if(f == nil)
+		return logfsebadfid;
+	e = f->entry;
+	if(e->deadandgone)
+		return Eio;
+	parent = e->parent;
+	if(name) {
+		Entry *oe;
+		if(parent == e)
+			return Eperm;
+		if(!logfsuserpermcheck(server, e->parent, f, DMWRITE))
+			return Eperm;
+		for(oe = parent->u.dir.list; oe; oe = oe->next) {
+			if(oe == e)
+				continue;
+			if(strcmp(oe->name, name) == 0)
+				return Eexist;
+		}
+	}
+	if(!lengthdonttouch) {
+		if(!logfsuserpermcheck(server, e, f, DMWRITE))
+			return Eperm;
+		if(e->qid.type & QTDIR) {
+			if(length != 0)
+				return Eperm;
+		}else if(length != e->u.file.length){
+			/*
+			 * TODO - truncate directory
+			 * TODO - truncate file
+			 */
+			return "wstat -- can't change length";
+		}
+	}
+	cuid = logfsisfindidfromname(server->is, f->uname);
+	/* TODO - change entries to have a group pointer */
+	eg = logfsisfindgroupfromid(server->is, e->uid);
+	if(gname) {
+		gname = logfsisustadd(server->is, gname);
+		if(gname == nil)
+			return Enomem;
+		ngid = logfsisfindidfromname(server->is, gname);
+		if(ngid == nil)
+			return Eunknown;
+	}
+	else
+		ngid = nil;
+	if(uname) {
+		uname = logfsisustadd(server->is, uname);
+		if(uname == nil)
+			return Enomem;
+		nuid = logfsisfindidfromname(server->is, uname);
+		if(nuid == nil)
+			return Eunknown;
+	}
+	else
+		nuid = nil;
+	if(!permdonttouch || !mtimedonttouch) {
+		/*
+		 * same permissions rules - change by owner, or by group leader
+		 */
+		if((server->openflags & LogfsOpenFlagWstatAllow) == 0 &&
+			e->uid != cuid && (eg == nil || !logfsisgroupuidisleader(server->is, eg, cuid)))
+			return Eperm;
+	}
+	if(!permdonttouch){
+		if((perm^e->perm) & DMDIR)
+			return "wstat -- attempt to change directory";
+		if(perm & ~(DMDIR|DMAPPEND|DMEXCL|0777))
+			return Eperm;
+	}
+	if(gname) {
+		int ok;
+		ng = logfsisfindgroupfromid(server->is, ngid);
+		ok = 0;
+		if(e->uid == cuid && logfsisgroupuidismember(server->is, ng, e->uid))
+			ok = 1;
+		if(!ok && eg && logfsisgroupuidisleader(server->is, eg, cuid)
+			&& logfsisgroupuidisleader(server->is, ng, cuid))
+			ok = 1;
+		if(!ok && (server->openflags & LogfsOpenFlagWstatAllow) == 0)
+			return Eperm;
+	}
+	if(!qiddonttouch)
+		return Eperm;
+	if(uname){
+		if((server->openflags & LogfsOpenFlagWstatAllow) == 0)
+			return Eperm;
+	}
+	if(muname)
+		return Eperm;
+	/*
+	 * we can do this
+	 */
+	if(mtimedonttouch && permdonttouch && lengthdonttouch
+		&& name == nil && uname == nil && gname == nil) {
+		/*
+		 * but we aren't doing anything - this is a wstat flush
+		 */
+		return logfsserverflush(server);
+	}
+	if(name) {
+		cname = logfsstrdup(name);
+		if(cname == nil)
+			return Enomem;
+	}
+	else
+		cname = nil;
+	/*
+	 * send the log message
+	 */
+	s.type = LogfsLogTwstat;
+	s.path = e->qid.path;	
+	s.u.wstat.name = cname;
+	s.u.wstat.perm = perm;
+	s.u.wstat.uid = nuid;
+	s.u.wstat.gid = ngid;
+	s.u.wstat.mtime = mtime;
+	s.u.wstat.muid = cuid;
+	errmsg = logfslog(server, 1, &s);
+	if(errmsg) {
+		logfsfreemem(cname);
+		return errmsg;
+	}
+	if(!mtimedonttouch)
+		e->mtime = mtime;
+	if(!permdonttouch)
+		e->perm = (e->perm & DMDIR) | perm;
+	if(!lengthdonttouch) {
+		/* TODO */
+	}
+	if(name) {
+		logfsfreemem(e->name);
+		e->name = cname;
+	}
+	if(uname)
+		e->uid = nuid;
+	if(ngid)
+		e->gid = ngid;
+	return nil;
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-DragonFly.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	setfsr(0);	/* Clear pending exceptions */
+	setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-FreeBSD.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	setfsr(0);	/* Clear pending exceptions */
+	setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Inferno.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	ulong fcr9 = FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL;
+	setfcr(fcr9);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Irix.c
@@ -1,0 +1,102 @@
+/* Load programs with -lfpe. See man pages for fpc and /usr/include/sigfpe.h, sys/fpu.h. */
+#include <stdlib.h>
+#include <sigfpe.h>
+#include <sys/fpu.h>
+typedef unsigned int ulong;
+#include "mathi.h"
+
+/*
+ * Irix does not permit a use handled SIGFPE since the floating point unit
+ * cannot be IEEE754 compliant without some software, so we must vector using
+ * the library
+ */
+extern	void trapFPE(unsigned exception[5], int value[2]);
+
+void
+FPinit(void)
+{
+	union fpc_csr csr;
+	int i;
+	for(i=1; i<=4; i++) {
+		sigfpe_[i].repls = _USER_DETERMINED;
+		sigfpe_[i].abort = 2;
+	}
+	handle_sigfpes(_ON,
+			_EN_UNDERFL|_EN_OVERFL|_EN_DIVZERO|_EN_INVALID,
+			trapFPE,
+			_ABORT_ON_ERROR, 0);
+}
+
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0;
+	union fpc_csr csr;
+	csr.fc_word = get_fpc_csr();
+	if(csr.fc_struct.se_inexact) fsr |= INEX;
+	if(csr.fc_struct.se_overflow) fsr |= OVFL;
+	if(csr.fc_struct.se_underflow) fsr |= UNFL;
+	if(csr.fc_struct.se_divide0) fsr |= ZDIV;
+	if(csr.fc_struct.se_invalid) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong old = getFPstatus();
+	union fpc_csr csr;
+	csr.fc_word = get_fpc_csr();
+	fsr = (fsr&mask) | (old&~mask);
+	csr.fc_struct.se_inexact = (fsr&INEX)?1:0;
+	csr.fc_struct.se_overflow = (fsr&OVFL)?1:0;
+	csr.fc_struct.se_underflow = (fsr&UNFL)?1:0;
+	csr.fc_struct.se_divide0 = (fsr&ZDIV)?1:0;
+	csr.fc_struct.se_invalid = (fsr&INVAL)?1:0;
+	set_fpc_csr(csr.fc_word);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0;
+	union fpc_csr csr;
+	double junk = fabs(1.); /* avoid bug mentioned in sigfpes man page [ehg] */
+	csr.fc_word = get_fpc_csr();
+	switch(csr.fc_struct.rounding_mode){
+		case ROUND_TO_NEAREST:		fcr = RND_NR; break;
+		case ROUND_TO_MINUS_INFINITY:	fcr = RND_NINF; break;
+		case ROUND_TO_PLUS_INFINITY:	fcr = RND_PINF; break;
+		case ROUND_TO_ZERO:		fcr = RND_Z; break;
+	}
+	if(csr.fc_struct.en_inexact) fcr |= INEX;
+	if(csr.fc_struct.en_overflow) fcr |= OVFL;
+	if(csr.fc_struct.en_underflow) fcr |= UNFL;
+	if(csr.fc_struct.en_divide0) fcr |= ZDIV;
+	if(csr.fc_struct.en_invalid) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong old = getFPcontrol();
+	union fpc_csr csr;
+	csr.fc_word = get_fpc_csr();
+	fcr = (fcr&mask) | (old&~mask);
+	csr.fc_struct.en_inexact = (fcr&INEX)?1:0;
+	csr.fc_struct.en_overflow = (fcr&OVFL)?1:0;
+	csr.fc_struct.en_underflow = (fcr&UNFL)?1:0;
+	csr.fc_struct.en_divide0 = (fcr&ZDIV)?1:0;
+	csr.fc_struct.en_invalid = (fcr&INVAL)?1:0;
+	switch(fcr&RND_MASK){
+		case RND_NR:	csr.fc_struct.rounding_mode = ROUND_TO_NEAREST; break;
+		case RND_NINF:	csr.fc_struct.rounding_mode = ROUND_TO_MINUS_INFINITY; break;
+		case RND_PINF:	csr.fc_struct.rounding_mode = ROUND_TO_PLUS_INFINITY; break;
+		case RND_Z:	csr.fc_struct.rounding_mode = ROUND_TO_ZERO; break;
+	}
+	set_fpc_csr(csr.fc_word);
+	return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-Linux.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	setfsr(0);	/* Clear pending exceptions */
+	setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-MacOSX.c
@@ -1,0 +1,79 @@
+#include "lib9.h"
+#include "mathi.h"
+
+#include <stdio.h>
+
+void
+FPinit(void)
+{
+	ulong fcr9 = FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL;
+	setfsr(0);	/* Clear pending exceptions */
+	setfcr(fcr9);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-NetBSD.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	setfsr(0);	/* Clear pending exceptions */
+	setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Nt.c
@@ -1,0 +1,82 @@
+#include "lib9.h"
+#include <float.h>
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	_controlfp(_EM_INEXACT,_MCW_EM);	// abort on underflow, etc.
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr32 = _statusfp();
+	if(fsr32&_SW_INEXACT) fsr |= INEX;
+	if(fsr32&_SW_OVERFLOW) fsr |= OVFL;
+	if(fsr32&_SW_UNDERFLOW) fsr |= UNFL;
+	if(fsr32&_SW_ZERODIVIDE) fsr |= ZDIV;
+	if(fsr32&_SW_INVALID) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr!=old){
+		_clearfp();
+		if(fsr){
+			ulong fcr = _controlfp(0,0);
+			double x = 1., y = 1e200, z = 0.;
+			_controlfp(_MCW_EM,_MCW_EM);
+			if(fsr&INEX) z = x + y;
+			if(fsr&OVFL) z = y*y;
+			if(fsr&UNFL) z = (x/y)/y;
+			if(fsr&ZDIV) z = x/z;
+			if(fsr&INVAL) z = z/z;
+			_controlfp(fcr,_MCW_EM);
+		}
+	}
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr, fcr32 = _controlfp(0,0);
+	switch(fcr32&_MCW_RC){
+		case _RC_NEAR:	fcr = RND_NR; break;
+		case _RC_DOWN:	fcr = RND_NINF; break;
+		case _RC_UP:	fcr = RND_PINF; break;
+		case _RC_CHOP:	fcr = RND_Z; break;
+	}
+	if(!(fcr32&_EM_INEXACT)) fcr |= INEX;
+	if(!(fcr32&_EM_OVERFLOW)) fcr |= OVFL;
+	if(!(fcr32&_EM_UNDERFLOW)) fcr |= UNFL;
+	if(!(fcr32&_EM_ZERODIVIDE)) fcr |= ZDIV;
+	if(!(fcr32&_EM_INVALID)) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong old = getFPcontrol();
+	ulong fcr32 = _MCW_EM, mask32 = _MCW_RC|_MCW_EM;
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr32 ^= _EM_INEXACT;
+	if(fcr&OVFL) fcr32 ^= _EM_OVERFLOW;
+	if(fcr&UNFL) fcr32 ^= _EM_UNDERFLOW;
+	if(fcr&ZDIV) fcr32 ^= _EM_ZERODIVIDE;
+	if(fcr&INVAL) fcr32 ^= _EM_INVALID;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr32 |= _RC_NEAR; break;
+		case RND_NINF:	fcr32 |= _RC_DOWN; break;
+		case RND_PINF:	fcr32 |= _RC_UP; break;
+		case RND_Z:	fcr32 |= _RC_CHOP; break;
+	}
+	_controlfp(fcr32,mask32);
+	return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-OpenBSD.c
@@ -1,0 +1,77 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	setfsr(0);	/* Clear pending exceptions */
+	setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
+
--- /dev/null
+++ b/libmath/FPcontrol-Plan9.c
@@ -1,0 +1,1 @@
+#include "FPcontrol-Inferno.c"
--- /dev/null
+++ b/libmath/FPcontrol-Solaris.c
@@ -1,0 +1,99 @@
+#include <ieeefp.h>
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	fpsetsticky(0);		/* Clear pending exceptions */
+	fpsetround(FP_RN);
+	fpsetmask(FP_X_INV|FP_X_DZ|FP_X_UFL|FP_X_OFL);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0;
+	fp_except fsr9=fpgetsticky();
+	if(fsr9&FP_X_IMP) fsr |= INEX;
+	if(fsr9&FP_X_OFL) fsr |= OVFL;
+	if(fsr9&FP_X_UFL) fsr |= UNFL;
+	if(fsr9&FP_X_DZ) fsr |= ZDIV;
+	if(fsr9&FP_X_INV) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FP_X_IMP;
+	if(fsr&OVFL) fsr9 |= FP_X_OFL;
+	if(fsr&UNFL) fsr9 |= FP_X_UFL;
+	if(fsr&ZDIV) fsr9 |= FP_X_DZ;
+	if(fsr&INVAL) fsr9 |= FP_X_INV;
+	/* fpsetmask(fsr9); */
+	fpsetsticky(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0;
+	fp_except fpc = fpgetmask();
+	fp_rnd fpround = fpgetround();
+
+	if(fpc&FP_X_INV)
+		fcr|=INVAL;
+	if(fpc&FP_X_DZ)
+		fcr|=ZDIV;
+	if(fpc&FP_X_OFL)
+		fcr|=OVFL;
+	if(fpc&FP_X_UFL)
+		fcr|=UNFL;
+	if(fpc&FP_X_IMP)
+		fcr|=INEX;
+	switch(fpround){
+	case FP_RZ:
+		fcr|=RND_Z;
+		break;
+    	case FP_RN:
+		fcr|=RND_NINF;
+		break;
+    	case FP_RP:
+		fcr|=RND_PINF;
+		break;
+    	case FP_RM:
+		fcr|=RND_NR;
+	}
+	return fcr;
+}
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	fp_except fc=0;
+	fp_rnd round;
+	ulong old = getFPcontrol();
+	ulong changed = mask&(fcr^old);
+	fcr = (fcr&mask) | (old&~mask);
+
+	if(fcr&INEX) fc |= FP_X_IMP;
+	if(fcr&OVFL) fc |= FP_X_OFL;
+	if(fcr&UNFL) fc |= FP_X_UFL;
+	if(fcr&ZDIV) fc |= FP_X_DZ;
+	if(fcr&INVAL) fc |= FP_X_INV;
+
+	switch(fcr&RND_MASK){
+		case RND_NR:    round |= FP_RM; break;
+		case RND_NINF:  round |= FP_RN; break;
+		case RND_PINF:  round |= FP_RP; break;
+		case RND_Z:     round |= FP_RZ; break;
+	}
+
+	fpsetround(round);
+	fpsetmask(fc);
+	return(old&mask);
+}
--- /dev/null
+++ b/libmath/FPcontrol-Unixware.c
@@ -1,0 +1,76 @@
+#include "lib9.h"
+#include "mathi.h"
+
+void
+FPinit(void)
+{
+	setfsr(0);	/* Clear pending exceptions */
+	setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPUNFL|FPOVFL);
+}
+
+ulong
+getFPstatus(void)
+{
+	ulong fsr = 0, fsr9 = getfsr();
+	/* on specific machines, could be table lookup */
+	if(fsr9&FPAINEX) fsr |= INEX;
+	if(fsr9&FPAOVFL) fsr |= OVFL;
+	if(fsr9&FPAUNFL) fsr |= UNFL;
+	if(fsr9&FPAZDIV) fsr |= ZDIV;
+	if(fsr9&FPAINVAL) fsr |= INVAL;
+	return fsr;
+}
+
+ulong
+FPstatus(ulong fsr, ulong mask)
+{
+	ulong fsr9 = 0;
+	ulong old = getFPstatus();
+	fsr = (fsr&mask) | (old&~mask);
+	if(fsr&INEX) fsr9 |= FPAINEX;
+	if(fsr&OVFL) fsr9 |= FPAOVFL;
+	if(fsr&UNFL) fsr9 |= FPAUNFL;
+	if(fsr&ZDIV) fsr9 |= FPAZDIV;
+	if(fsr&INVAL) fsr9 |= FPAINVAL;
+	setfsr(fsr9);
+	return(old&mask);
+}
+
+ulong
+getFPcontrol(void)
+{
+	ulong fcr = 0, fcr9 = getfcr();
+	switch(fcr9&FPRMASK){
+		case FPRNR:	fcr = RND_NR; break;
+		case FPRNINF:	fcr = RND_NINF; break;
+		case FPRPINF:	fcr = RND_PINF; break;
+		case FPRZ:	fcr = RND_Z; break;
+	}
+	if(fcr9&FPINEX) fcr |= INEX;
+	if(fcr9&FPOVFL) fcr |= OVFL;
+	if(fcr9&FPUNFL) fcr |= UNFL;
+	if(fcr9&FPZDIV) fcr |= ZDIV;
+	if(fcr9&FPINVAL) fcr |= INVAL;
+	return fcr;
+}
+
+ulong
+FPcontrol(ulong fcr, ulong mask)
+{
+	ulong fcr9 = FPPDBL;
+	ulong old = getFPcontrol();
+	fcr = (fcr&mask) | (old&~mask);
+	if(fcr&INEX) fcr9 |= FPINEX;
+	if(fcr&OVFL) fcr9 |= FPOVFL;
+	if(fcr&UNFL) fcr9 |= FPUNFL;
+	if(fcr&ZDIV) fcr9 |= FPZDIV;
+	if(fcr&INVAL) fcr9 |= FPINVAL;
+	switch(fcr&RND_MASK){
+		case RND_NR:	fcr9 |= FPRNR; break;
+		case RND_NINF:	fcr9 |= FPRNINF; break;
+		case RND_PINF:	fcr9 |= FPRPINF; break;
+		case RND_Z:	fcr9 |= FPRZ; break;
+	}
+	setfcr(fcr9);
+	return(old&mask);
+}
--- /dev/null
+++ b/libmath/NOTICE
@@ -1,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/libmath/bin/fdlibm-stubs
@@ -1,0 +1,71 @@
+echo '#include "real.h"' > real.c
+
+for(i in getFPcontrol getFPstatus){
+	echo 'void'
+	echo 'Real_'$i'(void *fp)'
+	echo '{'
+	echo '	F_Real_'$i' *f;'
+	echo ''
+	echo '	f = fp;'
+	echo ''
+	echo '	*f->ret = '$i'(f->x);'
+	echo '}'
+	echo ''
+} >> real.c
+
+for(i in finite ilogb isnan acos acosh asin asinh atan atanh cbrt ceil cos cosh erf erfc exp expm1 fabs floor j0 j1 log log10 log1p rint sin sinh sqrt tan tanh y0 y1){
+	echo 'void'
+	echo 'Real_'$i'(void *fp)'
+	echo '{'
+	echo '	F_Real_'$i' *f;'
+	echo ''
+	echo '	f = fp;'
+	echo ''
+	echo '	*f->ret = '$i'(f->x);'
+	echo '}'
+	echo ''
+} >> real.c
+
+for(i in fdim fmax fmin fmod hypot nextafter pow){
+	echo 'void'
+	echo 'Real_'$i'(void *fp)'
+	echo '{'
+	echo '	F_Real_'$i' *f;'
+	echo ''
+	echo '	f = fp;'
+	echo ''
+	echo '	*f->ret = '$i'(f->x, f->x);'
+	echo '}'
+	echo ''
+} >> real.c
+
+
+FPcontrol	fn(r, mask: int) of int;
+FPstatus	fn(r, mask: int) of int;
+atan2		fn(y, x: real) of real;
+copysign	fn(x, s: real) of real;
+jn		fn(n: int; x: real) of real;
+lgamma		fn(x: real) of (int,real);
+modf		fn(x: real) of (int,real);
+pow10		fn(p: int) of real;
+remainder	fn(x, p: real) of real;
+scalbn		fn(x: real; n: int) of real;
+yn		fn(n: int; x: real) of real;
+
+dot		fn(x, y: array of real) of real;
+iamax		fn(x: array of real) of int;
+norm1, norm2	fn(x: array of real) of real;
+gemm		fn(transa, transb: byte; m, n, k: int; alpha: real; a: array of real; ai0, aj0, lda: int; b: array of real; bi0, bj0, ldb: int; beta: real; c: array of real; ci0, cj0, ldc: int);
+
+for(i in FPcontrol FPstatus atan2 copysign jn lgamma modf pow10 remainder scalbn yn  dot iamax norm1, norm2 gemm){
+	echo 'void'
+	echo 'Real_'$i'(void *fp)'
+	echo '{'
+	echo '	F_Real_'$i' *f;'
+	echo ''
+	echo '	f = fp;'
+	echo ''
+	echo '	*f->ret = '$i'(f->x, f->x);'
+	echo '}'
+	echo ''
+} >> real.c
--- /dev/null
+++ b/libmath/bin/unif_dtoa
@@ -1,0 +1,37 @@
+#!/bin/rc
+test -d /netlib/fp || 9fs netlib
+test -d /n/hati/usr/ehg || 9fs hati
+
+echo '/* derived from /netlib/fp/dtoa.c assuming IEEE, Standard C */' > dtoa.c
+echo '/* kudos to dmg@research.att.com, gripes to ehg@research.att.com */' >> dtoa.c
+echo '#include "lib9.h"' >> dtoa.c
+
+sed 's/^#if defined.IEEE_8087. . defined.IEEE_MC68k.*!= 1/#ifndef IEEE_Arith/
+	s/^#if defined.IEEE_8087. . defined.IEEE_MC68k.*/#ifdef IEEE_Arith/' \
+		/netlib/fp/dtoa.c > /n/hati/usr/ehg/xxx.c
+# undefine __STDC__ because we can't depend on HUGE_VAL
+rx hati 'unifdef -UIBM -UVAX -UKR_headers -U__cplusplus -U__STDC__ -UDEBUG \
+	-UBad_float_h -UJust_16 -UInaccurate_Divide -UROUND_BIASED \
+	-URND_PRODQUOT -DNo_leftright -UCheck_FLT_ROUNDS -D__MATH_H__ \
+	-DUnsigned_Shifts -DMALLOC=Malloc -DCONST=const \
+	-DPack_32 -DIEEE_Arith xxx.c | cb -s' > xxx.c
+sam -d >> dtoa.c >[2] err <<!
+e xxx.c
+1,/include "float\.h"\n/d
+/The following definition of Storeinc/+-;/^#endif\n/d
+/^#define IEEE_Arith\n/+-d
+/When Pack_32 is not defined/+-;/^\n/d
+,s/\n\n\n+/\n\n/g
+,s/\n\(/(/g
+,s/\\\(/\\\n(/g
+,x/IEEE_8087/ c/__LITTLE_ENDIAN/
+,x/^#if / c/#ifdef /
+,x g/errno/d
+,x/MALLOC/ c/malloc/
+,x/Long/ c/long/
+,x/CONST/ c/const/
+w
+q
+!
+cat xxx.c >> dtoa.c
+rm xxx.c
--- /dev/null
+++ b/libmath/bin/unif_fdlibm
@@ -1,0 +1,20 @@
+#!/bin/rc
+test -d /netlib/fdlibm || 9fs netlib
+test -d /n/hati/usr/ehg || 9fs hati
+
+echo '/* derived from /netlib/fdlibm */' > $1
+if (~ $1 fdlibm.h) echo '#include "lib9.h"' >> $1
+
+cp /netlib/fdlibm/$1 /n/hati/usr/ehg/xxx.c
+rx hati 'unifdef -D__STDC__ -D_IEEE_LIBM -D_SCALB_INT -U__NEWVALID xxx.c' > xxx.c
+> /n/hati/usr/ehg/xxx.c
+sam -d >> $1 >[2] err <<!
+e xxx.c
+/extern int signgam;/,/#define	PLOSS/+d
+,x/HUGE_VAL/ c/DBL_MAX/
+,x/huge/ c/Huge/
+w
+q
+!
+cat xxx.c >> $1
+rm xxx.c
--- /dev/null
+++ b/libmath/blas.c
@@ -1,0 +1,62 @@
+#include "lib9.h"
+#include "mathi.h"
+
+double
+dot(int n, double *x, double *y)
+{
+	double	sum = 0;
+	if (n <= 0) 
+		return 0;
+	while (n--) {
+		sum += *x++ * *y++;
+	}
+	return sum;
+}
+
+
+int
+iamax(int n, double *x)
+{
+	int	i, m;
+	double	xm, a;
+	if (n <= 0) 
+		return 0;
+	m = 0;
+	xm = fabs(*x);
+	for (i = 1; i < n; i++) {
+		a = fabs(*++x);
+		if (xm < a) {
+			m = i;
+			xm = a;
+		}
+	}
+	return m;
+}
+
+
+double
+norm1(int n, double *x)
+{
+	double	sum = 0;
+	if (n <= 0) 
+		return 0;
+	while (n--) {
+		sum += fabs(*x);
+		x++;
+	}
+	return sum;
+}
+
+
+double
+norm2(int n, double *x)
+{
+	double	sum = 0;
+	if (n <= 0) 
+		return 0;
+	while (n--) {
+		sum += *x * *x;
+		x++;
+	}
+	return sqrt(sum);
+}
--- /dev/null
+++ b/libmath/dtoa.c
@@ -1,0 +1,1816 @@
+/* derived from /netlib/fp/dtoa.c assuming IEEE, Standard C */
+/* kudos to dmg@bell-labs.com, gripes to ehg@bell-labs.com */
+#include "lib9.h"
+
+#ifdef __APPLE__
+#pragma clang diagnostic ignored "-Wlogical-op-parentheses"
+#pragma clang diagnostic ignored "-Wparentheses"
+#endif
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+
+/* let's provide reasonable defaults for usual implementation of IEEE f.p. */
+#ifndef DBL_DIG
+#define DBL_DIG		15
+#endif
+#ifndef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP	308
+#endif
+#ifndef DBL_MAX_EXP
+#define DBL_MAX_EXP	1024
+#endif
+#ifndef FLT_RADIX
+#define FLT_RADIX	2
+#endif
+#ifndef FLT_ROUNDS
+#define FLT_ROUNDS 1
+#endif
+#ifndef Storeinc
+#define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+#endif
+
+#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000;
+
+#ifdef USE_FPdbleword
+#define word0(x) ((FPdbleword*)&x)->hi
+#define word1(x) ((FPdbleword*)&x)->lo
+#else
+#ifdef __LITTLE_ENDIAN
+#define word0(x) ((unsigned  long *)&x)[1]
+#define word1(x) ((unsigned  long *)&x)[0]
+#else
+#define word0(x) ((unsigned  long *)&x)[0]
+#define word1(x) ((unsigned  long *)&x)[1]
+#endif
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#define Infinite(x) (word0(x) == 0x7ff00000) /* sufficient test for here */
+#define Avoid_Underflow
+
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#define Kmax 15
+
+struct
+Bigint {
+	struct Bigint *next;
+	int	k, maxwds, sign, wds;
+	unsigned  long x[1];
+};
+
+typedef struct Bigint Bigint;
+
+static Bigint *freelist[Kmax+1];
+
+static Bigint *
+Balloc(int k)
+{
+	int	x;
+	Bigint * rv;
+
+	ACQUIRE_DTOA_LOCK(0);
+	if (rv = freelist[k]) {
+		freelist[k] = rv->next;
+	} else {
+		x = 1 << k;
+		rv = (Bigint * )malloc(sizeof(Bigint) + (x - 1) * sizeof(unsigned  long));
+		if(rv == nil)
+			return nil;
+		rv->k = k;
+		rv->maxwds = x;
+	}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+}
+
+static void
+Bfree(Bigint *v)
+{
+	if (v) {
+		ACQUIRE_DTOA_LOCK(0);
+		v->next = freelist[v->k];
+		freelist[v->k] = v;
+		FREE_DTOA_LOCK(0);
+	}
+}
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(long) + 2*sizeof(int))
+
+static Bigint *
+multadd(Bigint *b, int m, int a)	/* multiply by m and add a */
+{
+	int	i, wds;
+	unsigned  long * x, y;
+	unsigned  long xi, z;
+	Bigint * b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	do {
+		xi = *x;
+		y = (xi & 0xffff) * m + a;
+		z = (xi >> 16) * m + (y >> 16);
+		a = (int)(z >> 16);
+		*x++ = (z << 16) + (y & 0xffff);
+	} while (++i < wds);
+	if (a) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k + 1);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+		}
+		b->x[wds++] = a;
+		b->wds = wds;
+	}
+	return b;
+}
+
+static Bigint *
+s2b(const char *s, int nd0, int nd, unsigned  long y9)
+{
+	Bigint * b;
+	int	i, k;
+	long x, y;
+
+	x = (nd + 8) / 9;
+	for (k = 0, y = 1; x > y; y <<= 1, k++) 
+		;
+	b = Balloc(k);
+	b->x[0] = y9;
+	b->wds = 1;
+
+	i = 9;
+	if (9 < nd0) {
+		s += 9;
+		do 
+			b = multadd(b, 10, *s++ - '0');
+		while (++i < nd0);
+		s++;
+	} else
+		s += 10;
+	for (; i < nd; i++)
+		b = multadd(b, 10, *s++ - '0');
+	return b;
+}
+
+static int	
+hi0bits(register unsigned  long x)
+{
+	register int	k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+	}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+	}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+	}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+	}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+	}
+	return k;
+}
+
+static int	
+lo0bits(unsigned  long *y)
+{
+	register int	k;
+	register unsigned  long x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+		}
+		*y = x >> 2;
+		return 2;
+	}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+	}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+	}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+	}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+	}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x & 1)
+			return 32;
+	}
+	*y = x;
+	return k;
+}
+
+static Bigint *
+i2b(int i)
+{
+	Bigint * b;
+
+	b = Balloc(1);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+}
+
+static Bigint *
+mult(Bigint *a, Bigint *b)
+{
+	Bigint * c;
+	int	k, wa, wb, wc;
+	unsigned  long carry, y, z;
+	unsigned  long * x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	unsigned  long z2;
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+	}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	for (x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+	for (; xb < xbe; xb++, xc0++) {
+		if (y = *xb & 0xffff) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+			} while (x < xae);
+			*xc = carry;
+		}
+		if (y = *xb >> 16) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+			} while (x < xae);
+			*xc = z2;
+		}
+	}
+	for (xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) 
+		;
+	c->wds = wc;
+	return c;
+}
+
+static Bigint *p5s;
+
+static Bigint *
+pow5mult(Bigint *b, int k)
+{
+	Bigint * b1, *p5, *p51;
+	int	i;
+	static int	p05[3] = { 
+		5, 25, 125 	};
+
+	if (i = k & 3)
+		b = multadd(b, p05[i-1], 0);
+
+	if (!(k >>= 2))
+		return b;
+	if (!(p5 = p5s)) {
+		/* first time */
+		ACQUIRE_DTOA_LOCK(1);
+		if (!(p5 = p5s)) {
+			p5 = p5s = i2b(625);
+			p5->next = 0;
+		}
+		FREE_DTOA_LOCK(1);
+	}
+	for (; ; ) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			Bfree(b);
+			b = b1;
+		}
+		if (!(k >>= 1))
+			break;
+		if (!(p51 = p5->next)) {
+			ACQUIRE_DTOA_LOCK(1);
+			if (!(p51 = p5->next)) {
+				p51 = p5->next = mult(p5, p5);
+				p51->next = 0;
+			}
+			FREE_DTOA_LOCK(1);
+		}
+		p5 = p51;
+	}
+	return b;
+}
+
+static Bigint *
+lshift(Bigint *b, int k)
+{
+	int	i, k1, n, n1;
+	Bigint * b1;
+	unsigned  long * x, *x1, *xe, z;
+
+	n = k >> 5;
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for (i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	x1 = b1->x;
+	for (i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+	if (k &= 0x1f) {
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+		} while (x < xe);
+		if (*x1 = z)
+			++n1;
+	} else 
+		do
+			*x1++ = *x++;
+		while (x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+}
+
+static int	
+cmp(Bigint *a, Bigint *b)
+{
+	unsigned  long * xa, *xa0, *xb, *xb0;
+	int	i, j;
+
+	i = a->wds;
+	j = b->wds;
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for (; ; ) {
+		if (*--xa != *--xb)
+			return * xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+	}
+	return 0;
+}
+
+static Bigint *
+diff(Bigint *a, Bigint *b)
+{
+	Bigint * c;
+	int	i, wa, wb;
+	long borrow, y;	/* We need signed shifts here. */
+	unsigned  long * xa, *xae, *xb, *xbe, *xc;
+	long z;
+
+	i = cmp(a, b);
+	if (!i) {
+		c = Balloc(0);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+	}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+	} else
+		i = 0;
+	c = Balloc(a->k);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) + borrow;
+		borrow = y >> 16;
+		Sign_Extend(borrow, y);
+		z = (*xa++ >> 16) - (*xb++ >> 16) + borrow;
+		borrow = z >> 16;
+		Sign_Extend(borrow, z);
+		Storeinc(xc, z, y);
+	} while (xb < xbe);
+	while (xa < xae) {
+		y = (*xa & 0xffff) + borrow;
+		borrow = y >> 16;
+		Sign_Extend(borrow, y);
+		z = (*xa++ >> 16) + borrow;
+		borrow = z >> 16;
+		Sign_Extend(borrow, z);
+		Storeinc(xc, z, y);
+	}
+	while (!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+}
+
+static double	
+ulp(double x)
+{
+	register long L;
+	double	a;
+
+	L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1;
+#ifndef Sudden_Underflow
+	if (L > 0) {
+#endif
+		word0(a) = L;
+		word1(a) = 0;
+#ifndef Sudden_Underflow
+	} else {
+		L = -L >> Exp_shift;
+		if (L < Exp_shift) {
+			word0(a) = 0x80000 >> L;
+			word1(a) = 0;
+		} else {
+			word0(a) = 0;
+			L -= Exp_shift;
+			word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+		}
+	}
+#endif
+	return a;
+}
+
+static double	
+b2d(Bigint *a, int *e)
+{
+	unsigned  long * xa, *xa0, w, y, z;
+	int	k;
+	double	d;
+#define d0 word0(d)
+#define d1 word1(d)
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+	k = hi0bits(y);
+	*e = 32 - k;
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> Ebits - k;
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << (32 - Ebits) + k | w >> Ebits - k;
+		goto ret_d;
+	}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> 32 - k;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> 32 - k;
+	} else {
+		d0 = Exp_1 | y;
+		d1 = z;
+	}
+ret_d:
+#undef d0
+#undef d1
+	return d;
+}
+
+static Bigint *
+d2b(double d, int *e, int *bits)
+{
+	Bigint * b;
+	int	de, i, k;
+	unsigned  long * x, y, z;
+#define d0 word0(d)
+#define d1 word1(d)
+
+	b = Balloc(1);
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+	z |= Exp_msk11;
+#else
+	if (de = (int)(d0 >> Exp_shift))
+		z |= Exp_msk1;
+#endif
+	if (y = d1) {
+		if (k = lo0bits(&y)) {
+			x[0] = y | z << 32 - k;
+			z >>= k;
+		} else
+			x[0] = y;
+		i = b->wds = (x[1] = z) ? 2 : 1;
+	} else {
+		k = lo0bits(&z);
+		x[0] = z;
+		i = b->wds = 1;
+		k += 32;
+	}
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+		*e = de - Bias - (P - 1) + k;
+		*bits = P - k;
+#ifndef Sudden_Underflow
+	} else {
+		*e = de - Bias - (P - 1) + 1 + k;
+		*bits = 32 * i - hi0bits(x[i-1]);
+	}
+#endif
+	return b;
+}
+
+#undef d0
+#undef d1
+
+static double	
+ratio(Bigint *a, Bigint *b)
+{
+	double	da, db;
+	int	k, ka, kb;
+
+	da = b2d(a, &ka);
+	db = b2d(b, &kb);
+	k = ka - kb + 32 * (a->wds - b->wds);
+	if (k > 0)
+		word0(da) += k * Exp_msk1;
+	else {
+		k = -k;
+		word0(db) += k * Exp_msk1;
+	}
+	return da / db;
+}
+
+static const double
+tens[] = {
+	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+	1e20, 1e21, 1e22
+};
+
+static const double
+bigtens[] = { 
+	1e16, 1e32, 1e64, 1e128, 1e256 };
+
+static const double tinytens[] = { 
+	1e-16, 1e-32, 1e-64, 1e-128,
+	9007199254740992.e-256
+};
+
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+
+#define NAN_WORD0 0x7ff80000
+
+#define NAN_WORD1 0
+
+static int	
+match(const char **sp, char *t)
+{
+	int	c, d;
+	const char * s = *sp;
+
+	while (d = *t++) {
+		if ((c = *++s) >= 'A' && c <= 'Z')
+			c += 'a' - 'A';
+		if (c != d)
+			return 0;
+	}
+	*sp = s + 1;
+	return 1;
+}
+
+double
+strtod(const char *s00, char **se)
+{
+	int	scale;
+	int	bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+	e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+	const char * s, *s0, *s1;
+	double	aadj, aadj1, adj, rv, rv0;
+	long L;
+	unsigned  long y, z;
+	Bigint * bb, *bb1, *bd, *bd0, *bs, *delta;
+	sign = nz0 = nz = 0;
+	rv = 0.;
+	for (s = s00; ; s++) 
+		switch (*s) {
+		case '-':
+			sign = 1;
+			/* no break */
+		case '+':
+			if (*++s)
+				goto break2;
+			/* no break */
+		case 0:
+			s = s00;
+			goto ret;
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			continue;
+		default:
+			goto break2;
+		}
+break2:
+	if (*s == '0') {
+		nz0 = 1;
+		while (*++s == '0') 
+			;
+		if (!*s)
+			goto ret;
+	}
+	s0 = s;
+	y = z = 0;
+	for (nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+		if (nd < 9)
+			y = 10 * y + c - '0';
+		else if (nd < 16)
+			z = 10 * z + c - '0';
+	nd0 = nd;
+	if (c == '.') {
+		c = *++s;
+		if (!nd) {
+			for (; c == '0'; c = *++s)
+				nz++;
+			if (c > '0' && c <= '9') {
+				s0 = s;
+				nf += nz;
+				nz = 0;
+				goto have_dig;
+			}
+			goto dig_done;
+		}
+		for (; c >= '0' && c <= '9'; c = *++s) {
+have_dig:
+			nz++;
+			if (c -= '0') {
+				nf += nz;
+				for (i = 1; i < nz; i++)
+					if (nd++ < 9)
+						y *= 10;
+					else if (nd <= DBL_DIG + 1)
+						z *= 10;
+				if (nd++ < 9)
+					y = 10 * y + c;
+				else if (nd <= DBL_DIG + 1)
+					z = 10 * z + c;
+				nz = 0;
+			}
+		}
+	}
+dig_done:
+	e = 0;
+	if (c == 'e' || c == 'E') {
+		if (!nd && !nz && !nz0) {
+			s = s00;
+			goto ret;
+		}
+		s00 = s;
+		esign = 0;
+		switch (c = *++s) {
+		case '-':
+			esign = 1;
+		case '+':
+			c = *++s;
+		}
+		if (c >= '0' && c <= '9') {
+			while (c == '0')
+				c = *++s;
+			if (c > '0' && c <= '9') {
+				L = c - '0';
+				s1 = s;
+				while ((c = *++s) >= '0' && c <= '9')
+					L = 10 * L + c - '0';
+				if (s - s1 > 8 || L > 19999)
+					/* Avoid confusion from exponents
+					 * so large that e might overflow.
+					 */
+					e = 19999; /* safe for 16 bit ints */
+				else
+					e = (int)L;
+				if (esign)
+					e = -e;
+			} else
+				e = 0;
+		} else
+			s = s00;
+	}
+	if (!nd) {
+		if (!nz && !nz0) {
+			/* Check for Nan and Infinity */
+			switch (c) {
+			case 'i':
+			case 'I':
+				if (match(&s, "nfinity")) {
+					word0(rv) = 0x7ff00000;
+					word1(rv) = 0;
+					goto ret;
+				}
+				break;
+			case 'n':
+			case 'N':
+				if (match(&s, "an")) {
+					word0(rv) = NAN_WORD0;
+					word1(rv) = NAN_WORD1;
+					goto ret;
+				}
+			}
+			s = s00;
+		}
+		goto ret;
+	}
+	e1 = e -= nf;
+
+	/* Now we have nd0 digits, starting at s0, followed by a
+	 * decimal point, followed by nd-nd0 digits.  The number we're
+	 * after is the integer represented by those digits times
+	 * 10**e */
+
+	if (!nd0)
+		nd0 = nd;
+	k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+	rv = y;
+	if (k > 9)
+		rv = tens[k - 9] * rv + z;
+	bd0 = 0;
+	if (nd <= DBL_DIG
+	     && FLT_ROUNDS == 1
+	    ) {
+		if (!e)
+			goto ret;
+		if (e > 0) {
+			if (e <= Ten_pmax) {
+				/* rv = */ rounded_product(rv, tens[e]);
+				goto ret;
+			}
+			i = DBL_DIG - nd;
+			if (e <= Ten_pmax + i) {
+				/* A fancier test would sometimes let us do
+				 * this for larger i values.
+				 */
+				e -= i;
+				rv *= tens[i];
+				/* rv = */ rounded_product(rv, tens[e]);
+				goto ret;
+			}
+		} else if (e >= -Ten_pmax) {
+			/* rv = */ rounded_quotient(rv, tens[-e]);
+			goto ret;
+		}
+	}
+	e1 += nd - k;
+
+	scale = 0;
+
+	/* Get starting approximation = rv * 10**e1 */
+
+	if (e1 > 0) {
+		if (i = e1 & 15)
+			rv *= tens[i];
+		if (e1 &= ~15) {
+			if (e1 > DBL_MAX_10_EXP) {
+ovfl:
+				/* Can't trust HUGE_VAL */
+				word0(rv) = Exp_mask;
+				word1(rv) = 0;
+				if (bd0)
+					goto retfree;
+				goto ret;
+			}
+			if (e1 >>= 4) {
+				for (j = 0; e1 > 1; j++, e1 >>= 1)
+					if (e1 & 1)
+						rv *= bigtens[j];
+				/* The last multiplication could overflow. */
+				word0(rv) -= P * Exp_msk1;
+				rv *= bigtens[j];
+				if ((z = word0(rv) & Exp_mask)
+				     > Exp_msk1 * (DBL_MAX_EXP + Bias - P))
+					goto ovfl;
+				if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) {
+					/* set to largest number */
+					/* (Can't trust DBL_MAX) */
+					word0(rv) = Big0;
+					word1(rv) = Big1;
+				} else
+					word0(rv) += P * Exp_msk1;
+			}
+
+		}
+	} else if (e1 < 0) {
+		e1 = -e1;
+		if (i = e1 & 15)
+			rv /= tens[i];
+		if (e1 &= ~15) {
+			e1 >>= 4;
+			if (e1 >= 1 << n_bigtens)
+				goto undfl;
+			if (e1 & Scale_Bit)
+				scale = P;
+			for (j = 0; e1 > 0; j++, e1 >>= 1)
+				if (e1 & 1)
+					rv *= tinytens[j];
+			if (!rv) {
+undfl:
+				rv = 0.;
+				if (bd0)
+					goto retfree;
+				goto ret;
+			}
+		}
+	}
+
+	/* Now the hard part -- adjusting rv to the correct value.*/
+
+	/* Put digits into bd: true value = bd * 10^e */
+
+	bd0 = s2b(s0, nd0, nd, y);
+
+	for (; ; ) {
+		bd = Balloc(bd0->k);
+		Bcopy(bd, bd0);
+		bb = d2b(rv, &bbe, &bbbits);	/* rv = bb * 2^bbe */
+		bs = i2b(1);
+
+		if (e >= 0) {
+			bb2 = bb5 = 0;
+			bd2 = bd5 = e;
+		} else {
+			bb2 = bb5 = -e;
+			bd2 = bd5 = 0;
+		}
+		if (bbe >= 0)
+			bb2 += bbe;
+		else
+			bd2 -= bbe;
+		bs2 = bb2;
+#ifdef Sudden_Underflow
+		j = P + 1 - bbbits;
+#else
+		i = bbe + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j = bbe + (P - Emin);
+		else
+			j = P + 1 - bbbits;
+#endif
+		bb2 += j;
+		bd2 += j;
+		bd2 += scale;
+		i = bb2 < bd2 ? bb2 : bd2;
+		if (i > bs2)
+			i = bs2;
+		if (i > 0) {
+			bb2 -= i;
+			bd2 -= i;
+			bs2 -= i;
+		}
+		if (bb5 > 0) {
+			bs = pow5mult(bs, bb5);
+			bb1 = mult(bs, bb);
+			Bfree(bb);
+			bb = bb1;
+		}
+		if (bb2 > 0)
+			bb = lshift(bb, bb2);
+		if (bd5 > 0)
+			bd = pow5mult(bd, bd5);
+		if (bd2 > 0)
+			bd = lshift(bd, bd2);
+		if (bs2 > 0)
+			bs = lshift(bs, bs2);
+		delta = diff(bb, bd);
+		dsign = delta->sign;
+		delta->sign = 0;
+		i = cmp(delta, bs);
+		if (i < 0) {
+			/* Error is less than half an ulp -- check for
+			 * special case of mantissa a power of two.
+			 */
+			if (dsign || word1(rv) || word0(rv) & Bndry_mask
+			     || (word0(rv) & Exp_mask) <= Exp_msk1
+			    ) {
+				if (!delta->x[0] && delta->wds == 1)
+					dsign = 2;
+				break;
+			}
+			delta = lshift(delta, Log2P);
+			if (cmp(delta, bs) > 0)
+				goto drop_down;
+			break;
+		}
+		if (i == 0) {
+			/* exactly half-way between */
+			if (dsign) {
+				if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+				     &&  word1(rv) == 0xffffffff) {
+					/*boundary case -- increment exponent*/
+					word0(rv) = (word0(rv) & Exp_mask)
+					 + Exp_msk1
+					    ;
+					word1(rv) = 0;
+					dsign = 0;
+					break;
+				}
+			} else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+				dsign = 2;
+drop_down:
+				/* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow
+				L = word0(rv) & Exp_mask;
+				if (L <= Exp_msk1)
+					goto undfl;
+				L -= Exp_msk1;
+#else
+				L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif
+				word0(rv) = L | Bndry_mask1;
+				word1(rv) = 0xffffffff;
+				break;
+			}
+			if (!(word1(rv) & LSB))
+				break;
+			if (dsign)
+				rv += ulp(rv);
+			else {
+				rv -= ulp(rv);
+#ifndef Sudden_Underflow
+				if (!rv)
+					goto undfl;
+#endif
+			}
+			dsign = 1 - dsign;
+			break;
+		}
+		if ((aadj = ratio(delta, bs)) <= 2.) {
+			if (dsign)
+				aadj = aadj1 = 1.;
+			else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+				if (word1(rv) == Tiny1 && !word0(rv))
+					goto undfl;
+#endif
+				aadj = 1.;
+				aadj1 = -1.;
+			} else {
+				/* special case -- power of FLT_RADIX to be */
+				/* rounded down... */
+
+				if (aadj < 2. / FLT_RADIX)
+					aadj = 1. / FLT_RADIX;
+				else
+					aadj *= 0.5;
+				aadj1 = -aadj;
+			}
+		} else {
+			aadj *= 0.5;
+			aadj1 = dsign ? aadj : -aadj;
+			if (FLT_ROUNDS == 0)
+				aadj1 += 0.5;
+		}
+		y = word0(rv) & Exp_mask;
+
+		/* Check for overflow */
+
+		if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) {
+			rv0 = rv;
+			word0(rv) -= P * Exp_msk1;
+			adj = aadj1 * ulp(rv);
+			rv += adj;
+			if ((word0(rv) & Exp_mask) >= 
+			    Exp_msk1 * (DBL_MAX_EXP + Bias - P)) {
+				if (word0(rv0) == Big0 && word1(rv0) == Big1)
+					goto ovfl;
+				word0(rv) = Big0;
+				word1(rv) = Big1;
+				goto cont;
+			} else
+				word0(rv) += P * Exp_msk1;
+		} else {
+#ifdef Sudden_Underflow
+			if ((word0(rv) & Exp_mask) <= P * Exp_msk1) {
+				rv0 = rv;
+				word0(rv) += P * Exp_msk1;
+				adj = aadj1 * ulp(rv);
+				rv += adj;
+				if ((word0(rv) & Exp_mask) <= P * Exp_msk1) {
+					if (word0(rv0) == Tiny0
+					     && word1(rv0) == Tiny1)
+						goto undfl;
+					word0(rv) = Tiny0;
+					word1(rv) = Tiny1;
+					goto cont;
+				} else
+					word0(rv) -= P * Exp_msk1;
+			} else {
+				adj = aadj1 * ulp(rv);
+				rv += adj;
+			}
+#else
+			/* Compute adj so that the IEEE rounding rules will
+			 * correctly round rv + adj in some half-way cases.
+			 * If rv * ulp(rv) is denormalized (i.e.,
+			 * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+			 * trouble from bits lost to denormalization;
+			 * example: 1.2e-307 .
+			 */
+			if (y <= (P - 1) * Exp_msk1 && aadj >= 1.) {
+				aadj1 = (double)(int)(aadj + 0.5);
+				if (!dsign)
+					aadj1 = -aadj1;
+			}
+			adj = aadj1 * ulp(rv);
+			rv += adj;
+#endif
+		}
+		z = word0(rv) & Exp_mask;
+		if (!scale)
+			if (y == z) {
+				/* Can we stop now? */
+				L = aadj;
+				aadj -= L;
+				/* The tolerances below are conservative. */
+				if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+					if (aadj < .4999999 || aadj > .5000001)
+						break;
+				} else if (aadj < .4999999 / FLT_RADIX)
+					break;
+			}
+cont:
+		Bfree(bb);
+		Bfree(bd);
+		Bfree(bs);
+		Bfree(delta);
+	}
+	if (scale) {
+		if ((word0(rv) & Exp_mask) <= P * Exp_msk1
+		     && word1(rv) & 1
+		     && dsign != 2)
+			if (dsign)
+				rv += ulp(rv);
+			else
+				word1(rv) &= ~1;
+		word0(rv0) = Exp_1 - P * Exp_msk1;
+		word1(rv0) = 0;
+		rv *= rv0;
+	}
+retfree:
+	Bfree(bb);
+	Bfree(bd);
+	Bfree(bs);
+	Bfree(bd0);
+	Bfree(delta);
+ret:
+	if (se)
+		*se = (char *)s;
+	return sign ? -rv : rv;
+}
+
+static int	
+quorem(Bigint *b, Bigint *S)
+{
+	int	n;
+	long borrow, y;
+	unsigned  long carry, q, ys;
+	unsigned  long * bx, *bxe, *sx, *sxe;
+	long z;
+	unsigned  long si, zs;
+
+	n = S->wds;
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+			borrow = y >> 16;
+			Sign_Extend(borrow, y);
+			z = (*bx >> 16) - (zs & 0xffff) + borrow;
+			borrow = z >> 16;
+			Sign_Extend(borrow, z);
+			Storeinc(bx, z, y);
+		} while (sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while (--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+		}
+	}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+			borrow = y >> 16;
+			Sign_Extend(borrow, y);
+			z = (*bx >> 16) - (zs & 0xffff) + borrow;
+			borrow = z >> 16;
+			Sign_Extend(borrow, z);
+			Storeinc(bx, z, y);
+		} while (sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while (--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+		}
+	}
+	return q;
+}
+
+static char	*
+rv_alloc(int i)
+{
+	int	j, k, *r;
+
+	j = sizeof(unsigned  long);
+	for (k = 0; 
+	    sizeof(Bigint) - sizeof(unsigned  long) - sizeof(int) + j <= i; 
+	    j <<= 1)
+		k++;
+	r = (int * )Balloc(k);
+	*r = k;
+	return
+	    (char *)(r + 1);
+}
+
+static char	*
+nrv_alloc(char *s, char **rve, int n)
+{
+	char	*rv, *t;
+
+	t = rv = rv_alloc(n);
+	while (*t = *s++) 
+		t++;
+	if (rve)
+		*rve = t;
+	return rv;
+}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+void
+freedtoa(char *s)
+{
+	Bigint * b = (Bigint * )((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int * )b);
+	Bfree(b);
+}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the long
+ *	   calculation.
+ */
+
+char	*
+dtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+	/*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int	bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+	j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+	spec_case, try_quick;
+	long L;
+#ifndef Sudden_Underflow
+	int	denorm;
+	unsigned  long x;
+#endif
+	Bigint * b, *b1, *delta, *mlo, *mhi, *S;
+	double	d2, ds, eps;
+	char	*s, *s0;
+
+	if (word0(d) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(d) &= ~Sign_bit;	/* clear sign bit */
+	} else
+		*sign = 0;
+
+	if ((word0(d) & Exp_mask) == Exp_mask) {
+		/* Infinity or NaN */
+		*decpt = 9999;
+		if (!word1(d) && !(word0(d) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+		return nrv_alloc("NaN", rve, 3);
+	}
+	if (!d) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+	}
+
+	b = d2b(d, &be, &bbits);
+#ifdef Sudden_Underflow
+	i = (int)(word0(d) >> Exp_shift1 & (Exp_mask >> Exp_shift1));
+#else
+	if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask >> Exp_shift1))) {
+#endif
+		word0(d2) = (word0(d) & Frac_mask1) | Exp_11;
+		word1(d2) = word1(d);
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+		 *
+		 * This suggests computing an approximation k to log10(d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifndef Sudden_Underflow
+		denorm = 0;
+	} else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P - 1) - 1);
+		x = i > 32  ? word0(d) << 64 - i | word1(d) >> i - 32
+		     : word1(d) << 32 - i;
+		d2 = x;
+		word0(d2) -= 31 * Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P - 1) - 1) + 1;
+		denorm = 1;
+	}
+#endif
+	ds = (d2 - 1.5) * 0.289529654602168 + 0.1760912590558 + i * 0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (d < tens[k])
+			k--;
+		k_check = 0;
+	}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+	} else {
+		b2 = -j;
+		s2 = 0;
+	}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+	} else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+	}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+	try_quick = 1;
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+	}
+	leftright = 1;
+	switch (mode) {
+	case 0:
+	case 1:
+		ilim = ilim1 = -1;
+		i = 18;
+		ndigits = 0;
+		break;
+	case 2:
+		leftright = 0;
+		/* no break */
+	case 4:
+		if (ndigits <= 0)
+			ndigits = 1;
+		ilim = ilim1 = i = ndigits;
+		break;
+	case 3:
+		leftright = 0;
+		/* no break */
+	case 5:
+		i = ndigits + k + 1;
+		ilim = i;
+		ilim1 = i - 1;
+		if (i <= 0)
+			i = 1;
+	}
+	s = s0 = rv_alloc(i);
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		d2 = d;
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				d /= bigtens[n_bigtens-1];
+				ieps++;
+			}
+			for (; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+				}
+			d /= ds;
+		} else if (j1 = -k) {
+			d *= tens[j1 & 0xf];
+			for (j = j1 >> 4; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					d *= bigtens[i];
+				}
+		}
+		if (k_check && d < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			d *= 10.;
+			ieps++;
+		}
+		eps = ieps * d + 7.;
+		word0(eps) -= (P - 1) * Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			d -= 5.;
+			if (d > eps)
+				goto one_digit;
+			if (d < -eps)
+				goto no_digits;
+			goto fast_failed;
+		}
+		/* Generate ilim digits, then fix them up. */
+		eps *= tens[ilim-1];
+		for (i = 1; ; i++, d *= 10.) {
+			L = d;
+			d -= L;
+			*s++ = '0' + (int)L;
+			if (i == ilim) {
+				if (d > 0.5 + eps)
+					goto bump_up;
+				else if (d < 0.5 - eps) {
+					while (*--s == '0')
+						;
+					s++;
+					goto ret1;
+				}
+				break;
+			}
+		}
+fast_failed:
+		s = s0;
+		d = d2;
+		k = k0;
+		ilim = ilim0;
+	}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || d <= 5 * ds)
+				goto no_digits;
+			goto one_digit;
+		}
+		for (i = 1; ; i++) {
+			L = d / ds;
+			d -= L * ds;
+			*s++ = '0' + (int)L;
+			if (i == ilim) {
+				d += d;
+				if (d > ds || d == ds && L & 1) {
+bump_up:
+					while (*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+						}
+					++ * s++;
+				}
+				break;
+			}
+			if (!(d *= 10.))
+				break;
+		}
+		goto ret1;
+	}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		if (mode < 2) {
+			i = 
+#ifndef Sudden_Underflow
+			    denorm ? be + (Bias + (P - 1) - 1 + 1) : 
+#endif
+			    1 + P - bbits;
+		} else {
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+			}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+			}
+		}
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+	}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+	}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				b1 = mult(mhi, b);
+				Bfree(b);
+				b = b1;
+			}
+			if (j = b5 - m5)
+				b = pow5mult(b, j);
+		} else
+			b = pow5mult(b, b5);
+	}
+	S = i2b(1);
+	if (s5 > 0)
+		S = pow5mult(S, s5);
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if (mode < 2) {
+		if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+		     && word0(d) & Exp_mask
+#endif
+		    ) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+		}
+	}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f)
+		i = 32 - i;
+	if (i > 4) {
+		i -= 4;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+	} else if (i < 4) {
+		i += 28;
+		b2 += i;
+		m2 += i;
+		s2 += i;
+	}
+	if (b2 > 0)
+		b = lshift(b, b2);
+	if (s2 > 0)
+		S = lshift(S, s2);
+	if (k_check) {
+		if (cmp(b, S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (leftright)
+				mhi = multadd(mhi, 10, 0);
+			ilim = ilim1;
+		}
+	}
+	if (ilim <= 0 && mode > 2) {
+		if (ilim < 0 || cmp(b, S = multadd(S, 5, 0)) <= 0) {
+			/* no digits, fcvt style */
+no_digits:
+			k = -1 - ndigits;
+			goto ret;
+		}
+one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+	}
+	if (leftright) {
+		if (m2 > 0)
+			mhi = lshift(mhi, m2);
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+		}
+
+		for (i = 1; ; i++) {
+			dig = quorem(b, S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+			if (j1 == 0 && !mode && !(word1(d) & 1)) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+				*s++ = dig;
+				goto ret;
+			}
+			if (j < 0 || j == 0 && !mode
+			     && !(word1(d) & 1)
+			    ) {
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					j1 = cmp(b, S);
+					if ((j1 > 0 || j1 == 0 && dig & 1)
+					     && dig++ == '9')
+						goto round_9_up;
+				}
+				*s++ = dig;
+				goto ret;
+			}
+			if (j1 > 0) {
+				if (dig == '9') { /* possible if i == 1 */
+round_9_up:
+					*s++ = '9';
+					goto roundoff;
+				}
+				*s++ = dig + 1;
+				goto ret;
+			}
+			*s++ = dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (mlo == mhi)
+				mlo = mhi = multadd(mhi, 10, 0);
+			else {
+				mlo = multadd(mlo, 10, 0);
+				mhi = multadd(mhi, 10, 0);
+			}
+		}
+	} else
+		for (i = 1; ; i++) {
+			*s++ = dig = quorem(b, S) + '0';
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+		}
+
+	/* Round off last digit */
+
+	b = lshift(b, 1);
+	j = cmp(b, S);
+	if (j > 0 || j == 0 && dig & 1) {
+roundoff:
+		while (*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+			}
+		++ * s++;
+	} else {
+		while (*--s == '0')
+			;
+		s++;
+	}
+ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+	}
+ret1:
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+}
+
--- /dev/null
+++ b/libmath/fdim.c
@@ -1,0 +1,30 @@
+#include "lib9.h"
+#include "mathi.h"
+
+double
+fdim(double x, double y)
+{
+	if(x>y)
+		return x-y;
+	else
+		return 0;
+}
+
+double
+fmax(double x, double y)
+{
+	if(x>y)
+		return x;
+	else
+		return y;
+}
+
+double
+fmin(double x, double y)
+{
+	if(x<y)
+		return x;
+	else
+		return y;
+}
+
--- /dev/null
+++ b/libmath/fdlibm/e_acos.c
@@ -1,0 +1,97 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_acos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_acos(x)
+ * Method :                  
+ *	acos(x)  = pi/2 - asin(x)
+ *	acos(-x) = pi/2 + asin(x)
+ * For |x|<=0.5
+ *	acos(x) = pi/2 - (x + x*x^2*R(x^2))	(see asin.c)
+ * For x>0.5
+ * 	acos(x) = pi/2 - (pi/2 - 2asin(sqrt((1-x)/2)))
+ *		= 2asin(sqrt((1-x)/2))  
+ *		= 2s + 2s*z*R(z) 	...z=(1-x)/2, s=sqrt(z)
+ *		= 2f + (2c + 2s*z*R(z))
+ *     where f=hi part of s, and c = (z-f*f)/(s+f) is the correction term
+ *     for f so that f+c ~ sqrt(z).
+ * For x<-0.5
+ *	acos(x) = pi - 2asin(sqrt((1-|x|)/2))
+ *		= pi - 0.5*(s+s*z*R(z)), where z=(1-|x|)/2,s=sqrt(z)
+ *
+ * Special cases:
+ *	if x is NaN, return x itself;
+ *	if |x|>1, return NaN with invalid signal.
+ *
+ * Function needed: sqrt
+ */
+
+#include "fdlibm.h"
+
+static const double 
+one=  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+	double __ieee754_acos(double x)
+{
+	double z,p,q,r,w,s,c,df;
+	int hx,ix;
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>=0x3ff00000) {	/* |x| >= 1 */
+	    if(((ix-0x3ff00000)|__LO(x))==0) {	/* |x|==1 */
+		if(hx>0) return 0.0;		/* acos(1) = 0  */
+		else return pi+2.0*pio2_lo;	/* acos(-1)= pi */
+	    }
+	    return (x-x)/(x-x);		/* acos(|x|>1) is NaN */
+	}
+	if(ix<0x3fe00000) {	/* |x| < 0.5 */
+	    if(ix<=0x3c600000) return pio2_hi+pio2_lo;/*if|x|<2**-57*/
+	    z = x*x;
+	    p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+	    q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+	    r = p/q;
+	    return pio2_hi - (x - (pio2_lo-x*r));
+	} else  if (hx<0) {		/* x < -0.5 */
+	    z = (one+x)*0.5;
+	    p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+	    q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+	    s = sqrt(z);
+	    r = p/q;
+	    w = r*s-pio2_lo;
+	    return pi - 2.0*(s+w);
+	} else {			/* x > 0.5 */
+	    z = (one-x)*0.5;
+	    s = sqrt(z);
+	    df = s;
+	    __LO(df) = 0;
+	    c  = (z-df*df)/(s+df);
+	    p = z*(pS0+z*(pS1+z*(pS2+z*(pS3+z*(pS4+z*pS5)))));
+	    q = one+z*(qS1+z*(qS2+z*(qS3+z*qS4)));
+	    r = p/q;
+	    w = r*s+c;
+	    return 2.0*(df+w);
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/e_acosh.c
@@ -1,0 +1,57 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_acosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_acosh(x)
+ * Method :
+ *	Based on 
+ *		acosh(x) = log [ x + sqrt(x*x-1) ]
+ *	we have
+ *		acosh(x) := log(x)+ln2,	if x is large; else
+ *		acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
+ *		acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
+ *
+ * Special cases:
+ *	acosh(x) is NaN with signal if x<1.
+ *	acosh(NaN) is NaN without signal.
+ */
+
+#include "fdlibm.h"
+
+static const double 
+one	= 1.0,
+ln2	= 6.93147180559945286227e-01;  /* 0x3FE62E42, 0xFEFA39EF */
+
+	double __ieee754_acosh(double x)
+{	
+	double t;
+	int hx;
+	hx = __HI(x);
+	if(hx<0x3ff00000) {		/* x < 1 */
+	    return (x-x)/(x-x);
+	} else if(hx >=0x41b00000) {	/* x > 2**28 */
+	    if(hx >=0x7ff00000) {	/* x is inf of NaN */
+	        return x+x;
+	    } else 
+		return __ieee754_log(x)+ln2;	/* acosh(Huge)=log(2x) */
+	} else if(((hx-0x3ff00000)|__LO(x))==0) {
+	    return 0.0;			/* acosh(1) = 0 */
+	} else if (hx > 0x40000000) {	/* 2**28 > x > 2 */
+	    t=x*x;
+	    return __ieee754_log(2.0*x-one/(x+sqrt(t-one)));
+	} else {			/* 1<x<2 */
+	    t = x-one;
+	    return log1p(t+sqrt(2.0*t+t*t));
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/e_asin.c
@@ -1,0 +1,106 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_asin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_asin(x)
+ * Method :                  
+ *	Since  asin(x) = x + x^3/6 + x^5*3/40 + x^7*15/336 + ...
+ *	we approximate asin(x) on [0,0.5] by
+ *		asin(x) = x + x*x^2*R(x^2)
+ *	where
+ *		R(x^2) is a rational approximation of (asin(x)-x)/x^3 
+ *	and its remez error is bounded by
+ *		|(asin(x)-x)/x^3 - R(x^2)| < 2^(-58.75)
+ *
+ *	For x in [0.5,1]
+ *		asin(x) = pi/2-2*asin(sqrt((1-x)/2))
+ *	Let y = (1-x), z = y/2, s := sqrt(z), and pio2_hi+pio2_lo=pi/2;
+ *	then for x>0.98
+ *		asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *			= pio2_hi - (2*(s+s*z*R(z)) - pio2_lo)
+ *	For x<=0.98, let pio4_hi = pio2_hi/2, then
+ *		f = hi part of s;
+ *		c = sqrt(z) - f = (z-f*f)/(s+f) 	...f+c=sqrt(z)
+ *	and
+ *		asin(x) = pi/2 - 2*(s+s*z*R(z))
+ *			= pio4_hi+(pio4-2s)-(2s*z*R(z)-pio2_lo)
+ *			= pio4_hi+(pio4-2f)-(2s*z*R(z)-(pio2_lo+2c))
+ *
+ * Special cases:
+ *	if x is NaN, return x itself;
+ *	if |x|>1, return NaN with invalid signal.
+ *
+ */
+
+
+#include "fdlibm.h"
+
+static const double 
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+Huge =  1.000e+300,
+pio2_hi =  1.57079632679489655800e+00, /* 0x3FF921FB, 0x54442D18 */
+pio2_lo =  6.12323399573676603587e-17, /* 0x3C91A626, 0x33145C07 */
+pio4_hi =  7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+	/* coefficient for R(x^2) */
+pS0 =  1.66666666666666657415e-01, /* 0x3FC55555, 0x55555555 */
+pS1 = -3.25565818622400915405e-01, /* 0xBFD4D612, 0x03EB6F7D */
+pS2 =  2.01212532134862925881e-01, /* 0x3FC9C155, 0x0E884455 */
+pS3 = -4.00555345006794114027e-02, /* 0xBFA48228, 0xB5688F3B */
+pS4 =  7.91534994289814532176e-04, /* 0x3F49EFE0, 0x7501B288 */
+pS5 =  3.47933107596021167570e-05, /* 0x3F023DE1, 0x0DFDF709 */
+qS1 = -2.40339491173441421878e+00, /* 0xC0033A27, 0x1C8A2D4B */
+qS2 =  2.02094576023350569471e+00, /* 0x40002AE5, 0x9C598AC8 */
+qS3 = -6.88283971605453293030e-01, /* 0xBFE6066C, 0x1B8D0159 */
+qS4 =  7.70381505559019352791e-02; /* 0x3FB3B8C5, 0xB12E9282 */
+
+	double __ieee754_asin(double x)
+{
+	double t,w,p,q,c,r,s;
+	int hx,ix;
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>= 0x3ff00000) {		/* |x|>= 1 */
+	    if(((ix-0x3ff00000)|__LO(x))==0)
+		    /* asin(1)=+-pi/2 with inexact */
+		return x*pio2_hi+x*pio2_lo;	
+	    return (x-x)/(x-x);		/* asin(|x|>1) is NaN */   
+	} else if (ix<0x3fe00000) {	/* |x|<0.5 */
+	    if(ix<0x3e400000) {		/* if |x| < 2**-27 */
+		if(Huge+x>one) return x;/* return x with inexact if x!=0*/
+	    } 
+		t = x*x;
+		p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+		q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+		w = p/q;
+		return x+x*w;
+	}
+	/* 1> |x|>= 0.5 */
+	w = one-fabs(x);
+	t = w*0.5;
+	p = t*(pS0+t*(pS1+t*(pS2+t*(pS3+t*(pS4+t*pS5)))));
+	q = one+t*(qS1+t*(qS2+t*(qS3+t*qS4)));
+	s = sqrt(t);
+	if(ix>=0x3FEF3333) { 	/* if |x| > 0.975 */
+	    w = p/q;
+	    t = pio2_hi-(2.0*(s+s*w)-pio2_lo);
+	} else {
+	    w  = s;
+	    __LO(w) = 0;
+	    c  = (t-w*w)/(s+w);
+	    r  = p/q;
+	    p  = 2.0*s*r-(pio2_lo-2.0*c);
+	    q  = pio4_hi-2.0*w;
+	    t  = pio4_hi-(p-q);
+	}    
+	if(hx>0) return t; else return -t;    
+}
--- /dev/null
+++ b/libmath/fdlibm/e_atan2.c
@@ -1,0 +1,115 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_atan2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atan2(y,x)
+ * Method :
+ *	1. Reduce y to positive by atan2(y,x)=-atan2(-y,x).
+ *	2. Reduce x to positive by (if x and y are unexceptional): 
+ *		ARG (x+iy) = arctan(y/x)   	   ... if x > 0,
+ *		ARG (x+iy) = pi - arctan[y/(-x)]   ... if x < 0,
+ *
+ * Special cases:
+ *
+ *	ATAN2((anything), NaN ) is NaN;
+ *	ATAN2(NAN , (anything) ) is NaN;
+ *	ATAN2(+-0, +(anything but NaN)) is +-0  ;
+ *	ATAN2(+-0, -(anything but NaN)) is +-pi ;
+ *	ATAN2(+-(anything but 0 and NaN), 0) is +-pi/2;
+ *	ATAN2(+-(anything but INF and NaN), +INF) is +-0 ;
+ *	ATAN2(+-(anything but INF and NaN), -INF) is +-pi;
+ *	ATAN2(+-INF,+INF ) is +-pi/4 ;
+ *	ATAN2(+-INF,-INF ) is +-3pi/4;
+ *	ATAN2(+-INF, (anything but,0,NaN, and INF)) is +-pi/2;
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double 
+tiny  = 1.0e-300,
+zero  = 0.0,
+pi_o_4  = 7.8539816339744827900E-01, /* 0x3FE921FB, 0x54442D18 */
+pi_o_2  = 1.5707963267948965580E+00, /* 0x3FF921FB, 0x54442D18 */
+pi      = 3.1415926535897931160E+00, /* 0x400921FB, 0x54442D18 */
+pi_lo   = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
+
+	double __ieee754_atan2(double y, double x)
+{  
+	double z;
+	int k,m,hx,hy,ix,iy;
+	unsigned lx,ly;
+
+	hx = __HI(x); ix = hx&0x7fffffff;
+	lx = __LO(x);
+	hy = __HI(y); iy = hy&0x7fffffff;
+	ly = __LO(y);
+	if(((ix|((lx|-lx)>>31))>0x7ff00000)||
+	   ((iy|((ly|-ly)>>31))>0x7ff00000))	/* x or y is NaN */
+	   return x+y;
+	if((hx-0x3ff00000|lx)==0) return atan(y);   /* x=1.0 */
+	m = ((hy>>31)&1)|((hx>>30)&2);	/* 2*sign(x)+sign(y) */
+
+    /* when y = 0 */
+	if((iy|ly)==0) {
+	    switch(m) {
+		case 0: 
+		case 1: return y; 	/* atan(+-0,+anything)=+-0 */
+		case 2: return  pi+tiny;/* atan(+0,-anything) = pi */
+		case 3: return -pi-tiny;/* atan(-0,-anything) =-pi */
+	    }
+	}
+    /* when x = 0 */
+	if((ix|lx)==0) return (hy<0)?  -pi_o_2-tiny: pi_o_2+tiny;
+	    
+    /* when x is INF */
+	if(ix==0x7ff00000) {
+	    if(iy==0x7ff00000) {
+		switch(m) {
+		    case 0: return  pi_o_4+tiny;/* atan(+INF,+INF) */
+		    case 1: return -pi_o_4-tiny;/* atan(-INF,+INF) */
+		    case 2: return  3.0*pi_o_4+tiny;/*atan(+INF,-INF)*/
+		    case 3: return -3.0*pi_o_4-tiny;/*atan(-INF,-INF)*/
+		}
+	    } else {
+		switch(m) {
+		    case 0: return  zero  ;	/* atan(+...,+INF) */
+		    case 1: return -zero  ;	/* atan(-...,+INF) */
+		    case 2: return  pi+tiny  ;	/* atan(+...,-INF) */
+		    case 3: return -pi-tiny  ;	/* atan(-...,-INF) */
+		}
+	    }
+	}
+    /* when y is INF */
+	if(iy==0x7ff00000) return (hy<0)? -pi_o_2-tiny: pi_o_2+tiny;
+
+    /* compute y/x */
+	k = (iy-ix)>>20;
+	if(k > 60) z=pi_o_2+0.5*pi_lo; 	/* |y/x| >  2**60 */
+	else if(hx<0&&k<-60) z=0.0; 	/* |y|/x < -2**60 */
+	else z=atan(fabs(y/x));		/* safe to do y/x */
+	switch (m) {
+	    case 0: return       z  ;	/* atan(+,+) */
+	    case 1: __HI(z) ^= 0x80000000;
+		    return       z  ;	/* atan(-,+) */
+	    case 2: return  pi-(z-pi_lo);/* atan(+,-) */
+	    default: /* case 3 */
+	    	    return  (z-pi_lo)-pi;/* atan(-,-) */
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/e_atanh.c
@@ -1,0 +1,60 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_atanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_atanh(x)
+ * Method :
+ *    1.Reduced x to positive by atanh(-x) = -atanh(x)
+ *    2.For x>=0.5
+ *                  1              2x                          x
+ *	atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
+ *                  2             1 - x                      1 - x
+ *	
+ * 	For x<0.5
+ *	atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
+ *
+ * Special cases:
+ *	atanh(x) is NaN if |x| > 1 with signal;
+ *	atanh(NaN) is that NaN with no signal;
+ *	atanh(+-1) is +-INF with signal.
+ *
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, Huge = 1e300;
+
+static double zero = 0.0;
+
+	double __ieee754_atanh(double x)
+{
+	double t;
+	int hx,ix;
+	unsigned lx;
+	hx = __HI(x);		/* high word */
+	lx = __LO(x);		/* low word */
+	ix = hx&0x7fffffff;
+	if ((ix|((lx|(-lx))>>31))>0x3ff00000) /* |x|>1 */
+	    return (x-x)/(x-x);
+	if(ix==0x3ff00000) 
+	    return x/zero;
+	if(ix<0x3e300000&&(Huge+x)>zero) return x;	/* x<2**-28 */
+	__HI(x) = ix;		/* x <- |x| */
+	if(ix<0x3fe00000) {		/* x < 0.5 */
+	    t = x+x;
+	    t = 0.5*log1p(t+t*x/(one-x));
+	} else 
+	    t = 0.5*log1p((x+x)/(one-x));
+	if(hx>=0) return t; else return -t;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_cosh.c
@@ -1,0 +1,81 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_cosh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_cosh(x)
+ * Method : 
+ * mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2
+ *	1. Replace x by |x| (cosh(x) = cosh(-x)). 
+ *	2. 
+ *		                                        [ exp(x) - 1 ]^2 
+ *	    0        <= x <= ln2/2  :  cosh(x) := 1 + -------------------
+ *			       			           2*exp(x)
+ *
+ *		                                  exp(x) +  1/exp(x)
+ *	    ln2/2    <= x <= 22     :  cosh(x) := -------------------
+ *			       			          2
+ *	    22       <= x <= lnovft :  cosh(x) := exp(x)/2 
+ *	    lnovft   <= x <= ln2ovft:  cosh(x) := exp(x/2)/2 * exp(x/2)
+ *	    ln2ovft  <  x	    :  cosh(x) := Huge*Huge (overflow)
+ *
+ * Special cases:
+ *	cosh(x) is |x| if x is +INF, -INF, or NaN.
+ *	only cosh(0)=1 is exact for finite x.
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, half=0.5, Huge = 1.0e300;
+
+	double __ieee754_cosh(double x)
+{	
+	double t,w;
+	int ix;
+	unsigned lx;
+
+    /* High word of |x|. */
+	ix = __HI(x);
+	ix &= 0x7fffffff;
+
+    /* x is INF or NaN */
+	if(ix>=0x7ff00000) return x*x;	
+
+    /* |x| in [0,0.5*ln2], return 1+expm1(|x|)^2/(2*exp(|x|)) */
+	if(ix<0x3fd62e43) {
+	    t = expm1(fabs(x));
+	    w = one+t;
+	    if (ix<0x3c800000) return w;	/* cosh(tiny) = 1 */
+	    return one+(t*t)/(w+w);
+	}
+
+    /* |x| in [0.5*ln2,22], return (exp(|x|)+1/exp(|x|)/2; */
+	if (ix < 0x40360000) {
+		t = __ieee754_exp(fabs(x));
+		return half*t+half/t;
+	}
+
+    /* |x| in [22, log(maxdouble)] return half*exp(|x|) */
+	if (ix < 0x40862E42)  return half*__ieee754_exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+	lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+	if (ix<0x408633CE || 
+	      (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+	    w = __ieee754_exp(half*fabs(x));
+	    t = half*w;
+	    return t*w;
+	}
+
+    /* |x| > overflowthresold, cosh(x) overflow */
+	return Huge*Huge;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_exp.c
@@ -1,0 +1,149 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_exp.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_exp(x)
+ * Returns the exponential of x.
+ *
+ * Method
+ *   1. Argument reduction:
+ *      Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+ *	Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2.  
+ *
+ *      Here r will be represented as r = hi-lo for better 
+ *	accuracy.
+ *
+ *   2. Approximation of exp(r) by a special rational function on
+ *	the interval [0,0.34658]:
+ *	Write
+ *	    R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+ *      We use a special Reme algorithm on [0,0.34658] to generate 
+ * 	a polynomial of degree 5 to approximate R. The maximum error 
+ *	of this polynomial approximation is bounded by 2**-59. In
+ *	other words,
+ *	    R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+ *  	(where z=r*r, and the values of P1 to P5 are listed below)
+ *	and
+ *	    |                  5          |     -59
+ *	    | 2.0+P1*z+...+P5*z   -  R(z) | <= 2 
+ *	    |                             |
+ *	The computation of exp(r) thus becomes
+ *                             2*r
+ *		exp(r) = 1 + -------
+ *		              R - r
+ *                                 r*R1(r)	
+ *		       = 1 + r + ----------- (for better accuracy)
+ *		                  2 - R1(r)
+ *	where
+ *			         2       4             10
+ *		R1(r) = r - (P1*r  + P2*r  + ... + P5*r   ).
+ *	
+ *   3. Scale back to obtain exp(x):
+ *	From step 1, we have
+ *	   exp(x) = 2^k * exp(r)
+ *
+ * Special cases:
+ *	exp(INF) is INF, exp(NaN) is NaN;
+ *	exp(-INF) is 0, and
+ *	for finite argument, only exp(0)=1 is exact.
+ *
+ * Accuracy:
+ *	according to an error analysis, the error is always less than
+ *	1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *	For IEEE double 
+ *	    if x >  7.09782712893383973096e+02 then exp(x) overflow
+ *	    if x < -7.45133219101941108420e+02 then exp(x) underflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+one	= 1.0,
+halF[2]	= {0.5,-0.5,},
+Huge	= 1.0e+300,
+twom1000= 9.33263618503218878990e-302,     /* 2**-1000=0x01700000,0*/
+o_threshold=  7.09782712893383973096e+02,  /* 0x40862E42, 0xFEFA39EF */
+u_threshold= -7.45133219101941108420e+02,  /* 0xc0874910, 0xD52D3051 */
+ln2HI[2]   ={ 6.93147180369123816490e-01,  /* 0x3fe62e42, 0xfee00000 */
+	     -6.93147180369123816490e-01,},/* 0xbfe62e42, 0xfee00000 */
+ln2LO[2]   ={ 1.90821492927058770002e-10,  /* 0x3dea39ef, 0x35793c76 */
+	     -1.90821492927058770002e-10,},/* 0xbdea39ef, 0x35793c76 */
+invln2 =  1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
+
+
+	double __ieee754_exp(double x)	/* default IEEE double exp */
+{
+	double y,hi,lo,c,t;
+	int k,xsb;
+	unsigned hx;
+
+	hx  = __HI(x);	/* high word of x */
+	xsb = (hx>>31)&1;		/* sign bit of x */
+	hx &= 0x7fffffff;		/* high word of |x| */
+
+    /* filter out non-finite argument */
+	if(hx >= 0x40862E42) {			/* if |x|>=709.78... */
+            if(hx>=0x7ff00000) {
+		if(((hx&0xfffff)|__LO(x))!=0) 
+		     return x+x; 		/* NaN */
+		else return (xsb==0)? x:0.0;	/* exp(+-inf)={inf,0} */
+	    }
+	    if(x > o_threshold) return Huge*Huge; /* overflow */
+	    if(x < u_threshold) return twom1000*twom1000; /* underflow */
+	}
+
+    /* argument reduction */
+	if(hx > 0x3fd62e42) {		/* if  |x| > 0.5 ln2 */ 
+	    if(hx < 0x3FF0A2B2) {	/* and |x| < 1.5 ln2 */
+		hi = x-ln2HI[xsb]; lo=ln2LO[xsb]; k = 1-xsb-xsb;
+	    } else {
+		k  = invln2*x+halF[xsb];
+		t  = k;
+		hi = x - t*ln2HI[0];	/* t*ln2HI is exact here */
+		lo = t*ln2LO[0];
+	    }
+	    x  = hi - lo;
+	} 
+	else if(hx < 0x3e300000)  {	/* when |x|<2**-28 */
+	    if(Huge+x>one) return one+x;/* trigger inexact */
+	}
+	else k = 0;
+
+    /* x is now in primary range */
+	t  = x*x;
+	c  = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+	if(k==0) 	return one-((x*c)/(c-2.0)-x); 
+	else 		y = one-((lo-(x*c)/(2.0-c))-hi);
+	if(k >= -1021) {
+	    __HI(y) += (k<<20);	/* add k to y's exponent */
+	    return y;
+	} else {
+	    __HI(y) += ((k+1000)<<20);/* add k to y's exponent */
+	    return y*twom1000;
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/e_fmod.c
@@ -1,0 +1,132 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_fmod.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* 
+ * __ieee754_fmod(x,y)
+ * Return x mod y in exact arithmetic
+ * Method: shift and subtract
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, Zero[] = {0.0, -0.0,};
+
+	double __ieee754_fmod(double x, double y)
+{
+	int n,hx,hy,hz,ix,iy,sx,i;
+	unsigned lx,ly,lz;
+
+	hx = __HI(x);		/* high word of x */
+	lx = __LO(x);		/* low  word of x */
+	hy = __HI(y);		/* high word of y */
+	ly = __LO(y);		/* low  word of y */
+	sx = hx&0x80000000;		/* sign of x */
+	hx ^=sx;		/* |x| */
+	hy &= 0x7fffffff;	/* |y| */
+
+    /* purge off exception values */
+	if((hy|ly)==0||(hx>=0x7ff00000)||	/* y=0,or x not finite */
+	  ((hy|((ly|-ly)>>31))>0x7ff00000))	/* or y is NaN */
+	    return (x*y)/(x*y);
+	if(hx<=hy) {
+	    if((hx<hy)||(lx<ly)) return x;	/* |x|<|y| return x */
+	    if(lx==ly) 
+		return Zero[(unsigned)sx>>31];	/* |x|=|y| return x*0*/
+	}
+
+    /* determine ix = ilogb(x) */
+	if(hx<0x00100000) {	/* subnormal x */
+	    if(hx==0) {
+		for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
+	    } else {
+		for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
+	    }
+	} else ix = (hx>>20)-1023;
+
+    /* determine iy = ilogb(y) */
+	if(hy<0x00100000) {	/* subnormal y */
+	    if(hy==0) {
+		for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
+	    } else {
+		for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
+	    }
+	} else iy = (hy>>20)-1023;
+
+    /* set up {hx,lx}, {hy,ly} and align y to x */
+	if(ix >= -1022) 
+	    hx = 0x00100000|(0x000fffff&hx);
+	else {		/* subnormal x, shift x to normal */
+	    n = -1022-ix;
+	    if(n<=31) {
+	        hx = (hx<<n)|(lx>>(32-n));
+	        lx <<= n;
+	    } else {
+		hx = lx<<(n-32);
+		lx = 0;
+	    }
+	}
+	if(iy >= -1022) 
+	    hy = 0x00100000|(0x000fffff&hy);
+	else {		/* subnormal y, shift y to normal */
+	    n = -1022-iy;
+	    if(n<=31) {
+	        hy = (hy<<n)|(ly>>(32-n));
+	        ly <<= n;
+	    } else {
+		hy = ly<<(n-32);
+		ly = 0;
+	    }
+	}
+
+    /* fix point fmod */
+	n = ix - iy;
+	while(n--) {
+	    hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+	    if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
+	    else {
+	    	if((hz|lz)==0) 		/* return sign(x)*0 */
+		    return Zero[(unsigned)sx>>31];
+	    	hx = hz+hz+(lz>>31); lx = lz+lz;
+	    }
+	}
+	hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
+	if(hz>=0) {hx=hz;lx=lz;}
+
+    /* convert back to floating value and restore the sign */
+	if((hx|lx)==0) 			/* return sign(x)*0 */
+	    return Zero[(unsigned)sx>>31];	
+	while(hx<0x00100000) {		/* normalize x */
+	    hx = hx+hx+(lx>>31); lx = lx+lx;
+	    iy -= 1;
+	}
+	if(iy>= -1022) {	/* normalize output */
+	    hx = ((hx-0x00100000)|((iy+1023)<<20));
+	    __HI(x) = hx|sx;
+	    __LO(x) = lx;
+	} else {		/* subnormal output */
+	    n = -1022 - iy;
+	    if(n<=20) {
+		lx = (lx>>n)|((unsigned)hx<<(32-n));
+		hx >>= n;
+	    } else if (n<=31) {
+		lx = (hx<<(32-n))|(lx>>n); hx = sx;
+	    } else {
+		lx = hx>>(n-32); hx = sx;
+	    }
+	    __HI(x) = hx|sx;
+	    __LO(x) = lx;
+	    x *= one;		/* create necessary signal */
+	}
+	return x;		/* exact output */
+}
--- /dev/null
+++ b/libmath/fdlibm/e_hypot.c
@@ -1,0 +1,111 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_hypot.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_hypot(x,y)
+ *
+ * Method :                  
+ *	If (assume round-to-nearest) z=x*x+y*y 
+ *	has error less than sqrt(2)/2 ulp, than 
+ *	sqrt(z) has error less than 1 ulp (exercise).
+ *
+ *	So, compute sqrt(x*x+y*y) with some care as 
+ *	follows to get the error below 1 ulp:
+ *
+ *	Assume x>y>0;
+ *	(if possible, set rounding to round-to-nearest)
+ *	1. if x > 2y  use
+ *		x1*x1+(y*y+(x2*(x+x1))) for x*x+y*y
+ *	where x1 = x with lower 32 bits cleared, x2 = x-x1; else
+ *	2. if x <= 2y use
+ *		t1*y1+((x-y)*(x-y)+(t1*y2+t2*y))
+ *	where t1 = 2x with lower 32 bits cleared, t2 = 2x-t1, 
+ *	y1= y with lower 32 bits chopped, y2 = y-y1.
+ *		
+ *	NOTE: scaling may be necessary if some argument is too 
+ *	      large or too tiny
+ *
+ * Special cases:
+ *	hypot(x,y) is INF if x or y is +INF or -INF; else
+ *	hypot(x,y) is NAN if x or y is NAN.
+ *
+ * Accuracy:
+ * 	hypot(x,y) returns sqrt(x^2+y^2) with error less 
+ * 	than 1 ulps (units in the last place) 
+ */
+
+#include "fdlibm.h"
+
+	double __ieee754_hypot(double x, double y)
+{
+	double a=x,b=y,t1,t2,y1,y2,w;
+	int j,k,ha,hb;
+
+	ha = __HI(x)&0x7fffffff;	/* high word of  x */
+	hb = __HI(y)&0x7fffffff;	/* high word of  y */
+	if(hb > ha) {a=y;b=x;j=ha; ha=hb;hb=j;} else {a=x;b=y;}
+	__HI(a) = ha;	/* a <- |a| */
+	__HI(b) = hb;	/* b <- |b| */
+	if((ha-hb)>0x3c00000) {return a+b;} /* x/y > 2**60 */
+	k=0;
+	if(ha > 0x5f300000) {	/* a>2**500 */
+	   if(ha >= 0x7ff00000) {	/* Inf or NaN */
+	       w = a+b;			/* for sNaN */
+	       if(((ha&0xfffff)|__LO(a))==0) w = a;
+	       if(((hb^0x7ff00000)|__LO(b))==0) w = b;
+	       return w;
+	   }
+	   /* scale a and b by 2**-600 */
+	   ha -= 0x25800000; hb -= 0x25800000;	k += 600;
+	   __HI(a) = ha;
+	   __HI(b) = hb;
+	}
+	if(hb < 0x20b00000) {	/* b < 2**-500 */
+	    if(hb <= 0x000fffff) {	/* subnormal b or 0 */	
+		if((hb|(__LO(b)))==0) return a;
+		t1=0;
+		__HI(t1) = 0x7fd00000;	/* t1=2^1022 */
+		b *= t1;
+		a *= t1;
+		k -= 1022;
+	    } else {		/* scale a and b by 2^600 */
+	        ha += 0x25800000; 	/* a *= 2^600 */
+		hb += 0x25800000;	/* b *= 2^600 */
+		k -= 600;
+	   	__HI(a) = ha;
+	   	__HI(b) = hb;
+	    }
+	}
+    /* medium size a and b */
+	w = a-b;
+	if (w>b) {
+	    t1 = 0;
+	    __HI(t1) = ha;
+	    t2 = a-t1;
+	    w  = sqrt(t1*t1-(b*(-b)-t2*(a+t1)));
+	} else {
+	    a  = a+a;
+	    y1 = 0;
+	    __HI(y1) = hb;
+	    y2 = b - y1;
+	    t1 = 0;
+	    __HI(t1) = ha+0x00100000;
+	    t2 = a - t1;
+	    w  = sqrt(t1*y1-(w*(-w)-(t1*y2+t2*b)));
+	}
+	if(k!=0) {
+	    t1 = 1.0;
+	    __HI(t1) += (k<<20);
+	    return t1*w;
+	} else return w;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_j0.c
@@ -1,0 +1,375 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_j0.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j0(x), __ieee754_y0(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j0(x):
+ *	1. For tiny x, we use j0(x) = 1 - x^2/4 + x^4/64 - ...
+ *	2. Reduce x to |x| since j0(x)=j0(-x),  and
+ *	   for x in (0,2)
+ *		j0(x) = 1-z/4+ z^2*R0/S0,  where z = x*x;
+ *	   (precision:  |j0-1+z/4-z^2R0/S0 |<2**-63.67 )
+ *	   for x in (2,inf)
+ * 		j0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)-q0(x)*sin(x0))
+ * 	   where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ *	   as follow:
+ *		cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+ *			= 1/sqrt(2) * (cos(x) + sin(x))
+ *		sin(x0) = sin(x)cos(pi/4)-cos(x)sin(pi/4)
+ *			= 1/sqrt(2) * (sin(x) - cos(x))
+ * 	   (To avoid cancellation, use
+ *		sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * 	    to compute the worse one.)
+ *	   
+ *	3 Special cases
+ *		j0(nan)= nan
+ *		j0(0) = 1
+ *		j0(inf) = 0
+ *		
+ * Method -- y0(x):
+ *	1. For x<2.
+ *	   Since 
+ *		y0(x) = 2/pi*(j0(x)*(ln(x/2)+Euler) + x^2/4 - ...)
+ *	   therefore y0(x)-2/pi*j0(x)*ln(x) is an even function.
+ *	   We use the following function to approximate y0,
+ *		y0(x) = U(z)/V(z) + (2/pi)*(j0(x)*ln(x)), z= x^2
+ *	   where 
+ *		U(z) = u00 + u01*z + ... + u06*z^6
+ *		V(z) = 1  + v01*z + ... + v04*z^4
+ *	   with absolute approximation error bounded by 2**-72.
+ *	   Note: For tiny x, U/V = u0 and j0(x)~1, hence
+ *		y0(tiny) = u0 + (2/pi)*ln(tiny), (choose tiny<2**-27)
+ *	2. For x>=2.
+ * 		y0(x) = sqrt(2/(pi*x))*(p0(x)*cos(x0)+q0(x)*sin(x0))
+ * 	   where x0 = x-pi/4. It is better to compute sin(x0),cos(x0)
+ *	   by the method mentioned above.
+ *	3. Special cases: y0(0)=-inf, y0(x<0)=NaN, y0(inf)=0.
+ */
+
+#include "fdlibm.h"
+
+static double pzero(double), qzero(double);
+
+static const double 
+Huge 	= 1e300,
+one	= 1.0,
+invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi      =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+ 		/* R0/S0 on [0, 2.00] */
+R02  =  1.56249999999999947958e-02, /* 0x3F8FFFFF, 0xFFFFFFFD */
+R03  = -1.89979294238854721751e-04, /* 0xBF28E6A5, 0xB61AC6E9 */
+R04  =  1.82954049532700665670e-06, /* 0x3EBEB1D1, 0x0C503919 */
+R05  = -4.61832688532103189199e-09, /* 0xBE33D5E7, 0x73D63FCE */
+S01  =  1.56191029464890010492e-02, /* 0x3F8FFCE8, 0x82C8C2A4 */
+S02  =  1.16926784663337450260e-04, /* 0x3F1EA6D2, 0xDD57DBF4 */
+S03  =  5.13546550207318111446e-07, /* 0x3EA13B54, 0xCE84D5A9 */
+S04  =  1.16614003333790000205e-09; /* 0x3E1408BC, 0xF4745D8F */
+
+static double zero = 0.0;
+
+	double __ieee754_j0(double x) 
+{
+	double z, s,c,ss,cc,r,u,v;
+	int hx,ix;
+
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>=0x7ff00000) return one/(x*x);
+	x = fabs(x);
+	if(ix >= 0x40000000) {	/* |x| >= 2.0 */
+		s = sin(x);
+		c = cos(x);
+		ss = s-c;
+		cc = s+c;
+		if(ix<0x7fe00000) {  /* make sure x+x not overflow */
+		    z = -cos(x+x);
+		    if ((s*c)<zero) cc = z/ss;
+		    else 	    ss = z/cc;
+		}
+	/*
+	 * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+	 * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+	 */
+		if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(x);
+		else {
+		    u = pzero(x); v = qzero(x);
+		    z = invsqrtpi*(u*cc-v*ss)/sqrt(x);
+		}
+		return z;
+	}
+	if(ix<0x3f200000) {	/* |x| < 2**-13 */
+	    if(Huge+x>one) {	/* raise inexact if x != 0 */
+	        if(ix<0x3e400000) return one;	/* |x|<2**-27 */
+	        else 	      return one - 0.25*x*x;
+	    }
+	}
+	z = x*x;
+	r =  z*(R02+z*(R03+z*(R04+z*R05)));
+	s =  one+z*(S01+z*(S02+z*(S03+z*S04)));
+	if(ix < 0x3FF00000) {	/* |x| < 1.00 */
+	    return one + z*(-0.25+(r/s));
+	} else {
+	    u = 0.5*x;
+	    return((one+u)*(one-u)+z*(r/s));
+	}
+}
+
+static const double
+u00  = -7.38042951086872317523e-02, /* 0xBFB2E4D6, 0x99CBD01F */
+u01  =  1.76666452509181115538e-01, /* 0x3FC69D01, 0x9DE9E3FC */
+u02  = -1.38185671945596898896e-02, /* 0xBF8C4CE8, 0xB16CFA97 */
+u03  =  3.47453432093683650238e-04, /* 0x3F36C54D, 0x20B29B6B */
+u04  = -3.81407053724364161125e-06, /* 0xBECFFEA7, 0x73D25CAD */
+u05  =  1.95590137035022920206e-08, /* 0x3E550057, 0x3B4EABD4 */
+u06  = -3.98205194132103398453e-11, /* 0xBDC5E43D, 0x693FB3C8 */
+v01  =  1.27304834834123699328e-02, /* 0x3F8A1270, 0x91C9C71A */
+v02  =  7.60068627350353253702e-05, /* 0x3F13ECBB, 0xF578C6C1 */
+v03  =  2.59150851840457805467e-07, /* 0x3E91642D, 0x7FF202FD */
+v04  =  4.41110311332675467403e-10; /* 0x3DFE5018, 0x3BD6D9EF */
+
+	double __ieee754_y0(double x) 
+{
+	double z, s,c,ss,cc,u,v;
+	int hx,ix,lx;
+
+        hx = __HI(x);
+        ix = 0x7fffffff&hx;
+        lx = __LO(x);
+    /* Y0(NaN) is NaN, y0(-inf) is Nan, y0(inf) is 0  */
+	if(ix>=0x7ff00000) return  one/(x+x*x); 
+        if((ix|lx)==0) return -one/zero;
+        if(hx<0) return zero/zero;
+        if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+        /* y0(x) = sqrt(2/(pi*x))*(p0(x)*sin(x0)+q0(x)*cos(x0))
+         * where x0 = x-pi/4
+         *      Better formula:
+         *              cos(x0) = cos(x)cos(pi/4)+sin(x)sin(pi/4)
+         *                      =  1/sqrt(2) * (sin(x) + cos(x))
+         *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+         *                      =  1/sqrt(2) * (sin(x) - cos(x))
+         * To avoid cancellation, use
+         *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+         * to compute the worse one.
+         */
+                s = sin(x);
+                c = cos(x);
+                ss = s-c;
+                cc = s+c;
+	/*
+	 * j0(x) = 1/sqrt(pi) * (P(0,x)*cc - Q(0,x)*ss) / sqrt(x)
+	 * y0(x) = 1/sqrt(pi) * (P(0,x)*ss + Q(0,x)*cc) / sqrt(x)
+	 */
+                if(ix<0x7fe00000) {  /* make sure x+x not overflow */
+                    z = -cos(x+x);
+                    if ((s*c)<zero) cc = z/ss;
+                    else            ss = z/cc;
+                }
+                if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+                else {
+                    u = pzero(x); v = qzero(x);
+                    z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+                }
+                return z;
+	}
+	if(ix<=0x3e400000) {	/* x < 2**-27 */
+	    return(u00 + tpi*__ieee754_log(x));
+	}
+	z = x*x;
+	u = u00+z*(u01+z*(u02+z*(u03+z*(u04+z*(u05+z*u06)))));
+	v = one+z*(v01+z*(v02+z*(v03+z*v04)));
+	return(u/v + tpi*(__ieee754_j0(x)*__ieee754_log(x)));
+}
+
+/* The asymptotic expansions of pzero is
+ *	1 - 9/128 s^2 + 11025/98304 s^4 - ...,	where s = 1/x.
+ * For x >= 2, We approximate pzero by
+ * 	pzero(x) = 1 + (R/S)
+ * where  R = pR0 + pR1*s^2 + pR2*s^4 + ... + pR5*s^10
+ * 	  S = 1 + pS0*s^2 + ... + pS4*s^10
+ * and
+ *	| pzero(x)-1-R/S | <= 2  ** ( -60.26)
+ */
+static const double pR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -7.03124999999900357484e-02, /* 0xBFB1FFFF, 0xFFFFFD32 */
+ -8.08167041275349795626e+00, /* 0xC02029D0, 0xB44FA779 */
+ -2.57063105679704847262e+02, /* 0xC0701102, 0x7B19E863 */
+ -2.48521641009428822144e+03, /* 0xC0A36A6E, 0xCD4DCAFC */
+ -5.25304380490729545272e+03, /* 0xC0B4850B, 0x36CC643D */
+};
+static const double pS8[5] = {
+  1.16534364619668181717e+02, /* 0x405D2233, 0x07A96751 */
+  3.83374475364121826715e+03, /* 0x40ADF37D, 0x50596938 */
+  4.05978572648472545552e+04, /* 0x40E3D2BB, 0x6EB6B05F */
+  1.16752972564375915681e+05, /* 0x40FC810F, 0x8F9FA9BD */
+  4.76277284146730962675e+04, /* 0x40E74177, 0x4F2C49DC */
+};
+
+static const double pR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -1.14125464691894502584e-11, /* 0xBDA918B1, 0x47E495CC */
+ -7.03124940873599280078e-02, /* 0xBFB1FFFF, 0xE69AFBC6 */
+ -4.15961064470587782438e+00, /* 0xC010A370, 0xF90C6BBF */
+ -6.76747652265167261021e+01, /* 0xC050EB2F, 0x5A7D1783 */
+ -3.31231299649172967747e+02, /* 0xC074B3B3, 0x6742CC63 */
+ -3.46433388365604912451e+02, /* 0xC075A6EF, 0x28A38BD7 */
+};
+static const double pS5[5] = {
+  6.07539382692300335975e+01, /* 0x404E6081, 0x0C98C5DE */
+  1.05125230595704579173e+03, /* 0x40906D02, 0x5C7E2864 */
+  5.97897094333855784498e+03, /* 0x40B75AF8, 0x8FBE1D60 */
+  9.62544514357774460223e+03, /* 0x40C2CCB8, 0xFA76FA38 */
+  2.40605815922939109441e+03, /* 0x40A2CC1D, 0xC70BE864 */
+};
+
+static const double pR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+ -2.54704601771951915620e-09, /* 0xBE25E103, 0x6FE1AA86 */
+ -7.03119616381481654654e-02, /* 0xBFB1FFF6, 0xF7C0E24B */
+ -2.40903221549529611423e+00, /* 0xC00345B2, 0xAEA48074 */
+ -2.19659774734883086467e+01, /* 0xC035F74A, 0x4CB94E14 */
+ -5.80791704701737572236e+01, /* 0xC04D0A22, 0x420A1A45 */
+ -3.14479470594888503854e+01, /* 0xC03F72AC, 0xA892D80F */
+};
+static const double pS3[5] = {
+  3.58560338055209726349e+01, /* 0x4041ED92, 0x84077DD3 */
+  3.61513983050303863820e+02, /* 0x40769839, 0x464A7C0E */
+  1.19360783792111533330e+03, /* 0x4092A66E, 0x6D1061D6 */
+  1.12799679856907414432e+03, /* 0x40919FFC, 0xB8C39B7E */
+  1.73580930813335754692e+02, /* 0x4065B296, 0xFC379081 */
+};
+
+static const double pR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -8.87534333032526411254e-08, /* 0xBE77D316, 0xE927026D */
+ -7.03030995483624743247e-02, /* 0xBFB1FF62, 0x495E1E42 */
+ -1.45073846780952986357e+00, /* 0xBFF73639, 0x8A24A843 */
+ -7.63569613823527770791e+00, /* 0xC01E8AF3, 0xEDAFA7F3 */
+ -1.11931668860356747786e+01, /* 0xC02662E6, 0xC5246303 */
+ -3.23364579351335335033e+00, /* 0xC009DE81, 0xAF8FE70F */
+};
+static const double pS2[5] = {
+  2.22202997532088808441e+01, /* 0x40363865, 0x908B5959 */
+  1.36206794218215208048e+02, /* 0x4061069E, 0x0EE8878F */
+  2.70470278658083486789e+02, /* 0x4070E786, 0x42EA079B */
+  1.53875394208320329881e+02, /* 0x40633C03, 0x3AB6FAFF */
+  1.46576176948256193810e+01, /* 0x402D50B3, 0x44391809 */
+};
+
+	static double pzero(double x)
+{
+	const double *p,*q;
+	double z,r,s;
+	int ix;
+	ix = 0x7fffffff&__HI(x);
+	if(ix>=0x40200000)     {p = pR8; q= pS8;}
+	else if(ix>=0x40122E8B){p = pR5; q= pS5;}
+	else if(ix>=0x4006DB6D){p = pR3; q= pS3;}
+	else if(ix>=0x40000000){p = pR2; q= pS2;}
+	z = one/(x*x);
+	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+	return one+ r/s;
+}
+		
+
+/* For x >= 8, the asymptotic expansions of qzero is
+ *	-1/8 s + 75/1024 s^3 - ..., where s = 1/x.
+ * We approximate pzero by
+ * 	qzero(x) = s*(-1.25 + (R/S))
+ * where  R = qR0 + qR1*s^2 + qR2*s^4 + ... + qR5*s^10
+ * 	  S = 1 + qS0*s^2 + ... + qS5*s^12
+ * and
+ *	| qzero(x)/s +1.25-R/S | <= 2  ** ( -61.22)
+ */
+static const double qR8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+  7.32421874999935051953e-02, /* 0x3FB2BFFF, 0xFFFFFE2C */
+  1.17682064682252693899e+01, /* 0x40278952, 0x5BB334D6 */
+  5.57673380256401856059e+02, /* 0x40816D63, 0x15301825 */
+  8.85919720756468632317e+03, /* 0x40C14D99, 0x3E18F46D */
+  3.70146267776887834771e+04, /* 0x40E212D4, 0x0E901566 */
+};
+static const double qS8[6] = {
+  1.63776026895689824414e+02, /* 0x406478D5, 0x365B39BC */
+  8.09834494656449805916e+03, /* 0x40BFA258, 0x4E6B0563 */
+  1.42538291419120476348e+05, /* 0x41016652, 0x54D38C3F */
+  8.03309257119514397345e+05, /* 0x412883DA, 0x83A52B43 */
+  8.40501579819060512818e+05, /* 0x4129A66B, 0x28DE0B3D */
+ -3.43899293537866615225e+05, /* 0xC114FD6D, 0x2C9530C5 */
+};
+
+static const double qR5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+  1.84085963594515531381e-11, /* 0x3DB43D8F, 0x29CC8CD9 */
+  7.32421766612684765896e-02, /* 0x3FB2BFFF, 0xD172B04C */
+  5.83563508962056953777e+00, /* 0x401757B0, 0xB9953DD3 */
+  1.35111577286449829671e+02, /* 0x4060E392, 0x0A8788E9 */
+  1.02724376596164097464e+03, /* 0x40900CF9, 0x9DC8C481 */
+  1.98997785864605384631e+03, /* 0x409F17E9, 0x53C6E3A6 */
+};
+static const double qS5[6] = {
+  8.27766102236537761883e+01, /* 0x4054B1B3, 0xFB5E1543 */
+  2.07781416421392987104e+03, /* 0x40A03BA0, 0xDA21C0CE */
+  1.88472887785718085070e+04, /* 0x40D267D2, 0x7B591E6D */
+  5.67511122894947329769e+04, /* 0x40EBB5E3, 0x97E02372 */
+  3.59767538425114471465e+04, /* 0x40E19118, 0x1F7A54A0 */
+ -5.35434275601944773371e+03, /* 0xC0B4EA57, 0xBEDBC609 */
+};
+
+static const double qR3[6] = {/* for x in [4.547,2.8571]=1/[0.2199,0.35001] */
+  4.37741014089738620906e-09, /* 0x3E32CD03, 0x6ADECB82 */
+  7.32411180042911447163e-02, /* 0x3FB2BFEE, 0x0E8D0842 */
+  3.34423137516170720929e+00, /* 0x400AC0FC, 0x61149CF5 */
+  4.26218440745412650017e+01, /* 0x40454F98, 0x962DAEDD */
+  1.70808091340565596283e+02, /* 0x406559DB, 0xE25EFD1F */
+  1.66733948696651168575e+02, /* 0x4064D77C, 0x81FA21E0 */
+};
+static const double qS3[6] = {
+  4.87588729724587182091e+01, /* 0x40486122, 0xBFE343A6 */
+  7.09689221056606015736e+02, /* 0x40862D83, 0x86544EB3 */
+  3.70414822620111362994e+03, /* 0x40ACF04B, 0xE44DFC63 */
+  6.46042516752568917582e+03, /* 0x40B93C6C, 0xD7C76A28 */
+  2.51633368920368957333e+03, /* 0x40A3A8AA, 0xD94FB1C0 */
+ -1.49247451836156386662e+02, /* 0xC062A7EB, 0x201CF40F */
+};
+
+static const double qR2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+  1.50444444886983272379e-07, /* 0x3E84313B, 0x54F76BDB */
+  7.32234265963079278272e-02, /* 0x3FB2BEC5, 0x3E883E34 */
+  1.99819174093815998816e+00, /* 0x3FFFF897, 0xE727779C */
+  1.44956029347885735348e+01, /* 0x402CFDBF, 0xAAF96FE5 */
+  3.16662317504781540833e+01, /* 0x403FAA8E, 0x29FBDC4A */
+  1.62527075710929267416e+01, /* 0x403040B1, 0x71814BB4 */
+};
+static const double qS2[6] = {
+  3.03655848355219184498e+01, /* 0x403E5D96, 0xF7C07AED */
+  2.69348118608049844624e+02, /* 0x4070D591, 0xE4D14B40 */
+  8.44783757595320139444e+02, /* 0x408A6645, 0x22B3BF22 */
+  8.82935845112488550512e+02, /* 0x408B977C, 0x9C5CC214 */
+  2.12666388511798828631e+02, /* 0x406A9553, 0x0E001365 */
+ -5.31095493882666946917e+00, /* 0xC0153E6A, 0xF8B32931 */
+};
+
+	static double qzero(double x)
+{
+	const double *p,*q;
+	double s,r,z;
+	int ix;
+	ix = 0x7fffffff&__HI(x);
+	if(ix>=0x40200000)     {p = qR8; q= qS8;}
+	else if(ix>=0x40122E8B){p = qR5; q= qS5;}
+	else if(ix>=0x4006DB6D){p = qR3; q= qS3;}
+	else if(ix>=0x40000000){p = qR2; q= qS2;}
+	z = one/(x*x);
+	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+	return (-.125 + r/s)/x;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_j1.c
@@ -1,0 +1,370 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_j1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_j1(x), __ieee754_y1(x)
+ * Bessel function of the first and second kinds of order zero.
+ * Method -- j1(x):
+ *	1. For tiny x, we use j1(x) = x/2 - x^3/16 + x^5/384 - ...
+ *	2. Reduce x to |x| since j1(x)=-j1(-x),  and
+ *	   for x in (0,2)
+ *		j1(x) = x/2 + x*z*R0/S0,  where z = x*x;
+ *	   (precision:  |j1/x - 1/2 - R0/S0 |<2**-61.51 )
+ *	   for x in (2,inf)
+ * 		j1(x) = sqrt(2/(pi*x))*(p1(x)*cos(x1)-q1(x)*sin(x1))
+ * 		y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * 	   where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ *	   as follow:
+ *		cos(x1) =  cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+ *			=  1/sqrt(2) * (sin(x) - cos(x))
+ *		sin(x1) =  sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+ *			= -1/sqrt(2) * (sin(x) + cos(x))
+ * 	   (To avoid cancellation, use
+ *		sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+ * 	    to compute the worse one.)
+ *	   
+ *	3 Special cases
+ *		j1(nan)= nan
+ *		j1(0) = 0
+ *		j1(inf) = 0
+ *		
+ * Method -- y1(x):
+ *	1. screen out x<=0 cases: y1(0)=-inf, y1(x<0)=NaN 
+ *	2. For x<2.
+ *	   Since 
+ *		y1(x) = 2/pi*(j1(x)*(ln(x/2)+Euler)-1/x-x/2+5/64*x^3-...)
+ *	   therefore y1(x)-2/pi*j1(x)*ln(x)-1/x is an odd function.
+ *	   We use the following function to approximate y1,
+ *		y1(x) = x*U(z)/V(z) + (2/pi)*(j1(x)*ln(x)-1/x), z= x^2
+ *	   where for x in [0,2] (abs err less than 2**-65.89)
+ *		U(z) = U0[0] + U0[1]*z + ... + U0[4]*z^4
+ *		V(z) = 1  + v0[0]*z + ... + v0[4]*z^5
+ *	   Note: For tiny x, 1/x dominate y1 and hence
+ *		y1(tiny) = -2/pi/tiny, (choose tiny<2**-54)
+ *	3. For x>=2.
+ * 		y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x1)+q1(x)*cos(x1))
+ * 	   where x1 = x-3*pi/4. It is better to compute sin(x1),cos(x1)
+ *	   by method mentioned above.
+ */
+
+#include "fdlibm.h"
+
+static double pone(double), qone(double);
+
+static const double 
+Huge    = 1e300,
+one	= 1.0,
+invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+tpi      =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+	/* R0/S0 on [0,2] */
+r00  = -6.25000000000000000000e-02, /* 0xBFB00000, 0x00000000 */
+r01  =  1.40705666955189706048e-03, /* 0x3F570D9F, 0x98472C61 */
+r02  = -1.59955631084035597520e-05, /* 0xBEF0C5C6, 0xBA169668 */
+r03  =  4.96727999609584448412e-08, /* 0x3E6AAAFA, 0x46CA0BD9 */
+s01  =  1.91537599538363460805e-02, /* 0x3F939D0B, 0x12637E53 */
+s02  =  1.85946785588630915560e-04, /* 0x3F285F56, 0xB9CDF664 */
+s03  =  1.17718464042623683263e-06, /* 0x3EB3BFF8, 0x333F8498 */
+s04  =  5.04636257076217042715e-09, /* 0x3E35AC88, 0xC97DFF2C */
+s05  =  1.23542274426137913908e-11; /* 0x3DAB2ACF, 0xCFB97ED8 */
+
+static double zero    = 0.0;
+
+	double __ieee754_j1(double x) 
+{
+	double z, s,c,ss,cc,r,u,v,y;
+	int hx,ix;
+
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>=0x7ff00000) return one/x;
+	y = fabs(x);
+	if(ix >= 0x40000000) {	/* |x| >= 2.0 */
+		s = sin(y);
+		c = cos(y);
+		ss = -s-c;
+		cc = s-c;
+		if(ix<0x7fe00000) {  /* make sure y+y not overflow */
+		    z = cos(y+y);
+		    if ((s*c)>zero) cc = z/ss;
+		    else 	    ss = z/cc;
+		}
+	/*
+	 * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
+	 * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
+	 */
+		if(ix>0x48000000) z = (invsqrtpi*cc)/sqrt(y);
+		else {
+		    u = pone(y); v = qone(y);
+		    z = invsqrtpi*(u*cc-v*ss)/sqrt(y);
+		}
+		if(hx<0) return -z;
+		else  	 return  z;
+	}
+	if(ix<0x3e400000) {	/* |x|<2**-27 */
+	    if(Huge+x>one) return 0.5*x;/* inexact if x!=0 necessary */
+	}
+	z = x*x;
+	r =  z*(r00+z*(r01+z*(r02+z*r03)));
+	s =  one+z*(s01+z*(s02+z*(s03+z*(s04+z*s05))));
+	r *= x;
+	return(x*0.5+r/s);
+}
+
+static const double U0[5] = {
+ -1.96057090646238940668e-01, /* 0xBFC91866, 0x143CBC8A */
+  5.04438716639811282616e-02, /* 0x3FA9D3C7, 0x76292CD1 */
+ -1.91256895875763547298e-03, /* 0xBF5F55E5, 0x4844F50F */
+  2.35252600561610495928e-05, /* 0x3EF8AB03, 0x8FA6B88E */
+ -9.19099158039878874504e-08, /* 0xBE78AC00, 0x569105B8 */
+};
+static const double V0[5] = {
+  1.99167318236649903973e-02, /* 0x3F94650D, 0x3F4DA9F0 */
+  2.02552581025135171496e-04, /* 0x3F2A8C89, 0x6C257764 */
+  1.35608801097516229404e-06, /* 0x3EB6C05A, 0x894E8CA6 */
+  6.22741452364621501295e-09, /* 0x3E3ABF1D, 0x5BA69A86 */
+  1.66559246207992079114e-11, /* 0x3DB25039, 0xDACA772A */
+};
+
+	double __ieee754_y1(double x) 
+{
+	double z, s,c,ss,cc,u,v;
+	int hx,ix,lx;
+
+        hx = __HI(x);
+        ix = 0x7fffffff&hx;
+        lx = __LO(x);
+    /* if Y1(NaN) is NaN, Y1(-inf) is NaN, Y1(inf) is 0 */
+	if(ix>=0x7ff00000) return  one/(x+x*x); 
+        if((ix|lx)==0) return -one/zero;
+        if(hx<0) return zero/zero;
+        if(ix >= 0x40000000) {  /* |x| >= 2.0 */
+                s = sin(x);
+                c = cos(x);
+                ss = -s-c;
+                cc = s-c;
+                if(ix<0x7fe00000) {  /* make sure x+x not overflow */
+                    z = cos(x+x);
+                    if ((s*c)>zero) cc = z/ss;
+                    else            ss = z/cc;
+                }
+        /* y1(x) = sqrt(2/(pi*x))*(p1(x)*sin(x0)+q1(x)*cos(x0))
+         * where x0 = x-3pi/4
+         *      Better formula:
+         *              cos(x0) = cos(x)cos(3pi/4)+sin(x)sin(3pi/4)
+         *                      =  1/sqrt(2) * (sin(x) - cos(x))
+         *              sin(x0) = sin(x)cos(3pi/4)-cos(x)sin(3pi/4)
+         *                      = -1/sqrt(2) * (cos(x) + sin(x))
+         * To avoid cancellation, use
+         *              sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
+         * to compute the worse one.
+         */
+                if(ix>0x48000000) z = (invsqrtpi*ss)/sqrt(x);
+                else {
+                    u = pone(x); v = qone(x);
+                    z = invsqrtpi*(u*ss+v*cc)/sqrt(x);
+                }
+                return z;
+        } 
+        if(ix<=0x3c900000) {    /* x < 2**-54 */
+            return(-tpi/x);
+        } 
+        z = x*x;
+        u = U0[0]+z*(U0[1]+z*(U0[2]+z*(U0[3]+z*U0[4])));
+        v = one+z*(V0[0]+z*(V0[1]+z*(V0[2]+z*(V0[3]+z*V0[4]))));
+        return(x*(u/v) + tpi*(__ieee754_j1(x)*__ieee754_log(x)-one/x));
+}
+
+/* For x >= 8, the asymptotic expansions of pone is
+ *	1 + 15/128 s^2 - 4725/2^15 s^4 - ...,	where s = 1/x.
+ * We approximate pone by
+ * 	pone(x) = 1 + (R/S)
+ * where  R = pr0 + pr1*s^2 + pr2*s^4 + ... + pr5*s^10
+ * 	  S = 1 + ps0*s^2 + ... + ps4*s^10
+ * and
+ *	| pone(x)-1-R/S | <= 2  ** ( -60.06)
+ */
+
+static const double pr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+  1.17187499999988647970e-01, /* 0x3FBDFFFF, 0xFFFFFCCE */
+  1.32394806593073575129e+01, /* 0x402A7A9D, 0x357F7FCE */
+  4.12051854307378562225e+02, /* 0x4079C0D4, 0x652EA590 */
+  3.87474538913960532227e+03, /* 0x40AE457D, 0xA3A532CC */
+  7.91447954031891731574e+03, /* 0x40BEEA7A, 0xC32782DD */
+};
+static const double ps8[5] = {
+  1.14207370375678408436e+02, /* 0x405C8D45, 0x8E656CAC */
+  3.65093083420853463394e+03, /* 0x40AC85DC, 0x964D274F */
+  3.69562060269033463555e+04, /* 0x40E20B86, 0x97C5BB7F */
+  9.76027935934950801311e+04, /* 0x40F7D42C, 0xB28F17BB */
+  3.08042720627888811578e+04, /* 0x40DE1511, 0x697A0B2D */
+};
+
+static const double pr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+  1.31990519556243522749e-11, /* 0x3DAD0667, 0xDAE1CA7D */
+  1.17187493190614097638e-01, /* 0x3FBDFFFF, 0xE2C10043 */
+  6.80275127868432871736e+00, /* 0x401B3604, 0x6E6315E3 */
+  1.08308182990189109773e+02, /* 0x405B13B9, 0x452602ED */
+  5.17636139533199752805e+02, /* 0x40802D16, 0xD052D649 */
+  5.28715201363337541807e+02, /* 0x408085B8, 0xBB7E0CB7 */
+};
+static const double ps5[5] = {
+  5.92805987221131331921e+01, /* 0x404DA3EA, 0xA8AF633D */
+  9.91401418733614377743e+02, /* 0x408EFB36, 0x1B066701 */
+  5.35326695291487976647e+03, /* 0x40B4E944, 0x5706B6FB */
+  7.84469031749551231769e+03, /* 0x40BEA4B0, 0xB8A5BB15 */
+  1.50404688810361062679e+03, /* 0x40978030, 0x036F5E51 */
+};
+
+static const double pr3[6] = {
+  3.02503916137373618024e-09, /* 0x3E29FC21, 0xA7AD9EDD */
+  1.17186865567253592491e-01, /* 0x3FBDFFF5, 0x5B21D17B */
+  3.93297750033315640650e+00, /* 0x400F76BC, 0xE85EAD8A */
+  3.51194035591636932736e+01, /* 0x40418F48, 0x9DA6D129 */
+  9.10550110750781271918e+01, /* 0x4056C385, 0x4D2C1837 */
+  4.85590685197364919645e+01, /* 0x4048478F, 0x8EA83EE5 */
+};
+static const double ps3[5] = {
+  3.47913095001251519989e+01, /* 0x40416549, 0xA134069C */
+  3.36762458747825746741e+02, /* 0x40750C33, 0x07F1A75F */
+  1.04687139975775130551e+03, /* 0x40905B7C, 0x5037D523 */
+  8.90811346398256432622e+02, /* 0x408BD67D, 0xA32E31E9 */
+  1.03787932439639277504e+02, /* 0x4059F26D, 0x7C2EED53 */
+};
+
+static const double pr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+  1.07710830106873743082e-07, /* 0x3E7CE9D4, 0xF65544F4 */
+  1.17176219462683348094e-01, /* 0x3FBDFF42, 0xBE760D83 */
+  2.36851496667608785174e+00, /* 0x4002F2B7, 0xF98FAEC0 */
+  1.22426109148261232917e+01, /* 0x40287C37, 0x7F71A964 */
+  1.76939711271687727390e+01, /* 0x4031B1A8, 0x177F8EE2 */
+  5.07352312588818499250e+00, /* 0x40144B49, 0xA574C1FE */
+};
+static const double ps2[5] = {
+  2.14364859363821409488e+01, /* 0x40356FBD, 0x8AD5ECDC */
+  1.25290227168402751090e+02, /* 0x405F5293, 0x14F92CD5 */
+  2.32276469057162813669e+02, /* 0x406D08D8, 0xD5A2DBD9 */
+  1.17679373287147100768e+02, /* 0x405D6B7A, 0xDA1884A9 */
+  8.36463893371618283368e+00, /* 0x4020BAB1, 0xF44E5192 */
+};
+
+	static double pone(double x)
+{
+	const double *p,*q;
+	double z,r,s;
+        int ix;
+        ix = 0x7fffffff&__HI(x);
+        if(ix>=0x40200000)     {p = pr8; q= ps8;}
+        else if(ix>=0x40122E8B){p = pr5; q= ps5;}
+        else if(ix>=0x4006DB6D){p = pr3; q= ps3;}
+        else if(ix>=0x40000000){p = pr2; q= ps2;}
+        z = one/(x*x);
+        r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+        s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*q[4]))));
+        return one+ r/s;
+}
+		
+
+/* For x >= 8, the asymptotic expansions of qone is
+ *	3/8 s - 105/1024 s^3 - ..., where s = 1/x.
+ * We approximate pone by
+ * 	qone(x) = s*(0.375 + (R/S))
+ * where  R = qr1*s^2 + qr2*s^4 + ... + qr5*s^10
+ * 	  S = 1 + qs1*s^2 + ... + qs6*s^12
+ * and
+ *	| qone(x)/s -0.375-R/S | <= 2  ** ( -61.13)
+ */
+
+static const double qr8[6] = { /* for x in [inf, 8]=1/[0,0.125] */
+  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+ -1.02539062499992714161e-01, /* 0xBFBA3FFF, 0xFFFFFDF3 */
+ -1.62717534544589987888e+01, /* 0xC0304591, 0xA26779F7 */
+ -7.59601722513950107896e+02, /* 0xC087BCD0, 0x53E4B576 */
+ -1.18498066702429587167e+04, /* 0xC0C724E7, 0x40F87415 */
+ -4.84385124285750353010e+04, /* 0xC0E7A6D0, 0x65D09C6A */
+};
+static const double qs8[6] = {
+  1.61395369700722909556e+02, /* 0x40642CA6, 0xDE5BCDE5 */
+  7.82538599923348465381e+03, /* 0x40BE9162, 0xD0D88419 */
+  1.33875336287249578163e+05, /* 0x4100579A, 0xB0B75E98 */
+  7.19657723683240939863e+05, /* 0x4125F653, 0x72869C19 */
+  6.66601232617776375264e+05, /* 0x412457D2, 0x7719AD5C */
+ -2.94490264303834643215e+05, /* 0xC111F969, 0x0EA5AA18 */
+};
+
+static const double qr5[6] = { /* for x in [8,4.5454]=1/[0.125,0.22001] */
+ -2.08979931141764104297e-11, /* 0xBDB6FA43, 0x1AA1A098 */
+ -1.02539050241375426231e-01, /* 0xBFBA3FFF, 0xCB597FEF */
+ -8.05644828123936029840e+00, /* 0xC0201CE6, 0xCA03AD4B */
+ -1.83669607474888380239e+02, /* 0xC066F56D, 0x6CA7B9B0 */
+ -1.37319376065508163265e+03, /* 0xC09574C6, 0x6931734F */
+ -2.61244440453215656817e+03, /* 0xC0A468E3, 0x88FDA79D */
+};
+static const double qs5[6] = {
+  8.12765501384335777857e+01, /* 0x405451B2, 0xFF5A11B2 */
+  1.99179873460485964642e+03, /* 0x409F1F31, 0xE77BF839 */
+  1.74684851924908907677e+04, /* 0x40D10F1F, 0x0D64CE29 */
+  4.98514270910352279316e+04, /* 0x40E8576D, 0xAABAD197 */
+  2.79480751638918118260e+04, /* 0x40DB4B04, 0xCF7C364B */
+ -4.71918354795128470869e+03, /* 0xC0B26F2E, 0xFCFFA004 */
+};
+
+static const double qr3[6] = {
+ -5.07831226461766561369e-09, /* 0xBE35CFA9, 0xD38FC84F */
+ -1.02537829820837089745e-01, /* 0xBFBA3FEB, 0x51AEED54 */
+ -4.61011581139473403113e+00, /* 0xC01270C2, 0x3302D9FF */
+ -5.78472216562783643212e+01, /* 0xC04CEC71, 0xC25D16DA */
+ -2.28244540737631695038e+02, /* 0xC06C87D3, 0x4718D55F */
+ -2.19210128478909325622e+02, /* 0xC06B66B9, 0x5F5C1BF6 */
+};
+static const double qs3[6] = {
+  4.76651550323729509273e+01, /* 0x4047D523, 0xCCD367E4 */
+  6.73865112676699709482e+02, /* 0x40850EEB, 0xC031EE3E */
+  3.38015286679526343505e+03, /* 0x40AA684E, 0x448E7C9A */
+  5.54772909720722782367e+03, /* 0x40B5ABBA, 0xA61D54A6 */
+  1.90311919338810798763e+03, /* 0x409DBC7A, 0x0DD4DF4B */
+ -1.35201191444307340817e+02, /* 0xC060E670, 0x290A311F */
+};
+
+static const double qr2[6] = {/* for x in [2.8570,2]=1/[0.3499,0.5] */
+ -1.78381727510958865572e-07, /* 0xBE87F126, 0x44C626D2 */
+ -1.02517042607985553460e-01, /* 0xBFBA3E8E, 0x9148B010 */
+ -2.75220568278187460720e+00, /* 0xC0060484, 0x69BB4EDA */
+ -1.96636162643703720221e+01, /* 0xC033A9E2, 0xC168907F */
+ -4.23253133372830490089e+01, /* 0xC04529A3, 0xDE104AAA */
+ -2.13719211703704061733e+01, /* 0xC0355F36, 0x39CF6E52 */
+};
+static const double qs2[6] = {
+  2.95333629060523854548e+01, /* 0x403D888A, 0x78AE64FF */
+  2.52981549982190529136e+02, /* 0x406F9F68, 0xDB821CBA */
+  7.57502834868645436472e+02, /* 0x4087AC05, 0xCE49A0F7 */
+  7.39393205320467245656e+02, /* 0x40871B25, 0x48D4C029 */
+  1.55949003336666123687e+02, /* 0x40637E5E, 0x3C3ED8D4 */
+ -4.95949898822628210127e+00, /* 0xC013D686, 0xE71BE86B */
+};
+
+	static double qone(double x)
+{
+	const double *p,*q;
+	double  s,r,z;
+	int ix;
+	ix = 0x7fffffff&__HI(x);
+	if(ix>=0x40200000)     {p = qr8; q= qs8;}
+	else if(ix>=0x40122E8B){p = qr5; q= qs5;}
+	else if(ix>=0x4006DB6D){p = qr3; q= qs3;}
+	else if(ix>=0x40000000){p = qr2; q= qs2;}
+	z = one/(x*x);
+	r = p[0]+z*(p[1]+z*(p[2]+z*(p[3]+z*(p[4]+z*p[5]))));
+	s = one+z*(q[0]+z*(q[1]+z*(q[2]+z*(q[3]+z*(q[4]+z*q[5])))));
+	return (.375 + r/s)/x;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_jn.c
@@ -1,0 +1,259 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_jn.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __ieee754_jn(n, x), __ieee754_yn(n, x)
+ * floating point Bessel's function of the 1st and 2nd kind
+ * of order n
+ *          
+ * Special cases:
+ *	y0(0)=y1(0)=yn(n,0) = -inf with division by zero signal;
+ *	y0(-ve)=y1(-ve)=yn(n,-ve) are NaN with invalid signal.
+ * Note 2. About jn(n,x), yn(n,x)
+ *	For n=0, j0(x) is called,
+ *	for n=1, j1(x) is called,
+ *	for n<x, forward recursion us used starting
+ *	from values of j0(x) and j1(x).
+ *	for n>x, a continued fraction approximation to
+ *	j(n,x)/j(n-1,x) is evaluated and then backward
+ *	recursion is used starting from a supposed value
+ *	for j(n,x). The resulting value of j(0,x) is
+ *	compared with the actual value to correct the
+ *	supposed value of j(n,x).
+ *
+ *	yn(n,x) is similar in all respects, except
+ *	that forward recursion is used for all
+ *	values of n>1.
+ *	
+ */
+
+#include "fdlibm.h"
+
+static const double
+invsqrtpi=  5.64189583547756279280e-01, /* 0x3FE20DD7, 0x50429B6D */
+two   =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+one   =  1.00000000000000000000e+00; /* 0x3FF00000, 0x00000000 */
+
+static double zero  =  0.00000000000000000000e+00;
+
+	double __ieee754_jn(int n, double x)
+{
+	int i,hx,ix,lx, sgn;
+	double a, b, temp, di;
+	double z, w;
+
+    /* J(-n,x) = (-1)^n * J(n, x), J(n, -x) = (-1)^n * J(n, x)
+     * Thus, J(-n,x) = J(n,-x)
+     */
+	hx = __HI(x);
+	ix = 0x7fffffff&hx;
+	lx = __LO(x);
+    /* if J(n,NaN) is NaN */
+	if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+	if(n<0){		
+		n = -n;
+		x = -x;
+		hx ^= 0x80000000;
+	}
+	if(n==0) return(__ieee754_j0(x));
+	if(n==1) return(__ieee754_j1(x));
+	sgn = (n&1)&(hx>>31);	/* even n -- 0, odd n -- sign(x) */
+	x = fabs(x);
+	if((ix|lx)==0||ix>=0x7ff00000) 	/* if x is 0 or inf */
+	    b = zero;
+	else if((double)n<=x) {   
+		/* Safe to use J(n+1,x)=2n/x *J(n,x)-J(n-1,x) */
+	    if(ix>=0x52D00000) { /* x > 2**302 */
+    /* (x >> n**2) 
+     *	    Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *	    Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *	    Let s=sin(x), c=cos(x), 
+     *		xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+     *
+     *		   n	sin(xn)*sqt2	cos(xn)*sqt2
+     *		----------------------------------
+     *		   0	 s-c		 c+s
+     *		   1	-s-c 		-c+s
+     *		   2	-s+c		-c-s
+     *		   3	 s+c		 c-s
+     */
+		switch(n&3) {
+		    case 0: temp =  cos(x)+sin(x); break;
+		    case 1: temp = -cos(x)+sin(x); break;
+		    case 2: temp = -cos(x)-sin(x); break;
+		    case 3: temp =  cos(x)-sin(x); break;
+		}
+		b = invsqrtpi*temp/sqrt(x);
+	    } else {	
+	        a = __ieee754_j0(x);
+	        b = __ieee754_j1(x);
+	        for(i=1;i<n;i++){
+		    temp = b;
+		    b = b*((double)(i+i)/x) - a; /* avoid underflow */
+		    a = temp;
+	        }
+	    }
+	} else {
+	    if(ix<0x3e100000) {	/* x < 2**-29 */
+    /* x is tiny, return the first Taylor expansion of J(n,x) 
+     * J(n,x) = 1/n!*(x/2)^n  - ...
+     */
+		if(n>33)	/* underflow */
+		    b = zero;
+		else {
+		    temp = x*0.5; b = temp;
+		    for (a=one,i=2;i<=n;i++) {
+			a *= (double)i;		/* a = n! */
+			b *= temp;		/* b = (x/2)^n */
+		    }
+		    b = b/a;
+		}
+	    } else {
+		/* use backward recurrence */
+		/* 			x      x^2      x^2       
+		 *  J(n,x)/J(n-1,x) =  ----   ------   ------   .....
+		 *			2n  - 2(n+1) - 2(n+2)
+		 *
+		 * 			1      1        1       
+		 *  (for large x)   =  ----  ------   ------   .....
+		 *			2n   2(n+1)   2(n+2)
+		 *			-- - ------ - ------ - 
+		 *			 x     x         x
+		 *
+		 * Let w = 2n/x and h=2/x, then the above quotient
+		 * is equal to the continued fraction:
+		 *		    1
+		 *	= -----------------------
+		 *		       1
+		 *	   w - -----------------
+		 *			  1
+		 * 	        w+h - ---------
+		 *		       w+2h - ...
+		 *
+		 * To determine how many terms needed, let
+		 * Q(0) = w, Q(1) = w(w+h) - 1,
+		 * Q(k) = (w+k*h)*Q(k-1) - Q(k-2),
+		 * When Q(k) > 1e4	good for single 
+		 * When Q(k) > 1e9	good for double 
+		 * When Q(k) > 1e17	good for quadruple 
+		 */
+	    /* determine k */
+		double t,v;
+		double q0,q1,h,tmp; int k,m;
+		w  = (n+n)/(double)x; h = 2.0/(double)x;
+		q0 = w;  z = w+h; q1 = w*z - 1.0; k=1;
+		while(q1<1.0e9) {
+			k += 1; z += h;
+			tmp = z*q1 - q0;
+			q0 = q1;
+			q1 = tmp;
+		}
+		m = n+n;
+		for(t=zero, i = 2*(n+k); i>=m; i -= 2) t = one/(i/x-t);
+		a = t;
+		b = one;
+		/*  estimate log((2/x)^n*n!) = n*log(2/x)+n*ln(n)
+		 *  Hence, if n*(log(2n/x)) > ...
+		 *  single 8.8722839355e+01
+		 *  double 7.09782712893383973096e+02
+		 *  long double 1.1356523406294143949491931077970765006170e+04
+		 *  then recurrent value may overflow and the result is 
+		 *  likely underflow to zero
+		 */
+		tmp = n;
+		v = two/x;
+		tmp = tmp*__ieee754_log(fabs(v*tmp));
+		if(tmp<7.09782712893383973096e+02) {
+	    	    for(i=n-1,di=(double)(i+i);i>0;i--){
+		        temp = b;
+			b *= di;
+			b  = b/x - a;
+		        a = temp;
+			di -= two;
+	     	    }
+		} else {
+	    	    for(i=n-1,di=(double)(i+i);i>0;i--){
+		        temp = b;
+			b *= di;
+			b  = b/x - a;
+		        a = temp;
+			di -= two;
+		    /* scale b to avoid spurious overflow */
+			if(b>1e100) {
+			    a /= b;
+			    t /= b;
+			    b  = one;
+			}
+	     	    }
+		}
+	    	b = (t*__ieee754_j0(x)/b);
+	    }
+	}
+	if(sgn==1) return -b; else return b;
+}
+
+	double __ieee754_yn(int n, double x) 
+{
+	int i,hx,ix,lx;
+	int sign;
+	double a, b, temp;
+
+	hx = __HI(x);
+	ix = 0x7fffffff&hx;
+	lx = __LO(x);
+    /* if Y(n,NaN) is NaN */
+	if((ix|((unsigned)(lx|-lx))>>31)>0x7ff00000) return x+x;
+	if((ix|lx)==0) return -one/zero;
+	if(hx<0) return zero/zero;
+	sign = 1;
+	if(n<0){
+		n = -n;
+		sign = 1 - ((n&1)<<1);
+	}
+	if(n==0) return(__ieee754_y0(x));
+	if(n==1) return(sign*__ieee754_y1(x));
+	if(ix==0x7ff00000) return zero;
+	if(ix>=0x52D00000) { /* x > 2**302 */
+    /* (x >> n**2) 
+     *	    Jn(x) = cos(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *	    Yn(x) = sin(x-(2n+1)*pi/4)*sqrt(2/x*pi)
+     *	    Let s=sin(x), c=cos(x), 
+     *		xn=x-(2n+1)*pi/4, sqt2 = sqrt(2),then
+     *
+     *		   n	sin(xn)*sqt2	cos(xn)*sqt2
+     *		----------------------------------
+     *		   0	 s-c		 c+s
+     *		   1	-s-c 		-c+s
+     *		   2	-s+c		-c-s
+     *		   3	 s+c		 c-s
+     */
+		switch(n&3) {
+		    case 0: temp =  sin(x)-cos(x); break;
+		    case 1: temp = -sin(x)-cos(x); break;
+		    case 2: temp = -sin(x)+cos(x); break;
+		    case 3: temp =  sin(x)+cos(x); break;
+		}
+		b = invsqrtpi*temp/sqrt(x);
+	} else {
+	    a = __ieee754_y0(x);
+	    b = __ieee754_y1(x);
+	/* quit if b is -inf */
+	    for(i=1;i<n&&(__HI(b) != 0xfff00000);i++){ 
+		temp = b;
+		b = ((double)(i+i)/x)*b - a;
+		a = temp;
+	    }
+	}
+	if(sign>0) return b; else return -b;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_lgamma_r.c
@@ -1,0 +1,291 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_lgamma_r(x, signgamp)
+ * Reentrant version of the logarithm of the Gamma function 
+ * with user provide pointer for the sign of Gamma(x). 
+ *
+ * Method:
+ *   1. Argument Reduction for 0 < x <= 8
+ * 	Since gamma(1+s)=s*gamma(s), for x in [0,8], we may 
+ * 	reduce x to a number in [1.5,2.5] by
+ * 		lgamma(1+s) = log(s) + lgamma(s)
+ *	for example,
+ *		lgamma(7.3) = log(6.3) + lgamma(6.3)
+ *			    = log(6.3*5.3) + lgamma(5.3)
+ *			    = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3)
+ *   2. Polynomial approximation of lgamma around its
+ *	minimun ymin=1.461632144968362245 to maintain monotonicity.
+ *	On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use
+ *		Let z = x-ymin;
+ *		lgamma(x) = -1.214862905358496078218 + z^2*poly(z)
+ *	where
+ *		poly(z) is a 14 degree polynomial.
+ *   2. Rational approximation in the primary interval [2,3]
+ *	We use the following approximation:
+ *		s = x-2.0;
+ *		lgamma(x) = 0.5*s + s*P(s)/Q(s)
+ *	with accuracy
+ *		|P/Q - (lgamma(x)-0.5s)| < 2**-61.71
+ *	Our algorithms are based on the following observation
+ *
+ *                             zeta(2)-1    2    zeta(3)-1    3
+ * lgamma(2+s) = s*(1-Euler) + --------- * s  -  --------- * s  + ...
+ *                                 2                 3
+ *
+ *	where Euler = 0.5771... is the Euler constant, which is very
+ *	close to 0.5.
+ *
+ *   3. For x>=8, we have
+ *	lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+....
+ *	(better formula:
+ *	   lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...)
+ *	Let z = 1/x, then we approximation
+ *		f(z) = lgamma(x) - (x-0.5)(log(x)-1)
+ *	by
+ *	  			    3       5             11
+ *		w = w0 + w1*z + w2*z  + w3*z  + ... + w6*z
+ *	where 
+ *		|w - f(z)| < 2**-58.74
+ *		
+ *   4. For negative x, since (G is gamma function)
+ *		-x*G(-x)*G(x) = pi/sin(pi*x),
+ * 	we have
+ * 		G(x) = pi/(sin(pi*x)*(-x)*G(-x))
+ *	since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
+ *	Hence, for x<0, signgam = sign(sin(pi*x)) and 
+ *		lgamma(x) = log(|Gamma(x)|)
+ *			  = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
+ *	Note: one should avoid compute pi*(-x) directly in the 
+ *	      computation of sin(pi*(-x)).
+ *		
+ *   5. Special Cases
+ *		lgamma(2+s) ~ s*(1-Euler) for tiny s
+ *		lgamma(1)=lgamma(2)=0
+ *		lgamma(x) ~ -log(x) for tiny x
+ *		lgamma(0) = lgamma(inf) = inf
+ *	 	lgamma(-integer) = +-inf
+ *	
+ */
+
+#include "fdlibm.h"
+
+static const double 
+two52=  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pi  =  3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
+a0  =  7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */
+a1  =  3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */
+a2  =  6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */
+a3  =  2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */
+a4  =  7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */
+a5  =  2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */
+a6  =  1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */
+a7  =  5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */
+a8  =  2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */
+a9  =  1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */
+a10 =  2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */
+a11 =  4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */
+tc  =  1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */
+tf  = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */
+/* tt = -(tail of tf) */
+tt  = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */
+t0  =  4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */
+t1  = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */
+t2  =  6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */
+t3  = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */
+t4  =  1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */
+t5  = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */
+t6  =  6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */
+t7  = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */
+t8  =  2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */
+t9  = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */
+t10 =  8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */
+t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */
+t12 =  3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */
+t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */
+t14 =  3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */
+u0  = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+u1  =  6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */
+u2  =  1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */
+u3  =  9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */
+u4  =  2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */
+u5  =  1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */
+v1  =  2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */
+v2  =  2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */
+v3  =  7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */
+v4  =  1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */
+v5  =  3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */
+s0  = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */
+s1  =  2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */
+s2  =  3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */
+s3  =  1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */
+s4  =  2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */
+s5  =  1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */
+s6  =  3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */
+r1  =  1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */
+r2  =  7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */
+r3  =  1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */
+r4  =  1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */
+r5  =  7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */
+r6  =  7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */
+w0  =  4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */
+w1  =  8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */
+w2  = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */
+w3  =  7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */
+w4  = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
+w5  =  8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
+w6  = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
+
+static double zero=  0.00000000000000000000e+00;
+
+	static double sin_pi(double x)
+{
+	double y,z;
+	int n,ix;
+
+	ix = 0x7fffffff&__HI(x);
+
+	if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
+	y = -x;		/* x is assume negative */
+
+    /*
+     * argument reduction, make sure inexact flag not raised if input
+     * is an integer
+     */
+	z = floor(y);
+	if(z!=y) {				/* inexact anyway */
+	    y  *= 0.5;
+	    y   = 2.0*(y - floor(y));		/* y = |x| mod 2.0 */
+	    n   = (int) (y*4.0);
+	} else {
+            if(ix>=0x43400000) {
+                y = zero; n = 0;                 /* y must be even */
+            } else {
+                if(ix<0x43300000) z = y+two52;	/* exact */
+                n   = __LO(z)&1;        /* lower word of z */
+                y  = n;
+                n<<= 2;
+            }
+        }
+	switch (n) {
+	    case 0:   y =  __kernel_sin(pi*y,zero,0); break;
+	    case 1:   
+	    case 2:   y =  __kernel_cos(pi*(0.5-y),zero); break;
+	    case 3:  
+	    case 4:   y =  __kernel_sin(pi*(one-y),zero,0); break;
+	    case 5:
+	    case 6:   y = -__kernel_cos(pi*(y-1.5),zero); break;
+	    default:  y =  __kernel_sin(pi*(y-2.0),zero,0); break;
+	    }
+	return -y;
+}
+
+
+	double __ieee754_lgamma_r(double x, int *signgamp)
+{
+	double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+	int i,hx,lx,ix;
+
+	hx = __HI(x);
+	lx = __LO(x);
+
+    /* purge off +-inf, NaN, +-0, and negative arguments */
+	*signgamp = 1;
+	ix = hx&0x7fffffff;
+	if(ix>=0x7ff00000) return x*x;
+	if((ix|lx)==0) return one/zero;
+	if(ix<0x3b900000) {	/* |x|<2**-70, return -log(|x|) */
+	    if(hx<0) {
+	        *signgamp = -1;
+	        return -__ieee754_log(-x);
+	    } else return -__ieee754_log(x);
+	}
+	if(hx<0) {
+	    if(ix>=0x43300000) 	/* |x|>=2**52, must be -integer */
+		return one/zero;
+	    t = sin_pi(x);
+	    if(t==zero) return one/zero; /* -integer */
+	    nadj = __ieee754_log(pi/fabs(t*x));
+	    if(t<zero) *signgamp = -1;
+	    x = -x;
+	}
+
+    /* purge off 1 and 2 */
+	if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
+    /* for x < 2.0 */
+	else if(ix<0x40000000) {
+	    if(ix<=0x3feccccc) { 	/* lgamma(x) = lgamma(x+1)-log(x) */
+		r = -__ieee754_log(x);
+		if(ix>=0x3FE76944) {y = one-x; i= 0;}
+		else if(ix>=0x3FCDA661) {y= x-(tc-one); i=1;}
+	  	else {y = x; i=2;}
+	    } else {
+	  	r = zero;
+	        if(ix>=0x3FFBB4C3) {y=2.0-x;i=0;} /* [1.7316,2] */
+	        else if(ix>=0x3FF3B4C4) {y=x-tc;i=1;} /* [1.23,1.73] */
+		else {y=x-one;i=2;}
+	    }
+	    switch(i) {
+	      case 0:
+		z = y*y;
+		p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
+		p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+		p  = y*p1+p2;
+		r  += (p-0.5*y); break;
+	      case 1:
+		z = y*y;
+		w = z*y;
+		p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12)));	/* parallel comp */
+		p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
+		p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
+		p  = z*p1-(tt-w*(p2+y*p3));
+		r += (tf + p); break;
+	      case 2:	
+		p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
+		p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
+		r += (-0.5*y + p1/p2);
+	    }
+	}
+	else if(ix<0x40200000) { 			/* x < 8.0 */
+	    i = (int)x;
+	    t = zero;
+	    y = x-(double)i;
+	    p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+	    q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
+	    r = half*y+p/q;
+	    z = one;	/* lgamma(1+s) = log(s) + lgamma(s) */
+	    switch(i) {
+	    case 7: z *= (y+6.0);	/* FALLTHRU */
+	    case 6: z *= (y+5.0);	/* FALLTHRU */
+	    case 5: z *= (y+4.0);	/* FALLTHRU */
+	    case 4: z *= (y+3.0);	/* FALLTHRU */
+	    case 3: z *= (y+2.0);	/* FALLTHRU */
+		    r += __ieee754_log(z); break;
+	    }
+    /* 8.0 <= x < 2**58 */
+	} else if (ix < 0x43900000) {
+	    t = __ieee754_log(x);
+	    z = one/x;
+	    y = z*z;
+	    w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+	    r = (x-half)*(t-one)+w;
+	} else 
+    /* 2**58 <= x <= inf */
+	    r =  x*(__ieee754_log(x)-one);
+	if(hx<0) r = nadj - r;
+	return r;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_log.c
@@ -1,0 +1,131 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_log.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log(x)
+ * Return the logrithm of x
+ *
+ * Method :                  
+ *   1. Argument Reduction: find k and f such that 
+ *			x = 2^k * (1+f), 
+ *	   where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *   2. Approximation of log(1+f).
+ *	Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *		 = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *	     	 = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate 
+ * 	a polynomial of degree 14 to approximate R The maximum error 
+ *	of this polynomial approximation is bounded by 2**-58.45. In
+ *	other words,
+ *		        2      4      6      8      10      12      14
+ *	    R(z) ~ Lg1*s +Lg2*s +Lg3*s +Lg4*s +Lg5*s  +Lg6*s  +Lg7*s
+ *  	(the values of Lg1 to Lg7 are listed in the program)
+ *	and
+ *	    |      2          14          |     -58.45
+ *	    | Lg1*s +...+Lg7*s    -  R(z) | <= 2 
+ *	    |                             |
+ *	Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *	In order to guarantee error in log below 1ulp, we compute log
+ *	by
+ *		log(1+f) = f - s*(f - R)	(if f is not too large)
+ *		log(1+f) = f - (hfsq - s*(hfsq+R)).	(better accuracy)
+ *	
+ *	3. Finally,  log(x) = k*ln2 + log(1+f).  
+ *			    = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *	   Here ln2 is split into two floating point number: 
+ *			ln2_hi + ln2_lo,
+ *	   where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *	log(x) is NaN with signal if x < 0 (including -INF) ; 
+ *	log(+INF) is +INF; log(0) is -INF with signal;
+ *	log(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *	according to an error analysis, the error is always less than
+ *	1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01,	/* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10,	/* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lg1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lg2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lg3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lg4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lg5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lg6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lg7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static double zero   =  0.0;
+
+	double __ieee754_log(double x)
+{
+	double hfsq,f,s,z,R,w,t1,t2,dk;
+	int k,hx,i,j;
+	unsigned lx;
+
+	hx = __HI(x);		/* high word of x */
+	lx = __LO(x);		/* low  word of x */
+
+	k=0;
+	if (hx < 0x00100000) {			/* x < 2**-1022  */
+	    if (((hx&0x7fffffff)|lx)==0) 
+		return -two54/zero;		/* log(+-0)=-inf */
+	    if (hx<0) return (x-x)/zero;	/* log(-#) = NaN */
+	    k -= 54; x *= two54; /* subnormal number, scale up x */
+	    hx = __HI(x);		/* high word of x */
+	} 
+	if (hx >= 0x7ff00000) return x+x;
+	k += (hx>>20)-1023;
+	hx &= 0x000fffff;
+	i = (hx+0x95f64)&0x100000;
+	__HI(x) = hx|(i^0x3ff00000);	/* normalize x or x/2 */
+	k += (i>>20);
+	f = x-1.0;
+	if((0x000fffff&(2+hx))<3) {	/* |f| < 2**-20 */
+	    if(f==zero) if(k==0) return zero;  else {dk=(double)k;
+				 return dk*ln2_hi+dk*ln2_lo;}
+	    R = f*f*(0.5-0.33333333333333333*f);
+	    if(k==0) return f-R; else {dk=(double)k;
+	    	     return dk*ln2_hi-((R-dk*ln2_lo)-f);}
+	}
+ 	s = f/(2.0+f); 
+	dk = (double)k;
+	z = s*s;
+	i = hx-0x6147a;
+	w = z*z;
+	j = 0x6b851-hx;
+	t1= w*(Lg2+w*(Lg4+w*Lg6)); 
+	t2= z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); 
+	i |= j;
+	R = t2+t1;
+	if(i>0) {
+	    hfsq=0.5*f*f;
+	    if(k==0) return f-(hfsq-s*(hfsq+R)); else
+		     return dk*ln2_hi-((hfsq-(s*(hfsq+R)+dk*ln2_lo))-f);
+	} else {
+	    if(k==0) return f-s*(f-R); else
+		     return dk*ln2_hi-((s*(f-R)-dk*ln2_lo)-f);
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/e_log10.c
@@ -1,0 +1,83 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_log10.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_log10(x)
+ * Return the base 10 logarithm of x
+ * 
+ * Method :
+ *	Let log10_2hi = leading 40 bits of log10(2) and
+ *	    log10_2lo = log10(2) - log10_2hi,
+ *	    ivln10   = 1/log(10) rounded.
+ *	Then
+ *		n = ilogb(x), 
+ *		if(n<0)  n = n+1;
+ *		x = scalbn(x,-n);
+ *		log10(x) := n*log10_2hi + (n*log10_2lo + ivln10*log(x))
+ *
+ * Note 1:
+ *	To guarantee log10(10**n)=n, where 10**n is normal, the rounding 
+ *	mode must set to Round-to-Nearest.
+ * Note 2:
+ *	[1/log(10)] rounded to 53 bits has error  .198   ulps;
+ *	log10 is monotonic at all binary break points.
+ *
+ * Special cases:
+ *	log10(x) is NaN with signal if x < 0; 
+ *	log10(+INF) is +INF with no signal; log10(0) is -INF with signal;
+ *	log10(NaN) is that NaN with no signal;
+ *	log10(10**N) = N  for N=0,1,...,22.
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following constants.
+ * The decimal values may be used, provided that the compiler will convert
+ * from decimal to binary accurately enough to produce the hexadecimal values
+ * shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+two54      =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+ivln10     =  4.34294481903251816668e-01, /* 0x3FDBCB7B, 0x1526E50E */
+log10_2hi  =  3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */
+log10_2lo  =  3.69423907715893078616e-13; /* 0x3D59FEF3, 0x11F12B36 */
+
+static double zero   =  0.0;
+
+	double __ieee754_log10(double x)
+{
+	double y,z;
+	int i,k,hx;
+	unsigned lx;
+
+	hx = __HI(x);	/* high word of x */
+	lx = __LO(x);	/* low word of x */
+
+        k=0;
+        if (hx < 0x00100000) {                  /* x < 2**-1022  */
+            if (((hx&0x7fffffff)|lx)==0)
+                return -two54/zero;             /* log(+-0)=-inf */
+            if (hx<0) return (x-x)/zero;        /* log(-#) = NaN */
+            k -= 54; x *= two54; /* subnormal number, scale up x */
+            hx = __HI(x);                /* high word of x */
+        }
+	if (hx >= 0x7ff00000) return x+x;
+	k += (hx>>20)-1023;
+	i  = ((unsigned)k&0x80000000)>>31;
+        hx = (hx&0x000fffff)|((0x3ff-i)<<20);
+        y  = (double)(k+i);
+        __HI(x) = hx;
+	z  = y*log10_2lo + ivln10*__ieee754_log(x);
+	return  z+y*log10_2hi;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_pow.c
@@ -1,0 +1,296 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_pow.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_pow(x,y) return x**y
+ *
+ *		      n
+ * Method:  Let x =  2   * (1+f)
+ *	1. Compute and return log2(x) in two pieces:
+ *		log2(x) = w1 + w2,
+ *	   where w1 has 53-24 = 29 bit trailing zeros.
+ *	2. Perform y*log2(x) = n+y' by simulating muti-precision 
+ *	   arithmetic, where |y'|<=0.5.
+ *	3. Return x**y = 2**n*exp(y'*log2)
+ *
+ * Special cases:
+ *	1.  (anything) ** 0  is 1
+ *	2.  (anything) ** 1  is itself
+ *	3.  (anything) ** NAN is NAN
+ *	4.  NAN ** (anything except 0) is NAN
+ *	5.  +-(|x| > 1) **  +INF is +INF
+ *	6.  +-(|x| > 1) **  -INF is +0
+ *	7.  +-(|x| < 1) **  +INF is +0
+ *	8.  +-(|x| < 1) **  -INF is +INF
+ *	9.  +-1         ** +-INF is NAN
+ *	10. +0 ** (+anything except 0, NAN)               is +0
+ *	11. -0 ** (+anything except 0, NAN, odd integer)  is +0
+ *	12. +0 ** (-anything except 0, NAN)               is +INF
+ *	13. -0 ** (-anything except 0, NAN, odd integer)  is +INF
+ *	14. -0 ** (odd integer) = -( +0 ** (odd integer) )
+ *	15. +INF ** (+anything except 0,NAN) is +INF
+ *	16. +INF ** (-anything except 0,NAN) is +0
+ *	17. -INF ** (anything)  = -0 ** (-anything)
+ *	18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer)
+ *	19. (-anything except 0 and inf) ** (non-integer) is NAN
+ *
+ * Accuracy:
+ *	pow(x,y) returns x**y nearly rounded. In particular
+ *			pow(integer,integer)
+ *	always returns the correct integer provided it is 
+ *	representable.
+ *
+ * Constants :
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double 
+bp[] = {1.0, 1.5,},
+dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */
+dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */
+zero    =  0.0,
+one	=  1.0,
+two	=  2.0,
+two53	=  9007199254740992.0,	/* 0x43400000, 0x00000000 */
+Huge	=  1.0e300,
+tiny    =  1.0e-300,
+	/* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */
+L1  =  5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */
+L2  =  4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */
+L3  =  3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */
+L4  =  2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */
+L5  =  2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */
+L6  =  2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */
+P1   =  1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
+P2   = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
+P3   =  6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
+P4   = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
+P5   =  4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */
+lg2  =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+lg2_h  =  6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */
+lg2_l  = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */
+ovt =  8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */
+cp    =  9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */
+cp_h  =  9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */
+cp_l  = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/
+ivln2    =  1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */
+ivln2_h  =  1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/
+ivln2_l  =  1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/
+
+	double __ieee754_pow(double x, double y)
+{
+	double z,ax,z_h,z_l,p_h,p_l;
+	double y1,t1,t2,r,s,t,u,v,w;
+	int i,j,k,yisint,n;
+	int hx,hy,ix,iy;
+	unsigned lx,ly;
+
+	hx = __HI(x); lx = __LO(x);
+	hy = __HI(y); ly = __LO(y);
+	ix = hx&0x7fffffff;  iy = hy&0x7fffffff;
+
+    /* y==zero: x**0 = 1 */
+	if((iy|ly)==0) return one; 	
+
+    /* +-NaN return x+y */
+	if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) ||
+	   iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) 
+		return x+y;	
+
+    /* determine if y is an odd int when x < 0
+     * yisint = 0	... y is not an integer
+     * yisint = 1	... y is an odd int
+     * yisint = 2	... y is an even int
+     */
+	yisint  = 0;
+	if(hx<0) {	
+	    if(iy>=0x43400000) yisint = 2; /* even integer y */
+	    else if(iy>=0x3ff00000) {
+		k = (iy>>20)-0x3ff;	   /* exponent */
+		if(k>20) {
+		    j = ly>>(52-k);
+		    if((j<<(52-k))==ly) yisint = 2-(j&1);
+		} else if(ly==0) {
+		    j = iy>>(20-k);
+		    if((j<<(20-k))==iy) yisint = 2-(j&1);
+		}
+	    }		
+	} 
+
+    /* special value of y */
+	if(ly==0) { 	
+	    if (iy==0x7ff00000) {	/* y is +-inf */
+	        if(((ix-0x3ff00000)|lx)==0)
+		    return  y - y;	/* inf**+-1 is NaN */
+	        else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */
+		    return (hy>=0)? y: zero;
+	        else			/* (|x|<1)**-,+inf = inf,0 */
+		    return (hy<0)?-y: zero;
+	    } 
+	    if(iy==0x3ff00000) {	/* y is  +-1 */
+		if(hy<0) return one/x; else return x;
+	    }
+	    if(hy==0x40000000) return x*x; /* y is  2 */
+	    if(hy==0x3fe00000) {	/* y is  0.5 */
+		if(hx>=0)	/* x >= +0 */
+		return sqrt(x);	
+	    }
+	}
+
+	ax   = fabs(x);
+    /* special value of x */
+	if(lx==0) {
+	    if(ix==0x7ff00000||ix==0||ix==0x3ff00000){
+		z = ax;			/*x is +-0,+-inf,+-1*/
+		if(hy<0) z = one/z;	/* z = (1/|x|) */
+		if(hx<0) {
+		    if(((ix-0x3ff00000)|yisint)==0) {
+			z = (z-z)/(z-z); /* (-1)**non-int is NaN */
+		    } else if(yisint==1) 
+			z = -z;		/* (x<0)**odd = -(|x|**odd) */
+		}
+		return z;
+	    }
+	}
+    
+    /* (x<0)**(non-int) is NaN */
+	if((((hx>>31)+1)|yisint)==0) return (x-x)/(x-x);
+
+    /* |y| is Huge */
+	if(iy>0x41e00000) { /* if |y| > 2**31 */
+	    if(iy>0x43f00000){	/* if |y| > 2**64, must o/uflow */
+		if(ix<=0x3fefffff) return (hy<0)? Huge*Huge:tiny*tiny;
+		if(ix>=0x3ff00000) return (hy>0)? Huge*Huge:tiny*tiny;
+	    }
+	/* over/underflow if x is not close to one */
+	    if(ix<0x3fefffff) return (hy<0)? Huge*Huge:tiny*tiny;
+	    if(ix>0x3ff00000) return (hy>0)? Huge*Huge:tiny*tiny;
+	/* now |1-x| is tiny <= 2**-20, suffice to compute 
+	   log(x) by x-x^2/2+x^3/3-x^4/4 */
+	    t = x-1;		/* t has 20 trailing zeros */
+	    w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25));
+	    u = ivln2_h*t;	/* ivln2_h has 21 sig. bits */
+	    v = t*ivln2_l-w*ivln2;
+	    t1 = u+v;
+	    __LO(t1) = 0;
+	    t2 = v-(t1-u);
+	} else {
+	    double s2,s_h,s_l,t_h,t_l;
+	    n = 0;
+	/* take care subnormal number */
+	    if(ix<0x00100000)
+		{ax *= two53; n -= 53; ix = __HI(ax); }
+	    n  += ((ix)>>20)-0x3ff;
+	    j  = ix&0x000fffff;
+	/* determine interval */
+	    ix = j|0x3ff00000;		/* normalize ix */
+	    if(j<=0x3988E) k=0;		/* |x|<sqrt(3/2) */
+	    else if(j<0xBB67A) k=1;	/* |x|<sqrt(3)   */
+	    else {k=0;n+=1;ix -= 0x00100000;}
+	    __HI(ax) = ix;
+
+	/* compute s = s_h+s_l = (x-1)/(x+1) or (x-1.5)/(x+1.5) */
+	    u = ax-bp[k];		/* bp[0]=1.0, bp[1]=1.5 */
+	    v = one/(ax+bp[k]);
+	    s = u*v;
+	    s_h = s;
+	    __LO(s_h) = 0;
+	/* t_h=ax+bp[k] High */
+	    t_h = zero;
+	    __HI(t_h)=((ix>>1)|0x20000000)+0x00080000+(k<<18); 
+	    t_l = ax - (t_h-bp[k]);
+	    s_l = v*((u-s_h*t_h)-s_h*t_l);
+	/* compute log(ax) */
+	    s2 = s*s;
+	    r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6)))));
+	    r += s_l*(s_h+s);
+	    s2  = s_h*s_h;
+	    t_h = 3.0+s2+r;
+	    __LO(t_h) = 0;
+	    t_l = r-((t_h-3.0)-s2);
+	/* u+v = s*(1+...) */
+	    u = s_h*t_h;
+	    v = s_l*t_h+t_l*s;
+	/* 2/(3log2)*(s+...) */
+	    p_h = u+v;
+	    __LO(p_h) = 0;
+	    p_l = v-(p_h-u);
+	    z_h = cp_h*p_h;		/* cp_h+cp_l = 2/(3*log2) */
+	    z_l = cp_l*p_h+p_l*cp+dp_l[k];
+	/* log2(ax) = (s+..)*2/(3*log2) = n + dp_h + z_h + z_l */
+	    t = (double)n;
+	    t1 = (((z_h+z_l)+dp_h[k])+t);
+	    __LO(t1) = 0;
+	    t2 = z_l-(((t1-t)-dp_h[k])-z_h);
+	}
+
+	s = one; /* s (sign of result -ve**odd) = -1 else = 1 */
+	if((((hx>>31)+1)|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */
+
+    /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
+	y1  = y;
+	__LO(y1) = 0;
+	p_l = (y-y1)*t1+y*t2;
+	p_h = y1*t1;
+	z = p_l+p_h;
+	j = __HI(z);
+	i = __LO(z);
+	if (j>=0x40900000) {				/* z >= 1024 */
+	    if(((j-0x40900000)|i)!=0)			/* if z > 1024 */
+		return s*Huge*Huge;			/* overflow */
+	    else {
+		if(p_l+ovt>z-p_h) return s*Huge*Huge;	/* overflow */
+	    }
+	} else if((j&0x7fffffff)>=0x4090cc00 ) {	/* z <= -1075 */
+	    if(((j-0xc090cc00)|i)!=0) 		/* z < -1075 */
+		return s*tiny*tiny;		/* underflow */
+	    else {
+		if(p_l<=z-p_h) return s*tiny*tiny;	/* underflow */
+	    }
+	}
+    /*
+     * compute 2**(p_h+p_l)
+     */
+	i = j&0x7fffffff;
+	k = (i>>20)-0x3ff;
+	n = 0;
+	if(i>0x3fe00000) {		/* if |z| > 0.5, set n = [z+0.5] */
+	    n = j+(0x00100000>>(k+1));
+	    k = ((n&0x7fffffff)>>20)-0x3ff;	/* new k for n */
+	    t = zero;
+	    __HI(t) = (n&~(0x000fffff>>k));
+	    n = ((n&0x000fffff)|0x00100000)>>(20-k);
+	    if(j<0) n = -n;
+	    p_h -= t;
+	} 
+	t = p_l+p_h;
+	__LO(t) = 0;
+	u = t*lg2_h;
+	v = (p_l-(t-p_h))*lg2+t*lg2_l;
+	z = u+v;
+	w = v-(z-u);
+	t  = z*z;
+	t1  = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
+	r  = (z*t1)/(t1-two)-(w+z*w);
+	z  = one-(r-z);
+	j  = __HI(z);
+	j += (n<<20);
+	if((j>>20)<=0) z = scalbn(z,n);	/* subnormal output */
+	else __HI(z) += (n<<20);
+	return s*z;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_rem_pio2.c
@@ -1,0 +1,159 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_rem_pio2.c 1.4 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* __ieee754_rem_pio2(x,y)
+ * 
+ * return the remainder of x rem pi/2 in y[0]+y[1] 
+ * use __kernel_rem_pio2()
+ */
+
+#include "fdlibm.h"
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi 
+ */
+static const int two_over_pi[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, 
+};
+
+static const int npio2_hw[] = {
+0x3FF921FB, 0x400921FB, 0x4012D97C, 0x401921FB, 0x401F6A7A, 0x4022D97C,
+0x4025FDBB, 0x402921FB, 0x402C463A, 0x402F6A7A, 0x4031475C, 0x4032D97C,
+0x40346B9C, 0x4035FDBB, 0x40378FDB, 0x403921FB, 0x403AB41B, 0x403C463A,
+0x403DD85A, 0x403F6A7A, 0x40407E4C, 0x4041475C, 0x4042106C, 0x4042D97C,
+0x4043A28C, 0x40446B9C, 0x404534AC, 0x4045FDBB, 0x4046C6CB, 0x40478FDB,
+0x404858EB, 0x404921FB,
+};
+
+/*
+ * invpio2:  53 bits of 2/pi
+ * pio2_1:   first  33 bit of pi/2
+ * pio2_1t:  pi/2 - pio2_1
+ * pio2_2:   second 33 bit of pi/2
+ * pio2_2t:  pi/2 - (pio2_1+pio2_2)
+ * pio2_3:   third  33 bit of pi/2
+ * pio2_3t:  pi/2 - (pio2_1+pio2_2+pio2_3)
+ */
+
+static const double 
+zero =  0.00000000000000000000e+00, /* 0x00000000, 0x00000000 */
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+two24 =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+invpio2 =  6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
+pio2_1  =  1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
+pio2_1t =  6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
+pio2_2  =  6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
+pio2_2t =  2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
+pio2_3  =  2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
+pio2_3t =  8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
+
+	int __ieee754_rem_pio2(double x, double *y)
+{
+	double z,w,t,r,fn;
+	double tx[3];
+	int e0,i,j,nx,n,ix,hx;
+
+	hx = __HI(x);		/* high word of x */
+	ix = hx&0x7fffffff;
+	if(ix<=0x3fe921fb)   /* |x| ~<= pi/4 , no need for reduction */
+	    {y[0] = x; y[1] = 0; return 0;}
+	if(ix<0x4002d97c) {  /* |x| < 3pi/4, special case with n=+-1 */
+	    if(hx>0) { 
+		z = x - pio2_1;
+		if(ix!=0x3ff921fb) { 	/* 33+53 bit pi is good enough */
+		    y[0] = z - pio2_1t;
+		    y[1] = (z-y[0])-pio2_1t;
+		} else {		/* near pi/2, use 33+33+53 bit pi */
+		    z -= pio2_2;
+		    y[0] = z - pio2_2t;
+		    y[1] = (z-y[0])-pio2_2t;
+		}
+		return 1;
+	    } else {	/* negative x */
+		z = x + pio2_1;
+		if(ix!=0x3ff921fb) { 	/* 33+53 bit pi is good enough */
+		    y[0] = z + pio2_1t;
+		    y[1] = (z-y[0])+pio2_1t;
+		} else {		/* near pi/2, use 33+33+53 bit pi */
+		    z += pio2_2;
+		    y[0] = z + pio2_2t;
+		    y[1] = (z-y[0])+pio2_2t;
+		}
+		return -1;
+	    }
+	}
+	if(ix<=0x413921fb) { /* |x| ~<= 2^19*(pi/2), medium size */
+	    t  = fabs(x);
+	    n  = (int) (t*invpio2+half);
+	    fn = (double)n;
+	    r  = t-fn*pio2_1;
+	    w  = fn*pio2_1t;	/* 1st round good to 85 bit */
+	    if(n<32&&ix!=npio2_hw[n-1]) {	
+		y[0] = r-w;	/* quick check no cancellation */
+	    } else {
+	        j  = ix>>20;
+	        y[0] = r-w; 
+	        i = j-(((__HI(y[0]))>>20)&0x7ff);
+	        if(i>16) {  /* 2nd iteration needed, good to 118 */
+		    t  = r;
+		    w  = fn*pio2_2;	
+		    r  = t-w;
+		    w  = fn*pio2_2t-((t-r)-w);	
+		    y[0] = r-w;
+		    i = j-(((__HI(y[0]))>>20)&0x7ff);
+		    if(i>49)  {	/* 3rd iteration need, 151 bits acc */
+		    	t  = r;	/* will cover all possible cases */
+		    	w  = fn*pio2_3;	
+		    	r  = t-w;
+		    	w  = fn*pio2_3t-((t-r)-w);	
+		    	y[0] = r-w;
+		    }
+		}
+	    }
+	    y[1] = (r-y[0])-w;
+	    if(hx<0) 	{y[0] = -y[0]; y[1] = -y[1]; return -n;}
+	    else	 return n;
+	}
+    /* 
+     * all other (large) arguments
+     */
+	if(ix>=0x7ff00000) {		/* x is inf or NaN */
+	    y[0]=y[1]=x-x; return 0;
+	}
+    /* set z = scalbn(|x|,ilogb(x)-23) */
+	__LO(z) = __LO(x);
+	e0 	= (ix>>20)-1046;	/* e0 = ilogb(z)-23; */
+	__HI(z) = ix - (e0<<20);
+	for(i=0;i<2;i++) {
+		tx[i] = (double)((int)(z));
+		z     = (z-tx[i])*two24;
+	}
+	tx[2] = z;
+	nx = 3;
+	while(tx[nx-1]==zero) nx--;	/* skip zero term */
+	n  =  __kernel_rem_pio2(tx,y,e0,nx,2,two_over_pi);
+	if(hx<0) {y[0] = -y[0]; y[1] = -y[1]; return -n;}
+	return n;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_remainder.c
@@ -1,0 +1,69 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_remainder.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_remainder(x,p)
+ * Return :                  
+ * 	returns  x REM p  =  x - [x/p]*p as if in infinite 
+ * 	precise arithmetic, where [x/p] is the (infinite bit) 
+ *	integer nearest x/p (in half way case choose the even one).
+ * Method : 
+ *	Based on fmod() return x-[x/p]chopped*p exactlp.
+ */
+
+#include "fdlibm.h"
+
+static const double zero = 0.0;
+
+
+	double __ieee754_remainder(double x, double p)
+{
+	int hx,hp;
+	unsigned sx,lx,lp;
+	double p_half;
+
+	hx = __HI(x);		/* high word of x */
+	lx = __LO(x);		/* low  word of x */
+	hp = __HI(p);		/* high word of p */
+	lp = __LO(p);		/* low  word of p */
+	sx = hx&0x80000000;
+	hp &= 0x7fffffff;
+	hx &= 0x7fffffff;
+
+    /* purge off exception values */
+	if((hp|lp)==0) return (x*p)/(x*p); 	/* p = 0 */
+	if((hx>=0x7ff00000)||			/* x not finite */
+	  ((hp>=0x7ff00000)&&			/* p is NaN */
+	  (((hp-0x7ff00000)|lp)!=0)))
+	    return (x*p)/(x*p);
+
+
+	if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p);	/* now x < 2p */
+	if (((hx-hp)|(lx-lp))==0) return zero*x;
+	x  = fabs(x);
+	p  = fabs(p);
+	if (hp<0x00200000) {
+	    if(x+x>p) {
+		x-=p;
+		if(x+x>=p) x -= p;
+	    }
+	} else {
+	    p_half = 0.5*p;
+	    if(x>p_half) {
+		x-=p;
+		if(x>=p_half) x -= p;
+	    }
+	}
+	__HI(x) ^= sx;
+	return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_sinh.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)e_sinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sinh(x)
+ * Method : 
+ * mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2
+ *	1. Replace x by |x| (sinh(-x) = -sinh(x)). 
+ *	2. 
+ *		                                    E + E/(E+1)
+ *	    0        <= x <= 22     :  sinh(x) := --------------, E=expm1(x)
+ *			       			        2
+ *
+ *	    22       <= x <= lnovft :  sinh(x) := exp(x)/2 
+ *	    lnovft   <= x <= ln2ovft:  sinh(x) := exp(x/2)/2 * exp(x/2)
+ *	    ln2ovft  <  x	    :  sinh(x) := x*sHuge (overflow)
+ *
+ * Special cases:
+ *	sinh(x) is |x| if x is +INF, -INF, or NaN.
+ *	only sinh(0)=0 is exact for finite x.
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0, sHuge = 1.0e307;
+
+	double __ieee754_sinh(double x)
+{	
+	double t,w,h;
+	int ix,jx;
+	unsigned lx;
+
+    /* High word of |x|. */
+	jx = __HI(x);
+	ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+	if(ix>=0x7ff00000) return x+x;	
+
+	h = 0.5;
+	if (jx<0) h = -h;
+    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
+	if (ix < 0x40360000) {		/* |x|<22 */
+	    if (ix<0x3e300000) 		/* |x|<2**-28 */
+		if(sHuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
+	    t = expm1(fabs(x));
+	    if(ix<0x3ff00000) return h*(2.0*t-t*t/(t+one));
+	    return h*(t+t/(t+one));
+	}
+
+    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
+	if (ix < 0x40862E42)  return h*__ieee754_exp(fabs(x));
+
+    /* |x| in [log(maxdouble), overflowthresold] */
+	lx = *( (((*(unsigned*)&one)>>29)) + (unsigned*)&x);
+	if (ix<0x408633CE || (ix==0x408633ce)&&(lx<=(unsigned)0x8fb9f87d)) {
+	    w = __ieee754_exp(0.5*fabs(x));
+	    t = h*w;
+	    return t*w;
+	}
+
+    /* |x| > overflowthresold, sinh(x) overflow */
+	return x*sHuge;
+}
--- /dev/null
+++ b/libmath/fdlibm/e_sqrt.c
@@ -1,0 +1,442 @@
+/* derived from /netlib/fdlibm */
+/* @(#)e_sqrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __ieee754_sqrt(x)
+ * Return correctly rounded sqrt.
+ *           ------------------------------------------
+ *	     |  Use the hardware sqrt if you have one |
+ *           ------------------------------------------
+ * Method: 
+ *   Bit by bit method using integer arithmetic. (Slow, but portable) 
+ *   1. Normalization
+ *	Scale x to y in [1,4) with even powers of 2: 
+ *	find an integer k such that  1 <= (y=x*2^(2k)) < 4, then
+ *		sqrt(x) = 2^k * sqrt(y)
+ *   2. Bit by bit computation
+ *	Let q  = sqrt(y) truncated to i bit after binary point (q = 1),
+ *	     i							 0
+ *                                     i+1         2
+ *	    s  = 2*q , and	y  =  2   * ( y - q  ).		(1)
+ *	     i      i            i                 i
+ *                                                        
+ *	To compute q    from q , one checks whether 
+ *		    i+1       i                       
+ *
+ *			      -(i+1) 2
+ *			(q + 2      ) <= y.			(2)
+ *     			  i
+ *							      -(i+1)
+ *	If (2) is false, then q   = q ; otherwise q   = q  + 2      .
+ *		 	       i+1   i             i+1   i
+ *
+ *	With some algebric manipulation, it is not difficult to see
+ *	that (2) is equivalent to 
+ *                             -(i+1)
+ *			s  +  2       <= y			(3)
+ *			 i                i
+ *
+ *	The advantage of (3) is that s  and y  can be computed by 
+ *				      i      i
+ *	the following recurrence formula:
+ *	    if (3) is false
+ *
+ *	    s     =  s  ,	y    = y   ;			(4)
+ *	     i+1      i		 i+1    i
+ *
+ *	    otherwise,
+ *                         -i                     -(i+1)
+ *	    s	  =  s  + 2  ,  y    = y  -  s  - 2  		(5)
+ *           i+1      i          i+1    i     i
+ *				
+ *	One may easily use induction to prove (4) and (5). 
+ *	Note. Since the left hand side of (3) contain only i+2 bits,
+ *	      it does not necessary to do a full (53-bit) comparison 
+ *	      in (3).
+ *   3. Final rounding
+ *	After generating the 53 bits result, we compute one more bit.
+ *	Together with the remainder, we can decide whether the
+ *	result is exact, bigger than 1/2ulp, or less than 1/2ulp
+ *	(it will never equal to 1/2ulp).
+ *	The rounding mode can be detected by checking whether
+ *	Huge + tiny is equal to Huge, and whether Huge - tiny is
+ *	equal to Huge for some floating point number "Huge" and "tiny".
+ *		
+ * Special cases:
+ *	sqrt(+-0) = +-0 	... exact
+ *	sqrt(inf) = inf
+ *	sqrt(-ve) = NaN		... with invalid signal
+ *	sqrt(NaN) = NaN		... with invalid signal for signaling NaN
+ *
+ * Other methods : see the appended file at the end of the program below.
+ *---------------
+ */
+
+#include "fdlibm.h"
+
+static	const double	one	= 1.0, tiny=1.0e-300;
+
+	double __ieee754_sqrt(double x)
+{
+	double z;
+	int 	sign = (int)0x80000000; 
+	unsigned r,t1,s1,ix1,q1;
+	int ix0,s0,q,m,t,i;
+
+	ix0 = __HI(x);			/* high word of x */
+	ix1 = __LO(x);		/* low word of x */
+
+    /* take care of Inf and NaN */
+	if((ix0&0x7ff00000)==0x7ff00000) {			
+	    return x*x+x;		/* sqrt(NaN)=NaN, sqrt(+inf)=+inf
+					   sqrt(-inf)=sNaN */
+	} 
+    /* take care of zero */
+	if(ix0<=0) {
+	    if(((ix0&(~sign))|ix1)==0) return x;/* sqrt(+-0) = +-0 */
+	    else if(ix0<0)
+		return (x-x)/(x-x);		/* sqrt(-ve) = sNaN */
+	}
+    /* normalize x */
+	m = (ix0>>20);
+	if(m==0) {				/* subnormal x */
+	    while(ix0==0) {
+		m -= 21;
+		ix0 |= (ix1>>11); ix1 <<= 21;
+	    }
+	    for(i=0;(ix0&0x00100000)==0;i++) ix0<<=1;
+	    m -= i-1;
+	    ix0 |= (ix1>>(32-i));
+	    ix1 <<= i;
+	}
+	m -= 1023;	/* unbias exponent */
+	ix0 = (ix0&0x000fffff)|0x00100000;
+	if(m&1){	/* odd m, double x to make it even */
+	    ix0 += ix0 + ((ix1&sign)>>31);
+	    ix1 += ix1;
+	}
+	m >>= 1;	/* m = [m/2] */
+
+    /* generate sqrt(x) bit by bit */
+	ix0 += ix0 + ((ix1&sign)>>31);
+	ix1 += ix1;
+	q = q1 = s0 = s1 = 0;	/* [q,q1] = sqrt(x) */
+	r = 0x00200000;		/* r = moving bit from right to left */
+
+	while(r!=0) {
+	    t = s0+r; 
+	    if(t<=ix0) { 
+		s0   = t+r; 
+		ix0 -= t; 
+		q   += r; 
+	    } 
+	    ix0 += ix0 + ((ix1&sign)>>31);
+	    ix1 += ix1;
+	    r>>=1;
+	}
+
+	r = sign;
+	while(r!=0) {
+	    t1 = s1+r; 
+	    t  = s0;
+	    if((t<ix0)||((t==ix0)&&(t1<=ix1))) { 
+		s1  = t1+r;
+		if(((t1&sign)==sign)&&(s1&sign)==0) s0 += 1;
+		ix0 -= t;
+		if (ix1 < t1) ix0 -= 1;
+		ix1 -= t1;
+		q1  += r;
+	    }
+	    ix0 += ix0 + ((ix1&sign)>>31);
+	    ix1 += ix1;
+	    r>>=1;
+	}
+
+    /* use floating add to find out rounding direction */
+	if((ix0|ix1)!=0) {
+	    z = one-tiny; /* trigger inexact flag */
+	    if (z>=one) {
+	        z = one+tiny;
+	        if (q1==(unsigned)0xffffffff) { q1=0; q += 1;}
+		else if (z>one) {
+		    if (q1==(unsigned)0xfffffffe) q+=1;
+		    q1+=2; 
+		} else
+	            q1 += (q1&1);
+	    }
+	}
+	ix0 = (q>>1)+0x3fe00000;
+	ix1 =  q1>>1;
+	if ((q&1)==1) ix1 |= sign;
+	ix0 += (m <<20);
+	__HI(z) = ix0;
+	__LO(z) = ix1;
+	return z;
+}
+
+/*
+Other methods  (use floating-point arithmetic)
+-------------
+(This is a copy of a drafted paper by Prof W. Kahan 
+and K.C. Ng, written in May, 1986)
+
+	Two algorithms are given here to implement sqrt(x) 
+	(IEEE double precision arithmetic) in software.
+	Both supply sqrt(x) correctly rounded. The first algorithm (in
+	Section A) uses newton iterations and involves four divisions.
+	The second one uses reciproot iterations to avoid division, but
+	requires more multiplications. Both algorithms need the ability
+	to chop results of arithmetic operations instead of round them, 
+	and the INEXACT flag to indicate when an arithmetic operation
+	is executed exactly with no roundoff error, all part of the 
+	standard (IEEE 754-1985). The ability to perform shift, add,
+	subtract and logical AND operations upon 32-bit words is needed
+	too, though not part of the standard.
+
+A.  sqrt(x) by Newton Iteration
+
+   (1)	Initial approximation
+
+	Let x0 and x1 be the leading and the trailing 32-bit words of
+	a floating point number x (in IEEE double format) respectively 
+
+	    1    11		     52				  ...widths
+	   ------------------------------------------------------
+	x: |s|	  e     |	      f				|
+	   ------------------------------------------------------
+	      msb    lsb  msb				      lsb ...order
+
+ 
+	     ------------------------  	     ------------------------
+	x0:  |s|   e    |    f1     |	 x1: |          f2           |
+	     ------------------------  	     ------------------------
+
+	By performing shifts and subtracts on x0 and x1 (both regarded
+	as integers), we obtain an 8-bit approximation of sqrt(x) as
+	follows.
+
+		k  := (x0>>1) + 0x1ff80000;
+		y0 := k - T1[31&(k>>15)].	... y ~ sqrt(x) to 8 bits
+	Here k is a 32-bit integer and T1[] is an integer array containing
+	correction terms. Now magically the floating value of y (y's
+	leading 32-bit word is y0, the value of its trailing word is 0)
+	approximates sqrt(x) to almost 8-bit.
+
+	Value of T1:
+	static int T1[32]= {
+	0,	1024,	3062,	5746,	9193,	13348,	18162,	23592,
+	29598,	36145,	43202,	50740,	58733,	67158,	75992,	85215,
+	83599,	71378,	60428,	50647,	41945,	34246,	27478,	21581,
+	16499,	12183,	8588,	5674,	3403,	1742,	661,	130,};
+
+    (2)	Iterative refinement
+
+	Apply Heron's rule three times to y, we have y approximates 
+	sqrt(x) to within 1 ulp (Unit in the Last Place):
+
+		y := (y+x/y)/2		... almost 17 sig. bits
+		y := (y+x/y)/2		... almost 35 sig. bits
+		y := y-(y-x/y)/2	... within 1 ulp
+
+
+	Remark 1.
+	    Another way to improve y to within 1 ulp is:
+
+		y := (y+x/y)		... almost 17 sig. bits to 2*sqrt(x)
+		y := y - 0x00100006	... almost 18 sig. bits to sqrt(x)
+
+				2
+			    (x-y )*y
+		y := y + 2* ----------	...within 1 ulp
+			       2
+			     3y  + x
+
+
+	This formula has one division fewer than the one above; however,
+	it requires more multiplications and additions. Also x must be
+	scaled in advance to avoid spurious overflow in evaluating the
+	expression 3y*y+x. Hence it is not recommended uless division
+	is slow. If division is very slow, then one should use the 
+	reciproot algorithm given in section B.
+
+    (3) Final adjustment
+
+	By twiddling y's last bit it is possible to force y to be 
+	correctly rounded according to the prevailing rounding mode
+	as follows. Let r and i be copies of the rounding mode and
+	inexact flag before entering the square root program. Also we
+	use the expression y+-ulp for the next representable floating
+	numbers (up and down) of y. Note that y+-ulp = either fixed
+	point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+	mode.
+
+		I := FALSE;	... reset INEXACT flag I
+		R := RZ;	... set rounding mode to round-toward-zero
+		z := x/y;	... chopped quotient, possibly inexact
+		If(not I) then {	... if the quotient is exact
+		    if(z=y) {
+		        I := i;	 ... restore inexact flag
+		        R := r;  ... restore rounded mode
+		        return sqrt(x):=y.
+		    } else {
+			z := z - ulp;	... special rounding
+		    }
+		}
+		i := TRUE;		... sqrt(x) is inexact
+		If (r=RN) then z=z+ulp	... rounded-to-nearest
+		If (r=RP) then {	... round-toward-+inf
+		    y = y+ulp; z=z+ulp;
+		}
+		y := y+z;		... chopped sum
+		y0:=y0-0x00100000;	... y := y/2 is correctly rounded.
+	        I := i;	 		... restore inexact flag
+	        R := r;  		... restore rounded mode
+	        return sqrt(x):=y.
+		    
+    (4)	Special cases
+
+	Square root of +inf, +-0, or NaN is itself;
+	Square root of a negative number is NaN with invalid signal.
+
+
+B.  sqrt(x) by Reciproot Iteration
+
+   (1)	Initial approximation
+
+	Let x0 and x1 be the leading and the trailing 32-bit words of
+	a floating point number x (in IEEE double format) respectively
+	(see section A). By performing shifs and subtracts on x0 and y0,
+	we obtain a 7.8-bit approximation of 1/sqrt(x) as follows.
+
+	    k := 0x5fe80000 - (x0>>1);
+	    y0:= k - T2[63&(k>>14)].	... y ~ 1/sqrt(x) to 7.8 bits
+
+	Here k is a 32-bit integer and T2[] is an integer array 
+	containing correction terms. Now magically the floating
+	value of y (y's leading 32-bit word is y0, the value of
+	its trailing word y1 is set to zero) approximates 1/sqrt(x)
+	to almost 7.8-bit.
+
+	Value of T2:
+	static int T2[64]= {
+	0x1500,	0x2ef8,	0x4d67,	0x6b02,	0x87be,	0xa395,	0xbe7a,	0xd866,
+	0xf14a,	0x1091b,0x11fcd,0x13552,0x14999,0x15c98,0x16e34,0x17e5f,
+	0x18d03,0x19a01,0x1a545,0x1ae8a,0x1b5c4,0x1bb01,0x1bfde,0x1c28d,
+	0x1c2de,0x1c0db,0x1ba73,0x1b11c,0x1a4b5,0x1953d,0x18266,0x16be0,
+	0x1683e,0x179d8,0x18a4d,0x19992,0x1a789,0x1b445,0x1bf61,0x1c989,
+	0x1d16d,0x1d77b,0x1dddf,0x1e2ad,0x1e5bf,0x1e6e8,0x1e654,0x1e3cd,
+	0x1df2a,0x1d635,0x1cb16,0x1be2c,0x1ae4e,0x19bde,0x1868e,0x16e2e,
+	0x1527f,0x1334a,0x11051,0xe951,	0xbe01,	0x8e0d,	0x5924,	0x1edd,};
+
+    (2)	Iterative refinement
+
+	Apply Reciproot iteration three times to y and multiply the
+	result by x to get an approximation z that matches sqrt(x)
+	to about 1 ulp. To be exact, we will have 
+		-1ulp < sqrt(x)-z<1.0625ulp.
+	
+	... set rounding mode to Round-to-nearest
+	   y := y*(1.5-0.5*x*y*y)	... almost 15 sig. bits to 1/sqrt(x)
+	   y := y*((1.5-2^-30)+0.5*x*y*y)... about 29 sig. bits to 1/sqrt(x)
+	... special arrangement for better accuracy
+	   z := x*y			... 29 bits to sqrt(x), with z*y<1
+	   z := z + 0.5*z*(1-z*y)	... about 1 ulp to sqrt(x)
+
+	Remark 2. The constant 1.5-2^-30 is chosen to bias the error so that
+	(a) the term z*y in the final iteration is always less than 1; 
+	(b) the error in the final result is biased upward so that
+		-1 ulp < sqrt(x) - z < 1.0625 ulp
+	    instead of |sqrt(x)-z|<1.03125ulp.
+
+    (3)	Final adjustment
+
+	By twiddling y's last bit it is possible to force y to be 
+	correctly rounded according to the prevailing rounding mode
+	as follows. Let r and i be copies of the rounding mode and
+	inexact flag before entering the square root program. Also we
+	use the expression y+-ulp for the next representable floating
+	numbers (up and down) of y. Note that y+-ulp = either fixed
+	point y+-1, or multiply y by nextafter(1,+-inf) in chopped
+	mode.
+
+	R := RZ;		... set rounding mode to round-toward-zero
+	switch(r) {
+	    case RN:		... round-to-nearest
+	       if(x<= z*(z-ulp)...chopped) z = z - ulp; else
+	       if(x<= z*(z+ulp)...chopped) z = z; else z = z+ulp;
+	       break;
+	    case RZ:case RM:	... round-to-zero or round-to--inf
+	       R:=RP;		... reset rounding mod to round-to-+inf
+	       if(x<z*z ... rounded up) z = z - ulp; else
+	       if(x>=(z+ulp)*(z+ulp) ...rounded up) z = z+ulp;
+	       break;
+	    case RP:		... round-to-+inf
+	       if(x>(z+ulp)*(z+ulp)...chopped) z = z+2*ulp; else
+	       if(x>z*z ...chopped) z = z+ulp;
+	       break;
+	}
+
+	Remark 3. The above comparisons can be done in fixed point. For
+	example, to compare x and w=z*z chopped, it suffices to compare
+	x1 and w1 (the trailing parts of x and w), regarding them as
+	two's complement integers.
+
+	...Is z an exact square root?
+	To determine whether z is an exact square root of x, let z1 be the
+	trailing part of z, and also let x0 and x1 be the leading and
+	trailing parts of x.
+
+	If ((z1&0x03ffffff)!=0)	... not exact if trailing 26 bits of z!=0
+	    I := 1;		... Raise Inexact flag: z is not exact
+	else {
+	    j := 1 - [(x0>>20)&1]	... j = logb(x) mod 2
+	    k := z1 >> 26;		... get z's 25-th and 26-th 
+					    fraction bits
+	    I := i or (k&j) or ((k&(j+j+1))!=(x1&3));
+	}
+	R:= r		... restore rounded mode
+	return sqrt(x):=z.
+
+	If multiplication is cheaper then the foregoing red tape, the 
+	Inexact flag can be evaluated by
+
+	    I := i;
+	    I := (z*z!=x) or I.
+
+	Note that z*z can overwrite I; this value must be sensed if it is 
+	True.
+
+	Remark 4. If z*z = x exactly, then bit 25 to bit 0 of z1 must be
+	zero.
+
+		    --------------------
+		z1: |        f2        | 
+		    --------------------
+		bit 31		   bit 0
+
+	Further more, bit 27 and 26 of z1, bit 0 and 1 of x1, and the odd
+	or even of logb(x) have the following relations:
+
+	-------------------------------------------------
+	bit 27,26 of z1		bit 1,0 of x1	logb(x)
+	-------------------------------------------------
+	00			00		odd and even
+	01			01		even
+	10			10		odd
+	10			00		even
+	11			01		even
+	-------------------------------------------------
+
+    (4)	Special cases (see (4) of Section A).	
+ 
+ */
+ 
--- /dev/null
+++ b/libmath/fdlibm/fdlibm.h
@@ -1,0 +1,150 @@
+/* derived from /netlib/fdlibm */
+#include "lib9.h"
+
+/* @(#)fdlibm.h 1.5 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+
+#ifdef USE_FPdbleword
+#define __HI(x) ((FPdbleword*)&x)->hi
+#define __LO(x) ((FPdbleword*)&x)->lo
+#define __HIp(x) ((FPdbleword*)x)->hi
+#define __LOp(x) ((FPdbleword*)x)->lo
+#else
+#ifdef __LITTLE_ENDIAN
+#define __HI(x) *(1+(int*)&x)
+#define __LO(x) *(int*)&x
+#define __HIp(x) *(1+(int*)x)
+#define __LOp(x) *(int*)x
+#else
+#define __HI(x) *(int*)&x
+#define __LO(x) *(1+(int*)&x)
+#define __HIp(x) *(int*)x
+#define __LOp(x) *(1+(int*)x)
+#endif
+#endif
+
+/*
+ * ANSI/POSIX
+ */
+extern double acos(double);
+extern double asin(double);
+extern double atan(double);
+extern double atan2(double, double);
+extern double cos(double);
+extern double sin(double);
+extern double tan(double);
+
+extern double cosh(double);
+extern double sinh(double);
+extern double tanh(double);
+
+extern double exp(double);
+extern double frexp(double, int *);
+extern double ldexp(double, int);
+extern double log(double);
+extern double log10(double);
+extern double modf(double, double *);
+
+extern double pow(double, double);
+extern double sqrt(double);
+
+extern double ceil(double);
+extern double fabs(double);
+extern double floor(double);
+extern double fmod(double, double);
+
+extern double erf(double);
+extern double erfc(double);
+extern double gamma(double);
+extern double hypot(double, double);
+extern int finite(double);
+extern double j0(double);
+extern double j1(double);
+extern double jn(int, double);
+extern double lgamma(double);
+extern double y0(double);
+extern double y1(double);
+extern double yn(int, double);
+
+extern double acosh(double);
+extern double asinh(double);
+extern double atanh(double);
+extern double cbrt(double);
+extern double logb(double);
+extern double nextafter(double, double);
+extern double remainder(double, double);
+extern double scalb(double, double);
+
+/*
+ * IEEE Test Vector
+ */
+extern double significand(double);
+
+/*
+ * Functions callable from C, intended to support IEEE arithmetic.
+ */
+extern double copysign(double, double);
+extern int ilogb(double);
+extern double rint(double);
+extern double scalbn(double, int);
+
+/*
+ * BSD math library entry points
+ */
+extern double expm1(double);
+extern double log1p(double);
+
+/*
+ * Reentrant version of gamma & lgamma; passes signgam back by reference
+ * as the second argument; user must allocate space for signgam.
+ */
+#ifdef _REENTRANT
+extern double gamma_r(double, int *);
+extern double lgamma_r(double, int *);
+#endif	/* _REENTRANT */
+
+/* ieee style elementary functions */
+extern double __ieee754_sqrt(double);			
+extern double __ieee754_acos(double);			
+extern double __ieee754_acosh(double);			
+extern double __ieee754_log(double);			
+extern double __ieee754_atanh(double);			
+extern double __ieee754_asin(double);			
+extern double __ieee754_atan2(double,double);			
+extern double __ieee754_exp(double);
+extern double __ieee754_cosh(double);
+extern double __ieee754_fmod(double,double);
+extern double __ieee754_pow(double,double);
+extern double __ieee754_lgamma_r(double,int *);
+extern double __ieee754_gamma_r(double,int *);
+extern double __ieee754_lgamma(double);
+extern double __ieee754_gamma(double);
+extern double __ieee754_log10(double);
+extern double __ieee754_sinh(double);
+extern double __ieee754_hypot(double,double);
+extern double __ieee754_j0(double);
+extern double __ieee754_j1(double);
+extern double __ieee754_y0(double);
+extern double __ieee754_y1(double);
+extern double __ieee754_jn(int,double);
+extern double __ieee754_yn(int,double);
+extern double __ieee754_remainder(double,double);
+extern int    __ieee754_rem_pio2(double,double*);
+extern double __ieee754_scalb(double,int);
+
+/* fdlibm kernel function */
+extern double __kernel_standard(double,double,int);	
+extern double __kernel_sin(double,double,int);
+extern double __kernel_cos(double,double);
+extern double __kernel_tan(double,double,int);
+extern int    __kernel_rem_pio2(double*,double*,int,int,int,const int*);
--- /dev/null
+++ b/libmath/fdlibm/k_cos.c
@@ -1,0 +1,84 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_cos( x,  y )
+ * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x. 
+ *
+ * Algorithm
+ *	1. Since cos(-x) = cos(x), we need only to consider positive x.
+ *	2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
+ *	3. cos(x) is approximated by a polynomial of degree 14 on
+ *	   [0,pi/4]
+ *		  	                 4            14
+ *	   	cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
+ *	   where the remez error is
+ *	
+ * 	|              2     4     6     8     10    12     14 |     -58
+ * 	|cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  )| <= 2
+ * 	|    					               | 
+ * 
+ * 	               4     6     8     10    12     14 
+ *	4. let r = C1*x +C2*x +C3*x +C4*x +C5*x  +C6*x  , then
+ *	       cos(x) = 1 - x*x/2 + r
+ *	   since cos(x+y) ~ cos(x) - sin(x)*y 
+ *			  ~ cos(x) - x*y,
+ *	   a correction term is necessary in cos(x) and hence
+ *		cos(x+y) = 1 - (x*x/2 - (r - x*y))
+ *	   For better accuracy when x > 0.3, let qx = |x|/4 with
+ *	   the last 32 bits mask off, and if x > 0.78125, let qx = 0.28125.
+ *	   Then
+ *		cos(x+y) = (1-qx) - ((x*x/2-qx) - (r-x*y)).
+ *	   Note that 1-qx and (x*x/2-qx) is EXACT here, and the
+ *	   magnitude of the latter is at least a quarter of x*x/2,
+ *	   thus, reducing the rounding error in the subtraction.
+ */
+
+#include "fdlibm.h"
+
+static const double 
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+C1  =  4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
+C2  = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
+C3  =  2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
+C4  = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
+C5  =  2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
+C6  = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
+
+	double __kernel_cos(double x, double y)
+{
+	double a,hz,z,r,qx;
+	int ix;
+	ix = __HI(x)&0x7fffffff;	/* ix = |x|'s high word*/
+	if(ix<0x3e400000) {			/* if x < 2**27 */
+	    if(((int)x)==0) return one;		/* generate inexact */
+	}
+	z  = x*x;
+	r  = z*(C1+z*(C2+z*(C3+z*(C4+z*(C5+z*C6)))));
+	if(ix < 0x3FD33333) 			/* if |x| < 0.3 */ 
+	    return one - (0.5*z - (z*r - x*y));
+	else {
+	    if(ix > 0x3fe90000) {		/* x > 0.78125 */
+		qx = 0.28125;
+	    } else {
+	        __HI(qx) = ix-0x00200000;	/* x/4 */
+	        __LO(qx) = 0;
+	    }
+	    hz = 0.5*z-qx;
+	    a  = one-qx;
+	    return a - (hz - (z*r-x*y));
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/k_rem_pio2.c
@@ -1,0 +1,300 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec,ipio2)
+ * double x[],y[]; int e0,nx,prec; int ipio2[];
+ * 
+ * __kernel_rem_pio2 return the last three digits of N with 
+ *		y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of 
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a Huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ * 	x[]	The input value (must be positive) is broken into nx 
+ *		pieces of 24-bit integers in double precision format.
+ *		x[i] will be the i-th 24 bit of x. The scaled exponent 
+ *		of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 
+ *		match x's up to 24 bits.
+ *
+ *		Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ *			e0 = ilogb(z)-23
+ *			z  = scalbn(z,-e0)
+ *		for i = 0,1,2
+ *			x[i] = floor(z)
+ *			z    = (z-x[i])*2**24
+ *
+ *
+ *	y[]	ouput result in an array of double precision numbers.
+ *		The dimension of y[] is:
+ *			24-bit  precision	1
+ *			53-bit  precision	2
+ *			64-bit  precision	2
+ *			113-bit precision	3
+ *		The actual value is the sum of them. Thus for 113-bit
+ *		precison, one may have to do something like:
+ *
+ *		long double t,w,r_head, r_tail;
+ *		t = (long double)y[2] + (long double)y[1];
+ *		w = (long double)y[0];
+ *		r_head = t+w;
+ *		r_tail = w - (r_head - t);
+ *
+ *	e0	The exponent of x[0]
+ *
+ *	nx	dimension of x[]
+ *
+ *  	prec	an integer indicating the precision:
+ *			0	24  bits (single)
+ *			1	53  bits (double)
+ *			2	64  bits (extended)
+ *			3	113 bits (quad)
+ *
+ *	ipio2[]
+ *		integer array, contains the (24*i)-th to (24*i+23)-th 
+ *		bit of 2/pi after binary point. The corresponding 
+ *		floating value is
+ *
+ *			ipio2[i] * 2^(-24(i+1)).
+ *
+ * External function:
+ *	double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ * 	jk	jk+1 is the initial number of terms of ipio2[] needed
+ *		in the computation. The recommended value is 2,3,4,
+ *		6 for single, double, extended,and quad.
+ *
+ * 	jz	local integer variable indicating the number of 
+ *		terms of ipio2[] used. 
+ *
+ *	jx	nx - 1
+ *
+ *	jv	index for pointing to the suitable ipio2[] for the
+ *		computation. In general, we want
+ *			( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ *		is an integer. Thus
+ *			e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ *		Hence jv = max(0,(e0-3)/24).
+ *
+ *	jp	jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ * 	q[]	double array with integral value, representing the
+ *		24-bits chunk of the product of x and 2/pi.
+ *
+ *	q0	the corresponding exponent of q[0]. Note that the
+ *		exponent for q[i] would be q0-24*i.
+ *
+ *	PIo2[]	double precision array, obtained by cutting pi/2
+ *		into 24 bits chunks. 
+ *
+ *	f[]	ipio2[] in floating point 
+ *
+ *	iq[]	integer array by breaking up q[] in 24-bits chunk.
+ *
+ *	fq[]	final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ *	ih	integer. If >0 it indicates q[] is >= 0.5, hence
+ *		it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const int init_jk[] = {2,3,4,6}; /* initial value for jk */
+
+static const double PIo2[] = {
+  1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+  7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+  5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+  3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+  1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+  1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+  2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+  2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+static const double			
+zero   = 0.0,
+one    = 1.0,
+two24   =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24  =  5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+	int __kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec, const int *ipio2) 
+{
+	int jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+	double z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+	jk = init_jk[prec];
+	jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+	jx =  nx-1;
+	jv = (e0-3)/24; if(jv<0) jv=0;
+	q0 =  e0-24*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+	j = jv-jx; m = jx+jk;
+	for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+	for (i=0;i<=jk;i++) {
+	    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+	}
+
+	jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+	for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+	    fw    =  (double)((int)(twon24* z));
+	    iq[i] =  (int)(z-two24*fw);
+	    z     =  q[j-1]+fw;
+	}
+
+    /* compute n */
+	z  = scalbn(z,q0);		/* actual value of z */
+	z -= 8.0*floor(z*0.125);		/* trim off integer >= 8 */
+	n  = (int) z;
+	z -= (double)n;
+	ih = 0;
+	if(q0>0) {	/* need iq[jz-1] to determine n */
+	    i  = (iq[jz-1]>>(24-q0)); n += i;
+	    iq[jz-1] -= i<<(24-q0);
+	    ih = iq[jz-1]>>(23-q0);
+	} 
+	else if(q0==0) ih = iq[jz-1]>>23;
+	else if(z>=0.5) ih=2;
+
+	if(ih>0) {	/* q > 0.5 */
+	    n += 1; carry = 0;
+	    for(i=0;i<jz ;i++) {	/* compute 1-q */
+		j = iq[i];
+		if(carry==0) {
+		    if(j!=0) {
+			carry = 1; iq[i] = 0x1000000- j;
+		    }
+		} else  iq[i] = 0xffffff - j;
+	    }
+	    if(q0>0) {		/* rare case: chance is 1 in 12 */
+	        switch(q0) {
+	        case 1:
+	    	   iq[jz-1] &= 0x7fffff; break;
+	    	case 2:
+	    	   iq[jz-1] &= 0x3fffff; break;
+	        }
+	    }
+	    if(ih==2) {
+		z = one - z;
+		if(carry!=0) z -= scalbn(one,q0);
+	    }
+	}
+
+    /* check if recomputation is needed */
+	if(z==zero) {
+	    j = 0;
+	    for (i=jz-1;i>=jk;i--) j |= iq[i];
+	    if(j==0) { /* need recomputation */
+		for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+		for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+		    f[jx+i] = (double) ipio2[jv+i];
+		    for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+		    q[i] = fw;
+		}
+		jz += k;
+		goto recompute;
+	    }
+	}
+
+    /* chop off zero terms */
+	if(z==0.0) {
+	    jz -= 1; q0 -= 24;
+	    while(iq[jz]==0) { jz--; q0-=24;}
+	} else { /* break z into 24-bit if necessary */
+	    z = scalbn(z,-q0);
+	    if(z>=two24) { 
+		fw = (double)((int)(twon24*z));
+		iq[jz] = (int)(z-two24*fw);
+		jz += 1; q0 += 24;
+		iq[jz] = (int) fw;
+	    } else iq[jz] = (int) z ;
+	}
+
+    /* convert integer "bit" chunk to floating-point value */
+	fw = scalbn(one,q0);
+	for(i=jz;i>=0;i--) {
+	    q[i] = fw*(double)iq[i]; fw*=twon24;
+	}
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+	for(i=jz;i>=0;i--) {
+	    for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+	    fq[jz-i] = fw;
+	}
+
+    /* compress fq[] into y[] */
+	switch(prec) {
+	    case 0:
+		fw = 0.0;
+		for (i=jz;i>=0;i--) fw += fq[i];
+		y[0] = (ih==0)? fw: -fw; 
+		break;
+	    case 1:
+	    case 2:
+		fw = 0.0;
+		for (i=jz;i>=0;i--) fw += fq[i]; 
+		y[0] = (ih==0)? fw: -fw; 
+		fw = fq[0]-fw;
+		for (i=1;i<=jz;i++) fw += fq[i];
+		y[1] = (ih==0)? fw: -fw; 
+		break;
+	    case 3:	/* painful */
+		for (i=jz;i>0;i--) {
+		    fw      = fq[i-1]+fq[i]; 
+		    fq[i]  += fq[i-1]-fw;
+		    fq[i-1] = fw;
+		}
+		for (i=jz;i>1;i--) {
+		    fw      = fq[i-1]+fq[i]; 
+		    fq[i]  += fq[i-1]-fw;
+		    fq[i-1] = fw;
+		}
+		for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; 
+		if(ih==0) {
+		    y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+		} else {
+		    y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+		}
+	}
+	return n&7;
+}
--- /dev/null
+++ b/libmath/fdlibm/k_sin.c
@@ -1,0 +1,66 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_sin( x, y, iy)
+ * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input iy indicates whether y is 0. (if iy=0, y assume to be 0). 
+ *
+ * Algorithm
+ *	1. Since sin(-x) = -sin(x), we need only to consider positive x. 
+ *	2. if x < 2^-27 (hx<0x3e400000 0), return x with inexact if x!=0.
+ *	3. sin(x) is approximated by a polynomial of degree 13 on
+ *	   [0,pi/4]
+ *		  	         3            13
+ *	   	sin(x) ~ x + S1*x + ... + S6*x
+ *	   where
+ *	
+ * 	|sin(x)         2     4     6     8     10     12  |     -58
+ * 	|----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x  +S6*x   )| <= 2
+ * 	|  x 					           | 
+ * 
+ *	4. sin(x+y) = sin(x) + sin'(x')*y
+ *		    ~ sin(x) + (1-x*x/2)*y
+ *	   For better accuracy, let 
+ *		     3      2      2      2      2
+ *		r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
+ *	   then                   3    2
+ *		sin(x) = x + (S1*x + (x *(r-y/2)+y))
+ */
+
+#include "fdlibm.h"
+
+static const double 
+half =  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+S1  = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
+S2  =  8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
+S3  = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
+S4  =  2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
+S5  = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
+S6  =  1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
+
+	double __kernel_sin(double x, double y, int iy)
+{
+	double z,r,v;
+	int ix;
+	ix = __HI(x)&0x7fffffff;	/* high word of x */
+	if(ix<0x3e400000)			/* |x| < 2**-27 */
+	   {if((int)x==0) return x;}		/* generate inexact */
+	z	=  x*x;
+	v	=  z*x;
+	r	=  S2+z*(S3+z*(S4+z*(S5+z*S6)));
+	if(iy==0) return x+v*(S1+z*r);
+	else      return x-((z*(half*y-v*r)-y)-v*S1);
+}
--- /dev/null
+++ b/libmath/fdlibm/k_tan.c
@@ -1,0 +1,117 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)k_tan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* __kernel_tan( x, y, k )
+ * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854
+ * Input x is assumed to be bounded by ~pi/4 in magnitude.
+ * Input y is the tail of x.
+ * Input k indicates whether tan (if k=1) or 
+ * -1/tan (if k= -1) is returned.
+ *
+ * Algorithm
+ *	1. Since tan(-x) = -tan(x), we need only to consider positive x. 
+ *	2. if x < 2^-28 (hx<0x3e300000 0), return x with inexact if x!=0.
+ *	3. tan(x) is approximated by a odd polynomial of degree 27 on
+ *	   [0,0.67434]
+ *		  	         3             27
+ *	   	tan(x) ~ x + T1*x + ... + T13*x
+ *	   where
+ *	
+ * 	        |tan(x)         2     4            26   |     -59.2
+ * 	        |----- - (1+T1*x +T2*x +.... +T13*x    )| <= 2
+ * 	        |  x 					| 
+ * 
+ *	   Note: tan(x+y) = tan(x) + tan'(x)*y
+ *		          ~ tan(x) + (1+x*x)*y
+ *	   Therefore, for better accuracy in computing tan(x+y), let 
+ *		     3      2      2       2       2
+ *		r = x *(T2+x *(T3+x *(...+x *(T12+x *T13))))
+ *	   then
+ *		 		    3    2
+ *		tan(x+y) = x + (T1*x + (x *(r+y)+y))
+ *
+ *      4. For x in [0.67434,pi/4],  let y = pi/4 - x, then
+ *		tan(x) = tan(pi/4-y) = (1-tan(y))/(1+tan(y))
+ *		       = 1 - 2*(tan(y) - (tan(y)^2)/(1+tan(y)))
+ */
+
+#include "fdlibm.h"
+static const double 
+one   =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+pio4  =  7.85398163397448278999e-01, /* 0x3FE921FB, 0x54442D18 */
+pio4lo=  3.06161699786838301793e-17, /* 0x3C81A626, 0x33145C07 */
+T[] =  {
+  3.33333333333334091986e-01, /* 0x3FD55555, 0x55555563 */
+  1.33333333333201242699e-01, /* 0x3FC11111, 0x1110FE7A */
+  5.39682539762260521377e-02, /* 0x3FABA1BA, 0x1BB341FE */
+  2.18694882948595424599e-02, /* 0x3F9664F4, 0x8406D637 */
+  8.86323982359930005737e-03, /* 0x3F8226E3, 0xE96E8493 */
+  3.59207910759131235356e-03, /* 0x3F6D6D22, 0xC9560328 */
+  1.45620945432529025516e-03, /* 0x3F57DBC8, 0xFEE08315 */
+  5.88041240820264096874e-04, /* 0x3F4344D8, 0xF2F26501 */
+  2.46463134818469906812e-04, /* 0x3F3026F7, 0x1A8D1068 */
+  7.81794442939557092300e-05, /* 0x3F147E88, 0xA03792A6 */
+  7.14072491382608190305e-05, /* 0x3F12B80F, 0x32F0A7E9 */
+ -1.85586374855275456654e-05, /* 0xBEF375CB, 0xDB605373 */
+  2.59073051863633712884e-05, /* 0x3EFB2A70, 0x74BF7AD4 */
+};
+
+	double __kernel_tan(double x, double y, int iy)
+{
+	double z,r,v,w,s;
+	int ix,hx;
+	hx = __HI(x);	/* high word of x */
+	ix = hx&0x7fffffff;	/* high word of |x| */
+	if(ix<0x3e300000)			/* x < 2**-28 */
+	    {if((int)x==0) {			/* generate inexact */
+		if(((ix|__LO(x))|(iy+1))==0) return one/fabs(x);
+		else return (iy==1)? x: -one/x;
+	    }
+	    }
+	if(ix>=0x3FE59428) { 			/* |x|>=0.6744 */
+	    if(hx<0) {x = -x; y = -y;}
+	    z = pio4-x;
+	    w = pio4lo-y;
+	    x = z+w; y = 0.0;
+	}
+	z	=  x*x;
+	w 	=  z*z;
+    /* Break x^5*(T[1]+x^2*T[2]+...) into
+     *	  x^5(T[1]+x^4*T[3]+...+x^20*T[11]) +
+     *	  x^5(x^2*(T[2]+x^4*T[4]+...+x^22*[T12]))
+     */
+	r = T[1]+w*(T[3]+w*(T[5]+w*(T[7]+w*(T[9]+w*T[11]))));
+	v = z*(T[2]+w*(T[4]+w*(T[6]+w*(T[8]+w*(T[10]+w*T[12])))));
+	s = z*x;
+	r = y + z*(s*(r+v)+y);
+	r += T[0]*s;
+	w = x+r;
+	if(ix>=0x3FE59428) {
+	    v = (double)iy;
+	    return (double)(1-((hx>>30)&2))*(v-2.0*(x-(w*w/(w+v)-r)));
+	}
+	if(iy==1) return w;
+	else {		/* if allow error up to 2 ulp, 
+			   simply return -1.0/(x+r) here */
+     /*  compute -1.0/(x+r) accurately */
+	    double a,t;
+	    z  = w;
+	    __LO(z) = 0;
+	    v  = r-(z - x); 	/* z+v = r+x */
+	    t = a  = -1.0/w;	/* a = -1.0/w */
+	    __LO(t) = 0;
+	    s  = 1.0+t*z;
+	    return t+a*(s+t*v);
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/readme
@@ -1,0 +1,261 @@
+
+	  ********************************
+ 	  * Announcing FDLIBM Version 5  *
+	  ********************************
+============================================================
+			FDLIBM
+============================================================
+  (developed at SunSoft, a Sun Microsystems, Inc. business.)
+
+What's new in FDLIBM 5.2?
+BUGS FIXED
+    1. Little endian bug in frexp (affect only little endian machine):
+       in file s_frexp.c, last line of program frexp before exit
+       	     *(int*)&x = hx;
+       should read
+       	     *(n0+(int*)&x) = hx;
+
+    2. jn(-1,x) is three times larger that the actual answer:
+       in file e_jn.c, the line 
+	     sign = 1 - ((n&1)<<2);
+       should read
+	     sign = 1 - ((n&1)<<1);
+
+    3. Compiler failure on non-standard code
+       J.T. Conklin found that gcc optimizing out the manipulation of doubles
+       via pointer bashing of the form
+		double x = 0;
+		*(((int*)&x)+n0)=0x7fff0000;
+		foo(x);
+       C experts confirmed that the behavior of *(((int*)&x)+n0)=0x7fff0000
+       is undefined. By replacing n0 with a constant 0 or 1, the GCC "knows" 
+       that the assignment is modifying the double, and "does the right thing."
+       Thus, in FDLIBM 5.2, we replace n0 with a constant and use a macro 
+       __HI() and __LO() with #ifdef __LITTLE_ENDIAN to avoid the above problem.
+
+    4. Performance issue on rem_pio2
+       An attempt to speed up the argument reduction in the trig function is the
+       consider pi/4 < x < 3pi/4 a special case. This was done in the file
+       e_rem_pio2.c
+    
+	
+FDLIBM (Freely Distributable LIBM) is a C math library 
+for machines that support IEEE 754 floating-point arithmetic. 
+In this release, only double precision is supported.
+
+FDLIBM is intended to provide a reasonably portable (see 
+assumptions below), reference quality (below one ulp for
+major functions like sin,cos,exp,log) math library 
+(libm.a).  For a copy of FDLIBM, please send a message "send index from fdlibm"
+to netlib@research.att.com.
+
+--------------
+1. ASSUMPTIONS
+--------------
+FDLIBM (double precision version) assumes:
+ a.  IEEE 754 style (if not precise compliance) arithmetic;
+ b.  32 bit 2's complement integer arithmetic;
+ c.  Each double precision floating-point number must be in IEEE 754 
+     double format, and that each number can be retrieved as two 32-bit 
+     integers through the using of pointer bashing as in the example 
+     below:
+
+     Example: let y = 2.0
+	double fp number y: 	2.0
+	IEEE double format:	0x4000000000000000
+
+	Referencing y as two integers:
+	*(int*)&y,*(1+(int*)&y) =	{0x40000000,0x0} (on sparc)
+					{0x0,0x40000000} (on 386)
+
+	Note: Four macros are defined in fdlibm.h to handle this kind of
+	retrieving:
+
+	__HI(x)		the high part of a double x 
+			(sign,exponent,the first 21 significant bits)
+	__LO(x)		the least 32 significant bits of x
+	__HIp(x)	same as __HI except that the argument is a pointer
+			to a double
+	__LOp(x)	same as __LO except that the argument is a pointer
+			to a double
+	
+	To ensure obtaining correct ordering, one must define  __LITTLE_ENDIAN
+	during compilation for little endian machine (like 386,486). The 
+	default is big endian.
+
+	If the behavior of pointer bashing is undefined, one may hack on the 
+	macro in fdlibm.h.
+	
+  d. IEEE exceptions may trigger "signals" as is common in Unix
+     implementations. 
+
+-------------------
+2. EXCEPTION CASES
+-------------------
+All exception cases in the FDLIBM functions will be mapped
+to one of the following four exceptions:
+
+   +-huge*huge, +-tiny*tiny,    +-1.0/0.0,	+-0.0/0.0
+    (overflow)	(underflow)  (divided-by-zero) 	(invalid)
+
+For example, log(0) is a singularity and is thus mapped to 
+	-1.0/0.0 = -infinity.
+That is, FDLIBM's log will compute -one/zero and return the
+computed value.  On an IEEE machine, this will trigger the 
+divided-by-zero exception and a negative infinity is returned by 
+default.
+
+Similarly, exp(-huge) will be mapped to tiny*tiny to generate
+an underflow signal. 
+
+
+--------------------------------
+3. STANDARD CONFORMANCE WRAPPER 
+--------------------------------
+The default FDLIBM functions (compiled with -D_IEEE_LIBM flag)  
+are in "IEEE spirit" (i.e., return the most reasonable result in 
+floating-point arithmetic). If one wants FDLIBM to comply with
+standards like SVID, X/OPEN, or POSIX/ANSI, then one can 
+create a multi-standard compliant FDLIBM. In this case, each
+function in FDLIBM is actually a standard compliant wrapper
+function.  
+
+File organization:
+    1. For FDLIBM's kernel (internal) function,
+		File name	Entry point
+		---------------------------
+		k_sin.c		__kernel_sin
+		k_tan.c		__kernel_tan
+		---------------------------
+    2. For functions that have no standards conflict 
+		File name	Entry point
+		---------------------------
+		s_sin.c		sin
+		s_erf.c		erf
+		---------------------------
+    3. Ieee754 core functions
+		File name	Entry point
+		---------------------------
+		e_exp.c		__ieee754_exp
+		e_sinh.c	__ieee754_sinh
+		---------------------------
+    4. Wrapper functions
+		File name	Entry point
+		---------------------------
+		w_exp.c		exp
+		w_sinh.c	sinh
+		---------------------------
+
+Wrapper functions will twist the result of the ieee754 
+function to comply to the standard specified by the value 
+of _LIB_VERSION 
+    if _LIB_VERSION = _IEEE_, return the ieee754 result;
+    if _LIB_VERSION = _SVID_, return SVID result;
+    if _LIB_VERSION = _XOPEN_, return XOPEN result;
+    if _LIB_VERSION = _POSIX_, return POSIX/ANSI result.
+(These are macros, see fdlibm.h for their definition.)
+
+
+--------------------------------
+4. HOW TO CREATE FDLIBM's libm.a
+--------------------------------
+There are two types of libm.a. One is IEEE only, and the other is
+multi-standard compliant (supports IEEE,XOPEN,POSIX/ANSI,SVID).
+
+To create the IEEE only libm.a, use 
+	    make "CFLAGS = -D_IEEE_LIBM"	 
+This will create an IEEE libm.a, which is smaller in size, and 
+somewhat faster.
+
+To create a multi-standard compliant libm, use
+    make "CFLAGS = -D_IEEE_MODE"   --- multi-standard fdlibm: default
+					 to IEEE
+    make "CFLAGS = -D_XOPEN_MODE"  --- multi-standard fdlibm: default
+					 to X/OPEN
+    make "CFLAGS = -D_POSIX_MODE"  --- multi-standard fdlibm: default
+					 to POSIX/ANSI
+    make "CFLAGS = -D_SVID3_MODE"  --- multi-standard fdlibm: default
+					 to SVID
+
+
+Here is how one makes a SVID compliant libm.
+    Make the library by
+		make "CFLAGS = -D_SVID3_MODE".
+    The libm.a of FDLIBM will be multi-standard compliant and 
+    _LIB_VERSION is initialized to the value _SVID_ . 
+
+    example1:
+    ---------
+	    main()
+	    {
+		double y0();
+		printf("y0(1e300) = %1.20e\n",y0(1e300));
+		exit(0);
+	    }
+
+    % cc example1.c libm.a
+    % a.out
+    y0: TLOSS error
+    y0(1e300) = 0.00000000000000000000e+00
+
+
+It is possible to change the default standard in multi-standard 
+fdlibm. Here is an example of how to do it:
+    example2:
+    ---------
+	#include "fdlibm.h"	/* must include FDLIBM's fdlibm.h */
+	main()
+	{
+		double y0();
+		_LIB_VERSION =  _IEEE_;
+		printf("IEEE: y0(1e300) = %1.20e\n",y0(1e300));
+		_LIB_VERSION = _XOPEN_;
+		printf("XOPEN y0(1e300) = %1.20e\n",y0(1e300));
+		_LIB_VERSION = _POSIX_;
+		printf("POSIX y0(1e300) = %1.20e\n",y0(1e300));
+		_LIB_VERSION = _SVID_;
+		printf("SVID  y0(1e300) = %1.20e\n",y0(1e300));
+		exit(0);
+	}
+
+    % cc example2.c libm.a
+    % a.out
+      IEEE: y0(1e300) = -1.36813604503424810557e-151
+      XOPEN y0(1e300) = 0.00000000000000000000e+00
+      POSIX y0(1e300) = 0.00000000000000000000e+00
+      y0: TLOSS error
+      SVID  y0(1e300) = 0.00000000000000000000e+00
+
+Note:	Here _LIB_VERSION is a global variable. If global variables 
+	are forbidden, then one should modify fdlibm.h to change
+	_LIB_VERSION to be a global constant. In this case, one
+	may not change the value of _LIB_VERSION as in example2.
+
+---------------------------
+5. NOTES ON PORTING FDLIBM
+---------------------------
+	Care must be taken when installing FDLIBM over existing
+	libm.a.
+	All co-existing function prototypes must agree, otherwise
+	users will encounter mysterious failures.
+
+	So far, the only known likely conflict is the declaration 
+	of the IEEE recommended function scalb:
+
+		double scalb(double,double)	(1)	SVID3 defined
+		double scalb(double,int)	(2)	IBM,DEC,...
+
+	FDLIBM follows Sun definition and use (1) as default. 
+	If one's existing libm.a uses (2), then one may raise
+	the flags _SCALB_INT during the compilation of FDLIBM
+	to get the correct function prototype.
+	(E.g., make "CFLAGS = -D_IEEE_LIBM -D_SCALB_INT".)
+	NOTE that if -D_SCALB_INT is raised, it won't be SVID3
+	conformant.
+
+--------------
+6. PROBLEMS ?
+--------------
+Please send comments and bug report to: 
+		fdlibm-comments@sunpro.eng.sun.com
+
--- /dev/null
+++ b/libmath/fdlibm/s_asinh.c
@@ -1,0 +1,53 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_asinh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* asinh(x)
+ * Method :
+ *	Based on 
+ *		asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
+ *	we have
+ *	asinh(x) := x  if  1+x*x=1,
+ *		 := sign(x)*(log(x)+ln2)) for large |x|, else
+ *		 := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
+ *		 := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))  
+ */
+
+#include "fdlibm.h"
+
+static const double 
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+ln2 =  6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */
+Huge=  1.00000000000000000000e+300; 
+
+	double asinh(double x)
+{	
+	double t,w;
+	int hx,ix;
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>=0x7ff00000) return x+x;	/* x is inf or NaN */
+	if(ix< 0x3e300000) {	/* |x|<2**-28 */
+	    if(Huge+x>one) return x;	/* return x inexact except 0 */
+	} 
+	if(ix>0x41b00000) {	/* |x| > 2**28 */
+	    w = __ieee754_log(fabs(x))+ln2;
+	} else if (ix>0x40000000) {	/* 2**28 > |x| > 2.0 */
+	    t = fabs(x);
+	    w = __ieee754_log(2.0*t+one/(sqrt(x*x+one)+t));
+	} else {		/* 2.0 > |x| > 2**-28 */
+	    t = x*x;
+	    w =log1p(fabs(x)+t/(one+sqrt(one+t)));
+	}
+	if(hx>0) return w; else return -w;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_atan.c
@@ -1,0 +1,114 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_atan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* atan(x)
+ * Method
+ *   1. Reduce x to positive by atan(x) = -atan(-x).
+ *   2. According to the integer k=4t+0.25 chopped, t=x, the argument
+ *      is further reduced to one of the following intervals and the
+ *      arctangent of t is evaluated by the corresponding formula:
+ *
+ *      [0,7/16]      atan(x) = t-t^3*(a1+t^2*(a2+...(a10+t^2*a11)...)
+ *      [7/16,11/16]  atan(x) = atan(1/2) + atan( (t-0.5)/(1+t/2) )
+ *      [11/16.19/16] atan(x) = atan( 1 ) + atan( (t-1)/(1+t) )
+ *      [19/16,39/16] atan(x) = atan(3/2) + atan( (t-1.5)/(1+1.5t) )
+ *      [39/16,INF]   atan(x) = atan(INF) + atan( -1/t )
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double atanhi[] = {
+  4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
+  7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
+  9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
+  1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
+};
+
+static const double atanlo[] = {
+  2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
+  3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
+  1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
+  6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
+};
+
+static const double aT[] = {
+  3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
+ -1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
+  1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
+ -1.11111104054623557880e-01, /* 0xBFBC71C6, 0xFE231671 */
+  9.09088713343650656196e-02, /* 0x3FB745CD, 0xC54C206E */
+ -7.69187620504482999495e-02, /* 0xBFB3B0F2, 0xAF749A6D */
+  6.66107313738753120669e-02, /* 0x3FB10D66, 0xA0D03D51 */
+ -5.83357013379057348645e-02, /* 0xBFADDE2D, 0x52DEFD9A */
+  4.97687799461593236017e-02, /* 0x3FA97B4B, 0x24760DEB */
+ -3.65315727442169155270e-02, /* 0xBFA2B444, 0x2C6A6C2F */
+  1.62858201153657823623e-02, /* 0x3F90AD3A, 0xE322DA11 */
+};
+
+	static const double 
+one   = 1.0,
+Huge   = 1.0e300;
+
+	double atan(double x)
+{
+	double w,s1,s2,z;
+	int ix,hx,id;
+
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>=0x44100000) {	/* if |x| >= 2^66 */
+	    if(ix>0x7ff00000||
+		(ix==0x7ff00000&&(__LO(x)!=0)))
+		return x+x;		/* NaN */
+	    if(hx>0) return  atanhi[3]+atanlo[3];
+	    else     return -atanhi[3]-atanlo[3];
+	} if (ix < 0x3fdc0000) {	/* |x| < 0.4375 */
+	    if (ix < 0x3e200000) {	/* |x| < 2^-29 */
+		if(Huge+x>one) return x;	/* raise inexact */
+	    }
+	    id = -1;
+	} else {
+	x = fabs(x);
+	if (ix < 0x3ff30000) {		/* |x| < 1.1875 */
+	    if (ix < 0x3fe60000) {	/* 7/16 <=|x|<11/16 */
+		id = 0; x = (2.0*x-one)/(2.0+x); 
+	    } else {			/* 11/16<=|x|< 19/16 */
+		id = 1; x  = (x-one)/(x+one); 
+	    }
+	} else {
+	    if (ix < 0x40038000) {	/* |x| < 2.4375 */
+		id = 2; x  = (x-1.5)/(one+1.5*x);
+	    } else {			/* 2.4375 <= |x| < 2^66 */
+		id = 3; x  = -1.0/x;
+	    }
+	}}
+    /* end of argument reduction */
+	z = x*x;
+	w = z*z;
+    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
+	s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
+	s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
+	if (id<0) return x - x*(s1+s2);
+	else {
+	    z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
+	    return (hx<0)? -z:z;
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/s_cbrt.c
@@ -1,0 +1,75 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_cbrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+#include "fdlibm.h"
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+static const unsigned 
+	B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+	B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+
+static const double
+C =  5.42857142857142815906e-01, /* 19/35     = 0x3FE15F15, 0xF15F15F1 */
+D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+E =  1.41428571428571436819e+00, /* 99/70     = 0x3FF6A0EA, 0x0EA0EA0F */
+F =  1.60714285714285720630e+00, /* 45/28     = 0x3FF9B6DB, 0x6DB6DB6E */
+G =  3.57142857142857150787e-01; /* 5/14      = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+	double cbrt(double x) 
+{
+	int	hx;
+	double r,s,t=0.0,w;
+	unsigned sign;
+
+
+	hx = __HI(x);		/* high word of x */
+	sign=hx&0x80000000; 		/* sign= sign(x) */
+	hx  ^=sign;
+	if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+	if((hx|__LO(x))==0) 
+	    return(x);		/* cbrt(0) is itself */
+
+	__HI(x) = hx;	/* x <- |x| */
+    /* rough cbrt to 5 bits */
+	if(hx<0x00100000) 		/* subnormal number */
+	  {__HI(t)=0x43500000; 		/* set t= 2**54 */
+	   t*=x; __HI(t)=__HI(t)/3+B2;
+	  }
+	else
+	  __HI(t)=hx/3+B1;	
+
+
+    /* new cbrt to 23 bits, may be implemented in single precision */
+	r=t*t/x;
+	s=C+r*t;
+	t*=G+F/(s+E+D/s);	
+
+    /* chopped to 20 bits and make it larger than cbrt(x) */ 
+	__LO(t)=0; __HI(t)+=0x00000001;
+
+
+    /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+	s=t*t;		/* t*t is exact */
+	r=x/s;
+	w=t+t;
+	r=(r-t)/(w+r);	/* r-s is exact */
+	t=t+t*r;
+
+    /* retore the sign bit */
+	__HI(t) |= sign;
+	return(t);
+}
--- /dev/null
+++ b/libmath/fdlibm/s_ceil.c
@@ -1,0 +1,70 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_ceil.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * ceil(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *	Bit twiddling.
+ * Exception:
+ *	Inexact flag raised if x not equal to ceil(x).
+ */
+
+#include "fdlibm.h"
+
+static const double Huge = 1.0e300;
+
+	double ceil(double x)
+{
+	int i0,i1,j0;
+	unsigned i,j;
+	i0 =  __HI(x);
+	i1 =  __LO(x);
+	j0 = ((i0>>20)&0x7ff)-0x3ff;
+	if(j0<20) {
+	    if(j0<0) { 	/* raise inexact if x != 0 */
+		if(Huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+		    if(i0<0) {i0=0x80000000;i1=0;} 
+		    else if((i0|i1)!=0) { i0=0x3ff00000;i1=0;}
+		}
+	    } else {
+		i = (0x000fffff)>>j0;
+		if(((i0&i)|i1)==0) return x; /* x is integral */
+		if(Huge+x>0.0) {	/* raise inexact flag */
+		    if(i0>0) i0 += (0x00100000)>>j0;
+		    i0 &= (~i); i1=0;
+		}
+	    }
+	} else if (j0>51) {
+	    if(j0==0x400) return x+x;	/* inf or NaN */
+	    else return x;		/* x is integral */
+	} else {
+	    i = ((unsigned)(0xffffffff))>>(j0-20);
+	    if((i1&i)==0) return x;	/* x is integral */
+	    if(Huge+x>0.0) { 		/* raise inexact flag */
+		if(i0>0) {
+		    if(j0==20) i0+=1; 
+		    else {
+			j = i1 + (1<<(52-j0));
+			if(j<i1) i0+=1;	/* got a carry */
+			i1 = j;
+		    }
+		}
+		i1 &= (~i);
+	    }
+	}
+	__HI(x) = i0;
+	__LO(x) = i1;
+	return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_copysign.c
@@ -1,0 +1,27 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_copysign.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * copysign(double x, double y)
+ * copysign(x,y) returns a value with the magnitude of x and
+ * with the sign bit of y.
+ */
+
+#include "fdlibm.h"
+
+	double copysign(double x, double y)
+{
+	__HI(x) = (__HI(x)&0x7fffffff)|(__HI(y)&0x80000000);
+        return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_cos.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_cos.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* cos(x)
+ * Return cosine function of x.
+ *
+ * kernel function:
+ *	__kernel_sin		... sine function on [-pi/4,pi/4]
+ *	__kernel_cos		... cosine function on [-pi/4,pi/4]
+ *	__ieee754_rem_pio2	... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on 
+ *	[-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 
+ *	in [-pi/4 , +pi/4], and let n = k mod 4.
+ *	We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *	    0	       S	   C		 T
+ *	    1	       C	  -S		-1/T
+ *	    2	      -S	  -C		 T
+ *	    3	      -C	   S		-1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *	TRIG(x) returns trig(x) nearly rounded 
+ */
+
+#include "fdlibm.h"
+
+	double cos(double x)
+{
+	double y[2],z=0.0;
+	int n, ix;
+
+    /* High word of x. */
+	ix = __HI(x);
+
+    /* |x| ~< pi/4 */
+	ix &= 0x7fffffff;
+	if(ix <= 0x3fe921fb) return __kernel_cos(x,z);
+
+    /* cos(Inf or NaN) is NaN */
+	else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+	else {
+	    n = __ieee754_rem_pio2(x,y);
+	    switch(n&3) {
+		case 0: return  __kernel_cos(y[0],y[1]);
+		case 1: return -__kernel_sin(y[0],y[1],1);
+		case 2: return -__kernel_cos(y[0],y[1]);
+		default:
+		        return  __kernel_sin(y[0],y[1],1);
+	    }
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/s_erf.c
@@ -1,0 +1,297 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_erf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* double erf(double x)
+ * double erfc(double x)
+ *			     x
+ *		      2      |\
+ *     erf(x)  =  ---------  | exp(-t*t)dt
+ *	 	   sqrt(pi) \| 
+ *			     0
+ *
+ *     erfc(x) =  1-erf(x)
+ *  Note that 
+ *		erf(-x) = -erf(x)
+ *		erfc(-x) = 2 - erfc(x)
+ *
+ * Method:
+ *	1. For |x| in [0, 0.84375]
+ *	    erf(x)  = x + x*R(x^2)
+ *          erfc(x) = 1 - erf(x)           if x in [-.84375,0.25]
+ *                  = 0.5 + ((0.5-x)-x*R)  if x in [0.25,0.84375]
+ *	   where R = P/Q where P is an odd poly of degree 8 and
+ *	   Q is an odd poly of degree 10.
+ *						 -57.90
+ *			| R - (erf(x)-x)/x | <= 2
+ *	
+ *
+ *	   Remark. The formula is derived by noting
+ *          erf(x) = (2/sqrt(pi))*(x - x^3/3 + x^5/10 - x^7/42 + ....)
+ *	   and that
+ *          2/sqrt(pi) = 1.128379167095512573896158903121545171688
+ *	   is close to one. The interval is chosen because the fix
+ *	   point of erf(x) is near 0.6174 (i.e., erf(x)=x when x is
+ *	   near 0.6174), and by some experiment, 0.84375 is chosen to
+ * 	   guarantee the error is less than one ulp for erf.
+ *
+ *      2. For |x| in [0.84375,1.25], let s = |x| - 1, and
+ *         c = 0.84506291151 rounded to single (24 bits)
+ *         	erf(x)  = sign(x) * (c  + P1(s)/Q1(s))
+ *         	erfc(x) = (1-c)  - P1(s)/Q1(s) if x > 0
+ *			  1+(c+P1(s)/Q1(s))    if x < 0
+ *         	|P1/Q1 - (erf(|x|)-c)| <= 2**-59.06
+ *	   Remark: here we use the taylor series expansion at x=1.
+ *		erf(1+s) = erf(1) + s*Poly(s)
+ *			 = 0.845.. + P1(s)/Q1(s)
+ *	   That is, we use rational approximation to approximate
+ *			erf(1+s) - (c = (single)0.84506291151)
+ *	   Note that |P1/Q1|< 0.078 for x in [0.84375,1.25]
+ *	   where 
+ *		P1(s) = degree 6 poly in s
+ *		Q1(s) = degree 6 poly in s
+ *
+ *      3. For x in [1.25,1/0.35(~2.857143)], 
+ *         	erfc(x) = (1/x)*exp(-x*x-0.5625+R1/S1)
+ *         	erf(x)  = 1 - erfc(x)
+ *	   where 
+ *		R1(z) = degree 7 poly in z, (z=1/x^2)
+ *		S1(z) = degree 8 poly in z
+ *
+ *      4. For x in [1/0.35,28]
+ *         	erfc(x) = (1/x)*exp(-x*x-0.5625+R2/S2) if x > 0
+ *			= 2.0 - (1/x)*exp(-x*x-0.5625+R2/S2) if -6<x<0
+ *			= 2.0 - tiny		(if x <= -6)
+ *         	erf(x)  = sign(x)*(1.0 - erfc(x)) if x < 6, else
+ *         	erf(x)  = sign(x)*(1.0 - tiny)
+ *	   where
+ *		R2(z) = degree 6 poly in z, (z=1/x^2)
+ *		S2(z) = degree 7 poly in z
+ *
+ *      Note1:
+ *	   To compute exp(-x*x-0.5625+R/S), let s be a single
+ *	   precision number and s := x; then
+ *		-x*x = -s*s + (s-x)*(s+x)
+ *	        exp(-x*x-0.5626+R/S) = 
+ *			exp(-s*s-0.5625)*exp((s-x)*(s+x)+R/S);
+ *      Note2:
+ *	   Here 4 and 5 make use of the asymptotic series
+ *			  exp(-x*x)
+ *		erfc(x) ~ ---------- * ( 1 + Poly(1/x^2) )
+ *			  x*sqrt(pi)
+ *	   We use rational approximation to approximate
+ *      	g(s)=f(1/x^2) = log(erfc(x)*x) - x*x + 0.5625
+ *	   Here is the error bound for R1/S1 and R2/S2
+ *      	|R1/S1 - f(x)|  < 2**(-62.57)
+ *      	|R2/S2 - f(x)|  < 2**(-61.52)
+ *
+ *      5. For inf > x >= 28
+ *         	erf(x)  = sign(x) *(1 - tiny)  (raise inexact)
+ *         	erfc(x) = tiny*tiny (raise underflow) if x > 0
+ *			= 2 - tiny if x<0
+ *
+ *      7. Special case:
+ *         	erf(0)  = 0, erf(inf)  = 1, erf(-inf) = -1,
+ *         	erfc(0) = 1, erfc(inf) = 0, erfc(-inf) = 2, 
+ *	   	erfc/erf(NaN) is NaN
+ */
+
+
+#include "fdlibm.h"
+
+static const double
+tiny	    = 1e-300,
+half=  5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
+one =  1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
+two =  2.00000000000000000000e+00, /* 0x40000000, 0x00000000 */
+	/* c = (float)0.84506291151 */
+erx =  8.45062911510467529297e-01, /* 0x3FEB0AC1, 0x60000000 */
+/*
+ * Coefficients for approximation to  erf on [0,0.84375]
+ */
+efx =  1.28379167095512586316e-01, /* 0x3FC06EBA, 0x8214DB69 */
+efx8=  1.02703333676410069053e+00, /* 0x3FF06EBA, 0x8214DB69 */
+pp0  =  1.28379167095512558561e-01, /* 0x3FC06EBA, 0x8214DB68 */
+pp1  = -3.25042107247001499370e-01, /* 0xBFD4CD7D, 0x691CB913 */
+pp2  = -2.84817495755985104766e-02, /* 0xBF9D2A51, 0xDBD7194F */
+pp3  = -5.77027029648944159157e-03, /* 0xBF77A291, 0x236668E4 */
+pp4  = -2.37630166566501626084e-05, /* 0xBEF8EAD6, 0x120016AC */
+qq1  =  3.97917223959155352819e-01, /* 0x3FD97779, 0xCDDADC09 */
+qq2  =  6.50222499887672944485e-02, /* 0x3FB0A54C, 0x5536CEBA */
+qq3  =  5.08130628187576562776e-03, /* 0x3F74D022, 0xC4D36B0F */
+qq4  =  1.32494738004321644526e-04, /* 0x3F215DC9, 0x221C1A10 */
+qq5  = -3.96022827877536812320e-06, /* 0xBED09C43, 0x42A26120 */
+/*
+ * Coefficients for approximation to  erf  in [0.84375,1.25] 
+ */
+pa0  = -2.36211856075265944077e-03, /* 0xBF6359B8, 0xBEF77538 */
+pa1  =  4.14856118683748331666e-01, /* 0x3FDA8D00, 0xAD92B34D */
+pa2  = -3.72207876035701323847e-01, /* 0xBFD7D240, 0xFBB8C3F1 */
+pa3  =  3.18346619901161753674e-01, /* 0x3FD45FCA, 0x805120E4 */
+pa4  = -1.10894694282396677476e-01, /* 0xBFBC6398, 0x3D3E28EC */
+pa5  =  3.54783043256182359371e-02, /* 0x3FA22A36, 0x599795EB */
+pa6  = -2.16637559486879084300e-03, /* 0xBF61BF38, 0x0A96073F */
+qa1  =  1.06420880400844228286e-01, /* 0x3FBB3E66, 0x18EEE323 */
+qa2  =  5.40397917702171048937e-01, /* 0x3FE14AF0, 0x92EB6F33 */
+qa3  =  7.18286544141962662868e-02, /* 0x3FB2635C, 0xD99FE9A7 */
+qa4  =  1.26171219808761642112e-01, /* 0x3FC02660, 0xE763351F */
+qa5  =  1.36370839120290507362e-02, /* 0x3F8BEDC2, 0x6B51DD1C */
+qa6  =  1.19844998467991074170e-02, /* 0x3F888B54, 0x5735151D */
+/*
+ * Coefficients for approximation to  erfc in [1.25,1/0.35]
+ */
+ra0  = -9.86494403484714822705e-03, /* 0xBF843412, 0x600D6435 */
+ra1  = -6.93858572707181764372e-01, /* 0xBFE63416, 0xE4BA7360 */
+ra2  = -1.05586262253232909814e+01, /* 0xC0251E04, 0x41B0E726 */
+ra3  = -6.23753324503260060396e+01, /* 0xC04F300A, 0xE4CBA38D */
+ra4  = -1.62396669462573470355e+02, /* 0xC0644CB1, 0x84282266 */
+ra5  = -1.84605092906711035994e+02, /* 0xC067135C, 0xEBCCABB2 */
+ra6  = -8.12874355063065934246e+01, /* 0xC0545265, 0x57E4D2F2 */
+ra7  = -9.81432934416914548592e+00, /* 0xC023A0EF, 0xC69AC25C */
+sa1  =  1.96512716674392571292e+01, /* 0x4033A6B9, 0xBD707687 */
+sa2  =  1.37657754143519042600e+02, /* 0x4061350C, 0x526AE721 */
+sa3  =  4.34565877475229228821e+02, /* 0x407B290D, 0xD58A1A71 */
+sa4  =  6.45387271733267880336e+02, /* 0x40842B19, 0x21EC2868 */
+sa5  =  4.29008140027567833386e+02, /* 0x407AD021, 0x57700314 */
+sa6  =  1.08635005541779435134e+02, /* 0x405B28A3, 0xEE48AE2C */
+sa7  =  6.57024977031928170135e+00, /* 0x401A47EF, 0x8E484A93 */
+sa8  = -6.04244152148580987438e-02, /* 0xBFAEEFF2, 0xEE749A62 */
+/*
+ * Coefficients for approximation to  erfc in [1/.35,28]
+ */
+rb0  = -9.86494292470009928597e-03, /* 0xBF843412, 0x39E86F4A */
+rb1  = -7.99283237680523006574e-01, /* 0xBFE993BA, 0x70C285DE */
+rb2  = -1.77579549177547519889e+01, /* 0xC031C209, 0x555F995A */
+rb3  = -1.60636384855821916062e+02, /* 0xC064145D, 0x43C5ED98 */
+rb4  = -6.37566443368389627722e+02, /* 0xC083EC88, 0x1375F228 */
+rb5  = -1.02509513161107724954e+03, /* 0xC0900461, 0x6A2E5992 */
+rb6  = -4.83519191608651397019e+02, /* 0xC07E384E, 0x9BDC383F */
+sb1  =  3.03380607434824582924e+01, /* 0x403E568B, 0x261D5190 */
+sb2  =  3.25792512996573918826e+02, /* 0x40745CAE, 0x221B9F0A */
+sb3  =  1.53672958608443695994e+03, /* 0x409802EB, 0x189D5118 */
+sb4  =  3.19985821950859553908e+03, /* 0x40A8FFB7, 0x688C246A */
+sb5  =  2.55305040643316442583e+03, /* 0x40A3F219, 0xCEDF3BE6 */
+sb6  =  4.74528541206955367215e+02, /* 0x407DA874, 0xE79FE763 */
+sb7  = -2.24409524465858183362e+01; /* 0xC03670E2, 0x42712D62 */
+
+	double erf(double x) 
+{
+	int hx,ix,i;
+	double R,S,P,Q,s,y,z,r;
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>=0x7ff00000) {		/* erf(nan)=nan */
+	    i = ((unsigned)hx>>31)<<1;
+	    return (double)(1-i)+one/x;	/* erf(+-inf)=+-1 */
+	}
+
+	if(ix < 0x3feb0000) {		/* |x|<0.84375 */
+	    if(ix < 0x3e300000) { 	/* |x|<2**-28 */
+	        if (ix < 0x00800000) 
+		    return 0.125*(8.0*x+efx8*x);  /*avoid underflow */
+		return x + efx*x;
+	    }
+	    z = x*x;
+	    r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+	    s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+	    y = r/s;
+	    return x + x*y;
+	}
+	if(ix < 0x3ff40000) {		/* 0.84375 <= |x| < 1.25 */
+	    s = fabs(x)-one;
+	    P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+	    Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+	    if(hx>=0) return erx + P/Q; else return -erx - P/Q;
+	}
+	if (ix >= 0x40180000) {		/* inf>|x|>=6 */
+	    if(hx>=0) return one-tiny; else return tiny-one;
+	}
+	x = fabs(x);
+ 	s = one/(x*x);
+	if(ix< 0x4006DB6E) {	/* |x| < 1/0.35 */
+	    R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+				ra5+s*(ra6+s*ra7))))));
+	    S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+				sa5+s*(sa6+s*(sa7+s*sa8)))))));
+	} else {	/* |x| >= 1/0.35 */
+	    R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+				rb5+s*rb6)))));
+	    S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+				sb5+s*(sb6+s*sb7))))));
+	}
+	z  = x;  
+	__LO(z) = 0;
+	r  =  __ieee754_exp(-z*z-0.5625)*__ieee754_exp((z-x)*(z+x)+R/S);
+	if(hx>=0) return one-r/x; else return  r/x-one;
+}
+
+	double erfc(double x) 
+{
+	int hx,ix;
+	double R,S,P,Q,s,y,z,r;
+	hx = __HI(x);
+	ix = hx&0x7fffffff;
+	if(ix>=0x7ff00000) {			/* erfc(nan)=nan */
+						/* erfc(+-inf)=0,2 */
+	    return (double)(((unsigned)hx>>31)<<1)+one/x;
+	}
+
+	if(ix < 0x3feb0000) {		/* |x|<0.84375 */
+	    if(ix < 0x3c700000)  	/* |x|<2**-56 */
+		return one-x;
+	    z = x*x;
+	    r = pp0+z*(pp1+z*(pp2+z*(pp3+z*pp4)));
+	    s = one+z*(qq1+z*(qq2+z*(qq3+z*(qq4+z*qq5))));
+	    y = r/s;
+	    if(hx < 0x3fd00000) {  	/* x<1/4 */
+		return one-(x+x*y);
+	    } else {
+		r = x*y;
+		r += (x-half);
+	        return half - r ;
+	    }
+	}
+	if(ix < 0x3ff40000) {		/* 0.84375 <= |x| < 1.25 */
+	    s = fabs(x)-one;
+	    P = pa0+s*(pa1+s*(pa2+s*(pa3+s*(pa4+s*(pa5+s*pa6)))));
+	    Q = one+s*(qa1+s*(qa2+s*(qa3+s*(qa4+s*(qa5+s*qa6)))));
+	    if(hx>=0) {
+	        z  = one-erx; return z - P/Q; 
+	    } else {
+		z = erx+P/Q; return one+z;
+	    }
+	}
+	if (ix < 0x403c0000) {		/* |x|<28 */
+	    x = fabs(x);
+ 	    s = one/(x*x);
+	    if(ix< 0x4006DB6D) {	/* |x| < 1/.35 ~ 2.857143*/
+	        R=ra0+s*(ra1+s*(ra2+s*(ra3+s*(ra4+s*(
+				ra5+s*(ra6+s*ra7))))));
+	        S=one+s*(sa1+s*(sa2+s*(sa3+s*(sa4+s*(
+				sa5+s*(sa6+s*(sa7+s*sa8)))))));
+	    } else {			/* |x| >= 1/.35 ~ 2.857143 */
+		if(hx<0&&ix>=0x40180000) return two-tiny;/* x < -6 */
+	        R=rb0+s*(rb1+s*(rb2+s*(rb3+s*(rb4+s*(
+				rb5+s*rb6)))));
+	        S=one+s*(sb1+s*(sb2+s*(sb3+s*(sb4+s*(
+				sb5+s*(sb6+s*sb7))))));
+	    }
+	    z  = x;
+	    __LO(z)  = 0;
+	    r  =  __ieee754_exp(-z*z-0.5625)*
+			__ieee754_exp((z-x)*(z+x)+R/S);
+	    if(hx>0) return r/x; else return two-r/x;
+	} else {
+	    if(hx>0) return tiny*tiny; else return two-tiny;
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/s_expm1.c
@@ -1,0 +1,208 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_expm1.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* expm1(x)
+ * Returns exp(x)-1, the exponential of x minus 1.
+ *
+ * Method
+ *   1. Argument reduction:
+ *	Given x, find r and integer k such that
+ *
+ *               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658  
+ *
+ *      Here a correction term c will be computed to compensate 
+ *	the error in r when rounded to a floating-point number.
+ *
+ *   2. Approximating expm1(r) by a special rational function on
+ *	the interval [0,0.34658]:
+ *	Since
+ *	    r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
+ *	we define R1(r*r) by
+ *	    r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
+ *	That is,
+ *	    R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
+ *		     = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
+ *		     = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
+ *      We use a special Reme algorithm on [0,0.347] to generate 
+ * 	a polynomial of degree 5 in r*r to approximate R1. The 
+ *	maximum error of this polynomial approximation is bounded 
+ *	by 2**-61. In other words,
+ *	    R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
+ *	where 	Q1  =  -1.6666666666666567384E-2,
+ * 		Q2  =   3.9682539681370365873E-4,
+ * 		Q3  =  -9.9206344733435987357E-6,
+ * 		Q4  =   2.5051361420808517002E-7,
+ * 		Q5  =  -6.2843505682382617102E-9;
+ *  	(where z=r*r, and the values of Q1 to Q5 are listed below)
+ *	with error bounded by
+ *	    |                  5           |     -61
+ *	    | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2 
+ *	    |                              |
+ *	
+ *	expm1(r) = exp(r)-1 is then computed by the following 
+ * 	specific way which minimize the accumulation rounding error: 
+ *			       2     3
+ *			      r     r    [ 3 - (R1 + R1*r/2)  ]
+ *	      expm1(r) = r + --- + --- * [--------------------]
+ *		              2     2    [ 6 - r*(3 - R1*r/2) ]
+ *	
+ *	To compensate the error in the argument reduction, we use
+ *		expm1(r+c) = expm1(r) + c + expm1(r)*c 
+ *			   ~ expm1(r) + c + r*c 
+ *	Thus c+r*c will be added in as the correction terms for
+ *	expm1(r+c). Now rearrange the term to avoid optimization 
+ * 	screw up:
+ *		        (      2                                    2 )
+ *		        ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
+ *	 expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
+ *	                ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
+ *                      (                                             )
+ *    	
+ *		   = r - E
+ *   3. Scale back to obtain expm1(x):
+ *	From step 1, we have
+ *	   expm1(x) = either 2^k*[expm1(r)+1] - 1
+ *		    = or     2^k*[expm1(r) + (1-2^-k)]
+ *   4. Implementation notes:
+ *	(A). To save one multiplication, we scale the coefficient Qi
+ *	     to Qi*2^i, and replace z by (x^2)/2.
+ *	(B). To achieve maximum accuracy, we compute expm1(x) by
+ *	  (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
+ *	  (ii)  if k=0, return r-E
+ *	  (iii) if k=-1, return 0.5*(r-E)-0.5
+ *        (iv)	if k=1 if r < -0.25, return 2*((r+0.5)- E)
+ *	       	       else	     return  1.0+2.0*(r-E);
+ *	  (v)   if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
+ *	  (vi)  if k <= 20, return 2^k((1-2^-k)-(E-r)), else
+ *	  (vii) return 2^k(1-((E+2^-k)-r)) 
+ *
+ * Special cases:
+ *	expm1(INF) is INF, expm1(NaN) is NaN;
+ *	expm1(-INF) is -1, and
+ *	for finite argument, only expm1(0)=0 is exact.
+ *
+ * Accuracy:
+ *	according to an error analysis, the error is always less than
+ *	1 ulp (unit in the last place).
+ *
+ * Misc. info.
+ *	For IEEE double 
+ *	    if x >  7.09782712893383973096e+02 then expm1(x) overflow
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough
+ * to produce the hexadecimal values shown.
+ */
+
+#include "fdlibm.h"
+
+static const double
+one		= 1.0,
+Huge		= 1.0e+300,
+tiny		= 1.0e-300,
+o_threshold	= 7.09782712893383973096e+02,/* 0x40862E42, 0xFEFA39EF */
+ln2_hi		= 6.93147180369123816490e-01,/* 0x3fe62e42, 0xfee00000 */
+ln2_lo		= 1.90821492927058770002e-10,/* 0x3dea39ef, 0x35793c76 */
+invln2		= 1.44269504088896338700e+00,/* 0x3ff71547, 0x652b82fe */
+	/* scaled coefficients related to expm1 */
+Q1  =  -3.33333333333331316428e-02, /* BFA11111 111110F4 */
+Q2  =   1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
+Q3  =  -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
+Q4  =   4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
+Q5  =  -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
+
+	double expm1(double x)
+{
+	double y,hi,lo,c,t,e,hxs,hfx,r1;
+	int k,xsb;
+	unsigned hx;
+
+	hx  = __HI(x);	/* high word of x */
+	xsb = hx&0x80000000;		/* sign bit of x */
+	if(xsb==0) y=x; else y= -x;	/* y = |x| */
+	hx &= 0x7fffffff;		/* high word of |x| */
+
+    /* filter out Huge and non-finite argument */
+	if(hx >= 0x4043687A) {			/* if |x|>=56*ln2 */
+	    if(hx >= 0x40862E42) {		/* if |x|>=709.78... */
+                if(hx>=0x7ff00000) {
+		    if(((hx&0xfffff)|__LO(x))!=0) 
+		         return x+x; 	 /* NaN */
+		    else return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */
+	        }
+	        if(x > o_threshold) return Huge*Huge; /* overflow */
+	    }
+	    if(xsb!=0) { /* x < -56*ln2, return -1.0 with inexact */
+		if(x+tiny<0.0)		/* raise inexact */
+		return tiny-one;	/* return -1 */
+	    }
+	}
+
+    /* argument reduction */
+	if(hx > 0x3fd62e42) {		/* if  |x| > 0.5 ln2 */ 
+	    if(hx < 0x3FF0A2B2) {	/* and |x| < 1.5 ln2 */
+		if(xsb==0)
+		    {hi = x - ln2_hi; lo =  ln2_lo;  k =  1;}
+		else
+		    {hi = x + ln2_hi; lo = -ln2_lo;  k = -1;}
+	    } else {
+		k  = invln2*x+((xsb==0)?0.5:-0.5);
+		t  = k;
+		hi = x - t*ln2_hi;	/* t*ln2_hi is exact here */
+		lo = t*ln2_lo;
+	    }
+	    x  = hi - lo;
+	    c  = (hi-x)-lo;
+	} 
+	else if(hx < 0x3c900000) {  	/* when |x|<2**-54, return x */
+	    t = Huge+x;	/* return x with inexact flags when x!=0 */
+	    return x - (t-(Huge+x));	
+	}
+	else k = 0;
+
+    /* x is now in primary range */
+	hfx = 0.5*x;
+	hxs = x*hfx;
+	r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
+	t  = 3.0-r1*hfx;
+	e  = hxs*((r1-t)/(6.0 - x*t));
+	if(k==0) return x - (x*e-hxs);		/* c is 0 */
+	else {
+	    e  = (x*(e-c)-c);
+	    e -= hxs;
+	    if(k== -1) return 0.5*(x-e)-0.5;
+	    if(k==1) 
+	       	if(x < -0.25) return -2.0*(e-(x+0.5));
+	       	else 	      return  one+2.0*(x-e);
+	    if (k <= -2 || k>56) {   /* suffice to return exp(x)-1 */
+	        y = one-(e-x);
+	        __HI(y) += (k<<20);	/* add k to y's exponent */
+	        return y-one;
+	    }
+	    t = one;
+	    if(k<20) {
+	       	__HI(t) = 0x3ff00000 - (0x200000>>k);  /* t=1-2^-k */
+	       	y = t-(e-x);
+	       	__HI(y) += (k<<20);	/* add k to y's exponent */
+	   } else {
+	       	__HI(t)  = ((0x3ff-k)<<20);	/* 2^-k */
+	       	y = x-(e+t);
+	       	y += one;
+	       	__HI(y) += (k<<20);	/* add k to y's exponent */
+	    }
+	}
+	return y;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_fabs.c
@@ -1,0 +1,25 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_fabs.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * fabs(x) returns the absolute value of x.
+ */
+
+#include "fdlibm.h"
+
+	double fabs(double x)
+{
+	__HI(x) &= 0x7fffffff;
+        return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_finite.c
@@ -1,0 +1,27 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_finite.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * finite(x) returns 1 is x is finite, else 0;
+ * no branching!
+ */
+
+#include "fdlibm.h"
+
+	int finite(double x)
+{
+	int hx; 
+	hx = __HI(x);
+	return  (unsigned)((hx&0x7fffffff)-0x7ff00000)>>31;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_floor.c
@@ -1,0 +1,71 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_floor.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * floor(x)
+ * Return x rounded toward -inf to integral value
+ * Method:
+ *	Bit twiddling.
+ * Exception:
+ *	Inexact flag raised if x not equal to floor(x).
+ */
+
+#include "fdlibm.h"
+
+static const double Huge = 1.0e300;
+
+	double floor(double x)
+{
+	int i0,i1,j0;
+	unsigned i,j;
+	i0 =  __HI(x);
+	i1 =  __LO(x);
+	j0 = ((i0>>20)&0x7ff)-0x3ff;
+	if(j0<20) {
+	    if(j0<0) { 	/* raise inexact if x != 0 */
+		if(Huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
+		    if(i0>=0) {i0=i1=0;} 
+		    else if(((i0&0x7fffffff)|i1)!=0)
+			{ i0=0xbff00000;i1=0;}
+		}
+	    } else {
+		i = (0x000fffff)>>j0;
+		if(((i0&i)|i1)==0) return x; /* x is integral */
+		if(Huge+x>0.0) {	/* raise inexact flag */
+		    if(i0<0) i0 += (0x00100000)>>j0;
+		    i0 &= (~i); i1=0;
+		}
+	    }
+	} else if (j0>51) {
+	    if(j0==0x400) return x+x;	/* inf or NaN */
+	    else return x;		/* x is integral */
+	} else {
+	    i = ((unsigned)(0xffffffff))>>(j0-20);
+	    if((i1&i)==0) return x;	/* x is integral */
+	    if(Huge+x>0.0) { 		/* raise inexact flag */
+		if(i0<0) {
+		    if(j0==20) i0+=1; 
+		    else {
+			j = i1+(1<<(52-j0));
+			if(j<i1) i0 +=1 ; 	/* got a carry */
+			i1=j;
+		    }
+		}
+		i1 &= (~i);
+	    }
+	}
+	__HI(x) = i0;
+	__LO(x) = i1;
+	return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_ilogb.c
@@ -1,0 +1,42 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_ilogb.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* ilogb(double x)
+ * return the binary exponent of non-zero x
+ * ilogb(0) = 0x80000001
+ * ilogb(inf/NaN) = 0x7fffffff (no signal is raised)
+ */
+
+#include "fdlibm.h"
+
+	int ilogb(double x)
+{
+	int hx,lx,ix;
+
+	hx  = (__HI(x))&0x7fffffff;	/* high word of x */
+	if(hx<0x00100000) {
+	    lx = __LO(x);
+	    if((hx|lx)==0) 
+		return 0x80000001;	/* ilogb(0) = 0x80000001 */
+	    else			/* subnormal x */
+		if(hx==0) {
+		    for (ix = -1043; lx>0; lx<<=1) ix -=1;
+		} else {
+		    for (ix = -1022,hx<<=11; hx>0; hx<<=1) ix -=1;
+		}
+	    return ix;
+	}
+	else if (hx<0x7ff00000) return (hx>>20)-1023;
+	else return 0x7fffffff;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_isnan.c
@@ -1,0 +1,30 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_isnan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * isnan(x) returns 1 is x is nan, else 0;
+ * no branching!
+ */
+
+#include "fdlibm.h"
+
+	int isnan(double x)
+{
+	int hx,lx;
+	hx = (__HI(x)&0x7fffffff);
+	lx = __LO(x);
+	hx |= (unsigned)(lx|(-lx))>>31;	
+	hx = 0x7ff00000 - hx;
+	return ((unsigned)(hx))>>31;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_log1p.c
@@ -1,0 +1,157 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_log1p.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* double log1p(double x)
+ *
+ * Method :                  
+ *   1. Argument Reduction: find k and f such that 
+ *			1+x = 2^k * (1+f), 
+ *	   where  sqrt(2)/2 < 1+f < sqrt(2) .
+ *
+ *      Note. If k=0, then f=x is exact. However, if k!=0, then f
+ *	may not be representable exactly. In that case, a correction
+ *	term is need. Let u=1+x rounded. Let c = (1+x)-u, then
+ *	log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
+ *	and add back the correction term c/u.
+ *	(Note: when x > 2**53, one can simply return log(x))
+ *
+ *   2. Approximation of log1p(f).
+ *	Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
+ *		 = 2s + 2/3 s**3 + 2/5 s**5 + .....,
+ *	     	 = 2s + s*R
+ *      We use a special Reme algorithm on [0,0.1716] to generate 
+ * 	a polynomial of degree 14 to approximate R The maximum error 
+ *	of this polynomial approximation is bounded by 2**-58.45. In
+ *	other words,
+ *		        2      4      6      8      10      12      14
+ *	    R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s  +Lp6*s  +Lp7*s
+ *  	(the values of Lp1 to Lp7 are listed in the program)
+ *	and
+ *	    |      2          14          |     -58.45
+ *	    | Lp1*s +...+Lp7*s    -  R(z) | <= 2 
+ *	    |                             |
+ *	Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
+ *	In order to guarantee error in log below 1ulp, we compute log
+ *	by
+ *		log1p(f) = f - (hfsq - s*(hfsq+R)).
+ *	
+ *	3. Finally, log1p(x) = k*ln2 + log1p(f).  
+ *		 	     = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
+ *	   Here ln2 is split into two floating point number: 
+ *			ln2_hi + ln2_lo,
+ *	   where n*ln2_hi is always exact for |n| < 2000.
+ *
+ * Special cases:
+ *	log1p(x) is NaN with signal if x < -1 (including -INF) ; 
+ *	log1p(+INF) is +INF; log1p(-1) is -INF with signal;
+ *	log1p(NaN) is that NaN with no signal.
+ *
+ * Accuracy:
+ *	according to an error analysis, the error is always less than
+ *	1 ulp (unit in the last place).
+ *
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ *
+ * Note: Assuming log() return accurate answer, the following
+ * 	 algorithm can be used to compute log1p(x) to within a few ULP:
+ *	
+ *		u = 1+x;
+ *		if(u==1.0) return x ; else
+ *			   return log(u)*(x/(u-1.0));
+ *
+ *	 See HP-15C Advanced Functions Handbook, p.193.
+ */
+
+#include "fdlibm.h"
+
+static const double
+ln2_hi  =  6.93147180369123816490e-01,	/* 3fe62e42 fee00000 */
+ln2_lo  =  1.90821492927058770002e-10,	/* 3dea39ef 35793c76 */
+two54   =  1.80143985094819840000e+16,  /* 43500000 00000000 */
+Lp1 = 6.666666666666735130e-01,  /* 3FE55555 55555593 */
+Lp2 = 3.999999999940941908e-01,  /* 3FD99999 9997FA04 */
+Lp3 = 2.857142874366239149e-01,  /* 3FD24924 94229359 */
+Lp4 = 2.222219843214978396e-01,  /* 3FCC71C5 1D8E78AF */
+Lp5 = 1.818357216161805012e-01,  /* 3FC74664 96CB03DE */
+Lp6 = 1.531383769920937332e-01,  /* 3FC39A09 D078C69F */
+Lp7 = 1.479819860511658591e-01;  /* 3FC2F112 DF3E5244 */
+
+static double zero = 0.0;
+
+	double log1p(double x)
+{
+	double hfsq,f,c,s,z,R,u;
+	int k,hx,hu,ax;
+
+	hx = __HI(x);		/* high word of x */
+	ax = hx&0x7fffffff;
+
+	k = 1;
+	if (hx < 0x3FDA827A) {			/* x < 0.41422  */
+	    if(ax>=0x3ff00000) {		/* x <= -1.0 */
+		if(x==-1.0) return -two54/zero; /* log1p(-1)=+inf */
+		else return (x-x)/(x-x);	/* log1p(x<-1)=NaN */
+	    }
+	    if(ax<0x3e200000) {			/* |x| < 2**-29 */
+		if(two54+x>zero			/* raise inexact */
+	            &&ax<0x3c900000) 		/* |x| < 2**-54 */
+		    return x;
+		else
+		    return x - x*x*0.5;
+	    }
+	    if(hx>0||hx<=((int)0xbfd2bec3)) {
+		k=0;f=x;hu=1;}	/* -0.2929<x<0.41422 */
+	} 
+	if (hx >= 0x7ff00000) return x+x;
+	if(k!=0) {
+	    if(hx<0x43400000) {
+		u  = 1.0+x; 
+	        hu = __HI(u);		/* high word of u */
+	        k  = (hu>>20)-1023;
+	        c  = (k>0)? 1.0-(u-x):x-(u-1.0);/* correction term */
+		c /= u;
+	    } else {
+		u  = x;
+	        hu = __HI(u);		/* high word of u */
+	        k  = (hu>>20)-1023;
+		c  = 0;
+	    }
+	    hu &= 0x000fffff;
+	    if(hu<0x6a09e) {
+	        __HI(u) = hu|0x3ff00000;	/* normalize u */
+	    } else {
+	        k += 1; 
+	        __HI(u) = hu|0x3fe00000;	/* normalize u/2 */
+	        hu = (0x00100000-hu)>>2;
+	    }
+	    f = u-1.0;
+	}
+	hfsq=0.5*f*f;
+	if(hu==0) {	/* |f| < 2**-20 */
+	    if(f==zero) if(k==0) return zero;  
+			else {c += k*ln2_lo; return k*ln2_hi+c;}
+	    R = hfsq*(1.0-0.66666666666666666*f);
+	    if(k==0) return f-R; else
+	    	     return k*ln2_hi-((R-(k*ln2_lo+c))-f);
+	}
+ 	s = f/(2.0+f); 
+	z = s*s;
+	R = z*(Lp1+z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))));
+	if(k==0) return f-(hfsq-s*(hfsq+R)); else
+		 return k*ln2_hi-((hfsq-(s*(hfsq+R)+(k*ln2_lo+c)))-f);
+}
--- /dev/null
+++ b/libmath/fdlibm/s_modf.c
@@ -1,0 +1,72 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_modf.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/*
+ * modf(double x, double *iptr) 
+ * return fraction part of x, and return x's integral part in *iptr.
+ * Method:
+ *	Bit twiddling.
+ *
+ * Exception:
+ *	No exception.
+ */
+
+#include "fdlibm.h"
+
+static const double one = 1.0;
+
+	double modf(double x, double *iptr)
+{
+	int i0,i1,j0;
+	unsigned i;
+	i0 =  __HI(x);		/* high x */
+	i1 =  __LO(x);		/* low  x */
+	j0 = ((i0>>20)&0x7ff)-0x3ff;	/* exponent of x */
+	if(j0<20) {			/* integer part in high x */
+	    if(j0<0) {			/* |x|<1 */
+		__HIp(iptr) = i0&0x80000000;
+		__LOp(iptr) = 0;		/* *iptr = +-0 */
+		return x;
+	    } else {
+		i = (0x000fffff)>>j0;
+		if(((i0&i)|i1)==0) {		/* x is integral */
+		    *iptr = x;
+		    __HI(x) &= 0x80000000;
+		    __LO(x)  = 0;	/* return +-0 */
+		    return x;
+		} else {
+		    __HIp(iptr) = i0&(~i);
+		    __LOp(iptr) = 0;
+		    return x - *iptr;
+		}
+	    }
+	} else if (j0>51) {		/* no fraction part */
+	    *iptr = x*one;
+	    __HI(x) &= 0x80000000;
+	    __LO(x)  = 0;	/* return +-0 */
+	    return x;
+	} else {			/* fraction part in low x */
+	    i = ((unsigned)(0xffffffff))>>(j0-20);
+	    if((i1&i)==0) { 		/* x is integral */
+		*iptr = x;
+		__HI(x) &= 0x80000000;
+		__LO(x)  = 0;	/* return +-0 */
+		return x;
+	    } else {
+		__HIp(iptr) = i0;
+		__LOp(iptr) = i1&(~i);
+		return x - *iptr;
+	    }
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/s_nextafter.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_nextafter.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* IEEE functions
+ *	nextafter(x,y)
+ *	return the next machine floating-point number of x in the
+ *	direction toward y.
+ *   Special cases:
+ */
+
+#include "fdlibm.h"
+
+	double nextafter(double x, double y)
+{
+	int	hx,hy,ix,iy;
+	unsigned lx,ly;
+
+	hx = __HI(x);		/* high word of x */
+	lx = __LO(x);		/* low  word of x */
+	hy = __HI(y);		/* high word of y */
+	ly = __LO(y);		/* low  word of y */
+	ix = hx&0x7fffffff;		/* |x| */
+	iy = hy&0x7fffffff;		/* |y| */
+
+	if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   /* x is nan */ 
+	   ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     /* y is nan */ 
+	   return x+y;				
+	if(x==y) return x;		/* x=y, return x */
+	if((ix|lx)==0) {			/* x == 0 */
+	    __HI(x) = hy&0x80000000;	/* return +-minsubnormal */
+	    __LO(x) = 1;
+	    y = x*x;
+	    if(y==x) return y; else return x;	/* raise underflow flag */
+	} 
+	if(hx>=0) {				/* x > 0 */
+	    if(hx>hy||((hx==hy)&&(lx>ly))) {	/* x > y, x -= ulp */
+		if(lx==0) hx -= 1;
+		lx -= 1;
+	    } else {				/* x < y, x += ulp */
+		lx += 1;
+		if(lx==0) hx += 1;
+	    }
+	} else {				/* x < 0 */
+	    if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){/* x < y, x -= ulp */
+		if(lx==0) hx -= 1;
+		lx -= 1;
+	    } else {				/* x > y, x += ulp */
+		lx += 1;
+		if(lx==0) hx += 1;
+	    }
+	}
+	hy = hx&0x7ff00000;
+	if(hy>=0x7ff00000) return x+x;	/* overflow  */
+	if(hy<0x00100000) {		/* underflow */
+	    y = x*x;
+	    if(y!=x) {		/* raise underflow flag */
+		__HI(y) = hx; __LO(y) = lx;
+		return y;
+	    }
+	}
+	__HI(x) = hx; __LO(x) = lx;
+	return x;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_rint.c
@@ -1,0 +1,88 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_rint.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* dummy routine to get around over-eager arm compiler optimization.
+  * Calling this causes a store and reload of floating point numbers
+  */
+
+void
+dummy(void)
+{
+}
+
+
+/*
+ * rint(x)
+ * Return x rounded to integral value according to the prevailing
+ * rounding mode.
+ * Method:
+ *	Using floating addition.
+ * Exception:
+ *	Inexact flag raised if x not equal to rint(x).
+ */
+
+#include "fdlibm.h"
+
+static const double
+TWO52[2]={
+  4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+ -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
+};
+
+	double rint(double x)
+{
+	int i0,j0,sx;
+	unsigned i,i1;
+	double w,t;
+	i0 =  __HI(x);
+	sx = (i0>>31)&1;
+	i1 =  __LO(x);
+	j0 = ((i0>>20)&0x7ff)-0x3ff;
+	if(j0<20) {
+	    if(j0<0) { 	
+		if(((i0&0x7fffffff)|i1)==0) return x;
+		i1 |= (i0&0x0fffff);
+		i0 &= 0xfffe0000;
+		i0 |= ((i1|-i1)>>12)&0x80000;
+		__HI(x)=i0;
+	        w = TWO52[sx]+x;
+                 dummy();			/* fix optimiser */
+	        t =  w-TWO52[sx];
+	        i0 = __HI(t);
+	        __HI(t) = (i0&0x7fffffff)|(sx<<31);
+	        return t;
+	    } else {
+		i = (0x000fffff)>>j0;
+		if(((i0&i)|i1)==0) return x; /* x is integral */
+		i>>=1;
+		if(((i0&i)|i1)!=0) {
+		    if(j0==19) i1 = 0x40000000; else
+		    i0 = (i0&(~i))|((0x20000)>>j0);
+		}
+	    }
+	} else if (j0>51) {
+	    if(j0==0x400) return x+x;	/* inf or NaN */
+	    else return x;		/* x is integral */
+	} else {
+	    i = ((unsigned)(0xffffffff))>>(j0-20);
+	    if((i1&i)==0) return x;	/* x is integral */
+	    i>>=1;
+	    if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
+	}
+	__HI(x) = i0;
+	__LO(x) = i1;
+	w = TWO52[sx]+x;
+	dummy();			/* fix optimiser */
+	return w-TWO52[sx];
+}
--- /dev/null
+++ b/libmath/fdlibm/s_scalbn.c
@@ -1,0 +1,55 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_scalbn.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* 
+ * scalbn (double x, int n)
+ * scalbn(x,n) returns x* 2**n  computed by  exponent  
+ * manipulation rather than by actually performing an 
+ * exponentiation or a multiplication.
+ */
+
+#include "fdlibm.h"
+
+static const double
+two54   =  1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
+twom54  =  5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
+Huge   = 1.0e+300,
+tiny   = 1.0e-300;
+
+	double scalbn (double x, int n)
+{
+	int  k,hx,lx;
+	hx = __HI(x);
+	lx = __LO(x);
+        k = (hx&0x7ff00000)>>20;		/* extract exponent */
+        if (k==0) {				/* 0 or subnormal x */
+            if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */
+	    x *= two54; 
+	    hx = __HI(x);
+	    k = ((hx&0x7ff00000)>>20) - 54; 
+            if (n< -50000) return tiny*x; 	/*underflow*/
+	    }
+        if (k==0x7ff) return x+x;		/* NaN or Inf */
+        k = k+n; 
+        if (k >  0x7fe) return Huge*copysign(Huge,x); /* overflow  */
+        if (k > 0) 				/* normal result */
+	    {__HI(x) = (hx&0x800fffff)|(k<<20); return x;}
+        if (k <= -54)
+            if (n > 50000) 	/* in case integer overflow in n+k */
+		return Huge*copysign(Huge,x);	/*overflow*/
+	    else return tiny*copysign(tiny,x); 	/*underflow*/
+        k += 54;				/* subnormal result */
+        __HI(x) = (hx&0x800fffff)|(k<<20);
+        return x*twom54;
+}
--- /dev/null
+++ b/libmath/fdlibm/s_sin.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_sin.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* sin(x)
+ * Return sine function of x.
+ *
+ * kernel function:
+ *	__kernel_sin		... sine function on [-pi/4,pi/4]
+ *	__kernel_cos		... cose function on [-pi/4,pi/4]
+ *	__ieee754_rem_pio2	... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on 
+ *	[-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 
+ *	in [-pi/4 , +pi/4], and let n = k mod 4.
+ *	We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *	    0	       S	   C		 T
+ *	    1	       C	  -S		-1/T
+ *	    2	      -S	  -C		 T
+ *	    3	      -C	   S		-1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *	TRIG(x) returns trig(x) nearly rounded 
+ */
+
+#include "fdlibm.h"
+
+	double sin(double x)
+{
+	double y[2],z=0.0;
+	int n, ix;
+
+    /* High word of x. */
+	ix = __HI(x);
+
+    /* |x| ~< pi/4 */
+	ix &= 0x7fffffff;
+	if(ix <= 0x3fe921fb) return __kernel_sin(x,z,0);
+
+    /* sin(Inf or NaN) is NaN */
+	else if (ix>=0x7ff00000) return x-x;
+
+    /* argument reduction needed */
+	else {
+	    n = __ieee754_rem_pio2(x,y);
+	    switch(n&3) {
+		case 0: return  __kernel_sin(y[0],y[1],1);
+		case 1: return  __kernel_cos(y[0],y[1]);
+		case 2: return -__kernel_sin(y[0],y[1],1);
+		default:
+			return -__kernel_cos(y[0],y[1]);
+	    }
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/s_tan.c
@@ -1,0 +1,68 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_tan.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* tan(x)
+ * Return tangent function of x.
+ *
+ * kernel function:
+ *	__kernel_tan		... tangent function on [-pi/4,pi/4]
+ *	__ieee754_rem_pio2	... argument reduction routine
+ *
+ * Method.
+ *      Let S,C and T denote the sin, cos and tan respectively on 
+ *	[-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2 
+ *	in [-pi/4 , +pi/4], and let n = k mod 4.
+ *	We have
+ *
+ *          n        sin(x)      cos(x)        tan(x)
+ *     ----------------------------------------------------------
+ *	    0	       S	   C		 T
+ *	    1	       C	  -S		-1/T
+ *	    2	      -S	  -C		 T
+ *	    3	      -C	   S		-1/T
+ *     ----------------------------------------------------------
+ *
+ * Special cases:
+ *      Let trig be any of sin, cos, or tan.
+ *      trig(+-INF)  is NaN, with signals;
+ *      trig(NaN)    is that NaN;
+ *
+ * Accuracy:
+ *	TRIG(x) returns trig(x) nearly rounded 
+ */
+
+#include "fdlibm.h"
+
+	double tan(double x)
+{
+	double y[2],z=0.0;
+	int n, ix;
+
+    /* High word of x. */
+	ix = __HI(x);
+
+    /* |x| ~< pi/4 */
+	ix &= 0x7fffffff;
+	if(ix <= 0x3fe921fb) return __kernel_tan(x,z,1);
+
+    /* tan(Inf or NaN) is NaN */
+	else if (ix>=0x7ff00000) return x-x;		/* NaN */
+
+    /* argument reduction needed */
+	else {
+	    n = __ieee754_rem_pio2(x,y);
+	    return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /*   1 -- n even
+							-1 -- n odd */
+	}
+}
--- /dev/null
+++ b/libmath/fdlibm/s_tanh.c
@@ -1,0 +1,74 @@
+/* derived from /netlib/fdlibm */
+
+/* @(#)s_tanh.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+
+/* Tanh(x)
+ * Return the Hyperbolic Tangent of x
+ *
+ * Method :
+ *				       x    -x
+ *				      e  - e
+ *	0. tanh(x) is defined to be -----------
+ *				       x    -x
+ *				      e  + e
+ *	1. reduce x to non-negative by tanh(-x) = -tanh(x).
+ *	2.  0      <= x <= 2**-55 : tanh(x) := x*(one+x)
+ *					        -t
+ *	    2**-55 <  x <=  1     : tanh(x) := -----; t = expm1(-2x)
+ *					       t + 2
+ *						     2
+ *	    1      <= x <=  22.0  : tanh(x) := 1-  ----- ; t=expm1(2x)
+ *						   t + 2
+ *	    22.0   <  x <= INF    : tanh(x) := 1.
+ *
+ * Special cases:
+ *	tanh(NaN) is NaN;
+ *	only tanh(0)=0 is exact for finite argument.
+ */
+
+#include "fdlibm.h"
+
+static const double one=1.0, two=2.0, tiny = 1.0e-300;
+
+	double tanh(double x)
+{
+	double t,z;
+	int jx,ix;
+
+    /* High word of |x|. */
+	jx = __HI(x);
+	ix = jx&0x7fffffff;
+
+    /* x is INF or NaN */
+	if(ix>=0x7ff00000) { 
+	    if (jx>=0) return one/x+one;    /* tanh(+-inf)=+-1 */
+	    else       return one/x-one;    /* tanh(NaN) = NaN */
+	}
+
+    /* |x| < 22 */
+	if (ix < 0x40360000) {		/* |x|<22 */
+	    if (ix<0x3c800000) 		/* |x|<2**-55 */
+		return x*(one+x);    	/* tanh(small) = small */
+	    if (ix>=0x3ff00000) {	/* |x|>=1  */
+		t = expm1(two*fabs(x));
+		z = one - two/(t+two);
+	    } else {
+	        t = expm1(-two*fabs(x));
+	        z= -t/(t+two);
+	    }
+    /* |x| > 22, return +-1 */
+	} else {
+	    z = one - tiny;		/* raised inexact flag */
+	}
+	return (jx>=0)? z: -z;
+}
--- /dev/null
+++ b/libmath/g_fmt.c
@@ -1,0 +1,106 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 1996 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
+ * it suffices to declare buf
+ *	char buf[32];
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern char *dtoa(double, int, int, int *, int *, char **);
+ extern char *g_fmt(char *, double, int);
+ extern void freedtoa(char*);
+#ifdef __cplusplus
+	}
+#endif
+
+ char *
+g_fmt(register char *b, double x, int echr)
+{
+	register int i, k;
+	register char *s;
+	int decpt, j, sign;
+	char *b0, *s0, *se;
+
+	b0 = b;
+#ifdef IGNORE_ZERO_SIGN
+	if (!x) {
+		*b++ = '0';
+		*b = 0;
+		goto done;
+		}
+#endif
+	s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se);
+	if (sign)
+		*b++ = '-';
+	if (decpt == 9999) /* Infinity or Nan */ {
+		while(*b++ = *s++);
+		goto done0;
+		}
+	if (decpt <= -4 || decpt > se - s + 5) {
+		*b++ = *s++;
+		if (*s) {
+			*b++ = '.';
+			while(*b = *s++)
+				b++;
+			}
+		*b++ = echr;
+		/* sprintf(b, "%+.2d", decpt - 1); */
+		if (--decpt < 0) {
+			*b++ = '-';
+			decpt = -decpt;
+			}
+		else
+			*b++ = '+';
+		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
+		for(;;) {
+			i = decpt / k;
+			*b++ = i + '0';
+			if (--j <= 0)
+				break;
+			decpt -= i*k;
+			decpt *= 10;
+			}
+		*b = 0;
+		}
+	else if (decpt <= 0) {
+		*b++ = '.';
+		for(; decpt < 0; decpt++)
+			*b++ = '0';
+		while(*b++ = *s++);
+		}
+	else {
+		while(*b = *s++) {
+			b++;
+			if (--decpt == 0 && *s)
+				*b++ = '.';
+			}
+		for(; decpt > 0; decpt--)
+			*b++ = '0';
+		*b = 0;
+		}
+ done0:
+	freedtoa(s0);
+#ifdef IGNORE_ZERO_SIGN
+ done:
+#endif
+	return b0;
+	}
--- /dev/null
+++ b/libmath/gemm.c
@@ -1,0 +1,167 @@
+#include "lib9.h"
+#include "mathi.h"
+void
+gemm(int transa, int transb, int m, int n, int k, double alpha,
+	double *a, int lda,
+	double *b, int ldb, double beta,
+	double *c, int ldc)
+{
+    int i1, i2, i3, nota, notb, i, j, jb, jc, l, la;
+    double temp;
+
+    nota = transa=='N';
+    notb = transb=='N';
+
+    if(m == 0 || n == 0 || (alpha == 0. || k == 0) && beta == 1.){
+	return;
+    }
+    if(alpha == 0.){
+	if(beta == 0.){
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jc = j*ldc;
+		i2 = m;
+		for(i = 0; i < i2; ++i){
+		    c[i + jc] = 0.;
+		}
+	    }
+	}else{
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jc = j*ldc;
+		i2 = m;
+		for(i = 0; i < i2; ++i){
+		    c[i + jc] = beta * c[i + jc];
+		}
+	    }
+	}
+	return;
+    }
+
+    if(!a){
+	if(notb){   /* C := alpha*B + beta*C. */
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jb = j*ldb;
+		jc = j*ldc;
+		i2 = m;
+		for(i = 0; i < i2; ++i){
+		    c[i + jc] = alpha*b[i+jb] + beta*c[i+jc];
+		}
+	    }
+	}else{   /* C := alpha*B' + beta*C. */
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jc = j*ldc;
+		i2 = m;
+		for(i = 0; i < i2; ++i){
+		    c[i + jc] = alpha*b[j+i*ldb] + beta*c[i+jc];
+		}
+	    }
+	}
+	return;
+    }
+
+    if(notb){
+	if(nota){
+
+/*          Form  C := alpha*A*B + beta*C. */
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jc = j*ldc;
+		if(beta == 0.){
+		    i2 = m;
+		    for(i = 0; i < i2; ++i){
+			c[i + jc] = 0.;
+		    }
+		}else if(beta != 1.){
+		    i2 = m;
+		    for(i = 0; i < i2; ++i){
+			c[i + jc] = beta * c[i + jc];
+		    }
+		}
+		i2 = k;
+		for(l = 0; l < i2; ++l){
+		    la = l*lda;
+		    if(b[l + j*ldb] != 0.){
+			temp = alpha * b[l + j*ldb];
+			i3 = m;
+			for(i = 0; i < i3; ++i){
+			    c[i + jc] += temp * a[i + la];
+			}
+		    }
+		}
+	    }
+	}else{
+
+/*          Form  C := alpha*A'*B + beta*C */
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jc = j*ldc;
+		i2 = m;
+		for(i = 0; i < i2; ++i){
+		    temp = 0.;
+		    i3 = k;
+		    for(l = 0; l < i3; ++l){
+			temp += a[l + i*lda] * b[l + j*ldb];
+		    }
+		    if(beta == 0.){
+			c[i + jc] = alpha * temp;
+		    }else{
+			c[i + jc] = alpha * temp + beta * c[i + jc];
+		    }
+		}
+	    }
+	}
+    }else{
+	if(nota){
+
+/*          Form  C := alpha*A*B' + beta*C */
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jc = j*ldc;
+		if(beta == 0.){
+		    i2 = m;
+		    for(i = 0; i < i2; ++i){
+			c[i + jc] = 0.;
+		    }
+		}else if(beta != 1.){
+		    i2 = m;
+		    for(i = 0; i < i2; ++i){
+			c[i + jc] = beta * c[i + jc];
+		    }
+		}
+		i2 = k;
+		for(l = 0; l < i2; ++l){
+		    if(b[j + l*ldb] != 0.){
+			temp = alpha * b[j + l*ldb];
+			i3 = m;
+			for(i = 0; i < i3; ++i){
+			    c[i + jc] += temp * a[i + l*lda];
+			}
+		    }
+		}
+	    }
+	}else{
+
+/*          Form  C := alpha*A'*B' + beta*C */
+	    i1 = n;
+	    for(j = 0; j < i1; ++j){
+		jc = j*ldc;
+		i2 = m;
+		for(i = 0; i < i2; ++i){
+		    temp = 0.;
+		    i3 = k;
+		    for(l = 0; l < i3; ++l){
+			temp += a[l + i*lda] * b[j + l*ldb];
+		    }
+		    if(beta == 0.){
+			c[i + jc] = alpha * temp;
+		    }else{
+			c[i + jc] = alpha * temp + beta * c[i + jc];
+		    }
+		}
+	    }
+	}
+    }
+}
--- /dev/null
+++ b/libmath/gfltconv.c
@@ -1,0 +1,123 @@
+#include "lib9.h"
+#include "mathi.h"
+extern char	*dtoa(double, int, int, int *, int *, char **);
+extern void	freedtoa(char*);
+extern int	_fmtcpy(Fmt*, void*, int, int);
+
+enum
+{
+	NONE	= -1000,
+	FDIGIT	= 20,
+	FDEFLT	= 6,
+	NSIGNIF	= 17
+};
+
+int
+gfltconv(Fmt *f)
+{
+	int flags = f->flags;
+	int precision;
+	int fmt = f->r;
+	double d;
+	int echr, exponent, sign, ndig, nout, i;
+	char *digits, *edigits, ebuf[32], *eptr;
+	char out[64], *pout;
+
+	d = va_arg(f->args, double);
+	echr = 'e';
+	precision = FDEFLT;
+	if(f->flags & FmtPrec)
+		precision = f->prec;
+	if(precision > FDIGIT)
+		precision = FDIGIT;
+	switch(fmt){
+	case 'f':
+		digits = dtoa(d, 3, precision, &exponent, &sign, &edigits);
+		break;
+	case 0x00c9:	/* L'É' */
+	case 'E':
+		echr = 'E';
+		fmt = 'e';
+		/* fall through */
+	case 'e':
+		digits = dtoa(d, 2, 1+precision, &exponent, &sign, &edigits);
+		break;
+	case 'G':
+		echr = 'E';
+		/* fall through */
+	default:
+	case 'g':
+		if((flags&(FmtWidth|FmtPrec)) == 0){
+			g_fmt(out, d, echr);
+			f->flags &= FmtWidth|FmtLeft;
+			return _fmtcpy(f, out, strlen(out), strlen(out));
+		}
+		if (precision > 0)
+			digits = dtoa(d, 2, precision, &exponent, &sign, &edigits);
+		else {
+			digits = dtoa(d, 0, precision, &exponent, &sign, &edigits);
+			precision = edigits - digits;
+			if (exponent > precision && exponent <= precision + 4)
+				precision = exponent;
+			}
+		if(exponent >= -3 && exponent <= precision){
+			fmt = 'f';
+			precision -= exponent;
+		}else{
+			fmt = 'e';
+			--precision;
+		}
+		break;
+	}
+	if (exponent == 9999) {
+		/* Infinity or Nan */
+		precision = 0;
+		exponent = edigits - digits;
+		fmt = 'f';
+	}
+	ndig = edigits-digits;
+	if((f->r=='g' || f->r=='G') && !(flags&FmtSharp)){ /* knock off trailing zeros */
+		if(fmt == 'f'){
+			if(precision+exponent > ndig) {
+				precision = ndig - exponent;
+				if(precision < 0)
+					precision = 0;
+			}
+		}
+		else{
+			if(precision > ndig-1) precision = ndig-1;
+		}
+	}
+	eptr = ebuf;
+	if(fmt != 'f'){					/* exponent */
+		for(i=exponent<=0?1-exponent:exponent-1; i; i/=10)
+			*eptr++ = '0' + i%10;
+		while(eptr<ebuf+2) *eptr++ = '0';
+	}
+	pout = out;
+	if(sign) *pout++ = '-';
+	else if(flags&FmtSign) *pout++ = '+';
+	else if(flags&FmtSpace) *pout++ = ' ';
+	if(fmt == 'f'){
+		for(i=0; i<exponent; i++) *pout++ = i<ndig?digits[i]:'0';
+		if(i == 0) *pout++ = '0';
+		if(precision>0 || flags&FmtSharp) *pout++ = '.';
+		for(i=0; i!=precision; i++)
+			*pout++ = 0<=i+exponent && i+exponent<ndig?digits[i+exponent]:'0';
+	}
+	else{
+		*pout++ = digits[0];
+		if(precision>0 || flags&FmtSharp) *pout++ = '.';
+		for(i=0; i!=precision; i++) *pout++ = i<ndig-1?digits[i+1]:'0';
+	}
+	if(fmt != 'f'){
+		*pout++ = echr;
+		*pout++ = exponent<=0?'-':'+';
+		while(eptr>ebuf) *pout++ = *--eptr;
+	}
+	*pout = 0;
+	freedtoa(digits);
+	f->flags &= FmtWidth|FmtLeft;
+	nout = pout-out;
+	return _fmtcpy(f, out, nout, nout);
+}
--- /dev/null
+++ b/libmath/mkfile
@@ -1,0 +1,66 @@
+<../mkconfig
+
+TARGTYPE=${SYSTARG:os%=Inferno%}		# maps 'os' into 'Inferno'
+
+LIB=libmath.a
+OFILES=\
+	blas.$O\
+	dtoa.$O\
+	fdim.$O\
+	FPcontrol-$TARGTYPE.$O\
+	gemm.$O\
+	g_fmt.$O\
+	gfltconv.$O\
+	pow10.$O\
+	e_acos.$O\
+	e_acosh.$O\
+	e_asin.$O\
+	e_atan2.$O\
+	e_atanh.$O\
+	e_cosh.$O\
+	e_exp.$O\
+	e_fmod.$O\
+	e_hypot.$O\
+	e_j0.$O\
+	e_j1.$O\
+	e_jn.$O\
+	e_lgamma_r.$O\
+	e_log.$O\
+	e_log10.$O\
+	e_pow.$O\
+	e_rem_pio2.$O\
+	e_remainder.$O\
+	e_sinh.$O\
+	e_sqrt.$O\
+	k_cos.$O\
+	k_rem_pio2.$O\
+	k_sin.$O\
+	k_tan.$O\
+	s_asinh.$O\
+	s_atan.$O\
+	s_cbrt.$O\
+	s_ceil.$O\
+	s_copysign.$O\
+	s_cos.$O\
+	s_erf.$O\
+	s_expm1.$O\
+	s_fabs.$O\
+	s_finite.$O\
+	s_floor.$O\
+	s_ilogb.$O\
+	s_log1p.$O\
+	s_nextafter.$O\
+	s_rint.$O\
+	s_scalbn.$O\
+	s_sin.$O\
+	s_tan.$O\
+	s_tanh.$O\
+
+HFILES=\
+	$ROOT/include/mathi.h\
+	fdlibm/fdlibm.h\
+	
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+%.$O:	fdlibm/%.c
+	$CC $CFLAGS -o $target -Ifdlibm fdlibm/$stem.c
--- /dev/null
+++ b/libmath/pow10.c
@@ -1,0 +1,8 @@
+#include "lib9.h"
+#include "mathi.h"
+
+double
+ipow10(int n)
+{
+	return pow(10.,n);
+}
--- /dev/null
+++ b/libmemdraw/NOTICE
@@ -1,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/libmemdraw/alloc.c
@@ -1,0 +1,194 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "pool.h"
+
+extern	Pool*	imagmem;
+
+void
+memimagemove(void *from, void *to)
+{
+	Memdata *md;
+
+	md = *(Memdata**)to;
+	if(md->base != from){
+		print("compacted data not right: #%p\n", md->base);
+		abort();
+	}
+	md->base = to;
+
+	/* if allocmemimage changes this must change too */
+	md->bdata = (uchar*)&md->base[2];
+}
+
+Memimage*
+allocmemimaged(Rectangle r, ulong chan, Memdata *md)
+{
+	int d;
+	ulong l;
+	Memimage *i;
+
+	if((d = chantodepth(chan)) == 0) {
+		werrstr("bad channel descriptor %.8lux", chan);
+		return nil;
+	}
+
+	l = wordsperline(r, d);
+
+	i = mallocz(sizeof(Memimage), 1);
+	if(i == nil)
+		return nil;
+
+	i->data = md;
+	i->zero = sizeof(ulong)*l*r.min.y;
+	
+	if(r.min.x >= 0)
+		i->zero += (r.min.x*d)/8;
+	else
+		i->zero -= (-r.min.x*d+7)/8;
+	i->zero = -i->zero;
+	i->width = l;
+	i->r = r;
+	i->clipr = r;
+	i->flags = 0;
+	i->layer = nil;
+	i->cmap = memdefcmap;
+	if(memsetchan(i, chan) < 0){
+		free(i);
+		return nil;
+	}
+	return i;
+}
+
+Memimage*
+allocmemimage(Rectangle r, ulong chan)
+{
+	int d;
+	ulong l, nw;
+	Memdata *md;
+	Memimage *i;
+
+	if((d = chantodepth(chan)) == 0) {
+		werrstr("bad channel descriptor %.8lux", chan);
+		return nil;
+	}
+
+	l = wordsperline(r, d);
+	nw = l*Dy(r);
+	md = malloc(sizeof(Memdata));
+	if(md == nil)
+		return nil;
+
+	md->ref = 1;
+	md->base = poolalloc(imagmem, (2+nw)*sizeof(ulong));
+	if(md->base == nil){
+		free(md);
+		return nil;
+	}
+
+	md->base[0] = (ulong)md;
+	/* md->base[1] = getcallerpc(&r); */
+
+	/* if this changes, memimagemove must change too */
+	md->bdata = (uchar*)&md->base[2];
+
+	md->allocd = 1;
+
+	i = allocmemimaged(r, chan, md);
+	if(i == nil){
+		poolfree(imagmem, md->base);
+		free(md);
+		return nil;
+	}
+	md->imref = i;
+	return i;
+}
+
+void
+freememimage(Memimage *i)
+{
+	if(i == nil)
+		return;
+	if(i->data->ref-- == 1 && i->data->allocd){
+		if(i->data->base)
+			poolfree(imagmem, i->data->base);
+		free(i->data);
+	}
+	free(i);
+}
+
+/*
+ * Wordaddr is deprecated.
+ */
+ulong*
+wordaddr(Memimage *i, Point p)
+{
+	return (ulong*) ((ulong)byteaddr(i, p) & ~(sizeof(ulong)-1));
+}
+
+uchar*
+byteaddr(Memimage *i, Point p)
+{
+	uchar *a;
+
+	a = i->data->bdata+i->zero+sizeof(ulong)*p.y*i->width;
+
+	if(i->depth < 8){
+		/*
+		 * We need to always round down,
+		 * but C rounds toward zero.
+		 */
+		int np;
+		np = 8/i->depth;
+		if(p.x < 0)
+			return a+(p.x-np+1)/np;
+		else
+			return a+p.x/np;
+	}
+	else
+		return a+p.x*(i->depth/8);
+}
+
+int
+memsetchan(Memimage *i, ulong chan)
+{
+	int d;
+	int t, j, k;
+	ulong cc;
+	int bytes;
+
+	if((d = chantodepth(chan)) == 0) {
+		werrstr("bad channel descriptor");
+		return -1;
+	}
+
+	i->depth = d;
+	i->chan = chan;
+	i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes);
+	bytes = 1;
+	for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){
+		t=TYPE(cc);
+		if(t < 0 || t >= NChan){
+			werrstr("bad channel string");
+			return -1;
+		}
+		if(t == CGrey)
+			i->flags |= Fgrey;
+		if(t == CAlpha)
+			i->flags |= Falpha;
+		if(t == CMap && i->cmap == nil){
+			i->cmap = memdefcmap;
+			i->flags |= Fcmap;
+		}
+
+		i->shift[t] = j;
+		i->mask[t] = (1<<NBITS(cc))-1;
+		i->nbits[t] = NBITS(cc);
+		if(NBITS(cc) != 8)
+			bytes = 0;
+	}
+	i->nchan = k;
+	if(bytes)
+		i->flags |= Fbytes;
+	return 0;
+}
--- /dev/null
+++ b/libmemdraw/arc.c
@@ -1,0 +1,116 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * elarc(dst,c,a,b,t,src,sp,alpha,phi)
+ *   draws the part of an ellipse between rays at angles alpha and alpha+phi
+ *   measured counterclockwise from the positive x axis. other
+ *   arguments are as for ellipse(dst,c,a,b,t,src,sp)
+ */
+
+enum
+{
+	R, T, L, B	/* right, top, left, bottom */
+};
+
+static
+Point corners[] = {
+	{1,1},
+	{-1,1},
+	{-1,-1},
+	{1,-1}
+};
+
+static
+Point p00;
+
+/*
+ * make a "wedge" mask covering the desired angle and contained in
+ * a surrounding square; draw a full ellipse; intersect that with the
+ * wedge to make a mask through which to copy src to dst.
+ */
+void
+memarc(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int alpha, int phi, int op)
+{
+	int i, w, beta, tmp, c1, c2, m, m1;
+	Rectangle rect;
+	Point p,	bnd[8];
+	Memimage *wedge, *figure, *mask;
+
+	if(a < 0)
+		a = -a;
+	if(b < 0)
+		b = -b;
+	w = t;
+	if(w < 0)
+		w = 0;
+	alpha = -alpha;		/* compensate for upside-down coords */
+	phi = -phi;
+	beta = alpha + phi;
+	if(phi < 0){
+		tmp = alpha;
+		alpha = beta;
+		beta = tmp;
+		phi = -phi;
+	}
+	if(phi >= 360){
+		memellipse(dst, c, a, b, t, src, sp, op);
+		return;
+	}
+	while(alpha < 0)
+		alpha += 360;
+	while(beta < 0)
+		beta += 360;
+	c1 = alpha/90 & 3;	/* number of nearest corner */
+	c2 = beta/90 & 3;
+		/*
+		 * icossin returns point at radius ICOSSCALE.
+		 * multiplying by m1 moves it outside the ellipse
+		*/
+	rect = Rect(-a-w, -b-w, a+w+1, b+w+1);
+	m = rect.max.x;	/* inradius of bounding square */
+	if(m < rect.max.y)
+		m = rect.max.y;
+	m1 = (m+ICOSSCALE-1) >> 10;
+	m = m1 << 10;		/* assure m1*cossin is inside */
+	i = 0;
+	bnd[i++] = Pt(0,0);
+	icossin(alpha, &p.x, &p.y);
+	bnd[i++] = mulpt(p, m1);
+	for(;;) {
+		bnd[i++] = mulpt(corners[c1], m);
+		if(c1==c2 && phi<180)
+			break;
+		c1 = (c1+1) & 3;
+		phi -= 90;
+	}
+	icossin(beta, &p.x, &p.y);
+	bnd[i++] = mulpt(p, m1);
+
+	figure = nil;
+	mask = nil;
+	wedge = allocmemimage(rect, GREY1);
+	if(wedge == nil)
+		goto Return;
+	memfillcolor(wedge, DTransparent);
+	memfillpoly(wedge, bnd, i, ~0, memopaque, p00, S);
+	figure = allocmemimage(rect, GREY1);
+	if(figure == nil)
+		goto Return;
+	memfillcolor(figure, DTransparent);
+	memellipse(figure, p00, a, b, t, memopaque, p00, S);
+	mask = allocmemimage(rect, GREY1);
+	if(mask == nil)
+		goto Return;
+	memfillcolor(mask, DTransparent);
+	memimagedraw(mask, rect, figure, rect.min, wedge, rect.min, S);
+	c = subpt(c, dst->r.min);
+	memdraw(dst, dst->r, src, subpt(sp, c), mask, subpt(p00, c), op);
+
+    Return:
+	freememimage(wedge);
+	freememimage(figure);
+	freememimage(mask);
+}
--- /dev/null
+++ b/libmemdraw/cload.c
@@ -1,0 +1,67 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+	int y, bpl, c, cnt, offs;
+	uchar mem[NMEM], *memp, *omemp, *emem, *linep, *elinep, *u, *eu;
+
+	if(!rectinrect(r, i->r))
+		return -1;
+	bpl = bytesperline(r, i->depth);
+	u = data;
+	eu = data+ndata;
+	memp = mem;
+	emem = mem+NMEM;
+	y = r.min.y;
+	linep = byteaddr(i, Pt(r.min.x, y));
+	elinep = linep+bpl;
+	for(;;){
+		if(linep == elinep){
+			if(++y == r.max.y)
+				break;
+			linep = byteaddr(i, Pt(r.min.x, y));
+			elinep = linep+bpl;
+		}
+		if(u == eu){	/* buffer too small */
+			return -1;
+		}
+		c = *u++;
+		if(c >= 128){
+			for(cnt=c-128+1; cnt!=0 ;--cnt){
+				if(u == eu){		/* buffer too small */
+					return -1;
+				}
+				if(linep == elinep){	/* phase error */
+					return -1;
+				}
+				*linep++ = *u;
+				*memp++ = *u++;
+				if(memp == emem)
+					memp = mem;
+			}
+		}
+		else{
+			if(u == eu)	/* short buffer */
+				return -1;
+			offs = *u++ + ((c&3)<<8)+1;
+			if(memp-mem < offs)
+				omemp = memp+(NMEM-offs);
+			else
+				omemp = memp-offs;
+			for(cnt=(c>>2)+NMATCH; cnt!=0; --cnt){
+				if(linep == elinep)	/* phase error */
+					return -1;
+				*linep++ = *omemp;
+				*memp++ = *omemp++;
+				if(omemp == emem)
+					omemp = mem;
+				if(memp == emem)
+					memp = mem;
+			}
+		}
+	}
+	return u-data;
+}
--- /dev/null
+++ b/libmemdraw/cmap.c
@@ -1,0 +1,316 @@
+#include "lib9.h"
+#include <draw.h>
+#include <memdraw.h>
+
+static Memcmap def = {
+/* cmap2rgb */ {
+	0x00,0x00,0x00,0x00,0x00,0x44,0x00,0x00,0x88,0x00,0x00,0xcc,0x00,0x44,0x00,0x00,
+	0x44,0x44,0x00,0x44,0x88,0x00,0x44,0xcc,0x00,0x88,0x00,0x00,0x88,0x44,0x00,0x88,
+	0x88,0x00,0x88,0xcc,0x00,0xcc,0x00,0x00,0xcc,0x44,0x00,0xcc,0x88,0x00,0xcc,0xcc,
+	0x00,0xdd,0xdd,0x11,0x11,0x11,0x00,0x00,0x55,0x00,0x00,0x99,0x00,0x00,0xdd,0x00,
+	0x55,0x00,0x00,0x55,0x55,0x00,0x4c,0x99,0x00,0x49,0xdd,0x00,0x99,0x00,0x00,0x99,
+	0x4c,0x00,0x99,0x99,0x00,0x93,0xdd,0x00,0xdd,0x00,0x00,0xdd,0x49,0x00,0xdd,0x93,
+	0x00,0xee,0x9e,0x00,0xee,0xee,0x22,0x22,0x22,0x00,0x00,0x66,0x00,0x00,0xaa,0x00,
+	0x00,0xee,0x00,0x66,0x00,0x00,0x66,0x66,0x00,0x55,0xaa,0x00,0x4f,0xee,0x00,0xaa,
+	0x00,0x00,0xaa,0x55,0x00,0xaa,0xaa,0x00,0x9e,0xee,0x00,0xee,0x00,0x00,0xee,0x4f,
+	0x00,0xff,0x55,0x00,0xff,0xaa,0x00,0xff,0xff,0x33,0x33,0x33,0x00,0x00,0x77,0x00,
+	0x00,0xbb,0x00,0x00,0xff,0x00,0x77,0x00,0x00,0x77,0x77,0x00,0x5d,0xbb,0x00,0x55,
+	0xff,0x00,0xbb,0x00,0x00,0xbb,0x5d,0x00,0xbb,0xbb,0x00,0xaa,0xff,0x00,0xff,0x00,
+	0x44,0x00,0x44,0x44,0x00,0x88,0x44,0x00,0xcc,0x44,0x44,0x00,0x44,0x44,0x44,0x44,
+	0x44,0x88,0x44,0x44,0xcc,0x44,0x88,0x00,0x44,0x88,0x44,0x44,0x88,0x88,0x44,0x88,
+	0xcc,0x44,0xcc,0x00,0x44,0xcc,0x44,0x44,0xcc,0x88,0x44,0xcc,0xcc,0x44,0x00,0x00,
+	0x55,0x00,0x00,0x55,0x00,0x55,0x4c,0x00,0x99,0x49,0x00,0xdd,0x55,0x55,0x00,0x55,
+	0x55,0x55,0x4c,0x4c,0x99,0x49,0x49,0xdd,0x4c,0x99,0x00,0x4c,0x99,0x4c,0x4c,0x99,
+	0x99,0x49,0x93,0xdd,0x49,0xdd,0x00,0x49,0xdd,0x49,0x49,0xdd,0x93,0x49,0xdd,0xdd,
+	0x4f,0xee,0xee,0x66,0x00,0x00,0x66,0x00,0x66,0x55,0x00,0xaa,0x4f,0x00,0xee,0x66,
+	0x66,0x00,0x66,0x66,0x66,0x55,0x55,0xaa,0x4f,0x4f,0xee,0x55,0xaa,0x00,0x55,0xaa,
+	0x55,0x55,0xaa,0xaa,0x4f,0x9e,0xee,0x4f,0xee,0x00,0x4f,0xee,0x4f,0x4f,0xee,0x9e,
+	0x55,0xff,0xaa,0x55,0xff,0xff,0x77,0x00,0x00,0x77,0x00,0x77,0x5d,0x00,0xbb,0x55,
+	0x00,0xff,0x77,0x77,0x00,0x77,0x77,0x77,0x5d,0x5d,0xbb,0x55,0x55,0xff,0x5d,0xbb,
+	0x00,0x5d,0xbb,0x5d,0x5d,0xbb,0xbb,0x55,0xaa,0xff,0x55,0xff,0x00,0x55,0xff,0x55,
+	0x88,0x00,0x88,0x88,0x00,0xcc,0x88,0x44,0x00,0x88,0x44,0x44,0x88,0x44,0x88,0x88,
+	0x44,0xcc,0x88,0x88,0x00,0x88,0x88,0x44,0x88,0x88,0x88,0x88,0x88,0xcc,0x88,0xcc,
+	0x00,0x88,0xcc,0x44,0x88,0xcc,0x88,0x88,0xcc,0xcc,0x88,0x00,0x00,0x88,0x00,0x44,
+	0x99,0x00,0x4c,0x99,0x00,0x99,0x93,0x00,0xdd,0x99,0x4c,0x00,0x99,0x4c,0x4c,0x99,
+	0x4c,0x99,0x93,0x49,0xdd,0x99,0x99,0x00,0x99,0x99,0x4c,0x99,0x99,0x99,0x93,0x93,
+	0xdd,0x93,0xdd,0x00,0x93,0xdd,0x49,0x93,0xdd,0x93,0x93,0xdd,0xdd,0x99,0x00,0x00,
+	0xaa,0x00,0x00,0xaa,0x00,0x55,0xaa,0x00,0xaa,0x9e,0x00,0xee,0xaa,0x55,0x00,0xaa,
+	0x55,0x55,0xaa,0x55,0xaa,0x9e,0x4f,0xee,0xaa,0xaa,0x00,0xaa,0xaa,0x55,0xaa,0xaa,
+	0xaa,0x9e,0x9e,0xee,0x9e,0xee,0x00,0x9e,0xee,0x4f,0x9e,0xee,0x9e,0x9e,0xee,0xee,
+	0xaa,0xff,0xff,0xbb,0x00,0x00,0xbb,0x00,0x5d,0xbb,0x00,0xbb,0xaa,0x00,0xff,0xbb,
+	0x5d,0x00,0xbb,0x5d,0x5d,0xbb,0x5d,0xbb,0xaa,0x55,0xff,0xbb,0xbb,0x00,0xbb,0xbb,
+	0x5d,0xbb,0xbb,0xbb,0xaa,0xaa,0xff,0xaa,0xff,0x00,0xaa,0xff,0x55,0xaa,0xff,0xaa,
+	0xcc,0x00,0xcc,0xcc,0x44,0x00,0xcc,0x44,0x44,0xcc,0x44,0x88,0xcc,0x44,0xcc,0xcc,
+	0x88,0x00,0xcc,0x88,0x44,0xcc,0x88,0x88,0xcc,0x88,0xcc,0xcc,0xcc,0x00,0xcc,0xcc,
+	0x44,0xcc,0xcc,0x88,0xcc,0xcc,0xcc,0xcc,0x00,0x00,0xcc,0x00,0x44,0xcc,0x00,0x88,
+	0xdd,0x00,0x93,0xdd,0x00,0xdd,0xdd,0x49,0x00,0xdd,0x49,0x49,0xdd,0x49,0x93,0xdd,
+	0x49,0xdd,0xdd,0x93,0x00,0xdd,0x93,0x49,0xdd,0x93,0x93,0xdd,0x93,0xdd,0xdd,0xdd,
+	0x00,0xdd,0xdd,0x49,0xdd,0xdd,0x93,0xdd,0xdd,0xdd,0xdd,0x00,0x00,0xdd,0x00,0x49,
+	0xee,0x00,0x4f,0xee,0x00,0x9e,0xee,0x00,0xee,0xee,0x4f,0x00,0xee,0x4f,0x4f,0xee,
+	0x4f,0x9e,0xee,0x4f,0xee,0xee,0x9e,0x00,0xee,0x9e,0x4f,0xee,0x9e,0x9e,0xee,0x9e,
+	0xee,0xee,0xee,0x00,0xee,0xee,0x4f,0xee,0xee,0x9e,0xee,0xee,0xee,0xee,0x00,0x00,
+	0xff,0x00,0x00,0xff,0x00,0x55,0xff,0x00,0xaa,0xff,0x00,0xff,0xff,0x55,0x00,0xff,
+	0x55,0x55,0xff,0x55,0xaa,0xff,0x55,0xff,0xff,0xaa,0x00,0xff,0xaa,0x55,0xff,0xaa,
+	0xaa,0xff,0xaa,0xff,0xff,0xff,0x00,0xff,0xff,0x55,0xff,0xff,0xaa,0xff,0xff,0xff,
+},
+/* rgb2cmap */ {
+	0x00,0x00,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x04,0x04,0x04,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
+	0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
+	0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
+	0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
+	0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
+	0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
+	0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
+	0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
+	0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
+	0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
+	0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
+	0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
+	0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
+	0x00,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x04,0x04,0x22,0x05,0x05,0x05,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
+	0x04,0x04,0x04,0x05,0x05,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
+	0x15,0x15,0x15,0x05,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
+	0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
+	0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
+	0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
+	0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
+	0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
+	0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
+	0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
+	0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
+	0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
+	0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
+	0x11,0x11,0x11,0x01,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x11,0x11,0x22,0x22,0x01,0x12,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x11,0x22,0x22,0x22,0x33,0x33,0x23,0x34,0x02,0x13,0x24,0x35,0x03,0x14,0x25,0x36,
+	0x04,0x22,0x22,0x33,0x33,0x33,0x05,0x06,0x06,0x06,0x17,0x07,0x07,0x18,0x18,0x29,
+	0x04,0x04,0x33,0x33,0x33,0x05,0x16,0x06,0x06,0x17,0x28,0x07,0x07,0x18,0x29,0x3a,
+	0x15,0x15,0x33,0x33,0x05,0x16,0x16,0x06,0x06,0x17,0x28,0x39,0x07,0x18,0x29,0x3a,
+	0x26,0x26,0x26,0x05,0x16,0x16,0x27,0x27,0x38,0x28,0x28,0x39,0x39,0x29,0x29,0x3a,
+	0x37,0x37,0x37,0x09,0x09,0x09,0x27,0x38,0x0a,0x0a,0x39,0x0b,0x0b,0x0b,0x1c,0x3a,
+	0x08,0x08,0x08,0x09,0x09,0x09,0x38,0x0a,0x0a,0x0a,0x1b,0x0b,0x0b,0x1c,0x1c,0x2d,
+	0x19,0x19,0x19,0x09,0x1a,0x1a,0x2b,0x0a,0x0a,0x1b,0x1b,0x0b,0x0b,0x1c,0x2d,0x3e,
+	0x2a,0x2a,0x2a,0x1a,0x2b,0x2b,0x2b,0x3c,0x1b,0x1b,0x2c,0x2c,0x3d,0x2d,0x2d,0x3e,
+	0x3b,0x3b,0x3b,0x0d,0x0d,0x3c,0x3c,0x0e,0x0e,0x0e,0x2c,0x3d,0x0f,0x0f,0x3e,0x3e,
+	0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x3c,0x0e,0x0e,0x0e,0x3d,0x0f,0x0f,0x0f,0x10,0x3e,
+	0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x2f,0x0e,0x1f,0x1f,0x20,0x0f,0x0f,0x10,0x10,0x21,
+	0x2e,0x2e,0x2e,0x1e,0x2f,0x2f,0x2f,0x1f,0x1f,0x20,0x20,0x31,0x10,0x10,0x21,0x21,
+	0x3f,0x3f,0x3f,0x2f,0x30,0x30,0x30,0x30,0x20,0x31,0x31,0x31,0x31,0x21,0x21,0x32,
+	0x4f,0x4f,0x22,0x40,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
+	0x4f,0x22,0x22,0x22,0x40,0x40,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
+	0x22,0x22,0x22,0x33,0x33,0x33,0x40,0x41,0x41,0x41,0x52,0x42,0x42,0x53,0x53,0x64,
+	0x43,0x22,0x33,0x33,0x33,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x46,0x57,0x68,
+	0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68,
+	0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
+	0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+	0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79,
+	0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x4a,0x5b,0x6c,
+	0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c,
+	0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
+	0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x6c,0x7d,
+	0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x5f,
+	0x5c,0x5c,0x5c,0x4c,0x5d,0x5d,0x5d,0x4d,0x4d,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60,
+	0x5c,0x5c,0x5c,0x5d,0x5d,0x6e,0x6e,0x5e,0x5e,0x5e,0x6f,0x6f,0x5f,0x5f,0x60,0x60,
+	0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71,
+	0x4f,0x4f,0x40,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
+	0x4f,0x4f,0x22,0x40,0x40,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
+	0x43,0x22,0x33,0x33,0x33,0x40,0x51,0x41,0x41,0x52,0x63,0x42,0x42,0x53,0x64,0x75,
+	0x43,0x43,0x33,0x33,0x44,0x44,0x44,0x45,0x45,0x45,0x56,0x46,0x46,0x57,0x57,0x68,
+	0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
+	0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+	0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
+	0x47,0x47,0x47,0x48,0x48,0x48,0x48,0x49,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x5b,0x79,
+	0x47,0x47,0x47,0x48,0x48,0x48,0x59,0x49,0x49,0x49,0x5a,0x4a,0x4a,0x5b,0x5b,0x6c,
+	0x58,0x58,0x58,0x48,0x59,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
+	0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
+	0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x6b,0x4e,0x4e,0x4e,0x7d,0x7d,
+	0x4b,0x4b,0x4b,0x4c,0x4c,0x4c,0x7b,0x4d,0x4d,0x4d,0x5e,0x4e,0x4e,0x4e,0x5f,0x7d,
+	0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5d,0x4d,0x5e,0x5e,0x5e,0x4e,0x4e,0x5f,0x5f,0x60,
+	0x6d,0x6d,0x6d,0x5d,0x6e,0x6e,0x6e,0x5e,0x5e,0x6f,0x6f,0x70,0x5f,0x5f,0x60,0x60,
+	0x7e,0x7e,0x7e,0x6e,0x6e,0x7f,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x70,0x60,0x60,0x71,
+	0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
+	0x50,0x50,0x50,0x40,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
+	0x50,0x50,0x33,0x33,0x40,0x51,0x51,0x41,0x41,0x52,0x63,0x74,0x42,0x53,0x64,0x75,
+	0x43,0x43,0x33,0x44,0x44,0x44,0x55,0x45,0x45,0x56,0x56,0x46,0x46,0x57,0x68,0x68,
+	0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+	0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
+	0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79,
+	0x47,0x47,0x47,0x48,0x48,0x48,0x66,0x49,0x49,0x49,0x78,0x78,0x4a,0x4a,0x5b,0x79,
+	0x47,0x47,0x47,0x48,0x48,0x59,0x59,0x49,0x49,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
+	0x58,0x58,0x58,0x59,0x59,0x59,0x6a,0x49,0x5a,0x5a,0x6b,0x6b,0x5b,0x5b,0x6c,0x7d,
+	0x69,0x69,0x69,0x59,0x6a,0x6a,0x6a,0x7b,0x5a,0x6b,0x6b,0x6b,0x7c,0x6c,0x6c,0x7d,
+	0x7a,0x7a,0x7a,0x4c,0x4c,0x7b,0x7b,0x7b,0x4d,0x6b,0x6b,0x7c,0x7c,0x4e,0x7d,0x7d,
+	0x4b,0x4b,0x4b,0x4c,0x4c,0x7b,0x7b,0x4d,0x4d,0x5e,0x7c,0x7c,0x4e,0x5f,0x5f,0x7d,
+	0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x6e,0x4d,0x5e,0x5e,0x6f,0x4e,0x5f,0x5f,0x60,0x60,
+	0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x6e,0x5e,0x6f,0x6f,0x6f,0x70,0x5f,0x60,0x60,0x71,
+	0x7e,0x7e,0x7e,0x6e,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71,
+	0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
+	0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
+	0x61,0x61,0x61,0x40,0x51,0x51,0x62,0x62,0x73,0x63,0x63,0x74,0x74,0x64,0x64,0x75,
+	0x43,0x43,0x43,0x44,0x44,0x55,0x55,0x45,0x45,0x56,0x67,0x46,0x46,0x57,0x68,0x79,
+	0x54,0x54,0x54,0x44,0x55,0x55,0x55,0x45,0x56,0x56,0x67,0x78,0x78,0x57,0x68,0x79,
+	0x54,0x54,0x54,0x55,0x55,0x55,0x66,0x66,0x56,0x67,0x67,0x78,0x78,0x68,0x68,0x79,
+	0x65,0x65,0x65,0x55,0x55,0x66,0x66,0x66,0x77,0x67,0x78,0x78,0x78,0x78,0x79,0x79,
+	0x65,0x65,0x65,0x48,0x48,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x5b,0x79,0x79,
+	0x76,0x76,0x76,0x48,0x59,0x59,0x77,0x77,0x77,0x5a,0x5a,0x4a,0x4a,0x5b,0x6c,0x6c,
+	0x69,0x69,0x69,0x59,0x59,0x6a,0x6a,0x77,0x5a,0x5a,0x6b,0x6b,0x5b,0x6c,0x6c,0x7d,
+	0x69,0x69,0x69,0x6a,0x6a,0x6a,0x7b,0x7b,0x5a,0x6b,0x6b,0x7c,0x7c,0x6c,0x7d,0x7d,
+	0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x6b,0x7c,0x7c,0x7c,0x7c,0x7d,0x7d,
+	0x7a,0x7a,0x7a,0x4c,0x7b,0x7b,0x7b,0x7b,0x4d,0x5e,0x7c,0x7c,0x7c,0x5f,0x5f,0x7d,
+	0x6d,0x6d,0x6d,0x5d,0x5d,0x6e,0x7b,0x5e,0x5e,0x6f,0x6f,0x7c,0x5f,0x5f,0x60,0x60,
+	0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x7f,0x7f,0x6f,0x6f,0x70,0x70,0x5f,0x60,0x60,0x71,
+	0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x6f,0x70,0x70,0x70,0x70,0x60,0x71,0x71,
+	0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
+	0x72,0x72,0x72,0x8f,0x8f,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
+	0x72,0x72,0x72,0x83,0x83,0x62,0x62,0x73,0x73,0x80,0x74,0x81,0x81,0x81,0x92,0x75,
+	0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x84,0x85,0x85,0x85,0x96,0x79,
+	0x82,0x82,0x82,0x83,0x83,0x83,0x66,0x84,0x84,0x84,0x67,0x85,0x85,0x85,0x96,0x79,
+	0x65,0x65,0x65,0x83,0x83,0x66,0x66,0x66,0x84,0x84,0x78,0x78,0x85,0x85,0x96,0x79,
+	0x65,0x65,0x65,0x83,0x66,0x66,0x66,0x77,0x77,0x77,0x78,0x78,0x78,0x96,0x79,0x79,
+	0x76,0x76,0x76,0x87,0x87,0x66,0x77,0x77,0x77,0x88,0x78,0x89,0x89,0x89,0x89,0x79,
+	0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a,
+	0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x6b,0x89,0x89,0x9a,0x9a,0x7d,
+	0x7a,0x7a,0x7a,0x87,0x6a,0x7b,0x7b,0x7b,0x88,0x6b,0x6b,0x7c,0x7c,0x9a,0x7d,0x7d,
+	0x8a,0x8a,0x8a,0x8b,0x8b,0x7b,0x7b,0x8c,0x8c,0x8c,0x7c,0x7c,0x8d,0x8d,0x7d,0x7d,
+	0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x7b,0x8c,0x8c,0x8c,0x7c,0x8d,0x8d,0x8d,0x9e,0x9e,
+	0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0x9e,
+	0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0x7f,0x8c,0x9d,0x9d,0x70,0x70,0x9e,0x9e,0x9e,0x71,
+	0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x9d,0x70,0x70,0x70,0x9e,0x9e,0x71,0x71,
+	0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
+	0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
+	0x82,0x82,0x82,0x83,0x83,0x83,0x73,0x73,0x80,0x80,0x91,0x81,0x81,0x92,0x92,0xa3,
+	0x82,0x82,0x82,0x83,0x83,0x83,0x83,0x84,0x84,0x84,0x95,0x85,0x85,0x85,0x96,0xa7,
+	0x82,0x82,0x82,0x83,0x83,0x83,0x94,0x84,0x84,0x84,0x95,0x85,0x85,0x96,0x96,0xa7,
+	0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
+	0x76,0x76,0x76,0x83,0x94,0x94,0x77,0x77,0x77,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
+	0x76,0x76,0x76,0x87,0x87,0x87,0x77,0x77,0x88,0x88,0x88,0x89,0x89,0x89,0x9a,0x9a,
+	0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xab,
+	0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab,
+	0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
+	0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0xab,0xbc,
+	0x8a,0x8a,0x8a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8c,0x8c,0x9d,0x8d,0x8d,0x8d,0x9e,0x9e,
+	0x9b,0x9b,0x9b,0x8b,0x9c,0x9c,0x9c,0x8c,0x9d,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xaf,
+	0x9b,0x9b,0x9b,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0x9d,0xae,0xae,0x9e,0x9e,0xaf,0xaf,
+	0xac,0xac,0xac,0xad,0xad,0xad,0xad,0x9d,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xaf,
+	0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
+	0x9f,0x9f,0x9f,0x8f,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
+	0x9f,0x9f,0x9f,0x83,0x90,0x90,0xa1,0x80,0x80,0x91,0x91,0x81,0x81,0x92,0xa3,0xb4,
+	0x82,0x82,0x82,0x83,0x83,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0x96,0xa7,
+	0x93,0x93,0x93,0x83,0x94,0x94,0x94,0x84,0x84,0x95,0x95,0x85,0x85,0x96,0xa7,0xa7,
+	0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
+	0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x77,0x95,0x95,0xa6,0xa6,0x96,0xa7,0xa7,0xb8,
+	0x86,0x86,0x86,0x87,0x87,0x87,0x77,0x88,0x88,0x88,0x99,0x89,0x89,0x9a,0x9a,0xb8,
+	0x86,0x86,0x86,0x87,0x87,0x98,0x98,0x88,0x88,0x99,0x99,0x89,0x89,0x9a,0x9a,0xab,
+	0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
+	0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc,
+	0x8a,0x8a,0x8a,0x8b,0x8b,0xa9,0xa9,0x8c,0x8c,0x8c,0xaa,0x8d,0x8d,0x8d,0xab,0xbc,
+	0x8a,0x8a,0x8a,0x8b,0x8b,0x9c,0x9c,0x8c,0x8c,0x9d,0x9d,0x8d,0x8d,0x9e,0x9e,0xbc,
+	0x9b,0x9b,0x9b,0x9c,0x9c,0x9c,0xad,0x9d,0x9d,0x9d,0xae,0x8d,0x9e,0x9e,0xaf,0xaf,
+	0xac,0xac,0xac,0x9c,0xad,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0xaf,0xaf,0xaf,
+	0xbd,0xbd,0xbd,0xad,0xad,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xbf,0xaf,0xaf,0xb0,
+	0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
+	0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
+	0xa0,0xa0,0xa0,0x90,0xa1,0xa1,0xa1,0xb2,0x91,0x91,0xa2,0xa2,0xb3,0xa3,0xa3,0xb4,
+	0x93,0x93,0x93,0x94,0x94,0x94,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
+	0xa4,0xa4,0xa4,0x94,0x94,0xa5,0xa5,0x84,0x95,0x95,0xa6,0xa6,0x96,0x96,0xa7,0xb8,
+	0xa4,0xa4,0xa4,0x94,0xa5,0xa5,0xa5,0xb6,0x95,0xa6,0xa6,0xa6,0xb7,0xa7,0xa7,0xb8,
+	0xa4,0xa4,0xa4,0xa5,0xa5,0xa5,0xb6,0xb6,0x95,0xa6,0xa6,0xb7,0xb7,0xa7,0xb8,0xb8,
+	0xb5,0xb5,0xb5,0x87,0x87,0xb6,0xb6,0xb6,0x88,0x99,0xa6,0xb7,0xb7,0x9a,0xb8,0xb8,
+	0x97,0x97,0x97,0x98,0x98,0x98,0x98,0x88,0x99,0x99,0x99,0x89,0x9a,0x9a,0xab,0xab,
+	0x97,0x97,0x97,0x98,0x98,0xa9,0xa9,0x99,0x99,0x99,0xaa,0xaa,0x9a,0xab,0xab,0xbc,
+	0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xa9,0xa9,0x99,0xaa,0xaa,0xaa,0xbb,0xab,0xab,0xbc,
+	0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0x8c,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc,
+	0xb9,0xb9,0xb9,0x9c,0x9c,0xba,0xba,0xba,0x9d,0x9d,0xbb,0xbb,0xbb,0x9e,0x9e,0xbc,
+	0xac,0xac,0xac,0x9c,0x9c,0xad,0xad,0x9d,0x9d,0xae,0xae,0xae,0x9e,0x9e,0xaf,0xaf,
+	0xac,0xac,0xac,0xad,0xad,0xad,0xbe,0xbe,0xae,0xae,0xae,0xbf,0x9e,0xaf,0xaf,0xb0,
+	0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xae,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0,
+	0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
+	0xb1,0xb1,0xb1,0xce,0xce,0xb2,0xb2,0xcf,0xcf,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
+	0xb1,0xb1,0xb1,0xc2,0xc2,0xb2,0xb2,0xc3,0xc3,0xa2,0xa2,0xb3,0xb3,0xc0,0xb4,0xb4,
+	0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xa5,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xa7,0xb8,
+	0xc1,0xc1,0xc1,0xc2,0xc2,0xa5,0xb6,0xc3,0xc3,0xc3,0xa6,0xc4,0xc4,0xc4,0xb8,0xb8,
+	0xb5,0xb5,0xb5,0xc2,0xa5,0xb6,0xb6,0xb6,0xc3,0xa6,0xa6,0xb7,0xb7,0xc4,0xb8,0xb8,
+	0xb5,0xb5,0xb5,0xa5,0xb6,0xb6,0xb6,0xb6,0xc3,0xa6,0xb7,0xb7,0xb7,0xb7,0xb8,0xb8,
+	0xc5,0xc5,0xc5,0xc6,0xc6,0xb6,0xb6,0xc7,0xc7,0xc7,0xb7,0xb7,0xc8,0xc8,0xb8,0xb8,
+	0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xaa,0xc8,0xc8,0xc8,0xab,0xbc,
+	0xa8,0xa8,0xa8,0xc6,0xc6,0xa9,0xa9,0xc7,0xc7,0xaa,0xaa,0xaa,0xc8,0xc8,0xab,0xbc,
+	0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xba,0xba,0xaa,0xaa,0xaa,0xbb,0xbb,0xab,0xbc,0xbc,
+	0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xba,0xcb,0xaa,0xbb,0xbb,0xbb,0xcc,0xbc,0xbc,
+	0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc,
+	0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xae,0xcc,0xcc,0xcc,0xaf,0xaf,
+	0xbd,0xbd,0xbd,0xad,0xbe,0xbe,0xbe,0xbe,0xae,0xae,0xbf,0xbf,0xcc,0xaf,0xaf,0xb0,
+	0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbe,0xbe,0xbf,0xbf,0xbf,0xbf,0xbf,0xaf,0xb0,0xb0,
+	0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
+	0xcd,0xcd,0xcd,0xce,0xce,0xce,0xb2,0xcf,0xcf,0xcf,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
+	0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb2,0xc3,0xc3,0xc3,0xb3,0xb3,0xc0,0xc0,0xd1,0xb4,
+	0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xd5,
+	0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xb6,0xc3,0xc3,0xc3,0xd4,0xc4,0xc4,0xc4,0xd5,0xb8,
+	0xc1,0xc1,0xc1,0xc2,0xc2,0xb6,0xb6,0xc3,0xc3,0xd4,0xb7,0xb7,0xc4,0xd5,0xd5,0xb8,
+	0xb5,0xb5,0xb5,0xc2,0xb6,0xb6,0xb6,0xb6,0xc3,0xd4,0xb7,0xb7,0xb7,0xd5,0xd5,0xb8,
+	0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xb6,0xc7,0xc7,0xc7,0xb7,0xc8,0xc8,0xc8,0xd9,0xd9,
+	0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xc6,0xc7,0xc7,0xc7,0xd8,0xc8,0xc8,0xc8,0xd9,0xd9,
+	0xc5,0xc5,0xc5,0xc6,0xc6,0xd7,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xbc,
+	0xb9,0xb9,0xb9,0xd7,0xd7,0xba,0xba,0xba,0xd8,0xd8,0xbb,0xbb,0xbb,0xd9,0xd9,0xbc,
+	0xb9,0xb9,0xb9,0xca,0xca,0xba,0xba,0xcb,0xcb,0xcb,0xbb,0xbb,0xcc,0xcc,0xcc,0xbc,
+	0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xbb,0xcc,0xcc,0xcc,0xdd,0xdd,
+	0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd,
+	0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xb0,
+	0xbd,0xbd,0xbd,0xdb,0xbe,0xbe,0xbe,0xdc,0xdc,0xbf,0xbf,0xbf,0xdd,0xdd,0xb0,0xb0,
+	0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
+	0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xcf,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
+	0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xc3,0xd0,0xd0,0xe1,0xc0,0xc0,0xd1,0xd1,0xe2,
+	0xd2,0xd2,0xd2,0xc2,0xd3,0xd3,0xd3,0xc3,0xc3,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6,
+	0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xd3,0xc3,0xd4,0xd4,0xd4,0xc4,0xc4,0xd5,0xd5,0xe6,
+	0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xe4,0xc3,0xd4,0xd4,0xe5,0xc4,0xd5,0xd5,0xe6,0xe6,
+	0xe3,0xe3,0xe3,0xd3,0xd3,0xe4,0xb6,0xd4,0xd4,0xe5,0xe5,0xb7,0xd5,0xd5,0xe6,0xe6,
+	0xc5,0xc5,0xc5,0xc6,0xc6,0xc6,0xd7,0xc7,0xc7,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xd9,
+	0xd6,0xd6,0xd6,0xc6,0xd7,0xd7,0xd7,0xc7,0xd8,0xd8,0xd8,0xc8,0xc8,0xd9,0xd9,0xea,
+	0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xe8,0xd8,0xd8,0xd8,0xe9,0xc8,0xd9,0xd9,0xea,0xea,
+	0xe7,0xe7,0xe7,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xd9,0xea,0xea,
+	0xc9,0xc9,0xc9,0xca,0xca,0xca,0xba,0xcb,0xcb,0xcb,0xe9,0xcc,0xcc,0xcc,0xea,0xea,
+	0xc9,0xc9,0xc9,0xca,0xca,0xdb,0xdb,0xcb,0xcb,0xdc,0xdc,0xcc,0xcc,0xdd,0xdd,0xdd,
+	0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee,
+	0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee,
+	0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
+	0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
+	0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
+	0xef,0xef,0xef,0xdf,0xe0,0xe0,0xe0,0xd0,0xd0,0xe1,0xe1,0xf2,0xd1,0xd1,0xe2,0xe2,
+	0xd2,0xd2,0xd2,0xd3,0xd3,0xe4,0xe4,0xd4,0xd4,0xd4,0xe5,0xe5,0xd5,0xd5,0xe6,0xe6,
+	0xe3,0xe3,0xe3,0xd3,0xe4,0xe4,0xe4,0xd4,0xd4,0xe5,0xe5,0xf6,0xd5,0xd5,0xe6,0xe6,
+	0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xe4,0xd4,0xe5,0xe5,0xe5,0xf6,0xd5,0xe6,0xe6,0xf7,
+	0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7,
+	0xd6,0xd6,0xd6,0xd7,0xd7,0xd7,0xf5,0xc7,0xd8,0xd8,0xf6,0xc8,0xd9,0xd9,0xd9,0xf7,
+	0xd6,0xd6,0xd6,0xd7,0xd7,0xe8,0xe8,0xd8,0xd8,0xd8,0xe9,0xe9,0xd9,0xd9,0xea,0xea,
+	0xe7,0xe7,0xe7,0xd7,0xe8,0xe8,0xe8,0xd8,0xd8,0xe9,0xe9,0xe9,0xd9,0xea,0xea,0xea,
+	0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xf9,0xf9,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xfb,
+	0xf8,0xf8,0xf8,0xe8,0xf9,0xf9,0xf9,0xcb,0xe9,0xe9,0xfa,0xfa,0xcc,0xea,0xea,0xfb,
+	0xda,0xda,0xda,0xdb,0xdb,0xdb,0xdb,0xdc,0xdc,0xdc,0xdc,0xcc,0xdd,0xdd,0xdd,0xee,
+	0xda,0xda,0xda,0xdb,0xdb,0xec,0xec,0xdc,0xdc,0xed,0xed,0xed,0xdd,0xdd,0xee,0xee,
+	0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
+	0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff,
+	0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
+	0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
+	0xf0,0xf0,0xf0,0xe0,0xf1,0xf1,0xf1,0xf1,0xe1,0xf2,0xf2,0xf2,0xf2,0xe2,0xe2,0xf3,
+	0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xd5,0xe6,0xe6,0xf7,
+	0xf4,0xf4,0xf4,0xe4,0xe4,0xf5,0xf5,0xf5,0xe5,0xe5,0xf6,0xf6,0xf6,0xe6,0xe6,0xf7,
+	0xf4,0xf4,0xf4,0xe4,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7,
+	0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xe5,0xf6,0xf6,0xf6,0xf6,0xe6,0xf7,0xf7,
+	0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf5,0xf5,0xd8,0xf6,0xf6,0xf6,0xd9,0xd9,0xf7,0xf7,
+	0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xe8,0xd8,0xe9,0xe9,0xe9,0xfa,0xd9,0xea,0xea,0xea,
+	0xf8,0xf8,0xf8,0xe8,0xe8,0xf9,0xf9,0xf9,0xe9,0xe9,0xfa,0xfa,0xfa,0xea,0xea,0xfb,
+	0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xe9,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb,
+	0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfa,0xfa,0xea,0xfb,0xfb,
+	0xf8,0xf8,0xf8,0xdb,0xf9,0xf9,0xf9,0xdc,0xdc,0xfa,0xfa,0xfa,0xdd,0xdd,0xee,0xfb,
+	0xeb,0xeb,0xeb,0xec,0xec,0xec,0xec,0xdc,0xed,0xed,0xed,0xed,0xdd,0xee,0xee,0xee,
+	0xeb,0xeb,0xeb,0xec,0xec,0xfd,0xfd,0xfd,0xed,0xed,0xfe,0xfe,0xee,0xee,0xee,0xff,
+	0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfd,0xfd,0xed,0xfe,0xfe,0xfe,0xfe,0xee,0xff,0xff,
+}
+};
+Memcmap *memdefcmap = &def;
+void _memmkcmap(void){}
--- /dev/null
+++ b/libmemdraw/cread.c
@@ -1,0 +1,95 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memimage*
+creadmemimage(int fd)
+{
+	char hdr[5*12+1];
+	Rectangle r;
+	int m, nb, miny, maxy, new, ldepth, ncblock;
+	uchar *buf;
+	Memimage *i;
+	ulong chan;
+
+	if(readn(fd, hdr, 5*12) != 5*12){
+		werrstr("readmemimage: short header (2)");
+		return nil;
+	}
+
+	/*
+	 * distinguish new channel descriptor from old ldepth.
+	 * channel descriptors have letters as well as numbers,
+	 * while ldepths are a single digit formatted as %-11d.
+	 */
+	new = 0;
+	for(m=0; m<10; m++){
+		if(hdr[m] != ' '){
+			new = 1;
+			break;
+		}
+	}
+	if(hdr[11] != ' '){
+		werrstr("creadimage: bad format");
+		return nil;
+	}
+	if(new){
+		hdr[11] = '\0';
+		if((chan = strtochan(hdr)) == 0){
+			werrstr("creadimage: bad channel string %s", hdr);
+			return nil;
+		}
+	}else{
+		ldepth = ((int)hdr[10])-'0';
+		if(ldepth<0 || ldepth>3){
+			werrstr("creadimage: bad ldepth %d", ldepth);
+			return nil;
+		}
+		chan = drawld2chan[ldepth];
+	}
+	r.min.x=atoi(hdr+1*12);
+	r.min.y=atoi(hdr+2*12);
+	r.max.x=atoi(hdr+3*12);
+	r.max.y=atoi(hdr+4*12);
+	if(r.min.x>r.max.x || r.min.y>r.max.y){
+		werrstr("creadimage: bad rectangle");
+		return nil;
+	}
+
+	i = allocmemimage(r, chan);
+	if(i == nil)
+		return nil;
+	ncblock = _compblocksize(r, i->depth);
+	buf = malloc(ncblock);
+	if(buf == nil)
+		goto Errout;
+	miny = r.min.y;
+	while(miny != r.max.y){
+		if(readn(fd, hdr, 2*12) != 2*12){
+		Shortread:
+			werrstr("readmemimage: short read");
+		Errout:
+			freememimage(i);
+			free(buf);
+			return nil;
+		}
+		maxy = atoi(hdr+0*12);
+		nb = atoi(hdr+1*12);
+		if(maxy<=miny || r.max.y<maxy){
+			werrstr("readimage: bad maxy %d", maxy);
+			goto Errout;
+		}
+		if(nb<=0 || ncblock<nb){
+			werrstr("readimage: bad count %d", nb);
+			goto Errout;
+		}
+		if(readn(fd, buf, nb)!=nb)
+			goto Shortread;
+		if(!new)	/* old image: flip the data bits */
+			_twiddlecompressed(buf, nb);
+		cloadmemimage(i, Rect(r.min.x, miny, r.max.x, maxy), buf, nb);
+		miny = maxy;
+	}
+	free(buf);
+	return i;
+}
--- /dev/null
+++ b/libmemdraw/defont.c
@@ -1,0 +1,67 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memsubfont*
+getmemdefont(void)
+{
+	char *hdr, *p;
+	int n;
+	Fontchar *fc;
+	Memsubfont *f;
+	int ld;
+	Rectangle r;
+	Memdata *md;
+	Memimage *i;
+
+	/*
+	 * make sure data is word-aligned.  this is true with Plan 9 compilers
+	 * but not in general.  the byte order is right because the data is
+	 * declared as char*, not ulong*.
+	 */
+	p = (char*)defontdata;
+	n = (ulong)p & 3;
+	if(n != 0){
+		memmove(p+(4-n), p, sizeofdefont-n);
+		p += 4-n;
+	}
+	ld = atoi(p+0*12);
+	r.min.x = atoi(p+1*12);
+	r.min.y = atoi(p+2*12);
+	r.max.x = atoi(p+3*12);
+	r.max.y = atoi(p+4*12);
+
+	md = mallocz(sizeof(Memdata), 1);
+	if(md == nil)
+		return nil;
+	
+	p += 5*12;
+
+	md->base = nil;		/* so freememimage doesn't free p */
+	md->bdata = (uchar*)p;	/* ick */
+	md->ref = 1;
+	md->allocd = 1;		/* so freememimage does free md */
+
+	i = allocmemimaged(r, drawld2chan[ld], md);
+	if(i == nil){
+		free(md);
+		return nil;
+	}
+
+	hdr = p+Dy(r)*i->width*sizeof(ulong);
+	n = atoi(hdr);
+	p = hdr+3*12;
+	fc = malloc(sizeof(Fontchar)*(n+1));
+	if(fc == 0){
+		freememimage(i);
+		return 0;
+	}
+	_unpackinfo(fc, (uchar*)p, n);
+	f = allocmemsubfont("*default*", n, atoi(hdr+12), atoi(hdr+24), fc, i);
+	if(f == 0){
+		freememimage(i);
+		free(fc);
+		return 0;
+	}
+	return f;
+}
--- /dev/null
+++ b/libmemdraw/draw.c
@@ -1,0 +1,2505 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "pool.h"
+
+extern Pool* imagmem;
+int drawdebug;
+static int	tablesbuilt;
+
+/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
+#define RGB2K(r,g,b)	((156763*(r)+307758*(g)+59769*(b))>>19)
+
+/*
+ * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation.
+ * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation.
+ * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole.
+ */
+/* #define DIV255(x) (((x)*257+256)>>16)  */
+#define DIV255(x) ((((x)+1)*257)>>16)
+/* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */
+
+#define MUL(x, y, t)	(t = (x)*(y)+128, (t+(t>>8))>>8)
+#define MASK13	0xFF00FF00
+#define MASK02	0x00FF00FF
+#define MUL13(a, x, t)		(t = (a)*(((x)&MASK13)>>8)+0x800080, ((t+((t>>8)&MASK02))>>8)&MASK02)
+#define MUL02(a, x, t)		(t = (a)*(((x)&MASK02)>>0)+0x800080, ((t+((t>>8)&MASK02))>>8)&MASK02)
+#define MUL0123(a, x, s, t)	((MUL13(a, x, s)<<8)|MUL02(a, x, t))
+
+#define MUL2(u, v, x, y)	(t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8)
+
+#define BWADD(x, y)	((((x)&MASK13)+((y)&MASK13))&MASK13|(((x)&MASK02)+((y)&MASK02))&MASK02)
+
+static void mktables(void);
+typedef int Subdraw(Memdrawparam*);
+static Subdraw chardraw, alphadraw, memoptdraw;
+
+static Memimage*	memones;
+static Memimage*	memzeros;
+Memimage *memwhite;
+Memimage *memblack;
+Memimage *memtransparent;
+Memimage *memopaque;
+
+int	_ifmt(Fmt*);
+
+void
+memimageinit(void)
+{
+	static int didinit = 0;
+	char *n;
+
+	if(didinit)
+		return;
+
+	didinit = 1;
+
+	n = poolname(imagmem);
+	if(strcmp(n, "Image") == 0 || strcmp(n, "image") == 0)
+		poolsetcompact(imagmem, memimagemove);
+	mktables();
+	_memmkcmap();
+
+	fmtinstall('R', Rfmt); 
+	fmtinstall('P', Pfmt);
+	fmtinstall('b', _ifmt);
+
+	memones = allocmemimage(Rect(0,0,1,1), GREY1);
+	memones->flags |= Frepl;
+	memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+	*byteaddr(memones, ZP) = ~0;
+
+	memzeros = allocmemimage(Rect(0,0,1,1), GREY1);
+	memzeros->flags |= Frepl;
+	memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+	*byteaddr(memzeros, ZP) = 0;
+
+	if(memones == nil || memzeros == nil)
+		assert(0 /*cannot initialize memimage library */);	/* RSC BUG */
+
+	memwhite = memones;
+	memblack = memzeros;
+	memopaque = memones;
+	memtransparent = memzeros;
+}
+
+static ulong imgtorgba(Memimage*, ulong);
+static ulong rgbatoimg(Memimage*, ulong);
+static ulong pixelbits(Memimage*, Point);
+
+#define DBG if(0)
+void
+memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
+{
+	Memdrawparam par;
+
+	if(mask == nil)
+		mask = memopaque;
+
+DBG	print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1);
+
+	if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){
+//		if(drawdebug)
+//			iprint("empty clipped rectangle\n");
+		return;
+	}
+
+	if(op < Clear || op > SoverD){
+//		if(drawdebug)
+//			iprint("op out of range: %d\n", op);
+		return;
+	}
+
+	par.op = op;
+	par.dst = dst;
+	par.r = r;
+	par.src = src;
+	/* par.sr set by drawclip */
+	par.mask = mask;
+	/* par.mr set by drawclip */
+
+	par.state = 0;
+	if(src->flags&Frepl){
+		par.state |= Replsrc;
+		if(Dx(src->r)==1 && Dy(src->r)==1){
+			par.sval = pixelbits(src, src->r.min);
+			par.state |= Simplesrc;
+			par.srgba = imgtorgba(src, par.sval);
+			par.sdval = rgbatoimg(dst, par.srgba);
+			if((par.srgba&0xFF) == 0 && (op&DoutS)){
+//				if (drawdebug) iprint("fill with transparent source\n");
+				return;	/* no-op successfully handled */
+			}
+		}
+	}
+
+	if(mask->flags & Frepl){
+		par.state |= Replmask;
+		if(Dx(mask->r)==1 && Dy(mask->r)==1){
+			par.mval = pixelbits(mask, mask->r.min);
+			if(par.mval == 0 && (op&DoutS)){
+//				if(drawdebug) iprint("fill with zero mask\n");
+				return;	/* no-op successfully handled */
+			}
+			par.state |= Simplemask;
+			if(par.mval == ~0)
+				par.state |= Fullmask;
+			par.mrgba = imgtorgba(mask, par.mval);
+		}
+	}
+
+//	if(drawdebug)
+//		iprint("dr %R sr %R mr %R...", r, par.sr, par.mr);
+DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state);
+
+	/*
+	 * Now that we've clipped the parameters down to be consistent, we 
+	 * simply try sub-drawing routines in order until we find one that was able
+	 * to handle us.  If the sub-drawing routine returns zero, it means it was
+	 * unable to satisfy the request, so we do not return.
+	 */
+
+	/*
+	 * Hardware support.  Each video driver provides this function,
+	 * which checks to see if there is anything it can help with.
+	 * There could be an if around this checking to see if dst is in video memory.
+	 */
+DBG print("test hwdraw\n");
+	if(hwdraw(&par)){
+//if(drawdebug) iprint("hw handled\n");
+DBG print("hwdraw handled\n");
+		return;
+	}
+	/*
+	 * Optimizations using memmove and memset.
+	 */
+DBG print("test memoptdraw\n");
+	if(memoptdraw(&par)){
+//if(drawdebug) iprint("memopt handled\n");
+DBG print("memopt handled\n");
+		return;
+	}
+
+	/*
+	 * Character drawing.
+	 * Solid source color being painted through a boolean mask onto a high res image.
+	 */
+DBG print("test chardraw\n");
+	if(chardraw(&par)){
+//if(drawdebug) iprint("chardraw handled\n");
+DBG print("chardraw handled\n");
+		return;
+	}
+
+	/*
+	 * General calculation-laden case that does alpha for each pixel.
+	 */
+DBG print("do alphadraw\n");
+	alphadraw(&par);
+//if(drawdebug) iprint("alphadraw handled\n");
+DBG print("alphadraw handled\n");
+}
+#undef DBG
+
+/*
+ * Clip the destination rectangle further based on the properties of the 
+ * source and mask rectangles.  Once the destination rectangle is properly
+ * clipped, adjust the source and mask rectangles to be the same size.
+ * Then if source or mask is replicated, move its clipped rectangle
+ * so that its minimum point falls within the repl rectangle.
+ *
+ * Return zero if the final rectangle is null.
+ */
+int
+drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr)
+{
+	Point rmin, delta;
+	int splitcoords;
+	Rectangle omr;
+
+	if(r->min.x>=r->max.x || r->min.y>=r->max.y)
+		return 0;
+	splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);
+	/* clip to destination */
+	rmin = r->min;
+	if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr))
+		return 0;
+	/* move mask point */
+	p1->x += r->min.x-rmin.x;
+	p1->y += r->min.y-rmin.y;
+	/* move source point */
+	p0->x += r->min.x-rmin.x;
+	p0->y += r->min.y-rmin.y;
+	/* map destination rectangle into source */
+	sr->min = *p0;
+	sr->max.x = p0->x+Dx(*r);
+	sr->max.y = p0->y+Dy(*r);
+	/* sr is r in source coordinates; clip to source */
+	if(!(src->flags&Frepl) && !rectclip(sr, src->r))
+		return 0;
+	if(!rectclip(sr, src->clipr))
+		return 0;
+	/* compute and clip rectangle in mask */
+	if(splitcoords){
+		/* move mask point with source */
+		p1->x += sr->min.x-p0->x;
+		p1->y += sr->min.y-p0->y;
+		mr->min = *p1;
+		mr->max.x = p1->x+Dx(*sr);
+		mr->max.y = p1->y+Dy(*sr);
+		omr = *mr;
+		/* mr is now rectangle in mask; clip it */
+		if(!(mask->flags&Frepl) && !rectclip(mr, mask->r))
+			return 0;
+		if(!rectclip(mr, mask->clipr))
+			return 0;
+		/* reflect any clips back to source */
+		sr->min.x += mr->min.x-omr.min.x;
+		sr->min.y += mr->min.y-omr.min.y;
+		sr->max.x += mr->max.x-omr.max.x;
+		sr->max.y += mr->max.y-omr.max.y;
+		*p1 = mr->min;
+	}else{
+		if(!(mask->flags&Frepl) && !rectclip(sr, mask->r))
+			return 0;
+		if(!rectclip(sr, mask->clipr))
+			return 0;
+		*p1 = sr->min;
+	}
+
+	/* move source clipping back to destination */
+	delta.x = r->min.x - p0->x;
+	delta.y = r->min.y - p0->y;
+	r->min.x = sr->min.x + delta.x;
+	r->min.y = sr->min.y + delta.y;
+	r->max.x = sr->max.x + delta.x;
+	r->max.y = sr->max.y + delta.y;
+
+	/* move source rectangle so sr->min is in src->r */
+	if(src->flags&Frepl) {
+		delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x;
+		delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y;
+		sr->min.x += delta.x;
+		sr->min.y += delta.y;
+		sr->max.x += delta.x;
+		sr->max.y += delta.y;
+	}
+	*p0 = sr->min;
+
+	/* move mask point so it is in mask->r */
+	*p1 = drawrepl(mask->r, *p1);
+	mr->min = *p1;
+	mr->max.x = p1->x+Dx(*sr);
+	mr->max.y = p1->y+Dy(*sr);
+
+	assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r));
+	assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r));
+	assert(ptinrect(*p0, src->r));
+	assert(ptinrect(*p1, mask->r));
+	assert(ptinrect(r->min, dst->r));
+
+	return 1;
+}
+
+/*
+ * Conversion tables.
+ */
+static uchar replbit[1+8][256];		/* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */
+
+/*
+ * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8.
+ * the X's are where to put the bottom (ones) bit of the n-bit pattern.
+ * only the top 8 bits of the result are actually used.
+ * (the lower 8 bits are needed to get bits in the right place
+ * when n is not a divisor of 8.)
+ *
+ * Should check to see if its easier to just refer to replmul than
+ * use the precomputed values in replbit.  On PCs it may well
+ * be; on machines with slow multiply instructions it probably isn't.
+ */
+#define a ((((((((((((((((0
+#define X *2+1)
+#define _ *2)
+static int replmul[1+8] = {
+	0,
+	a X X X X X X X X X X X X X X X X,
+	a _ X _ X _ X _ X _ X _ X _ X _ X,
+	a _ _ X _ _ X _ _ X _ _ X _ _ X _,
+	a _ _ _ X _ _ _ X _ _ _ X _ _ _ X,
+	a _ _ _ _ X _ _ _ _ X _ _ _ _ X _,
+	a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, 
+	a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _,
+	a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,
+};
+#undef a
+#undef X
+#undef _
+
+static void
+mktables(void)
+{
+	int i, j, small;
+		
+	if(tablesbuilt)
+		return;
+
+	fmtinstall('R', Rfmt);
+	fmtinstall('P', Pfmt);
+	tablesbuilt = 1;
+
+	/* bit replication up to 8 bits */
+	for(i=0; i<256; i++){
+		for(j=0; j<=8; j++){	/* j <= 8 [sic] */
+			small = i & ((1<<j)-1);
+			replbit[j][i] = (small*replmul[j])>>8;
+		}
+	}
+}
+
+static uchar ones = 0xff;
+
+/*
+ * General alpha drawing case.  Can handle anything.
+ */
+typedef struct	Buffer	Buffer;
+struct Buffer {
+	/* used by most routines */
+	uchar	*red;
+	uchar	*grn;
+	uchar	*blu;
+	uchar	*alpha;
+	uchar	*grey;
+	ulong	*rgba;
+	int	delta;	/* number of bytes to add to pointer to get next pixel to the right */
+
+	/* used by boolcalc* for mask data */
+	uchar	*m;		/* ptr to mask data r.min byte; like p->bytermin */
+	int		mskip;	/* no. of left bits to skip in *m */
+	uchar	*bm;		/* ptr to mask data img->r.min byte; like p->bytey0s */
+	int		bmskip;	/* no. of left bits to skip in *bm */
+	uchar	*em;		/* ptr to mask data img->r.max.x byte; like p->bytey0e */
+	int		emskip;	/* no. of right bits to skip in *em */
+};
+
+typedef struct	Param	Param;
+typedef Buffer	Readfn(Param*, uchar*, int);
+typedef void	Writefn(Param*, uchar*, Buffer);
+typedef Buffer	Calcfn(Buffer, Buffer, Buffer, int, int, int);
+
+enum {
+	MAXBCACHE = 16
+};
+
+/* giant rathole to customize functions with */
+struct Param {
+	Readfn	*replcall;
+	Readfn	*greymaskcall;	
+	Readfn	*convreadcall;
+	Writefn	*convwritecall;
+
+	Memimage *img;
+	Rectangle	r;
+	int	dx;	/* of r */
+	int	needbuf;
+	int	convgrey;
+	int	alphaonly;
+
+	uchar	*bytey0s;		/* byteaddr(Pt(img->r.min.x, img->r.min.y)) */
+	uchar	*bytermin;	/* byteaddr(Pt(r.min.x, img->r.min.y)) */
+	uchar	*bytey0e;		/* byteaddr(Pt(img->r.max.x, img->r.min.y)) */
+	int		bwidth;
+
+	int	replcache;	/* if set, cache buffers */
+	Buffer	bcache[MAXBCACHE];
+	ulong	bfilled;
+	uchar	*bufbase;
+	int	bufoff;
+	int	bufdelta;
+
+	int	dir;
+
+	int	convbufoff;
+	uchar	*convbuf;
+	Param	*convdpar;
+	int	convdx;
+};
+
+static Readfn	greymaskread, replread, readptr;
+static Writefn	nullwrite;
+static Calcfn	alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;
+static Calcfn	boolcalc14, boolcalc236789, boolcalc1011;
+
+static Readfn*	readfn(Memimage*);
+static Readfn*	readalphafn(Memimage*);
+static Writefn*	writefn(Memimage*);
+
+static Calcfn*	boolcopyfn(Memimage*, Memimage*);
+static Readfn*	convfn(Memimage*, Param*, Memimage*, Param*, int*);
+static Readfn*	ptrfn(Memimage*);
+
+static Calcfn *alphacalc[Ncomp] = 
+{
+	alphacalc0,		/* Clear */
+	alphacalc14,		/* DoutS */
+	alphacalc2810,		/* SoutD */
+	alphacalc3679,		/* DxorS */
+	alphacalc14,		/* DinS */
+	alphacalc5,		/* D */
+	alphacalc3679,		/* DatopS */
+	alphacalc3679,		/* DoverS */
+	alphacalc2810,		/* SinD */
+	alphacalc3679,		/* SatopD */
+	alphacalc2810,		/* S */
+	alphacalc11,		/* SoverD */
+};
+
+static Calcfn *boolcalc[Ncomp] =
+{
+	alphacalc0,		/* Clear */
+	boolcalc14,		/* DoutS */
+	boolcalc236789,		/* SoutD */
+	boolcalc236789,		/* DxorS */
+	boolcalc14,		/* DinS */
+	alphacalc5,		/* D */
+	boolcalc236789,		/* DatopS */
+	boolcalc236789,		/* DoverS */
+	boolcalc236789,		/* SinD */
+	boolcalc236789,		/* SatopD */
+	boolcalc1011,		/* S */
+	boolcalc1011,		/* SoverD */
+};
+
+/*
+ * Avoid standard Lock, QLock so that can be used in kernel.
+ */
+typedef struct Dbuf Dbuf;
+struct Dbuf
+{
+	uchar *p;
+	int n;
+	Param spar, mpar, dpar;
+	int inuse;
+};
+static Dbuf dbuf[10];
+
+static Dbuf*
+allocdbuf(void)
+{
+	int i;
+
+	for(i=0; i<nelem(dbuf); i++){
+		if(dbuf[i].inuse)
+			continue;
+		if(!_tas(&dbuf[i].inuse))
+			return &dbuf[i];
+	}
+	return nil;
+}
+
+static void
+getparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf, int *ndrawbuf)
+{
+	int nbuf;
+
+	memset(p, 0, sizeof *p);
+
+	p->img = img;
+	p->r = r;
+	p->dx = Dx(r);
+	p->needbuf = needbuf;
+	p->convgrey = convgrey;
+
+	assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x);
+
+	p->bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y));
+	p->bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y));
+	p->bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y));
+	p->bwidth = sizeof(ulong)*img->width;
+
+	assert(p->bytey0s <= p->bytermin && p->bytermin <= p->bytey0e);
+
+	if(p->r.min.x == p->img->r.min.x)
+		assert(p->bytermin == p->bytey0s);
+
+	nbuf = 1;
+	if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){
+		p->replcache = 1;
+		nbuf = Dy(img->r);
+	}
+	p->bufdelta = 4*p->dx;
+	p->bufoff = *ndrawbuf;
+	*ndrawbuf += p->bufdelta*nbuf;
+}
+
+static void
+clipy(Memimage *img, int *y)
+{
+	int dy;
+
+	dy = Dy(img->r);
+	if(*y == dy)
+		*y = 0;
+	else if(*y == -1)
+		*y = dy-1;
+	assert(0 <= *y && *y < dy);
+}
+
+static void
+dumpbuf(char *s, Buffer b, int n)
+{
+	int i;
+	uchar *p;
+	
+	print("%s", s);
+	for(i=0; i<n; i++){
+		print(" ");
+		if(p=b.grey){
+			print(" k%.2uX", *p);
+			b.grey += b.delta;
+		}else{	
+			if(p=b.red){
+				print(" r%.2uX", *p);
+				b.red += b.delta;
+			}
+			if(p=b.grn){
+				print(" g%.2uX", *p);
+				b.grn += b.delta;
+			}
+			if(p=b.blu){
+				print(" b%.2uX", *p);
+				b.blu += b.delta;
+			}
+		}
+		if((p=b.alpha) != &ones){
+			print(" α%.2uX", *p);
+			b.alpha += b.delta;
+		}
+	}
+	print("\n");
+}
+
+/*
+ * For each scan line, we expand the pixels from source, mask, and destination
+ * into byte-aligned red, green, blue, alpha, and grey channels.  If buffering is not
+ * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32),
+ * the readers need not copy the data: they can simply return pointers to the data.
+ * If the destination image is grey and the source is not, it is converted using the NTSC
+ * formula.
+ *
+ * Once we have all the channels, we call either rgbcalc or greycalc, depending on 
+ * whether the destination image is color.  This is allowed to overwrite the dst buffer (perhaps
+ * the actual data, perhaps a copy) with its result.  It should only overwrite the dst buffer
+ * with the same format (i.e. red bytes with red bytes, etc.)  A new buffer is returned from
+ * the calculator, and that buffer is passed to a function to write it to the destination.
+ * If the buffer is already pointing at the destination, the writing function is a no-op.
+ */
+#define DBG if(0)
+static int
+alphadraw(Memdrawparam *par)
+{
+	int isgrey, starty, endy, op;
+	int needbuf, dsty, srcy, masky;
+	int y, dir, dx, dy, ndrawbuf;
+	uchar *drawbuf;
+	Buffer bsrc, bdst, bmask;
+	Readfn *rdsrc, *rdmask, *rddst;
+	Calcfn *calc;
+	Writefn *wrdst;
+	Memimage *src, *mask, *dst;
+	Rectangle r, sr, mr;
+	Dbuf *z;
+
+	z = allocdbuf();
+	if(z == nil)
+		return 0;
+
+	r = par->r;
+	dx = Dx(r);
+	dy = Dy(r);
+
+	src = par->src;
+	mask = par->mask;	
+	dst = par->dst;
+	sr = par->sr;
+	mr = par->mr;
+	op = par->op;
+
+	isgrey = dst->flags&Fgrey;
+
+	/*
+	 * Buffering when src and dst are the same bitmap is sufficient but not 
+	 * necessary.  There are stronger conditions we could use.  We could
+	 * check to see if the rectangles intersect, and if simply moving in the
+	 * correct y direction can avoid the need to buffer.
+	 */
+	needbuf = (src->data == dst->data);
+
+	ndrawbuf = 0;
+	getparam(&z->spar, src, sr, isgrey, needbuf, &ndrawbuf);
+	getparam(&z->dpar, dst, r, isgrey, needbuf, &ndrawbuf);
+	getparam(&z->mpar, mask, mr, 0, needbuf, &ndrawbuf);
+
+	dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1;
+	z->spar.dir = z->mpar.dir = z->dpar.dir = dir;
+
+	/*
+	 * If the mask is purely boolean, we can convert from src to dst format
+	 * when we read src, and then just copy it to dst where the mask tells us to.
+	 * This requires a boolean (1-bit grey) mask and lack of a source alpha channel.
+	 *
+	 * The computation is accomplished by assigning the function pointers as follows:
+	 *	rdsrc - read and convert source into dst format in a buffer
+	 * 	rdmask - convert mask to bytes, set pointer to it
+	 * 	rddst - fill with pointer to real dst data, but do no reads
+	 *	calc - copy src onto dst when mask says to.
+	 *	wrdst - do nothing
+	 * This is slightly sleazy, since things aren't doing exactly what their names say,
+	 * but it avoids a fair amount of code duplication to make this a case here
+	 * rather than have a separate booldraw.
+	 */
+//if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth);
+	if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){
+//if(drawdebug) iprint("boolcopy...");
+		rdsrc = convfn(dst, &z->dpar, src, &z->spar, &ndrawbuf);
+		rddst = readptr;
+		rdmask = readfn(mask);
+		calc = boolcopyfn(dst, mask);
+		wrdst = nullwrite;
+	}else{
+		/* usual alphadraw parameter fetching */
+		rdsrc = readfn(src);
+		rddst = readfn(dst);
+		wrdst = writefn(dst);
+		calc = alphacalc[op];
+
+		/*
+		 * If there is no alpha channel, we'll ask for a grey channel
+		 * and pretend it is the alpha.
+		 */
+		if(mask->flags&Falpha){
+			rdmask = readalphafn(mask);
+			z->mpar.alphaonly = 1;
+		}else{
+			z->mpar.greymaskcall = readfn(mask);
+			z->mpar.convgrey = 1;
+			rdmask = greymaskread;
+
+			/*
+			 * Should really be above, but then boolcopyfns would have
+			 * to deal with bit alignment, and I haven't written that.
+			 *
+			 * This is a common case for things like ellipse drawing.
+			 * When there's no alpha involved and the mask is boolean,
+			 * we can avoid all the division and multiplication.
+			 */
+			if(mask->chan == GREY1 && !(src->flags&Falpha))
+				calc = boolcalc[op];
+			else if(op == SoverD && !(src->flags&Falpha))
+				calc = alphacalcS;
+		}
+	}
+
+	/*
+	 * If the image has a small enough repl rectangle,
+	 * we can just read each line once and cache them.
+	 */
+	if(z->spar.replcache){
+		z->spar.replcall = rdsrc;
+		rdsrc = replread;
+	}
+	if(z->mpar.replcache){
+		z->mpar.replcall = rdmask;
+		rdmask = replread;
+	}
+
+	if(z->n < ndrawbuf){
+		free(z->p);
+		if((z->p = mallocz(ndrawbuf, 0)) == nil){
+			z->inuse = 0;
+			return 0;
+		}
+		z->n = ndrawbuf;
+	}
+	drawbuf = z->p;
+
+	/*
+	 * Before we were saving only offsets from drawbuf in the parameter
+	 * structures; now that drawbuf has been grown to accomodate us,
+	 * we can fill in the pointers.
+	 */
+	z->spar.bufbase = drawbuf+z->spar.bufoff;
+	z->mpar.bufbase = drawbuf+z->mpar.bufoff;
+	z->dpar.bufbase = drawbuf+z->dpar.bufoff;
+	z->spar.convbuf = drawbuf+z->spar.convbufoff;
+
+	if(dir == 1){
+		starty = 0;
+		endy = dy;
+	}else{
+		starty = dy-1;
+		endy = -1;
+	}
+
+	/*
+	 * srcy, masky, and dsty are offsets from the top of their
+	 * respective Rectangles.  they need to be contained within
+	 * the rectangles, so clipy can keep them there without division.
+ 	 */
+	srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r);
+	masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r);
+	dsty = starty + r.min.y - dst->r.min.y;
+
+	assert(0 <= srcy && srcy < Dy(src->r));
+	assert(0 <= masky && masky < Dy(mask->r));
+	assert(0 <= dsty && dsty < Dy(dst->r));
+
+	for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){
+		clipy(src, &srcy);
+		clipy(dst, &dsty);
+		clipy(mask, &masky);
+
+		bsrc = rdsrc(&z->spar, z->spar.bufbase, srcy);
+DBG print("[");
+		bmask = rdmask(&z->mpar, z->mpar.bufbase, masky);
+DBG print("]\n");
+		bdst = rddst(&z->dpar, z->dpar.bufbase, dsty);
+		if(op != Clear && (bsrc.delta != 4 || bdst.delta != 4 || src->chan != dst->chan))
+			bdst.rgba = nil;
+DBG		dumpbuf("src", bsrc, dx);
+DBG		dumpbuf("mask", bmask, dx);
+DBG		dumpbuf("dst", bdst, dx);
+		bdst = calc(bdst, bsrc, bmask, dx, isgrey, op);
+		wrdst(&z->dpar, z->dpar.bytermin+dsty*z->dpar.bwidth, bdst);
+	}
+
+	z->inuse = 0;
+	return 1;
+}
+#undef DBG
+
+static Buffer
+alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
+{
+	USED(b1.grey);
+	USED(b2.grey);
+	USED(grey);
+	USED(op);
+	memset(bdst.rgba, 0, dx*bdst.delta);
+	return bdst;
+}
+
+static Buffer
+alphacalc14(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int fd, sadelta;
+	int i, sa, ma;
+	ulong s, t;
+
+	obdst = bdst;
+	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+	for(i=0; i<dx; i++){
+		sa = *bsrc.alpha;
+		ma = *bmask.alpha;
+		fd = MUL(sa, ma, t);
+		if(op == DoutS)
+			fd = 255-fd;
+
+		if(grey){
+			*bdst.grey = MUL(fd, *bdst.grey, t);
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			if(bdst.rgba){
+				*bdst.rgba = MUL0123(fd, *bdst.rgba, s, t);
+				bsrc.rgba++;
+				bdst.rgba++;
+				bsrc.alpha += sadelta;
+				bmask.alpha += bmask.delta;
+				continue;
+			}
+			*bdst.red = MUL(fd, *bdst.red, t);
+			*bdst.grn = MUL(fd, *bdst.grn, t);
+			*bdst.blu = MUL(fd, *bdst.blu, t);
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		if(bdst.alpha != &ones){
+			*bdst.alpha = MUL(fd, *bdst.alpha, t);
+			bdst.alpha += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+		bsrc.alpha += sadelta;
+	}
+	return obdst;
+}
+
+static Buffer
+alphacalc2810(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int fs, sadelta;
+	int i, ma, da;
+	ulong s, t;
+
+	obdst = bdst;
+	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+	for(i=0; i<dx; i++){
+		ma = *bmask.alpha;
+		da = *bdst.alpha;
+		if(op == SoutD)
+			da = 255-da;
+		fs = ma;
+		if(op != S)
+			fs = MUL(fs, da, t);
+
+		if(grey){
+			*bdst.grey = MUL(fs, *bsrc.grey, t);
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			if(bdst.rgba){
+				*bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t);
+				bsrc.rgba++;
+				bdst.rgba++;
+				bmask.alpha += bmask.delta;
+				bdst.alpha += bdst.delta;
+				continue;
+			}
+			*bdst.red = MUL(fs, *bsrc.red, t);
+			*bdst.grn = MUL(fs, *bsrc.grn, t);
+			*bdst.blu = MUL(fs, *bsrc.blu, t);
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		if(bdst.alpha != &ones){
+			*bdst.alpha = MUL(fs, *bsrc.alpha, t);
+			bdst.alpha += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+		bsrc.alpha += sadelta;
+	}
+	return obdst;
+}
+
+static Buffer
+alphacalc3679(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int fs, fd, sadelta;
+	int i, sa, ma, da;
+	ulong s, t, q1, q2;
+
+	obdst = bdst;
+	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+	for(i=0; i<dx; i++){
+		sa = *bsrc.alpha;
+		ma = *bmask.alpha;
+		da = *bdst.alpha;
+		if(op == SatopD)
+			fs = MUL(ma, da, t);
+		else
+			fs = MUL(ma, 255-da, t);
+		if(op == DoverS)
+			fd = 255;
+		else{
+			fd = MUL(sa, ma, t);
+			if(op != DatopS)
+				fd = 255-fd;
+		}
+
+		if(grey){
+			*bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			if(bdst.rgba){
+				q1 = MUL0123(fs, *bsrc.rgba, s, t);
+				q2 = MUL0123(fd, *bdst.rgba, s, t);
+				*bdst.rgba = BWADD(q1, q2);
+				bsrc.rgba++;
+				bdst.rgba++;
+				bsrc.alpha += sadelta;
+				bmask.alpha += bmask.delta;
+				bdst.alpha += bdst.delta;
+				continue;
+			}
+			*bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+			*bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+			*bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		if(bdst.alpha != &ones){
+			*bdst.alpha = MUL(fs, sa, s)+MUL(fd, da, t);
+			bdst.alpha += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+		bsrc.alpha += sadelta;
+	}
+	return obdst;
+}
+
+static Buffer
+alphacalc5(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
+{
+	USED(b1.grey);
+	USED(b2.grey);
+	USED(dx);
+	USED(grey);
+	USED(op);
+	return bdst;
+}
+
+static Buffer
+alphacalc11(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int fd, sadelta;
+	int i, sa, ma;
+	ulong s, t, q1, q2;
+
+	USED(op);
+	obdst = bdst;
+	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
+
+	for(i=0; i<dx; i++){
+		sa = *bsrc.alpha;
+		ma = *bmask.alpha;
+		fd = 255-MUL(sa, ma, t);
+
+		if(grey){
+			*bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			if(bdst.rgba){
+				q1 = MUL0123(ma, *bsrc.rgba, s, t);
+				q2 = MUL0123(fd, *bdst.rgba, s, t);
+				*bdst.rgba = BWADD(q1, q2);
+				bsrc.rgba++;
+				bdst.rgba++;
+				bsrc.alpha += sadelta;
+				bmask.alpha += bmask.delta;
+				continue;
+			}
+			*bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+			*bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+			*bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		if(bdst.alpha != &ones){
+			*bdst.alpha = MUL(ma, sa, s)+MUL(fd, *bdst.alpha, t);
+			bdst.alpha += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+		bsrc.alpha += sadelta;
+	}
+	return obdst;
+}
+
+/*
+not used yet
+source and mask alpha 1
+static Buffer
+alphacalcS0(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int i;
+
+	USED(op);
+	obdst = bdst;
+	if(bsrc.delta == bdst.delta){
+		memmove(bdst.rgba, bsrc.rgba, dx*bdst.delta);
+		return obdst;
+	}
+	for(i=0; i<dx; i++){
+		if(grey){
+			*bdst.grey = *bsrc.grey;
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			*bdst.red = *bsrc.red;
+			*bdst.grn = *bsrc.grn;
+			*bdst.blu = *bsrc.blu;
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		if(bdst.alpha != &ones){
+			*bdst.alpha = 255;
+			bdst.alpha += bdst.delta;
+		}
+	}
+	return obdst;
+}
+*/
+
+/* source alpha 1 */
+static Buffer
+alphacalcS(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int fd;
+	int i, ma;
+	ulong s, t;
+
+	USED(op);
+	obdst = bdst;
+
+	for(i=0; i<dx; i++){
+		ma = *bmask.alpha;
+		fd = 255-ma;
+
+		if(grey){
+			*bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			*bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+			*bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+			*bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		if(bdst.alpha != &ones){
+			*bdst.alpha = ma+MUL(fd, *bdst.alpha, t);
+			bdst.alpha += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+	}
+	return obdst;
+}
+
+static Buffer
+boolcalc14(Buffer bdst, Buffer b1, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int i, ma, zero;
+
+	USED(b1.grey);
+	obdst = bdst;
+
+	for(i=0; i<dx; i++){
+		ma = *bmask.alpha;
+		zero = ma ? op == DoutS : op == DinS;
+
+		if(grey){
+			if(zero)
+				*bdst.grey = 0;
+			bdst.grey += bdst.delta;
+		}else{
+			if(zero)
+				*bdst.red = *bdst.grn = *bdst.blu = 0;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+		if(bdst.alpha != &ones){
+			if(zero)
+				*bdst.alpha = 0;
+			bdst.alpha += bdst.delta;
+		}
+	}
+	return obdst;
+}
+
+static Buffer
+boolcalc236789(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int fs, fd;
+	int i, ma, da, zero;
+	ulong s, t;
+
+	obdst = bdst;
+	zero = !(op&1);
+
+	for(i=0; i<dx; i++){
+		ma = *bmask.alpha;
+		da = *bdst.alpha;
+		fs = da;
+		if(op&2)
+			fs = 255-da;
+		fd = 0;
+		if(op&4)
+			fd = 255;
+
+		if(grey){
+			if(ma)
+				*bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
+			else if(zero)
+				*bdst.grey = 0;
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			if(ma){
+				*bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
+				*bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
+				*bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
+			}
+			else if(zero)
+				*bdst.red = *bdst.grn = *bdst.blu = 0;
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+		if(bdst.alpha != &ones){
+			if(ma)
+				*bdst.alpha = fs+MUL(fd, da, t);
+			else if(zero)
+				*bdst.alpha = 0;
+			bdst.alpha += bdst.delta;
+		}
+	}
+	return obdst;
+}
+
+static Buffer
+boolcalc1011(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
+{
+	Buffer obdst;
+	int i, ma, zero;
+
+	obdst = bdst;
+	zero = !(op&1);
+
+	for(i=0; i<dx; i++){
+		ma = *bmask.alpha;
+
+		if(grey){
+			if(ma)
+				*bdst.grey = *bsrc.grey;
+			else if(zero)
+				*bdst.grey = 0;
+			bsrc.grey += bsrc.delta;
+			bdst.grey += bdst.delta;
+		}else{
+			if(ma){
+				*bdst.red = *bsrc.red;
+				*bdst.grn = *bsrc.grn;
+				*bdst.blu = *bsrc.blu;
+			}
+			else if(zero)
+				*bdst.red = *bdst.grn = *bdst.blu = 0;
+			bsrc.red += bsrc.delta;
+			bsrc.blu += bsrc.delta;
+			bsrc.grn += bsrc.delta;
+			bdst.red += bdst.delta;
+			bdst.blu += bdst.delta;
+			bdst.grn += bdst.delta;
+		}
+		bmask.alpha += bmask.delta;
+		if(bdst.alpha != &ones){
+			if(ma)
+				*bdst.alpha = 255;
+			else if(zero)
+				*bdst.alpha = 0;
+			bdst.alpha += bdst.delta;
+		}
+	}
+	return obdst;
+}
+/*
+ * Replicated cached scan line read.  Call the function listed in the Param,
+ * but cache the result so that for replicated images we only do the work once.
+ */
+static Buffer
+replread(Param *p, uchar *s, int y)
+{
+	Buffer *b;
+
+	USED(s);
+	b = &p->bcache[y];
+	if((p->bfilled & (1<<y)) == 0){
+		p->bfilled |= 1<<y;
+		*b = p->replcall(p, p->bufbase+y*p->bufdelta, y);
+	}
+	return *b;
+}
+
+/*
+ * Alpha reading function that simply relabels the grey pointer.
+ */
+static Buffer
+greymaskread(Param *p, uchar *buf, int y)
+{
+	Buffer b;
+
+	b = p->greymaskcall(p, buf, y);
+	b.alpha = b.grey;
+	return b;
+}
+
+#define DBG if(0)
+static Buffer
+readnbit(Param *p, uchar *buf, int y)
+{
+	Buffer b;
+	Memimage *img;
+	uchar *repl, *r, *w, *ow, bits;
+	int i, n, sh, depth, x, dx, npack, nbits;
+
+	b.rgba = (ulong*)buf;
+	b.grey = w = buf;
+	b.red = b.blu = b.grn = w;
+	b.alpha = &ones;
+	b.delta = 1;
+
+	dx = p->dx;
+	img = p->img;
+	depth = img->depth;
+	repl = &replbit[depth][0];
+	npack = 8/depth;
+	sh = 8-depth;
+
+	/* copy from p->r.min.x until end of repl rectangle */
+	x = p->r.min.x;
+	n = dx;
+	if(n > p->img->r.max.x - x)
+		n = p->img->r.max.x - x;
+
+	r = p->bytermin + y*p->bwidth;
+DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n);
+	bits = *r++;
+	nbits = 8;
+	if(i=x&(npack-1)){
+DBG print("throwaway %d...", i);
+		bits <<= depth*i;
+		nbits -= depth*i;
+	}
+	for(i=0; i<n; i++){
+		if(nbits == 0){
+DBG print("(%.2ux)...", *r);
+			bits = *r++;
+			nbits = 8;
+		}
+		*w++ = repl[bits>>sh];
+DBG print("bit %x...", repl[bits>>sh]);
+		bits <<= depth;
+		nbits -= depth;
+	}
+	dx -= n;
+	if(dx == 0)
+		return b;
+
+	assert(x+i == p->img->r.max.x);
+
+	/* copy from beginning of repl rectangle until where we were before. */
+	x = p->img->r.min.x;
+	n = dx;
+	if(n > p->r.min.x - x)
+		n = p->r.min.x - x;
+
+	r = p->bytey0s + y*p->bwidth;
+DBG print("x=%d r=%p...", x, r);
+	bits = *r++;
+	nbits = 8;
+	if(i=x&(npack-1)){
+		bits <<= depth*i;
+		nbits -= depth*i;
+	}
+DBG print("nbits=%d...", nbits);
+	for(i=0; i<n; i++){
+		if(nbits == 0){
+			bits = *r++;
+			nbits = 8;
+		}
+		*w++ = repl[bits>>sh];
+DBG print("bit %x...", repl[bits>>sh]);
+		bits <<= depth;
+		nbits -= depth;
+DBG print("bits %x nbits %d...", bits, nbits);
+	}
+	dx -= n;
+	if(dx == 0)
+		return b;
+
+	assert(dx > 0);
+	/* now we have exactly one full scan line: just replicate the buffer itself until we are done */
+	ow = buf;
+	while(dx--)
+		*w++ = *ow++;
+
+	return b;
+}
+#undef DBG
+
+#define DBG if(0)
+static void
+writenbit(Param *p, uchar *w, Buffer src)
+{
+	uchar *r;
+	ulong bits;
+	int i, sh, depth, npack, nbits, x, ex;
+
+	assert(src.grey != nil && src.delta == 1);
+
+	x = p->r.min.x;
+	ex = x+p->dx;
+	depth = p->img->depth;
+	npack = 8/depth;
+
+	i=x&(npack-1);
+	bits = i ? (*w >> (8-depth*i)) : 0;
+	nbits = depth*i;
+	sh = 8-depth;
+	r = src.grey;
+
+	for(; x<ex; x++){
+		bits <<= depth;
+DBG print(" %x", *r);
+		bits |= (*r++ >> sh);
+		nbits += depth;
+		if(nbits == 8){
+			*w++ = bits;
+			nbits = 0;
+		}
+	}
+
+	if(nbits){
+		sh = 8-nbits;
+		bits <<= sh;
+		bits |= *w & ((1<<sh)-1);
+		*w = bits;
+	}
+DBG print("\n");
+	return;
+}
+#undef DBG
+
+static Buffer
+readcmap(Param *p, uchar *buf, int y)
+{
+	Buffer b;
+	int a, convgrey, copyalpha, dx, i, m;
+	uchar *q, *cmap, *begin, *end, *r, *w;
+
+	begin = p->bytey0s + y*p->bwidth;
+	r = p->bytermin + y*p->bwidth;
+	end = p->bytey0e + y*p->bwidth;
+	cmap = p->img->cmap->cmap2rgb;
+	convgrey = p->convgrey;
+	copyalpha = (p->img->flags&Falpha) ? 1 : 0;
+
+	w = buf;
+	dx = p->dx;
+	if(copyalpha){
+		b.alpha = buf++;
+		a = p->img->shift[CAlpha]/8;
+		m = p->img->shift[CMap]/8;
+		for(i=0; i<dx; i++){
+			*w++ = r[a];
+			q = cmap+r[m]*3;
+			r += 2;
+			if(r == end)
+				r = begin;
+			if(convgrey){
+				*w++ = RGB2K(q[0], q[1], q[2]);
+			}else{
+				*w++ = q[2];	/* blue */
+				*w++ = q[1];	/* green */
+				*w++ = q[0];	/* red */
+			}
+		}
+	}else{
+		b.alpha = &ones;
+		for(i=0; i<dx; i++){
+			q = cmap+*r++*3;
+			if(r == end)
+				r = begin;
+			if(convgrey){
+				*w++ = RGB2K(q[0], q[1], q[2]);
+			}else{
+				*w++ = q[2];	/* blue */
+				*w++ = q[1];	/* green */
+				*w++ = q[0];	/* red */
+			}
+		}
+	}
+
+	b.rgba = (ulong*)(buf-copyalpha);
+
+	if(convgrey){
+		b.grey = buf;
+		b.red = b.blu = b.grn = buf;
+		b.delta = 1+copyalpha;
+	}else{
+		b.blu = buf;
+		b.grn = buf+1;
+		b.red = buf+2;
+		b.grey = nil;
+		b.delta = 3+copyalpha;
+	}
+	return b;
+}
+
+static void
+writecmap(Param *p, uchar *w, Buffer src)
+{
+	uchar *cmap, *red, *grn, *blu;
+	int i, dx, delta;
+
+	cmap = p->img->cmap->rgb2cmap;
+	
+	delta = src.delta;
+	red= src.red;
+	grn = src.grn;
+	blu = src.blu;
+
+	dx = p->dx;
+	for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
+		*w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
+}
+
+#define DBG if(0)
+static Buffer
+readbyte(Param *p, uchar *buf, int y)
+{
+	Buffer b;
+	Memimage *img;
+	int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb;
+	uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl;
+	uchar ured, ugrn, ublu;
+	ulong u;
+
+	img = p->img;
+	begin = p->bytey0s + y*p->bwidth;
+	r = p->bytermin + y*p->bwidth;
+	end = p->bytey0e + y*p->bwidth;
+
+	w = buf;
+	dx = p->dx;
+	nb = img->depth/8;
+
+	convgrey = p->convgrey;	/* convert rgb to grey */
+	isgrey = img->flags&Fgrey;
+	alphaonly = p->alphaonly;
+	copyalpha = (img->flags&Falpha) ? 1 : 0;
+
+DBG print("copyalpha %d alphaonly %d convgrey %d isgrey %d\n", copyalpha, alphaonly, convgrey, isgrey);
+	/* if we can, avoid processing everything */
+	if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){
+		memset(&b, 0, sizeof b);
+		if(p->needbuf){
+			memmove(buf, r, dx*nb);
+			r = buf;
+		}
+		b.rgba = (ulong*)r;
+		if(copyalpha)
+			b.alpha = r+img->shift[CAlpha]/8;
+		else
+			b.alpha = &ones;
+		if(isgrey){
+			b.grey = r+img->shift[CGrey]/8;
+			b.red = b.grn = b.blu = b.grey;
+		}else{
+			b.red = r+img->shift[CRed]/8;
+			b.grn = r+img->shift[CGreen]/8;
+			b.blu = r+img->shift[CBlue]/8;
+		}
+		b.delta = nb;
+		return b;
+	}
+
+DBG print("2\n");
+	rrepl = replbit[img->nbits[CRed]];
+	grepl = replbit[img->nbits[CGreen]];
+	brepl = replbit[img->nbits[CBlue]];
+	arepl = replbit[img->nbits[CAlpha]];
+	krepl = replbit[img->nbits[CGrey]];
+
+	for(i=0; i<dx; i++){
+		u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24);
+		if(copyalpha) {
+			*w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]];
+DBG print("a %x\n", w[-1]);
+		}
+
+		if(isgrey)
+			*w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]];
+		else if(!alphaonly){
+			ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
+			ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
+			ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
+			if(convgrey){
+DBG print("g %x %x %x\n", ured, ugrn, ublu);
+				*w++ = RGB2K(ured, ugrn, ublu);
+DBG print("%x\n", w[-1]);
+			}else{
+				*w++ = ublu;
+				*w++ = ugrn;
+				*w++ = ured;
+			}
+		}
+		r += nb;
+		if(r == end)
+			r = begin;
+	}
+	
+	b.alpha = copyalpha ? buf : &ones;
+	b.rgba = (ulong*)buf;
+	if(alphaonly){
+		b.red = b.grn = b.blu = b.grey = nil;
+		if(!copyalpha)
+			b.rgba = nil;
+		b.delta = 1;
+	}else if(isgrey || convgrey){
+		b.grey = buf+copyalpha;
+		b.red = b.grn = b.blu = buf+copyalpha;
+		b.delta = copyalpha+1;
+DBG print("alpha %x grey %x\n", b.alpha ? *b.alpha : 0xFF, *b.grey);
+	}else{
+		b.blu = buf+copyalpha;
+		b.grn = buf+copyalpha+1;
+		b.grey = nil;
+		b.red = buf+copyalpha+2;
+		b.delta = copyalpha+3;
+	}
+	return b;
+}
+#undef DBG
+
+#define DBG if(0)
+static void
+writebyte(Param *p, uchar *w, Buffer src)
+{
+	Memimage *img;
+	int i, isalpha, isgrey, nb, delta, dx, adelta;
+	uchar ff, *red, *grn, *blu, *grey, *alpha;
+	ulong u, mask;
+
+	img = p->img;
+
+	red = src.red;
+	grn = src.grn;
+	blu = src.blu;
+	alpha = src.alpha;
+	delta = src.delta;
+	grey = src.grey;
+	dx = p->dx;
+
+	nb = img->depth/8;
+	mask = (nb==4) ? 0 : ~((1<<img->depth)-1);
+
+	isalpha = img->flags&Falpha;
+	isgrey = img->flags&Fgrey;
+	adelta = src.delta;
+
+	if(isalpha && (alpha == nil || alpha == &ones)){
+		ff = 0xFF;
+		alpha = &ff;
+		adelta = 0;
+	}
+
+	for(i=0; i<dx; i++){
+		u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24);
+DBG print("u %.8lux...", u);
+		u &= mask;
+DBG print("&mask %.8lux...", u);
+		if(isgrey){
+			u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey];
+DBG print("|grey %.8lux...", u);
+			grey += delta;
+		}else{
+			u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed];
+			u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen];
+			u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue];
+			red += delta;
+			grn += delta;
+			blu += delta;
+DBG print("|rgb %.8lux...", u);
+		}
+
+		if(isalpha){
+			u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha];
+			alpha += adelta;
+DBG print("|alpha %.8lux...", u);
+		}
+
+		w[0] = u;
+		w[1] = u>>8;
+		w[2] = u>>16;
+		w[3] = u>>24;
+		w += nb;
+	}
+}
+#undef DBG
+
+static Readfn*
+readfn(Memimage *img)
+{
+	if(img->depth < 8)
+		return readnbit;
+	if(img->nbits[CMap] == 8)
+		return readcmap;
+	return readbyte;
+}
+
+static Readfn*
+readalphafn(Memimage *m)
+{
+	USED(m);
+	return readbyte;
+}
+
+static Writefn*
+writefn(Memimage *img)
+{
+	if(img->depth < 8)
+		return writenbit;
+	if(img->chan == CMAP8)
+		return writecmap;
+	return writebyte;
+}
+
+static void
+nullwrite(Param *p, uchar *s, Buffer b)
+{
+	USED(p);
+	USED(s);
+	USED(b.grey);
+}
+
+static Buffer
+readptr(Param *p, uchar *s, int y)
+{
+	Buffer b;
+	uchar *q;
+
+	USED(s);
+	q = p->bytermin + y*p->bwidth;
+	b.red = q;	/* ptr to data */
+	b.grn = b.blu = b.grey = b.alpha = nil;
+	b.rgba = (ulong*)q;
+	b.delta = p->img->depth/8;
+	return b;
+}
+
+static Buffer
+boolmemmove(Buffer bdst, Buffer bsrc, Buffer b1, int dx, int i, int o)
+{
+	USED(i);
+	USED(o);
+	USED(b1.grey);
+	memmove(bdst.red, bsrc.red, dx*bdst.delta);
+	return bdst;
+}
+
+static Buffer
+boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+	uchar *m, *r, *w, *ew;
+
+	USED(i);
+	USED(o);
+	m = bmask.grey;
+	w = bdst.red;
+	r = bsrc.red;
+	ew = w+dx;
+	for(; w < ew; w++,r++)
+		if(*m++)
+			*w = *r;
+	return bdst;	/* not used */
+}
+
+static Buffer
+boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+	uchar *m;
+	ushort *r, *w, *ew;
+
+	USED(i);
+	USED(o);
+	m = bmask.grey;
+	w = (ushort*)bdst.red;
+	r = (ushort*)bsrc.red;
+	ew = w+dx;
+	for(; w < ew; w++,r++)
+		if(*m++)
+			*w = *r;
+	return bdst;	/* not used */
+}
+
+static Buffer
+boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+	uchar *m;
+	uchar *r, *w, *ew;
+
+	USED(i);
+	USED(o);
+	m = bmask.grey;
+	w = bdst.red;
+	r = bsrc.red;
+	ew = w+dx*3;
+	while(w < ew){
+		if(*m++){
+			*w++ = *r++;
+			*w++ = *r++;
+			*w++ = *r++;
+		}else{
+			w += 3;
+			r += 3;
+		}
+	}
+	return bdst;	/* not used */
+}
+
+static Buffer
+boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
+{
+	uchar *m;
+	ulong *r, *w, *ew;
+
+	USED(i);
+	USED(o);
+	m = bmask.grey;
+	w = (ulong*)bdst.red;
+	r = (ulong*)bsrc.red;
+	ew = w+dx;
+	for(; w < ew; w++,r++)
+		if(*m++)
+			*w = *r;
+	return bdst;	/* not used */
+}
+
+static Buffer
+genconv(Param *p, uchar *buf, int y)
+{
+	Buffer b;
+	int nb;
+	uchar *r, *w, *ew;
+
+	/* read from source into RGB format in convbuf */
+	b = p->convreadcall(p, p->convbuf, y);
+
+	/* write RGB format into dst format in buf */
+	p->convwritecall(p->convdpar, buf, b);
+
+	if(p->convdx){
+		nb = p->convdpar->img->depth/8;
+		r = buf;
+		w = buf+nb*p->dx;
+		ew = buf+nb*p->convdx;
+		while(w<ew)
+			*w++ = *r++;
+	}
+
+	b.red = buf;
+	b.blu = b.grn = b.grey = b.alpha = nil;
+	b.rgba = (ulong*)buf;
+	b.delta = 0;
+	
+	return b;
+}
+
+static Readfn*
+convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar, int *ndrawbuf)
+{
+	if(dst->chan == src->chan && !(src->flags&Frepl)){
+//if(drawdebug) iprint("readptr...");
+		return readptr;
+	}
+
+	if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){
+		/* cheat because we know the replicated value is exactly the color map entry. */
+//if(drawdebug) iprint("Readnbit...");
+		return readnbit;
+	}
+
+	spar->convreadcall = readfn(src);
+	spar->convwritecall = writefn(dst);
+	spar->convdpar = dpar;
+
+	/* allocate a conversion buffer */
+	spar->convbufoff = *ndrawbuf;
+	*ndrawbuf += spar->dx*4;
+
+	if(spar->dx > Dx(spar->img->r)){
+		spar->convdx = spar->dx;
+		spar->dx = Dx(spar->img->r);
+	}
+
+//if(drawdebug) iprint("genconv...");
+	return genconv;
+}
+
+static ulong
+pixelbits(Memimage *i, Point pt)
+{
+	uchar *p;
+	ulong val;
+	int off, bpp, npack;
+
+	val = 0;
+	p = byteaddr(i, pt);
+	switch(bpp=i->depth){
+	case 1:
+	case 2:
+	case 4:
+		npack = 8/bpp;
+		off = pt.x%npack;
+		val = p[0] >> bpp*(npack-1-off);
+		val &= (1<<bpp)-1;
+		break;
+	case 8:
+		val = p[0];
+		break;
+	case 16:
+		val = p[0]|(p[1]<<8);
+		break;
+	case 24:
+		val = p[0]|(p[1]<<8)|(p[2]<<16);
+		break;
+	case 32:
+		val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+		break;
+	}
+	while(bpp<32){
+		val |= val<<bpp;
+		bpp *= 2;
+	}
+	return val;
+}
+
+static Calcfn*
+boolcopyfn(Memimage *img, Memimage *mask)
+{
+	if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0)
+		return boolmemmove;
+
+	switch(img->depth){
+	case 8:
+		return boolcopy8;
+	case 16:
+		return boolcopy16;
+	case 24:
+		return boolcopy24;
+	case 32:
+		return boolcopy32;
+	default:
+		assert(0 /* boolcopyfn */);
+	}
+	return nil;
+}
+
+/*
+ * Optimized draw for filling and scrolling; uses memset and memmove.
+ */
+static void
+memsetb(void *vp, uchar val, int n)
+{
+	uchar *p, *ep;
+
+	p = vp;
+	ep = p+n;
+	while(p<ep)
+		*p++ = val;
+}
+
+static void
+memsets(void *vp, ushort val, int n)
+{
+	ushort *p, *ep;
+
+	p = vp;
+	ep = p+n;
+	while(p<ep)
+		*p++ = val;
+}
+
+static void
+memsetl(void *vp, ulong val, int n)
+{
+	ulong *p, *ep;
+
+	p = vp;
+	ep = p+n;
+	while(p<ep)
+		*p++ = val;
+}
+
+static void
+memset24(void *vp, ulong val, int n)
+{
+	uchar *p, *ep;
+	uchar a,b,c;
+
+	p = vp;
+	ep = p+3*n;
+	a = val;
+	b = val>>8;
+	c = val>>16;
+	while(p<ep){
+		*p++ = a;
+		*p++ = b;
+		*p++ = c;
+	}
+}
+
+static ulong
+imgtorgba(Memimage *img, ulong val)
+{
+	uchar r, g, b, a;
+	int nb, ov, v;
+	ulong chan;
+	uchar *p;
+
+	a = 0xFF;
+	r = g = b = 0xAA;	/* garbage */
+	for(chan=img->chan; chan; chan>>=8){
+		nb = NBITS(chan);
+		ov = v = val&((1<<nb)-1);
+		val >>= nb;
+
+		while(nb < 8){
+			v |= v<<nb;
+			nb *= 2;
+		}
+		v >>= (nb-8);
+
+		switch(TYPE(chan)){
+		case CRed:
+			r = v;
+			break;
+		case CGreen:
+			g = v;
+			break;
+		case CBlue:
+			b = v;
+			break;
+		case CAlpha:
+			a = v;
+			break;
+		case CGrey:
+			r = g = b = v;
+			break;
+		case CMap:
+			p = img->cmap->cmap2rgb+3*ov;
+			r = *p++;
+			g = *p++;	
+			b = *p;
+			break;
+		}
+	}
+	return (r<<24)|(g<<16)|(b<<8)|a;	
+}
+
+static ulong
+rgbatoimg(Memimage *img, ulong rgba)
+{
+	ulong chan;
+	int d, nb;
+	ulong v;
+	uchar *p, r, g, b, a, m;
+
+	v = 0;
+	r = rgba>>24;
+	g = rgba>>16;
+	b = rgba>>8;
+	a = rgba;
+	d = 0;
+	for(chan=img->chan; chan; chan>>=8){
+		nb = NBITS(chan);
+		switch(TYPE(chan)){
+		case CRed:
+			v |= (r>>(8-nb))<<d;
+			break;
+		case CGreen:
+			v |= (g>>(8-nb))<<d;
+			break;
+		case CBlue:
+			v |= (b>>(8-nb))<<d;
+			break;
+		case CAlpha:
+			v |= (a>>(8-nb))<<d;
+			break;
+		case CMap:
+			p = img->cmap->rgb2cmap;
+			m = p[(r>>4)*256+(g>>4)*16+(b>>4)];
+			v |= (m>>(8-nb))<<d;
+			break;
+		case CGrey:
+			m = RGB2K(r,g,b);
+			v |= (m>>(8-nb))<<d;
+			break;
+		}
+		d += nb;
+	}
+//	print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v);
+	return v;
+}
+
+#define DBG if(0)
+static int
+memoptdraw(Memdrawparam *par)
+{
+	int m, y, dy, dx, op;
+	ulong v;
+	Memimage *src;
+	Memimage *dst;
+
+	dx = Dx(par->r);
+	dy = Dy(par->r);
+	src = par->src;
+	dst = par->dst;
+	op = par->op;
+
+DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth);
+	/*
+	 * If we have an opaque mask and source is one opaque pixel we can convert to the
+	 * destination format and just replicate with memset.
+	 */
+	m = Simplesrc|Simplemask|Fullmask;
+	if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){
+		uchar *dp, p[4];
+		int d, dwid, ppb, np, nb;
+		uchar lm, rm;
+
+DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata);
+		dwid = dst->width*sizeof(ulong);
+		dp = byteaddr(dst, par->r.min);
+		v = par->sdval;
+DBG print("sdval %lud, depth %d\n", v, dst->depth);
+		switch(dst->depth){
+		case 1:
+		case 2:
+		case 4:
+			for(d=dst->depth; d<8; d*=2)
+				v |= (v<<d);
+			ppb = 8/dst->depth;	/* pixels per byte */
+			m = ppb-1;
+			/* left edge */
+			np = par->r.min.x&m;		/* no. pixels unused on left side of word */
+			dx -= (ppb-np);
+			nb = 8 - np * dst->depth;		/* no. bits used on right side of word */
+			lm = (1<<nb)-1;
+DBG print("np %d x %d nb %d lm %ux ppb %d m %ux\n", np, par->r.min.x, nb, lm, ppb, m);	
+
+			/* right edge */
+			np = par->r.max.x&m;	/* no. pixels used on left side of word */
+			dx -= np;
+			nb = 8 - np * dst->depth;		/* no. bits unused on right side of word */
+			rm = ~((1<<nb)-1);
+DBG print("np %d x %d nb %d rm %ux ppb %d m %ux\n", np, par->r.max.x, nb, rm, ppb, m);	
+
+DBG print("dx %d Dx %d\n", dx, Dx(par->r));
+			/* lm, rm are masks that are 1 where we should touch the bits */
+			if(dx < 0){	/* just one byte */
+				lm &= rm;
+				for(y=0; y<dy; y++, dp+=dwid)
+					*dp ^= (v ^ *dp) & lm;
+			}else if(dx == 0){	/* no full bytes */
+				if(lm)
+					dwid--;
+
+				for(y=0; y<dy; y++, dp+=dwid){
+					if(lm){
+DBG print("dp %p v %lux lm %ux (v ^ *dp) & lm %lux\n", dp, v, lm, (v^*dp)&lm);
+						*dp ^= (v ^ *dp) & lm;
+						dp++;
+					}
+					*dp ^= (v ^ *dp) & rm;
+				}
+			}else{		/* full bytes in middle */
+				dx /= ppb;
+				if(lm)
+					dwid--;
+				dwid -= dx;
+
+				for(y=0; y<dy; y++, dp+=dwid){
+					if(lm){
+						*dp ^= (v ^ *dp) & lm;
+						dp++;
+					}
+					memset(dp, v, dx);
+					dp += dx;
+					*dp ^= (v ^ *dp) & rm;
+				}
+			}
+			return 1;
+		case 8:
+			for(y=0; y<dy; y++, dp+=dwid)
+				memset(dp, v, dx);
+			return 1;
+		case 16:
+			p[0] = v;		/* make little endian */
+			p[1] = v>>8;
+			v = *(ushort*)p;
+DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n",
+	dp, dx, dy, dwid);
+			for(y=0; y<dy; y++, dp+=dwid)
+				memsets(dp, v, dx);
+			return 1;
+		case 24:
+			for(y=0; y<dy; y++, dp+=dwid)
+				memset24(dp, v, dx);
+			return 1;
+		case 32:
+			p[0] = v;		/* make little endian */
+			p[1] = v>>8;
+			p[2] = v>>16;
+			p[3] = v>>24;
+			v = *(ulong*)p;
+			for(y=0; y<dy; y++, dp+=dwid)
+				memsetl(dp, v, dx);
+			return 1;
+		default:
+			assert(0 /* bad dest depth in memoptdraw */);
+		}
+	}
+
+	/*
+	 * If no source alpha, an opaque mask, we can just copy the
+	 * source onto the destination.  If the channels are the same and
+	 * the source is not replicated, memmove suffices.
+	 */
+	m = Simplemask|Fullmask;
+	if((par->state&(m|Replsrc))==m && src->depth >= 8 
+	&& src->chan == dst->chan && (op == S || (op == SoverD && !(src->flags&Falpha)))){
+		uchar *sp, *dp;
+		long swid, dwid, nb;
+		int dir;
+
+		if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min))
+			dir = -1;
+		else
+			dir = 1;
+
+		swid = src->width*sizeof(ulong);
+		dwid = dst->width*sizeof(ulong);
+		sp = byteaddr(src, par->sr.min);
+		dp = byteaddr(dst, par->r.min);
+		if(dir == -1){
+			sp += (dy-1)*swid;
+			dp += (dy-1)*dwid;
+			swid = -swid;
+			dwid = -dwid;
+		}
+		nb = (dx*src->depth)/8;
+		for(y=0; y<dy; y++, sp+=swid, dp+=dwid)
+			memmove(dp, sp, nb);
+		return 1;
+	}
+
+	/*
+	 * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and
+	 * they're all bit aligned, we can just use bit operators.  This happens
+	 * when we're manipulating boolean masks, e.g. in the arc code.
+	 */
+	if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0 
+	&& dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1 
+	&& (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){
+		uchar *sp, *dp, *mp;
+		uchar lm, rm;
+		long swid, dwid, mwid;
+		int i, x, dir;
+
+		sp = byteaddr(src, par->sr.min);
+		dp = byteaddr(dst, par->r.min);
+		mp = byteaddr(par->mask, par->mr.min);
+		swid = src->width*sizeof(ulong);
+		dwid = dst->width*sizeof(ulong);
+		mwid = par->mask->width*sizeof(ulong);
+
+		if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){
+			dir = -1;
+		}else
+			dir = 1;
+
+		lm = 0xFF>>(par->r.min.x&7);
+		rm = 0xFF<<(8-(par->r.max.x&7));
+		dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7);
+
+		if(dx < 0){	/* one byte wide */
+			lm &= rm;
+			if(dir == -1){
+				dp += dwid*(dy-1);
+				sp += swid*(dy-1);
+				mp += mwid*(dy-1);
+				dwid = -dwid;
+				swid = -swid;
+				mwid = -mwid;
+			}
+			for(y=0; y<dy; y++){
+				*dp ^= (*dp ^ *sp) & *mp & lm;
+				dp += dwid;
+				sp += swid;
+				mp += mwid;
+			}
+			return 1;
+		}
+
+		dx /= 8;
+		if(dir == 1){
+			i = (lm!=0)+dx+(rm!=0);
+			mwid -= i;
+			swid -= i;
+			dwid -= i;
+			for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
+				if(lm){
+					*dp ^= (*dp ^ *sp++) & *mp++ & lm;
+					dp++;
+				}
+				for(x=0; x<dx; x++){
+					*dp ^= (*dp ^ *sp++) & *mp++;
+					dp++;
+				}
+				if(rm){
+					*dp ^= (*dp ^ *sp++) & *mp++ & rm;
+					dp++;
+				}
+			}
+			return 1;
+		}else{
+		/* dir == -1 */
+			i = (lm!=0)+dx+(rm!=0);
+			dp += dwid*(dy-1)+i-1;
+			sp += swid*(dy-1)+i-1;
+			mp += mwid*(dy-1)+i-1;
+			dwid = -dwid+i;
+			swid = -swid+i;
+			mwid = -mwid+i;
+			for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
+				if(rm){
+					*dp ^= (*dp ^ *sp--) & *mp-- & rm;
+					dp--;
+				}
+				for(x=0; x<dx; x++){
+					*dp ^= (*dp ^ *sp--) & *mp--;
+					dp--;
+				}
+				if(lm){
+					*dp ^= (*dp ^ *sp--) & *mp-- & lm;
+					dp--;
+				}
+			}
+		}
+		return 1;
+	}
+	return 0;	
+}
+#undef DBG
+
+/*
+ * Boolean character drawing.
+ * Solid opaque color through a 1-bit greyscale mask.
+ */
+#define DBG if(0)
+static int
+chardraw(Memdrawparam *par)
+{
+	ulong bits;
+	int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth, op;
+	ulong v, maskwid, dstwid;
+	uchar *wp, *rp, *q, *wc;
+	ushort *ws;
+	ulong *wl;
+	uchar sp[4];
+	Rectangle r, mr;
+	Memimage *mask, *src, *dst;
+
+if(0) if(drawdebug) iprint("chardraw? mf %lux md %d sf %lux dxs %d dys %d dd %d ddat %p sdat %p\n",
+		par->mask->flags, par->mask->depth, par->src->flags, 
+		Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data);
+
+	mask = par->mask;
+	src = par->src;
+	dst = par->dst;
+	r = par->r;
+	mr = par->mr;
+	op = par->op;
+
+	if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc)
+	|| mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data
+	|| op != SoverD)
+		return 0;
+
+//if(drawdebug) iprint("chardraw...");
+
+	depth = mask->depth;
+	maskwid = mask->width*sizeof(ulong);
+	rp = byteaddr(mask, mr.min);
+	npack = 8/depth;
+	bsh = (mr.min.x % npack) * depth;
+
+	wp = byteaddr(dst, r.min);
+	dstwid = dst->width*sizeof(ulong);
+DBG print("bsh %d\n", bsh);
+	dy = Dy(r);
+	dx = Dx(r);
+
+	ddepth = dst->depth;
+
+	/*
+	 * for loop counts from bsh to bsh+dx
+	 *
+	 * we want the bottom bits to be the amount
+	 * to shift the pixels down, so for n≡0 (mod 8) we want 
+	 * bottom bits 7.  for n≡1, 6, etc.
+	 * the bits come from -n-1.
+	 */
+
+	bx = -bsh-1;
+	ex = -bsh-1-dx;
+	bits = 0;
+	v = par->sdval;
+
+	/* make little endian */
+	sp[0] = v;
+	sp[1] = v>>8;
+	sp[2] = v>>16;
+	sp[3] = v>>24;
+
+//print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]);
+	for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){
+		q = rp;
+		if(bsh)
+			bits = *q++;
+		switch(ddepth){
+		case 8:
+//if(drawdebug) iprint("8loop...");
+			wc = wp;
+			for(x=bx; x>ex; x--, wc++){
+				i = x&7;
+				if(i == 8-1)
+					bits = *q++;
+DBG print("bits %lux sh %d...", bits, i);
+				if((bits>>i)&1)
+					*wc = v;
+			}
+			break;
+		case 16:
+			ws = (ushort*)wp;
+			v = *(ushort*)sp;
+			for(x=bx; x>ex; x--, ws++){
+				i = x&7;
+				if(i == 8-1)
+					bits = *q++;
+DBG print("bits %lux sh %d...", bits, i);
+				if((bits>>i)&1)
+					*ws = v;
+			}
+			break;
+		case 24:
+			wc = wp;
+			for(x=bx; x>ex; x--, wc+=3){
+				i = x&7;
+				if(i == 8-1)
+					bits = *q++;
+DBG print("bits %lux sh %d...", bits, i);
+				if((bits>>i)&1){
+					wc[0] = sp[0];
+					wc[1] = sp[1];
+					wc[2] = sp[2];
+				}
+			}
+			break;
+		case 32:
+			wl = (ulong*)wp;
+			v = *(ulong*)sp;
+			for(x=bx; x>ex; x--, wl++){
+				i = x&7;
+				if(i == 8-1)
+					bits = *q++;
+DBG iprint("bits %lux sh %d...", bits, i);
+				if((bits>>i)&1)
+					*wl = v;
+			}
+			break;
+		}
+	}
+
+DBG print("\n");	
+	return 1;	
+}
+#undef DBG
+
+
+/*
+ * Fill entire byte with replicated (if necessary) copy of source pixel,
+ * assuming destination ldepth is >= source ldepth.
+ *
+ * This code is just plain wrong for >8bpp.
+ *
+ulong
+membyteval(Memimage *src)
+{
+	int i, val, bpp;
+	uchar uc;
+
+	unloadmemimage(src, src->r, &uc, 1);
+	bpp = src->depth;
+	uc <<= (src->r.min.x&(7/src->depth))*src->depth;
+	uc &= ~(0xFF>>bpp);
+	// pixel value is now in high part of byte. repeat throughout byte 
+	val = uc;
+	for(i=bpp; i<8; i<<=1)
+		val |= val>>i;
+	return val;
+}
+ * 
+ */
+
+void
+memfillcolor(Memimage *i, ulong val)
+{
+	ulong bits;
+	int d, y;
+	uchar p[4];
+
+	if(val == DNofill)
+		return;
+
+	bits = rgbatoimg(i, val);
+	switch(i->depth){
+	case 24:	/* 24-bit images suck */
+		for(y=i->r.min.y; y<i->r.max.y; y++)
+			memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r));
+		break;
+	default:	/* 1, 2, 4, 8, 16, 32 */
+		for(d=i->depth; d<32; d*=2)
+			bits = (bits << d) | bits;
+		p[0] = bits;		/* make little endian */
+		p[1] = bits>>8;
+		p[2] = bits>>16;
+		p[3] = bits>>24;
+		bits = *(u32int*)p;
+		memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r));
+		break;
+	}
+}
+
--- /dev/null
+++ b/libmemdraw/drawtest.c
@@ -1,0 +1,1003 @@
+#include "lib9.h"
+#include "bio.h"
+#include "draw.h"
+#include "memdraw.h"
+
+#define DBG if(0)
+#define RGB2K(r,g,b)	((299*((ulong)(r))+587*((ulong)(g))+114*((ulong)(b)))/1000)
+
+/*
+ * This program tests the 'memimagedraw' primitive stochastically.
+ * It tests the combination aspects of it thoroughly, but since the
+ * three images it uses are disjoint, it makes no check of the
+ * correct behavior when images overlap.  That is, however, much
+ * easier to get right and to test.
+ */
+
+void	drawonepixel(Memimage*, Point, Memimage*, Point, Memimage*, Point);
+void	verifyone(void);
+void	verifyline(void);
+void	verifyrect(void);
+void	verifyrectrepl(int, int);
+void putpixel(Memimage *img, Point pt, ulong nv);
+ulong rgbatopix(uchar, uchar, uchar, uchar);
+
+char *dchan, *schan, *mchan;
+int dbpp, sbpp, mbpp;
+
+int drawdebug=0;
+int	seed;
+int	niters = 100;
+int	dbpp;	/* bits per pixel in destination */
+int	sbpp;	/* bits per pixel in src */
+int	mbpp;	/* bits per pixel in mask */
+int	dpm;	/* pixel mask at high part of byte, in destination */
+int	nbytes;	/* in destination */
+
+int	Xrange	= 64;
+int	Yrange	= 8;
+
+Memimage	*dst;
+Memimage	*src;
+Memimage	*mask;
+Memimage	*stmp;
+Memimage	*mtmp;
+Memimage	*ones;
+uchar	*dstbits;
+uchar	*srcbits;
+uchar	*maskbits;
+ulong	*savedstbits;
+
+void
+rdb(void)
+{
+}
+
+int
+iprint(char *fmt, ...)
+{
+	int n;	
+	va_list va;
+	char buf[1024];
+
+	va_start(va, fmt);
+	n = doprint(buf, buf+sizeof buf, fmt, va) - buf;
+	va_end(va);
+
+	write(1,buf,n);
+	return 1;
+}
+
+void
+main(int argc, char *argv[])
+{
+	memimageinit();
+	seed = time(0);
+
+	ARGBEGIN{
+	case 'x':
+		Xrange = atoi(ARGF());
+		break;
+	case 'y':
+		Yrange = atoi(ARGF());
+		break;
+	case 'n':
+		niters = atoi(ARGF());
+		break;
+	case 's':
+		seed = atoi(ARGF());
+		break;
+	}ARGEND
+
+	dchan = "r8g8b8";
+	schan = "r8g8b8";
+	mchan = "r8g8b8";
+	switch(argc){
+	case 3:	mchan = argv[2];
+	case 2:	schan = argv[1];
+	case 1:	dchan = argv[0];
+	case 0:	break;
+	default:	goto Usage;
+	Usage:
+		fprint(2, "usage: dtest [dchan [schan [mchan]]]\n");
+		exits("usage");
+	}
+
+	fmtinstall('b', numbconv);	/* binary! */
+
+	fprint(2, "%s -x %d -y %d -s 0x%x %s %s %s\n", argv0, Xrange, Yrange, seed, dchan, schan, mchan);
+	srand(seed);
+
+	dst = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(dchan));
+	src = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
+	mask = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
+	stmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
+	mtmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
+	ones = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
+//	print("chan %lux %lux %lux %lux %lux %lux\n", dst->chan, src->chan, mask->chan, stmp->chan, mtmp->chan, ones->chan);
+	if(dst==0 || src==0 || mask==0 || mtmp==0 || ones==0) {
+	Alloc:
+		fprint(2, "dtest: allocation failed: %r\n");
+		exits("alloc");
+	}
+	nbytes = (4*Xrange+4)*Yrange;
+	srcbits = malloc(nbytes);
+	dstbits = malloc(nbytes);
+	maskbits = malloc(nbytes);
+	savedstbits = malloc(nbytes);
+	if(dstbits==0 || srcbits==0 || maskbits==0 || savedstbits==0)
+		goto Alloc;
+	dbpp = dst->depth;
+	sbpp = src->depth;
+	mbpp = mask->depth;
+	dpm = 0xFF ^ (0xFF>>dbpp);
+	memset(ones->data->bdata, 0xFF, ones->width*sizeof(ulong)*Yrange);
+
+
+	fprint(2, "dtest: verify single pixel operation\n");
+	verifyone();
+
+	fprint(2, "dtest: verify full line non-replicated\n");
+	verifyline();
+
+	fprint(2, "dtest: verify full rectangle non-replicated\n");
+	verifyrect();
+
+	fprint(2, "dtest: verify full rectangle source replicated\n");
+	verifyrectrepl(1, 0);
+
+	fprint(2, "dtest: verify full rectangle mask replicated\n");
+	verifyrectrepl(0, 1);
+
+	fprint(2, "dtest: verify full rectangle source and mask replicated\n");
+	verifyrectrepl(1, 1);
+
+	exits(0);
+}
+
+/*
+ * Dump out an ASCII representation of an image.  The label specifies
+ * a list of characters to put at various points in the picture.
+ */
+static void
+Bprintr5g6b5(Biobuf *bio, char*, ulong v)
+{
+	int r,g,b;
+	r = (v>>11)&31;
+	g = (v>>5)&63;
+	b = v&31;
+	Bprint(bio, "%.2x%.2x%.2x", r,g,b);
+}
+
+static void
+Bprintr5g5b5a1(Biobuf *bio, char*, ulong v)
+{
+	int r,g,b,a;
+	r = (v>>11)&31;
+	g = (v>>6)&31;
+	b = (v>>1)&31;
+	a = v&1;
+	Bprint(bio, "%.2x%.2x%.2x%.2x", r,g,b,a);
+}
+
+void
+dumpimage(char *name, Memimage *img, void *vdata, Point labelpt)
+{
+	Biobuf b;
+	uchar *data;
+	uchar *p;
+	char *arg;
+	void (*fmt)(Biobuf*, char*, ulong);
+	int npr, x, y, nb, bpp;
+	ulong v, mask;
+	Rectangle r;
+
+	fmt = nil;
+	arg = nil;
+	switch(img->depth){
+	case 1:
+	case 2:
+	case 4:
+		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+		arg = "%.1ux";
+		break;
+	case 8:
+		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+		arg = "%.2ux";
+		break;
+	case 16:
+		arg = nil;
+		if(img->chan == RGB16)
+			fmt = Bprintr5g6b5;
+		else{
+			fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+			arg = "%.4ux";
+		}
+		break;
+	case 24:
+		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+		arg = "%.6lux";
+		break;
+	case 32:
+		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
+		arg = "%.8lux";
+		break;
+	}
+	if(fmt == nil){
+		fprint(2, "bad format\n");
+		abort();
+	}
+
+	r  = img->r;
+	Binit(&b, 2, OWRITE);
+	data = vdata;
+	bpp = img->depth;
+	Bprint(&b, "%s\t%d\tr %R clipr %R repl %d data %p *%P\n", name, r.min.x, r, img->clipr, (img->flags&Frepl) ? 1 : 0, vdata, labelpt);
+	mask = (1ULL<<bpp)-1;
+//	for(y=r.min.y; y<r.max.y; y++){
+	for(y=0; y<Yrange; y++){
+		nb = 0;
+		v = 0;
+		p = data+(byteaddr(img, Pt(0,y))-(uchar*)img->data->bdata);
+		Bprint(&b, "%-4d\t", y);
+//		for(x=r.min.x; x<r.max.x; x++){
+		for(x=0; x<Xrange; x++){
+			if(x==0)
+				Bprint(&b, "\t");
+
+			if(x != 0 && (x%8)==0)
+				Bprint(&b, " ");
+
+			npr = 0;
+			if(x==labelpt.x && y==labelpt.y){
+				Bprint(&b, "*");
+				npr++;
+			}
+			if(npr == 0)
+				Bprint(&b, " ");
+
+			while(nb < bpp){
+				v &= (1<<nb)-1;
+				v |= (ulong)(*p++) << nb;
+				nb += 8;
+			}
+			nb -= bpp;
+//			print("bpp %d v %.8lux mask %.8lux nb %d\n", bpp, v, mask, nb);
+			fmt(&b, arg, (v>>nb)&mask);
+		}
+		Bprint(&b, "\n");
+	}
+	Bterm(&b);
+}
+
+/*
+ * Verify that the destination pixel has the specified value.
+ * The value is in the high bits of v, suitably masked, but must
+ * be extracted from the destination Memimage.
+ */
+void
+checkone(Point p, Point sp, Point mp)
+{
+	int delta;
+	uchar *dp, *sdp;
+
+	delta = (uchar*)byteaddr(dst, p)-(uchar*)dst->data->bdata;
+	dp = (uchar*)dst->data->bdata+delta;
+	sdp = (uchar*)savedstbits+delta;
+
+	if(memcmp(dp, sdp, (dst->depth+7)/8) != 0) {
+		fprint(2, "dtest: one bad pixel drawing at dst %P from source %P mask %P\n", p, sp, mp);
+		fprint(2, " %.2ux %.2ux %.2ux %.2ux should be %.2ux %.2ux %.2ux %.2ux\n",
+			dp[0], dp[1], dp[2], dp[3], sdp[0], sdp[1], sdp[2], sdp[3]);
+		fprint(2, "addresses dst %p src %p mask %p\n", dp, byteaddr(src, sp), byteaddr(mask, mp));
+		dumpimage("src", src, src->data->bdata, sp);
+		dumpimage("mask", mask, mask->data->bdata, mp);
+		dumpimage("origdst", dst, dstbits, p);
+		dumpimage("dst", dst, dst->data->bdata, p);
+		dumpimage("gooddst", dst, savedstbits, p);
+		abort();
+	}
+}
+
+/*
+ * Verify that the destination line has the same value as the saved line.
+ */
+#define RECTPTS(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y
+void
+checkline(Rectangle r, Point sp, Point mp, int y, Memimage *stmp, Memimage *mtmp)
+{
+	ulong *dp;
+	int nb;
+	ulong *saved;
+
+	dp = wordaddr(dst, Pt(0, y));
+	saved = savedstbits + y*dst->width;
+	if(dst->depth < 8)
+		nb = Xrange/(8/dst->depth);
+	else
+		nb = Xrange*(dst->depth/8);
+	if(memcmp(dp, saved, nb) != 0){
+		fprint(2, "dtest: bad line at y=%d; saved %p dp %p\n", y, saved, dp);
+		fprint(2, "draw dst %R src %P mask %P\n", r, sp, mp);
+		dumpimage("src", src, src->data->bdata, sp);
+		if(stmp) dumpimage("stmp", stmp, stmp->data->bdata, sp);
+		dumpimage("mask", mask, mask->data->bdata, mp);
+		if(mtmp) dumpimage("mtmp", mtmp, mtmp->data->bdata, mp);
+		dumpimage("origdst", dst, dstbits, r.min);
+		dumpimage("dst", dst, dst->data->bdata, r.min);
+		dumpimage("gooddst", dst, savedstbits, r.min);
+		abort();
+	}
+}
+
+/*
+ * Fill the bits of an image with random data.
+ * The Memimage parameter is used only to make sure
+ * the data is well formatted: only ucbits is written.
+ */
+void
+fill(Memimage *img, uchar *ucbits)
+{
+	int i, x, y;
+	ushort *up;
+	uchar alpha, r, g, b;
+	void *data;
+
+	if((img->flags&Falpha) == 0){
+		up = (ushort*)ucbits;
+		for(i=0; i<nbytes/2; i++)
+			*up++ = lrand() >> 7;
+		if(i+i != nbytes)
+			*(uchar*)up = lrand() >> 7;
+	}else{
+		data = img->data->bdata;
+		img->data->bdata = ucbits;
+
+		for(x=img->r.min.x; x<img->r.max.x; x++)
+		for(y=img->r.min.y; y<img->r.max.y; y++){
+			alpha = rand() >> 4;
+			r = rand()%(alpha+1);
+			g = rand()%(alpha+1);
+			b = rand()%(alpha+1);
+			putpixel(img, Pt(x,y), rgbatopix(r,g,b,alpha));
+		}
+		img->data->bdata = data;
+	}
+		
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifyonemask(void)
+{
+	Point dp, sp, mp;
+
+	fill(dst, dstbits);
+	fill(src, srcbits);
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+	dp.x = nrand(Xrange);
+	dp.y = nrand(Yrange);
+
+	sp.x = nrand(Xrange);
+	sp.y = nrand(Yrange);
+
+	mp.x = nrand(Xrange);
+	mp.y = nrand(Yrange);
+
+	drawonepixel(dst, dp, src, sp, mask, mp);
+	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+	
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+	memimagedraw(dst, Rect(dp.x, dp.y, dp.x+1, dp.y+1), src, sp, mask, mp, SoverD);
+	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+	checkone(dp, sp, mp);
+}
+
+void
+verifyone(void)
+{
+	int i;
+
+	/* mask all zeros */
+	memset(maskbits, 0, nbytes);
+	for(i=0; i<niters; i++)
+		verifyonemask();
+
+	/* mask all ones */
+	memset(maskbits, 0xFF, nbytes);
+	for(i=0; i<niters; i++)
+		verifyonemask();
+
+	/* random mask */
+	for(i=0; i<niters; i++){
+		fill(mask, maskbits);
+		verifyonemask();
+	}
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifylinemask(void)
+{
+	Point sp, mp, tp, up;
+	Rectangle dr;
+	int x;
+
+	fill(dst, dstbits);
+	fill(src, srcbits);
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+	dr.min.x = nrand(Xrange-1);
+	dr.min.y = nrand(Yrange-1);
+	dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
+	dr.max.y = dr.min.y + 1;
+
+	sp.x = nrand(Xrange);
+	sp.y = nrand(Yrange);
+
+	mp.x = nrand(Xrange);
+	mp.y = nrand(Yrange);
+
+	tp = sp;
+	up = mp;
+	for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
+		memimagedraw(dst, Rect(x, dr.min.y, x+1, dr.min.y+1), src, tp, mask, up, SoverD);
+	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+
+	memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
+	checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), dr.min.y, nil, nil);
+}
+
+void
+verifyline(void)
+{
+	int i;
+
+	/* mask all ones */
+	memset(maskbits, 0xFF, nbytes);
+	for(i=0; i<niters; i++)
+		verifylinemask();
+
+	/* mask all zeros */
+	memset(maskbits, 0, nbytes);
+	for(i=0; i<niters; i++)
+		verifylinemask();
+
+	/* random mask */
+	for(i=0; i<niters; i++){
+		fill(mask, maskbits);
+		verifylinemask();
+	}
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifyrectmask(void)
+{
+	Point sp, mp, tp, up;
+	Rectangle dr;
+	int x, y;
+
+	fill(dst, dstbits);
+	fill(src, srcbits);
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+	dr.min.x = nrand(Xrange-1);
+	dr.min.y = nrand(Yrange-1);
+	dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
+	dr.max.y = dr.min.y + 1 + nrand(Yrange-1-dr.min.y);
+
+	sp.x = nrand(Xrange);
+	sp.y = nrand(Yrange);
+
+	mp.x = nrand(Xrange);
+	mp.y = nrand(Yrange);
+
+	tp = sp;
+	up = mp;
+	for(y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++){
+		for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
+			memimagedraw(dst, Rect(x, y, x+1, y+1), src, tp, mask, up, SoverD);
+		tp.x = sp.x;
+		up.x = mp.x;
+	}
+	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+
+	memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
+	for(y=0; y<Yrange; y++)
+		checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, nil, nil);
+}
+
+void
+verifyrect(void)
+{
+	int i;
+
+	/* mask all zeros */
+	memset(maskbits, 0, nbytes);
+	for(i=0; i<niters; i++)
+		verifyrectmask();
+
+	/* mask all ones */
+	memset(maskbits, 0xFF, nbytes);
+	for(i=0; i<niters; i++)
+		verifyrectmask();
+
+	/* random mask */
+	for(i=0; i<niters; i++){
+		fill(mask, maskbits);
+		verifyrectmask();
+	}
+}
+
+Rectangle
+randrect(void)
+{
+	Rectangle r;
+
+	r.min.x = nrand(Xrange-1);
+	r.min.y = nrand(Yrange-1);
+	r.max.x = r.min.x + 1 + nrand(Xrange-1-r.min.x);
+	r.max.y = r.min.y + 1 + nrand(Yrange-1-r.min.y);
+	return r;
+}
+
+/*
+ * Return coordinate corresponding to x withing range [minx, maxx)
+ */
+int
+tilexy(int minx, int maxx, int x)
+{
+	int sx;
+
+	sx = (x-minx) % (maxx-minx);
+	if(sx < 0)
+		sx += maxx-minx;
+	return sx+minx;
+}
+
+void
+replicate(Memimage *i, Memimage *tmp)
+{
+	Rectangle r, r1;
+	int x, y, nb;
+
+	/* choose the replication window (i->r) */
+	r.min.x = nrand(Xrange-1);
+	r.min.y = nrand(Yrange-1);
+	/* make it trivial more often than pure chance allows */
+	switch(lrand()&0){
+	case 1:
+		r.max.x = r.min.x + 2;
+		r.max.y = r.min.y + 2;
+		if(r.max.x < Xrange && r.max.y < Yrange)
+			break;
+		/* fall through */
+	case 0:
+		r.max.x = r.min.x + 1;
+		r.max.y = r.min.y + 1;
+		break;
+	default:
+		if(r.min.x+3 >= Xrange)
+			r.max.x = Xrange;
+		else
+			r.max.x = r.min.x+3 + nrand(Xrange-(r.min.x+3));
+
+		if(r.min.y+3 >= Yrange)
+			r.max.y = Yrange;
+		else
+			r.max.y = r.min.y+3 + nrand(Yrange-(r.min.y+3));
+	}
+	assert(r.min.x >= 0);	
+	assert(r.max.x <= Xrange);
+	assert(r.min.y >= 0);
+	assert(r.max.y <= Yrange);
+	/* copy from i to tmp so we have just the replicated bits */
+	nb = tmp->width*sizeof(ulong)*Yrange;
+	memset(tmp->data->bdata, 0, nb);
+	memimagedraw(tmp, r, i, r.min, ones, r.min, SoverD);
+	memmove(i->data->bdata, tmp->data->bdata, nb);
+	/* i is now a non-replicated instance of the replication */
+	/* replicate it by hand through tmp */
+	memset(tmp->data->bdata, 0, nb);
+	x = -(tilexy(r.min.x, r.max.x, 0)-r.min.x);
+	for(; x<Xrange; x+=Dx(r)){
+		y = -(tilexy(r.min.y, r.max.y, 0)-r.min.y);
+		for(; y<Yrange; y+=Dy(r)){
+			/* set r1 to instance of tile by translation */
+			r1.min.x = x;
+			r1.min.y = y;
+			r1.max.x = r1.min.x+Dx(r);
+			r1.max.y = r1.min.y+Dy(r);
+			memimagedraw(tmp, r1, i, r.min, ones, r.min, SoverD);
+		}
+	}
+	i->flags |= Frepl;
+	i->r = r;
+	i->clipr = randrect();
+//	fprint(2, "replicate [[%d %d] [%d %d]] [[%d %d][%d %d]]\n", r.min.x, r.min.y, r.max.x, r.max.y,
+//		i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
+	tmp->clipr = i->clipr;
+}
+
+/*
+ * Mask is preset; do the rest
+ */
+void
+verifyrectmaskrepl(int srcrepl, int maskrepl)
+{
+	Point sp, mp, tp, up;
+	Rectangle dr;
+	int x, y;
+	Memimage *s, *m;
+
+//	print("verfrect %d %d\n", srcrepl, maskrepl);
+	src->flags &= ~Frepl;
+	src->r = Rect(0, 0, Xrange, Yrange);
+	src->clipr = src->r;
+	stmp->flags &= ~Frepl;
+	stmp->r = Rect(0, 0, Xrange, Yrange);
+	stmp->clipr = src->r;
+	mask->flags &= ~Frepl;
+	mask->r = Rect(0, 0, Xrange, Yrange);
+	mask->clipr = mask->r;
+	mtmp->flags &= ~Frepl;
+	mtmp->r = Rect(0, 0, Xrange, Yrange);
+	mtmp->clipr = mask->r;
+
+	fill(dst, dstbits);
+	fill(src, srcbits);
+
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
+	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
+
+	if(srcrepl){
+		replicate(src, stmp);
+		s = stmp;
+	}else
+		s = src;
+	if(maskrepl){
+		replicate(mask, mtmp);
+		m = mtmp;
+	}else
+		m = mask;
+
+	dr = randrect();
+
+	sp.x = nrand(Xrange);
+	sp.y = nrand(Yrange);
+
+	mp.x = nrand(Xrange);
+	mp.y = nrand(Yrange);
+
+DBG	print("smalldraws\n");
+	for(tp.y=sp.y,up.y=mp.y,y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++)
+		for(tp.x=sp.x,up.x=mp.x,x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
+			memimagedraw(dst, Rect(x, y, x+1, y+1), s, tp, m, up, SoverD);
+	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
+
+	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
+
+DBG	print("bigdraw\n");
+	memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
+	for(y=0; y<Yrange; y++)
+		checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, srcrepl?stmp:nil, maskrepl?mtmp:nil);
+}
+
+void
+verifyrectrepl(int srcrepl, int maskrepl)
+{
+	int i;
+
+	/* mask all ones */
+	memset(maskbits, 0xFF, nbytes);
+	for(i=0; i<niters; i++)
+		verifyrectmaskrepl(srcrepl, maskrepl);
+
+	/* mask all zeros */
+	memset(maskbits, 0, nbytes);
+	for(i=0; i<niters; i++)
+		verifyrectmaskrepl(srcrepl, maskrepl);
+
+	/* random mask */
+	for(i=0; i<niters; i++){
+		fill(mask, maskbits);
+		verifyrectmaskrepl(srcrepl, maskrepl);
+	}
+}
+
+/*
+ * Trivial draw implementation.
+ * Color values are passed around as ulongs containing ααRRGGBB
+ */
+
+/*
+ * Convert v, which is nhave bits wide, into its nwant bits wide equivalent.
+ * Replicates to widen the value, truncates to narrow it.
+ */
+ulong
+replbits(ulong v, int nhave, int nwant)
+{
+	v &= (1<<nhave)-1;
+	for(; nhave<nwant; nhave*=2)
+		v |= v<<nhave;
+	v >>= (nhave-nwant);
+	return v & ((1<<nwant)-1);
+}
+
+/*
+ * Decode a pixel into the uchar* values.
+ */
+void
+pixtorgba(ulong v, uchar *r, uchar *g, uchar *b, uchar *a)
+{
+	*a = v>>24;
+	*r = v>>16;
+	*g = v>>8;
+	*b = v;
+}
+
+/*
+ * Convert uchar channels into ulong pixel.
+ */
+ulong
+rgbatopix(uchar r, uchar g, uchar b, uchar a)
+{
+	return (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+/*
+ * Retrieve the pixel value at pt in the image.
+ */
+ulong
+getpixel(Memimage *img, Point pt)
+{
+	uchar r, g, b, a, *p;
+	int nbits, npack, bpp;
+	ulong v, c, rbits, bits;
+
+	r = g = b = 0;
+	a = ~0;	/* default alpha is full */
+
+	p = byteaddr(img, pt);
+	v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+	bpp = img->depth;
+	if(bpp<8){
+		/*
+		 * Sub-byte greyscale pixels.
+		 *
+		 * We want to throw away the top pt.x%npack pixels and then use the next bpp bits
+		 * in the bottom byte of v.  This madness is due to having big endian bits
+		 * but little endian bytes.
+		 */
+		npack = 8/bpp;
+		v >>= 8 - bpp*(pt.x%npack+1);
+		v &= (1<<bpp)-1;
+		r = g = b = replbits(v, bpp, 8);
+	}else{
+		/*
+		 * General case.  We need to parse the channel descriptor and do what it says.
+		 * In all channels but the color map, we replicate to 8 bits because that's the
+		 * precision that all calculations are done at.
+		 *
+		 * In the case of the color map, we leave the bits alone, in case a color map
+		 * with less than 8 bits of index is used.  This is currently disallowed, so it's
+		 * sort of silly.
+		 */
+
+		for(c=img->chan; c; c>>=8){
+			nbits = NBITS(c);
+			bits = v & ((1<<nbits)-1);
+			rbits = replbits(bits, nbits, 8);
+			v >>= nbits;
+			switch(TYPE(c)){
+			case CRed:
+				r = rbits;
+				break;
+			case CGreen:
+				g = rbits;
+				break;
+			case CBlue:
+				b = rbits;
+				break;
+			case CGrey:
+				r = g = b = rbits;
+				break;
+			case CAlpha:
+				a = rbits;
+				break;
+			case CMap:
+				p = img->cmap->cmap2rgb + 3*bits;
+				r = p[0];
+				g = p[1];
+				b = p[2];
+				break;
+			case CIgnore:
+				break;
+			default:
+				fprint(2, "unknown channel type %lud\n", TYPE(c));
+				abort();
+			}
+		}
+	}
+	return rgbatopix(r, g, b, a);
+}
+
+/*
+ * Return the greyscale equivalent of a pixel.
+ */
+uchar
+getgrey(Memimage *img, Point pt)
+{
+	uchar r, g, b, a;
+	pixtorgba(getpixel(img, pt), &r, &g, &b, &a);
+	return RGB2K(r, g, b);
+}
+
+/*
+ * Return the value at pt in image, if image is interpreted
+ * as a mask.  This means the alpha channel if present, else
+ * the greyscale or its computed equivalent.
+ */
+uchar
+getmask(Memimage *img, Point pt)
+{
+	if(img->flags&Falpha)
+		return getpixel(img, pt)>>24;
+	else
+		return getgrey(img, pt);
+}
+#undef DBG
+
+#define DBG if(0)
+/*
+ * Write a pixel to img at point pt.
+ * 
+ * We do this by reading a 32-bit little endian
+ * value from p and then writing it back
+ * after tweaking the appropriate bits.  Because
+ * the data is little endian, we don't have to worry
+ * about what the actual depth is, as long as it is
+ * less than 32 bits.
+ */
+void
+putpixel(Memimage *img, Point pt, ulong nv)
+{
+	uchar r, g, b, a, *p, *q;
+	ulong c, mask, bits, v;
+	int bpp, sh, npack, nbits;
+
+	pixtorgba(nv, &r, &g, &b, &a);
+
+	p = byteaddr(img, pt);
+	v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+	bpp = img->depth;
+DBG print("v %.8lux...", v);
+	if(bpp < 8){
+		/*
+		 * Sub-byte greyscale pixels.  We need to skip the leftmost pt.x%npack pixels,
+		 * which is equivalent to skipping the rightmost npack - pt.x%npack - 1 pixels.
+		 */	
+		npack = 8/bpp;
+		sh = bpp*(npack - pt.x%npack - 1);
+		bits = RGB2K(r,g,b);
+DBG print("repl %lux 8 %d = %lux...", bits, bpp, replbits(bits, 8, bpp));
+		bits = replbits(bits, 8, bpp);
+		mask = (1<<bpp)-1;
+DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
+		mask <<= sh;
+		bits <<= sh;
+DBG print("(%lux & %lux) | (%lux & %lux)", v, ~mask, bits, mask);
+		v = (v & ~mask) | (bits & mask);
+	} else {
+		/*
+		 * General case.  We need to parse the channel descriptor again.
+		 */
+		sh = 0;
+		for(c=img->chan; c; c>>=8){
+			nbits = NBITS(c);
+			switch(TYPE(c)){
+			case CRed:
+				bits = r;
+				break;
+			case CGreen:
+				bits = g;
+				break;
+			case CBlue:
+				bits = b;
+				break;
+			case CGrey:
+				bits = RGB2K(r, g, b);
+				break;
+			case CAlpha:
+				bits = a;
+				break;
+			case CIgnore:
+				bits = 0;
+				break;
+			case CMap:
+				q = img->cmap->rgb2cmap;
+				bits = q[(r>>4)*16*16+(g>>4)*16+(b>>4)];
+				break;
+			default:
+				SET(bits);
+				fprint(2, "unknown channel type %lud\n", TYPE(c));
+				abort();
+			}
+
+DBG print("repl %lux 8 %d = %lux...", bits, nbits, replbits(bits, 8, nbits));
+			if(TYPE(c) != CMap)
+				bits = replbits(bits, 8, nbits);
+			mask = (1<<nbits)-1;
+DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
+			bits <<= sh;
+			mask <<= sh;
+			v = (v & ~mask) | (bits & mask);
+			sh += nbits;
+		}
+	}
+DBG print("v %.8lux\n", v);
+	p[0] = v;
+	p[1] = v>>8;
+	p[2] = v>>16;
+	p[3] = v>>24;	
+}
+#undef DBG
+
+#define DBG if(0)
+void
+drawonepixel(Memimage *dst, Point dp, Memimage *src, Point sp, Memimage *mask, Point mp)
+{
+	uchar m, M, sr, sg, sb, sa, sk, dr, dg, db, da, dk;
+
+	pixtorgba(getpixel(dst, dp), &dr, &dg, &db, &da);
+	pixtorgba(getpixel(src, sp), &sr, &sg, &sb, &sa);
+	m = getmask(mask, mp);
+	M = 255-(sa*m)/255;
+
+DBG print("dst %x %x %x %x src %x %x %x %x m %x = ", dr,dg,db,da, sr,sg,sb,sa, m);
+	if(dst->flags&Fgrey){
+		/*
+		 * We need to do the conversion to grey before the alpha calculation
+		 * because the draw operator does this, and we need to be operating
+		 * at the same precision so we get exactly the same answers.
+		 */
+		sk = RGB2K(sr, sg, sb);
+		dk = RGB2K(dr, dg, db);
+		dk = (sk*m + dk*M)/255;
+		dr = dg = db = dk;
+		da = (sa*m + da*M)/255;
+	}else{
+		/*
+		 * True color alpha calculation treats all channels (including alpha)
+		 * the same.  It might have been nice to use an array, but oh well.
+		 */
+		dr = (sr*m + dr*M)/255;
+		dg = (sg*m + dg*M)/255;
+		db = (sb*m + db*M)/255;
+		da = (sa*m + da*M)/255;
+	}
+
+DBG print("%x %x %x %x\n", dr,dg,db,da);
+	putpixel(dst, dp, rgbatopix(dr, dg, db, da));
+}
--- /dev/null
+++ b/libmemdraw/ellipse.c
@@ -1,0 +1,247 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * ellipse(dst, c, a, b, t, src, sp)
+ *   draws an ellipse centered at c with semiaxes a,b>=0
+ *   and semithickness t>=0, or filled if t<0.  point sp
+ *   in src maps to c in dst
+ *
+ *   very thick skinny ellipses are brushed with circles (slow)
+ *   others are approximated by filling between 2 ellipses
+ *   criterion for very thick when b<a: t/b > 0.5*x/(1-x)
+ *   where x = b/a
+ */
+
+typedef struct Param	Param;
+typedef struct State	State;
+
+static	void	bellipse(int, State*, Param*);
+static	void	erect(int, int, int, int, Param*);
+static	void	eline(int, int, int, int, Param*);
+
+struct Param {
+	Memimage	*dst;
+	Memimage	*src;
+	Point			c;
+	int			t;
+	Point			sp;
+	Memimage	*disc;
+	int			op;
+};
+
+/*
+ * denote residual error by e(x,y) = b^2*x^2 + a^2*y^2 - a^2*b^2
+ * e(x,y) = 0 on ellipse, e(x,y) < 0 inside, e(x,y) > 0 outside
+ */
+
+struct State {
+	int	a;
+	int	x;
+	vlong	a2;	/* a^2 */
+	vlong	b2;	/* b^2 */
+	vlong	b2x;	/* b^2 * x */
+	vlong	a2y;	/* a^2 * y */
+	vlong	c1;
+	vlong	c2;	/* test criteria */
+	vlong	ee;	/* ee = e(x+1/2,y-1/2) - (a^2+b^2)/4 */
+	vlong	dxe;
+	vlong	dye;
+	vlong	d2xe;
+	vlong	d2ye;
+};
+
+static
+State*
+newstate(State *s, int a, int b)
+{
+	s->x = 0;
+	s->a = a;
+	s->a2 = (vlong)(a*a);
+	s->b2 = (vlong)(b*b);
+	s->b2x = (vlong)0;
+	s->a2y = s->a2*(vlong)b;
+	s->c1 = -((s->a2>>2) + (vlong)(a&1) + s->b2);
+	s->c2 = -((s->b2>>2) + (vlong)(b&1));
+	s->ee = -s->a2y;
+	s->dxe = (vlong)0;
+	s->dye = s->ee<<1;
+	s->d2xe = s->b2<<1;
+	s->d2ye = s->a2<<1;
+	return s;
+}
+
+/*
+ * return x coord of rightmost pixel on next scan line
+ */
+static
+int
+step(State *s)
+{
+	while(s->x < s->a) {
+		if(s->ee+s->b2x <= s->c1 ||	/* e(x+1,y-1/2) <= 0 */
+		   s->ee+s->a2y <= s->c2) {	/* e(x+1/2,y) <= 0 (rare) */
+			s->dxe += s->d2xe;	  
+			s->ee += s->dxe;	  
+			s->b2x += s->b2;
+			s->x++;	  
+			continue;
+		}
+		s->dye += s->d2ye;	  
+		s->ee += s->dye;	  
+		s->a2y -= s->a2;
+		if(s->ee-s->a2y <= s->c2) {	/* e(x+1/2,y-1) <= 0 */
+			s->dxe += s->d2xe;	  
+			s->ee += s->dxe;	  
+			s->b2x += s->b2;
+			return s->x++;
+		}
+		break;
+	}
+	return s->x;	  
+}
+
+void
+memellipse(Memimage *dst, Point c, int a, int b, int t, Memimage *src, Point sp, int op)
+{
+	State in, out;
+	int y, inb, inx, outx, u;
+	Param p;
+
+	if(a < 0)
+		a = -a;
+	if(b < 0)
+		b = -b;
+	p.dst = dst;
+	p.src = src;
+	p.c = c;
+	p.t = t;
+	p.sp = subpt(sp, c);
+	p.disc = nil;
+	p.op = op;
+
+	u = (t<<1)*(a-b);
+	if(b<a && u>b*b || a<b && -u>a*a) {
+/*	if(b<a&&(t<<1)>b*b/a || a<b&&(t<<1)>a*a/b)	# very thick */
+		bellipse(b, newstate(&in, a, b), &p);
+		return;
+	}
+
+	if(t < 0) {
+		inb = -1;
+		newstate(&out, a, y = b);
+	} else {	
+		inb = b - t;
+		newstate(&out, a+t, y = b+t);
+	}
+	if(t > 0)
+		newstate(&in, a-t, inb);
+	inx = 0;
+	for( ; y>=0; y--) {
+		outx = step(&out);
+		if(y > inb) {
+			erect(-outx, y, outx, y, &p);
+			if(y != 0)
+				erect(-outx, -y, outx, -y, &p);
+			continue;
+		}
+		if(t > 0) {
+			inx = step(&in);
+			if(y == inb)
+				inx = 0;
+		} else if(inx > outx)
+			inx = outx;
+		erect(inx, y, outx, y, &p);
+		if(y != 0)
+			erect(inx, -y, outx, -y, &p);
+		erect(-outx, y, -inx, y, &p);
+		if(y != 0)
+			erect(-outx, -y, -inx, -y, &p);
+		inx = outx + 1;
+	}
+}
+
+static Point p00 = {0, 0};
+
+/*
+ * a brushed ellipse
+ */
+static
+void
+bellipse(int y, State *s, Param *p)
+{
+	int t, ox, oy, x, nx;
+
+	t = p->t;
+	p->disc = allocmemimage(Rect(-t,-t,t+1,t+1), GREY1);
+	if(p->disc == nil)
+		return;
+	memfillcolor(p->disc, DTransparent);
+	memellipse(p->disc, p00, t, t, -1, memopaque, p00, p->op);
+	oy = y;
+	ox = 0;
+	nx = x = step(s);
+	do {
+		while(nx==x && y-->0)
+			nx = step(s);
+		y++;
+		eline(-x,-oy,-ox, -y, p);
+		eline(ox,-oy,  x, -y, p);
+		eline(-x,  y,-ox, oy, p);
+		eline(ox,  y,  x, oy, p);
+		ox = x+1;
+		x = nx;
+		y--;
+		oy = y;
+	} while(oy > 0);
+}
+
+/*
+ * a rectangle with closed (not half-open) coordinates expressed
+ * relative to the center of the ellipse
+ */
+static
+void
+erect(int x0, int y0, int x1, int y1, Param *p)
+{
+	Rectangle r;
+
+/*	print("R %d,%d %d,%d\n", x0, y0, x1, y1); /**/
+	r = Rect(p->c.x+x0, p->c.y+y0, p->c.x+x1+1, p->c.y+y1+1);
+	memdraw(p->dst, r, p->src, addpt(p->sp, r.min), memopaque, p00, p->op);
+}
+
+/*
+ * a brushed point similarly specified
+ */
+static
+void
+epoint(int x, int y, Param *p)
+{
+	Point p0;
+	Rectangle r;
+
+/*	print("P%d %d,%d\n", p->t, x, y);	/**/
+	p0 = Pt(p->c.x+x, p->c.y+y);
+	r = Rpt(addpt(p0, p->disc->r.min), addpt(p0, p->disc->r.max));
+	memdraw(p->dst, r, p->src, addpt(p->sp, r.min), p->disc, p->disc->r.min, p->op);
+}
+
+/* 
+ * a brushed horizontal or vertical line similarly specified
+ */
+static
+void
+eline(int x0, int y0, int x1, int y1, Param *p)
+{
+/*	print("L%d %d,%d %d,%d\n", p->t, x0, y0, x1, y1); /**/
+	if(x1 > x0+1)
+		erect(x0+1, y0-p->t, x1-1, y1+p->t, p);
+	else if(y1 > y0+1)
+		erect(x0-p->t, y0+1, x1+p->t, y1-1, p);
+	epoint(x0, y0, p);
+	if(x1-x0 || y1-y0)
+		epoint(x1, y1, p);
+}
--- /dev/null
+++ b/libmemdraw/fillpoly.c
@@ -1,0 +1,522 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+typedef struct Seg	Seg;
+
+struct Seg
+{
+	Point	p0;
+	Point	p1;
+	long	num;
+	long	den;
+	long	dz;
+	long	dzrem;
+	long	z;
+	long	zerr;
+	long	d;
+};
+
+static	void	zsort(Seg **seg, Seg **ep);
+static	int	ycompare(void*, void*);
+static	int	xcompare(void*, void*);
+static	int	zcompare(void*, void*);
+static	void	xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int, int, int);
+static	void	yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int, int);
+
+static void
+fillcolor(Memimage *dst, int left, int right, int y, Memimage *src, Point p)
+{
+	int srcval;
+
+	USED(src);
+	srcval = p.x;
+	p.x = left;
+	p.y = y;
+	memset(byteaddr(dst, p), srcval, right-left);
+}
+
+static void
+fillline(Memimage *dst, int left, int right, int y, Memimage *src, Point p, int op)
+{
+	Rectangle r;
+
+	r.min.x = left;
+	r.min.y = y;
+	r.max.x = right;
+	r.max.y = y+1;
+	p.x += left;
+	p.y += y;
+	memdraw(dst, r, src, p, memopaque, p, op);
+}
+
+static void
+fillpoint(Memimage *dst, int x, int y, Memimage *src, Point p, int op)
+{
+	Rectangle r;
+
+	r.min.x = x;
+	r.min.y = y;
+	r.max.x = x+1;
+	r.max.y = y+1;
+	p.x += x;
+	p.y += y;
+	memdraw(dst, r, src, p, memopaque, p, op);
+}
+
+void
+memfillpoly(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int op)
+{
+	_memfillpolysc(dst, vert, nvert, w, src, sp, 0, 0, 0, op);
+}
+
+void
+_memfillpolysc(Memimage *dst, Point *vert, int nvert, int w, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
+{
+	Seg **seg, *segtab;
+	Point p0;
+	int i;
+
+	if(nvert == 0)
+		return;
+
+	seg = malloc((nvert+2)*sizeof(Seg*));
+	if(seg == nil)
+		return;
+	segtab = malloc((nvert+1)*sizeof(Seg));
+	if(segtab == nil) {
+		free(seg);
+		return;
+	}
+
+	sp.x = (sp.x - vert[0].x) >> fixshift;
+	sp.y = (sp.y - vert[0].y) >> fixshift;
+	p0 = vert[nvert-1];
+	if(!fixshift) {
+		p0.x <<= 1;
+		p0.y <<= 1;
+	}
+	for(i = 0; i < nvert; i++) {
+		segtab[i].p0 = p0;
+		p0 = vert[i];
+		if(!fixshift) {
+			p0.x <<= 1;
+			p0.y <<= 1;
+		}
+		segtab[i].p1 = p0;
+		segtab[i].d = 1;
+	}
+	if(!fixshift)
+		fixshift = 1;
+
+	xscan(dst, seg, segtab, nvert, w, src, sp, detail, fixshift, clipped, op);
+	if(detail)
+		yscan(dst, seg, segtab, nvert, w, src, sp, fixshift, op);
+
+	free(seg);
+	free(segtab);
+}
+
+static long
+mod(long x, long y)
+{
+	long z;
+
+	z = x%y;
+	if((long)(((ulong)z)^((ulong)y)) > 0 || z == 0)
+		return z;
+	return z + y;
+}
+
+static long
+sdiv(long x, long y)
+{
+	if((long)(((ulong)x)^((ulong)y)) >= 0 || x == 0)
+		return x/y;
+
+	return (x+((y>>30)|1))/y-1;
+}
+
+static long
+smuldivmod(long x, long y, long z, long *mod)
+{
+	vlong vx;
+
+	if(x == 0 || y == 0){
+		*mod = 0;
+		return 0;
+	}
+	vx = x;
+	vx *= y;
+	*mod = vx % z;
+	if(*mod < 0)
+		*mod += z;	/* z is always >0 */
+	if((vx < 0) == (z < 0))
+		return vx/z;
+	return -((-vx)/z);
+}
+
+static void
+xscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int detail, int fixshift, int clipped, int op)
+{
+	long y, maxy, x, x2, xerr, xden, onehalf;
+	Seg **ep, **next, **p, **q, *s;
+	long n, i, iy, cnt, ix, ix2, minx, maxx;
+	Point pt;
+	void	(*fill)(Memimage*, int, int, int, Memimage*, Point, int);
+
+	fill = fillline;
+/*
+ * This can only work on 8-bit destinations, since fillcolor is
+ * just using memset on sp.x.
+ *
+ * I'd rather not even enable it then, since then if the general
+ * code is too slow, someone will come up with a better improvement
+ * than this sleazy hack.	-rsc
+ *
+	if(clipped && (src->flags&Frepl) && src->depth==8 && Dx(src->r)==1 && Dy(src->r)==1) {
+		fill = fillcolor;
+		sp.x = membyteval(src);
+	}
+ *
+ */
+	USED(clipped);
+
+
+	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
+		*p = s;
+		if(s->p0.y == s->p1.y)
+			continue;
+		if(s->p0.y > s->p1.y) {
+			pt = s->p0;
+			s->p0 = s->p1;
+			s->p1 = pt;
+			s->d = -s->d;
+		}
+		s->num = s->p1.x - s->p0.x;
+		s->den = s->p1.y - s->p0.y;
+		s->dz = sdiv(s->num, s->den) << fixshift;
+		s->dzrem = mod(s->num, s->den) << fixshift;
+		s->dz += sdiv(s->dzrem, s->den);
+		s->dzrem = mod(s->dzrem, s->den);
+		p++;
+	}
+	n = p-seg;
+	if(n == 0)
+		return;
+	*p = 0;
+	qsort(seg, p-seg , sizeof(Seg*), ycompare);
+
+	onehalf = 0;
+	if(fixshift)
+		onehalf = 1 << (fixshift-1);
+
+	minx = dst->clipr.min.x;
+	maxx = dst->clipr.max.x;
+
+	y = seg[0]->p0.y;
+	if(y < (dst->clipr.min.y << fixshift))
+		y = dst->clipr.min.y << fixshift;
+	iy = (y + onehalf) >> fixshift;
+	y = (iy << fixshift) + onehalf;
+	maxy = dst->clipr.max.y << fixshift;
+
+	ep = next = seg;
+
+	while(y<maxy) {
+		for(q = p = seg; p < ep; p++) {
+			s = *p;
+			if(s->p1.y < y)
+				continue;
+			s->z += s->dz;
+			s->zerr += s->dzrem;
+			if(s->zerr >= s->den) {
+				s->z++;
+				s->zerr -= s->den;
+				if(s->zerr < 0 || s->zerr >= s->den)
+					print("bad ratzerr1: %ld den %ld dzrem %ld\n", s->zerr, s->den, s->dzrem);
+			}
+			*q++ = s;
+		}
+
+		for(p = next; *p; p++) {
+			s = *p;
+			if(s->p0.y >= y)
+				break;
+			if(s->p1.y < y)
+				continue;
+			s->z = s->p0.x;
+			s->z += smuldivmod(y - s->p0.y, s->num, s->den, &s->zerr);
+			if(s->zerr < 0 || s->zerr >= s->den)
+				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
+			*q++ = s;
+		}
+		ep = q;
+		next = p;
+
+		if(ep == seg) {
+			if(*next == 0)
+				break;
+			iy = (next[0]->p0.y + onehalf) >> fixshift;
+			y = (iy << fixshift) + onehalf;
+			continue;
+		}
+
+		zsort(seg, ep);
+
+		for(p = seg; p < ep; p++) {
+			cnt = 0;
+			x = p[0]->z;
+			xerr = p[0]->zerr;
+			xden = p[0]->den;
+			ix = (x + onehalf) >> fixshift;
+			if(ix >= maxx)
+				break;
+			if(ix < minx)
+				ix = minx;
+			cnt += p[0]->d;
+			p++;
+			for(;;) {
+				if(p == ep) {
+					print("xscan: fill to infinity");
+					return;
+				}
+				cnt += p[0]->d;
+				if((cnt&wind) == 0)
+					break;
+				p++;
+			}
+			x2 = p[0]->z;
+			ix2 = (x2 + onehalf) >> fixshift;
+			if(ix2 <= minx)
+				continue;
+			if(ix2 > maxx)
+				ix2 = maxx;
+			if(ix == ix2 && detail) {
+				if(xerr*p[0]->den + p[0]->zerr*xden > p[0]->den*xden)
+					x++;
+				ix = (x + x2) >> (fixshift+1);
+				ix2 = ix+1;
+			}
+			(*fill)(dst, ix, ix2, iy, src, sp, op);
+		}
+		y += (1<<fixshift);
+		iy++;
+	}
+}
+
+static void
+yscan(Memimage *dst, Seg **seg, Seg *segtab, int nseg, int wind, Memimage *src, Point sp, int fixshift, int op)
+{
+	long x, maxx, y, y2, yerr, yden, onehalf;
+	Seg **ep, **next, **p, **q, *s;
+	int n, i, ix, cnt, iy, iy2, miny, maxy;
+	Point pt;
+
+	for(i=0, s=segtab, p=seg; i<nseg; i++, s++) {
+		*p = s;
+		if(s->p0.x == s->p1.x)
+			continue;
+		if(s->p0.x > s->p1.x) {
+			pt = s->p0;
+			s->p0 = s->p1;
+			s->p1 = pt;
+			s->d = -s->d;
+		}
+		s->num = s->p1.y - s->p0.y;
+		s->den = s->p1.x - s->p0.x;
+		s->dz = sdiv(s->num, s->den) << fixshift;
+		s->dzrem = mod(s->num, s->den) << fixshift;
+		s->dz += sdiv(s->dzrem, s->den);
+		s->dzrem = mod(s->dzrem, s->den);
+		p++;
+	}
+	n = p-seg;
+	if(n == 0)
+		return;
+	*p = 0;
+	qsort(seg, n , sizeof(Seg*), xcompare);
+
+	onehalf = 0;
+	if(fixshift)
+		onehalf = 1 << (fixshift-1);
+
+	miny = dst->clipr.min.y;
+	maxy = dst->clipr.max.y;
+
+	x = seg[0]->p0.x;
+	if(x < (dst->clipr.min.x << fixshift))
+		x = dst->clipr.min.x << fixshift;
+	ix = (x + onehalf) >> fixshift;
+	x = (ix << fixshift) + onehalf;
+	maxx = dst->clipr.max.x << fixshift;
+
+	ep = next = seg;
+
+	while(x<maxx) {
+		for(q = p = seg; p < ep; p++) {
+			s = *p;
+			if(s->p1.x < x)
+				continue;
+			s->z += s->dz;
+			s->zerr += s->dzrem;
+			if(s->zerr >= s->den) {
+				s->z++;
+				s->zerr -= s->den;
+				if(s->zerr < 0 || s->zerr >= s->den)
+					print("bad ratzerr1: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
+			}
+			*q++ = s;
+		}
+
+		for(p = next; *p; p++) {
+			s = *p;
+			if(s->p0.x >= x)
+				break;
+			if(s->p1.x < x)
+				continue;
+			s->z = s->p0.y;
+			s->z += smuldivmod(x - s->p0.x, s->num, s->den, &s->zerr);
+			if(s->zerr < 0 || s->zerr >= s->den)
+				print("bad ratzerr2: %ld den %ld ratdzrem %ld\n", s->zerr, s->den, s->dzrem);
+			*q++ = s;
+		}
+		ep = q;
+		next = p;
+
+		if(ep == seg) {
+			if(*next == 0)
+				break;
+			ix = (next[0]->p0.x + onehalf) >> fixshift;
+			x = (ix << fixshift) + onehalf;
+			continue;
+		}
+
+		zsort(seg, ep);
+
+		for(p = seg; p < ep; p++) {
+			cnt = 0;
+			y = p[0]->z;
+			yerr = p[0]->zerr;
+			yden = p[0]->den;
+			iy = (y + onehalf) >> fixshift;
+			if(iy >= maxy)
+				break;
+			if(iy < miny)
+				iy = miny;
+			cnt += p[0]->d;
+			p++;
+			for(;;) {
+				if(p == ep) {
+					print("yscan: fill to infinity");
+					return;
+				}
+				cnt += p[0]->d;
+				if((cnt&wind) == 0)
+					break;
+				p++;
+			}
+			y2 = p[0]->z;
+			iy2 = (y2 + onehalf) >> fixshift;
+			if(iy2 <= miny)
+				continue;
+			if(iy2 > maxy)
+				iy2 = maxy;
+			if(iy == iy2) {
+				if(yerr*p[0]->den + p[0]->zerr*yden > p[0]->den*yden)
+					y++;
+				iy = (y + y2) >> (fixshift+1);
+				fillpoint(dst, ix, iy, src, sp, op);
+			}
+		}
+		x += (1<<fixshift);
+		ix++;
+	}
+}
+
+static void
+zsort(Seg **seg, Seg **ep)
+{
+	int done;
+	Seg **q, **p, *s;
+
+	if(ep-seg < 20) {
+		/* bubble sort by z - they should be almost sorted already */
+		q = ep;
+		do {
+			done = 1;
+			q--;
+			for(p = seg; p < q; p++) {
+				if(p[0]->z > p[1]->z) {
+					s = p[0];
+					p[0] = p[1];
+					p[1] = s;
+					done = 0;
+				}
+			}
+		} while(!done);
+	} else {
+		q = ep-1;
+		for(p = seg; p < q; p++) {
+			if(p[0]->z > p[1]->z) {
+				qsort(seg, ep-seg, sizeof(Seg*), zcompare);
+				break;
+			}
+		}
+	}
+}
+
+static int
+ycompare(void *a, void *b)
+{
+	Seg **s0, **s1;
+	long y0, y1;
+
+	s0 = a;
+	s1 = b;
+	y0 = (*s0)->p0.y;
+	y1 = (*s1)->p0.y;
+
+	if(y0 < y1)
+		return -1;
+	if(y0 == y1)
+		return 0;
+	return 1;
+}
+
+static int
+xcompare(void *a, void *b)
+{
+	Seg **s0, **s1;
+	long x0, x1;
+
+	s0 = a;
+	s1 = b;
+	x0 = (*s0)->p0.x;
+	x1 = (*s1)->p0.x;
+
+	if(x0 < x1)
+		return -1;
+	if(x0 == x1)
+		return 0;
+	return 1;
+}
+
+static int
+zcompare(void *a, void *b)
+{
+	Seg **s0, **s1;
+	long z0, z1;
+
+	s0 = a;
+	s1 = b;
+	z0 = (*s0)->z;
+	z1 = (*s1)->z;
+
+	if(z0 < z1)
+		return -1;
+	if(z0 == z1)
+		return 0;
+	return 1;
+}
--- /dev/null
+++ b/libmemdraw/hwdraw.c
@@ -1,0 +1,11 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+hwdraw(Memdrawparam *p)
+{
+	USED(p);
+	return 0;	/* could not satisfy request */
+}
+
--- /dev/null
+++ b/libmemdraw/icossin.c
@@ -1,0 +1,139 @@
+#include	"lib9.h"
+#include	"draw.h"
+
+/*
+ * Integer sine and cosine for integral degree argument.
+ * Tables computed by (sin,cos)(PI*d/180).
+ */
+static short sinus[91] = {
+	0,	/* 0 */
+	18,	/* 1 */
+	36,	/* 2 */
+	54,	/* 3 */
+	71,	/* 4 */
+	89,	/* 5 */
+	107,	/* 6 */
+	125,	/* 7 */
+	143,	/* 8 */
+	160,	/* 9 */
+	178,	/* 10 */
+	195,	/* 11 */
+	213,	/* 12 */
+	230,	/* 13 */
+	248,	/* 14 */
+	265,	/* 15 */
+	282,	/* 16 */
+	299,	/* 17 */
+	316,	/* 18 */
+	333,	/* 19 */
+	350,	/* 20 */
+	367,	/* 21 */
+	384,	/* 22 */
+	400,	/* 23 */
+	416,	/* 24 */
+	433,	/* 25 */
+	449,	/* 26 */
+	465,	/* 27 */
+	481,	/* 28 */
+	496,	/* 29 */
+	512,	/* 30 */
+	527,	/* 31 */
+	543,	/* 32 */
+	558,	/* 33 */
+	573,	/* 34 */
+	587,	/* 35 */
+	602,	/* 36 */
+	616,	/* 37 */
+	630,	/* 38 */
+	644,	/* 39 */
+	658,	/* 40 */
+	672,	/* 41 */
+	685,	/* 42 */
+	698,	/* 43 */
+	711,	/* 44 */
+	724,	/* 45 */
+	737,	/* 46 */
+	749,	/* 47 */
+	761,	/* 48 */
+	773,	/* 49 */
+	784,	/* 50 */
+	796,	/* 51 */
+	807,	/* 52 */
+	818,	/* 53 */
+	828,	/* 54 */
+	839,	/* 55 */
+	849,	/* 56 */
+	859,	/* 57 */
+	868,	/* 58 */
+	878,	/* 59 */
+	887,	/* 60 */
+	896,	/* 61 */
+	904,	/* 62 */
+	912,	/* 63 */
+	920,	/* 64 */
+	928,	/* 65 */
+	935,	/* 66 */
+	943,	/* 67 */
+	949,	/* 68 */
+	956,	/* 69 */
+	962,	/* 70 */
+	968,	/* 71 */
+	974,	/* 72 */
+	979,	/* 73 */
+	984,	/* 74 */
+	989,	/* 75 */
+	994,	/* 76 */
+	998,	/* 77 */
+	1002,	/* 78 */
+	1005,	/* 79 */
+	1008,	/* 80 */
+	1011,	/* 81 */
+	1014,	/* 82 */
+	1016,	/* 83 */
+	1018,	/* 84 */
+	1020,	/* 85 */
+	1022,	/* 86 */
+	1023,	/* 87 */
+	1023,	/* 88 */
+	1024,	/* 89 */
+	1024,	/* 90 */
+};
+
+void
+icossin(int deg, int *cosp, int *sinp)
+{
+	int sinsign, cossign;
+	short *stp, *ctp;
+
+	deg %= 360;
+	if(deg < 0)
+		deg += 360;
+	sinsign = 1;
+	cossign = 1;
+	stp = 0;
+	ctp = 0;
+	switch(deg/90){
+	case 2:
+		sinsign = -1;
+		cossign = -1;
+		deg -= 180;
+		/* fall through */
+	case 0:
+		stp = &sinus[deg];
+		ctp = &sinus[90-deg];
+		break;
+	case 3:
+		sinsign = -1;
+		cossign = -1;
+		deg -= 180;
+		/* fall through */
+	case 1:
+		deg = 180-deg;
+		cossign = -cossign;
+		stp = &sinus[deg];
+		ctp = &sinus[90-deg];
+		break;
+	}
+	*sinp = sinsign*stp[0];
+	*cosp = cossign*ctp[0];
+}
--- /dev/null
+++ b/libmemdraw/icossin2.c
@@ -1,0 +1,260 @@
+#include	"lib9.h"
+#include	"draw.h"
+
+/*
+ * Sine and Cosine of arctangents, calculated by 
+ *   (sin(atan(index/100.0))*1024.+0.5)
+ *   (cos(atan(index/100.0))*1024.+0.5)
+ * To use, get rational tangent between 0<=tan<=1, scale by 100,
+ * and look up sin and cos, and use linear interpolation.  divide by 1024.
+ * Maximum error is 0.0020.  Without linear interpolation, it's 0.010.
+ */
+static
+short sinus[] = {
+	0,	/* 0.00 */
+	10,	/* 0.01 */
+	20,	/* 0.02 */
+	31,	/* 0.03 */
+	41,	/* 0.04 */
+	51,	/* 0.05 */
+	61,	/* 0.06 */
+	72,	/* 0.07 */
+	82,	/* 0.08 */
+	92,	/* 0.09 */
+	102,	/* 0.10 */
+	112,	/* 0.11 */
+	122,	/* 0.12 */
+	132,	/* 0.13 */
+	142,	/* 0.14 */
+	152,	/* 0.15 */
+	162,	/* 0.16 */
+	172,	/* 0.17 */
+	181,	/* 0.18 */
+	191,	/* 0.19 */
+	201,	/* 0.20 */
+	210,	/* 0.21 */
+	220,	/* 0.22 */
+	230,	/* 0.23 */
+	239,	/* 0.24 */
+	248,	/* 0.25 */
+	258,	/* 0.26 */
+	267,	/* 0.27 */
+	276,	/* 0.28 */
+	285,	/* 0.29 */
+	294,	/* 0.30 */
+	303,	/* 0.31 */
+	312,	/* 0.32 */
+	321,	/* 0.33 */
+	330,	/* 0.34 */
+	338,	/* 0.35 */
+	347,	/* 0.36 */
+	355,	/* 0.37 */
+	364,	/* 0.38 */
+	372,	/* 0.39 */
+	380,	/* 0.40 */
+	388,	/* 0.41 */
+	397,	/* 0.42 */
+	405,	/* 0.43 */
+	412,	/* 0.44 */
+	420,	/* 0.45 */
+	428,	/* 0.46 */
+	436,	/* 0.47 */
+	443,	/* 0.48 */
+	451,	/* 0.49 */
+	458,	/* 0.50 */
+	465,	/* 0.51 */
+	472,	/* 0.52 */
+	480,	/* 0.53 */
+	487,	/* 0.54 */
+	493,	/* 0.55 */
+	500,	/* 0.56 */
+	507,	/* 0.57 */
+	514,	/* 0.58 */
+	520,	/* 0.59 */
+	527,	/* 0.60 */
+	533,	/* 0.61 */
+	540,	/* 0.62 */
+	546,	/* 0.63 */
+	552,	/* 0.64 */
+	558,	/* 0.65 */
+	564,	/* 0.66 */
+	570,	/* 0.67 */
+	576,	/* 0.68 */
+	582,	/* 0.69 */
+	587,	/* 0.70 */
+	593,	/* 0.71 */
+	598,	/* 0.72 */
+	604,	/* 0.73 */
+	609,	/* 0.74 */
+	614,	/* 0.75 */
+	620,	/* 0.76 */
+	625,	/* 0.77 */
+	630,	/* 0.78 */
+	635,	/* 0.79 */
+	640,	/* 0.80 */
+	645,	/* 0.81 */
+	649,	/* 0.82 */
+	654,	/* 0.83 */
+	659,	/* 0.84 */
+	663,	/* 0.85 */
+	668,	/* 0.86 */
+	672,	/* 0.87 */
+	676,	/* 0.88 */
+	681,	/* 0.89 */
+	685,	/* 0.90 */
+	689,	/* 0.91 */
+	693,	/* 0.92 */
+	697,	/* 0.93 */
+	701,	/* 0.94 */
+	705,	/* 0.95 */
+	709,	/* 0.96 */
+	713,	/* 0.97 */
+	717,	/* 0.98 */
+	720,	/* 0.99 */
+	724,	/* 1.00 */
+	728,	/* 1.01 */
+};
+
+static
+short cosinus[] = {
+	1024,	/* 0.00 */
+	1024,	/* 0.01 */
+	1024,	/* 0.02 */
+	1024,	/* 0.03 */
+	1023,	/* 0.04 */
+	1023,	/* 0.05 */
+	1022,	/* 0.06 */
+	1022,	/* 0.07 */
+	1021,	/* 0.08 */
+	1020,	/* 0.09 */
+	1019,	/* 0.10 */
+	1018,	/* 0.11 */
+	1017,	/* 0.12 */
+	1015,	/* 0.13 */
+	1014,	/* 0.14 */
+	1013,	/* 0.15 */
+	1011,	/* 0.16 */
+	1010,	/* 0.17 */
+	1008,	/* 0.18 */
+	1006,	/* 0.19 */
+	1004,	/* 0.20 */
+	1002,	/* 0.21 */
+	1000,	/* 0.22 */
+	998,	/* 0.23 */
+	996,	/* 0.24 */
+	993,	/* 0.25 */
+	991,	/* 0.26 */
+	989,	/* 0.27 */
+	986,	/* 0.28 */
+	983,	/* 0.29 */
+	981,	/* 0.30 */
+	978,	/* 0.31 */
+	975,	/* 0.32 */
+	972,	/* 0.33 */
+	969,	/* 0.34 */
+	967,	/* 0.35 */
+	963,	/* 0.36 */
+	960,	/* 0.37 */
+	957,	/* 0.38 */
+	954,	/* 0.39 */
+	951,	/* 0.40 */
+	947,	/* 0.41 */
+	944,	/* 0.42 */
+	941,	/* 0.43 */
+	937,	/* 0.44 */
+	934,	/* 0.45 */
+	930,	/* 0.46 */
+	927,	/* 0.47 */
+	923,	/* 0.48 */
+	920,	/* 0.49 */
+	916,	/* 0.50 */
+	912,	/* 0.51 */
+	909,	/* 0.52 */
+	905,	/* 0.53 */
+	901,	/* 0.54 */
+	897,	/* 0.55 */
+	893,	/* 0.56 */
+	890,	/* 0.57 */
+	886,	/* 0.58 */
+	882,	/* 0.59 */
+	878,	/* 0.60 */
+	874,	/* 0.61 */
+	870,	/* 0.62 */
+	866,	/* 0.63 */
+	862,	/* 0.64 */
+	859,	/* 0.65 */
+	855,	/* 0.66 */
+	851,	/* 0.67 */
+	847,	/* 0.68 */
+	843,	/* 0.69 */
+	839,	/* 0.70 */
+	835,	/* 0.71 */
+	831,	/* 0.72 */
+	827,	/* 0.73 */
+	823,	/* 0.74 */
+	819,	/* 0.75 */
+	815,	/* 0.76 */
+	811,	/* 0.77 */
+	807,	/* 0.78 */
+	804,	/* 0.79 */
+	800,	/* 0.80 */
+	796,	/* 0.81 */
+	792,	/* 0.82 */
+	788,	/* 0.83 */
+	784,	/* 0.84 */
+	780,	/* 0.85 */
+	776,	/* 0.86 */
+	773,	/* 0.87 */
+	769,	/* 0.88 */
+	765,	/* 0.89 */
+	761,	/* 0.90 */
+	757,	/* 0.91 */
+	754,	/* 0.92 */
+	750,	/* 0.93 */
+	746,	/* 0.94 */
+	742,	/* 0.95 */
+	739,	/* 0.96 */
+	735,	/* 0.97 */
+	731,	/* 0.98 */
+	728,	/* 0.99 */
+	724,	/* 1.00 */
+	720,	/* 1.01 */
+};
+
+void
+icossin2(int x, int y, int *cosp, int *sinp)
+{
+	int sinsign, cossign, tan, tan10, rem;
+	short *stp, *ctp;
+
+	if(x == 0){
+		if(y >= 0)
+			*sinp = ICOSSCALE, *cosp = 0;
+		else
+			*sinp = -ICOSSCALE, *cosp = 0;
+		return;
+	}
+	sinsign = cossign = 1;
+	if(x < 0){
+		cossign = -1;
+		x = -x;
+	}
+	if(y < 0){
+		sinsign = -1;
+		y = -y;
+	}
+	if(y > x){
+		tan = 1000*x/y;
+		tan10 = tan/10;
+		stp = &cosinus[tan10];
+		ctp = &sinus[tan10];
+	}else{
+		tan = 1000*y/x;
+		tan10 = tan/10;
+		stp = &sinus[tan10];
+		ctp = &cosinus[tan10];
+	}
+	rem = tan-(tan10*10);
+	*sinp = sinsign*(stp[0]+(stp[1]-stp[0])*rem/10);
+	*cosp = cossign*(ctp[0]+(ctp[1]-ctp[0])*rem/10);
+}
--- /dev/null
+++ b/libmemdraw/iprint.c
@@ -1,0 +1,11 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+iprint(char *f,...)
+{
+	USED(f);
+	return -1;
+}
+
--- /dev/null
+++ b/libmemdraw/line.c
@@ -1,0 +1,481 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+enum
+{
+	Arrow1 = 8,
+	Arrow2 = 10,
+	Arrow3 = 3,
+};
+
+static
+int
+lmin(int a, int b)
+{
+	if(a < b)
+		return a;
+	return b;
+}
+
+static
+int
+lmax(int a, int b)
+{
+	if(a > b)
+		return a;
+	return b;
+}
+
+/*
+ * Rather than line clip, we run the Bresenham loop over the full line,
+ * and clip on each pixel.  This is more expensive but means that
+ * lines look the same regardless of how the windowing has tiled them.
+ * For speed, we check for clipping outside the loop and make the
+ * test easy when possible.
+ */
+
+#ifdef XXX
+static
+void
+horline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
+{
+	int x, y, dy, deltay, deltax, maxx;
+	int dd, easy, e, bpp, m, m0;
+	uchar *d;
+
+	deltax = p1.x - p0.x;
+	deltay = p1.y - p0.y;
+	dd = dst->width*sizeof(ulong);
+	dy = 1;
+	if(deltay < 0){
+		dd = -dd;
+		deltay = -deltay;
+		dy = -1;
+	}
+	maxx = lmin(p1.x, clipr.max.x-1);
+	bpp = dst->depth;
+	m0 = 0xFF^(0xFF>>bpp);
+	m = m0 >> (p0.x&(7/dst->depth))*bpp;
+	easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
+	e = 2*deltay - deltax;
+	y = p0.y;
+	d = byteaddr(dst, p0);
+	deltay *= 2;
+	deltax = deltay - 2*deltax;
+	for(x=p0.x; x<=maxx; x++){
+		if(easy || (clipr.min.x<=x && clipr.min.y<=y && y<clipr.max.y))
+			*d ^= (*d^srcval) & m;
+		if(e > 0){
+			y += dy;
+			d += dd;
+			e += deltax;
+		}else
+			e += deltay;
+		d++;
+		m >>= bpp;
+		if(m == 0)
+			m = m0;
+	}
+}
+
+static
+void
+verline1(Memimage *dst, Point p0, Point p1, int srcval, Rectangle clipr)
+{
+	int x, y, deltay, deltax, maxy;
+	int easy, e, bpp, m, m0, dd;
+	uchar *d;
+
+	deltax = p1.x - p0.x;
+	deltay = p1.y - p0.y;
+	dd = 1;
+	if(deltax < 0){
+		dd = -1;
+		deltax = -deltax;
+	}
+	maxy = lmin(p1.y, clipr.max.y-1);
+	bpp = dst->depth;
+	m0 = 0xFF^(0xFF>>bpp);
+	m = m0 >> (p0.x&(7/dst->depth))*bpp;
+	easy = ptinrect(p0, clipr) && ptinrect(p1, clipr);
+	e = 2*deltax - deltay;
+	x = p0.x;
+	d = byteaddr(dst, p0);
+	deltax *= 2;
+	deltay = deltax - 2*deltay;
+	for(y=p0.y; y<=maxy; y++){
+		if(easy || (clipr.min.y<=y && clipr.min.x<=x && x<clipr.max.x))
+			*d ^= (*d^srcval) & m;
+		if(e > 0){
+			x += dd;
+			d += dd;
+			e += deltay;
+		}else
+			e += deltax;
+		d += dst->width*sizeof(ulong);
+		m >>= bpp;
+		if(m == 0)
+			m = m0;
+	}
+}
+
+static
+void
+horliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+	int x, y, sx, sy, deltay, deltax, minx, maxx;
+	int bpp, m, m0;
+	uchar *d, *s;
+
+	deltax = p1.x - p0.x;
+	deltay = p1.y - p0.y;
+	sx = drawreplxy(src->r.min.x, src->r.max.x, p0.x+dsrc.x);
+	minx = lmax(p0.x, clipr.min.x);
+	maxx = lmin(p1.x, clipr.max.x-1);
+	bpp = dst->depth;
+	m0 = 0xFF^(0xFF>>bpp);
+	m = m0 >> (minx&(7/dst->depth))*bpp;
+	for(x=minx; x<=maxx; x++){
+		y = p0.y + (deltay*(x-p0.x)+deltax/2)/deltax;
+		if(clipr.min.y<=y && y<clipr.max.y){
+			d = byteaddr(dst, Pt(x, y));
+			sy = drawreplxy(src->r.min.y, src->r.max.y, y+dsrc.y);
+			s = byteaddr(src, Pt(sx, sy));
+			*d ^= (*d^*s) & m;
+		}
+		if(++sx >= src->r.max.x)
+			sx = src->r.min.x;
+		m >>= bpp;
+		if(m == 0)
+			m = m0;
+	}
+}
+
+static
+void
+verliner(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+	int x, y, sx, sy, deltay, deltax, miny, maxy;
+	int bpp, m, m0;
+	uchar *d, *s;
+
+	deltax = p1.x - p0.x;
+	deltay = p1.y - p0.y;
+	sy = drawreplxy(src->r.min.y, src->r.max.y, p0.y+dsrc.y);
+	miny = lmax(p0.y, clipr.min.y);
+	maxy = lmin(p1.y, clipr.max.y-1);
+	bpp = dst->depth;
+	m0 = 0xFF^(0xFF>>bpp);
+	for(y=miny; y<=maxy; y++){
+		if(deltay == 0)	/* degenerate line */
+			x = p0.x;
+		else
+			x = p0.x + (deltax*(y-p0.y)+deltay/2)/deltay;
+		if(clipr.min.x<=x && x<clipr.max.x){
+			m = m0 >> (x&(7/dst->depth))*bpp;
+			d = byteaddr(dst, Pt(x, y));
+			sx = drawreplxy(src->r.min.x, src->r.max.x, x+dsrc.x);
+			s = byteaddr(src, Pt(sx, sy));
+			*d ^= (*d^*s) & m;
+		}
+		if(++sy >= src->r.max.y)
+			sy = src->r.min.y;
+	}
+}
+
+static
+void
+horline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+	int x, y, deltay, deltax, minx, maxx;
+	int bpp, m, m0;
+	uchar *d, *s;
+
+	deltax = p1.x - p0.x;
+	deltay = p1.y - p0.y;
+	minx = lmax(p0.x, clipr.min.x);
+	maxx = lmin(p1.x, clipr.max.x-1);
+	bpp = dst->depth;
+	m0 = 0xFF^(0xFF>>bpp);
+	m = m0 >> (minx&(7/dst->depth))*bpp;
+	for(x=minx; x<=maxx; x++){
+		y = p0.y + (deltay*(x-p0.x)+deltay/2)/deltax;
+		if(clipr.min.y<=y && y<clipr.max.y){
+			d = byteaddr(dst, Pt(x, y));
+			s = byteaddr(src, addpt(dsrc, Pt(x, y)));
+			*d ^= (*d^*s) & m;
+		}
+		m >>= bpp;
+		if(m == 0)
+			m = m0;
+	}
+}
+
+static
+void
+verline(Memimage *dst, Point p0, Point p1, Memimage *src, Point dsrc, Rectangle clipr)
+{
+	int x, y, deltay, deltax, miny, maxy;
+	int bpp, m, m0;
+	uchar *d, *s;
+
+	deltax = p1.x - p0.x;
+	deltay = p1.y - p0.y;
+	miny = lmax(p0.y, clipr.min.y);
+	maxy = lmin(p1.y, clipr.max.y-1);
+	bpp = dst->depth;
+	m0 = 0xFF^(0xFF>>bpp);
+	for(y=miny; y<=maxy; y++){
+		if(deltay == 0)	/* degenerate line */
+			x = p0.x;
+		else
+			x = p0.x + deltax*(y-p0.y)/deltay;
+		if(clipr.min.x<=x && x<clipr.max.x){
+			m = m0 >> (x&(7/dst->depth))*bpp;
+			d = byteaddr(dst, Pt(x, y));
+			s = byteaddr(src, addpt(dsrc, Pt(x, y)));
+			*d ^= (*d^*s) & m;
+		}
+	}
+}
+#endif
+
+static Memimage*
+membrush(int radius)
+{
+	static Memimage *brush;
+	static int brushradius;
+
+	if(brush==nil || brushradius!=radius){
+		freememimage(brush);
+		brush = allocmemimage(Rect(0, 0, 2*radius+1, 2*radius+1), memopaque->chan);
+		if(brush != nil){
+			memfillcolor(brush, DTransparent);	/* zeros */
+			memellipse(brush, Pt(radius, radius), radius, radius, -1, memopaque, Pt(radius, radius), S);
+		}
+		brushradius = radius;
+	}
+	return brush;
+}
+
+static
+void
+discend(Point p, int radius, Memimage *dst, Memimage *src, Point dsrc, int op)
+{
+	Memimage *disc;
+	Rectangle r;
+
+	disc = membrush(radius);
+	if(disc != nil){
+		r.min.x = p.x - radius;
+		r.min.y = p.y - radius;
+		r.max.x = p.x + radius+1;
+		r.max.y = p.y + radius+1;
+		memdraw(dst, r, src, addpt(r.min, dsrc), disc, Pt(0,0), op);
+	}
+}
+
+static
+void
+arrowend(Point tip, Point *pp, int end, int sin, int cos, int radius)
+{
+	int x1, x2, x3;
+
+	/* before rotation */
+	if(end == Endarrow){
+		x1 = Arrow1;
+		x2 = Arrow2;
+		x3 = Arrow3;
+	}else{
+		x1 = (end>>5) & 0x1FF;	/* distance along line from end of line to tip */
+		x2 = (end>>14) & 0x1FF;	/* distance along line from barb to tip */
+		x3 = (end>>23) & 0x1FF;	/* distance perpendicular from edge of line to barb */
+	}
+
+	/* comments follow track of right-facing arrowhead */
+	pp->x = tip.x+((2*radius+1)*sin/2-x1*cos);		/* upper side of shaft */
+	pp->y = tip.y-((2*radius+1)*cos/2+x1*sin);
+	pp++;
+	pp->x = tip.x+((2*radius+2*x3+1)*sin/2-x2*cos);		/* upper barb */
+	pp->y = tip.y-((2*radius+2*x3+1)*cos/2+x2*sin);
+	pp++;
+	pp->x = tip.x;
+	pp->y = tip.y;
+	pp++;
+	pp->x = tip.x+(-(2*radius+2*x3+1)*sin/2-x2*cos);	/* lower barb */
+	pp->y = tip.y-(-(2*radius+2*x3+1)*cos/2+x2*sin);
+	pp++;
+	pp->x = tip.x+(-(2*radius+1)*sin/2-x1*cos);		/* lower side of shaft */
+	pp->y = tip.y+((2*radius+1)*cos/2-x1*sin);
+}
+
+void
+_memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
+{
+	int hor;
+	int sin, cos, dx, dy, t;
+	Rectangle oclipr, r;
+	Point q, pts[10], *pp, d;
+
+	if(radius < 0)
+		return;
+	if(rectclip(&clipr, dst->r) == 0)
+		return;
+	if(rectclip(&clipr, dst->clipr) == 0)
+		return;
+	d = subpt(sp, p0);
+	if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
+		return;
+	if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
+		return;
+	/* this means that only verline() handles degenerate lines (p0==p1) */
+	hor = (abs(p1.x-p0.x) > abs(p1.y-p0.y));
+	/*
+	 * Clipping is a little peculiar.  We can't use Sutherland-Cohen
+	 * clipping because lines are wide.  But this is probably just fine:
+	 * we do all math with the original p0 and p1, but clip when deciding
+	 * what pixels to draw.  This means the layer code can call this routine,
+	 * using clipr to define the region being written, and get the same set
+	 * of pixels regardless of the dicing.
+	 */
+	if((hor && p0.x>p1.x) || (!hor && p0.y>p1.y)){
+		q = p0;
+		p0 = p1;
+		p1 = q;
+		t = end0;
+		end0 = end1;
+		end1 = t;
+	}
+
+	if((p0.x == p1.x || p0.y == p1.y) && (end0&0x1F) == Endsquare && (end1&0x1F) == Endsquare){
+		r.min = p0;
+		r.max = p1;
+		if(p0.x == p1.x){
+			r.min.x -= radius;
+			r.max.x += radius+1;
+			r.max.y++;
+		}
+		else{
+			r.min.y -= radius;
+			r.max.y += radius+1;
+			r.max.x++;
+		}
+		oclipr = dst->clipr;
+		dst->clipr = clipr;
+		sp = addpt(r.min, d);
+		memimagedraw(dst, r, src, sp, memopaque, sp, op);
+		dst->clipr = oclipr;
+		return;
+	}
+
+/*    Hard: */
+	/* draw thick line using polygon fill */
+	icossin2(p1.x-p0.x, p1.y-p0.y, &cos, &sin);
+	dx = (sin*(2*radius+1))/2;
+	dy = (cos*(2*radius+1))/2;
+	pp = pts;
+	oclipr = dst->clipr;
+	dst->clipr = clipr;
+	q.x = ICOSSCALE*p0.x+ICOSSCALE/2-cos/2;
+	q.y = ICOSSCALE*p0.y+ICOSSCALE/2-sin/2;
+	switch(end0 & 0x1F){
+	case Enddisc:
+		discend(p0, radius, dst, src, d, op);
+		/* fall through */
+	case Endsquare:
+	default:
+		pp->x = q.x-dx;
+		pp->y = q.y+dy;
+		pp++;
+		pp->x = q.x+dx;
+		pp->y = q.y-dy;
+		pp++;
+		break;
+	case Endarrow:
+		arrowend(q, pp, end0, -sin, -cos, radius);
+		_memfillpolysc(dst, pts, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
+		pp[1] = pp[4];
+		pp += 2;
+	}
+	q.x = ICOSSCALE*p1.x+ICOSSCALE/2+cos/2;
+	q.y = ICOSSCALE*p1.y+ICOSSCALE/2+sin/2;
+	switch(end1 & 0x1F){
+	case Enddisc:
+		discend(p1, radius, dst, src, d, op);
+		/* fall through */
+	case Endsquare:
+	default:
+		pp->x = q.x+dx;
+		pp->y = q.y-dy;
+		pp++;
+		pp->x = q.x-dx;
+		pp->y = q.y+dy;
+		pp++;
+		break;
+	case Endarrow:
+		arrowend(q, pp, end1, sin, cos, radius);
+		_memfillpolysc(dst, pp, 5, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 1, 10, 1, op);
+		pp[1] = pp[4];
+		pp += 2;
+	}
+	_memfillpolysc(dst, pts, pp-pts, ~0, src, addpt(pts[0], mulpt(d, ICOSSCALE)), 0, 10, 1, op);
+	dst->clipr = oclipr;
+	return;
+}
+
+void
+memimageline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
+{
+	_memimageline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
+}
+
+/*
+ * Simple-minded conservative code to compute bounding box of line.
+ * Result is probably a little larger than it needs to be.
+ */
+static
+void
+addbbox(Rectangle *r, Point p)
+{
+	if(r->min.x > p.x)
+		r->min.x = p.x;
+	if(r->min.y > p.y)
+		r->min.y = p.y;
+	if(r->max.x < p.x+1)
+		r->max.x = p.x+1;
+	if(r->max.y < p.y+1)
+		r->max.y = p.y+1;
+}
+
+int
+memlineendsize(int end)
+{
+	int x3;
+
+	if((end&0x3F) != Endarrow)
+		return 0;
+	if(end == Endarrow)
+		x3 = Arrow3;
+	else
+		x3 = (end>>23) & 0x1FF;
+	return x3;
+}
+
+Rectangle
+memlinebbox(Point p0, Point p1, int end0, int end1, int radius)
+{
+	Rectangle r, r1;
+	int extra;
+
+	r.min.x = 10000000;
+	r.min.y = 10000000;
+	r.max.x = -10000000;
+	r.max.y = -10000000;
+	extra = lmax(memlineendsize(end0), memlineendsize(end1));
+	r1 = insetrect(canonrect(Rpt(p0, p1)), -(radius+extra));
+	addbbox(&r, r1.min);
+	addbbox(&r, r1.max);
+	return r;
+}
--- /dev/null
+++ b/libmemdraw/load.c
@@ -1,0 +1,71 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+	int y, l, lpart, rpart, mx, m, mr;
+	uchar *q;
+
+	if(!rectinrect(r, i->r))
+		return -1;
+	l = bytesperline(r, i->depth);
+	if(ndata < l*Dy(r))
+		return -1;
+	ndata = l*Dy(r);
+	q = byteaddr(i, r.min);
+	mx = 7/i->depth;
+	lpart = (r.min.x & mx) * i->depth;
+	rpart = (r.max.x & mx) * i->depth;
+	m = 0xFF >> lpart;
+	/* may need to do bit insertion on edges */
+	if(l == 1){	/* all in one byte */
+		if(rpart)
+			m ^= 0xFF >> rpart;
+		for(y=r.min.y; y<r.max.y; y++){
+			*q ^= (*data^*q) & m;
+			q += i->width*sizeof(ulong);
+			data++;
+		}
+		return ndata;
+	}
+	if(lpart==0 && rpart==0){	/* easy case */
+		for(y=r.min.y; y<r.max.y; y++){
+			memmove(q, data, l);
+			q += i->width*sizeof(ulong);
+			data += l;
+		}
+		return ndata;
+	}
+	mr = 0xFF ^ (0xFF >> rpart);
+	if(lpart!=0 && rpart==0){
+		for(y=r.min.y; y<r.max.y; y++){
+			*q ^= (*data^*q) & m;
+			if(l > 1)
+				memmove(q+1, data+1, l-1);
+			q += i->width*sizeof(ulong);
+			data += l;
+		}
+		return ndata;
+	}
+	if(lpart==0 && rpart!=0){
+		for(y=r.min.y; y<r.max.y; y++){
+			if(l > 1)
+				memmove(q, data, l-1);
+			q[l-1] ^= (data[l-1]^q[l-1]) & mr;
+			q += i->width*sizeof(ulong);
+			data += l;
+		}
+		return ndata;
+	}
+	for(y=r.min.y; y<r.max.y; y++){
+		*q ^= (*data^*q) & m;
+		if(l > 2)
+			memmove(q+1, data+1, l-2);
+		q[l-1] ^= (data[l-1]^q[l-1]) & mr;
+		q += i->width*sizeof(ulong);
+		data += l;
+	}
+	return ndata;
+}
--- /dev/null
+++ b/libmemdraw/mkfile
@@ -1,0 +1,33 @@
+<../mkconfig
+
+LIB=libmemdraw.a
+
+COMMONFILES=\
+	arc.$O\
+	cmap.$O\
+	cread.$O\
+	defont.$O\
+	ellipse.$O\
+	fillpoly.$O\
+	hwdraw.$O\
+	icossin.$O\
+	icossin2.$O\
+	iprint.$O\
+	line.$O\
+	openmemsubfont.$O\
+	poly.$O\
+	read.$O\
+	string.$O\
+	subfont.$O\
+	write.$O\
+
+<mkfile-$SYSTARG		#sets $SYSFILES based on target OS architecture
+
+OFILES=$COMMONFILES $SYSFILES
+
+HFILES=	$ROOT/include/draw.h\
+	$ROOT/include/memdraw.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+%-x11.$O:	xmem.h
--- /dev/null
+++ b/libmemdraw/mkfile-FreeBSD
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Inferno
@@ -1,0 +1,9 @@
+#
+#	Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+	cload.$O\
+	draw.$O\
+	load.$O\
+	unload.$O\
+
--- /dev/null
+++ b/libmemdraw/mkfile-Irix
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Linux
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-MacOSX
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Mac OS X
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-NetBSD
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Nt
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-OpenBSD
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-Plan9
@@ -1,0 +1,9 @@
+#
+#	Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+	cload.$O\
+	draw.$O\
+	load.$O\
+	unload.$O\
+
--- /dev/null
+++ b/libmemdraw/mkfile-Solaris
@@ -1,0 +1,4 @@
+#
+#	Object files specific for Nt
+#
+<mkfile-Inferno
--- /dev/null
+++ b/libmemdraw/mkfile-os
@@ -1,0 +1,9 @@
+#
+#	Object files specific for Inferno/Plan9
+#
+SYSFILES=alloc.$O\
+	cload.$O\
+	draw.$O\
+	load.$O\
+	unload.$O\
+
--- /dev/null
+++ b/libmemdraw/openmemsubfont.c
@@ -1,0 +1,51 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memsubfont*
+openmemsubfont(char *name)
+{
+	Memsubfont *sf;
+	Memimage *i;
+	Fontchar *fc;
+	int fd, n;
+	char hdr[3*12+4+1];
+	uchar *p = nil;
+
+	fd = open(name, OREAD);
+	if(fd < 0)
+		return nil;
+	i = readmemimage(fd);
+	if(i == nil)
+		goto Err;
+	if(read(fd, hdr, 3*12) != 3*12){
+		werrstr("openmemsubfont: header read error: %r");
+		goto Err;
+	}
+	n = atoi(hdr);
+	p = malloc(6*(n+1));
+	if(p == nil)
+		goto Err;
+	if(read(fd, p, 6*(n+1)) != 6*(n+1)){
+		werrstr("openmemsubfont: fontchar read error: %r");
+		goto Err;
+	}
+	fc = malloc(sizeof(Fontchar)*(n+1));
+	if(fc == nil)
+		goto Err;
+	_unpackinfo(fc, p, n);
+	sf = allocmemsubfont(name, n, atoi(hdr+12), atoi(hdr+24), fc, i);
+	if(sf == nil){
+		free(fc);
+		goto Err;
+	}
+	free(p);
+	return sf;
+Err:
+	close(fd);
+	if (i != nil)
+		freememimage(i);
+	if (p != nil)
+		free(p);
+	return nil;
+}
--- /dev/null
+++ b/libmemdraw/poly.c
@@ -1,0 +1,23 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+mempoly(Memimage *dst, Point *vert, int nvert, int end0, int end1, int radius, Memimage *src, Point sp, int op)
+{
+	int i, e0, e1;
+	Point d;
+
+	if(nvert < 2)
+		return;
+	d = subpt(sp, vert[0]);
+	for(i=1; i<nvert; i++){
+		e0 = e1 = Enddisc;
+		if(i == 1)
+			e0 = end0;
+		if(i == nvert-1)
+			e1 = end1;
+		memline(dst, vert[i-1], vert[i], e0, e1, radius, src, addpt(d, vert[i-1]), op);
+	}
+}
--- /dev/null
+++ b/libmemdraw/read.c
@@ -1,0 +1,112 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+#define	CHUNK	(32*1024)
+
+Memimage*
+readmemimage(int fd)
+{
+	char hdr[5*12+1];
+	int dy;
+	ulong chan;
+	uint l, n;
+	int m, j;
+	int new, miny, maxy;
+	Rectangle r;
+	uchar *tmp;
+	int ldepth, chunk;
+	Memimage *i;
+
+	if(readn(fd, hdr, 11) != 11){
+		werrstr("readimage: short header");
+		return nil;
+	}
+	if(memcmp(hdr, "compressed\n", 11) == 0)
+		return creadmemimage(fd);
+	if(readn(fd, hdr+11, 5*12-11) != 5*12-11){
+		werrstr("readimage: short header (2)");
+		return nil;
+	}
+
+	/*
+	 * distinguish new channel descriptor from old ldepth.
+	 * channel descriptors have letters as well as numbers,
+	 * while ldepths are a single digit formatted as %-11d.
+	 */
+	new = 0;
+	for(m=0; m<10; m++){
+		if(hdr[m] != ' '){
+			new = 1;
+			break;
+		}
+	}
+	if(hdr[11] != ' '){
+		werrstr("readimage: bad format");
+		return nil;
+	}
+	if(new){
+		hdr[11] = '\0';
+		if((chan = strtochan(hdr)) == 0){
+			werrstr("readimage: bad channel string %s", hdr);
+			return nil;
+		}
+	}else{
+		ldepth = ((int)hdr[10])-'0';
+		if(ldepth<0 || ldepth>3){
+			werrstr("readimage: bad ldepth %d", ldepth);
+			return nil;
+		}
+		chan = drawld2chan[ldepth];
+	}
+
+	r.min.x = atoi(hdr+1*12);
+	r.min.y = atoi(hdr+2*12);
+	r.max.x = atoi(hdr+3*12);
+	r.max.y = atoi(hdr+4*12);
+	if(r.min.x>r.max.x || r.min.y>r.max.y){
+		werrstr("readimage: bad rectangle");
+		return nil;
+	}
+
+	miny = r.min.y;
+	maxy = r.max.y;
+
+	l = bytesperline(r, chantodepth(chan));
+	i = allocmemimage(r, chan);
+	if(i == nil)
+		return nil;
+	chunk = CHUNK;
+	if(chunk < l)
+		chunk = l;
+	tmp = malloc(chunk);
+	if(tmp == nil)
+		goto Err;
+	while(maxy > miny){
+		dy = maxy - miny;
+		if(dy*l > chunk)
+			dy = chunk/l;
+		if(dy <= 0){
+			werrstr("readmemimage: image too wide for buffer");
+			goto Err;
+		}
+		n = dy*l;
+		m = readn(fd, tmp, n);
+		if(m != n){
+			werrstr("readmemimage: read count %d not %d: %r", m, n);
+   Err:
+ 			freememimage(i);
+			free(tmp);
+			return nil;
+		}
+		if(!new)	/* an old image: must flip all the bits */
+			for(j=0; j<chunk; j++)
+				tmp[j] ^= 0xFF;
+
+		if(loadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), tmp, chunk) <= 0)
+			goto Err;
+		miny += dy;
+	}
+	free(tmp);
+	return i;
+}
--- /dev/null
+++ b/libmemdraw/string.c
@@ -1,0 +1,66 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+Point
+memimagestring(Memimage *b, Point p, Memimage *color, Point cp, Memsubfont *f, char *cs)
+{
+	int w, width;
+	uchar *s;
+	Rune c;
+	Fontchar *i;
+
+	s = (uchar*)cs;
+	for(; c=*s; p.x+=width, cp.x+=width){
+		width = 0;
+		if(c < Runeself)
+			s++;
+		else{
+			w = chartorune(&c, (char*)s);
+			if(w == 0){
+				s++;
+				continue;
+			}
+			s += w;
+		}
+		if(c >= f->n)
+			continue;
+		i = f->info+c;
+		width = i->width;
+		memdraw(b, Rect(p.x+i->left, p.y+i->top, p.x+i->left+(i[1].x-i[0].x), p.y+i->bottom),
+			color, cp, f->bits, Pt(i->x, i->top), SoverD);
+	}
+	return p;
+}
+
+Point
+memsubfontwidth(Memsubfont *f, char *cs)
+{
+	Rune c;
+	Point p;
+	uchar *s;
+	Fontchar *i;
+	int w, width;
+
+	p = Pt(0, f->height);
+	s = (uchar*)cs;
+	for(; c=*s; p.x+=width){
+		width = 0;
+		if(c < Runeself)
+			s++;
+		else{
+			w = chartorune(&c, (char*)s);
+			if(w == 0){
+				s++;
+				continue;
+			}
+			s += w;
+		}
+		if(c >= f->n)
+			continue;
+		i = f->info+c;
+		width = i->width;
+	}
+	return p;
+}
--- /dev/null
+++ b/libmemdraw/subfont.c
@@ -1,0 +1,33 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memsubfont*
+allocmemsubfont(char *name, int n, int height, int ascent, Fontchar *info, Memimage *i)
+{
+	Memsubfont *f;
+
+	f = malloc(sizeof(Memsubfont));
+	if(f == 0)
+		return 0;
+	f->n = n;
+	f->height = height;
+	f->ascent = ascent;
+	f->info = info;
+	f->bits = i;
+	if(name)
+		f->name = strdup(name);
+	else
+		f->name = 0;
+	return f;
+}
+
+void
+freememsubfont(Memsubfont *f)
+{
+	if(f == 0)
+		return;
+	free(f->info);	/* note: f->info must have been malloc'ed! */
+	freememimage(f->bits);
+	free(f);
+}
--- /dev/null
+++ b/libmemdraw/unload.c
@@ -1,0 +1,24 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+int
+unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+	int y, l;
+	uchar *q;
+
+	if(!rectinrect(r, i->r))
+		return -1;
+	l = bytesperline(r, i->depth);
+	if(ndata < l*Dy(r))
+		return -1;
+	ndata = l*Dy(r);
+	q = byteaddr(i, r.min);
+	for(y=r.min.y; y<r.max.y; y++){
+		memmove(data, q, l);
+		q += i->width*sizeof(ulong);
+		data += l;
+	}
+	return ndata;
+}
--- /dev/null
+++ b/libmemdraw/write.c
@@ -1,0 +1,182 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+
+#define	CHUNK	8000
+
+#define	HSHIFT	3	/* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */
+#define	NHASH	(1<<(HSHIFT*NMATCH))
+#define	HMASK	(NHASH-1)
+#define	hupdate(h, c)	((((h)<<HSHIFT)^(c))&HMASK)
+typedef struct Hlist Hlist;
+struct Hlist{
+	uchar *s;
+	Hlist *next, *prev;
+};
+
+int
+writememimage(int fd, Memimage *i)
+{
+	uchar *outbuf, *outp, *eout;		/* encoded data, pointer, end */
+	uchar *loutp;				/* start of encoded line */
+	Hlist *hash;				/* heads of hash chains of past strings */
+	Hlist *chain, *hp;			/* hash chain members, pointer */
+	Hlist *cp;				/* next Hlist to fall out of window */
+	int h;					/* hash value */
+	uchar *line, *eline;			/* input line, end pointer */
+	uchar *data, *edata;			/* input buffer, end pointer */
+	ulong n;				/* length of input buffer */
+	ulong nb;				/* # of bytes returned by unloadimage */
+	int bpl;				/* input line length */
+	int offs, runlen;			/* offset, length of consumed data */
+	uchar dumpbuf[NDUMP];			/* dump accumulator */
+	int ndump;				/* length of dump accumulator */
+	int miny, dy;				/* y values while unloading input */
+	int ncblock;				/* size of compressed blocks */
+	Rectangle r;
+	uchar *p, *q, *s, *es, *t;
+	char hdr[11+5*12+1];
+	char cbuf[20];
+
+	r = i->r;
+	bpl = bytesperline(r, i->depth);
+	n = Dy(r)*bpl;
+	data = malloc(n);
+	ncblock = _compblocksize(r, i->depth);
+	outbuf = malloc(ncblock);
+	hash = malloc(NHASH*sizeof(Hlist));
+	chain = malloc(NMEM*sizeof(Hlist));
+	if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
+	ErrOut:
+		free(data);
+		free(outbuf);
+		free(hash);
+		free(chain);
+		return -1;
+	}
+	for(miny = r.min.y; miny != r.max.y; miny += dy){
+		dy = r.max.y-miny;
+		if(dy*bpl > CHUNK)
+			dy = CHUNK/bpl;
+		nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
+			data+(miny-r.min.y)*bpl, dy*bpl);
+		if(nb != dy*bpl)
+			goto ErrOut;
+	}
+	sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
+		chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
+	if(write(fd, hdr, 11+5*12) != 11+5*12)
+		goto ErrOut;
+	edata = data+n;
+	eout = outbuf+ncblock;
+	line = data;
+	r.max.y = r.min.y;
+	while(line != edata){
+		memset(hash, 0, NHASH*sizeof(Hlist));
+		memset(chain, 0, NMEM*sizeof(Hlist));
+		cp = chain;
+		h = 0;
+		outp = outbuf;
+		for(n = 0; n != NMATCH; n++)
+			h = hupdate(h, line[n]);
+		loutp = outbuf;
+		while(line != edata){
+			ndump = 0;
+			eline = line+bpl;
+			for(p = line; p != eline; ){
+				if(eline-p < NRUN)
+					es = eline;
+				else
+					es = p+NRUN;
+				q = 0;
+				runlen = 0;
+				for(hp = hash[h].next; hp; hp = hp->next){
+					s = p + runlen;
+					if(s >= es)
+						continue;
+					t = hp->s + runlen;
+					for(; s >= p; s--)
+						if(*s != *t--)
+							goto matchloop;
+					t += runlen+2;
+					s += runlen+2;
+					for(; s < es; s++)
+						if(*s != *t++)
+							break;
+					n = s-p;
+					if(n > runlen){
+						runlen = n;
+						q = hp->s;
+						if(n == NRUN)
+							break;
+					}
+			matchloop: ;
+				}
+				if(runlen < NMATCH){
+					if(ndump == NDUMP){
+						if(eout-outp < ndump+1)
+							goto Bfull;
+						*outp++ = ndump-1+128;
+						memmove(outp, dumpbuf, ndump);
+						outp += ndump;
+						ndump = 0;
+					}
+					dumpbuf[ndump++] = *p;
+					runlen = 1;
+				}
+				else{
+					if(ndump != 0){
+						if(eout-outp < ndump+1)
+							goto Bfull;
+						*outp++ = ndump-1+128;
+						memmove(outp, dumpbuf, ndump);
+						outp += ndump;
+						ndump = 0;
+					}
+					offs = p-q-1;
+					if(eout-outp < 2)
+						goto Bfull;
+					*outp++ = ((runlen-NMATCH)<<2) + (offs>>8);
+					*outp++ = offs&255;
+				}
+				for(q = p+runlen; p != q; p++){
+					if(cp->prev)
+						cp->prev->next = 0;
+					cp->next = hash[h].next;
+					cp->prev = &hash[h];
+					if(cp->next)
+						cp->next->prev = cp;
+					cp->prev->next = cp;
+					cp->s = p;
+					if(++cp == &chain[NMEM])
+						cp = chain;
+					if(edata-p > NMATCH)
+						h = hupdate(h, p[NMATCH]);
+				}
+			}
+			if(ndump != 0){
+				if(eout-outp < ndump+1)
+					goto Bfull;
+				*outp++ = ndump-1+128;
+				memmove(outp, dumpbuf, ndump);
+				outp += ndump;
+			}
+			line = eline;
+			loutp = outp;
+			r.max.y++;
+		}
+	Bfull:
+		if(loutp == outbuf)
+			goto ErrOut;
+		n = loutp-outbuf;
+		sprint(hdr, "%11d %11ld ", r.max.y, n);
+		write(fd, hdr, 2*12);
+		write(fd, outbuf, n);
+		r.min.y = r.max.y;
+	}
+	free(data);
+	free(outbuf);
+	free(hash);
+	free(chain);
+	return 0;
+}
--- /dev/null
+++ b/libmemlayer/NOTICE
@@ -1,0 +1,29 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
--- /dev/null
+++ b/libmemlayer/draw.c
@@ -1,0 +1,192 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+struct Draw
+{
+	Point	deltas;
+	Point	deltam;
+	Memlayer		*dstlayer;
+	Memimage	*src;
+	Memimage	*mask;
+	int	op;
+};
+
+static
+void
+ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+	struct Draw *d;
+	Point p0, p1;
+	Rectangle oclipr, srcr, r, mr;
+	int ok;
+
+	d = etc;
+	if(insave && d->dstlayer->save==nil)
+		return;
+
+	p0 = addpt(screenr.min, d->deltas);
+	p1 = addpt(screenr.min, d->deltam);
+
+	if(insave){
+		r = rectsubpt(screenr, d->dstlayer->delta);
+		clipr = rectsubpt(clipr, d->dstlayer->delta);
+	}else
+		r = screenr;
+
+	/* now in logical coordinates */
+
+	/* clipr may have narrowed what we should draw on, so clip if necessary */
+	if(!rectinrect(r, clipr)){
+		oclipr = dst->clipr;
+		dst->clipr = clipr;
+		ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr);
+		dst->clipr = oclipr;
+		if(!ok)
+			return;
+	}
+	memdraw(dst, r, d->src, p0, d->mask, p1, d->op);
+}
+
+void
+memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
+{
+	struct Draw d;
+	Rectangle srcr, tr, mr;
+	Memlayer *dl, *sl;
+
+	if(drawdebug)
+		iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1);
+
+	if(mask == nil)
+		mask = memopaque;
+
+	if(mask->layer){
+if(drawdebug)	iprint("mask->layer != nil\n");
+		return;	/* too hard, at least for now */
+	}
+
+    Top:
+	if(dst->layer==nil && src->layer==nil){
+		memimagedraw(dst, r, src, p0, mask, p1, op);
+		return;
+	}
+
+	if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){
+if(drawdebug)	iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr);
+		return;
+	}
+
+	/*
+ 	 * Convert to screen coordinates.
+	 */
+	dl = dst->layer;
+	if(dl != nil){
+		r.min.x += dl->delta.x;
+		r.min.y += dl->delta.y;
+		r.max.x += dl->delta.x;
+		r.max.y += dl->delta.y;
+	}
+    Clearlayer:
+	if(dl!=nil && dl->clear){
+		if(src == dst){
+			p0.x += dl->delta.x;
+			p0.y += dl->delta.y;
+			src = dl->screen->image;
+		}
+		dst = dl->screen->image;
+		goto Top;
+	}
+
+	sl = src->layer;
+	if(sl != nil){
+		p0.x += sl->delta.x;
+		p0.y += sl->delta.y;
+		srcr.min.x += sl->delta.x;
+		srcr.min.y += sl->delta.y;
+		srcr.max.x += sl->delta.x;
+		srcr.max.y += sl->delta.y;
+	}
+
+	/*
+	 * Now everything is in screen coordinates.
+	 * mask is an image.  dst and src are images or obscured layers.
+	 */
+
+	/*
+	 * if dst and src are the same layer, just draw in save area and expose.
+	 */
+	if(dl!=nil && dst==src){
+		if(dl->save == nil)
+			return;	/* refresh function makes this case unworkable */
+		if(rectXrect(r, srcr)){
+			tr = r;
+			if(srcr.min.x < tr.min.x){
+				p1.x += tr.min.x - srcr.min.x;
+				tr.min.x = srcr.min.x;
+			}
+			if(srcr.min.y < tr.min.y){
+				p1.y += tr.min.x - srcr.min.x;
+				tr.min.y = srcr.min.y;
+			}
+			if(srcr.max.x > tr.max.x)
+				tr.max.x = srcr.max.x;
+			if(srcr.max.y > tr.max.y)
+				tr.max.y = srcr.max.y;
+			memlhide(dst, tr);
+		}else{
+			memlhide(dst, r);
+			memlhide(dst, srcr);
+		}
+		memdraw(dl->save, rectsubpt(r, dl->delta), dl->save,
+			subpt(srcr.min, src->layer->delta), mask, p1, op);
+		memlexpose(dst, r);
+		return;
+	}
+
+	if(sl){
+		if(sl->clear){
+			src = sl->screen->image;
+			if(dl != nil){
+				r.min.x -= dl->delta.x;
+				r.min.y -= dl->delta.y;
+				r.max.x -= dl->delta.x;
+				r.max.y -= dl->delta.y;
+			}
+			goto Top;
+		}
+		/* relatively rare case; use save area */
+		if(sl->save == nil)
+			return;	/* refresh function makes this case unworkable */
+		memlhide(src, srcr);
+		/* convert back to logical coordinates */
+		p0.x -= sl->delta.x;
+		p0.y -= sl->delta.y;
+		srcr.min.x -= sl->delta.x;
+		srcr.min.y -= sl->delta.y;
+		srcr.max.x -= sl->delta.x;
+		srcr.max.y -= sl->delta.y;
+		src = src->layer->save;
+	}
+
+	/*
+	 * src is now an image.  dst may be an image or a clear layer
+	 */
+	if(dst->layer==nil)
+		goto Top;
+	if(dst->layer->clear)
+		goto Clearlayer;
+
+	/*
+	 * dst is an obscured layer
+	 */
+	d.deltas = subpt(p0, r.min);
+	d.deltam = subpt(p1, r.min);
+	d.dstlayer = dl;
+	d.src = src;
+	d.mask = mask;
+	d.op = op;
+	_memlayerop(ldrawop, dst, r, r, &d);
+}
--- /dev/null
+++ b/libmemlayer/lalloc-x11.c
@@ -1,0 +1,185 @@
+#include "lib9.h"
+#include "image.h"
+#include "memimage.h"
+#include "memlayer.h"
+
+#include "../memimage/xmem.h"
+
+
+static ulong colorword;
+static Memdata colordata = {
+	nil,
+	&colorword
+};
+
+static Memimage paint =
+{
+	{ 0, 0, 1, 1 },
+	{ -1000000, -1000000, 10000000, 1000000 },
+	0,
+	1,
+	&colordata,
+	0,
+	1,
+	0,
+};
+
+static Memimage *xpaint;
+
+static void
+setcolor(int val, int ldepth)
+{
+	int bpp;
+
+	paint.ldepth = ldepth;
+	bpp = 1<<ldepth;
+	val &= ~(0xFF>>bpp);
+	/* color is now in low part of word; replicate through pixel */
+	for(; bpp<32; bpp<<=1)
+		val |= val<<bpp;
+	colorword = val;
+}
+
+ulong*
+makememones(void)
+{
+	Xmem *xm;
+	extern Memimage	screenimage;
+	extern void drawreset();
+
+	if(memones->X)
+		return;
+	drawreset();
+	/* set up screen pixmap */
+	xm = malloc(sizeof(Xmem));
+	if(xm == nil){
+		print("can't alloc for screen pixmap\n");
+		return;
+	}
+	if(screenimage.ldepth == 0)
+		xm->pmid0 = xscreenid;
+	else
+		xm->pmid0 = PMundef;
+	xm->pmid = xscreenid;
+	xm->wordp = &xm->word;
+	screenimage.X = xm;
+	screenimage.data->data = &xm->word;
+
+	memones = allocmemimage(paint.r, paint.ldepth);
+	memones->clipr = paint.clipr;
+	memones->repl = 1;
+	memfillcolor(memones, ~0);
+
+	return screenimage.data->data;
+}
+
+Memimage*
+memlalloc(Memscreen *s, Rectangle screenr, Refreshfn refreshfn, void *refreshptr, int val)
+{
+	Memimage *n;
+	Memlayer *l;
+	Xmem *xm, *sxm;
+
+	n = malloc(sizeof(Memimage));
+	if(n == nil)
+		return nil;
+
+	l = malloc(sizeof(Memlayer));
+	if(l == nil){
+		free(n);
+		return nil;
+	}
+
+	xm = malloc(sizeof(Xmem));
+	if(xm == nil){
+		free(l);
+		free(n);
+		return nil;
+	}
+
+	if(refreshfn) {
+		l->save = nil;
+	}
+	else{
+		l->save = allocmemimage(screenr, s->image->ldepth);
+		if(l->save == nil){
+			free(l);
+			free(n);
+			free(xm);
+			return nil;
+		}
+
+		/* allocmemimage doesn't initialize memory; this paints save area */
+		if(val >= 0)
+			memfillcolor(l->save, val);
+	}
+
+	n->r = screenr;
+	n->clipr = screenr;
+	n->ldepth = s->image->ldepth;
+	n->repl = 0;
+	n->data = s->image->data;
+	n->zero = s->image->zero;
+	n->width = s->image->width;
+	n->layer = l;
+	n->X = xm;
+
+	sxm = s->image->X;
+	xm->pmid0 = sxm->pmid0;
+	xm->pmid = sxm->pmid;
+	xm->flag = 0;
+	xm->wordp = sxm->wordp;
+
+	l->screen = s;
+	l->refreshfn = refreshfn;
+	l->screenr = screenr;
+	l->delta = Pt(0,0);
+
+	/* start with new window behind all existing ones */
+	l->front = s->rearmost;
+	l->rear = nil;
+	if(s->rearmost)
+		s->rearmost->layer->rear = n;
+	s->rearmost = n;
+	if(s->frontmost == nil)
+		s->frontmost = n;
+	l->clear = 0;
+
+	/* don't set it until we're done */
+	l->refreshptr = nil;	
+
+	/* now pull new window to front */
+	memltofront(n);
+
+	/* now we're done */
+	l->refreshptr = refreshptr;
+
+	/*
+	 * paint with requested color.
+	 * previously exposed areas are already right
+	 * if this window has backing store, but just painting 
+	 * the whole thing is simplest.
+	 */
+
+	if(val >= 0){
+		setcolor(val, s->image->ldepth);
+		if(xpaint == nil){
+			xpaint = allocmemimage(paint.r, paint.ldepth);
+			if(xpaint == nil) {
+				if(l->save != nil)
+					freememimage(l->save);
+				free(l);
+				free(n);
+				free(xm);
+				return nil;
+			}
+			xpaint->clipr = paint.clipr;
+			xpaint->repl = 1;
+		}
+		((Xmem*)(xpaint->X))->word = colorword;
+		((Xmem*)(xpaint->X))->flag |= XXonepixel;
+		memfillcolor(xpaint, val);
+		memdraw(n, n->r, xpaint, n->r.min, memones, n->r.min, S);
+	}
+	return n;
+}
--- /dev/null
+++ b/libmemlayer/lalloc.c
@@ -1,0 +1,78 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+Memimage*
+memlalloc(Memscreen *s, Rectangle screenr, Refreshfn refreshfn, void *refreshptr, ulong val)
+{
+	Memlayer *l;
+	Memimage *n;
+	static Memimage *paint;
+
+	if(paint == nil){
+		paint = allocmemimage(Rect(0,0,1,1), RGBA32);
+		if(paint == nil)
+			return nil;
+		paint->flags |= Frepl;
+		paint->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+	}
+
+	n = allocmemimaged(screenr, s->image->chan, s->image->data);
+	if(n == nil)
+		return nil;
+	l = malloc(sizeof(Memlayer));
+	if(l == nil){
+		free(n);
+		return nil;
+	}
+
+	l->screen = s;
+	if(refreshfn)
+		l->save = nil;
+	else{
+		l->save = allocmemimage(screenr, s->image->chan);
+		if(l->save == nil){
+			free(l);
+			free(n);
+			return nil;
+		}
+		/* allocmemimage doesn't initialize memory; this paints save area */
+		if(val != DNofill)
+			memfillcolor(l->save, val);
+	}
+	l->refreshfn = refreshfn;
+	l->refreshptr = nil;	/* don't set it until we're done */
+	l->screenr = screenr;
+	l->delta = Pt(0,0);
+
+	n->data->ref++;
+	n->zero = s->image->zero;
+	n->width = s->image->width;
+	n->layer = l;
+
+	/* start with new window behind all existing ones */
+	l->front = s->rearmost;
+	l->rear = nil;
+	if(s->rearmost)
+		s->rearmost->layer->rear = n;
+	s->rearmost = n;
+	if(s->frontmost == nil)
+		s->frontmost = n;
+	l->clear = 0;
+
+	/* now pull new window to front */
+	_memltofrontfill(n, val != DNofill);
+	l->refreshptr = refreshptr;
+
+	/*
+	 * paint with requested color; previously exposed areas are already right
+	 * if this window has backing store, but just painting the whole thing is simplest.
+	 */
+	if(val != DNofill){
+		memsetchan(paint, n->chan);
+		memfillcolor(paint, val);
+		memdraw(n, n->r, paint, n->r.min, nil, n->r.min, S);
+	}
+	return n;
+}
--- /dev/null
+++ b/libmemlayer/layerop.c
@@ -1,0 +1,111 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+#define	RECUR(a,b,c,d)	_layerop(fn, i, Rect(a.x, b.y, c.x, d.y), clipr, etc, front->layer->rear);
+
+static void
+_layerop(
+	void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
+	Memimage *i,
+	Rectangle r,
+	Rectangle clipr,
+	void *etc,
+	Memimage *front)
+{
+	Rectangle fr;
+
+    Top:
+	if(front == i){
+		/* no one is in front of this part of window; use the screen */
+		fn(i->layer->screen->image, r, clipr, etc, 0);
+		return;
+	}
+	fr = front->layer->screenr;
+	if(rectXrect(r, fr) == 0){
+		/* r doesn't touch this window; continue on next rearmost */
+	/* assert(front && front->layer && front->layer->screen && front->layer->rear); */
+		front = front->layer->rear;
+		goto Top;
+	}
+	if(fr.max.y < r.max.y){
+		RECUR(r.min, fr.max, r.max, r.max);
+		r.max.y = fr.max.y;
+	}
+	if(r.min.y < fr.min.y){
+		RECUR(r.min, r.min, r.max, fr.min);
+		r.min.y = fr.min.y;
+	}
+	if(fr.max.x < r.max.x){
+		RECUR(fr.max, r.min, r.max, r.max);
+		r.max.x = fr.max.x;
+	}
+	if(r.min.x < fr.min.x){
+		RECUR(r.min, r.min, fr.min, r.max);
+		r.min.x = fr.min.x;
+	}
+	/* r is covered by front, so put in save area */
+	(*fn)(i->layer->save, r, clipr, etc, 1);
+}
+
+/*
+ * Assumes incoming rectangle has already been clipped to i's logical r and clipr
+ */
+void
+_memlayerop(
+	void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
+	Memimage *i,
+	Rectangle screenr,	/* clipped to window boundaries */
+	Rectangle clipr,		/* clipped also to clipping rectangles of hierarchy */
+	void *etc)
+{
+	Memlayer *l;
+	Rectangle r, scr;
+
+	l = i->layer;
+	if(!rectclip(&screenr, l->screenr))
+		return;
+	if(l->clear){
+		fn(l->screen->image, screenr, clipr, etc, 0);
+		return;
+	}
+	r = screenr;
+	scr = l->screen->image->clipr;
+
+	/*
+	 * Do the piece on the screen
+	 */
+	if(rectclip(&screenr, scr))
+		_layerop(fn, i, screenr, clipr, etc, l->screen->frontmost);
+	if(rectinrect(r, scr))
+		return;
+
+	/*
+	 * Do the piece off the screen
+	*/
+	if(!rectXrect(r, scr)){
+		/* completely offscreen; easy */
+		fn(l->save, r, clipr, etc, 1);
+		return;
+	}
+	if(r.min.y < scr.min.y){
+		/* above screen */
+		fn(l->save, Rect(r.min.x, r.min.y, r.max.x, scr.min.y), clipr, etc, 1);
+		r.min.y = scr.min.y;
+	}
+	if(r.max.y > scr.max.y){
+		/* below screen */
+		fn(l->save, Rect(r.min.x, scr.max.y, r.max.x, r.max.y), clipr, etc, 1);
+		r.max.y = scr.max.y;
+	}
+	if(r.min.x < scr.min.x){
+		/* left of screen */
+		fn(l->save, Rect(r.min.x, r.min.y, scr.min.x, r.max.y), clipr, etc, 1);
+		r.min.x = scr.min.x;
+	}
+	if(r.max.x > scr.max.x){
+		/* right of screen */
+		fn(l->save, Rect(scr.max.x, r.min.y, r.max.x, r.max.y), clipr, etc, 1);
+	}
+}
--- /dev/null
+++ b/libmemlayer/ldelete.c
@@ -1,0 +1,66 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+memldelete(Memimage *i)
+{
+	Memscreen *s;
+	Memlayer *l;
+
+	l = i->layer;
+	/* free backing store and disconnect refresh, to make pushback fast */
+	freememimage(l->save);
+	l->save = nil;
+	l->refreshptr = nil;
+	memltorear(i);
+
+	/* window is now the rearmost;  clean up screen structures and deallocate */
+	s = i->layer->screen;
+	if(s->fill){
+		i->clipr = i->r;
+		memdraw(i, i->r, s->fill, i->r.min, nil, i->r.min, S);
+	}
+	if(l->front){
+		l->front->layer->rear = nil;
+		s->rearmost = l->front;
+	}else{
+		s->frontmost = nil;
+		s->rearmost = nil;
+	}
+	free(l);
+	freememimage(i);
+}
+
+/*
+ * Just free the data structures, don't do graphics
+ */
+void
+memlfree(Memimage *i)
+{
+	Memlayer *l;
+
+	l = i->layer;
+	freememimage(l->save);
+	free(l);
+	freememimage(i);
+}
+
+void
+_memlsetclear(Memscreen *s)
+{
+	Memimage *i, *j;
+	Memlayer *l;
+
+	for(i=s->rearmost; i; i=i->layer->front){
+		l = i->layer;
+		l->clear = rectinrect(l->screenr, l->screen->image->clipr);
+		if(l->clear)
+			for(j=l->front; j; j=j->layer->front)
+				if(rectXrect(l->screenr, j->layer->screenr)){
+					l->clear = 0;
+					break;
+				}
+	}
+}
--- /dev/null
+++ b/libmemlayer/lhide.c
@@ -1,0 +1,67 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+/*
+ * Hide puts that portion of screenr now on the screen into the window's save area.
+ * Expose puts that portion of screenr now in the save area onto the screen.
+ *
+ * Hide and Expose both require that the layer structures in the screen
+ * match the geometry they are being asked to update, that is, they update the
+ * save area (hide) or screen (expose) based on what those structures tell them.
+ * This means they must be called at the correct time during window shuffles.
+ */
+
+static
+void
+lhideop(Memimage *src, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+	Rectangle r;
+	Memlayer *l;
+
+	USED(clipr.min.x);
+	USED(insave);
+	l = etc;
+	if(src != l->save){	/* do nothing if src is already in save area */
+		r = rectsubpt(screenr, l->delta);
+		memdraw(l->save, r, src, screenr.min, nil, screenr.min, S);
+	}
+}
+
+void
+memlhide(Memimage *i, Rectangle screenr)
+{
+	if(i->layer->save == nil)
+		return;
+	if(rectclip(&screenr, i->layer->screen->image->r) == 0)
+		return;
+	_memlayerop(lhideop, i, screenr, screenr, i->layer);
+}
+
+static
+void
+lexposeop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+	Memlayer *l;
+	Rectangle r;
+
+	USED(clipr.min.x);
+	if(insave)	/* if dst is save area, don't bother */
+		return;
+	l = etc;
+	r = rectsubpt(screenr, l->delta);
+	if(l->save)
+		memdraw(dst, screenr, l->save, r.min, nil, r.min, S);
+	else
+		l->refreshfn(dst, r, l->refreshptr);
+}
+
+void
+memlexpose(Memimage *i, Rectangle screenr)
+{
+	if(rectclip(&screenr, i->layer->screen->image->r) == 0)
+		return;
+	_memlayerop(lexposeop, i, screenr, screenr, i->layer);
+}
--- /dev/null
+++ b/libmemlayer/line.c
@@ -1,0 +1,121 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+struct Lline
+{
+	Point			p0;
+	Point			p1;
+	Point			delta;
+	int			end0;
+	int			end1;
+	int			radius;
+	Point			sp;
+	Memlayer		*dstlayer;
+	Memimage	*src;
+	int	op;
+};
+
+static void llineop(Memimage*, Rectangle, Rectangle, void*, int);
+
+static
+void
+_memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, Rectangle clipr, int op)
+{
+	Rectangle r;
+	struct Lline ll;
+	Point d;
+	int srcclipped;
+	Memlayer *dl;
+
+	if(radius < 0)
+		return;
+	if(src->layer)	/* can't draw line with layered source */
+		return;
+	srcclipped = 0;
+
+   Top:
+	dl = dst->layer;
+	if(dl == nil){
+		_memimageline(dst, p0, p1, end0, end1, radius, src, sp, clipr, op);
+		return;
+	}
+	if(!srcclipped){
+		d = subpt(sp, p0);
+		if(rectclip(&clipr, rectsubpt(src->clipr, d)) == 0)
+			return;
+		if((src->flags&Frepl)==0 && rectclip(&clipr, rectsubpt(src->r, d))==0)
+			return;
+		srcclipped = 1;
+	}
+
+	/* dst is known to be a layer */
+	p0.x += dl->delta.x;
+	p0.y += dl->delta.y;
+	p1.x += dl->delta.x;
+	p1.y += dl->delta.y;
+	clipr.min.x += dl->delta.x;
+	clipr.min.y += dl->delta.y;
+	clipr.max.x += dl->delta.x;
+	clipr.max.y += dl->delta.y;
+	if(dl->clear){
+		dst = dst->layer->screen->image;
+		goto Top;
+	}
+
+	/* XXX */
+	/* this is not the correct set of tests */
+//	if(log2[dst->depth] != log2[src->depth] || log2[dst->depth]!=3)
+//		return;
+
+	/* can't use sutherland-cohen clipping because lines are wide */
+	r = memlinebbox(p0, p1, end0, end1, radius);
+	/*
+	 * r is now a bounding box for the line;
+	 * use it as a clipping rectangle for subdivision
+	 */
+	if(rectclip(&r, clipr) == 0)
+		return;
+	ll.p0 = p0;
+	ll.p1 = p1;
+	ll.end0 = end0;
+	ll.end1 = end1;
+	ll.sp = sp;
+	ll.dstlayer = dst->layer;
+	ll.src = src;
+	ll.radius = radius;
+	ll.delta = dl->delta;
+	ll.op = op;
+	_memlayerop(llineop, dst, r, r, &ll);
+}
+
+static
+void
+llineop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
+{
+	struct Lline *ll;
+	Point p0, p1;
+
+	USED(screenr.min.x);
+	ll = etc;
+	if(insave && ll->dstlayer->save==nil)
+		return;
+	if(!rectclip(&clipr, screenr))
+		return;
+	if(insave){
+		p0 = subpt(ll->p0, ll->delta);
+		p1 = subpt(ll->p1, ll->delta);
+		clipr = rectsubpt(clipr, ll->delta);
+	}else{
+		p0 = ll->p0;
+		p1 = ll->p1;
+	}
+	_memline(dst, p0, p1, ll->end0, ll->end1, ll->radius, ll->src, ll->sp, clipr, ll->op);
+}
+
+void
+memline(Memimage *dst, Point p0, Point p1, int end0, int end1, int radius, Memimage *src, Point sp, int op)
+{
+	_memline(dst, p0, p1, end0, end1, radius, src, sp, dst->clipr, op);
+}
--- /dev/null
+++ b/libmemlayer/load.c
@@ -1,0 +1,54 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memload(Memimage *dst, Rectangle r, uchar *data, int n, int iscompressed)
+{
+	int (*loadfn)(Memimage*, Rectangle, uchar*, int);
+	Memimage *tmp;
+	Memlayer *dl;
+	Rectangle lr;
+	int dx;
+
+	loadfn = loadmemimage;
+	if(iscompressed)
+		loadfn = cloadmemimage;
+
+    Top:
+	dl = dst->layer;
+	if(dl == nil)
+		return loadfn(dst, r, data, n);
+
+	/*
+ 	 * Convert to screen coordinates.
+	 */
+	lr = r;
+	r.min.x += dl->delta.x;
+	r.min.y += dl->delta.y;
+	r.max.x += dl->delta.x;
+	r.max.y += dl->delta.y;
+	dx = dl->delta.x&(7/dst->depth);
+	if(dl->clear && dx==0){
+		dst = dl->screen->image;
+		goto Top;
+	}
+
+	/*
+	 * dst is an obscured layer or data is unaligned
+	 */
+	if(dl->save && dx==0){
+		n = loadfn(dl->save, lr, data, n);
+		if(n > 0)
+			memlexpose(dst, r);
+		return n;
+	}
+	tmp = allocmemimage(lr, dst->chan);
+	if(tmp == nil)
+		return -1;
+	n = loadfn(tmp, lr, data, n);
+	memdraw(dst, lr, tmp, lr.min, nil, lr.min, S);
+	freememimage(tmp);
+	return n;
+}
--- /dev/null
+++ b/libmemlayer/lorigin.c
@@ -1,0 +1,106 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+/*
+ * Place i so i->r.min = log, i->layer->screenr.min == scr.
+*/
+int
+memlorigin(Memimage *i, Point log, Point scr)
+{
+	Memlayer *l;
+	Memscreen *s;
+	Memimage *t, *shad, *nsave;
+	Rectangle x, newr, oldr;
+	Point delta;
+	int overlap, eqlog, eqscr, wasclear;
+
+	l = i->layer;
+	s = l->screen;
+	oldr = l->screenr;
+	newr = Rect(scr.x, scr.y, scr.x+Dx(oldr), scr.y+Dy(oldr));
+	eqscr = eqpt(scr, oldr.min);
+	eqlog = eqpt(log, i->r.min);
+	if(eqscr && eqlog)
+		return 0;
+	nsave = nil;
+	if(eqlog==0 && l->save!=nil){
+		nsave = allocmemimage(Rect(log.x, log.y, log.x+Dx(oldr), log.y+Dy(oldr)), i->chan);
+		if(nsave == nil)
+			return -1;
+	}
+
+	/*
+	 * Bring it to front and move logical coordinate system.
+	 */
+	memltofront(i);
+	wasclear = l->clear;
+	if(nsave){
+		if(!wasclear)
+			memimagedraw(nsave, nsave->r, l->save, l->save->r.min, nil, Pt(0,0), S);
+		freememimage(l->save);
+		l->save = nsave;
+	}
+	delta = subpt(log, i->r.min);
+	i->r = rectaddpt(i->r, delta);
+	i->clipr = rectaddpt(i->clipr, delta);
+	l->delta = subpt(l->screenr.min, i->r.min);
+	if(eqscr)
+		return 0;
+
+	/*
+	 * To clean up old position, make a shadow window there, don't paint it,
+	 * push it behind this one, and (later) delete it.  Because the refresh function
+	 * for this fake window is a no-op, this will cause no graphics action except
+	 * to restore the background and expose the windows previously hidden.
+	 */
+	shad = memlalloc(s, oldr, memlnorefresh, nil, DNofill);
+	if(shad == nil)
+		return -1;
+	s->frontmost = i;
+	if(s->rearmost == i)
+		s->rearmost = shad;
+	else
+		l->rear->layer->front = shad;
+	shad->layer->front = i;
+	shad->layer->rear = l->rear;
+	l->rear = shad;
+	l->front = nil;
+	shad->layer->clear = 0;
+
+	/*
+	 * Shadow is now holding down the fort at the old position.
+	 * Move the window and hide things obscured by new position.
+	 */
+	for(t=l->rear->layer->rear; t!=nil; t=t->layer->rear){
+		x = newr;
+		overlap = rectclip(&x, t->layer->screenr);
+		if(overlap){
+			memlhide(t, x);
+			t->layer->clear = 0;
+		}
+	}
+	l->screenr = newr;
+	l->delta = subpt(scr, i->r.min);
+	l->clear = rectinrect(newr, l->screen->image->clipr);
+
+	/*
+	 * Everything's covered.  Copy to new position and delete shadow window.
+	 */
+	if(wasclear)
+		memdraw(s->image, newr, s->image, oldr.min, nil, Pt(0,0), S);
+	else
+		memlexpose(i, newr);
+	memldelete(shad);
+
+	return 1;
+}
+
+void
+memlnorefresh(Memimage *l, Rectangle r, void *v)
+{
+	USED(l);
+	USED(r.min.x);
+	USED(v);
+}
--- /dev/null
+++ b/libmemlayer/lsetrefresh.c
@@ -1,0 +1,34 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memlsetrefresh(Memimage *i, Refreshfn fn, void *ptr)
+{
+	Memlayer *l;
+
+	l = i->layer;
+	if(l->refreshfn!=nil && fn!=nil){	/* just change functions */
+		l->refreshfn = fn;
+		l->refreshptr = ptr;
+		return 1;
+	}
+
+	if(l->refreshfn == nil){	/* is using backup image; just free it */
+		freememimage(l->save);
+		l->save = nil;
+		l->refreshfn = fn;
+		l->refreshptr = ptr;
+		return 1;
+	}
+
+	l->save = allocmemimage(i->r, i->chan);
+	if(l->save == nil)
+		return 0;
+	/* easiest way is just to update the entire save area */
+	l->refreshfn(i, i->r, l->refreshptr);
+	l->refreshfn = nil;
+	l->refreshptr = nil;
+	return 1;
+}
--- /dev/null
+++ b/libmemlayer/ltofront.c
@@ -1,0 +1,80 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+#include "pool.h"
+
+/*
+ * Pull i towards top of screen, just behind front
+*/
+static
+void
+_memltofront(Memimage *i, Memimage *front, int fill)
+{
+	Memlayer *l;
+	Memscreen *s;
+	Memimage *f, *ff, *rr;
+	Rectangle x;
+	int overlap;
+
+	l = i->layer;
+	s = l->screen;
+	while(l->front != front){
+		f = l->front;
+		x = l->screenr;
+		overlap = rectclip(&x, f->layer->screenr);
+		if(overlap){
+			memlhide(f, x);
+			f->layer->clear = 0;
+		}
+		/* swap l and f in screen's list */
+		ff = f->layer->front;
+		rr = l->rear;
+		if(ff == nil)
+			s->frontmost = i;
+		else
+			ff->layer->rear = i;
+		if(rr == nil)
+			s->rearmost = f;
+		else
+			rr->layer->front = f;
+		l->front = ff;
+		l->rear = f;
+		f->layer->front = i;
+		f->layer->rear = rr;
+		if(overlap && fill)
+			memlexpose(i, x);
+	}
+}
+
+void
+_memltofrontfill(Memimage *i, int fill)
+{
+	_memltofront(i, nil, fill);
+	_memlsetclear(i->layer->screen);
+}
+
+void
+memltofront(Memimage *i)
+{
+	_memltofront(i, nil, 1);
+	_memlsetclear(i->layer->screen);
+}
+
+void
+memltofrontn(Memimage **ip, int n)
+{
+	Memimage *i, *front;
+	Memscreen *s;
+
+	if(n == 0)
+		return;
+	front = nil;
+	while(--n >= 0){
+		i = *ip++;
+		_memltofront(i, front, 1);
+		front = i;
+	}
+	s = front->layer->screen;
+	_memlsetclear(s);
+}
--- /dev/null
+++ b/libmemlayer/ltorear.c
@@ -1,0 +1,68 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+void
+_memltorear(Memimage *i, Memimage *rear)
+{
+	Memlayer *l;
+	Memscreen *s;
+	Memimage *f, *r, *rr;
+	Rectangle x;
+	int overlap;
+
+	l = i->layer;
+	s = l->screen;
+	while(l->rear != rear){
+		r = l->rear;
+		x = l->screenr;
+		overlap = rectclip(&x, r->layer->screenr);
+		if(overlap){
+			memlhide(i, x);
+			l->clear = 0;
+		}
+		/* swap l and r in screen's list */
+		rr = r->layer->rear;
+		f = l->front;
+		if(rr == nil)
+			s->rearmost = i;
+		else
+			rr->layer->front = i;
+		if(f == nil)
+			s->frontmost = r;
+		else
+			f->layer->rear = r;
+		l->rear = rr;
+		l->front = r;
+		r->layer->rear = i;
+		r->layer->front = f;
+		if(overlap)
+			memlexpose(r, x);
+	}
+}
+
+void
+memltorear(Memimage *i)
+{
+	_memltorear(i, nil);
+	_memlsetclear(i->layer->screen);
+}
+
+void
+memltorearn(Memimage **ip, int n)
+{
+	Memimage *i, *rear;
+	Memscreen *s;
+
+	if(n == 0)
+		return;
+	rear = nil;
+	while(--n >= 0){
+		i = *ip++;
+		_memltorear(i, rear);
+		rear = i;
+	}
+	s = rear->layer->screen;
+	_memlsetclear(s);
+}
--- /dev/null
+++ b/libmemlayer/mkfile
@@ -1,0 +1,26 @@
+<../mkconfig
+
+LIB=libmemlayer.a
+
+COMMONFILES=\
+	draw.$O\
+	layerop.$O\
+	ldelete.$O\
+	lhide.$O\
+	line.$O\
+	load.$O\
+	lorigin.$O\
+	lsetrefresh.$O\
+	ltofront.$O\
+	ltorear.$O\
+	unload.$O\
+
+<mkfile-$SYSTARG		#sets $SYSFILES based on OS architecture
+
+OFILES=$COMMONFILES $SYSFILES
+
+HFILES=	$ROOT/include/draw.h\
+	$ROOT/include/memdraw.h\
+	$ROOT/include/memlayer.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmemlayer/mkfile-FreeBSD
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Hp
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Inferno
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Irix
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Linux
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-MacOSX
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-NetBSD
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Nt
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Nt model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-OpenBSD
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Plan9
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Posix
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Solaris
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-Unixware
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Posix model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/mkfile-os
@@ -1,0 +1,4 @@
+#
+#	System dependent objects for Inferno model systems
+#
+SYSFILES=lalloc.$O
--- /dev/null
+++ b/libmemlayer/unload.c
@@ -1,0 +1,51 @@
+#include "lib9.h"
+#include "draw.h"
+#include "memdraw.h"
+#include "memlayer.h"
+
+int
+memunload(Memimage *src, Rectangle r, uchar *data, int n)
+{
+	Memimage *tmp;
+	Memlayer *dl;
+	Rectangle lr;
+	int dx;
+
+    Top:
+	dl = src->layer;
+	if(dl == nil)
+		return unloadmemimage(src, r, data, n);
+
+	/*
+ 	 * Convert to screen coordinates.
+	 */
+	lr = r;
+	r.min.x += dl->delta.x;
+	r.min.y += dl->delta.y;
+	r.max.x += dl->delta.x;
+	r.max.y += dl->delta.y;
+	dx = dl->delta.x&(7/src->depth);
+	if(dl->clear && dx==0){
+		src = dl->screen->image;
+		goto Top;
+	}
+
+	/*
+	 * src is an obscured layer or data is unaligned
+	 */
+	if(dl->save && dx==0){
+		if(dl->refreshfn != nil)
+			return -1;	/* can't unload window if it's not Refbackup */
+		if(n > 0)
+			memlhide(src, r);
+		n = unloadmemimage(dl->save, lr, data, n);
+		return n;
+	}
+	tmp = allocmemimage(lr, src->chan);
+	if(tmp == nil)
+		return -1;
+	memdraw(tmp, lr, src, lr.min, nil, lr.min, S);
+	n = unloadmemimage(tmp, lr, data, n);
+	freememimage(tmp);
+	return n;
+}
--- /dev/null
+++ b/libmp/Inferno-386/mkfile
@@ -1,0 +1,22 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+OBJDIR=Inferno/$OBJTYPE
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+	mpdigdiv.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-386/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT	mpdigdiv(SB),$0
+
+	MOVL	dividend+0(FP),BX
+	MOVL	0(BX),AX
+	MOVL	4(BX),DX
+	MOVL	divisor+4(FP),BX
+	MOVL	quotient+8(FP),BP
+	XORL	CX,CX
+	CMPL	DX,BX		/* dividend >= 2^32 * divisor */
+	JHS	_divovfl
+	CMPL	BX,CX		/* divisor == 0 */
+	JE	_divovfl
+	DIVL	BX		/* AX = DX:AX/BX */
+	MOVL	AX,0(BP)
+	RET
+
+	/* return all 1's */
+_divovfl:
+	NOTL	CX
+	MOVL	CX,0(BP)
+	RET
--- /dev/null
+++ b/libmp/Inferno-386/mpvecadd.s
@@ -1,0 +1,53 @@
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT	mpvecadd(SB),$0
+
+	MOVL	alen+4(FP),DX
+	MOVL	blen+12(FP),CX
+	MOVL	a+0(FP),SI
+	MOVL	b+8(FP),BX
+	SUBL	CX,DX
+	MOVL	sum+16(FP),DI
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip addition if b is zero */
+	TESTL	CX,CX
+	JZ	_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+	MOVL	(SI)(BP*4), AX
+	ADCL	(BX)(BP*4), AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop1
+
+_add1:
+	/* jump if alen > blen */
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	JC	_addcarry
+	MOVL	$0,(DI)(BP*4)
+	RET
+_addcarry:
+	MOVL	$1,(DI)(BP*4)
+	RET
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+	MOVL	(SI)(BP*4),AX
+	ADCL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop2
+	JMP	_addend
+
--- /dev/null
+++ b/libmp/Inferno-386/mpvecdigmuladd.s
@@ -1,0 +1,52 @@
+/*
+ *	mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b+n = SI	- can't be BP
+ *		p+n = DI	- can't be BP
+ *		i-n = BP
+ *		m = BX
+ *		oldhi = CX
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+	MOVL	b+0(FP),SI
+	MOVL	n+4(FP),CX
+	MOVL	m+8(FP),BX
+	MOVL	p+12(FP),DI
+	MOVL	CX,BP
+	NEGL	BP		/* BP = -n */
+	SHLL	$2,CX
+	ADDL	CX,SI		/* SI = b + n */
+	ADDL	CX,DI		/* DI = p + n */
+	XORL	CX,CX
+_muladdloop:
+	MOVL	(SI)(BP*4),AX	/* lo = b[i] */
+	MULL	BX		/* hi, lo = b[i] * m */
+	ADDL	CX,AX		/* lo += oldhi */
+	JCC	_muladdnocarry1
+	INCL	DX		/* hi += carry */
+_muladdnocarry1:
+	ADDL	AX,(DI)(BP*4)	/* p[i] += lo */
+	JCC	_muladdnocarry2
+	INCL	DX		/* hi += carry */
+_muladdnocarry2:
+	MOVL	DX,CX		/* oldhi = hi */
+	INCL	BP		/* i++ */
+	JNZ	_muladdloop
+	XORL	AX,AX
+	ADDL	CX,(DI)(BP*4)	/* p[n] + oldhi */
+	ADCL	AX,AX		/* return carry out of p[n] */
+	RET
--- /dev/null
+++ b/libmp/Inferno-386/mpvecdigmulsub.s
@@ -1,0 +1,53 @@
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b = SI		- can't be BP
+ *		p = DI		- can't be BP
+ *		i = BP
+ *		n = CX		- constrained by LOOP instr
+ *		m = BX
+ *		oldhi = EX
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+	MOVL	b+0(FP),SI
+	MOVL	n+4(FP),CX
+	MOVL	m+8(FP),BX
+	MOVL	p+12(FP),DI
+	XORL	BP,BP
+	PUSHL	BP
+_mulsubloop:
+	MOVL	(SI)(BP*4),AX		/* lo = b[i] */
+	MULL	BX			/* hi, lo = b[i] * m */
+	ADDL	0(SP),AX		/* lo += oldhi */
+	JCC	_mulsubnocarry1
+	INCL	DX			/* hi += carry */
+_mulsubnocarry1:
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry2
+	INCL	DX			/* hi += carry */
+_mulsubnocarry2:
+	MOVL	DX,0(SP)
+	INCL	BP
+	LOOP	_mulsubloop
+	POPL	AX
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry3
+	MOVL	$-1,AX
+	RET
+_mulsubnocarry3:
+	MOVL	$1,AX
+	RET
--- /dev/null
+++ b/libmp/Inferno-386/mpvecsub.s
@@ -1,0 +1,44 @@
+/*
+ *	mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ *		diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT	mpvecsub(SB),$0
+
+	MOVL	a+0(FP),SI
+	MOVL	b+8(FP),BX
+	MOVL	alen+4(FP),DX
+	MOVL	blen+12(FP),CX
+	MOVL	diff+16(FP),DI
+	SUBL	CX,DX
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip subraction if b is zero */
+	TESTL	CX,CX
+	JZ	_sub1
+
+	/* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+	MOVL	(SI)(BP*4),AX
+	SBBL	(BX)(BP*4),AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop1
+
+_sub1:
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_subloop2
+	RET
+
+	/* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+	MOVL	(SI)(BP*4),AX
+	SBBL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop2
+	RET
+
--- /dev/null
+++ b/libmp/Inferno-amd64/mkfile
@@ -1,0 +1,21 @@
+objtype=amd64
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+	mpdigdiv.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-amd64/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT	mpdigdiv(SB),$0
+
+/*	MOVL	dividend+0(FP),BX */
+	MOVL	0(RARG),AX
+	MOVL	4(RARG),DX
+	MOVL	divisor+8(FP),BX
+	MOVQ	quotient+16(FP),DI
+	XORL	CX,CX
+	CMPL	DX,BX		/* dividend >= 2^32 * divisor */
+	JHS	_divovfl
+	CMPL	BX,CX		/* divisor == 0 */
+	JE	_divovfl
+	DIVL	BX		/* AX = DX:AX/BX */
+	MOVL	AX,0(DI)
+	RET
+
+	/* return all 1's */
+_divovfl:
+	NOTL	CX
+	MOVL	CX,0(DI)
+	RET
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecadd.s
@@ -1,0 +1,54 @@
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT	mpvecadd(SB),$0
+
+	MOVL	alen+8(FP),DX
+	MOVL	blen+24(FP),CX
+/*	MOVL	a+0(FP),SI */
+	MOVQ	RARG, SI
+	MOVQ	b+16(FP),BX
+	SUBL	CX,DX
+	MOVQ	sum+32(FP),DI
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip addition if b is zero */
+	TESTL	CX,CX
+	JZ	_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+	MOVL	(SI)(BP*4), AX
+	ADCL	(BX)(BP*4), AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop1
+
+_add1:
+	/* jump if alen > blen */
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	JC	_addcarry
+	MOVL	$0,(DI)(BP*4)
+	RET
+_addcarry:
+	MOVL	$1,(DI)(BP*4)
+	RET
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+	MOVL	(SI)(BP*4),AX
+	ADCL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop2
+	JMP	_addend
+
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecdigmuladd.s
@@ -1,0 +1,53 @@
+/*
+ *	mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b+n = SI	- can't be BP
+ *		p+n = DI	- can't be BP
+ *		i-n = BP
+ *		m = BX
+ *		oldhi = CX
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+/*	MOVQ	b+0(FP),SI	*/
+	MOVQ	RARG,SI
+	MOVL	n+8(FP),CX
+	MOVL	m+16(FP),BX
+	MOVQ	p+24(FP),DI
+	MOVL	CX,BP
+	NEGQ	BP		/* BP = -n */
+	SHLL	$2,CX
+	ADDQ	CX,SI		/* SI = b + n */
+	ADDQ	CX,DI		/* DI = p + n */
+	XORL	CX,CX
+_muladdloop:
+	MOVL	(SI)(BP*4),AX	/* lo = b[i] */
+	MULL	BX		/* hi, lo = b[i] * m */
+	ADDL	CX,AX		/* lo += oldhi */
+	JCC	_muladdnocarry1
+	INCL	DX		/* hi += carry */
+_muladdnocarry1:
+	ADDL	AX,(DI)(BP*4)	/* p[i] += lo */
+	JCC	_muladdnocarry2
+	INCL	DX		/* hi += carry */
+_muladdnocarry2:
+	MOVL	DX,CX		/* oldhi = hi */
+	INCQ	BP		/* i++ */
+	JNZ	_muladdloop
+	XORL	AX,AX
+	ADDL	CX,(DI)(BP*4)	/* p[n] + oldhi */
+	ADCL	AX,AX		/* return carry out of p[n] */
+	RET
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecdigmulsub.s
@@ -1,0 +1,54 @@
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b = SI		- can't be BP
+ *		p = DI		- can't be BP
+ *		i = BP
+ *		n = CX		- constrained by LOOP instr
+ *		m = BX
+ *		oldhi = EX
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+/*	MOVL	b+0(FP),SI	*/
+	MOVQ	RARG,SI
+	MOVL	n+8(FP),CX
+	MOVL	m+16(FP),BX
+	MOVQ	p+24(FP),DI
+	XORL	BP,BP
+	PUSHQ	BP
+_mulsubloop:
+	MOVL	(SI)(BP*4),AX		/* lo = b[i] */
+	MULL	BX			/* hi, lo = b[i] * m */
+	ADDL	0(SP),AX		/* lo += oldhi */
+	JCC	_mulsubnocarry1
+	INCL	DX			/* hi += carry */
+_mulsubnocarry1:
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry2
+	INCL	DX			/* hi += carry */
+_mulsubnocarry2:
+	MOVL	DX,0(SP)
+	INCL	BP
+	LOOP	_mulsubloop
+	POPQ	AX
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry3
+	MOVQ	$-1,AX
+	RET
+_mulsubnocarry3:
+	MOVQ	$1,AX
+	RET
--- /dev/null
+++ b/libmp/Inferno-amd64/mpvecsub.s
@@ -1,0 +1,45 @@
+/*
+ *	mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ *		diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT	mpvecsub(SB),$0
+
+/*	MOVQ	a+0(FP),SI */
+	MOVQ	RARG, SI
+	MOVQ	b+16(FP),BX
+	MOVL	alen+8(FP),DX
+	MOVL	blen+24(FP),CX
+	MOVQ	diff+32(FP),DI
+	SUBL	CX,DX
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip subraction if b is zero */
+	TESTL	CX,CX
+	JZ	_sub1
+
+	/* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+	MOVL	(SI)(BP*4),AX
+	SBBL	(BX)(BP*4),AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop1
+
+_sub1:
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_subloop2
+	RET
+
+	/* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+	MOVL	(SI)(BP*4),AX
+	SBBL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop2
+	RET
+
--- /dev/null
+++ b/libmp/Inferno-mips/mkfile
@@ -1,0 +1,21 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+	mpdigdiv.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-mips/mpdigdiv.s
@@ -1,0 +1,41 @@
+/*
+ *  This only works on R[45]000 chips that allow 64 bit
+ *  integer arithmetic even when uding 32 bit addresses
+ *
+ *	R1 = dividend*
+ *	R2 = dividend[low]
+ *	R3 = dividend[high]
+ *	R4 = 32 bit divisor
+ *	R5 = quotient*
+ */
+TEXT	mpdigdiv(SB),$0
+
+	MOVW	0(R1),R2
+	MOVW	4(R1),R3
+	MOVW	divisor+4(FP),R4
+	MOVW	quotient+8(FP),R5
+
+	/* divisor == 0 */
+	BEQ	R4,_digovfl
+
+	/* dividend >= 2^32 * divisor */
+	SGTU	R4,R3,R7
+	BEQ	R7,_digovfl
+
+_digdiv1:
+	SLLV	$32,R2
+	SLLV	$32,R3
+	SRLV	$32,R2
+	ADDVU	R2,R3
+	SLLV	$32,R4
+	SRLV	$32,R4
+	DIVVU	R4,R3
+	MOVW	LO,R1
+	MOVW	R1,0(R5)
+	RET
+
+_digovfl:
+	MOVW	$-1,R1
+	MOVW	R1,0(R5)
+	RET
+
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecadd.s
@@ -1,0 +1,67 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ *		R1 == a	(first arg passed in R1)
+ *		R3 == carry
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == sum
+ *		R2 == temporary
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecadd(SB),$-4
+
+	MOVW	alen+4(FP), R4
+	MOVW	b+8(FP), R5
+	MOVW	blen+12(FP), R6
+	MOVW	sum+16(FP), R7
+	SUBU	R6, R4		/* calculate counter for second loop (alen > blen) */
+	MOVW	R0, R3
+
+	/* if blen == 0, don't need to add it in */
+	BEQ	R6,_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	MOVW	0(R5), R9
+	ADDU	$4, R5
+	ADDU	R3, R8
+	SGTU	R3, R8, R3
+	ADDU	R8, R9
+	SGTU	R8, R9, R2
+	ADDU	R2, R3
+	MOVW	R9, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R6
+	BNE	R6, _addloop1
+
+_add1:
+	/* if alen == blen, we're done */
+	BEQ	R4, _addend
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_addloop2:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	ADDU	R3, R8
+	SGTU	R3, R8, R3
+	MOVW	R8, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R4
+	BNE	R4, _addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	MOVW	R3, 0(R7)
+	RET
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecdigmuladd.s
@@ -1,0 +1,58 @@
+/*
+ *	mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R1
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+	MOVW	n+4(FP),R4
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+
+
+	MOVW	R0, R10		/* oldhi = 0 */
+	BEQ	R6, _muladd1
+_muladdloop:
+	MOVW	0(R1), R9	/* lo = b[i] */
+	ADDU	$4, R1
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	MULU	R9, R5
+	MOVW	HI, R8		/* hi = (b[i] * m)>>32 */
+	MOVW	LO, R9		/* lo = b[i] * m */
+	ADDU	R10, R9		/* lo += oldhi */
+	SGTU	R10, R9, R2
+	ADDU	R2, R8		/* hi += carry */
+	ADDU	R9, R11		/* tmp += lo */
+	SGTU	R9, R11, R2
+	ADDU	R2, R8		/* hi += carry */
+	MOVW	R11, 0(R6)	/* p[i] = tmp */
+	ADDU	$4, R6
+	MOVW	R8, R10		/* oldhi = hi */
+	SUBU	$1, R4
+	BNE	R4, _muladdloop
+
+_muladd1:
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	ADDU	R10, R11	/* tmp += oldhi */
+	MOVW	R11, 0(R6)	/* p[i] = tmp */
+
+	RET
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecdigmulsub.s
@@ -1,0 +1,61 @@
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R1
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+	MOVW	n+4(FP),R4
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+
+	MOVW	R0, R10		/* oldhi = 0 */
+_mulsubloop:
+	MOVW	0(R1), R9	/* lo = b[i] */
+	ADDU	$4, R1
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	MULU	R9, R5
+	MOVW	HI, R8		/* hi = (b[i] * m)>>32 */
+	MOVW	LO, R9		/* lo = b[i] * m */
+	ADDU	R10, R9		/* lo += oldhi */
+	SGTU	R10, R9, R2
+	ADDU	R2, R8		/* hi += carry */
+	SUBU	R9, R11, R3	/* tmp -= lo */
+	SGTU	R3, R11, R2
+	ADDU	R2, R8		/* hi += carry */
+	MOVW	R3, 0(R6)	/* p[i] = tmp */
+	ADDU	$4, R6
+	MOVW	R8, R10		/* oldhi = hi */
+	SUBU	$1, R4
+	BNE	R4, _mulsubloop
+
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	SUBU	R10, R11, R3	/* tmp -= oldhi */
+	MOVW	R3, 0(R6)	/* p[i] = tmp */
+	SGTU	R3, R11, R1
+	BNE	R1, _mulsub2
+	MOVW	$1, R1		/* return +1 for positive result */
+	RET
+
+_mulsub2:
+	MOVW	$-1, R1		/* return -1 for negative result */
+	RET
--- /dev/null
+++ b/libmp/Inferno-mips/mpvecsub.s
@@ -1,0 +1,66 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ *		R1 == a	(first arg passed in R1)
+ *		R3 == carry
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == sum
+ *		R2 == temporary
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecsub(SB),$-4
+
+	MOVW	alen+4(FP), R4
+	MOVW	b+8(FP), R5
+	MOVW	blen+12(FP), R6
+	MOVW	sum+16(FP), R7
+	SUBU	R6, R4		/* calculate counter for second loop (alen > blen) */
+	MOVW	R0, R3
+
+	/* if blen == 0, don't need to subtract it */
+	BEQ	R6,_sub1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	MOVW	0(R5), R9
+	ADDU	$4, R5
+	SUBU	R3, R8, R2
+	SGTU	R2, R8, R3
+	SUBU	R9, R2, R8
+	SGTU	R8, R2, R9
+	ADDU	R9, R3
+	MOVW	R8, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R6
+	BNE	R6, _subloop1
+
+_sub1:
+	/* if alen == blen, we're done */
+	BEQ	R4, _subend
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_subloop2:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	SUBU	R3, R8, R2
+	SGTU	R2, R8, R3
+	MOVW	R2, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R4
+	BNE	R4, _subloop2
+
+	/* sum[alen] = carry */
+_subend:
+	RET
--- /dev/null
+++ b/libmp/Inferno-power/mkfile
@@ -1,0 +1,20 @@
+objtype=power
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+
+HFILES=$ROOT/Inferno/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Inferno-power/mpvecadd.s
@@ -1,0 +1,61 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ *		R3 == a	(first arg passed in R3)
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == sum
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecadd(SB),$-4
+
+	MOVW	alen+4(FP), R4
+	MOVW	b+8(FP), R5
+	MOVW	blen+12(FP), R6
+	MOVW	sum+16(FP), R7
+	SUB	R6, R4		/* calculate counter for second loop (alen > blen) */
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUB	$4, R5		/* pre decrement for MOVWU's */
+	SUB	$4, R7		/* pre decrement for MOVWU's */
+	MOVW	R0, XER		/* zero carry going in */
+
+	/* if blen == 0, don't need to add it in */
+	CMP	R0, R6
+	BEQ	_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+	MOVW	R6, CTR
+_addloop1:
+	MOVWU	4(R3), R8
+	MOVWU	4(R5), R9
+	ADDE	R8, R9
+	MOVWU	R9, 4(R7)
+	BDNZ	_addloop1
+
+_add1:
+	/* if alen == blen, we're done */
+	CMP	R0, R4
+	BEQ	_addend
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+	MOVW	R4, CTR
+_addloop2:
+	MOVWU	4(R3), R8
+	ADDE	R0, R8
+	MOVWU	R8, 4(R7)
+	BDNZ	_addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	ADDE	R0, R0, R8
+	MOVW	R8, 4(R7)
+	RETURN
--- /dev/null
+++ b/libmp/Inferno-power/mpvecdigmuladd.s
@@ -1,0 +1,56 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R3
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+	MOVW	n+4(FP),R4
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUB	$4, R6		/* pre decrement for MOVWU's */
+
+	MOVW	R0, R10	
+	MOVW	R0, XER
+	MOVW	R4, CTR
+_muladdloop:
+	MOVWU	4(R3),R9	/* lo = b[i] */
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	MULHWU	R9,R5,R8	/* hi = (b[i] * m)>>32 */
+	MULLW	R9,R5,R9	/* lo = b[i] * m */
+	ADDC	R10,R9		/* lo += oldhi */
+	ADDE	R0,R8		/* hi += carry */
+	ADDC	R9,R11		/* tmp += lo */
+	ADDE	R0,R8		/* hi += carry */
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+	MOVW	R8,R10		/* oldhi = hi */
+	BDNZ	_muladdloop
+
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	ADDC	R10,R11
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+
+	RETURN
--- /dev/null
+++ b/libmp/Inferno-power/mpvecdigmulsub.s
@@ -1,0 +1,66 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+#define	BLT	BC	0xC,0,
+
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R3
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		borrow = R12
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+	MOVW	n+4(FP),R10
+	MOVW	R10,CTR
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUBC	$4, R6		/* pre decrement for MOVWU's and set carry */
+	MOVW	XER,R12
+
+	MOVW	R0, R10	
+
+_mulsubloop:
+	MOVWU	4(R3),R9	/* lo = b[i] */
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	MULHWU	R9,R5,R8	/* hi = (b[i] * m)>>32 */
+	MULLW	R9,R5,R9	/* lo = b[i] * m */
+	ADDC	R10,R9		/* lo += oldhi */
+	ADDE	R0,R8		/* hi += carry */
+	MOVW	R12,XER
+	SUBE	R9,R11		/* tmp -= lo */
+	MOVW	XER,R12
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+	MOVW	R8,R10		/* oldhi = hi */
+	BDNZ	_mulsubloop
+
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	MOVW	R12,XER
+	SUBE	R10,R11		/* tmp -= lo */
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+
+	/* return -1 if the result was negative, +1 otherwise */
+	SUBECC	R0,R0,R3
+	BLT	_mulsub2
+	MOVW	$1,R3
+_mulsub2:
+	RETURN
--- /dev/null
+++ b/libmp/Inferno-power/mpvecsub.s
@@ -1,0 +1,57 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ *		diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, diff has room for alen digits
+ *
+ *		R3 == a
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == diff
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecsub(SB),$-4
+
+	MOVW	alen+4(FP),R4
+	MOVW	b+8(FP),R5
+	MOVW	blen+12(FP),R6
+	MOVW	diff+16(FP),R7
+	SUB	R6, R4		/* calculate counter for second loop (alen > blen) */
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUB	$4, R5		/* pre decrement for MOVWU's */
+	SUBC	$4, R7		/* pre decrement for MOVWU's and set carry */
+
+	/* skip subraction if b is zero */
+	CMP	R0,R6
+	BEQ	_sub1
+
+	/* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+	MOVW	R6, CTR
+_subloop1:
+	MOVWU	4(R3), R8
+	MOVWU	4(R5), R9
+	SUBE	R9, R8, R8
+	MOVWU	R8, 4(R7)
+	BDNZ	_subloop1
+
+_sub1:
+	/* skip subtraction if a is zero */
+	CMP	R0, R4
+	BEQ	_subend
+
+	/* diff[blen:alen-1] = a[blen:alen-1] - 0 + carry */
+	MOVW	R4, CTR
+_subloop2:
+	MOVWU	4(R3), R8
+	SUBE	R0, R8
+	MOVWU	R8, 4(R7)
+	BDNZ	_subloop2
+_subend:
+	RETURN
+
--- /dev/null
+++ b/libmp/NOTICE
@@ -1,0 +1,4 @@
+Copyright © 2000-2007 Lucent Technologies Inc. and others.  All rights reserved.
+Revisions for use with Inferno © 2006 Vita Nuova Holdings Limited.
+
+This software is provided under the terms of the Lucent Public License, Version 1.02.
--- /dev/null
+++ b/libmp/Plan9-386/mkfile
@@ -1,0 +1,21 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+	mpdigdiv.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-386/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT	mpdigdiv(SB),$0
+
+	MOVL	dividend+0(FP),BX
+	MOVL	0(BX),AX
+	MOVL	4(BX),DX
+	MOVL	divisor+4(FP),BX
+	MOVL	quotient+8(FP),BP
+	XORL	CX,CX
+	CMPL	DX,BX		/* dividend >= 2^32 * divisor */
+	JHS	_divovfl
+	CMPL	BX,CX		/* divisor == 0 */
+	JE	_divovfl
+	DIVL	BX		/* AX = DX:AX/BX */
+	MOVL	AX,0(BP)
+	RET
+
+	/* return all 1's */
+_divovfl:
+	NOTL	CX
+	MOVL	CX,0(BP)
+	RET
--- /dev/null
+++ b/libmp/Plan9-386/mpvecadd.s
@@ -1,0 +1,53 @@
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT	mpvecadd(SB),$0
+
+	MOVL	alen+4(FP),DX
+	MOVL	blen+12(FP),CX
+	MOVL	a+0(FP),SI
+	MOVL	b+8(FP),BX
+	SUBL	CX,DX
+	MOVL	sum+16(FP),DI
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip addition if b is zero */
+	TESTL	CX,CX
+	JZ	_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+	MOVL	(SI)(BP*4), AX
+	ADCL	(BX)(BP*4), AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop1
+
+_add1:
+	/* jump if alen > blen */
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	JC	_addcarry
+	MOVL	$0,(DI)(BP*4)
+	RET
+_addcarry:
+	MOVL	$1,(DI)(BP*4)
+	RET
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+	MOVL	(SI)(BP*4),AX
+	ADCL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop2
+	JMP	_addend
+
--- /dev/null
+++ b/libmp/Plan9-386/mpvecdigmuladd.s
@@ -1,0 +1,52 @@
+/*
+ *	mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b+n = SI	- can't be BP
+ *		p+n = DI	- can't be BP
+ *		i-n = BP
+ *		m = BX
+ *		oldhi = CX
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+	MOVL	b+0(FP),SI
+	MOVL	n+4(FP),CX
+	MOVL	m+8(FP),BX
+	MOVL	p+12(FP),DI
+	MOVL	CX,BP
+	NEGL	BP		/* BP = -n */
+	SHLL	$2,CX
+	ADDL	CX,SI		/* SI = b + n */
+	ADDL	CX,DI		/* DI = p + n */
+	XORL	CX,CX
+_muladdloop:
+	MOVL	(SI)(BP*4),AX	/* lo = b[i] */
+	MULL	BX		/* hi, lo = b[i] * m */
+	ADDL	CX,AX		/* lo += oldhi */
+	JCC	_muladdnocarry1
+	INCL	DX		/* hi += carry */
+_muladdnocarry1:
+	ADDL	AX,(DI)(BP*4)	/* p[i] += lo */
+	JCC	_muladdnocarry2
+	INCL	DX		/* hi += carry */
+_muladdnocarry2:
+	MOVL	DX,CX		/* oldhi = hi */
+	INCL	BP		/* i++ */
+	JNZ	_muladdloop
+	XORL	AX,AX
+	ADDL	CX,(DI)(BP*4)	/* p[n] + oldhi */
+	ADCL	AX,AX		/* return carry out of p[n] */
+	RET
--- /dev/null
+++ b/libmp/Plan9-386/mpvecdigmulsub.s
@@ -1,0 +1,53 @@
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b = SI		- can't be BP
+ *		p = DI		- can't be BP
+ *		i = BP
+ *		n = CX		- constrained by LOOP instr
+ *		m = BX
+ *		oldhi = EX
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+	MOVL	b+0(FP),SI
+	MOVL	n+4(FP),CX
+	MOVL	m+8(FP),BX
+	MOVL	p+12(FP),DI
+	XORL	BP,BP
+	PUSHL	BP
+_mulsubloop:
+	MOVL	(SI)(BP*4),AX		/* lo = b[i] */
+	MULL	BX			/* hi, lo = b[i] * m */
+	ADDL	0(SP),AX		/* lo += oldhi */
+	JCC	_mulsubnocarry1
+	INCL	DX			/* hi += carry */
+_mulsubnocarry1:
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry2
+	INCL	DX			/* hi += carry */
+_mulsubnocarry2:
+	MOVL	DX,0(SP)
+	INCL	BP
+	LOOP	_mulsubloop
+	POPL	AX
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry3
+	MOVL	$-1,AX
+	RET
+_mulsubnocarry3:
+	MOVL	$1,AX
+	RET
--- /dev/null
+++ b/libmp/Plan9-386/mpvecsub.s
@@ -1,0 +1,44 @@
+/*
+ *	mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ *		diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT	mpvecsub(SB),$0
+
+	MOVL	a+0(FP),SI
+	MOVL	b+8(FP),BX
+	MOVL	alen+4(FP),DX
+	MOVL	blen+12(FP),CX
+	MOVL	diff+16(FP),DI
+	SUBL	CX,DX
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip subraction if b is zero */
+	TESTL	CX,CX
+	JZ	_sub1
+
+	/* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+	MOVL	(SI)(BP*4),AX
+	SBBL	(BX)(BP*4),AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop1
+
+_sub1:
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_subloop2
+	RET
+
+	/* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+	MOVL	(SI)(BP*4),AX
+	SBBL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop2
+	RET
+
--- /dev/null
+++ b/libmp/Plan9-amd64/mkfile
@@ -1,0 +1,21 @@
+objtype=amd64
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+	mpdigdiv.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-amd64/mpdigdiv.s
@@ -1,0 +1,21 @@
+TEXT	mpdigdiv(SB),$0
+
+/*	MOVL	dividend+0(FP),BX */
+	MOVL	0(RARG),AX
+	MOVL	4(RARG),DX
+	MOVL	divisor+8(FP),BX
+	MOVQ	quotient+16(FP),DI
+	XORL	CX,CX
+	CMPL	DX,BX		/* dividend >= 2^32 * divisor */
+	JHS	_divovfl
+	CMPL	BX,CX		/* divisor == 0 */
+	JE	_divovfl
+	DIVL	BX		/* AX = DX:AX/BX */
+	MOVL	AX,0(DI)
+	RET
+
+	/* return all 1's */
+_divovfl:
+	NOTL	CX
+	MOVL	CX,0(DI)
+	RET
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecadd.s
@@ -1,0 +1,54 @@
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ */
+TEXT	mpvecadd(SB),$0
+
+	MOVL	alen+8(FP),DX
+	MOVL	blen+24(FP),CX
+/*	MOVL	a+0(FP),SI */
+	MOVQ	RARG, SI
+	MOVQ	b+16(FP),BX
+	SUBL	CX,DX
+	MOVQ	sum+32(FP),DI
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip addition if b is zero */
+	TESTL	CX,CX
+	JZ	_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+	MOVL	(SI)(BP*4), AX
+	ADCL	(BX)(BP*4), AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop1
+
+_add1:
+	/* jump if alen > blen */
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	JC	_addcarry
+	MOVL	$0,(DI)(BP*4)
+	RET
+_addcarry:
+	MOVL	$1,(DI)(BP*4)
+	RET
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 */
+_addloop2:
+	MOVL	(SI)(BP*4),AX
+	ADCL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_addloop2
+	JMP	_addend
+
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecdigmuladd.s
@@ -1,0 +1,53 @@
+/*
+ *	mpvecdigmul(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b+n = SI	- can't be BP
+ *		p+n = DI	- can't be BP
+ *		i-n = BP
+ *		m = BX
+ *		oldhi = CX
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+/*	MOVQ	b+0(FP),SI	*/
+	MOVQ	RARG,SI
+	MOVL	n+8(FP),CX
+	MOVL	m+16(FP),BX
+	MOVQ	p+24(FP),DI
+	MOVL	CX,BP
+	NEGQ	BP		/* BP = -n */
+	SHLL	$2,CX
+	ADDQ	CX,SI		/* SI = b + n */
+	ADDQ	CX,DI		/* DI = p + n */
+	XORL	CX,CX
+_muladdloop:
+	MOVL	(SI)(BP*4),AX	/* lo = b[i] */
+	MULL	BX		/* hi, lo = b[i] * m */
+	ADDL	CX,AX		/* lo += oldhi */
+	JCC	_muladdnocarry1
+	INCL	DX		/* hi += carry */
+_muladdnocarry1:
+	ADDL	AX,(DI)(BP*4)	/* p[i] += lo */
+	JCC	_muladdnocarry2
+	INCL	DX		/* hi += carry */
+_muladdnocarry2:
+	MOVL	DX,CX		/* oldhi = hi */
+	INCQ	BP		/* i++ */
+	JNZ	_muladdloop
+	XORL	AX,AX
+	ADDL	CX,(DI)(BP*4)	/* p[n] + oldhi */
+	ADCL	AX,AX		/* return carry out of p[n] */
+	RET
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecdigmulsub.s
@@ -1,0 +1,54 @@
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step look like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		hi = DX		- constrained by hardware
+ *		lo = AX		- constrained by hardware
+ *		b = SI		- can't be BP
+ *		p = DI		- can't be BP
+ *		i = BP
+ *		n = CX		- constrained by LOOP instr
+ *		m = BX
+ *		oldhi = EX
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+/*	MOVL	b+0(FP),SI	*/
+	MOVQ	RARG,SI
+	MOVL	n+8(FP),CX
+	MOVL	m+16(FP),BX
+	MOVQ	p+24(FP),DI
+	XORL	BP,BP
+	PUSHQ	BP
+_mulsubloop:
+	MOVL	(SI)(BP*4),AX		/* lo = b[i] */
+	MULL	BX			/* hi, lo = b[i] * m */
+	ADDL	0(SP),AX		/* lo += oldhi */
+	JCC	_mulsubnocarry1
+	INCL	DX			/* hi += carry */
+_mulsubnocarry1:
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry2
+	INCL	DX			/* hi += carry */
+_mulsubnocarry2:
+	MOVL	DX,0(SP)
+	INCL	BP
+	LOOP	_mulsubloop
+	POPQ	AX
+	SUBL	AX,(DI)(BP*4)
+	JCC	_mulsubnocarry3
+	MOVQ	$-1,AX
+	RET
+_mulsubnocarry3:
+	MOVQ	$1,AX
+	RET
--- /dev/null
+++ b/libmp/Plan9-amd64/mpvecsub.s
@@ -1,0 +1,45 @@
+/*
+ *	mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ *		diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, diff has room for alen digits
+ */
+TEXT	mpvecsub(SB),$0
+
+/*	MOVQ	a+0(FP),SI */
+	MOVQ	RARG, SI
+	MOVQ	b+16(FP),BX
+	MOVL	alen+8(FP),DX
+	MOVL	blen+24(FP),CX
+	MOVQ	diff+32(FP),DI
+	SUBL	CX,DX
+	XORL	BP,BP			/* this also sets carry to 0 */
+
+	/* skip subraction if b is zero */
+	TESTL	CX,CX
+	JZ	_sub1
+
+	/* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+	MOVL	(SI)(BP*4),AX
+	SBBL	(BX)(BP*4),AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop1
+
+_sub1:
+	INCL	DX
+	MOVL	DX,CX
+	LOOP	_subloop2
+	RET
+
+	/* diff[blen:alen-1] = a[blen:alen-1] - 0 */
+_subloop2:
+	MOVL	(SI)(BP*4),AX
+	SBBL	$0,AX
+	MOVL	AX,(DI)(BP*4)
+	INCL	BP
+	LOOP	_subloop2
+	RET
+
--- /dev/null
+++ b/libmp/Plan9-mips/mkfile
@@ -1,0 +1,21 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+	mpdigdiv.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-mips/mpdigdiv.s
@@ -1,0 +1,41 @@
+/*
+ *  This only works on R[45]000 chips that allow 64 bit
+ *  integer arithmetic even when uding 32 bit addresses
+ *
+ *	R1 = dividend*
+ *	R2 = dividend[low]
+ *	R3 = dividend[high]
+ *	R4 = 32 bit divisor
+ *	R5 = quotient*
+ */
+TEXT	mpdigdiv(SB),$0
+
+	MOVW	0(R1),R2
+	MOVW	4(R1),R3
+	MOVW	divisor+4(FP),R4
+	MOVW	quotient+8(FP),R5
+
+	/* divisor == 0 */
+	BEQ	R4,_digovfl
+
+	/* dividend >= 2^32 * divisor */
+	SGTU	R4,R3,R7
+	BEQ	R7,_digovfl
+
+_digdiv1:
+	SLLV	$32,R2
+	SLLV	$32,R3
+	SRLV	$32,R2
+	ADDVU	R2,R3
+	SLLV	$32,R4
+	SRLV	$32,R4
+	DIVVU	R4,R3
+	MOVW	LO,R1
+	MOVW	R1,0(R5)
+	RET
+
+_digovfl:
+	MOVW	$-1,R1
+	MOVW	R1,0(R5)
+	RET
+
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecadd.s
@@ -1,0 +1,67 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ *		R1 == a	(first arg passed in R1)
+ *		R3 == carry
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == sum
+ *		R2 == temporary
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecadd(SB),$-4
+
+	MOVW	alen+4(FP), R4
+	MOVW	b+8(FP), R5
+	MOVW	blen+12(FP), R6
+	MOVW	sum+16(FP), R7
+	SUBU	R6, R4		/* calculate counter for second loop (alen > blen) */
+	MOVW	R0, R3
+
+	/* if blen == 0, don't need to add it in */
+	BEQ	R6,_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+_addloop1:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	MOVW	0(R5), R9
+	ADDU	$4, R5
+	ADDU	R3, R8
+	SGTU	R3, R8, R3
+	ADDU	R8, R9
+	SGTU	R8, R9, R2
+	ADDU	R2, R3
+	MOVW	R9, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R6
+	BNE	R6, _addloop1
+
+_add1:
+	/* if alen == blen, we're done */
+	BEQ	R4, _addend
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_addloop2:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	ADDU	R3, R8
+	SGTU	R3, R8, R3
+	MOVW	R8, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R4
+	BNE	R4, _addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	MOVW	R3, 0(R7)
+	RET
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecdigmuladd.s
@@ -1,0 +1,58 @@
+/*
+ *	mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R1
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+	MOVW	n+4(FP),R4
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+
+
+	MOVW	R0, R10		/* oldhi = 0 */
+	BEQ	R6, _muladd1
+_muladdloop:
+	MOVW	0(R1), R9	/* lo = b[i] */
+	ADDU	$4, R1
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	MULU	R9, R5
+	MOVW	HI, R8		/* hi = (b[i] * m)>>32 */
+	MOVW	LO, R9		/* lo = b[i] * m */
+	ADDU	R10, R9		/* lo += oldhi */
+	SGTU	R10, R9, R2
+	ADDU	R2, R8		/* hi += carry */
+	ADDU	R9, R11		/* tmp += lo */
+	SGTU	R9, R11, R2
+	ADDU	R2, R8		/* hi += carry */
+	MOVW	R11, 0(R6)	/* p[i] = tmp */
+	ADDU	$4, R6
+	MOVW	R8, R10		/* oldhi = hi */
+	SUBU	$1, R4
+	BNE	R4, _muladdloop
+
+_muladd1:
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	ADDU	R10, R11	/* tmp += oldhi */
+	MOVW	R11, 0(R6)	/* p[i] = tmp */
+
+	RET
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecdigmulsub.s
@@ -1,0 +1,61 @@
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R1
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+	MOVW	n+4(FP),R4
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+
+	MOVW	R0, R10		/* oldhi = 0 */
+_mulsubloop:
+	MOVW	0(R1), R9	/* lo = b[i] */
+	ADDU	$4, R1
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	MULU	R9, R5
+	MOVW	HI, R8		/* hi = (b[i] * m)>>32 */
+	MOVW	LO, R9		/* lo = b[i] * m */
+	ADDU	R10, R9		/* lo += oldhi */
+	SGTU	R10, R9, R2
+	ADDU	R2, R8		/* hi += carry */
+	SUBU	R9, R11, R3	/* tmp -= lo */
+	SGTU	R3, R11, R2
+	ADDU	R2, R8		/* hi += carry */
+	MOVW	R3, 0(R6)	/* p[i] = tmp */
+	ADDU	$4, R6
+	MOVW	R8, R10		/* oldhi = hi */
+	SUBU	$1, R4
+	BNE	R4, _mulsubloop
+
+	MOVW	0(R6), R11	/* tmp = p[i] */
+	SUBU	R10, R11, R3	/* tmp -= oldhi */
+	MOVW	R3, 0(R6)	/* p[i] = tmp */
+	SGTU	R3, R11, R1
+	BNE	R1, _mulsub2
+	MOVW	$1, R1		/* return +1 for positive result */
+	RET
+
+_mulsub2:
+	MOVW	$-1, R1		/* return -1 for negative result */
+	RET
--- /dev/null
+++ b/libmp/Plan9-mips/mpvecsub.s
@@ -1,0 +1,66 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ *		R1 == a	(first arg passed in R1)
+ *		R3 == carry
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == sum
+ *		R2 == temporary
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecsub(SB),$-4
+
+	MOVW	alen+4(FP), R4
+	MOVW	b+8(FP), R5
+	MOVW	blen+12(FP), R6
+	MOVW	sum+16(FP), R7
+	SUBU	R6, R4		/* calculate counter for second loop (alen > blen) */
+	MOVW	R0, R3
+
+	/* if blen == 0, don't need to subtract it */
+	BEQ	R6,_sub1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] - b[0:blen-1] */
+_subloop1:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	MOVW	0(R5), R9
+	ADDU	$4, R5
+	SUBU	R3, R8, R2
+	SGTU	R2, R8, R3
+	SUBU	R9, R2, R8
+	SGTU	R8, R2, R9
+	ADDU	R9, R3
+	MOVW	R8, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R6
+	BNE	R6, _subloop1
+
+_sub1:
+	/* if alen == blen, we're done */
+	BEQ	R4, _subend
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+_subloop2:
+	MOVW	0(R1), R8
+	ADDU	$4, R1
+	SUBU	R3, R8, R2
+	SGTU	R2, R8, R3
+	MOVW	R2, 0(R7)
+	ADDU	$4, R7
+	SUBU	$1, R4
+	BNE	R4, _subloop2
+
+	/* sum[alen] = carry */
+_subend:
+	RET
--- /dev/null
+++ b/libmp/Plan9-power/mkfile
@@ -1,0 +1,20 @@
+objtype=power
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libmp.a
+SFILES=\
+	mpvecadd.s\
+	mpvecdigmuladd.s\
+	mpvecdigmulsub.s\
+	mpvecsub.s\
+
+HFILES=$ROOT/$SYSTARG/$OBJTYPE/include/u.h $ROOT/include/mp.h ../port/dat.h
+
+OFILES=${SFILES:%.s=%.$O}
+
+UPDATE=mkfile\
+	$HFILES\
+	$SFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/Plan9-power/mpvecadd.s
@@ -1,0 +1,61 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+ *
+ *		sum[0:alen] = a[0:alen-1] + b[0:blen-1]
+ *
+ *	prereq: alen >= blen, sum has room for alen+1 digits
+ *
+ *		R3 == a	(first arg passed in R3)
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == sum
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecadd(SB),$-4
+
+	MOVW	alen+4(FP), R4
+	MOVW	b+8(FP), R5
+	MOVW	blen+12(FP), R6
+	MOVW	sum+16(FP), R7
+	SUB	R6, R4		/* calculate counter for second loop (alen > blen) */
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUB	$4, R5		/* pre decrement for MOVWU's */
+	SUB	$4, R7		/* pre decrement for MOVWU's */
+	MOVW	R0, XER		/* zero carry going in */
+
+	/* if blen == 0, don't need to add it in */
+	CMP	R0, R6
+	BEQ	_add1
+
+	/* sum[0:blen-1],carry = a[0:blen-1] + b[0:blen-1] */
+	MOVW	R6, CTR
+_addloop1:
+	MOVWU	4(R3), R8
+	MOVWU	4(R5), R9
+	ADDE	R8, R9
+	MOVWU	R9, 4(R7)
+	BDNZ	_addloop1
+
+_add1:
+	/* if alen == blen, we're done */
+	CMP	R0, R4
+	BEQ	_addend
+
+	/* sum[blen:alen-1],carry = a[blen:alen-1] + 0 + carry */
+	MOVW	R4, CTR
+_addloop2:
+	MOVWU	4(R3), R8
+	ADDE	R0, R8
+	MOVWU	R8, 4(R7)
+	BDNZ	_addloop2
+
+	/* sum[alen] = carry */
+_addend:
+	ADDE	R0, R0, R8
+	MOVW	R8, 4(R7)
+	RETURN
--- /dev/null
+++ b/libmp/Plan9-power/mpvecdigmuladd.s
@@ -1,0 +1,56 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p += b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R3
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		
+ */
+TEXT	mpvecdigmuladd(SB),$0
+
+	MOVW	n+4(FP),R4
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUB	$4, R6		/* pre decrement for MOVWU's */
+
+	MOVW	R0, R10	
+	MOVW	R0, XER
+	MOVW	R4, CTR
+_muladdloop:
+	MOVWU	4(R3),R9	/* lo = b[i] */
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	MULHWU	R9,R5,R8	/* hi = (b[i] * m)>>32 */
+	MULLW	R9,R5,R9	/* lo = b[i] * m */
+	ADDC	R10,R9		/* lo += oldhi */
+	ADDE	R0,R8		/* hi += carry */
+	ADDC	R9,R11		/* tmp += lo */
+	ADDE	R0,R8		/* hi += carry */
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+	MOVW	R8,R10		/* oldhi = hi */
+	BDNZ	_muladdloop
+
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	ADDC	R10,R11
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+
+	RETURN
--- /dev/null
+++ b/libmp/Plan9-power/mpvecdigmulsub.s
@@ -1,0 +1,66 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+#define	BLT	BC	0xC,0,
+
+/*
+ *	mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+ *
+ *	p -= b*m
+ *
+ *	each step looks like:
+ *		hi,lo = m*b[i]
+ *		lo += oldhi + carry
+ *		hi += carry
+ *		p[i] += lo
+ *		oldhi = hi
+ *
+ *	the registers are:
+ *		b = R3
+ *		n = R4
+ *		m = R5
+ *		p = R6
+ *		i = R7
+ *		hi = R8		- constrained by hardware
+ *		lo = R9		- constrained by hardware
+ *		oldhi = R10
+ *		tmp = R11
+ *		borrow = R12
+ *		
+ */
+TEXT	mpvecdigmulsub(SB),$0
+
+	MOVW	n+4(FP),R10
+	MOVW	R10,CTR
+	MOVW	m+8(FP),R5
+	MOVW	p+12(FP),R6
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUBC	$4, R6		/* pre decrement for MOVWU's and set carry */
+	MOVW	XER,R12
+
+	MOVW	R0, R10	
+
+_mulsubloop:
+	MOVWU	4(R3),R9	/* lo = b[i] */
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	MULHWU	R9,R5,R8	/* hi = (b[i] * m)>>32 */
+	MULLW	R9,R5,R9	/* lo = b[i] * m */
+	ADDC	R10,R9		/* lo += oldhi */
+	ADDE	R0,R8		/* hi += carry */
+	MOVW	R12,XER
+	SUBE	R9,R11		/* tmp -= lo */
+	MOVW	XER,R12
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+	MOVW	R8,R10		/* oldhi = hi */
+	BDNZ	_mulsubloop
+
+	MOVW	4(R6),R11	/* tmp = p[i] */
+	MOVW	R12,XER
+	SUBE	R10,R11		/* tmp -= lo */
+	MOVWU	R11,4(R6)	/* p[i] = tmp */
+
+	/* return -1 if the result was negative, +1 otherwise */
+	SUBECC	R0,R0,R3
+	BLT	_mulsub2
+	MOVW	$1,R3
+_mulsub2:
+	RETURN
--- /dev/null
+++ b/libmp/Plan9-power/mpvecsub.s
@@ -1,0 +1,57 @@
+#define	BDNZ	BC	16,0,
+#define	BDNE	BC	0,2,
+
+/*
+ *	mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+ *
+ *		diff[0:alen-1] = a[0:alen-1] - b[0:blen-1]
+ *
+ *	prereq: alen >= blen, diff has room for alen digits
+ *
+ *		R3 == a
+ *		R4 == alen
+ *		R5 == b
+ *		R6 == blen
+ *		R7 == diff
+ *		R8 == temporary
+ *		R9 == temporary
+ */
+TEXT	mpvecsub(SB),$-4
+
+	MOVW	alen+4(FP),R4
+	MOVW	b+8(FP),R5
+	MOVW	blen+12(FP),R6
+	MOVW	diff+16(FP),R7
+	SUB	R6, R4		/* calculate counter for second loop (alen > blen) */
+	SUB	$4, R3		/* pre decrement for MOVWU's */
+	SUB	$4, R5		/* pre decrement for MOVWU's */
+	SUBC	$4, R7		/* pre decrement for MOVWU's and set carry */
+
+	/* skip subraction if b is zero */
+	CMP	R0,R6
+	BEQ	_sub1
+
+	/* diff[0:blen-1],borrow = a[0:blen-1] - b[0:blen-1] */
+	MOVW	R6, CTR
+_subloop1:
+	MOVWU	4(R3), R8
+	MOVWU	4(R5), R9
+	SUBE	R9, R8, R8
+	MOVWU	R8, 4(R7)
+	BDNZ	_subloop1
+
+_sub1:
+	/* skip subtraction if a is zero */
+	CMP	R0, R4
+	BEQ	_subend
+
+	/* diff[blen:alen-1] = a[blen:alen-1] - 0 + carry */
+	MOVW	R4, CTR
+_subloop2:
+	MOVWU	4(R3), R8
+	SUBE	R0, R8
+	MOVWU	R8, 4(R7)
+	BDNZ	_subloop2
+_subend:
+	RETURN
+
--- /dev/null
+++ b/libmp/bigtest.c
@@ -1,0 +1,102 @@
+#include <lib9.h>
+#include <mp.h>
+#include <libsec.h>
+
+char *sfactors[] =
+{	"3", "5", "17", "257", "641", "65537", "274177", "2424833", "6700417", "45592577",
+    "6487031809", "67280421310721", "1238926361552897", "59649589127497217",
+    "5704689200685129054721", "4659775785220018543264560743076778192897",
+    "7455602825647884208337395736200454918783366342657",
+    "93461639715357977769163558199606896584051237541638188580280321",
+
+    "741640062627530801524787141901937474059940781097519023905821316144415759504705008092818711693940737",
+
+    "130439874405488189727484768796509903946608530841611892186895295776832416251471863574140227977573104895898783928842923844831149032913798729088601617946094119449010595906710130531906171018354491609619193912488538116080712299672322806217820753127014424577"
+};
+
+long start;
+
+void
+printmp(mpint *b, char *tag)
+{
+	int n;
+	char *p;
+
+	print("%s (%d) ", tag, b->top);
+	p = mptoa(b, 10, nil, 0);
+	write(1, p, strlen(p));
+	free(p);
+	print("\n");
+}
+
+int
+timing(void)
+{
+	long now, span;
+
+	now = time(0);
+	span = now-start;
+	start = now;
+
+	return span;
+}
+
+int expdebug;
+
+
+void
+main(int argc, char **argv)
+{
+	mpint *p, *k, *d, *b, *e, *x, *r;
+	int i;
+
+	start = time(0);
+	fmtinstall('B', mpconv);
+	mpsetminbits(2*Dbits);
+
+	x = mpnew(0);
+	e = mpnew(0);
+	r = mpnew(0);
+	p = mpnew(0);
+
+	// b = 2^32
+	b = mpcopy(mpone);
+	mpleft(b, 32, b);
+
+	// 2^29440
+	p = mpcopy(mpone);
+	mpleft(p, 29440, p);
+	// 2^27392
+	k = mpcopy(mpone);
+	mpleft(k, 27392, k);
+	// k = 2^29440 - 2^27392
+	mpsub(p, k, k);
+	// p = 2^29440 - 2^27392 + 1
+	mpadd(k, mpone, p);
+
+//	if(!probably_prime(p, 18)){
+//		print("not a prime\n");
+//		exits(0);
+//	}
+//	print("probably prime\n");
+
+	mpright(k, 10, k);
+	printmp(k, "k =");
+
+expdebug = 1;
+	mpexp(b, k, p, x);
+	printmp(x, "x =");
+	print("timing %d\n", timing());
+
+	for(i = 0; i < nelem(sfactors); i++){
+		d = strtomp(sfactors[i], nil, 10, nil);
+		// e = k/d
+		mpdiv(k, d, e, r);
+		printmp(r, "r =");
+
+		// x = b^e mod p
+		mpexp(b, e, p, x);
+		printmp(x, "x =");
+		print("timing %d\n", timing());
+	}
+}
--- /dev/null
+++ b/libmp/mkfile
@@ -1,0 +1,27 @@
+<../mkconfig
+
+# TARGMODEL not SYSTARG for now
+DIRS=port $TARGMODEL-$OBJTYPE
+
+<$ROOT/mkfiles/mklibsubdirs
+
+# the remainder are only intended for testing on a few system types
+test.$O:	test.c $ROOT/$OBJDIR/include/lib9.h $ROOT/include/mp.h port/dat.h
+	$CC -Iport test.c
+
+$O.test:	test.$O $ROOT/$OBJDIR/lib/libmp.a
+	$LD -o $O.test test.$O
+
+bigtest.$O: bigtest.c  $ROOT/$OBJDIR/include/lib9.h $ROOT/include/mp.h port/dat.h
+	$CC -Iport bigtest.c
+
+$O.bigtest: bigtest.$O  $ROOT/$OBJDIR/lib/libmp.a
+	$LD -o $O.bigtest bigtest.$O
+
+allout:
+	objtype=386; OBJTYPE=$objtype; mk; mk 8.test 8.bigtest
+	objtype=power; OBJTYPE=$objtype; mk; mk q.test q.bigtest
+	objtype=mips; OBJTYPE=$objtype; mk; mk v.test v.bigtest
+
+cleanout:
+	rm -f [qv8].* *.[qv8]
--- /dev/null
+++ b/libmp/mtest.c
@@ -1,0 +1,70 @@
+#include <u.h>
+#include <libc.h>
+#include <mp.h>
+#include "port/dat.h"
+
+int loops = 1;
+
+long randomreg;
+
+void
+srand(long seed)
+{
+	randomreg = seed;
+}
+
+long
+lrand(void)
+{
+	randomreg = randomreg*104381 + 81761;
+	return randomreg;
+}
+
+void
+prng(uchar *p, int n)
+{
+	while(n-- > 0)
+		*p++ = lrand();
+}
+
+
+void
+testshift(char *str)
+{
+	mpint *b1, *b2;
+	int i;
+
+	b1 = strtomp(str, nil, 16, nil);
+	malloccheck();
+fprint(2, "A");
+	b2 = mpnew(0);
+fprint(2, "B");
+	malloccheck();
+	mpleft(b1, 20, b2);
+fprint(2, "C");
+	malloccheck();
+	mpfree(b1);
+fprint(2, "D");
+	malloccheck();
+	mpfree(b2);
+}
+
+void
+main(int argc, char **argv)
+{
+	mpint *x, *y;
+
+	ARGBEGIN{
+	case 'n':
+		loops = atoi(ARGF());
+		break;
+	}ARGEND;
+
+	fmtinstall('B', mpfmt);
+	fmtinstall('Q', mpfmt);
+	srand(0);
+	mpsetminbits(2*Dbits);
+	testshift("1111111111111111");
+	print("done\n");
+	exits(0);
+}
--- /dev/null
+++ b/libmp/port/betomp.c
@@ -1,0 +1,40 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert a big-endian byte array (most significant byte first) to an mpint
+mpint*
+betomp(uchar *p, uint n, mpint *b)
+{
+	int m, s;
+	mpdigit x;
+
+	if(b == nil)
+		b = mpnew(0);
+
+	// dump leading zeros
+	while(*p == 0 && n > 1){
+		p++;
+		n--;
+	}
+
+	// get the space
+	mpbits(b, n*8);
+	b->top = DIGITS(n*8);
+	m = b->top-1;
+
+	// first digit might not be Dbytes long
+	s = ((n-1)*8)%Dbits;
+	x = 0;
+	for(; n > 0; n--){
+		x |= ((mpdigit)(*p++)) << s;
+		s -= 8;
+		if(s < 0){
+			b->p[m--] = x;
+			s = Dbits-8;
+			x = 0;
+		}
+	}
+
+	return b;
+}
--- /dev/null
+++ b/libmp/port/crt.c
@@ -1,0 +1,122 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// chinese remainder theorem
+//
+// handbook of applied cryptography, menezes et al, 1997, pp 610 - 613
+
+struct CRTpre
+{
+	int	n;		// number of moduli
+	mpint	**m;		// pointer to moduli
+	mpint	**c;		// precomputed coefficients
+	mpint	**p;		// precomputed products
+	mpint	*a[1];		// local storage
+};
+
+// setup crt info, returns a newly created structure
+CRTpre*
+crtpre(int n, mpint **m)
+{
+	CRTpre *crt;
+	int i, j;
+	mpint *u;
+
+	crt = malloc(sizeof(CRTpre)+sizeof(mpint)*3*n);
+	if(crt == nil)
+		sysfatal("crtpre: %r");
+	crt->m = crt->a;
+	crt->c = crt->a+n;
+	crt->p = crt->c+n;
+	crt->n = n;
+
+	// make a copy of the moduli
+	for(i = 0; i < n; i++)
+		crt->m[i] = mpcopy(m[i]);
+
+	// precompute the products
+	u = mpcopy(mpone);
+	for(i = 0; i < n; i++){
+		mpmul(u, m[i], u);
+		crt->p[i] = mpcopy(u);
+	}
+
+	// precompute the coefficients
+	for(i = 1; i < n; i++){
+		crt->c[i] = mpcopy(mpone);
+		for(j = 0; j < i; j++){
+			mpinvert(m[j], m[i], u);
+			mpmul(u, crt->c[i], u);
+			mpmod(u, m[i], crt->c[i]);
+		}
+	}
+
+	mpfree(u);
+
+	return crt;		
+}
+
+void
+crtprefree(CRTpre *crt)
+{
+	int i;
+
+	for(i = 0; i < crt->n; i++){
+		if(i != 0)
+			mpfree(crt->c[i]);
+		mpfree(crt->p[i]);
+		mpfree(crt->m[i]);
+	}
+	free(crt);
+}
+
+// convert to residues, returns a newly created structure
+CRTres*
+crtin(CRTpre *crt, mpint *x)
+{
+	int i;
+	CRTres *res;
+
+	res = malloc(sizeof(CRTres)+sizeof(mpint)*crt->n);
+	if(res == nil)
+		sysfatal("crtin: %r");
+	res->n = crt->n;
+	for(i = 0; i < res->n; i++){
+		res->r[i] = mpnew(0);
+		mpmod(x, crt->m[i], res->r[i]);
+	}
+	return res;
+}
+
+// garners algorithm for converting residue form to linear
+void
+crtout(CRTpre *crt, CRTres *res, mpint *x)
+{
+	mpint *u;
+	int i;
+
+	u = mpnew(0);
+	mpassign(res->r[0], x);
+
+	for(i = 1; i < crt->n; i++){
+		mpsub(res->r[i], x, u);
+		mpmul(u, crt->c[i], u);
+		mpmod(u, crt->m[i], u);
+		mpmul(u, crt->p[i-1], u);
+		mpadd(x, u, x);
+	}
+
+	mpfree(u);
+}
+
+// free the residue
+void
+crtresfree(CRTres *res)
+{
+	int i;
+
+	for(i = 0; i < res->n; i++)
+		mpfree(res->r[i]);
+	free(res);
+}
--- /dev/null
+++ b/libmp/port/crttest.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+void
+testcrt(mpint **p)
+{
+	CRTpre *crt;
+	CRTres *res;
+	mpint *m, *x, *y;
+	int i;
+
+	fmtinstall('B', mpconv);
+
+	// get a modulus and a test number
+	m = mpnew(1024+160);
+	mpmul(p[0], p[1], m);
+	x = mpnew(1024+160);
+	mpadd(m, mpone, x);
+
+	// do the precomputation for crt conversion
+	crt = crtpre(2, p);
+
+	// convert x to residues
+	res = crtin(crt, x);
+
+	// convert back
+	y = mpnew(1024+160);
+	crtout(crt, res, y);
+	print("x %B\ny %B\n", x, y);
+	mpfree(m);
+	mpfree(x);
+	mpfree(y);
+}
+
+void
+main(void)
+{
+	int i;
+	mpint *p[2];
+	long start;
+
+	start = time(0);
+	for(i = 0; i < 10; i++){
+		p[0] = mpnew(1024);
+		p[1] = mpnew(1024);
+		DSAprimes(p[0], p[1], nil);
+		testcrt(p);
+		mpfree(p[0]);
+		mpfree(p[1]);
+	}
+	print("%d secs with more\n", time(0)-start);
+	exits(0);
+}
--- /dev/null
+++ b/libmp/port/dat.h
@@ -1,0 +1,12 @@
+#define	mpdighi  (mpdigit)((ulong)1<<(Dbits-1))
+#define DIGITS(x) ((Dbits - 1 + (x))/Dbits)
+
+// for converting between int's and mpint's
+#define MAXUINT ((uint)-1)
+#define MAXINT (MAXUINT>>1)
+#define MININT (MAXINT+1)
+
+// for converting between vlongs's and mpint's
+#define MAXUVLONG (~(uvlong)0)
+#define MAXVLONG (MAXUVLONG>>1)
+#define MINVLONG (MAXVLONG+(uvlong)1)
--- /dev/null
+++ b/libmp/port/letomp.c
@@ -1,0 +1,28 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert a little endian byte array (least significant byte first) to an mpint
+mpint*
+letomp(uchar *s, uint n, mpint *b)
+{
+	int i=0, m = 0;
+	mpdigit x=0;
+
+	if(b == nil)
+		b = mpnew(0);
+	mpbits(b, 8*n);
+	for(; n > 0; n--){
+		x |= ((mpdigit)(*s++)) << i;
+		i += 8;
+		if(i == Dbits){
+			b->p[m++] = x;
+			i = 0;
+			x = 0;
+		}
+	}
+	if(i > 0)
+		b->p[m++] = x;
+	b->top = m;
+	return b;
+}
--- /dev/null
+++ b/libmp/port/mkfile
@@ -1,0 +1,52 @@
+<../../mkconfig
+
+LIB=libmp.a
+FILES=\
+	mpaux\
+	mpfmt\
+	strtomp\
+	mptobe\
+	mptole\
+	betomp\
+	letomp\
+	mpadd\
+	mpsub\
+	mpcmp\
+	mpfactorial\
+	mpmul\
+	mpleft\
+	mpright\
+	mpvecadd\
+	mpvecsub\
+	mpvecdigmuladd\
+	mpveccmp\
+	mpdigdiv\
+	mpdiv\
+	mpexp\
+	mpmod\
+	mpextendedgcd\
+	mpinvert\
+	mprand\
+	crt\
+	mptoi\
+	mptoui\
+	mptov\
+	mptouv\
+
+ALLOFILES=${FILES:%=%.$O}
+# cull things in the per-machine directories from this list
+OFILES=	`{$SHELLNAME ./reduce-$SHELLTYPE $O $TARGMODEL-$OBJTYPE $ALLOFILES }
+
+HFILES=\
+	$ROOT/$OBJDIR/include/lib9.h\
+	$ROOT/include/mp.h\
+	dat.h\
+
+CFILES=${FILES:%=%.c}
+
+
+UPDATE=mkfile\
+	$HFILES\
+	$CFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libmp/port/mpadd.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// sum = abs(b1) + abs(b2), i.e., add the magnitudes
+void
+mpmagadd(mpint *b1, mpint *b2, mpint *sum)
+{
+	int m, n;
+	mpint *t;
+
+	// get the sizes right
+	if(b2->top > b1->top){
+		t = b1;
+		b1 = b2;
+		b2 = t;
+	}
+	n = b1->top;
+	m = b2->top;
+	if(n == 0){
+		mpassign(mpzero, sum);
+		return;
+	}
+	if(m == 0){
+		mpassign(b1, sum);
+		return;
+	}
+	mpbits(sum, (n+1)*Dbits);
+	sum->top = n+1;
+
+	mpvecadd(b1->p, n, b2->p, m, sum->p);
+	sum->sign = 1;
+
+	mpnorm(sum);
+}
+
+// sum = b1 + b2
+void
+mpadd(mpint *b1, mpint *b2, mpint *sum)
+{
+	int sign;
+
+	if(b1->sign != b2->sign){
+		if(b1->sign < 0)
+			mpmagsub(b2, b1, sum);
+		else
+			mpmagsub(b1, b2, sum);
+	} else {
+		sign = b1->sign;
+		mpmagadd(b1, b2, sum);
+		if(sum->top != 0)
+			sum->sign = sign;
+	}
+}
--- /dev/null
+++ b/libmp/port/mpaux.c
@@ -1,0 +1,189 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+static mpdigit _mptwodata[1] = { 2 };
+static mpint _mptwo =
+{
+	1,
+	1,
+	1,
+	_mptwodata,
+	MPstatic
+};
+mpint *mptwo = &_mptwo;
+
+static mpdigit _mponedata[1] = { 1 };
+static mpint _mpone =
+{
+	1,
+	1,
+	1,
+	_mponedata,
+	MPstatic
+};
+mpint *mpone = &_mpone;
+
+static mpdigit _mpzerodata[1] = { 0 };
+static mpint _mpzero =
+{
+	1,
+	1,
+	0,
+	_mpzerodata,
+	MPstatic
+};
+mpint *mpzero = &_mpzero;
+
+static int mpmindigits = 33;
+
+// set minimum digit allocation
+void
+mpsetminbits(int n)
+{
+	if(n < 0)
+		sysfatal("mpsetminbits: n < 0");
+	if(n == 0)
+		n = 1;
+	mpmindigits = DIGITS(n);
+}
+
+// allocate an n bit 0'd number 
+mpint*
+mpnew(int n)
+{
+	mpint *b;
+
+	if(n < 0)
+		sysfatal("mpsetminbits: n < 0");
+
+	b = mallocz(sizeof(mpint), 1);
+	if(b == nil)
+		sysfatal("mpnew: %r");
+	n = DIGITS(n);
+	if(n < mpmindigits)
+		n = mpmindigits;
+	b->p = (mpdigit*)mallocz(n*Dbytes, 1);
+	if(b->p == nil)
+		sysfatal("mpnew: %r");
+	b->size = n;
+	b->sign = 1;
+
+	return b;
+}
+
+// guarantee at least n significant bits
+void
+mpbits(mpint *b, int m)
+{
+	int n;
+
+	n = DIGITS(m);
+	if(b->size >= n){
+		if(b->top >= n)
+			return;
+		memset(&b->p[b->top], 0, Dbytes*(n - b->top));
+		b->top = n;
+		return;
+	}
+	b->p = (mpdigit*)realloc(b->p, n*Dbytes);
+	if(b->p == nil)
+		sysfatal("mpbits: %r");
+	memset(&b->p[b->top], 0, Dbytes*(n - b->top));
+	b->size = n;
+	b->top = n;
+}
+
+void
+mpfree(mpint *b)
+{
+	if(b == nil)
+		return;
+	if(b->flags & MPstatic)
+		sysfatal("freeing mp constant");
+	memset(b->p, 0, b->size*Dbytes);	// information hiding
+	free(b->p);
+	free(b);
+}
+
+void
+mpnorm(mpint *b)
+{
+	int i;
+
+	for(i = b->top-1; i >= 0; i--)
+		if(b->p[i] != 0)
+			break;
+	b->top = i+1;
+	if(b->top == 0)
+		b->sign = 1;
+}
+
+mpint*
+mpcopy(mpint *old)
+{
+	mpint *new;
+
+	new = mpnew(Dbits*old->size);
+	new->top = old->top;
+	new->sign = old->sign;
+	memmove(new->p, old->p, Dbytes*old->top);
+	return new;
+}
+
+void
+mpassign(mpint *old, mpint *new)
+{
+	mpbits(new, Dbits*old->top);
+	new->sign = old->sign;
+	new->top = old->top;
+	memmove(new->p, old->p, Dbytes*old->top);
+}
+
+// number of significant bits in mantissa
+int
+mpsignif(mpint *n)
+{
+	int i, j;
+	mpdigit d;
+
+	if(n->top == 0)
+		return 0;
+	for(i = n->top-1; i >= 0; i--){
+		d = n->p[i];
+		for(j = Dbits-1; j >= 0; j--){
+			if(d & (((mpdigit)1)<<j))
+				return i*Dbits + j + 1;
+		}
+	}
+	return 0;
+}
+
+// k, where n = 2**k * q for odd q
+int
+mplowbits0(mpint *n)
+{
+	int k, bit, digit;
+	mpdigit d;
+
+	if(n->top==0)
+		return 0;
+	k = 0;
+	bit = 0;
+	digit = 0;
+	d = n->p[0];
+	for(;;){
+		if(d & (1<<bit))
+			break;
+		k++;
+		bit++;
+		if(bit==Dbits){
+			if(++digit >= n->top)
+				return 0;
+			d = n->p[digit];
+			bit = 0;
+		}
+	}
+	return k;
+}
+
--- /dev/null
+++ b/libmp/port/mpcmp.c
@@ -1,0 +1,28 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// return neg, 0, pos as abs(b1)-abs(b2) is neg, 0, pos
+int
+mpmagcmp(mpint *b1, mpint *b2)
+{
+	int i;
+
+	i = b1->top - b2->top;
+	if(i)
+		return i;
+
+	return mpveccmp(b1->p, b1->top, b2->p, b2->top);
+}
+
+// return neg, 0, pos as b1-b2 is neg, 0, pos
+int
+mpcmp(mpint *b1, mpint *b2)
+{
+	if(b1->sign != b2->sign)
+		return b1->sign - b2->sign;
+	if(b1->sign < 0)
+		return mpmagcmp(b2, b1);
+	else
+		return mpmagcmp(b1, b2);
+}
--- /dev/null
+++ b/libmp/port/mpdigdiv.c
@@ -1,0 +1,43 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+//
+//	divide two digits by one and return quotient
+//
+void
+mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient)
+{
+	mpdigit hi, lo, q, x, y;
+	int i;
+
+	hi = dividend[1];
+	lo = dividend[0];
+
+	// return highest digit value if the result >= 2**32
+	if(hi >= divisor || divisor == 0){
+		divisor = 0;
+		*quotient = ~divisor;
+		return;
+	}
+
+	// at this point we know that hi < divisor
+	// just shift and subtract till we're done
+	q = 0;
+	x = divisor;
+	for(i = Dbits-1; hi > 0 && i >= 0; i--){
+		x >>= 1;
+		if(x > hi)
+			continue;
+		y = divisor<<i;
+		if(x == hi && y > lo)
+			continue;
+		if(y > lo)
+			hi--;
+		lo -= y;
+		hi -= x;
+		q |= 1<<i;
+	}
+	q += lo/divisor;
+	*quotient = q;
+}
--- /dev/null
+++ b/libmp/port/mpdiv.c
@@ -1,0 +1,112 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// division ala knuth, seminumerical algorithms, pp 237-238
+// the numbers are stored backwards to what knuth expects so j
+// counts down rather than up.
+
+void
+mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder)
+{
+	int j, s, vn, sign;
+	mpdigit qd, *up, *vp, *qp;
+	mpint *u, *v, *t;
+
+	// divide bv zero
+	if(divisor->top == 0)
+		sysfatal("mpdiv: divide by zero");
+
+	// quick check
+	if(mpmagcmp(dividend, divisor) < 0){
+		if(remainder != nil)
+			mpassign(dividend, remainder);
+		if(quotient != nil)
+			mpassign(mpzero, quotient);
+		return;
+	}
+
+	// D1: shift until divisor, v, has hi bit set (needed to make trial
+	//     divisor accurate)
+	qd = divisor->p[divisor->top-1];
+	for(s = 0; (qd & mpdighi) == 0; s++)
+		qd <<= 1;
+	u = mpnew((dividend->top+2)*Dbits + s);
+	if(s == 0 && divisor != quotient && divisor != remainder) {
+		mpassign(dividend, u);
+		v = divisor;
+	} else {
+		mpleft(dividend, s, u);
+		v = mpnew(divisor->top*Dbits);
+		mpleft(divisor, s, v);
+	}
+	up = u->p+u->top-1;
+	vp = v->p+v->top-1;
+	vn = v->top;
+
+	// D1a: make sure high digit of dividend is less than high digit of divisor
+	if(*up >= *vp){
+		*++up = 0;
+		u->top++;
+	}
+
+	// storage for multiplies
+	t = mpnew(4*Dbits);
+
+	qp = nil;
+	if(quotient != nil){
+		mpbits(quotient, (u->top - v->top)*Dbits);
+		quotient->top = u->top - v->top;
+		qp = quotient->p+quotient->top-1;
+	}
+
+	// D2, D7: loop on length of dividend
+	for(j = u->top; j > vn; j--){
+
+		// D3: calculate trial divisor
+		mpdigdiv(up-1, *vp, &qd);
+
+		// D3a: rule out trial divisors 2 greater than real divisor
+		if(vn > 1) for(;;){
+			memset(t->p, 0, 3*Dbytes);	// mpvecdigmuladd adds to what's there
+			mpvecdigmuladd(vp-1, 2, qd, t->p);
+			if(mpveccmp(t->p, 3, up-2, 3) > 0)
+				qd--;
+			else
+				break;
+		}
+
+		// D4: u -= v*qd << j*Dbits
+		sign = mpvecdigmulsub(v->p, vn, qd, up-vn);
+		if(sign < 0){
+
+			// D6: trial divisor was too high, add back borrowed
+			//     value and decrease divisor
+			mpvecadd(up-vn, vn+1, v->p, vn, up-vn);
+			qd--;
+		}
+
+		// D5: save quotient digit
+		if(qp != nil)
+			*qp-- = qd;
+
+		// push top of u down one
+		u->top--;
+		*up-- = 0;
+	}
+	if(qp != nil){
+		mpnorm(quotient);
+		if(dividend->sign != divisor->sign)
+			quotient->sign = -1;
+	}
+
+	if(remainder != nil){
+		mpright(u, s, remainder);	// u is the remainder shifted
+		remainder->sign = dividend->sign;
+	}
+
+	mpfree(t);
+	mpfree(u);
+	if(v != divisor)
+		mpfree(v);
+}
--- /dev/null
+++ b/libmp/port/mpeuclid.c
@@ -1,0 +1,85 @@
+#include "os.h"
+#include <mp.h>
+
+// extended euclid
+//
+// For a and b it solves, d = gcd(a,b) and finds x and y s.t.
+// ax + by = d
+//
+// Handbook of Applied Cryptography, Menezes et al, 1997, pg 67
+
+void
+mpeuclid(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y)
+{
+	mpint *tmp, *x0, *x1, *x2, *y0, *y1, *y2, *q, *r;
+
+	if(a->sign<0 || b->sign<0)
+		sysfatal("mpeuclid: negative arg");
+
+	if(mpcmp(a, b) < 0){
+		tmp = a;
+		a = b;
+		b = tmp;
+		tmp = x;
+		x = y;
+		y = tmp;
+	}
+
+	if(b->top == 0){
+		mpassign(a, d);
+		mpassign(mpone, x);
+		mpassign(mpzero, y);
+		return;
+	}
+
+	a = mpcopy(a);
+	b = mpcopy(b);
+	x0 = mpnew(0);
+	x1 = mpcopy(mpzero);
+	x2 = mpcopy(mpone);
+	y0 = mpnew(0);
+	y1 = mpcopy(mpone);
+	y2 = mpcopy(mpzero);
+	q = mpnew(0);
+	r = mpnew(0);
+
+	while(b->top != 0 && b->sign > 0){
+		// q = a/b
+		// r = a mod b
+		mpdiv(a, b, q, r);
+		// x0 = x2 - qx1
+		mpmul(q, x1, x0);
+		mpsub(x2, x0, x0);
+		// y0 = y2 - qy1
+		mpmul(q, y1, y0);
+		mpsub(y2, y0, y0);
+		// rotate values
+		tmp = a;
+		a = b;
+		b = r;
+		r = tmp;
+		tmp = x2;
+		x2 = x1;
+		x1 = x0;
+		x0 = tmp;
+		tmp = y2;
+		y2 = y1;
+		y1 = y0;
+		y0 = tmp;
+	}
+
+	mpassign(a, d);
+	mpassign(x2, x);
+	mpassign(y2, y);
+
+	mpfree(x0);
+	mpfree(x1);
+	mpfree(x2);
+	mpfree(y0);
+	mpfree(y1);
+	mpfree(y2);
+	mpfree(q);
+	mpfree(r);
+	mpfree(a);
+	mpfree(b);
+}
--- /dev/null
+++ b/libmp/port/mpexp.c
@@ -1,0 +1,94 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// res = b**e
+//
+// knuth, vol 2, pp 398-400
+
+enum {
+	Freeb=	0x1,
+	Freee=	0x2,
+	Freem=	0x4,
+};
+
+//int expdebug;
+
+void
+mpexp(mpint *b, mpint *e, mpint *m, mpint *res)
+{
+	mpint *t[2];
+	int tofree;
+	mpdigit d, bit;
+	int i, j;
+
+	i = mpcmp(e,mpzero);
+	if(i==0){
+		mpassign(mpone, res);
+		return;
+	}
+	if(i<0)
+		sysfatal("mpexp: negative exponent");
+
+	t[0] = mpcopy(b);
+	t[1] = res;
+
+	tofree = 0;
+	if(res == b){
+		b = mpcopy(b);
+		tofree |= Freeb;
+	}
+	if(res == e){
+		e = mpcopy(e);
+		tofree |= Freee;
+	}
+	if(res == m){
+		m = mpcopy(m);
+		tofree |= Freem;
+	}
+
+	// skip first bit
+	i = e->top-1;
+	d = e->p[i];
+	for(bit = mpdighi; (bit & d) == 0; bit >>= 1)
+		;
+	bit >>= 1;
+
+	j = 0;
+	for(;;){
+		for(; bit != 0; bit >>= 1){
+			mpmul(t[j], t[j], t[j^1]);
+			if(bit & d)
+				mpmul(t[j^1], b, t[j]);
+			else
+				j ^= 1;
+			if(m != nil && t[j]->top > m->top){
+				mpmod(t[j], m, t[j^1]);
+				j ^= 1;
+			}
+		}
+		if(--i < 0)
+			break;
+		bit = mpdighi;
+		d = e->p[i];
+	}
+	if(m != nil){
+		mpmod(t[j], m, t[j^1]);
+		j ^= 1;
+	}
+	if(t[j] == res){
+		mpfree(t[j^1]);
+	} else {
+		mpassign(t[j], res);
+		mpfree(t[j]);
+	}
+
+	if(tofree){
+		if(tofree & Freeb)
+			mpfree(b);
+		if(tofree & Freee)
+			mpfree(e);
+		if(tofree & Freem)
+			mpfree(m);
+	}
+}
--- /dev/null
+++ b/libmp/port/mpextendedgcd.c
@@ -1,0 +1,104 @@
+#include "os.h"
+#include <mp.h>
+
+#define iseven(a)	(((a)->p[0] & 1) == 0)
+
+// extended binary gcd
+//
+// For a anv b it solves, v = gcd(a,b) and finds x and y s.t.
+// ax + by = v
+//
+// Handbook of Applied Cryptography, Menezes et al, 1997, pg 608.  
+void
+mpextendedgcd(mpint *a, mpint *b, mpint *v, mpint *x, mpint *y)
+{
+	mpint *u, *A, *B, *C, *D;
+	int g;
+
+	if(a->sign < 0 || b->sign < 0){
+		mpassign(mpzero, v);
+		mpassign(mpzero, y);
+		mpassign(mpzero, x);
+		return;
+	}
+
+	if(a->top == 0){
+		mpassign(b, v);
+		mpassign(mpone, y);
+		mpassign(mpzero, x);
+		return;
+	}
+	if(b->top == 0){
+		mpassign(a, v);
+		mpassign(mpone, x);
+		mpassign(mpzero, y);
+		return;
+	}
+
+	g = 0;
+	a = mpcopy(a);
+	b = mpcopy(b);
+
+	while(iseven(a) && iseven(b)){
+		mpright(a, 1, a);
+		mpright(b, 1, b);
+		g++;
+	}
+
+	u = mpcopy(a);
+	mpassign(b, v);
+	A = mpcopy(mpone);
+	B = mpcopy(mpzero);
+	C = mpcopy(mpzero);
+	D = mpcopy(mpone);
+
+	for(;;) {
+//		print("%B %B %B %B %B %B\n", u, v, A, B, C, D);
+		while(iseven(u)){
+			mpright(u, 1, u);
+			if(!iseven(A) || !iseven(B)) {
+				mpadd(A, b, A);
+				mpsub(B, a, B);
+			}
+			mpright(A, 1, A);
+			mpright(B, 1, B);
+		}
+	
+//		print("%B %B %B %B %B %B\n", u, v, A, B, C, D);
+		while(iseven(v)){
+			mpright(v, 1, v);
+			if(!iseven(C) || !iseven(D)) {
+				mpadd(C, b, C);
+				mpsub(D, a, D);
+			}
+			mpright(C, 1, C);
+			mpright(D, 1, D);
+		}
+	
+//		print("%B %B %B %B %B %B\n", u, v, A, B, C, D);
+		if(mpcmp(u, v) >= 0){
+			mpsub(u, v, u);
+			mpsub(A, C, A);
+			mpsub(B, D, B);
+		} else {
+			mpsub(v, u, v);
+			mpsub(C, A, C);
+			mpsub(D, B, D);
+		}
+
+		if(u->top == 0)
+			break;
+
+	}
+	mpassign(C, x);
+	mpassign(D, y);
+	mpleft(v, g, v);
+
+	mpfree(A);
+	mpfree(B);
+	mpfree(C);
+	mpfree(D);
+	mpfree(u);
+	mpfree(a);
+	mpfree(b);
+}
--- /dev/null
+++ b/libmp/port/mpfactorial.c
@@ -1,0 +1,79 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+mpint*
+mpfactorial(ulong n)
+{
+	int i;
+	ulong k;
+	unsigned cnt;
+	int max, mmax;
+	mpdigit p, pp[2];
+	mpint *r, *s, *stk[31];
+
+	cnt = 0;
+	max = mmax = -1;
+	p = 1;
+	r = mpnew(0);
+	for(k=2; k<=n; k++){
+		pp[0] = 0;
+		pp[1] = 0;
+		mpvecdigmuladd(&p, 1, (mpdigit)k, pp);
+		if(pp[1] == 0)	/* !overflow */
+			p = pp[0];
+		else{
+			cnt++;
+			if((cnt & 1) == 0){
+				s = stk[max];
+				mpbits(r, Dbits*(s->top+1+1));
+				memset(r->p, 0, Dbytes*(s->top+1+1));
+				mpvecmul(s->p, s->top, &p, 1, r->p);
+				r->sign = 1;
+				r->top = s->top+1+1;		/* XXX: norm */
+				mpassign(r, s);
+				for(i=4; (cnt & (i-1)) == 0; i=i<<1){
+					mpmul(stk[max], stk[max-1], r);
+					mpassign(r, stk[max-1]);
+					max--;
+				}
+			}else{
+				max++;
+				if(max > mmax){
+					mmax++;
+					if(max >= nelem(stk)){
+						while(--max >= 0)
+							mpfree(stk[max]);
+						mpfree(r);
+						sysfatal("mpfactorial: stack overflow");
+					}
+					stk[max] = mpnew(Dbits);
+				}
+				stk[max]->top = 1;
+				stk[max]->p[0] = p;
+			}
+			p = (mpdigit)k;
+		}
+	}
+	if(max < 0){
+		mpbits(r, Dbits);
+		r->top = 1;
+		r->sign = 1;
+		r->p[0] = p;
+	}else{
+		s = stk[max--];
+		mpbits(r, Dbits*(s->top+1+1));
+		memset(r->p, 0, Dbytes*(s->top+1+1));
+		mpvecmul(s->p, s->top, &p, 1, r->p);
+		r->sign = 1;
+		r->top = s->top+1+1;		/* XXX: norm */
+	}
+
+	while(max >= 0)
+		mpmul(r, stk[max--], r);
+	for(max=mmax; max>=0; max--)
+		mpfree(stk[max]);
+	mpnorm(r);
+	return r;
+}
--- /dev/null
+++ b/libmp/port/mpfmt.c
@@ -1,0 +1,193 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+static int
+to64(mpint *b, char *buf, int len)
+{
+	uchar *p;
+	int n, rv;
+
+	p = nil;
+	n = mptobe(b, nil, 0, &p);
+	if(n < 0)
+		return -1;
+	rv = enc64(buf, len, p, n);
+	free(p);
+	return rv;
+}
+
+static int
+to32(mpint *b, char *buf, int len)
+{
+	uchar *p;
+	int n, rv;
+
+	// leave room for a multiple of 5 buffer size
+	n = b->top*Dbytes + 5;
+	p = malloc(n);
+	if(p == nil)
+		return -1;
+	n = mptobe(b, p, n, nil);
+	if(n < 0)
+		return -1;
+
+	// round up buffer size, enc32 only accepts a multiple of 5
+	if(n%5)
+		n += 5 - (n%5);
+	rv = enc32(buf, len, p, n);
+	free(p);
+	return rv;
+}
+
+static char set16[] = "0123456789ABCDEF";
+
+static int
+to16(mpint *b, char *buf, int len)
+{
+	mpdigit *p, x;
+	int i, j;
+	char *out, *eout;
+
+	if(len < 1)
+		return -1;
+
+	out = buf;
+	eout = buf+len;
+	for(p = &b->p[b->top-1]; p >= b->p; p--){
+		x = *p;
+		for(i = Dbits-4; i >= 0; i -= 4){
+			j = 0xf & (x>>i);
+			if(j != 0 || out != buf){
+				if(out >= eout)
+					return -1;
+				*out++ = set16[j];
+			}
+		}
+	}
+	if(out == buf)
+		*out++ = '0';
+	if(out >= eout)
+		return -1;
+	*out = 0;
+	return 0;
+}
+
+static char*
+modbillion(int rem, ulong r, char *out, char *buf)
+{
+	ulong rr;
+	int i;
+
+	for(i = 0; i < 9; i++){
+		rr = r%10;
+		r /= 10;
+		if(out <= buf)
+			return nil;
+		*--out = '0' + rr;
+		if(rem == 0 && r == 0)
+			break;
+	}
+	return out;
+}
+
+static int
+to10(mpint *b, char *buf, int len)
+{
+	mpint *d, *r, *billion;
+	char *out;
+
+	if(len < 1)
+		return -1;
+
+	d = mpcopy(b);
+	r = mpnew(0);
+	billion = uitomp(1000000000, nil);
+	out = buf+len;
+	*--out = 0;
+	do {
+		mpdiv(d, billion, d, r);
+		out = modbillion(d->top, r->p[0], out, buf);
+		if(out == nil)
+			break;
+	} while(d->top != 0);
+	mpfree(d);
+	mpfree(r);
+	mpfree(billion);
+
+	if(out == nil)
+		return -1;
+	len -= out-buf;
+	if(out != buf)
+		memmove(buf, out, len);
+	return 0;
+}
+
+int
+mpfmt(Fmt *fmt)
+{
+	mpint *b;
+	char *p;
+
+	b = va_arg(fmt->args, mpint*);
+	if(b == nil)
+		return fmtstrcpy(fmt, "*");
+	
+	p = mptoa(b, fmt->prec, nil, 0);
+	fmt->flags &= ~FmtPrec;
+
+	if(p == nil)
+		return fmtstrcpy(fmt, "*");
+	else{
+		fmtstrcpy(fmt, p);
+		free(p);
+		return 0;
+	}
+}
+
+char*
+mptoa(mpint *b, int base, char *buf, int len)
+{
+	char *out;
+	int rv, alloced;
+
+	alloced = 0;
+	if(buf == nil){
+		len = ((b->top+1)*Dbits+2)/3 + 1;
+		buf = malloc(len);
+		if(buf == nil)
+			return nil;
+		alloced = 1;
+	}
+
+	if(len < 2)
+		return nil;
+
+	out = buf;
+	if(b->sign < 0){
+		*out++ = '-';
+		len--;
+	}
+	switch(base){
+	case 64:
+		rv = to64(b, out, len);
+		break;
+	case 32:
+		rv = to32(b, out, len);
+		break;
+	default:
+	case 16:
+		rv = to16(b, out, len);
+		break;
+	case 10:
+		rv = to10(b, out, len);
+		break;
+	}
+	if(rv < 0){
+		if(alloced)
+			free(buf);
+		return nil;
+	}
+	return buf;
+}
--- /dev/null
+++ b/libmp/port/mpinvert.c
@@ -1,0 +1,23 @@
+#include "os.h"
+#include <mp.h>
+
+#define iseven(a)	(((a)->p[0] & 1) == 0)
+
+// use extended gcd to find the multiplicative inverse
+// res = b**-1 mod m
+void
+mpinvert(mpint *b, mpint *m, mpint *res)
+{
+	mpint *dc1, *dc2;	// don't care
+	int r;
+
+	dc1 = mpnew(0);
+	dc2 = mpnew(0);
+	mpextendedgcd(b, m, dc1, res, dc2);
+	r = mpcmp(dc1, mpone);
+	mpfree(dc1);
+	mpfree(dc2);
+	if(r != 0)
+		sysfatal("mpinvert: no inverse");
+	mpmod(res, m, res);
+}
--- /dev/null
+++ b/libmp/port/mpleft.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// res = b << shift
+void
+mpleft(mpint *b, int shift, mpint *res)
+{
+	int d, l, r, i, otop;
+	mpdigit this, last;
+
+	res->sign = b->sign;
+	if(b->top==0){
+		res->top = 0;
+		return;
+	}
+
+	// a negative left shift is a right shift
+	if(shift < 0){
+		mpright(b, -shift, res);
+		return;
+	}
+
+	// b and res may be the same so remember the old top
+	otop = b->top;
+
+	// shift
+	mpbits(res, otop*Dbits + shift);	// overkill
+	res->top = DIGITS(otop*Dbits + shift);
+	d = shift/Dbits;
+	l = shift - d*Dbits;
+	r = Dbits - l;
+
+	if(l == 0){
+		for(i = otop-1; i >= 0; i--)
+			res->p[i+d] = b->p[i];
+	} else {
+		last = 0;
+		for(i = otop-1; i >= 0; i--) {
+			this = b->p[i];
+			res->p[i+d+1] = (last<<l) | (this>>r);
+			last = this;
+		}
+		res->p[d] = last<<l;
+	}
+	for(i = 0; i < d; i++)
+		res->p[i] = 0;
+
+	// normalize
+	while(res->top > 0 && res->p[res->top-1] == 0)
+		res->top--;
+}
--- /dev/null
+++ b/libmp/port/mpmod.c
@@ -1,0 +1,15 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// remainder = b mod m
+//
+// knuth, vol 2, pp 398-400
+
+void
+mpmod(mpint *b, mpint *m, mpint *remainder)
+{
+	mpdiv(b, m, nil, remainder);
+	if(remainder->sign < 0)
+		mpadd(m, remainder, remainder);
+}
--- /dev/null
+++ b/libmp/port/mpmul.c
@@ -1,0 +1,156 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+//
+//  from knuth's 1969 seminumberical algorithms, pp 233-235 and pp 258-260
+//
+//  mpvecmul is an assembly language routine that performs the inner
+//  loop.
+//
+//  the karatsuba trade off is set empiricly by measuring the algs on
+//  a 400 MHz Pentium II.
+//
+
+// karatsuba like (see knuth pg 258)
+// prereq: p is already zeroed
+static void
+mpkaratsuba(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
+{
+	mpdigit *t, *u0, *u1, *v0, *v1, *u0v0, *u1v1, *res, *diffprod;
+	int u0len, u1len, v0len, v1len, reslen;
+	int sign, n;
+
+	// divide each piece in half
+	n = alen/2;
+	if(alen&1)
+		n++;
+	u0len = n;
+	u1len = alen-n;
+	if(blen > n){
+		v0len = n;
+		v1len = blen-n;
+	} else {
+		v0len = blen;
+		v1len = 0;
+	}
+	u0 = a;
+	u1 = a + u0len;
+	v0 = b;
+	v1 = b + v0len;
+
+	// room for the partial products
+	t = mallocz(Dbytes*5*(2*n+1), 1);
+	if(t == nil)
+		sysfatal("mpkaratsuba: %r");
+	u0v0 = t;
+	u1v1 = t + (2*n+1);
+	diffprod = t + 2*(2*n+1);
+	res = t + 3*(2*n+1);
+	reslen = 4*n+1;
+
+	// t[0] = (u1-u0)
+	sign = 1;
+	if(mpveccmp(u1, u1len, u0, u0len) < 0){
+		sign = -1;
+		mpvecsub(u0, u0len, u1, u1len, u0v0);
+	} else
+		mpvecsub(u1, u1len, u0, u1len, u0v0);
+
+	// t[1] = (v0-v1)
+	if(mpveccmp(v0, v0len, v1, v1len) < 0){
+		sign *= -1;
+		mpvecsub(v1, v1len, v0, v1len, u1v1);
+	} else
+		mpvecsub(v0, v0len, v1, v1len, u1v1);
+
+	// t[4:5] = (u1-u0)*(v0-v1)
+	mpvecmul(u0v0, u0len, u1v1, v0len, diffprod);
+
+	// t[0:1] = u1*v1
+	memset(t, 0, 2*(2*n+1)*Dbytes);
+	if(v1len > 0)
+		mpvecmul(u1, u1len, v1, v1len, u1v1);
+
+	// t[2:3] = u0v0
+	mpvecmul(u0, u0len, v0, v0len, u0v0);
+
+	// res = u0*v0<<n + u0*v0
+	mpvecadd(res, reslen, u0v0, u0len+v0len, res);
+	mpvecadd(res+n, reslen-n, u0v0, u0len+v0len, res+n);
+
+	// res += u1*v1<<n + u1*v1<<2*n
+	if(v1len > 0){
+		mpvecadd(res+n, reslen-n, u1v1, u1len+v1len, res+n);
+		mpvecadd(res+2*n, reslen-2*n, u1v1, u1len+v1len, res+2*n);
+	}
+
+	// res += (u1-u0)*(v0-v1)<<n
+	if(sign < 0)
+		mpvecsub(res+n, reslen-n, diffprod, u0len+v0len, res+n);
+	else
+		mpvecadd(res+n, reslen-n, diffprod, u0len+v0len, res+n);
+	memmove(p, res, (alen+blen)*Dbytes);
+
+	free(t);
+}
+
+#define KARATSUBAMIN 32
+
+void
+mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p)
+{
+	int i;
+	mpdigit d;
+	mpdigit *t;
+
+	// both mpvecdigmuladd and karatsuba are fastest when a is the longer vector
+	if(alen < blen){
+		i = alen;
+		alen = blen;
+		blen = i;
+		t = a;
+		a = b;
+		b = t;
+	}
+	if(blen == 0){
+		memset(p, 0, Dbytes*(alen+blen));
+		return;
+	}
+
+	if(alen >= KARATSUBAMIN && blen > 1){
+		// O(n^1.585)
+		mpkaratsuba(a, alen, b, blen, p);
+	} else {
+		// O(n^2)
+		for(i = 0; i < blen; i++){
+			d = b[i];
+			if(d != 0)
+				mpvecdigmuladd(a, alen, d, &p[i]);
+		}
+	}
+}
+
+void
+mpmul(mpint *b1, mpint *b2, mpint *prod)
+{
+	mpint *oprod;
+
+	oprod = nil;
+	if(prod == b1 || prod == b2){
+		oprod = prod;
+		prod = mpnew(0);
+	}
+
+	prod->top = 0;
+	mpbits(prod, (b1->top+b2->top+1)*Dbits);
+	mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p);
+	prod->top = b1->top+b2->top+1;
+	prod->sign = b1->sign*b2->sign;
+	mpnorm(prod);
+
+	if(oprod != nil){
+		mpassign(prod, oprod);
+		mpfree(prod);
+	}
+}
--- /dev/null
+++ b/libmp/port/mprand.c
@@ -1,0 +1,42 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+mpint*
+mprand(int bits, void (*gen)(uchar*, int), mpint *b)
+{
+	int n, m;
+	mpdigit mask;
+	uchar *p;
+
+	n = DIGITS(bits);
+	if(b == nil)
+		b = mpnew(bits);
+	else
+		mpbits(b, bits);
+
+	p = malloc(n*Dbytes);
+	if(p == nil)
+		return nil;
+	(*gen)(p, n*Dbytes);
+	betomp(p, n*Dbytes, b);
+	free(p);
+
+	// make sure we don't give too many bits
+	m = bits%Dbits;
+	n--;
+	if(m > 0){
+		mask = 1;
+		mask <<= m;
+		mask--;
+		b->p[n] &= mask;
+	}
+
+	for(; n >= 0; n--)
+		if(b->p[n] != 0)
+			break;
+	b->top = n+1;
+	b->sign = 1;
+	return b;
+}
--- /dev/null
+++ b/libmp/port/mpright.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// res = b >> shift
+void
+mpright(mpint *b, int shift, mpint *res)
+{
+	int d, l, r, i;
+	mpdigit this, last;
+
+	res->sign = b->sign;
+	if(b->top==0){
+		res->top = 0;
+		return;
+	}
+
+	// a negative right shift is a left shift
+	if(shift < 0){
+		mpleft(b, -shift, res);
+		return;
+	}
+
+	if(res != b)
+		mpbits(res, b->top*Dbits - shift);
+	d = shift/Dbits;
+	r = shift - d*Dbits;
+	l = Dbits - r;
+
+	//  shift all the bits out == zero
+	if(d>=b->top){
+		res->top = 0;
+		return;
+	}
+
+	// special case digit shifts
+	if(r == 0){
+		for(i = 0; i < b->top-d; i++)
+			res->p[i] = b->p[i+d];
+	} else {
+		last = b->p[d];
+		for(i = 0; i < b->top-d-1; i++){
+			this = b->p[i+d+1];
+			res->p[i] = (this<<l) | (last>>r);
+			last = this;
+		}
+		res->p[i++] = last>>r;
+	}
+	while(i > 0 && res->p[i-1] == 0)
+		i--;
+	res->top = i;
+	if(i==0)
+		res->sign = 1;
+}
--- /dev/null
+++ b/libmp/port/mpsub.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// diff = abs(b1) - abs(b2), i.e., subtract the magnitudes
+void
+mpmagsub(mpint *b1, mpint *b2, mpint *diff)
+{
+	int n, m, sign;
+	mpint *t;
+
+	// get the sizes right
+	if(mpmagcmp(b1, b2) < 0){
+		sign = -1;
+		t = b1;
+		b1 = b2;
+		b2 = t;
+	} else
+		sign = 1;
+	n = b1->top;
+	m = b2->top;
+	if(m == 0){
+		mpassign(b1, diff);
+		diff->sign = sign;
+		return;
+	}
+	mpbits(diff, n*Dbits);
+
+	mpvecsub(b1->p, n, b2->p, m, diff->p);
+	diff->sign = sign;
+	diff->top = n;
+	mpnorm(diff);
+}
+
+// diff = b1 - b2
+void
+mpsub(mpint *b1, mpint *b2, mpint *diff)
+{
+	int sign;
+
+	if(b1->sign != b2->sign){
+		sign = b1->sign;
+		mpmagadd(b1, b2, diff);
+		diff->sign = sign;
+		return;
+	}
+
+	sign = b1->sign;
+	mpmagsub(b1, b2, diff);
+	if(diff->top != 0)
+		diff->sign *= sign;
+}
--- /dev/null
+++ b/libmp/port/mptobe.c
@@ -1,0 +1,57 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert an mpint into a big endian byte array (most significant byte first)
+//   return number of bytes converted
+//   if p == nil, allocate and result array
+int
+mptobe(mpint *b, uchar *p, uint n, uchar **pp)
+{
+	int i, j, suppress;
+	mpdigit x;
+	uchar *e, *s, c;
+
+	if(p == nil){
+		n = (b->top+1)*Dbytes;
+		p = malloc(n);
+	}
+	if(p == nil)
+		return -1;
+	if(pp != nil)
+		*pp = p;
+	memset(p, 0, n);
+
+	// special case 0
+	if(b->top == 0){
+		if(n < 1)
+			return -1;
+		else
+			return 1;
+	}
+		
+	s = p;
+	e = s+n;
+	suppress = 1;
+	for(i = b->top-1; i >= 0; i--){
+		x = b->p[i];
+		for(j = Dbits-8; j >= 0; j -= 8){
+			c = x>>j;
+			if(c == 0 && suppress)
+				continue;
+			if(p >= e)
+				return -1;
+			*p++ = c;
+			suppress = 0;
+		}
+	}
+
+	// guarantee at least one byte
+	if(s == p){
+		if(p >= e)
+			return -1;
+		*p++ = 0;
+	}
+
+	return p - s;
+}
--- /dev/null
+++ b/libmp/port/mptoi.c
@@ -1,0 +1,46 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+/*
+ *  this code assumes that mpdigit is at least as
+ *  big as an int.
+ */
+
+mpint*
+itomp(int i, mpint *b)
+{
+	if(b == nil)
+		b = mpnew(0);
+	mpassign(mpzero, b);
+	if(i != 0)
+		b->top = 1;
+	if(i < 0){
+		b->sign = -1;
+		*b->p = -i;
+	} else
+		*b->p = i;
+	return b;
+}
+
+int
+mptoi(mpint *b)
+{
+	uint x;
+
+	if(b->top==0)
+		return 0;
+	x = *b->p;
+	if(b->sign > 0){
+		if(b->top > 1 || (x > MAXINT))
+			x = (int)MAXINT;
+		else
+			x = (int)x;
+	} else {
+		if(b->top > 1 || x > MAXINT+1)
+			x = (int)MININT;
+		else
+			x = -(int)x;
+	}
+	return x;
+}
--- /dev/null
+++ b/libmp/port/mptole.c
@@ -1,0 +1,54 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// convert an mpint into a little endian byte array (least significant byte first)
+
+//   return number of bytes converted
+//   if p == nil, allocate and result array
+int
+mptole(mpint *b, uchar *p, uint n, uchar **pp)
+{
+	int i, j;
+	mpdigit x;
+	uchar *e, *s;
+
+	if(p == nil){
+		n = (b->top+1)*Dbytes;
+		p = malloc(n);
+	}
+	if(pp != nil)
+		*pp = p;
+	if(p == nil)
+		return -1;
+	memset(p, 0, n);
+
+	// special case 0
+	if(b->top == 0){
+		if(n < 1)
+			return -1;
+		else
+			return 0;
+	}
+		
+	s = p;
+	e = s+n;
+	for(i = 0; i < b->top-1; i++){
+		x = b->p[i];
+		for(j = 0; j < Dbytes; j++){
+			if(p >= e)
+				return -1;
+			*p++ = x;
+			x >>= 8;
+		}
+	}
+	x = b->p[i];
+	while(x > 0){
+		if(p >= e)
+			return -1;
+		*p++ = x;
+		x >>= 8;
+	}
+
+	return p - s;
+}
--- /dev/null
+++ b/libmp/port/mptoui.c
@@ -1,0 +1,33 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+/*
+ *  this code assumes that mpdigit is at least as
+ *  big as an int.
+ */
+
+mpint*
+uitomp(uint i, mpint *b)
+{
+	if(b == nil)
+		b = mpnew(0);
+	mpassign(mpzero, b);
+	if(i != 0)
+		b->top = 1;
+	*b->p = i;
+	return b;
+}
+
+uint
+mptoui(mpint *b)
+{
+	uint x;
+
+	x = *b->p;
+	if(b->sign < 0)
+		x = 0;
+	else if(b->top > 1 || (sizeof(mpdigit) > sizeof(uint) && x > MAXUINT))
+		x =  MAXUINT;
+	return x;
+}
--- /dev/null
+++ b/libmp/port/mptouv.c
@@ -1,0 +1,49 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+#define VLDIGITS (sizeof(vlong)/sizeof(mpdigit))
+
+/*
+ *  this code assumes that a vlong is an integral number of
+ *  mpdigits long.
+ */
+mpint*
+uvtomp(uvlong v, mpint *b)
+{
+	int s;
+
+	if(b == nil)
+		b = mpnew(VLDIGITS*sizeof(mpdigit));
+	else
+		mpbits(b, VLDIGITS*sizeof(mpdigit));
+	mpassign(mpzero, b);
+	if(v == 0)
+		return b;
+	for(s = 0; s < VLDIGITS && v != 0; s++){
+		b->p[s] = v;
+		v >>= sizeof(mpdigit)*8;
+	}
+	b->top = s;
+	return b;
+}
+
+uvlong
+mptouv(mpint *b)
+{
+	uvlong v;
+	int s;
+
+	if(b->top == 0)
+		return 0;
+
+	mpnorm(b);
+	if(b->top > VLDIGITS)
+		return MAXVLONG;
+
+	v = 0;
+	for(s = 0; s < b->top; s++)
+		v |= (uvlong)b->p[s]<<(s*sizeof(mpdigit)*8);
+
+	return v;
+}
--- /dev/null
+++ b/libmp/port/mptov.c
@@ -1,0 +1,69 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+#define VLDIGITS (sizeof(vlong)/sizeof(mpdigit))
+
+/*
+ *  this code assumes that a vlong is an integral number of
+ *  mpdigits long.
+ */
+mpint*
+vtomp(vlong v, mpint *b)
+{
+	int s;
+	uvlong uv;
+
+	if(b == nil)
+		b = mpnew(VLDIGITS*sizeof(mpdigit));
+	else
+		mpbits(b, VLDIGITS*sizeof(mpdigit));
+	mpassign(mpzero, b);
+	if(v == 0)
+		return b;
+	if(v < 0){
+		b->sign = -1;
+		uv = -v;
+	} else
+		uv = v;
+	for(s = 0; s < VLDIGITS && uv != 0; s++){
+		b->p[s] = uv;
+		uv >>= sizeof(mpdigit)*8;
+	}
+	b->top = s;
+	return b;
+}
+
+vlong
+mptov(mpint *b)
+{
+	uvlong v;
+	int s;
+
+	if(b->top == 0)
+		return 0;
+
+	mpnorm(b);
+	if(b->top > VLDIGITS){
+		if(b->sign > 0)
+			return (vlong)MAXVLONG;
+		else
+			return (vlong)MINVLONG;
+	}
+
+	v = 0;
+	for(s = 0; s < b->top; s++)
+		v |= b->p[s]<<(s*sizeof(mpdigit)*8);
+
+	if(b->sign > 0){
+		if(v > MAXVLONG)
+			v = MAXVLONG;
+	} else {
+		if(v > MINVLONG)
+			v = MINVLONG;
+		else
+			v = -(vlong)v;
+	}
+
+	return (vlong)v;
+}
--- /dev/null
+++ b/libmp/port/mpvecadd.c
@@ -1,0 +1,35 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// prereq: alen >= blen, sum has at least blen+1 digits
+void
+mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum)
+{
+	int i, carry;
+	mpdigit x, y;
+
+	carry = 0;
+	for(i = 0; i < blen; i++){
+		x = *a++;
+		y = *b++;
+		x += carry;
+		if(x < carry)
+			carry = 1;
+		else
+			carry = 0;
+		x += y;
+		if(x < y)
+			carry++;
+		*sum++ = x;
+	}
+	for(; i < alen; i++){
+		x = *a++ + carry;
+		if(x < carry)
+			carry = 1;
+		else
+			carry = 0;
+		*sum++ = x;
+	}
+	*sum = carry;
+}
--- /dev/null
+++ b/libmp/port/mpveccmp.c
@@ -1,0 +1,27 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+int
+mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen)
+{
+	mpdigit x;
+
+	while(alen > blen)
+		if(a[--alen] != 0)
+			return 1;
+	while(blen > alen)
+		if(b[--blen] != 0)
+			return -1;
+	while(alen > 0){
+		--alen;
+		x = a[alen] - b[alen];
+		if(x == 0)
+			continue;
+		if(x > a[alen])
+			return -1;
+		else
+			return 1;
+	}
+	return 0;
+}
--- /dev/null
+++ b/libmp/port/mpvecdigmuladd.c
@@ -1,0 +1,103 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+#define LO(x) ((x) & ((1<<(Dbits/2))-1))
+#define HI(x) ((x) >> (Dbits/2))
+
+static void
+mpdigmul(mpdigit a, mpdigit b, mpdigit *p)
+{
+	mpdigit x, ah, al, bh, bl, p1, p2, p3, p4;
+	int carry;
+
+	// half digits
+	ah = HI(a);
+	al = LO(a);
+	bh = HI(b);
+	bl = LO(b);
+
+	// partial products
+	p1 = ah*bl;
+	p2 = bh*al;
+	p3 = bl*al;
+	p4 = ah*bh;
+
+	// p = ((p1+p2)<<(Dbits/2)) + (p4<<Dbits) + p3
+	carry = 0;
+	x = p1<<(Dbits/2);
+	p3 += x;
+	if(p3 < x)
+		carry++;
+	x = p2<<(Dbits/2);
+	p3 += x;
+	if(p3 < x)
+		carry++;
+	p4 += carry + HI(p1) + HI(p2);	// can't carry out of the high digit
+	p[0] = p3;
+	p[1] = p4;
+}
+
+// prereq: p must have room for n+1 digits
+void
+mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p)
+{
+	int i;
+	mpdigit carry, x, y, part[2];
+
+	carry = 0;
+	part[1] = 0;
+	for(i = 0; i < n; i++){
+		x = part[1] + carry;
+		if(x < carry)
+			carry = 1;
+		else
+			carry = 0;
+		y = *p;
+		mpdigmul(*b++, m, part);
+		x += part[0];
+		if(x < part[0])
+			carry++;
+		x += y;
+		if(x < y)
+			carry++;
+		*p++ = x;
+	}
+	*p = part[1] + carry;
+}
+
+// prereq: p must have room for n+1 digits
+int
+mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p)
+{
+	int i;
+	mpdigit x, y, part[2], borrow;
+
+	borrow = 0;
+	part[1] = 0;
+	for(i = 0; i < n; i++){
+		x = *p;
+		y = x - borrow;
+		if(y > x)
+			borrow = 1;
+		else
+			borrow = 0;
+		x = part[1];
+		mpdigmul(*b++, m, part);
+		x += part[0];
+		if(x < part[0])
+			borrow++;
+		x = y - x;
+		if(x > y)
+			borrow++;
+		*p++ = x;
+	}
+
+	x = *p;
+	y = x - borrow - part[1];
+	*p = y;
+	if(y > x)
+		return -1;
+	else
+		return 1;
+}
--- /dev/null
+++ b/libmp/port/mpvecsub.c
@@ -1,0 +1,34 @@
+#include "os.h"
+#include <mp.h>
+#include "dat.h"
+
+// prereq: a >= b, alen >= blen, diff has at least alen digits
+void
+mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff)
+{
+	int i, borrow;
+	mpdigit x, y;
+
+	borrow = 0;
+	for(i = 0; i < blen; i++){
+		x = *a++;
+		y = *b++;
+		y += borrow;
+		if(y < borrow)
+			borrow = 1;
+		else
+			borrow = 0;
+		if(x < y)
+			borrow++;
+		*diff++ = x - y;
+	}
+	for(; i < alen; i++){
+		x = *a++;
+		y = x - borrow;
+		if(y > x)
+			borrow = 1;
+		else
+			borrow = 0;
+		*diff++ = y;
+	}
+}
--- /dev/null
+++ b/libmp/port/os.h
@@ -1,0 +1,3 @@
+#include <lib9.h>
+extern ulong truerand(void);
+extern vlong nsec(void);
--- /dev/null
+++ b/libmp/port/reduce-nt
@@ -1,0 +1,4 @@
+# for now, just return the input files
+shift	# $O
+shift	# $SYSTARG-$OBJTYPE
+echo -n $*
--- /dev/null
+++ b/libmp/port/reduce-rc
@@ -1,0 +1,16 @@
+O=$1
+shift
+nonport=$1
+shift
+
+ls -p ../$nonport/*.[cs] >[2]/dev/null | sed 's/..$//' > /tmp/reduce.$pid
+#
+#	if empty directory, just return the input files
+#
+if (! ~ $status '|') {
+	echo $*
+	rm /tmp/reduce.$pid
+	exit 0
+}
+echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' '
+rm /tmp/reduce.$pid
--- /dev/null
+++ b/libmp/port/reduce-sh
@@ -1,0 +1,13 @@
+O=$1
+shift
+nonport=$1
+shift
+
+for i in $*
+do
+	j=`echo $i | sed 's/\.'$O'//'`
+	if test ! -f ../$nonport/$j.c -a ! -f ../$nonport/$j.s -a ! -f ../$nonport/$j.spp
+	then
+		echo $i
+	fi
+done
--- /dev/null
+++ b/libmp/port/strtomp.c
@@ -1,0 +1,205 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include "dat.h"
+
+static struct {
+	int	inited;
+
+	uchar	t64[256];
+	uchar	t32[256];
+	uchar	t16[256];
+	uchar	t10[256];
+} tab;
+
+enum {
+	INVAL=	255
+};
+
+static char set64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static char set32[] = "23456789abcdefghijkmnpqrstuvwxyz";
+static char set16[] = "0123456789ABCDEF0123456789abcdef";
+static char set10[] = "0123456789";
+
+static void
+init(void)
+{
+	char *p;
+
+	memset(tab.t64, INVAL, sizeof(tab.t64));
+	memset(tab.t32, INVAL, sizeof(tab.t32));
+	memset(tab.t16, INVAL, sizeof(tab.t16));
+	memset(tab.t10, INVAL, sizeof(tab.t10));
+
+	for(p = set64; *p; p++)
+		tab.t64[*p] = p-set64;
+	for(p = set32; *p; p++)
+		tab.t32[*p] = p-set32;
+	for(p = set16; *p; p++)
+		tab.t16[*p] = (p-set16)%16;
+	for(p = set10; *p; p++)
+		tab.t10[*p] = (p-set10);
+
+	tab.inited = 1;
+}
+
+static char*
+from16(char *a, mpint *b)
+{
+	char *p, *next;
+	int i;
+	mpdigit x;
+
+	b->top = 0;
+	for(p = a; *p; p++)
+		if(tab.t16[*(uchar*)p] == INVAL)
+			break;
+	mpbits(b, (p-a)*4);
+	b->top = 0;
+	next = p;
+	while(p > a){
+		x = 0;
+		for(i = 0; i < Dbits; i += 4){
+			if(p <= a)
+				break;
+			x |= tab.t16[*(uchar*)--p]<<i;
+		}
+		b->p[b->top++] = x;
+	}
+	return next;
+}
+
+static ulong mppow10[] = {
+	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
+};
+
+static char*
+from10(char *a, mpint *b)
+{
+	ulong x, y;
+	mpint *pow, *r;
+	int i;
+
+	pow = mpnew(0);
+	r = mpnew(0);
+
+	b->top = 0;
+	for(;;){
+		// do a billion at a time in native arithmetic
+		x = 0;
+		for(i = 0; i < 9; i++){
+			y = tab.t10[*(uchar*)a];
+			if(y == INVAL)
+				break;
+			a++;
+			x *= 10;
+			x += y;
+		}
+		if(i == 0)
+			break;
+
+		// accumulate into mpint
+		uitomp(mppow10[i], pow);
+		uitomp(x, r);
+		mpmul(b, pow, b);
+		mpadd(b, r, b);
+		if(i != 9)
+			break;
+	}
+	mpfree(pow);
+	mpfree(r);
+	return a;
+}
+
+static char*
+from64(char *a, mpint *b)
+{
+	char *buf = a;
+	uchar *p;
+	int n, m;
+
+	for(; tab.t64[*(uchar*)a] != INVAL; a++)
+		;
+	n = a-buf;
+	mpbits(b, n*6);
+	p = malloc(n);
+	if(p == nil)
+		return a;
+	m = dec64(p, n, buf, n);
+	betomp(p, m, b);
+	free(p);
+	return a;
+}
+
+static char*
+from32(char *a, mpint *b)
+{
+	char *buf = a;
+	uchar *p;
+	int n, m;
+
+	for(; tab.t64[*(uchar*)a] != INVAL; a++)
+		;
+	n = a-buf;
+	mpbits(b, n*5);
+	p = malloc(n);
+	if(p == nil)
+		return a;
+	m = dec32(p, n, buf, n);
+	betomp(p, m, b);
+	free(p);
+	return a;
+}
+
+mpint*
+strtomp(char *a, char **pp, int base, mpint *b)
+{
+	int sign;
+	char *e;
+
+	if(b == nil)
+		b = mpnew(0);
+
+	if(tab.inited == 0)
+		init();
+
+	while(*a==' ' || *a=='\t')
+		a++;
+
+	sign = 1;
+	for(;; a++){
+		switch(*a){
+		case '-':
+			sign *= -1;
+			continue;
+		}
+		break;
+	}
+
+	switch(base){
+	case 10:
+		e = from10(a, b);
+		break;
+	default:
+	case 16:
+		e = from16(a, b);
+		break;
+	case 32:
+		e = from32(a, b);
+		break;
+	case 64:
+		e = from64(a, b);
+		break;
+	}
+
+	// if no characters parsed, there wasn't a number to convert
+	if(e == a)
+		return nil;
+
+	mpnorm(b);
+	b->sign = sign;
+	if(pp != nil)
+		*pp = e;
+
+	return b;
+}
--- /dev/null
+++ b/libmp/test.c
@@ -1,0 +1,453 @@
+#include <lib9.h>
+#include <mp.h>
+#include "dat.h"
+
+int loops = 1;
+
+long randomreg;
+
+void
+srand(long seed)
+{
+	randomreg = seed;
+}
+
+long
+lrand(void)
+{
+	randomreg = randomreg*104381 + 81761;
+	return randomreg;
+}
+
+void
+prng(uchar *p, int n)
+{
+	while(n-- > 0)
+		*p++ = lrand();
+}
+
+void
+testconv(char *str)
+{
+	mpint *b;
+	char *p;
+
+	b = strtomp(str, nil, 16, nil);
+
+	p = mptoa(b, 10, nil, 0);
+	print("%s = ", p);
+	strtomp(p, nil, 10, b);
+	free(p);
+	print("%B\n", b);
+
+	p = mptoa(b, 16, nil, 0);
+	print("%s = ", p);
+	strtomp(p, nil, 16, b);
+	free(p);
+	print("%B\n", b);
+
+	p = mptoa(b, 32, nil, 0);
+	print("%s = ", p);
+	strtomp(p, nil, 32, b);
+	free(p);
+	print("%B\n", b);
+
+	p = mptoa(b, 64, nil, 0);
+	print("%s = ", p);
+	strtomp(p, nil, 64, b);
+	free(p);
+	print("%B\n", b);
+
+	mpfree(b);
+}
+
+void
+testshift(char *str)
+{
+	mpint *b1, *b2;
+	int i;
+
+	b1 = strtomp(str, nil, 16, nil);
+	b2 = mpnew(0);
+	for(i = 0; i < 64; i++){
+		mpleft(b1, i, b2);
+		print("%2.2d %B\n", i, b2);
+	}
+	for(i = 0; i < 64; i++){
+		mpright(b2, i, b1);
+		print("%2.2d %B\n", i, b1);
+	}
+	mpfree(b1);
+	mpfree(b2);
+}
+
+void
+testaddsub(char *str)
+{
+	mpint *b1, *b2;
+	int i;
+
+	b1 = strtomp(str, nil, 16, nil);
+	b2 = mpnew(0);
+	for(i = 0; i < 16; i++){
+		mpadd(b1, b2, b2);
+		print("%2.2d %B\n", i, b2);
+	}
+	for(i = 0; i < 16; i++){
+		mpsub(b2, b1, b2);
+		print("%2.2d %B\n", i, b2);
+	}
+	mpfree(b1);
+	mpfree(b2);
+}
+
+void
+testvecdigmuladd(char *str, mpdigit d)
+{
+	mpint *b, *b2;
+	int i;
+	vlong now;
+
+	b = strtomp(str, nil, 16, nil);
+	b2 = mpnew(0);
+
+	mpbits(b2, (b->top+1)*Dbits);
+	now = nsec();
+	for(i = 0; i < loops; i++){
+		memset(b2->p, 0, b2->top*Dbytes);
+		mpvecdigmuladd(b->p, b->top, d, b2->p);
+	}
+	if(loops > 1)
+		print("%lld ns for a %d*%d vecdigmul\n", (nsec()-now)/loops, b->top*Dbits, Dbits);
+	mpnorm(b2);
+	print("0 + %B * %ux = %B\n", b, d, b2);
+
+	mpfree(b);
+	mpfree(b2);
+}
+
+void
+testvecdigmulsub(char *str, mpdigit d)
+{
+	mpint *b, *b2;
+	int i;
+	vlong now;
+
+	b = strtomp(str, nil, 16, nil);
+	b2 = mpnew(0);
+
+	mpbits(b2, (b->top+1)*Dbits);
+	now = nsec();
+	for(i = 0; i < loops; i++){
+		memset(b2->p, 0, b2->top*Dbytes);
+		mpvecdigmulsub(b->p, b->top, d, b2->p);
+	}
+	if(loops > 1)
+		print("%lld ns for a %d*%d vecdigmul\n", (nsec()-now)/loops, b->top*Dbits, Dbits);
+	mpnorm(b2);
+	print("0 - %B * %ux = %B\n", b, d, b2);
+
+	mpfree(b);
+	mpfree(b2);
+}
+
+void
+testmul(char *str)
+{
+	mpint *b, *b1, *b2;
+	vlong now;
+	int i;
+
+	b = strtomp(str, nil, 16, nil);
+	b1 = mpcopy(b);
+	b2 = mpnew(0);
+
+	now = nsec();
+	for(i = 0; i < loops; i++)
+		mpmul(b, b1, b2);
+	if(loops > 1)
+		print("%lld µs for a %d*%d mult\n", (nsec()-now)/(loops*1000),
+			b->top*Dbits, b1->top*Dbits);
+	print("%B * %B = %B\n", b, b1, b2);
+
+	mpfree(b);
+	mpfree(b1);
+	mpfree(b2);
+}
+
+void
+testmul2(mpint *b, mpint *b1)
+{
+	mpint *b2;
+	vlong now;
+	int i;
+
+	b2 = mpnew(0);
+
+	now = nsec();
+	for(i = 0; i < loops; i++)
+		mpmul(b, b1, b2);
+	if(loops > 1)
+		print("%lld µs for a %d*%d mult\n", (nsec()-now)/(loops*1000), b->top*Dbits, b1->top*Dbits);
+	print("%B * ", b);
+	print("%B = ", b1);
+	print("%B\n", b2);
+
+	mpfree(b2);
+}
+
+void
+testdigdiv(char *str, mpdigit d)
+{
+	mpint *b;
+	mpdigit q;
+	int i;
+	vlong now;
+
+	b = strtomp(str, nil, 16, nil);
+	now = nsec();
+	for(i = 0; i < loops; i++)
+		mpdigdiv(b->p, d, &q);
+	if(loops > 1)
+		print("%lld ns for a %d / %d div\n", (nsec()-now)/loops, 2*Dbits, Dbits);
+	print("%B / %ux = %ux\n", b, d, q);
+	mpfree(b);
+}
+
+void
+testdiv(mpint *x, mpint *y)
+{
+	mpint *b2, *b3;
+	vlong now;
+	int i;
+
+	b2 = mpnew(0);
+	b3 = mpnew(0);
+	now = nsec();
+	for(i = 0; i < loops; i++)
+		mpdiv(x, y, b2, b3);
+	if(loops > 1)
+		print("%lld µs for a %d/%d div\n", (nsec()-now)/(1000*loops),
+			x->top*Dbits, y->top*Dbits);
+	print("%B / %B = %B %B\n", x, y, b2, b3);
+	mpfree(b2);
+	mpfree(b3);
+}
+
+void
+testmod(mpint *x, mpint *y)
+{
+	mpint *r;
+	vlong now;
+	int i;
+
+	r = mpnew(0);
+	now = nsec();
+	for(i = 0; i < loops; i++)
+		mpmod(x, y, r);
+	if(loops > 1)
+		print("%lld µs for a %d/%d mod\n", (nsec()-now)/(1000*loops),
+			x->top*Dbits, y->top*Dbits);
+	print("%B mod %B = %B\n", x, y, r);
+	mpfree(r);
+}
+
+void
+testinvert(mpint *x, mpint *y)
+{
+	mpint *r, *d1, *d2;
+	vlong now;
+	int i;
+
+	r = mpnew(0);
+	d1 = mpnew(0);
+	d2 = mpnew(0);
+	now = nsec();
+	mpextendedgcd(x, y, r, d1, d2);
+	mpdiv(x, r, x, d1);
+	mpdiv(y, r, y, d1);
+	for(i = 0; i < loops; i++)
+		mpinvert(x, y, r);
+	if(loops > 1)
+		print("%lld µs for a %d in %d invert\n", (nsec()-now)/(1000*loops),
+			x->top*Dbits, y->top*Dbits);
+	print("%B**-1 mod %B = %B\n", x, y, r);
+	mpmul(r, x, d1);
+	mpmod(d1, y, d2);
+	print("%B*%B mod %B = %B\n", x, r, y, d2);
+	mpfree(r);
+	mpfree(d1);
+	mpfree(d2);
+}
+
+void
+testsub1(char *a, char *b)
+{
+	mpint *b1, *b2, *b3;
+
+	b1 = strtomp(a, nil, 16, nil);
+	b2 = strtomp(b, nil, 16, nil);
+	b3 = mpnew(0);
+	mpsub(b1, b2, b3);
+	print("%B - %B = %B\n", b1, b2, b3);
+}
+
+void
+testmul1(char *a, char *b)
+{
+	mpint *b1, *b2, *b3;
+
+	b1 = strtomp(a, nil, 16, nil);
+	b2 = strtomp(b, nil, 16, nil);
+	b3 = mpnew(0);
+	mpmul(b1, b2, b3);
+	print("%B * %B = %B\n", b1, b2, b3);
+}
+
+void
+testexp(char *base, char *exp, char *mod)
+{
+	mpint *b, *e, *m, *res;
+	int i;
+	uvlong now;
+
+	b = strtomp(base, nil, 16, nil);
+	e = strtomp(exp, nil, 16, nil);
+	res = mpnew(0);
+	if(mod != nil)
+		m = strtomp(mod, nil, 16, nil);
+	else
+		m = nil;
+	now = nsec();
+	for(i = 0; i < loops; i++)
+		mpexp(b, e, m, res);
+	if(loops > 1)
+		print("%ulldµs for a %d to the %d bit exp\n", (nsec()-now)/(loops*1000),
+			b->top*Dbits, e->top*Dbits);
+	if(m != nil)
+		print("%B ^ %B mod %B == %B\n", b, e, m, res);
+	else
+		print("%B ^ %B == %B\n", b, e, res);
+	mpfree(b);
+	mpfree(e);
+	mpfree(res);
+	if(m != nil)
+		mpfree(m);
+}
+
+void
+testgcd(void)
+{
+	mpint *a, *b, *d, *x, *y, *t1, *t2;
+	int i;
+	uvlong now, then;
+	uvlong etime;
+
+	d = mpnew(0);
+	x = mpnew(0);
+	y = mpnew(0);
+	t1 = mpnew(0);
+	t2 = mpnew(0);
+
+	etime = 0;
+
+	a = strtomp("4EECAB3E04C4E6BC1F49D438731450396BF272B4D7B08F91C38E88ADCD281699889AFF872E2204C80CCAA8E460797103DE539D5DF8335A9B20C0B44886384F134C517287202FCA914D8A5096446B40CD861C641EF9C2730CB057D7B133F4C2B16BBD3D75FDDBD9151AAF0F9144AAA473AC93CF945DBFE0859FB685D5CBD0A8B3", nil, 16, nil);
+	b = strtomp("C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBDB12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A863A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D93D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D", nil, 16, nil);
+	mpextendedgcd(a, b, d, x, y);
+	print("gcd %B*%B+%B*%B = %B?\n", a, x, b, y, d);
+	mpfree(a);
+	mpfree(b);
+
+	for(i = 0; i < loops; i++){
+		a = mprand(2048, prng, nil);
+		b = mprand(2048, prng, nil);
+		then = nsec();
+		mpextendedgcd(a, b, d, x, y);
+		now = nsec();
+		etime += now-then;
+		mpmul(a, x, t1);
+		mpmul(b, y, t2);
+		mpadd(t1, t2, t2);
+		if(mpcmp(d, t2) != 0)
+			print("%d gcd %B*%B+%B*%B != %B\n", i, a, x, b, y, d);
+//		else
+//			print("%d euclid %B*%B+%B*%B == %B\n", i, a, x, b, y, d);
+		mpfree(a);
+		mpfree(b);
+	}
+
+	mpfree(x);
+	mpfree(y);
+	mpfree(d);
+	mpfree(t1);
+	mpfree(t2);
+
+	if(loops > 1)
+		print("binary %llud\n", etime);
+}
+
+extern int _unnormalizedwarning = 1;
+
+void
+main(int argc, char **argv)
+{
+	mpint *x, *y;
+
+	ARGBEGIN{
+	case 'n':
+		loops = atoi(ARGF());
+		break;
+	}ARGEND;
+
+	fmtinstall('B', mpfmt);
+	fmtinstall('Q', mpfmt);
+	srand(0);
+	mpsetminbits(2*Dbits);
+	testshift("1111111111111111");
+	testaddsub("fffffffffffffffff");
+	testdigdiv("1234567812345678", 0x76543218);
+	testdigdiv("1ffff", 0xffff);
+	testdigdiv("ffff", 0xffff);
+	testdigdiv("fff", 0xffff);
+	testdigdiv("effffffff", 0xffff);
+	testdigdiv("ffffffff", 0x1);
+	testdigdiv("ffffffff", 0);
+	testdigdiv("200000000", 2);
+	testdigdiv("ffffff00fffffff1", 0xfffffff1);
+	testvecdigmuladd("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2);
+	testconv("0");
+	testconv("-abc0123456789abcedf");
+	testconv("abc0123456789abcedf");
+	testvecdigmulsub("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 2);
+	testsub1("1FFFFFFFE00000000", "FFFFFFFE00000001");
+	testmul1("ffffffff", "f");
+	testmul("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+	testmul1("100000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000004FFFFFFFFFFFFFFFE0000000200000000000000000000000000000003FFFFFFFFFFFFFFFE0000000200000000000000000000000000000002FFFFFFFFFFFFFFFE0000000200000000000000000000000000000001FFFFFFFFFFFFFFFE0000000200000000000000000000000000000000FFFFFFFFFFFFFFFE0000000200000000FFFFFFFE00000001", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+	testmul1("1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001", "1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001");
+	testmul1("1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001", "1000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001000000000000000000000001");
+	testmul1("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+	x = mprand(256, prng, nil);
+	y = mprand(128, prng, nil);
+	testdiv(x, y);
+	x = mprand(2048, prng, nil);
+	y = mprand(1024, prng, nil);
+	testdiv(x, y);
+//	x = mprand(4*1024, prng, nil);
+//	y = mprand(4*1024, prng, nil);
+//	testmul2(x, y);
+	testsub1("677132C9", "-A26559B6");
+	testgcd();
+	x = mprand(512, prng, nil);
+	x->sign = -1;
+	y = mprand(256, prng, nil);
+	testdiv(x, y);
+	testmod(x, y);
+	x->sign = 1;
+	testinvert(y, x);
+	testexp("111111111", "222", "1000000000000000000000");
+	testexp("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+#ifdef asdf
+#endif adsf
+	print("done\n");
+	exits(0);
+}
--- /dev/null
+++ b/libnandfs/NOTICE
@@ -1,0 +1,23 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 2002, 2003 Vita Nuova Holdings Limited.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libnandfs/calcformat.c
@@ -1,0 +1,24 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+int
+nandfscalcformat(Nandfs *nandfs, long base, long limit, long bootsize, long *baseblock, long *limitblock, long *bootblocks)
+{
+	*baseblock = (base + nandfs->rawblocksize - 1) / nandfs->rawblocksize;
+	if (limit == 0)
+		*limitblock = nandfs->limitblock;	
+	else
+		*limitblock = limit / nandfs->rawblocksize;
+	*bootblocks = (bootsize + nandfs->rawblocksize - 1) / nandfs->rawblocksize;
+	if (*bootblocks < 3)
+		*bootblocks = 3;
+	/* sanity checks */	
+	if (*limitblock > nandfs->limitblock
+		|| *baseblock < nandfs->baseblock
+		|| *bootblocks > nandfs->limitblock - nandfs->baseblock)
+		return 0;
+	return 1;
+}
+
--- /dev/null
+++ b/libnandfs/correctauxilliary.c
@@ -1,0 +1,81 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+static int
+hammingdistance(uchar a, uchar b)
+{
+	uchar c;
+	int i, k;
+	if (a == b)
+		return 0;
+	c =  a ^ b;
+	for (i = 0x80, k = 0; i; i >>= 1)
+		if (c & i)
+			k++;
+	return k;
+}
+
+static int
+allones(uchar *data, int len)
+{
+	while (len-- > 0)
+		if (*data++ != 0xff)
+			return 0;
+	return 1;
+}
+
+LogfsLowLevelReadResult
+_nandfscorrectauxiliary(NandfsAuxiliary *hdr)
+{
+	/*
+	 * correct single bit errors, detect more than 1, in
+	 * tag, signature
+	 * TODO: add nerase and path protection
+	 */
+	LogfsLowLevelReadResult e;
+	int x;
+	int min, minx;
+
+	e = LogfsLowLevelReadResultOk;
+	
+	min = 8;
+	minx = 0;
+	for (x = 0; x < _nandfsvalidtagscount; x++) {
+		int d = hammingdistance(hdr->tag, _nandfsvalidtags[x]);
+		if (d < min) {
+			min = d;
+			minx = x;
+			if (d == 0)
+				break;
+		}
+	}
+	if (min == 1) {
+		hdr->tag = _nandfsvalidtags[minx];
+		e = LogfsLowLevelReadResultSoftError;
+	}
+	else if (min > 1)
+		e = LogfsLowLevelReadResultHardError;
+	else {
+		if (hdr->tag != LogfsTnone) {
+			ulong tmp = getbig4(hdr->parth);
+			if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
+				putbig4(hdr->parth, tmp);
+				if (e != LogfsLowLevelReadResultOk)	
+					e = LogfsLowLevelReadResultSoftError;
+			}
+			tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw);
+			if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
+				putbig2(hdr->nerasemagicmsw, tmp >> 16);
+				putbig2(hdr->nerasemagiclsw, tmp);
+				if (e != LogfsLowLevelReadResultOk)	
+					e = LogfsLowLevelReadResultSoftError;
+			}
+		}
+		else if (allones((uchar *)hdr, sizeof(*hdr)))
+			e = LogfsLowLevelReadResultAllOnes;
+	}
+			
+	return e;
+}
--- /dev/null
+++ b/libnandfs/ecc.c
@@ -1,0 +1,98 @@
+#include "logfsos.h"
+#include "nandecc.h"
+
+static uchar ecctab[] = {
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+ulong
+nandecc(uchar *buf)
+{
+	int cp, zeros, ones, im;
+	int lp, om;
+	int i;
+
+	cp = 0xff;
+	zeros = 0xff;
+	ones = 0xff;
+	for (i = 0; i < 256; i++) {
+		int tabent = ecctab[buf[i]];
+		cp ^= tabent;
+		if (tabent & 1) {
+			zeros ^= ~i;
+			ones ^= i;
+		}
+	}
+	lp = 0;
+	for (im = 0x80, om = 0x8000; im; im >>= 1, om >>= 1) {
+		if (ones & im)
+			lp |= om;
+		om >>= 1;
+		if (zeros & im)
+			lp |= om;
+	}
+	return (((cp & 0xff) | 3) << 16) | lp;
+}
+
+#define CORRECTABLEMASK 0x545555
+
+NandEccError
+nandecccorrect(uchar *buf, ulong calcecc, ulong *storedecc, int reportbad)
+{
+	ulong xorecc;
+	ulong mask;
+	int k;
+
+	if (calcecc == *storedecc)
+		return NandEccErrorGood;
+	if (reportbad)
+		print("nandecccorrect: calculated ecc %.8lux stored ecc %.8lux\n", calcecc, *storedecc);
+	xorecc = calcecc ^ *storedecc;
+	if (((xorecc ^ (xorecc >> 1)) & CORRECTABLEMASK) == CORRECTABLEMASK) {
+		ulong imask;
+		ushort out;
+		ushort omask;
+		int line, col;
+
+		for (imask = 0x800000, omask = 0x800, out = 0; imask; imask >>= 2, omask >>= 1) {
+			if (xorecc & imask)
+				out |= omask;
+		}
+		line = out & 0xff;
+		col = out >> 9;
+		if (reportbad)
+			print("nandecccorrect: single bit error line %d col %d\n", line, col);
+		buf[line] ^= (1 << col);
+		*storedecc = calcecc;
+		return NandEccErrorOneBit;
+	}
+	for (mask = 0x800000, k = 0; mask; mask >>= 1)
+		if (mask & xorecc)
+			k++;
+	if (k == 1) {
+		if (reportbad)
+			print("nandecccorrect: single bit error in ecc\n");
+		// assume the stored ecc was wrong
+		*storedecc = calcecc;
+		return NandEccErrorOneBitInEcc;
+	}
+	if (reportbad)
+		print("nandecccorrect: 2 bit error\n");
+	return NandEccErrorBad;
+}
+
--- /dev/null
+++ b/libnandfs/eraseblock.c
@@ -1,0 +1,50 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfseraseblock(Nandfs *nandfs, long block, void **llsavep, int *markedbad)
+{
+	NandfsBlockData *d;
+	char *errmsg;
+
+	if (markedbad)
+		*markedbad = 0;
+
+	errmsg = (*nandfs->erase)(nandfs->magic, nandfs->rawblocksize * (nandfs->baseblock + block));
+	if (errmsg) {
+		if (nandfs->blockdata) {
+			d = &nandfs->blockdata[block];
+			d->tag = LogfsTworse;
+			nandfs->worseblocks = 1;
+		}
+		if (strcmp(errmsg, Eio) != 0)
+			return errmsg;
+		if (markedbad) {
+			*markedbad = 1;
+			errmsg = nandfsmarkblockbad(nandfs, block);
+			if (strcmp(errmsg, Eio) != 0)
+				return errmsg;
+			return nil;
+		}
+		return errmsg;
+	}
+
+	if (nandfs->blockdata) {
+		ulong *llsave;
+		d = &nandfs->blockdata[block];
+		if (llsavep) {
+			llsave = nandfsrealloc(nil, sizeof(ulong));
+			if (llsave == nil)
+				return Enomem;
+			*llsave = d->nerase;
+			*llsavep = llsave;
+		}
+		d->tag = 0xff;
+		d->path = NandfsPathMask;
+		d->nerase = NandfsNeraseMask;
+	}
+	return  nil;
+}
+
--- /dev/null
+++ b/libnandfs/extracttags.c
@@ -1,0 +1,26 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+void
+_nandfsextracttags(NandfsAuxiliary *hdr, NandfsTags *tags)
+{
+	ulong tmp;
+	tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw);
+	if (tmp == 0xffffffff) {
+		tags->nerase = 0xffffffff;
+		tags->magic = 0xff;
+	}
+	else {
+		tags->nerase = (tmp >> 6) & 0x3ffff;
+		tags->magic = tmp >> 24;
+	}
+	tmp = getbig4(hdr->parth);
+	if (tmp != 0xffffffff)
+		tags->path = tmp >> 6;
+	else
+		tags->path = 0xffffffff;
+	tags->tag = hdr->tag;
+}
+
--- /dev/null
+++ b/libnandfs/findfreeblock.c
@@ -1,0 +1,28 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+long
+nandfsfindfreeblock(Nandfs *nandfs, long *freeblocksp)
+{
+	long bestnewblock;
+	long bestnerase;
+	long i;
+
+	if (freeblocksp)
+		*freeblocksp = 0;
+	for (i = 0, bestnewblock = -1, bestnerase = 0x7fffffff; i < nandfs->ll.blocks; i++) {
+		long nerase;
+		if (nandfsgettag(nandfs, i) == LogfsTnone) {
+			if (freeblocksp) {
+				(*freeblocksp)++;
+			}
+			if ((nerase = nandfsgetnerase(nandfs, i)) < bestnerase) {
+				bestnewblock = i;
+				bestnerase = nerase;
+			}
+		}
+	}
+	return bestnewblock;
+}
--- /dev/null
+++ b/libnandfs/formatblock.c
@@ -1,0 +1,57 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsformatblock(Nandfs *nandfs, long absblock, uchar tag, ulong path, long baseblock, long sizeinblocks, int xcount, long *xdata, void *llsave, int *markedbad)
+{
+	int page;
+	char *rv;
+	NandfsTags t;
+	int ppb;
+
+	if (markedbad)
+		*markedbad = 0;
+
+	t.tag = tag;
+	t.magic = LogfsMagic;
+	t.nerase = *(ulong *)llsave < NandfsNeraseMask ? *(ulong *)llsave + 1 : 1;
+
+	ppb = 1 << nandfs->ll.l2pagesperblock;
+	for (page = 0, rv = nil; rv == nil && page < ppb; page++) {
+		if (tag == LogfsTboot && page > 0 && page < xcount + 3) {
+			switch (page) {
+			case 1:
+				t.path = baseblock;
+				break;
+			case 2:
+				t.path = sizeinblocks;
+				break;
+			default:
+				t.path = xdata[page - 3];
+				break;
+			}
+		}
+		else
+			t.path = path;
+		rv = nandfswritepageauxiliary(nandfs, &t, absblock, page);
+		if (rv)
+			break;
+	}
+
+	if (rv) {
+		if (strcmp(rv, Eio) != 0)
+			return rv;
+		if (markedbad) {
+			*markedbad = 1;
+			rv = nandfsmarkabsblockbad(nandfs, absblock);
+			if (strcmp(rv, Eio) != 0)
+				return rv;
+			return nil;
+		}
+		return rv;
+	}
+		
+	return nil;
+}
--- /dev/null
+++ b/libnandfs/getblockstatus.c
@@ -1,0 +1,27 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsgetblockstatus(Nandfs *nandfs, long absblock, int *magicfound, void **llsavep, LogfsLowLevelReadResult *result)
+{
+	NandfsTags tags;
+	char *errmsg;
+	ulong *llsave;
+
+	errmsg = nandfsreadpageauxiliary(nandfs, &tags, absblock, 0, 1, result);
+
+	*magicfound = tags.magic == LogfsMagic;
+
+	if (llsavep) {
+		llsave = nandfsrealloc(nil, sizeof(ulong));
+		if (llsave == nil)
+			return Enomem;
+		*llsave = tags.nerase;
+		*llsavep = llsave;
+	}
+
+	return errmsg;
+}
+
--- /dev/null
+++ b/libnandfs/hamming31_26.c
@@ -1,0 +1,62 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+
+static unsigned long row4 = 0x001fffc0;
+static unsigned long row3 = 0x0fe03fc0;
+static unsigned long row2 = 0x71e3c3c0;
+static unsigned long row1 = 0xb66cccc0;
+static unsigned long row0 = 0xdab55540;
+
+static char map[] = {
+	-5, -4, 0, -3, 1, 2, 3, -2,
+	4, 5, 6, 7, 8, 9, 10, -1, 11,
+	12, 13, 14, 15, 16, 17, 18,
+	19, 20, 21, 22, 23, 24, 25,
+};
+
+#define mashbits(rown) \
+	c = (in) & (rown); \
+	c ^= c >> 16; \
+	c ^= c >> 8; \
+	c ^= c >> 4; \
+	c ^= c >> 2; \
+	c = (c ^ (c >> 1)) & 1; \
+
+static uchar
+_nandfshamming31_26calcparity(ulong in)
+{
+	ulong c;
+	uchar out;
+	mashbits(row4); out = c;
+	mashbits(row3); out = (out << 1) | c;
+	mashbits(row2); out = (out << 1) | c;
+	mashbits(row1); out = (out << 1) | c;
+	mashbits(row0); out = (out << 1) | c;
+	return out;
+}
+
+ulong
+_nandfshamming31_26calc(ulong in)
+{
+	in &= 0xffffffc0;
+	return in | _nandfshamming31_26calcparity(in);
+}
+
+int
+_nandfshamming31_26correct(ulong *in)
+{
+	uchar eparity, parity;
+	ulong e;
+	eparity = _nandfshamming31_26calcparity(*in);
+	parity = (*in) & 0x1f;
+	e = eparity ^ parity;
+	if (e == 0)
+		return 0;
+	e--;
+	if (map[e] < 0)
+		return 1;		// error in parity bits
+	e = map[e];
+	*in ^= 1 << (31 - e);
+	return 1;
+}
--- /dev/null
+++ b/libnandfs/init.c
@@ -1,0 +1,102 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+uchar _nandfsvalidtags[] = {
+	LogfsTnone,
+	LogfsTboot,
+	LogfsTlog,
+	LogfsTdata,
+};
+
+int _nandfsvalidtagscount = nelem(_nandfsvalidtags);
+
+static int
+l2(long n)
+{
+	int i;
+	for (i = 0; i < 32; i++)
+		if ((1 << i) >= n)
+			return i;
+	return 0;
+}
+
+char *
+nandfsinit(void *magic, long rawsize, long rawblocksize,
+	char *(*read)(void *magic, void *buf, long nbytes, ulong offset),
+	char *(*write)(void *magic, void *buf, long nbytes, ulong offset),
+	char *(*erase)(void *magic, long blockaddr),
+	char *(*sync)(void *magic),
+	LogfsLowLevel **llp)
+{
+	Nandfs *nandfs;
+	nandfs = nandfsrealloc(nil, sizeof(*nandfs));
+	if (nandfs == nil)
+		return Enomem;
+	if (rawblocksize % NandfsFullSize)
+		return "unsupported block size";
+	if (rawsize % rawblocksize)
+		return "size not multiple of block size";
+	nandfs->read = read;
+	nandfs->write = write;
+	nandfs->erase = erase;
+	nandfs->sync = sync;
+	nandfs->magic = magic;
+	nandfs->limitblock = rawsize / rawblocksize;
+//print("rawsize %ld\n", rawsize);
+//print("rawblocksize %ld\n", rawblocksize);
+//print("limitblock %ld\n", nandfs->limitblock);
+	nandfs->rawblocksize = rawblocksize;
+	/* fill in upper interface */
+	nandfs->ll.pathbits = NandfsPathBits;
+	nandfs->ll.blocks = 0;
+	nandfs->ll.l2pagesize = NandfsL2PageSize;
+	nandfs->ll.l2pagesperblock = l2(rawblocksize / NandfsFullSize);
+	nandfs->ll.open = (LOGFSOPENFN *)nandfsopen;
+	nandfs->ll.getblocktag = (LOGFSGETBLOCKTAGFN *)nandfsgettag;
+	nandfs->ll.setblocktag = (LOGFSSETBLOCKTAGFN *)nandfssettag;
+	nandfs->ll.getblockpath = (LOGFSGETBLOCKPATHFN *)nandfsgetpath;
+	nandfs->ll.setblockpath = (LOGFSSETBLOCKPATHFN *)nandfssetpath;
+	nandfs->ll.getblockpartialformatstatus = (LOGFSGETBLOCKPARTIALFORMATSTATUSFN *)nandfsgetblockpartialformatstatus;
+	nandfs->ll.findfreeblock = (LOGFSFINDFREEBLOCKFN *)nandfsfindfreeblock;
+	nandfs->ll.readpagerange = (LOGFSREADPAGERANGEFN *)nandfsreadpagerange;
+	nandfs->ll.writepage = (LOGFSWRITEPAGEFN *)nandfswritepage;
+	nandfs->ll.readblock = (LOGFSREADBLOCKFN *)nandfsreadblock;
+	nandfs->ll.writeblock = (LOGFSWRITEBLOCKFN *)nandfswriteblock;
+	nandfs->ll.eraseblock = (LOGFSERASEBLOCKFN *)nandfseraseblock;
+	nandfs->ll.formatblock = (LOGFSFORMATBLOCKFN *)nandfsformatblock;
+	nandfs->ll.reformatblock = (LOGFSREFORMATBLOCKFN *)nandfsreformatblock;
+	nandfs->ll.markblockbad = (LOGFSMARKBLOCKBADFN *)nandfsmarkblockbad;
+	nandfs->ll.getbaseblock = (LOGFSGETBASEBLOCKFN *)nandfsgetbaseblock;
+	nandfs->ll.getblocksize = (LOGFSGETBLOCKSIZEFN *)nandfsgetblocksize;
+	nandfs->ll.calcrawaddress = (LOGFSCALCRAWADDRESSFN *)nandfscalcrawaddress;
+	nandfs->ll.getblockstatus = (LOGFSGETBLOCKSTATUSFN *)nandfsgetblockstatus;
+	nandfs->ll.calcformat = (LOGFSCALCFORMATFN *)nandfscalcformat;
+	nandfs->ll.getopenstatus = (LOGFSGETOPENSTATUSFN *)nandfsgetopenstatus;
+	nandfs->ll.free = (LOGFSFREEFN *)nandfsfree;
+	nandfs->ll.sync = (LOGFSSYNCFN *)nandfssync;
+	*llp = (LogfsLowLevel *)nandfs;
+	return nil;
+}
+
+void
+nandfsfree(Nandfs *nandfs)
+{
+	if (nandfs) {
+		nandfsfreemem(nandfs->blockdata);
+		nandfsfreemem(nandfs);
+	}
+}
+
+void
+nandfssetmagic(Nandfs *nandfs, void *magic)
+{
+	nandfs->magic = magic;
+}
+
+char *
+nandfssync(Nandfs *nandfs)
+{
+	return (*nandfs->sync)(nandfs->magic);
+}
--- /dev/null
+++ b/libnandfs/local.h
@@ -1,0 +1,54 @@
+typedef struct NandfsBlockData NandfsBlockData;
+typedef struct NandfsAuxiliary NandfsAuxiliary;
+
+struct NandfsBlockData {
+	ulong path;
+	short tag;
+	ulong nerase;
+	int partial;
+};
+
+struct Nandfs {
+	LogfsLowLevel ll;
+	char *(*read)(void*, void*, long, ulong);
+	char *(*write)(void*, void*, long, ulong);
+	char *(*erase)(void*, long blockaddr);
+	char *(*sync)(void*);
+	void *magic;
+	long rawblocksize;
+	long baseblock;
+	long limitblock;
+	NandfsBlockData *blockdata;
+	int trace;
+	int worseblocks;
+	int printbad;
+};
+
+struct NandfsAuxiliary {
+	uchar parth[4];		// ggpppppp pppppppp pppppppp pp1hhhhh (bigendian) self-protected
+	uchar tag;			// self-protecting
+	uchar blockstatus;	// self-protecting
+	uchar nerasemagicmsw[2];	// see nerasemagiclsw
+	uchar ecc2[3];		// self-protecting
+	uchar nerasemagiclsw[2];	// mmmmmm mmeeeeee eeeeeeeeee ee1hhhhh (bigendian) self-protected
+	uchar ecc1[3];		// self-protecting
+};
+
+#define getbig2(p) (((p)[0] << 8) | (p)[1])
+#define getbig4(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | (p)[3])
+#define getlittle3(p) (((p)[2] << 16) | ((p)[1] << 8) | (p)[0])
+#define putlittle3(p, q) ((p)[0] = (q), (p)[1] = (q) >> 8, (p)[2] = (q) >> 16)
+#define putbig2(p, q) ((p)[0] = (q) >> 8, (p)[1] = (q))
+#define putbig4(p, q) ((p)[0] = (q) >> 24, (p)[1] = (q) >> 16, (p)[2] = (q) >> 8, (p)[3] = (q))
+
+LogfsLowLevelReadResult _nandfscorrectauxiliary(NandfsAuxiliary*);
+
+extern uchar _nandfsvalidtags[];
+extern int _nandfsvalidtagscount;
+
+ulong _nandfshamming31_26calc(ulong in);
+int _nandfshamming31_26correct(ulong *in);
+
+void _nandfsextracttags(NandfsAuxiliary*, NandfsTags*);
+
+extern char Enomem[], Eperm[], Eio[];
--- /dev/null
+++ b/libnandfs/markblockbad.c
@@ -1,0 +1,42 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsmarkabsblockbad(Nandfs *nandfs, long absblock)
+{
+	NandfsAuxiliary hdr;
+	int page;
+	int ppb;
+
+	memset(&hdr, 0xff, sizeof(hdr));
+	hdr.blockstatus = 0xf0;		// late failure
+
+	ppb = 1 << nandfs->ll.l2pagesperblock;
+	for (page = 0; page < ppb; page++) {
+		char *errmsg = (*nandfs->write)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * absblock + page * NandfsFullSize + NandfsPageSize);
+		if (errmsg && strcmp(errmsg, Eio) != 0)
+			return errmsg;
+	}
+
+	return nil;
+}
+
+char *
+nandfsmarkblockbad(Nandfs *nandfs, long block)
+{
+	char *errmsg;
+	errmsg = nandfsmarkabsblockbad(nandfs, block + nandfs->baseblock);
+	if (errmsg)
+		return errmsg;
+
+	if (nandfs->blockdata) {
+		NandfsBlockData *d;
+		d = &nandfs->blockdata[block];
+		d->tag = LogfsTbad;
+	}
+
+	return nil;
+}
+
--- /dev/null
+++ b/libnandfs/mkfile
@@ -1,0 +1,33 @@
+<../mkconfig
+
+LIB=libnandfs.a
+
+OFILES=	\
+		calcformat.$O\
+		correctauxilliary.$O\
+		ecc.$O\
+		eraseblock.$O\
+		extracttags.$O\
+		findfreeblock.$O\
+		formatblock.$O\
+		getblockstatus.$O\
+		hamming31_26.$O\
+		init.$O\
+		markblockbad.$O\
+		open.$O\
+		readblock.$O\
+		readpage.$O\
+		readpageauxilliary.$O\
+		reformatblock.$O\
+		setget.$O\
+		updatepage.$O\
+		writeblock.$O\
+		writepageauxilliary.$O\
+
+HFILES=\
+	$ROOT/include/nandfs.h \
+	$ROOT/include/logfs.h \
+	local.h
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
--- /dev/null
+++ b/libnandfs/open.c
@@ -1,0 +1,253 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsopen(Nandfs *nandfs, long base, long limit, int trace, int xcount, long *xdata)
+{
+	NandfsBlockData *blockdata = nil;
+	long u;
+	ulong badones, goodones;
+	char *errmsg;
+	long possiblebaseblock, possiblesize;
+	long baseblock, limitblock;
+	int ppb;
+
+	if (trace > 1)
+		print("nandfsopen: base %ld limit %ld ppb %d\n", base, limit, 1 << nandfs->ll.l2pagesperblock);
+
+	if (nandfs->blockdata)
+		return Eperm;
+
+	if (base % nandfs->rawblocksize)
+		return Ebadarg;
+	baseblock = base / nandfs->rawblocksize;
+
+	if (limit == 0)
+		limitblock = nandfs->limitblock;
+	else if (limit % nandfs->rawblocksize)
+		return Ebadarg;
+	else
+		limitblock = limit / nandfs->rawblocksize;
+
+	if (trace > 1)
+		print("nandfsopen: baseblock %ld limitblock %ld\n", baseblock, limitblock);
+
+	possiblebaseblock = 0;
+	possiblesize = 0;
+
+	/*
+	 * search for Tboot block which will reveal the parameters
+	 */
+	nandfs->baseblock = 0;
+
+	for (u = baseblock; u < limitblock; u++) {
+		NandfsTags tags;
+		LogfsLowLevelReadResult e;
+		int p;
+		int lim;
+
+		lim = xcount + 3;
+
+		for (p = 0; p < lim; p++) {
+			errmsg = nandfsreadpageauxiliary(nandfs, &tags, u, p, 1, &e);
+			if (errmsg)
+				goto error;
+			if (e != LogfsLowLevelReadResultOk || tags.magic != LogfsMagic || tags.tag != LogfsTboot)
+				break;
+			if (trace > 1)
+				print("block %lud/%d: 0x%.lux\n", u, p, tags.path);
+			switch (p) {
+			case 1:
+				possiblebaseblock = tags.path;
+				break;
+			case 2:
+				possiblesize = tags.path;
+				break;
+			default:
+				xdata[p - 3] = tags.path;
+				break;
+			}
+		}
+		if (p == lim)
+			break;
+	}
+
+	if (u >= limitblock) {
+		errmsg = "no valid boot blocks found";
+		goto error;
+	}
+
+	if (possiblebaseblock < baseblock
+		|| possiblebaseblock >= limitblock
+		|| possiblebaseblock + possiblesize > limitblock
+		|| possiblesize == 0) {
+		errmsg = "embedded parameters out of range";
+		goto error;
+	}
+
+	baseblock = possiblebaseblock;
+	limitblock = possiblebaseblock + possiblesize;
+
+	if (trace > 0) {
+		int x;
+		print("nandfs filesystem detected: base %lud limit %lud",
+			baseblock, limitblock);
+		for (x = 0; x < xcount; x++)
+			print(" data%d %ld", x, xdata[x]);
+		print("\n");
+	}
+
+	blockdata = nandfsrealloc(nil, (limitblock - baseblock) * sizeof(NandfsBlockData));
+	if (blockdata == nil) {
+		errmsg = Enomem;
+		goto error;
+	}
+	/*
+	 * sanity check
+	 * check the partition until 10 good blocks have been found
+	 * check that bad blocks represent 10% or less
+	 */
+
+	badones = goodones = 0;
+	ppb = 1 << nandfs->ll.l2pagesperblock;
+	for (u = baseblock; u < limitblock; u++) {
+		LogfsLowLevelReadResult firste, laste;
+		NandfsTags firsttags, lasttags;
+		errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
+		if (errmsg)
+			goto error;
+		errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
+		if (errmsg)
+			goto error;
+		if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad)
+			continue;
+		if (firste == LogfsLowLevelReadResultOk && laste == LogfsLowLevelReadResultOk && firsttags.magic == LogfsMagic &&
+			lasttags.magic == LogfsMagic)
+			goodones++;
+		else
+			badones++;
+		if (badones == 0 && goodones >= 10)
+			break;
+	}
+
+	if (badones * 10 > goodones) {
+		errmsg = "most likely not a Log Filesystem";
+		goto error;
+	}
+
+	for (u = baseblock; u < limitblock; u++) {
+		int erased, partial;
+		LogfsLowLevelReadResult firste, laste;
+		NandfsTags firsttags, lasttags, newtags;
+		int markedbad;
+		errmsg = nandfsreadpageauxiliary(nandfs, &firsttags, u, 0, 1, &firste);
+		if (errmsg)
+			goto error;
+		errmsg = nandfsreadpageauxiliary(nandfs, &lasttags, u, ppb - 1, 1, &laste);
+		if (errmsg)
+			goto error;
+		if (trace > 1)
+			print("%lud: ", u);
+		if (firste == LogfsLowLevelReadResultBad || laste == LogfsLowLevelReadResultBad) {
+			if (trace > 1)
+				print("bad\n");
+			blockdata[u - baseblock].tag = LogfsTbad;
+			continue;
+		}
+		newtags = firsttags;
+		erased = 0;
+		partial = 0;
+		if (firsttags.tag != lasttags.tag) {
+			partial = 1;
+			if (trace > 1)
+				print("partially written\n");
+			/*
+			 * partially written block
+			 * if Tboot, then it is either
+			 * 	a failure during logfsformat() - well, we never got started, so give up
+			 *	a failure during blocktransfer() - erase it as the transfer was not completed
+			 *	tell the difference by the presence of another block with the same path
+			 * if Tnone, then it's a no brainer
+			 * if anything else, leave alone
+			 */
+			if (newtags.tag == LogfsTnone) {
+				newtags.tag = LogfsTnone;
+				newtags.path = NandfsPathMask;
+				errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
+				if (errmsg)
+					goto error;
+				if (markedbad) {
+					blockdata[u - baseblock].tag = LogfsTbad;
+					continue;
+				}
+				/* now erased */
+				erased = 1;
+				partial = 0;
+			}
+		}
+		if (!erased && !partial && firste == LogfsLowLevelReadResultAllOnes) {
+			if (trace > 1)
+				print("probably erased");
+			/*
+			 * finding erased blocks at this stage is a rare event, so
+			 * erase again just in case
+			 */
+			newtags.tag = LogfsTnone;
+			newtags.path = NandfsPathMask;
+			newtags.nerase = 1;		// what do I do here?
+			errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
+			if (errmsg)
+				goto error;
+			if (markedbad) {
+				blockdata[u - baseblock].tag = LogfsTbad;
+				continue;
+			}
+			erased = 1;
+		}
+		if (erased) {
+			newtags.magic = 'V';
+			errmsg = nandfseraseblock(nandfs, u, nil, &markedbad);
+			if (errmsg)
+				goto error;
+			if (markedbad) {
+				blockdata[u - baseblock].tag = LogfsTbad;
+				continue;
+			}
+		}
+		switch (newtags.tag) {
+		case LogfsTboot:
+		case LogfsTnone:
+		case LogfsTdata:
+		case LogfsTlog:
+			blockdata[u - baseblock].path = newtags.path;
+			blockdata[u - baseblock].tag = newtags.tag;
+			blockdata[u - baseblock].nerase = newtags.nerase;
+			blockdata[u - baseblock].partial = partial;
+			if (trace > 1)
+				print("%s 0x%.8lux %lud\n",
+					logfstagname(blockdata[u - baseblock].tag),
+					blockdata[u - baseblock].path,
+					blockdata[u - baseblock].nerase);
+			continue;
+		}
+		break;
+	}
+	nandfs->ll.blocks = u - baseblock;
+	nandfs->baseblock = baseblock;
+	nandfs->blockdata = nandfsrealloc(nil, nandfs->ll.blocks * sizeof(NandfsBlockData));
+	if (nandfs->blockdata == nil) {
+		errmsg = Enomem;
+		goto error;
+	}
+	nandfs->trace = trace;
+	memmove(nandfs->blockdata, blockdata, sizeof(*nandfs->blockdata) * nandfs->ll.blocks);
+	nandfsfreemem(blockdata);
+	if (trace > 0)
+		print("nandfsopen: success\n");
+	return nil;
+error:
+	nandfsfreemem(blockdata);
+	return errmsg;
+}
--- /dev/null
+++ b/libnandfs/readblock.c
@@ -1,0 +1,36 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsreadblock(Nandfs *nandfs, void *buf, long block, LogfsLowLevelReadResult *blocke)
+{
+	int p;
+	uchar *bp;
+	int ppb;
+
+	*blocke = LogfsLowLevelReadResultOk;
+	ppb = 1 << nandfs->ll.l2pagesperblock;
+	for (p = 0, bp = buf; p < ppb; p++, bp += NandfsPageSize) {
+		LogfsLowLevelReadResult e;
+		char *errmsg;
+		errmsg = nandfsreadpage(nandfs, bp, nil, block, p, nandfs->printbad, &e);
+		if (errmsg)
+			return errmsg;
+		switch (e) {
+		case LogfsLowLevelReadResultOk:
+			break;
+		case LogfsLowLevelReadResultSoftError:
+			if (*blocke == LogfsLowLevelReadResultOk)
+				*blocke = LogfsLowLevelReadResultSoftError;
+			break;
+		case LogfsLowLevelReadResultHardError:
+			if (*blocke == LogfsLowLevelReadResultOk || *blocke == LogfsLowLevelReadResultSoftError)
+				*blocke = LogfsLowLevelReadResultHardError;
+			break;
+		}
+	}
+
+	return nil;
+}
--- /dev/null
+++ b/libnandfs/readpage.c
@@ -1,0 +1,52 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "nandecc.h"
+#include "local.h"
+
+char *
+nandfsreadpage(Nandfs *nandfs, void *buf, NandfsTags *tags, long block, int page, int reportbad, LogfsLowLevelReadResult *result)
+{
+	ulong ecc1, ecc2, storedecc1, storedecc2;
+	NandEccError e1, e2;
+	ulong rawoffset;
+	NandfsAuxiliary hdr;
+	char *errmsg;
+
+	rawoffset = nandfs->rawblocksize * (nandfs->baseblock + block) + NandfsFullSize * page;
+	errmsg = (*nandfs->read)(nandfs->magic, buf, NandfsPageSize, rawoffset);
+	if (errmsg)
+		return errmsg;
+	errmsg = (*nandfs->read)(nandfs->magic, &hdr, sizeof(hdr), rawoffset + NandfsPageSize);
+	if (errmsg)
+		return errmsg;
+	ecc1 = nandecc(buf);
+	ecc2 = nandecc((uchar *)buf + 256);
+	storedecc1 = getlittle3(hdr.ecc1);
+	storedecc2 = getlittle3(hdr.ecc2);
+	e1 = nandecccorrect(buf, ecc1, &storedecc1, reportbad);
+	e2 = nandecccorrect((uchar *)buf + 256, ecc2, &storedecc2, reportbad);
+	if (e1 == NandEccErrorBad || e2 == NandEccErrorBad)
+		*result = LogfsLowLevelReadResultHardError;
+	else if (e1 != NandEccErrorGood || e2 != NandEccErrorGood)
+		*result = LogfsLowLevelReadResultSoftError;
+	else
+		*result = LogfsLowLevelReadResultOk;
+	if (tags) {
+		*result = _nandfscorrectauxiliary(&hdr);
+		_nandfsextracttags(&hdr, tags);
+	}
+	return nil;
+}
+
+char *
+nandfsreadpagerange(Nandfs *nandfs, void *buf, long block, int page, int offset, int count, LogfsLowLevelReadResult *result)
+{
+	char *errmsg;
+	uchar tmpbuf[NandfsPageSize];
+	errmsg = nandfsreadpage(nandfs, tmpbuf, nil, block, page, 1, result);
+	if (errmsg == nil)
+		memmove(buf, tmpbuf + offset, count);
+	return errmsg;
+}
+
--- /dev/null
+++ b/libnandfs/readpageauxilliary.c
@@ -1,0 +1,35 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+static int
+countzeros(uchar byte)
+{
+	int b, count;
+	for (b = 0x80, count = 0; b; b>>= 1)
+		if ((byte & b) == 0)
+			count++;
+	return count;
+}
+
+char *
+nandfsreadpageauxiliary(Nandfs *nandfs, NandfsTags *tags, long block, int page, int correct, LogfsLowLevelReadResult *result)
+{
+	NandfsAuxiliary hdr;
+	char *rv;
+
+	rv = (*nandfs->read)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * (nandfs->baseblock + block) + page * NandfsFullSize + NandfsPageSize);
+	if (rv)
+		return rv;
+	if (countzeros(hdr.blockstatus) > 2) {
+		*result = LogfsLowLevelReadResultBad;
+		return nil;
+	}
+	if (correct)
+		*result = _nandfscorrectauxiliary(&hdr);
+	else
+		*result = LogfsLowLevelReadResultOk;
+	_nandfsextracttags(&hdr, tags);
+	return nil;
+}
--- /dev/null
+++ b/libnandfs/reformatblock.c
@@ -1,0 +1,34 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfsreformatblock(Nandfs *nandfs, long block, uchar tag, ulong path, int xcount, long *xdata, void *llsave, int *markedbad)
+{
+	int bad;
+	char *errmsg;
+	NandfsBlockData *d;
+	long nerase;
+
+	if (nandfs->blockdata == nil)
+		return Eperm;
+
+	nerase = *(ulong *)llsave;
+
+	errmsg = nandfsformatblock(nandfs, block, tag, path,
+		nandfs->baseblock, nandfs->limitblock - nandfs->baseblock, xcount, xdata, &nerase, &bad);
+
+	if (markedbad)
+		*markedbad = bad;
+	if (errmsg)
+		return errmsg;
+
+	d = &nandfs->blockdata[block];
+	d->tag = bad ? LogfsTbad : tag;
+	d->path = path;
+	d->nerase = nerase;
+	d->partial = 0;
+
+	return nil;
+}
--- /dev/null
+++ b/libnandfs/setget.c
@@ -1,0 +1,101 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+short
+nandfsgettag(Nandfs *nandfs, long block)
+{
+	if (nandfs->blockdata)
+		return nandfs->blockdata[block].tag;
+	return 0;
+}
+
+void
+nandfssettag(Nandfs *nandfs, long block, short tag)
+{
+	if (nandfs->blockdata) {
+		nandfs->blockdata[block].tag = tag;
+		if (tag == LogfsTworse)
+			nandfs->worseblocks = 1;
+		return;
+	}
+}
+
+long
+nandfsgetpath(Nandfs *nandfs, long block)
+{
+	if (nandfs->blockdata)
+		return nandfs->blockdata[block].path;
+	return 0;
+}
+
+void
+nandfssetpath(Nandfs *nandfs, long block, ulong path)
+{
+	if (nandfs->blockdata) {
+		nandfs->blockdata[block].path = path;
+		return;
+	}
+}
+
+long
+nandfsgetnerase(Nandfs *nandfs, long block)
+{
+	if (nandfs->blockdata)
+		return nandfs->blockdata[block].nerase;
+	return 0;
+}
+
+void
+nandfssetnerase(Nandfs *nandfs, long block, ulong nerase)
+{
+	if (nandfs->blockdata) {
+		nandfs->blockdata[block].nerase = nerase;
+		return;
+	}
+}
+
+int
+nandfsgetblockpartialformatstatus(Nandfs *nandfs, long block)
+{
+	if (nandfs->blockdata)
+		return nandfs->blockdata[block].partial;
+	return 0;
+}
+
+void
+nandfssetblockpartialformatstatus(Nandfs *nandfs, long block, int partial)
+{
+	if (nandfs->blockdata) {
+		nandfs->blockdata[block].partial = partial;
+		return;
+	}
+}
+
+long
+nandfsgetbaseblock(Nandfs *nandfs)
+{
+	return nandfs->baseblock;
+}
+
+int
+nandfsgetblocksize(Nandfs *nandfs)
+{
+	return 1 << (nandfs->ll.l2pagesperblock + NandfsL2PageSize);
+}
+
+ulong
+nandfscalcrawaddress(Nandfs *nandfs, long pblock, int dataoffset)
+{
+	int lpage, pageoffset;
+	lpage = dataoffset / NandfsPageSize;
+	pageoffset = dataoffset % NandfsPageSize;
+	return nandfs->rawblocksize * pblock + lpage * NandfsFullSize + pageoffset;
+}
+
+int
+nandfsgetopenstatus(Nandfs *nandfs)
+{
+	return nandfs->blockdata != nil;
+}
--- /dev/null
+++ b/libnandfs/updatepage.c
@@ -1,0 +1,38 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "nandecc.h"
+#include "local.h"
+
+char *
+nandfsupdatepage(Nandfs *nandfs, void *buf, ulong path, uchar tag, long block, int page)
+{
+	uchar tbuf[NandfsFullSize];
+	ulong ecc1, ecc2;
+	ulong rawoffset;
+	NandfsAuxiliary *hdr;
+
+	rawoffset =  (nandfs->baseblock + block) * nandfs->rawblocksize + page * NandfsFullSize;
+	memmove(tbuf, buf, NandfsPageSize);
+	ecc1 = nandecc(tbuf);
+	ecc2 = nandecc(tbuf + 256);
+	hdr = (NandfsAuxiliary *)(tbuf + NandfsPageSize);
+	memset(hdr, 0xff, sizeof(*hdr));
+	hdr->tag = tag;
+	if (path < NandfsPathMask) {
+		ulong tmp = _nandfshamming31_26calc(path << 6) | (1 << 5);
+		putbig4(hdr->parth, tmp);
+	}
+	putlittle3(hdr->ecc1, ecc1);
+	putlittle3(hdr->ecc2, ecc2);
+	return (*nandfs->write)(nandfs->magic, tbuf, sizeof(tbuf), rawoffset);
+}
+
+char *
+nandfswritepage(Nandfs *nandfs, void *buf, long block, int page)
+{
+	ulong writepath = nandfsgetpath(nandfs, block);
+	uchar writetag = nandfsgettag(nandfs, block);
+//print("block %ld writepath 0x%.8lux writetag 0x%.2ux\n", block, writepath, writetag);
+	return nandfsupdatepage(nandfs, buf, writepath, writetag, block, page);
+}
--- /dev/null
+++ b/libnandfs/writeblock.c
@@ -1,0 +1,47 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+char *
+nandfswriteblock(Nandfs *nandfs, void *buf, uchar tag, ulong path, int xcount, long *data, long block)
+{
+	int p;
+	char *errmsg;
+
+	ulong opath = nandfsgetpath(nandfs, block);
+	ulong writepath = (~opath | path) & NandfsPathMask;
+	uchar writetag = ~nandfsgettag(nandfs, block) | tag;
+	int ppb = 1 << nandfs->ll.l2pagesperblock;
+
+	for (p = 0; p < ppb; p++) {
+		ulong wp;
+		if (p > 0 && p <= 2 + xcount) {
+			switch (p) {
+			case 1:
+				wp = (~opath | nandfsgetbaseblock(nandfs)) & NandfsPathMask;
+				break;
+			case 2:
+				wp = (~opath | nandfs->ll.blocks) & NandfsPathMask;
+				break;
+			default:
+				wp = (~opath | data[p - 3]) & NandfsPathMask;
+				break;
+			}
+		}
+		else
+			wp = writepath;
+		errmsg = nandfsupdatepage(nandfs, buf, wp, writetag, block, p);
+		if (errmsg)
+			return errmsg;
+#ifdef LOGFSTEST
+		if (logfstest.partialupdate && p > 0) {
+			print("skipping pageupdate\n");
+			break;
+		}
+#endif
+		buf = (uchar *)buf + NandfsPageSize;
+	}
+
+	return nil;
+}
--- /dev/null
+++ b/libnandfs/writepageauxilliary.c
@@ -1,0 +1,33 @@
+#include "logfsos.h"
+#include "logfs.h"
+#include "nandfs.h"
+#include "local.h"
+
+/*
+ * update the tags in a page's auxiliary area
+ * only touch the fields if they contain some zeros, and compute the hamming codes
+ * as well
+ */
+
+char *
+nandfswritepageauxiliary(Nandfs *nandfs, NandfsTags *tags, long absblock, int page)
+{
+	NandfsAuxiliary hdr;
+	ulong tmp;
+	ushort htmp;
+
+	memset(&hdr, 0xff, sizeof(hdr));
+	if (tags->path < NandfsPathMask) {
+		tmp = _nandfshamming31_26calc((tags->path << 6)) | (1 << 5);
+		putbig4(hdr.parth, tmp);
+	}
+	if (tags->nerase < NandfsNeraseMask || tags->magic != 0xff) {
+		tmp = _nandfshamming31_26calc((tags->magic << 24) | (tags->nerase << 6)) | (1 << 5);
+		htmp = tmp >> 16;
+		putbig2(hdr.nerasemagicmsw, htmp);
+		putbig2(hdr.nerasemagiclsw, tmp);
+	}
+	if  (tags->tag != 0xff)
+		hdr.tag = tags->tag;
+	return (*nandfs->write)(nandfs->magic, &hdr, sizeof(hdr), nandfs->rawblocksize * absblock + page * NandfsFullSize + NandfsPageSize);
+}
--- /dev/null
+++ b/libprefab/NOTICE
@@ -1,0 +1,25 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libprefab/box.c
@@ -1,0 +1,80 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+PCompound*
+box(Prefab_Environ *e, Draw_Point p, Prefab_Element *title, Prefab_Element *list)
+{
+	Draw_Rect er, r, lr;
+	PCompound *pc;
+	Prefab_Compound *c;
+	Image *disp;
+	Draw_Image *ddisp;
+	Screen *screen;
+	Heap *h;
+	Point pt;
+	int w;
+
+	if(list == H)
+		return H;
+	screen = lookupscreen(e->screen);
+	if(screen == nil)
+		return H;
+	h = heapz(TCompound);
+	if(h == H)
+		return H;
+	pc = H2D(PCompound*, h);
+	c = &pc->c;
+
+	gchalt++;
+	r = list->r;
+	if(title != H){
+		w = 2+1+3+Dx(title->r)+1;
+		if(w > Dx(r))
+			r.max.x = r.min.x + w;
+		r.max.y += 2+1+Dy(title->r)+1;
+	}
+
+	er = edgerect(e, p, &r);
+
+	disp = allocwindow(screen, IRECT(er), Refbackup /*refreshcompound*/, DWhite);
+	if(disp == nil){
+   Err:
+		destroy(c);
+		gchalt--;
+		return H;
+	}
+	if((ddisp=mkdrawimage(disp, e->screen, e->screen->display, nil)) == H){
+		freeimage(disp);
+		goto Err;
+	}
+
+	lr = r;
+	if(title != H){
+		pt.x = r.min.x+3;
+		pt.y = r.min.y+3;
+		translateelement(title, pt);
+		lr.min.y = title->r.max.y+1;
+	}
+	translateelement(list, subpt(IPOINT(lr.min), IPOINT(list->r.min)));
+
+	c->r = r;
+	c->image = ddisp;
+	c->environ = e;
+	D2H(e)->ref++;
+	if(title != H){
+		c->title = title;
+		D2H(title)->ref++;
+	}
+	if(list != H){
+		c->contents = (Prefab_Element*)list;
+		D2H(list)->ref++;
+	}
+	pc->display = screen->display;
+	gchalt--;
+	return pc;
+}
--- /dev/null
+++ b/libprefab/compound.c
@@ -1,0 +1,193 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+extern void queuerefresh(Image *i, Rectangle r, Reffn reffn, void *refptr);
+
+Draw_Rect
+edgerect(Prefab_Environ *e, Draw_Point p, Draw_Rect *rin)
+{
+	Draw_Rect r;
+	Screen *s;
+
+	r.min.x = p.x;
+	r.min.y = p.y;
+	r.max.x = p.x + 1 + Dx(*rin) + 1;
+	r.max.y = p.y + 1 + Dy(*rin) + 1;
+	/* outer box computed; now make sure it's all visible */
+	s = lookupscreen(e->screen);
+	if(s != nil)
+		fitrect((Rectangle*)&r, s->display->image->r);
+
+	rin->min.x = r.min.x+1;
+	rin->min.y = r.min.y+1;
+	rin->max.x = r.max.x-1;
+	rin->max.y = r.max.y-1;
+
+	return r;
+}
+
+/*
+ * Draw edge around r.
+ * Assume geometry has already been clipped and adjusted.
+ */
+void
+edge(Prefab_Environ *e, Image *box, Draw_Rect dr, Draw_Rect dclipr)
+{
+	Rectangle r, r1, clipr;
+	Image *ec;
+	Screen *s;
+
+	R2R(r, dr);
+	R2R(clipr, dclipr);
+	r.min.x -= 1;
+	r.min.y -= 1;
+	r.max.x += 1;
+	r.max.y += 1;
+	s = lookupscreen(e->screen);
+	if(s == nil)
+		return;
+	ec = lookupimage(e->style->edgecolor);
+	if(ec == nil)
+		return;
+
+	r1 = r;
+	r1.min.y++;
+	r1.max.y = r1.min.y+2;
+	r1.max.x = r1.min.x+2*(r1.max.x-r1.min.x)/3;
+	if(rectclip(&r1, clipr))
+		draw(box, r1, ec, nil, r1.min);
+	r1 = r;
+	r1.min.x++;
+	r1.max.x = r1.min.x+2;
+	r1.max.y = r1.min.y+2*(r1.max.y-r1.min.y)/3;
+	if(rectclip(&r1, clipr))
+		draw(box, r1, ec, nil, r1.min);
+	r1=r;
+	r1.min.x = r1.max.x-1;
+	if(rectclip(&r1, clipr))
+		draw(box, r1, ec, nil, r1.min);
+	r1=r;
+	r1.min.y = r1.max.y-1;
+	if(rectclip(&r1, clipr))
+		draw(box, r1, ec, nil, r1.min);
+	r1 = r;
+	r1.max.y = r1.min.y+1;
+	if(rectclip(&r1, clipr))
+		draw(box, r1, ec, nil, r1.min);
+	r1=r;
+	r1.max.x = r1.min.x+1;
+	if(rectclip(&r1, clipr))
+		draw(box, r1, ec, nil, r1.min);
+}
+
+void
+redrawcompound(Image *i, Rectangle clipr, Prefab_Compound *c)
+{
+	Rectangle r1, rt, r;
+	int l, len;
+	Prefab_Style *s;
+	Image *elemcolor, *edgecolor;
+	List *list;
+	Font *font;
+	Prefab_Element *e;
+
+	if(c==H || badenviron(c->environ, 0))
+		return;
+	
+	r = clipr;
+	s = c->environ->style;
+	elemcolor = lookupimage(s->elemcolor);
+	edgecolor = lookupimage(s->edgecolor);
+	if(elemcolor==nil || edgecolor==nil)
+		return;
+	draw(i, r, elemcolor, nil, r.min);
+	if(lookupelement(c->title) != H){
+		R2R(rt, c->title->r);
+		if(c->title->environ!=H && c->title->environ->style!=H && rectXrect(r, rt)){
+			drawelement(c->title, i, r, c->environ==c->title->environ, 0);
+			r1.min.x = c->r.min.x;
+			r1.min.y = c->title->r.max.y;
+			s = c->title->environ->style;
+			len = 0;
+			switch(c->title->kind){
+			case ETitle:
+				font = lookupfont(s->titlefont);
+				if(font != nil)
+					len = 2+1+stringwidth(font, string2c(c->title->str));
+				break;
+			case EVertical:
+				font = lookupfont(s->titlefont);
+				if(font != nil)
+					for(list=c->title->kids; list!=H; list=list->tail){
+						e = *(Prefab_Element**)list->data;
+						l = stringwidth(font, string2c(e->str));
+						if(l > len)
+							len = l;
+					}
+				len += 2+1;
+				break;
+			default: 
+				len = r1.min.x+2*Dx(c->r)/3;
+			}
+			r1.max.x = r1.min.x + len;
+			r1.max.y = r1.min.y+1;
+			draw(i, r1, edgecolor, nil, r.min);
+			r.min.y = r1.max.y;
+		}
+	}
+	if(c->contents!=H)
+		drawelement(c->contents, i, r, c->environ==c->contents->environ, 0);
+	edge(c->environ, i, c->r, DRECT(clipr));
+}
+
+void
+refreshcompound(Image *i, Rectangle r, void *ptr)
+{
+	Prefab_Compound *c;
+
+	c = ptr;
+	if(c == nil)
+		return;
+	if(i == nil){	/* called from flushimage */
+		i = lookupimage(c->image);
+		if(i  == nil)
+			return;
+	}
+	redrawcompound(i, r, c);
+}
+
+void
+localrefreshcompound(Memimage *mi, Rectangle r, void *ptr)
+{
+	Prefab_Compound *c;
+	Image *i;
+
+	USED(mi);	/* can't do anything with this, but it's part of the memlayer interface */
+	c = ptr;
+	if(c == nil)
+		return;
+	i = lookupimage(c->image);
+	if(i == nil)
+		return;
+	queuerefresh(i, r, refreshcompound, ptr);
+}
+
+void
+drawcompound(Prefab_Compound *c)
+{
+	Image *i;
+
+	if(c==H || c->image==H)
+		return;
+	i = lookupimage(c->image);
+	redrawcompound(i, insetrect(IRECT(c->r), -1), c);
+	if(i->display->local && i->refptr==nil)
+		if(drawlsetrefresh(i->display->dataqid, i->id, localrefreshcompound, c) <= 0)
+			fprint(2, "drawcompound: can't set refresh\n");
+	i->refptr = c;	/* can now be refreshed */
+}
--- /dev/null
+++ b/libprefab/element.c
@@ -1,0 +1,723 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+
+void	icondraw(Prefab_Element*, Image*, Rectangle, int, int);
+void	textdraw(Prefab_Element*, Image*, Rectangle, int, int);
+void	listdraw(Prefab_Element*, Image*, Rectangle, int, int);
+void	outlinehighlight(Prefab_Element*, Image*, Prefab_Compound*, int);
+void	texthighlight(Prefab_Element*, Image*, Prefab_Compound*, int);
+void	simpleclip(Prefab_Element*, Rectangle);
+void	horizontalclip(Prefab_Element*, Rectangle);
+void	verticalclip(Prefab_Element*, Rectangle);
+void	textscroll(Prefab_Element*, Point, int*);
+void	horizontalscroll(Prefab_Element*, Point, int*);
+void	verticalscroll(Prefab_Element*, Point, int*);
+void	iconscroll(Prefab_Element*, Point, int*);
+
+struct
+{
+	void	(*draw)(Prefab_Element*, Image*, Rectangle, int, int);
+	void	(*highlight)(Prefab_Element*, Image*, Prefab_Compound*, int);
+	void	(*clip)(Prefab_Element*, Rectangle);
+	void	(*scroll)(Prefab_Element*, Point, int*);
+}elemfn[] = {
+ /* EIcon */		{ icondraw, outlinehighlight, simpleclip, iconscroll, },
+ /* EText */		{ textdraw, texthighlight, simpleclip, textscroll, },
+ /* ETitle */		{ textdraw, outlinehighlight, simpleclip, textscroll, },
+ /* EHorizontal */	{ listdraw, outlinehighlight, horizontalclip, horizontalscroll, },
+ /* EVertical */	{ listdraw, outlinehighlight, verticalclip, verticalscroll, },
+ /* ESeparator */	{ icondraw, outlinehighlight, simpleclip, iconscroll, },
+};
+
+Point
+iconsize(Image *image)
+{
+	Point dd;
+
+	if(image->repl){
+		dd.x = Dx(image->clipr);
+		dd.y = Dy(image->clipr);
+	}else{
+		dd.x = Dx(image->r);
+		dd.y = Dy(image->r);
+	}
+	return dd;
+}
+
+void
+icondraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+	Prefab_Style *style;
+	Rectangle r;
+	Point p;
+	PElement *pelem;
+	Image *image, *c;
+	Point size;
+
+	USED(highlight);
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	if(!rectclip(&clipr, i->clipr))
+		return;
+	R2R(r, elem->r);
+	if(!rectclip(&clipr, r))
+		return;
+	if(elem->image==H || elem->mask==H || badenviron(elem->environ, 0))
+		return;
+	style = elem->environ->style;
+	if(!clean){
+		c = lookupimage(style->elemcolor);
+		if(c != nil)
+			draw(i, clipr, c, nil, clipr.min);
+	}
+	r.min = pelem->drawpt;
+	image = lookupimage(elem->image);
+	if(image == nil)
+		return;
+	size = iconsize(image);
+	r.max.x = r.min.x+size.x;
+	r.max.y = r.min.y+size.y;
+	if(rectclip(&r, clipr)){
+		p = image->r.min;
+		p.x += r.min.x-pelem->drawpt.x;
+		p.y += r.min.y-pelem->drawpt.y;
+		c = lookupimage(elem->mask);
+		if(c != nil)
+			draw(i, r, image, c, p);
+	}
+}
+
+void
+textdraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+	Prefab_Style *style;
+	Rectangle r;
+	PElement *pelem;
+	Image *color, *c;
+	Font *font;
+
+	USED(highlight);
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	if(!rectclip(&clipr, i->clipr))
+		return;
+	R2R(r, elem->r);
+	if(!rectclip(&clipr, r))
+		return;
+	if(elem->str==H || badenviron(elem->environ, 0))
+		return;
+	style = elem->environ->style;
+	font = lookupfont(elem->font);
+	if(font == nil)
+		return;
+	if(highlight)
+		color = lookupimage(style->highlightcolor);
+	else
+		color = lookupimage(elem->image);
+	if(!clean){
+		c = lookupimage(style->elemcolor);
+		if(c != nil)
+			draw(i, clipr, c, nil, clipr.min);
+	}
+	if(color != nil)
+		_string(i, pelem->drawpt, color, pelem->drawpt, font, string2c(elem->str), nil, 1<<24, clipr, nil, pelem->drawpt, SoverD);
+}
+
+void
+listdraw(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+	Prefab_Style *style;
+	Prefab_Element *e;
+	List *l;
+	Rectangle r;
+	PElement *pelem;
+	Image *c;
+
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	if(!rectclip(&clipr, i->clipr))
+		return;
+	R2R(r, elem->r);
+	if(!rectclip(&clipr, r))
+		return;
+	if(elem->kids==H || badenviron(elem->environ, 0))
+		return;
+	if(pelem->first != elem->kids)	/* error? */
+		return;
+	style = elem->environ->style;
+	if(!clean){
+		c = lookupimage(style->elemcolor);
+		if(c != nil)
+			draw(i, clipr, c, nil, clipr.min);
+	}
+	for(l=pelem->vfirst; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		R2R(r, e->r);
+		if(rectXrect(r, clipr))
+			drawelement(e, i, clipr, elem->environ==e->environ, highlight);
+		if(l == pelem->vlast)
+			break;
+	}
+}
+
+void
+drawelement(Prefab_Element *elem, Image *i, Rectangle clipr, int clean, int highlight)
+{
+	PElement *pelem;
+
+	if(elem != H){
+		pelem = lookupelement(elem);
+		if(pelem == H)
+			return;
+		(*elemfn[elem->kind].draw)(elem, i, clipr, clean, highlight);
+		if(!highlight && pelem->highlight!=H)
+			(*elemfn[elem->kind].highlight)(elem, i, pelem->highlight, 1);
+	}
+}
+
+void
+translateelement(Prefab_Element *elem, Point delta)
+{
+	PElement *pelem;
+	List *l;
+
+	if(elem == H)
+		return;
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	elem->r.min.x += delta.x;
+	elem->r.min.y += delta.y;
+	elem->r.max.x += delta.x;
+	elem->r.max.y += delta.y;
+	pelem->drawpt.x += delta.x;
+	pelem->drawpt.y += delta.y;
+	switch(elem->kind){
+	case EHorizontal:
+	case EVertical:
+		if(pelem->first != elem->kids)
+			return;
+		for(l=elem->kids; l!=H; l=l->tail)
+			translateelement(*(Prefab_Element**)l->data, delta);
+		break;
+	}
+}
+
+int
+fitrect(Rectangle *r, Rectangle sr)
+{
+	if(r->max.x > sr.max.x){
+		r->min.x -= r->max.x-sr.max.x;
+		r->max.x = sr.max.x;
+	}
+	if(r->max.y > sr.max.y){
+		r->min.y -= r->max.y-sr.max.y;
+		r->max.y = sr.max.y;
+	}
+	if(r->min.x < sr.min.x){
+		r->max.x += sr.min.x-r->min.x;
+		r->min.x = sr.min.x;
+	}
+	if(r->min.y < sr.min.y){
+		r->max.y += sr.min.y-r->min.y;
+		r->min.y = sr.min.y;
+	}
+	return rectinrect(*r, sr);
+}
+
+void
+adjusthorizontal(Prefab_Element *elem, int spacing, int position)
+{
+	int edx, dx, i, x;
+	int nlist;	/* BUG: should precompute */
+	List *l;
+	PElement *pelem;
+	Prefab_Element *e;
+	Point p;
+
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	if(pelem->first != elem->kids)
+		return;
+	p.y = 0;
+	switch(spacing){
+	default:	/* shouldn't happen; protected by adjustelement */
+	case Adjpack:
+		x = elem->r.min.x;
+		for(l=elem->kids; l!=H; l=l->tail){
+			e = *(Prefab_Element**)l->data;
+			p.x = x - e->r.min.x;
+			translateelement(e, p);
+			x += Dx(e->r);
+		}
+		elem->r.max.x = x;
+		return;
+
+	case Adjequal:
+		dx = 0;
+		nlist = 0;
+		for(l=elem->kids; l!=H; l=l->tail){
+			e = *(Prefab_Element**)l->data;
+			if(dx < Dx(e->r))
+				dx = Dx(e->r);
+			nlist++;
+		}
+		elem->r.max.x = elem->r.min.x+nlist*dx;
+		break;
+
+	case Adjfill:
+		nlist = 0;
+		for(l=elem->kids; l!=H; l=l->tail)
+			nlist++;
+		dx = Dx(elem->r)/nlist;
+		break;
+	}
+	i = 0;
+	for(l=elem->kids; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		edx = Dx(e->r);
+		if(position == Adjleft)
+			edx = 0;
+		else if(position == Adjcenter)
+			edx = (dx-edx)/2;
+		else	/* right */
+			edx = dx-edx;
+		p.x = (elem->r.min.x+i*dx + edx) - e->r.min.x;
+		translateelement(e, p);
+		i++;
+	}
+}
+
+void
+adjustvertical(Prefab_Element *elem, int spacing, int position)
+{
+	int edy, dy, i, y;
+	int nlist;	/* BUG: should precompute */
+	List *l;
+	PElement *pelem;
+	Prefab_Element *e;
+	Point p;
+
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	if(pelem->first != elem->kids)
+		return;
+	p.x = 0;
+	switch(spacing){
+	default:	/* shouldn't happen; protected by adjustelement */
+	case Adjpack:
+		y = elem->r.min.y;
+		for(l=elem->kids; l!=H; l=l->tail){
+			e = *(Prefab_Element**)l->data;
+			p.y = y - e->r.min.y;
+			translateelement(e, p);
+			y += Dy(e->r);
+		}
+		elem->r.max.y = y;
+		return;
+
+	case Adjequal:
+		dy = 0;
+		nlist = 0;
+		for(l=elem->kids; l!=H; l=l->tail){
+			e = *(Prefab_Element**)l->data;
+			if(dy < Dy(e->r))
+				dy = Dy(e->r);
+			nlist++;
+		}
+		elem->r.max.y = elem->r.min.y+nlist*dy;
+		break;
+
+	case Adjfill:
+		nlist = 0;
+		for(l=elem->kids; l!=H; l=l->tail)
+			nlist++;
+		dy = Dy(elem->r)/nlist;
+		break;
+	}
+	i = 0;
+	for(l=elem->kids; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		edy = Dy(e->r);
+		if(position == Adjup)
+			edy = 0;
+		else if(position == Adjcenter)
+			edy = (dy-edy)/2;
+		else	/* down */
+			edy = dy-edy;
+		p.y = (elem->r.min.y+i*dy + edy) - e->r.min.y;
+		translateelement(e, p);
+		i++;
+	}
+}
+
+void
+adjustelement(Prefab_Element *elem, int spacing, int position)
+{
+	if(lookupelement(elem) == H)
+		return;
+	if(spacing<Adjpack || spacing>Adjfill || position<Adjleft || position>Adjdown)
+		return;
+	switch(elem->kind){
+	case EVertical:
+		adjustvertical(elem, spacing, position);
+		break;
+	case EHorizontal:
+		adjusthorizontal(elem, spacing, position);
+		break;
+	}
+}
+
+void
+highlightelement(Prefab_Element *elem, Image *i, Prefab_Compound *comp, int on)
+{
+	PElement *pelem;
+
+	pelem = lookupelement(elem);
+	if(pelem!=H && lookupcompound(comp)!=H){
+		if(on)
+			pelem->highlight = comp;
+		else
+			pelem->highlight = H;
+		(*elemfn[elem->kind].highlight)(elem, i, comp, on);
+	}
+}
+
+static
+int
+anytextelements(Prefab_Element *e)
+{
+	Prefab_Element *t;
+	List *l;
+
+	for(l=e->kids; l!=H; l=l->tail){
+		t = *(Prefab_Element**)l->data;
+		if(t->kind == EText)
+			return 1;
+	}
+	return 0;
+}
+
+void
+textlisthighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
+{
+	Prefab_Element *t;
+	List *l;
+
+	for(l=e->kids; l!=H; l=l->tail){
+		t = *(Prefab_Element**)l->data;
+		if(t->kind == EText)
+			texthighlight(t, i, c, on);
+	}
+}
+
+void
+outlinehighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
+{
+	List *l;
+	Prefab_Element *t;
+	Image *color;
+	Rectangle r, r1, r2;
+	Point dp;
+	int done;
+
+	/* see if we can do it by highlighting just a text element */
+	if((e->kind==EVertical || e->kind==EHorizontal) && e->kids!=H){
+		/* is any child a text element? */
+		if(anytextelements(e)){
+			textlisthighlight(e, i, c, on);
+			return;
+		}
+		/* grandchild? */
+		done = 0;
+		for(l=e->kids; l!=H; l=l->tail){
+			t = *(Prefab_Element**)l->data;
+			if(t->kind==EVertical || t->kind==EHorizontal)
+				if(anytextelements(t)){
+					textlisthighlight(t, i, c, on);
+					done = 1;
+				}
+		}
+		if(done)
+			return;
+	}
+	if(on){
+		color = lookupimage(e->environ->style->highlightcolor);
+		if(color == nil)
+			return;
+		R2R(r, e->r);
+		/* avoid outlining empty space around images */
+		dp = ((PElement*)e)->drawpt;
+		if(e->kind==EIcon && e->image->repl==0 && ptinrect(dp, r)){
+			R2R(r1, e->image->r);
+			R2R(r2, e->image->clipr);
+			if(rectclip(&r1, r2)){
+				dp.x += Dx(r1);
+				dp.y += Dy(r1);
+				if(ptinrect(dp, r))
+					r = Rpt(((PElement*)e)->drawpt, dp);
+			}
+		}
+		draw(i, r, color, nil, r.min);
+		drawelement(e, i, insetrect(r, 2), Dirty, 1);
+	}else{
+		drawelement(e, i, IRECT(e->r), Dirty, 0);
+		edge(c->environ, i, c->r, e->r);
+	}
+}
+
+void
+texthighlight(Prefab_Element *e, Image *i, Prefab_Compound *c, int on)
+{
+	drawelement(e, i, IRECT(e->r), Clean, on);
+	edge(c->environ, i, c->r, e->r);
+}
+
+void
+clipelement(Prefab_Element *elem, Rectangle r)
+{
+	if(lookupelement(elem) != H)
+		(*elemfn[elem->kind].clip)(elem, r);
+}
+
+void
+simpleclip(Prefab_Element *elem, Rectangle r)
+{
+	R2R(elem->r, r);
+}
+
+void
+horizontalclip(Prefab_Element *elem, Rectangle r)
+{
+	int x;
+	List *l;
+	Prefab_Element *e;
+	PElement *pelem;
+
+	x = r.min.x;
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	for(l=pelem->vfirst; l!=H && x<r.max.x; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		x += Dx(e->r);
+	}
+	pelem->vlast = l;
+	R2R(elem->r, r);
+}
+
+void
+verticalclip(Prefab_Element *elem, Rectangle r)
+{
+	int y;
+	List *l;
+	Prefab_Element *e;
+	PElement *pelem;
+
+	y = r.min.y;
+	pelem = lookupelement(elem);
+	if(pelem == H)
+		return;
+	for(l=pelem->vfirst; l!=H && y<r.max.y; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		y += Dy(e->r);
+	}
+	pelem->vlast = l;
+	R2R(elem->r, r);
+}
+
+void
+scrollelement(Prefab_Element *elem, Point d, int *moved)
+{
+	if(lookupelement(elem) != H)
+		(*elemfn[elem->kind].scroll)(elem, d, moved);
+}
+
+void
+textscroll(Prefab_Element *elem, Point d, int *moved)
+{
+	PElement *pelem;
+
+	pelem = lookupelement(elem);
+	if(pelem==H || (d.x==0 && d.y==0))
+		return;
+	pelem->drawpt = subpt(pelem->drawpt, d);
+	*moved = 1;
+}
+
+void
+iconscroll(Prefab_Element *elem, Point d, int *moved)
+{
+	Point p;
+	Image *i;
+	PElement *pelem;
+
+	pelem = lookupelement(elem);
+	if(pelem==H || elem->image==H || (d.x==0 && d.y==0))
+		return;
+	i = lookupimage(elem->image);
+	if(i == nil)
+		return;
+	p = subpt(pelem->drawpt, d);
+	if(i->repl == 0){
+		if(p.x+Dx(i->clipr) < elem->r.max.x)
+			p.x = elem->r.max.x - Dx(i->clipr);
+		if(p.y+Dy(i->clipr) < elem->r.max.y)
+			p.y = elem->r.max.y - Dy(i->clipr);
+		if(p.x > elem->r.min.x)
+			p.x = elem->r.min.x;
+		if(p.y > elem->r.min.y)
+			p.y = elem->r.min.y;
+	}
+	*moved = !eqpt(pelem->drawpt, p);
+	pelem->drawpt = p;
+}
+
+void
+horizontalscroll(Prefab_Element *elem, Point d, int *moved)
+{
+	List *l;
+	Prefab_Element *e;
+	PElement *pelem;
+
+	pelem = lookupelement(elem);
+	if(pelem==H || elem->kids==H || (d.x==0 && d.y==0))
+		return;
+	for(l=pelem->first; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		translateelement(e, d);
+	}
+	for(l=pelem->first; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		if(e->r.max.x > elem->r.min.x)
+			break;
+	}
+	pelem->vfirst = l;
+	pelem->vlast = l;
+	for(; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		pelem->vlast = l;
+		if(e->r.min.x >= elem->r.max.x)
+			break;
+	}
+	*moved = 1;
+}
+
+void
+verticalscroll(Prefab_Element *elem, Point d, int *moved)
+{
+	List *l;
+	Prefab_Element *e;
+	PElement *pelem;
+
+	pelem = lookupelement(elem);
+	if(pelem==H || elem->kids==H || (d.x==0 && d.y==0))
+		return;
+	for(l=pelem->first; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		translateelement(e, d);
+	}
+	for(l=pelem->first; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		if(e->r.max.y > elem->r.min.y)
+			break;
+	}
+	pelem->vfirst = l;
+	pelem->vlast = l;
+	for(; l!=H; l=l->tail){
+		e = *(Prefab_Element**)l->data;
+		pelem->vlast = l;
+		if(e->r.min.y >= elem->r.max.y)
+			break;
+	}
+	*moved = 1;
+}
+
+/*
+ * Make e visible within list.  Return value is whether any change was made;
+ * if so, must redraw (BUG: should probably do this here)
+ */
+int
+showelement(Prefab_Element *list, Prefab_Element *e)
+{
+	Point p;
+	Prefab_Element *h, *t;
+	PElement *plist;
+	int moved;
+
+	p.x = p.y = 0;
+	if(list->kids == H)
+		return 0;
+	plist = lookupelement(list);
+	if(plist == H)
+		return 0;
+	h = *(Prefab_Element**)plist->first->data;
+	t = *(Prefab_Element**)plist->last->data;
+	if(list->kind == EHorizontal){
+		p.x = (list->r.min.x+Dx(list->r)/2) - e->r.min.x;
+		if(e->r.min.x < list->r.min.x){	/* scroll to right */
+			if(e->r.max.x+p.x > list->r.max.x)
+				p.x = list->r.min.x-e->r.min.x;
+			if(h->r.min.x + p.x > list->r.min.x)
+				p.x = list->r.min.x-h->r.min.x;
+		}else if(e->r.max.x > list->r.max.x){	/* scroll to left */
+			if(e->r.min.x+p.x < list->r.min.x)
+				p.x = list->r.min.x-e->r.min.x;
+			if(t->r.max.x + p.x < list->r.max.x)
+				p.x = list->r.max.x-t->r.max.x;
+		}else
+			return 0;
+	}else if(list->kind == EVertical){
+		p.y = (list->r.min.y+Dy(list->r)/2) - e->r.min.y;
+		if(e->r.min.y < list->r.min.y){	/* scroll towards bottom */
+			if(e->r.max.y+p.y > list->r.max.y)
+				p.y = list->r.min.y-e->r.min.y;
+			if(h->r.min.y + p.y > list->r.min.y)
+				p.y = list->r.min.y-h->r.min.y;
+		}else if(e->r.max.y > list->r.max.y){	/* scroll towards top */
+			if(e->r.min.y+p.y < list->r.min.y)
+				p.y = list->r.min.y-e->r.min.y;
+			if(t->r.max.y + p.y < list->r.max.y)
+				p.y = list->r.max.y-t->r.max.y;
+		}else
+			return 0;
+	}else
+		return 0;
+	if(p.x!=0 || p.y!=0){
+		scrollelement(list, p, &moved);
+		return 1;
+	}
+	return 0;
+}
+
+PElement*
+mkelement(Prefab_Environ *env, enum Elementtype t)
+{
+	Heap *h;
+	PElement *p;
+
+	h = heapz(TElement);
+	p = H2D(PElement*, h);
+	p->highlight = H;
+	p->first = H;
+	p->last = H;
+	p->vfirst = H;
+	p->vlast = H;
+	p->nkids = 1;
+	p->pkind = t;
+	p->e.kind = t;
+	p->e.environ = env;
+	D2H(env)->ref++;
+	return p;
+}
--- /dev/null
+++ b/libprefab/elistelement.c
@@ -1,0 +1,113 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+#include <kernel.h>
+
+List*
+prefabwrap(void *elem)
+{
+	List *l;
+	Heap *h, *e;
+
+	e = D2H(elem);
+	h = nheap(sizeof(List) + sizeof(WORD*));
+	h->t = &Tlist;
+	Tlist.ref++;
+	l = H2D(List*, h);
+	l->tail = H;
+	l->t = &Tptr;
+	Tptr.ref++;
+	e->ref++;
+	*(WORD**)l->data = elem;
+	return l;
+}
+
+static
+PElement*
+elistelement1(Prefab_Environ *e, Prefab_Element *elem, Prefab_Element *new, enum Elementtype kind)
+{
+	int first;
+	PElement *pelem;
+	List *atom;
+
+	if(badenviron(e, 0))
+		return H;
+
+	gchalt++;
+	first = 0;
+	if(new == H)
+		atom = H;
+	else
+		atom = prefabwrap(new);
+	if(elem == H){
+		pelem = mkelement(e, kind);
+		elem = &pelem->e;
+		pelem->first = H;
+		pelem->nkids = 0;
+	}else
+		pelem = (PElement*)elem;
+	if(atom == H)
+		goto Return;
+
+	if(elem->kids != pelem->first)
+		error("list Element has been modified externally");
+	if(elem->kids == H){
+		elem->kids = atom;
+		pelem->first = atom;
+		pelem->last = atom;
+		pelem->vfirst = atom;
+		pelem->vlast = atom;
+		first = 1;
+	}
+	if(new->kind!=ESeparator && Dx(elem->r)==0){
+		elem->r = new->r;
+		pelem->drawpt.x = elem->r.min.x;
+		pelem->drawpt.y = elem->r.min.y;
+	}
+	pelem->nkids++;
+	if(first)
+		goto Return;
+	pelem->last->tail = atom;
+	pelem->last = atom;
+	pelem->vlast = atom;
+	if(new->kind != ESeparator){
+		if(kind == EVertical){
+			elem->r.max.y += Dy(new->r);
+			if(elem->r.min.x > new->r.min.x)
+				elem->r.min.x = new->r.min.x;
+			if(elem->r.max.x < new->r.max.x)
+				elem->r.max.x = new->r.max.x;
+		}else{
+			elem->r.max.x += Dx(new->r);
+			if(elem->r.min.y > new->r.min.y)
+				elem->r.min.y = new->r.min.y;
+			if(elem->r.max.y < new->r.max.y)
+				elem->r.max.y = new->r.max.y;
+		}
+	}
+	pelem->pkind = kind;
+
+    Return:
+	gchalt--;
+	return pelem;
+}
+
+PElement*
+elistelement(Prefab_Environ *e, Prefab_Element *new, enum Elementtype kind)
+{
+	return elistelement1(e, H, new, kind);
+}
+
+PElement*
+appendelist(Prefab_Element *elem, Prefab_Element *new)
+{
+	if(elem->kind!=EVertical && elem->kind!=EHorizontal){
+		kwerrstr("appendelist to non-list");
+		return H;
+	}
+	return elistelement1(elem->environ, elem, new, elem->kind);
+}
--- /dev/null
+++ b/libprefab/iconbox.c
@@ -1,0 +1,83 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+PCompound*
+iconbox(Prefab_Environ *e, Draw_Point p, String *titletext, Draw_Image *icon, Draw_Image *mask)
+{
+	Draw_Rect er, r, ir;
+	PCompound *pc;
+	Prefab_Compound *c;
+	PElement *elem, *title;
+	Image *disp;
+	Draw_Image *ddisp;
+	Screen *screen;
+	Heap *h;
+	Rectangle t;
+	Point pt;
+
+	screen = lookupscreen(e->screen);
+	if(screen == nil)
+		return H;
+	h = heapz(TCompound);
+	if(h == H)
+		return H;
+	pc = H2D(PCompound*, h);
+	c = &pc->c;
+
+	gchalt++;
+	title = H;
+	if(titletext != H){
+		er.min.x = 0;
+		er.min.y = 0;
+		er.max.x = Dx(icon->r)-5;
+		er.max.y = 0;
+		title = textelement(e, titletext, er, ETitle);
+		if(title == H){
+    Err:
+			destroy(c);
+			gchalt--;
+			return H;
+		}
+		c->title = (Prefab_Element*)title;
+	}
+
+	r = icon->r;
+	if(title != H)
+		r.max.y += 2+1+title->nkids*e->style->titlefont->height+1;
+
+	er = edgerect(e, p, &r);
+
+	R2R(t, er);
+	disp = allocwindow(screen, t, Refbackup /*refreshcompound*/, DWhite);
+	if(disp == nil)
+		goto Err;
+
+	if((ddisp=mkdrawimage(disp, e->screen, e->screen->display, nil)) == H){
+		freeimage(disp);
+		goto Err;
+	}
+
+	ir = r;
+	if(title != H){
+		ir = r;
+		pt.x = r.min.x+3;
+		pt.y = r.min.y+3;
+		translateelement(&title->e, pt);
+		ir.min.y = title->e.r.max.y+1;
+	}
+
+	elem = iconelement(e, ir, icon, mask);
+	c->r = r;
+	c->image = ddisp;
+	c->environ = e;
+	D2H(e)->ref++;
+	c->contents = (Prefab_Element*)elem;
+	pc->display = screen->display;
+	gchalt--;
+	return pc;
+}
--- /dev/null
+++ b/libprefab/iconelement.c
@@ -1,0 +1,50 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+static
+PElement*
+iconelement1(Prefab_Environ *e, Draw_Rect r, Draw_Image *icon, Draw_Image *mask, enum Elementtype kind)
+{
+	PElement *pelem;
+	Prefab_Element *elem;
+
+	if(badenviron(e, 0) || icon==H || mask==H)
+		return H;
+	pelem = mkelement(e, kind);
+	if(pelem == H)
+		return H;
+	elem = &pelem->e;
+
+	if(Dx(r))
+		elem->r = r;
+	else{
+		elem->r.min = r.min;
+		elem->r.max.x = r.min.x + Dx(icon->r);
+		elem->r.max.y = r.min.y + Dy(icon->r);
+	}
+	elem->mask = mask;
+	D2H(mask)->ref++;
+	elem->image = icon;
+	D2H(icon)->ref++;
+	pelem->drawpt = IPOINT(r.min);
+	pelem->nkids = 1;
+	pelem->pkind = kind;
+	return pelem;
+}
+
+PElement*
+iconelement(Prefab_Environ *e, Draw_Rect r, Draw_Image *icon, Draw_Image *mask)
+{
+	return iconelement1(e, r, icon, mask, EIcon);
+}
+
+PElement*
+separatorelement(Prefab_Environ *e, Draw_Rect r, Draw_Image *icon, Draw_Image *mask)
+{
+	return iconelement1(e, r, icon, mask, ESeparator);
+}
--- /dev/null
+++ b/libprefab/mkfile
@@ -1,0 +1,21 @@
+<../mkconfig
+
+LIB=libprefab.a
+
+OFILES=\
+	box.$O\
+	compound.$O\
+	element.$O\
+	elistelement.$O\
+	iconbox.$O\
+	iconelement.$O\
+	textbox.$O\
+	textelement.$O\
+
+HFILES=\
+	$ROOT/include/draw.h\
+	$ROOT/include/prefab.h\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+$OFILES:	$ROOT/module/prefab.m
--- /dev/null
+++ b/libprefab/textbox.c
@@ -1,0 +1,138 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+
+PCompound*
+layoutbox(Prefab_Environ *e, Draw_Rect rr, String *titletext, List *texttext)
+{
+	Draw_Rect er, r, lr;
+	PCompound *pc;
+	Prefab_Compound *c;
+	PElement *title, *text;
+	Image *disp;
+	Draw_Image *ddisp;
+	Screen *screen;
+	Heap *h;
+	Rectangle t;
+	int wid, w;
+	Point p, pt;
+
+	screen = lookupscreen(e->screen);
+	if(screen == nil)
+		return H;
+
+	gchalt++;
+	wid = Dx(rr);
+	P2P(p, rr.min);
+	title = H;
+	text = H;
+	if(texttext != H){
+		er.min.x = 0;
+		er.min.y = 0;
+		er.max.x = wid-5;
+		er.max.y = Dy(rr);
+		text = layoutelement(e, texttext, er, EText);
+		if(text == H){
+			gchalt--;
+			return H;
+		}
+		if(wid <= 0)
+			wid = Dx(text->e.r)+5;
+	}
+	if(titletext != H){
+		/* see how wide title wants to be */
+		memset(&er, 0, sizeof er);
+		title = textelement(e, titletext, er, ETitle);
+		if(title == H){
+    Errtitle:
+			destroy(text);
+			gchalt--;
+			return H;
+		}
+		w = 2+1+3+Dx(title->e.r)+1;
+		/* if title is wider than text, adjust wid accordingly */
+		if(text!=0 && Dx(text->e.r)<w){
+			if(Dx(text->e.r) < 100){	/* narrow text; don't let title get too wide */
+				if(w > 250+5)
+					w = 250+5;
+				wid = w;
+			}
+			destroy(title);
+			er.min.x = 0;
+			er.min.y = 0;
+			er.max.x = wid-5;
+			er.max.y = 0;
+			title = textelement(e, titletext, er, ETitle);
+			if(title == H)
+				goto Errtitle;
+		}
+		if(wid <= 0)
+			wid = Dx(title->e.r)+5;
+	}
+
+	h = heapz(TCompound);
+	pc = H2D(PCompound*, h);
+	c = &pc->c;
+	c->title = (Prefab_Element*)title;
+	c->contents = (Prefab_Element*)text;
+	/* now can just destroy c to clean up */
+
+	r.min = DPOINT(p);
+	r.max.x = r.min.x+wid;
+	r.max.y = p.y+2+1 + 1+1;
+	if(title != H)
+		r.max.y += title->nkids*e->style->titlefont->height+1;
+	if(text != H)
+		r.max.y += Dy(text->e.r);
+
+	er = edgerect(e, DPOINT(p), &r);
+
+	R2R(t, er);
+	disp = allocwindow(screen, t, Refbackup /*refreshcompound*/, DWhite);
+	if(disp == nil){
+    Err:
+		destroy(c);
+		gchalt--;
+		return H;
+	}
+	if((ddisp=mkdrawimage(disp, e->screen, e->screen->display, nil)) == H){
+		freeimage(disp);
+		goto Err;
+	}
+
+	lr = r;
+	if(title != H){
+		pt.x = r.min.x+3;
+		pt.y = r.min.y+3;
+		translateelement(&title->e, pt);
+		lr.min.y = title->e.r.max.y+1;
+	}
+
+	if(text != H)
+		translateelement((Prefab_Element*)text, subpt(IPOINT(lr.min), IPOINT(text->e.r.min)));
+
+	c->r = r;
+	c->environ = e;
+	c->image = ddisp;
+	D2H(e)->ref++;
+	pc->display = screen->display;
+	gchalt--;
+	return pc;
+
+}
+
+PCompound*
+textbox(Prefab_Environ *e, Draw_Rect rr, String *titletext, String *texttext)
+{
+	PCompound *pc;
+	List *l;
+
+	l = listoflayout(e->style, texttext, EText);
+	pc = layoutbox(e, rr, titletext, l);
+	free(l);
+	return pc;
+}
--- /dev/null
+++ b/libprefab/textelement.c
@@ -1,0 +1,488 @@
+#include <lib9.h>
+#include <draw.h>
+#include <interp.h>
+#include <isa.h>
+#include "../libinterp/runt.h"
+#include <drawif.h>
+#include <prefab.h>
+#include <kernel.h>
+
+typedef struct State State;
+
+struct State
+{
+	Prefab_Environ	*env;
+	List			*list;
+	char			word[Maxchars+UTFmax];
+	char			*s;
+	char			*pending;
+	Draw_Font	*font;
+	Draw_Image	*color;
+	Draw_Image	*icon;
+	Draw_Image	*mask;
+	String		*tag;
+	Point			p;
+	int			mainkind;
+	int			kind;
+	int			wid;
+	int			newelem;
+	int			ascent;
+	int			descent;
+};
+
+static
+char*
+advword(char *s, char *word)
+{
+	char *e;
+	int w;
+	Rune r;
+
+	e = s+Maxchars-1;
+	switch(*word++ = *s){
+	case '\t':		/* BUG: what to do about tabs? */
+		strcpy(word-1, "    ");
+		return s+1;
+	case '\n':
+	case ' ':
+		*word = 0;
+		return s+1;
+	case '\0':
+		return s;
+	}
+	s++;
+	while(s<e && *s && *s!=' ' && *s!='\t' && *s!='\n'){
+		if(*(uchar*)s < Runeself)
+			*word++ = *s++;
+		else{
+			w = chartorune(&r, s);
+			memmove(word, s, w);
+			word += w;
+			s += w;
+		}
+	}
+	*word = 0;
+	return s;
+}
+
+static
+int
+ismore(State *state)
+{
+	Prefab_Style *style;
+	Prefab_Layout *lay;
+	int text, icon;
+
+	state->newelem = 0;
+	if(state->kind==EIcon || (state->s && state->s[0]) || state->pending)
+		return 1;
+	if(state->list == H)
+		return 0;
+	lay = (Prefab_Layout*)state->list->data;
+	text = (lay->text!=H && lay->text->len != 0);
+	icon = (lay->icon!=H && lay->mask!=H);
+	if(!text && !icon)
+		return 0;
+	state->newelem = 1;
+	state->s = string2c(lay->text);
+	state->font = lay->font;
+	state->color = lay->color;
+	state->icon = lay->icon;
+	state->mask = lay->mask;
+	state->tag = lay->tag;
+	style = state->env->style;
+	if(icon)	/* has precedence; if lay->icon is set, we ignore the text */
+		state->kind = EIcon;
+	else{
+		if(state->mainkind == ETitle){
+			if(state->font == H)
+				state->font = style->titlefont;
+			if(state->color == H)
+				state->color = style->titlecolor;
+		}else{
+			if(state->font == H)
+				state->font = style->textfont;
+			if(state->color == H)
+				state->color = style->textcolor;
+		}
+		state->kind = state->mainkind;
+	}
+	state->list = state->list->tail;
+	return 1;
+}
+
+PElement*
+growtext(PElement *pline, State *state, char *w, int minx, int maxx)
+{
+	String *s;
+	PElement *pe, *plist;
+	Prefab_Element *e;
+	List *atom;
+	Point size;
+	Image *image;
+
+	if(state->newelem || pline==H) {
+		pe = mkelement(state->env, state->kind);
+		e = &pe->e;
+		e->r.min.x = minx;
+		if(state->kind == EIcon){
+			e->image = state->icon;
+			D2H(e->image)->ref++;
+			e->mask = state->mask;
+			D2H(e->mask)->ref++;
+		}else{
+			e->image = state->color;
+			D2H(e->image)->ref++;
+			e->font = state->font;
+			D2H(e->font)->ref++;
+		}
+		e->tag = state->tag;
+		if(e->tag != H)
+			D2H(e->tag)->ref++;
+		if(pline == H)
+			pline = pe;
+		else{
+			if(pline->pkind != EHorizontal){
+				/* promote pline to list encapsulating current contents */
+				atom = prefabwrap(pline);
+				plist = mkelement(state->env, EHorizontal);
+				destroy(pline);
+				/* rest of plist->e.r will be set later */
+				plist->e.r.min.x = state->p.x;
+				plist->drawpt = state->p;
+				plist->e.kids = atom;
+				plist->first = atom;
+				plist->last = atom;
+				plist->vfirst = atom;
+				plist->vlast = atom;
+				pline = plist;
+			}
+			/* add e to line */
+			atom = prefabwrap(e);
+			destroy(e);	/* relevant data now in wrapper */
+			e = *(Prefab_Element**)atom->data;
+			pline->last->tail = atom;
+			pline->last = atom;
+			pline->vlast = atom;
+			pline->nkids++;
+		}
+		state->newelem = 0;
+	}else{
+		pe = pline;
+		if(pe->pkind == EHorizontal)
+			pe = *(PElement**)pe->last->data;
+		e = &pe->e;
+	}
+
+	if(state->kind == EIcon){
+		/* guaranteed OK by buildine */	
+		image = lookupimage(state->icon);
+		size = iconsize(image);
+		/* put one pixel on each side */
+		e->r.max.x = e->r.min.x+1+size.x+1;
+		pline->e.r.max.x = e->r.max.x;
+		if(state->ascent < size.y)
+			state->ascent = size.y;
+		state->kind = -1;	/* consume EIcon from state */
+		return pline;
+	}
+
+	e->r.max.x = maxx;
+	pline->e.r.max.x = maxx;
+	if(*w == '\n') {
+		pline->newline = 1;
+		return pline;
+	}
+
+	s = addstring(e->str, c2string(w, strlen(w)), 0);
+	destroy(e->str);
+	e->str = s;
+
+	if(state->ascent < e->font->ascent)
+		state->ascent = e->font->ascent;
+	if(state->descent < e->font->height-e->font->ascent)
+		state->descent = e->font->height-e->font->ascent;
+	return pline;
+}
+
+PElement*
+buildline(State *state, int *ok)
+{
+	int wordwid, linewid, nb, rwid, x;
+	char tmp[UTFmax+1], *w, *t;
+	PElement *pl, *pe;
+	Rune r;
+	Font *f;
+	List *l;
+	Image *icon;
+	Point size;
+
+	*ok = 1;
+	linewid = 0;
+	pl = H;
+	state->ascent = 0;
+	state->descent = 0;
+	x = state->p.x;
+	while(ismore(state)){
+		f = nil;
+		if(state->kind == EIcon){
+			icon = lookupimage(state->icon);
+			if(icon == nil){
+    Error:
+				destroy(pl);
+				*ok = 0;
+				return H;
+			}
+			size = iconsize(icon);
+			wordwid = 1+size.x+1;
+		}else{
+			if(state->pending == 0){
+				state->s = advword(state->s, state->word);
+				state->pending = state->word;
+			}
+			if(*(state->pending) == '\n'){
+				pl = growtext(pl, state, state->pending, x, x);
+				if(pl == H){
+					*ok = 0;
+					return H;
+				}
+				state->pending = 0;
+				break;
+			}
+			f = lookupfont(state->font);
+			if(f == nil)
+				goto Error;
+			wordwid = stringwidth(f, state->pending);
+		}
+		if(linewid+wordwid<=state->wid){
+    Easy:
+			pl = growtext(pl, state, state->pending, x, x+wordwid);
+			if(pl == H){
+				*ok = 0;
+				return H;
+			}
+			linewid += wordwid;
+			state->pending = 0;
+			x += wordwid;
+			continue;
+		}
+		/* this word doesn't fit on this line */
+		/* if it's white space or an icon, just generate a line break */
+		if(state->word[0]==' ' || state->kind==EIcon){
+			if(linewid == 0)	/* it's just too wide; emit it and it'll get clipped */
+				goto Easy;
+			state->pending = 0;
+			break;
+		}
+		/* if word would fit were we to break the line now, do so */
+		if(wordwid <= state->wid)
+			break;
+		/* worst case: bite off the biggest piece that fits */
+		w = state->pending;
+		while(*w){
+			nb = chartorune(&r, w);
+			memmove(tmp, w, nb);
+			tmp[nb] = 0;
+			rwid = stringwidth(f, tmp);
+			if(linewid+rwid > state->wid)
+				break;
+			linewid += rwid;
+			w += nb;
+		}
+		if(w == state->pending){
+			/* first char too wide for remaining space */
+			if(linewid > 0)
+				break;
+			/* remaining space is all we'll get */
+			kwerrstr("can't handle wide word in textelement\n");
+			goto Error;
+		}
+		nb = w-state->pending;
+		t = malloc(nb+1);
+		if(t == nil)
+			goto Error;
+		memmove(t, state->pending, nb);
+		t[nb] = 0;
+		pl = growtext(pl, state, t, x, state->p.x+linewid);
+		free(t);
+		if(pl == H){
+			*ok = 0;
+			return H;
+		}
+		state->pending = w;
+		break;
+	}
+	pl->e.r.min.y = state->p.y;
+	pl->e.r.max.y = state->p.y+state->ascent+state->descent;
+	P2P(pl->drawpt, pl->e.r.min);
+	if(pl->pkind==EHorizontal){
+		for(l=pl->first; l!=H; l=l->tail){
+			pe = *(PElement**)l->data;
+			pe->e.r.min.y = state->p.y;
+			pe->e.r.max.y = state->p.y+state->ascent+state->descent;
+			pe->drawpt.x = pe->e.r.min.x;
+			if(pe->e.kind == EIcon){
+				/* add a pixel on the left; room was left in growtext */
+				pe->drawpt.x += 1;
+				pe->drawpt.y = pe->e.r.min.y+(state->ascent-Dy(pe->e.image->r));
+			}else
+				pe->drawpt.y = pe->e.r.min.y+(state->ascent-pe->e.font->ascent);
+		}
+	}
+	return pl;
+}
+
+PElement*
+layoutelement(Prefab_Environ *env, List *laylist, Draw_Rect rr, enum Elementtype kind)
+{
+	PElement *pline, *plist, *firstpline;
+	List *lines, *atom, *tail;
+	State state;
+	int nlines, linewid, maxwid, wid, trim, maxy, ok;
+	Point p;
+	Rectangle r;
+	Screen *screen;
+
+	nlines = 0;
+	trim = 0;
+	wid = Dx(rr);
+	if(wid < 25){
+		if(wid <= 0)
+			trim = 1;
+		screen = lookupscreen(env->screen);
+		if(screen == nil)
+			return H;
+		wid = Dx(screen->display->image->r)-32;
+		if(wid < 100)
+			wid = 100;
+	}
+	wid -= 3+3;	/* three pixels left and right */
+
+	gchalt++;
+	state.env = env;
+	state.list = laylist;
+	state.s = 0;
+	state.pending = 0;
+	state.font = H;
+	state.color = H;
+	state.tag = H;
+	p = IPOINT(rr.min);
+	p.x += 3;
+	state.p = p;
+	state.kind = EText;	/* anything but EIcon */
+	state.mainkind = kind;
+	state.wid = wid;
+	lines = H;
+	tail = H;
+	firstpline = H;
+	maxwid = 0;
+	maxy = 0;
+	while(ismore(&state)){
+		pline = buildline(&state, &ok);
+		if(ok == 0){
+			plist = H;
+			goto Return;
+		}
+		if(pline == H)
+			break;
+		linewid = Dx(pline->e.r);
+		if(linewid > maxwid)
+			maxwid = linewid;
+		if(firstpline == H)
+			firstpline = pline;
+		else{
+			atom = prefabwrap(pline);
+			destroy(pline);	/* relevant data now in wrapper */
+			pline = *(PElement**)atom->data;
+			if(lines == H){
+				lines = prefabwrap(firstpline);
+				destroy(firstpline);
+				firstpline = 0;	/* never used again; this proves it! */
+				tail = lines;
+			}
+			tail->tail = atom;
+			tail = atom;
+		}
+		nlines++;
+		state.p.y = pline->e.r.max.y;
+		if(maxy==0 || state.p.y<=rr.max.y)
+			maxy = state.p.y;
+	}
+	if(trim == 0)
+		maxwid = wid;
+	if(nlines == 0){
+		plist = H;
+		goto Return;
+	}
+	if(nlines == 1){
+		if(trim == 0){	/* restore clipping around element */
+			firstpline->e.r.min.x = rr.min.x;
+			firstpline->e.r.max.x = rr.min.x+3+maxwid+3;
+		}
+		plist = firstpline;
+		goto Return;
+	}
+	plist = mkelement(env, EVertical);
+	plist->e.r.min.x = rr.min.x;
+	plist->e.r.min.y = p.y;
+	plist->e.r.max.x = rr.min.x+3+maxwid+3;
+	plist->e.r.max.y = (*(Prefab_Element**)tail->data)->r.max.y;
+	plist->drawpt = p;
+	plist->e.kids = lines;
+	plist->first = lines;
+	plist->last = tail;
+	plist->vfirst = lines;
+	plist->vlast = tail;
+	plist->nkids = nlines;
+	/* if asked for a fixed size and list is too long, clip */
+	if(Dy(rr)>0 && rr.max.y<plist->e.r.max.y){
+		R2R(r, plist->e.r);
+		r.max.y = maxy;
+		clipelement(&plist->e, r);
+	}
+
+Return:
+	gchalt--;
+	return plist;
+}
+
+/*
+ * Create List with one Layout in it, using malloc instead of heap to
+ * keep it out of the eyes of the garbage collector
+ */
+List*
+listoflayout(Prefab_Style *style, String *text, int kind)
+{
+	List *listp;
+	Prefab_Layout *layp;
+
+	listp = malloc(sizeof(List) + TLayout->size);
+	if(listp == nil)
+		return H;
+	listp->tail = H;
+	layp = (Prefab_Layout*)listp->data;
+	if(kind == EText){
+		layp->font = style->textfont;
+		layp->color = style->textcolor;
+	}else{
+		layp->font = style->titlefont;
+		layp->color = style->titlecolor;
+	}
+	layp->text = text;
+	layp->icon = H;
+	layp->mask = H;
+	layp->tag = H;
+	return listp;
+}
+
+PElement*
+textelement(Prefab_Environ *env, String *str, Draw_Rect rr, enum Elementtype kind)
+{
+	PElement *pe;
+	List *l;
+
+	l = listoflayout(env->style, str, kind);
+	pe = layoutelement(env, l, rr, kind);
+	free(l);
+	return pe;
+}
--- /dev/null
+++ b/libsec/Inferno-386/md5block.s
@@ -1,0 +1,220 @@
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/*
+ * SI is data
+ *	a += FN(B,C,D);
+ *	a += x[sh] + t[sh];
+ *	a = (a << S11) | (a >> (32 - S11));
+ *	a += b;
+ */
+
+#define BODY1(off,V,FN,SH,A,B,C,D)\
+	FN(B,C,D)\
+	LEAL V(A)(DI*1),A;\
+	ADDL (off)(BP),A;\
+	ROLL $SH,A;\
+	ADDL B,A;\
+
+#define BODY(off,V,FN,SH,A,B,C,D)\
+	FN(B,C,D)\
+	LEAL V(A)(DI*1),A;\
+	ADDL (off)(BP),A;\
+	ROLL $SH,A;\
+	ADDL B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+	MOVL C,DI;\
+	XORL D,DI;\
+	ANDL B,DI;\
+	XORL D,DI;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	ANDL D,DI;\
+	XORL C,DI;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL D,DI;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+	MOVL D,DI;\
+	XORL $-1,DI;\
+	ORL B,DI;\
+	XORL C,DI;\
+
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+#define EDATA	(-4)
+
+	TEXT	_md5block+0(SB),$4
+
+	MOVL	data+DATA(FP),AX
+	ADDL	len+LEN(FP),AX
+	MOVL	AX,edata+EDATA(SP)
+
+	MOVL data+DATA(FP),BP
+
+mainloop:
+	MOVL state+STATE(FP),SI
+	MOVL (SI),AX
+	MOVL 4(SI),BX
+	MOVL 8(SI),CX
+	MOVL 12(SI),DX
+
+	BODY1( 0*4,0xd76aa478,FN1,S11,AX,BX,CX,DX)
+	BODY1( 1*4,0xe8c7b756,FN1,S12,DX,AX,BX,CX)
+	BODY1( 2*4,0x242070db,FN1,S13,CX,DX,AX,BX)
+	BODY1( 3*4,0xc1bdceee,FN1,S14,BX,CX,DX,AX)
+
+	BODY1( 4*4,0xf57c0faf,FN1,S11,AX,BX,CX,DX)
+	BODY1( 5*4,0x4787c62a,FN1,S12,DX,AX,BX,CX)
+	BODY1( 6*4,0xa8304613,FN1,S13,CX,DX,AX,BX)
+	BODY1( 7*4,0xfd469501,FN1,S14,BX,CX,DX,AX)
+
+	BODY1( 8*4,0x698098d8,FN1,S11,AX,BX,CX,DX)
+	BODY1( 9*4,0x8b44f7af,FN1,S12,DX,AX,BX,CX)
+	BODY1(10*4,0xffff5bb1,FN1,S13,CX,DX,AX,BX)
+	BODY1(11*4,0x895cd7be,FN1,S14,BX,CX,DX,AX)
+
+	BODY1(12*4,0x6b901122,FN1,S11,AX,BX,CX,DX)
+	BODY1(13*4,0xfd987193,FN1,S12,DX,AX,BX,CX)
+	BODY1(14*4,0xa679438e,FN1,S13,CX,DX,AX,BX)
+	BODY1(15*4,0x49b40821,FN1,S14,BX,CX,DX,AX)
+
+
+	BODY( 1*4,0xf61e2562,FN2,S21,AX,BX,CX,DX)
+	BODY( 6*4,0xc040b340,FN2,S22,DX,AX,BX,CX)
+	BODY(11*4,0x265e5a51,FN2,S23,CX,DX,AX,BX)
+	BODY( 0*4,0xe9b6c7aa,FN2,S24,BX,CX,DX,AX)
+
+	BODY( 5*4,0xd62f105d,FN2,S21,AX,BX,CX,DX)
+	BODY(10*4,0x02441453,FN2,S22,DX,AX,BX,CX)
+	BODY(15*4,0xd8a1e681,FN2,S23,CX,DX,AX,BX)
+	BODY( 4*4,0xe7d3fbc8,FN2,S24,BX,CX,DX,AX)
+
+	BODY( 9*4,0x21e1cde6,FN2,S21,AX,BX,CX,DX)
+	BODY(14*4,0xc33707d6,FN2,S22,DX,AX,BX,CX)
+	BODY( 3*4,0xf4d50d87,FN2,S23,CX,DX,AX,BX)
+	BODY( 8*4,0x455a14ed,FN2,S24,BX,CX,DX,AX)
+
+	BODY(13*4,0xa9e3e905,FN2,S21,AX,BX,CX,DX)
+	BODY( 2*4,0xfcefa3f8,FN2,S22,DX,AX,BX,CX)
+	BODY( 7*4,0x676f02d9,FN2,S23,CX,DX,AX,BX)
+	BODY(12*4,0x8d2a4c8a,FN2,S24,BX,CX,DX,AX)
+
+
+	BODY( 5*4,0xfffa3942,FN3,S31,AX,BX,CX,DX)
+	BODY( 8*4,0x8771f681,FN3,S32,DX,AX,BX,CX)
+	BODY(11*4,0x6d9d6122,FN3,S33,CX,DX,AX,BX)
+	BODY(14*4,0xfde5380c,FN3,S34,BX,CX,DX,AX)
+
+	BODY( 1*4,0xa4beea44,FN3,S31,AX,BX,CX,DX)
+	BODY( 4*4,0x4bdecfa9,FN3,S32,DX,AX,BX,CX)
+	BODY( 7*4,0xf6bb4b60,FN3,S33,CX,DX,AX,BX)
+	BODY(10*4,0xbebfbc70,FN3,S34,BX,CX,DX,AX)
+
+	BODY(13*4,0x289b7ec6,FN3,S31,AX,BX,CX,DX)
+	BODY( 0*4,0xeaa127fa,FN3,S32,DX,AX,BX,CX)
+	BODY( 3*4,0xd4ef3085,FN3,S33,CX,DX,AX,BX)
+	BODY( 6*4,0x04881d05,FN3,S34,BX,CX,DX,AX)
+
+	BODY( 9*4,0xd9d4d039,FN3,S31,AX,BX,CX,DX)
+	BODY(12*4,0xe6db99e5,FN3,S32,DX,AX,BX,CX)
+	BODY(15*4,0x1fa27cf8,FN3,S33,CX,DX,AX,BX)
+	BODY( 2*4,0xc4ac5665,FN3,S34,BX,CX,DX,AX)
+
+
+	BODY( 0*4,0xf4292244,FN4,S41,AX,BX,CX,DX)
+	BODY( 7*4,0x432aff97,FN4,S42,DX,AX,BX,CX)
+	BODY(14*4,0xab9423a7,FN4,S43,CX,DX,AX,BX)
+	BODY( 5*4,0xfc93a039,FN4,S44,BX,CX,DX,AX)
+
+	BODY(12*4,0x655b59c3,FN4,S41,AX,BX,CX,DX)
+	BODY( 3*4,0x8f0ccc92,FN4,S42,DX,AX,BX,CX)
+	BODY(10*4,0xffeff47d,FN4,S43,CX,DX,AX,BX)
+	BODY( 1*4,0x85845dd1,FN4,S44,BX,CX,DX,AX)
+
+	BODY( 8*4,0x6fa87e4f,FN4,S41,AX,BX,CX,DX)
+	BODY(15*4,0xfe2ce6e0,FN4,S42,DX,AX,BX,CX)
+	BODY( 6*4,0xa3014314,FN4,S43,CX,DX,AX,BX)
+	BODY(13*4,0x4e0811a1,FN4,S44,BX,CX,DX,AX)
+
+	BODY( 4*4,0xf7537e82,FN4,S41,AX,BX,CX,DX)
+	BODY(11*4,0xbd3af235,FN4,S42,DX,AX,BX,CX)
+	BODY( 2*4,0x2ad7d2bb,FN4,S43,CX,DX,AX,BX)
+	BODY( 9*4,0xeb86d391,FN4,S44,BX,CX,DX,AX)
+
+	ADDL $(16*4),BP
+	MOVL state+STATE(FP),DI
+	ADDL AX,0(DI)
+	ADDL BX,4(DI)
+	ADDL CX,8(DI)
+	ADDL DX,12(DI)
+
+	MOVL edata+EDATA(SP),DI
+	CMPL BP,DI
+	JCS mainloop
+
+	RET
+
+	END
--- /dev/null
+++ b/libsec/Inferno-386/mkfile
@@ -1,0 +1,17 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+OBJDIR=Inferno/$OBJTYPE
+
+LIB=libsec.a
+FILES=\
+	md5block\
+	sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Inferno-386/sha1block.s
@@ -1,0 +1,195 @@
+	TEXT	_sha1block+0(SB),$352
+
+/* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BSWAPDI	BYTE $0x0f; BYTE $0xcf;
+
+#define BODY(off,FN,V,A,B,C,D,E)\
+	MOVL (off-64)(BP),DI;\
+	XORL (off-56)(BP),DI;\
+	XORL (off-32)(BP),DI;\
+	XORL (off-12)(BP),DI;\
+	ROLL $1,DI;\
+	MOVL DI,off(BP);\
+	LEAL V(DI)(E*1),E;\
+	MOVL A,DI;\
+	ROLL $5,DI;\
+	ADDL DI,E;\
+	FN(B,C,D)\
+	ADDL DI,E;\
+	RORL $2,B;\
+
+#define BODY0(off,FN,V,A,B,C,D,E)\
+	MOVL off(BX),DI;\
+	BSWAPDI;\
+	MOVL DI,off(BP);\
+	LEAL V(DI)(E*1),E;\
+	MOVL A,DI;\
+	ROLL $5,DI;\
+	ADDL DI,E;\
+	FN(B,C,D)\
+	ADDL DI,E;\
+	RORL $2,B;\
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+	MOVL C,DI;\
+	XORL D,DI;\
+	ANDL B,DI;\
+	XORL D,DI;\
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL D,DI;\
+
+/*
+ * fn3 = ((B ^ C) & (D ^= B)) ^ B
+ * D ^= B to restore D
+ */
+#define FN3(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL B,D;\
+	ANDL D,DI;\
+	XORL B,DI;\
+	XORL B,D;\
+
+/*
+ * stack offsets
+ * void sha1block(uchar *DATA, int LEN, ulong *STATE)
+ */
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY	(-4-(80*4))
+#define TMP1	(-8-(80*4))
+#define TMP2	(-12-(80*4))
+#define W15	(-16-(80*4))
+#define W40	(-20-(80*4))
+#define W60	(-24-(80*4))
+#define W80	(-28-(80*4))
+#define EDATA	(-32-(80*4))
+
+	MOVL data+DATA(FP),AX
+	ADDL len+LEN(FP),AX
+	MOVL AX,edata+EDATA(SP)
+
+	LEAL aw15+(WARRAY+15*4)(SP),DI
+	MOVL DI,w15+W15(SP)
+	LEAL aw40+(WARRAY+40*4)(SP),DX
+	MOVL DX,w40+W40(SP)
+	LEAL aw60+(WARRAY+60*4)(SP),CX
+	MOVL CX,w60+W60(SP)
+	LEAL aw80+(WARRAY+80*4)(SP),DI
+	MOVL DI,w80+W80(SP)
+
+mainloop:
+	LEAL warray+WARRAY(SP),BP
+
+	MOVL state+STATE(FP),DI
+	MOVL (DI),AX
+	MOVL 4(DI),BX
+	MOVL BX,tmp1+TMP1(SP)
+	MOVL 8(DI),CX
+	MOVL 12(DI),DX
+	MOVL 16(DI),SI
+
+	MOVL data+DATA(FP),BX
+
+loop1:
+	BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+	MOVL SI,tmp2+TMP2(SP)
+	BODY0(4,FN1,0x5a827999,SI,AX,tmp1+TMP1(SP),CX,DX)
+	MOVL tmp1+TMP1(SP),SI
+	BODY0(8,FN1,0x5a827999,DX,tmp2+TMP2(SP),AX,SI,CX)
+	BODY0(12,FN1,0x5a827999,CX,DX,tmp2+TMP2(SP),AX,SI)
+	MOVL SI,tmp1+TMP1(SP)
+	BODY0(16,FN1,0x5a827999,SI,CX,DX,tmp2+TMP2(SP),AX)
+	MOVL tmp2+TMP2(SP),SI
+
+	ADDL $20,BX
+	ADDL $20,BP
+	CMPL BP,w15+W15(SP)
+	JCS loop1
+
+	BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+	ADDL $4,BX
+	MOVL BX,data+DATA(FP)
+	MOVL tmp1+TMP1(SP),BX
+
+	BODY(4,FN1,0x5a827999,SI,AX,BX,CX,DX)
+	BODY(8,FN1,0x5a827999,DX,SI,AX,BX,CX)
+	BODY(12,FN1,0x5a827999,CX,DX,SI,AX,BX)
+	BODY(16,FN1,0x5a827999,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+
+loop2:
+	BODY(0,FN24,0x6ed9eba1,AX,BX,CX,DX,SI)
+	BODY(4,FN24,0x6ed9eba1,SI,AX,BX,CX,DX)
+	BODY(8,FN24,0x6ed9eba1,DX,SI,AX,BX,CX)
+	BODY(12,FN24,0x6ed9eba1,CX,DX,SI,AX,BX)
+	BODY(16,FN24,0x6ed9eba1,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+	CMPL BP,w40+W40(SP)
+	JCS loop2
+
+loop3:
+	BODY(0,FN3,0x8f1bbcdc,AX,BX,CX,DX,SI)
+	BODY(4,FN3,0x8f1bbcdc,SI,AX,BX,CX,DX)
+	BODY(8,FN3,0x8f1bbcdc,DX,SI,AX,BX,CX)
+	BODY(12,FN3,0x8f1bbcdc,CX,DX,SI,AX,BX)
+	BODY(16,FN3,0x8f1bbcdc,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+	CMPL BP,w60+W60(SP)
+	JCS loop3
+
+loop4:
+	BODY(0,FN24,0xca62c1d6,AX,BX,CX,DX,SI)
+	BODY(4,FN24,0xca62c1d6,SI,AX,BX,CX,DX)
+	BODY(8,FN24,0xca62c1d6,DX,SI,AX,BX,CX)
+	BODY(12,FN24,0xca62c1d6,CX,DX,SI,AX,BX)
+	BODY(16,FN24,0xca62c1d6,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+	CMPL BP,w80+W80(SP)
+	JCS loop4
+
+	MOVL state+STATE(FP),DI
+	ADDL AX,0(DI)
+	ADDL BX,4(DI)
+	ADDL CX,8(DI)
+	ADDL DX,12(DI)
+	ADDL SI,16(DI)
+
+	MOVL edata+EDATA(SP),DI
+	CMPL data+DATA(FP),DI
+	JCS mainloop
+
+	RET
+	END
--- /dev/null
+++ b/libsec/Inferno-mips/md5block.s
@@ -1,0 +1,305 @@
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+
+	/* round 1 */
+	DATA	md5tab<>+( 0*4)(SB)/4,$0xd76aa478	
+	DATA	md5tab<>+( 1*4)(SB)/4,$0xe8c7b756	
+	DATA	md5tab<>+( 2*4)(SB)/4,$0x242070db	
+	DATA	md5tab<>+( 3*4)(SB)/4,$0xc1bdceee	
+	DATA	md5tab<>+( 4*4)(SB)/4,$0xf57c0faf	
+	DATA	md5tab<>+( 5*4)(SB)/4,$0x4787c62a	
+	DATA	md5tab<>+( 6*4)(SB)/4,$0xa8304613	
+	DATA	md5tab<>+( 7*4)(SB)/4,$0xfd469501	
+	DATA	md5tab<>+( 8*4)(SB)/4,$0x698098d8	
+	DATA	md5tab<>+( 9*4)(SB)/4,$0x8b44f7af	
+	DATA	md5tab<>+(10*4)(SB)/4,$0xffff5bb1	
+	DATA	md5tab<>+(11*4)(SB)/4,$0x895cd7be	
+	DATA	md5tab<>+(12*4)(SB)/4,$0x6b901122	
+	DATA	md5tab<>+(13*4)(SB)/4,$0xfd987193	
+	DATA	md5tab<>+(14*4)(SB)/4,$0xa679438e	
+	DATA	md5tab<>+(15*4)(SB)/4,$0x49b40821
+
+	/* round 2 */
+	DATA	md5tab<>+(16*4)(SB)/4,$0xf61e2562	
+	DATA	md5tab<>+(17*4)(SB)/4,$0xc040b340	
+	DATA	md5tab<>+(18*4)(SB)/4,$0x265e5a51	
+	DATA	md5tab<>+(19*4)(SB)/4,$0xe9b6c7aa	
+	DATA	md5tab<>+(20*4)(SB)/4,$0xd62f105d	
+	DATA	md5tab<>+(21*4)(SB)/4,$0x02441453	
+	DATA	md5tab<>+(22*4)(SB)/4,$0xd8a1e681	
+	DATA	md5tab<>+(23*4)(SB)/4,$0xe7d3fbc8	
+	DATA	md5tab<>+(24*4)(SB)/4,$0x21e1cde6	
+	DATA	md5tab<>+(25*4)(SB)/4,$0xc33707d6	
+	DATA	md5tab<>+(26*4)(SB)/4,$0xf4d50d87	
+	DATA	md5tab<>+(27*4)(SB)/4,$0x455a14ed	
+	DATA	md5tab<>+(28*4)(SB)/4,$0xa9e3e905	
+	DATA	md5tab<>+(29*4)(SB)/4,$0xfcefa3f8	
+	DATA	md5tab<>+(30*4)(SB)/4,$0x676f02d9	
+	DATA	md5tab<>+(31*4)(SB)/4,$0x8d2a4c8a
+
+	/* round 3 */
+	DATA	md5tab<>+(32*4)(SB)/4,$0xfffa3942	
+	DATA	md5tab<>+(33*4)(SB)/4,$0x8771f681	
+	DATA	md5tab<>+(34*4)(SB)/4,$0x6d9d6122	
+	DATA	md5tab<>+(35*4)(SB)/4,$0xfde5380c	
+	DATA	md5tab<>+(36*4)(SB)/4,$0xa4beea44	
+	DATA	md5tab<>+(37*4)(SB)/4,$0x4bdecfa9	
+	DATA	md5tab<>+(38*4)(SB)/4,$0xf6bb4b60	
+	DATA	md5tab<>+(39*4)(SB)/4,$0xbebfbc70	
+	DATA	md5tab<>+(40*4)(SB)/4,$0x289b7ec6	
+	DATA	md5tab<>+(41*4)(SB)/4,$0xeaa127fa	
+	DATA	md5tab<>+(42*4)(SB)/4,$0xd4ef3085	
+	DATA	md5tab<>+(43*4)(SB)/4,$0x04881d05	
+	DATA	md5tab<>+(44*4)(SB)/4,$0xd9d4d039	
+	DATA	md5tab<>+(45*4)(SB)/4,$0xe6db99e5	
+	DATA	md5tab<>+(46*4)(SB)/4,$0x1fa27cf8	
+	DATA	md5tab<>+(47*4)(SB)/4,$0xc4ac5665	
+
+	/* round 4 */
+	DATA	md5tab<>+(48*4)(SB)/4,$0xf4292244	
+	DATA	md5tab<>+(49*4)(SB)/4,$0x432aff97	
+	DATA	md5tab<>+(50*4)(SB)/4,$0xab9423a7	
+	DATA	md5tab<>+(51*4)(SB)/4,$0xfc93a039	
+	DATA	md5tab<>+(52*4)(SB)/4,$0x655b59c3	
+	DATA	md5tab<>+(53*4)(SB)/4,$0x8f0ccc92	
+	DATA	md5tab<>+(54*4)(SB)/4,$0xffeff47d	
+	DATA	md5tab<>+(55*4)(SB)/4,$0x85845dd1	
+	DATA	md5tab<>+(56*4)(SB)/4,$0x6fa87e4f	
+	DATA	md5tab<>+(57*4)(SB)/4,$0xfe2ce6e0	
+	DATA	md5tab<>+(58*4)(SB)/4,$0xa3014314	
+	DATA	md5tab<>+(59*4)(SB)/4,$0x4e0811a1	
+	DATA	md5tab<>+(60*4)(SB)/4,$0xf7537e82	
+	DATA	md5tab<>+(61*4)(SB)/4,$0xbd3af235	
+	DATA	md5tab<>+(62*4)(SB)/4,$0x2ad7d2bb	
+	DATA	md5tab<>+(63*4)(SB)/4,$0xeb86d391
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+#define	AREG		R5
+#define BREG		R6
+#define CREG		R7
+#define DREG		R8
+#define DATAREG		R1
+#define TABREG		R10
+#define STREG		R11
+#define XREG		R12
+#define ELOOPREG	R13
+#define EDREG		R14
+#define IREG		R15
+
+#define TMP1		R9
+#define TMP2		R2
+#define TMP3		R3
+#define TMP4		R4
+
+/*
+ * decode little endian data into x[off], then the body
+ * bodies have this form:
+ *	a += FN(B,C,D);
+ *	a += x[off] + t[off];
+ *	a = (a << S11) | (a >> (32 - S11));
+ *	a += b;
+ */
+#define BODY1(off,FN,SH,A,B,C,D)\
+	MOVBU off(DATAREG),TMP2;\
+	MOVBU (off+1)(DATAREG),TMP3;\
+	MOVBU (off+2)(DATAREG),TMP1;\
+	MOVBU (off+3)(DATAREG),TMP4;\
+	SLL $8,TMP3;\
+	OR TMP3,TMP2;\
+	SLL $16,TMP1;\
+	OR TMP1,TMP2;\
+	SLL $24,TMP4;\
+	OR TMP4,TMP2;\
+	MOVW off(TABREG),TMP3;\
+	FN(B,C,D)\
+	ADDU TMP1,A;\
+	MOVW TMP2,off(XREG);\
+	ADDU TMP2,A;\
+	ADDU TMP3,A;\
+	SLL $SH,A,TMP1;\
+	SRL $(32-SH),A;\
+	OR TMP1,A;\
+	ADDU B,A;\
+
+#define BODY(off,inc,FN,SH,A,B,C,D)\
+	MOVW off(TABREG),TMP3;\
+	ADDU XREG,IREG,TMP4;\
+	MOVW (TMP4),TMP2;\
+	ADDU $(inc*4),IREG;\
+	AND $63,IREG;\
+	FN(B,C,D)\
+	ADDU TMP1,A;\
+	ADDU TMP2,A;\
+	ADDU TMP3,A;\
+	SLL $SH,A,TMP1;\
+	SRL $(32-SH),A;\
+	OR  TMP1,A;\
+	ADDU B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+	XOR C,D,TMP1;\
+	AND B,TMP1;\
+	XOR D,TMP1;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+	XOR B,C,TMP1;\
+	AND D,TMP1;\
+	XOR C,TMP1;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+	XOR B,C,TMP1;\
+	XOR D,TMP1;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+	XOR $-1,D,TMP1;\
+	OR B,TMP1;\
+	XOR C,TMP1;\
+
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+#define XOFF	(-4-16*4)
+
+	TEXT	_md5block+0(SB),$68
+
+	MOVW	len+LEN(FP),TMP1
+	ADDU	DATAREG,TMP1,EDREG
+	MOVW	state+STATE(FP),STREG
+
+	MOVW 0(STREG),AREG
+	MOVW 4(STREG),BREG
+	MOVW 8(STREG),CREG
+	MOVW 12(STREG),DREG
+
+mainloop:
+
+	MOVW $md5tab<>+0(SB),TABREG
+	ADDU $(16*4),DATAREG,ELOOPREG
+	MOVW $x+XOFF(SP),XREG
+
+loop1:
+	BODY1(0,FN1,S11,AREG,BREG,CREG,DREG)
+	BODY1(4,FN1,S12,DREG,AREG,BREG,CREG)
+	BODY1(8,FN1,S13,CREG,DREG,AREG,BREG)
+	BODY1(12,FN1,S14,BREG,CREG,DREG,AREG)
+
+	ADDU $16,DATAREG
+	ADDU $16,TABREG
+	ADDU $16,XREG
+
+	BNE DATAREG,ELOOPREG,loop1
+
+
+	MOVW $x+XOFF(SP),XREG
+	MOVW $(1*4),IREG
+	MOVW $(1*4),ELOOPREG
+loop2:
+	BODY(0,5,FN2,S21,AREG,BREG,CREG,DREG)
+	BODY(4,5,FN2,S22,DREG,AREG,BREG,CREG)
+	BODY(8,5,FN2,S23,CREG,DREG,AREG,BREG)
+	BODY(12,5,FN2,S24,BREG,CREG,DREG,AREG)
+
+	ADDU $16,TABREG
+
+	BNE IREG,ELOOPREG,loop2
+
+
+	MOVW $(5*4),IREG
+	MOVW $(5*4),ELOOPREG
+loop3:
+	BODY(0,3,FN3,S31,AREG,BREG,CREG,DREG)
+	BODY(4,3,FN3,S32,DREG,AREG,BREG,CREG)
+	BODY(8,3,FN3,S33,CREG,DREG,AREG,BREG)
+	BODY(12,3,FN3,S34,BREG,CREG,DREG,AREG)
+
+	ADDU $16,TABREG
+
+	BNE IREG,ELOOPREG,loop3
+
+
+	MOVW $0,IREG
+loop4:
+	BODY(0,7,FN4,S41,AREG,BREG,CREG,DREG)
+	BODY(4,7,FN4,S42,DREG,AREG,BREG,CREG)
+	BODY(8,7,FN4,S43,CREG,DREG,AREG,BREG)
+	BODY(12,7,FN4,S44,BREG,CREG,DREG,AREG)
+
+	ADDU $16,TABREG
+
+	BNE IREG,R0,loop4
+
+	MOVW 0(STREG),TMP1
+	MOVW 4(STREG),TMP2
+	MOVW 8(STREG),TMP3
+	MOVW 12(STREG),TMP4
+	ADDU TMP1,AREG
+	ADDU TMP2,BREG
+	ADDU TMP3,CREG
+	ADDU TMP4,DREG
+	MOVW AREG,0(STREG)
+	MOVW BREG,4(STREG)
+	MOVW CREG,8(STREG)
+	MOVW DREG,12(STREG)
+
+	BNE DATAREG,EDREG,mainloop
+
+	RET
+
+	GLOBL	md5tab<>+0(SB),$256
+
+	END
--- /dev/null
+++ b/libsec/Inferno-mips/mkfile
@@ -1,0 +1,16 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+	md5block\
+	sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Inferno-mips/sha1block.s
@@ -1,0 +1,220 @@
+	TEXT	_sha1block+0(SB),$328
+
+/*
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BODYX(off,FN,V,A,B,C,D,E)\
+	FN(B,C,D)\
+	ADDU TMP1,E;\
+	ADDU V,E;\
+	MOVW TMP2,off(WREG);\
+	ADDU TMP2,E;\
+	SLL $5,A,TMP3;\
+	SRL $27,A,TMP4;\
+	OR TMP3,TMP4;\
+	ADDU TMP4,E;\
+	SLL $30,B,TMP4;\
+	SRL $2,B;\
+	OR TMP4,B
+
+/*
+ * x = data[i]
+ * BODYX
+ */
+#define BODY1(off,FN,V,A,B,C,D,E)\
+	MOVBU off(DATAREG),TMP2;\
+	MOVBU (off+1)(DATAREG),TMP3;\
+	MOVBU (off+2)(DATAREG),TMP1;\
+	MOVBU (off+3)(DATAREG),TMP4;\
+	SLL $24,TMP2;\
+	SLL $16,TMP3;\
+	OR TMP3,TMP2;\
+	SLL $8,TMP1;\
+	OR TMP1,TMP2;\
+	OR TMP4,TMP2;\
+	BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * x = (wp[off-3] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * BODYX
+ */
+#define BODY(off,FN,V,A,B,C,D,E)\
+	MOVW (off-64)(WREG),TMP1;\
+	MOVW (off-56)(WREG),TMP2;\
+	MOVW (off-32)(WREG),TMP3;\
+	MOVW (off-12)(WREG),TMP4;\
+	XOR TMP1,TMP2;\
+	XOR TMP3,TMP2;\
+	XOR TMP4,TMP2;\
+	SLL $1,TMP2,TMP1;\
+	SRL $31,TMP2;\
+	OR TMP1,TMP2;\
+	BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+	XOR C,D,TMP1;\
+	AND B,TMP1;\
+	XOR D,TMP1;
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+	XOR B,C,TMP1;\
+	XOR D,TMP1;
+
+/*
+ * fn3 = ((B ^ C) & (D ^ B)) ^ B
+ */
+#define FN3(B,C,D)\
+	XOR B,C,TMP1;\
+	XOR B,D,TMP4;\
+	AND TMP4,TMP1;\
+	XOR B,TMP1;
+
+/*
+ * stack offsets
+ * void vtSha1Block(ulong *STATE, uchar *DATA, int LEN)
+ */
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY	(-4-(80*4))
+
+#define	AREG		R5
+#define BREG		R6
+#define CREG		R7
+#define DREG		R8
+#define EREG		R9
+#define DATAREG		R1
+#define STREG		R11
+#define WREG		R12
+#define W15REG		R13
+#define W60REG		R14
+#define W40REG		R15
+#define W80REG		R16
+#define EDREG		R17
+#define VREG		R18
+
+#define TMP1		R10
+#define TMP2		R2
+#define TMP3		R3
+#define TMP4		R4
+#define TMP5		R19
+
+	MOVW len+LEN(FP),TMP1
+	MOVW state+STATE(FP),STREG
+	ADDU DATAREG,TMP1,EDREG
+
+	MOVW 0(STREG),AREG
+	MOVW 4(STREG),BREG
+	MOVW 8(STREG),CREG
+	MOVW 12(STREG),DREG
+	MOVW 16(STREG),EREG
+
+	MOVW $warray+WARRAY(SP),WREG
+	ADDU $(15*4),WREG,W15REG
+	ADDU $(40*4),WREG,W40REG
+	ADDU $(60*4),WREG,W60REG
+	ADDU $(80*4),WREG,W80REG
+
+mainloop:
+	MOVW $warray+WARRAY(SP),WREG
+
+	MOVW $0x5a827999,VREG
+loop1:
+	BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY1(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY1(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY1(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY1(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,DATAREG
+	ADDU $20,WREG
+	BNE WREG,W15REG,loop1
+
+	BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+	ADDU $4,DATAREG
+
+	BODY(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+
+	MOVW $0x6ed9eba1,VREG
+loop2:
+	BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+	BNE WREG,W40REG,loop2
+
+	MOVW $0x8f1bbcdc,VREG
+loop3:
+	BODY(0,FN3,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY(4,FN3,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN3,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN3,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN3,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+	BNE WREG,W60REG,loop3
+
+	MOVW $0xca62c1d6,VREG
+loop4:
+	BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+	BNE WREG,W80REG,loop4
+
+	MOVW 0(STREG),TMP1
+	MOVW 4(STREG),TMP2
+	MOVW 8(STREG),TMP3
+	MOVW 12(STREG),TMP4
+	MOVW 16(STREG),TMP5
+
+	ADDU TMP1,AREG
+	ADDU TMP2,BREG
+	ADDU TMP3,CREG
+	ADDU TMP4,DREG
+	ADDU TMP5,EREG
+
+	MOVW AREG,0(STREG)
+	MOVW BREG,4(STREG)
+	MOVW CREG,8(STREG)
+	MOVW DREG,12(STREG)
+	MOVW EREG,16(STREG)
+
+	BNE DATAREG,EDREG,mainloop
+
+	RET
+
+	END
--- /dev/null
+++ b/libsec/NOTICE
@@ -1,0 +1,4 @@
+Copyright © 2000-2007 Lucent Technologies Inc. and others.  All rights reserved.
+Revisions for use with Inferno © 2006 Vita Nuova Holdings Limited.
+
+This software is provided under the terms of the Lucent Public License, Version 1.02.
--- /dev/null
+++ b/libsec/Plan9-386/md5block.s
@@ -1,0 +1,220 @@
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+/*
+ * SI is data
+ *	a += FN(B,C,D);
+ *	a += x[sh] + t[sh];
+ *	a = (a << S11) | (a >> (32 - S11));
+ *	a += b;
+ */
+
+#define BODY1(off,V,FN,SH,A,B,C,D)\
+	FN(B,C,D)\
+	LEAL V(A)(DI*1),A;\
+	ADDL (off)(BP),A;\
+	ROLL $SH,A;\
+	ADDL B,A;\
+
+#define BODY(off,V,FN,SH,A,B,C,D)\
+	FN(B,C,D)\
+	LEAL V(A)(DI*1),A;\
+	ADDL (off)(BP),A;\
+	ROLL $SH,A;\
+	ADDL B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+	MOVL C,DI;\
+	XORL D,DI;\
+	ANDL B,DI;\
+	XORL D,DI;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	ANDL D,DI;\
+	XORL C,DI;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL D,DI;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+	MOVL D,DI;\
+	XORL $-1,DI;\
+	ORL B,DI;\
+	XORL C,DI;\
+
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+#define EDATA	(-4)
+
+	TEXT	_md5block+0(SB),$4
+
+	MOVL	data+DATA(FP),AX
+	ADDL	len+LEN(FP),AX
+	MOVL	AX,edata+EDATA(SP)
+
+	MOVL data+DATA(FP),BP
+
+mainloop:
+	MOVL state+STATE(FP),SI
+	MOVL (SI),AX
+	MOVL 4(SI),BX
+	MOVL 8(SI),CX
+	MOVL 12(SI),DX
+
+	BODY1( 0*4,0xd76aa478,FN1,S11,AX,BX,CX,DX)
+	BODY1( 1*4,0xe8c7b756,FN1,S12,DX,AX,BX,CX)
+	BODY1( 2*4,0x242070db,FN1,S13,CX,DX,AX,BX)
+	BODY1( 3*4,0xc1bdceee,FN1,S14,BX,CX,DX,AX)
+
+	BODY1( 4*4,0xf57c0faf,FN1,S11,AX,BX,CX,DX)
+	BODY1( 5*4,0x4787c62a,FN1,S12,DX,AX,BX,CX)
+	BODY1( 6*4,0xa8304613,FN1,S13,CX,DX,AX,BX)
+	BODY1( 7*4,0xfd469501,FN1,S14,BX,CX,DX,AX)
+
+	BODY1( 8*4,0x698098d8,FN1,S11,AX,BX,CX,DX)
+	BODY1( 9*4,0x8b44f7af,FN1,S12,DX,AX,BX,CX)
+	BODY1(10*4,0xffff5bb1,FN1,S13,CX,DX,AX,BX)
+	BODY1(11*4,0x895cd7be,FN1,S14,BX,CX,DX,AX)
+
+	BODY1(12*4,0x6b901122,FN1,S11,AX,BX,CX,DX)
+	BODY1(13*4,0xfd987193,FN1,S12,DX,AX,BX,CX)
+	BODY1(14*4,0xa679438e,FN1,S13,CX,DX,AX,BX)
+	BODY1(15*4,0x49b40821,FN1,S14,BX,CX,DX,AX)
+
+
+	BODY( 1*4,0xf61e2562,FN2,S21,AX,BX,CX,DX)
+	BODY( 6*4,0xc040b340,FN2,S22,DX,AX,BX,CX)
+	BODY(11*4,0x265e5a51,FN2,S23,CX,DX,AX,BX)
+	BODY( 0*4,0xe9b6c7aa,FN2,S24,BX,CX,DX,AX)
+
+	BODY( 5*4,0xd62f105d,FN2,S21,AX,BX,CX,DX)
+	BODY(10*4,0x02441453,FN2,S22,DX,AX,BX,CX)
+	BODY(15*4,0xd8a1e681,FN2,S23,CX,DX,AX,BX)
+	BODY( 4*4,0xe7d3fbc8,FN2,S24,BX,CX,DX,AX)
+
+	BODY( 9*4,0x21e1cde6,FN2,S21,AX,BX,CX,DX)
+	BODY(14*4,0xc33707d6,FN2,S22,DX,AX,BX,CX)
+	BODY( 3*4,0xf4d50d87,FN2,S23,CX,DX,AX,BX)
+	BODY( 8*4,0x455a14ed,FN2,S24,BX,CX,DX,AX)
+
+	BODY(13*4,0xa9e3e905,FN2,S21,AX,BX,CX,DX)
+	BODY( 2*4,0xfcefa3f8,FN2,S22,DX,AX,BX,CX)
+	BODY( 7*4,0x676f02d9,FN2,S23,CX,DX,AX,BX)
+	BODY(12*4,0x8d2a4c8a,FN2,S24,BX,CX,DX,AX)
+
+
+	BODY( 5*4,0xfffa3942,FN3,S31,AX,BX,CX,DX)
+	BODY( 8*4,0x8771f681,FN3,S32,DX,AX,BX,CX)
+	BODY(11*4,0x6d9d6122,FN3,S33,CX,DX,AX,BX)
+	BODY(14*4,0xfde5380c,FN3,S34,BX,CX,DX,AX)
+
+	BODY( 1*4,0xa4beea44,FN3,S31,AX,BX,CX,DX)
+	BODY( 4*4,0x4bdecfa9,FN3,S32,DX,AX,BX,CX)
+	BODY( 7*4,0xf6bb4b60,FN3,S33,CX,DX,AX,BX)
+	BODY(10*4,0xbebfbc70,FN3,S34,BX,CX,DX,AX)
+
+	BODY(13*4,0x289b7ec6,FN3,S31,AX,BX,CX,DX)
+	BODY( 0*4,0xeaa127fa,FN3,S32,DX,AX,BX,CX)
+	BODY( 3*4,0xd4ef3085,FN3,S33,CX,DX,AX,BX)
+	BODY( 6*4,0x04881d05,FN3,S34,BX,CX,DX,AX)
+
+	BODY( 9*4,0xd9d4d039,FN3,S31,AX,BX,CX,DX)
+	BODY(12*4,0xe6db99e5,FN3,S32,DX,AX,BX,CX)
+	BODY(15*4,0x1fa27cf8,FN3,S33,CX,DX,AX,BX)
+	BODY( 2*4,0xc4ac5665,FN3,S34,BX,CX,DX,AX)
+
+
+	BODY( 0*4,0xf4292244,FN4,S41,AX,BX,CX,DX)
+	BODY( 7*4,0x432aff97,FN4,S42,DX,AX,BX,CX)
+	BODY(14*4,0xab9423a7,FN4,S43,CX,DX,AX,BX)
+	BODY( 5*4,0xfc93a039,FN4,S44,BX,CX,DX,AX)
+
+	BODY(12*4,0x655b59c3,FN4,S41,AX,BX,CX,DX)
+	BODY( 3*4,0x8f0ccc92,FN4,S42,DX,AX,BX,CX)
+	BODY(10*4,0xffeff47d,FN4,S43,CX,DX,AX,BX)
+	BODY( 1*4,0x85845dd1,FN4,S44,BX,CX,DX,AX)
+
+	BODY( 8*4,0x6fa87e4f,FN4,S41,AX,BX,CX,DX)
+	BODY(15*4,0xfe2ce6e0,FN4,S42,DX,AX,BX,CX)
+	BODY( 6*4,0xa3014314,FN4,S43,CX,DX,AX,BX)
+	BODY(13*4,0x4e0811a1,FN4,S44,BX,CX,DX,AX)
+
+	BODY( 4*4,0xf7537e82,FN4,S41,AX,BX,CX,DX)
+	BODY(11*4,0xbd3af235,FN4,S42,DX,AX,BX,CX)
+	BODY( 2*4,0x2ad7d2bb,FN4,S43,CX,DX,AX,BX)
+	BODY( 9*4,0xeb86d391,FN4,S44,BX,CX,DX,AX)
+
+	ADDL $(16*4),BP
+	MOVL state+STATE(FP),DI
+	ADDL AX,0(DI)
+	ADDL BX,4(DI)
+	ADDL CX,8(DI)
+	ADDL DX,12(DI)
+
+	MOVL edata+EDATA(SP),DI
+	CMPL BP,DI
+	JCS mainloop
+
+	RET
+
+	END
--- /dev/null
+++ b/libsec/Plan9-386/mkfile
@@ -1,0 +1,16 @@
+objtype=386
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+	md5block\
+	sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Plan9-386/sha1block.s
@@ -1,0 +1,195 @@
+	TEXT	_sha1block+0(SB),$352
+
+/* x = (wp[off-f] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BSWAPDI	BYTE $0x0f; BYTE $0xcf;
+
+#define BODY(off,FN,V,A,B,C,D,E)\
+	MOVL (off-64)(BP),DI;\
+	XORL (off-56)(BP),DI;\
+	XORL (off-32)(BP),DI;\
+	XORL (off-12)(BP),DI;\
+	ROLL $1,DI;\
+	MOVL DI,off(BP);\
+	LEAL V(DI)(E*1),E;\
+	MOVL A,DI;\
+	ROLL $5,DI;\
+	ADDL DI,E;\
+	FN(B,C,D)\
+	ADDL DI,E;\
+	RORL $2,B;\
+
+#define BODY0(off,FN,V,A,B,C,D,E)\
+	MOVL off(BX),DI;\
+	BSWAPDI;\
+	MOVL DI,off(BP);\
+	LEAL V(DI)(E*1),E;\
+	MOVL A,DI;\
+	ROLL $5,DI;\
+	ADDL DI,E;\
+	FN(B,C,D)\
+	ADDL DI,E;\
+	RORL $2,B;\
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+	MOVL C,DI;\
+	XORL D,DI;\
+	ANDL B,DI;\
+	XORL D,DI;\
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL D,DI;\
+
+/*
+ * fn3 = ((B ^ C) & (D ^= B)) ^ B
+ * D ^= B to restore D
+ */
+#define FN3(B,C,D)\
+	MOVL B,DI;\
+	XORL C,DI;\
+	XORL B,D;\
+	ANDL D,DI;\
+	XORL B,DI;\
+	XORL B,D;\
+
+/*
+ * stack offsets
+ * void sha1block(uchar *DATA, int LEN, ulong *STATE)
+ */
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY	(-4-(80*4))
+#define TMP1	(-8-(80*4))
+#define TMP2	(-12-(80*4))
+#define W15	(-16-(80*4))
+#define W40	(-20-(80*4))
+#define W60	(-24-(80*4))
+#define W80	(-28-(80*4))
+#define EDATA	(-32-(80*4))
+
+	MOVL data+DATA(FP),AX
+	ADDL len+LEN(FP),AX
+	MOVL AX,edata+EDATA(SP)
+
+	LEAL aw15+(WARRAY+15*4)(SP),DI
+	MOVL DI,w15+W15(SP)
+	LEAL aw40+(WARRAY+40*4)(SP),DX
+	MOVL DX,w40+W40(SP)
+	LEAL aw60+(WARRAY+60*4)(SP),CX
+	MOVL CX,w60+W60(SP)
+	LEAL aw80+(WARRAY+80*4)(SP),DI
+	MOVL DI,w80+W80(SP)
+
+mainloop:
+	LEAL warray+WARRAY(SP),BP
+
+	MOVL state+STATE(FP),DI
+	MOVL (DI),AX
+	MOVL 4(DI),BX
+	MOVL BX,tmp1+TMP1(SP)
+	MOVL 8(DI),CX
+	MOVL 12(DI),DX
+	MOVL 16(DI),SI
+
+	MOVL data+DATA(FP),BX
+
+loop1:
+	BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+	MOVL SI,tmp2+TMP2(SP)
+	BODY0(4,FN1,0x5a827999,SI,AX,tmp1+TMP1(SP),CX,DX)
+	MOVL tmp1+TMP1(SP),SI
+	BODY0(8,FN1,0x5a827999,DX,tmp2+TMP2(SP),AX,SI,CX)
+	BODY0(12,FN1,0x5a827999,CX,DX,tmp2+TMP2(SP),AX,SI)
+	MOVL SI,tmp1+TMP1(SP)
+	BODY0(16,FN1,0x5a827999,SI,CX,DX,tmp2+TMP2(SP),AX)
+	MOVL tmp2+TMP2(SP),SI
+
+	ADDL $20,BX
+	ADDL $20,BP
+	CMPL BP,w15+W15(SP)
+	JCS loop1
+
+	BODY0(0,FN1,0x5a827999,AX,tmp1+TMP1(SP),CX,DX,SI)
+	ADDL $4,BX
+	MOVL BX,data+DATA(FP)
+	MOVL tmp1+TMP1(SP),BX
+
+	BODY(4,FN1,0x5a827999,SI,AX,BX,CX,DX)
+	BODY(8,FN1,0x5a827999,DX,SI,AX,BX,CX)
+	BODY(12,FN1,0x5a827999,CX,DX,SI,AX,BX)
+	BODY(16,FN1,0x5a827999,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+
+loop2:
+	BODY(0,FN24,0x6ed9eba1,AX,BX,CX,DX,SI)
+	BODY(4,FN24,0x6ed9eba1,SI,AX,BX,CX,DX)
+	BODY(8,FN24,0x6ed9eba1,DX,SI,AX,BX,CX)
+	BODY(12,FN24,0x6ed9eba1,CX,DX,SI,AX,BX)
+	BODY(16,FN24,0x6ed9eba1,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+	CMPL BP,w40+W40(SP)
+	JCS loop2
+
+loop3:
+	BODY(0,FN3,0x8f1bbcdc,AX,BX,CX,DX,SI)
+	BODY(4,FN3,0x8f1bbcdc,SI,AX,BX,CX,DX)
+	BODY(8,FN3,0x8f1bbcdc,DX,SI,AX,BX,CX)
+	BODY(12,FN3,0x8f1bbcdc,CX,DX,SI,AX,BX)
+	BODY(16,FN3,0x8f1bbcdc,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+	CMPL BP,w60+W60(SP)
+	JCS loop3
+
+loop4:
+	BODY(0,FN24,0xca62c1d6,AX,BX,CX,DX,SI)
+	BODY(4,FN24,0xca62c1d6,SI,AX,BX,CX,DX)
+	BODY(8,FN24,0xca62c1d6,DX,SI,AX,BX,CX)
+	BODY(12,FN24,0xca62c1d6,CX,DX,SI,AX,BX)
+	BODY(16,FN24,0xca62c1d6,BX,CX,DX,SI,AX)
+
+	ADDL $20,BP
+	CMPL BP,w80+W80(SP)
+	JCS loop4
+
+	MOVL state+STATE(FP),DI
+	ADDL AX,0(DI)
+	ADDL BX,4(DI)
+	ADDL CX,8(DI)
+	ADDL DX,12(DI)
+	ADDL SI,16(DI)
+
+	MOVL edata+EDATA(SP),DI
+	CMPL data+DATA(FP),DI
+	JCS mainloop
+
+	RET
+	END
--- /dev/null
+++ b/libsec/Plan9-mips/md5block.s
@@ -1,0 +1,305 @@
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+
+	/* round 1 */
+	DATA	md5tab<>+( 0*4)(SB)/4,$0xd76aa478	
+	DATA	md5tab<>+( 1*4)(SB)/4,$0xe8c7b756	
+	DATA	md5tab<>+( 2*4)(SB)/4,$0x242070db	
+	DATA	md5tab<>+( 3*4)(SB)/4,$0xc1bdceee	
+	DATA	md5tab<>+( 4*4)(SB)/4,$0xf57c0faf	
+	DATA	md5tab<>+( 5*4)(SB)/4,$0x4787c62a	
+	DATA	md5tab<>+( 6*4)(SB)/4,$0xa8304613	
+	DATA	md5tab<>+( 7*4)(SB)/4,$0xfd469501	
+	DATA	md5tab<>+( 8*4)(SB)/4,$0x698098d8	
+	DATA	md5tab<>+( 9*4)(SB)/4,$0x8b44f7af	
+	DATA	md5tab<>+(10*4)(SB)/4,$0xffff5bb1	
+	DATA	md5tab<>+(11*4)(SB)/4,$0x895cd7be	
+	DATA	md5tab<>+(12*4)(SB)/4,$0x6b901122	
+	DATA	md5tab<>+(13*4)(SB)/4,$0xfd987193	
+	DATA	md5tab<>+(14*4)(SB)/4,$0xa679438e	
+	DATA	md5tab<>+(15*4)(SB)/4,$0x49b40821
+
+	/* round 2 */
+	DATA	md5tab<>+(16*4)(SB)/4,$0xf61e2562	
+	DATA	md5tab<>+(17*4)(SB)/4,$0xc040b340	
+	DATA	md5tab<>+(18*4)(SB)/4,$0x265e5a51	
+	DATA	md5tab<>+(19*4)(SB)/4,$0xe9b6c7aa	
+	DATA	md5tab<>+(20*4)(SB)/4,$0xd62f105d	
+	DATA	md5tab<>+(21*4)(SB)/4,$0x02441453	
+	DATA	md5tab<>+(22*4)(SB)/4,$0xd8a1e681	
+	DATA	md5tab<>+(23*4)(SB)/4,$0xe7d3fbc8	
+	DATA	md5tab<>+(24*4)(SB)/4,$0x21e1cde6	
+	DATA	md5tab<>+(25*4)(SB)/4,$0xc33707d6	
+	DATA	md5tab<>+(26*4)(SB)/4,$0xf4d50d87	
+	DATA	md5tab<>+(27*4)(SB)/4,$0x455a14ed	
+	DATA	md5tab<>+(28*4)(SB)/4,$0xa9e3e905	
+	DATA	md5tab<>+(29*4)(SB)/4,$0xfcefa3f8	
+	DATA	md5tab<>+(30*4)(SB)/4,$0x676f02d9	
+	DATA	md5tab<>+(31*4)(SB)/4,$0x8d2a4c8a
+
+	/* round 3 */
+	DATA	md5tab<>+(32*4)(SB)/4,$0xfffa3942	
+	DATA	md5tab<>+(33*4)(SB)/4,$0x8771f681	
+	DATA	md5tab<>+(34*4)(SB)/4,$0x6d9d6122	
+	DATA	md5tab<>+(35*4)(SB)/4,$0xfde5380c	
+	DATA	md5tab<>+(36*4)(SB)/4,$0xa4beea44	
+	DATA	md5tab<>+(37*4)(SB)/4,$0x4bdecfa9	
+	DATA	md5tab<>+(38*4)(SB)/4,$0xf6bb4b60	
+	DATA	md5tab<>+(39*4)(SB)/4,$0xbebfbc70	
+	DATA	md5tab<>+(40*4)(SB)/4,$0x289b7ec6	
+	DATA	md5tab<>+(41*4)(SB)/4,$0xeaa127fa	
+	DATA	md5tab<>+(42*4)(SB)/4,$0xd4ef3085	
+	DATA	md5tab<>+(43*4)(SB)/4,$0x04881d05	
+	DATA	md5tab<>+(44*4)(SB)/4,$0xd9d4d039	
+	DATA	md5tab<>+(45*4)(SB)/4,$0xe6db99e5	
+	DATA	md5tab<>+(46*4)(SB)/4,$0x1fa27cf8	
+	DATA	md5tab<>+(47*4)(SB)/4,$0xc4ac5665	
+
+	/* round 4 */
+	DATA	md5tab<>+(48*4)(SB)/4,$0xf4292244	
+	DATA	md5tab<>+(49*4)(SB)/4,$0x432aff97	
+	DATA	md5tab<>+(50*4)(SB)/4,$0xab9423a7	
+	DATA	md5tab<>+(51*4)(SB)/4,$0xfc93a039	
+	DATA	md5tab<>+(52*4)(SB)/4,$0x655b59c3	
+	DATA	md5tab<>+(53*4)(SB)/4,$0x8f0ccc92	
+	DATA	md5tab<>+(54*4)(SB)/4,$0xffeff47d	
+	DATA	md5tab<>+(55*4)(SB)/4,$0x85845dd1	
+	DATA	md5tab<>+(56*4)(SB)/4,$0x6fa87e4f	
+	DATA	md5tab<>+(57*4)(SB)/4,$0xfe2ce6e0	
+	DATA	md5tab<>+(58*4)(SB)/4,$0xa3014314	
+	DATA	md5tab<>+(59*4)(SB)/4,$0x4e0811a1	
+	DATA	md5tab<>+(60*4)(SB)/4,$0xf7537e82	
+	DATA	md5tab<>+(61*4)(SB)/4,$0xbd3af235	
+	DATA	md5tab<>+(62*4)(SB)/4,$0x2ad7d2bb	
+	DATA	md5tab<>+(63*4)(SB)/4,$0xeb86d391
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+#define	AREG		R5
+#define BREG		R6
+#define CREG		R7
+#define DREG		R8
+#define DATAREG		R1
+#define TABREG		R10
+#define STREG		R11
+#define XREG		R12
+#define ELOOPREG	R13
+#define EDREG		R14
+#define IREG		R15
+
+#define TMP1		R9
+#define TMP2		R2
+#define TMP3		R3
+#define TMP4		R4
+
+/*
+ * decode little endian data into x[off], then the body
+ * bodies have this form:
+ *	a += FN(B,C,D);
+ *	a += x[off] + t[off];
+ *	a = (a << S11) | (a >> (32 - S11));
+ *	a += b;
+ */
+#define BODY1(off,FN,SH,A,B,C,D)\
+	MOVBU off(DATAREG),TMP2;\
+	MOVBU (off+1)(DATAREG),TMP3;\
+	MOVBU (off+2)(DATAREG),TMP1;\
+	MOVBU (off+3)(DATAREG),TMP4;\
+	SLL $8,TMP3;\
+	OR TMP3,TMP2;\
+	SLL $16,TMP1;\
+	OR TMP1,TMP2;\
+	SLL $24,TMP4;\
+	OR TMP4,TMP2;\
+	MOVW off(TABREG),TMP3;\
+	FN(B,C,D)\
+	ADDU TMP1,A;\
+	MOVW TMP2,off(XREG);\
+	ADDU TMP2,A;\
+	ADDU TMP3,A;\
+	SLL $SH,A,TMP1;\
+	SRL $(32-SH),A;\
+	OR TMP1,A;\
+	ADDU B,A;\
+
+#define BODY(off,inc,FN,SH,A,B,C,D)\
+	MOVW off(TABREG),TMP3;\
+	ADDU XREG,IREG,TMP4;\
+	MOVW (TMP4),TMP2;\
+	ADDU $(inc*4),IREG;\
+	AND $63,IREG;\
+	FN(B,C,D)\
+	ADDU TMP1,A;\
+	ADDU TMP2,A;\
+	ADDU TMP3,A;\
+	SLL $SH,A,TMP1;\
+	SRL $(32-SH),A;\
+	OR  TMP1,A;\
+	ADDU B,A;\
+
+/*
+ * fn1 = ((c ^ d) & b) ^ d
+ */
+#define FN1(B,C,D)\
+	XOR C,D,TMP1;\
+	AND B,TMP1;\
+	XOR D,TMP1;\
+
+/*
+ * fn2 = ((b ^ c) & d) ^ c;
+ */
+#define FN2(B,C,D)\
+	XOR B,C,TMP1;\
+	AND D,TMP1;\
+	XOR C,TMP1;\
+
+/*
+ * fn3 = b ^ c ^ d;
+ */
+#define FN3(B,C,D)\
+	XOR B,C,TMP1;\
+	XOR D,TMP1;\
+
+/*
+ * fn4 = c ^ (b | ~d);
+ */
+#define FN4(B,C,D)\
+	XOR $-1,D,TMP1;\
+	OR B,TMP1;\
+	XOR C,TMP1;\
+
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+#define XOFF	(-4-16*4)
+
+	TEXT	_md5block+0(SB),$68
+
+	MOVW	len+LEN(FP),TMP1
+	ADDU	DATAREG,TMP1,EDREG
+	MOVW	state+STATE(FP),STREG
+
+	MOVW 0(STREG),AREG
+	MOVW 4(STREG),BREG
+	MOVW 8(STREG),CREG
+	MOVW 12(STREG),DREG
+
+mainloop:
+
+	MOVW $md5tab<>+0(SB),TABREG
+	ADDU $(16*4),DATAREG,ELOOPREG
+	MOVW $x+XOFF(SP),XREG
+
+loop1:
+	BODY1(0,FN1,S11,AREG,BREG,CREG,DREG)
+	BODY1(4,FN1,S12,DREG,AREG,BREG,CREG)
+	BODY1(8,FN1,S13,CREG,DREG,AREG,BREG)
+	BODY1(12,FN1,S14,BREG,CREG,DREG,AREG)
+
+	ADDU $16,DATAREG
+	ADDU $16,TABREG
+	ADDU $16,XREG
+
+	BNE DATAREG,ELOOPREG,loop1
+
+
+	MOVW $x+XOFF(SP),XREG
+	MOVW $(1*4),IREG
+	MOVW $(1*4),ELOOPREG
+loop2:
+	BODY(0,5,FN2,S21,AREG,BREG,CREG,DREG)
+	BODY(4,5,FN2,S22,DREG,AREG,BREG,CREG)
+	BODY(8,5,FN2,S23,CREG,DREG,AREG,BREG)
+	BODY(12,5,FN2,S24,BREG,CREG,DREG,AREG)
+
+	ADDU $16,TABREG
+
+	BNE IREG,ELOOPREG,loop2
+
+
+	MOVW $(5*4),IREG
+	MOVW $(5*4),ELOOPREG
+loop3:
+	BODY(0,3,FN3,S31,AREG,BREG,CREG,DREG)
+	BODY(4,3,FN3,S32,DREG,AREG,BREG,CREG)
+	BODY(8,3,FN3,S33,CREG,DREG,AREG,BREG)
+	BODY(12,3,FN3,S34,BREG,CREG,DREG,AREG)
+
+	ADDU $16,TABREG
+
+	BNE IREG,ELOOPREG,loop3
+
+
+	MOVW $0,IREG
+loop4:
+	BODY(0,7,FN4,S41,AREG,BREG,CREG,DREG)
+	BODY(4,7,FN4,S42,DREG,AREG,BREG,CREG)
+	BODY(8,7,FN4,S43,CREG,DREG,AREG,BREG)
+	BODY(12,7,FN4,S44,BREG,CREG,DREG,AREG)
+
+	ADDU $16,TABREG
+
+	BNE IREG,R0,loop4
+
+	MOVW 0(STREG),TMP1
+	MOVW 4(STREG),TMP2
+	MOVW 8(STREG),TMP3
+	MOVW 12(STREG),TMP4
+	ADDU TMP1,AREG
+	ADDU TMP2,BREG
+	ADDU TMP3,CREG
+	ADDU TMP4,DREG
+	MOVW AREG,0(STREG)
+	MOVW BREG,4(STREG)
+	MOVW CREG,8(STREG)
+	MOVW DREG,12(STREG)
+
+	BNE DATAREG,EDREG,mainloop
+
+	RET
+
+	GLOBL	md5tab<>+0(SB),$256
+
+	END
--- /dev/null
+++ b/libsec/Plan9-mips/mkfile
@@ -1,0 +1,16 @@
+objtype=mips
+OBJTYPE=$objtype
+<../../mkconfig
+
+LIB=libsec.a
+FILES=\
+	md5block\
+	sha1block\
+
+HFILES=$ROOT/include/libsec.h
+
+SFILES=${FILES:%=%.s}
+
+OFILES=${FILES:%=%.$O}
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/Plan9-mips/sha1block.s
@@ -1,0 +1,220 @@
+	TEXT	_sha1block+0(SB),$328
+
+/*
+ * wp[off] = x;
+ * x += A <<< 5;
+ * E += 0xca62c1d6 + x;
+ * x = FN(B,C,D);
+ * E += x;
+ * B >>> 2
+ */
+#define BODYX(off,FN,V,A,B,C,D,E)\
+	FN(B,C,D)\
+	ADDU TMP1,E;\
+	ADDU V,E;\
+	MOVW TMP2,off(WREG);\
+	ADDU TMP2,E;\
+	SLL $5,A,TMP3;\
+	SRL $27,A,TMP4;\
+	OR TMP3,TMP4;\
+	ADDU TMP4,E;\
+	SLL $30,B,TMP4;\
+	SRL $2,B;\
+	OR TMP4,B
+
+/*
+ * x = data[i]
+ * BODYX
+ */
+#define BODY1(off,FN,V,A,B,C,D,E)\
+	MOVBU off(DATAREG),TMP2;\
+	MOVBU (off+1)(DATAREG),TMP3;\
+	MOVBU (off+2)(DATAREG),TMP1;\
+	MOVBU (off+3)(DATAREG),TMP4;\
+	SLL $24,TMP2;\
+	SLL $16,TMP3;\
+	OR TMP3,TMP2;\
+	SLL $8,TMP1;\
+	OR TMP1,TMP2;\
+	OR TMP4,TMP2;\
+	BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * x = (wp[off-3] ^ wp[off-8] ^ wp[off-14] ^ wp[off-16]) <<< 1;
+ * BODYX
+ */
+#define BODY(off,FN,V,A,B,C,D,E)\
+	MOVW (off-64)(WREG),TMP1;\
+	MOVW (off-56)(WREG),TMP2;\
+	MOVW (off-32)(WREG),TMP3;\
+	MOVW (off-12)(WREG),TMP4;\
+	XOR TMP1,TMP2;\
+	XOR TMP3,TMP2;\
+	XOR TMP4,TMP2;\
+	SLL $1,TMP2,TMP1;\
+	SRL $31,TMP2;\
+	OR TMP1,TMP2;\
+	BODYX(off,FN,V,A,B,C,D,E)
+
+/*
+ * fn1 = (((C^D)&B)^D);
+ */
+#define FN1(B,C,D)\
+	XOR C,D,TMP1;\
+	AND B,TMP1;\
+	XOR D,TMP1;
+
+/*
+ * fn24 = B ^ C ^ D
+ */
+#define FN24(B,C,D)\
+	XOR B,C,TMP1;\
+	XOR D,TMP1;
+
+/*
+ * fn3 = ((B ^ C) & (D ^ B)) ^ B
+ */
+#define FN3(B,C,D)\
+	XOR B,C,TMP1;\
+	XOR B,D,TMP4;\
+	AND TMP4,TMP1;\
+	XOR B,TMP1;
+
+/*
+ * stack offsets
+ * void vtSha1Block(ulong *STATE, uchar *DATA, int LEN)
+ */
+#define	DATA	0
+#define	LEN	4
+#define	STATE	8
+
+/*
+ * stack offsets for locals
+ * ulong w[80];
+ * uchar *edata;
+ * ulong *w15, *w40, *w60, *w80;
+ * register local
+ * ulong *wp = BP
+ * ulong a = eax, b = ebx, c = ecx, d = edx, e = esi
+ * ulong tmp = edi
+ */
+#define WARRAY	(-4-(80*4))
+
+#define	AREG		R5
+#define BREG		R6
+#define CREG		R7
+#define DREG		R8
+#define EREG		R9
+#define DATAREG		R1
+#define STREG		R11
+#define WREG		R12
+#define W15REG		R13
+#define W60REG		R14
+#define W40REG		R15
+#define W80REG		R16
+#define EDREG		R17
+#define VREG		R18
+
+#define TMP1		R10
+#define TMP2		R2
+#define TMP3		R3
+#define TMP4		R4
+#define TMP5		R19
+
+	MOVW len+LEN(FP),TMP1
+	MOVW state+STATE(FP),STREG
+	ADDU DATAREG,TMP1,EDREG
+
+	MOVW 0(STREG),AREG
+	MOVW 4(STREG),BREG
+	MOVW 8(STREG),CREG
+	MOVW 12(STREG),DREG
+	MOVW 16(STREG),EREG
+
+	MOVW $warray+WARRAY(SP),WREG
+	ADDU $(15*4),WREG,W15REG
+	ADDU $(40*4),WREG,W40REG
+	ADDU $(60*4),WREG,W60REG
+	ADDU $(80*4),WREG,W80REG
+
+mainloop:
+	MOVW $warray+WARRAY(SP),WREG
+
+	MOVW $0x5a827999,VREG
+loop1:
+	BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY1(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY1(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY1(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY1(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,DATAREG
+	ADDU $20,WREG
+	BNE WREG,W15REG,loop1
+
+	BODY1(0,FN1,VREG,AREG,BREG,CREG,DREG,EREG)
+	ADDU $4,DATAREG
+
+	BODY(4,FN1,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN1,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN1,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN1,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+
+	MOVW $0x6ed9eba1,VREG
+loop2:
+	BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+	BNE WREG,W40REG,loop2
+
+	MOVW $0x8f1bbcdc,VREG
+loop3:
+	BODY(0,FN3,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY(4,FN3,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN3,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN3,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN3,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+	BNE WREG,W60REG,loop3
+
+	MOVW $0xca62c1d6,VREG
+loop4:
+	BODY(0,FN24,VREG,AREG,BREG,CREG,DREG,EREG)
+	BODY(4,FN24,VREG,EREG,AREG,BREG,CREG,DREG)
+	BODY(8,FN24,VREG,DREG,EREG,AREG,BREG,CREG)
+	BODY(12,FN24,VREG,CREG,DREG,EREG,AREG,BREG)
+	BODY(16,FN24,VREG,BREG,CREG,DREG,EREG,AREG)
+
+	ADDU $20,WREG
+	BNE WREG,W80REG,loop4
+
+	MOVW 0(STREG),TMP1
+	MOVW 4(STREG),TMP2
+	MOVW 8(STREG),TMP3
+	MOVW 12(STREG),TMP4
+	MOVW 16(STREG),TMP5
+
+	ADDU TMP1,AREG
+	ADDU TMP2,BREG
+	ADDU TMP3,CREG
+	ADDU TMP4,DREG
+	ADDU TMP5,EREG
+
+	MOVW AREG,0(STREG)
+	MOVW BREG,4(STREG)
+	MOVW CREG,8(STREG)
+	MOVW DREG,12(STREG)
+	MOVW EREG,16(STREG)
+
+	BNE DATAREG,EDREG,mainloop
+
+	RET
+
+	END
--- /dev/null
+++ b/libsec/mkfile
@@ -1,0 +1,6 @@
+<../mkconfig
+
+# TARGMODEL not SYSTARG for now
+DIRS=port $TARGMODEL-$OBJTYPE
+
+<$ROOT/mkfiles/mklibsubdirs
--- /dev/null
+++ b/libsec/port/aes.c
@@ -1,0 +1,1543 @@
+/*
+ * this code is derived from the following source,
+ * and modified to fit into the plan 9 libsec interface.
+ * most of the changes are confined to the top section,
+ * with the exception of converting Te4 and Td4 into u8 rather than u32 arrays.
+ *
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "os.h"
+#include <libsec.h>
+
+typedef uchar	u8;
+typedef u32int	u32;
+#define FULL_UNROLL
+
+static const u32 Td0[256];
+static const u32 Td1[256];
+static const u32 Td2[256];
+static const u32 Td3[256];
+static const u8  Te4[256];
+
+static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits);
+static void	rijndaelEncrypt(const u32int rk[], int Nr, const uchar pt[16], uchar ct[16]);
+static void	rijndaelDecrypt(const u32int rk[], int Nr, const uchar ct[16], uchar pt[16]);
+
+void
+setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec)
+{
+	memset(s, 0, sizeof(*s));
+	if(keybytes > AESmaxkey)
+		keybytes = AESmaxkey;
+	memmove(s->key, key, keybytes);
+	s->keybytes = keybytes;
+	s->rounds = rijndaelKeySetup(s->ekey, s->dkey, s->key, keybytes * 8);
+	if(ivec != nil)
+		memmove(s->ivec, ivec, AESbsize);
+	if(keybytes==16 || keybytes==24 || keybytes==32)
+		s->setup = 0xcafebabe;
+	// else rijndaelKeySetup was invalid
+}
+
+// Define by analogy with desCBCencrypt;  AES modes are not standardized yet.
+// Because of the way that non-multiple-of-16 buffers are handled,
+// the decryptor must be fed buffers of the same size as the encryptor.
+void
+aesCBCencrypt(uchar *p, int len, AESstate *s)
+{
+	uchar *p2, *ip, *eip;
+	uchar q[AESbsize];
+
+	for(; len >= AESbsize; len -= AESbsize){
+		p2 = p;
+		ip = s->ivec;
+		for(eip = ip+AESbsize; ip < eip; )
+			*p2++ ^= *ip++;
+		rijndaelEncrypt(s->ekey, s->rounds, p, q);
+		memmove(s->ivec, q, AESbsize);
+		memmove(p, q, AESbsize);
+		p += AESbsize;
+	}
+
+	if(len > 0){
+		ip = s->ivec;
+		rijndaelEncrypt(s->ekey, s->rounds, ip, q);
+		memmove(s->ivec, q, AESbsize);
+		for(eip = ip+len; ip < eip; )
+			*p++ ^= *ip++;
+	}
+}
+
+void
+aesCBCdecrypt(uchar *p, int len, AESstate *s)
+{
+	uchar *ip, *eip, *tp;
+	uchar tmp[AESbsize], q[AESbsize];
+
+	for(; len >= AESbsize; len -= AESbsize){
+		memmove(tmp, p, AESbsize);
+		rijndaelDecrypt(s->dkey, s->rounds, p, q);
+		memmove(p, q, AESbsize);
+		tp = tmp;
+		ip = s->ivec;
+		for(eip = ip+AESbsize; ip < eip; ){
+			*p++ ^= *ip;
+			*ip++ = *tp++;
+		}
+	}
+
+	if(len > 0){
+		ip = s->ivec;
+		rijndaelEncrypt(s->ekey, s->rounds, ip, q);
+		memmove(s->ivec, q, AESbsize);
+		for(eip = ip+len; ip < eip; )
+			*p++ ^= *ip++;
+	}
+}
+
+/*
+ * this function has been changed for plan 9.
+ * Expand the cipher key into the encryption and decryption key schedules.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetup(u32 erk[/*4*(Nr + 1)*/], u32 drk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+	int Nr, i;
+
+	/* expand the cipher key: */
+	Nr = rijndaelKeySetupEnc(erk, cipherKey, keyBits);
+
+	/*
+	 * invert the order of the round keys and
+	 * apply the inverse MixColumn transform to all round keys but the first and the last
+	 */
+	drk[0       ] = erk[4*Nr    ]; 
+	drk[1       ] = erk[4*Nr + 1];
+	drk[2       ] = erk[4*Nr + 2]; 
+	drk[3       ] = erk[4*Nr + 3];
+	drk[4*Nr    ] = erk[0       ]; 
+	drk[4*Nr + 1] = erk[1       ];
+	drk[4*Nr + 2] = erk[2       ]; 
+	drk[4*Nr + 3] = erk[3       ];
+	erk += 4 * Nr;
+	for (i = 1; i < Nr; i++) {
+		drk += 4;
+		erk -= 4;
+		drk[0] =
+		    Td0[Te4[(erk[0] >> 24)       ]] ^
+		    Td1[Te4[(erk[0] >> 16) & 0xff]] ^
+		    Td2[Te4[(erk[0] >>  8) & 0xff]] ^
+		    Td3[Te4[(erk[0]      ) & 0xff]];
+		drk[1] =
+		    Td0[Te4[(erk[1] >> 24)       ]] ^
+		    Td1[Te4[(erk[1] >> 16) & 0xff]] ^
+		    Td2[Te4[(erk[1] >>  8) & 0xff]] ^
+		    Td3[Te4[(erk[1]      ) & 0xff]];
+		drk[2] =
+		    Td0[Te4[(erk[2] >> 24)       ]] ^
+		    Td1[Te4[(erk[2] >> 16) & 0xff]] ^
+		    Td2[Te4[(erk[2] >>  8) & 0xff]] ^
+		    Td3[Te4[(erk[2]      ) & 0xff]];
+		drk[3] =
+		    Td0[Te4[(erk[3] >> 24)       ]] ^
+		    Td1[Te4[(erk[3] >> 16) & 0xff]] ^
+		    Td2[Te4[(erk[3] >>  8) & 0xff]] ^
+		    Td3[Te4[(erk[3]      ) & 0xff]];
+	}
+	return Nr;
+}
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x]
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x]
+*/
+
+static const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u8 Te4[256] = {
+    0x63U, 0x7cU, 0x77U, 0x7bU,
+    0xf2U, 0x6bU, 0x6fU, 0xc5U,
+    0x30U, 0x01U, 0x67U, 0x2bU,
+    0xfeU, 0xd7U, 0xabU, 0x76U,
+    0xcaU, 0x82U, 0xc9U, 0x7dU,
+    0xfaU, 0x59U, 0x47U, 0xf0U,
+    0xadU, 0xd4U, 0xa2U, 0xafU,
+    0x9cU, 0xa4U, 0x72U, 0xc0U,
+    0xb7U, 0xfdU, 0x93U, 0x26U,
+    0x36U, 0x3fU, 0xf7U, 0xccU,
+    0x34U, 0xa5U, 0xe5U, 0xf1U,
+    0x71U, 0xd8U, 0x31U, 0x15U,
+    0x04U, 0xc7U, 0x23U, 0xc3U,
+    0x18U, 0x96U, 0x05U, 0x9aU,
+    0x07U, 0x12U, 0x80U, 0xe2U,
+    0xebU, 0x27U, 0xb2U, 0x75U,
+    0x09U, 0x83U, 0x2cU, 0x1aU,
+    0x1bU, 0x6eU, 0x5aU, 0xa0U,
+    0x52U, 0x3bU, 0xd6U, 0xb3U,
+    0x29U, 0xe3U, 0x2fU, 0x84U,
+    0x53U, 0xd1U, 0x00U, 0xedU,
+    0x20U, 0xfcU, 0xb1U, 0x5bU,
+    0x6aU, 0xcbU, 0xbeU, 0x39U,
+    0x4aU, 0x4cU, 0x58U, 0xcfU,
+    0xd0U, 0xefU, 0xaaU, 0xfbU,
+    0x43U, 0x4dU, 0x33U, 0x85U,
+    0x45U, 0xf9U, 0x02U, 0x7fU,
+    0x50U, 0x3cU, 0x9fU, 0xa8U,
+    0x51U, 0xa3U, 0x40U, 0x8fU,
+    0x92U, 0x9dU, 0x38U, 0xf5U,
+    0xbcU, 0xb6U, 0xdaU, 0x21U,
+    0x10U, 0xffU, 0xf3U, 0xd2U,
+    0xcdU, 0x0cU, 0x13U, 0xecU,
+    0x5fU, 0x97U, 0x44U, 0x17U,
+    0xc4U, 0xa7U, 0x7eU, 0x3dU,
+    0x64U, 0x5dU, 0x19U, 0x73U,
+    0x60U, 0x81U, 0x4fU, 0xdcU,
+    0x22U, 0x2aU, 0x90U, 0x88U,
+    0x46U, 0xeeU, 0xb8U, 0x14U,
+    0xdeU, 0x5eU, 0x0bU, 0xdbU,
+    0xe0U, 0x32U, 0x3aU, 0x0aU,
+    0x49U, 0x06U, 0x24U, 0x5cU,
+    0xc2U, 0xd3U, 0xacU, 0x62U,
+    0x91U, 0x95U, 0xe4U, 0x79U,
+    0xe7U, 0xc8U, 0x37U, 0x6dU,
+    0x8dU, 0xd5U, 0x4eU, 0xa9U,
+    0x6cU, 0x56U, 0xf4U, 0xeaU,
+    0x65U, 0x7aU, 0xaeU, 0x08U,
+    0xbaU, 0x78U, 0x25U, 0x2eU,
+    0x1cU, 0xa6U, 0xb4U, 0xc6U,
+    0xe8U, 0xddU, 0x74U, 0x1fU,
+    0x4bU, 0xbdU, 0x8bU, 0x8aU,
+    0x70U, 0x3eU, 0xb5U, 0x66U,
+    0x48U, 0x03U, 0xf6U, 0x0eU,
+    0x61U, 0x35U, 0x57U, 0xb9U,
+    0x86U, 0xc1U, 0x1dU, 0x9eU,
+    0xe1U, 0xf8U, 0x98U, 0x11U,
+    0x69U, 0xd9U, 0x8eU, 0x94U,
+    0x9bU, 0x1eU, 0x87U, 0xe9U,
+    0xceU, 0x55U, 0x28U, 0xdfU,
+    0x8cU, 0xa1U, 0x89U, 0x0dU,
+    0xbfU, 0xe6U, 0x42U, 0x68U,
+    0x41U, 0x99U, 0x2dU, 0x0fU,
+    0xb0U, 0x54U, 0xbbU, 0x16U,
+};
+static const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u8 Td4[256] = {
+    0x52U, 0x09U, 0x6aU, 0xd5U,
+    0x30U, 0x36U, 0xa5U, 0x38U,
+    0xbfU, 0x40U, 0xa3U, 0x9eU,
+    0x81U, 0xf3U, 0xd7U, 0xfbU,
+    0x7cU, 0xe3U, 0x39U, 0x82U,
+    0x9bU, 0x2fU, 0xffU, 0x87U,
+    0x34U, 0x8eU, 0x43U, 0x44U,
+    0xc4U, 0xdeU, 0xe9U, 0xcbU,
+    0x54U, 0x7bU, 0x94U, 0x32U,
+    0xa6U, 0xc2U, 0x23U, 0x3dU,
+    0xeeU, 0x4cU, 0x95U, 0x0bU,
+    0x42U, 0xfaU, 0xc3U, 0x4eU,
+    0x08U, 0x2eU, 0xa1U, 0x66U,
+    0x28U, 0xd9U, 0x24U, 0xb2U,
+    0x76U, 0x5bU, 0xa2U, 0x49U,
+    0x6dU, 0x8bU, 0xd1U, 0x25U,
+    0x72U, 0xf8U, 0xf6U, 0x64U,
+    0x86U, 0x68U, 0x98U, 0x16U,
+    0xd4U, 0xa4U, 0x5cU, 0xccU,
+    0x5dU, 0x65U, 0xb6U, 0x92U,
+    0x6cU, 0x70U, 0x48U, 0x50U,
+    0xfdU, 0xedU, 0xb9U, 0xdaU,
+    0x5eU, 0x15U, 0x46U, 0x57U,
+    0xa7U, 0x8dU, 0x9dU, 0x84U,
+    0x90U, 0xd8U, 0xabU, 0x00U,
+    0x8cU, 0xbcU, 0xd3U, 0x0aU,
+    0xf7U, 0xe4U, 0x58U, 0x05U,
+    0xb8U, 0xb3U, 0x45U, 0x06U,
+    0xd0U, 0x2cU, 0x1eU, 0x8fU,
+    0xcaU, 0x3fU, 0x0fU, 0x02U,
+    0xc1U, 0xafU, 0xbdU, 0x03U,
+    0x01U, 0x13U, 0x8aU, 0x6bU,
+    0x3aU, 0x91U, 0x11U, 0x41U,
+    0x4fU, 0x67U, 0xdcU, 0xeaU,
+    0x97U, 0xf2U, 0xcfU, 0xceU,
+    0xf0U, 0xb4U, 0xe6U, 0x73U,
+    0x96U, 0xacU, 0x74U, 0x22U,
+    0xe7U, 0xadU, 0x35U, 0x85U,
+    0xe2U, 0xf9U, 0x37U, 0xe8U,
+    0x1cU, 0x75U, 0xdfU, 0x6eU,
+    0x47U, 0xf1U, 0x1aU, 0x71U,
+    0x1dU, 0x29U, 0xc5U, 0x89U,
+    0x6fU, 0xb7U, 0x62U, 0x0eU,
+    0xaaU, 0x18U, 0xbeU, 0x1bU,
+    0xfcU, 0x56U, 0x3eU, 0x4bU,
+    0xc6U, 0xd2U, 0x79U, 0x20U,
+    0x9aU, 0xdbU, 0xc0U, 0xfeU,
+    0x78U, 0xcdU, 0x5aU, 0xf4U,
+    0x1fU, 0xddU, 0xa8U, 0x33U,
+    0x88U, 0x07U, 0xc7U, 0x31U,
+    0xb1U, 0x12U, 0x10U, 0x59U,
+    0x27U, 0x80U, 0xecU, 0x5fU,
+    0x60U, 0x51U, 0x7fU, 0xa9U,
+    0x19U, 0xb5U, 0x4aU, 0x0dU,
+    0x2dU, 0xe5U, 0x7aU, 0x9fU,
+    0x93U, 0xc9U, 0x9cU, 0xefU,
+    0xa0U, 0xe0U, 0x3bU, 0x4dU,
+    0xaeU, 0x2aU, 0xf5U, 0xb0U,
+    0xc8U, 0xebU, 0xbbU, 0x3cU,
+    0x83U, 0x53U, 0x99U, 0x61U,
+    0x17U, 0x2bU, 0x04U, 0x7eU,
+    0xbaU, 0x77U, 0xd6U, 0x26U,
+    0xe1U, 0x69U, 0x14U, 0x63U,
+    0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+static const u32 rcon[] = {
+	0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000,
+	0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+
+#ifdef _MSC_VER
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+#endif
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+   	int i = 0;
+	u32 temp;
+
+	rk[0] = GETU32(cipherKey     );
+	rk[1] = GETU32(cipherKey +  4);
+	rk[2] = GETU32(cipherKey +  8);
+	rk[3] = GETU32(cipherKey + 12);
+	if (keyBits == 128) {
+		for (;;) {
+			temp  = rk[3];
+			rk[4] = rk[0] ^
+				(Te4[(temp >> 16) & 0xff] << 24) ^
+				(Te4[(temp >>  8) & 0xff] << 16) ^
+				(Te4[(temp      ) & 0xff] <<  8) ^
+				(Te4[(temp >> 24)       ]      ) ^
+				rcon[i];
+			rk[5] = rk[1] ^ rk[4];
+			rk[6] = rk[2] ^ rk[5];
+			rk[7] = rk[3] ^ rk[6];
+			if (++i == 10) {
+				return 10;
+			}
+			rk += 4;
+		}
+	}
+	rk[4] = GETU32(cipherKey + 16);
+	rk[5] = GETU32(cipherKey + 20);
+	if (keyBits == 192) {
+		for (;;) {
+			temp = rk[ 5];
+			rk[ 6] = rk[ 0] ^
+				(Te4[(temp >> 16) & 0xff] << 24) ^
+				(Te4[(temp >>  8) & 0xff] << 16) ^
+				(Te4[(temp      ) & 0xff] <<  8) ^
+				(Te4[(temp >> 24)       ]      ) ^
+				rcon[i];
+			rk[ 7] = rk[ 1] ^ rk[ 6];
+			rk[ 8] = rk[ 2] ^ rk[ 7];
+			rk[ 9] = rk[ 3] ^ rk[ 8];
+			if (++i == 8) {
+				return 12;
+			}
+			rk[10] = rk[ 4] ^ rk[ 9];
+			rk[11] = rk[ 5] ^ rk[10];
+			rk += 6;
+		}
+	}
+	rk[6] = GETU32(cipherKey + 24);
+	rk[7] = GETU32(cipherKey + 28);
+	if (keyBits == 256) {
+        for (;;) {
+        	temp = rk[ 7];
+        	rk[ 8] = rk[ 0] ^
+        		(Te4[(temp >> 16) & 0xff] << 24) ^
+        		(Te4[(temp >>  8) & 0xff] << 16) ^
+        		(Te4[(temp      ) & 0xff] <<  8) ^
+        		(Te4[(temp >> 24)       ]      ) ^
+        		rcon[i];
+        	rk[ 9] = rk[ 1] ^ rk[ 8];
+        	rk[10] = rk[ 2] ^ rk[ 9];
+        	rk[11] = rk[ 3] ^ rk[10];
+			if (++i == 7) {
+				return 14;
+			}
+        	temp = rk[11];
+        	rk[12] = rk[ 4] ^
+        		(Te4[(temp >> 24)       ] << 24) ^
+        		(Te4[(temp >> 16) & 0xff] << 16) ^
+        		(Te4[(temp >>  8) & 0xff] <<  8) ^
+        		(Te4[(temp      ) & 0xff]      );
+        	rk[13] = rk[ 5] ^ rk[12];
+        	rk[14] = rk[ 6] ^ rk[13];
+        	rk[15] = rk[ 7] ^ rk[14];
+
+			rk += 8;
+        }
+	}
+	return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits) {
+	int Nr, i, j;
+	u32 temp;
+
+	/* expand the cipher key: */
+	Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+	/* invert the order of the round keys: */
+	for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+		temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+		temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+		temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+		temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+	}
+	/* apply the inverse MixColumn transform to all round keys but the first and the last: */
+	for (i = 1; i < Nr; i++) {
+		rk += 4;
+		rk[0] =
+			Td0[Te4[(rk[0] >> 24)       ]] ^
+			Td1[Te4[(rk[0] >> 16) & 0xff]] ^
+			Td2[Te4[(rk[0] >>  8) & 0xff]] ^
+			Td3[Te4[(rk[0]      ) & 0xff]];
+		rk[1] =
+			Td0[Te4[(rk[1] >> 24)       ]] ^
+			Td1[Te4[(rk[1] >> 16) & 0xff]] ^
+			Td2[Te4[(rk[1] >>  8) & 0xff]] ^
+			Td3[Te4[(rk[1]      ) & 0xff]];
+		rk[2] =
+			Td0[Te4[(rk[2] >> 24)       ]] ^
+			Td1[Te4[(rk[2] >> 16) & 0xff]] ^
+			Td2[Te4[(rk[2] >>  8) & 0xff]] ^
+			Td3[Te4[(rk[2]      ) & 0xff]];
+		rk[3] =
+			Td0[Te4[(rk[3] >> 24)       ]] ^
+			Td1[Te4[(rk[3] >> 16) & 0xff]] ^
+			Td2[Te4[(rk[3] >>  8) & 0xff]] ^
+			Td3[Te4[(rk[3]      ) & 0xff]];
+	}
+	return Nr;
+}
+
+static void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]) {
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+    int r;
+#endif /* ?FULL_UNROLL */
+
+    /*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(pt     ) ^ rk[0];
+	s1 = GETU32(pt +  4) ^ rk[1];
+	s2 = GETU32(pt +  8) ^ rk[2];
+	s3 = GETU32(pt + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
+   	/* round 2: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
+    /* round 3: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
+   	/* round 4: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
+    /* round 5: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
+   	/* round 6: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
+    /* round 7: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
+   	/* round 8: */
+   	s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
+   	s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
+   	s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
+   	s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
+    /* round 9: */
+   	t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
+   	t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
+   	t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
+   	t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
+    if (Nr > 10) {
+        /* round 10: */
+        s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[40];
+        s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[41];
+        s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[42];
+        s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[44];
+        t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[45];
+        t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[46];
+        t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[47];
+        if (Nr > 12) {
+            /* round 12: */
+            s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+            s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+            s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+            s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+            t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+            t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+            t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+        }
+    }
+    rk += Nr << 2;
+#else  /* !FULL_UNROLL */
+    /*
+	 * Nr - 1 full rounds:
+	 */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Te0[(s0 >> 24)       ] ^
+            Te1[(s1 >> 16) & 0xff] ^
+            Te2[(s2 >>  8) & 0xff] ^
+            Te3[(s3      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Te0[(s1 >> 24)       ] ^
+            Te1[(s2 >> 16) & 0xff] ^
+            Te2[(s3 >>  8) & 0xff] ^
+            Te3[(s0      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Te0[(s2 >> 24)       ] ^
+            Te1[(s3 >> 16) & 0xff] ^
+            Te2[(s0 >>  8) & 0xff] ^
+            Te3[(s1      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Te0[(s3 >> 24)       ] ^
+            Te1[(s0 >> 16) & 0xff] ^
+            Te2[(s1 >>  8) & 0xff] ^
+            Te3[(s2      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te0[(t0 >> 24)       ] ^
+            Te1[(t1 >> 16) & 0xff] ^
+            Te2[(t2 >>  8) & 0xff] ^
+            Te3[(t3      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Te0[(t1 >> 24)       ] ^
+            Te1[(t2 >> 16) & 0xff] ^
+            Te2[(t3 >>  8) & 0xff] ^
+            Te3[(t0      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Te0[(t2 >> 24)       ] ^
+            Te1[(t3 >> 16) & 0xff] ^
+            Te2[(t0 >>  8) & 0xff] ^
+            Te3[(t1      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Te0[(t3 >> 24)       ] ^
+            Te1[(t0 >> 16) & 0xff] ^
+            Te2[(t1 >>  8) & 0xff] ^
+            Te3[(t2      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 =
+		(Te4[(t0 >> 24)       ] << 24) ^
+		(Te4[(t1 >> 16) & 0xff] << 16) ^
+		(Te4[(t2 >>  8) & 0xff] <<  8) ^
+		(Te4[(t3      ) & 0xff]      ) ^
+		rk[0];
+	PUTU32(ct     , s0);
+	s1 =
+		(Te4[(t1 >> 24)       ] << 24) ^
+		(Te4[(t2 >> 16) & 0xff] << 16) ^
+		(Te4[(t3 >>  8) & 0xff] <<  8) ^
+		(Te4[(t0      ) & 0xff]      ) ^
+		rk[1];
+	PUTU32(ct +  4, s1);
+	s2 =
+		(Te4[(t2 >> 24)       ] << 24) ^
+		(Te4[(t3 >> 16) & 0xff] << 16) ^
+		(Te4[(t0 >>  8) & 0xff] <<  8) ^
+		(Te4[(t1      ) & 0xff]      ) ^
+		rk[2];
+	PUTU32(ct +  8, s2);
+	s3 =
+		(Te4[(t3 >> 24)       ] << 24) ^
+		(Te4[(t0 >> 16) & 0xff] << 16) ^
+		(Te4[(t1 >>  8) & 0xff] <<  8) ^
+		(Te4[(t2      ) & 0xff]      ) ^
+		rk[3];
+	PUTU32(ct + 12, s3);
+}
+
+static void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]) {
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+    int r;
+#endif /* ?FULL_UNROLL */
+
+    /*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+    s0 = GETU32(ct     ) ^ rk[0];
+    s1 = GETU32(ct +  4) ^ rk[1];
+    s2 = GETU32(ct +  8) ^ rk[2];
+    s3 = GETU32(ct + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
+    /* round 2: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
+    /* round 3: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
+    /* round 4: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
+    /* round 5: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
+    /* round 6: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
+    /* round 7: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
+    /* round 8: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
+    /* round 9: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+    if (Nr > 10) {
+        /* round 10: */
+        s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[40];
+        s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[41];
+        s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[42];
+        s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[44];
+        t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[45];
+        t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[46];
+        t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[47];
+        if (Nr > 12) {
+            /* round 12: */
+            s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+            s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+            s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+            s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+            t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+            t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+            t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+        }
+    }
+	rk += Nr << 2;
+#else  /* !FULL_UNROLL */
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = Nr >> 1;
+    for (;;) {
+        t0 =
+            Td0[(s0 >> 24)       ] ^
+            Td1[(s3 >> 16) & 0xff] ^
+            Td2[(s2 >>  8) & 0xff] ^
+            Td3[(s1      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Td0[(s1 >> 24)       ] ^
+            Td1[(s0 >> 16) & 0xff] ^
+            Td2[(s3 >>  8) & 0xff] ^
+            Td3[(s2      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Td0[(s2 >> 24)       ] ^
+            Td1[(s1 >> 16) & 0xff] ^
+            Td2[(s0 >>  8) & 0xff] ^
+            Td3[(s3      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Td0[(s3 >> 24)       ] ^
+            Td1[(s2 >> 16) & 0xff] ^
+            Td2[(s1 >>  8) & 0xff] ^
+            Td3[(s0      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td0[(t0 >> 24)       ] ^
+            Td1[(t3 >> 16) & 0xff] ^
+            Td2[(t2 >>  8) & 0xff] ^
+            Td3[(t1      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Td0[(t1 >> 24)       ] ^
+            Td1[(t0 >> 16) & 0xff] ^
+            Td2[(t3 >>  8) & 0xff] ^
+            Td3[(t2      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Td0[(t2 >> 24)       ] ^
+            Td1[(t1 >> 16) & 0xff] ^
+            Td2[(t0 >>  8) & 0xff] ^
+            Td3[(t3      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Td0[(t3 >> 24)       ] ^
+            Td1[(t2 >> 16) & 0xff] ^
+            Td2[(t1 >>  8) & 0xff] ^
+            Td3[(t0      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+   	s0 =
+   		(Td4[(t0 >> 24)       ] << 24) ^
+   		(Td4[(t3 >> 16) & 0xff] << 16) ^
+   		(Td4[(t2 >>  8) & 0xff] <<  8) ^
+   		(Td4[(t1      ) & 0xff]      ) ^
+   		rk[0];
+	PUTU32(pt     , s0);
+   	s1 =
+   		(Td4[(t1 >> 24)       ] << 24) ^
+   		(Td4[(t0 >> 16) & 0xff] << 16) ^
+   		(Td4[(t3 >>  8) & 0xff] <<  8) ^
+   		(Td4[(t2      ) & 0xff]      ) ^
+   		rk[1];
+	PUTU32(pt +  4, s1);
+   	s2 =
+   		(Td4[(t2 >> 24)       ] << 24) ^
+   		(Td4[(t1 >> 16) & 0xff] << 16) ^
+   		(Td4[(t0 >>  8) & 0xff] <<  8) ^
+   		(Td4[(t3      ) & 0xff]      ) ^
+   		rk[2];
+	PUTU32(pt +  8, s2);
+   	s3 =
+   		(Td4[(t3 >> 24)       ] << 24) ^
+   		(Td4[(t2 >> 16) & 0xff] << 16) ^
+   		(Td4[(t1 >>  8) & 0xff] <<  8) ^
+   		(Td4[(t0      ) & 0xff]      ) ^
+   		rk[3];
+	PUTU32(pt + 12, s3);
+}
+
+#ifdef INTERMEDIATE_VALUE_KAT
+
+static void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
+	int r;
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+
+    /*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(block     ) ^ rk[0];
+	s1 = GETU32(block +  4) ^ rk[1];
+	s2 = GETU32(block +  8) ^ rk[2];
+	s3 = GETU32(block + 12) ^ rk[3];
+    rk += 4;
+
+    /*
+	 * Nr - 1 full rounds:
+	 */
+	for (r = (rounds < Nr ? rounds : Nr - 1); r > 0; r--) {
+		t0 =
+			Te0[(s0 >> 24)       ] ^
+			Te1[(s1 >> 16) & 0xff] ^
+			Te2[(s2 >>  8) & 0xff] ^
+			Te3[(s3      ) & 0xff] ^
+			rk[0];
+		t1 =
+			Te0[(s1 >> 24)       ] ^
+			Te1[(s2 >> 16) & 0xff] ^
+			Te2[(s3 >>  8) & 0xff] ^
+			Te3[(s0      ) & 0xff] ^
+			rk[1];
+		t2 =
+			Te0[(s2 >> 24)       ] ^
+			Te1[(s3 >> 16) & 0xff] ^
+			Te2[(s0 >>  8) & 0xff] ^
+			Te3[(s1      ) & 0xff] ^
+			rk[2];
+		t3 =
+			Te0[(s3 >> 24)       ] ^
+			Te1[(s0 >> 16) & 0xff] ^
+			Te2[(s1 >>  8) & 0xff] ^
+			Te3[(s2      ) & 0xff] ^
+			rk[3];
+
+		s0 = t0;
+		s1 = t1;
+		s2 = t2;
+		s3 = t3;
+		rk += 4;
+
+    }
+
+    /*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	if (rounds == Nr) {
+    	t0 =
+    		(Te4[(s0 >> 24)       ] << 24) ^
+    		(Te4[(s1 >> 16) & 0xff] << 16) ^
+    		(Te4[(s2 >>  8) & 0xff] <<  8) ^
+    		(Te4[(s3      ) & 0xff]      ) ^
+    		rk[0];
+    	t1 =
+    		(Te4[(s1 >> 24)       ] << 24) ^
+    		(Te4[(s2 >> 16) & 0xff] << 16) ^
+    		(Te4[(s3 >>  8) & 0xff] <<  8) ^
+    		(Te4[(s0      ) & 0xff]      ) ^
+    		rk[1];
+    	t2 =
+    		(Te4[(s2 >> 24)       ] << 24) ^
+    		(Te4[(s3 >> 16) & 0xff] << 16) ^
+    		(Te4[(s0 >>  8) & 0xff] <<  8) ^
+    		(Te4[(s1      ) & 0xff]      ) ^
+    		rk[2];
+    	t3 =
+    		(Te4[(s3 >> 24)       ] << 24) ^
+    		(Te4[(s0 >> 16) & 0xff] << 16) ^
+    		(Te4[(s1 >>  8) & 0xff] <<  8) ^
+    		(Te4[(s2      ) & 0xff]      ) ^
+    		rk[3];
+		
+		s0 = t0;
+		s1 = t1;
+		s2 = t2;
+		s3 = t3;
+	}
+
+	PUTU32(block     , s0);
+	PUTU32(block +  4, s1);
+	PUTU32(block +  8, s2);
+	PUTU32(block + 12, s3);
+}
+
+static void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds) {
+	int r;
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+
+    /*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(block     ) ^ rk[0];
+	s1 = GETU32(block +  4) ^ rk[1];
+	s2 = GETU32(block +  8) ^ rk[2];
+	s3 = GETU32(block + 12) ^ rk[3];
+    rk += 4;
+
+    /*
+	 * Nr - 1 full rounds:
+	 */
+	for (r = (rounds < Nr ? rounds : Nr) - 1; r > 0; r--) {
+		t0 =
+			Td0[(s0 >> 24)       ] ^
+			Td1[(s3 >> 16) & 0xff] ^
+			Td2[(s2 >>  8) & 0xff] ^
+			Td3[(s1      ) & 0xff] ^
+			rk[0];
+		t1 =
+			Td0[(s1 >> 24)       ] ^
+			Td1[(s0 >> 16) & 0xff] ^
+			Td2[(s3 >>  8) & 0xff] ^
+			Td3[(s2      ) & 0xff] ^
+			rk[1];
+		t2 =
+			Td0[(s2 >> 24)       ] ^
+			Td1[(s1 >> 16) & 0xff] ^
+			Td2[(s0 >>  8) & 0xff] ^
+			Td3[(s3      ) & 0xff] ^
+			rk[2];
+		t3 =
+			Td0[(s3 >> 24)       ] ^
+			Td1[(s2 >> 16) & 0xff] ^
+			Td2[(s1 >>  8) & 0xff] ^
+			Td3[(s0      ) & 0xff] ^
+			rk[3];
+
+		s0 = t0;
+		s1 = t1;
+		s2 = t2;
+		s3 = t3;
+		rk += 4;
+
+    }
+
+    /*
+	 * complete the last round and
+	 * map cipher state to byte array block:
+	 */
+	t0 =
+		(Td4[(s0 >> 24)       ] << 24) ^
+		(Td4[(s3 >> 16) & 0xff] << 16) ^
+		(Td4[(s2 >>  8) & 0xff] <<  8) ^
+		(Td4[(s1      ) & 0xff]      );
+	t1 =
+		(Td4[(s1 >> 24)       ] << 24) ^
+		(Td4[(s0 >> 16) & 0xff] << 16) ^
+		(Td4[(s3 >>  8) & 0xff] <<  8) ^
+		(Td4[(s2      ) & 0xff]      );
+	t2 =
+		(Td4[(s2 >> 24)       ] << 24) ^
+		(Td4[(s1 >> 16) & 0xff] << 16) ^
+		(Td4[(s0 >>  8) & 0xff] <<  8) ^
+		(Td4[(s3      ) & 0xff]      );
+	t3 =
+		(Td4[(s3 >> 24)       ] << 24) ^
+		(Td4[(s2 >> 16) & 0xff] << 16) ^
+		(Td4[(s1 >>  8) & 0xff] <<  8) ^
+		(Td4[(s0      ) & 0xff]      );
+
+	if (rounds == Nr) {
+	    t0 ^= rk[0];
+	    t1 ^= rk[1];
+	    t2 ^= rk[2];
+	    t3 ^= rk[3];
+	}
+
+	PUTU32(block     , t0);
+	PUTU32(block +  4, t1);
+	PUTU32(block +  8, t2);
+	PUTU32(block + 12, t3);
+}
+
+#endif /* INTERMEDIATE_VALUE_KAT */
--- /dev/null
+++ b/libsec/port/blowfish.c
@@ -1,0 +1,579 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Blowfish block cipher.  See:
+// 	Lecture Notes in Computer Science 809
+// 	Fast Software Encryption
+// 	Cambridge Security Workshop, Cambridge, England (1993)
+
+static u32int sbox[1024];
+static u32int pbox[BFrounds+2];
+
+static void bfencrypt(u32int *, BFstate *);
+static void bfdecrypt(u32int *, BFstate *);
+
+void
+setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec)
+{
+	int i, j;
+	u32int n, buf[2];
+
+	memset(s, 0, sizeof(*s));
+	memset(buf, 0, sizeof buf);
+
+	if (keybytes > sizeof(s->key))
+		keybytes = sizeof(s->key);
+
+	memmove(s->key, key, keybytes);
+
+	if (ivec != nil)
+		memmove(s->ivec, ivec, sizeof(s->ivec));
+	else
+		memset(s->ivec, 0, sizeof(s->ivec));
+		
+	memmove(s->pbox, pbox, sizeof(pbox));
+	memmove(s->sbox, sbox, sizeof(sbox));
+
+	if (keybytes > 4*(BFrounds + 2))
+		keybytes = 4*(BFrounds + 2);
+
+	for(i=j=0; i < BFrounds+2; i++) {
+		n = key[j];
+		j = (j+1) % keybytes;
+
+		n <<= 8;
+		n |= key[j];
+		j = (j+1) % keybytes;
+
+		n <<= 8;
+		n |= key[j];
+		j = (j+1) % keybytes;
+
+		n <<= 8;
+		n |= key[j];
+		j = (j+1) % keybytes;
+
+		s->pbox[i] ^= n;
+	}
+
+	for(i=0; i < BFrounds+2; i += 2) {
+		bfencrypt(buf, s);
+		s->pbox[i] = buf[0];
+		s->pbox[i+1] = buf[1];
+	}
+
+	for(i=0; i < 1024; i += 2) {
+		bfencrypt(buf, s);
+		s->sbox[i] = buf[0];
+		s->sbox[i+1] = buf[1];
+	}
+
+	s->setup = 0xcafebabe;
+}
+
+void
+bfCBCencrypt(uchar *buf, int n, BFstate *s)
+{
+	int i;
+	uchar *p;
+	u32int bo[2], bi[2], b;
+
+	assert((n & 7) == 0);
+
+	bo[0] =  s->ivec[0] | ((u32int) s->ivec[1]<<8) | ((u32int)s->ivec[2]<<16) | ((u32int)s->ivec[3]<<24);
+	bo[1] =  s->ivec[4] | ((u32int) s->ivec[5]<<8) | ((u32int)s->ivec[6]<<16) | ((u32int)s->ivec[7]<<24);
+
+	for(i=0; i < n; i += 8, buf += 8) {
+		bi[0] =  buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+		bi[1] =  buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+		bi[0] ^= bo[0];
+		bi[1] ^= bo[1];
+
+		bfencrypt(bi, s);
+
+		bo[0] = bi[0];
+		bo[1] = bi[1];
+
+		p = buf;
+		b = bo[0];
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+
+		b = bo[1];
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p = b;
+	}
+
+	s->ivec[7] = bo[1] >> 24;
+	s->ivec[6] = bo[1] >> 16;
+	s->ivec[5] = bo[1] >> 8;
+	s->ivec[4] = bo[1];
+
+	s->ivec[3] = bo[0] >> 24;
+	s->ivec[2] = bo[0] >> 16;
+	s->ivec[1] = bo[0] >> 8;
+	s->ivec[0] = bo[0];
+
+	return;
+}
+
+void
+bfCBCdecrypt(uchar *buf, int n, BFstate *s)
+{
+	int i;
+	uchar *p;
+	u32int b, bo[2], bi[2], xr[2];
+
+	assert((n & 7) == 0);
+
+	bo[0] =  s->ivec[0] | ((u32int) s->ivec[1]<<8) | ((u32int)s->ivec[2]<<16) | ((u32int)s->ivec[3]<<24);
+	bo[1] =  s->ivec[4] | ((u32int) s->ivec[5]<<8) | ((u32int)s->ivec[6]<<16) | ((u32int)s->ivec[7]<<24);
+
+	for(i=0; i < n; i += 8, buf += 8) {
+		bi[0] =  buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+		bi[1] =  buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+		xr[0] = bi[0];
+		xr[1] = bi[1];
+
+		bfdecrypt(bi, s);
+
+		bo[0] ^= bi[0];
+		bo[1] ^= bi[1];
+
+		p = buf;
+		b = bo[0];
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+
+		b = bo[1];
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p++ = b;
+		b >>= 8;
+		*p = b;
+
+		bo[0] = xr[0];
+		bo[1] = xr[1];
+	}
+
+	s->ivec[7] = bo[1] >> 24;
+	s->ivec[6] = bo[1] >> 16;
+	s->ivec[5] = bo[1] >> 8;
+	s->ivec[4] = bo[1];
+
+	s->ivec[3] = bo[0] >> 24;
+	s->ivec[2] = bo[0] >> 16;
+	s->ivec[1] = bo[0] >> 8;
+	s->ivec[0] = bo[0];
+
+	return;
+}
+
+void
+bfECBencrypt(uchar *buf, int n, BFstate *s)
+{
+	int i;
+	u32int b[2];
+
+	for(i=0; i < n; i += 8, buf += 8) {
+		b[0] =  buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+		b[1] =  buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+		bfencrypt(b, s);
+
+		buf[7] = b[1] >> 24;
+		buf[6] = b[1] >> 16;
+		buf[5] = b[1] >> 8;
+		buf[4] = b[1];
+
+		buf[3] = b[0] >> 24;
+		buf[2] = b[0] >> 16;
+		buf[1] = b[0] >> 8;
+		buf[0] = b[0];
+	}
+
+	return;
+}
+
+void
+bfECBdecrypt(uchar *buf, int n, BFstate *s)
+{
+	int i;
+	u32int b[2];
+
+	for(i=0; i < n; i += 8, buf += 8) {
+		b[0] =  buf[0] | ((u32int) buf[1]<<8) | ((u32int)buf[2]<<16) | ((u32int)buf[3]<<24);
+		b[1] =  buf[4] | ((u32int) buf[5]<<8) | ((u32int)buf[6]<<16) | ((u32int)buf[7]<<24);
+
+		bfdecrypt(b, s);
+
+		buf[7] = b[1] >> 24;
+		buf[6] = b[1] >> 16;
+		buf[5] = b[1] >> 8;
+		buf[4] = b[1];
+
+		buf[3] = b[0] >> 24;
+		buf[2] = b[0] >> 16;
+		buf[1] = b[0] >> 8;
+		buf[0] = b[0];
+	}
+
+	return;		
+}
+
+static void
+bfencrypt(u32int *b, BFstate *s)
+{
+	int i;
+	u32int l, r;
+	u32int *pb, *sb;
+
+	l = b[0];
+	r = b[1];
+
+	pb = s->pbox;
+	sb = s->sbox;
+
+	l ^= pb[0];
+
+	for(i=1; i<16; i += 2) {
+		r ^= pb[i];
+		r ^= ( (sb[ (uchar) (l>>24)] + sb[256 + ((uchar) (l>>16))]) ^  
+			sb[512 + ((uchar) (l>>8))]) + sb[768 +((uchar) l)];
+
+		l ^= pb[i+1];
+		l ^= ( (sb[ (uchar) (r>>24)] + sb[256 + ((uchar) (r>>16))]) ^  
+			sb[512 + ((uchar) (r>>8))]) + sb[768 +((uchar) r)];
+	}
+
+	r ^= pb[BFrounds+1];
+
+	/* sic */
+	b[0] = r;
+	b[1] = l;
+
+	return;
+}
+
+static void
+bfdecrypt(u32int *b, BFstate *s)
+{
+	int i;
+	u32int l, r;
+	u32int *pb, *sb;
+
+	l = b[0];
+	r = b[1];
+
+	pb = s->pbox;
+	sb = s->sbox;
+
+	l ^= pb[BFrounds+1];
+
+	for(i=16; i > 0; i -= 2) {
+		r ^= pb[i];
+		r ^= ( (sb[ (uchar) (l>>24)] + sb[256 + ((uchar) (l>>16))]) ^  
+			sb[512 + ((uchar) (l>>8))]) + sb[768 +((uchar) l)];
+
+		l ^= pb[i-1];
+		l ^= ( (sb[ (uchar) (r>>24)] + sb[256 + ((uchar) (r>>16))]) ^  
+			sb[512 + ((uchar) (r>>8))]) + sb[768 +((uchar) r)];
+	}
+
+	r ^= pb[0];
+
+	/* sic */
+	b[0] = r;
+	b[1] = l;
+
+	return;
+}
+
+static u32int pbox[BFrounds+2] = {
+	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 
+	0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, 
+	0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 
+	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 
+	0x9216d5d9, 0x8979fb1b
+};
+
+static u32int sbox[1024] = {
+	0xd1310ba6L, 0x98dfb5acL, 0x2ffd72dbL, 0xd01adfb7L, 
+	0xb8e1afedL, 0x6a267e96L, 0xba7c9045L, 0xf12c7f99L, 
+	0x24a19947L, 0xb3916cf7L, 0x0801f2e2L, 0x858efc16L, 
+	0x636920d8L, 0x71574e69L, 0xa458fea3L, 0xf4933d7eL, 
+	0x0d95748fL, 0x728eb658L, 0x718bcd58L, 0x82154aeeL, 
+	0x7b54a41dL, 0xc25a59b5L, 0x9c30d539L, 0x2af26013L, 
+	0xc5d1b023L, 0x286085f0L, 0xca417918L, 0xb8db38efL, 
+	0x8e79dcb0L, 0x603a180eL, 0x6c9e0e8bL, 0xb01e8a3eL, 
+	0xd71577c1L, 0xbd314b27L, 0x78af2fdaL, 0x55605c60L, 
+	0xe65525f3L, 0xaa55ab94L, 0x57489862L, 0x63e81440L, 
+	0x55ca396aL, 0x2aab10b6L, 0xb4cc5c34L, 0x1141e8ceL, 
+	0xa15486afL, 0x7c72e993L, 0xb3ee1411L, 0x636fbc2aL, 
+	0x2ba9c55dL, 0x741831f6L, 0xce5c3e16L, 0x9b87931eL, 
+	0xafd6ba33L, 0x6c24cf5cL, 0x7a325381L, 0x28958677L, 
+	0x3b8f4898L, 0x6b4bb9afL, 0xc4bfe81bL, 0x66282193L, 
+	0x61d809ccL, 0xfb21a991L, 0x487cac60L, 0x5dec8032L, 
+	0xef845d5dL, 0xe98575b1L, 0xdc262302L, 0xeb651b88L, 
+	0x23893e81L, 0xd396acc5L, 0x0f6d6ff3L, 0x83f44239L, 
+	0x2e0b4482L, 0xa4842004L, 0x69c8f04aL, 0x9e1f9b5eL, 
+	0x21c66842L, 0xf6e96c9aL, 0x670c9c61L, 0xabd388f0L, 
+	0x6a51a0d2L, 0xd8542f68L, 0x960fa728L, 0xab5133a3L, 
+	0x6eef0b6cL, 0x137a3be4L, 0xba3bf050L, 0x7efb2a98L, 
+	0xa1f1651dL, 0x39af0176L, 0x66ca593eL, 0x82430e88L, 
+	0x8cee8619L, 0x456f9fb4L, 0x7d84a5c3L, 0x3b8b5ebeL, 
+	0xe06f75d8L, 0x85c12073L, 0x401a449fL, 0x56c16aa6L, 
+	0x4ed3aa62L, 0x363f7706L, 0x1bfedf72L, 0x429b023dL, 
+	0x37d0d724L, 0xd00a1248L, 0xdb0fead3L, 0x49f1c09bL, 
+	0x075372c9L, 0x80991b7bL, 0x25d479d8L, 0xf6e8def7L, 
+	0xe3fe501aL, 0xb6794c3bL, 0x976ce0bdL, 0x04c006baL, 
+	0xc1a94fb6L, 0x409f60c4L, 0x5e5c9ec2L, 0x196a2463L, 
+	0x68fb6fafL, 0x3e6c53b5L, 0x1339b2ebL, 0x3b52ec6fL, 
+	0x6dfc511fL, 0x9b30952cL, 0xcc814544L, 0xaf5ebd09L, 
+	0xbee3d004L, 0xde334afdL, 0x660f2807L, 0x192e4bb3L, 
+	0xc0cba857L, 0x45c8740fL, 0xd20b5f39L, 0xb9d3fbdbL, 
+	0x5579c0bdL, 0x1a60320aL, 0xd6a100c6L, 0x402c7279L, 
+	0x679f25feL, 0xfb1fa3ccL, 0x8ea5e9f8L, 0xdb3222f8L, 
+	0x3c7516dfL, 0xfd616b15L, 0x2f501ec8L, 0xad0552abL, 
+	0x323db5faL, 0xfd238760L, 0x53317b48L, 0x3e00df82L, 
+	0x9e5c57bbL, 0xca6f8ca0L, 0x1a87562eL, 0xdf1769dbL, 
+	0xd542a8f6L, 0x287effc3L, 0xac6732c6L, 0x8c4f5573L, 
+	0x695b27b0L, 0xbbca58c8L, 0xe1ffa35dL, 0xb8f011a0L, 
+	0x10fa3d98L, 0xfd2183b8L, 0x4afcb56cL, 0x2dd1d35bL, 
+	0x9a53e479L, 0xb6f84565L, 0xd28e49bcL, 0x4bfb9790L, 
+	0xe1ddf2daL, 0xa4cb7e33L, 0x62fb1341L, 0xcee4c6e8L, 
+	0xef20cadaL, 0x36774c01L, 0xd07e9efeL, 0x2bf11fb4L, 
+	0x95dbda4dL, 0xae909198L, 0xeaad8e71L, 0x6b93d5a0L, 
+	0xd08ed1d0L, 0xafc725e0L, 0x8e3c5b2fL, 0x8e7594b7L, 
+	0x8ff6e2fbL, 0xf2122b64L, 0x8888b812L, 0x900df01cL, 
+	0x4fad5ea0L, 0x688fc31cL, 0xd1cff191L, 0xb3a8c1adL, 
+	0x2f2f2218L, 0xbe0e1777L, 0xea752dfeL, 0x8b021fa1L, 
+	0xe5a0cc0fL, 0xb56f74e8L, 0x18acf3d6L, 0xce89e299L, 
+	0xb4a84fe0L, 0xfd13e0b7L, 0x7cc43b81L, 0xd2ada8d9L, 
+	0x165fa266L, 0x80957705L, 0x93cc7314L, 0x211a1477L, 
+	0xe6ad2065L, 0x77b5fa86L, 0xc75442f5L, 0xfb9d35cfL, 
+	0xebcdaf0cL, 0x7b3e89a0L, 0xd6411bd3L, 0xae1e7e49L, 
+	0x00250e2dL, 0x2071b35eL, 0x226800bbL, 0x57b8e0afL, 
+	0x2464369bL, 0xf009b91eL, 0x5563911dL, 0x59dfa6aaL, 
+	0x78c14389L, 0xd95a537fL, 0x207d5ba2L, 0x02e5b9c5L, 
+	0x83260376L, 0x6295cfa9L, 0x11c81968L, 0x4e734a41L, 
+	0xb3472dcaL, 0x7b14a94aL, 0x1b510052L, 0x9a532915L, 
+	0xd60f573fL, 0xbc9bc6e4L, 0x2b60a476L, 0x81e67400L, 
+	0x08ba6fb5L, 0x571be91fL, 0xf296ec6bL, 0x2a0dd915L, 
+	0xb6636521L, 0xe7b9f9b6L, 0xff34052eL, 0xc5855664L, 
+	0x53b02d5dL, 0xa99f8fa1L, 0x08ba4799L, 0x6e85076aL, 
+	0x4b7a70e9L, 0xb5b32944L, 0xdb75092eL, 0xc4192623L, 
+	0xad6ea6b0L, 0x49a7df7dL, 0x9cee60b8L, 0x8fedb266L, 
+	0xecaa8c71L, 0x699a17ffL, 0x5664526cL, 0xc2b19ee1L, 
+	0x193602a5L, 0x75094c29L, 0xa0591340L, 0xe4183a3eL, 
+	0x3f54989aL, 0x5b429d65L, 0x6b8fe4d6L, 0x99f73fd6L, 
+	0xa1d29c07L, 0xefe830f5L, 0x4d2d38e6L, 0xf0255dc1L, 
+	0x4cdd2086L, 0x8470eb26L, 0x6382e9c6L, 0x021ecc5eL, 
+	0x09686b3fL, 0x3ebaefc9L, 0x3c971814L, 0x6b6a70a1L, 
+	0x687f3584L, 0x52a0e286L, 0xb79c5305L, 0xaa500737L, 
+	0x3e07841cL, 0x7fdeae5cL, 0x8e7d44ecL, 0x5716f2b8L, 
+	0xb03ada37L, 0xf0500c0dL, 0xf01c1f04L, 0x0200b3ffL, 
+	0xae0cf51aL, 0x3cb574b2L, 0x25837a58L, 0xdc0921bdL, 
+	0xd19113f9L, 0x7ca92ff6L, 0x94324773L, 0x22f54701L, 
+	0x3ae5e581L, 0x37c2dadcL, 0xc8b57634L, 0x9af3dda7L, 
+	0xa9446146L, 0x0fd0030eL, 0xecc8c73eL, 0xa4751e41L, 
+	0xe238cd99L, 0x3bea0e2fL, 0x3280bba1L, 0x183eb331L, 
+	0x4e548b38L, 0x4f6db908L, 0x6f420d03L, 0xf60a04bfL, 
+	0x2cb81290L, 0x24977c79L, 0x5679b072L, 0xbcaf89afL, 
+	0xde9a771fL, 0xd9930810L, 0xb38bae12L, 0xdccf3f2eL, 
+	0x5512721fL, 0x2e6b7124L, 0x501adde6L, 0x9f84cd87L, 
+	0x7a584718L, 0x7408da17L, 0xbc9f9abcL, 0xe94b7d8cL, 
+	0xec7aec3aL, 0xdb851dfaL, 0x63094366L, 0xc464c3d2L, 
+	0xef1c1847L, 0x3215d908L, 0xdd433b37L, 0x24c2ba16L, 
+	0x12a14d43L, 0x2a65c451L, 0x50940002L, 0x133ae4ddL, 
+	0x71dff89eL, 0x10314e55L, 0x81ac77d6L, 0x5f11199bL, 
+	0x043556f1L, 0xd7a3c76bL, 0x3c11183bL, 0x5924a509L, 
+	0xf28fe6edL, 0x97f1fbfaL, 0x9ebabf2cL, 0x1e153c6eL, 
+	0x86e34570L, 0xeae96fb1L, 0x860e5e0aL, 0x5a3e2ab3L, 
+	0x771fe71cL, 0x4e3d06faL, 0x2965dcb9L, 0x99e71d0fL, 
+	0x803e89d6L, 0x5266c825L, 0x2e4cc978L, 0x9c10b36aL, 
+	0xc6150ebaL, 0x94e2ea78L, 0xa5fc3c53L, 0x1e0a2df4L, 
+	0xf2f74ea7L, 0x361d2b3dL, 0x1939260fL, 0x19c27960L, 
+	0x5223a708L, 0xf71312b6L, 0xebadfe6eL, 0xeac31f66L, 
+	0xe3bc4595L, 0xa67bc883L, 0xb17f37d1L, 0x018cff28L, 
+	0xc332ddefL, 0xbe6c5aa5L, 0x65582185L, 0x68ab9802L, 
+	0xeecea50fL, 0xdb2f953bL, 0x2aef7dadL, 0x5b6e2f84L, 
+	0x1521b628L, 0x29076170L, 0xecdd4775L, 0x619f1510L, 
+	0x13cca830L, 0xeb61bd96L, 0x0334fe1eL, 0xaa0363cfL, 
+	0xb5735c90L, 0x4c70a239L, 0xd59e9e0bL, 0xcbaade14L, 
+	0xeecc86bcL, 0x60622ca7L, 0x9cab5cabL, 0xb2f3846eL, 
+	0x648b1eafL, 0x19bdf0caL, 0xa02369b9L, 0x655abb50L, 
+	0x40685a32L, 0x3c2ab4b3L, 0x319ee9d5L, 0xc021b8f7L, 
+	0x9b540b19L, 0x875fa099L, 0x95f7997eL, 0x623d7da8L, 
+	0xf837889aL, 0x97e32d77L, 0x11ed935fL, 0x16681281L, 
+	0x0e358829L, 0xc7e61fd6L, 0x96dedfa1L, 0x7858ba99L, 
+	0x57f584a5L, 0x1b227263L, 0x9b83c3ffL, 0x1ac24696L, 
+	0xcdb30aebL, 0x532e3054L, 0x8fd948e4L, 0x6dbc3128L, 
+	0x58ebf2efL, 0x34c6ffeaL, 0xfe28ed61L, 0xee7c3c73L, 
+	0x5d4a14d9L, 0xe864b7e3L, 0x42105d14L, 0x203e13e0L, 
+	0x45eee2b6L, 0xa3aaabeaL, 0xdb6c4f15L, 0xfacb4fd0L, 
+	0xc742f442L, 0xef6abbb5L, 0x654f3b1dL, 0x41cd2105L, 
+	0xd81e799eL, 0x86854dc7L, 0xe44b476aL, 0x3d816250L, 
+	0xcf62a1f2L, 0x5b8d2646L, 0xfc8883a0L, 0xc1c7b6a3L, 
+	0x7f1524c3L, 0x69cb7492L, 0x47848a0bL, 0x5692b285L, 
+	0x095bbf00L, 0xad19489dL, 0x1462b174L, 0x23820e00L, 
+	0x58428d2aL, 0x0c55f5eaL, 0x1dadf43eL, 0x233f7061L, 
+	0x3372f092L, 0x8d937e41L, 0xd65fecf1L, 0x6c223bdbL, 
+	0x7cde3759L, 0xcbee7460L, 0x4085f2a7L, 0xce77326eL, 
+	0xa6078084L, 0x19f8509eL, 0xe8efd855L, 0x61d99735L, 
+	0xa969a7aaL, 0xc50c06c2L, 0x5a04abfcL, 0x800bcadcL, 
+	0x9e447a2eL, 0xc3453484L, 0xfdd56705L, 0x0e1e9ec9L, 
+	0xdb73dbd3L, 0x105588cdL, 0x675fda79L, 0xe3674340L, 
+	0xc5c43465L, 0x713e38d8L, 0x3d28f89eL, 0xf16dff20L, 
+	0x153e21e7L, 0x8fb03d4aL, 0xe6e39f2bL, 0xdb83adf7L, 
+	0xe93d5a68L, 0x948140f7L, 0xf64c261cL, 0x94692934L, 
+	0x411520f7L, 0x7602d4f7L, 0xbcf46b2eL, 0xd4a20068L, 
+	0xd4082471L, 0x3320f46aL, 0x43b7d4b7L, 0x500061afL, 
+	0x1e39f62eL, 0x97244546L, 0x14214f74L, 0xbf8b8840L, 
+	0x4d95fc1dL, 0x96b591afL, 0x70f4ddd3L, 0x66a02f45L, 
+	0xbfbc09ecL, 0x03bd9785L, 0x7fac6dd0L, 0x31cb8504L, 
+	0x96eb27b3L, 0x55fd3941L, 0xda2547e6L, 0xabca0a9aL, 
+	0x28507825L, 0x530429f4L, 0x0a2c86daL, 0xe9b66dfbL, 
+	0x68dc1462L, 0xd7486900L, 0x680ec0a4L, 0x27a18deeL, 
+	0x4f3ffea2L, 0xe887ad8cL, 0xb58ce006L, 0x7af4d6b6L, 
+	0xaace1e7cL, 0xd3375fecL, 0xce78a399L, 0x406b2a42L, 
+	0x20fe9e35L, 0xd9f385b9L, 0xee39d7abL, 0x3b124e8bL, 
+	0x1dc9faf7L, 0x4b6d1856L, 0x26a36631L, 0xeae397b2L, 
+	0x3a6efa74L, 0xdd5b4332L, 0x6841e7f7L, 0xca7820fbL, 
+	0xfb0af54eL, 0xd8feb397L, 0x454056acL, 0xba489527L, 
+	0x55533a3aL, 0x20838d87L, 0xfe6ba9b7L, 0xd096954bL, 
+	0x55a867bcL, 0xa1159a58L, 0xcca92963L, 0x99e1db33L, 
+	0xa62a4a56L, 0x3f3125f9L, 0x5ef47e1cL, 0x9029317cL, 
+	0xfdf8e802L, 0x04272f70L, 0x80bb155cL, 0x05282ce3L, 
+	0x95c11548L, 0xe4c66d22L, 0x48c1133fL, 0xc70f86dcL, 
+	0x07f9c9eeL, 0x41041f0fL, 0x404779a4L, 0x5d886e17L, 
+	0x325f51ebL, 0xd59bc0d1L, 0xf2bcc18fL, 0x41113564L, 
+	0x257b7834L, 0x602a9c60L, 0xdff8e8a3L, 0x1f636c1bL, 
+	0x0e12b4c2L, 0x02e1329eL, 0xaf664fd1L, 0xcad18115L, 
+	0x6b2395e0L, 0x333e92e1L, 0x3b240b62L, 0xeebeb922L, 
+	0x85b2a20eL, 0xe6ba0d99L, 0xde720c8cL, 0x2da2f728L, 
+	0xd0127845L, 0x95b794fdL, 0x647d0862L, 0xe7ccf5f0L, 
+	0x5449a36fL, 0x877d48faL, 0xc39dfd27L, 0xf33e8d1eL, 
+	0x0a476341L, 0x992eff74L, 0x3a6f6eabL, 0xf4f8fd37L, 
+	0xa812dc60L, 0xa1ebddf8L, 0x991be14cL, 0xdb6e6b0dL, 
+	0xc67b5510L, 0x6d672c37L, 0x2765d43bL, 0xdcd0e804L, 
+	0xf1290dc7L, 0xcc00ffa3L, 0xb5390f92L, 0x690fed0bL, 
+	0x667b9ffbL, 0xcedb7d9cL, 0xa091cf0bL, 0xd9155ea3L, 
+	0xbb132f88L, 0x515bad24L, 0x7b9479bfL, 0x763bd6ebL, 
+	0x37392eb3L, 0xcc115979L, 0x8026e297L, 0xf42e312dL, 
+	0x6842ada7L, 0xc66a2b3bL, 0x12754cccL, 0x782ef11cL, 
+	0x6a124237L, 0xb79251e7L, 0x06a1bbe6L, 0x4bfb6350L, 
+	0x1a6b1018L, 0x11caedfaL, 0x3d25bdd8L, 0xe2e1c3c9L, 
+	0x44421659L, 0x0a121386L, 0xd90cec6eL, 0xd5abea2aL, 
+	0x64af674eL, 0xda86a85fL, 0xbebfe988L, 0x64e4c3feL, 
+	0x9dbc8057L, 0xf0f7c086L, 0x60787bf8L, 0x6003604dL, 
+	0xd1fd8346L, 0xf6381fb0L, 0x7745ae04L, 0xd736fcccL, 
+	0x83426b33L, 0xf01eab71L, 0xb0804187L, 0x3c005e5fL, 
+	0x77a057beL, 0xbde8ae24L, 0x55464299L, 0xbf582e61L, 
+	0x4e58f48fL, 0xf2ddfda2L, 0xf474ef38L, 0x8789bdc2L, 
+	0x5366f9c3L, 0xc8b38e74L, 0xb475f255L, 0x46fcd9b9L, 
+	0x7aeb2661L, 0x8b1ddf84L, 0x846a0e79L, 0x915f95e2L, 
+	0x466e598eL, 0x20b45770L, 0x8cd55591L, 0xc902de4cL, 
+	0xb90bace1L, 0xbb8205d0L, 0x11a86248L, 0x7574a99eL, 
+	0xb77f19b6L, 0xe0a9dc09L, 0x662d09a1L, 0xc4324633L, 
+	0xe85a1f02L, 0x09f0be8cL, 0x4a99a025L, 0x1d6efe10L, 
+	0x1ab93d1dL, 0x0ba5a4dfL, 0xa186f20fL, 0x2868f169L, 
+	0xdcb7da83L, 0x573906feL, 0xa1e2ce9bL, 0x4fcd7f52L, 
+	0x50115e01L, 0xa70683faL, 0xa002b5c4L, 0x0de6d027L, 
+	0x9af88c27L, 0x773f8641L, 0xc3604c06L, 0x61a806b5L, 
+	0xf0177a28L, 0xc0f586e0L, 0x006058aaL, 0x30dc7d62L, 
+	0x11e69ed7L, 0x2338ea63L, 0x53c2dd94L, 0xc2c21634L, 
+	0xbbcbee56L, 0x90bcb6deL, 0xebfc7da1L, 0xce591d76L, 
+	0x6f05e409L, 0x4b7c0188L, 0x39720a3dL, 0x7c927c24L, 
+	0x86e3725fL, 0x724d9db9L, 0x1ac15bb4L, 0xd39eb8fcL, 
+	0xed545578L, 0x08fca5b5L, 0xd83d7cd3L, 0x4dad0fc4L, 
+	0x1e50ef5eL, 0xb161e6f8L, 0xa28514d9L, 0x6c51133cL, 
+	0x6fd5c7e7L, 0x56e14ec4L, 0x362abfceL, 0xddc6c837L, 
+	0xd79a3234L, 0x92638212L, 0x670efa8eL, 0x406000e0L, 
+	0x3a39ce37L, 0xd3faf5cfL, 0xabc27737L, 0x5ac52d1bL, 
+	0x5cb0679eL, 0x4fa33742L, 0xd3822740L, 0x99bc9bbeL, 
+	0xd5118e9dL, 0xbf0f7315L, 0xd62d1c7eL, 0xc700c47bL, 
+	0xb78c1b6bL, 0x21a19045L, 0xb26eb1beL, 0x6a366eb4L, 
+	0x5748ab2fL, 0xbc946e79L, 0xc6a376d2L, 0x6549c2c8L, 
+	0x530ff8eeL, 0x468dde7dL, 0xd5730a1dL, 0x4cd04dc6L, 
+	0x2939bbdbL, 0xa9ba4650L, 0xac9526e8L, 0xbe5ee304L, 
+	0xa1fad5f0L, 0x6a2d519aL, 0x63ef8ce2L, 0x9a86ee22L, 
+	0xc089c2b8L, 0x43242ef6L, 0xa51e03aaL, 0x9cf2d0a4L, 
+	0x83c061baL, 0x9be96a4dL, 0x8fe51550L, 0xba645bd6L, 
+	0x2826a2f9L, 0xa73a3ae1L, 0x4ba99586L, 0xef5562e9L, 
+	0xc72fefd3L, 0xf752f7daL, 0x3f046f69L, 0x77fa0a59L, 
+	0x80e4a915L, 0x87b08601L, 0x9b09e6adL, 0x3b3ee593L, 
+	0xe990fd5aL, 0x9e34d797L, 0x2cf0b7d9L, 0x022b8b51L, 
+	0x96d5ac3aL, 0x017da67dL, 0xd1cf3ed6L, 0x7c7d2d28L, 
+	0x1f9f25cfL, 0xadf2b89bL, 0x5ad6b472L, 0x5a88f54cL, 
+	0xe029ac71L, 0xe019a5e6L, 0x47b0acfdL, 0xed93fa9bL, 
+	0xe8d3c48dL, 0x283b57ccL, 0xf8d56629L, 0x79132e28L, 
+	0x785f0191L, 0xed756055L, 0xf7960e44L, 0xe3d35e8cL, 
+	0x15056dd4L, 0x88f46dbaL, 0x03a16125L, 0x0564f0bdL, 
+	0xc3eb9e15L, 0x3c9057a2L, 0x97271aecL, 0xa93a072aL, 
+	0x1b3f6d9bL, 0x1e6321f5L, 0xf59c66fbL, 0x26dcf319L, 
+	0x7533d928L, 0xb155fdf5L, 0x03563482L, 0x8aba3cbbL, 
+	0x28517711L, 0xc20ad9f8L, 0xabcc5167L, 0xccad925fL, 
+	0x4de81751L, 0x3830dc8eL, 0x379d5862L, 0x9320f991L, 
+	0xea7a90c2L, 0xfb3e7bceL, 0x5121ce64L, 0x774fbe32L, 
+	0xa8b6e37eL, 0xc3293d46L, 0x48de5369L, 0x6413e680L, 
+	0xa2ae0810L, 0xdd6db224L, 0x69852dfdL, 0x09072166L, 
+	0xb39a460aL, 0x6445c0ddL, 0x586cdecfL, 0x1c20c8aeL, 
+	0x5bbef7ddL, 0x1b588d40L, 0xccd2017fL, 0x6bb4e3bbL, 
+	0xdda26a7eL, 0x3a59ff45L, 0x3e350a44L, 0xbcb4cdd5L, 
+	0x72eacea8L, 0xfa6484bbL, 0x8d6612aeL, 0xbf3c6f47L, 
+	0xd29be463L, 0x542f5d9eL, 0xaec2771bL, 0xf64e6370L, 
+	0x740e0d8dL, 0xe75b1357L, 0xf8721671L, 0xaf537d5dL, 
+	0x4040cb08L, 0x4eb4e2ccL, 0x34d2466aL, 0x0115af84L, 
+	0xe1b00428L, 0x95983a1dL, 0x06b89fb4L, 0xce6ea048L, 
+	0x6f3f3b82L, 0x3520ab82L, 0x011a1d4bL, 0x277227f8L, 
+	0x611560b1L, 0xe7933fdcL, 0xbb3a792bL, 0x344525bdL, 
+	0xa08839e1L, 0x51ce794bL, 0x2f32c9b7L, 0xa01fbac9L, 
+	0xe01cc87eL, 0xbcc7d1f6L, 0xcf0111c3L, 0xa1e8aac7L, 
+	0x1a908749L, 0xd44fbd9aL, 0xd0dadecbL, 0xd50ada38L, 
+	0x0339c32aL, 0xc6913667L, 0x8df9317cL, 0xe0b12b4fL, 
+	0xf79e59b7L, 0x43f5bb3aL, 0xf2d519ffL, 0x27d9459cL, 
+	0xbf97222cL, 0x15e6fc2aL, 0x0f91fc71L, 0x9b941525L, 
+	0xfae59361L, 0xceb69cebL, 0xc2a86459L, 0x12baa8d1L, 
+	0xb6c1075eL, 0xe3056a0cL, 0x10d25065L, 0xcb03a442L, 
+	0xe0ec6e0eL, 0x1698db3bL, 0x4c98a0beL, 0x3278e964L, 
+	0x9f1f9532L, 0xe0d392dfL, 0xd3a0342bL, 0x8971f21eL, 
+	0x1b0a7441L, 0x4ba3348cL, 0xc5be7120L, 0xc37632d8L, 
+	0xdf359f8dL, 0x9b992f2eL, 0xe60b6f47L, 0x0fe3f11dL, 
+	0xe54cda54L, 0x1edad891L, 0xce6279cfL, 0xcd3e7e6fL, 
+	0x1618b166L, 0xfd2c1d05L, 0x848fd2c5L, 0xf6fb2299L, 
+	0xf523f357L, 0xa6327623L, 0x93a83531L, 0x56cccd02L, 
+	0xacf08162L, 0x5a75ebb5L, 0x6e163697L, 0x88d273ccL, 
+	0xde966292L, 0x81b949d0L, 0x4c50901bL, 0x71c65614L, 
+	0xe6c6c7bdL, 0x327a140aL, 0x45e1d006L, 0xc3f27b9aL, 
+	0xc9aa53fdL, 0x62a80f00L, 0xbb25bfe2L, 0x35bdd2f6L, 
+	0x71126905L, 0xb2040222L, 0xb6cbcf7cL, 0xcd769c2bL, 
+	0x53113ec0L, 0x1640e3d3L, 0x38abbd60L, 0x2547adf0L, 
+	0xba38209cL, 0xf746ce76L, 0x77afa1c5L, 0x20756060L, 
+	0x85cbfe4eL, 0x8ae88dd8L, 0x7aaaf9b0L, 0x4cf9aa7eL, 
+	0x1948c25cL, 0x02fb8a8cL, 0x01c36ae4L, 0xd6ebe1f9L, 
+	0x90d4f869L, 0xa65cdea0L, 0x3f09252dL, 0xc208e69fL, 
+	0xb74e6132L, 0xce77e25bL, 0x578fdfe3L, 0x3ac372e6L, 
+};
+
+
--- /dev/null
+++ b/libsec/port/decodepem.c
@@ -1,0 +1,89 @@
+#include <u.h>
+#include <libc.h>
+#include <mp.h>
+#include <libsec.h>
+
+#define STRLEN(s)	(sizeof(s)-1)
+
+uchar*
+decodePEM(char *s, char *type, int *len, char **new_s)
+{
+	uchar *d;
+	char *t, *e, *tt;
+	int n;
+
+	*len = 0;
+
+	/*
+	 * find the correct section of the file, stripping garbage at the beginning and end.
+	 * the data is delimited by -----BEGIN <type>-----\n and -----END <type>-----\n
+	 */
+	n = strlen(type);
+	e = strchr(s, '\0');
+	for(t = s; t != nil && t < e; ){
+		tt = t;
+		t = strchr(tt, '\n');
+		if(t != nil)
+			t++;
+		if(strncmp(tt, "-----BEGIN ", STRLEN("-----BEGIN ")) == 0
+		&& strncmp(&tt[STRLEN("-----BEGIN ")], type, n) == 0
+		&& strncmp(&tt[STRLEN("-----BEGIN ")+n], "-----\n", STRLEN("-----\n")) == 0)
+			break;
+	}
+	for(tt = t; tt != nil && tt < e; tt++){
+		if(strncmp(tt, "-----END ", STRLEN("-----END ")) == 0
+		&& strncmp(&tt[STRLEN("-----END ")], type, n) == 0
+		&& strncmp(&tt[STRLEN("-----END ")+n], "-----\n", STRLEN("-----\n")) == 0)
+			break;
+		tt = strchr(tt, '\n');
+		if(tt == nil)
+			break;
+	}
+	if(tt == nil || tt == e){
+		werrstr("incorrect .pem file format: bad header or trailer");
+		return nil;
+	}
+
+	if(new_s)
+		*new_s = tt+1;
+	n = ((tt - t) * 6 + 7) / 8;
+	d = malloc(n);
+	if(d == nil){
+		werrstr("out of memory");
+		return nil;
+	}
+	n = dec64(d, n, t, tt - t);
+	if(n < 0){
+		free(d);
+		werrstr("incorrect .pem file format: bad base64 encoded data");
+		return nil;
+	}
+	*len = n;
+	return d;
+}
+
+PEMChain*
+decodepemchain(char *s, char *type)
+{
+	PEMChain *first = nil, *last = nil, *chp;
+	uchar *d;
+	char *e;
+	int n;
+
+	e = strchr(s, '\0');
+	while (s < e) {
+		d = decodePEM(s, type, &n, &s);
+		if(d == nil)
+			break;
+		chp = malloc(sizeof(PEMChain));
+		chp->next = nil;
+		chp->pem = d;
+		chp->pemlen = n;
+		if (first == nil)
+			first = chp;
+		else
+			last->next = chp;
+		last = chp;
+	}
+	return first;
+}
--- /dev/null
+++ b/libsec/port/des.c
@@ -1,0 +1,480 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ * integrated sbox & p perm
+ */
+static u32int spbox[] = {
+
+0x00808200,0x00000000,0x00008000,0x00808202,0x00808002,0x00008202,0x00000002,0x00008000,
+0x00000200,0x00808200,0x00808202,0x00000200,0x00800202,0x00808002,0x00800000,0x00000002,
+0x00000202,0x00800200,0x00800200,0x00008200,0x00008200,0x00808000,0x00808000,0x00800202,
+0x00008002,0x00800002,0x00800002,0x00008002,0x00000000,0x00000202,0x00008202,0x00800000,
+0x00008000,0x00808202,0x00000002,0x00808000,0x00808200,0x00800000,0x00800000,0x00000200,
+0x00808002,0x00008000,0x00008200,0x00800002,0x00000200,0x00000002,0x00800202,0x00008202,
+0x00808202,0x00008002,0x00808000,0x00800202,0x00800002,0x00000202,0x00008202,0x00808200,
+0x00000202,0x00800200,0x00800200,0x00000000,0x00008002,0x00008200,0x00000000,0x00808002,
+
+0x40084010,0x40004000,0x00004000,0x00084010,0x00080000,0x00000010,0x40080010,0x40004010,
+0x40000010,0x40084010,0x40084000,0x40000000,0x40004000,0x00080000,0x00000010,0x40080010,
+0x00084000,0x00080010,0x40004010,0x00000000,0x40000000,0x00004000,0x00084010,0x40080000,
+0x00080010,0x40000010,0x00000000,0x00084000,0x00004010,0x40084000,0x40080000,0x00004010,
+0x00000000,0x00084010,0x40080010,0x00080000,0x40004010,0x40080000,0x40084000,0x00004000,
+0x40080000,0x40004000,0x00000010,0x40084010,0x00084010,0x00000010,0x00004000,0x40000000,
+0x00004010,0x40084000,0x00080000,0x40000010,0x00080010,0x40004010,0x40000010,0x00080010,
+0x00084000,0x00000000,0x40004000,0x00004010,0x40000000,0x40080010,0x40084010,0x00084000,
+
+0x00000104,0x04010100,0x00000000,0x04010004,0x04000100,0x00000000,0x00010104,0x04000100,
+0x00010004,0x04000004,0x04000004,0x00010000,0x04010104,0x00010004,0x04010000,0x00000104,
+0x04000000,0x00000004,0x04010100,0x00000100,0x00010100,0x04010000,0x04010004,0x00010104,
+0x04000104,0x00010100,0x00010000,0x04000104,0x00000004,0x04010104,0x00000100,0x04000000,
+0x04010100,0x04000000,0x00010004,0x00000104,0x00010000,0x04010100,0x04000100,0x00000000,
+0x00000100,0x00010004,0x04010104,0x04000100,0x04000004,0x00000100,0x00000000,0x04010004,
+0x04000104,0x00010000,0x04000000,0x04010104,0x00000004,0x00010104,0x00010100,0x04000004,
+0x04010000,0x04000104,0x00000104,0x04010000,0x00010104,0x00000004,0x04010004,0x00010100,
+
+0x80401000,0x80001040,0x80001040,0x00000040,0x00401040,0x80400040,0x80400000,0x80001000,
+0x00000000,0x00401000,0x00401000,0x80401040,0x80000040,0x00000000,0x00400040,0x80400000,
+0x80000000,0x00001000,0x00400000,0x80401000,0x00000040,0x00400000,0x80001000,0x00001040,
+0x80400040,0x80000000,0x00001040,0x00400040,0x00001000,0x00401040,0x80401040,0x80000040,
+0x00400040,0x80400000,0x00401000,0x80401040,0x80000040,0x00000000,0x00000000,0x00401000,
+0x00001040,0x00400040,0x80400040,0x80000000,0x80401000,0x80001040,0x80001040,0x00000040,
+0x80401040,0x80000040,0x80000000,0x00001000,0x80400000,0x80001000,0x00401040,0x80400040,
+0x80001000,0x00001040,0x00400000,0x80401000,0x00000040,0x00400000,0x00001000,0x00401040,
+
+0x00000080,0x01040080,0x01040000,0x21000080,0x00040000,0x00000080,0x20000000,0x01040000,
+0x20040080,0x00040000,0x01000080,0x20040080,0x21000080,0x21040000,0x00040080,0x20000000,
+0x01000000,0x20040000,0x20040000,0x00000000,0x20000080,0x21040080,0x21040080,0x01000080,
+0x21040000,0x20000080,0x00000000,0x21000000,0x01040080,0x01000000,0x21000000,0x00040080,
+0x00040000,0x21000080,0x00000080,0x01000000,0x20000000,0x01040000,0x21000080,0x20040080,
+0x01000080,0x20000000,0x21040000,0x01040080,0x20040080,0x00000080,0x01000000,0x21040000,
+0x21040080,0x00040080,0x21000000,0x21040080,0x01040000,0x00000000,0x20040000,0x21000000,
+0x00040080,0x01000080,0x20000080,0x00040000,0x00000000,0x20040000,0x01040080,0x20000080,
+
+0x10000008,0x10200000,0x00002000,0x10202008,0x10200000,0x00000008,0x10202008,0x00200000,
+0x10002000,0x00202008,0x00200000,0x10000008,0x00200008,0x10002000,0x10000000,0x00002008,
+0x00000000,0x00200008,0x10002008,0x00002000,0x00202000,0x10002008,0x00000008,0x10200008,
+0x10200008,0x00000000,0x00202008,0x10202000,0x00002008,0x00202000,0x10202000,0x10000000,
+0x10002000,0x00000008,0x10200008,0x00202000,0x10202008,0x00200000,0x00002008,0x10000008,
+0x00200000,0x10002000,0x10000000,0x00002008,0x10000008,0x10202008,0x00202000,0x10200000,
+0x00202008,0x10202000,0x00000000,0x10200008,0x00000008,0x00002000,0x10200000,0x00202008,
+0x00002000,0x00200008,0x10002008,0x00000000,0x10202000,0x10000000,0x00200008,0x10002008,
+
+0x00100000,0x02100001,0x02000401,0x00000000,0x00000400,0x02000401,0x00100401,0x02100400,
+0x02100401,0x00100000,0x00000000,0x02000001,0x00000001,0x02000000,0x02100001,0x00000401,
+0x02000400,0x00100401,0x00100001,0x02000400,0x02000001,0x02100000,0x02100400,0x00100001,
+0x02100000,0x00000400,0x00000401,0x02100401,0x00100400,0x00000001,0x02000000,0x00100400,
+0x02000000,0x00100400,0x00100000,0x02000401,0x02000401,0x02100001,0x02100001,0x00000001,
+0x00100001,0x02000000,0x02000400,0x00100000,0x02100400,0x00000401,0x00100401,0x02100400,
+0x00000401,0x02000001,0x02100401,0x02100000,0x00100400,0x00000000,0x00000001,0x02100401,
+0x00000000,0x00100401,0x02100000,0x00000400,0x02000001,0x02000400,0x00000400,0x00100001,
+
+0x08000820,0x00000800,0x00020000,0x08020820,0x08000000,0x08000820,0x00000020,0x08000000,
+0x00020020,0x08020000,0x08020820,0x00020800,0x08020800,0x00020820,0x00000800,0x00000020,
+0x08020000,0x08000020,0x08000800,0x00000820,0x00020800,0x00020020,0x08020020,0x08020800,
+0x00000820,0x00000000,0x00000000,0x08020020,0x08000020,0x08000800,0x00020820,0x00020000,
+0x00020820,0x00020000,0x08020800,0x00000800,0x00000020,0x08020020,0x00000800,0x00020820,
+0x08000800,0x00000020,0x08000020,0x08020000,0x08020020,0x08000000,0x00020000,0x08000820,
+0x00000000,0x08020820,0x00020020,0x08000020,0x08020000,0x08000800,0x08000820,0x00000000,
+0x08020820,0x00020800,0x00020800,0x00000820,0x00000820,0x00020020,0x08000000,0x08020800,
+};
+
+/*
+ * for manual index calculation
+ * #define fetch(box, i, sh) (*((u32int*)((uchar*)spbox + (box << 8) + ((i >> (sh)) & 0xfc))))
+ */
+#define fetch(box, i, sh) ((spbox+(box << 6))[((i >> (sh + 2)) & 0x3f)])
+
+/*
+ * DES electronic codebook encryption of one block
+ */
+void
+block_cipher(ulong key[32], uchar text[8], int decrypting)
+{
+	u32int right, left, v0, v1;
+	int i, keystep;
+
+	/*
+	 * initial permutation
+	 */
+	v0 = text[0] | ((u32int)text[2]<<8) | ((u32int)text[4]<<16) | ((u32int)text[6]<<24);
+	left = text[1] | ((u32int)text[3]<<8) | ((u32int)text[5]<<16) | ((u32int)text[7]<<24);
+	right = (left & 0xaaaaaaaa) | ((v0 >> 1) & 0x55555555);
+	left = ((left << 1) & 0xaaaaaaaa) | (v0 & 0x55555555);
+	left = ((left << 6) & 0x33003300)
+		| (left & 0xcc33cc33)
+		| ((left >> 6) & 0x00cc00cc);
+	left = ((left << 12) & 0x0f0f0000)
+		| (left & 0xf0f00f0f)
+		| ((left >> 12) & 0x0000f0f0);
+	right = ((right << 6) & 0x33003300)
+		| (right & 0xcc33cc33)
+		| ((right >> 6) & 0x00cc00cc);
+	right = ((right << 12) & 0x0f0f0000)
+		| (right & 0xf0f00f0f)
+		| ((right >> 12) & 0x0000f0f0);
+
+	if (decrypting) {
+		keystep = -2;
+		key = key + 32 - 2;
+	} else
+		keystep = 2;
+	for (i = 0; i < 8; i++) {
+		v0 = key[0];
+		v0 ^= (right >> 1) | (right << 31);
+		left ^= fetch(0, v0, 24)
+			^ fetch(2, v0, 16)
+			^ fetch(4, v0, 8)
+			^ fetch(6, v0, 0);
+		v1 = key[1];
+		v1 ^= (right << 3) | (right >> 29);
+		left ^= fetch(1, v1, 24)
+			^ fetch(3, v1, 16)
+			^ fetch(5, v1, 8)
+			^ fetch(7, v1, 0);
+		key += keystep;
+		
+		v0 = key[0];
+		v0 ^= (left >> 1) | (left << 31);
+		right ^= fetch(0, v0, 24)
+			^ fetch(2, v0, 16)
+			^ fetch(4, v0, 8)
+			^ fetch(6, v0, 0);
+		v1 = key[1];
+		v1 ^= (left << 3) | (left >> 29);
+		right ^= fetch(1, v1, 24)
+			^ fetch(3, v1, 16)
+			^ fetch(5, v1, 8)
+			^ fetch(7, v1, 0);
+		key += keystep;
+	}
+
+	/*
+	 * final permutation, inverse initial permutation
+	 */
+	v0 = ((left << 1) & 0xaaaaaaaa) | (right & 0x55555555);
+	v1 = (left & 0xaaaaaaaa) | ((right >> 1) & 0x55555555);
+	v1 = ((v1 << 6) & 0x33003300)
+		| (v1 & 0xcc33cc33)
+		| ((v1 >> 6) & 0x00cc00cc);
+	v1 = ((v1 << 12) & 0x0f0f0000)
+		| (v1 & 0xf0f00f0f)
+		| ((v1 >> 12) & 0x0000f0f0);
+	v0 = ((v0 << 6) & 0x33003300)
+		| (v0 & 0xcc33cc33)
+		| ((v0 >> 6) & 0x00cc00cc);
+	v0 = ((v0 << 12) & 0x0f0f0000)
+		| (v0 & 0xf0f00f0f)
+		| ((v0 >> 12) & 0x0000f0f0);
+	text[0] = v0;
+	text[2] = v0 >> 8;
+	text[4] = v0 >> 16;
+	text[6] = v0 >> 24;
+	text[1] = v1;
+	text[3] = v1 >> 8;
+	text[5] = v1 >> 16;
+	text[7] = v1 >> 24;
+}
+
+/*
+ * triple DES electronic codebook encryption of one block
+ */
+void
+triple_block_cipher(ulong expanded_key[3][32], uchar text[8], int ende)
+{
+	ulong *key;
+	u32int right, left, v0, v1;
+	int i, j, keystep;
+
+	/*
+	 * initial permutation
+	 */
+	v0 = text[0] | ((u32int)text[2]<<8) | ((u32int)text[4]<<16) | ((u32int)text[6]<<24);
+	left = text[1] | ((u32int)text[3]<<8) | ((u32int)text[5]<<16) | ((u32int)text[7]<<24);
+	right = (left & 0xaaaaaaaa) | ((v0 >> 1) & 0x55555555);
+	left = ((left << 1) & 0xaaaaaaaa) | (v0 & 0x55555555);
+	left = ((left << 6) & 0x33003300)
+		| (left & 0xcc33cc33)
+		| ((left >> 6) & 0x00cc00cc);
+	left = ((left << 12) & 0x0f0f0000)
+		| (left & 0xf0f00f0f)
+		| ((left >> 12) & 0x0000f0f0);
+	right = ((right << 6) & 0x33003300)
+		| (right & 0xcc33cc33)
+		| ((right >> 6) & 0x00cc00cc);
+	right = ((right << 12) & 0x0f0f0000)
+		| (right & 0xf0f00f0f)
+		| ((right >> 12) & 0x0000f0f0);
+
+	for(j = 0; j < 3; j++){
+		if((ende & 1) == DES3D) {
+			key = &expanded_key[2-j][32-2];
+			keystep = -2;
+		} else {
+			key = &expanded_key[j][0];
+			keystep = 2;
+		}
+		ende >>= 1;
+		for (i = 0; i < 8; i++) {
+			v0 = key[0];
+			v0 ^= (right >> 1) | (right << 31);
+			left ^= fetch(0, v0, 24)
+				^ fetch(2, v0, 16)
+				^ fetch(4, v0, 8)
+				^ fetch(6, v0, 0);
+			v1 = key[1];
+			v1 ^= (right << 3) | (right >> 29);
+			left ^= fetch(1, v1, 24)
+				^ fetch(3, v1, 16)
+				^ fetch(5, v1, 8)
+				^ fetch(7, v1, 0);
+			key += keystep;
+			
+			v0 = key[0];
+			v0 ^= (left >> 1) | (left << 31);
+			right ^= fetch(0, v0, 24)
+				^ fetch(2, v0, 16)
+				^ fetch(4, v0, 8)
+				^ fetch(6, v0, 0);
+			v1 = key[1];
+			v1 ^= (left << 3) | (left >> 29);
+			right ^= fetch(1, v1, 24)
+				^ fetch(3, v1, 16)
+				^ fetch(5, v1, 8)
+				^ fetch(7, v1, 0);
+			key += keystep;
+		}
+
+		v0 = left;
+		left = right;
+		right = v0;
+	}
+
+	/*
+	 * final permutation, inverse initial permutation
+	 * left and right are swapped here
+	 */
+	v0 = ((right << 1) & 0xaaaaaaaa) | (left & 0x55555555);
+	v1 = (right & 0xaaaaaaaa) | ((left >> 1) & 0x55555555);
+	v1 = ((v1 << 6) & 0x33003300)
+		| (v1 & 0xcc33cc33)
+		| ((v1 >> 6) & 0x00cc00cc);
+	v1 = ((v1 << 12) & 0x0f0f0000)
+		| (v1 & 0xf0f00f0f)
+		| ((v1 >> 12) & 0x0000f0f0);
+	v0 = ((v0 << 6) & 0x33003300)
+		| (v0 & 0xcc33cc33)
+		| ((v0 >> 6) & 0x00cc00cc);
+	v0 = ((v0 << 12) & 0x0f0f0000)
+		| (v0 & 0xf0f00f0f)
+		| ((v0 >> 12) & 0x0000f0f0);
+	text[0] = v0;
+	text[2] = v0 >> 8;
+	text[4] = v0 >> 16;
+	text[6] = v0 >> 24;
+	text[1] = v1;
+	text[3] = v1 >> 8;
+	text[5] = v1 >> 16;
+	text[7] = v1 >> 24;
+}
+
+/*
+ * key compression permutation, 4 bits at a time
+ */
+static u32int comptab[] = {
+
+0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088,
+0x000000,0x010000,0x000008,0x010008,0x000080,0x010080,0x000088,0x010088,
+
+0x000000,0x100000,0x000800,0x100800,0x000000,0x100000,0x000800,0x100800,
+0x002000,0x102000,0x002800,0x102800,0x002000,0x102000,0x002800,0x102800,
+
+0x000000,0x000004,0x000400,0x000404,0x000000,0x000004,0x000400,0x000404,
+0x400000,0x400004,0x400400,0x400404,0x400000,0x400004,0x400400,0x400404,
+
+0x000000,0x000020,0x008000,0x008020,0x800000,0x800020,0x808000,0x808020,
+0x000002,0x000022,0x008002,0x008022,0x800002,0x800022,0x808002,0x808022,
+
+0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200,
+0x000000,0x000200,0x200000,0x200200,0x001000,0x001200,0x201000,0x201200,
+
+0x000000,0x000040,0x000010,0x000050,0x004000,0x004040,0x004010,0x004050,
+0x040000,0x040040,0x040010,0x040050,0x044000,0x044040,0x044010,0x044050,
+
+0x000000,0x000100,0x020000,0x020100,0x000001,0x000101,0x020001,0x020101,
+0x080000,0x080100,0x0a0000,0x0a0100,0x080001,0x080101,0x0a0001,0x0a0101,
+
+0x000000,0x000100,0x040000,0x040100,0x000000,0x000100,0x040000,0x040100,
+0x000040,0x000140,0x040040,0x040140,0x000040,0x000140,0x040040,0x040140,
+
+0x000000,0x400000,0x008000,0x408000,0x000008,0x400008,0x008008,0x408008,
+0x000400,0x400400,0x008400,0x408400,0x000408,0x400408,0x008408,0x408408,
+
+0x000000,0x001000,0x080000,0x081000,0x000020,0x001020,0x080020,0x081020,
+0x004000,0x005000,0x084000,0x085000,0x004020,0x005020,0x084020,0x085020,
+
+0x000000,0x000800,0x000000,0x000800,0x000010,0x000810,0x000010,0x000810,
+0x800000,0x800800,0x800000,0x800800,0x800010,0x800810,0x800010,0x800810,
+
+0x000000,0x010000,0x000200,0x010200,0x000000,0x010000,0x000200,0x010200,
+0x100000,0x110000,0x100200,0x110200,0x100000,0x110000,0x100200,0x110200,
+
+0x000000,0x000004,0x000000,0x000004,0x000080,0x000084,0x000080,0x000084,
+0x002000,0x002004,0x002000,0x002004,0x002080,0x002084,0x002080,0x002084,
+
+0x000000,0x000001,0x200000,0x200001,0x020000,0x020001,0x220000,0x220001,
+0x000002,0x000003,0x200002,0x200003,0x020002,0x020003,0x220002,0x220003,
+};
+
+static int keysh[] =
+{
+	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1,
+};
+
+static void
+keycompperm(u32int left, u32int right, ulong *ek)
+{
+	u32int v0, v1;
+	int i;
+
+	for(i = 0; i < 16; i++){
+		left = (left << keysh[i]) | (left >> (28 - keysh[i]));
+		left &= 0xfffffff0;
+		right = (right << keysh[i]) | (right >> (28 - keysh[i]));
+		right &= 0xfffffff0;
+		v0 = comptab[6 * (1 << 4) + ((left >> (32-4)) & 0xf)]
+			| comptab[5 * (1 << 4) + ((left >> (32-8)) & 0xf)]
+			| comptab[4 * (1 << 4) + ((left >> (32-12)) & 0xf)]
+			| comptab[3 * (1 << 4) + ((left >> (32-16)) & 0xf)]
+			| comptab[2 * (1 << 4) + ((left >> (32-20)) & 0xf)]
+			| comptab[1 * (1 << 4) + ((left >> (32-24)) & 0xf)]
+			| comptab[0 * (1 << 4) + ((left >> (32-28)) & 0xf)];
+		v1 = comptab[13 * (1 << 4) + ((right >> (32-4)) & 0xf)]
+			| comptab[12 * (1 << 4) + ((right >> (32-8)) & 0xf)]
+			| comptab[11 * (1 << 4) + ((right >> (32-12)) & 0xf)]
+			| comptab[10 * (1 << 4) + ((right >> (32-16)) & 0xf)]
+			| comptab[9 * (1 << 4) + ((right >> (32-20)) & 0xf)]
+			| comptab[8 * (1 << 4) + ((right >> (32-24)) & 0xf)]
+			| comptab[7 * (1 << 4) + ((right >> (32-28)) & 0xf)];
+		ek[0] = (((v0 >> (24-6)) & 0x3f) << 26)
+			| (((v0 >> (24-18)) & 0x3f) << 18)
+			| (((v1 >> (24-6)) & 0x3f) << 10)
+			| (((v1 >> (24-18)) & 0x3f) << 2);
+		ek[1] = (((v0 >> (24-12)) & 0x3f) << 26)
+			| (((v0 >> (24-24)) & 0x3f) << 18)
+			| (((v1 >> (24-12)) & 0x3f) << 10)
+			| (((v1 >> (24-24)) & 0x3f) << 2);
+		ek += 2;
+	}
+}
+
+void
+des_key_setup(uchar key[8], ulong *ek)
+{
+	u32int left, right, v0, v1;
+
+	v0 = key[0] | ((u32int)key[2] << 8) | ((u32int)key[4] << 16) | ((u32int)key[6] << 24);
+	v1 = key[1] | ((u32int)key[3] << 8) | ((u32int)key[5] << 16) | ((u32int)key[7] << 24);
+	left = ((v0 >> 1) & 0x40404040)
+		| ((v0 >> 2) & 0x10101010)
+		| ((v0 >> 3) & 0x04040404)
+		| ((v0 >> 4) & 0x01010101)
+		| ((v1 >> 0) & 0x80808080)
+		| ((v1 >> 1) & 0x20202020)
+		| ((v1 >> 2) & 0x08080808)
+		| ((v1 >> 3) & 0x02020202);
+	right = ((v0 >> 1) & 0x04040404)
+		| ((v0 << 2) & 0x10101010)
+		| ((v0 << 5) & 0x40404040)
+		| ((v1 << 0) & 0x08080808)
+		| ((v1 << 3) & 0x20202020)
+		| ((v1 << 6) & 0x80808080);
+	left = ((left << 6) & 0x33003300)
+		| (left & 0xcc33cc33)
+		| ((left >> 6) & 0x00cc00cc);
+	v0 = ((left << 12) & 0x0f0f0000)
+		| (left & 0xf0f00f0f)
+		| ((left >> 12) & 0x0000f0f0);
+	right = ((right << 6) & 0x33003300)
+		| (right & 0xcc33cc33)
+		| ((right >> 6) & 0x00cc00cc);
+	v1 = ((right << 12) & 0x0f0f0000)
+		| (right & 0xf0f00f0f)
+		| ((right >> 12) & 0x0000f0f0);
+	left = v0 & 0xfffffff0;
+	right = (v1 & 0xffffff00) | ((v0 << 4) & 0xf0);
+
+	keycompperm(left, right, ek);
+}
+
+static uchar parity[128] =
+{
+	0x01, 0x02, 0x04, 0x07, 0x08, 0x0b, 0x0d, 0x0e, 
+	0x10, 0x13, 0x15, 0x16, 0x19, 0x1a, 0x1c, 0x1f, 
+	0x20, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c, 0x2f, 
+	0x31, 0x32, 0x34, 0x37, 0x38, 0x3b, 0x3d, 0x3e, 
+	0x40, 0x43, 0x45, 0x46, 0x49, 0x4a, 0x4c, 0x4f, 
+	0x51, 0x52, 0x54, 0x57, 0x58, 0x5b, 0x5d, 0x5e, 
+	0x61, 0x62, 0x64, 0x67, 0x68, 0x6b, 0x6d, 0x6e, 
+	0x70, 0x73, 0x75, 0x76, 0x79, 0x7a, 0x7c, 0x7f, 
+	0x80, 0x83, 0x85, 0x86, 0x89, 0x8a, 0x8c, 0x8f, 
+	0x91, 0x92, 0x94, 0x97, 0x98, 0x9b, 0x9d, 0x9e, 
+	0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xab, 0xad, 0xae, 
+	0xb0, 0xb3, 0xb5, 0xb6, 0xb9, 0xba, 0xbc, 0xbf, 
+	0xc1, 0xc2, 0xc4, 0xc7, 0xc8, 0xcb, 0xcd, 0xce, 
+	0xd0, 0xd3, 0xd5, 0xd6, 0xd9, 0xda, 0xdc, 0xdf, 
+	0xe0, 0xe3, 0xe5, 0xe6, 0xe9, 0xea, 0xec, 0xef, 
+	0xf1, 0xf2, 0xf4, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe,
+};
+
+/*
+ *  convert a 7 byte key to an 8 byte one
+ */
+void
+des56to64(uchar *k56, uchar *k64)
+{
+	u32int hi, lo;
+
+	hi = ((u32int)k56[0]<<24)|((u32int)k56[1]<<16)|((u32int)k56[2]<<8)|k56[3];
+	lo = ((u32int)k56[4]<<24)|((u32int)k56[5]<<16)|((u32int)k56[6]<<8);
+
+	k64[0] = parity[(hi>>25)&0x7f];
+	k64[1] = parity[(hi>>18)&0x7f];
+	k64[2] = parity[(hi>>11)&0x7f];
+	k64[3] = parity[(hi>>4)&0x7f];
+	k64[4] = parity[((hi<<3)|(lo>>29))&0x7f];
+	k64[5] = parity[(lo>>22)&0x7f];
+	k64[6] = parity[(lo>>15)&0x7f];
+	k64[7] = parity[(lo>>8)&0x7f];
+}
+
+/*
+ *  convert an 8 byte key to a 7 byte one
+ */
+void
+des64to56(uchar *k64, uchar *k56)
+{
+	u32int hi, lo;
+
+	hi = (((u32int)k64[0]&0xfe)<<24)|(((u32int)k64[1]&0xfe)<<17)|(((u32int)k64[2]&0xfe)<<10)
+		|((k64[3]&0xfe)<<3)|(k64[4]>>4);
+	lo = (((u32int)k64[4]&0xfe)<<28)|(((u32int)k64[5]&0xfe)<<21)|(((u32int)k64[6]&0xfe)<<14)
+		|(((u32int)k64[7]&0xfe)<<7);
+
+	k56[0] = hi>>24;
+	k56[1] = hi>>16;
+	k56[2] = hi>>8;
+	k56[3] = hi>>0;
+	k56[4] = lo>>24;
+	k56[5] = lo>>16;
+	k56[6] = lo>>8;
+}
+
+void
+key_setup(uchar key[7], ulong *ek)
+{
+	uchar k64[8];
+
+	des56to64(key, k64);
+	des_key_setup(k64, ek);	
+}
--- /dev/null
+++ b/libsec/port/des3CBC.c
@@ -1,0 +1,59 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Because of the way that non multiple of 8
+// buffers are handled, the decryptor must
+// be fed buffers of the same size as the
+// encryptor
+
+
+// If the length is not a multiple of 8, I encrypt
+// the overflow to be compatible with lacy's cryptlib
+void
+des3CBCencrypt(uchar *p, int len, DES3state *s)
+{
+	uchar *p2, *ip, *eip;
+
+	for(; len >= 8; len -= 8){
+		p2 = p;
+		ip = s->ivec;
+		for(eip = ip+8; ip < eip; )
+			*p2++ ^= *ip++;
+		triple_block_cipher(s->expanded, p, DES3EDE);
+		memmove(s->ivec, p, 8);
+		p += 8;
+	}
+
+	if(len > 0){
+		ip = s->ivec;
+		triple_block_cipher(s->expanded, ip, DES3EDE);
+		for(eip = ip+len; ip < eip; )
+			*p++ ^= *ip++;
+	}
+}
+
+void
+des3CBCdecrypt(uchar *p, int len, DES3state *s)
+{
+	uchar *ip, *eip, *tp;
+	uchar tmp[8];
+
+	for(; len >= 8; len -= 8){
+		memmove(tmp, p, 8);
+		triple_block_cipher(s->expanded, p, DES3DED);
+		tp = tmp;
+		ip = s->ivec;
+		for(eip = ip+8; ip < eip; ){
+			*p++ ^= *ip;
+			*ip++ = *tp++;
+		}
+	}
+
+	if(len > 0){
+		ip = s->ivec;
+		triple_block_cipher(s->expanded, ip, DES3EDE);
+		for(eip = ip+len; ip < eip; )
+			*p++ ^= *ip++;
+	}
+}
--- /dev/null
+++ b/libsec/port/des3ECB.c
@@ -1,0 +1,48 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// I wasn't sure what to do when the buffer was not
+// a multiple of 8.  I did what lacy's cryptolib did
+// to be compatible, but it looks dangerous to me
+// since its encrypting plain text with the key. -- presotto
+
+void
+des3ECBencrypt(uchar *p, int len, DES3state *s)
+{
+	int i;
+	uchar tmp[8];
+
+	for(; len >= 8; len -= 8){
+		triple_block_cipher(s->expanded, p, DES3EDE);
+		p += 8;
+	}
+	
+	if(len > 0){
+		for (i=0; i<8; i++)
+			tmp[i] = i;
+		triple_block_cipher(s->expanded, tmp, DES3EDE);
+		for (i = 0; i < len; i++)
+			p[i] ^= tmp[i];
+	}
+}
+
+void
+des3ECBdecrypt(uchar *p, int len, DES3state *s)
+{
+	int i;
+	uchar tmp[8];
+
+	for(; len >= 8; len -= 8){
+		triple_block_cipher(s->expanded, p, DES3DED);
+		p += 8;
+	}
+	
+	if(len > 0){
+		for (i=0; i<8; i++)
+			tmp[i] = i;
+		triple_block_cipher(s->expanded, tmp, DES3EDE);
+		for (i = 0; i < len; i++)
+			p[i] ^= tmp[i];
+	}
+}
--- /dev/null
+++ b/libsec/port/desCBC.c
@@ -1,0 +1,59 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Because of the way that non multiple of 8
+// buffers are handled, the decryptor must
+// be fed buffers of the same size as the
+// encryptor
+
+
+// If the length is not a multiple of 8, I encrypt
+// the overflow to be compatible with lacy's cryptlib
+void
+desCBCencrypt(uchar *p, int len, DESstate *s)
+{
+	uchar *p2, *ip, *eip;
+
+	for(; len >= 8; len -= 8){
+		p2 = p;
+		ip = s->ivec;
+		for(eip = ip+8; ip < eip; )
+			*p2++ ^= *ip++;
+		block_cipher(s->expanded, p, 0);
+		memmove(s->ivec, p, 8);
+		p += 8;
+	}
+
+	if(len > 0){
+		ip = s->ivec;
+		block_cipher(s->expanded, ip, 0);
+		for(eip = ip+len; ip < eip; )
+			*p++ ^= *ip++;
+	}
+}
+
+void
+desCBCdecrypt(uchar *p, int len, DESstate *s)
+{
+	uchar *ip, *eip, *tp;
+	uchar tmp[8];
+
+	for(; len >= 8; len -= 8){
+		memmove(tmp, p, 8);
+		block_cipher(s->expanded, p, 1);
+		tp = tmp;
+		ip = s->ivec;
+		for(eip = ip+8; ip < eip; ){
+			*p++ ^= *ip;
+			*ip++ = *tp++;
+		}
+	}
+
+	if(len > 0){
+		ip = s->ivec;
+		block_cipher(s->expanded, ip, 0);
+		for(eip = ip+len; ip < eip; )
+			*p++ ^= *ip++;
+	}
+}
--- /dev/null
+++ b/libsec/port/desECB.c
@@ -1,0 +1,48 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// I wasn't sure what to do when the buffer was not
+// a multiple of 8.  I did what lacy's cryptolib did
+// to be compatible, but it looks dangerous to me
+// since its encrypting plain text with the key. -- presotto
+
+void
+desECBencrypt(uchar *p, int len, DESstate *s)
+{
+	int i;
+	uchar tmp[8];
+
+	for(; len >= 8; len -= 8){
+		block_cipher(s->expanded, p, 0);
+		p += 8;
+	}
+	
+	if(len > 0){
+		for (i=0; i<8; i++)
+			tmp[i] = i;
+		block_cipher(s->expanded, tmp, 0);
+		for (i = 0; i < len; i++)
+			p[i] ^= tmp[i];
+	}
+}
+
+void
+desECBdecrypt(uchar *p, int len, DESstate *s)
+{
+	int i;
+	uchar tmp[8];
+
+	for(; len >= 8; len -= 8){
+		block_cipher(s->expanded, p, 1);
+		p += 8;
+	}
+	
+	if(len > 0){
+		for (i=0; i<8; i++)
+			tmp[i] = i;
+		block_cipher(s->expanded, tmp, 0);
+		for (i = 0; i < len; i++)
+			p[i] ^= tmp[i];
+	}
+}
--- /dev/null
+++ b/libsec/port/desmodes.c
@@ -1,0 +1,31 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ *  these routines use the 64bit format for
+ *  DES keys.
+ */
+
+void
+setupDESstate(DESstate *s, uchar key[8], uchar *ivec)
+{
+	memset(s, 0, sizeof(*s));
+	memmove(s->key, key, sizeof(s->key));
+	des_key_setup(key, s->expanded);
+	if(ivec)
+		memmove(s->ivec, ivec, 8);
+	s->setup = 0xdeadbeef;
+}
+
+void
+setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec)
+{
+	memset(s, 0, sizeof(*s));
+	memmove(s->key, key, sizeof(s->key));
+	des_key_setup(key[0], s->expanded[0]);
+	des_key_setup(key[1], s->expanded[1]);
+	des_key_setup(key[2], s->expanded[2]);
+	if(ivec)
+		memmove(s->ivec, ivec, 8);
+	s->setup = 0xdeadbeef;
+}
--- /dev/null
+++ b/libsec/port/dsaalloc.c
@@ -1,0 +1,72 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSApub*
+dsapuballoc(void)
+{
+	DSApub *dsa;
+
+	dsa = mallocz(sizeof(*dsa), 1);
+	if(dsa == nil)
+		sysfatal("dsapuballoc");
+	return dsa;
+}
+
+void
+dsapubfree(DSApub *dsa)
+{
+	if(dsa == nil)
+		return;
+	mpfree(dsa->p);
+	mpfree(dsa->q);
+	mpfree(dsa->alpha);
+	mpfree(dsa->key);
+	free(dsa);
+}
+
+
+DSApriv*
+dsaprivalloc(void)
+{
+	DSApriv *dsa;
+
+	dsa = mallocz(sizeof(*dsa), 1);
+	if(dsa == nil)
+		sysfatal("dsaprivalloc");
+	return dsa;
+}
+
+void
+dsaprivfree(DSApriv *dsa)
+{
+	if(dsa == nil)
+		return;
+	mpfree(dsa->pub.p);
+	mpfree(dsa->pub.q);
+	mpfree(dsa->pub.alpha);
+	mpfree(dsa->pub.key);
+	mpfree(dsa->secret);
+	free(dsa);
+}
+
+DSAsig*
+dsasigalloc(void)
+{
+	DSAsig *dsa;
+
+	dsa = mallocz(sizeof(*dsa), 1);
+	if(dsa == nil)
+		sysfatal("dsasigalloc");
+	return dsa;
+}
+
+void
+dsasigfree(DSAsig *dsa)
+{
+	if(dsa == nil)
+		return;
+	mpfree(dsa->r);
+	mpfree(dsa->s);
+	free(dsa);
+}
--- /dev/null
+++ b/libsec/port/dsagen.c
@@ -1,0 +1,58 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSApriv*
+dsagen(DSApub *opub)
+{
+	DSApub *pub;
+	DSApriv *priv;
+	mpint *exp;
+	mpint *g;
+	mpint *r;
+	int bits;
+
+	priv = dsaprivalloc();
+	pub = &priv->pub;
+
+	if(opub != nil){
+		pub->p = mpcopy(opub->p);
+		pub->q = mpcopy(opub->q);
+	} else {
+		pub->p = mpnew(0);
+		pub->q = mpnew(0);
+		DSAprimes(pub->q, pub->p, nil);
+	}
+	bits = Dbits*pub->p->top;
+
+	pub->alpha = mpnew(0);
+	pub->key = mpnew(0);
+	priv->secret = mpnew(0);
+
+	// find a generator alpha of the multiplicative
+	// group Z*p, i.e., of order n = p-1.  We use the
+	// fact that q divides p-1 to reduce the exponent.
+	exp = mpnew(0);
+	g = mpnew(0);
+	r = mpnew(0);
+	mpsub(pub->p, mpone, exp);
+	mpdiv(exp, pub->q, exp, r);
+	if(mpcmp(r, mpzero) != 0)
+		sysfatal("dsagen foul up");
+	while(1){
+		mprand(bits, genrandom, g);
+		mpmod(g, pub->p, g);
+		mpexp(g, exp, pub->p, pub->alpha);
+		if(mpcmp(pub->alpha, mpone) != 0)
+			break;
+	}
+	mpfree(g);
+	mpfree(exp);
+
+	// create the secret key
+	mprand(bits, genrandom, priv->secret);
+	mpmod(priv->secret, pub->p, priv->secret);
+	mpexp(pub->alpha, priv->secret, pub->p, pub->key);
+
+	return priv;
+}
--- /dev/null
+++ b/libsec/port/dsaprimes.c
@@ -1,0 +1,97 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// NIST algorithm for generating DSA primes
+// Menezes et al (1997) Handbook of Applied Cryptography, p.151
+// q is a 160-bit prime;  p is a 1024-bit prime;  q divides p-1
+
+// arithmetic on unsigned ints mod 2**160, represented
+//    as 20-byte, little-endian uchar array
+
+static void
+Hrand(uchar *s)
+{
+	ulong *u = (ulong*)s;
+	*u++ = fastrand();
+	*u++ = fastrand();
+	*u++ = fastrand();
+	*u++ = fastrand();
+	*u = fastrand();
+}
+
+static void
+Hincr(uchar *s)
+{
+	int i;
+	for(i=0; i<20; i++)
+		if(++s[i]!=0)
+			break;
+}
+
+// this can run for quite a while;  be patient
+void
+DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen])
+{
+	int i, j, k, n = 6, b = 63;
+	uchar s[SHA1dlen], Hs[SHA1dlen], Hs1[SHA1dlen], sj[SHA1dlen], sjk[SHA1dlen];
+	mpint *two1023, *mb, *Vk, *W, *X, *q2;
+
+	two1023 = mpnew(1024);
+	mpleft(mpone, 1023, two1023);
+	mb = mpnew(0);
+	mpleft(mpone, b, mb);
+	W = mpnew(1024);
+	Vk = mpnew(1024);
+	X = mpnew(0);
+	q2 = mpnew(0);
+forever:
+	do{
+		Hrand(s);
+		memcpy(sj, s, 20);
+		sha1(s, 20, Hs, 0);
+		Hincr(sj);
+		sha1(sj, 20, Hs1, 0);
+		for(i=0; i<20; i++)
+			Hs[i] ^= Hs1[i];
+		Hs[0] |= 1;
+		Hs[19] |= 0x80;
+		letomp(Hs, 20, q);
+	}while(!probably_prime(q, 18));
+	if(seed != nil)	// allow skeptics to confirm computation
+		memmove(seed, s, SHA1dlen);
+	i = 0;
+	j = 2;
+	Hincr(sj);
+	mpleft(q, 1, q2);
+	while(i<4096){
+		memcpy(sjk, sj, 20);
+		for(k=0; k <= n; k++){
+			sha1(sjk, 20, Hs, 0);
+			letomp(Hs, 20, Vk);
+			if(k == n)
+				mpmod(Vk, mb, Vk);
+			mpleft(Vk, 160*k, Vk);
+			mpadd(W, Vk, W);
+			Hincr(sjk);
+		}
+		mpadd(W, two1023, X);
+		mpmod(X, q2, W);
+		mpsub(W, mpone, W);
+		mpsub(X, W, p);
+		if(mpcmp(p, two1023)>=0 && probably_prime(p, 5))
+			goto done;
+		i += 1;
+		j += n+1;
+		for(k=0; k<n+1; k++)
+			Hincr(sj);
+	}
+	goto forever;
+done:
+	mpfree(q2);
+	mpfree(X);
+	mpfree(Vk);
+	mpfree(W);
+	mpfree(mb);
+	mpfree(two1023);
+}
--- /dev/null
+++ b/libsec/port/dsaprivtopub.c
@@ -1,0 +1,16 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSApub*
+dsaprivtopub(DSApriv *priv)
+{
+	DSApub *pub;
+
+	pub = dsapuballoc();
+	pub->p = mpcopy(priv->pub.p);
+	pub->q = mpcopy(priv->pub.q);
+	pub->alpha = mpcopy(priv->pub.alpha);
+	pub->key = mpcopy(priv->pub.key);
+	return pub;
+}
--- /dev/null
+++ b/libsec/port/dsasign.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+DSAsig*
+dsasign(DSApriv *priv, mpint *m)
+{
+	DSApub *pub = &priv->pub;
+	DSAsig *sig;
+	mpint *qm1, *k, *kinv, *r, *s;
+	mpint *q = pub->q, *p = pub->p, *alpha = pub->alpha;
+	int qlen = mpsignif(q);
+
+	qm1 = mpnew(0);
+	kinv = mpnew(0);
+	r = mpnew(0);
+	s = mpnew(0);
+	k = mpnew(0);
+	mpsub(pub->q, mpone, qm1);
+
+	// find a k that has an inverse mod q
+	while(1){
+		mprand(qlen, genrandom, k);
+		if((mpcmp(mpone, k) > 0) || (mpcmp(k, pub->q) >= 0))
+			continue;
+		mpextendedgcd(k, q, r, kinv, s);
+		if(mpcmp(r, mpone) != 0)
+			sysfatal("dsasign: pub->q not prime");
+		break;
+	}
+
+  	// make kinv positive
+	mpmod(kinv, pub->q, kinv);
+
+	// r = ((alpha**k) mod p) mod q
+	mpexp(alpha, k, p, r);
+	mpmod(r, q, r);
+
+	// s = (kinv*(m + ar)) mod q
+	mpmul(r, priv->secret, s);
+	mpadd(s, m, s);
+	mpmul(s, kinv, s);
+	mpmod(s, q, s);
+
+	sig = dsasigalloc();
+	sig->r = r;
+	sig->s = s;
+	mpfree(qm1);
+	mpfree(k);
+	mpfree(kinv);
+	return sig;
+}
--- /dev/null
+++ b/libsec/port/dsaverify.c
@@ -1,0 +1,46 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+int
+dsaverify(DSApub *pub, DSAsig *sig, mpint *m)
+{
+	int rv = -1;
+	mpint *u1, *u2, *v, *sinv;
+
+	if(mpcmp(sig->r, mpone) < 0 || mpcmp(sig->r, pub->q) >= 0)
+		return rv;
+	if(mpcmp(sig->s, mpone) < 0 || mpcmp(sig->s, pub->q) >= 0)
+		return rv;
+	u1 = mpnew(0);
+	u2 = mpnew(0);
+	v = mpnew(0);
+	sinv = mpnew(0);
+
+	// find (s**-1) mod q, make sure it exists
+	mpextendedgcd(sig->s, pub->q, u1, sinv, v);
+	if(mpcmp(u1, mpone) != 0)
+		goto out;
+
+	// u1 = (sinv * m) mod q, u2 = (r * sinv) mod q
+	mpmul(sinv, m, u1);
+	mpmod(u1, pub->q, u1);
+	mpmul(sig->r, sinv, u2);
+	mpmod(u2, pub->q, u2);
+
+	// v = (((alpha**u1)*(key**u2)) mod p) mod q
+	mpexp(pub->alpha, u1, pub->p, sinv);
+	mpexp(pub->key, u2, pub->p, v);
+	mpmul(sinv, v, v);
+	mpmod(v, pub->p, v);
+	mpmod(v, pub->q, v);
+
+	if(mpcmp(v, sig->r) == 0)
+		rv = 0;
+out:
+	mpfree(v);
+	mpfree(u1);
+	mpfree(u2);
+	mpfree(sinv);
+	return rv;
+}
--- /dev/null
+++ b/libsec/port/egalloc.c
@@ -1,0 +1,70 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGpub*
+egpuballoc(void)
+{
+	EGpub *eg;
+
+	eg = mallocz(sizeof(*eg), 1);
+	if(eg == nil)
+		sysfatal("egpuballoc");
+	return eg;
+}
+
+void
+egpubfree(EGpub *eg)
+{
+	if(eg == nil)
+		return;
+	mpfree(eg->p);
+	mpfree(eg->alpha);
+	mpfree(eg->key);
+	free(eg);
+}
+
+
+EGpriv*
+egprivalloc(void)
+{
+	EGpriv *eg;
+
+	eg = mallocz(sizeof(*eg), 1);
+	if(eg == nil)
+		sysfatal("egprivalloc");
+	return eg;
+}
+
+void
+egprivfree(EGpriv *eg)
+{
+	if(eg == nil)
+		return;
+	mpfree(eg->pub.p);
+	mpfree(eg->pub.alpha);
+	mpfree(eg->pub.key);
+	mpfree(eg->secret);
+	free(eg);
+}
+
+EGsig*
+egsigalloc(void)
+{
+	EGsig *eg;
+
+	eg = mallocz(sizeof(*eg), 1);
+	if(eg == nil)
+		sysfatal("egsigalloc");
+	return eg;
+}
+
+void
+egsigfree(EGsig *eg)
+{
+	if(eg == nil)
+		return;
+	mpfree(eg->r);
+	mpfree(eg->s);
+	free(eg);
+}
--- /dev/null
+++ b/libsec/port/egdecrypt.c
@@ -1,0 +1,28 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+mpint*
+egdecrypt(EGpriv *priv, mpint *in, mpint *out)
+{
+	EGpub *pub = &priv->pub;
+	mpint *gamma, *delta;
+	mpint *p = pub->p;
+	int plen = mpsignif(p)+1;
+	int shift = ((plen+Dbits-1)/Dbits)*Dbits;
+
+	if(out == nil)
+		out = mpnew(0);
+	gamma = mpnew(0);
+	delta = mpnew(0);
+	mpright(in, shift, gamma);
+	mpleft(gamma, shift, delta);
+	mpsub(in, delta, delta);	
+	mpexp(gamma, priv->secret, p, out);
+	mpinvert(out, p, gamma);
+	mpmul(gamma, delta, out);
+	mpmod(out, p, out);
+	mpfree(gamma);
+	mpfree(delta);
+	return out;
+}
--- /dev/null
+++ b/libsec/port/egencrypt.c
@@ -1,0 +1,38 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+mpint*
+egencrypt(EGpub *pub, mpint *in, mpint *out)
+{
+	mpint *m, *k, *gamma, *delta, *pm1;
+	mpint *p = pub->p, *alpha = pub->alpha;
+	int plen = mpsignif(p);
+	int shift = ((plen+Dbits)/Dbits)*Dbits;
+	// in libcrypt version, (int)(LENGTH(pub->p)*sizeof(NumType)*CHARBITS);
+
+	if(out == nil)
+		out = mpnew(0);
+	pm1 = mpnew(0);
+	m = mpnew(0);
+	gamma = mpnew(0);
+	delta = mpnew(0);
+	mpmod(in, p, m);
+	while(1){
+		k = mprand(plen, genrandom, nil);
+		if((mpcmp(mpone, k) <= 0) && (mpcmp(k, pm1) < 0))
+			break;
+	}
+	mpexp(alpha, k, p, gamma);
+	mpexp(pub->key, k, p, delta);
+	mpmul(m, delta, delta);
+	mpmod(delta, p, delta);
+	mpleft(gamma, shift, out);
+	mpadd(delta, out, out);
+	mpfree(pm1);
+	mpfree(m);
+	mpfree(k);
+	mpfree(gamma);
+	mpfree(delta);
+	return out;
+}
--- /dev/null
+++ b/libsec/port/eggen.c
@@ -1,0 +1,21 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGpriv*
+eggen(int nlen, int rounds)
+{
+	EGpub *pub;
+	EGpriv *priv;
+
+	priv = egprivalloc();
+	pub = &priv->pub;
+	pub->p = mpnew(0);
+	pub->alpha = mpnew(0);
+	pub->key = mpnew(0);
+	priv->secret = mpnew(0);
+	gensafeprime(pub->p, pub->alpha, nlen, rounds);
+	mprand(nlen-1, genrandom, priv->secret);
+	mpexp(pub->alpha, priv->secret, pub->p, pub->key);
+	return priv;
+}
--- /dev/null
+++ b/libsec/port/egprivtopub.c
@@ -1,0 +1,17 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGpub*
+egprivtopub(EGpriv *priv)
+{
+	EGpub *pub;
+
+	pub = egpuballoc();
+	if(pub == nil)
+		return nil;
+	pub->p = mpcopy(priv->pub.p);
+	pub->alpha = mpcopy(priv->pub.alpha);
+	pub->key = mpcopy(priv->pub.key);
+	return pub;
+}
--- /dev/null
+++ b/libsec/port/egsign.c
@@ -1,0 +1,43 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+EGsig*
+egsign(EGpriv *priv, mpint *m)
+{
+	EGpub *pub = &priv->pub;
+	EGsig *sig;
+	mpint *pm1, *k, *kinv, *r, *s;
+	mpint *p = pub->p, *alpha = pub->alpha;
+	int plen = mpsignif(p);
+
+	pm1 = mpnew(0);
+	kinv = mpnew(0);
+	r = mpnew(0);
+	s = mpnew(0);
+	k = mpnew(0);
+	mpsub(p, mpone, pm1);
+	while(1){
+		mprand(plen, genrandom, k);
+		if((mpcmp(mpone, k) > 0) || (mpcmp(k, pm1) >= 0))
+			continue;
+		mpextendedgcd(k, pm1, r, kinv, s);
+		if(mpcmp(r, mpone) != 0)
+			continue;
+		break;
+	}
+	mpmod(kinv, pm1, kinv);  // make kinv positive
+	mpexp(alpha, k, p, r);
+	mpmul(priv->secret, r, s);
+	mpmod(s, pm1, s);
+	mpsub(m, s, s);
+	mpmul(kinv, s, s);
+	mpmod(s, pm1, s);
+	sig = egsigalloc();
+	sig->r = r;
+	sig->s = s;
+	mpfree(pm1);
+	mpfree(k);
+	mpfree(kinv);
+	return sig;
+}
--- /dev/null
+++ b/libsec/port/egtest.c
@@ -1,0 +1,34 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+void
+main(void)
+{
+	EGpriv *sk;
+	mpint *m, *gamma, *delta, *in, *out;
+	int plen, shift;
+
+	fmtinstall('B', mpconv);
+
+	sk = egprivalloc();
+	sk->pub.p = uitomp(2357, nil);
+	sk->pub.alpha = uitomp(2, nil);
+	sk->pub.key = uitomp(1185, nil);
+	sk->secret = uitomp(1751, nil);
+
+	m = uitomp(2035, nil);
+
+	plen = mpsignif(sk->pub.p)+1;
+	shift = ((plen+Dbits-1)/Dbits)*Dbits;
+	gamma = uitomp(1430, nil);
+	delta = uitomp(697, nil);
+	out = mpnew(0);
+	in = mpnew(0);
+	mpleft(gamma, shift, in);
+	mpadd(delta, in, in);
+	egdecrypt(sk, in, out);
+
+	if(mpcmp(m, out) != 0)
+		print("decrypt failed to recover message\n");
+}
--- /dev/null
+++ b/libsec/port/egverify.c
@@ -1,0 +1,29 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+int
+egverify(EGpub *pub, EGsig *sig, mpint *m)
+{
+	mpint *p = pub->p, *alpha = pub->alpha;
+	mpint *r = sig->r, *s = sig->s;
+	mpint *v1, *v2, *rs;
+	int rv = -1;
+
+	if(mpcmp(r, mpone) < 0 || mpcmp(r, p) >= 0)
+		return rv;
+	v1 = mpnew(0);
+	rs = mpnew(0);
+	v2 = mpnew(0);
+	mpexp(pub->key, r, p, v1);
+	mpexp(r, s, p, rs);
+	mpmul(v1, rs, v1);
+	mpmod(v1, p, v1);
+	mpexp(alpha, m, p, v2);
+	if(mpcmp(v1, v2) == 0)
+		rv = 0;
+	mpfree(v1);
+	mpfree(rs);
+	mpfree(v2);
+	return rv;
+}
--- /dev/null
+++ b/libsec/port/fastrand.c
@@ -1,0 +1,15 @@
+#include	"os.h"
+#include	<libsec.h>
+
+/* 
+ *  use the X917 random number generator to create random
+ *  numbers (faster than truerand() but not as random).
+ */
+ulong
+fastrand(void)
+{
+	ulong x;
+	
+	genrandom((uchar*)&x, sizeof x);
+	return x;
+}
--- /dev/null
+++ b/libsec/port/genprime.c
@@ -1,0 +1,27 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+//  generate a probable prime.  accuracy is the miller-rabin interations
+void
+genprime(mpint *p, int n, int accuracy)
+{
+	mpdigit x;
+
+	// generate n random bits with high and low bits set
+	mpbits(p, n);
+	genrandom((uchar*)p->p, (n+7)/8);
+	p->top = (n+Dbits-1)/Dbits;
+	x = 1;
+	x <<= ((n-1)%Dbits);
+	p->p[p->top-1] &= (x-1);
+	p->p[p->top-1] |= x;
+	p->p[0] |= 1;
+
+	// keep icrementing till it looks prime
+	for(;;){
+		if(probably_prime(p, accuracy))
+			break;
+		mpadd(p, mptwo, p);
+	}
+}
--- /dev/null
+++ b/libsec/port/genrandom.c
@@ -1,0 +1,62 @@
+#include "os.h"
+#include "kernel.h"
+#include <mp.h>
+#include <libsec.h>
+
+typedef struct State{
+	int		seeded;
+	uvlong		seed;
+	DES3state	des3;
+} State;
+static State x917state;
+
+static void
+X917(uchar *rand, int nrand)
+{
+	int i, m, n8;
+	uvlong I, x;
+
+	/* 1. Compute intermediate value I = Ek(time). */
+	I = nsec();
+	triple_block_cipher(x917state.des3.expanded, (uchar*)&I, 0); /* two-key EDE */
+
+	/* 2. x[i] = Ek(I^seed);  seed = Ek(x[i]^I); */
+	m = (nrand+7)/8;
+	for(i=0; i<m; i++){
+		x = I ^ x917state.seed;
+		triple_block_cipher(x917state.des3.expanded, (uchar*)&x, 0);
+		n8 = (nrand>8) ? 8 : nrand;
+		memcpy(rand, (uchar*)&x, n8);
+		rand += 8;
+		nrand -= 8;
+		x ^= I;
+		triple_block_cipher(x917state.des3.expanded, (uchar*)&x, 0);
+		x917state.seed = x;
+	}
+}
+
+static void
+X917init(void)
+{
+	int n;
+	uchar mix[128];
+	uchar key3[3][8];
+	ulong *ulp;
+
+	ulp = (ulong*)key3;
+	for(n = 0; n < sizeof(key3)/sizeof(ulong); n++)
+		ulp[n] = truerand();
+	setupDES3state(&x917state.des3, key3, nil);
+	X917(mix, sizeof mix);
+	x917state.seeded = 1;
+}
+
+void
+genrandom(uchar *p, int n)
+{
+	_genrandomqlock();
+	if(x917state.seeded == 0)
+		X917init();
+	X917(p, n);
+	_genrandomqunlock();
+}
--- /dev/null
+++ b/libsec/port/gensafeprime.c
@@ -1,0 +1,36 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// find a prime p of length n and a generator alpha of Z^*_p
+// Alg 4.86 Menezes et al () Handbook, p.164
+void
+gensafeprime(mpint *p, mpint *alpha, int n, int accuracy)
+{
+	mpint *q, *b;
+
+	q = mpnew(n-1);
+	while(1){
+		genprime(q, n-1, accuracy);
+		mpleft(q, 1, p);
+		mpadd(p, mpone, p); // p = 2*q+1
+		if(probably_prime(p, accuracy))
+			break;
+	}
+	// now find a generator alpha of the multiplicative
+	// group Z*_p of order p-1=2q
+	b = mpnew(0);
+	while(1){
+		mprand(n, genrandom, alpha);
+		mpmod(alpha, p, alpha);
+		mpmul(alpha, alpha, b);
+		mpmod(b, p, b);
+		if(mpcmp(b, mpone) == 0)
+			continue;
+		mpexp(alpha, q, p, b);
+		if(mpcmp(b, mpone) != 0)
+			break;
+	}
+	mpfree(b);
+	mpfree(q);
+}
--- /dev/null
+++ b/libsec/port/genstrongprime.c
@@ -1,0 +1,57 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// Gordon's algorithm for generating a strong prime
+//	Menezes et al () Handbook, p.150
+void
+genstrongprime(mpint *p, int n, int accuracy)
+{
+	mpint *s, *t, *r, *i;
+
+	if(n < 64)
+		n = 64;
+
+	s = mpnew(n/2);
+	genprime(s, (n/2)-16, accuracy);
+	t = mpnew(n/2);
+	genprime(t, n-mpsignif(s)-32, accuracy);
+
+	// first r = 2it + 1 that's prime
+	i = mpnew(16);
+	r = mpnew(0);
+	itomp(0x8000, i);
+	mpleft(t, 1, t);	// 2t
+	mpmul(i, t, r);		// 2it
+	mpadd(r, mpone, r);	// 2it + 1
+	for(;;){
+		if(probably_prime(r, 18))
+			break;
+		mpadd(r, t, r);	// r += 2t
+	}
+
+	// p0 = 2(s**(r-2) mod r)s - 1
+	itomp(2, p);
+	mpsub(r, p, p);
+	mpexp(s, p, r, p);
+	mpmul(s, p, p);
+	mpleft(p, 1, p);
+	mpsub(p, mpone, p);
+
+	// first p = p0 + 2irs that's prime
+	itomp(0x8000, i);
+	mpleft(r, 1, r);	// 2r
+	mpmul(r, s, r);		// 2rs
+	mpmul(r, i, i);		// 2irs
+	mpadd(p, i, p);		// p0 + 2irs
+	for(;;){
+		if(probably_prime(p, accuracy))
+			break;
+		mpadd(p, r, p); // p += 2rs
+	}
+
+	mpfree(i);
+	mpfree(s);
+	mpfree(r);
+	mpfree(t);
+}
--- /dev/null
+++ b/libsec/port/hmac.c
@@ -1,0 +1,56 @@
+#include "os.h"
+#include <libsec.h>
+
+/* rfc2104 */
+static DigestState*
+hmac_x(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s,
+	DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), int xlen)
+{
+	int i;
+	uchar pad[65], innerdigest[256];
+
+	if(xlen > sizeof(innerdigest))
+		return nil;
+
+	if(klen>64)
+		return nil;
+
+	/* first time through */
+	if(s == nil || s->seeded == 0){
+		for(i=0; i<64; i++)
+			pad[i] = 0x36;
+		pad[64] = 0;
+		for(i=0; i<klen; i++)
+			pad[i] ^= key[i];
+		s = (*x)(pad, 64, nil, s);
+		if(s == nil)
+			return nil;
+	}
+
+	s = (*x)(p, len, nil, s);
+	if(digest == nil)
+		return s;
+
+	/* last time through */
+	for(i=0; i<64; i++)
+		pad[i] = 0x5c;
+	pad[64] = 0;
+	for(i=0; i<klen; i++)
+		pad[i] ^= key[i];
+	(*x)(nil, 0, innerdigest, s);
+	s = (*x)(pad, 64, nil, nil);
+	(*x)(innerdigest, xlen, digest, s);
+	return nil;
+}
+
+DigestState*
+hmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
+{
+	return hmac_x(p, len, key, klen, digest, s, sha1, SHA1dlen);
+}
+
+DigestState*
+hmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s)
+{
+	return hmac_x(p, len, key, klen, digest, s, md5, MD5dlen);
+}
--- /dev/null
+++ b/libsec/port/hmactest.c
@@ -1,0 +1,19 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+uchar key[] = "Jefe";
+uchar data[] = "what do ya want for nothing?";
+
+void
+main(void)
+{
+	int i;
+	uchar hash[MD5dlen];
+
+	hmac_md5(data, strlen((char*)data), key, 4, hash, nil);
+	for(i=0; i<MD5dlen; i++)
+		print("%2.2x", hash[i]);
+	print("\n");
+	print("750c783e6ab0b503eaa86e310a5db738\n");
+}
--- /dev/null
+++ b/libsec/port/idea.c
@@ -1,0 +1,168 @@
+#include "os.h"
+#include "mp.h"
+#include "libsec.h"
+
+#define KEYLEN	52
+
+#define	MODA	0x10000
+#define	MODM	0x10001
+#define	MASKA	(MODA-1)
+
+#define 	OP1(x, y)		((x) ^ (y))
+#define	OP2(x, y)		(((x) + (y)) & MASKA)
+#define 	OP3(x, y)		mod(x, y)
+
+#define	OP2INV(x)	(-(x))
+#define	OP3INV(x)	inv(x)
+
+#define BIGEND(k, i)	((k[i]<<8)|k[i+1])
+#define MSB(x)		((x)>>8)
+#define LSB(x)		((x)&0xff)
+
+static ushort
+mod(ushort x, ushort y)
+{
+	ushort q, r;
+	uint z;
+
+	if (x == 0)
+		return 1-y;
+	if (y == 0)
+		return 1-x;
+	z = (uint)x*(uint)y;
+	q = z >> 16;
+	r = z & MASKA;
+	return r-q+(r<q);
+}
+
+static ushort 
+inv(ushort x)
+{
+	int q, r0, r1, r2, v0, v1, v2;
+
+	if (x <= 1)
+		return x;
+	r0 = MODM;
+	r1 = x;
+	v0 = 0;
+	v1 = 1;
+	while (r1 != 0) {
+		q = r0/r1;
+		r2 = r0-q*r1;
+		v2 = v0-q*v1;
+		r0 = r1;
+		r1 = r2;
+		v0 = v1;
+		v1 = v2;
+	}
+	if (v0 < 0)
+		v0 += MODM;
+	return v0 & MASKA;
+}
+
+static void
+idea_key_setup_decrypt(ushort ek[KEYLEN], ushort dk[KEYLEN])
+{
+	int i;
+
+	for (i = 0; i < 54; i += 6) {
+		dk[i] = OP3INV(ek[48-i]);
+		dk[i+1] = OP2INV(ek[50-i]);
+		dk[i+2] = OP2INV(ek[49-i]);
+		dk[i+3] = OP3INV(ek[51-i]);
+		if (i < 48) {
+			dk[i+4] = ek[46-i];
+			dk[i+5] = ek[47-i];
+		}
+	}
+}
+
+void
+idea_key_setup(uchar key[16], ushort ek[2*KEYLEN])
+{
+	int i, j;
+	ushort tmp, *e = ek;
+
+	for (i = 0; i < 8; i++)
+		ek[i] = BIGEND(key, 2*i);
+	for (i = 8, j = 1; i < KEYLEN; i++, j++) {
+		ek[i] = (e[j&7]<<9)|(e[(j+1)&7]>>7);
+		if (((i+1) & 7) == 0)
+			e += 8;
+	}
+	tmp = ek[49];
+	ek[49] = ek[50];
+	ek[50] = tmp;
+	idea_key_setup_decrypt(ek, &ek[KEYLEN]);
+}
+
+void
+idea_cipher(ushort key[2*KEYLEN], uchar text[8], int decrypting)
+{
+	int i;
+	ushort *k;
+	ushort x[4];
+	ushort tmp, yout, zout;
+
+	k = decrypting ? &key[KEYLEN] : key;
+	for (i = 0; i < 4; i++)
+		x[i] = BIGEND(text, 2*i);
+	for (i = 0; i < 17; i++) {
+		if (!(i&1)) {		/* odd round */
+			x[0] = OP3(x[0], k[3*i]);
+			tmp = OP2(x[2], k[3*i+2]);
+			x[2] = OP2(x[1], k[3*i+1]);
+			x[3] = OP3(x[3], k[3*i+3]);
+			x[1] = tmp;
+		}
+		else {
+			tmp = OP3(k[3*i+1], OP1(x[0], x[1]));
+			yout = OP3(OP2(tmp, OP1(x[2], x[3])), k[3*i+2]);
+			zout = OP2(tmp, yout);
+			x[0] = OP1(x[0], yout);
+			x[1] = OP1(x[1], yout);
+			x[2] = OP1(x[2], zout);
+			x[3] = OP1(x[3], zout);
+		}
+	}
+	for (i = 0; i < 4; i++) {
+		text[2*i] = MSB(x[i]); 
+		text[2*i+1] = LSB(x[i]);
+	}
+}
+
+void
+setupIDEAstate(IDEAstate *s, uchar key[16], uchar *ivec)
+{
+	memset(s, 0, sizeof(*s));
+	memmove(s->key, key, sizeof(s->key));
+	idea_key_setup(key, s->edkey);
+	if(ivec)
+		memmove(s->ivec, ivec, 8);
+}
+
+/*
+void
+main()
+{
+	uchar key[] = { 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
+			        0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08 };
+	uchar plain[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03 };
+	uchar cipher[] = { 0x11, 0xFB, 0xED, 0x2B, 0x01, 0x98, 0x6D, 0xE5 };
+	ushort edkey[2*KEYLEN];
+	uchar tmp[8];
+
+	memcpy(tmp, plain, 8);
+	idea_key_setup(key, edkey);
+	idea_cipher(edkey, tmp, 0);
+	if (memcmp(tmp, cipher, 8)) {
+		print("encrypt wrong\n");
+		exits("");
+	}
+	idea_cipher(edkey, tmp, 1);
+	if (memcmp(tmp, plain, 8)) {
+		print("decrypt wrong\n");
+		exits("");
+	}
+}
+*/	
--- /dev/null
+++ b/libsec/port/md4.c
@@ -1,0 +1,271 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ *  This MD4 is implemented from the description in Stinson's Cryptography,
+ *  theory and practice. -- presotto
+ */
+
+/*
+ *	Rotate ammounts used in the algorithm
+ */
+enum
+{
+	S11=	3,
+	S12=	7,
+	S13=	11,
+	S14=	19,
+
+	S21=	3,
+	S22=	5,
+	S23=	9,
+	S24=	13,
+
+	S31=	3,
+	S32=	9,
+	S33=	11,
+	S34=	15,
+};
+
+typedef struct MD4Table MD4Table;
+struct MD4Table
+{
+	uchar	x;	/* index into data block */
+	uchar	rot;	/* amount to rotate left by */
+};
+
+static MD4Table tab[] =
+{
+	/* round 1 */
+/*[0]*/	{ 0,	S11},	
+	{ 1,	S12},	
+	{ 2,	S13},	
+	{ 3,	S14},	
+	{ 4,	S11},	
+	{ 5,	S12},	
+	{ 6,	S13},	
+	{ 7,	S14},	
+	{ 8,	S11},	
+	{ 9,	S12},	
+	{ 10,	S13},	
+	{ 11,	S14},	
+	{ 12,	S11},	
+	{ 13,	S12},	
+	{ 14,	S13},	
+	{ 15,	S14},
+
+	/* round 2 */
+/*[16]*/{ 0,	S21},	
+	{ 4,	S22},	
+	{ 8,	S23},	
+	{ 12,	S24},	
+	{ 1,	S21},	
+	{ 5,	S22},	
+	{ 9,	S23},	
+	{ 13,	S24},	
+	{ 2,	S21},	
+	{ 6,	S22},	
+	{ 10,	S23},	
+	{ 14,	S24},	
+	{ 3,	S21},	
+	{ 7,	S22},	
+	{ 11,	S23},	
+	{ 15,	S24},
+
+	/* round 3 */
+/*[32]*/{ 0,	S31},	
+	{ 8,	S32},	
+	{ 4,	S33},	
+	{ 12,	S34},	
+	{ 2,	S31},	
+	{ 10,	S32},	
+	{ 6,	S33},	
+	{ 14,	S34},	
+	{ 1,	S31},	
+	{ 9,	S32},	
+	{ 5,	S33},	
+	{ 13,	S34},	
+	{ 3,	S31},	
+	{ 11,	S32},	
+	{ 7,	S33},	
+	{ 15,	S34},	
+};
+
+static void encode(uchar*, u32int*, ulong);
+static void decode(u32int*, uchar*, ulong);
+
+static void
+md4block(uchar *p, ulong len, MD4state *s)
+{
+	int i;
+	u32int a, b, c, d, tmp;
+	MD4Table *t;
+	uchar *end;
+	u32int x[16];
+
+	for(end = p+len; p < end; p += 64){
+		a = s->state[0];
+		b = s->state[1];
+		c = s->state[2];
+		d = s->state[3];
+
+		decode(x, p, 64);
+	
+		for(i = 0; i < 48; i++){
+			t = tab + i;
+			switch(i>>4){
+			case 0:
+				a += (b & c) | (~b & d);
+				break;
+			case 1:
+				a += ((b & c) | (b & d) | (c & d)) + 0x5A827999;
+				break;
+			case 2:
+				a += (b ^ c ^ d) + 0x6ED9EBA1;
+				break;
+			}
+			a += x[t->x];
+			a = (a << t->rot) | (a >> (32 - t->rot));
+	
+			/* rotate variables */
+			tmp = d;
+			d = c;
+			c = b;
+			b = a;
+			a = tmp;
+		}
+
+		s->state[0] += a;
+		s->state[1] += b;
+		s->state[2] += c;
+		s->state[3] += d;
+
+		s->len += 64;
+	}
+}
+
+MD4state*
+md4(uchar *p, ulong len, uchar *digest, MD4state *s)
+{
+	u32int x[16];
+	uchar buf[128];
+	int i;
+	uchar *e;
+
+	if(s == nil){
+		s = malloc(sizeof(*s));
+		if(s == nil)
+			return nil;
+		memset(s, 0, sizeof(*s));
+		s->malloced = 1;
+	}
+
+	if(s->seeded == 0){
+		/* seed the state, these constants would look nicer big-endian */
+		s->state[0] = 0x67452301;
+		s->state[1] = 0xefcdab89;
+		s->state[2] = 0x98badcfe;
+		s->state[3] = 0x10325476;
+		s->seeded = 1;
+	}
+
+	/* fill out the partial 64 byte block from previous calls */
+	if(s->blen){
+		i = 64 - s->blen;
+		if(len < i)
+			i = len;
+		memmove(s->buf + s->blen, p, i);
+		len -= i;
+		s->blen += i;
+		p += i;
+		if(s->blen == 64){
+			md4block(s->buf, s->blen, s);
+			s->blen = 0;
+		}
+	}
+
+	/* do 64 byte blocks */
+	i = len & ~0x3f;
+	if(i){
+		md4block(p, i, s);
+		len -= i;
+		p += i;
+	}
+
+	/* save the left overs if not last call */
+	if(digest == 0){
+		if(len){
+			memmove(s->buf, p, len);
+			s->blen += len;
+		}
+		return s;
+	}
+
+	/*
+	 *  this is the last time through, pad what's left with 0x80,
+	 *  0's, and the input count to create a multiple of 64 bytes
+	 */
+	if(s->blen){
+		p = s->buf;
+		len = s->blen;
+	} else {
+		memmove(buf, p, len);
+		p = buf;
+	}
+	s->len += len;
+	e = p + len;
+	if(len < 56)
+		i = 56 - len;
+	else
+		i = 120 - len;
+	memset(e, 0, i);
+	*e = 0x80;
+	len += i;
+
+	/* append the count */
+	x[0] = s->len<<3;
+	x[1] = s->len>>29;
+	encode(p+len, x, 8);
+
+	/* digest the last part */
+	md4block(p, len+8, s);
+
+	/* return result and free state */
+	encode(digest, s->state, MD4dlen);
+	if(s->malloced == 1)
+		free(s);
+	return nil;
+}
+
+/*
+ *	encodes input (u32int) into output (uchar). Assumes len is
+ *	a multiple of 4.
+ */
+static void
+encode(uchar *output, u32int *input, ulong len)
+{
+	u32int x;
+	uchar *e;
+
+	for(e = output + len; output < e;) {
+		x = *input++;
+		*output++ = x;
+		*output++ = x >> 8;
+		*output++ = x >> 16;
+		*output++ = x >> 24;
+	}
+}
+
+/*
+ *	decodes input (uchar) into output (u32int). Assumes len is
+ *	a multiple of 4.
+ */
+static void
+decode(u32int *output, uchar *input, ulong len)
+{
+	uchar *e;
+
+	for(e = input+len; input < e; input += 4)
+		*output++ = input[0] | (input[1] << 8) |
+			(input[2] << 16) | (input[3] << 24);
+}
--- /dev/null
+++ b/libsec/port/md4test.c
@@ -1,0 +1,31 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+char *tests[] = {
+	"",
+	"a",
+	"abc",
+	"message digest",
+	"abcdefghijklmnopqrstuvwxyz",
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+	"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	0
+};
+
+void
+main(void)
+{
+	char **pp;
+	uchar *p;
+	int i;
+	uchar digest[MD5dlen];
+
+	for(pp = tests; *pp; pp++){
+		p = (uchar*)*pp;
+		md4(p, strlen(*pp), digest, 0);
+		for(i = 0; i < MD5dlen; i++)
+			print("%2.2ux", digest[i]);
+		print("\n");
+	}
+}
--- /dev/null
+++ b/libsec/port/md5.c
@@ -1,0 +1,147 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+
+static void encode(uchar*, u32int*, ulong);
+
+extern void _md5block(uchar*, ulong, u32int*);
+
+MD5state*
+md5(uchar *p, ulong len, uchar *digest, MD5state *s)
+{
+	u32int x[16];
+	uchar buf[128];
+	int i;
+	uchar *e;
+
+	if(s == nil){
+		s = malloc(sizeof(*s));
+		if(s == nil)
+			return nil;
+		memset(s, 0, sizeof(*s));
+		s->malloced = 1;
+	}
+
+	if(s->seeded == 0){
+		/* seed the state, these constants would look nicer big-endian */
+		s->state[0] = 0x67452301;
+		s->state[1] = 0xefcdab89;
+		s->state[2] = 0x98badcfe;
+		s->state[3] = 0x10325476;
+		s->seeded = 1;
+	}
+
+	/* fill out the partial 64 byte block from previous calls */
+	if(s->blen){
+		i = 64 - s->blen;
+		if(len < i)
+			i = len;
+		memmove(s->buf + s->blen, p, i);
+		len -= i;
+		s->blen += i;
+		p += i;
+		if(s->blen == 64){
+			_md5block(s->buf, s->blen, s->state);
+			s->len += s->blen;
+			s->blen = 0;
+		}
+	}
+
+	/* do 64 byte blocks */
+	i = len & ~0x3f;
+	if(i){
+		_md5block(p, i, s->state);
+		s->len += i;
+		len -= i;
+		p += i;
+	}
+
+	/* save the left overs if not last call */
+	if(digest == 0){
+		if(len){
+			memmove(s->buf, p, len);
+			s->blen += len;
+		}
+		return s;
+	}
+
+	/*
+	 *  this is the last time through, pad what's left with 0x80,
+	 *  0's, and the input count to create a multiple of 64 bytes
+	 */
+	if(s->blen){
+		p = s->buf;
+		len = s->blen;
+	} else {
+		memmove(buf, p, len);
+		p = buf;
+	}
+	s->len += len;
+	e = p + len;
+	if(len < 56)
+		i = 56 - len;
+	else
+		i = 120 - len;
+	memset(e, 0, i);
+	*e = 0x80;
+	len += i;
+
+	/* append the count */
+	x[0] = s->len<<3;
+	x[1] = s->len>>29;
+	encode(p+len, x, 8);
+
+	/* digest the last part */
+	_md5block(p, len+8, s->state);
+	s->len += len;
+
+	/* return result and free state */
+	encode(digest, s->state, MD5dlen);
+	if(s->malloced == 1)
+		free(s);
+	return nil;
+}
+
+/*
+ *	encodes input (u32int) into output (uchar). Assumes len is
+ *	a multiple of 4.
+ */
+static void
+encode(uchar *output, u32int *input, ulong len)
+{
+	u32int x;
+	uchar *e;
+
+	for(e = output + len; output < e;) {
+		x = *input++;
+		*output++ = x;
+		*output++ = x >> 8;
+		*output++ = x >> 16;
+		*output++ = x >> 24;
+	}
+}
--- /dev/null
+++ b/libsec/port/md5block.c
@@ -1,0 +1,267 @@
+#include "os.h"
+#include <libsec.h>
+
+/*
+ *  rfc1321 requires that I include this.  The code is new.  The constants
+ *  all come from the rfc (hence the copyright).  We trade a table for the
+ *  macros in rfc.  The total size is a lot less. -- presotto
+ *
+ *	Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ *	rights reserved.
+ *
+ *	License to copy and use this software is granted provided that it
+ *	is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ *	Algorithm" in all material mentioning or referencing this software
+ *	or this function.
+ *
+ *	License is also granted to make and use derivative works provided
+ *	that such works are identified as "derived from the RSA Data
+ *	Security, Inc. MD5 Message-Digest Algorithm" in all material
+ *	mentioning or referencing the derived work.
+ *
+ *	RSA Data Security, Inc. makes no representations concerning either
+ *	the merchantability of this software or the suitability of this
+ *	software forany particular purpose. It is provided "as is"
+ *	without express or implied warranty of any kind.
+ *	These notices must be retained in any copies of any part of this
+ *	documentation and/or software.
+ */
+
+/*
+ *	Rotate ammounts used in the algorithm
+ */
+enum
+{
+	S11=	7,
+	S12=	12,
+	S13=	17,
+	S14=	22,
+
+	S21=	5,
+	S22=	9,
+	S23=	14,
+	S24=	20,
+
+	S31=	4,
+	S32=	11,
+	S33=	16,
+	S34=	23,
+
+	S41=	6,
+	S42=	10,
+	S43=	15,
+	S44=	21
+};
+
+static u32int md5tab[] =
+{
+	/* round 1 */
+/*[0]*/	0xd76aa478,	
+	0xe8c7b756,	
+	0x242070db,	
+	0xc1bdceee,	
+	0xf57c0faf,	
+	0x4787c62a,	
+	0xa8304613,	
+	0xfd469501,	
+	0x698098d8,	
+	0x8b44f7af,	
+	0xffff5bb1,	
+	0x895cd7be,	
+	0x6b901122,	
+	0xfd987193,	
+	0xa679438e,	
+	0x49b40821,
+
+	/* round 2 */
+/*[16]*/0xf61e2562,	
+	0xc040b340,	
+	0x265e5a51,	
+	0xe9b6c7aa,	
+	0xd62f105d,	
+	 0x2441453,	
+	0xd8a1e681,	
+	0xe7d3fbc8,	
+	0x21e1cde6,	
+	0xc33707d6,	
+	0xf4d50d87,	
+	0x455a14ed,	
+	0xa9e3e905,	
+	0xfcefa3f8,	
+	0x676f02d9,	
+	0x8d2a4c8a,
+
+	/* round 3 */
+/*[32]*/0xfffa3942,	
+	0x8771f681,	
+	0x6d9d6122,	
+	0xfde5380c,	
+	0xa4beea44,	
+	0x4bdecfa9,	
+	0xf6bb4b60,	
+	0xbebfbc70,	
+	0x289b7ec6,	
+	0xeaa127fa,	
+	0xd4ef3085,	
+	 0x4881d05,	
+	0xd9d4d039,	
+	0xe6db99e5,	
+	0x1fa27cf8,	
+	0xc4ac5665,	
+
+	/* round 4 */
+/*[48]*/0xf4292244,	
+	0x432aff97,	
+	0xab9423a7,	
+	0xfc93a039,	
+	0x655b59c3,	
+	0x8f0ccc92,	
+	0xffeff47d,	
+	0x85845dd1,	
+	0x6fa87e4f,	
+	0xfe2ce6e0,	
+	0xa3014314,	
+	0x4e0811a1,	
+	0xf7537e82,	
+	0xbd3af235,	
+	0x2ad7d2bb,	
+	0xeb86d391,	
+};
+
+static void decode(u32int*, uchar*, ulong);
+extern void _md5block(uchar *p, ulong len, u32int *s);
+
+void
+_md5block(uchar *p, ulong len, u32int *s)
+{
+	u32int a, b, c, d, sh;
+	u32int *t;
+	uchar *end;
+	u32int x[16];
+
+	for(end = p+len; p < end; p += 64){
+		a = s[0];
+		b = s[1];
+		c = s[2];
+		d = s[3];
+
+		decode(x, p, 64);
+	
+		t = md5tab;
+		sh = 0;
+		for(; sh != 16; t += 4){
+			a += ((c ^ d) & b) ^ d;
+			a += x[sh] + t[0];
+			a = (a << S11) | (a >> (32 - S11));
+			a += b;
+
+			d += ((b ^ c) & a) ^ c;
+			d += x[sh + 1] + t[1];
+			d = (d << S12) | (d >> (32 - S12));
+			d += a;
+
+			c += ((a ^ b) & d) ^ b;
+			c += x[sh + 2] + t[2];
+			c = (c << S13) | (c >> (32 - S13));
+			c += d;
+
+			b += ((d ^ a) & c) ^ a;
+			b += x[sh + 3] + t[3];
+			b = (b << S14) | (b >> (32 - S14));
+			b += c;
+
+			sh += 4;
+		}
+		sh = 1;
+		for(; sh != 1+20*4; t += 4){
+			a += ((b ^ c) & d) ^ c;
+			a += x[sh & 0xf] + t[0];
+			a = (a << S21) | (a >> (32 - S21));
+			a += b;
+
+			d += ((a ^ b) & c) ^ b;
+			d += x[(sh + 5) & 0xf] + t[1];
+			d = (d << S22) | (d >> (32 - S22));
+			d += a;
+
+			c += ((d ^ a) & b) ^ a;
+			c += x[(sh + 10) & 0xf] + t[2];
+			c = (c << S23) | (c >> (32 - S23));
+			c += d;
+
+			b += ((c ^ d) & a) ^ d;
+			b += x[(sh + 15) & 0xf] + t[3];
+			b = (b << S24) | (b >> (32 - S24));
+			b += c;
+
+			sh += 20;
+		}
+		sh = 5;
+		for(; sh != 5+12*4; t += 4){
+			a += b ^ c ^ d;
+			a += x[sh & 0xf] + t[0];
+			a = (a << S31) | (a >> (32 - S31));
+			a += b;
+
+			d += a ^ b ^ c;
+			d += x[(sh + 3) & 0xf] + t[1];
+			d = (d << S32) | (d >> (32 - S32));
+			d += a;
+
+			c += d ^ a ^ b;
+			c += x[(sh + 6) & 0xf] + t[2];
+			c = (c << S33) | (c >> (32 - S33));
+			c += d;
+
+			b += c ^ d ^ a;
+			b += x[(sh + 9) & 0xf] + t[3];
+			b = (b << S34) | (b >> (32 - S34));
+			b += c;
+
+			sh += 12;
+		}
+		sh = 0;
+		for(; sh != 28*4; t += 4){
+			a += c ^ (b | ~d);
+			a += x[sh & 0xf] + t[0];
+			a = (a << S41) | (a >> (32 - S41));
+			a += b;
+
+			d += b ^ (a | ~c);
+			d += x[(sh + 7) & 0xf] + t[1];
+			d = (d << S42) | (d >> (32 - S42));
+			d += a;
+
+			c += a ^ (d | ~b);
+			c += x[(sh + 14) & 0xf] + t[2];
+			c = (c << S43) | (c >> (32 - S43));
+			c += d;
+
+			b += d ^ (c | ~a);
+			b += x[(sh + 21) & 0xf] + t[3];
+			b = (b << S44) | (b >> (32 - S44));
+			b += c;
+
+			sh += 28;
+		}
+
+		s[0] += a;
+		s[1] += b;
+		s[2] += c;
+		s[3] += d;
+	}
+}
+
+/*
+ *	decodes input (uchar) into output (u32int). Assumes len is
+ *	a multiple of 4.
+ */
+static void
+decode(u32int *output, uchar *input, ulong len)
+{
+	uchar *e;
+
+	for(e = input+len; input < e; input += 4)
+		*output++ = input[0] | (input[1] << 8) |
+			(input[2] << 16) | (input[3] << 24);
+}
--- /dev/null
+++ b/libsec/port/md5pickle.c
@@ -1,0 +1,39 @@
+#include "os.h"
+#include <libsec.h>
+
+char*
+md5pickle(MD5state *s)
+{
+	char *p;
+	int m, n;
+
+	m = 17+4*9+4*((s->blen+3)/3 + 1);
+	p = malloc(m);
+	if(p == nil)
+		return p;
+	n = sprint(p, "%16.16llux %8.8ux %8.8ux %8.8ux %8.8ux ",
+		s->len,
+		s->state[0], s->state[1], s->state[2],
+		s->state[3]);
+	enc64(p+n, m-n, s->buf, s->blen);
+	return p;
+}
+
+MD5state*
+md5unpickle(char *p)
+{
+	MD5state *s;
+
+	s = malloc(sizeof(*s));
+	if(s == nil)
+		return nil;
+	s->len = strtoull(p, &p, 16);
+	s->state[0] = strtoul(p, &p, 16);
+	s->state[1] = strtoul(p, &p, 16);
+	s->state[2] = strtoul(p, &p, 16);
+	s->state[3] = strtoul(p, &p, 16);
+	s->blen = dec64(s->buf, sizeof(s->buf), p, strlen(p));
+	s->malloced = 1;
+	s->seeded = 1;
+	return s;
+}
--- /dev/null
+++ b/libsec/port/mkfile
@@ -1,0 +1,33 @@
+<../../mkconfig
+
+LIB=libsec.a
+
+CFILES = des.c desmodes.c desECB.c desCBC.c des3ECB.c des3CBC.c\
+	aes.c blowfish.c \
+	idea.c \
+	hmac.c md5.c md5block.c md4.c sha1.c sha1block.c\
+	sha2.c sha256block.c sha512block.c\
+	sha1pickle.c md5pickle.c\
+	rc4.c\
+	genrandom.c prng.c fastrand.c nfastrand.c\
+	probably_prime.c smallprimetest.c genprime.c dsaprimes.c gensafeprime.c genstrongprime.c\
+	rsagen.c rsafill.c rsaencrypt.c rsadecrypt.c rsaalloc.c rsaprivtopub.c \
+	eggen.c egencrypt.c egdecrypt.c egalloc.c egprivtopub.c egsign.c egverify.c \
+	dsagen.c dsaalloc.c dsaprivtopub.c dsasign.c dsaverify.c \
+
+ALLOFILES=${CFILES:%.c=%.$O}
+
+# cull things in the per-machine directories from this list
+OFILES=	`{$SHELLNAME ./reduce-$SHELLTYPE $O $TARGMODEL-$OBJTYPE $ALLOFILES }
+
+HFILES=\
+	$ROOT/include/libsec.h\
+	$ROOT/libmp/port/os.h\
+
+CFLAGS=$CFLAGS -I../../libmp/port
+
+UPDATE=mkfile\
+	$HFILES\
+	$CFILES\
+
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
--- /dev/null
+++ b/libsec/port/nfastrand.c
@@ -1,0 +1,22 @@
+#include "os.h"
+#include <libsec.h>
+
+#define Maxrand	((1UL<<31)-1)
+
+ulong
+nfastrand(ulong n)
+{
+	ulong m, r;
+	
+	/*
+	 * set m to the maximum multiple of n <= 2^31-1
+	 * so we want a random number < m.
+	 */
+	if(n > Maxrand)
+		sysfatal("nfastrand: n too large");
+
+	m = Maxrand - Maxrand % n;
+	while((r = fastrand()) >= m)
+		;
+	return r%n;
+}
--- /dev/null
+++ b/libsec/port/primetest.c
@@ -1,0 +1,41 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+void
+main(void)
+{
+	mpint *z = mpnew(0);
+	mpint *p = mpnew(0);
+	mpint *q = mpnew(0);
+	mpint *nine = mpnew(0);
+
+	fmtinstall('B', mpconv);
+	strtomp("2492491", nil, 16, z);	// 38347921 = x*y = (2**28-9)/7, 
+				//    an example of 3**(n-1)=1 mod n
+	strtomp("15662C00E811", nil, 16, p);// 23528569104401, a prime
+	uitomp(9, nine);
+
+	if(probably_prime(z, 5) == 1)
+		fprint(2, "tricked primality test\n");
+	if(probably_prime(nine, 5) == 1)
+		fprint(2, "9 passed primality test!\n");
+	if(probably_prime(p, 25) == 1)
+		fprint(2, "ok\n");
+
+	DSAprimes(q, p, nil);
+	print("q=%B\np=%B\n", q, p);
+
+	exits(0);
+}
+
+// example output, checked with Maple:
+// seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E
+// q=E0F0EF284E10796C5A2A511E94748BA03C795C13
+//  = 1284186945063585093695748280224501481698995297299
+// p=C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBDB12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A863A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D93D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D
+//  = 137715385439333164327584575331308277462546592976152006175830654712456008630139443747529133857837818585400418619916530061955288983751958831927807888408309879880101870216437711393638413509484569804814373511469405934988856674935304074081350525593807908358867354528898618574659752879015380013845760006721861915693
+// r=DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241CEF2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E887D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D21C4656848614D888A4
+//  = 107239359478548771267308764204625458348785444483302647285245969203446101233421655396874997253111222983406676955642093641709149748793954493558324738441197139556917622937892491175016280660608595599724194374948056515856812347094848443460715881455884639869144172708
+// g=2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D2327173444ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD410E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734E3E2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1
+//  = 33081848392740465806285326014906437543653045153885419334085917570615301913274531387168723847139029827598735376746057461417880810924280288611116213062512408829164220104555543445909528701551198146080221790002337033997295756585193926863581671466708482411159477816144226847280417522524922667065714073338662508017
--- /dev/null
+++ b/libsec/port/prng.c
@@ -1,0 +1,15 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+//
+//  just use the libc prng to fill a buffer
+//
+void
+prng(uchar *p, int n)
+{
+	uchar *e;
+
+	for(e = p+n; p < e; p++)
+		*p = rand();
+}
--- /dev/null
+++ b/libsec/port/probably_prime.c
@@ -1,0 +1,89 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+/* Miller-Rabin probabilistic primality testing */
+/*	Knuth (1981) Seminumerical Algorithms, p.379 */
+/*	Menezes et al () Handbook, p.39 */
+/* 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep */
+int
+probably_prime(mpint *n, int nrep)
+{
+	int j, k, rep, nbits, isprime;
+	mpint *nm1, *q, *x, *y, *r;
+
+	if(n->sign < 0)
+		sysfatal("negative prime candidate");
+
+	if(nrep <= 0)
+		nrep = 18;
+
+	k = mptoi(n);
+	if(k == 2)		/* 2 is prime */
+		return 1;
+	if(k < 2)		/* 1 is not prime */
+		return 0;
+	if((n->p[0] & 1) == 0)	/* even is not prime */
+		return 0;
+
+	/* test against small prime numbers */
+	if(smallprimetest(n) < 0)
+		return 0;
+
+	/* fermat test, 2^n mod n == 2 if p is prime */
+	x = uitomp(2, nil);
+	y = mpnew(0);
+	mpexp(x, n, n, y);
+	k = mptoi(y);
+	if(k != 2){
+		mpfree(x);
+		mpfree(y);
+		return 0;
+	}
+
+	nbits = mpsignif(n);
+	nm1 = mpnew(nbits);
+	mpsub(n, mpone, nm1);	/* nm1 = n - 1 */
+	k = mplowbits0(nm1);
+	q = mpnew(0);
+	mpright(nm1, k, q);	/* q = (n-1)/2**k */
+
+	for(rep = 0; rep < nrep; rep++){
+		for(;;){
+			/* find x = random in [2, n-2] */
+			r = mprand(nbits, prng, nil);
+			mpmod(r, nm1, x);
+			mpfree(r);
+			if(mpcmp(x, mpone) > 0)
+				break;
+		}
+
+		/* y = x**q mod n */
+		mpexp(x, q, n, y);
+
+		if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0)
+			continue;
+
+		for(j = 1;; j++){
+			if(j >= k) {
+				isprime = 0;
+				goto done;
+			}
+			mpmul(y, y, x);
+			mpmod(x, n, y);	/* y = y*y mod n */
+			if(mpcmp(y, nm1) == 0)
+				break;
+			if(mpcmp(y, mpone) == 0){
+				isprime = 0;
+				goto done;
+			}
+		}
+	}
+	isprime = 1;
+done:
+	mpfree(y);
+	mpfree(x);
+	mpfree(q);
+	mpfree(nm1);
+	return isprime;
+}
--- /dev/null
+++ b/libsec/port/rc4.c
@@ -1,0 +1,104 @@
+#include "os.h"
+#include <libsec.h>
+
+void
+setupRC4state(RC4state *key, uchar *start, int n)
+{
+	int t;
+	int index2;
+	uchar *state;
+	uchar *p, *e, *sp, *se;
+
+	state = key->state;
+	se = &state[256];
+	for(sp = state; sp < se; sp++)
+		*sp = sp - state;
+
+	key->x = 0;
+	key->y = 0;
+	index2 = 0;
+	e = start + n;
+	p = start;
+	for(sp = state; sp < se; sp++)
+	{
+		t = *sp;
+		index2 = (*p + t + index2) & 255;
+		*sp = state[index2];
+		state[index2] = t;
+		if(++p >= e)
+			p = start;
+	}
+}
+
+void
+rc4(RC4state *key, uchar *p, int len)
+{
+	int tx, ty;
+	int x, y;
+	uchar *state;
+	uchar *e;
+
+	x = key->x;
+	y = key->y;
+	state = &key->state[0];
+	for(e = p + len; p < e; p++)
+	{
+		x = (x+1)&255;
+		tx = state[x];
+		y = (y+tx)&255;
+		ty = state[y];
+		state[x] = ty;
+		state[y] = tx;
+		*p ^= state[(tx+ty)&255];
+	}
+	key->x = x;
+	key->y = y;
+}
+
+void
+rc4skip(RC4state *key, int len)
+{
+	int tx, ty;
+	int x, y;
+	uchar *state;
+	int i;
+
+	x = key->x;
+	y = key->y;
+	state = &key->state[0];
+	for(i=0; i<len; i++)
+	{
+		x = (x+1)&255;
+		tx = state[x];
+		y = (y+tx)&255;
+		ty = state[y];
+		state[x] = ty;
+		state[y] = tx;
+	}
+	key->x = x;
+	key->y = y;
+}
+
+void
+rc4back(RC4state *key, int len)
+{
+	int tx, ty;
+	int x, y;
+	uchar *state;
+	int i;
+
+	x = key->x;
+	y = key->y;
+	state = &key->state[0];
+	for(i=0; i<len; i++)
+	{
+		ty = state[x];
+		tx = state[y];
+		state[y] = ty;
+		state[x] = tx;
+		y = (y-tx)&255;
+		x = (x-1)&255;
+	}
+	key->x = x;
+	key->y = y;
+}
--- /dev/null
+++ b/libsec/port/reduce-nt
@@ -1,0 +1,4 @@
+# for now, just return the input files
+shift	# $O
+shift	# $SYSTARG-$OBJTYPE
+echo -n $*
--- /dev/null
+++ b/libsec/port/reduce-rc
@@ -1,0 +1,16 @@
+O=$1
+shift
+nonport=$1
+shift
+
+ls -p ../$nonport/*.[cs] >[2]/dev/null | sed 's/..$//' > /tmp/reduce.$pid
+#
+#	if empty directory, just return the input files
+#
+if (! ~ $status '|') {
+	echo $*
+	rm /tmp/reduce.$pid
+	exit 0
+}
+echo $* | tr ' ' \012 | grep -v -f /tmp/reduce.$pid | tr \012 ' '
+rm /tmp/reduce.$pid
--- /dev/null
+++ b/libsec/port/reduce-sh
@@ -1,0 +1,13 @@
+O=$1
+shift
+nonport=$1
+shift
+
+for i in $*
+do
+	j=`echo $i | sed 's/\.'$O'//'`
+	if test ! -f ../$nonport/$j.c -a ! -f ../$nonport/$j.s -a ! -f ../$nonport/$j.spp
+	then
+		echo $i
+	fi
+done
--- /dev/null
+++ b/libsec/port/rsaalloc.c
@@ -1,0 +1,52 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApub*
+rsapuballoc(void)
+{
+	RSApub *rsa;
+
+	rsa = mallocz(sizeof(*rsa), 1);
+	if(rsa == nil)
+		sysfatal("rsapuballoc");
+	return rsa;
+}
+
+void
+rsapubfree(RSApub *rsa)
+{
+	if(rsa == nil)
+		return;
+	mpfree(rsa->ek);
+	mpfree(rsa->n);
+	free(rsa);
+}
+
+
+RSApriv*
+rsaprivalloc(void)
+{
+	RSApriv *rsa;
+
+	rsa = mallocz(sizeof(*rsa), 1);
+	if(rsa == nil)
+		sysfatal("rsaprivalloc");
+	return rsa;
+}
+
+void
+rsaprivfree(RSApriv *rsa)
+{
+	if(rsa == nil)
+		return;
+	mpfree(rsa->pub.ek);
+	mpfree(rsa->pub.n);
+	mpfree(rsa->dk);
+	mpfree(rsa->p);
+	mpfree(rsa->q);
+	mpfree(rsa->kp);
+	mpfree(rsa->kq);
+	mpfree(rsa->c2);
+	free(rsa);
+}
--- /dev/null
+++ b/libsec/port/rsadecrypt.c
@@ -1,0 +1,37 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+// decrypt rsa using garner's algorithm for the chinese remainder theorem
+//	seminumerical algorithms, knuth, pp 253-254
+//	applied cryptography, menezes et al, pg 612
+mpint*
+rsadecrypt(RSApriv *rsa, mpint *in, mpint *out)
+{
+	mpint *v1, *v2;
+
+	if(out == nil)
+		out = mpnew(0);
+
+	// convert in to modular representation
+	v1 = mpnew(0);
+	mpmod(in, rsa->p, v1);
+	v2 = mpnew(0);
+	mpmod(in, rsa->q, v2);
+
+	// exponentiate the modular rep
+	mpexp(v1, rsa->kp, rsa->p, v1);
+	mpexp(v2, rsa->kq, rsa->q, v2);
+	
+	// out = v1 + p*((v2-v1)*c2 mod q)
+	mpsub(v2, v1, v2);
+	mpmul(v2, rsa->c2, v2);
+	mpmod(v2, rsa->q, v2);
+	mpmul(v2, rsa->p, out);
+	mpadd(v1, out, out);
+
+	mpfree(v1);
+	mpfree(v2);
+
+	return out;
+}
--- /dev/null
+++ b/libsec/port/rsaencrypt.c
@@ -1,0 +1,12 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+mpint*
+rsaencrypt(RSApub *rsa, mpint *in, mpint *out)
+{
+	if(out == nil)
+		out = mpnew(0);
+	mpexp(in, rsa->ek, rsa->n, out);
+	return out;
+}
--- /dev/null
+++ b/libsec/port/rsafill.c
@@ -1,0 +1,61 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApriv*
+rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q)
+{
+	mpint *c2, *kq, *kp, *x;
+	RSApriv *rsa;
+
+	// make sure we're not being hoodwinked
+	if(!probably_prime(p, 10) || !probably_prime(q, 10)){
+		werrstr("rsafill: p or q not prime");
+		return nil;
+	}
+	x = mpnew(0);
+	mpmul(p, q, x);
+	if(mpcmp(n, x) != 0){
+		werrstr("rsafill: n != p*q");
+		mpfree(x);
+		return nil;
+	}
+	c2 = mpnew(0);
+	mpsub(p, mpone, c2);
+	mpsub(q, mpone, x);
+	mpmul(c2, x, x);
+	mpmul(e, d, c2);
+	mpmod(c2, x, x);
+	if(mpcmp(x, mpone) != 0){
+		werrstr("rsafill: e*d != 1 mod (p-1)*(q-1)");
+		mpfree(x);
+		mpfree(c2);
+		return nil;
+	}
+
+	// compute chinese remainder coefficient
+	mpinvert(p, q, c2);
+
+	// for crt a**k mod p == (a**(k mod p-1)) mod p
+	kq = mpnew(0);
+	kp = mpnew(0);
+	mpsub(p, mpone, x);
+	mpmod(d, x, kp);
+	mpsub(q, mpone, x);
+	mpmod(d, x, kq);
+
+	rsa = rsaprivalloc();
+	rsa->pub.ek = mpcopy(e);
+	rsa->pub.n = mpcopy(n);
+	rsa->dk = mpcopy(d);
+	rsa->kp = kp;
+	rsa->kq = kq;
+	rsa->p = mpcopy(p);
+	rsa->q = mpcopy(q);
+	rsa->c2 = c2;
+
+	mpfree(x);
+
+	return rsa;
+}
+
--- /dev/null
+++ b/libsec/port/rsagen.c
@@ -1,0 +1,70 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApriv*
+rsagen(int nlen, int elen, int rounds)
+{
+	mpint *p, *q, *e, *d, *phi, *n, *t1, *t2, *kp, *kq, *c2;
+	RSApriv *rsa;
+
+	p = mpnew(nlen/2);
+	q = mpnew(nlen/2);
+	n = mpnew(nlen);
+	e = mpnew(elen);
+	d = mpnew(0);
+	phi = mpnew(nlen);
+
+	// create the prime factors and euclid's function
+	genprime(p, nlen/2, rounds);
+	genprime(q, nlen - mpsignif(p) + 1, rounds);
+	mpmul(p, q, n);
+	mpsub(p, mpone, e);
+	mpsub(q, mpone, d);
+	mpmul(e, d, phi);
+
+	// find an e relatively prime to phi
+	t1 = mpnew(0);
+	t2 = mpnew(0);
+	mprand(elen, genrandom, e);
+	if(mpcmp(e,mptwo) <= 0)
+		itomp(3, e);
+	// See Menezes et al. p.291 "8.8 Note (selecting primes)" for discussion
+	// of the merits of various choices of primes and exponents.  e=3 is a
+	// common and recommended exponent, but doesn't necessarily work here
+	// because we chose strong rather than safe primes.
+	for(;;){
+		mpextendedgcd(e, phi, t1, d, t2);
+		if(mpcmp(t1, mpone) == 0)
+			break;
+		mpadd(mpone, e, e);
+	}
+	mpfree(t1);
+	mpfree(t2);
+
+	// compute chinese remainder coefficient
+	c2 = mpnew(0);
+	mpinvert(p, q, c2);
+
+	// for crt a**k mod p == (a**(k mod p-1)) mod p
+	kq = mpnew(0);
+	kp = mpnew(0);
+	mpsub(p, mpone, phi);
+	mpmod(d, phi, kp);
+	mpsub(q, mpone, phi);
+	mpmod(d, phi, kq);
+
+	rsa = rsaprivalloc();
+	rsa->pub.ek = e;
+	rsa->pub.n = n;
+	rsa->dk = d;
+	rsa->kp = kp;
+	rsa->kq = kq;
+	rsa->p = p;
+	rsa->q = q;
+	rsa->c2 = c2;
+
+	mpfree(phi);
+
+	return rsa;
+}
--- /dev/null
+++ b/libsec/port/rsaprivtopub.c
@@ -1,0 +1,16 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+RSApub*
+rsaprivtopub(RSApriv *priv)
+{
+	RSApub *pub;
+
+	pub = rsapuballoc();
+	if(pub == nil)
+		return nil;
+	pub->n = mpcopy(priv->pub.n);
+	pub->ek = mpcopy(priv->pub.ek);
+	return pub;
+}
--- /dev/null
+++ b/libsec/port/rsatest.c
@@ -1,0 +1,57 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+#include <bio.h>
+
+void
+main(void)
+{
+	RSApriv *rsa;
+	Biobuf b;
+	char *p;
+	int n;
+	mpint *clr, *enc, *clr2;
+	uchar buf[4096];
+	uchar *e;
+	vlong start;
+
+	fmtinstall('B', mpfmt);
+
+	rsa = rsagen(1024, 16, 0);
+	if(rsa == nil)
+		sysfatal("rsagen");
+	Binit(&b, 0, OREAD);
+	clr = mpnew(0);
+	clr2 = mpnew(0);
+	enc = mpnew(0);
+
+	strtomp("123456789abcdef123456789abcdef123456789abcdef123456789abcdef", nil, 16, clr);
+	rsaencrypt(&rsa->pub, clr, enc);
+	
+	start = nsec();
+	for(n = 0; n < 10; n++)
+		rsadecrypt(rsa, enc, clr);
+	print("%lld\n", nsec()-start);
+
+	start = nsec();
+	for(n = 0; n < 10; n++)
+		mpexp(enc, rsa->dk, rsa->pub.n, clr2);
+	print("%lld\n", nsec()-start);
+
+	if(mpcmp(clr, clr2) != 0)
+		print("%B != %B\n", clr, clr2);
+	
+	print("> ");
+	while(p = Brdline(&b, '\n')){
+		n = Blinelen(&b);
+		letomp((uchar*)p, n, clr);
+		print("clr %B\n", clr);
+		rsaencrypt(&rsa->pub, clr, enc);
+		print("enc %B\n", enc);
+		rsadecrypt(rsa, enc, clr);
+		print("clr %B\n", clr);
+		n = mptole(clr, buf, sizeof(buf), nil);
+		write(1, buf, n);
+		print("> ");
+	}
+}
--- /dev/null
+++ b/libsec/port/sha1.c
@@ -1,0 +1,127 @@
+#include "os.h"
+#include <libsec.h>
+
+static void encode(uchar*, u32int*, ulong);
+
+extern void _sha1block(uchar*, ulong, u32int*);
+
+/*
+ *  we require len to be a multiple of 64 for all but
+ *  the last call.  There must be room in the input buffer
+ *  to pad.
+ */
+SHA1state*
+sha1(uchar *p, ulong len, uchar *digest, SHA1state *s)
+{
+	uchar buf[128];
+	u32int x[16];
+	int i;
+	uchar *e;
+
+	if(s == nil){
+		s = malloc(sizeof(*s));
+		if(s == nil)
+			return nil;
+		memset(s, 0, sizeof(*s));
+		s->malloced = 1;
+	}
+
+	if(s->seeded == 0){
+		/* seed the state, these constants would look nicer big-endian */
+		s->state[0] = 0x67452301;
+		s->state[1] = 0xefcdab89;
+		s->state[2] = 0x98badcfe;
+		s->state[3] = 0x10325476;
+		s->state[4] = 0xc3d2e1f0;
+		s->seeded = 1;
+	}
+
+	/* fill out the partial 64 byte block from previous calls */
+	if(s->blen){
+		i = 64 - s->blen;
+		if(len < i)
+			i = len;
+		memmove(s->buf + s->blen, p, i);
+		len -= i;
+		s->blen += i;
+		p += i;
+		if(s->blen == 64){
+			_sha1block(s->buf, s->blen, s->state);
+			s->len += s->blen;
+			s->blen = 0;
+		}
+	}
+
+	/* do 64 byte blocks */
+	i = len & ~0x3f;
+	if(i){
+		_sha1block(p, i, s->state);
+		s->len += i;
+		len -= i;
+		p += i;
+	}
+
+	/* save the left overs if not last call */
+	if(digest == 0){
+		if(len){
+			memmove(s->buf, p, len);
+			s->blen += len;
+		}
+		return s;
+	}
+
+	/*
+	 *  this is the last time through, pad what's left with 0x80,
+	 *  0's, and the input count to create a multiple of 64 bytes
+	 */
+	if(s->blen){
+		p = s->buf;
+		len = s->blen;
+	} else {
+		memmove(buf, p, len);
+		p = buf;
+	}
+	s->len += len;
+	e = p + len;
+	if(len < 56)
+		i = 56 - len;
+	else
+		i = 120 - len;
+	memset(e, 0, i);
+	*e = 0x80;
+	len += i;
+
+	/* append the count */
+	x[0] = s->len>>29;
+	x[1] = s->len<<3;
+	encode(p+len, x, 8);
+
+	/* digest the last part */
+	_sha1block(p, len+8, s->state);
+	s->len += len+8;
+
+	/* return result and free state */
+	encode(digest, s->state, SHA1dlen);
+	if(s->malloced == 1)
+		free(s);
+	return nil;
+}
+
+/*
+ *	encodes input (ulong) into output (uchar). Assumes len is
+ *	a multiple of 4.
+ */
+static void
+encode(uchar *output, u32int *input, ulong len)
+{
+	u32int x;
+	uchar *e;
+
+	for(e = output + len; output < e;) {
+		x = *input++;
+		*output++ = x >> 24;
+		*output++ = x >> 16;
+		*output++ = x >> 8;
+		*output++ = x;
+	}
+}
--- /dev/null
+++ b/libsec/port/sha1block.c
@@ -1,0 +1,187 @@
+#include "os.h"
+
+void
+_sha1block(uchar *p, ulong len, u32int *s)
+{
+	u32int a, b, c, d, e, x;
+	uchar *end;
+	u32int *wp, *wend;
+	u32int w[80];
+
+	/* at this point, we have a multiple of 64 bytes */
+	for(end = p+len; p < end;){
+		a = s[0];
+		b = s[1];
+		c = s[2];
+		d = s[3];
+		e = s[4];
+
+		wend = w + 15;
+		for(wp = w; wp < wend; wp += 5){
+			wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+			e += ((a<<5) | (a>>27)) + wp[0];
+			e += 0x5a827999 + (((c^d)&b)^d);
+			b = (b<<30)|(b>>2);
+
+			wp[1] = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7];
+			d += ((e<<5) | (e>>27)) + wp[1];
+			d += 0x5a827999 + (((b^c)&a)^c);
+			a = (a<<30)|(a>>2);
+
+			wp[2] = (p[8]<<24) | (p[9]<<16) | (p[10]<<8) | p[11];
+			c += ((d<<5) | (d>>27)) + wp[2];
+			c += 0x5a827999 + (((a^b)&e)^b);
+			e = (e<<30)|(e>>2);
+
+			wp[3] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15];
+			b += ((c<<5) | (c>>27)) + wp[3];
+			b += 0x5a827999 + (((e^a)&d)^a);
+			d = (d<<30)|(d>>2);
+
+			wp[4] = (p[16]<<24) | (p[17]<<16) | (p[18]<<8) | p[19];
+			a += ((b<<5) | (b>>27)) + wp[4];
+			a += 0x5a827999 + (((d^e)&c)^e);
+			c = (c<<30)|(c>>2);
+			
+			p += 20;
+		}
+
+		wp[0] = (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+		e += ((a<<5) | (a>>27)) + wp[0];
+		e += 0x5a827999 + (((c^d)&b)^d);
+		b = (b<<30)|(b>>2);
+
+		x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+		wp[1] = (x<<1) | (x>>31);
+		d += ((e<<5) | (e>>27)) + wp[1];
+		d += 0x5a827999 + (((b^c)&a)^c);
+		a = (a<<30)|(a>>2);
+
+		x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+		wp[2] = (x<<1) | (x>>31);
+		c += ((d<<5) | (d>>27)) + wp[2];
+		c += 0x5a827999 + (((a^b)&e)^b);
+		e = (e<<30)|(e>>2);
+
+		x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+		wp[3] = (x<<1) | (x>>31);
+		b += ((c<<5) | (c>>27)) + wp[3];
+		b += 0x5a827999 + (((e^a)&d)^a);
+		d = (d<<30)|(d>>2);
+
+		x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+		wp[4] = (x<<1) | (x>>31);
+		a += ((b<<5) | (b>>27)) + wp[4];
+		a += 0x5a827999 + (((d^e)&c)^e);
+		c = (c<<30)|(c>>2);
+
+		wp += 5;
+		p += 4;
+
+		wend = w + 40;
+		for(; wp < wend; wp += 5){
+			x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16];
+			wp[0] = (x<<1) | (x>>31);
+			e += ((a<<5) | (a>>27)) + wp[0];
+			e += 0x6ed9eba1 + (b^c^d);
+			b = (b<<30)|(b>>2);
+
+			x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+			wp[1] = (x<<1) | (x>>31);
+			d += ((e<<5) | (e>>27)) + wp[1];
+			d += 0x6ed9eba1 + (a^b^c);
+			a = (a<<30)|(a>>2);
+
+			x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+			wp[2] = (x<<1) | (x>>31);
+			c += ((d<<5) | (d>>27)) + wp[2];
+			c += 0x6ed9eba1 + (e^a^b);
+			e = (e<<30)|(e>>2);
+
+			x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+			wp[3] = (x<<1) | (x>>31);
+			b += ((c<<5) | (c>>27)) + wp[3];
+			b += 0x6ed9eba1 + (d^e^a);
+			d = (d<<30)|(d>>2);
+
+			x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+			wp[4] = (x<<1) | (x>>31);
+			a += ((b<<5) | (b>>27)) + wp[4];
+			a += 0x6ed9eba1 + (c^d^e);
+			c = (c<<30)|(c>>2);
+		}
+
+		wend = w + 60;
+		for(; wp < wend; wp += 5){
+			x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16];
+			wp[0] = (x<<1) | (x>>31);
+			e += ((a<<5) | (a>>27)) + wp[0];
+			e += 0x8f1bbcdc + ((b&c)|((b|c)&d));
+			b = (b<<30)|(b>>2);
+
+			x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+			wp[1] = (x<<1) | (x>>31);
+			d += ((e<<5) | (e>>27)) + wp[1];
+			d += 0x8f1bbcdc + ((a&b)|((a|b)&c));
+			a = (a<<30)|(a>>2);
+
+			x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+			wp[2] = (x<<1) | (x>>31);
+			c += ((d<<5) | (d>>27)) + wp[2];
+			c += 0x8f1bbcdc + ((e&a)|((e|a)&b));
+			e = (e<<30)|(e>>2);
+
+			x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+			wp[3] = (x<<1) | (x>>31);
+			b += ((c<<5) | (c>>27)) + wp[3];
+			b += 0x8f1bbcdc + ((d&e)|((d|e)&a));
+			d = (d<<30)|(d>>2);
+
+			x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+			wp[4] = (x<<1) | (x>>31);
+			a += ((b<<5) | (b>>27)) + wp[4];
+			a += 0x8f1bbcdc + ((c&d)|((c|d)&e));
+			c = (c<<30)|(c>>2);
+		}
+
+		wend = w + 80;
+		for(; wp < wend; wp += 5){
+			x = wp[-3] ^ wp[-8] ^ wp[-14] ^ wp[-16];
+			wp[0] = (x<<1) | (x>>31);
+			e += ((a<<5) | (a>>27)) + wp[0];
+			e += 0xca62c1d6 + (b^c^d);
+			b = (b<<30)|(b>>2);
+
+			x = wp[-2] ^ wp[-7] ^ wp[-13] ^ wp[-15];
+			wp[1] = (x<<1) | (x>>31);
+			d += ((e<<5) | (e>>27)) + wp[1];
+			d += 0xca62c1d6 + (a^b^c);
+			a = (a<<30)|(a>>2);
+
+			x = wp[-1] ^ wp[-6] ^ wp[-12] ^ wp[-14];
+			wp[2] = (x<<1) | (x>>31);
+			c += ((d<<5) | (d>>27)) + wp[2];
+			c += 0xca62c1d6 + (e^a^b);
+			e = (e<<30)|(e>>2);
+
+			x = wp[0] ^ wp[-5] ^ wp[-11] ^ wp[-13];
+			wp[3] = (x<<1) | (x>>31);
+			b += ((c<<5) | (c>>27)) + wp[3];
+			b += 0xca62c1d6 + (d^e^a);
+			d = (d<<30)|(d>>2);
+
+			x = wp[1] ^ wp[-4] ^ wp[-10] ^ wp[-12];
+			wp[4] = (x<<1) | (x>>31);
+			a += ((b<<5) | (b>>27)) + wp[4];
+			a += 0xca62c1d6 + (c^d^e);
+			c = (c<<30)|(c>>2);
+		}
+
+		/* save state */
+		s[0] += a;
+		s[1] += b;
+		s[2] += c;
+		s[3] += d;
+		s[4] += e;
+	}
+}
--- /dev/null
+++ b/libsec/port/sha1pickle.c
@@ -1,0 +1,38 @@
+#include "os.h"
+#include <libsec.h>
+
+char*
+sha1pickle(SHA1state *s)
+{
+	char *p;
+	int m, n;
+
+	m = 5*9+4*((s->blen+3)/3);
+	p = malloc(m);
+	if(p == nil)
+		return p;
+	n = sprint(p, "%8.8ux %8.8ux %8.8ux %8.8ux %8.8ux ",
+		s->state[0], s->state[1], s->state[2],
+		s->state[3], s->state[4]);
+	enc64(p+n, m-n, s->buf, s->blen);
+	return p;
+}
+
+SHA1state*
+sha1unpickle(char *p)
+{
+	SHA1state *s;
+
+	s = malloc(sizeof(*s));
+	if(s == nil)
+		return nil;
+	s->state[0] = strtoul(p, &p, 16);
+	s->state[1] = strtoul(p, &p, 16);
+	s->state[2] = strtoul(p, &p, 16);
+	s->state[3] = strtoul(p, &p, 16);
+	s->state[4] = strtoul(p, &p, 16);
+	s->blen = dec64(s->buf, sizeof(s->buf), p, strlen(p));
+	s->malloced = 1;
+	s->seeded = 1;
+	return s;
+}
--- /dev/null
+++ b/libsec/port/sha2.c
@@ -1,0 +1,281 @@
+#include "os.h"
+#include <libsec.h>
+
+extern void _sha256block(SHA256state*, uchar*);
+extern void _sha512block(SHA512state*, uchar*);
+
+u32int sha224h0[] = {
+0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4,
+};
+u32int sha256h0[] = {
+0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
+};
+
+u64int sha384h0[] = {
+0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL, 0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
+0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL, 0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL,
+};
+u64int sha512h0[] = {
+0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
+0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL,
+};
+
+
+static SHA256state *
+sha256init(void)
+{
+	SHA256state *s;
+
+	s = malloc(sizeof(*s));
+	if(s == nil)
+		return nil;
+	s->malloced = 1;
+	s->seeded = 0;
+	s->len = 0;
+	s->blen = 0;
+
+	return s;
+}
+
+static void
+p32(u32int v, uchar *p)
+{
+	p[0] = v>>24;
+	p[1] = v>>16;
+	p[2] = v>>8;
+	p[3] = v>>0;
+}
+
+static void
+p64(u64int v, uchar *p)
+{
+	p32(v>>32, p);
+	p32(v, p+4);
+}
+
+enum {
+	HI	= 0,
+	LO	= 1,
+};
+static void
+p128(u64int v[2], uchar *p)
+{
+	p64(v[HI], p);
+	p64(v[LO], p+8);
+}
+
+static void
+uvvadd(u64int v[2], int n)
+{
+	v[LO] += n;
+	if(v[LO] < n)  /* overflow */
+		v[HI]++;
+}
+
+static void
+uvvmult8(u64int v[2])
+{
+	v[HI] = (v[HI]<<3) | (v[LO] >> (64-3));
+	v[LO] <<= 3;
+}
+
+
+static void
+_sha256(uchar *p, ulong len, SHA256state *s)
+{
+	u32int take;
+
+	/* complete possible partial block from last time */
+	if(s->blen > 0 && s->blen+len >= SHA256bsize) {
+		take = SHA256bsize-s->blen;
+		memmove(s->buf+s->blen, p, take);
+		p += take;
+		len -= take;
+		_sha256block(s, s->buf);
+		s->len += SHA256bsize;
+		s->blen = 0;
+		memset(s->buf, 0, SHA256bsize);
+	}
+	/* whole blocks */
+	while(len >= SHA256bsize) {
+		_sha256block(s, p);
+		s->len += SHA256bsize;
+		p += SHA256bsize;
+		len -= SHA256bsize;
+	}
+	/* keep possible leftover bytes */
+	if(len > 0) {
+		memmove(s->buf+s->blen, p, len);
+		s->blen += len;
+	}
+}
+
+static void
+sha256finish(SHA256state *s, uchar *digest, int smaller)
+{
+	int i;
+	uchar end[SHA256bsize+8];
+	u32int nzero, nb, nd;
+
+	nzero = (2*SHA256bsize - s->blen - 1 - 8) % SHA256bsize;
+	end[0] = 0x80;
+	memset(end+1, 0, nzero);
+	nb = 8*(s->len+s->blen);
+	p64(nb, end+1+nzero);
+	_sha256(end, 1+nzero+8, s);
+
+	nd = SHA256dlen/4;
+	if(smaller)
+		nd = SHA224dlen/4;
+	for(i = 0; i < nd; i++, digest += 4)
+		p32(s->h32[i], digest);
+}
+
+static SHA256state*
+sha256x(uchar *p, ulong len, uchar *digest, SHA256state *s, int smaller)
+{
+	if(s == nil) {
+		s = sha256init();
+		if(s == nil)
+			return nil;
+	}
+
+	if(s->seeded == 0){
+		memmove(s->h32, smaller? sha224h0: sha256h0, sizeof s->h32);
+		s->seeded = 1;
+	}
+
+	_sha256(p, len, s);
+
+	if(digest == 0)
+		return s;
+
+	sha256finish(s, digest, smaller);
+	if(s->malloced == 1)
+		free(s);
+	return nil;
+}
+
+SHA256state*
+sha224(uchar *p, ulong len, uchar *digest, SHA256state *s)
+{
+	return sha256x(p, len, digest, s, 1);
+}
+
+SHA256state*
+sha256(uchar *p, ulong len, uchar *digest, SHA256state *s)
+{
+	return sha256x(p, len, digest, s, 0);
+}
+
+
+static SHA512state *
+sha512init(void)
+{
+	SHA512state *s;
+
+	s = malloc(sizeof(*s));
+	if(s == nil)
+		return nil;
+	s->malloced = 1;
+	s->seeded = 0;
+	s->nb128[HI] = 0;
+	s->nb128[LO] = 0;
+	s->blen = 0;
+
+	return s;
+}
+
+static void
+_sha512(uchar *p, ulong len, SHA512state *s)
+{
+	u32int take;
+
+	/* complete possible partial block from last time */
+	if(s->blen > 0 && s->blen+len >= SHA512bsize) {
+		take = SHA512bsize-s->blen;
+		memmove(s->buf+s->blen, p, take);
+		p += take;
+		len -= take;
+		_sha512block(s, s->buf);
+		uvvadd(s->nb128, SHA512bsize);
+		s->blen = 0;
+		memset(s->buf, 0, SHA512bsize);
+	}
+	/* whole blocks */
+	while(len >= SHA512bsize) {
+		_sha512block(s, p);
+		uvvadd(s->nb128, SHA512bsize);
+		p += SHA512bsize;
+		len -= SHA512bsize;
+	}
+	/* keep possible leftover bytes */
+	if(len > 0) {
+		memmove(s->buf+s->blen, p, len);
+		s->blen += len;
+	}
+}
+
+void
+sha512finish(SHA512state *s, uchar *digest, int smaller)
+{
+	int i;
+	uchar end[SHA512bsize+16];
+	u32int nzero, n;
+	u64int nb[2];
+
+	nzero = (2*SHA512bsize - s->blen - 1 - 16) % SHA512bsize;
+	end[0] = 0x80;
+	memset(end+1, 0, nzero);
+	nb[0] = s->nb128[0];
+	nb[1] = s->nb128[1];
+	uvvadd(nb, s->blen);
+	uvvmult8(nb);
+	p128(nb, end+1+nzero);
+	_sha512(end, 1+nzero+16, s);
+
+	n = SHA512dlen/8;
+	if(smaller)
+		n = SHA384dlen/8;
+	for(i = 0; i < n; i++, digest += 8)
+		p64(s->h64[i], digest);
+}
+
+static SHA512state*
+sha512x(uchar *p, ulong len, uchar *digest, SHA512state *s, int smaller)
+{
+	if(s == nil) {
+		s = sha512init();
+		if(s == nil)
+			return nil;
+	}
+
+	if(s->seeded == 0){
+		memmove(s->h64, smaller? sha384h0: sha512h0, sizeof s->h64);
+		s->seeded = 1;
+	}
+
+	_sha512(p, len, s);
+
+	if(digest == 0)
+		return s;
+
+	sha512finish(s, digest, smaller);
+	if(s->malloced == 1)
+		free(s);
+	return nil;
+}
+
+SHA512state*
+sha384(uchar *p, ulong len, uchar *digest, SHA512state *s)
+{
+	return sha512x(p, len, digest, s, 1);
+}
+
+SHA512state*
+sha512(uchar *p, ulong len, uchar *digest, SHA512state *s)
+{
+	return sha512x(p, len, digest, s, 0);
+}
--- /dev/null
+++ b/libsec/port/sha256block.c
@@ -1,0 +1,81 @@
+#include "os.h"
+#include <libsec.h>
+
+enum {
+	SHA256rounds =  64,
+};
+
+u32int sha256const[] = {
+0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
+};
+
+
+#define CH(x,y,z)	((x&y) ^ (~x&z))
+#define MAJ(x,y,z)	((x&y) ^ (x&z) ^ (y&z))
+#define ROTR32(n, v)	((v>>n) | (v<<(32-n)))
+#define ROTR64(n, v)	((v>>n) | (v<<(64-n)))
+#define SHR(n, x)	(x>>n)
+
+#define SIGMA0a(x)	(ROTR32(2, x)^ROTR32(13, x)^ROTR32(22, x))
+#define SIGMA1a(x)	(ROTR32(6, x)^ROTR32(11, x)^ROTR32(25, x))
+#define sigma0a(x)	(ROTR32(7, x)^ROTR32(18, x)^SHR(3, x))
+#define sigma1a(x)	(ROTR32(17, x)^ROTR32(19, x)^SHR(10, x))
+
+/* for use in _sha*() */
+#define A	v[0]
+#define B	v[1]
+#define C	v[2]
+#define D	v[3]
+#define E	v[4]
+#define F	v[5]
+#define G	v[6]
+#define H	v[7]
+
+static u32int
+g32(uchar *p)
+{
+	return p[0]<<24|p[1]<<16|p[2]<<8|p[3]<<0;
+}
+
+void
+_sha256block(SHA256state *s, uchar *buf)
+{
+	u32int w[2*SHA256bsize/4];
+	int i, t;
+	u32int t1, t2;
+	u32int v[8];
+
+	for(t = 0; t < nelem(w)/2; t++) {
+		if(t < 16) {
+			w[t] = g32(buf);
+			buf += 4;
+		}
+	}
+
+	memmove(v, s->h32, sizeof s->h32);
+
+	for(t = 0; t < SHA256rounds; t++) {
+		if(t >= 16)
+			w[t&31] = sigma1a(w[(t-2)&31]) + w[(t-7)&31] + sigma0a(w[(t-15)&31]) + w[(t-16)&31];
+		t1 = H + SIGMA1a(E) + CH(E,F,G) + sha256const[t] + w[t&31];
+		t2 = SIGMA0a(A) + MAJ(A,B,C);
+		H = G;
+		G = F;
+		F = E;
+		E = D+t1;
+		D = C;
+		C = B;
+		B = A;
+		A = t1+t2;
+	}
+
+	for(i = 0; i < nelem(v); i++)
+		s->h32[i] += v[i];
+}
--- /dev/null
+++ b/libsec/port/sha512block.c
@@ -1,0 +1,114 @@
+#include "os.h"
+#include <libsec.h>
+
+
+enum {
+	SHA512rounds =  80,
+};
+
+u64int sha512const[] = {
+0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
+0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
+0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
+0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
+0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
+0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
+0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
+0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
+0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
+0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
+0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
+0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
+0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
+0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
+};
+
+
+static u32int
+g32(uchar *p)
+{
+	return p[0]<<24|p[1]<<16|p[2]<<8|p[3]<<0;
+}
+
+static u64int
+g64(uchar *p)
+{
+	return ((u64int)g32(p)<<32)|g32(p+4);
+}
+
+
+#define CH(x,y,z)	((x&y) ^ (~x&z))
+#define MAJ(x,y,z)	((x&y) ^ (x&z) ^ (y&z))
+#define ROTR32(n, v)	((v>>n) | (v<<(32-n)))
+#define ROTR64(n, v)	((v>>n) | (v<<(64-n)))
+#define SHR(n, x)	(x>>n)
+
+#define SIGMA0b(x)	(ROTR64(28, x)^ROTR64(34, x)^ROTR64(39, x))
+#define SIGMA1b(x)	(ROTR64(14, x)^ROTR64(18, x)^ROTR64(41, x))
+#define sigma0b(x)	(ROTR64(1, x)^ROTR64(8, x)^SHR(7, x))
+#define sigma1b(x)	(ROTR64(19, x)^ROTR64(61, x)^SHR(6, x))
+
+#define A	v[0]
+#define B	v[1]
+#define C	v[2]
+#define D	v[3]
+#define E	v[4]
+#define F	v[5]
+#define G	v[6]
+#define H	v[7]
+
+void
+_sha512block(SHA512state *s, uchar *buf)
+{
+	u64int w[2*SHA512bsize/8];
+	int i, t;
+	u64int t1, t2, t3, v[8];
+
+	for(t = 0; t < nelem(w)/2; t++) {
+		if(t < 16) {
+			w[t] = g64(buf);
+			buf += 8;
+		}
+	}
+
+	memmove(v, s->h64, sizeof s->h64);
+
+	for(t = 0; t < SHA512rounds; t++) {
+		if(t >= 16) {
+			/* w[t&31] = sigma1b(w[(t-2)&31]) + w[(t-7)&31] + sigma0b(w[(t-15)&31]) + w[(t-16)&31]; */
+			t2 = w[(t-2)&31];
+			t3 = w[(t-15)&31];
+			/* w[t&31] = sigma1b(t2) + w[(t-7)&31] + sigma0b(t3) + w[(t-16)&31]; */
+			t1 = sigma1b(t2);
+			t1 += w[(t-7)&31];
+			t1 +=  sigma0b(t3);
+			t1 += w[(t-16)&31];
+			w[t&31] = t1;
+		}
+		/* t1 = H + SIGMA1b(E) + CH(E,F,G) + sha512const[t] + w[t&31]; */
+		t1 = H;
+		t1 += SIGMA1b(E);
+		t1 += CH(E, F, G);
+		t1 += sha512const[t] + w[t&31];
+		/* t2 = SIGMA0b(A) + MAJ(A,B,C); */
+		t2 = SIGMA0b(A);
+		t2 += MAJ(A, B, C);
+		H = G;
+		G = F;
+		F = E;
+		E = D+t1;
+		D = C;
+		C = B;
+		B = A;
+		A = t1+t2;
+	}
+
+	for(i = 0; i < nelem(v); i++)
+		s->h64[i] += v[i];
+}
--- /dev/null
+++ b/libsec/port/smallprimes.c
@@ -1,0 +1,1004 @@
+#include "os.h"
+
+ulong smallprimes[1000] = {
+	2,
+	3,
+	5,
+	7,
+	11,
+	13,
+	17,
+	19,
+	23,
+	29,
+	31,
+	37,
+	41,
+	43,
+	47,
+	53,
+	59,
+	61,
+	67,
+	71,
+	73,
+	79,
+	83,
+	89,
+	97,
+	101,
+	103,
+	107,
+	109,
+	113,
+	127,
+	131,
+	137,
+	139,
+	149,
+	151,
+	157,
+	163,
+	167,
+	173,
+	179,
+	181,
+	191,
+	193,
+	197,
+	199,
+	211,
+	223,
+	227,
+	229,
+	233,
+	239,
+	241,
+	251,
+	257,
+	263,
+	269,
+	271,
+	277,
+	281,
+	283,
+	293,
+	307,
+	311,
+	313,
+	317,
+	331,
+	337,
+	347,
+	349,
+	353,
+	359,
+	367,
+	373,
+	379,
+	383,
+	389,
+	397,
+	401,
+	409,
+	419,
+	421,
+	431,
+	433,
+	439,
+	443,
+	449,
+	457,
+	461,
+	463,
+	467,
+	479,
+	487,
+	491,
+	499,
+	503,
+	509,
+	521,
+	523,
+	541,
+	547,
+	557,
+	563,
+	569,
+	571,
+	577,
+	587,
+	593,
+	599,
+	601,
+	607,
+	613,
+	617,
+	619,
+	631,
+	641,
+	643,
+	647,
+	653,
+	659,
+	661,
+	673,
+	677,
+	683,
+	691,
+	701,
+	709,
+	719,
+	727,
+	733,
+	739,
+	743,
+	751,
+	757,
+	761,
+	769,
+	773,
+	787,
+	797,
+	809,
+	811,
+	821,
+	823,
+	827,
+	829,
+	839,
+	853,
+	857,
+	859,
+	863,
+	877,
+	881,
+	883,
+	887,
+	907,
+	911,
+	919,
+	929,
+	937,
+	941,
+	947,
+	953,
+	967,
+	971,
+	977,
+	983,
+	991,
+	997,
+	1009,
+	1013,
+	1019,
+	1021,
+	1031,
+	1033,
+	1039,
+	1049,
+	1051,
+	1061,
+	1063,
+	1069,
+	1087,
+	1091,
+	1093,
+	1097,
+	1103,
+	1109,
+	1117,
+	1123,
+	1129,
+	1151,
+	1153,
+	1163,
+	1171,
+	1181,
+	1187,
+	1193,
+	1201,
+	1213,
+	1217,
+	1223,
+	1229,
+	1231,
+	1237,
+	1249,
+	1259,
+	1277,
+	1279,
+	1283,
+	1289,
+	1291,
+	1297,
+	1301,
+	1303,
+	1307,
+	1319,
+	1321,
+	1327,
+	1361,
+	1367,
+	1373,
+	1381,
+	1399,
+	1409,
+	1423,
+	1427,
+	1429,
+	1433,
+	1439,
+	1447,
+	1451,
+	1453,
+	1459,
+	1471,
+	1481,
+	1483,
+	1487,
+	1489,
+	1493,
+	1499,
+	1511,
+	1523,
+	1531,
+	1543,
+	1549,
+	1553,
+	1559,
+	1567,
+	1571,
+	1579,
+	1583,
+	1597,
+	1601,
+	1607,
+	1609,
+	1613,
+	1619,
+	1621,
+	1627,
+	1637,
+	1657,
+	1663,
+	1667,
+	1669,
+	1693,
+	1697,
+	1699,
+	1709,
+	1721,
+	1723,
+	1733,
+	1741,
+	1747,
+	1753,
+	1759,
+	1777,
+	1783,
+	1787,
+	1789,
+	1801,
+	1811,
+	1823,
+	1831,
+	1847,
+	1861,
+	1867,
+	1871,
+	1873,
+	1877,
+	1879,
+	1889,
+	1901,
+	1907,
+	1913,
+	1931,
+	1933,
+	1949,
+	1951,
+	1973,
+	1979,
+	1987,
+	1993,
+	1997,
+	1999,
+	2003,
+	2011,
+	2017,
+	2027,
+	2029,
+	2039,
+	2053,
+	2063,
+	2069,
+	2081,
+	2083,
+	2087,
+	2089,
+	2099,
+	2111,
+	2113,
+	2129,
+	2131,
+	2137,
+	2141,
+	2143,
+	2153,
+	2161,
+	2179,
+	2203,
+	2207,
+	2213,
+	2221,
+	2237,
+	2239,
+	2243,
+	2251,
+	2267,
+	2269,
+	2273,
+	2281,
+	2287,
+	2293,
+	2297,
+	2309,
+	2311,
+	2333,
+	2339,
+	2341,
+	2347,
+	2351,
+	2357,
+	2371,
+	2377,
+	2381,
+	2383,
+	2389,
+	2393,
+	2399,
+	2411,
+	2417,
+	2423,
+	2437,
+	2441,
+	2447,
+	2459,
+	2467,
+	2473,
+	2477,
+	2503,
+	2521,
+	2531,
+	2539,
+	2543,
+	2549,
+	2551,
+	2557,
+	2579,
+	2591,
+	2593,
+	2609,
+	2617,
+	2621,
+	2633,
+	2647,
+	2657,
+	2659,
+	2663,
+	2671,
+	2677,
+	2683,
+	2687,
+	2689,
+	2693,
+	2699,
+	2707,
+	2711,
+	2713,
+	2719,
+	2729,
+	2731,
+	2741,
+	2749,
+	2753,
+	2767,
+	2777,
+	2789,
+	2791,
+	2797,
+	2801,
+	2803,
+	2819,
+	2833,
+	2837,
+	2843,
+	2851,
+	2857,
+	2861,
+	2879,
+	2887,
+	2897,
+	2903,
+	2909,
+	2917,
+	2927,
+	2939,
+	2953,
+	2957,
+	2963,
+	2969,
+	2971,
+	2999,
+	3001,
+	3011,
+	3019,
+	3023,
+	3037,
+	3041,
+	3049,
+	3061,
+	3067,
+	3079,
+	3083,
+	3089,
+	3109,
+	3119,
+	3121,
+	3137,
+	3163,
+	3167,
+	3169,
+	3181,
+	3187,
+	3191,
+	3203,
+	3209,
+	3217,
+	3221,
+	3229,
+	3251,
+	3253,
+	3257,
+	3259,
+	3271,
+	3299,
+	3301,
+	3307,
+	3313,
+	3319,
+	3323,
+	3329,
+	3331,
+	3343,
+	3347,
+	3359,
+	3361,
+	3371,
+	3373,
+	3389,
+	3391,
+	3407,
+	3413,
+	3433,
+	3449,
+	3457,
+	3461,
+	3463,
+	3467,
+	3469,
+	3491,
+	3499,
+	3511,
+	3517,
+	3527,
+	3529,
+	3533,
+	3539,
+	3541,
+	3547,
+	3557,
+	3559,
+	3571,
+	3581,
+	3583,
+	3593,
+	3607,
+	3613,
+	3617,
+	3623,
+	3631,
+	3637,
+	3643,
+	3659,
+	3671,
+	3673,
+	3677,
+	3691,
+	3697,
+	3701,
+	3709,
+	3719,
+	3727,
+	3733,
+	3739,
+	3761,
+	3767,
+	3769,
+	3779,
+	3793,
+	3797,
+	3803,
+	3821,
+	3823,
+	3833,
+	3847,
+	3851,
+	3853,
+	3863,
+	3877,
+	3881,
+	3889,
+	3907,
+	3911,
+	3917,
+	3919,
+	3923,
+	3929,
+	3931,
+	3943,
+	3947,
+	3967,
+	3989,
+	4001,
+	4003,
+	4007,
+	4013,
+	4019,
+	4021,
+	4027,
+	4049,
+	4051,
+	4057,
+	4073,
+	4079,
+	4091,
+	4093,
+	4099,
+	4111,
+	4127,
+	4129,
+	4133,
+	4139,
+	4153,
+	4157,
+	4159,
+	4177,
+	4201,
+	4211,
+	4217,
+	4219,
+	4229,
+	4231,
+	4241,
+	4243,
+	4253,
+	4259,
+	4261,
+	4271,
+	4273,
+	4283,
+	4289,
+	4297,
+	4327,
+	4337,
+	4339,
+	4349,
+	4357,
+	4363,
+	4373,
+	4391,
+	4397,
+	4409,
+	4421,
+	4423,
+	4441,
+	4447,
+	4451,
+	4457,
+	4463,
+	4481,
+	4483,
+	4493,
+	4507,
+	4513,
+	4517,
+	4519,
+	4523,
+	4547,
+	4549,
+	4561,
+	4567,
+	4583,
+	4591,
+	4597,
+	4603,
+	4621,
+	4637,
+	4639,
+	4643,
+	4649,
+	4651,
+	4657,
+	4663,
+	4673,
+	4679,
+	4691,
+	4703,
+	4721,
+	4723,
+	4729,
+	4733,
+	4751,
+	4759,
+	4783,
+	4787,
+	4789,
+	4793,
+	4799,
+	4801,
+	4813,
+	4817,
+	4831,
+	4861,
+	4871,
+	4877,
+	4889,
+	4903,
+	4909,
+	4919,
+	4931,
+	4933,
+	4937,
+	4943,
+	4951,
+	4957,
+	4967,
+	4969,
+	4973,
+	4987,
+	4993,
+	4999,
+	5003,
+	5009,
+	5011,
+	5021,
+	5023,
+	5039,
+	5051,
+	5059,
+	5077,
+	5081,
+	5087,
+	5099,
+	5101,
+	5107,
+	5113,
+	5119,
+	5147,
+	5153,
+	5167,
+	5171,
+	5179,
+	5189,
+	5197,
+	5209,
+	5227,
+	5231,
+	5233,
+	5237,
+	5261,
+	5273,
+	5279,
+	5281,
+	5297,
+	5303,
+	5309,
+	5323,
+	5333,
+	5347,
+	5351,
+	5381,
+	5387,
+	5393,
+	5399,
+	5407,
+	5413,
+	5417,
+	5419,
+	5431,
+	5437,
+	5441,
+	5443,
+	5449,
+	5471,
+	5477,
+	5479,
+	5483,
+	5501,
+	5503,
+	5507,
+	5519,
+	5521,
+	5527,
+	5531,
+	5557,
+	5563,
+	5569,
+	5573,
+	5581,
+	5591,
+	5623,
+	5639,
+	5641,
+	5647,
+	5651,
+	5653,
+	5657,
+	5659,
+	5669,
+	5683,
+	5689,
+	5693,
+	5701,
+	5711,
+	5717,
+	5737,
+	5741,
+	5743,
+	5749,
+	5779,
+	5783,
+	5791,
+	5801,
+	5807,
+	5813,
+	5821,
+	5827,
+	5839,
+	5843,
+	5849,
+	5851,
+	5857,
+	5861,
+	5867,
+	5869,
+	5879,
+	5881,
+	5897,
+	5903,
+	5923,
+	5927,
+	5939,
+	5953,
+	5981,
+	5987,
+	6007,
+	6011,
+	6029,
+	6037,
+	6043,
+	6047,
+	6053,
+	6067,
+	6073,
+	6079,
+	6089,
+	6091,
+	6101,
+	6113,
+	6121,
+	6131,
+	6133,
+	6143,
+	6151,
+	6163,
+	6173,
+	6197,
+	6199,
+	6203,
+	6211,
+	6217,
+	6221,
+	6229,
+	6247,
+	6257,
+	6263,
+	6269,
+	6271,
+	6277,
+	6287,
+	6299,
+	6301,
+	6311,
+	6317,
+	6323,
+	6329,
+	6337,
+	6343,
+	6353,
+	6359,
+	6361,
+	6367,
+	6373,
+	6379,
+	6389,
+	6397,
+	6421,
+	6427,
+	6449,
+	6451,
+	6469,
+	6473,
+	6481,
+	6491,
+	6521,
+	6529,
+	6547,
+	6551,
+	6553,
+	6563,
+	6569,
+	6571,
+	6577,
+	6581,
+	6599,
+	6607,
+	6619,
+	6637,
+	6653,
+	6659,
+	6661,
+	6673,
+	6679,
+	6689,
+	6691,
+	6701,
+	6703,
+	6709,
+	6719,
+	6733,
+	6737,
+	6761,
+	6763,
+	6779,
+	6781,
+	6791,
+	6793,
+	6803,
+	6823,
+	6827,
+	6829,
+	6833,
+	6841,
+	6857,
+	6863,
+	6869,
+	6871,
+	6883,
+	6899,
+	6907,
+	6911,
+	6917,
+	6947,
+	6949,
+	6959,
+	6961,
+	6967,
+	6971,
+	6977,
+	6983,
+	6991,
+	6997,
+	7001,
+	7013,
+	7019,
+	7027,
+	7039,
+	7043,
+	7057,
+	7069,
+	7079,
+	7103,
+	7109,
+	7121,
+	7127,
+	7129,
+	7151,
+	7159,
+	7177,
+	7187,
+	7193,
+	7207,
+	7211,
+	7213,
+	7219,
+	7229,
+	7237,
+	7243,
+	7247,
+	7253,
+	7283,
+	7297,
+	7307,
+	7309,
+	7321,
+	7331,
+	7333,
+	7349,
+	7351,
+	7369,
+	7393,
+	7411,
+	7417,
+	7433,
+	7451,
+	7457,
+	7459,
+	7477,
+	7481,
+	7487,
+	7489,
+	7499,
+	7507,
+	7517,
+	7523,
+	7529,
+	7537,
+	7541,
+	7547,
+	7549,
+	7559,
+	7561,
+	7573,
+	7577,
+	7583,
+	7589,
+	7591,
+	7603,
+	7607,
+	7621,
+	7639,
+	7643,
+	7649,
+	7669,
+	7673,
+	7681,
+	7687,
+	7691,
+	7699,
+	7703,
+	7717,
+	7723,
+	7727,
+	7741,
+	7753,
+	7757,
+	7759,
+	7789,
+	7793,
+	7817,
+	7823,
+	7829,
+	7841,
+	7853,
+	7867,
+	7873,
+	7877,
+	7879,
+	7883,
+	7901,
+	7907,
+	7919,
+};
--- /dev/null
+++ b/libsec/port/smallprimetest.c
@@ -1,0 +1,1039 @@
+#include "os.h"
+#include <mp.h>
+#include <libsec.h>
+
+static ulong smallprimes[] = {
+	2,	3,	5,	7,	11,	13,	17,	19,	23,	29,
+	31,	37,	41,	43,	47,	53,	59,	61,	67,	71,
+	73,	79,	83,	89,	97,	101,	103,	107,	109,	113,
+	127,	131,	137,	139,	149,	151,	157,	163,	167,	173,
+	179,	181,	191,	193,	197,	199,	211,	223,	227,	229,
+	233,	239,	241,	251,	257,	263,	269,	271,	277,	281,
+	283,	293,	307,	311,	313,	317,	331,	337,	347,	349,
+	353,	359,	367,	373,	379,	383,	389,	397,	401,	409,
+	419,	421,	431,	433,	439,	443,	449,	457,	461,	463,
+	467,	479,	487,	491,	499,	503,	509,	521,	523,	541,
+	547,	557,	563,	569,	571,	577,	587,	593,	599,	601,
+	607,	613,	617,	619,	631,	641,	643,	647,	653,	659,
+	661,	673,	677,	683,	691,	701,	709,	719,	727,	733,
+	739,	743,	751,	757,	761,	769,	773,	787,	797,	809,
+	811,	821,	823,	827,	829,	839,	853,	857,	859,	863,
+	877,	881,	883,	887,	907,	911,	919,	929,	937,	941,
+	947,	953,	967,	971,	977,	983,	991,	997,	1009,	1013,
+	1019,	1021,	1031,	1033,	1039,	1049,	1051,	1061,	1063,	1069,
+	1087,	1091,	1093,	1097,	1103,	1109,	1117,	1123,	1129,	1151,
+	1153,	1163,	1171,	1181,	1187,	1193,	1201,	1213,	1217,	1223,
+	1229,	1231,	1237,	1249,	1259,	1277,	1279,	1283,	1289,	1291,
+	1297,	1301,	1303,	1307,	1319,	1321,	1327,	1361,	1367,	1373,
+	1381,	1399,	1409,	1423,	1427,	1429,	1433,	1439,	1447,	1451,
+	1453,	1459,	1471,	1481,	1483,	1487,	1489,	1493,	1499,	1511,
+	1523,	1531,	1543,	1549,	1553,	1559,	1567,	1571,	1579,	1583,
+	1597,	1601,	1607,	1609,	1613,	1619,	1621,	1627,	1637,	1657,
+	1663,	1667,	1669,	1693,	1697,	1699,	1709,	1721,	1723,	1733,
+	1741,	1747,	1753,	1759,	1777,	1783,	1787,	1789,	1801,	1811,
+	1823,	1831,	1847,	1861,	1867,	1871,	1873,	1877,	1879,	1889,
+	1901,	1907,	1913,	1931,	1933,	1949,	1951,	1973,	1979,	1987,
+	1993,	1997,	1999,	2003,	2011,	2017,	2027,	2029,	2039,	2053,
+	2063,	2069,	2081,	2083,	2087,	2089,	2099,	2111,	2113,	2129,
+	2131,	2137,	2141,	2143,	2153,	2161,	2179,	2203,	2207,	2213,
+	2221,	2237,	2239,	2243,	2251,	2267,	2269,	2273,	2281,	2287,
+	2293,	2297,	2309,	2311,	2333,	2339,	2341,	2347,	2351,	2357,
+	2371,	2377,	2381,	2383,	2389,	2393,	2399,	2411,	2417,	2423,
+	2437,	2441,	2447,	2459,	2467,	2473,	2477,	2503,	2521,	2531,
+	2539,	2543,	2549,	2551,	2557,	2579,	2591,	2593,	2609,	2617,
+	2621,	2633,	2647,	2657,	2659,	2663,	2671,	2677,	2683,	2687,
+	2689,	2693,	2699,	2707,	2711,	2713,	2719,	2729,	2731,	2741,
+	2749,	2753,	2767,	2777,	2789,	2791,	2797,	2801,	2803,	2819,
+	2833,	2837,	2843,	2851,	2857,	2861,	2879,	2887,	2897,	2903,
+	2909,	2917,	2927,	2939,	2953,	2957,	2963,	2969,	2971,	2999,
+	3001,	3011,	3019,	3023,	3037,	3041,	3049,	3061,	3067,	3079,
+	3083,	3089,	3109,	3119,	3121,	3137,	3163,	3167,	3169,	3181,
+	3187,	3191,	3203,	3209,	3217,	3221,	3229,	3251,	3253,	3257,
+	3259,	3271,	3299,	3301,	3307,	3313,	3319,	3323,	3329,	3331,
+	3343,	3347,	3359,	3361,	3371,	3373,	3389,	3391,	3407,	3413,
+	3433,	3449,	3457,	3461,	3463,	3467,	3469,	3491,	3499,	3511,
+	3517,	3527,	3529,	3533,	3539,	3541,	3547,	3557,	3559,	3571,
+	3581,	3583,	3593,	3607,	3613,	3617,	3623,	3631,	3637,	3643,
+	3659,	3671,	3673,	3677,	3691,	3697,	3701,	3709,	3719,	3727,
+	3733,	3739,	3761,	3767,	3769,	3779,	3793,	3797,	3803,	3821,
+	3823,	3833,	3847,	3851,	3853,	3863,	3877,	3881,	3889,	3907,
+	3911,	3917,	3919,	3923,	3929,	3931,	3943,	3947,	3967,	3989,
+	4001,	4003,	4007,	4013,	4019,	4021,	4027,	4049,	4051,	4057,
+	4073,	4079,	4091,	4093,	4099,	4111,	4127,	4129,	4133,	4139,
+	4153,	4157,	4159,	4177,	4201,	4211,	4217,	4219,	4229,	4231,
+	4241,	4243,	4253,	4259,	4261,	4271,	4273,	4283,	4289,	4297,
+	4327,	4337,	4339,	4349,	4357,	4363,	4373,	4391,	4397,	4409,
+	4421,	4423,	4441,	4447,	4451,	4457,	4463,	4481,	4483,	4493,
+	4507,	4513,	4517,	4519,	4523,	4547,	4549,	4561,	4567,	4583,
+	4591,	4597,	4603,	4621,	4637,	4639,	4643,	4649,	4651,	4657,
+	4663,	4673,	4679,	4691,	4703,	4721,	4723,	4729,	4733,	4751,
+	4759,	4783,	4787,	4789,	4793,	4799,	4801,	4813,	4817,	4831,
+	4861,	4871,	4877,	4889,	4903,	4909,	4919,	4931,	4933,	4937,
+	4943,	4951,	4957,	4967,	4969,	4973,	4987,	4993,	4999,	5003,
+	5009,	5011,	5021,	5023,	5039,	5051,	5059,	5077,	5081,	5087,
+	5099,	5101,	5107,	5113,	5119,	5147,	5153,	5167,	5171,	5179,
+	5189,	5197,	5209,	5227,	5231,	5233,	5237,	5261,	5273,	5279,
+	5281,	5297,	5303,	5309,	5323,	5333,	5347,	5351,	5381,	5387,
+	5393,	5399,	5407,	5413,	5417,	5419,	5431,	5437,	5441,	5443,
+	5449,	5471,	5477,	5479,	5483,	5501,	5503,	5507,	5519,	5521,
+	5527,	5531,	5557,	5563,	5569,	5573,	5581,	5591,	5623,	5639,
+	5641,	5647,	5651,	5653,	5657,	5659,	5669,	5683,	5689,	5693,
+	5701,	5711,	5717,	5737,	5741,	5743,	5749,	5779,	5783,	5791,
+	5801,	5807,	5813,	5821,	5827,	5839,	5843,	5849,	5851,	5857,
+	5861,	5867,	5869,	5879,	5881,	5897,	5903,	5923,	5927,	5939,
+	5953,	5981,	5987,	6007,	6011,	6029,	6037,	6043,	6047,	6053,
+	6067,	6073,	6079,	6089,	6091,	6101,	6113,	6121,	6131,	6133,
+	6143,	6151,	6163,	6173,	6197,	6199,	6203,	6211,	6217,	6221,
+	6229,	6247,	6257,	6263,	6269,	6271,	6277,	6287,	6299,	6301,
+	6311,	6317,	6323,	6329,	6337,	6343,	6353,	6359,	6361,	6367,
+	6373,	6379,	6389,	6397,	6421,	6427,	6449,	6451,	6469,	6473,
+	6481,	6491,	6521,	6529,	6547,	6551,	6553,	6563,	6569,	6571,
+	6577,	6581,	6599,	6607,	6619,	6637,	6653,	6659,	6661,	6673,
+	6679,	6689,	6691,	6701,	6703,	6709,	6719,	6733,	6737,	6761,
+	6763,	6779,	6781,	6791,	6793,	6803,	6823,	6827,	6829,	6833,
+	6841,	6857,	6863,	6869,	6871,	6883,	6899,	6907,	6911,	6917,
+	6947,	6949,	6959,	6961,	6967,	6971,	6977,	6983,	6991,	6997,
+	7001,	7013,	7019,	7027,	7039,	7043,	7057,	7069,	7079,	7103,
+	7109,	7121,	7127,	7129,	7151,	7159,	7177,	7187,	7193,	7207,
+	7211,	7213,	7219,	7229,	7237,	7243,	7247,	7253,	7283,	7297,
+	7307,	7309,	7321,	7331,	7333,	7349,	7351,	7369,	7393,	7411,
+	7417,	7433,	7451,	7457,	7459,	7477,	7481,	7487,	7489,	7499,
+	7507,	7517,	7523,	7529,	7537,	7541,	7547,	7549,	7559,	7561,
+	7573,	7577,	7583,	7589,	7591,	7603,	7607,	7621,	7639,	7643,
+	7649,	7669,	7673,	7681,	7687,	7691,	7699,	7703,	7717,	7723,
+	7727,	7741,	7753,	7757,	7759,	7789,	7793,	7817,	7823,	7829,
+	7841,	7853,	7867,	7873,	7877,	7879,	7883,	7901,	7907,	7919,
+	7927,	7933,	7937,	7949,	7951,	7963,	7993,	8009,	8011,	8017,
+	8039,	8053,	8059,	8069,	8081,	8087,	8089,	8093,	8101,	8111,
+	8117,	8123,	8147,	8161,	8167,	8171,	8179,	8191,	8209,	8219,
+	8221,	8231,	8233,	8237,	8243,	8263,	8269,	8273,	8287,	8291,
+	8293,	8297,	8311,	8317,	8329,	8353,	8363,	8369,	8377,	8387,
+	8389,	8419,	8423,	8429,	8431,	8443,	8447,	8461,	8467,	8501,
+	8513,	8521,	8527,	8537,	8539,	8543,	8563,	8573,	8581,	8597,
+	8599,	8609,	8623,	8627,	8629,	8641,	8647,	8663,	8669,	8677,
+	8681,	8689,	8693,	8699,	8707,	8713,	8719,	8731,	8737,	8741,
+	8747,	8753,	8761,	8779,	8783,	8803,	8807,	8819,	8821,	8831,
+	8837,	8839,	8849,	8861,	8863,	8867,	8887,	8893,	8923,	8929,
+	8933,	8941,	8951,	8963,	8969,	8971,	8999,	9001,	9007,	9011,
+	9013,	9029,	9041,	9043,	9049,	9059,	9067,	9091,	9103,	9109,
+	9127,	9133,	9137,	9151,	9157,	9161,	9173,	9181,	9187,	9199,
+	9203,	9209,	9221,	9227,	9239,	9241,	9257,	9277,	9281,	9283,
+	9293,	9311,	9319,	9323,	9337,	9341,	9343,	9349,	9371,	9377,
+	9391,	9397,	9403,	9413,	9419,	9421,	9431,	9433,	9437,	9439,
+	9461,	9463,	9467,	9473,	9479,	9491,	9497,	9511,	9521,	9533,
+	9539,	9547,	9551,	9587,	9601,	9613,	9619,	9623,	9629,	9631,
+	9643,	9649,	9661,	9677,	9679,	9689,	9697,	9719,	9721,	9733,
+	9739,	9743,	9749,	9767,	9769,	9781,	9787,	9791,	9803,	9811,
+	9817,	9829,	9833,	9839,	9851,	9857,	9859,	9871,	9883,	9887,
+	9901,	9907,	9923,	9929,	9931,	9941,	9949,	9967,	9973,	10007,
+	10009,	10037,	10039,	10061,	10067,	10069,	10079,	10091,	10093,	10099,
+	10103,	10111,	10133,	10139,	10141,	10151,	10159,	10163,	10169,	10177,
+	10181,	10193,	10211,	10223,	10243,	10247,	10253,	10259,	10267,	10271,
+	10273,	10289,	10301,	10303,	10313,	10321,	10331,	10333,	10337,	10343,
+	10357,	10369,	10391,	10399,	10427,	10429,	10433,	10453,	10457,	10459,
+	10463,	10477,	10487,	10499,	10501,	10513,	10529,	10531,	10559,	10567,
+	10589,	10597,	10601,	10607,	10613,	10627,	10631,	10639,	10651,	10657,
+	10663,	10667,	10687,	10691,	10709,	10711,	10723,	10729,	10733,	10739,
+	10753,	10771,	10781,	10789,	10799,	10831,	10837,	10847,	10853,	10859,
+	10861,	10867,	10883,	10889,	10891,	10903,	10909,	10937,	10939,	10949,
+	10957,	10973,	10979,	10987,	10993,	11003,	11027,	11047,	11057,	11059,
+	11069,	11071,	11083,	11087,	11093,	11113,	11117,	11119,	11131,	11149,
+	11159,	11161,	11171,	11173,	11177,	11197,	11213,	11239,	11243,	11251,
+	11257,	11261,	11273,	11279,	11287,	11299,	11311,	11317,	11321,	11329,
+	11351,	11353,	11369,	11383,	11393,	11399,	11411,	11423,	11437,	11443,
+	11447,	11467,	11471,	11483,	11489,	11491,	11497,	11503,	11519,	11527,
+	11549,	11551,	11579,	11587,	11593,	11597,	11617,	11621,	11633,	11657,
+	11677,	11681,	11689,	11699,	11701,	11717,	11719,	11731,	11743,	11777,
+	11779,	11783,	11789,	11801,	11807,	11813,	11821,	11827,	11831,	11833,
+	11839,	11863,	11867,	11887,	11897,	11903,	11909,	11923,	11927,	11933,
+	11939,	11941,	11953,	11959,	11969,	11971,	11981,	11987,	12007,	12011,
+	12037,	12041,	12043,	12049,	12071,	12073,	12097,	12101,	12107,	12109,
+	12113,	12119,	12143,	12149,	12157,	12161,	12163,	12197,	12203,	12211,
+	12227,	12239,	12241,	12251,	12253,	12263,	12269,	12277,	12281,	12289,
+	12301,	12323,	12329,	12343,	12347,	12373,	12377,	12379,	12391,	12401,
+	12409,	12413,	12421,	12433,	12437,	12451,	12457,	12473,	12479,	12487,
+	12491,	12497,	12503,	12511,	12517,	12527,	12539,	12541,	12547,	12553,
+	12569,	12577,	12583,	12589,	12601,	12611,	12613,	12619,	12637,	12641,
+	12647,	12653,	12659,	12671,	12689,	12697,	12703,	12713,	12721,	12739,
+	12743,	12757,	12763,	12781,	12791,	12799,	12809,	12821,	12823,	12829,
+	12841,	12853,	12889,	12893,	12899,	12907,	12911,	12917,	12919,	12923,
+	12941,	12953,	12959,	12967,	12973,	12979,	12983,	13001,	13003,	13007,
+	13009,	13033,	13037,	13043,	13049,	13063,	13093,	13099,	13103,	13109,
+	13121,	13127,	13147,	13151,	13159,	13163,	13171,	13177,	13183,	13187,
+	13217,	13219,	13229,	13241,	13249,	13259,	13267,	13291,	13297,	13309,
+	13313,	13327,	13331,	13337,	13339,	13367,	13381,	13397,	13399,	13411,
+	13417,	13421,	13441,	13451,	13457,	13463,	13469,	13477,	13487,	13499,
+	13513,	13523,	13537,	13553,	13567,	13577,	13591,	13597,	13613,	13619,
+	13627,	13633,	13649,	13669,	13679,	13681,	13687,	13691,	13693,	13697,
+	13709,	13711,	13721,	13723,	13729,	13751,	13757,	13759,	13763,	13781,
+	13789,	13799,	13807,	13829,	13831,	13841,	13859,	13873,	13877,	13879,
+	13883,	13901,	13903,	13907,	13913,	13921,	13931,	13933,	13963,	13967,
+	13997,	13999,	14009,	14011,	14029,	14033,	14051,	14057,	14071,	14081,
+	14083,	14087,	14107,	14143,	14149,	14153,	14159,	14173,	14177,	14197,
+	14207,	14221,	14243,	14249,	14251,	14281,	14293,	14303,	14321,	14323,
+	14327,	14341,	14347,	14369,	14387,	14389,	14401,	14407,	14411,	14419,
+	14423,	14431,	14437,	14447,	14449,	14461,	14479,	14489,	14503,	14519,
+	14533,	14537,	14543,	14549,	14551,	14557,	14561,	14563,	14591,	14593,
+	14621,	14627,	14629,	14633,	14639,	14653,	14657,	14669,	14683,	14699,
+	14713,	14717,	14723,	14731,	14737,	14741,	14747,	14753,	14759,	14767,
+	14771,	14779,	14783,	14797,	14813,	14821,	14827,	14831,	14843,	14851,
+	14867,	14869,	14879,	14887,	14891,	14897,	14923,	14929,	14939,	14947,
+	14951,	14957,	14969,	14983,	15013,	15017,	15031,	15053,	15061,	15073,
+	15077,	15083,	15091,	15101,	15107,	15121,	15131,	15137,	15139,	15149,
+	15161,	15173,	15187,	15193,	15199,	15217,	15227,	15233,	15241,	15259,
+	15263,	15269,	15271,	15277,	15287,	15289,	15299,	15307,	15313,	15319,
+	15329,	15331,	15349,	15359,	15361,	15373,	15377,	15383,	15391,	15401,
+	15413,	15427,	15439,	15443,	15451,	15461,	15467,	15473,	15493,	15497,
+	15511,	15527,	15541,	15551,	15559,	15569,	15581,	15583,	15601,	15607,
+	15619,	15629,	15641,	15643,	15647,	15649,	15661,	15667,	15671,	15679,
+	15683,	15727,	15731,	15733,	15737,	15739,	15749,	15761,	15767,	15773,
+	15787,	15791,	15797,	15803,	15809,	15817,	15823,	15859,	15877,	15881,
+	15887,	15889,	15901,	15907,	15913,	15919,	15923,	15937,	15959,	15971,
+	15973,	15991,	16001,	16007,	16033,	16057,	16061,	16063,	16067,	16069,
+	16073,	16087,	16091,	16097,	16103,	16111,	16127,	16139,	16141,	16183,
+	16187,	16189,	16193,	16217,	16223,	16229,	16231,	16249,	16253,	16267,
+	16273,	16301,	16319,	16333,	16339,	16349,	16361,	16363,	16369,	16381,
+	16411,	16417,	16421,	16427,	16433,	16447,	16451,	16453,	16477,	16481,
+	16487,	16493,	16519,	16529,	16547,	16553,	16561,	16567,	16573,	16603,
+	16607,	16619,	16631,	16633,	16649,	16651,	16657,	16661,	16673,	16691,
+	16693,	16699,	16703,	16729,	16741,	16747,	16759,	16763,	16787,	16811,
+	16823,	16829,	16831,	16843,	16871,	16879,	16883,	16889,	16901,	16903,
+	16921,	16927,	16931,	16937,	16943,	16963,	16979,	16981,	16987,	16993,
+	17011,	17021,	17027,	17029,	17033,	17041,	17047,	17053,	17077,	17093,
+	17099,	17107,	17117,	17123,	17137,	17159,	17167,	17183,	17189,	17191,
+	17203,	17207,	17209,	17231,	17239,	17257,	17291,	17293,	17299,	17317,
+	17321,	17327,	17333,	17341,	17351,	17359,	17377,	17383,	17387,	17389,
+	17393,	17401,	17417,	17419,	17431,	17443,	17449,	17467,	17471,	17477,
+	17483,	17489,	17491,	17497,	17509,	17519,	17539,	17551,	17569,	17573,
+	17579,	17581,	17597,	17599,	17609,	17623,	17627,	17657,	17659,	17669,
+	17681,	17683,	17707,	17713,	17729,	17737,	17747,	17749,	17761,	17783,
+	17789,	17791,	17807,	17827,	17837,	17839,	17851,	17863,	17881,	17891,
+	17903,	17909,	17911,	17921,	17923,	17929,	17939,	17957,	17959,	17971,
+	17977,	17981,	17987,	17989,	18013,	18041,	18043,	18047,	18049,	18059,
+	18061,	18077,	18089,	18097,	18119,	18121,	18127,	18131,	18133,	18143,
+	18149,	18169,	18181,	18191,	18199,	18211,	18217,	18223,	18229,	18233,
+	18251,	18253,	18257,	18269,	18287,	18289,	18301,	18307,	18311,	18313,
+	18329,	18341,	18353,	18367,	18371,	18379,	18397,	18401,	18413,	18427,
+	18433,	18439,	18443,	18451,	18457,	18461,	18481,	18493,	18503,	18517,
+	18521,	18523,	18539,	18541,	18553,	18583,	18587,	18593,	18617,	18637,
+	18661,	18671,	18679,	18691,	18701,	18713,	18719,	18731,	18743,	18749,
+	18757,	18773,	18787,	18793,	18797,	18803,	18839,	18859,	18869,	18899,
+	18911,	18913,	18917,	18919,	18947,	18959,	18973,	18979,	19001,	19009,
+	19013,	19031,	19037,	19051,	19069,	19073,	19079,	19081,	19087,	19121,
+	19139,	19141,	19157,	19163,	19181,	19183,	19207,	19211,	19213,	19219,
+	19231,	19237,	19249,	19259,	19267,	19273,	19289,	19301,	19309,	19319,
+	19333,	19373,	19379,	19381,	19387,	19391,	19403,	19417,	19421,	19423,
+	19427,	19429,	19433,	19441,	19447,	19457,	19463,	19469,	19471,	19477,
+	19483,	19489,	19501,	19507,	19531,	19541,	19543,	19553,	19559,	19571,
+	19577,	19583,	19597,	19603,	19609,	19661,	19681,	19687,	19697,	19699,
+	19709,	19717,	19727,	19739,	19751,	19753,	19759,	19763,	19777,	19793,
+	19801,	19813,	19819,	19841,	19843,	19853,	19861,	19867,	19889,	19891,
+	19913,	19919,	19927,	19937,	19949,	19961,	19963,	19973,	19979,	19991,
+	19993,	19997,	20011,	20021,	20023,	20029,	20047,	20051,	20063,	20071,
+	20089,	20101,	20107,	20113,	20117,	20123,	20129,	20143,	20147,	20149,
+	20161,	20173,	20177,	20183,	20201,	20219,	20231,	20233,	20249,	20261,
+	20269,	20287,	20297,	20323,	20327,	20333,	20341,	20347,	20353,	20357,
+	20359,	20369,	20389,	20393,	20399,	20407,	20411,	20431,	20441,	20443,
+	20477,	20479,	20483,	20507,	20509,	20521,	20533,	20543,	20549,	20551,
+	20563,	20593,	20599,	20611,	20627,	20639,	20641,	20663,	20681,	20693,
+	20707,	20717,	20719,	20731,	20743,	20747,	20749,	20753,	20759,	20771,
+	20773,	20789,	20807,	20809,	20849,	20857,	20873,	20879,	20887,	20897,
+	20899,	20903,	20921,	20929,	20939,	20947,	20959,	20963,	20981,	20983,
+	21001,	21011,	21013,	21017,	21019,	21023,	21031,	21059,	21061,	21067,
+	21089,	21101,	21107,	21121,	21139,	21143,	21149,	21157,	21163,	21169,
+	21179,	21187,	21191,	21193,	21211,	21221,	21227,	21247,	21269,	21277,
+	21283,	21313,	21317,	21319,	21323,	21341,	21347,	21377,	21379,	21383,
+	21391,	21397,	21401,	21407,	21419,	21433,	21467,	21481,	21487,	21491,
+	21493,	21499,	21503,	21517,	21521,	21523,	21529,	21557,	21559,	21563,
+	21569,	21577,	21587,	21589,	21599,	21601,	21611,	21613,	21617,	21647,
+	21649,	21661,	21673,	21683,	21701,	21713,	21727,	21737,	21739,	21751,
+	21757,	21767,	21773,	21787,	21799,	21803,	21817,	21821,	21839,	21841,
+	21851,	21859,	21863,	21871,	21881,	21893,	21911,	21929,	21937,	21943,
+	21961,	21977,	21991,	21997,	22003,	22013,	22027,	22031,	22037,	22039,
+	22051,	22063,	22067,	22073,	22079,	22091,	22093,	22109,	22111,	22123,
+	22129,	22133,	22147,	22153,	22157,	22159,	22171,	22189,	22193,	22229,
+	22247,	22259,	22271,	22273,	22277,	22279,	22283,	22291,	22303,	22307,
+	22343,	22349,	22367,	22369,	22381,	22391,	22397,	22409,	22433,	22441,
+	22447,	22453,	22469,	22481,	22483,	22501,	22511,	22531,	22541,	22543,
+	22549,	22567,	22571,	22573,	22613,	22619,	22621,	22637,	22639,	22643,
+	22651,	22669,	22679,	22691,	22697,	22699,	22709,	22717,	22721,	22727,
+	22739,	22741,	22751,	22769,	22777,	22783,	22787,	22807,	22811,	22817,
+	22853,	22859,	22861,	22871,	22877,	22901,	22907,	22921,	22937,	22943,
+	22961,	22963,	22973,	22993,	23003,	23011,	23017,	23021,	23027,	23029,
+	23039,	23041,	23053,	23057,	23059,	23063,	23071,	23081,	23087,	23099,
+	23117,	23131,	23143,	23159,	23167,	23173,	23189,	23197,	23201,	23203,
+	23209,	23227,	23251,	23269,	23279,	23291,	23293,	23297,	23311,	23321,
+	23327,	23333,	23339,	23357,	23369,	23371,	23399,	23417,	23431,	23447,
+	23459,	23473,	23497,	23509,	23531,	23537,	23539,	23549,	23557,	23561,
+	23563,	23567,	23581,	23593,	23599,	23603,	23609,	23623,	23627,	23629,
+	23633,	23663,	23669,	23671,	23677,	23687,	23689,	23719,	23741,	23743,
+	23747,	23753,	23761,	23767,	23773,	23789,	23801,	23813,	23819,	23827,
+	23831,	23833,	23857,	23869,	23873,	23879,	23887,	23893,	23899,	23909,
+	23911,	23917,	23929,	23957,	23971,	23977,	23981,	23993,	24001,	24007,
+	24019,	24023,	24029,	24043,	24049,	24061,	24071,	24077,	24083,	24091,
+	24097,	24103,	24107,	24109,	24113,	24121,	24133,	24137,	24151,	24169,
+	24179,	24181,	24197,	24203,	24223,	24229,	24239,	24247,	24251,	24281,
+	24317,	24329,	24337,	24359,	24371,	24373,	24379,	24391,	24407,	24413,
+	24419,	24421,	24439,	24443,	24469,	24473,	24481,	24499,	24509,	24517,
+	24527,	24533,	24547,	24551,	24571,	24593,	24611,	24623,	24631,	24659,
+	24671,	24677,	24683,	24691,	24697,	24709,	24733,	24749,	24763,	24767,
+	24781,	24793,	24799,	24809,	24821,	24841,	24847,	24851,	24859,	24877,
+	24889,	24907,	24917,	24919,	24923,	24943,	24953,	24967,	24971,	24977,
+	24979,	24989,	25013,	25031,	25033,	25037,	25057,	25073,	25087,	25097,
+	25111,	25117,	25121,	25127,	25147,	25153,	25163,	25169,	25171,	25183,
+	25189,	25219,	25229,	25237,	25243,	25247,	25253,	25261,	25301,	25303,
+	25307,	25309,	25321,	25339,	25343,	25349,	25357,	25367,	25373,	25391,
+	25409,	25411,	25423,	25439,	25447,	25453,	25457,	25463,	25469,	25471,
+	25523,	25537,	25541,	25561,	25577,	25579,	25583,	25589,	25601,	25603,
+	25609,	25621,	25633,	25639,	25643,	25657,	25667,	25673,	25679,	25693,
+	25703,	25717,	25733,	25741,	25747,	25759,	25763,	25771,	25793,	25799,
+	25801,	25819,	25841,	25847,	25849,	25867,	25873,	25889,	25903,	25913,
+	25919,	25931,	25933,	25939,	25943,	25951,	25969,	25981,	25997,	25999,
+	26003,	26017,	26021,	26029,	26041,	26053,	26083,	26099,	26107,	26111,
+	26113,	26119,	26141,	26153,	26161,	26171,	26177,	26183,	26189,	26203,
+	26209,	26227,	26237,	26249,	26251,	26261,	26263,	26267,	26293,	26297,
+	26309,	26317,	26321,	26339,	26347,	26357,	26371,	26387,	26393,	26399,
+	26407,	26417,	26423,	26431,	26437,	26449,	26459,	26479,	26489,	26497,
+	26501,	26513,	26539,	26557,	26561,	26573,	26591,	26597,	26627,	26633,
+	26641,	26647,	26669,	26681,	26683,	26687,	26693,	26699,	26701,	26711,
+	26713,	26717,	26723,	26729,	26731,	26737,	26759,	26777,	26783,	26801,
+	26813,	26821,	26833,	26839,	26849,	26861,	26863,	26879,	26881,	26891,
+	26893,	26903,	26921,	26927,	26947,	26951,	26953,	26959,	26981,	26987,
+	26993,	27011,	27017,	27031,	27043,	27059,	27061,	27067,	27073,	27077,
+	27091,	27103,	27107,	27109,	27127,	27143,	27179,	27191,	27197,	27211,
+	27239,	27241,	27253,	27259,	27271,	27277,	27281,	27283,	27299,	27329,
+	27337,	27361,	27367,	27397,	27407,	27409,	27427,	27431,	27437,	27449,
+	27457,	27479,	27481,	27487,	27509,	27527,	27529,	27539,	27541,	27551,
+	27581,	27583,	27611,	27617,	27631,	27647,	27653,	27673,	27689,	27691,
+	27697,	27701,	27733,	27737,	27739,	27743,	27749,	27751,	27763,	27767,
+	27773,	27779,	27791,	27793,	27799,	27803,	27809,	27817,	27823,	27827,
+	27847,	27851,	27883,	27893,	27901,	27917,	27919,	27941,	27943,	27947,
+	27953,	27961,	27967,	27983,	27997,	28001,	28019,	28027,	28031,	28051,
+	28057,	28069,	28081,	28087,	28097,	28099,	28109,	28111,	28123,	28151,
+	28163,	28181,	28183,	28201,	28211,	28219,	28229,	28277,	28279,	28283,
+	28289,	28297,	28307,	28309,	28319,	28349,	28351,	28387,	28393,	28403,
+	28409,	28411,	28429,	28433,	28439,	28447,	28463,	28477,	28493,	28499,
+	28513,	28517,	28537,	28541,	28547,	28549,	28559,	28571,	28573,	28579,
+	28591,	28597,	28603,	28607,	28619,	28621,	28627,	28631,	28643,	28649,
+	28657,	28661,	28663,	28669,	28687,	28697,	28703,	28711,	28723,	28729,
+	28751,	28753,	28759,	28771,	28789,	28793,	28807,	28813,	28817,	28837,
+	28843,	28859,	28867,	28871,	28879,	28901,	28909,	28921,	28927,	28933,
+	28949,	28961,	28979,	29009,	29017,	29021,	29023,	29027,	29033,	29059,
+	29063,	29077,	29101,	29123,	29129,	29131,	29137,	29147,	29153,	29167,
+	29173,	29179,	29191,	29201,	29207,	29209,	29221,	29231,	29243,	29251,
+	29269,	29287,	29297,	29303,	29311,	29327,	29333,	29339,	29347,	29363,
+	29383,	29387,	29389,	29399,	29401,	29411,	29423,	29429,	29437,	29443,
+	29453,	29473,	29483,	29501,	29527,	29531,	29537,	29567,	29569,	29573,
+	29581,	29587,	29599,	29611,	29629,	29633,	29641,	29663,	29669,	29671,
+	29683,	29717,	29723,	29741,	29753,	29759,	29761,	29789,	29803,	29819,
+	29833,	29837,	29851,	29863,	29867,	29873,	29879,	29881,	29917,	29921,
+	29927,	29947,	29959,	29983,	29989,	30011,	30013,	30029,	30047,	30059,
+	30071,	30089,	30091,	30097,	30103,	30109,	30113,	30119,	30133,	30137,
+	30139,	30161,	30169,	30181,	30187,	30197,	30203,	30211,	30223,	30241,
+	30253,	30259,	30269,	30271,	30293,	30307,	30313,	30319,	30323,	30341,
+	30347,	30367,	30389,	30391,	30403,	30427,	30431,	30449,	30467,	30469,
+	30491,	30493,	30497,	30509,	30517,	30529,	30539,	30553,	30557,	30559,
+	30577,	30593,	30631,	30637,	30643,	30649,	30661,	30671,	30677,	30689,
+	30697,	30703,	30707,	30713,	30727,	30757,	30763,	30773,	30781,	30803,
+	30809,	30817,	30829,	30839,	30841,	30851,	30853,	30859,	30869,	30871,
+	30881,	30893,	30911,	30931,	30937,	30941,	30949,	30971,	30977,	30983,
+	31013,	31019,	31033,	31039,	31051,	31063,	31069,	31079,	31081,	31091,
+	31121,	31123,	31139,	31147,	31151,	31153,	31159,	31177,	31181,	31183,
+	31189,	31193,	31219,	31223,	31231,	31237,	31247,	31249,	31253,	31259,
+	31267,	31271,	31277,	31307,	31319,	31321,	31327,	31333,	31337,	31357,
+	31379,	31387,	31391,	31393,	31397,	31469,	31477,	31481,	31489,	31511,
+	31513,	31517,	31531,	31541,	31543,	31547,	31567,	31573,	31583,	31601,
+	31607,	31627,	31643,	31649,	31657,	31663,	31667,	31687,	31699,	31721,
+	31723,	31727,	31729,	31741,	31751,	31769,	31771,	31793,	31799,	31817,
+	31847,	31849,	31859,	31873,	31883,	31891,	31907,	31957,	31963,	31973,
+	31981,	31991,	32003,	32009,	32027,	32029,	32051,	32057,	32059,	32063,
+	32069,	32077,	32083,	32089,	32099,	32117,	32119,	32141,	32143,	32159,
+	32173,	32183,	32189,	32191,	32203,	32213,	32233,	32237,	32251,	32257,
+	32261,	32297,	32299,	32303,	32309,	32321,	32323,	32327,	32341,	32353,
+	32359,	32363,	32369,	32371,	32377,	32381,	32401,	32411,	32413,	32423,
+	32429,	32441,	32443,	32467,	32479,	32491,	32497,	32503,	32507,	32531,
+	32533,	32537,	32561,	32563,	32569,	32573,	32579,	32587,	32603,	32609,
+	32611,	32621,	32633,	32647,	32653,	32687,	32693,	32707,	32713,	32717,
+	32719,	32749,	32771,	32779,	32783,	32789,	32797,	32801,	32803,	32831,
+	32833,	32839,	32843,	32869,	32887,	32909,	32911,	32917,	32933,	32939,
+	32941,	32957,	32969,	32971,	32983,	32987,	32993,	32999,	33013,	33023,
+	33029,	33037,	33049,	33053,	33071,	33073,	33083,	33091,	33107,	33113,
+	33119,	33149,	33151,	33161,	33179,	33181,	33191,	33199,	33203,	33211,
+	33223,	33247,	33287,	33289,	33301,	33311,	33317,	33329,	33331,	33343,
+	33347,	33349,	33353,	33359,	33377,	33391,	33403,	33409,	33413,	33427,
+	33457,	33461,	33469,	33479,	33487,	33493,	33503,	33521,	33529,	33533,
+	33547,	33563,	33569,	33577,	33581,	33587,	33589,	33599,	33601,	33613,
+	33617,	33619,	33623,	33629,	33637,	33641,	33647,	33679,	33703,	33713,
+	33721,	33739,	33749,	33751,	33757,	33767,	33769,	33773,	33791,	33797,
+	33809,	33811,	33827,	33829,	33851,	33857,	33863,	33871,	33889,	33893,
+	33911,	33923,	33931,	33937,	33941,	33961,	33967,	33997,	34019,	34031,
+	34033,	34039,	34057,	34061,	34123,	34127,	34129,	34141,	34147,	34157,
+	34159,	34171,	34183,	34211,	34213,	34217,	34231,	34253,	34259,	34261,
+	34267,	34273,	34283,	34297,	34301,	34303,	34313,	34319,	34327,	34337,
+	34351,	34361,	34367,	34369,	34381,	34403,	34421,	34429,	34439,	34457,
+	34469,	34471,	34483,	34487,	34499,	34501,	34511,	34513,	34519,	34537,
+	34543,	34549,	34583,	34589,	34591,	34603,	34607,	34613,	34631,	34649,
+	34651,	34667,	34673,	34679,	34687,	34693,	34703,	34721,	34729,	34739,
+	34747,	34757,	34759,	34763,	34781,	34807,	34819,	34841,	34843,	34847,
+	34849,	34871,	34877,	34883,	34897,	34913,	34919,	34939,	34949,	34961,
+	34963,	34981,	35023,	35027,	35051,	35053,	35059,	35069,	35081,	35083,
+	35089,	35099,	35107,	35111,	35117,	35129,	35141,	35149,	35153,	35159,
+	35171,	35201,	35221,	35227,	35251,	35257,	35267,	35279,	35281,	35291,
+	35311,	35317,	35323,	35327,	35339,	35353,	35363,	35381,	35393,	35401,
+	35407,	35419,	35423,	35437,	35447,	35449,	35461,	35491,	35507,	35509,
+	35521,	35527,	35531,	35533,	35537,	35543,	35569,	35573,	35591,	35593,
+	35597,	35603,	35617,	35671,	35677,	35729,	35731,	35747,	35753,	35759,
+	35771,	35797,	35801,	35803,	35809,	35831,	35837,	35839,	35851,	35863,
+	35869,	35879,	35897,	35899,	35911,	35923,	35933,	35951,	35963,	35969,
+	35977,	35983,	35993,	35999,	36007,	36011,	36013,	36017,	36037,	36061,
+	36067,	36073,	36083,	36097,	36107,	36109,	36131,	36137,	36151,	36161,
+	36187,	36191,	36209,	36217,	36229,	36241,	36251,	36263,	36269,	36277,
+	36293,	36299,	36307,	36313,	36319,	36341,	36343,	36353,	36373,	36383,
+	36389,	36433,	36451,	36457,	36467,	36469,	36473,	36479,	36493,	36497,
+	36523,	36527,	36529,	36541,	36551,	36559,	36563,	36571,	36583,	36587,
+	36599,	36607,	36629,	36637,	36643,	36653,	36671,	36677,	36683,	36691,
+	36697,	36709,	36713,	36721,	36739,	36749,	36761,	36767,	36779,	36781,
+	36787,	36791,	36793,	36809,	36821,	36833,	36847,	36857,	36871,	36877,
+	36887,	36899,	36901,	36913,	36919,	36923,	36929,	36931,	36943,	36947,
+	36973,	36979,	36997,	37003,	37013,	37019,	37021,	37039,	37049,	37057,
+	37061,	37087,	37097,	37117,	37123,	37139,	37159,	37171,	37181,	37189,
+	37199,	37201,	37217,	37223,	37243,	37253,	37273,	37277,	37307,	37309,
+	37313,	37321,	37337,	37339,	37357,	37361,	37363,	37369,	37379,	37397,
+	37409,	37423,	37441,	37447,	37463,	37483,	37489,	37493,	37501,	37507,
+	37511,	37517,	37529,	37537,	37547,	37549,	37561,	37567,	37571,	37573,
+	37579,	37589,	37591,	37607,	37619,	37633,	37643,	37649,	37657,	37663,
+	37691,	37693,	37699,	37717,	37747,	37781,	37783,	37799,	37811,	37813,
+	37831,	37847,	37853,	37861,	37871,	37879,	37889,	37897,	37907,	37951,
+	37957,	37963,	37967,	37987,	37991,	37993,	37997,	38011,	38039,	38047,
+	38053,	38069,	38083,	38113,	38119,	38149,	38153,	38167,	38177,	38183,
+	38189,	38197,	38201,	38219,	38231,	38237,	38239,	38261,	38273,	38281,
+	38287,	38299,	38303,	38317,	38321,	38327,	38329,	38333,	38351,	38371,
+	38377,	38393,	38431,	38447,	38449,	38453,	38459,	38461,	38501,	38543,
+	38557,	38561,	38567,	38569,	38593,	38603,	38609,	38611,	38629,	38639,
+	38651,	38653,	38669,	38671,	38677,	38693,	38699,	38707,	38711,	38713,
+	38723,	38729,	38737,	38747,	38749,	38767,	38783,	38791,	38803,	38821,
+	38833,	38839,	38851,	38861,	38867,	38873,	38891,	38903,	38917,	38921,
+	38923,	38933,	38953,	38959,	38971,	38977,	38993,	39019,	39023,	39041,
+	39043,	39047,	39079,	39089,	39097,	39103,	39107,	39113,	39119,	39133,
+	39139,	39157,	39161,	39163,	39181,	39191,	39199,	39209,	39217,	39227,
+	39229,	39233,	39239,	39241,	39251,	39293,	39301,	39313,	39317,	39323,
+	39341,	39343,	39359,	39367,	39371,	39373,	39383,	39397,	39409,	39419,
+	39439,	39443,	39451,	39461,	39499,	39503,	39509,	39511,	39521,	39541,
+	39551,	39563,	39569,	39581,	39607,	39619,	39623,	39631,	39659,	39667,
+	39671,	39679,	39703,	39709,	39719,	39727,	39733,	39749,	39761,	39769,
+	39779,	39791,	39799,	39821,	39827,	39829,	39839,	39841,	39847,	39857,
+	39863,	39869,	39877,	39883,	39887,	39901,	39929,	39937,	39953,	39971,
+	39979,	39983,	39989,	40009,	40013,	40031,	40037,	40039,	40063,	40087,
+	40093,	40099,	40111,	40123,	40127,	40129,	40151,	40153,	40163,	40169,
+	40177,	40189,	40193,	40213,	40231,	40237,	40241,	40253,	40277,	40283,
+	40289,	40343,	40351,	40357,	40361,	40387,	40423,	40427,	40429,	40433,
+	40459,	40471,	40483,	40487,	40493,	40499,	40507,	40519,	40529,	40531,
+	40543,	40559,	40577,	40583,	40591,	40597,	40609,	40627,	40637,	40639,
+	40693,	40697,	40699,	40709,	40739,	40751,	40759,	40763,	40771,	40787,
+	40801,	40813,	40819,	40823,	40829,	40841,	40847,	40849,	40853,	40867,
+	40879,	40883,	40897,	40903,	40927,	40933,	40939,	40949,	40961,	40973,
+	40993,	41011,	41017,	41023,	41039,	41047,	41051,	41057,	41077,	41081,
+	41113,	41117,	41131,	41141,	41143,	41149,	41161,	41177,	41179,	41183,
+	41189,	41201,	41203,	41213,	41221,	41227,	41231,	41233,	41243,	41257,
+	41263,	41269,	41281,	41299,	41333,	41341,	41351,	41357,	41381,	41387,
+	41389,	41399,	41411,	41413,	41443,	41453,	41467,	41479,	41491,	41507,
+	41513,	41519,	41521,	41539,	41543,	41549,	41579,	41593,	41597,	41603,
+	41609,	41611,	41617,	41621,	41627,	41641,	41647,	41651,	41659,	41669,
+	41681,	41687,	41719,	41729,	41737,	41759,	41761,	41771,	41777,	41801,
+	41809,	41813,	41843,	41849,	41851,	41863,	41879,	41887,	41893,	41897,
+	41903,	41911,	41927,	41941,	41947,	41953,	41957,	41959,	41969,	41981,
+	41983,	41999,	42013,	42017,	42019,	42023,	42043,	42061,	42071,	42073,
+	42083,	42089,	42101,	42131,	42139,	42157,	42169,	42179,	42181,	42187,
+	42193,	42197,	42209,	42221,	42223,	42227,	42239,	42257,	42281,	42283,
+	42293,	42299,	42307,	42323,	42331,	42337,	42349,	42359,	42373,	42379,
+	42391,	42397,	42403,	42407,	42409,	42433,	42437,	42443,	42451,	42457,
+	42461,	42463,	42467,	42473,	42487,	42491,	42499,	42509,	42533,	42557,
+	42569,	42571,	42577,	42589,	42611,	42641,	42643,	42649,	42667,	42677,
+	42683,	42689,	42697,	42701,	42703,	42709,	42719,	42727,	42737,	42743,
+	42751,	42767,	42773,	42787,	42793,	42797,	42821,	42829,	42839,	42841,
+	42853,	42859,	42863,	42899,	42901,	42923,	42929,	42937,	42943,	42953,
+	42961,	42967,	42979,	42989,	43003,	43013,	43019,	43037,	43049,	43051,
+	43063,	43067,	43093,	43103,	43117,	43133,	43151,	43159,	43177,	43189,
+	43201,	43207,	43223,	43237,	43261,	43271,	43283,	43291,	43313,	43319,
+	43321,	43331,	43391,	43397,	43399,	43403,	43411,	43427,	43441,	43451,
+	43457,	43481,	43487,	43499,	43517,	43541,	43543,	43573,	43577,	43579,
+	43591,	43597,	43607,	43609,	43613,	43627,	43633,	43649,	43651,	43661,
+	43669,	43691,	43711,	43717,	43721,	43753,	43759,	43777,	43781,	43783,
+	43787,	43789,	43793,	43801,	43853,	43867,	43889,	43891,	43913,	43933,
+	43943,	43951,	43961,	43963,	43969,	43973,	43987,	43991,	43997,	44017,
+	44021,	44027,	44029,	44041,	44053,	44059,	44071,	44087,	44089,	44101,
+	44111,	44119,	44123,	44129,	44131,	44159,	44171,	44179,	44189,	44201,
+	44203,	44207,	44221,	44249,	44257,	44263,	44267,	44269,	44273,	44279,
+	44281,	44293,	44351,	44357,	44371,	44381,	44383,	44389,	44417,	44449,
+	44453,	44483,	44491,	44497,	44501,	44507,	44519,	44531,	44533,	44537,
+	44543,	44549,	44563,	44579,	44587,	44617,	44621,	44623,	44633,	44641,
+	44647,	44651,	44657,	44683,	44687,	44699,	44701,	44711,	44729,	44741,
+	44753,	44771,	44773,	44777,	44789,	44797,	44809,	44819,	44839,	44843,
+	44851,	44867,	44879,	44887,	44893,	44909,	44917,	44927,	44939,	44953,
+	44959,	44963,	44971,	44983,	44987,	45007,	45013,	45053,	45061,	45077,
+	45083,	45119,	45121,	45127,	45131,	45137,	45139,	45161,	45179,	45181,
+	45191,	45197,	45233,	45247,	45259,	45263,	45281,	45289,	45293,	45307,
+	45317,	45319,	45329,	45337,	45341,	45343,	45361,	45377,	45389,	45403,
+	45413,	45427,	45433,	45439,	45481,	45491,	45497,	45503,	45523,	45533,
+	45541,	45553,	45557,	45569,	45587,	45589,	45599,	45613,	45631,	45641,
+	45659,	45667,	45673,	45677,	45691,	45697,	45707,	45737,	45751,	45757,
+	45763,	45767,	45779,	45817,	45821,	45823,	45827,	45833,	45841,	45853,
+	45863,	45869,	45887,	45893,	45943,	45949,	45953,	45959,	45971,	45979,
+	45989,	46021,	46027,	46049,	46051,	46061,	46073,	46091,	46093,	46099,
+	46103,	46133,	46141,	46147,	46153,	46171,	46181,	46183,	46187,	46199,
+	46219,	46229,	46237,	46261,	46271,	46273,	46279,	46301,	46307,	46309,
+	46327,	46337,	46349,	46351,	46381,	46399,	46411,	46439,	46441,	46447,
+	46451,	46457,	46471,	46477,	46489,	46499,	46507,	46511,	46523,	46549,
+	46559,	46567,	46573,	46589,	46591,	46601,	46619,	46633,	46639,	46643,
+	46649,	46663,	46679,	46681,	46687,	46691,	46703,	46723,	46727,	46747,
+	46751,	46757,	46769,	46771,	46807,	46811,	46817,	46819,	46829,	46831,
+	46853,	46861,	46867,	46877,	46889,	46901,	46919,	46933,	46957,	46993,
+	46997,	47017,	47041,	47051,	47057,	47059,	47087,	47093,	47111,	47119,
+	47123,	47129,	47137,	47143,	47147,	47149,	47161,	47189,	47207,	47221,
+	47237,	47251,	47269,	47279,	47287,	47293,	47297,	47303,	47309,	47317,
+	47339,	47351,	47353,	47363,	47381,	47387,	47389,	47407,	47417,	47419,
+	47431,	47441,	47459,	47491,	47497,	47501,	47507,	47513,	47521,	47527,
+	47533,	47543,	47563,	47569,	47581,	47591,	47599,	47609,	47623,	47629,
+	47639,	47653,	47657,	47659,	47681,	47699,	47701,	47711,	47713,	47717,
+	47737,	47741,	47743,	47777,	47779,	47791,	47797,	47807,	47809,	47819,
+	47837,	47843,	47857,	47869,	47881,	47903,	47911,	47917,	47933,	47939,
+	47947,	47951,	47963,	47969,	47977,	47981,	48017,	48023,	48029,	48049,
+	48073,	48079,	48091,	48109,	48119,	48121,	48131,	48157,	48163,	48179,
+	48187,	48193,	48197,	48221,	48239,	48247,	48259,	48271,	48281,	48299,
+	48311,	48313,	48337,	48341,	48353,	48371,	48383,	48397,	48407,	48409,
+	48413,	48437,	48449,	48463,	48473,	48479,	48481,	48487,	48491,	48497,
+	48523,	48527,	48533,	48539,	48541,	48563,	48571,	48589,	48593,	48611,
+	48619,	48623,	48647,	48649,	48661,	48673,	48677,	48679,	48731,	48733,
+	48751,	48757,	48761,	48767,	48779,	48781,	48787,	48799,	48809,	48817,
+	48821,	48823,	48847,	48857,	48859,	48869,	48871,	48883,	48889,	48907,
+	48947,	48953,	48973,	48989,	48991,	49003,	49009,	49019,	49031,	49033,
+	49037,	49043,	49057,	49069,	49081,	49103,	49109,	49117,	49121,	49123,
+	49139,	49157,	49169,	49171,	49177,	49193,	49199,	49201,	49207,	49211,
+	49223,	49253,	49261,	49277,	49279,	49297,	49307,	49331,	49333,	49339,
+	49363,	49367,	49369,	49391,	49393,	49409,	49411,	49417,	49429,	49433,
+	49451,	49459,	49463,	49477,	49481,	49499,	49523,	49529,	49531,	49537,
+	49547,	49549,	49559,	49597,	49603,	49613,	49627,	49633,	49639,	49663,
+	49667,	49669,	49681,	49697,	49711,	49727,	49739,	49741,	49747,	49757,
+	49783,	49787,	49789,	49801,	49807,	49811,	49823,	49831,	49843,	49853,
+	49871,	49877,	49891,	49919,	49921,	49927,	49937,	49939,	49943,	49957,
+	49991,	49993,	49999,	50021,	50023,	50033,	50047,	50051,	50053,	50069,
+	50077,	50087,	50093,	50101,	50111,	50119,	50123,	50129,	50131,	50147,
+	50153,	50159,	50177,	50207,	50221,	50227,	50231,	50261,	50263,	50273,
+	50287,	50291,	50311,	50321,	50329,	50333,	50341,	50359,	50363,	50377,
+	50383,	50387,	50411,	50417,	50423,	50441,	50459,	50461,	50497,	50503,
+	50513,	50527,	50539,	50543,	50549,	50551,	50581,	50587,	50591,	50593,
+	50599,	50627,	50647,	50651,	50671,	50683,	50707,	50723,	50741,	50753,
+	50767,	50773,	50777,	50789,	50821,	50833,	50839,	50849,	50857,	50867,
+	50873,	50891,	50893,	50909,	50923,	50929,	50951,	50957,	50969,	50971,
+	50989,	50993,	51001,	51031,	51043,	51047,	51059,	51061,	51071,	51109,
+	51131,	51133,	51137,	51151,	51157,	51169,	51193,	51197,	51199,	51203,
+	51217,	51229,	51239,	51241,	51257,	51263,	51283,	51287,	51307,	51329,
+	51341,	51343,	51347,	51349,	51361,	51383,	51407,	51413,	51419,	51421,
+	51427,	51431,	51437,	51439,	51449,	51461,	51473,	51479,	51481,	51487,
+	51503,	51511,	51517,	51521,	51539,	51551,	51563,	51577,	51581,	51593,
+	51599,	51607,	51613,	51631,	51637,	51647,	51659,	51673,	51679,	51683,
+	51691,	51713,	51719,	51721,	51749,	51767,	51769,	51787,	51797,	51803,
+	51817,	51827,	51829,	51839,	51853,	51859,	51869,	51871,	51893,	51899,
+	51907,	51913,	51929,	51941,	51949,	51971,	51973,	51977,	51991,	52009,
+	52021,	52027,	52051,	52057,	52067,	52069,	52081,	52103,	52121,	52127,
+	52147,	52153,	52163,	52177,	52181,	52183,	52189,	52201,	52223,	52237,
+	52249,	52253,	52259,	52267,	52289,	52291,	52301,	52313,	52321,	52361,
+	52363,	52369,	52379,	52387,	52391,	52433,	52453,	52457,	52489,	52501,
+	52511,	52517,	52529,	52541,	52543,	52553,	52561,	52567,	52571,	52579,
+	52583,	52609,	52627,	52631,	52639,	52667,	52673,	52691,	52697,	52709,
+	52711,	52721,	52727,	52733,	52747,	52757,	52769,	52783,	52807,	52813,
+	52817,	52837,	52859,	52861,	52879,	52883,	52889,	52901,	52903,	52919,
+	52937,	52951,	52957,	52963,	52967,	52973,	52981,	52999,	53003,	53017,
+	53047,	53051,	53069,	53077,	53087,	53089,	53093,	53101,	53113,	53117,
+	53129,	53147,	53149,	53161,	53171,	53173,	53189,	53197,	53201,	53231,
+	53233,	53239,	53267,	53269,	53279,	53281,	53299,	53309,	53323,	53327,
+	53353,	53359,	53377,	53381,	53401,	53407,	53411,	53419,	53437,	53441,
+	53453,	53479,	53503,	53507,	53527,	53549,	53551,	53569,	53591,	53593,
+	53597,	53609,	53611,	53617,	53623,	53629,	53633,	53639,	53653,	53657,
+	53681,	53693,	53699,	53717,	53719,	53731,	53759,	53773,	53777,	53783,
+	53791,	53813,	53819,	53831,	53849,	53857,	53861,	53881,	53887,	53891,
+	53897,	53899,	53917,	53923,	53927,	53939,	53951,	53959,	53987,	53993,
+	54001,	54011,	54013,	54037,	54049,	54059,	54083,	54091,	54101,	54121,
+	54133,	54139,	54151,	54163,	54167,	54181,	54193,	54217,	54251,	54269,
+	54277,	54287,	54293,	54311,	54319,	54323,	54331,	54347,	54361,	54367,
+	54371,	54377,	54401,	54403,	54409,	54413,	54419,	54421,	54437,	54443,
+	54449,	54469,	54493,	54497,	54499,	54503,	54517,	54521,	54539,	54541,
+	54547,	54559,	54563,	54577,	54581,	54583,	54601,	54617,	54623,	54629,
+	54631,	54647,	54667,	54673,	54679,	54709,	54713,	54721,	54727,	54751,
+	54767,	54773,	54779,	54787,	54799,	54829,	54833,	54851,	54869,	54877,
+	54881,	54907,	54917,	54919,	54941,	54949,	54959,	54973,	54979,	54983,
+	55001,	55009,	55021,	55049,	55051,	55057,	55061,	55073,	55079,	55103,
+	55109,	55117,	55127,	55147,	55163,	55171,	55201,	55207,	55213,	55217,
+	55219,	55229,	55243,	55249,	55259,	55291,	55313,	55331,	55333,	55337,
+	55339,	55343,	55351,	55373,	55381,	55399,	55411,	55439,	55441,	55457,
+	55469,	55487,	55501,	55511,	55529,	55541,	55547,	55579,	55589,	55603,
+	55609,	55619,	55621,	55631,	55633,	55639,	55661,	55663,	55667,	55673,
+	55681,	55691,	55697,	55711,	55717,	55721,	55733,	55763,	55787,	55793,
+	55799,	55807,	55813,	55817,	55819,	55823,	55829,	55837,	55843,	55849,
+	55871,	55889,	55897,	55901,	55903,	55921,	55927,	55931,	55933,	55949,
+	55967,	55987,	55997,	56003,	56009,	56039,	56041,	56053,	56081,	56087,
+	56093,	56099,	56101,	56113,	56123,	56131,	56149,	56167,	56171,	56179,
+	56197,	56207,	56209,	56237,	56239,	56249,	56263,	56267,	56269,	56299,
+	56311,	56333,	56359,	56369,	56377,	56383,	56393,	56401,	56417,	56431,
+	56437,	56443,	56453,	56467,	56473,	56477,	56479,	56489,	56501,	56503,
+	56509,	56519,	56527,	56531,	56533,	56543,	56569,	56591,	56597,	56599,
+	56611,	56629,	56633,	56659,	56663,	56671,	56681,	56687,	56701,	56711,
+	56713,	56731,	56737,	56747,	56767,	56773,	56779,	56783,	56807,	56809,
+	56813,	56821,	56827,	56843,	56857,	56873,	56891,	56893,	56897,	56909,
+	56911,	56921,	56923,	56929,	56941,	56951,	56957,	56963,	56983,	56989,
+	56993,	56999,	57037,	57041,	57047,	57059,	57073,	57077,	57089,	57097,
+	57107,	57119,	57131,	57139,	57143,	57149,	57163,	57173,	57179,	57191,
+	57193,	57203,	57221,	57223,	57241,	57251,	57259,	57269,	57271,	57283,
+	57287,	57301,	57329,	57331,	57347,	57349,	57367,	57373,	57383,	57389,
+	57397,	57413,	57427,	57457,	57467,	57487,	57493,	57503,	57527,	57529,
+	57557,	57559,	57571,	57587,	57593,	57601,	57637,	57641,	57649,	57653,
+	57667,	57679,	57689,	57697,	57709,	57713,	57719,	57727,	57731,	57737,
+	57751,	57773,	57781,	57787,	57791,	57793,	57803,	57809,	57829,	57839,
+	57847,	57853,	57859,	57881,	57899,	57901,	57917,	57923,	57943,	57947,
+	57973,	57977,	57991,	58013,	58027,	58031,	58043,	58049,	58057,	58061,
+	58067,	58073,	58099,	58109,	58111,	58129,	58147,	58151,	58153,	58169,
+	58171,	58189,	58193,	58199,	58207,	58211,	58217,	58229,	58231,	58237,
+	58243,	58271,	58309,	58313,	58321,	58337,	58363,	58367,	58369,	58379,
+	58391,	58393,	58403,	58411,	58417,	58427,	58439,	58441,	58451,	58453,
+	58477,	58481,	58511,	58537,	58543,	58549,	58567,	58573,	58579,	58601,
+	58603,	58613,	58631,	58657,	58661,	58679,	58687,	58693,	58699,	58711,
+	58727,	58733,	58741,	58757,	58763,	58771,	58787,	58789,	58831,	58889,
+	58897,	58901,	58907,	58909,	58913,	58921,	58937,	58943,	58963,	58967,
+	58979,	58991,	58997,	59009,	59011,	59021,	59023,	59029,	59051,	59053,
+	59063,	59069,	59077,	59083,	59093,	59107,	59113,	59119,	59123,	59141,
+	59149,	59159,	59167,	59183,	59197,	59207,	59209,	59219,	59221,	59233,
+	59239,	59243,	59263,	59273,	59281,	59333,	59341,	59351,	59357,	59359,
+	59369,	59377,	59387,	59393,	59399,	59407,	59417,	59419,	59441,	59443,
+	59447,	59453,	59467,	59471,	59473,	59497,	59509,	59513,	59539,	59557,
+	59561,	59567,	59581,	59611,	59617,	59621,	59627,	59629,	59651,	59659,
+	59663,	59669,	59671,	59693,	59699,	59707,	59723,	59729,	59743,	59747,
+	59753,	59771,	59779,	59791,	59797,	59809,	59833,	59863,	59879,	59887,
+	59921,	59929,	59951,	59957,	59971,	59981,	59999,	60013,	60017,	60029,
+	60037,	60041,	60077,	60083,	60089,	60091,	60101,	60103,	60107,	60127,
+	60133,	60139,	60149,	60161,	60167,	60169,	60209,	60217,	60223,	60251,
+	60257,	60259,	60271,	60289,	60293,	60317,	60331,	60337,	60343,	60353,
+	60373,	60383,	60397,	60413,	60427,	60443,	60449,	60457,	60493,	60497,
+	60509,	60521,	60527,	60539,	60589,	60601,	60607,	60611,	60617,	60623,
+	60631,	60637,	60647,	60649,	60659,	60661,	60679,	60689,	60703,	60719,
+	60727,	60733,	60737,	60757,	60761,	60763,	60773,	60779,	60793,	60811,
+	60821,	60859,	60869,	60887,	60889,	60899,	60901,	60913,	60917,	60919,
+	60923,	60937,	60943,	60953,	60961,	61001,	61007,	61027,	61031,	61043,
+	61051,	61057,	61091,	61099,	61121,	61129,	61141,	61151,	61153,	61169,
+	61211,	61223,	61231,	61253,	61261,	61283,	61291,	61297,	61331,	61333,
+	61339,	61343,	61357,	61363,	61379,	61381,	61403,	61409,	61417,	61441,
+	61463,	61469,	61471,	61483,	61487,	61493,	61507,	61511,	61519,	61543,
+	61547,	61553,	61559,	61561,	61583,	61603,	61609,	61613,	61627,	61631,
+	61637,	61643,	61651,	61657,	61667,	61673,	61681,	61687,	61703,	61717,
+	61723,	61729,	61751,	61757,	61781,	61813,	61819,	61837,	61843,	61861,
+	61871,	61879,	61909,	61927,	61933,	61949,	61961,	61967,	61979,	61981,
+	61987,	61991,	62003,	62011,	62017,	62039,	62047,	62053,	62057,	62071,
+	62081,	62099,	62119,	62129,	62131,	62137,	62141,	62143,	62171,	62189,
+	62191,	62201,	62207,	62213,	62219,	62233,	62273,	62297,	62299,	62303,
+	62311,	62323,	62327,	62347,	62351,	62383,	62401,	62417,	62423,	62459,
+	62467,	62473,	62477,	62483,	62497,	62501,	62507,	62533,	62539,	62549,
+	62563,	62581,	62591,	62597,	62603,	62617,	62627,	62633,	62639,	62653,
+	62659,	62683,	62687,	62701,	62723,	62731,	62743,	62753,	62761,	62773,
+	62791,	62801,	62819,	62827,	62851,	62861,	62869,	62873,	62897,	62903,
+	62921,	62927,	62929,	62939,	62969,	62971,	62981,	62983,	62987,	62989,
+	63029,	63031,	63059,	63067,	63073,	63079,	63097,	63103,	63113,	63127,
+	63131,	63149,	63179,	63197,	63199,	63211,	63241,	63247,	63277,	63281,
+	63299,	63311,	63313,	63317,	63331,	63337,	63347,	63353,	63361,	63367,
+	63377,	63389,	63391,	63397,	63409,	63419,	63421,	63439,	63443,	63463,
+	63467,	63473,	63487,	63493,	63499,	63521,	63527,	63533,	63541,	63559,
+	63577,	63587,	63589,	63599,	63601,	63607,	63611,	63617,	63629,	63647,
+	63649,	63659,	63667,	63671,	63689,	63691,	63697,	63703,	63709,	63719,
+	63727,	63737,	63743,	63761,	63773,	63781,	63793,	63799,	63803,	63809,
+	63823,	63839,	63841,	63853,	63857,	63863,	63901,	63907,	63913,	63929,
+	63949,	63977,	63997,	64007,	64013,	64019,	64033,	64037,	64063,	64067,
+	64081,	64091,	64109,	64123,	64151,	64153,	64157,	64171,	64187,	64189,
+	64217,	64223,	64231,	64237,	64271,	64279,	64283,	64301,	64303,	64319,
+	64327,	64333,	64373,	64381,	64399,	64403,	64433,	64439,	64451,	64453,
+	64483,	64489,	64499,	64513,	64553,	64567,	64577,	64579,	64591,	64601,
+	64609,	64613,	64621,	64627,	64633,	64661,	64663,	64667,	64679,	64693,
+	64709,	64717,	64747,	64763,	64781,	64783,	64793,	64811,	64817,	64849,
+	64853,	64871,	64877,	64879,	64891,	64901,	64919,	64921,	64927,	64937,
+	64951,	64969,	64997,	65003,	65011,	65027,	65029,	65033,	65053,	65063,
+	65071,	65089,	65099,	65101,	65111,	65119,	65123,	65129,	65141,	65147,
+	65167,	65171,	65173,	65179,	65183,	65203,	65213,	65239,	65257,	65267,
+	65269,	65287,	65293,	65309,	65323,	65327,	65353,	65357,	65371,	65381,
+	65393,	65407,	65413,	65419,	65423,	65437,	65447,	65449,	65479,	65497,
+	65519,	65521,	65537,	65539,	65543,	65551,	65557,	65563,	65579,	65581,
+	65587,	65599,	65609,	65617,	65629,	65633,	65647,	65651,	65657,	65677,
+	65687,	65699,	65701,	65707,	65713,	65717,	65719,	65729,	65731,	65761,
+	65777,	65789,	65809,	65827,	65831,	65837,	65839,	65843,	65851,	65867,
+	65881,	65899,	65921,	65927,	65929,	65951,	65957,	65963,	65981,	65983,
+	65993,	66029,	66037,	66041,	66047,	66067,	66071,	66083,	66089,	66103,
+	66107,	66109,	66137,	66161,	66169,	66173,	66179,	66191,	66221,	66239,
+	66271,	66293,	66301,	66337,	66343,	66347,	66359,	66361,	66373,	66377,
+	66383,	66403,	66413,	66431,	66449,	66457,	66463,	66467,	66491,	66499,
+	66509,	66523,	66529,	66533,	66541,	66553,	66569,	66571,	66587,	66593,
+	66601,	66617,	66629,	66643,	66653,	66683,	66697,	66701,	66713,	66721,
+	66733,	66739,	66749,	66751,	66763,	66791,	66797,	66809,	66821,	66841,
+	66851,	66853,	66863,	66877,	66883,	66889,	66919,	66923,	66931,	66943,
+	66947,	66949,	66959,	66973,	66977,	67003,	67021,	67033,	67043,	67049,
+	67057,	67061,	67073,	67079,	67103,	67121,	67129,	67139,	67141,	67153,
+	67157,	67169,	67181,	67187,	67189,	67211,	67213,	67217,	67219,	67231,
+	67247,	67261,	67271,	67273,	67289,	67307,	67339,	67343,	67349,	67369,
+	67391,	67399,	67409,	67411,	67421,	67427,	67429,	67433,	67447,	67453,
+	67477,	67481,	67489,	67493,	67499,	67511,	67523,	67531,	67537,	67547,
+	67559,	67567,	67577,	67579,	67589,	67601,	67607,	67619,	67631,	67651,
+	67679,	67699,	67709,	67723,	67733,	67741,	67751,	67757,	67759,	67763,
+	67777,	67783,	67789,	67801,	67807,	67819,	67829,	67843,	67853,	67867,
+	67883,	67891,	67901,	67927,	67931,	67933,	67939,	67943,	67957,	67961,
+	67967,	67979,	67987,	67993,	68023,	68041,	68053,	68059,	68071,	68087,
+	68099,	68111,	68113,	68141,	68147,	68161,	68171,	68207,	68209,	68213,
+	68219,	68227,	68239,	68261,	68279,	68281,	68311,	68329,	68351,	68371,
+	68389,	68399,	68437,	68443,	68447,	68449,	68473,	68477,	68483,	68489,
+	68491,	68501,	68507,	68521,	68531,	68539,	68543,	68567,	68581,	68597,
+	68611,	68633,	68639,	68659,	68669,	68683,	68687,	68699,	68711,	68713,
+	68729,	68737,	68743,	68749,	68767,	68771,	68777,	68791,	68813,	68819,
+	68821,	68863,	68879,	68881,	68891,	68897,	68899,	68903,	68909,	68917,
+	68927,	68947,	68963,	68993,	69001,	69011,	69019,	69029,	69031,	69061,
+	69067,	69073,	69109,	69119,	69127,	69143,	69149,	69151,	69163,	69191,
+	69193,	69197,	69203,	69221,	69233,	69239,	69247,	69257,	69259,	69263,
+	69313,	69317,	69337,	69341,	69371,	69379,	69383,	69389,	69401,	69403,
+	69427,	69431,	69439,	69457,	69463,	69467,	69473,	69481,	69491,	69493,
+	69497,	69499,	69539,	69557,	69593,	69623,	69653,	69661,	69677,	69691,
+	69697,	69709,	69737,	69739,	69761,	69763,	69767,	69779,	69809,	69821,
+	69827,	69829,	69833,	69847,	69857,	69859,	69877,	69899,	69911,	69929,
+	69931,	69941,	69959,	69991,	69997,	70001,	70003,	70009,	70019,	70039,
+	70051,	70061,	70067,	70079,	70099,	70111,	70117,	70121,	70123,	70139,
+	70141,	70157,	70163,	70177,	70181,	70183,	70199,	70201,	70207,	70223,
+	70229,	70237,	70241,	70249,	70271,	70289,	70297,	70309,	70313,	70321,
+	70327,	70351,	70373,	70379,	70381,	70393,	70423,	70429,	70439,	70451,
+	70457,	70459,	70481,	70487,	70489,	70501,	70507,	70529,	70537,	70549,
+	70571,	70573,	70583,	70589,	70607,	70619,	70621,	70627,	70639,	70657,
+	70663,	70667,	70687,	70709,	70717,	70729,	70753,	70769,	70783,	70793,
+	70823,	70841,	70843,	70849,	70853,	70867,	70877,	70879,	70891,	70901,
+	70913,	70919,	70921,	70937,	70949,	70951,	70957,	70969,	70979,	70981,
+	70991,	70997,	70999,	71011,	71023,	71039,	71059,	71069,	71081,	71089,
+	71119,	71129,	71143,	71147,	71153,	71161,	71167,	71171,	71191,	71209,
+	71233,	71237,	71249,	71257,	71261,	71263,	71287,	71293,	71317,	71327,
+	71329,	71333,	71339,	71341,	71347,	71353,	71359,	71363,	71387,	71389,
+	71399,	71411,	71413,	71419,	71429,	71437,	71443,	71453,	71471,	71473,
+	71479,	71483,	71503,	71527,	71537,	71549,	71551,	71563,	71569,	71593,
+	71597,	71633,	71647,	71663,	71671,	71693,	71699,	71707,	71711,	71713,
+	71719,	71741,	71761,	71777,	71789,	71807,	71809,	71821,	71837,	71843,
+	71849,	71861,	71867,	71879,	71881,	71887,	71899,	71909,	71917,	71933,
+	71941,	71947,	71963,	71971,	71983,	71987,	71993,	71999,	72019,	72031,
+	72043,	72047,	72053,	72073,	72077,	72089,	72091,	72101,	72103,	72109,
+	72139,	72161,	72167,	72169,	72173,	72211,	72221,	72223,	72227,	72229,
+	72251,	72253,	72269,	72271,	72277,	72287,	72307,	72313,	72337,	72341,
+	72353,	72367,	72379,	72383,	72421,	72431,	72461,	72467,	72469,	72481,
+	72493,	72497,	72503,	72533,	72547,	72551,	72559,	72577,	72613,	72617,
+	72623,	72643,	72647,	72649,	72661,	72671,	72673,	72679,	72689,	72701,
+	72707,	72719,	72727,	72733,	72739,	72763,	72767,	72797,	72817,	72823,
+	72859,	72869,	72871,	72883,	72889,	72893,	72901,	72907,	72911,	72923,
+	72931,	72937,	72949,	72953,	72959,	72973,	72977,	72997,	73009,	73013,
+	73019,	73037,	73039,	73043,	73061,	73063,	73079,	73091,	73121,	73127,
+	73133,	73141,	73181,	73189,	73237,	73243,	73259,	73277,	73291,	73303,
+	73309,	73327,	73331,	73351,	73361,	73363,	73369,	73379,	73387,	73417,
+	73421,	73433,	73453,	73459,	73471,	73477,	73483,	73517,	73523,	73529,
+	73547,	73553,	73561,	73571,	73583,	73589,	73597,	73607,	73609,	73613,
+	73637,	73643,	73651,	73673,	73679,	73681,	73693,	73699,	73709,	73721,
+	73727,	73751,	73757,	73771,	73783,	73819,	73823,	73847,	73849,	73859,
+	73867,	73877,	73883,	73897,	73907,	73939,	73943,	73951,	73961,	73973,
+	73999,	74017,	74021,	74027,	74047,	74051,	74071,	74077,	74093,	74099,
+	74101,	74131,	74143,	74149,	74159,	74161,	74167,	74177,	74189,	74197,
+	74201,	74203,	74209,	74219,	74231,	74257,	74279,	74287,	74293,	74297,
+	74311,	74317,	74323,	74353,	74357,	74363,	74377,	74381,	74383,	74411,
+	74413,	74419,	74441,	74449,	74453,	74471,	74489,	74507,	74509,	74521,
+	74527,	74531,	74551,	74561,	74567,	74573,	74587,	74597,	74609,	74611,
+	74623,	74653,	74687,	74699,	74707,	74713,	74717,	74719,	74729,	74731,
+	74747,	74759,	74761,	74771,	74779,	74797,	74821,	74827,	74831,	74843,
+	74857,	74861,	74869,	74873,	74887,	74891,	74897,	74903,	74923,	74929,
+	74933,	74941,	74959,	75011,	75013,	75017,	75029,	75037,	75041,	75079,
+	75083,	75109,	75133,	75149,	75161,	75167,	75169,	75181,	75193,	75209,
+	75211,	75217,	75223,	75227,	75239,	75253,	75269,	75277,	75289,	75307,
+	75323,	75329,	75337,	75347,	75353,	75367,	75377,	75389,	75391,	75401,
+	75403,	75407,	75431,	75437,	75479,	75503,	75511,	75521,	75527,	75533,
+	75539,	75541,	75553,	75557,	75571,	75577,	75583,	75611,	75617,	75619,
+	75629,	75641,	75653,	75659,	75679,	75683,	75689,	75703,	75707,	75709,
+	75721,	75731,	75743,	75767,	75773,	75781,	75787,	75793,	75797,	75821,
+	75833,	75853,	75869,	75883,	75913,	75931,	75937,	75941,	75967,	75979,
+	75983,	75989,	75991,	75997,	76001,	76003,	76031,	76039,	76079,	76081,
+	76091,	76099,	76103,	76123,	76129,	76147,	76157,	76159,	76163,	76207,
+	76213,	76231,	76243,	76249,	76253,	76259,	76261,	76283,	76289,	76303,
+	76333,	76343,	76367,	76369,	76379,	76387,	76403,	76421,	76423,	76441,
+	76463,	76471,	76481,	76487,	76493,	76507,	76511,	76519,	76537,	76541,
+	76543,	76561,	76579,	76597,	76603,	76607,	76631,	76649,	76651,	76667,
+	76673,	76679,	76697,	76717,	76733,	76753,	76757,	76771,	76777,	76781,
+	76801,	76819,	76829,	76831,	76837,	76847,	76871,	76873,	76883,	76907,
+	76913,	76919,	76943,	76949,	76961,	76963,	76991,	77003,	77017,	77023,
+	77029,	77041,	77047,	77069,	77081,	77093,	77101,	77137,	77141,	77153,
+	77167,	77171,	77191,	77201,	77213,	77237,	77239,	77243,	77249,	77261,
+	77263,	77267,	77269,	77279,	77291,	77317,	77323,	77339,	77347,	77351,
+	77359,	77369,	77377,	77383,	77417,	77419,	77431,	77447,	77471,	77477,
+	77479,	77489,	77491,	77509,	77513,	77521,	77527,	77543,	77549,	77551,
+	77557,	77563,	77569,	77573,	77587,	77591,	77611,	77617,	77621,	77641,
+	77647,	77659,	77681,	77687,	77689,	77699,	77711,	77713,	77719,	77723,
+	77731,	77743,	77747,	77761,	77773,	77783,	77797,	77801,	77813,	77839,
+	77849,	77863,	77867,	77893,	77899,	77929,	77933,	77951,	77969,	77977,
+	77983,	77999,	78007,	78017,	78031,	78041,	78049,	78059,	78079,	78101,
+	78121,	78137,	78139,	78157,	78163,	78167,	78173,	78179,	78191,	78193,
+	78203,	78229,	78233,	78241,	78259,	78277,	78283,	78301,	78307,	78311,
+	78317,	78341,	78347,	78367,	78401,	78427,	78437,	78439,	78467,	78479,
+	78487,	78497,	78509,	78511,	78517,	78539,	78541,	78553,	78569,	78571,
+	78577,	78583,	78593,	78607,	78623,	78643,	78649,	78653,	78691,	78697,
+	78707,	78713,	78721,	78737,	78779,	78781,	78787,	78791,	78797,	78803,
+	78809,	78823,	78839,	78853,	78857,	78877,	78887,	78889,	78893,	78901,
+	78919,	78929,	78941,	78977,	78979,	78989,	79031,	79039,	79043,	79063,
+	79087,	79103,	79111,	79133,	79139,	79147,	79151,	79153,	79159,	79181,
+	79187,	79193,	79201,	79229,	79231,	79241,	79259,	79273,	79279,	79283,
+	79301,	79309,	79319,	79333,	79337,	79349,	79357,	79367,	79379,	79393,
+	79397,	79399,	79411,	79423,	79427,	79433,	79451,	79481,	79493,	79531,
+	79537,	79549,	79559,	79561,	79579,	79589,	79601,	79609,	79613,	79621,
+	79627,	79631,	79633,	79657,	79669,	79687,	79691,	79693,	79697,	79699,
+	79757,	79769,	79777,	79801,	79811,	79813,	79817,	79823,	79829,	79841,
+	79843,	79847,	79861,	79867,	79873,	79889,	79901,	79903,	79907,	79939,
+	79943,	79967,	79973,	79979,	79987,	79997,	79999,	80021,	80039,	80051,
+	80071,	80077,	80107,	80111,	80141,	80147,	80149,	80153,	80167,	80173,
+	80177,	80191,	80207,	80209,	80221,	80231,	80233,	80239,	80251,	80263,
+	80273,	80279,	80287,	80309,	80317,	80329,	80341,	80347,	80363,	80369,
+	80387,	80407,	80429,	80447,	80449,	80471,	80473,	80489,	80491,	80513,
+	80527,	80537,	80557,	80567,	80599,	80603,	80611,	80621,	80627,	80629,
+	80651,	80657,	80669,	80671,	80677,	80681,	80683,	80687,	80701,	80713,
+	80737,	80747,	80749,	80761,	80777,	80779,	80783,	80789,	80803,	80809,
+	80819,	80831,	80833,	80849,	80863,	80897,	80909,	80911,	80917,	80923,
+	80929,	80933,	80953,	80963,	80989,	81001,	81013,	81017,	81019,	81023,
+	81031,	81041,	81043,	81047,	81049,	81071,	81077,	81083,	81097,	81101,
+	81119,	81131,	81157,	81163,	81173,	81181,	81197,	81199,	81203,	81223,
+	81233,	81239,	81281,	81283,	81293,	81299,	81307,	81331,	81343,	81349,
+	81353,	81359,	81371,	81373,	81401,	81409,	81421,	81439,	81457,	81463,
+	81509,	81517,	81527,	81533,	81547,	81551,	81553,	81559,	81563,	81569,
+	81611,	81619,	81629,	81637,	81647,	81649,	81667,	81671,	81677,	81689,
+	81701,	81703,	81707,	81727,	81737,	81749,	81761,	81769,	81773,	81799,
+	81817,	81839,	81847,	81853,	81869,	81883,	81899,	81901,	81919,	81929,
+	81931,	81937,	81943,	81953,	81967,	81971,	81973,	82003,	82007,	82009,
+	82013,	82021,	82031,	82037,	82039,	82051,	82067,	82073,	82129,	82139,
+	82141,	82153,	82163,	82171,	82183,	82189,	82193,	82207,	82217,	82219,
+	82223,	82231,	82237,	82241,	82261,	82267,	82279,	82301,	82307,	82339,
+	82349,	82351,	82361,	82373,	82387,	82393,	82421,	82457,	82463,	82469,
+	82471,	82483,	82487,	82493,	82499,	82507,	82529,	82531,	82549,	82559,
+	82561,	82567,	82571,	82591,	82601,	82609,	82613,	82619,	82633,	82651,
+	82657,	82699,	82721,	82723,	82727,	82729,	82757,	82759,	82763,	82781,
+	82787,	82793,	82799,	82811,	82813,	82837,	82847,	82883,	82889,	82891,
+	82903,	82913,	82939,	82963,	82981,	82997,	83003,	83009,	83023,	83047,
+	83059,	83063,	83071,	83077,	83089,	83093,	83101,	83117,	83137,	83177,
+	83203,	83207,	83219,	83221,	83227,	83231,	83233,	83243,	83257,	83267,
+	83269,	83273,	83299,	83311,	83339,	83341,	83357,	83383,	83389,	83399,
+	83401,	83407,	83417,	83423,	83431,	83437,	83443,	83449,	83459,	83471,
+	83477,	83497,	83537,	83557,	83561,	83563,	83579,	83591,	83597,	83609,
+	83617,	83621,	83639,	83641,	83653,	83663,	83689,	83701,	83717,	83719,
+	83737,	83761,	83773,	83777,	83791,	83813,	83833,	83843,	83857,	83869,
+	83873,	83891,	83903,	83911,	83921,	83933,	83939,	83969,	83983,	83987,
+	84011,	84017,	84047,	84053,	84059,	84061,	84067,	84089,	84121,	84127,
+	84131,	84137,	84143,	84163,	84179,	84181,	84191,	84199,	84211,	84221,
+	84223,	84229,	84239,	84247,	84263,	84299,	84307,	84313,	84317,	84319,
+	84347,	84349,	84377,	84389,	84391,	84401,	84407,	84421,	84431,	84437,
+	84443,	84449,	84457,	84463,	84467,	84481,	84499,	84503,	84509,	84521,
+	84523,	84533,	84551,	84559,	84589,	84629,	84631,	84649,	84653,	84659,
+	84673,	84691,	84697,	84701,	84713,	84719,	84731,	84737,	84751,	84761,
+	84787,	84793,	84809,	84811,	84827,	84857,	84859,	84869,	84871,	84913,
+	84919,	84947,	84961,	84967,	84977,	84979,	84991,	85009,	85021,	85027,
+	85037,	85049,	85061,	85081,	85087,	85091,	85093,	85103,	85109,	85121,
+	85133,	85147,	85159,	85193,	85199,	85201,	85213,	85223,	85229,	85237,
+	85243,	85247,	85259,	85297,	85303,	85313,	85331,	85333,	85361,	85363,
+	85369,	85381,	85411,	85427,	85429,	85439,	85447,	85451,	85453,	85469,
+	85487,	85513,	85517,	85523,	85531,	85549,	85571,	85577,	85597,	85601,
+	85607,	85619,	85621,	85627,	85639,	85643,	85661,	85667,	85669,	85691,
+	85703,	85711,	85717,	85733,	85751,	85781,	85793,	85817,	85819,	85829,
+	85831,	85837,	85843,	85847,	85853,	85889,	85903,	85909,	85931,	85933,
+	85991,	85999,	86011,	86017,	86027,	86029,	86069,	86077,	86083,	86111,
+	86113,	86117,	86131,	86137,	86143,	86161,	86171,	86179,	86183,	86197,
+	86201,	86209,	86239,	86243,	86249,	86257,	86263,	86269,	86287,	86291,
+	86293,	86297,	86311,	86323,	86341,	86351,	86353,	86357,	86369,	86371,
+	86381,	86389,	86399,	86413,	86423,	86441,	86453,	86461,	86467,	86477,
+	86491,	86501,	86509,	86531,	86533,	86539,	86561,	86573,	86579,	86587,
+	86599,	86627,	86629,	86677,	86689,	86693,	86711,	86719,	86729,	86743,
+	86753,	86767,	86771,	86783,	86813,	86837,	86843,	86851,	86857,	86861,
+	86869,	86923,	86927,	86929,	86939,	86951,	86959,	86969,	86981,	86993,
+	87011,	87013,	87037,	87041,	87049,	87071,	87083,	87103,	87107,	87119,
+	87121,	87133,	87149,	87151,	87179,	87181,	87187,	87211,	87221,	87223,
+	87251,	87253,	87257,	87277,	87281,	87293,	87299,	87313,	87317,	87323,
+	87337,	87359,	87383,	87403,	87407,	87421,	87427,	87433,	87443,	87473,
+	87481,	87491,	87509,	87511,	87517,	87523,	87539,	87541,	87547,	87553,
+	87557,	87559,	87583,	87587,	87589,	87613,	87623,	87629,	87631,	87641,
+	87643,	87649,	87671,	87679,	87683,	87691,	87697,	87701,	87719,	87721,
+	87739,	87743,	87751,	87767,	87793,	87797,	87803,	87811,	87833,	87853,
+	87869,	87877,	87881,	87887,	87911,	87917,	87931,	87943,	87959,	87961,
+	87973,	87977,	87991,	88001,	88003,	88007,	88019,	88037,	88069,	88079,
+	88093,	88117,	88129,	88169,	88177,	88211,	88223,	88237,	88241,	88259,
+	88261,	88289,	88301,	88321,	88327,	88337,	88339,	88379,	88397,	88411,
+	88423,	88427,	88463,	88469,	88471,	88493,	88499,	88513,	88523,	88547,
+	88589,	88591,	88607,	88609,	88643,	88651,	88657,	88661,	88663,	88667,
+	88681,	88721,	88729,	88741,	88747,	88771,	88789,	88793,	88799,	88801,
+	88807,	88811,	88813,	88817,	88819,	88843,	88853,	88861,	88867,	88873,
+	88883,	88897,	88903,	88919,	88937,	88951,	88969,	88993,	88997,	89003,
+	89009,	89017,	89021,	89041,	89051,	89057,	89069,	89071,	89083,	89087,
+	89101,	89107,	89113,	89119,	89123,	89137,	89153,	89189,	89203,	89209,
+	89213,	89227,	89231,	89237,	89261,	89269,	89273,	89293,	89303,	89317,
+	89329,	89363,	89371,	89381,	89387,	89393,	89399,	89413,	89417,	89431,
+	89443,	89449,	89459,	89477,	89491,	89501,	89513,	89519,	89521,	89527,
+	89533,	89561,	89563,	89567,	89591,	89597,	89599,	89603,	89611,	89627,
+	89633,	89653,	89657,	89659,	89669,	89671,	89681,	89689,	89753,	89759,
+	89767,	89779,	89783,	89797,	89809,	89819,	89821,	89833,	89839,	89849,
+	89867,	89891,	89897,	89899,	89909,	89917,	89923,	89939,	89959,	89963,
+	89977,	89983,	89989,	90001,	90007,	90011,	90017,	90019,	90023,	90031,
+	90053,	90059,	90067,	90071,	90073,	90089,	90107,	90121,	90127,	90149,
+	90163,	90173,	90187,	90191,	90197,	90199,	90203,	90217,	90227,	90239,
+	90247,	90263,	90271,	90281,	90289,	90313,	90353,	90359,	90371,	90373,
+	90379,	90397,	90401,	90403,	90407,	90437,	90439,	90469,	90473,	90481,
+	90499,	90511,	90523,	90527,	90529,	90533,	90547,	90583,	90599,	90617,
+	90619,	90631,	90641,	90647,	90659,	90677,	90679,	90697,	90703,	90709,
+	90731,	90749,	90787,	90793,	90803,	90821,	90823,	90833,	90841,	90847,
+	90863,	90887,	90901,	90907,	90911,	90917,	90931,	90947,	90971,	90977,
+	90989,	90997,	91009,	91019,	91033,	91079,	91081,	91097,	91099,	91121,
+	91127,	91129,	91139,	91141,	91151,	91153,	91159,	91163,	91183,	91193,
+	91199,	91229,	91237,	91243,	91249,	91253,	91283,	91291,	91297,	91303,
+	91309,	91331,	91367,	91369,	91373,	91381,	91387,	91393,	91397,	91411,
+	91423,	91433,	91453,	91457,	91459,	91463,	91493,	91499,	91513,	91529,
+	91541,	91571,	91573,	91577,	91583,	91591,	91621,	91631,	91639,	91673,
+	91691,	91703,	91711,	91733,	91753,	91757,	91771,	91781,	91801,	91807,
+	91811,	91813,	91823,	91837,	91841,	91867,	91873,	91909,	91921,	91939,
+	91943,	91951,	91957,	91961,	91967,	91969,	91997,	92003,	92009,	92033,
+	92041,	92051,	92077,	92083,	92107,	92111,	92119,	92143,	92153,	92173,
+	92177,	92179,	92189,	92203,	92219,	92221,	92227,	92233,	92237,	92243,
+	92251,	92269,	92297,	92311,	92317,	92333,	92347,	92353,	92357,	92363,
+	92369,	92377,	92381,	92383,	92387,	92399,	92401,	92413,	92419,	92431,
+	92459,	92461,	92467,	92479,	92489,	92503,	92507,	92551,	92557,	92567,
+	92569,	92581,	92593,	92623,	92627,	92639,	92641,	92647,	92657,	92669,
+	92671,	92681,	92683,	92693,	92699,	92707,	92717,	92723,	92737,	92753,
+	92761,	92767,	92779,	92789,	92791,	92801,	92809,	92821,	92831,	92849,
+	92857,	92861,	92863,	92867,	92893,	92899,	92921,	92927,	92941,	92951,
+	92957,	92959,	92987,	92993,	93001,	93047,	93053,	93059,	93077,	93083,
+	93089,	93097,	93103,	93113,	93131,	93133,	93139,	93151,	93169,	93179,
+	93187,	93199,	93229,	93239,	93241,	93251,	93253,	93257,	93263,	93281,
+	93283,	93287,	93307,	93319,	93323,	93329,	93337,	93371,	93377,	93383,
+	93407,	93419,	93427,	93463,	93479,	93481,	93487,	93491,	93493,	93497,
+	93503,	93523,	93529,	93553,	93557,	93559,	93563,	93581,	93601,	93607,
+	93629,	93637,	93683,	93701,	93703,	93719,	93739,	93761,	93763,	93787,
+	93809,	93811,	93827,	93851,	93871,	93887,	93889,	93893,	93901,	93911,
+	93913,	93923,	93937,	93941,	93949,	93967,	93971,	93979,	93983,	93997,
+	94007,	94009,	94033,	94049,	94057,	94063,	94079,	94099,	94109,	94111,
+	94117,	94121,	94151,	94153,	94169,	94201,	94207,	94219,	94229,	94253,
+	94261,	94273,	94291,	94307,	94309,	94321,	94327,	94331,	94343,	94349,
+	94351,	94379,	94397,	94399,	94421,	94427,	94433,	94439,	94441,	94447,
+	94463,	94477,	94483,	94513,	94529,	94531,	94541,	94543,	94547,	94559,
+	94561,	94573,	94583,	94597,	94603,	94613,	94621,	94649,	94651,	94687,
+	94693,	94709,	94723,	94727,	94747,	94771,	94777,	94781,	94789,	94793,
+	94811,	94819,	94823,	94837,	94841,	94847,	94849,	94873,	94889,	94903,
+	94907,	94933,	94949,	94951,	94961,	94993,	94999,	95003,	95009,	95021,
+	95027,	95063,	95071,	95083,	95087,	95089,	95093,	95101,	95107,	95111,
+	95131,	95143,	95153,	95177,	95189,	95191,	95203,	95213,	95219,	95231,
+	95233,	95239,	95257,	95261,	95267,	95273,	95279,	95287,	95311,	95317,
+	95327,	95339,	95369,	95383,	95393,	95401,	95413,	95419,	95429,	95441,
+	95443,	95461,	95467,	95471,	95479,	95483,	95507,	95527,	95531,	95539,
+	95549,	95561,	95569,	95581,	95597,	95603,	95617,	95621,	95629,	95633,
+	95651,	95701,	95707,	95713,	95717,	95723,	95731,	95737,	95747,	95773,
+	95783,	95789,	95791,	95801,	95803,	95813,	95819,	95857,	95869,	95873,
+	95881,	95891,	95911,	95917,	95923,	95929,	95947,	95957,	95959,	95971,
+	95987,	95989,	96001,	96013,	96017,	96043,	96053,	96059,	96079,	96097,
+	96137,	96149,	96157,	96167,	96179,	96181,	96199,	96211,	96221,	96223,
+	96233,	96259,	96263,	96269,	96281,	96289,	96293,	96323,	96329,	96331,
+	96337,	96353,	96377,	96401,	96419,	96431,	96443,	96451,	96457,	96461,
+	96469,	96479,	96487,	96493,	96497,	96517,	96527,	96553,	96557,	96581,
+	96587,	96589,	96601,	96643,	96661,	96667,	96671,	96697,	96703,	96731,
+	96737,	96739,	96749,	96757,	96763,	96769,	96779,	96787,	96797,	96799,
+	96821,	96823,	96827,	96847,	96851,	96857,	96893,	96907,	96911,	96931,
+	96953,	96959,	96973,	96979,	96989,	96997,	97001,	97003,	97007,	97021,
+	97039,	97073,	97081,	97103,	97117,	97127,	97151,	97157,	97159,	97169,
+	97171,	97177,	97187,	97213,	97231,	97241,	97259,	97283,	97301,	97303,
+	97327,	97367,	97369,	97373,	97379,	97381,	97387,	97397,	97423,	97429,
+	97441,	97453,	97459,	97463,	97499,	97501,	97511,	97523,	97547,	97549,
+	97553,	97561,	97571,	97577,	97579,	97583,	97607,	97609,	97613,	97649,
+	97651,	97673,	97687,	97711,	97729,	97771,	97777,	97787,	97789,	97813,
+	97829,	97841,	97843,	97847,	97849,	97859,	97861,	97871,	97879,	97883,
+	97919,	97927,	97931,	97943,	97961,	97967,	97973,	97987,	98009,	98011,
+	98017,	98041,	98047,	98057,	98081,	98101,	98123,	98129,	98143,	98179,
+	98207,	98213,	98221,	98227,	98251,	98257,	98269,	98297,	98299,	98317,
+	98321,	98323,	98327,	98347,	98369,	98377,	98387,	98389,	98407,	98411,
+	98419,	98429,	98443,	98453,	98459,	98467,	98473,	98479,	98491,	98507,
+	98519,	98533,	98543,	98561,	98563,	98573,	98597,	98621,	98627,	98639,
+	98641,	98663,	98669,	98689,	98711,	98713,	98717,	98729,	98731,	98737,
+	98773,	98779,	98801,	98807,	98809,	98837,	98849,	98867,	98869,	98873,
+	98887,	98893,	98897,	98899,	98909,	98911,	98927,	98929,	98939,	98947,
+	98953,	98963,	98981,	98993,	98999,	99013,	99017,	99023,	99041,	99053,
+	99079,	99083,	99089,	99103,	99109,	99119,	99131,	99133,	99137,	99139,
+	99149,	99173,	99181,	99191,	99223,	99233,	99241,	99251,	99257,	99259,
+	99277,	99289,	99317,	99347,	99349,	99367,	99371,	99377,	99391,	99397,
+	99401,	99409,	99431,	99439,	99469,	99487,	99497,	99523,	99527,	99529,
+	99551,	99559,	99563,	99571,	99577,	99581,	99607,	99611,	99623,	99643,
+	99661,	99667,	99679,	99689,	99707,	99709,	99713,	99719,	99721,	99733,
+	99761,	99767,	99787,	99793,	99809,	99817,	99823,	99829,	99833,	99839,
+	99859,	99871,	99877,	99881,	99901,	99907,	99923,	99929,	99961,	99971,
+	99989,	99991,	100003,	100019,	100043,	100049,	100057,	100069,	100103,	100109,
+	100129,	100151,	100153,	100169,	100183,	100189,	100193,	100207,	100213,	100237,
+	100267,	100271,	100279,	100291,	100297,	100313,	100333,	100343,	100357,	100361,
+	100363,	100379,	100391,	100393,	100403,	100411,	100417,	100447,	100459,	100469,
+	100483,	100493,	100501,	100511,	100517,	100519,	100523,	100537,	100547,	100549,
+	100559,	100591,	100609,	100613,	100621,	100649,	100669,	100673,	100693,	100699,
+	100703,	100733,	100741,	100747,	100769,	100787,	100799,	100801,	100811,	100823,
+	100829,	100847,	100853,	100907,	100913,	100927,	100931,	100937,	100943,	100957,
+	100981,	100987,	100999,	101009,	101021,	101027,	101051,	101063,	101081,	101089,
+	101107,	101111,	101113,	101117,	101119,	101141,	101149,	101159,	101161,	101173,
+	101183,	101197,	101203,	101207,	101209,	101221,	101267,	101273,	101279,	101281,
+	101287,	101293,	101323,	101333,	101341,	101347,	101359,	101363,	101377,	101383,
+	101399,	101411,	101419,	101429,	101449,	101467,	101477,	101483,	101489,	101501,
+	101503,	101513,	101527,	101531,	101533,	101537,	101561,	101573,	101581,	101599,
+	101603,	101611,	101627,	101641,	101653,	101663,	101681,	101693,	101701,	101719,
+	101723,	101737,	101741,	101747,	101749,	101771,	101789,	101797,	101807,	101833,
+	101837,	101839,	101863,	101869,	101873,	101879,	101891,	101917,	101921,	101929,
+	101939,	101957,	101963,	101977,	101987,	101999,	102001,	102013,	102019,	102023,
+	102031,	102043,	102059,	102061,	102071,	102077,	102079,	102101,	102103,	102107,
+	102121,	102139,	102149,	102161,	102181,	102191,	102197,	102199,	102203,	102217,
+	102229,	102233,	102241,	102251,	102253,	102259,	102293,	102299,	102301,	102317,
+	102329,	102337,	102359,	102367,	102397,	102407,	102409,	102433,	102437,	102451,
+	102461,	102481,	102497,	102499,	102503,	102523,	102533,	102539,	102547,	102551,
+	102559,	102563,	102587,	102593,	102607,	102611,	102643,	102647,	102653,	102667,
+	102673,	102677,	102679,	102701,	102761,	102763,	102769,	102793,	102797,	102811,
+	102829,	102841,	102859,	102871,	102877,	102881,	102911,	102913,	102929,	102931,
+	102953,	102967,	102983,	103001,	103007,	103043,	103049,	103067,	103069,	103079,
+	103087,	103091,	103093,	103099,	103123,	103141,	103171,	103177,	103183,	103217,
+	103231,	103237,	103289,	103291,	103307,	103319,	103333,	103349,	103357,	103387,
+	103391,	103393,	103399,	103409,	103421,	103423,	103451,	103457,	103471,	103483,
+	103511,	103529,	103549,	103553,	103561,	103567,	103573,	103577,	103583,	103591,
+	103613,	103619,	103643,	103651,	103657,	103669,	103681,	103687,	103699,	103703,
+	103723,	103769,	103787,	103801,	103811,	103813,	103837,	103841,	103843,	103867,
+	103889,	103903,	103913,	103919,	103951,	103963,	103967,	103969,	103979,	103981,
+	103991,	103993,	103997,	104003,	104009,	104021,	104033,	104047,	104053,	104059,
+	104087,	104089,	104107,	104113,	104119,	104123,	104147,	104149,	104161,	104173,
+	104179,	104183,	104207,	104231,	104233,	104239,	104243,	104281,	104287,	104297,
+	104309,	104311,	104323,	104327,	104347,	104369,	104381,	104383,	104393,	104399,
+	104417,	104459,	104471,	104473,	104479,	104491,	104513,	104527,	104537,	104543,
+	104549,	104551,	104561,	104579,	104593,	104597,	104623,	104639,	104651,	104659,
+	104677,	104681,	104683,	104693,	104701,	104707,	104711,	104717,	104723,	104729,
+};
+
+//  return 1 if p is divisable by sp, 0 otherwise
+static int
+divides(mpint *dividend, ulong divisor)
+{
+	mpdigit d[2], q;
+	int i;
+
+	d[1] = 0;
+	for(i = dividend->top-1; i >= 0; i--){
+		d[0] = dividend->p[i];
+		mpdigdiv(d, divisor, &q);
+		d[1] = d[0] - divisor*q;
+	}
+	return d[1] == 0;
+}
+
+//  return -1 if p is divisable by one of the small primes, 0 otherwise
+int
+smallprimetest(mpint *p)
+{
+	int i;
+	ulong sp;
+
+	for(i = 0; i < nelem(smallprimes); i++){
+		sp = smallprimes[i];
+		if(p->top == 1 && p->p[0] <= sp)
+			break;
+		if(divides(p, sp))
+			return -1;
+	}
+	return 0;
+}
--- /dev/null
+++ b/libtk/NOTES
@@ -1,0 +1,90 @@
+Notes on the Tk implementation.
+
+General
+
+	TkTop represents a top-level window.
+	It holds pointers to the widgets created in that
+	window:
+		windows		gives a list of all windows (this includes "." and any menu widgets)
+		root			the list of all widgets, whether packed or not.
+	
+	Each Tk widget holds pointers to the widgets packed inside it, its slaves.
+	Widgets that do their own child widget management (canvas
+	and text) do not use the slaves list, but store pointers
+	to them in their own data structures.
+	
+	Each Tk widget, w, holds a pointer to the widget it's packed or stored inside.
+	
+		w->master
+			if it's packed or stored in a grid
+		w->parent
+			if it's a child widget of a canvas or text widget.
+	
+	A widget type is operated on through functions referred to in its TkMethod structure,
+	defined in that widget type's source file, and pointed to by the
+	method dispatch table, tkmethod, defined in xdata.c.
+	
+	utils.c contains the master table holding the built-in commands
+	(e.g. widget creation, focus, grab, etc) with their
+	associated functions.
+	
+	xdata.c holds the method table (tkmethod) mapping from
+	widget type to the method functions supported by individual widgets.
+
+
+
+Coordinates:
+
+	A widget requests a particular size allocation
+	by setting its req.width and req.height fields.
+	The packer (or its parent) determines the actual
+	size allocation, and position and sets act.x, act.y, act.width
+	and act.height appropriately.
+
+	The requested width and height do not include the
+	borderwidth, which is factored in additionally.
+
+	Coordinates as delivered by the %x and %y verbs provided
+	by bind(9) are relative to the top left of the widget,
+	inside its border. I'll call this the "widget's coordinate system".
+
+	The draw method of each widget type is provided with
+	an "origin" argument.
+
+		(origin.x + act.x + borderwidth, origin.y + act.y + borderwidth)
+
+	gives the screen coordinate of (0, 0) in the widget coordinate
+	system.
+
+
+Dirtiness
+
+	Each widget has a "dirty" rectangle, the bounding
+	box of any changes that it needs to make visible.
+	This is in the widget's coordinate system.
+
+	A widget does not have to update everything in
+	the dirty rectangle, unless the Tkrefresh flag
+	is set, in which case it must.
+
+	A widget never has to draw anything outside of its dirty
+	rectangle.
+
+Locking
+
+	Mostly, Tk is non-reentrant because the interpreter is held
+	when a call to, e.g.  Tk_cmd, is made.
+
+	However, when the display is remote, any access of the display
+	(drawing, stringsize, etc) can do a release() and therefore
+	let another thread access tk.
+
+	The drawing code itself locks the display, so code invoked
+	from within a widgets draw() method is guaranteed
+	non-reentrant.
+
+	If access to the draw device is required during code executed
+	in a non-drawing context (e.g.  to calculate the size of a
+	string), care must be taken to lock the draw device
+	appropriately.  Tk provides some convenience functions to do
+	this (e.g.  tkstringsize).
--- /dev/null
+++ b/libtk/NOTICE
@@ -1,0 +1,26 @@
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take substantial code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices below.  It is fine (and often tidier) to do that in a separate
+file such as NOTICE, LICENCE or COPYING.
+
+Copyright © 1995-1999 Lucent Technologies Inc.
+Portions Copyright © 1997-2000 Vita Nuova Limited
+Portions Copyright © 2000-2008 Vita Nuova Holdings Limited
+Portions Copyright © 2010 Vita Nuova Holdings Limited
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License (`LGPL') as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--- /dev/null
+++ b/libtk/buton.c
@@ -1,0 +1,794 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "label.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Widget Commands (+ means implemented)
+	+cget
+	+configure
+	+invoke
+	+select
+	+deselect
+	+toggle
+ */
+
+enum {
+	/* other constants */
+	InvokePause	= 200,	/* delay showing button in down state when invoked */
+};
+
+TkOption tkbutopts[] =
+{
+	"text",		OPTtext,	O(TkLabel, text),	nil,
+	"label",	OPTtext,	O(TkLabel, text),	nil,
+	"underline",	OPTdist,	O(TkLabel, ul),		nil,
+	"justify",	OPTstab,	O(TkLabel, justify),	tkjustify,
+	"anchor",	OPTflag,	O(TkLabel, anchor),	tkanchor,
+	"command",	OPTtext,	O(TkLabel, command),	nil,
+	"bitmap",	OPTbmap,	O(TkLabel, bitmap),	nil,
+	"image",	OPTimag,	O(TkLabel, img),	nil,
+	nil
+};
+
+TkOption tkcbopts[] =
+{
+	"variable",	OPTtext,	O(TkLabel, variable),	nil,
+	"indicatoron",	OPTstab,	O(TkLabel, indicator),	tkbool,
+	"onvalue",	OPTtext,	O(TkLabel, value),	nil,
+	"offvalue",	OPTtext,	O(TkLabel, offvalue), nil,
+	nil,
+};
+
+TkOption tkradopts[] =
+{
+	"variable",	OPTtext,	O(TkLabel, variable),	nil,
+	"value",	OPTtext,	O(TkLabel, value), nil,
+	"indicatoron",	OPTstab,	O(TkLabel, indicator),	tkbool,
+	nil,
+};
+
+static
+TkEbind bb[] =
+{
+	{TkEnter,	"%W configure -state active"},
+	{TkLeave,	"%W configure -state normal"},
+	{TkButton1P,	"%W tkButton1P"},
+	{TkButton1R,	"%W tkButton1R %x %y"},
+	{TkMotion|TkButton1P, 	"" },
+	{TkKey,	"%W tkButtonKey 0x%K"},
+};
+
+static
+TkEbind cb[] = 
+{
+	{TkEnter,		"%W configure -state active"},
+	{TkLeave,		"%W configure -state normal"},
+	{TkButton1P,		"%W invoke"},
+	{TkMotion|TkButton1P, 	"" },
+	{TkKey,	"%W tkButtonKey 0x%K"},
+};
+
+
+static char	tkselbut[] = "selectedButton";
+
+static char*	newbutton(TkTop*, int, char*, char**);
+static int	istransparent(Tk*);
+static void tkvarchanged(Tk*, char*, char*);
+
+char*
+tkbutton(TkTop *t, char *arg, char **ret)
+{
+	return newbutton(t, TKbutton, arg, ret);
+}
+
+char*
+tkcheckbutton(TkTop *t, char *arg, char **ret)
+{
+	return newbutton(t, TKcheckbutton, arg, ret);
+}
+
+char*
+tkradiobutton(TkTop *t, char *arg, char **ret)
+{
+	return newbutton(t, TKradiobutton, arg, ret);
+}
+
+static char*
+newbutton(TkTop *t, int btype, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkLabel *tkl;
+	TkName *names;
+	TkOptab tko[4];
+	TkVar *v;
+
+	tk = tkmkbutton(t, btype);
+	if(tk == nil)
+		return TkNomem;
+
+	tkl = TKobj(TkLabel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = tkbutopts;
+	switch(btype){
+	case TKcheckbutton:
+		tko[2].ptr = tkl;
+		tko[2].optab = tkcbopts;
+		break;
+	case TKradiobutton:
+		tko[2].ptr = tkl;
+		tko[2].optab = tkradopts;
+		break;
+	default:
+		tk->relief = TKraised;
+		tk->borderwidth = 1;
+		tko[2].ptr = nil;
+		break;
+	}
+	tko[3].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	tksettransparent(tk, istransparent(tk));
+	tksizebutton(tk);
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	if (btype == TKradiobutton &&
+			tkl->variable != nil &&
+			strcmp(tkl->variable, tkselbut) == 0 &&
+			tkl->value == nil &&
+			tk->name != nil)
+		tkl->value = strdup(tk->name->name);
+
+	if (tkl->variable != nil) {
+		v = tkmkvar(t, tkl->variable, 0);
+		if (v == nil){
+			if(btype == TKcheckbutton){
+				e = tksetvar(t, tkl->variable, tkl->offvalue ? tkl->offvalue : "0");
+				if (e != nil)
+					goto err;
+			}
+		} else if(v->type != TkVstring){
+			e = TkNotvt;
+			goto err;
+		} else
+			tkvarchanged(tk, tkl->variable, v->value);
+	}
+
+	return tkvalue(ret, "%s", tk->name->name);
+
+err:
+	tkfreeobj(tk);
+	return e;
+}
+
+Tk*
+tkmkbutton(TkTop *t, int btype)
+{
+	Tk *tk;
+	TkLabel *tkl;
+	char *e;
+
+	tk = tknewobj(t, btype, sizeof(Tk)+sizeof(TkLabel));
+	if (tk == nil)
+		return nil;
+
+	e = nil;
+	tk->relief = TKraised;
+	tk->borderwidth = 0;
+	tk->highlightwidth = 1;
+	tk->flag |= Tktakefocus;
+	tkl = TKobj(TkLabel, tk);
+	tkl->ul = -1;
+	tkl->justify = Tkleft;
+
+	switch (btype) {
+	case TKbutton:
+		e = tkbindings(t, tk, bb, nelem(bb));
+		break;
+	case TKcheckbutton:
+		e = tkbindings(t, tk, cb, nelem(cb));
+		break;
+	case TKradiobutton:
+		tkl->variable = strdup(tkselbut);
+		e = tkbindings(t, tk, cb, nelem(cb));
+		break;
+	}
+
+	if (e != nil) {
+		print("tkmkbutton internal error: %s\n", e);
+		tkfreeobj(tk);
+		return nil;
+	}
+	return tk;
+}
+
+/*
+ * draw TKbutton, TKcheckbutton, TKradiobutton
+ */
+char*
+tkdrawbutton(Tk *tk, Point orig)
+{
+ 	TkEnv *e;
+	TkLabel *tkl;
+	Rectangle r, s, mainr, focusr;
+	int dx, dy, h;
+	Point p, u, v, pp[4];
+	Image *i, *dst, *cd, *cl, *ct, *img;
+	int relief, bgnd, fgnd;
+
+	e = tk->env;
+
+	dst = tkimageof(tk);
+	if(dst == nil)
+		return nil;
+
+	v.x = tk->act.width + 2*tk->borderwidth;
+	v.y = tk->act.height + 2*tk->borderwidth;
+
+	r.min = ZP;
+	r.max = v;
+	focusr = insetrect(r, tk->borderwidth);
+	mainr = insetrect(focusr, tk->highlightwidth);
+	relief = tk->relief;
+
+	tkl = TKobj(TkLabel, tk);
+
+	fgnd = TkCforegnd;
+	bgnd = TkCbackgnd;
+	if (tk->flag & Tkdisabled)
+		fgnd = TkCdisablefgnd;
+	else if ((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator == BoolF && tkl->check)
+		bgnd = TkCselect;
+	else if (tk->flag & Tkactive) {
+		fgnd = TkCactivefgnd;
+		bgnd = TkCactivebgnd;
+	}
+
+	i = tkitmp(e, r.max, bgnd);
+	if(i == nil)
+		return nil;
+
+	if(tk->flag & Tkactive)
+		draw(i, r, tkgc(e, bgnd), nil, ZP);
+
+	p = mainr.min;
+	h = tkl->h - 2 * tk->highlightwidth;
+
+	dx = tk->act.width - tkl->w - tk->ipad.x;
+	dy = tk->act.height - tkl->h - tk->ipad.y;
+	if((tkl->anchor & (Tknorth|Tksouth)) == 0)
+		p.y += dy/2;
+	else if(tkl->anchor & Tksouth)
+		p.y += dy;
+
+	if((tkl->anchor & (Tkeast|Tkwest)) == 0)
+		p.x += dx/2;
+	else if(tkl->anchor & Tkeast)
+		p.x += dx;
+
+	switch(tk->type) {
+	case TKcheckbutton:
+		if(tkl->indicator == BoolF) {
+			relief = tkl->check? TKsunken: TKraised;
+			break;
+		}
+		u.x = p.x + ButtonBorder;
+		u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
+
+		cl = tkgc(e, bgnd+TkLightshade);
+		cd = tkgc(e, bgnd+TkDarkshade);
+		tkbevel(i, u, CheckButton, CheckButton, CheckButtonBW, cd, cl);
+		if(tkl->check) {
+			u.x += CheckButtonBW+1;
+			u.y += CheckButtonBW+1;
+			pp[0] = u;
+			pp[0].y += CheckButton/2-1;
+			pp[1] = pp[0];
+			pp[1].x += 2;
+			pp[1].y += 2;
+			pp[2] = u;
+			pp[2].x += CheckButton/4;
+			pp[2].y += CheckButton-2;
+			pp[3] = u;
+			pp[3].x += CheckButton-2;
+			pp[3].y++;
+			bezspline(i, pp, 4, Enddisc, Enddisc, 1, tkgc(e, TkCforegnd), ZP);
+		}
+		break;
+	case TKradiobutton:
+		if(tkl->indicator == BoolF) {
+			relief = tkl->check? TKsunken: TKraised;
+			break;
+		}
+		u.x = p.x + ButtonBorder;
+		u.y = p.y + ButtonBorder + (h - CheckSpace) / 2;
+		v = Pt(u.x+CheckButton/2,u.y+CheckButton/2);
+		ellipse(i, v, CheckButton/2, CheckButton/2, CheckButtonBW-1, tkgc(e, bgnd+TkDarkshade), ZP);
+		if(tkl->check)
+			fillellipse(i, v, CheckButton/2-2, CheckButton/2-2, tkgc(e, TkCforegnd), ZP);	/* could be TkCselect */
+		break;
+	case TKbutton:
+		if ((tk->flag & (Tkactivated|Tkactive)) == (Tkactivated|Tkactive))
+			relief = TKsunken;
+		break;
+	}
+
+	p.x += tk->ipad.x/2;
+	p.y += tk->ipad.y/2;
+	u = ZP;
+	if(tk->type == TKbutton && relief == TKsunken) {
+		u.x++;
+		u.y++;
+	}
+	if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF)
+		u.x += CheckSpace;
+
+	img = nil;
+	if (tkl->img != nil && tkl->img->img != nil)
+		img = tkl->img->img;
+	else if (tkl->bitmap != nil)
+		img = tkl->bitmap;
+	if (img != nil) {
+		s.min.x = p.x + Bitpadx;
+		s.min.y = p.y + Bitpady;
+		s.max.x = s.min.x + Dx(img->r);
+		s.max.y = s.min.y + Dy(img->r);
+		s = rectaddpt(s, u);
+		if(tkchanhastype(img->chan, CGrey))
+			draw(i, s, tkgc(e, fgnd), img, ZP);
+		else
+			draw(i, s, img, nil, ZP);
+	} else if(tkl->text != nil) {
+		u.x += Textpadx;
+		u.y += Textpady;
+		ct = tkgc(e, fgnd);
+		
+		p.y += (h - tkl->textheight) / 2;
+		tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
+	}
+
+//	if(tkhaskeyfocus(tk))
+//		tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
+	tkdrawrelief(i, tk, ZP, bgnd, relief);
+
+	p.x = tk->act.x + orig.x;
+	p.y = tk->act.y + orig.y;
+	r = rectaddpt(r, p);
+	draw(dst, r, i, nil, ZP);
+
+	return nil;
+}
+
+void
+tksizebutton(Tk *tk)
+{
+	int w, h;
+	TkLabel *tkl;
+	
+	tkl = TKobj(TkLabel, tk);
+	if(tkl->anchor == 0)	
+		tkl->anchor = Tkcenter;
+
+	tksizelabel(tk);	/* text, bitmap or image, and highlight */
+	w = tkl->w;
+	h = tkl->h;
+
+	if((tk->type == TKcheckbutton || tk->type == TKradiobutton) && tkl->indicator != BoolF) {
+		w += CheckSpace;
+		if(h < CheckSpace)
+			h = CheckSpace;
+	}
+	tkl->w = w;
+	tkl->h = h;
+	if((tk->flag & Tksetwidth) == 0)
+		tk->req.width = w;
+	if((tk->flag & Tksetheight) == 0)
+		tk->req.height = h;
+}
+
+int
+tkbuttonmargin(Tk *tk)
+{
+	TkLabel *tkl;
+	tkl = TKobj(TkLabel, tk);
+
+	switch (tk->type) {
+	case TKbutton:
+		if (tkl->img != nil || tkl->bitmap != nil)
+			return 0;
+		return Textpadx+tk->highlightwidth;
+	case TKcheckbutton:
+	case TKradiobutton:
+		return CheckButton + 2*CheckButtonBW + 2*ButtonBorder;
+	}
+	return tklabelmargin(tk);
+}
+
+void
+tkfreebutton(Tk *tk)
+{
+	tkfreelabel(tk);
+}
+
+static char*
+tkbuttoncget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[4];
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = tkbutopts;
+	switch(tk->type){
+	case TKcheckbutton:
+		tko[2].ptr = tkl;
+		tko[2].optab = tkcbopts;
+		break;
+	case TKradiobutton:
+		tko[2].ptr = tkl;
+		tko[2].optab = tkradopts;
+		break;
+	default:
+		tko[2].ptr = nil;
+		break;
+	}
+	tko[3].ptr = nil;
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkbuttonconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkOptab tko[4];
+	TkVar *v;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = tkbutopts;
+	switch(tk->type){
+	case TKcheckbutton:
+		tko[2].ptr = tkl;
+		tko[2].optab = tkcbopts;
+		break;
+	case TKradiobutton:
+		tko[2].ptr = tkl;
+		tko[2].optab = tkradopts;
+		break;
+	default:
+		tko[2].ptr = nil;
+		break;
+	}
+	tko[3].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksizebutton(tk);
+	tkgeomchg(tk, &g, bd);
+
+	tk->dirty = tkrect(tk, 1);
+	tksettransparent(tk, istransparent(tk));
+	/*
+	 * XXX what happens if we're now disabled, but we were in
+	 * active state before?
+	 */
+	if (tkl->variable != nil) {
+		v = tkmkvar(tk->env->top, tkl->variable, 0);
+		if (v != nil) {
+			if (v->type != TkVstring) {
+				e = TkNotvt;
+				free(tkl->variable);
+				tkl->variable = nil;
+			}
+			else
+				tkvarchanged(tk, tkl->variable, v->value);
+		}
+	}
+	return e;
+}
+
+static int
+istransparent(Tk *tk)
+{
+	TkEnv *e = tk->env;
+	return (tkhasalpha(e, TkCbackgnd) || tkhasalpha(e, TkCselectbgnd) || tkhasalpha(e, TkCactivebgnd));
+}
+
+static void
+tkvarchanged(Tk *tk, char *var, char *val)
+{
+	TkLabel *tkl;
+	char *sval;
+
+	tkl = TKobj(TkLabel, tk);
+	if (tkl->variable != nil && strcmp(tkl->variable, var) == 0) {
+		sval = tkl->value;
+		if (sval == nil)
+			sval = tk->type == TKcheckbutton ? "1" : "";
+		tkl->check = (strcmp(val, sval) == 0);
+		tk->dirty = tkrect(tk, 1);
+		tkdirty(tk);
+	}
+}
+
+static char*
+tkbutton1p(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+	if(tk->flag & Tkdisabled)
+		return nil;
+	tk->flag |= Tkactivated;
+	tk->dirty = tkrect(tk, 1);
+	tkdirty(tk);
+	return nil;
+}
+
+static char*
+tkbutton1r(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	Point p;
+	Rectangle hitr;
+
+	USED(arg);
+
+	if(tk->flag & Tkdisabled)
+		return nil;
+	e = tkxyparse(tk, &arg, &p);
+	if (e == nil) {
+		hitr.min = ZP;
+		hitr.max.x = tk->act.width + tk->borderwidth*2;
+		hitr.max.y = tk->act.height + tk->borderwidth*2;
+		if(ptinrect(p, hitr) && (tk->flag & Tkactivated))
+			e = tkbuttoninvoke(tk, nil, val);
+	}
+	tk->flag &= ~Tkactivated;
+	tk->dirty = tkrect(tk, 1);
+	tkdirty(tk);
+	return e;
+}
+
+static char*
+tkbuttonkey(Tk *tk, char *arg, char **val)
+{
+	int key;
+
+	if(tk->flag & Tkdisabled)
+		return nil;
+
+	key = strtol(arg, nil, 0);
+	if (key == '\n' || key ==' ')
+		return tkbuttoninvoke(tk, nil, val);
+	return nil;
+}
+
+static char*
+tkbuttontoggle(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+	char *v;
+
+	USED(arg);
+	USED(val);
+	if(tk->flag & Tkdisabled)
+		return nil;
+	tkl->check = !tkl->check;
+	if (tkl->check)
+		v = tkl->value ? tkl->value : "1";
+	else
+		v = tkl->offvalue ? tkl->offvalue : "0";
+	e = tksetvar(tk->env->top, tkl->variable, v);
+	tk->dirty = tkrect(tk, 0);
+	return e;
+}
+
+static char*
+buttoninvoke(Tk *tk, char **val)
+{
+	char *e = nil;
+	TkTop *top;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	top = tk->env->top;
+	if (tk->type == TKcheckbutton)
+		e = tkbuttontoggle(tk, "", val);
+	else if (tk->type == TKradiobutton)
+		e = tksetvar(top, tkl->variable, tkl->value);
+	if(e != nil)
+		return e;
+	if(tkl->command != nil)
+		return tkexec(tk->env->top, tkl->command, val);
+	return nil;
+}
+
+static void
+cancelinvoke(Tk *tk, void *v, int cancelled)
+{
+	int unset;
+	USED(cancelled);
+	USED(v);
+
+	/* if it was active before then leave it active unless cleared since */
+	if (v)
+		unset = 0;
+	else
+		unset = Tkactive;
+	unset &= (tk->flag & Tkactive);
+	unset |= Tkactivated;
+	tk->flag &= ~unset;
+	tksettransparent(tk, istransparent(tk));
+	tk->dirty = tkrect(tk, 1);
+	tkdirty(tk);
+	tkupdate(tk->env->top);
+}
+
+char*
+tkbuttoninvoke(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	USED(arg);
+
+	if(tk->flag & Tkdisabled)
+		return nil;
+	e = buttoninvoke(tk, val);
+	if (e == nil && tk->type == TKbutton && !(tk->flag & Tkactivated)) {
+		tkrepeat(tk, cancelinvoke, (void*)(tk->flag&Tkactive), InvokePause, 0);
+		tk->flag |= Tkactivated | Tkactive;
+		tksettransparent(tk, istransparent(tk));
+		tk->dirty = tkrect(tk, 1);
+		tkdirty(tk);
+		tkupdate(tk->env->top);
+	}
+	return e;
+}
+
+static char*
+tkbuttonselect(Tk *tk, char *arg, char **val)
+{
+	char *e, *v;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	USED(arg);
+	USED(val);
+	if (tk->type == TKradiobutton)
+		v = tkl->value;
+	else if (tk->type == TKcheckbutton) {
+		v = tkl->value ? tkl->value : "1";
+		tkl->check = 1;
+		tk->dirty = tkrect(tk, 0);
+	} else
+		v = nil;
+	e = tksetvar(tk->env->top, tkl->variable, v);
+	if(e != nil)
+		return e;
+	return nil;
+}
+
+static char*
+tkbuttondeselect(Tk *tk, char *arg, char **val)
+{
+	char *e, *v;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	USED(arg);
+	USED(val);
+
+	if (tk->type == TKcheckbutton) {
+		v = tkl->offvalue ? tkl->offvalue : "0";
+		tkl->check = 0;
+		tk->dirty = tkrect(tk, 0);
+	} else
+		v = nil;
+
+	e = tksetvar(tk->env->top, tkl->variable, v);
+	if(e != nil)
+		return e;
+	return nil;
+}
+
+static
+TkCmdtab tkbuttoncmd[] =
+{
+	"cget",			tkbuttoncget,
+	"configure",		tkbuttonconf,
+	"invoke",		tkbuttoninvoke,
+	"tkButton1P",		tkbutton1p,
+	"tkButton1R",		tkbutton1r,
+	"tkButtonKey",		tkbuttonkey,
+	nil
+};
+
+static
+TkCmdtab tkchkbuttoncmd[] =
+{
+	"cget",			tkbuttoncget,
+	"configure",		tkbuttonconf,
+	"invoke",		tkbuttoninvoke,
+	"select",		tkbuttonselect,
+	"deselect",		tkbuttondeselect,
+	"toggle",		tkbuttontoggle,
+	"tkButtonKey",		tkbuttonkey,
+	nil
+};
+
+static
+TkCmdtab tkradbuttoncmd[] =
+{
+	"cget",			tkbuttoncget,
+	"configure",		tkbuttonconf,
+	"invoke",		tkbuttoninvoke,
+	"select",		tkbuttonselect,
+	"deselect",		tkbuttondeselect,
+	"tkButtonKey",		tkbuttonkey,
+	nil
+};
+
+TkMethod buttonmethod = {
+	"button",
+	tkbuttoncmd,
+	tkfreebutton,
+	tkdrawbutton,
+	nil,
+	tklabelgetimgs
+};
+
+TkMethod checkbuttonmethod = {
+	"checkbutton",
+	tkchkbuttoncmd,
+	tkfreebutton,
+	tkdrawbutton,
+	nil,
+	tklabelgetimgs,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	tkvarchanged
+};
+
+TkMethod radiobuttonmethod = {
+	"radiobutton",
+	tkradbuttoncmd,
+	tkfreebutton,
+	tkdrawbutton,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	tkvarchanged
+};
--- /dev/null
+++ b/libtk/canvs.c
@@ -1,0 +1,2220 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+/* Widget Commands (+ means implemented)
+	+addtag
+		except halo and start options of closest spec
+	+bbox
+	+bind
+	+canvasx
+	+canvasy
+	+cget
+	+configure
+	+coords
+	+create
+	+dchars
+	+delete
+	+dtag
+	+find
+	+focus
+	+gettags
+	+icursor
+	+index
+	+insert
+	+itemcget
+	+itemconfigure
+	+lower
+	+move
+	 postscript
+	+raise
+	+scale
+	 scan
+	+select
+	+type
+	+xview
+	+yview
+*/
+
+static
+TkStab tkbuffer[] = {
+	"visible",	TkCbufvisible,
+	"all",		TkCbufall,
+	"none",	TkCbufnone,
+	"auto",	TkCbufauto,
+
+	/* backwards compatibility */
+	"1",		TkCbufall,
+	"yes",	TkCbufall,
+	"off",		TkCbufall,
+	"0",		TkCbufauto,
+	"no",		TkCbufauto,
+	"off",		TkCbufauto,
+	nil
+};
+	
+#define	O(t, e)		((long)(&((t*)0)->e))
+#define OA(t, e)	((long)(((t*)0)->e))
+
+static
+TkOption opts[] =
+{
+	"closeenough",		OPTfrac,	O(TkCanvas, close),	nil,
+	"confine",		OPTfrac,	O(TkCanvas, confine),	nil,
+	"scrollregion",		OPTfrac,	OA(TkCanvas, scrollr),	IAUX(4),
+	"xscrollincrement",	OPTfrac,	O(TkCanvas, xscrolli),	nil,
+	"yscrollincrement",	OPTfrac,	O(TkCanvas, yscrolli),	nil,
+	"xscrollcommand",	OPTtext,	O(TkCanvas, xscroll),	nil,
+	"yscrollcommand",	OPTtext,	O(TkCanvas, yscroll),	nil,
+	"width",		OPTnnfrac,	O(TkCanvas, width),	nil,
+	"height",		OPTnnfrac,	O(TkCanvas, height),	nil,
+	"buffer",		OPTstab,	O(TkCanvas, buffer),		tkbuffer,
+	"buffered",		OPTstab,	O(TkCanvas, buffer),	tkbool,	/* backwards compatibility */
+	"selectborderwidth",	OPTnndist, O(TkCanvas, sborderwidth), nil,
+	nil
+};
+
+int cvslshape[] = { TKI2F(8), TKI2F(10), TKI2F(3) };
+Rectangle	bbnil = { 1000000, 1000000, -1000000, -1000000 };
+Rectangle	huger = { -1000000, -1000000, 1000000, 1000000 };
+
+static void tkcvsgeom(Tk *tk);
+
+
+static void
+tkcvsf2i(Tk *tk, TkCanvas *tkc)
+{
+	Rectangle r;
+	tk->req.width = TKF2I(tkc->width);
+	tk->req.height = TKF2I(tkc->height);
+
+	r.min.x = TKF2I(tkc->scrollr[0]);
+	r.min.y = TKF2I(tkc->scrollr[1]);
+	r.max.x = TKF2I(tkc->scrollr[2]);
+	r.max.y = TKF2I(tkc->scrollr[3]);
+
+	/*
+	 * make sure that the region is big enough to hold
+	 * the actually displayed area
+	 */
+	if (Dx(r) < tk->act.width)
+		r.max.x = r.min.x + tk->act.width;
+	if (Dy(r) < tk->act.height)
+		r.max.y = r.min.y + tk->act.height;
+	tkc->region = r;
+
+	/*
+	 * make sure that the view origin is at a valid
+	 * position with respect to the scroll region.
+	 */
+	if (tkc->view.x + tk->act.width > r.max.x)
+		tkc->view.x = r.max.x - tk->act.width;
+	if (tkc->view.x < r.min.x)
+		tkc->view.x = r.min.x;
+
+	if (tkc->view.y + tk->act.height > r.max.y)
+		tkc->view.y = r.max.y - tk->act.height;
+	if (tkc->view.y < r.min.y)
+		tkc->view.y = r.min.y;
+
+}
+
+char*
+tkcanvas(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkCanvas *tkc;
+	TkName *names;
+	TkOptab tko[3];
+
+	tk = tknewobj(t, TKcanvas, sizeof(Tk)+sizeof(TkCanvas));
+	if(tk == nil)
+		return TkNomem;
+
+	tkc = TKobj(TkCanvas, tk);
+	tkc->close = TKI2F(1);
+	tkc->xscrolli = TKI2F(1);
+	tkc->yscrolli = TKI2F(1);
+	tkc->width = TKI2F(360);
+	tkc->height = TKI2F(270);
+	tkc->actions = 0;
+	tkc->actlim = Tksweep;
+	tkc->mask = nil;
+	tkc->sborderwidth = 1;
+
+	tko[0].ptr = tkc;
+	tko[0].optab = opts;
+	tko[1].ptr = tk;
+	tko[1].optab = tkgeneric;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil)
+		goto err;
+	if(names == nil) {
+		/* tkerr(t, arg); XXX */
+		e = TkBadwp;
+		goto err;
+	}
+
+	tkc->current = tkmkname("current");
+	if(tkc->current == nil) {
+		e = TkNomem;
+		goto err;
+	}
+
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tkcvsf2i(tk, tkc);
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreename(tkc->current);
+		tkc->current = nil;
+		goto err;
+	}
+	tk->name->link = nil;
+
+	e = tkvalue(ret, "%s", tk->name->name);
+	if(e == nil)
+	        return nil;
+	
+	tkfreename(tkc->current);
+	return e;
+err:
+	tkfreeobj(tk);
+	return e;
+}
+
+void
+tkcvsdirty(Tk *sub)
+{
+	TkCanvas *c;
+	Tk *tk, *parent;
+	Rectangle r;
+	Point rel;
+
+	rel = ZP;
+	for(tk = sub; tk;  tk = tk->master) {
+		rel.x += tk->borderwidth + tk->act.x;
+		rel.y += tk->borderwidth + tk->act.y;
+		if (tk->parent != nil)
+			break;
+	}
+	if (tk == nil)
+		return;
+	parent = tk->parent;
+	c = TKobj(TkCanvas, parent);
+	r = rectaddpt(sub->dirty, rel);
+	tkbbmax(&c->update, &r);
+	tkcvssetdirty(parent);
+}
+
+static void
+tkcvsfocusorder(Tk *tk)
+{
+	TkCanvas *tkc = TKobj(TkCanvas, tk);
+	TkCwind *win;
+	TkCitem *it;
+	TkWinfo *inf;
+	int i, n;
+
+	n = 0;
+	for (it = tkc->head; it != nil; it = it->next) {
+		if (it->type == TkCVwindow) {
+			win = TKobj(TkCwind, it);
+			if (win->sub != nil)
+				n++;
+		}
+	}
+	if (n == 0)
+		return;
+
+	inf = malloc(sizeof(*inf) * n);
+	if (inf == nil)
+		return;
+
+	i = 0;
+	for (it = tkc->head; it != nil; it = it->next) {
+		if (it->type == TkCVwindow) {
+			win = TKobj(TkCwind, it);
+			if (win->sub != nil) {
+				inf[i].w = win->sub;
+				inf[i].r = it->p.bb;
+				i++;
+			}
+		}
+	}
+
+	tksortfocusorder(inf, n);
+	for (i = 0; i < n; i++)
+		tkappendfocusorder(inf[i].w);
+}
+
+static char*
+tkcvscget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCanvas *tkc = TKobj(TkCanvas, tk);
+
+	tko[0].ptr = tkc;
+	tko[0].optab = opts;
+	tko[1].ptr = tk;
+	tko[1].optab = tkgeneric;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkcvsconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	int bd;
+	TkGeom g;
+	Rectangle r;
+	TkOptab tko[3];
+	TkCanvas *c = TKobj(TkCanvas, tk);
+
+	tko[0].ptr = c;
+	tko[0].optab = opts;
+	tko[1].ptr = tk;
+	tko[1].optab = tkgeneric;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	r.min = c->view;
+	r.max.x = r.min.x+tk->act.width;
+	r.max.y = r.min.y+tk->act.height;
+	tkbbmax(&c->update, &r);
+	tkbbmax(&c->update, &c->region);
+
+	bd = tk->borderwidth;
+	g = tk->req;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil)
+		return e;
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+	tkcvsf2i(tk, c);
+	
+	tkcvsgeom(tk);	
+	tkgeomchg(tk, &g, bd);
+	tkbbmax(&c->update, &c->region);
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+void
+tkcvsfreeitem(TkCitem *i)
+{
+	int locked;
+	Display *d;
+
+	d = i->env->top->display;
+
+	locked = lockdisplay(d);
+	tkcimethod[i->type].free(i);
+	if(locked)
+		unlockdisplay(d);
+
+	tkfreepoint(&i->p);
+	tkputenv(i->env);
+	free(i);
+}
+
+void
+tkfreecanv(Tk *tk)
+{
+	Display *d;
+	int j, locked;
+	TkCanvas *c;
+	TkName *n, *nn;
+	TkCtag *t, *tt;
+	TkCitem *i, *next;
+
+	c = TKobj(TkCanvas, tk);
+	for(i = c->head; i; i = next) {
+		next = i->next;
+		tkcvsfreeitem(i);
+	}
+
+	if(c->xscroll != nil)
+		free(c->xscroll);
+	if(c->yscroll != nil)
+		free(c->yscroll);
+
+	for(j = 0; j < TkChash; j++) {
+		for(n = c->thash[j]; n; n = nn) {
+			nn = n->link;
+			for(t = n->obj; t; t = tt) {
+				tt = t->taglist;
+				free(t);
+			}
+			tkfreebind(n->prop.binds);
+			free(n);
+		}
+	}
+
+	free(c->current);
+
+	if((c->ialloc && c->image != nil) || c->mask != nil) {
+		if (c->ialloc && c->image != nil)
+			d = c->image->display;
+		else
+			d = c->mask->display;
+		locked = lockdisplay(d);
+		if (c->image != nil && c->ialloc)
+			freeimage(c->image);
+		if (c->mask != nil)
+			freeimage(c->mask);
+		if(locked)
+			unlockdisplay(d);
+	}
+}
+
+char*
+tkdrawcanv(Tk *tk, Point orig)
+{
+	Image *dst;
+	TkCitem *i;
+	Display *d;
+	TkCanvas *c;
+	Rectangle r, bufr, oclipr;
+	int vis, alpha, buffer;
+	Point rel, p;
+	TkCimeth *imeth;
+
+	c = TKobj(TkCanvas, tk);
+	d = tk->env->top->display;
+	dst = tkimageof(tk);
+	/*
+	 * translation from local to screen coords
+	 */
+	rel.x = orig.x + tk->act.x + tk->borderwidth;
+	rel.y = orig.y + tk->act.y + tk->borderwidth;
+
+	buffer = c->buffer;
+	if (buffer == TkCbufauto)
+		buffer = TkCbufvisible;
+/*		buffer = (dst == TKobj(TkWin, tk->env->top->root)->image) ? TkCbufvisible : TkCbufnone; */
+
+	if (buffer == TkCbufnone) {
+		if(c->image != nil && c->ialloc)
+			freeimage(c->image);
+		c->image = dst;
+		c->ialloc = 0;
+
+		r = tkrect(tk, 0);
+		bufr = r;
+		rectclip(&bufr, tk->dirty);
+		oclipr = dst->clipr;
+
+		replclipr(dst, 0, rectaddpt(bufr, rel));
+		draw(dst, rectaddpt(bufr, rel), tkgc(tk->env, TkCbackgnd), nil, ZP);
+
+		p = subpt(rel, c->view);
+		p.x = TKI2F(p.x);
+		p.y = TKI2F(p.y);
+		bufr = rectaddpt(bufr, c->view);
+		for(i = c->head; i; i = i->next) {
+			if(rectXrect(i->p.bb, bufr)) {
+				imeth = &tkcimethod[i->type];
+				imeth->coord(i, nil, p.x, p.y);
+				imeth->draw(dst, i, tk->env);
+				imeth->coord(i, nil, -p.x, -p.y);
+			}
+		}
+		replclipr(dst, 0, oclipr);
+	} else {
+		if (c->buffer == TkCbufall)
+			bufr = c->region;
+		else {
+			bufr.min = c->view;
+			bufr.max.x = c->view.x + tk->act.width;
+			bufr.max.y = c->view.y + tk->act.height;
+		}
+		alpha = (tk->env->colors[TkCbackgnd] & 0xff) != 0xff;
+		if(c->image == nil || eqrect(bufr, c->image->r) == 0) {
+			if(c->image != nil && c->ialloc)
+				freeimage(c->image);
+			c->image = allocimage(d, bufr, alpha?RGBA32:d->image->chan, 0, tk->env->colors[TkCbackgnd]);
+			c->ialloc = 1;
+			c->update = bufr;
+			tkcvssetdirty(tk);		/* unnecessary? */
+		}
+	
+		if(c->image == nil)
+			return nil;
+	
+		r = c->update;
+		if (rectclip(&r, c->image->r)) {
+			if (alpha)
+				drawop(c->image, c->update, nil, nil, ZP, Clear);
+			draw(c->image, c->update, tkgc(tk->env, TkCbackgnd), nil, c->view);
+			replclipr(c->image, 0, r);
+			for(i = c->head; i; i = i->next) {
+				if(rectXrect(i->p.bb, r))
+					tkcimethod[i->type].draw(c->image, i, tk->env);
+			}
+			replclipr(c->image, 0, c->image->r);
+		}
+		/*
+		 * if the visible area of the canvas image doesn't
+		 * fit completely within the dirty rectangle,
+		 * then we'll need to draw the background behind it
+		 */
+		r = tkrect(tk, 0);
+		bufr = rectsubpt(bufr, c->view);
+		vis = rectclip(&bufr, tkrect(tk, 0));
+	
+		if (!vis || !rectinrect(tk->dirty, bufr))
+			draw(dst, rectaddpt(tk->dirty, rel), tkgc(tk->env, TkCbackgnd), nil, c->view);
+	
+		if (vis && rectclip(&bufr, tk->dirty))
+			draw(dst, rectaddpt(bufr, rel), c->image, nil, addpt(bufr.min, c->view));
+	}
+
+
+	/*
+	 * if the border is dirty too, then draw that
+	 */
+	if (!rectinrect(tk->dirty, bufr)) {
+		r.min = addpt(r.min, rel);
+		r.min.x -= tk->borderwidth;
+		r.min.y -= tk->borderwidth;
+		tkdrawrelief(dst, tk, r.min, TkCbackgnd, tk->relief);
+	}
+	c->update = bbnil;
+	return nil;
+}
+
+void
+tkcvsappend(TkCanvas *c, TkCitem *i)
+{
+	if(c->head == nil)
+		c->head = i;
+	else
+		c->tail->next = i;
+	c->tail = i;
+}
+
+void
+tkcvssv(Tk *tk)
+{
+	TkCanvas *c;
+	int top, bot, height;
+	char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+
+	c = TKobj(TkCanvas, tk);
+	if(c->yscroll == nil)
+		return;
+
+	top = 0;
+	bot = TKI2F(1);
+
+	height = Dy(c->region);
+	if(height != 0) {
+		top = TKI2F(c->view.y)/height;
+		bot = TKI2F(c->view.y+tk->act.height)/height;
+	}
+
+	v = tkfprint(val, top);
+	*v++ = ' ';
+	tkfprint(v, bot);
+	snprint(cmd, sizeof(cmd), "%s %s", c->yscroll, val);
+	e = tkexec(tk->env->top, cmd, nil);
+	if ((e != nil) && (tk->name != nil))
+		print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+void
+tkcvssh(Tk *tk)
+{
+	int top, bot, width;
+	TkCanvas *c = TKobj(TkCanvas, tk);
+	char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+
+	if(c->xscroll == nil)
+		return;
+
+	top = 0;
+	bot = TKI2F(1);
+
+	width = Dx(c->region);
+	if(width != 0) {
+		top = TKI2F(c->view.x)/width;
+		bot = TKI2F(c->view.x+tk->act.width)/width;
+	}
+
+	v = tkfprint(val, top);
+	*v++ = ' ';
+	tkfprint(v, bot);
+	snprint(cmd, sizeof(cmd), "%s %s", c->xscroll, val);
+	e = tkexec(tk->env->top, cmd, nil);
+	if ((e != nil) && (tk->name != nil))
+		print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+static void
+tkcvsgeom(Tk *tk)
+{
+	TkCanvas *c;
+	c = TKobj(TkCanvas, tk);
+
+	tkcvsf2i(tk, c);
+	tk->dirty = tkrect(tk, 1);
+	c->update = c->region;
+
+	tkcvssv(tk);
+	tkcvssh(tk);
+}
+
+char*
+tkcvstags(Tk *tk, char *arg, char **val, int af)
+{
+	TkTop *o;
+	int x, y;
+	TkName *f;
+	TkCtag *t, *tt;
+	char *fmt;
+	TkCpoints p;
+	TkCanvas *c;
+	TkCitem *i, *b;
+	int d, dist, dx, dy;
+	char tag[Tkmaxitem], buf[Tkmaxitem];
+	char *e;
+
+	USED(val);
+
+	c = TKobj(TkCanvas, tk);
+
+	o = tk->env->top;
+	if(af == TkCadd) {
+		arg = tkword(o, arg, tag, tag+sizeof(tag), nil);
+		if(tag[0] == '\0' || (tag[0] >= '0' && tag[0] <= '9'))
+			return TkBadtg;
+	}
+
+	fmt = "%d";
+	arg = tkword(o, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "above") == 0) {
+		tkword(o, arg, buf, buf+sizeof(buf), nil);
+		f = tkctaglook(tk, nil, buf);
+		if(f == nil)
+			return TkBadtg;
+
+		t = tkclasttag(c->head, f->obj);
+		if(t == nil)
+			return TkBadtg;
+
+		for(i = t->item->next; i; i = i->next) {
+			if(af == TkCadd) {
+				i->tags = tkmkname(tag);
+				if(i->tags == nil)
+					return TkNomem;
+				tkcaddtag(tk, i, 0);
+			}
+			else {
+				e = tkvalue(val, fmt, i->id);
+				if(e != nil)
+					return e;
+				fmt = " %d";
+			}
+		}
+		return nil;
+	}
+
+	if(strcmp(buf, "all") == 0) {
+		for(i = c->head; i; i = i->next) {
+			if(af == TkCadd) {
+				i->tags = tkmkname(tag);
+				if(i->tags == nil)
+					return TkNomem;
+				tkcaddtag(tk, i, 0);
+			}
+			else {
+				e = tkvalue(val, fmt, i->id);
+				if(e != nil)
+					return e;
+				fmt = " %d";
+			}
+		}
+		return nil;
+	}
+
+	if(strcmp(buf, "below") == 0) {
+		tkword(o, arg, buf, buf+sizeof(buf), nil);
+		f = tkctaglook(tk, nil, buf);
+		if(f == nil)
+			return TkBadtg;
+		tt = f->obj;
+		for(b = c->head; b; b = b->next) {
+			for(t = tt; t; t = t->itemlist)
+				if(t->item == b)
+					goto found;
+		}
+	found:
+		for(i = c->head; i != b; i = i->next) {
+			if(af == TkCadd) {
+				i->tags = tkmkname(tag);
+				if(i->tags == nil)
+					return TkNomem;
+				tkcaddtag(tk, i, 0);
+			}
+			else {
+				e = tkvalue(val, fmt, i->id);
+				if(e != nil)
+					return e;
+				fmt = " %d";
+			}
+		}
+		return nil;
+	}
+
+	if(strcmp(buf, "closest") == 0) {
+		e = tkfracword(o, &arg, &x, nil);
+		if (e == nil)
+			e = tkfracword(o, &arg, &y, nil);
+		if (e != nil)
+			return e;
+		if(*arg != '\0')
+			return "!not implemented";
+
+		x = TKF2I(x);
+		y = TKF2I(y);
+		i = nil;
+		dist = 0;
+		for(b = c->head; b != nil; b = b->next) {
+			dx = x - (b->p.bb.min.x + Dx(b->p.bb)/2);
+			dy = y - (b->p.bb.min.y + Dy(b->p.bb)/2);
+			d = dx*dx + dy*dy;
+			if(d < dist || dist == 0) {
+				i = b;
+				dist = d;
+			}
+		}
+		if(i == nil)
+			return nil;
+
+		if(af == TkCadd) {
+			i->tags = tkmkname(tag);
+			if(i->tags == nil)
+				e = TkNomem;
+			else
+				tkcaddtag(tk, i, 0);
+		}
+		else
+			e = tkvalue(val, fmt, i->id);
+		return e;
+	}
+
+	if(strcmp(buf, "withtag") == 0) {
+		tkword(o, arg, buf, buf+sizeof(buf), nil);
+		f = tkctaglook(tk, nil, buf);
+		if(f == nil)
+			return TkBadtg;
+		for(t = f->obj; t; t = t->taglist) {
+			i = t->item;
+			if(af == TkCadd) {
+				i->tags = tkmkname(tag);
+				if(i->tags == nil)
+					return TkNomem;
+				tkcaddtag(tk, i, 0);
+			}
+			else {
+				e = tkvalue(val, fmt, i->id);
+				if(e != nil)
+					return e;
+				fmt = " %d";
+			}
+		}
+		return nil;
+	}
+
+	if(strcmp(buf, "enclosed") == 0) {
+		e = tkparsepts(o, &p, &arg, 0);
+		if(e != nil)
+			goto done;
+		if(p.npoint != 2) {
+			e = TkFewpt;
+			goto done;
+		}
+		for(i = c->head; i; i = i->next) {
+			if(rectinrect(i->p.bb, p.bb)) {
+				if(af == TkCadd) {
+					i->tags = tkmkname(tag);
+					if(i->tags == nil) {
+						e = TkNomem;
+						goto done;
+					}
+					tkcaddtag(tk, i, 0);
+				}
+				else {
+					e = tkvalue(val, fmt, i->id);
+					if(e != nil)
+						goto done;
+					fmt = " %d";
+				}
+			}
+		}
+		goto done;
+	}
+
+	if(strcmp(buf, "overlapping") == 0) {
+		e = tkparsepts(o, &p, &arg, 0);
+		if(e != nil)
+			goto done;
+		if(p.npoint != 2) {
+			e = TkFewpt;
+			goto done;
+		}
+		for(i = c->head; i; i = i->next) {
+			if(rectXrect(i->p.bb, p.bb)) {
+				if(af == TkCadd) {
+					i->tags = tkmkname(tag);
+					if(i->tags == nil) {
+						e = TkNomem;
+						goto done;
+					}
+					tkcaddtag(tk, i, 0);
+				}
+				else {
+					e = tkvalue(val, "%d ", i->id);
+					if(e != nil)
+						goto done;
+				}
+			}
+		}
+		goto done;
+	}
+
+	return TkBadcm;
+
+done: 		 /* both no error and error do the same thing */
+	tkfreepoint(&p);
+	return e;
+}
+
+static char*
+tkcvsaddtag(Tk *tk, char *arg, char **val)
+{
+	return tkcvstags(tk, arg, val, TkCadd);
+}
+
+static char*
+tkcvsfind(Tk *tk, char *arg, char **val)
+{
+	return tkcvstags(tk, arg, val, TkCfind);
+}
+
+static void
+tksweepcanv(Tk *tk)
+{
+	int j, k;
+	TkCtag *t, *tt;
+	TkName **np, *n, *nn;
+	TkCitem *i;
+	TkCanvas *c;
+	TkAction *a;
+
+	c = TKobj(TkCanvas, tk);
+
+	for(j = 0; j < TkChash; j++)
+		for(n = c->thash[j]; n != nil; n = n->link)
+			n->ref = 0;
+
+	for(i = c->head; i != nil; i = i->next)
+		for(t = i->stag; t != nil; t = t->itemlist)
+			t->name->ref = 1;
+
+	k = 0;
+	for(j = 0; j < TkChash; j++) {
+		np = &c->thash[j];
+		for(n = *np; n != nil; n = nn) {
+			nn = n->link;
+			if(n->ref == 0) {
+				for(t = n->obj; t != nil; t = tt) {
+					tt = t->taglist;
+					free(t);
+				}
+				tkfreebind(n->prop.binds);
+				free(n);
+				*np = nn;
+			} else {
+				np = &n->link;
+				for(a = n->prop.binds; a != nil; a = a->link)
+					k++;
+			}
+		}
+	}
+
+	c->actions = k;
+	k = 3 * k / 2;
+	if (k < Tksweep)
+		c->actlim = Tksweep;
+	else
+		c->actlim = k;
+}
+
+/*
+ * extension to tcl/tk:
+ * grab set tag
+ * grab release tag
+ * grab ifunset tag
+ */
+static char*
+tkcvsgrab(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkName *f;
+	TkCanvas *c;
+	char buf[Tkmaxitem];
+
+	c = TKobj(TkCanvas, tk);
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if (strcmp(buf, "status") == 0) {
+		if (c->grab != nil)
+			return tkvalue(val, "%d", c->grab->id);
+	}
+	else if (strcmp(buf, "release") == 0) {
+		c->grab = nil;
+	}
+	else if (strcmp(buf, "set") == 0 || strcmp(buf, "ifunset") == 0) {
+		if (buf[0] == 'i' && c->grab != nil)
+			return nil;
+		tkword(tk->env->top, arg, buf, buf + sizeof(buf), nil);
+
+		f = tkctaglook(tk, nil, buf);
+		if(f == nil || f->obj == nil)
+			return TkBadtg;
+	
+		c = TKobj(TkCanvas, tk);
+		t = tkcfirsttag(c->head, f->obj);
+		if(t == nil)
+			return TkBadtg;
+		c->grab = t->item;
+	}
+	else
+		return TkBadvl;
+	return nil;
+}
+
+static char*
+tkcvsbind(Tk *tk, char *arg, char **val)
+{
+	Rune r;
+	TkCtag *t;
+	TkName *f;
+	TkAction *a;
+	TkCanvas *c;
+	int event, mode;
+	char *cmd, buf[Tkmaxitem];
+	char *e;
+
+	c = TKobj(TkCanvas, tk);
+	if (c->actions >= c->actlim)
+		tksweepcanv(tk);
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil) {
+		f = tkctaglook(tk, tkmkname(buf), buf);
+		if(f == nil)
+			return TkNomem;
+	}
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '<') {
+		event = tkseqparse(buf+1);
+		if(event == -1)
+			return TkBadsq;
+	}
+	else {
+		chartorune(&r, buf);
+		event = TkKey | r;
+	}
+	if(event == 0)
+		return TkBadsq;
+
+	arg = tkskip(arg, " \t");
+	if(*arg == '\0') {
+		for(t = f->obj; t; t = t->taglist) {
+			for(a = t->name->prop.binds; a; a = a->link)
+				if(event == a->event)
+					return tkvalue(val, "%s", a->arg);
+			for(a = t->name->prop.binds; a; a = a->link)
+				if(event & a->event)
+					return tkvalue(val, "%s", a->arg);
+		}
+		return nil;		
+	}
+
+	mode = TkArepl;
+	if(*arg == '+') {
+		mode = TkAadd;
+		arg++;
+	}
+	else if(*arg == '-'){
+		mode = TkAsub;
+		arg++;
+	}
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	cmd = strdup(buf);
+	if(cmd == nil)
+		return TkNomem;
+	e = tkaction(&f->prop.binds, event, TkDynamic, cmd, mode);
+	if(e == nil)
+		c->actions++;
+	return e;
+}
+
+static char*
+tkcvscreate(Tk *tk, char *arg, char **val)
+{
+	TkCimeth *m;
+	char buf[Tkmaxitem];
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	for(m = tkcimethod; m->name; m++)
+		if(strcmp(buf, m->name) == 0)
+			return m->create(tk, arg, val);
+
+	return TkBadit;
+}
+
+static char*
+tkcvsbbox(Tk *tk, char *arg, char **val)
+{
+	TkName *f;
+	TkCtag *t;
+	Rectangle bb;
+	char buf[Tkmaxitem];
+
+	bb = bbnil;
+	for(;;) {
+		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		if(buf[0] == '\0')
+			break;
+		f = tkctaglook(tk, nil, buf);
+		if(f == nil)
+			return TkBadtg;
+		for(t = f->obj; t; t = t->taglist)
+			tkbbmax(&bb, &t->item->p.bb);
+	}
+	return tkvalue(val, "%d %d %d %d", bb.min.x, bb.min.y, bb.max.x, bb.max.y);
+}
+
+static char*
+tkcvscanvx(Tk *tk, char *arg, char **val)
+{
+	int x, s;
+	TkCanvas *c;
+	Point p;
+	char buf[Tkmaxitem];
+
+	c = TKobj(TkCanvas, tk);
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+
+	p = tkposn(tk);
+	x = atoi(buf) + c->view.x - (p.x + tk->borderwidth);
+
+	if(*arg) {
+		tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		s = atoi(buf);
+		if (s) {
+			if (x>=0)
+				x = ((x+s/2)/s)*s;
+			else
+				x = ((x-s/2)/s)*s;
+		}
+	}
+	return tkvalue(val, "%d", x);
+}
+
+static char*
+tkcvscanvy(Tk *tk, char *arg, char **val)
+{
+	int y, s;
+	TkCanvas *c;
+	Point p;
+	char buf[Tkmaxitem];
+
+	c = TKobj(TkCanvas, tk);
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+
+	p = tkposn(tk);
+	y = atoi(buf) + c->view.y - (p.y + tk->borderwidth);
+
+	if(*arg) {
+		tkitem(buf, arg);
+		s = atoi(buf);
+		if (s) {
+			if (y>=0)
+				y = ((y+s/2)/s)*s;
+			else
+				y = ((y-s/2)/s)*s;
+		}
+	}
+	return tkvalue(val, "%d", y);
+}
+
+static char *
+tkcvsscreenx(Tk *tk, char *arg, char **val)
+{
+	int x;
+	TkCanvas *c;
+	Point p;
+	char buf[Tkmaxitem];
+
+	c = TKobj(TkCanvas, tk);
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+	p = tkposn(tk);
+	x = atoi(buf) - c->view.x + (p.x + tk->borderwidth);
+	return tkvalue(val, "%d", x);
+}
+
+static char *
+tkcvsscreeny(Tk *tk, char *arg, char **val)
+{
+	int y;
+	TkCanvas *c;
+	Point p;
+	char buf[Tkmaxitem];
+
+	c = TKobj(TkCanvas, tk);
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+	p = tkposn(tk);
+	y = atoi(buf) - c->view.y + (p.y + tk->borderwidth);
+	return tkvalue(val, "%d", y);
+}
+
+static char*
+tkcvscoords(Tk *tk, char *arg, char **val)
+{
+	int i;
+	Point *p;
+	TkCtag *t;
+	TkName *f;
+	TkCanvas *c;
+	TkCitem *item;
+	char *fmt, *e, *v, buf[Tkmaxitem];
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	c = TKobj(TkCanvas, tk);
+
+	t = tkcfirsttag(c->head, f->obj);
+	if(t == nil)
+		return TkBadtg;
+
+	item = t->item;
+
+	if(*arg == '\0') {
+		fmt = "%s";
+		p = item->p.parampt;
+		for(i = 0; i < item->p.npoint; i++) {
+			v = tkfprint(buf, p->x);
+			*v++ = ' ';
+			tkfprint(v, p->y);
+			e = tkvalue(val, fmt, buf);
+			if(e != nil)
+				return e;
+			fmt = " %s";
+			p++;
+		}
+		return nil;
+	}
+
+	tkbbmax(&c->update, &item->p.bb);
+	e = tkcimethod[item->type].coord(item, arg, 0, 0);
+	tkbbmax(&c->update, &item->p.bb);
+	tkcvssetdirty(tk);
+	return e;
+}
+
+static char*
+tkcvsscale(Tk *tk, char *arg, char **val)
+{
+	TkName *f;
+	TkCtag *t;
+	TkCanvas *c;
+	TkCpoints pts;
+	TkCitem *item;
+	int j;
+	char *e, buf[Tkmaxitem];
+	Point *p, *d, origin, scalef;
+
+	USED(val);
+
+	c = TKobj(TkCanvas, tk);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	e = tkparsepts(tk->env->top, &pts, &arg, 0);
+	if(e != nil)
+		return e;
+	if(pts.npoint != 2) {
+		tkfreepoint(&pts);
+		return TkFewpt;
+	}
+	origin = pts.parampt[0];
+	scalef = pts.parampt[1];
+	tkfreepoint(&pts);
+	for(t = f->obj; t; t = t->taglist) {
+		item = t->item;
+		p = item->p.parampt;
+		d = item->p.drawpt;
+		for(j = 0; j < item->p.npoint; j++) {
+			p->x -= origin.x;
+			p->y -= origin.y;
+			p->x = TKF2I(p->x*scalef.x);
+			p->y = TKF2I(p->y*scalef.y);
+			p->x += origin.x;
+			p->y += origin.y;
+			d->x = TKF2I(p->x);
+			d->y = TKF2I(p->y);
+			d++;
+			p++;
+		}
+		tkbbmax(&c->update, &item->p.bb);
+		e = tkcimethod[item->type].coord(item, nil, 0, 0);
+		tkbbmax(&c->update, &item->p.bb);
+		if(e != nil)
+			return e;
+
+		tkcvssetdirty(tk);
+	}
+	return nil;
+}
+
+static char*
+tkcvsdtag(Tk *tk, char *arg, char **val)
+{
+	TkName *f, *dt;
+	char buf[Tkmaxitem];
+	TkCtag **l, *t, *it, *tf;
+
+	USED(val);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+/*
+	XXX this code doesn't appear to work properly.
+	fix it later. for the moment, it's just a somewhat more
+	efficient substitute for the later code, so just use that
+	instead.
+
+	if(*arg == '\0') {
+		for(t = f->obj; t; t = tf) {
+			l = &t->item->stag;
+			for(it = *l; it; it = it->itemlist) {
+				if(it->item == t->item) {
+					*l = it->itemlist;
+					break;
+				}
+				l = &it->itemlist;
+			}
+
+			tf = t->taglist;
+			free(t);
+		}
+		f->obj = nil;
+		return nil;
+	}
+*/
+	if (*arg == '\0')
+		dt = f;
+	else {
+		tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		dt = tkctaglook(tk, nil, buf);
+		if(dt == nil || dt->obj == nil)
+			return TkBadtg;
+	}
+
+	for(t = f->obj; t; t = t->taglist) {
+		l = (TkCtag **)&dt->obj;
+		for(it = dt->obj; it; it = it->taglist) {
+			if(t->item == it->item) {
+				*l = it->taglist;
+				l = &t->item->stag;
+				for(tf = *l; tf; tf = tf->itemlist) {
+					if(tf == it) {
+						*l = tf->itemlist;
+						break;
+					}
+					l = &tf->itemlist;
+				}
+				free(it);
+				break;
+			}
+			l = &it->taglist;
+		}
+	}
+	return nil;
+}
+
+static char*
+tkcvsdchars(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkName *f;
+	char *e, buf[Tkmaxitem];
+
+	USED(val);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	for(t = f->obj; t; t = t->taglist) {
+		if(t->item->type == TkCVtext) {
+			e = tkcvstextdchar(tk, t->item, arg);
+			if(e != nil)
+				return e;
+		}
+	}
+
+	return nil;
+}
+
+static char*
+tkcvsindex(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkName *f;
+	char *e, buf[Tkmaxitem];
+
+	USED(val);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	for(t = f->obj; t; t = t->taglist) {
+		if(t->item->type == TkCVtext) {
+			e = tkcvstextindex(tk, t->item, arg, val);
+			if(e != nil)
+				return e;
+			return nil;
+		}
+	}
+	return nil;
+}
+
+static char*
+tkcvsicursor(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkName *f;
+	char *e, buf[Tkmaxitem];
+
+	USED(val);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	for(t = f->obj; t; t = t->taglist) {
+		if(t->item->type == TkCVtext) {
+			e = tkcvstexticursor(tk, t->item, arg);
+			if(e != nil)
+				return e;
+			return nil;
+		}
+	}
+	return nil;
+}
+
+static char*
+tkcvsinsert(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkName *f;
+	char *e, buf[Tkmaxitem];
+
+	USED(val);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	for(t = f->obj; t; t = t->taglist) {
+		if(t->item->type == TkCVtext) {
+			e = tkcvstextinsert(tk, t->item, arg);
+			if(e != nil)
+				return e;
+		}
+	}
+
+	return nil;
+}
+
+static char*
+tkcvsselect(Tk *tk, char *arg, char **val)
+{
+	int op;
+	TkCtag *t;
+	TkName *f;
+	TkCanvas *c;
+	char buf[Tkmaxitem];
+
+	c = TKobj(TkCanvas, tk);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "clear") == 0) {
+		tkcvstextclr(tk);
+		return nil;		
+	}
+	if(strcmp(buf, "item") == 0) {
+		if(c->selection)
+			return tkvalue(val, "%d", c->selection->id);
+		return nil;		
+	}
+
+	if(strcmp(buf, "to") == 0)
+		op = TkCselto;
+	else
+	if(strcmp(buf, "from") == 0)
+		op = TkCselfrom;
+	else
+	if(strcmp(buf, "adjust") == 0)
+		op = TkCseladjust;
+	else
+		return TkBadcm;
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil)
+		return TkBadtg;
+
+	t = tkcfirsttag(c->head, f->obj);
+	if(t == nil)
+		return TkBadtg;
+
+	return tkcvstextselect(tk, t->item, arg, op);
+}
+
+static char*
+tkcvsitemcget(Tk *tk, char *arg, char **val)
+{
+	TkName *f;
+	TkCtag *t;
+	TkCitem *i;
+	char buf[Tkmaxitem];
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	for(i = TKobj(TkCanvas, tk)->head; i; i = i->next) {
+		for(t = f->obj; t; t = t->taglist)
+			if(i == t->item)
+				return tkcimethod[i->type].cget(i, arg, val);
+	}
+	return nil;
+}
+
+static char*
+tkcvsitemconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkName *f;
+	TkCtag *t;
+	TkCitem *i;
+	TkCanvas *c;
+	char buf[Tkmaxitem];
+
+	USED(val);
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return TkBadtg;
+
+	c = TKobj(TkCanvas, tk);
+	for(t = f->obj; t; t = t->taglist) {
+		for(i = c->head; i; i = i->next) {
+			if(i == t->item) {
+				tkbbmax(&c->update, &i->p.bb);
+				e = tkcimethod[i->type].conf(tk, i, arg);
+				tkbbmax(&c->update, &i->p.bb);
+				tkcvssetdirty(tk);
+				if(e != nil)
+					return e;
+			}
+		}
+	}
+	return nil;
+}
+
+static void
+tkcvsfreename(TkCanvas *c, TkName *n)
+{
+	ulong h;
+	char *p, *s;
+	TkName *f, **l;
+	
+	/* just free implicit ones for now */
+	if(n == nil)
+		return;
+	s = n->name;
+	if(s == nil || (s[0] < '0' || s[0] > '9'))
+		return;
+	h = 0;
+	for(p = s; *p; p++)
+		h += 3*h + *p;
+	l = &c->thash[h%TkChash];
+	for(f = *l; f; l = &f->link, f = *l)
+		if(f == n){
+			*l = f->link;
+			tkfreebind(f->prop.binds);
+			free(f);
+			return;
+		}
+}
+
+static char*
+tkcvsdelete(Tk *tk, char *arg, char **val)
+{
+	TkName *f;
+	TkCanvas *c;
+	char buf[Tkmaxitem];
+	TkCitem *item, *prev, *i;
+	TkCtag *t, *inext, **l, *dit, *it;
+
+	USED(val);
+
+	c = TKobj(TkCanvas, tk);
+	for(;;) {
+		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		if(buf[0] == '\0')
+			break;
+		f = tkctaglook(tk, nil, buf);
+		if(f == nil || f->obj == nil)
+			return nil;
+		while(f->obj) {
+			t = f->obj;
+			item = t->item;
+			for(it = item->stag; it; it = inext) {
+				inext = it->itemlist;
+				l = (TkCtag **)&it->name->obj;
+				for(dit = *l; dit; dit = dit->taglist) {
+					if(dit->item == item) {
+						*l = dit->taglist;
+						if(dit != t){
+							tkcvsfreename(c, dit->name);
+							free(dit);
+						}
+						break;
+					}
+					l = &dit->taglist;
+				}
+			}
+			tkbbmax(&c->update, &item->p.bb);
+			tkcvssetdirty(tk);
+			prev = nil;
+			for(i = c->head; i; i = i->next) {
+				if(i == item)
+					break;
+				prev = i;
+			}
+			if(prev == nil)
+				c->head = i->next;
+			else
+				prev->next = i->next;
+			if(c->tail == item)
+				c->tail = prev;
+			if(c->focus == item)
+				c->focus = nil;
+			if(c->mouse == item)
+				c->mouse = nil;
+			if(c->selection == item)
+				c->selection = nil;
+			if(c->curtag.item == item)
+				c->current->obj = nil;
+			if (c->grab == item)
+				c->grab = nil;
+
+			tkcvsfreeitem(item);
+			free(t);
+		}
+	}
+	return nil;
+}
+
+static char*
+tkcvsfocus(Tk *tk, char *arg, char **val)
+{
+	TkName *f;
+	TkCtag *t;
+	TkCanvas *c;
+	TkCitem *i, *focus;
+	char buf[Tkmaxitem];
+
+	c = TKobj(TkCanvas, tk);
+
+	if(*arg == '\0') {
+		if(c->focus == nil)
+			return nil;
+		return tkvalue(val, "%d", c->focus->id);
+	}
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return nil;
+
+	focus = c->focus;
+	if(focus != nil && focus->type == TkCVtext)
+		tkcvstextfocus(tk, focus, 0);
+
+	for(i = c->head; i; i = i->next) {
+		if(i->type == TkCVtext || i->type == TkCVwindow) {
+			for(t = f->obj; t; t = t->taglist)
+				if(t->item == i)
+					focus = i;
+		}
+	}
+
+	if(focus != nil && focus->type == TkCVtext)
+		tkcvstextfocus(tk, focus, 1);
+
+	c->focus = focus;
+	return nil;
+}
+
+static char*
+tkcvsgettags(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkName *f;
+	TkCanvas *c;
+	char *fmt, *e, buf[Tkmaxitem];
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil)
+		return TkBadtg;
+
+	c = TKobj(TkCanvas, tk);
+	t = tkclasttag(c->head, f->obj);
+	if(t == nil)
+		return TkBadtg;
+	fmt = "%s";
+	t = t->item->stag;
+	while(t) {
+		/* XXX when might t->name be legally nil? */
+		if (t->name != nil) {
+			if (strcmp(t->name->name, "all")) {
+				e = tkvalue(val, fmt, t->name->name);
+				if(e != nil)
+					return e;
+				fmt = " %s";
+			}
+		}
+		t = t->itemlist;
+	}
+	return nil;
+}
+
+static char*
+tkcvslower(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkCanvas *c;
+	TkName *f, *b;
+	char buf[Tkmaxitem];
+	TkCitem *it, **l, **below, *items, **itemtail, *prev, *iprev;
+
+	USED(val);
+	c = TKobj(TkCanvas, tk);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return nil;
+
+	below = &c->head;
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] != '\0') {
+		b = tkctaglook(tk, nil, buf);
+		if(b == nil || f->obj == nil)
+			return TkBadtg;
+		for(it = c->head; it; it = it->next) {
+			for(t = b->obj; t; t = t->taglist)
+				if(t->item == it)
+					goto found;
+			below = &it->next;
+		}
+	found:;
+	}
+	l = &c->head;
+	prev = iprev = nil;
+	itemtail = &items;;
+	for (it = *l; it != nil; it = *l) {
+		for (t = f->obj; t; t = t->taglist) {
+			if(t->item == it) {
+				if (it == *below || below == &it->next)
+					below = l;
+				if (it == c->tail)
+					c->tail = prev;
+				*l = it->next;
+				*itemtail = it;
+				iprev = it;
+				itemtail = &it->next;
+				tkbbmax(&c->update, &it->p.bb);
+				goto next;
+			}
+		}
+		prev = it;
+		l = &it->next;
+next:;
+	}
+	if (prev == nil)
+		c->tail = iprev;
+	*itemtail = *below;
+	*below = items;
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+static char*
+tkcvsmove(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	int fx, fy;
+	TkTop *top;
+	TkCpoints *p;
+	TkName *tag;
+	Rectangle *u;
+	TkCitem *item;
+	char *e;
+	char buf[Tkmaxitem];
+
+	USED(val);
+	top = tk->env->top;
+	arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
+	tag = tkctaglook(tk, nil, buf);
+	if(tag == nil)
+		return nil;
+
+	e = tkfracword(top, &arg, &fx, nil);
+	if (e != nil)
+		return e;
+	e = tkfracword(top, &arg, &fy, nil);
+	if(e != nil)
+		return e;
+
+	u = &TKobj(TkCanvas, tk)->update;
+	for(t = tag->obj; t; t = t->taglist) {
+		item = t->item;
+		p = &item->p;
+		tkbbmax(u, &p->bb);
+		tkcimethod[item->type].coord(item, nil, fx, fy);
+		tkbbmax(u, &p->bb);
+	}
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+static char*
+tkcvsraise(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkCanvas *c;
+	TkName *f, *a;
+	char buf[Tkmaxitem];
+	TkCitem *prev, *it, *above, *items, *itemtail, *next;
+
+	USED(val);
+	c = TKobj(TkCanvas, tk);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil)
+		return nil;
+
+	above = c->tail;
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] != '\0') {
+		a = tkctaglook(tk, nil, buf);
+		if(a == nil)
+			return TkBadtg;
+		/*
+		 * find topmost item in the display list matching the "above" tag
+		 */
+		for(it = c->head; it != nil; it = it->next) {
+			for(t = a->obj; t; t = t->taglist)
+				if(t->item == it)
+					above = it;
+		}
+	}
+	prev = nil;
+	items = itemtail = nil;
+	for (it = c->head; it != nil; it = next) {
+		next = it->next;
+		for (t = f->obj; t; t = t->taglist) {
+			if(t->item == it) {
+				if (it == above)
+					above = next;
+				if (prev)
+					prev->next = next;
+				else
+					c->head = next;
+				if (itemtail)
+					itemtail->next = it;
+				else
+					items = it;
+				itemtail = it;
+				tkbbmax(&c->update, &it->p.bb);
+				goto next;
+			}
+		}
+		prev = it;
+next:;
+	}
+	if (items != nil) {
+		if (above) {
+			itemtail->next = above->next;
+			if (above->next == nil)
+				c->tail = itemtail;
+			above->next = items;
+		} else {
+			if (prev)
+				prev->next = items;
+			else
+				c->head = items;
+			c->tail = itemtail;
+			itemtail->next = nil;
+		}
+	}
+
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+static char*
+tkcvstype(Tk *tk, char *arg, char **val)
+{
+	TkCtag *t;
+	TkName *f;
+	TkCanvas *c;
+	char buf[Tkmaxitem];
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+
+	f = tkctaglook(tk, nil, buf);
+	if(f == nil || f->obj == nil)
+		return nil;
+
+	c = TKobj(TkCanvas, tk);
+
+	t = tkcfirsttag(c->head, f->obj);
+	if(t == nil)
+		return nil;
+
+	return tkvalue(val, "%s", tkcimethod[t->item->type].name);
+}
+
+static char*
+tkcvsview(Tk *tk, char *arg, char **val, int nl, int *posn, int min, int max, int inc)
+{
+	TkTop *t;
+	int top, bot, diff, amount;
+	char *e;
+	char buf[Tkmaxitem], *v;
+
+	diff = max-min;
+	if(*arg == '\0') {
+		if ( diff == 0 ) 
+			top = bot = 0;
+		else {
+			top = TKI2F(*posn-min)/diff;
+			bot = TKI2F(*posn+nl-min)/diff;
+		}
+		v = tkfprint(buf, top);
+		*v++ = ' ';
+		tkfprint(v, bot);
+		return tkvalue(val, "%s", buf);
+	}
+
+	t = tk->env->top;
+	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "moveto") == 0) {
+		e = tkfrac(&arg, &top, nil);
+		if (e != nil)
+			return e;
+		*posn = min + TKF2I((top+1)*diff);
+	}
+	else
+	if(strcmp(buf, "scroll") == 0) {
+		arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+		amount = atoi(buf);
+		tkword(t, arg, buf, buf+sizeof(buf), nil);
+		if(buf[0] == 'p')		/* Pages */
+			amount = amount * nl * 9 /10;
+		else if (inc > 0)
+			amount *= inc;
+		else
+			amount = amount * nl / 10;
+		*posn += amount;
+	}
+	else	
+		return TkBadcm;
+
+	bot = max - nl;
+	if(*posn > bot)
+		*posn = bot;
+	if(*posn < min)
+		*posn = min;
+
+	tk->dirty = tkrect(tk, 0);
+	return nil;
+}
+
+static char*
+tkcvsyview(Tk *tk, char *arg, char **val)
+{
+	int si;
+	char *e;
+	TkCanvas *c = TKobj(TkCanvas, tk);
+
+	si = TKF2I(c->yscrolli);
+	e = tkcvsview(tk, arg, val, tk->act.height, &c->view.y, c->region.min.y, c->region.max.y, si); 
+	tkcvssv(tk);
+	return e;
+}
+
+static char*
+tkcvsxview(Tk *tk, char *arg, char **val)
+{
+	int si;
+	char *e;
+	TkCanvas *c = TKobj(TkCanvas, tk);
+
+	si = TKF2I(c->xscrolli);
+	e = tkcvsview(tk, arg, val, tk->act.width, &c->view.x, c->region.min.x, c->region.max.x, si);
+	tkcvssh(tk);
+	return e;
+}
+
+/*
+ * return in posn the new view origin such that (preferably) smin and smax
+ * lie between cmin and cmax (cmin is the current view origin, and cmax the
+ * other end of the visible area).
+ * adjust posn (the view origin) so that (preferably) both smin and smax lie
+ * inside cmin to cmax. if both smin and smax cannot fit, then
+ * at least make sure that spref (smin<=spref<=smax) is visible.
+ * return 0 if no adjustment is required (the interval is already visible).
+ *
+ * attempt to make an adjustment as small as possible that
+ * fits these criteria.
+ */
+static int
+tkadjustvis(int *posn, int c0, int c1, int s0, int s1, int spref)
+{
+	int d, v;
+
+	d = c1 - c0;		/* visible width */
+
+	/*
+	 * if requested range fits inside visible range,
+	 * no adjustment is necessary
+	 */
+	if (c0 <= s0 && s1 <= c1)
+		return 0;
+
+	/*
+	 * if requested range fits, make it fully visible
+	 */
+	if (s1 - s0 < d) {
+		if (s0 < c0)
+			v = s0;
+		else
+			v = s1 - d;
+	} else {
+		/*
+		 * choose upper or lower end of requested range,
+		 * depending on which end of requested area is already
+		 * visible (if any).
+		 */
+		if (c0 <= s1 && s1 < c1) {		/* overlapping left of visible */
+			v = s1 - d;
+			if (v > spref)
+				v = spref;
+		}
+		else
+		if (c0 <= s0 && s0 < c1) {		/* overlapping right of visible */
+			v = s0;
+			if (v + d <= spref)
+				v = spref - d;
+		}
+		else
+		if (s1 < c0) {				/* left of visible */
+			v = spref;
+			if (v + d > s1)
+				v = s1 - d;
+		}
+		else {					/* right of visible */
+			v = spref - d;
+			if (v < s0)
+				v = s0;
+		}
+	}
+	*posn = v;
+	return 1;
+}
+
+static void
+tkcvsseerect(Tk *tk, Rectangle r, Point p)
+{
+	TkCanvas *c;
+	int scrollh, scrollv;
+
+	c = TKobj(TkCanvas, tk);
+
+	scrollh = tkadjustvis(&c->view.x, c->view.x, c->view.x + tk->act.width,
+			r.min.x, r.max.x, p.x);
+	scrollv = tkadjustvis(&c->view.y, c->view.y, c->view.y + tk->act.height,
+			r.min.y, r.max.y, p.y);
+	if (scrollh)
+		tkcvssh(tk);
+	if (scrollv)
+		tkcvssv(tk);
+	if (scrollh || scrollv)
+		tk->dirty = tkrect(tk, 0);
+}
+			
+static char*
+tkcvssee(Tk *tk, char *arg, char **val)
+{
+	Rectangle r;
+	int n, coords[4];
+	char *e;
+
+	USED(val);
+	n = 0;
+	while (n < 4) {
+		if (*arg == '\0')
+			break;
+		e = tkfracword(tk->env->top, &arg, &coords[n++], nil);
+		if (e != nil)
+			return e;
+	}
+
+	if (n != 2 && n != 4)
+		return TkFewpt;
+
+	r.min.x = TKF2I(coords[0]);
+	r.min.y = TKF2I(coords[1]);
+	if (n == 4) {
+		r.max.x = TKF2I(coords[2]);
+		r.max.y = TKF2I(coords[3]);
+	} else
+		r.max = r.min;
+	r = canonrect(r);
+	/*
+	 * XXX should intersect r with scrollregion here, as you shouldn't
+	 * be able to display things outside the scroll region. (??)
+	 */
+
+	tkcvsseerect(tk, r, r.min);
+	return nil;
+}
+
+static void
+tkcvsseesub(Tk *tk, Rectangle *rr, Point *pp)
+{
+	Rectangle r;
+	Point p;
+	TkCanvas *c;
+	c = TKobj(TkCanvas, tk);
+
+	r = rectaddpt(*rr, c->view);
+	p = addpt(*pp, c->view);
+
+	tkcvsseerect(tk, r, p);
+
+	*rr = rectsubpt(r, c->view);
+	*pp = subpt(p, c->view);
+}
+
+static void
+tkcvsgetimgs(Tk* tk, Image **image, Image **mask)
+{
+	TkCanvas *c;
+	c = TKobj(TkCanvas, tk);
+
+	*image = c->image;
+	*mask = c->mask;		/* XXX this is wrong - the mask image has nothing to do with the main image */
+}
+
+TkCimeth tkcimethod[] =
+{
+	"line",		tkcvslinecreat,
+			tkcvslinedraw,
+			tkcvslinefree,
+			tkcvslinecoord,
+			tkcvslinecget,
+			tkcvslineconf,
+			tkcvslinehit,
+
+	"text",		tkcvstextcreat,	
+			tkcvstextdraw,
+			tkcvstextfree,
+			tkcvstextcoord,
+			tkcvstextcget,
+			tkcvstextconf,
+			nil,
+
+	"rectangle",	tkcvsrectcreat,	
+			tkcvsrectdraw,
+			tkcvsrectfree,
+			tkcvsrectcoord,
+			tkcvsrectcget,
+			tkcvsrectconf,
+			nil,
+
+	"oval",		tkcvsovalcreat,	
+			tkcvsovaldraw,
+			tkcvsovalfree,
+			tkcvsovalcoord,
+			tkcvsovalcget,
+			tkcvsovalconf,
+			tkcvsovalhit,
+
+	"bitmap",	tkcvsbitcreat,	
+			tkcvsbitdraw,
+			tkcvsbitfree,
+			tkcvsbitcoord,
+			tkcvsbitcget,
+			tkcvsbitconf,
+			nil,
+
+	"polygon",	tkcvspolycreat,	
+			tkcvspolydraw,
+			tkcvspolyfree,
+			tkcvspolycoord,
+			tkcvspolycget,
+			tkcvspolyconf,
+			tkcvspolyhit,
+
+	"window",	tkcvswindcreat,	
+			tkcvswinddraw,
+			tkcvswindfree,
+			tkcvswindcoord,
+			tkcvswindcget,
+			tkcvswindconf,
+			nil,
+
+	"image",	tkcvsimgcreat,	
+			tkcvsimgdraw,
+			tkcvsimgfree,
+			tkcvsimgcoord,
+			tkcvsimgcget,
+			tkcvsimgconf,
+			nil,
+
+	"arc",		tkcvsarccreat,	
+			tkcvsarcdraw,
+			tkcvsarcfree,
+			tkcvsarccoord,
+			tkcvsarccget,
+			tkcvsarcconf,
+			nil,
+	nil
+};
+
+static
+TkCmdtab tkcanvcmd[] =
+{
+	"addtag",		tkcvsaddtag,
+	"bbox",			tkcvsbbox,
+	"bind",			tkcvsbind,
+	"cget",			tkcvscget,
+	"configure",		tkcvsconf,
+	"create",		tkcvscreate,
+	"canvasx",		tkcvscanvx,
+	"canvasy",		tkcvscanvy,
+	"coords",		tkcvscoords,
+	"dchars",		tkcvsdchars,
+	"delete",		tkcvsdelete,
+	"dtag",			tkcvsdtag,
+	"find",			tkcvsfind,
+	"focus",		tkcvsfocus,
+	"gettags",		tkcvsgettags,
+	"grab",		tkcvsgrab,
+	"icursor",		tkcvsicursor,
+	"insert",		tkcvsinsert,
+	"index",		tkcvsindex,
+	"itemcget",		tkcvsitemcget,
+	"itemconfigure",	tkcvsitemconf,
+	"lower",		tkcvslower,
+	"move",			tkcvsmove,
+	"raise",		tkcvsraise,
+	"screenx",		tkcvsscreenx,
+	"screeny",		tkcvsscreeny,
+	"see",		tkcvssee,
+	"select",		tkcvsselect,
+	"scale",		tkcvsscale,
+	"type",			tkcvstype,
+	"yview",		tkcvsyview,
+	"xview",		tkcvsxview,
+	nil
+};
+
+TkMethod canvasmethod = {
+	"canvas",
+	tkcanvcmd,
+	tkfreecanv,
+	tkdrawcanv,
+	tkcvsgeom,
+	tkcvsgetimgs,
+	tkcvsfocusorder,
+	tkcvsdirty,
+	tkcvsrelpos,
+	tkcvsevent,
+	tkcvsseesub,
+	tkcvsinwindow,
+	nil,
+	tkcvsforgetsub,
+};
--- /dev/null
+++ b/libtk/canvs.h
@@ -1,0 +1,240 @@
+typedef struct TkCimeth TkCimeth;
+typedef struct TkCitem TkCitem;
+typedef struct TkCanvas TkCanvas;
+typedef struct TkCline TkCline;
+typedef struct TkCtag TkCtag;
+typedef struct TkCpoints TkCpoints;
+typedef struct TkCwind TkCwind;
+
+struct TkCline
+{
+	int		arrow;
+	int		shape[3];
+	int		width;
+	Image*		stipple;
+	Image*		pen;
+	int		arrowf;
+	int		arrowl;
+	int		capstyle;
+	int		smooth;
+	int		steps;
+};
+
+struct TkCwind
+{
+	Tk*		sub;		/* Subwindow of canvas */
+	Tk*		focus;		/* Current Mouse focus */
+	int		width;		/* Requested width */
+	int		height;		/* Requested height */
+	int		flags;		/* possible: Tkanchor|Tksetwidth|Tksetheight */
+};
+
+struct TkCpoints
+{
+	int		npoint;		/* Number of points */
+	Point*		parampt;	/* Parameters in fixed point */
+	Point*		drawpt;		/* Draw coord in pixels */
+	Rectangle	bb;		/* Bounding box in pixels */
+};
+
+struct TkCitem
+{
+	int		id;		/* Unique id */
+	int		type;		/* Object type */
+	TkCpoints	p;		/* Points plus bounding box */
+	TkEnv*		env;		/* Colors & fonts */
+	TkCitem*	next;		/* Z order */
+	TkName*		tags;		/* Temporary tag spot */
+	TkCtag*		stag;		/* Real tag structure */
+//	char		obj[TKSTRUCTALIGN];
+};
+
+struct TkCtag
+{
+	TkCitem*	item;		/* Link to item */
+	TkName*		name;		/* Text name or id */
+	TkCtag*		taglist;	/* link items with this tag */
+	TkCtag*		itemlist;	/* link tags for this item */
+};
+
+enum
+{
+	/* Item types */
+	TkCVline,
+	TkCVtext,
+	TkCVrect,
+	TkCVoval,
+	TkCVbitmap,
+	TkCVpoly,
+	TkCVwindow,
+	TkCVimage,
+	TkCVarc,
+
+	TkCselto	= 0,
+	TkCselfrom,
+	TkCseladjust,
+
+	TkCbufauto	= 0,
+	TkCbufnone,
+	TkCbufvisible,
+	TkCbufall,
+
+	TkCadd		= 0,
+	TkCfind,
+	
+	TkChash		= 32,
+
+	TkCarrowf	= (1<<0),
+	TkCarrowl	= (1<<1),
+	Tknarrow	= 6		/* Number of points in arrow */
+};
+
+struct TkCanvas
+{
+	int		close;
+	int		confine;
+	int		cleanup;
+	int		scrollr[4];
+	Rectangle	region;
+	Rectangle	update;		/* Area to paint next draw */
+	Point		view;
+	TkCitem*	selection;
+	int		width;
+	int		height;
+	int		sborderwidth;
+	int		xscrolli;	/* Scroll increment */
+	int		yscrolli;
+	char*		xscroll;	/* Scroll commands */
+	char*		yscroll;
+	int		id;		/* Unique id */
+	TkCitem*	head;		/* Items in Z order */
+	TkCitem*	tail;		/* Head is lowest, tail is highest */
+	TkCitem*	focus;		/* Keyboard focus */
+	TkCitem*	mouse;		/* Mouse focus */
+	TkCitem* grab;
+	TkName*		current;	/* Fake for current tag */
+	TkCtag		curtag;
+	Image*		image;		/* Drawing space */
+	int			ialloc;		/* image was allocated by us? */
+	Image*		mask;		/* mask space (for stippling) */
+	TkName*		thash[TkChash];	/* Tag hash */
+	int		actions;
+	int		actlim;
+	int		buffer;
+};
+
+struct TkCimeth
+{
+	char*	name;
+	char*	(*create)(Tk*, char *arg, char **val);
+	void	(*draw)(Image*, TkCitem*, TkEnv*);
+	void	(*free)(TkCitem*);
+	char*	(*coord)(TkCitem*, char*, int, int);
+	char*	(*cget)(TkCitem*, char*, char**);
+	char*	(*conf)(Tk*, TkCitem*, char*);
+	int		(*hit)(TkCitem*, Point);
+};
+
+extern	TkCimeth	tkcimethod[];
+extern	int	cvslshape[];
+extern	Rectangle	bbnil;
+extern	Rectangle	huger;
+
+/* General */
+extern	char*		tkcaddtag(Tk*, TkCitem*, int);
+extern	TkCtag*		tkcfirsttag(TkCitem*, TkCtag*);
+extern	TkCtag*		tkclasttag(TkCitem*, TkCtag*);
+extern	void		tkcvsappend(TkCanvas*, TkCitem*);
+extern	TkCitem*	 tkcnewitem(Tk*, int, int);
+extern	void		tkcvsfreeitem(TkCitem*);
+extern	Point		tkcvsrelpos(Tk*);
+extern	Tk*		tkcvsinwindow(Tk*, Point*);
+extern	char*		tkcvstextdchar(Tk*, TkCitem*, char*);
+extern	char*		tkcvstextindex(Tk*, TkCitem*, char*, char **val);
+extern	char*		tkcvstextinsert(Tk*, TkCitem*, char*);
+extern	char*		tkcvstexticursor(Tk*, TkCitem*, char*);
+extern	void		tkmkpen(Image**, TkEnv*, Image*);
+extern	void		tkcvstextfocus(Tk*, TkCitem*, int);
+extern	char*		tkcvstextselect(Tk*, TkCitem*, char*, int);
+extern	void		tkcvstextclr(Tk*);
+extern	Tk*		tkcvsevent(Tk*, int, void*);
+extern	Point		tkcvsanchor(Point, int, int, int);
+extern	void		tkcvsdirty(Tk*);
+extern	void		tkfreectag(TkCtag*);
+extern	char*		tkparsepts(TkTop*, TkCpoints*, char**, int);
+extern	void		tkfreepoint(TkCpoints*);
+extern	void		tkxlatepts(Point*, int, int, int);
+extern	void		tkpolybound(Point*, int, Rectangle*);
+extern	TkName*		tkctaglook(Tk*, TkName*, char*);
+extern	void		tkbbmax(Rectangle*, Rectangle*);
+extern	void		tkcvssetdirty(Tk*);
+
+/* Canvas Item methods - required to populate tkcimethod in canvs.c */
+extern	char*	tkcvslinecreat(Tk*, char *arg, char **val);
+extern	void	tkcvslinedraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvslinefree(TkCitem*);
+extern	char*	tkcvslinecoord(TkCitem*, char*, int, int);
+extern	char*	tkcvslinecget(TkCitem*, char*, char**);
+extern	char*	tkcvslineconf(Tk*, TkCitem*, char*);
+extern	int		tkcvslinehit(TkCitem*, Point);
+
+extern	char*	tkcvstextcreat(Tk*, char *arg, char **val);
+extern	void	tkcvstextdraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvstextfree(TkCitem*);
+extern	char*	tkcvstextcoord(TkCitem*, char*, int, int);
+extern	char*	tkcvstextcget(TkCitem*, char*, char**);
+extern	char*	tkcvstextconf(Tk*, TkCitem*, char*);
+
+extern	char*	tkcvsrectcreat(Tk*, char *arg, char **val);
+extern	void	tkcvsrectdraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvsrectfree(TkCitem*);
+extern	char*	tkcvsrectcoord(TkCitem*, char*, int, int);
+extern	char*	tkcvsrectcget(TkCitem*, char*, char**);
+extern	char*	tkcvsrectconf(Tk*, TkCitem*, char*);
+
+extern	char*	tkcvsovalcreat(Tk*, char *arg, char **val);
+extern	void	tkcvsovaldraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvsovalfree(TkCitem*);
+extern	char*	tkcvsovalcoord(TkCitem*, char*, int, int);
+extern	char*	tkcvsovalcget(TkCitem*, char*, char**);
+extern	char*	tkcvsovalconf(Tk*, TkCitem*, char*);
+extern	int		tkcvsovalhit(TkCitem*, Point);
+
+extern	char*	tkcvsarccreat(Tk*, char *arg, char **val);
+extern	void	tkcvsarcdraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvsarcfree(TkCitem*);
+extern	char*	tkcvsarccoord(TkCitem*, char*, int, int);
+extern	char*	tkcvsarccget(TkCitem*, char*, char**);
+extern	char*	tkcvsarcconf(Tk*, TkCitem*, char*);
+
+extern	char*	tkcvsbitcreat(Tk*, char *arg, char **val);
+extern	void	tkcvsbitdraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvsbitfree(TkCitem*);
+extern	char*	tkcvsbitcoord(TkCitem*, char*, int, int);
+extern	char*	tkcvsbitcget(TkCitem*, char*, char**);
+extern	char*	tkcvsbitconf(Tk*, TkCitem*, char*);
+
+extern	char*	tkcvswindcreat(Tk*, char *arg, char **val);
+extern	void	tkcvswinddraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvswindfree(TkCitem*);
+extern	char*	tkcvswindcoord(TkCitem*, char*, int, int);
+extern	char*	tkcvswindcget(TkCitem*, char*, char**);
+extern	char*	tkcvswindconf(Tk*, TkCitem*, char*);
+
+extern	char*	tkcvspolycreat(Tk*, char *arg, char **val);
+extern	void	tkcvspolydraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvspolyfree(TkCitem*);
+extern	char*	tkcvspolycoord(TkCitem*, char*, int, int);
+extern	char*	tkcvspolycget(TkCitem*, char*, char**);
+extern	char*	tkcvspolyconf(Tk*, TkCitem*, char*);
+extern	int		tkcvspolyhit(TkCitem*, Point);
+
+extern	char*	tkcvsimgcreat(Tk*, char *arg, char **val);
+extern	void	tkcvsimgdraw(Image*, TkCitem*, TkEnv*);
+extern	void	tkcvsimgfree(TkCitem*);
+extern	char*	tkcvsimgcoord(TkCitem*, char*, int, int);
+extern	char*	tkcvsimgcget(TkCitem*, char*, char**);
+extern	char*	tkcvsimgconf(Tk*, TkCitem*, char*);
+
+extern	TkCitem*	tkcvsfindwin(Tk*);
+extern	void		tkcvsforgetsub(Tk*, Tk*);
--- /dev/null
+++ b/libtk/canvu.c
@@ -1,0 +1,540 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+char*
+tkparsepts(TkTop *t, TkCpoints *i, char **arg, int close)
+{
+	char *s, *e;
+	Point *p, *d;
+	int n, npoint;
+
+	i->parampt = nil;
+	i->drawpt = nil;
+	i->bb = bbnil;
+	s = *arg;
+	npoint = 0;
+	while(*s) {
+		s = tkskip(s, " \t");
+		if(*s == '-' && (s[1] < '0' || s[1] > '9'))
+			break;
+		while(*s && *s != ' ' && *s != '\t')
+			s++;
+		npoint++;
+	}
+
+	i->parampt = mallocz(npoint*sizeof(Point), 0);
+	if(i->parampt == nil)
+		return TkNomem;
+
+	s = *arg;
+	p = i->parampt;
+	npoint = 0;
+	while(*s) {
+		e = tkfracword(t, &s, &p->x, nil);
+		if(e != nil)
+			goto Error;
+		e = tkfracword(t, &s, &p->y, nil);
+		if(e != nil)
+			goto Error;
+		npoint++;
+		s = tkskip(s, " \t");
+		if(*s == '-' && (s[1] < '0' || s[1] > '9'))
+			break;
+		p++;
+	}
+	*arg = s;
+	close = (close != 0);
+	i->drawpt = mallocz((npoint+close)*sizeof(Point), 0);
+	if(i->drawpt == nil){
+		e = TkNomem;
+		goto Error;
+	}
+
+	d = i->drawpt;
+	p = i->parampt;
+	for(n = 0; n < npoint; n++) {
+		d->x = TKF2I(p->x);
+		d->y = TKF2I(p->y);
+		if(d->x < i->bb.min.x)
+			i->bb.min.x = d->x;
+		if(d->x > i->bb.max.x)
+			i->bb.max.x = d->x;
+		if(d->y < i->bb.min.y)
+			i->bb.min.y = d->y;
+		if(d->y > i->bb.max.y)
+			i->bb.max.y = d->y;
+		d++;
+		p++;
+	}
+	if (close)
+		*d = i->drawpt[0];			
+
+	i->npoint = npoint;
+	return nil;
+
+Error:
+	tkfreepoint(i);
+	i->parampt = nil;
+	i->drawpt = nil;
+	return e;
+}
+
+TkCitem*
+tkcnewitem(Tk *tk, int t, int n)
+{
+	TkCitem *i;
+
+	i = malloc(n);
+	if(i == nil)
+		return nil;
+	memset(i, 0, n);
+
+	i->type = t;
+	i->env = tk->env;
+	i->env->ref++;
+
+	return i;
+}
+
+/*
+ * expand the canvas's dirty rectangle, clipping
+ * appropriately to its boundaries.
+ */
+void
+tkcvssetdirty(Tk *tk)
+{
+	TkCanvas *c;
+	Rectangle r;
+	c = TKobj(TkCanvas, tk);
+
+	r = tkrect(tk, 0);
+	if (rectclip(&r, rectsubpt(c->update, c->view)))
+		combinerect(&tk->dirty, r);
+}
+
+void
+tkxlatepts(Point *p, int npoints, int x, int y)
+{
+	while(npoints--) {
+		p->x += x;
+		p->y += y;
+		p++;
+	}
+}
+
+void
+tkbbmax(Rectangle *bb, Rectangle *r)
+{
+	if(r->min.x < bb->min.x)
+		bb->min.x = r->min.x;
+	if(r->min.y < bb->min.y)
+		bb->min.y = r->min.y;
+	if(r->max.x > bb->max.x)
+		bb->max.x = r->max.x;
+	if(r->max.y > bb->max.y)
+		bb->max.y = r->max.y;
+}
+
+void
+tkpolybound(Point *p, int n, Rectangle *r)
+{
+	while(n--) {
+		if(p->x < r->min.x)
+			r->min.x = p->x;
+		if(p->y < r->min.y)
+			r->min.y = p->y;
+		if(p->x > r->max.x)
+			r->max.x = p->x;
+		if(p->y > r->max.y)
+			r->max.y = p->y;
+		p++;
+	}
+}
+
+/*
+ * look up a tag for a canvas item.
+ * if n is non-nil, and the tag isn't found,
+ * then add it to the canvas's taglist.
+ * NB if there are no binds done on the
+ * canvas, these tags never get cleared out,
+ * even if nothing refers to them.
+ */
+TkName*
+tkctaglook(Tk* tk, TkName *n, char *name)
+{
+	ulong h;
+	TkCanvas *c;
+	char *p, *s;
+	TkName *f, **l;
+
+	c = TKobj(TkCanvas, tk);
+
+	s = name;
+	if(s == nil)
+		s = n->name;
+
+	if(strcmp(s, "current") == 0)
+		return c->current;
+
+	h = 0;
+	for(p = s; *p; p++)
+		h += 3*h + *p;
+
+	l = &c->thash[h%TkChash];
+	for(f = *l; f; f = f->link)
+		if(strcmp(f->name, s) == 0)
+			return f;
+
+	if(n == nil)
+		return nil;
+	n->link = *l;
+	*l = n;
+	return n;
+}
+
+char*
+tkcaddtag(Tk *tk, TkCitem *i, int new)
+{
+	TkCtag *t;
+	TkCanvas *c;
+	char buf[16];
+	TkName *n, *f, *link;
+
+	c = TKobj(TkCanvas, tk);
+	if(new != 0) {
+		i->id = ++c->id;
+		snprint(buf, sizeof(buf), "%d", i->id);
+		n = tkmkname(buf);
+		if(n == nil)
+			return TkNomem;
+		n->link = i->tags;
+		i->tags = n;
+	}
+
+	for(n = i->tags; n; n = link) {
+		link = n->link;
+		f = tkctaglook(tk, n, nil);
+		if(n != f)
+			free(n);
+
+		for(t = i->stag; t; t = t->itemlist)
+			if(t->name == f)
+				break;
+		if(t == nil) {
+			t = malloc(sizeof(TkCtag));
+			if(t == nil) {
+				tkfreename(link);
+				return TkNomem;
+			}
+			t->name = f;
+			t->taglist = f->obj;		/* add to head of items with this tag */
+			f->obj = t;
+			t->item = i;
+			t->itemlist = i->stag;	/* add to head of tags for this item */
+			i->stag = t;
+		}
+	}
+	i->tags = nil;
+
+	if(new != 0) {
+		i->tags = tkmkname("all");
+		if(i->tags == nil)
+			return TkNomem;		/* XXX - Tad: memory leak? */
+		return tkcaddtag(tk, i, 0);
+	}
+
+	return nil;
+}
+
+void
+tkfreepoint(TkCpoints *p)
+{
+	free(p->drawpt);
+	free(p->parampt);
+}
+
+/*
+ * of all the items in ilist tagged with tag,
+ * return that tag for the first (topmost) item.
+ */
+TkCtag*
+tkclasttag(TkCitem *ilist, TkCtag* tag)
+{
+	TkCtag *last, *t;
+
+	if (tag == nil || tag->taglist == nil)
+		return tag;
+	last = nil;
+	while(ilist) {
+		for(t = tag; t; t = t->taglist) {
+			if(t->item == ilist) {
+				last = t;
+				break;
+			}
+		}
+		ilist = ilist->next;
+	}
+	return last;
+}
+
+/*
+ * of all the items in ilist tagged with tag,
+ * return that tag for the first (bottommost) item.
+ */
+TkCtag*
+tkcfirsttag(TkCitem *ilist, TkCtag* tag)
+{
+	TkCtag *t;
+
+	if (tag == nil || tag->taglist == nil)
+		return tag;
+	for (; ilist != nil; ilist = ilist->next)
+		for(t = tag; t; t = t->taglist)
+			if(t->item == ilist)
+				return t;
+	return nil;
+}
+		
+void
+tkmkpen(Image **pen, TkEnv *e, Image *stipple)
+{
+	int locked;
+	Display *d;
+	Image *new, *fill;
+
+	fill = tkgc(e, TkCfill);
+
+	d = e->top->display;
+	locked = lockdisplay(d);
+	if(*pen != nil) {
+		freeimage(*pen);
+		*pen = nil;
+	}
+	if(stipple == nil) {
+		if(locked)
+			unlockdisplay(d);
+		return;
+	}
+
+	if(fill == nil)
+		fill = d->black;
+	new = allocimage(d, stipple->r, RGBA32, 1, DTransparent);	/* XXX RGBA32 is excessive sometimes... */
+	if (new != nil)
+		draw(new, stipple->r, fill, stipple, ZP);
+	else
+		new = fill;
+	if(locked)
+		unlockdisplay(d);
+	*pen = new;
+}
+
+Point
+tkcvsanchor(Point dp, int w, int h, int anchor)
+{
+	Point o;
+
+	if(anchor & Tknorth)
+		o.y = dp.y;
+	else if(anchor & Tksouth)
+		o.y = dp.y - h;
+	else
+		o.y = dp.y - h/2;
+
+	if(anchor & Tkwest)
+		o.x = dp.x;
+	else if(anchor & Tkeast)
+		o.x = dp.x - w;
+	else
+		o.x = dp.x - w/2;
+
+	return o;
+}
+
+static TkCitem*
+tkcvsmousefocus(TkCanvas *c, Point p)
+{
+	TkCitem *i, *s;
+	int (*hit)(TkCitem*, Point);
+
+	if (c->grab != nil)
+		return c->grab;
+	s = nil;
+	for(i = c->head; i; i = i->next)
+		if(ptinrect(p, i->p.bb)) {
+			if ((hit = tkcimethod[i->type].hit) != nil && !(*hit)(i, p))
+				continue;
+			s = i;
+		}
+
+	return s;
+}
+
+Tk*
+tkcvsinwindow(Tk *tk, Point *p)
+{
+	TkCanvas *c;
+	TkCitem *i;
+	Point q;
+	TkCwind *w;
+
+	c = TKobj(TkCanvas, tk);
+
+	q = addpt(*p, c->view);
+	i = tkcvsmousefocus(c, addpt(*p, c->view));
+	if (i == nil || i->type != TkCVwindow)
+		return tk;
+	w = TKobj(TkCwind, i);
+	if (w->sub == nil)
+		return tk;
+	p->x = q.x - (i->p.bb.min.x + w->sub->borderwidth);
+	p->y = q.y - (i->p.bb.min.y + w->sub->borderwidth);
+	return w->sub;
+}
+
+static Tk*
+tkcvsmouseinsub(TkCwind *w, TkMouse m)
+{
+	Point g, mp;
+	int bd;
+
+	g = tkposn(w->sub);
+	bd = w->sub->borderwidth;
+	mp.x = m.x - (g.x + bd);
+	mp.y = m.y - (g.y + bd);
+	return tkinwindow(w->sub, mp, 0);
+}
+
+static Tk*
+tkcvsdeliver(Tk *tk, TkCitem *i, int event, void *data)
+{
+	Tk *ftk, *dest;
+	TkCtag *t;
+	TkCwind *w;
+	TkAction *a;
+
+	if(i->type == TkCVwindow) {
+		dest = nil;
+		w = TKobj(TkCwind, i);
+		if(w->sub == nil)
+			return nil;
+
+		if(!(event & TkKey) && (event & TkEmouse)) {
+			ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
+			if(ftk != w->focus) {
+				tkdeliver(w->focus, TkLeave, data);
+if(0)print("focus %p %q %p %q\n", w->sub, tkname(w->sub), ftk, tkname(ftk));
+				tkdeliver(ftk, TkEnter, data);
+				w->focus = ftk;
+			}
+			if(ftk != nil)
+				dest = tkdeliver(ftk, event, data);
+		} else {
+			if(event & TkLeave) {
+				tkdeliver(w->focus, TkLeave, data);
+				w->focus = nil;
+			} else if(event & TkEnter) {
+				ftk = tkcvsmouseinsub(w, *(TkMouse*)data);
+				tkdeliver(ftk, TkEnter, data);
+				w->focus = ftk;
+			} else
+				dest = tkdeliver(w->sub, event, data);
+		}
+		return dest;
+	}
+
+	for(t = i->stag; t != nil; t = t->itemlist) {
+		a = t->name->prop.binds;
+		if(a != nil)
+			tksubdeliver(tk, a, event, data, 0);
+	}
+	return nil;
+}
+
+Tk*
+tkcvsevent(Tk *tk, int event, void *data)
+{
+	TkMouse m;
+	TkCitem *f;
+	Point mp, g;
+	TkCanvas *c;
+	Tk *dest;
+
+	c = TKobj(TkCanvas, tk);
+
+	if(event == TkLeave && c->mouse != nil) {
+		tkcvsdeliver(tk, c->mouse, TkLeave, data);
+		c->mouse = nil;
+	}
+
+	dest = nil;
+	if(!(event & TkKey) && (event & TkEmouse) || (event & TkEnter)) {
+		m = *(TkMouse*)data;
+		g = tkposn(tk);
+		mp.x = (m.x - g.x - tk->borderwidth) + c->view.x;
+		mp.y = (m.y - g.y - tk->borderwidth) + c->view.y;
+		f = tkcvsmousefocus(c, mp);
+		if(c->mouse != f) {
+			if(c->mouse != nil) {
+				tkcvsdeliver(tk, c->mouse, TkLeave, data);
+				c->current->obj = nil;
+			}
+			if(f != nil) {
+				c->current->obj = &c->curtag;
+				c->curtag.item = f;
+				tkcvsdeliver(tk, f, TkEnter, data);
+			}
+			c->mouse = f;
+		}
+		f = c->mouse;
+		if(f != nil && (event & TkEnter) == 0)
+			dest = tkcvsdeliver(tk, f, event, &m);
+	}
+
+	if(event & TkKey) {
+		f = c->focus;
+		if(f != nil)
+			tkcvsdeliver(tk, f, event, data);
+	}
+	if(dest == nil)
+		tksubdeliver(tk, tk->binds, event, data, 0);
+	return dest;
+}
+
+/*
+ * debugging
+ */
+void
+tkcvsdump(Tk *tk)
+{
+	TkCanvas *c;
+	TkCitem *it;
+	TkCwind *w;
+	char v1[Tkminitem], v2[Tkminitem];
+	int i;
+
+	if(tk == nil)
+		return;
+	c = TKobj(TkCanvas, tk);
+	tkfprint(v1, c->width);
+	tkfprint(v2, c->height);
+	print("%q configure -width %s -height %s", tkname(tk), v1, v2);
+	print(" # focus %#p mouse %#p grab %#p\n", c->focus, c->mouse, c->grab);
+	for(it = c->head; it != nil; it = it->next){
+		print("%q create %q", tkname(tk), tkcimethod[it->type].name);
+		for(i = 0; i < it->p.npoint; i++){
+			tkfprint(v1, it->p.parampt[i].x);
+			tkfprint(v2, it->p.parampt[i].y);
+			print(" %s %s", v1, v2);
+		}
+		if(it->type == TkCVwindow){
+			w = TKobj(TkCwind, it);
+			if(w->sub != nil)
+				print(" -window %q", tkname(w->sub));
+			print(" # item %#p id %d sub %#p focus [%#p %q]\n", it, it->id, w->sub, w->focus, tkname(w->focus));
+		}else
+			print("# item %#p id %d\n", it, it->id);
+	}
+}
--- /dev/null
+++ b/libtk/carcs.c
@@ -1,0 +1,280 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+typedef void	(*Drawfn)(Image*, Point, int, int, Image*, int);
+
+/* Arc Options (+ means implemented)
+	+extent
+	+fill
+	+outline
+	 outlinestipple
+	+start 
+	+stipple
+	+style (+pieslice chord +arc)
+	+tags
+	+width
+*/
+
+typedef struct TkCarc TkCarc;
+struct TkCarc
+{
+	int	width;
+	int 	start;
+	int 	extent;
+	int 	style;
+	Image*	stipple;
+	Image*	pen;
+};
+
+enum Style
+{
+	Pieslice,
+	Chord,
+	Arc
+};
+
+static 
+TkStab tkstyle[] =
+{
+	"pieslice",	Pieslice,
+	"arc",		Arc,
+	"chord",	Arc,	/* Can't do chords */
+	nil
+};
+
+static
+TkOption arcopts[] =
+{
+	"start",	OPTfrac,	O(TkCarc, start),	nil,
+	"extent",	OPTfrac,	O(TkCarc, extent),	nil,
+	"style",	OPTstab,	O(TkCarc, style),	tkstyle,
+	"width",	OPTnnfrac,	O(TkCarc, width),	nil,
+	"stipple",	OPTbmap,	O(TkCarc, stipple),	nil,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCfill),
+	"outline",	OPTcolr,	O(TkCitem, env),	IAUX(TkCforegnd),
+	nil
+};
+
+void
+tkcvsarcsize(TkCitem *i)
+{
+	int w;
+	TkCarc *a;
+
+	a = TKobj(TkCarc, i);
+	w = TKF2I(a->width)*2;
+
+	i->p.bb = bbnil;
+	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+	i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvsarccreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCarc *a;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVarc, sizeof(TkCitem)+sizeof(TkCarc));
+	if(i == nil)
+		return TkNomem;
+
+	a = TKobj(TkCarc, i);
+	a->width = TKI2F(1);
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	if(i->p.npoint != 2) {
+		tkcvsfreeitem(i);
+		return TkFewpt;
+	}
+
+	tko[0].ptr = a;
+	tko[0].optab = arcopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsarcsize(i);
+	tkmkpen(&a->pen, i->env, a->stipple);
+
+	tkcvsappend(c, i);
+
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return tkvalue(val, "%d", i->id);
+}
+
+char*
+tkcvsarccget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCarc *a = TKobj(TkCarc, i);
+
+	tko[0].ptr = a;
+	tko[0].optab = arcopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsarcconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCarc *a = TKobj(TkCarc, i);
+
+	tko[0].ptr = a;
+	tko[0].optab = arcopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tkcvsarcsize(i);
+	tkmkpen(&a->pen, i->env, a->stipple);
+
+	return e;
+}
+
+
+void
+tkcvsarcfree(TkCitem *i)
+{
+	TkCarc *a;
+
+	a = TKobj(TkCarc, i);
+	if(a->stipple)
+		freeimage(a->stipple);
+	if(a->pen)
+		freeimage(a->pen);
+}
+
+void
+tkcvsarcdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	TkEnv *e;
+	TkCarc *a;
+	Rectangle d;
+	int w, dx, dy;
+	int s, ext, s0, s1, e0, e1, l;
+	Image *pen, *col, *tmp;
+	Point p0, p1, c;
+	extern void drawarc(Point,int,int,int,int,int,Image *,Image *,Image *);
+
+	USED(pe);
+
+	d.min = i->p.drawpt[0];
+	d.max = i->p.drawpt[1];
+
+	e = i->env;
+	a = TKobj(TkCarc, i);
+
+	pen = a->pen;
+	if(pen == nil && (e->set & (1<<TkCfill)))
+		pen = tkgc(e, TkCfill);
+
+	w = TKF2I(a->width)/2;
+	if(w < 0)
+		return;
+
+	d = canonrect(d);
+	dx = Dx(d)/2;
+	dy = Dy(d)/2;
+	c.x = (d.min.x+d.max.x)/2;
+	c.y = (d.min.y+d.max.y)/2;
+	s = TKF2I(a->start);
+	ext = TKF2I(a->extent);
+/*
+	if(ext == 0)
+		ext = 90;
+*/
+
+	if(a->style != Arc && pen != nil)
+		fillarc(img, c, dx, dy, pen, Pt(0,0), s, ext);
+	col = tkgc(e, TkCforegnd);
+	arc(img, c, dx, dy, w, col, Pt(0,0), s, ext);
+	if(a->style == Pieslice){
+		/*
+		 * It is difficult to compute the intersection of the lines
+		 * and the ellipse using integers, so let the draw library
+		 * do it for us: use a full ellipse as the source of color
+		 * for drawing the lines.
+		 */
+		tmp = allocimage(img->display, d, img->chan, 0, DNofill);
+		if(tmp == nil)
+			return;
+		/* copy dest to tmp so lines don't spill beyond edge of ellipse */
+		drawop(tmp, d, img, nil, d.min, S);
+		fillellipse(tmp, c, dx, dy, col, Pt(0,0));
+		icossin(s, &s1, &s0);
+		icossin(s+ext, &e1, &e0);
+		if(dx > dy)
+			l = 2*dx+1;
+		else
+			l = 2*dy+1;
+		p0 = Pt(c.x+l*s1/ICOSSCALE, c.y-l*s0/ICOSSCALE);
+		p1 = Pt(c.x+l*e1/ICOSSCALE, c.y-l*e0/ICOSSCALE);
+		line(img, c, p0, Endsquare, Endsquare, w, tmp, c);
+		line(img, c, p1, Endsquare, Endsquare, w, tmp, c);
+		freeimage(tmp);
+	}
+}
+
+char*
+tkcvsarccoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint != 2) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvsarcsize(i);
+	}
+	return nil;
+}
--- /dev/null
+++ b/libtk/cbits.c
@@ -1,0 +1,211 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Bitmap Options (+ means implemented)
+	+anchor
+	+bitmap
+*/
+
+typedef struct TkCbits TkCbits;
+struct TkCbits
+{
+	int	anchor;
+	Point	anchorp;
+	Image*	bitmap;
+};
+
+static
+TkOption bitopts[] =
+{
+	"anchor",	OPTstab,	O(TkCbits, anchor),	tkanchor,
+	"bitmap",	OPTbmap,	O(TkCbits, bitmap),	nil,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	"background",	OPTcolr,	O(TkCitem, env),	IAUX(TkCbackgnd),
+	"foreground",	OPTcolr,	O(TkCitem, env),	IAUX(TkCforegnd),
+	nil
+};
+
+void
+tkcvsbitsize(TkCitem *i)
+{
+	Point o;
+	int dx, dy;
+	TkCbits *b;
+
+	b = TKobj(TkCbits, i);
+	i->p.bb = bbnil;
+	if(b->bitmap == nil)
+		return;
+
+	dx = Dx(b->bitmap->r);
+	dy = Dy(b->bitmap->r);
+
+	o = tkcvsanchor(i->p.drawpt[0], dx, dy, b->anchor);
+
+	i->p.bb.min.x = o.x;
+	i->p.bb.min.y = o.y;
+	i->p.bb.max.x = o.x + dx;
+	i->p.bb.max.y = o.y + dy;
+	b->anchorp = subpt(o, i->p.drawpt[0]);
+}
+
+char*
+tkcvsbitcreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCbits *b;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVbitmap, sizeof(TkCitem)+sizeof(TkCbits));
+	if(i == nil)
+		return TkNomem;
+
+	b = TKobj(TkCbits, i);
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	if(i->p.npoint != 1) {
+		tkcvsfreeitem(i);
+		return TkFewpt;
+	}
+
+	tko[0].ptr = b;
+	tko[0].optab = bitopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsbitsize(i);
+	tkcvsappend(c, i);
+
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return tkvalue(val, "%d", i->id);
+}
+
+char*
+tkcvsbitcget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCbits *b = TKobj(TkCbits, i);
+
+	tko[0].ptr = b;
+	tko[0].optab = bitopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsbitconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCbits *b = TKobj(TkCbits, i);
+
+	tko[0].ptr = b;
+	tko[0].optab = bitopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tkcvsbitsize(i);
+	return e;
+}
+
+void
+tkcvsbitfree(TkCitem *i)
+{
+	TkCbits *b;
+
+	b = TKobj(TkCbits, i);
+	if(b->bitmap)
+		freeimage(b->bitmap);
+}
+
+void
+tkcvsbitdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	TkEnv *e;
+	TkCbits *b;
+	Rectangle r;
+	Image *bi;
+
+	USED(pe);
+
+	e = i->env;
+	b = TKobj(TkCbits, i);
+
+	bi = b->bitmap;
+	if(bi == nil)
+		return;
+
+	r.min = addpt(b->anchorp, i->p.drawpt[0]);
+	r.max = r.min;
+	r.max.x += Dx(bi->r);
+	r.max.y += Dy(bi->r);
+
+	if(bi->depth != 1) {
+		draw(img, r, bi, nil, ZP);
+		return;
+	}
+	gendraw(img, r, tkgc(e, TkCbackgnd), r.min, nil, ZP);
+	draw(img, r, tkgc(e, TkCforegnd), bi, ZP);
+}
+
+char*
+tkcvsbitcoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint != 1) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvsbitsize(i);
+	}
+	return nil;
+}
--- /dev/null
+++ b/libtk/cimag.c
@@ -1,0 +1,211 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Image Options (+ means implemented)
+	+anchor
+	+image
+*/
+
+typedef struct TkCimag TkCimag;
+struct TkCimag
+{
+	int	anchor;
+	Point	anchorp;
+	TkImg*	tki;
+};
+
+static
+TkOption imgopts[] =
+{
+	"anchor",	OPTstab,	O(TkCimag, anchor),	tkanchor,
+	"image",	OPTimag,	O(TkCimag, tki),	nil,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	nil
+};
+
+void
+tkcvsimgsize(TkCitem *i)
+{
+	Point o;
+	int dx, dy;
+	TkCimag *t;
+
+	t = TKobj(TkCimag, i);
+	i->p.bb = bbnil;
+	if(t->tki == nil)
+		return;
+
+	dx = t->tki->w;
+	dy = t->tki->h;
+
+	o = tkcvsanchor(i->p.drawpt[0], dx, dy, t->anchor);
+
+	i->p.bb.min.x = o.x;
+	i->p.bb.min.y = o.y;
+	i->p.bb.max.x = o.x + dx;
+	i->p.bb.max.y = o.y + dy;
+	t->anchorp = subpt(o, i->p.drawpt[0]);
+}
+
+char*
+tkcvsimgcreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCimag *t;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVimage, sizeof(TkCitem)+sizeof(TkCimag));
+	if(i == nil)
+		return TkNomem;
+
+	t = TKobj(TkCimag, i);
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	if(i->p.npoint != 1) {
+		tkcvsfreeitem(i);
+		return TkFewpt;
+	}
+
+	tko[0].ptr = t;
+	tko[0].optab = imgopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsimgsize(i);
+
+	e = tkvalue(val, "%d", i->id);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsappend(c, i);
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvsimgcget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCimag *t = TKobj(TkCimag, i);
+
+	tko[0].ptr = t;
+	tko[0].optab = imgopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsimgconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCimag *t = TKobj(TkCimag, i);
+
+	tko[0].ptr = t;
+	tko[0].optab = imgopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tkcvsimgsize(i);
+	return e;
+}
+
+void
+tkcvsimgfree(TkCitem *i)
+{
+	TkCimag *t;
+
+	t = TKobj(TkCimag, i);
+	if(t->tki)
+		tkimgput(t->tki);
+}
+
+void
+tkcvsimgdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	TkCimag *t;
+	TkImg *tki;
+	Rectangle r;
+	Image *fg;
+
+	USED(pe);
+
+	t = TKobj(TkCimag, i);
+	tki = t->tki;
+	if(tki == nil)
+		return;
+	fg = tki->img;
+	if(fg == nil)
+		return;
+
+	r.min = addpt(t->anchorp, i->p.drawpt[0]);
+	r.max = r.min;
+	r.max.x += tki->w;
+	r.max.y += tki->h;
+
+	draw(img, r, fg, nil, ZP);
+}
+
+char*
+tkcvsimgcoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint != 1) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvsimgsize(i);
+	}
+	return nil;
+}
--- /dev/null
+++ b/libtk/cline.c
@@ -1,0 +1,268 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Line Options (+ means implemented)
+	+arrow
+	+arrowshape
+	+capstyle
+	+fill
+	 joinstyle
+	+smooth
+	+splinesteps
+	+stipple
+	+tags
+	+width
+*/
+
+static
+TkStab tklines[] =
+{
+	"none",		0,
+	"first",	TkCarrowf,
+	"last",		TkCarrowl,
+	"both",		TkCarrowf|TkCarrowl,
+	nil
+};
+
+static
+TkStab tkcapstyle[] =
+{
+	"butt",	Endsquare,
+	"projecting",	Endsquare,
+	"round",	Enddisc,
+	nil
+};
+
+static
+TkOption lineopts[] =
+{
+	"arrow",	OPTstab,	O(TkCline, arrow),	tklines,
+	"arrowshape",	OPTfrac,	O(TkCline, shape[0]),	IAUX(3),
+	"width",	OPTnnfrac,	O(TkCline, width),	nil,
+	"stipple",	OPTbmap,	O(TkCline, stipple),	nil,
+	"smooth",	OPTstab,	O(TkCline, smooth),	tkbool,
+	"splinesteps",	OPTdist,	O(TkCline, steps),	nil,
+	"capstyle",	OPTstab,	O(TkCline, capstyle),	tkcapstyle,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCforegnd),
+	nil
+};
+
+void
+tkcvslinesize(TkCitem *i)
+{
+	TkCline *l;
+	int j, w, as, shape[3], arrow;
+
+	l = TKobj(TkCline, i);
+	w = TKF2I(l->width);
+
+	i->p.bb = bbnil;
+	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+
+	l->arrowf = l->capstyle;
+	l->arrowl = l->capstyle;
+	if(l->arrow != 0) {
+		as = w/3;
+		if(as < 1)
+			as = 1;
+		for(j = 0; j < 3; j++) {
+			shape[j] = l->shape[j];
+			if(shape[j] == 0)
+				shape[j] = as * cvslshape[j];
+		}
+		arrow = ARROW(TKF2I(shape[0]), TKF2I(shape[1]), TKF2I(shape[2]));
+		if(l->arrow & TkCarrowf)
+			l->arrowf = arrow;
+		if(l->arrow & TkCarrowl)
+			l->arrowl = arrow;
+		w += shape[2];
+	}
+
+	i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvslinecreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCline *l;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVline, sizeof(TkCitem)+sizeof(TkCline));
+	if(i == nil)
+		return TkNomem;
+
+	l = TKobj(TkCline, i);
+	l->width = TKI2F(1);
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tko[0].ptr = l;
+	tko[0].optab = lineopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	tkmkpen(&l->pen, i->env, l->stipple);
+
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvslinesize(i);
+	e = tkvalue(val, "%d", i->id);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	tkcvsappend(c, i);
+
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvslinecget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCline *l = TKobj(TkCline, i);
+
+	tko[0].ptr = l;
+	tko[0].optab = lineopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvslineconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCline *l = TKobj(TkCline, i);
+
+	tko[0].ptr = l;
+	tko[0].optab = lineopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+
+	tkmkpen(&l->pen, i->env, l->stipple);
+	tkcvslinesize(i);
+
+	return e;
+}
+
+void
+tkcvslinefree(TkCitem *i)
+{
+	TkCline *l;
+
+	l = TKobj(TkCline, i);
+	if(l->stipple)
+		freeimage(l->stipple);
+	if(l->pen)
+		freeimage(l->pen);
+}
+
+void
+tkcvslinedraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	int w;
+	Point *p;
+	TkCline *l;
+	Image *pen;
+
+	USED(pe);
+
+	l = TKobj(TkCline, i);
+
+	pen = l->pen;
+	if(pen == nil)
+		pen = tkgc(i->env, TkCforegnd);
+
+	w = TKF2I(l->width)/2;
+	if(w < 0)
+		return;
+
+	p = i->p.drawpt;
+	if(l->smooth == BoolT && i->p.npoint >= 3)
+		bezspline(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
+	else
+		poly(img, p, i->p.npoint, l->arrowf, l->arrowl, w, pen, p[0]);
+}
+
+char*
+tkcvslinecoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint < 2) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvslinesize(i);
+	}
+	return nil;
+}
+
+int
+tkcvslinehit(TkCitem *i, Point p)
+{
+	TkCline *l;
+	int w, np, r;
+	Point *pp;
+
+	l = TKobj(TkCline, i);
+	w =TKF2I(l->width) + 2;	/* 2 for slop */
+
+	if (l->smooth == BoolT) {
+		np = getbezsplinepts(i->p.drawpt, i->p.npoint, &pp);
+		r = tklinehit(pp, np, w, p);
+		free(pp);
+	} else
+		r = tklinehit(i->p.drawpt, i->p.npoint, w, p);
+	return r;
+}
--- /dev/null
+++ b/libtk/colrs.c
@@ -1,0 +1,93 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define RGB(R,G,B) ((R<<24)|(G<<16)|(B<<8)|(0xff))
+
+enum
+{
+	tkBackR		= 0xdd,		/* Background base color */
+	tkBackG 	= 0xdd,
+	tkBackB 	= 0xdd,
+
+	tkSelectR	= 0xb0,		/* Check box selected color */
+	tkSelectG	= 0x30,
+	tkSelectB	= 0x60,
+
+	tkSelectbgndR	= 0x40,		/* Selected item background */
+	tkSelectbgndG	= 0x40,
+	tkSelectbgndB	= 0x40
+};
+
+typedef struct Coltab Coltab;
+struct Coltab {
+	int	c;
+	ulong rgba;
+	int shade;
+};
+
+static Coltab coltab[] =
+{
+	TkCbackgnd,
+		RGB(tkBackR, tkBackG, tkBackB),
+		TkSameshade,
+	TkCbackgndlght,
+		RGB(tkBackR, tkBackG, tkBackB),
+		TkLightshade,
+	TkCbackgnddark,
+		RGB(tkBackR, tkBackG, tkBackB),
+		TkDarkshade,
+	TkCactivebgnd,
+		RGB(tkBackR+0x10, tkBackG+0x10, tkBackB+0x10),
+		TkSameshade,
+	TkCactivebgndlght,
+		RGB(tkBackR+0x10, tkBackG+0x10, tkBackB+0x10),
+		TkLightshade,
+	TkCactivebgnddark,
+		RGB(tkBackR+0x10, tkBackG+0x10, tkBackB+0x10),
+		TkDarkshade,
+	TkCactivefgnd,
+		RGB(0, 0, 0),
+		TkSameshade,
+	TkCforegnd,
+		RGB(0, 0, 0),
+		TkSameshade,
+	TkCselect,
+		RGB(tkSelectR, tkSelectG, tkSelectB),
+		TkSameshade,
+	TkCselectbgnd,
+		RGB(tkSelectbgndR, tkSelectbgndG, tkSelectbgndB),
+		TkSameshade,
+	TkCselectbgndlght,
+		RGB(tkSelectbgndR, tkSelectbgndG, tkSelectbgndB),
+		TkLightshade,
+	TkCselectbgnddark,
+		RGB(tkSelectbgndR, tkSelectbgndG, tkSelectbgndB),
+		TkDarkshade,
+	TkCselectfgnd,
+		RGB(0xff, 0xff, 0xff),
+		TkSameshade,
+	TkCdisablefgnd,
+		RGB(0x88, 0x88, 0x88),
+		TkSameshade,
+	TkChighlightfgnd,
+		RGB(0, 0, 0),
+		TkSameshade,
+	TkCtransparent,
+		DTransparent,
+		TkSameshade,
+	-1,
+};
+
+void
+tksetenvcolours(TkEnv *env)
+{
+	Coltab *c;
+
+	c = &coltab[0];
+	while(c->c != -1) {
+		env->colors[c->c] = tkrgbashade(c->rgba, c->shade);
+		env->set |= (1<<c->c);
+		c++;
+	}
+}
--- /dev/null
+++ b/libtk/coval.c
@@ -1,0 +1,251 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+typedef void	(*Drawfn)(Image*, Point, int, int, Image*, int);
+
+/* Oval Options (+ means implemented)
+	+fill
+	+outline
+	+stipple
+	+tags
+	+width
+*/
+
+typedef struct TkCoval TkCoval;
+struct TkCoval
+{
+	int	width;
+	Image*	stipple;
+	Image*	pen;
+	TkCanvas*	canv;
+};
+
+static
+TkOption ovalopts[] =
+{
+	"width",	OPTnnfrac,	O(TkCoval, width),	nil,			/* XXX should be nnfrac */
+	"stipple",	OPTbmap,	O(TkCoval, stipple),	nil,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCfill),
+	"outline",	OPTcolr,	O(TkCitem, env),	IAUX(TkCforegnd),
+	nil
+};
+
+void
+tkcvsovalsize(TkCitem *i)
+{
+	int w;
+	TkCoval *o;
+
+	o = TKobj(TkCoval, i);
+	w = TKF2I(o->width)*2;
+
+	i->p.bb = bbnil;
+	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+	i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvsovalcreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCoval *o;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVoval, sizeof(TkCitem)+sizeof(TkCoval));
+	if(i == nil)
+		return TkNomem;
+
+	o = TKobj(TkCoval, i);
+	o->width = TKI2F(1);
+	o->canv = c;
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	if(i->p.npoint != 2) {
+		tkcvsfreeitem(i);
+		return TkFewpt;
+	}
+
+	tko[0].ptr = o;
+	tko[0].optab = ovalopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsovalsize(i);
+
+	e = tkvalue(val, "%d", i->id);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsappend(c, i);
+	tkbbmax(&c->update, &i->p.bb);
+	tkmkpen(&o->pen, i->env, o->stipple);
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvsovalcget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCoval *o = TKobj(TkCoval, i);
+
+	tko[0].ptr = o;
+	tko[0].optab = ovalopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsovalconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCoval *o = TKobj(TkCoval, i);
+
+	tko[0].ptr = o;
+	tko[0].optab = ovalopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tkcvsovalsize(i);
+	tkmkpen(&o->pen, i->env, o->stipple);
+
+	return e;
+}
+
+void
+tkcvsovalfree(TkCitem *i)
+{
+	TkCoval *o;
+
+	o = TKobj(TkCoval, i);
+	if(o->stipple)
+		freeimage(o->stipple);
+	if(o->pen)
+		freeimage(o->pen);
+}
+
+void
+tkcvsovaldraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	Point c;
+	TkEnv *e;
+	Image *pen;
+	TkCoval *o;
+	Rectangle d;
+	int w, dx, dy;
+
+	USED(pe);
+
+	d.min = i->p.drawpt[0];
+	d.max = i->p.drawpt[1];
+
+	e = i->env;
+	o = TKobj(TkCoval, i);
+
+	pen = o->pen;
+	if(pen == nil && (e->set & (1<<TkCfill)))
+		pen = tkgc(e, TkCfill);
+
+	w = TKF2I(o->width)/2;
+	if(w < 0)
+		return;
+
+	d = canonrect(d);
+	dx = Dx(d)/2;
+	dy = Dy(d)/2;
+	c.x = d.min.x + dx;
+	c.y = d.min.y + dy;
+	if(pen != nil)
+		fillellipse(img, c, dx, dy, pen, c);
+	ellipse(img, c, dx, dy, w, tkgc(e, TkCforegnd), c);
+}
+
+char*
+tkcvsovalcoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint != 2) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvsovalsize(i);
+	}
+	return nil;
+}
+
+int
+tkcvsovalhit(TkCitem *i, Point p)
+{
+	TkCoval *o;
+	int w, dx, dy;
+	Rectangle d;
+	vlong v;
+	
+	o = TKobj(TkCoval, i);
+	w = TKF2I(o->width)/2;
+	d = canonrect(Rpt(i->p.drawpt[0], i->p.drawpt[1]));
+	d = insetrect(d, -(w/2 + 1));
+
+	dx = Dx(d)/2;
+	dy = Dy(d)/2;
+
+	p.x -= d.min.x + dx;
+	p.y -= d.min.y + dy;
+
+	dx *= dx;
+	dy *= dy;
+
+	/* XXX can we do this nicely without overflow and without vlongs? */
+	v = (vlong)(p.x*p.x)*dy;
+	v += (vlong)(p.y*p.y)*dx;
+	return v < (vlong)dx*dy;
+}
--- /dev/null
+++ b/libtk/cpoly.c
@@ -1,0 +1,270 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+typedef struct TkCpoly TkCpoly;
+struct TkCpoly
+{
+	int		width;
+	Image*		stipple;
+	Image*		pen;
+	TkCanvas*	canv;
+	int		smooth;
+	int		steps;
+	int		winding;
+};
+
+static
+TkStab tkwinding[] =
+{
+	"nonzero",	~0,
+	"odd",		1,
+	nil
+};
+
+/* Polygon Options (+ means implemented)
+	+fill
+	+smooth
+	+splinesteps
+	+stipple
+	+tags
+	+width
+	+outline
+*/
+static
+TkOption polyopts[] =
+{
+	"width",	OPTnnfrac,	O(TkCpoly, width),	nil,
+	"stipple",	OPTbmap,	O(TkCpoly, stipple),	nil,
+	"smooth",	OPTstab,	O(TkCpoly, smooth),	tkbool,
+	"splinesteps",	OPTdist,	O(TkCpoly, steps),	nil,
+	"winding",	OPTstab, O(TkCpoly, winding), tkwinding,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCfill),
+	"outline",	OPTcolr,	O(TkCitem, env),	IAUX(TkCforegnd),
+	nil
+};
+
+void
+tkcvspolysize(TkCitem *i)
+{
+	int w;
+	TkCpoly *p;
+
+	p = TKobj(TkCpoly, i);
+	w = TKF2I(p->width);
+
+	i->p.bb = bbnil;
+	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+	i->p.bb = insetrect(i->p.bb, -w);
+}
+
+char*
+tkcvspolycreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCpoly *p;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVpoly, sizeof(TkCitem)+sizeof(TkCpoly));
+	if(i == nil)
+		return TkNomem;
+
+	p = TKobj(TkCpoly, i);
+	p->width = TKI2F(1);
+	p->winding = ~0;
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 1);
+	if(e == nil && i->p.npoint < 3)
+		e = TkBadvl;
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tko[0].ptr = p;
+	tko[0].optab = polyopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	p->canv = c;
+
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvspolysize(i);
+	tkmkpen(&p->pen, i->env, p->stipple);
+
+	e = tkvalue(val, "%d", i->id);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsappend(c, i);
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvspolycget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCpoly *p = TKobj(TkCpoly, i);
+
+	tko[0].ptr = p;
+	tko[0].optab = polyopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvspolyconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCpoly *p = TKobj(TkCpoly, i);
+
+	tko[0].ptr = p;
+	tko[0].optab = polyopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+
+	tkcvspolysize(i);
+	tkmkpen(&p->pen, i->env, p->stipple);
+
+	return e;
+}
+
+void
+tkcvspolyfree(TkCitem *i)
+{
+	TkCpoly *p;
+
+	p = TKobj(TkCpoly, i);
+	if(p->stipple)
+		freeimage(p->stipple);
+	if(p->pen)
+		freeimage(p->pen);
+}
+
+void
+tkcvspolydraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	int w;
+	TkEnv *e;
+	TkCpoly *p;
+	Image *pen;
+	Point *pts;
+
+	USED(pe);
+
+	p = TKobj(TkCpoly, i);
+
+	e = i->env;
+
+	pen = p->pen;
+	if(pen == nil && (e->set & (1<<TkCfill)))
+		pen = tkgc(e, TkCfill);
+
+	pts = i->p.drawpt;
+	if(i->p.npoint > 0 && pen != nil) {
+		if (p->smooth == BoolT)
+			fillbezspline(img, pts, i->p.npoint+1, p->winding, pen, pts[0]);
+		else
+			fillpoly(img, pts, i->p.npoint+1, p->winding, pen, pts[0]);
+	}
+
+	w = TKF2I(p->width) - 1;
+	if(w >= 0 && (e->set & (1<<TkCforegnd))) {
+		pen = tkgc(i->env, TkCforegnd);
+		if (p->smooth == BoolT)
+			bezspline(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]);
+		else
+			poly(img, pts, i->p.npoint+1, Enddisc, Enddisc, w, pen, pts[0]);
+	}
+}
+
+char*
+tkcvspolycoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.drawpt[i->p.npoint] = i->p.drawpt[0];
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 1);
+		if(e != nil)
+			return e;
+		if(p.npoint < 2) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvspolysize(i);
+	}
+	return nil;
+}
+
+int
+tkcvspolyhit(TkCitem *item, Point p)
+{
+	Point *poly;
+	int r, np, fill, w;
+	TkCpoly *l;
+	TkEnv *e;
+
+	l = TKobj(TkCpoly, item);
+	w = TKF2I(l->width) + 2;		/* include some slop */
+	e = item->env;
+	fill = e->set & (1<<TkCfill);
+	if (l->smooth == BoolT) {
+		/* this works but it's slow if used intensively... */
+		np = getbezsplinepts(item->p.drawpt, item->p.npoint + 1, &poly);
+		if (fill)
+			r = tkinsidepoly(poly, np, l->winding, p);
+		else
+			r = tklinehit(poly, np, w, p);
+		free(poly);
+	} else {
+		if (fill)
+			r = tkinsidepoly(item->p.drawpt, item->p.npoint, l->winding, p);
+		else
+			r = tklinehit(item->p.drawpt, item->p.npoint + 1, w, p);
+	}
+	return r;
+}
--- /dev/null
+++ b/libtk/crect.c
@@ -1,0 +1,252 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Rectangle Options (+ means implemented)
+	+fill
+	+outline
+	+stipple
+	+tags
+	+width
+*/
+
+typedef struct TkCrect TkCrect;
+struct TkCrect
+{
+	int	width;
+	Image*	stipple;
+};
+
+static
+TkOption rectopts[] =
+{
+	"width",	OPTnnfrac,	O(TkCrect, width),	nil,
+	"stipple",	OPTbmap,	O(TkCrect, stipple),	nil,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCfill),
+	"outline",	OPTcolr,	O(TkCitem, env),	IAUX(TkCforegnd),
+	nil
+};
+
+void
+tkcvsrectsize(TkCitem *i)
+{
+	TkCrect *r;
+	int w;
+
+	r = TKobj(TkCrect, i);
+	w = TKF2I(r->width)*2;
+
+	i->p.bb = bbnil;
+	tkpolybound(i->p.drawpt, i->p.npoint, &i->p.bb);
+	i->p.bb = insetrect(i->p.bb, -w);
+}
+
+static void
+tkmkstipple(Image *stipple)
+{
+	int locked;
+	if (stipple != nil && !stipple->repl) {
+		locked = lockdisplay(stipple->display);
+		replclipr(stipple, 1, huger);
+		if (locked)
+			unlockdisplay(stipple->display);
+	}
+}
+
+char*
+tkcvsrectcreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCrect *r;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVrect, sizeof(TkCitem)+sizeof(TkCrect));
+	if(i == nil)
+		return TkNomem;
+
+	r = TKobj(TkCrect, i);
+	r->width = TKI2F(1);
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	if(i->p.npoint != 2) {
+		tkcvsfreeitem(i);
+		return TkFewpt;
+	}
+
+	tko[0].ptr = r;
+	tko[0].optab = rectopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	tkmkstipple(r->stipple);
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsrectsize(i);
+	e = tkvalue(val, "%d", i->id);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	tkcvsappend(c, i);
+
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvsrectcget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCrect *r = TKobj(TkCrect, i);
+
+	tko[0].ptr = r;
+	tko[0].optab = rectopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvsrectconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCrect *r = TKobj(TkCrect, i);
+
+	tko[0].ptr = r;
+	tko[0].optab = rectopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tkcvsrectsize(i);
+	tkmkstipple(r->stipple);
+	return e;
+}
+
+void
+tkcvsrectfree(TkCitem *i)
+{
+	TkCrect *r;
+
+	r = TKobj(TkCrect, i);
+	if(r->stipple)
+		freeimage(r->stipple);
+}
+
+void
+tkcvsrectdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	int lw, rw;
+	TkEnv *e;
+	TkCrect *r;
+	Rectangle d, rr;
+	Point tr, bl;
+	Image *pen;
+
+	USED(pe);
+
+	d.min = i->p.drawpt[0];
+	d.max = i->p.drawpt[1];
+
+	e = i->env;
+	r = TKobj(TkCrect, i);
+
+	pen = nil;
+	if((e->set & (1<<TkCfill)))
+		pen = tkgc(e, TkCfill);
+
+	if(pen != nil)
+		draw(img, d, pen, r->stipple, d.min);
+
+	tr.x = d.max.x;
+	tr.y = d.min.y;
+	bl.x = d.min.x;
+	bl.y = d.max.y;
+
+	rw = (TKF2I(r->width) + 1)/2;
+	if(rw <= 0)
+		return;
+	lw = (TKF2I(r->width))/2;
+
+	pen = tkgc(e, TkCforegnd);
+	if(pen != nil) {
+		/* horizontal lines first */
+		rr.min.x = d.min.x - lw;
+		rr.max.x = d.max.x + rw;
+		rr.min.y = d.min.y - lw;
+		rr.max.y = d.min.y + rw;
+		draw(img, rr, pen, nil, rr.min);
+		rr.min.y += Dy(d);
+		rr.max.y += Dy(d);
+		draw(img, rr, pen, nil, rr.min);
+		/* now the vertical */
+		/* horizontal lines first */
+		rr.min.x = d.min.x - lw;
+		rr.max.x = d.min.x + rw;
+		rr.min.y = d.min.y + rw;
+		rr.max.y = d.max.y - lw;
+		draw(img, rr, pen, nil, rr.min);
+		rr.min.x += Dx(d);
+		rr.max.x += Dx(d);
+		draw(img, rr, pen, nil, rr.min);
+	}
+}
+
+char*
+tkcvsrectcoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint != 2) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvsrectsize(i);
+	}
+	return nil;
+}
--- /dev/null
+++ b/libtk/ctext.c
@@ -1,0 +1,666 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Text Options (+ means implemented)
+	+anchor
+	+fill
+	+font
+	+justify
+	+stipple
+	+tags
+	+text
+	+width
+*/
+
+/* Layout constants */
+enum {
+	Cvsicursor	= 1,	/* Extra height of insertion cursor in canvas */
+};
+
+typedef struct TkCtext TkCtext;
+struct TkCtext
+{
+	int	anchor;
+	Point	anchorp;
+	int	justify;
+	int	icursor;
+	int	focus;
+	int	pixwidth;
+	int	pixheight;
+	int	sell;
+	int	self;
+	int	selfrom;
+	int	sbw;
+	int	width;
+	int	nlines;
+	Image*	stipple;
+	Image*	pen;
+	char*	text;
+	int	tlen;
+	TkEnv	*env;
+};
+
+static
+TkOption textopts[] =
+{
+	"anchor",	OPTstab,	O(TkCtext, anchor),	tkanchor,
+	"justify",	OPTstab,	O(TkCtext, justify),	tktabjust,
+	"width",	OPTdist,	O(TkCtext, width),	IAUX(O(TkCtext, env)),
+	"stipple",	OPTbmap,	O(TkCtext, stipple),	nil,
+	"text",		OPTtext,	O(TkCtext, text),	nil,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	"font",		OPTfont,	O(TkCitem, env),	nil,
+	"fill",		OPTcolr,	O(TkCitem, env),	IAUX(TkCfill),
+	nil
+};
+
+static char*
+tkcvstextgetl(TkCtext *t, Font *font, char *start, int *len)
+{
+	int w, n;
+	char *lspc, *posn;
+
+	w = t->width;
+	if(w <= 0)
+		w = 1000000;
+
+	n = 0;
+	lspc = nil;
+	posn = start;
+	while(*posn && *posn != '\n') {
+		if(*posn == ' ')
+			lspc = posn;
+		n += stringnwidth(font, posn, 1);
+		if(n >= w && posn != start) {
+			if(lspc != nil)
+				posn = lspc;
+			*len = posn - start;
+			if(lspc != nil)
+				posn++;
+			return posn;
+		}
+		posn++;
+	}
+	*len = posn - start;
+	if(*posn == '\n')
+		posn++;
+	return posn;
+}
+
+void
+tkcvstextsize(TkCitem *i)
+{
+	Point o;
+	Font *font;
+	TkCtext *t;
+	Display *d;
+	char *next, *p;
+	int len, pixw, locked;
+
+	t = TKobj(TkCtext, i);
+
+	font = i->env->font;
+	d = i->env->top->display;
+	t->pixwidth = 0;
+	t->pixheight = 0;
+
+	p = t->text;
+	if(p != nil) {
+		locked = lockdisplay(d);
+		while(*p) {
+			next = tkcvstextgetl(t, font, p, &len);
+			pixw = stringnwidth(font, p, len);
+			if(pixw > t->pixwidth)
+				t->pixwidth = pixw;
+			t->pixheight += font->height;
+			p = next;
+		}
+		if(locked)
+			unlockdisplay(d);
+	}
+
+	o = tkcvsanchor(i->p.drawpt[0], t->pixwidth, t->pixheight, t->anchor);
+
+	i->p.bb.min.x = o.x;
+	i->p.bb.min.y = o.y - Cvsicursor;
+	i->p.bb.max.x = o.x + t->pixwidth;
+	i->p.bb.max.y = o.y + t->pixheight + Cvsicursor;
+	i->p.bb = insetrect(i->p.bb, -2*t->sbw);
+	t->anchorp = subpt(o, i->p.drawpt[0]);
+}
+
+char*
+tkcvstextcreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCtext *t;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVtext, sizeof(TkCitem)+sizeof(TkCtext));
+	if(i == nil)
+		return TkNomem;
+
+	t = TKobj(TkCtext, i);
+	t->justify = Tkleft;
+	t->anchor = Tkcenter;
+	t->sell = -1;
+	t->self = -1;
+	t->icursor = -1;
+	t->sbw = c->sborderwidth;
+	t->env = tk->env;
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	if(i->p.npoint != 1) {
+		tkcvsfreeitem(i);
+		return TkFewpt;
+	}
+
+	tko[0].ptr = t;
+	tko[0].optab = textopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	t->tlen = 0;
+	if(t->text != nil)
+		t->tlen = strlen(t->text);
+
+	tkmkpen(&t->pen, i->env, t->stipple);
+	tkcvstextsize(i);
+	e = tkvalue(val, "%d", i->id);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	tkcvsappend(c, i);
+
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvstextcget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCtext *t = TKobj(TkCtext, i);
+
+	tko[0].ptr = t;
+	tko[0].optab = textopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvstextconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	TkOptab tko[3];
+	TkCtext *t = TKobj(TkCtext, i);
+
+	tko[0].ptr = t;
+	tko[0].optab = textopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+
+	t->tlen = 0;
+	if(t->text != nil)
+		t->tlen = strlen(t->text);
+
+	tkmkpen(&t->pen, i->env, t->stipple);
+	tkcvstextsize(i);
+
+	return e;
+}
+
+void
+tkcvstextfree(TkCitem *i)
+{
+	TkCtext *t;
+
+	t = TKobj(TkCtext, i);
+	if(t->stipple != nil)
+		freeimage(t->stipple);
+	if(t->pen != nil)
+		freeimage(t->pen);
+	if(t->text != nil)
+		free(t->text);
+}
+
+void
+tkcvstextdraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	TkEnv *e;
+	TkCtext *t;
+	Point o, dp;
+	Rectangle r;
+	char *p, *next;
+	Image *pen;
+	int len, lw, end, start;
+
+	t = TKobj(TkCtext, i);
+
+	e = i->env;
+	pen = t->pen;
+	if(pen == nil) {
+		if (e->set & (1<<TkCfill))
+			pen = tkgc(e, TkCfill);
+		else
+			pen = img->display->black;
+	}
+
+
+	o = addpt(t->anchorp, i->p.drawpt[0]);
+	p = t->text;
+	while(p && *p) {
+		next = tkcvstextgetl(t, e->font, p, &len);
+		dp = o;
+		if(t->justify != Tkleft) {
+			lw = stringnwidth(e->font, p, len);
+			if(t->justify == Tkcenter)
+				dp.x += (t->pixwidth - lw)/2;
+			else
+			if(t->justify == Tkright)
+				dp.x += t->pixwidth - lw;
+		}
+		lw = p - t->text;
+		if(t->self != -1 && lw+len > t->self) {
+			if(t->sell >= t->self) {
+				start = t->self - lw;
+				end = t->sell - lw;
+			}
+			else {
+				start = t->sell - lw;
+				end = t->self - lw;
+			}
+			if(start < 0)
+				r.min.x = o.x;
+			else
+				r.min.x = dp.x + stringnwidth(e->font, p, start);
+			r.min.y = dp.y;
+			if(end > len)
+				r.max.x = o.x + t->pixwidth;
+			else
+				r.max.x = dp.x + stringnwidth(e->font, p, end);
+			r.max.y = dp.y + e->font->height;
+			tktextsdraw(img, r, pe, t->sbw);
+			r.max.y = dp.y;
+			if(start > 0)
+				stringn(img, dp, pen, dp, e->font, p, start);
+			if(end > start)
+				stringn(img, r.min, tkgc(pe, TkCselectfgnd), r.min, e->font, p+start, end-start);
+			if(len > end)
+				stringn(img, r.max, pen, r.max, e->font, p+end, len-end);
+		}
+		else
+			stringn(img, dp, pen, dp, e->font, p, len);
+		if(t->focus) {
+			lw = p - t->text;
+			if(t->icursor >= lw && t->icursor <= lw+len) {
+				lw = t->icursor - lw;
+				if(lw > 0)
+					lw = stringnwidth(e->font, p, lw);
+				r.min.x = dp.x + lw;
+				r.min.y = dp.y - 1;
+				r.max.x = r.min.x + 2;
+				r.max.y = r.min.y + e->font->height + 1;
+				draw(img, r, pen, nil, ZP);
+			}
+		}
+		o.y += e->font->height;
+		p = next;
+	}
+}
+
+char*
+tkcvstextcoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		i->p.bb = rectaddpt(i->p.bb, Pt(TKF2I(x), TKF2I(y)));
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint != 1) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvstextsize(i);
+	}
+	return nil;
+}
+
+int
+tkcvstextsrch(TkCitem *i, int x, int y)
+{
+	TkCtext *t;
+	Font *font;
+	Display *d;
+	char *p, *next;
+	int n, len, locked;
+
+	t = TKobj(TkCtext, i);
+
+	n = 0;
+	font = i->env->font;
+	d = i->env->top->display;
+	p = t->text;
+	if(p == nil)
+		return 0;
+	while(*p) {
+		next = tkcvstextgetl(t, font, p, &len);
+		if(y <= font->height) {
+			locked = lockdisplay(d);
+			for(n = 0; n < len && x > stringnwidth(font, p, n+1); n++)
+				;
+			if(locked)
+				unlockdisplay(d);
+			break;
+		}
+		y -= font->height;
+		p = next;
+	}	
+	return p - t->text + n;
+}
+
+static char*
+tkcvsparseindex(TkCitem *i, char *buf, int *index)
+{
+	Point o;
+	char *p;
+	int x, y;
+	TkCtext *t;
+
+	t = TKobj(TkCtext, i);
+
+	if(strcmp(buf, "end") == 0) {
+		*index = t->tlen;
+		return nil;
+	}
+	if(strcmp(buf, "sel.first") == 0) {
+		if(t->self < 0)
+			return TkBadix;
+		*index = t->self;
+		return nil;
+	}
+	if(strcmp(buf, "sel.last") == 0) {
+		if(t->sell < 0)
+			return TkBadix;
+		*index = t->sell;
+		return nil;
+	}
+	if(strcmp(buf, "insert") == 0) {
+		*index = t->icursor;
+		return nil;
+	}
+	if(buf[0] == '@') {
+		x = atoi(buf+1);
+		p = strchr(buf, ',');
+		if(p == nil)
+			return TkBadix;
+		y = atoi(p+1);
+		o = i->p.drawpt[0];
+		*index = tkcvstextsrch(i, (x-t->anchorp.x)-o.x, (y-t->anchorp.y)-o.y);
+		return nil;
+	}
+
+	if(buf[0] < '0' || buf[0] > '9')
+		return TkBadix;
+	x = atoi(buf);
+	if(x < 0)
+		x = 0;
+	if(x > t->tlen)
+		x = t->tlen;
+	*index = x;	
+	return nil;
+}
+
+char*
+tkcvstextdchar(Tk *tk, TkCitem *i, char *arg)
+{
+	TkTop *top;
+	TkCtext *t;
+	int first, last;
+	char *e, buf[Tkmaxitem];
+
+	t = TKobj(TkCtext, i);
+
+	top = tk->env->top;
+	arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
+	e = tkcvsparseindex(i, buf, &first);
+	if(e != nil)
+		return e;
+
+	last = first+1;
+	if(*arg != '\0') {
+		tkword(top, arg, buf, buf+sizeof(buf), nil);
+		e = tkcvsparseindex(i, buf, &last);
+		if(e != nil)
+			return e;
+	}
+	if(last <= first || t->tlen == 0)
+		return nil;
+
+	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+	memmove(t->text+first, t->text+last, t->tlen-last+1);
+	t->tlen -= last-first;
+
+	tkcvstextsize(i);
+	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvstextinsert(Tk *tk, TkCitem *i, char *arg)
+{
+	TkTop *top;
+	TkCtext *t;
+	int first, n;
+	char *e, *text, buf[Tkmaxitem];
+
+	t = TKobj(TkCtext, i);
+
+	top = tk->env->top;
+	arg = tkword(top, arg, buf, buf+sizeof(buf), nil);
+	e = tkcvsparseindex(i, buf, &first);
+	if(e != nil)
+		return e;
+
+	if(*arg == '\0')
+		return nil;
+
+	text = malloc(Tkcvstextins);
+	if(text == nil)
+		return TkNomem;
+
+	tkword(top, arg, text, text+Tkcvstextins, nil);
+	n = strlen(text);
+	t->text = realloc(t->text, t->tlen+n+1);
+	if(t->text == nil) {
+		free(text);
+		return TkNomem;
+	}
+	if(t->tlen == 0)
+		t->text[0] = '\0';
+
+	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+	memmove(t->text+first+n, t->text+first, t->tlen-first+1);
+	memmove(t->text+first, text, n);
+	t->tlen += n;
+	free(text);
+
+	tkcvstextsize(i);
+	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvstextindex(Tk *tk, TkCitem *i, char *arg, char **val)
+{
+	int first;
+	char *e, buf[Tkmaxitem];
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	e = tkcvsparseindex(i, buf, &first);
+	if(e != nil)
+		return e;
+
+	return tkvalue(val, "%d", first);
+}
+
+char*
+tkcvstexticursor(Tk *tk, TkCitem *i, char *arg)
+{
+	int first;
+	TkCanvas *c;
+	char *e, buf[Tkmaxitem];
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	e = tkcvsparseindex(i, buf, &first);
+	if(e != nil)
+		return e;
+
+	TKobj(TkCtext, i)->icursor = first;
+
+	c = TKobj(TkCanvas, tk);
+	if(c->focus == i) {
+		tkbbmax(&c->update, &i->p.bb);
+		tkcvssetdirty(tk);
+	}
+	return nil;
+}
+
+void
+tkcvstextfocus(Tk *tk, TkCitem *i, int x)
+{
+	TkCtext *t;
+	TkCanvas *c;
+
+	if(i == nil)
+		return;
+
+	t = TKobj(TkCtext, i);
+	c = TKobj(TkCanvas, tk);
+
+	if(t->focus != x) {
+		t->focus = x;
+		tkbbmax(&c->update, &i->p.bb);
+		tkcvssetdirty(tk);
+	}
+}
+
+void
+tkcvstextclr(Tk *tk)
+{
+	TkCtext *t;
+	TkCanvas *c;
+	TkCitem *item;
+
+	c = TKobj(TkCanvas, tk);
+	item = c->selection;
+	if(item == nil)
+		return;
+
+	c->selection = nil;
+	t = TKobj(TkCtext, item);
+	t->sell = -1;
+	t->self = -1;
+	tkbbmax(&c->update, &item->p.bb);
+	tkcvssetdirty(tk);
+}
+
+char*
+tkcvstextselect(Tk *tk, TkCitem *i, char *arg, int op)
+{
+	int indx;
+	TkCtext *t;
+	TkCanvas *c;
+	char *e, buf[Tkmaxitem];
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	e = tkcvsparseindex(i, buf, &indx);
+	if(e != nil)
+		return e;
+
+	c = TKobj(TkCanvas, tk);
+	t = TKobj(TkCtext, i);
+	switch(op) {
+	case TkCselfrom:
+		t->selfrom = indx;
+		return nil;
+	case TkCseladjust:
+		if(c->selection == i) {
+			if(abs(t->self-indx) < abs(t->sell-indx)) {
+				t->self = indx;
+				t->selfrom = t->sell;
+			}
+			else {
+				t->sell = indx;
+				t->selfrom = t->self;
+			}
+		}
+		/* No break */
+	case TkCselto:
+		if(c->selection != i)
+			tkcvstextclr(tk);
+		c->selection = i;
+		t->self = t->selfrom;
+		t->sell = indx;
+		break;
+	}
+	t->sbw = c->sborderwidth;
+	tkbbmax(&TKobj(TkCanvas, tk)->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return nil;
+}
--- /dev/null
+++ b/libtk/cwind.c
@@ -1,0 +1,438 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Window Options (+ means implemented)
+	 +tags
+	 +width
+	 +height
+	 +window
+	 +anchor
+*/
+
+static
+TkOption windopts[] =
+{
+	"width",	OPTdist,	O(TkCwind, width),	nil,
+	"height",	OPTdist,	O(TkCwind, height),	nil,
+	"anchor",	OPTstab,	O(TkCwind, flags),	tkanchor,
+	"window",	OPTwinp,	O(TkCwind, sub),	nil,
+	nil
+};
+
+static
+TkOption itemopts[] =
+{
+	"tags",		OPTctag,	O(TkCitem, tags),	nil,
+	nil
+};
+
+static void
+tkcvswindsize(TkCitem *i)
+{
+	Tk *s;
+	int bw;
+	Point p;
+	TkGeom old;
+	TkCwind *w;
+
+	w = TKobj(TkCwind, i);
+	s = w->sub;
+	if(s == nil)
+		return;
+
+	if(w->width != s->act.width || w->height != s->act.height) {
+		old = s->act;
+		s->act.width = w->width;
+		s->act.height = w->height;
+		if(s->slave) {
+			tkpackqit(s);
+			tkrunpack(s->env->top);
+		}
+		tkdeliver(s, TkConfigure, &old);
+	}
+	p = tkcvsanchor(i->p.drawpt[0], s->act.width, s->act.height, w->flags);
+	s->act.x = p.x;
+	s->act.y = p.y;
+
+	bw = 2*s->borderwidth;
+	i->p.bb.min = p;
+	i->p.bb.max.x = p.x + s->act.width + bw;
+	i->p.bb.max.y = p.y + s->act.height + bw;
+}
+
+TkCitem*
+tkcvsfindwin(Tk *tk)
+{
+	Tk *parent, *sub;
+	TkCitem *i;
+	TkCanvas *c;
+	TkCwind *w;
+
+	sub = tkfindsub(tk);
+	if(sub == nil)
+		return nil;
+	parent = sub->parent;
+	if(parent->type != TKcanvas)
+		return nil;	/* inconsistent */
+	c = TKobj(TkCanvas, parent);
+	for(i = c->head; i != nil; i = i->next) {
+		if(i->type == TkCVwindow) {
+			w = TKobj(TkCwind, i);
+			if(w->sub == sub)
+				return i;
+		}
+	}
+	return nil;
+}
+
+void
+tkcvsforgetsub(Tk *sub, Tk *tk)
+{
+	TkCwind *w;
+	TkCitem *i;
+
+	i = tkcvsfindwin(sub);
+	if(i == nil)
+		return;
+	w = TKobj(TkCwind, i);
+	if(w->focus == tk) {
+if(0)print("tkcsvsforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk));
+		w->focus = nil;
+	}
+}
+
+static void
+tkcvswindgeom(Tk *sub, int x, int y, int w, int h)
+{
+	TkCitem *i;
+	Tk *parent;
+	TkCanvas *c;
+	TkCwind *win;
+
+	USED(x);
+	USED(y);
+	parent = sub->parent;
+	win = nil;
+	c = TKobj(TkCanvas, parent);
+	for(i = c->head; i; i = i->next) {
+		if(i->type == TkCVwindow) {
+			win = TKobj(TkCwind, i);
+			if(win->sub == sub)
+				break;
+		}
+	}
+
+	tkbbmax(&c->update, &i->p.bb);
+
+	if((win->flags & Tksetwidth) == 0)
+		win->width = w;
+	if ((win->flags & Tksetheight) == 0)
+		win->height = h;
+
+	sub->req.width = w;
+	sub->req.height = h;
+	tkcvswindsize(i);
+
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvsdirty(parent);
+}
+
+static void
+tkcvssubdestry(Tk *sub)
+{
+	Tk *tk;
+	TkCitem *i;
+	TkCanvas *c;
+	TkCwind *win;
+
+	tk = sub->parent;
+	if(tk == nil)
+		return;
+
+if(0)print("tkcvssubdestry %p %q\n", sub, tkname(sub));
+	i = tkcvsfindwin(sub);
+	if(i == nil)
+		return;
+	win = TKobj(TkCwind, i);
+	if(win->sub != sub){
+		if(win->sub != nil)
+			print("inconsistent tkcvssubdestry %p %q\n", sub, tkname(sub));
+		return;
+	}
+
+	c = TKobj(TkCanvas, tk);
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+
+	win->focus = nil;
+	win->sub = nil;
+	sub->parent = nil;
+	sub->geom = nil;
+}
+
+Point
+tkcvsrelpos(Tk *sub)
+{
+	Tk *tk;
+	TkCitem *i;
+	TkCanvas *c;
+	TkCwind *win;
+
+	tk = sub->parent;
+	if(tk == nil)
+		return ZP;
+
+	c = TKobj(TkCanvas, tk);
+	for(i = c->head; i; i = i->next) {
+		if(i->type == TkCVwindow) {
+			win = TKobj(TkCwind, i);
+			if(win->sub == sub)
+				return subpt(i->p.bb.min, c->view);
+		}
+	}
+	return ZP;
+}
+
+static char*
+tkcvswindchk(Tk *tk, TkCwind *w, Tk *oldsub)
+{
+	Tk *sub;
+
+	sub = w->sub;
+	if (sub != oldsub) {
+		w->sub = oldsub;
+		if(sub == nil)
+			return nil;
+	
+		if(sub->flag & Tkwindow)
+			return TkIstop;
+
+		if(sub->master != nil || sub->parent != nil)
+			return TkWpack;
+
+		if (oldsub != nil) {
+			oldsub->parent = nil;
+			oldsub->geom = nil;
+			oldsub->destroyed = nil;
+		}
+		w->sub = sub;
+		w->focus = nil;
+		sub->parent = tk;
+		tksetbits(w->sub, Tksubsub);
+		sub->geom = tkcvswindgeom;
+		sub->destroyed = tkcvssubdestry;
+	
+		if(w->width == 0)
+			w->width = sub->req.width;
+		if(w->height == 0)
+			w->height = sub->req.height;
+	}
+
+	return nil;
+}
+
+char*
+tkcvswindcreat(Tk* tk, char *arg, char **val)
+{
+	char *e;
+	TkCwind *w;
+	TkCitem *i;
+	TkCanvas *c;
+	TkOptab tko[3];
+
+	c = TKobj(TkCanvas, tk);
+
+	i = tkcnewitem(tk, TkCVwindow, sizeof(TkCitem)+sizeof(TkCwind));
+	if(i == nil)
+		return TkNomem;
+
+	w = TKobj(TkCwind, i);
+	w->flags = Tkcenter;
+
+	e = tkparsepts(tk->env->top, &i->p, &arg, 0);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	if(i->p.npoint != 1) {
+		tkcvsfreeitem(i);
+		return TkFewpt;
+	}
+
+	tko[0].ptr = w;
+	tko[0].optab = windopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	e = tkcvswindchk(tk, w, nil);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	e = tkcaddtag(tk, i, 1);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+
+	e = tkvalue(val, "%d", i->id);
+	if(e != nil) {
+		tkcvsfreeitem(i);
+		return e;
+	}
+	tkcvsappend(c, i);
+	tkcvswindsize(i);
+
+	tkbbmax(&c->update, &i->p.bb);
+	tkcvssetdirty(tk);
+	return nil;
+}
+
+char*
+tkcvswindcget(TkCitem *i, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkCwind *w = TKobj(TkCwind, i);
+
+	tko[0].ptr = w;
+	tko[0].optab = windopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, i->env->top);
+}
+
+char*
+tkcvswindconf(Tk *tk, TkCitem *i, char *arg)
+{
+	char *e;
+	int dx, dy;
+	TkOptab tko[3];
+	TkCwind *w = TKobj(TkCwind, i);
+	Tk *oldsub;
+
+	tko[0].ptr = w;
+	tko[0].optab = windopts;
+	tko[1].ptr = i;
+	tko[1].optab = itemopts;
+	tko[2].ptr = nil;
+
+	dx = w->width;
+	dy = w->height;
+	w->width = -1;
+	w->height = -1;
+
+	oldsub = w->sub;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e == nil) {
+		e = tkcvswindchk(tk, w, oldsub);
+		if(e != nil)
+			return e;
+		if(w->width == -1)
+			w->width = dx;
+		else
+			w->flags |= Tksetwidth;
+		if(w->height == -1)
+			w->height = dy;
+		else
+			w->flags |= Tksetheight;
+		tkcvswindsize(i);
+	} else {
+		w->width = dx;
+		w->height = dy;
+	}
+	return e;
+}
+
+void
+tkcvswindfree(TkCitem *i)
+{
+	Tk *sub;
+	TkCwind *w;
+
+	w = TKobj(TkCwind, i);
+	sub = w->sub;
+	if(sub != nil) {
+		sub->parent = nil;
+		sub->geom = nil;
+		sub->destroyed = nil;
+	}
+	w->focus = nil;
+	w->sub = nil;
+}
+
+void
+tkcvswinddraw(Image *img, TkCitem *i, TkEnv *pe)
+{
+	TkCwind *w;
+	Point rel;
+	Rectangle r;
+	Tk *sub;
+
+	USED(img);			/* See tkimageof */
+	USED(pe);
+	w = TKobj(TkCwind, i);
+	sub = w->sub;
+	if(sub != nil) {
+		int dirty;
+		r = i->p.bb;
+		rel.x = r.min.x + sub->borderwidth;
+		rel.y = r.min.y + sub->borderwidth;
+		if (rectclip(&r, img->clipr)) {
+			sub->dirty = rectsubpt(r, rel);
+			sub->flag |= Tkrefresh;
+			tkdrawslaves(sub, ZP, &dirty);	/* XXX - Tad: propagate err? */
+		}
+	}
+}
+
+char*
+tkcvswindcoord(TkCitem *i, char *arg, int x, int y)
+{
+	char *e;
+	TkCpoints p;
+/*
+	TkCwind *w;
+	int xi, yi;
+*/
+
+	if(arg == nil) {
+		tkxlatepts(i->p.parampt, i->p.npoint, x, y);
+		tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y));
+		tkcvswindsize(i);
+/*
+		w = TKobj(TkCwind, i);
+		xi = TKF2I(x);
+		yi = TKF2I(y);
+		if (w->sub != nil) {
+			w->sub->act.x += xi;
+			w->sub->act.y += yi;
+		}
+		i->p.bb = rectaddpt(i->p.bb, Pt(xi, yi));
+*/
+	}
+	else {
+		e = tkparsepts(i->env->top, &p, &arg, 0);
+		if(e != nil)
+			return e;
+		if(p.npoint != 1) {
+			tkfreepoint(&p);
+			return TkFewpt;
+		}
+		tkfreepoint(&i->p);
+		i->p = p;
+		tkcvswindsize(i);
+	}
+	return nil;
+}
--- /dev/null
+++ b/libtk/ebind.c
@@ -1,0 +1,1028 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include <kernel.h>
+#include <interp.h>
+
+enum
+{
+	Cmask,
+	Cctl,
+	Ckey,
+	Cbp,
+	Cbr,
+};
+
+struct 
+{
+	char*	event;
+	int	mask;
+	int	action;
+} etab[] =
+{
+	"Motion",		TkMotion,	Cmask,
+	"Double",		TkDouble,	Cmask,	
+	"Map",			TkMap,		Cmask,
+	"Unmap",		TkUnmap,	Cmask,
+	"Destroy",		TkDestroy, Cmask,
+	"Enter",		TkEnter,	Cmask,
+	"Leave",		TkLeave,	Cmask,
+	"FocusIn",		TkFocusin,	Cmask,
+	"FocusOut",		TkFocusout,	Cmask,
+	"Configure",		TkConfigure,	Cmask,
+	"Control",		0,		Cctl,
+	"Key",			0,		Ckey,
+	"KeyPress",		0,		Ckey,
+	"Button",		0,		Cbp,
+	"ButtonPress",		0,		Cbp,
+	"ButtonRelease",	0,		Cbr,
+};
+
+static
+TkOption tkcurop[] =
+{
+	"x",		OPTdist,	O(TkCursor, p.x),	nil,
+	"y",		OPTdist,	O(TkCursor, p.y),	nil,
+	"bitmap",	OPTbmap,	O(TkCursor, bit),	nil,
+	"image",	OPTimag,	O(TkCursor, img),	nil,
+	"default",	OPTbool,	O(TkCursor, def),	nil,
+	nil
+};
+
+static
+TkOption focusopts[] = {
+	"global",			OPTbool,	0,	nil,
+	nil
+};
+
+static char*
+tkseqitem(char *buf, char *arg)
+{
+	while(*arg && (*arg == ' ' || *arg == '-'))
+		arg++;
+	while(*arg && *arg != ' ' && *arg != '-' && *arg != '>')
+		*buf++ = *arg++;
+	*buf = '\0';
+	return arg;
+}
+
+static char*
+tkseqkey(Rune *r, char *arg)
+{
+	char *narg;
+
+	while(*arg && (*arg == ' ' || *arg == '-'))
+		arg++;
+	if (*arg == '\\') {
+		if (*++arg == '\0') {
+			*r = 0;
+			return arg;
+		}
+	} else if (*arg == '\0' || *arg == '>' || *arg == '-') {
+		*r = 0;
+		return arg;
+	}
+	narg = arg + chartorune(r, arg);
+	return narg;
+}
+
+int
+tkseqparse(char *seq)
+{
+	Rune r;
+	int i, event;
+	char *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return -1;
+
+	event = 0;
+
+	while(*seq && *seq != '>') {
+		seq = tkseqitem(buf, seq);
+	
+		for(i = 0; i < nelem(etab); i++)	
+			if(strcmp(buf, etab[i].event) == 0)
+				break;
+	
+		if(i >= nelem(etab)) {
+			seq = tkextnparseseq(buf, seq, &event);
+			if (seq == nil) {
+				free(buf);
+				return -1;
+			}
+			continue;
+		}
+	
+	
+		switch(etab[i].action) {
+		case Cmask:
+			event |= etab[i].mask;
+			break;
+		case Cctl:
+			seq = tkseqkey(&r, seq);
+			if(r == 0) {
+				free(buf);
+				return -1;
+			}
+			if(r <= '~')
+				r &= 0x1f;
+			event |= TkKey|TKKEY(r);
+			break;	
+		case Ckey:
+			seq = tkseqkey(&r, seq);
+			if(r != 0)
+				event |= TKKEY(r);
+			event |= TkKey;
+			break;
+		case Cbp:
+			seq = tkseqitem(buf, seq);
+			switch(buf[0]) {
+			default:
+				free(buf);
+				return -1;
+			case '\0':
+				event |= TkEpress;
+				break;
+			case '1':
+				event |= TkButton1P;
+				break;
+			case '2':
+				event |= TkButton2P;
+				break;
+			case '3':
+				event |= TkButton3P;
+				break;
+			case '4':
+				event |= TkButton4P;
+				break;
+			case '5':
+				event |= TkButton5P;
+				break;
+			case '6':
+				event |= TkButton6P;
+				break;
+			}
+			break;
+		case Cbr:
+			seq = tkseqitem(buf, seq);
+			switch(buf[0]) {
+			default:
+				free(buf);
+				return -1;
+			case '\0':
+				event |= TkErelease;
+				break;
+			case '1':
+				event |= TkButton1R;
+				break;
+			case '2':
+				event |= TkButton2R;
+				break;
+			case '3':
+				event |= TkButton3R;
+				break;
+			case '4':
+				event |= TkButton4R;
+				break;
+			case '5':
+				event |= TkButton5R;
+				break;
+			case '6':
+				event |= TkButton6R;
+				break;
+			}
+			break;
+		}
+	}
+	free(buf);
+	return event;
+}
+
+void
+tkcmdbind(Tk *tk, int event, char *s, void *data)
+{
+	Point p;
+	TkMouse *m;
+	TkGeom *g;
+	int v, len;
+	char *e, *c, *ec, *cmd;
+	TkTop *t;
+
+	if(s == nil)
+		return;
+	cmd = malloc(2*Tkmaxitem);
+	if (cmd == nil) {
+		print("tk: bind command \"%s\": %s\n",
+			tk->name ? tk->name->name : "(noname)", TkNomem);
+		return;
+	}
+
+	m = (TkMouse*)data;
+	c = cmd;
+	ec = cmd+2*Tkmaxitem-1;
+	while(*s && c < ec) {
+		if(*s != '%') {
+			*c++ = *s++;
+			continue;
+		}
+		s++;
+		len = ec-c;
+		switch(*s++) {
+		def:
+		default:
+			*c++ = s[-1];
+			break;
+		case '%':
+			*c++ = '%';
+			break;
+		case 'b':
+			v = 0;
+			if (!(event & TkKey)) {
+				if(event & (TkButton1P|TkButton1R))
+					v = 1;
+				else if(event & (TkButton2P|TkButton2R))
+					v = 2;
+				else if(event & (TkButton3P|TkButton3R))
+					v = 3;
+			}
+			c += snprint(c, len, "%d", v);
+			break;
+		case 'h':
+			if((event & TkConfigure) == 0)
+				goto def;
+			g = (TkGeom*)data;
+			c += snprint(c, len, "%d", g->height);
+			break;
+		case 's':
+			if((event & TkKey))
+				c += snprint(c, len, "%d", TKKEY(event));
+			else if((event & (TkEmouse|TkEnter)))
+				c += snprint(c, len, "%d", m->b);
+			else if((event & TkFocusin))
+				c += snprint(c, len, "%d", (int)data);
+			else
+				goto def;
+			break;
+		case 'w':
+			if((event & TkConfigure) == 0)
+				goto def;
+			g = (TkGeom*)data;
+			c += snprint(c, len, "%d", g->width);
+			break;
+		case 'x':		/* Relative mouse coords */
+		case 'y':
+			if((event & TkKey) || (event & (TkEmouse|TkEnter)) == 0)
+				goto def;
+			p = tkposn(tk);
+			if(s[-1] == 'x')
+				v = m->x - p.x;
+			else
+				v = m->y - p.y;
+			c += snprint(c, len, "%d", v - tk->borderwidth);
+			break;
+		case 'X':		/* Absolute mouse coords */
+		case 'Y':
+			if((event & TkKey) || (event & TkEmouse) == 0)
+				goto def;
+			c += snprint(c, len, "%d", s[-1] == 'X' ? m->x : m->y);
+			break;
+		case 'A':
+			if((event & TkKey) == 0)
+				goto def;
+			v = TKKEY(event);
+			if(v == '{' || v == '}' || v == '\\')
+				c += snprint(c, len, "\\%C", v);
+			else if(v != '\0')
+				c += snprint(c, len, "%C", v);
+			break;
+		case 'K':
+			if((event & TkKey) == 0)
+				goto def;
+			c += snprint(c, len, "%.4X", TKKEY(event));
+			break;
+		case 'W':
+		        if (tk->name != nil) 
+			  c += snprint(c, len, "%s", tk->name->name);
+			break;
+		}
+	}
+	*c = '\0';
+	e = nil;
+	t = tk->env->top;
+	t->execdepth = 0;
+	if(cmd[0] == '|')
+		tkexec(t, cmd+1, nil);
+	else if(cmd[0] != '\0')
+		e = tkexec(t, cmd, nil);
+	t->execdepth = -1;
+
+	if(e == nil) {
+		free(cmd);
+		return;
+	}
+
+	if(tk->name != nil){
+		char *s;
+
+		if(t->errx[0] != '\0')
+			s = tkerrstr(t, e);
+		else
+			s = e;
+		print("tk: bind command \"%s\": %s: %s\n", tk->name->name, cmd, s);
+		if(s != e)
+			free(s);
+	}
+	free(cmd);
+}
+
+char*
+tkbind(TkTop *t, char *arg, char **ret)
+{
+	Rune r;
+	Tk *tk;
+	TkAction **ap;
+	int i, mode, event;
+	char *cmd, *tag, *seq;
+	char *e;
+
+	USED(ret);
+
+	tag = mallocz(Tkmaxitem, 0);
+	if(tag == nil)
+		return TkNomem;
+	seq = mallocz(Tkmaxitem, 0);
+	if(seq == nil) {
+		free(tag);
+		return TkNomem;
+	}
+
+	arg = tkword(t, arg, tag, tag+Tkmaxitem, nil);
+	if(tag[0] == '\0') {
+		e = TkBadtg;
+		goto err;
+	}
+
+	arg = tkword(t, arg, seq, seq+Tkmaxitem, nil);
+	if(seq[0] == '<') {
+		event = tkseqparse(seq+1);
+		if(event == -1) {
+			e = TkBadsq;
+			goto err;
+		}
+	}
+	else {
+		chartorune(&r, seq);
+		event = TkKey | r;
+	}
+	if(event == 0) {
+		e = TkBadsq;
+		goto err;
+	}
+
+	arg = tkskip(arg, " \t");
+
+	mode = TkArepl;
+	if(*arg == '+') {
+		mode = TkAadd;
+		arg++;
+	}
+	else if(*arg == '-'){
+		mode = TkAsub;
+		arg++;
+	}
+
+	if(*arg == '{') {
+		cmd = tkskip(arg+1, " \t");
+		if(*cmd == '}') {
+			tk = tklook(t, tag, 0);
+			if(tk == nil) {
+				for(i = 0; ; i++) {
+					if(i >= TKwidgets) {
+						e = TkBadwp;
+						tkerr(t, tag);
+						goto err;
+					}
+					if(strcmp(tag, tkmethod[i]->name) == 0) {
+						ap = &(t->binds[i]);
+						break;
+					}
+				}
+			}
+			else
+				ap = &tk->binds;
+			tkcancel(ap, event);
+		}
+	}
+
+	tkword(t, arg, seq, seq+Tkmaxitem, nil);
+	if(tag[0] == '.') {
+		tk = tklook(t, tag, 0);
+		if(tk == nil) {
+			e = TkBadwp;
+			tkerr(t, tag);
+			goto err;
+		}
+
+		cmd = strdup(seq);
+		if(cmd == nil) {
+			e = TkNomem;
+			goto err;
+		}
+		e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
+		if(e != nil)
+			goto err;	/* tkaction does free(cmd) */
+		free(tag);
+		free(seq);
+		return nil;
+	}
+	/* documented but doesn't work */
+	if(strcmp(tag, "all") == 0) {
+		for(tk = t->root; tk; tk = tk->next) {
+			cmd = strdup(seq);
+			if(cmd == nil) {
+				e = TkNomem;
+				goto err;
+			}
+			e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
+			if(e != nil)
+				goto err;
+		}
+		free(tag);
+		free(seq);
+		return nil;
+	}
+	/* undocumented, probably unused, and doesn't work consistently */
+	for(i = 0; i < TKwidgets; i++) {
+		if(strcmp(tag, tkmethod[i]->name) == 0) {
+			cmd = strdup(seq);
+			if(cmd == nil) {
+				e = TkNomem;
+				goto err;
+			}
+			e = tkaction(t->binds + i,event, TkDynamic, cmd, mode);
+			if(e != nil)
+				goto err;
+			free(tag);
+			free(seq);
+			return nil;
+		}
+	}
+
+	e = TkBadtg;
+err:
+	free(tag);
+	free(seq);
+
+	return e;
+}
+
+char*
+tksend(TkTop *t, char *arg, char **ret)
+{
+
+	TkVar *v;
+	char *var;
+
+	USED(ret);
+
+	var = mallocz(Tkmaxitem, 0);
+	if(var == nil)
+		return TkNomem;
+
+	arg = tkword(t, arg, var, var+Tkmaxitem, nil);
+	v = tkmkvar(t, var, 0);
+	free(var);
+	if(v == nil)
+		return TkBadvr;
+	if(v->type != TkVchan)
+		return TkNotvt;
+
+	arg = tkskip(arg, " \t");
+	if(tktolimbo(v->value, arg) == 0)
+		return TkMovfw;
+
+	return nil;
+}
+
+static Tk*
+tknextfocus(TkTop *t, int d)
+{
+	int i, n, j, k;
+	Tk *oldfocus;
+
+	if (t->focusorder == nil)
+		tkbuildfocusorder(t);
+
+	oldfocus = t->ctxt->tkkeygrab;
+	n = t->nfocus;
+	if (n == 0)
+		return oldfocus;
+	for (i = 0; i < n; i++)
+		if (t->focusorder[i] == oldfocus)
+			break;
+	if (i == n) {
+		for (i = 0; i < n; i++)
+			if ((t->focusorder[i]->flag & Tkdisabled) == 0)
+				return t->focusorder[i];
+		return oldfocus;
+	}
+	for (j = 1; j < n; j++) {
+		k = (i + d * j + n) % n;
+		if ((t->focusorder[k]->flag & Tkdisabled) == 0)
+			return t->focusorder[k];
+	}
+	return oldfocus;
+}
+
+/* our dirty little secret */
+static void
+focusdirty(Tk *tk)
+{
+	if(tk->highlightwidth > 0){
+		tk->dirty = tkrect(tk, 1);
+		tkdirty(tk);
+	}
+}
+
+void
+tksetkeyfocus(TkTop *top, Tk *new, int dir)
+{
+	TkCtxt *c;
+	Tk *old;
+
+	c = top->ctxt;
+	old = c->tkkeygrab;
+
+	if(old == new)
+		return;
+	c->tkkeygrab = new;
+	if(top->focused == 0)
+		return;
+	if(old != nil && old != top->root){
+		tkdeliver(old, TkFocusout, nil);
+		focusdirty(old);
+	}
+	if(new != nil && new != top->root){
+		tkdeliver(new, TkFocusin, (void*)dir);
+		focusdirty(new);
+	}
+}
+
+void
+tksetglobalfocus(TkTop *top, int in)
+{
+	Tk *tk;
+	in = (in != 0);
+	if (in != top->focused){
+		top->focused = in;
+		tk = top->ctxt->tkkeygrab;
+		if(in){
+			tkdeliver(top->root, TkFocusin, (void*)0);
+			if(tk != nil && tk != top->root){
+				tkdeliver(tk, TkFocusin, (void*)0);
+				focusdirty(tk);
+			}
+		}else{
+			if(tk != nil && tk != top->root){
+				tkdeliver(tk, TkFocusout, nil);
+				focusdirty(tk);
+			}
+			tkdeliver(top->root, TkFocusout, nil);
+		}
+	}
+}
+
+char*
+tkfocus(TkTop *top, char *arg, char **ret)
+{
+	Tk *tk;
+	char *wp, *e;
+	int dir, global;
+	TkOptab tko[2];
+	TkName *names;
+
+	tko[0].ptr = &global;
+	tko[0].optab = focusopts;
+	tko[1].ptr = nil;
+
+	global = 0;
+	
+	names = nil;
+	e = tkparse(top, arg, tko, &names);
+	if (e != nil)
+		return e;
+
+	if(names == nil){
+		if(global)
+			return tkvalue(ret, "%d", top->focused);
+		tk = top->ctxt->tkkeygrab;
+		if (tk != nil && tk->name != nil)
+			return tkvalue(ret, "%s", tk->name->name);
+		return nil;
+	}
+
+	if(global){
+		tksetglobalfocus(top, atoi(names->name));
+		return nil;
+	}
+
+	wp = mallocz(Tkmaxitem, 0);
+	if(wp == nil)
+		return TkNomem;
+
+	tkword(top, arg, wp, wp+Tkmaxitem, nil);
+	if (!strcmp(wp, "next")) {
+		tk = tknextfocus(top, 1);		/* can only return nil if c->tkkeygrab is already nil */
+		dir = +1;
+	} else if (!strcmp(wp, "previous")) {
+		tk = tknextfocus(top, -1);
+		dir = -1;
+	} else if(*wp == '\0') {
+		tk = nil;
+		dir = 0;
+	} else {
+		tk = tklook(top, wp, 0);
+		if(tk == nil){
+			tkerr(top, wp);
+			free(wp);
+			return TkBadwp;
+		}
+		dir = 0;
+	}
+	free(wp);
+
+	tksetkeyfocus(top, tk, dir);
+	return nil;
+}
+
+char*
+tkraise(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *wp;
+
+	USED(ret);
+
+	wp = mallocz(Tkmaxitem, 0);
+	if(wp == nil)
+		return TkNomem;
+	tkword(t, arg, wp, wp+Tkmaxitem, nil);
+	tk = tklook(t, wp, 0);
+	if(tk == nil){
+		tkerr(t, wp);
+		free(wp);
+		return TkBadwp;
+	}
+	free(wp);
+
+	if((tk->flag & Tkwindow) == 0)
+		return TkNotwm;
+
+	tkwreq(tk->env->top, "raise %s", tk->name->name);
+	return nil;
+}
+
+char*
+tklower(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *wp;
+
+	USED(ret);
+	wp = mallocz(Tkmaxitem, 0);
+	if(wp == nil)
+		return TkNomem;
+	tkword(t, arg, wp, wp+Tkmaxitem, nil);
+	tk = tklook(t, wp, 0);
+	if(tk == nil){
+		tkerr(t, wp);
+		free(wp);
+		return TkBadwp;
+	}
+	free(wp);
+
+	if((tk->flag & Tkwindow) == 0)
+		return TkNotwm;
+
+	tkwreq(tk->env->top, "lower %s", tk->name->name);
+	return nil;
+}
+
+char*
+tkgrab(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	TkCtxt *c;
+	char *r, *buf, *wp;
+
+	USED(ret);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	wp = mallocz(Tkmaxitem, 0);
+	if(wp == nil) {
+		free(buf);
+		return TkNomem;
+	}
+	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+
+	tkword(t, arg, wp, wp+Tkmaxitem, nil);
+	tk = tklook(t, wp, 0);
+	if(tk == nil) {
+		free(buf);
+		tkerr(t, wp);
+		free(wp);
+		return TkBadwp;
+	}
+	free(wp);
+
+	c = t->ctxt;
+	if(strcmp(buf, "release") == 0) {
+		free(buf);
+		if(c->mgrab == tk)
+			tksetmgrab(t, nil);
+		return nil;
+	}
+	if(strcmp(buf, "set") == 0) {
+		free(buf);
+		return tksetmgrab(t, tk);
+	}
+	if(strcmp(buf, "ifunset") == 0) {
+		free(buf);
+		if(c->mgrab == nil)
+			return tksetmgrab(t, tk);
+		return nil;
+	}
+	if(strcmp(buf, "status") == 0) {
+		free(buf);
+		r = "none";
+		if ((c->mgrab != nil) && (c->mgrab->name != nil))
+			r = c->mgrab->name->name;
+		return tkvalue(ret, "%s", r);
+	}
+	free(buf);
+	return TkBadcm;
+}
+
+char*
+tkputs(TkTop *t, char *arg, char **ret)
+{
+	char *buf;
+
+	USED(ret);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	print("%s\n", buf);
+	free(buf);
+	return nil;
+}
+
+char*
+tkdestroy(TkTop *t, char *arg, char **ret)
+{
+	int found, len, isroot;
+	Tk *tk, **l, *next, *slave;
+	char *n, *e, *buf;
+
+	USED(ret);
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	e = nil;
+	for(;;) {
+		arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+		if(buf[0] == '\0')
+			break;
+
+		len = strlen(buf);
+		found = 0;
+		isroot = (strcmp(buf, ".") == 0);
+		for(tk = t->root; tk; tk = tk->siblings) {
+		        if (tk->name != nil) {
+				n = tk->name->name;
+				if(strcmp(buf, n) == 0) {
+					tk->flag |= Tkdestroy;
+					found = 1;
+				} else if(isroot || (strncmp(buf, n, len) == 0 && n[len] == '.'))
+					tk->flag |= Tkdestroy;
+			}
+		}
+		if(!found) {
+			e = TkBadwp;
+			tkerr(t, buf);
+			break;
+		}
+	}
+	free(buf);
+
+	for(tk = t->root; tk; tk = tk->siblings) {
+		if((tk->flag & Tkdestroy) == 0)
+			continue;
+		if(tk->flag & Tkwindow) {
+			tkunmap(tk);
+			if(tk->name != nil &&
+			   strcmp(tk->name->name, ".") == 0)
+				tk->flag &= ~Tkdestroy;
+			else
+				tkdeliver(tk, TkDestroy, nil);
+		} else
+			tkdeliver(tk, TkDestroy, nil);
+if(0)print("tkdestroy %q\n", tkname(tk));
+		if(tk->destroyed != nil)
+			tk->destroyed(tk);
+		tkpackqit(tk->master);
+		tkdelpack(tk);
+		for (slave = tk->slave; slave != nil; slave = next) {
+			next = slave->next;
+			slave->master = nil;
+			slave->next = nil;
+		}
+		tk->slave = nil;
+		if(tk->parent != nil && tk->geom != nil)		/* XXX this appears to be bogus */
+			tk->geom(tk, 0, 0, 0, 0);
+		if(tk->grid){
+			tkfreegrid(tk->grid);
+			tk->grid = nil;
+		}
+	}
+	tkrunpack(t);
+
+	l = &t->windows;
+	for(tk = t->windows; tk; tk = next) {
+		next = TKobj(TkWin, tk)->next;
+		if(tk->flag & Tkdestroy) {
+			*l = next;
+			continue;
+		}
+		l = &TKobj(TkWin, tk)->next;		
+	}
+	l = &t->root;
+	for(tk = t->root; tk; tk = next) {
+		next = tk->siblings;
+		if(tk->flag & Tkdestroy) {
+			*l = next;
+			tkfreeobj(tk);
+			continue;
+		}
+		l = &tk->siblings;
+	}
+
+	return e;
+}
+
+char*
+tkupdatecmd(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	int x, y;
+	Rectangle *dr;
+	char buf[Tkmaxitem];
+
+	USED(ret);
+
+	tkword(t, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "-onscreen") == 0){
+		tk = t->root;
+		dr = &t->screenr;
+		x = tk->act.x;
+		if(x+tk->act.width > dr->max.x)
+			x = dr->max.x - tk->act.width;
+		if(x < 0)
+			x = 0;
+		y = tk->act.y;
+		if(y+tk->act.height > dr->max.y)
+			y = dr->max.y - tk->act.height;
+		if(y < 0)
+			y = 0;
+		tkmovewin(tk, Pt(x, y));
+	}else if(strcmp(buf, "-disable") == 0){
+		t->noupdate = 1;
+	}else if(strcmp(buf, "-enable") == 0){
+		t->noupdate = 0;
+	}
+	return tkupdate(t);
+}
+
+char*
+tkwinfo(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *cmd, *arg1;
+
+	cmd = mallocz(Tkmaxitem, 0);
+	if(cmd == nil)
+		return TkNomem;
+
+	arg = tkword(t, arg, cmd, cmd+Tkmaxitem, nil);
+	if(strcmp(cmd, "class") == 0) {
+		arg1 = mallocz(Tkmaxitem, 0);
+		if(arg1 == nil) {
+			free(cmd);
+			return TkNomem;
+		}
+		tkword(t, arg, arg1, arg1+Tkmaxitem, nil);
+		tk = tklook(t, arg1, 0);
+		if(tk == nil){
+			tkerr(t, arg1);
+			free(arg1);
+			free(cmd);
+			return TkBadwp;
+		}
+		free(arg1);
+		free(cmd);
+		return tkvalue(ret, "%s", tkmethod[tk->type]->name);
+	}
+	free(cmd);
+	return TkBadvl;
+}
+
+char*
+tkcursorcmd(TkTop *t, char *arg, char **ret)
+{
+	char *e;
+	int locked;
+	Display *d;
+	TkCursor c;
+	TkOptab tko[3];
+	enum {Notset = 0x80000000};
+
+	c.def = 0;
+	c.p.x = Notset;
+	c.p.y = Notset;
+	c.bit = nil;
+	c.img = nil;
+	
+	USED(ret);
+
+	c.def = 0;
+	tko[0].ptr = &c;
+	tko[0].optab = tkcurop;
+	tko[1].ptr = nil;
+	e = tkparse(t, arg, tko, nil);
+	if(e != nil)
+		return e;
+
+	d = t->display;
+	locked = lockdisplay(d);
+	if(c.def)
+		tkcursorswitch(t, nil, nil);
+	if(c.img != nil || c.bit != nil){
+		e = tkcursorswitch(t, c.bit, c.img);
+		tkimgput(c.img);
+		freeimage(c.bit);
+	}
+	if(e == nil){
+		if(c.p.x != Notset && c.p.y != Notset)
+			tkcursorset(t, c.p);
+	}
+	if(locked)
+		unlockdisplay(d);
+	return e;	
+}
+
+char *
+tkbindings(TkTop *t, Tk *tk, TkEbind *b, int blen)
+{
+	TkAction *a, **ap;
+	char *cmd, *e;
+	int i;
+
+	e = nil;
+	for(i = 0; e == nil && i < blen; i++)	/* default bindings */ {
+		int how = TkArepl;
+		char *cmd = b[i].cmd;
+		if(cmd[0] == '+') {
+			how = TkAadd;
+			cmd++;
+		}
+		else if(cmd[0] == '-'){
+			how = TkAsub;
+			cmd++;
+		}
+		e = tkaction(&tk->binds, b[i].event, TkStatic, cmd, how);
+	}
+	
+	if(e != nil)
+		return e;
+
+	ap = &tk->binds;
+	for(a = t->binds[tk->type]; a; a = a->link) {	/* user "defaults" */
+		cmd = strdup(a->arg);
+		if(cmd == nil)
+			return TkNomem;
+
+		e = tkaction(ap, a->event, TkDynamic, cmd,
+						(a->type >> 8) & 0xff);
+		if(e != nil)
+			return e;
+		ap = &(*ap)->link;
+	}
+	return nil;
+}
--- /dev/null
+++ b/libtk/entry.c
@@ -1,0 +1,1368 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+
+/* Widget Commands (+ means implemented)
+	+bbox
+	+cget
+	+configure
+	+delete
+	+get
+	+icursor
+	+index
+	 scan
+	+selection
+	+xview
+	+see
+*/
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+#define CNTL(c) ((c)&0x1f)
+#define DEL 0x7f
+
+/* Layout constants */
+enum {
+	Entrypady	= 0,
+	Entrypadx	= 0,
+	Inswidth = 2,
+
+	Ecursoron = 1<<0,
+	Ecenter = 1<<1,
+	Eright = 1<<2,
+	Eleft = 1<<3,
+	Ewordsel = 1<<4,
+
+	Ejustify = Ecenter|Eleft|Eright
+};
+
+static TkStab tkjust[] =
+{
+	"left",	Eleft,
+	"right",	Eright,
+	"center",	Ecenter,
+	nil
+};
+
+static
+TkEbind b[] = 
+{
+	{TkKey,			"%W delete sel.first sel.last; %W insert insert {%A};%W see insert"},
+	{TkKey|CNTL('a'),	"%W icursor 0;%W see insert;%W selection clear"},
+	{TkKey|Home,		"%W icursor 0;%W see insert;%W selection clear"},
+	{TkKey|CNTL('d'),	"%W delete insert; %W see insert"},
+	{TkKey|CNTL('e'),    "%W icursor end; %W see insert;%W selection clear"},
+	{TkKey|End,	     "%W icursor end; %W see insert;%W selection clear"},
+	{TkKey|CNTL('h'),	"%W tkEntryBS;%W see insert"},
+	{TkKey|CNTL('k'),	"%W delete insert end;%W see insert"},
+	{TkKey|CNTL('u'),	"%W delete 0 end;%W see insert"},
+	{TkKey|CNTL('w'),	"%W delete sel.first sel.last; %W tkEntryBW;%W see insert"},
+	{TkKey|DEL,		"%W tkEntryBS 1;%W see insert"},
+	{TkKey|CNTL('\\'),	"%W selection clear"},
+	{TkKey|CNTL('/'),	"%W selection range 0 end"},
+	{TkKey|Left,	"%W icursor insert-1;%W selection clear;%W selection from insert;%W see insert"},
+	{TkKey|Right,	"%W icursor insert+1;%W selection clear;%W selection from insert;%W see insert"},
+	{TkButton1P,		"focus %W; %W tkEntryB1P %X"},
+	{TkButton1P|TkMotion, 	"%W tkEntryB1M %X"},
+	{TkButton1R,		"%W tkEntryB1R"},
+	{TkButton1P|TkDouble,	"%W tkEntryB1P %X;%W selection word @%x"},
+	{TkButton2P,			"%W tkEntryB2P %x"},
+	{TkButton2P|TkMotion,	"%W xview scroll %x scr"},
+	{TkFocusin,		"%W tkEntryFocus in"},
+	{TkFocusout,		"%W tkEntryFocus out"},
+	{TkKey|APP|'\t',	""},
+	{TkKey|BackTab,		""},
+};
+
+typedef struct TkEntry TkEntry;
+struct TkEntry
+{
+	Rune*	text;
+	int		textlen;
+
+	char*	xscroll;
+	char*	show;
+	int		flag;
+	int		oldx;
+
+	int		icursor;		/* index of insertion cursor */
+	int		anchor;		/* selection anchor point */
+	int		sel0;			/* index of start of selection */
+	int		sel1;			/* index of end of selection */
+
+	int		x0;			/* x-offset of visible area */
+
+	/* derived values */
+	int		v0;			/* index of first visible character */
+	int		v1;			/* index of last visible character + 1 */
+	int		xlen;			/* length of text in pixels*/
+	int		xv0;			/* position of first visible character */
+	int		xsel0;		/* position of start of selection */
+	int		xsel1;		/* position of end of selection */
+	int		xicursor;		/* position of insertion cursor */
+};
+
+static void blinkreset(Tk*);
+
+static
+TkOption opts[] =
+{
+	"xscrollcommand",	OPTtext,	O(TkEntry, xscroll),	nil,
+	"justify",		OPTstab,	O(TkEntry, flag),	tkjust,
+	"show",			OPTtext,	O(TkEntry, show),	nil,
+	nil
+};
+
+static int
+xinset(Tk *tk)
+{
+	return Entrypadx + tk->highlightwidth;
+}
+
+static int
+yinset(Tk *tk)
+{
+	return Entrypady + tk->highlightwidth;
+}
+
+static void
+tksizeentry(Tk *tk)
+{
+	if((tk->flag & Tksetwidth) == 0)
+		tk->req.width = tk->env->wzero*25 + 2*xinset(tk) + Inswidth;
+	if((tk->flag & Tksetheight) == 0)
+		tk->req.height = tk->env->font->height+ 2*yinset(tk);
+}
+
+int
+entrytextwidth(Tk *tk, int n)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	Rune c;
+	Font *f;
+
+	f = tk->env->font;
+	if (tke->show != nil) {
+		chartorune(&c, tke->show);
+		return n * runestringnwidth(f, &c, 1);
+	}
+	return runestringnwidth(f, tke->text, n);
+}
+
+static int
+x2index(Tk *tk,  int x, int *xc)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	int t0, t1, r, q;
+
+	t0 = 0;
+	t1 = tke->textlen;
+	while (t0 <= t1) {
+		r = (t0 + t1) / 2;
+		q = entrytextwidth(tk, r);
+		if (q == x) {
+			if (xc != nil)
+				*xc = q;
+			return r;
+		}
+		if (q < x)
+			t0 = r + 1;
+		else
+			t1 = r - 1;
+	}
+	if (xc != nil)
+		*xc = t1 > 0 ? entrytextwidth(tk, t1) : 0;
+	if (t1 < 0)
+		t1 = 0;
+	return t1;
+}
+
+/*
+ * recalculate derived values
+ */
+static void
+recalcentry(Tk *tk)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	int x, avail, locked;
+
+	locked = lockdisplay(tk->env->top->display);
+
+	tke->xlen = entrytextwidth(tk, tke->textlen) + Inswidth;
+
+	avail = tk->act.width - 2*xinset(tk);
+	if (tke->xlen < avail) {
+		switch(tke->flag & Ejustify) {
+		default:
+			tke->x0 = 0;
+			break;
+		case Eright:
+			tke->x0 = -(avail - tke->xlen);
+			break;
+		case Ecenter:
+			tke->x0 = -(avail - tke->xlen) / 2;
+			break;
+		}
+	}
+
+	tke->v0 = x2index(tk, tke->x0, &tke->xv0);
+	tke->v1 = x2index(tk, tk->act.width + tke->x0, &x);
+	/* perhaps include partial last character */
+	if (tke->v1 < tke->textlen && x < avail + tke->x0)
+		tke->v1++;
+	tke->xsel0 = entrytextwidth(tk, tke->sel0);
+	tke->xsel1 = entrytextwidth(tk, tke->sel1);
+	tke->xicursor = entrytextwidth(tk, tke->icursor);
+
+	if (locked)
+		unlockdisplay(tk->env->top->display);
+}
+
+char*
+tkentry(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkName *names;
+	TkEntry *tke;
+	TkOptab tko[3];
+
+	tk = tknewobj(t, TKentry, sizeof(Tk)+sizeof(TkEntry));
+	if(tk == nil)
+		return TkNomem;
+
+	tk->relief = TKsunken;
+	tk->borderwidth = 1;
+	tk->flag |= Tktakefocus;
+	tk->highlightwidth = 1;
+
+	tke = TKobj(TkEntry, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tke;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tksizeentry(tk);
+	e = tkbindings(t, tk, b, nelem(b));
+
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+	recalcentry(tk);
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tkentrycget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkEntry *tke = TKobj(TkEntry, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tke;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreeentry(Tk *tk)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+
+	free(tke->xscroll);
+	free(tke->text);
+	free(tke->show);
+}
+
+static void
+tkentrytext(Image *i, Rectangle s, Tk *tk, TkEnv *env)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	Point dp;
+	int s0, s1, xs0, xs1, j;
+	Rectangle r;
+	Rune showr, *text;
+
+	dp = Pt(s.min.x - (tke->x0 - tke->xv0), s.min.y);
+	if (tke->show) {
+		chartorune(&showr, tke->show);
+		text = mallocz(sizeof(Rune) * (tke->textlen+1), 0);
+		if (text == nil)
+			return;
+		for (j = 0; j < tke->textlen; j++)
+			text[j] = showr;
+	} else
+		text = tke->text;
+
+	runestringn(i, dp, tkgc(env, TkCforegnd), dp, env->font,
+				text+tke->v0, tke->v1-tke->v0);
+
+	if (tke->sel0 < tke->v1 && tke->sel1 > tke->v0) {
+		if (tke->sel0 < tke->v0) {
+			s0 = tke->v0;
+			xs0 = tke->xv0 - tke->x0;
+		} else {
+			s0 = tke->sel0;
+			xs0 = tke->xsel0 - tke->x0;
+		}
+
+		if (tke->sel1 > tke->v1) {
+			s1 = tke->v1;
+			xs1 = s.max.x;
+		} else {
+			s1 = tke->sel1;
+			xs1 = tke->xsel1 - tke->x0;
+		}
+
+		r = rectaddpt(Rect(xs0, 0, xs1, env->font->height), s.min);
+		tktextsdraw(i, r, env, 1);
+		runestringn(i, r.min, tkgc(env, TkCselectfgnd), r.min, env->font,
+				text+s0, s1-s0);
+	}
+
+	if((tke->flag&Ecursoron) && tke->icursor >= tke->v0 && tke->icursor <= tke->v1) {
+		r = Rect(
+			tke->xicursor - tke->x0, 0, 
+			tke->xicursor - tke->x0 + Inswidth, env->font->height
+		);
+		draw(i, rectaddpt(r, s.min), tkgc(env, TkCforegnd), nil, ZP);
+	}
+	if (tke->show)
+		free(text);
+}
+
+char*
+tkdrawentry(Tk *tk, Point orig)
+{
+	Point p;
+	TkEnv *env;
+	Rectangle r, s;
+	Image *i;
+	int xp, yp;
+
+	env = tk->env;
+
+	r.min = ZP;
+	r.max.x = tk->act.width + 2*tk->borderwidth;
+	r.max.y = tk->act.height + 2*tk->borderwidth;
+	i = tkitmp(env, r.max, TkCbackgnd);
+	if(i == nil)
+		return nil;
+
+	xp = tk->borderwidth + xinset(tk);
+	yp = tk->borderwidth + yinset(tk);
+	s = r;
+	s.min.x += xp;
+	s.max.x -= xp;
+	s.min.y += yp;
+	s.max.y -= yp;
+	tkentrytext(i, s, tk, env);
+
+	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+
+	if (tkhaskeyfocus(tk))
+		tkbox(i, insetrect(r, tk->borderwidth), tk->highlightwidth, tkgc(tk->env, TkChighlightfgnd));
+
+	p.x = tk->act.x + orig.x;
+	p.y = tk->act.y + orig.y;
+	r = rectaddpt(r, p);
+	draw(tkimageof(tk), r, i, nil, ZP);
+
+	return nil;
+}
+	
+char*
+tkentrysh(Tk *tk)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	int dx, top, bot;
+	char *val, *cmd, *v, *e;
+
+	if(tke->xscroll == nil)
+		return nil;
+
+	bot = 0;
+	top = Tkfpscalar;
+
+	if(tke->text != 0 && tke->textlen != 0) {
+		dx = tk->act.width - 2*xinset(tk);
+
+		if (tke->xlen > dx) {
+			bot = TKI2F(tke->x0) / tke->xlen;
+			top = TKI2F(tke->x0 + dx) / tke->xlen;
+		}
+	}
+
+	val = mallocz(Tkminitem, 0);
+	if(val == nil)
+		return TkNomem;
+	v = tkfprint(val, bot);
+	*v++ = ' ';
+	tkfprint(v, top);
+	cmd = mallocz(Tkminitem, 0);
+	if(cmd == nil) {
+		free(val);
+		return TkNomem;
+	}
+	sprint(cmd, "%s %s", tke->xscroll, val);
+	e = tkexec(tk->env->top, cmd, nil);
+	free(cmd);
+	free(val);
+	return e;
+}
+
+void
+tkentrygeom(Tk *tk)
+{
+	char *e;
+	e = tkentrysh(tk);
+	if ((e != nil) &&	/* XXX - Tad: should propagate not print */
+             (tk->name != nil))
+		print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
+	recalcentry(tk);
+}
+
+static char*
+tkentryconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkOptab tko[3];
+	TkEntry *tke = TKobj(TkEntry, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tke;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	bd = tk->borderwidth;
+	g = tk->req;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tksizeentry(tk);
+	tkgeomchg(tk, &g, bd);
+	recalcentry(tk);
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static char*
+tkentryparseindex(Tk *tk, char *buf, int *index)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	TkEnv *env;
+	char *mod;
+	int i, x, locked, modstart;
+
+	modstart = 0;
+	for(mod = buf; *mod != '\0'; mod++)
+		if(*mod == '-' || *mod == '+') {
+			modstart = *mod;
+			*mod = '\0';
+			break;
+		}
+	if(strcmp(buf, "end") == 0)
+		i = tke->textlen;
+	else
+	if(strcmp(buf, "anchor") == 0)
+		i = tke->anchor;
+	else
+	if(strcmp(buf, "insert") == 0)
+		i = tke->icursor;
+	else
+	if(strcmp(buf, "sel.first") == 0)
+		i = tke->sel0;
+	else
+	if(strcmp(buf, "sel.last") == 0)
+		i = tke->sel1;
+	else
+	if(buf[0] >= '0' && buf[0] <= '9')
+		i = atoi(buf);
+	else
+	if(buf[0] == '@') {
+		x = atoi(buf+1) - xinset(tk);
+		if(tke->textlen == 0) {
+			*index = 0;
+			return nil;
+		}
+		env = tk->env;
+		locked = lockdisplay(env->top->display);
+		i = x2index(tk, x + tke->x0, nil);	/* XXX could possibly select nearest character? */
+		if(locked)
+			unlockdisplay(env->top->display);
+	}
+	else
+		return TkBadix;
+
+	if(i < 0 || i > tke->textlen)
+		return TkBadix;
+	if(modstart) {
+		*mod = modstart;
+		i += atoi(mod);
+		if(i < 0)
+			i = 0;
+		if(i > tke->textlen)
+			i = tke->textlen;
+	}
+	*index = i;
+	return nil;
+}
+
+/*
+ * return bounding box of character at index, in coords relative to
+ * the top left position of the text.
+ */
+static Rectangle
+tkentrybbox(Tk *tk, int index)
+{
+	TkEntry *tke;
+	TkEnv *env;
+	Display *d;
+	int x, cw, locked;
+	Rectangle r;
+
+	tke = TKobj(TkEntry, tk);
+	env = tk->env;
+
+	d = env->top->display;
+
+	locked = lockdisplay(d);
+	x = entrytextwidth(tk, index);
+	if (index < tke->textlen)
+		cw = entrytextwidth(tk, index+1) - x;
+	else
+		cw = Inswidth;
+	if(locked)
+		unlockdisplay(d);
+
+	r.min.x = x;
+	r.min.y = 0;
+	r.max.x = x + cw;
+	r.max.y = env->font->height;
+	return r;
+}
+
+static void
+tkentrysee(Tk *tk, int index, int jump)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	int dx, margin;
+	Rectangle r;
+
+	r = tkentrybbox(tk, index);
+	dx = tk->act.width - 2*xinset(tk);
+	if (jump)
+		margin = dx / 4;
+	else
+		margin = 0;
+	if (r.min.x <= tke->x0 || r.max.x > tke->x0 + dx) {
+		if (r.min.x <= tke->x0) {
+			tke->x0 = r.min.x - margin;
+			if (tke->x0 < 0)
+				tke->x0 = 0;
+		} else if (r.max.x >= tke->x0 + dx) {
+			tke->x0 = r.max.x - dx + margin;
+			if (tke->x0 > tke->xlen - dx)
+				tke->x0 = tke->xlen - dx;
+		}
+		tk->dirty = tkrect(tk, 0);
+	}
+	r = rectaddpt(r, Pt(xinset(tk) - tke->x0, yinset(tk)));
+	tksee(tk, r, r.min);
+}
+
+static char*
+tkentryseecmd(Tk *tk, char *arg, char **val)
+{
+	int index;
+	char *e, *buf;
+
+	USED(val);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	e = tkentryparseindex(tk, buf, &index);
+	free(buf);
+	if(e != nil)
+		return e;
+
+	tkentrysee(tk, index, 1);
+	recalcentry(tk);
+	
+	return nil;
+}
+
+static char*
+tkentrybboxcmd(Tk *tk, char *arg, char **val)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	char *r, *buf;
+	int index;
+	Rectangle bbox;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	r = tkentryparseindex(tk, buf, &index);
+	free(buf);
+	if(r != nil)
+		return r;
+	bbox = rectaddpt(tkentrybbox(tk, index), Pt(xinset(tk) - tke->x0, yinset(tk)));
+	return tkvalue(val, "%d %d %d %d", bbox.min.x, bbox.min.y, bbox.max.x, bbox.max.y);
+}
+
+static char*
+tkentryindex(Tk *tk, char *arg, char **val)
+{
+	int index;
+	char *r, *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	r = tkentryparseindex(tk, buf, &index);
+	free(buf);
+	if(r != nil)
+		return r;
+	return tkvalue(val, "%d", index);
+}
+
+static char*
+tkentryicursor(Tk *tk, char *arg, char **val)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	int index, locked;
+	char *r, *buf;
+
+	USED(val);
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	r = tkentryparseindex(tk, buf, &index);
+	free(buf);
+	if(r != nil)
+		return r;
+	tke->icursor = index;
+	locked = lockdisplay(tk->env->top->display);
+	tke->xicursor = entrytextwidth(tk, tke->icursor);
+	if (locked)
+		unlockdisplay(tk->env->top->display);
+
+	blinkreset(tk);
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static int
+adjustforins(int i, int n, int q)
+{
+	if (i <= q)
+		q += n;
+	return q;
+}
+
+static int
+adjustfordel(int d0, int d1, int q)
+{
+	if (d1 <= q)
+		q -= d1 - d0;
+	else if (d0 <= q && q <= d1)
+		q = d0;
+	return q;
+}
+
+static char*
+tkentryget(Tk *tk, char *arg, char **val)
+{
+	TkTop *top;
+	TkEntry *tke;
+	int first, last;
+	char *e, *buf;
+
+	tke = TKobj(TkEntry, tk);	
+	if(tke->text == nil)
+		return nil;
+
+	arg = tkskip(arg, " \t");
+	if(*arg == '\0')
+		return tkvalue(val, "%.*S", tke->textlen, tke->text);
+
+	top = tk->env->top;
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+	e = tkentryparseindex(tk, buf, &first);
+	if(e != nil) {
+		free(buf);
+		return e;
+	}
+	last = first+1;
+	tkword(top, arg, buf, buf+Tkmaxitem, nil);
+	if(buf[0] != '\0') {
+		e = tkentryparseindex(tk, buf, &last);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+	}
+	free(buf);
+	if(last <= first || tke->textlen == 0 || first == tke->textlen)
+		return tkvalue(val, "%S", L"");
+	return tkvalue(val, "%.*S", last-first, tke->text+first);
+}
+
+static char*
+tkentryinsert(Tk *tk, char *arg, char **val)
+{
+	TkTop *top;
+	TkEntry *tke;
+	int ins, i, n, locked;
+	char *e, *t, *text, *buf;
+	Rune *etext;
+
+	USED(val);
+	tke = TKobj(TkEntry, tk);
+
+	top = tk->env->top;
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+	e = tkentryparseindex(tk, buf, &ins);
+	free(buf);
+	if(e != nil)
+		return e;
+
+	if(*arg == '\0')
+		return nil;
+
+	n = strlen(arg) + 1;
+	if(n < Tkmaxitem)
+		n = Tkmaxitem;
+	text = malloc(n);
+	if(text == nil)
+		return TkNomem;
+
+	tkword(top, arg, text, text+n, nil);
+	n = utflen(text);
+	etext = realloc(tke->text, (tke->textlen+n+1)*sizeof(Rune));
+	if(etext == nil) {
+		free(text);
+		return TkNomem;
+	}
+	tke->text = etext;
+
+	memmove(tke->text+ins+n, tke->text+ins, (tke->textlen-ins)*sizeof(Rune));
+	t = text;
+	for(i=0; i<n; i++)
+		t += chartorune(tke->text+ins+i, t);
+	free(text);
+
+	tke->textlen += n;
+
+	tke->sel0 = adjustforins(ins, n, tke->sel0);
+	tke->sel1 = adjustforins(ins, n, tke->sel1);
+	tke->icursor = adjustforins(ins, n, tke->icursor);
+	tke->anchor = adjustforins(ins, n, tke->anchor);
+
+	locked = lockdisplay(tk->env->top->display);
+	if (ins < tke->v0)
+		tke->x0 += entrytextwidth(tk, tke->v0 + n) + (tke->x0 - tke->xv0);
+	if (locked)
+		unlockdisplay(tk->env->top->display);
+	recalcentry(tk);
+
+	e = tkentrysh(tk);
+	blinkreset(tk);
+	tk->dirty = tkrect(tk, 1);
+
+	return e;
+}
+
+static char*
+tkentrydelete(Tk *tk, char *arg, char **val)
+{
+	TkTop *top;
+	TkEntry *tke;
+	int d0, d1, locked;
+	char *e, *buf;
+	Rune *text;
+
+	USED(val);
+
+	tke = TKobj(TkEntry, tk);
+
+	top = tk->env->top;
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+	e = tkentryparseindex(tk, buf, &d0);
+	if(e != nil) {
+		free(buf);
+		return e;
+	}
+
+	d1 = d0+1;
+	tkword(top, arg, buf, buf+Tkmaxitem, nil);
+	if(buf[0] != '\0') {
+		e = tkentryparseindex(tk, buf, &d1);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+	}
+	free(buf);
+	if(d1 <= d0 || tke->textlen == 0 || d0 >= tke->textlen)
+		return nil;
+
+	memmove(tke->text+d0, tke->text+d1, (tke->textlen-d1)*sizeof(Rune));
+	tke->textlen -= d1 - d0;
+
+	text = realloc(tke->text, (tke->textlen+1) * sizeof(Rune));
+	if (text != nil)
+		tke->text = text;
+	tke->sel0 = adjustfordel(d0, d1, tke->sel0);
+	tke->sel1 = adjustfordel(d0, d1, tke->sel1);
+	tke->icursor = adjustfordel(d0, d1, tke->icursor);
+	tke->anchor = adjustfordel(d0, d1, tke->anchor);
+
+	locked = lockdisplay(tk->env->top->display);
+	if (d1 < tke->v0)
+		tke->x0 = entrytextwidth(tk, tke->v0 - (d1 - d0)) + (tke->x0 - tke->xv0);
+	else if (d0 < tke->v0)
+		tke->x0 = entrytextwidth(tk, d0);
+	if (locked)
+		unlockdisplay(tk->env->top->display);
+	recalcentry(tk);
+
+	e = tkentrysh(tk);
+	blinkreset(tk);
+	tk->dirty = tkrect(tk, 1);
+
+	return e;
+}
+
+/*	Used for both backspace and DEL.  If a selection exists, delete it.
+ *	Otherwise delete the character to the left(right) of the insertion
+ *	cursor, if any.
+ */
+static char*
+tkentrybs(Tk *tk, char *arg, char **val)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	char *buf, *e;
+	int ix;
+
+	USED(val);
+	USED(arg);
+
+	if(tke->textlen == 0)
+		return nil;
+
+	if(tke->sel0 < tke->sel1)
+		return tkentrydelete(tk, "sel.first sel.last", nil);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	ix = -1;
+	if(buf[0] != '\0') {
+		e = tkentryparseindex(tk, buf, &ix);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+	}
+	if(ix > -1) {			/* DEL */
+		if(tke->icursor >= tke->textlen) {
+			free(buf);
+			return nil;
+		}
+	}
+	else {				/* backspace */
+		if(tke->icursor == 0) {
+			free(buf);
+			return nil;
+		}
+		tke->icursor--;
+	}
+	snprint(buf, Tkmaxitem, "%d", tke->icursor);
+	e = tkentrydelete(tk, buf, nil);
+	free(buf);
+	return e;
+}
+
+static char*
+tkentrybw(Tk *tk, char *arg, char **val)
+{
+	int start;
+	Rune *text;
+	TkEntry *tke;
+	char buf[32];
+
+	USED(val);
+	USED(arg);
+
+	tke = TKobj(TkEntry, tk);
+	if(tke->textlen == 0 || tke->icursor == 0)
+		return nil;
+
+	text = tke->text;
+	start = tke->icursor-1;
+	while(start > 0 && !tkiswordchar(text[start]))
+		--start;
+	while(start > 0 && tkiswordchar(text[start-1]))
+		--start;
+
+	snprint(buf, sizeof(buf), "%d %d", start, tke->icursor);
+	return tkentrydelete(tk, buf, nil);
+}
+
+char*
+tkentryselect(Tk *tk, char *arg, char **val)
+{
+	TkTop *top;
+	int start, from, to, locked;
+	TkEntry *tke;
+	char *e, *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	tke = TKobj(TkEntry, tk);
+
+	top = tk->env->top;
+	arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+	if(strcmp(buf, "clear") == 0) {
+		tke->sel0 = 0;
+		tke->sel1 = 0;
+	}
+	else
+	if(strcmp(buf, "from") == 0) {
+		tkword(top, arg, buf, buf+Tkmaxitem, nil);
+		e = tkentryparseindex(tk, buf, &tke->anchor);
+		tke->flag &= ~Ewordsel;
+		free(buf);
+		return e;
+	}
+	else
+	if(strcmp(buf, "to") == 0) {
+		tkword(top, arg, buf, buf+Tkmaxitem, nil);
+		e = tkentryparseindex(tk, buf, &to);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+		
+		if(to < tke->anchor) {
+			if(tke->flag & Ewordsel)
+				while(to > 0 && tkiswordchar(tke->text[to-1]))
+					--to;
+			tke->sel0 = to;
+			tke->sel1 = tke->anchor;
+		}
+		else
+		if(to >= tke->anchor) {
+			if(tke->flag & Ewordsel)
+				while(to < tke->textlen &&
+						tkiswordchar(tke->text[to]))
+					to++;
+			tke->sel0 = tke->anchor;
+			tke->sel1 = to;
+		}
+		tkentrysee(tk, to, 0);
+		recalcentry(tk);
+	}
+	else
+	if(strcmp(buf, "word") == 0) {	/* inferno invention */
+		tkword(top, arg, buf, buf+Tkmaxitem, nil);
+		e = tkentryparseindex(tk, buf, &start);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+		from = start;
+		while(from > 0 && tkiswordchar(tke->text[from-1]))
+			--from;
+		to = start;
+		while(to < tke->textlen && tkiswordchar(tke->text[to]))
+			to++;
+		tke->sel0 = from;
+		tke->sel1 = to;
+		tke->anchor = from;
+		tke->icursor = from;
+		tke->flag |= Ewordsel;
+		locked = lockdisplay(tk->env->top->display);
+		tke->xicursor = entrytextwidth(tk, tke->icursor);
+		if (locked)
+			unlockdisplay(tk->env->top->display);
+	}
+	else
+	if(strcmp(buf, "present") == 0) {
+		e = tkvalue(val, "%d", tke->sel1 > tke->sel0);
+		free(buf);
+		return e;
+	}
+	else
+	if(strcmp(buf, "range") == 0) {
+		arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+		e = tkentryparseindex(tk, buf, &from);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+		tkword(top, arg, buf, buf+Tkmaxitem, nil);
+		e = tkentryparseindex(tk, buf, &to);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+		tke->sel0 = from;
+		tke->sel1 = to;
+		if(to <= from) {
+			tke->sel0 = 0;
+			tke->sel1 = 0;
+		}
+	}
+	else
+	if(strcmp(buf, "adjust") == 0) {
+		tkword(top, arg, buf, buf+Tkmaxitem, nil);
+		e = tkentryparseindex(tk, buf, &to);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+		if(tke->sel0 == 0 && tke->sel1 == 0) {
+			tke->sel0 = tke->anchor;
+			tke->sel1 = to;
+		}
+		else {
+			if(abs(tke->sel0-to) < abs(tke->sel1-to)) {
+				tke->sel0 = to;
+				tke->anchor = tke->sel1;
+			}
+			else {
+				tke->sel1 = to;
+				tke->anchor = tke->sel0;
+			}
+		}
+		if(tke->sel0 > tke->sel1) {
+			to = tke->sel0;
+			tke->sel0 = tke->sel1;
+			tke->sel1 = to;
+		}
+	}
+	else {
+		free(buf);
+		return TkBadcm;
+	}
+	locked = lockdisplay(tk->env->top->display);
+	tke->xsel0 = entrytextwidth(tk, tke->sel0);
+	tke->xsel1 = entrytextwidth(tk, tke->sel1);
+	if (locked)
+		unlockdisplay(tk->env->top->display);
+	tk->dirty = tkrect(tk, 1);
+	free(buf);
+	return nil;
+}
+
+
+static char*
+tkentryb2p(Tk *tk, char *arg, char **val)
+{
+	TkEntry *tke;
+	char *buf;
+
+	USED(val);
+
+	tke = TKobj(TkEntry, tk);
+	buf = malloc(Tkmaxitem);
+	if (buf == nil)
+		return TkNomem;
+
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	tke->oldx = atoi(buf);
+	return nil;
+}
+
+static char*
+tkentryxview(Tk *tk, char *arg, char **val)
+{
+	int locked;
+	TkEnv *env;
+	TkEntry *tke;
+	char *buf, *v;
+	int dx, top, bot, amount, ix, x;
+	char *e;
+
+	tke = TKobj(TkEntry, tk);
+	env = tk->env;
+	dx = tk->act.width - 2*xinset(tk);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	if(*arg == '\0') {
+		if (tke->textlen == 0 || tke->xlen < dx) {
+			bot = TKI2F(0);
+			top = TKI2F(1);
+		} else {
+			bot = TKI2F(tke->x0) / tke->xlen;
+			top = TKI2F(tke->x0 + dx) / tke->xlen;
+		}
+		v = tkfprint(buf, bot);
+		*v++ = ' ';
+		tkfprint(v, top);
+		e = tkvalue(val, "%s", buf);
+		free(buf);
+		return e;
+	}
+
+	arg = tkitem(buf, arg);
+	if(strcmp(buf, "moveto") == 0) {
+		e = tkfracword(env->top, &arg, &top, nil);
+		if (e != nil) {
+			free(buf);
+			return e;
+		}
+		tke->x0 = TKF2I(top*tke->xlen);
+	}
+	else
+	if(strcmp(buf, "scroll") == 0) {
+		arg = tkitem(buf, arg);
+		amount = atoi(buf);
+		if(*arg == 'p')		/* Pages */
+			amount *= (9*tke->xlen)/10;
+		else
+		if(*arg == 's') {		/* Inferno-ism, "scr", must be used in the context of button2p */
+			x = amount;
+			amount = x < tke->oldx ? env->wzero : (x > tke->oldx ? -env->wzero : 0);
+			tke->oldx = x;
+		}
+		tke->x0 += amount;
+	}
+	else {
+		e = tkentryparseindex(tk, buf, &ix);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+		locked = lockdisplay(env->top->display);
+		tke->x0 = entrytextwidth(tk, ix);
+		if (locked)
+			unlockdisplay(env->top->display);
+	}
+	free(buf);
+
+	if (tke->x0 > tke->xlen - dx)
+		tke->x0 = tke->xlen - dx;
+	if (tke->x0 < 0)
+		tke->x0 = 0;
+	recalcentry(tk);
+	e = tkentrysh(tk);
+	blinkreset(tk);
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static void
+autoselect(Tk *tk, void *v, int cancelled)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	Rectangle hitr;
+	char buf[32];
+	Point p;
+
+	USED(v);
+
+	if (cancelled)
+		return;
+
+	p = tkscrn2local(tk, Pt(tke->oldx, 0));
+	p.y = 0;
+	if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
+		return;
+
+	snprint(buf, sizeof(buf), "to @%d", p.x);
+	tkentryselect(tk, buf, nil);
+	tkdirty(tk);
+	tkupdate(tk->env->top);
+}
+
+static char*
+tkentryb1p(Tk *tk, char* arg, char **ret)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	Point p;
+	int i, locked, x;
+	char buf[32], *e;
+	USED(ret);
+
+	x = atoi(arg);
+	p = tkscrn2local(tk, Pt(x, 0));
+	sprint(buf, "@%d", p.x);
+	e = tkentryparseindex(tk, buf, &i);
+	if (e != nil)
+		return e;
+	tke->sel0 = 0;
+	tke->sel1 = 0;
+	tke->icursor = i;
+	tke->anchor = i;
+	tke->flag &= ~Ewordsel;
+
+	locked = lockdisplay(tk->env->top->display);
+	tke->xsel0 = 0;
+	tke->xsel1 = 0;
+	tke->xicursor = entrytextwidth(tk, tke->icursor);
+	if (locked)
+		unlockdisplay(tk->env->top->display);
+
+	tke->oldx = x;
+	blinkreset(tk);
+	tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
+	tk->dirty = tkrect(tk, 0);
+	return nil;
+}
+
+static char*
+tkentryb1m(Tk *tk, char* arg, char **ret)
+{
+	TkEntry *tke = TKobj(TkEntry, tk);
+	Point p;
+	Rectangle hitr;
+	char buf[32];
+	USED(ret);
+
+	p.x = atoi(arg);
+	tke->oldx = p.x;
+	p = tkscrn2local(tk, p);
+	p.y = 0;
+	if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
+		return nil;
+	snprint(buf, sizeof(buf), "to @%d", p.x);
+	tkentryselect(tk, buf, nil);
+	return nil;
+}
+
+static char*
+tkentryb1r(Tk *tk, char* arg, char **ret)
+{
+	USED(tk);
+	USED(arg);
+	USED(ret);
+	tkcancelrepeat(tk);
+	return nil;
+}
+
+static void
+blinkreset(Tk *tk)
+{
+	TkEntry *e = TKobj(TkEntry, tk);
+	if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
+		return;
+	e->flag |= Ecursoron;
+	tkblinkreset(tk);
+}
+
+static void
+showcaret(Tk *tk, int on)
+{
+	TkEntry *e = TKobj(TkEntry, tk);
+
+	if (on)
+		e->flag |= Ecursoron;
+	else
+		e->flag &= ~Ecursoron;
+	tk->dirty = tkrect(tk, 0);
+}
+
+char*
+tkentryfocus(Tk *tk, char* arg, char **ret)
+{
+	int on = 0;
+	USED(ret);
+
+	if (tk->flag&Tkdisabled)
+		return nil;
+
+	if(strcmp(arg, " in") == 0) {
+		tkblink(tk, showcaret);
+		on = 1;
+	}
+	else
+		tkblink(nil, nil);
+
+	showcaret(tk, on);
+	return nil;
+}
+
+static
+TkCmdtab tkentrycmd[] =
+{
+	"cget",			tkentrycget,
+	"configure",		tkentryconf,
+	"delete",		tkentrydelete,
+	"get",			tkentryget,
+	"icursor",		tkentryicursor,
+	"index",		tkentryindex,
+	"insert",		tkentryinsert,
+	"selection",		tkentryselect,
+	"xview",		tkentryxview,
+	"tkEntryBS",		tkentrybs,
+	"tkEntryBW",		tkentrybw,
+	"tkEntryB1P",		tkentryb1p,
+	"tkEntryB1M",		tkentryb1m,
+	"tkEntryB1R",		tkentryb1r,
+	"tkEntryB2P",		tkentryb2p,
+	"tkEntryFocus",		tkentryfocus,
+	"bbox",			tkentrybboxcmd,
+	"see",		tkentryseecmd,
+	nil
+};
+
+TkMethod entrymethod = {
+	"entry",
+	tkentrycmd,
+	tkfreeentry,
+	tkdrawentry,
+	tkentrygeom
+};
--- /dev/null
+++ b/libtk/extns.c
@@ -1,0 +1,37 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+int	
+tkextndeliver(Tk *tk, TkAction *binds, int event, void *data)
+{
+	return tksubdeliver(tk, binds, event, data, 1);
+}
+
+void
+tkextnfreeobj(Tk *tk)
+{
+	USED(tk);
+}
+
+int
+tkextnnewctxt(TkCtxt *ctxt)
+{
+	USED(ctxt);
+	return 0;
+}
+
+void
+tkextnfreectxt(TkCtxt *ctxt)
+{
+	USED(ctxt);
+}
+
+char*
+tkextnparseseq(char *seq, char *rest, int *event)
+{
+	USED(seq);
+	USED(rest);
+	USED(event);
+	return nil;
+}
--- /dev/null
+++ b/libtk/frame.c
@@ -1,0 +1,277 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "frame.h"
+
+char*
+tkframe(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkOptab tko[2];
+	TkName *names;
+
+	tk = tknewobj(t, TKframe, sizeof(Tk));
+	if(tk == nil)
+		return TkNomem;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = nil;
+	names = nil;
+
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+	e = tkaddchild(t, tk, &names);
+
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+/*
+ * Also used for windows, menus, separators
+ */
+void
+tkfreeframe(Tk *tk)
+{
+	TkWin *tkw;
+
+	if((tk->flag & Tkwindow) == 0)
+		return;
+
+	if(tk->type == TKmenu) {
+		tkw = TKobj(TkWin, tk);
+		free(tkw->postcmd);
+		free(tkw->cascade);
+		free(tkw->cbname);
+	}
+
+	tkunmap(tk);		/* XXX do this only if (tk->flag&Tkswept)==0 ?? */
+}
+
+char*
+tkdrawframe(Tk *tk, Point orig)
+{	
+	int bw;
+	Point p;
+	Image *i;
+	Tk *f;
+	Rectangle r, slaver;		/* dribbling, whipping or just square? */
+
+	i = tkimageof(tk);
+	if(i == nil)
+		return nil;
+	
+	p.x = orig.x + tk->act.x + tk->borderwidth;
+	p.y = orig.y + tk->act.y + tk->borderwidth;
+
+	draw(i, rectaddpt(tk->dirty, p), tkgc(tk->env, TkCbackgnd), nil, ZP);
+
+	/*
+	 * doesn't matter about drawing TKseparator
+	 * oblivious of dirty rect, as it never has any children to sully anyway
+	 */
+	if(tk->type == TKseparator) {
+		r = rectaddpt(tkrect(tk, 1), p);
+		r.min.x += 4;
+		r.max.x -= 4;
+		r.min.y += (Dy(r) - 2)/2;
+		r.max.y = r.min.y+1;
+		draw(i, r, tkgc(tk->env, TkCbackgnddark), nil, ZP);
+		r.min.y += 1;
+		r.max.y += 1;
+		draw(i, r, tkgc(tk->env, TkCbackgndlght), nil, ZP);
+		return nil;
+	}
+
+	/*
+	 * make sure all the slaves inside the area we've just drawn
+	 * refresh themselves properly.
+	 */
+	for(f = tk->slave; f; f = f->next) {
+		bw = f->borderwidth;
+		slaver.min.x = f->act.x;
+		slaver.min.y = f->act.y;
+		slaver.max.x = slaver.min.x + f->act.width + 2*bw;
+		slaver.max.y = slaver.min.y + f->act.height + 2*bw;
+		if (rectclip(&slaver, tk->dirty)) {
+			f->flag |= Tkrefresh;
+			slaver = rectsubpt(slaver, Pt(f->act.x + bw, f->act.y + bw));
+			combinerect(&f->dirty, slaver);
+		}
+	}
+	p.x -= tk->borderwidth;
+	p.y -= tk->borderwidth;
+
+	if (!rectinrect(tk->dirty, tkrect(tk, 0)))
+		tkdrawrelief(i, tk, p, TkCbackgnd, tk->relief);
+	return nil;
+}
+
+/* Frame commands */
+
+static char*
+tkframecget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = nil;
+	if(tk->flag & Tkwindow){
+		tko[1].ptr = TKobj(TkWin, tk);
+		tko[1].optab = tktop;
+		tko[2].ptr = nil;
+	}
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkframeconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	Point oldp;
+	TkOptab tko[3];
+	TkWin *tkw;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = nil;
+	tkw = nil;
+	if(tk->flag & Tkwindow) {
+		tkw = TKobj(TkWin, tk);
+		tko[1].ptr = tkw;
+		tko[1].optab = tktop;
+		tko[2].ptr = nil;
+		oldp = tkw->act;
+	}
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	if(tkw != nil){
+		/*
+		 * see whether only -x or -y is being configured,
+		 * in which case just move the window; don't redraw
+		 * everything
+		 */
+		e = tkparse(tk->env->top, arg, &tko[1], nil);
+		if(e == nil){
+			if(!eqpt(oldp, tkw->req))
+				tkmovewin(tk, tkw->req);
+			return nil;
+		}
+	}
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tk->req.x = tk->act.x;
+	tk->req.y = tk->act.y;
+	tkgeomchg(tk, &g, bd);
+	if(tkw != nil && !eqpt(oldp, tkw->act))
+		tkmovewin(tk, tkw->req);
+
+	tk->dirty = tkrect(tk, 1);
+
+	return e;
+}
+
+static char*
+tkframesuspend(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+	if((tk->flag & Tkwindow) == 0)
+		return TkNotwm;
+	tk->flag |= Tksuspended;
+	return nil;
+}
+
+static char*
+tkframemap(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+	if(tk->flag & Tkwindow)
+		return tkmap(tk);
+	return TkNotwm;
+}
+
+static char*
+tkframeunmap(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+	if(tk->flag & Tkwindow) {
+		tkunmap(tk);
+		return nil;
+	}
+	return TkNotwm;
+}
+
+static void
+tkframefocusorder(Tk *tk)
+{
+	int i, n;
+	Tk *sub;
+	TkWinfo *inf;
+
+	n = 0;
+	for (sub = tk->slave; sub != nil; sub = sub->next)
+		n++;
+
+	if (n == 0)
+		return;
+
+	inf = malloc(sizeof(*inf) * n);
+	if (inf == nil)
+		return;
+	i = 0;
+	for (sub = tk->slave; sub != nil; sub = sub->next) {
+		inf[i].w = sub;
+		inf[i].r = rectaddpt(tkrect(sub, 1), Pt(sub->act.x, sub->act.y));
+		i++;
+	}
+	tksortfocusorder(inf, n);
+	for (i = 0; i < n; i++)
+		tkappendfocusorder(inf[i].w);
+	free(inf);
+}
+
+static
+TkCmdtab tkframecmd[] =
+{
+	"cget",			tkframecget,
+	"configure",		tkframeconf,
+	"map",			tkframemap,
+	"unmap",		tkframeunmap,
+	"suspend",		tkframesuspend,
+	nil
+};
+
+TkMethod framemethod = {
+	"frame",
+	tkframecmd,
+	tkfreeframe,
+	tkdrawframe,
+	nil,
+	nil,
+	tkframefocusorder
+};
--- /dev/null
+++ b/libtk/frame.h
@@ -1,0 +1,2 @@
+extern	char*		tkdrawframe(Tk*, Point);
+extern	void		tkfreeframe(Tk*);
--- /dev/null
+++ b/libtk/grids.c
@@ -1,0 +1,1526 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+/*
+ * XXX TODO
+ * - grid rowcget|columncget
+ * - grid columnconfigure/rowconfigure accepts a list of indexes?
+ */
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+typedef struct TkGridparam TkGridparam;
+typedef struct TkBeamparam TkBeamparam;
+
+struct TkGridparam{
+	Point	span;
+	Tk*	in;
+	Point	pad;
+	Point ipad;
+	char	*row;
+	char *col;
+	int	sticky;
+};
+
+struct TkBeamparam{
+	int	minsize;
+	int	maxsize;
+	int	weight;
+	int	pad;
+	char	*name;
+	int	equalise;
+};
+
+static
+TkOption opts[] =
+{
+	"padx",		OPTnndist,	O(TkGridparam, pad.x),	nil,
+	"pady",		OPTnndist,	O(TkGridparam, pad.y),	nil,
+	"ipadx",	OPTnndist,	O(TkGridparam, ipad.x),	nil,
+	"ipady",	OPTnndist,	O(TkGridparam, ipad.y),	nil,
+	"in",		OPTwinp,		O(TkGridparam, in),		nil,
+	"row",	OPTtext,		O(TkGridparam, row), nil,
+	"column",	OPTtext,		O(TkGridparam, col), nil,
+	"rowspan",	OPTnndist,	O(TkGridparam, span.y), nil,
+	"columnspan",	OPTnndist,	O(TkGridparam, span.x), nil,
+	"sticky",	OPTsticky,		O(TkGridparam, sticky), nil,
+	nil
+};
+
+static
+TkOption beamopts[] =
+{
+	"minsize",		OPTnndist,	O(TkBeamparam, minsize),	nil,
+	"maxsize",	OPTnndist,	O(TkBeamparam, maxsize),	nil,
+	"weight",		OPTnndist,	O(TkBeamparam, weight),	nil,
+	"pad",		OPTnndist,	O(TkBeamparam, pad),		nil,
+	"name",		OPTtext,		O(TkBeamparam, name),		nil,
+	"equalise",	OPTstab,		O(TkBeamparam, equalise),	tkbool,
+	nil
+};
+
+void
+printgrid(TkGrid *grid)
+{
+	int x, y;
+	Point dim;
+
+	dim = grid->dim;
+	print("grid %P\n", grid->dim);
+	print("  row heights: ");
+	for(y = 0; y < dim.y; y++)
+		print("%d[%d,%d,w%d,p%d]%s ",
+			grid->rows[y].act,
+			grid->rows[y].minsize,
+			grid->rows[y].maxsize < 0x7fffffff ? grid->rows[y].maxsize : -1,
+			grid->rows[y].weight,
+			grid->rows[y].pad,
+			grid->rows[y].name ? grid->rows[y].name : "");
+	print("\n");
+	print("  col widths: ");
+	for(x = 0; x < dim.x; x++)
+		print("%d[%d,%d,w%d,p%d]%s ",
+			grid->cols[x].act,
+			grid->cols[x].minsize,
+			grid->cols[x].maxsize < 0x7fffffff ? grid->cols[x].maxsize : -1,
+			grid->cols[x].weight,
+			grid->cols[x].pad,
+			grid->cols[x].name ? grid->cols[x].name : "");
+	print("\n");
+	for(y = 0; y < dim.y; y++){
+		print("  row %d: ", y);
+		for(x = 0; x < dim.x; x++){
+			print("%p;", grid->cells[y][x].tk);
+			print("%s%P\t", grid->cells[y][x].tk?grid->cells[y][x].tk->name->name:"(nil)",
+				grid->cells[y][x].span);
+		}
+		print("\n");
+	}
+}
+
+static void
+tkgridsetopt(TkGridparam *p, Tk *tk)
+{
+	if(p->pad.x != -1)
+		tk->pad.x = p->pad.x*2;
+	if(p->pad.y != -1)
+		tk->pad.y = p->pad.y*2;
+	if(p->ipad.x != -1)
+		tk->ipad.x = p->ipad.x*2;
+	if(p->ipad.y != -1)
+		tk->ipad.y = p->ipad.y*2;
+	if(p->sticky != -1)
+		tk->flag = (tk->flag & ~(Tkanchor|Tkfill)) | (p->sticky & (Tkanchor|Tkfill));
+}
+
+static void
+initbeam(TkGridbeam *beam, int n)
+{
+	int i;
+	memset(beam, 0, n * sizeof(TkGridbeam));
+	for(i = 0; i < n; i++)
+		beam[i].maxsize = 0x7fffffff;
+}
+
+static char*
+ensuregridsize(TkGrid *grid, Point dim)
+{
+	TkGridcell **cells, *cellrow;
+	TkGridbeam *cols, *rows;
+	Point olddim;
+	int i;
+	olddim = grid->dim;
+	if(dim.x < olddim.x)
+		dim.x = olddim.x;
+	if(dim.y < olddim.y)
+		dim.y = olddim.y;
+	if(dim.y > olddim.y){
+		cells = realloc(grid->cells, sizeof(TkGridcell*)*dim.y);
+		if(cells == nil)
+			return TkNomem;
+		grid->cells = cells;
+		for(i = olddim.y; i < dim.y; i++){
+			cells[i] = malloc(sizeof(TkGridcell)*dim.x);
+			if(cells[i] == nil){
+				while(--i >= olddim.y)
+					free(cells[i]);
+				return TkNomem;
+			}
+		}
+		rows = realloc(grid->rows, sizeof(TkGridbeam)*dim.y);
+		if(rows == nil)
+			return TkNomem;
+		grid->rows = rows;
+		initbeam(rows + olddim.y, dim.y - olddim.y);
+		grid->dim.y = dim.y;
+	}
+
+	if(dim.x > olddim.x){
+		/*
+		 * any newly allocated rows will have the correct number of
+		 * columns, so we don't need to reallocate them
+		 */
+		cells = grid->cells;
+		for(i = 0; i < olddim.y; i++){
+			cellrow = realloc(cells[i], sizeof(TkGridcell) * dim.x);
+			if(cellrow == nil)
+				return TkNomem;	/* leak some earlier rows, but not permanently */
+			memset(cellrow + olddim.x, 0, (dim.x-olddim.x)*sizeof(TkGridcell));
+			cells[i] = cellrow;
+		}
+		cols = realloc(grid->cols, sizeof(TkGridbeam)*dim.x);
+		if(cols == nil)
+			return TkNomem;
+		initbeam(cols + olddim.x, dim.x - olddim.x);
+		grid->cols = cols;
+		grid->dim.x = dim.x;
+	}
+	return nil;
+}
+
+static TkGridbeam*
+delbeams(TkGridbeam *beam, int nb, int x0, int x1)
+{
+	int i;
+	TkGridbeam *b;
+	for(i = x0; i < x1; i++)
+		free(beam[i].name);
+	memmove(&beam[x0], &beam[x1], sizeof(TkGridbeam) * (nb-x1));
+	b = realloc(beam, sizeof(TkGridbeam) * (nb-(x1-x0)));
+	return b ? b : beam;
+}
+
+static void
+delrows(TkGrid *grid, int y0, int y1)
+{
+	TkGridcell **cells;
+	memmove(grid->cells+y0, grid->cells+y1, sizeof(TkGridcell*) * (grid->dim.y-y1));
+	grid->dim.y -= (y1 - y0);
+	cells = realloc(grid->cells, sizeof(TkGridcell*) * grid->dim.y);
+	if(cells != nil || grid->dim.y == 0)
+		grid->cells = cells;		/* can realloc to a smaller size ever fail? */
+}
+
+static void
+delcols(TkGrid *grid, int x0, int x1)
+{
+	TkGridcell **cells, *row;
+	int y, ndx;
+	Point dim;
+	dim = grid->dim;
+	ndx = dim.x - (x1 - x0);
+	cells = grid->cells;
+	for(y = 0; y < dim.y; y++){
+		row = cells[y];
+		memmove(row+x0, row+x1, sizeof(TkGridcell) * (dim.x - x1));
+		row = realloc(row, sizeof(TkGridcell) * ndx);
+		if(row != nil || ndx == 0)
+			cells[y] = row;
+	}
+	grid->dim.x = ndx;
+}
+
+/*
+ * insert items into rows/cols; the beam has already been expanded appropriately.
+ */
+void
+insbeams(TkGridbeam *beam, int nb, int x, int n)
+{
+	memmove(&beam[x+n], &beam[x], sizeof(TkGridbeam)*(nb-x-n));
+	initbeam(beam+x, n);
+}
+
+static char*
+insrows(TkGrid *grid, int y0, int n)
+{
+	Point olddim;
+	char *e;
+	TkGridcell **cells, *tmp;
+	int y;
+
+	olddim = grid->dim;
+	if(y0 > olddim.y){
+		n = y0 + n - olddim.y;
+		y0 = olddim.y;
+	}
+
+	e = ensuregridsize(grid, Pt(olddim.x, olddim.y + n));
+	if(e != nil)
+		return e;
+	/*
+	 * we know the extra rows will have been filled
+	 * with blank, properly allocated rows, so just swap 'em with the
+	 * ones that need moving.
+	 */
+	cells = grid->cells;
+	for(y = olddim.y - 1; y >= y0; y--){
+		tmp = cells[y + n];
+		cells[y + n] = cells[y];
+		cells[y] = tmp;
+	}
+	insbeams(grid->rows, grid->dim.y, y0, n);
+	return nil;
+}
+
+static char*
+inscols(TkGrid *grid, int x0, int n)
+{
+	TkGridcell **cells;
+	Point olddim;
+	int y;
+	char *e;
+
+	olddim = grid->dim;
+	if(x0 > olddim.x){
+		n = x0 + n - olddim.x;
+		x0 = olddim.x;
+	}
+
+	e = ensuregridsize(grid, Pt(olddim.x + n, olddim.y));
+	if(e != nil)
+		return e;
+
+	cells = grid->cells;
+	for(y = 0; y < olddim.y; y++){
+		memmove(cells[y] + x0 + n, cells[y] + x0, sizeof(TkGridcell) * (olddim.x - x0));
+		memset(cells[y] + x0, 0, sizeof(TkGridcell) * n);
+	}
+	insbeams(grid->cols, grid->dim.x, x0, n);
+	return nil;
+}
+
+static int
+maximum(int a, int b)
+{
+	if(a > b)
+		return a;
+	return b;
+}
+
+/*
+ * return the width of cols/rows between x0 and x1 in the beam,
+ * excluding the padding at either end, but including padding in the middle.
+ */
+static int
+beamsize(TkGridbeam *cols, int x0, int x1)
+{
+	int tot, fpad, x;
+
+	if(x0 >= x1)
+		return 0;
+
+	tot = cols[x0].act;
+	fpad = cols[x0].pad;
+	for(x = x0 + 1; x < x1; x++){
+		tot += cols[x].act + maximum(cols[x].pad, fpad);
+		fpad = cols[x].pad;
+	}
+	return tot;
+}
+
+/*
+ * return starting position of cell index on beam, relative
+ * to top-left of grid
+ */
+static int
+beamcellpos(TkGridbeam *beam, int blen, int index)
+{
+	int x;
+	if(blen == 0 || index >= blen || index < 0)
+		return 0;
+	x = beam[0].pad + beamsize(beam, 0, index);
+	if(index > 0)
+		x += maximum(beam[index-1].pad, beam[index].pad);
+	return x;
+}
+
+static Rectangle
+cellbbox(TkGrid *grid, Point pos)
+{
+	Point dim;
+	Rectangle r;
+
+	dim = grid->dim;
+	if(pos.x > dim.x)
+		pos.x = dim.x;
+	if(pos.y > dim.y)
+		pos.y = dim.y;
+
+	r.min.x = beamcellpos(grid->cols, dim.x, pos.x);
+	r.min.y = beamcellpos(grid->rows, dim.y, pos.y);
+	if(pos.x == dim.x)
+		r.max.x = r.min.x;
+	else
+		r.max.x = r.min.x + grid->cols[pos.x].act;
+	if(pos.y == dim.y)
+		r.max.y = r.min.y;
+	else
+		r.max.y = r.min.y + grid->rows[pos.y].act;
+	return rectaddpt(r, grid->origin);
+}
+
+/*
+ * return true ifthere are any spanning cells covering row _index_
+ */
+static int
+gridrowhasspan(TkGrid *grid, int index)
+{
+	int i, d;
+	Point dim;
+	TkGridcell *cell;
+
+	dim = grid->dim;
+	if(index > 0 && index < dim.y){
+		for(i = 0; i < dim.x; i++){
+			cell = &grid->cells[index][i];
+			if(cell->tk != nil){
+				d = cell->span.x;
+				if(d == 0)
+					return 1;
+				i += d - 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * return true ifthere are any spanning cells covering column _index_
+ */
+static int
+gridcolhasspan(TkGrid *grid, int index)
+{
+	int i, d;
+	Point dim;
+	TkGridcell *cell;
+
+	dim = grid->dim;
+	if(index > 0 && index < dim.x){
+		for(i = 0; i < dim.y; i++){
+			cell = &grid->cells[i][index];
+			if(cell->tk != nil){
+				d = cell->span.y;
+				if(d == 0)
+					return 1;
+				i += d - 1;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * find cell that's spanning the grid position p
+ */
+static int
+findspan(TkGrid *grid, Point p, Point *cp)
+{
+	Point dim;
+	TkGridcell **cells;
+	Tk *tk;
+
+	dim = grid->dim;
+	cells = grid->cells;
+
+	if(p.x < 0 || p.y < 0 || p.x >= dim.x || p.y >= dim.y)
+		return 0;
+
+	if(cells[p.y][p.x].tk == nil)
+		return 0;
+
+	if(cells[p.y][p.x].span.x == 0){
+		tk = cells[p.y][p.x].tk;
+		for(; p.y >= 0; p.y--)
+			if(cells[p.y][p.x].tk != tk)
+				break;
+		p.y++;
+		for(; p.x >= 0; p.x--)
+			if(cells[p.y][p.x].tk != tk)
+				break;
+		p.x++;
+	}
+	*cp = p;
+	return 1;
+}
+
+static int
+parsegridindex(TkGridbeam *beam, int blen, char *s)
+{
+	int n, i;
+	char *e;
+
+	if(s[0] == '\0')
+		return -1;
+
+	n = strtol(s, &e, 10);
+	if(*e == '\0')
+		return n;
+
+	if(strcmp(s, "end") == 0)
+		return blen;
+
+	for(i = 0; i < blen; i++)
+		if(beam[i].name != nil && strcmp(beam[i].name, s) == 0)
+			return i;
+	return -1;
+}
+
+static char*
+tkgridconfigure(TkTop *t, TkGridparam *p, TkName *names)
+{
+	TkGrid *grid;
+	TkGridcell **cells;
+	TkName *n;
+	Tk *tkf, *tkp;
+	Point dim, pos, q, span, startpos;
+	int maxcol, c, i, j, x;
+	char *e;
+
+	if(names == nil)
+		return nil;
+
+	if(p->span.x < 1 || p->span.y < 1)
+		return TkBadvl;
+
+	tkf = nil;
+
+	maxcol = 0;
+	for(n = names; n; n = n->link){
+		c = n->name[0];
+		if((c=='-' || c=='^' || c=='x') && n->name[1] == '\0'){
+			maxcol++;
+			continue;
+		}
+		tkp = tklook(t, n->name, 0);
+		if(tkp == nil){
+			tkerr(t, n->name);
+			return TkBadwp;
+		}
+		if(tkp->flag & Tkwindow)
+			return TkIstop;
+		if(tkp->parent != nil)
+			return TkWpack;
+	
+		/*
+		 * unpacking now does give an non-reversible side effect
+		 * ifthere's an error encountered later, but also means
+		 * that a widget repacked in the same grid will
+		 * have its original cell still available
+		 */
+		if(tkp->master != nil){
+			tkpackqit(tkp->master);
+			tkdelpack(tkp);
+		}
+		if(tkf == nil)
+			tkf = tkp;
+		n->obj = tkp;
+		tkp->flag &= ~Tkgridpack;
+		maxcol += p->span.x;
+	}
+
+	if(p->in == nil && tkf != nil)
+		p->in = tklook(t, tkf->name->name, 1);
+
+	if(p->in == nil)
+		return TkNomaster;
+
+	grid = p->in->grid;
+	if(grid == nil && p->in->slave != nil)
+		return TkNotgrid;
+
+	if(grid == nil){
+		grid = malloc(sizeof(TkGrid));
+		if(grid == nil)
+			return TkNomem;
+		p->in->grid = grid;
+	}
+
+	dim = grid->dim;
+	pos = ZP;
+	if(p->row != nil){
+		pos.y = parsegridindex(grid->rows, dim.y, p->row);
+		if(pos.y < 0)
+			return TkBadix;
+	}
+	if(p->col != nil){
+		pos.x = parsegridindex(grid->cols, dim.x, p->col);
+		if(pos.x < 0)
+			return TkBadix;
+	}
+	/*
+	 * ifrow is not specified, find first unoccupied row
+	 */
+	if(p->row == nil){
+		for(pos.y = 0; pos.y < dim.y; pos.y++){
+			for(x = 0; x < dim.x; x++)
+				if(grid->cells[pos.y][x].tk != nil)
+					break;
+			if(x == dim.x)
+				break;
+		}
+	}
+	e = ensuregridsize(grid, Pt(pos.x + maxcol, pos.y + p->span.y));
+	if(e != nil)
+		return e;
+	cells = grid->cells;
+
+	startpos = pos;
+	/*
+	 * check that all our grid cells are empty, and that row/col spans
+	 * are well formed
+	 */
+	n = names;
+	while(n != nil){
+		c = n->name[0];
+		switch (c){
+		case 'x':
+			n = n->link;
+			pos.x++;
+			break;
+		case '^':
+			if(findspan(grid, Pt(pos.x, pos.y - 1), &q) == 0)
+				return TkBadspan;
+			span = cells[q.y][q.x].span;
+			for(i = 0; i < span.x; i++){
+				if(n == nil || strcmp(n->name, "^"))
+					return TkBadspan;
+				if(cells[pos.y][pos.x + i].tk != nil)
+					return TkBadgridcell;
+				n = n->link;
+			}
+			pos.x += span.x;
+			break;
+		case '-':
+			return TkBadspan;
+		case '.':
+			tkp = n->obj;
+			if(tkisslave(p->in, tkp))
+				return TkRecur;
+			n = n->link;
+			if(tkp->flag & Tkgridpack)
+				return TkWpack;
+			tkp->flag |= Tkgridpack;
+			span = p->span;
+			for(; n != nil && strcmp(n->name, "-") == 0; n = n->link)
+				span.x++;
+			for(i = pos.x; i < pos.x + span.x; i++)
+				for(j = pos.y; j < pos.y + span.y; j++)
+					if(cells[j][i].tk != nil)
+						return TkBadgridcell;
+			pos.x = i;
+			break; 
+		}
+	}
+
+	/*
+	 * actually insert the items into the grid
+	 */
+	n = names;
+	pos = startpos;
+	while(n != nil){
+		c = n->name[0];
+		switch (c){
+		case 'x':
+			n = n->link;
+			pos.x++;
+			break;
+		case '^':
+			findspan(grid, Pt(pos.x, pos.y - 1), &q);
+			span = cells[q.y][q.x].span;
+			tkf = cells[q.y][q.x].tk;
+			if(q.y + span.y == pos.y)
+				cells[q.y][q.x].span.y++;
+
+			for(i = 0; i < span.x; i++){
+				cells[pos.y][pos.x++].tk = tkf;
+				n = n->link;
+			}
+			break;
+		case '.':
+			tkf = n->obj;
+			n = n->link;
+			span = p->span;
+			for(; n != nil && strcmp(n->name, "-") == 0; n = n->link)
+				span.x++;
+			for(i = pos.x; i < pos.x + span.x; i++)
+				for(j = pos.y; j < pos.y + span.y; j++)
+					cells[j][i].tk = tkf;
+			cells[pos.y][pos.x].span = span;
+			tkf->master = p->in;
+			tkf->next = p->in->slave;
+			p->in->slave = tkf;
+			if(p->in->flag & Tksubsub)
+				tksetbits(tkf, Tksubsub);
+			tkgridsetopt(p, tkf);
+			pos.x = i;
+			break; 
+		}
+	}
+	tkpackqit(p->in);
+	tkrunpack(t);
+	return nil;
+}
+
+void
+tkgriddelslave(Tk *tk)
+{
+	int y, x, yy;
+	TkGrid *grid;
+	TkGridcell **cells, *cell;
+	Point dim, span;
+
+	if(tk == nil || tk->master == nil || tk->master->grid == nil)
+		return;
+	grid = tk->master->grid;
+	cells = grid->cells;
+	dim = grid->dim;
+	for(y = 0; y < dim.y; y++){
+		for(x = 0; x < dim.x; x++){
+			cell = &cells[y][x];
+			if(cell->tk == tk){
+				span = cell->span;
+				for(yy = y; yy < y + span.y; yy++)
+					memset(cells[yy] + x, 0, span.x * sizeof(TkGridcell));
+				return;
+			}
+		}
+	}
+}
+
+char*
+tkgetgridmaster(TkTop *t, char **arg, char *buf, char *ebuf, Tk **master)
+{
+	TkGrid *grid;
+
+	*arg = tkword(t, *arg, buf, ebuf, nil);
+	*master = tklook(t, buf, 0);
+	if(*master == nil)
+		return TkBadwp;
+	grid = (*master)->grid;
+	if(grid == nil && (*master)->slave != nil)
+		return TkNotgrid;
+	return nil;
+}
+
+static int
+gridfindloc(TkGridbeam *beam, int blen, int f)
+{
+	int x, i, fpad;
+	if(blen == 0 || f < 0)
+		return -1;
+
+	fpad = 0;
+	x =  0;
+	for(i = 0; i < blen; i++){
+		x += maximum(fpad, beam[i].pad);
+		if(x <= f && f < x + beam[i].act)
+			return i;
+		x += beam[i].act;
+	}
+	return -1;
+}
+
+static char*
+tkgridcellinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+	/* grid cellinfo master x y */
+	Tk *master;
+	char *e;
+	Point p;
+	TkGrid *grid;
+	TkGridcell **cells;
+
+	e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+	if(e != nil || master->grid == nil)
+		return e;
+	grid = master->grid;
+
+	e = tkfracword(t, &arg, &p.x, nil);
+	if(e != nil)
+		return e;
+	e = tkfracword(t, &arg, &p.y, nil);
+	if(e != nil)
+		return e;
+
+	p.x = TKF2I(p.x);
+	p.y = TKF2I(p.y);
+	if(p.x < 0 || p.x >= grid->dim.x || p.y < 0 || p.y >= grid->dim.y)
+		return nil;
+
+	if(!findspan(grid, p, &p))
+		return nil;
+
+	cells = grid->cells;
+	return tkvalue(val, "%s -in %s -column %d -row %d -columnspan %d -rowspan %d",
+		cells[p.y][p.x].tk->name->name,
+		cells[p.y][p.x].tk->master->name->name, p.x, p.y,
+		cells[p.y][p.x].span.x, cells[p.y][p.x].span.y);
+}
+
+static char*
+tkgridlocation(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+	/* grid location master x y */
+	Tk *master;
+	char *e;
+	Point p;
+	int col, row;
+	TkGrid *grid;
+
+	e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+	if(e != nil || master->grid == nil)
+		return e;
+	grid = master->grid;
+
+	e = tkfracword(t, &arg, &p.x, nil);
+	if(e != nil)
+		return e;
+	e = tkfracword(t, &arg, &p.y, nil);
+	if(e != nil)
+		return e;
+
+	p.x = TKF2I(p.x);
+	p.y = TKF2I(p.y);
+
+	p = subpt(p, grid->origin);
+	col = gridfindloc(grid->cols, grid->dim.x, p.x);
+	row = gridfindloc(grid->rows, grid->dim.y, p.y);
+	if(col < 0 || row < 0)
+		return nil;
+	return tkvalue(val, "%d %d", col, row);
+}
+
+static char*
+tkgridinfo(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+	Tk *tk;
+	TkGrid *grid;
+	int x, y;
+	Point dim;
+	TkGridcell *row;
+
+	tkword(t, arg, buf, ebuf, nil);
+	tk = tklook(t, buf, 0);
+	if(tk == nil)
+		return TkBadwp;
+	if(tk->master == nil || tk->master->grid == nil)
+		return TkNotgrid;
+	grid = tk->master->grid;
+	dim = grid->dim;
+	for(y = 0; y < dim.y; y++){
+		row = grid->cells[y];
+		for(x = 0; x < dim.x; x++)
+			if(row[x].tk == tk)
+				goto Found;
+	}
+	return TkNotgrid;		/* should not happen */
+Found:
+	return tkvalue(val, "-in %s -column %d -row %d -columnspan %d -rowspan %d",
+		tk->master->name->name, x, y, grid->cells[y][x].span.x, grid->cells[y][x].span.y);
+}
+
+static char*
+tkgridforget(TkTop *t, char *arg, char *buf, char *ebuf)
+{
+	Tk *tk;
+	for(;;){
+		arg = tkword(t, arg, buf, ebuf, nil);
+		if(arg == nil || buf[0] == '\0')
+			break;
+		tk = tklook(t, buf, 0);
+		if(tk == nil){
+			tkrunpack(t);
+			tkerr(t, buf);
+			return TkBadwp;
+		}
+		tkpackqit(tk->master);
+		tkdelpack(tk);
+	}
+	tkrunpack(t);
+	return nil;
+}
+
+static char*
+tkgridslaves(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+	Tk *master, *tk;
+	char *fmt;
+	int i, isrow, index;
+	TkGrid *grid;
+	TkGridcell *cell;
+	char *e;
+	e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+	if(e != nil || master->grid == nil)
+		return e;
+	grid = master->grid;
+	arg = tkword(t, arg, buf, ebuf, nil);
+	fmt = "%s";
+	if(buf[0] == '\0'){
+		for(tk = master->slave; tk != nil; tk = tk->next){
+			if(tk->name != nil){
+				e = tkvalue(val, fmt, tk->name->name);
+				if(e != nil)
+					return e;
+				fmt = " %s";
+			}
+		}
+		return nil;
+	}
+	if(strcmp(buf, "-row") == 0)
+		isrow = 1;
+	else if(strcmp(buf, "-column") == 0)
+		isrow = 0;
+	else
+		return TkBadop;
+	tkword(t, arg, buf, ebuf, nil);
+	if(isrow)
+		index = parsegridindex(grid->rows, grid->dim.y, buf);
+	else
+		index = parsegridindex(grid->cols, grid->dim.x, buf);
+	if(index < 0)
+		return TkBadix;
+	if(isrow){
+		if(index >= grid->dim.y)
+			return nil;
+		for(i = 0; i < grid->dim.x; i++){
+			cell = &grid->cells[index][i];
+			if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){
+				e = tkvalue(val, fmt, cell->tk->name->name);
+				if(e != nil)
+					return e;
+				fmt = " %s";
+			}
+		}
+	} else{
+		if(index >= grid->dim.x)
+			return nil;
+		for(i = 0; i < grid->dim.y; i++){
+			cell = &grid->cells[i][index];
+			if(cell->tk != nil && cell->span.x > 0 && cell->tk->name != nil){
+				e = tkvalue(val, fmt, cell->tk->name->name);
+				if(e != nil)
+					return e;
+				fmt = " %s";
+			}
+		}
+	}		
+
+	return nil;
+}
+
+static char*
+tkgriddelete(TkTop *t, char *arg, char *buf, char *ebuf, int delrow)
+{
+	Tk *master, **l, *f;
+	TkGrid *grid;
+	TkGridbeam *beam;
+	int blen, i0, i1, x, y;
+	Point dim;
+	TkGridcell **cells;
+	char *e;
+
+	/*
+	 * grid (columndelete|rowdelete) master index0 ?index1?
+	 */
+
+	e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+	if(e != nil || master->grid == nil)
+		return e;
+	grid = master->grid;
+
+	if(delrow){
+		beam = grid->rows;
+		blen = grid->dim.y;
+	} else{
+		beam = grid->cols;
+		blen = grid->dim.x;
+	}
+
+	arg = tkword(t, arg, buf, ebuf, nil);
+	i0 = parsegridindex(beam, blen, buf);
+	if(i0 < 0)
+		return TkBadix;
+
+	tkword(t, arg, buf, ebuf, nil);
+	if(buf[0] == '\0')
+		i1 = i0 + 1;
+	else
+		i1 = parsegridindex(beam, blen, buf);
+	if(i1 < 0 || i0 > i1)
+		return TkBadix;
+	if(i0 > blen || i0 == i1)
+		return nil;
+	if(i1 > blen)
+		i1 = blen;
+	cells = grid->cells;
+	dim = grid->dim;
+	if(delrow){
+		if(gridrowhasspan(grid, i0) || gridrowhasspan(grid, i1))
+			return TkBadgridcell;
+		for(y = i0; y < i1; y++)
+			for(x = 0; x < dim.x; x++)
+				if(cells[y][x].tk != nil)
+					cells[y][x].tk->flag |= Tkgridremove;
+		delrows(grid, i0, i1);
+		grid->rows = delbeams(beam, blen, i0, i1);
+	} else{
+		if(gridcolhasspan(grid, i0) || gridcolhasspan(grid, i1))
+			return TkBadgridcell;
+		for(y = 0; y < dim.y; y++)
+			for(x = i0; x < i1; x++)
+				if(cells[y][x].tk != nil)
+					cells[y][x].tk->flag |= Tkgridremove;
+		delcols(grid, i0, i1);
+		grid->cols = delbeams(beam, blen, i0, i1);
+	}
+	l = &master->slave;
+	for(f = *l; f; f = f->next){
+		if(f->flag & Tkgridremove){
+			*l = f->next;
+			f->master = nil;
+			f->flag &= ~Tkgridremove;
+		} else
+			l = &f->next;
+	}
+	tkpackqit(master);
+	tkrunpack(t);
+	return nil;
+}
+
+
+static char*
+tkgridinsert(TkTop *t, char *arg, char *buf, char *ebuf, int insertrow)
+{
+	int index, count;
+	Point dim;
+	Tk *master;
+	TkGrid *grid;
+	int gotarg;
+	char *e;
+
+	/*
+	 * grid (rowinsert|columninsert) master index ?count?
+	 * it's an error ifthe insert splits any spanning cells.
+	 */
+	e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+	if(e != nil || master->grid == nil)
+		return e;
+	grid = master->grid;
+	dim = grid->dim;
+
+	arg = tkword(t, arg, buf, ebuf, nil);
+	if(insertrow)
+		index = parsegridindex(grid->rows, dim.y, buf);
+	else
+		index = parsegridindex(grid->cols, dim.x, buf);
+	if(index < 0 || index > (insertrow ? dim.y : dim.x))
+		return TkBadix;
+
+	tkword(t, arg, buf, ebuf, &gotarg);
+	if(gotarg){
+		count = strtol(buf, &buf, 10);
+		if(buf[0] != '\0' || count < 0)
+			return TkBadvl;
+	} else
+		count = 1;
+
+	/*
+	 * check that we're not splitting any spanning cells
+	 */
+	if(insertrow){
+		if(gridrowhasspan(grid, index))
+			return TkBadgridcell;
+		e = insrows(grid, index, count);
+	} else{
+		if(gridcolhasspan(grid, index))
+			return TkBadgridcell;
+		e = inscols(grid, index, count);
+	}
+	tkpackqit(master);
+	tkrunpack(t);
+	return e;
+}
+
+/*
+ * (rowconfigure|columnconfigure) master index ?-option value ...?
+ */
+static char*
+tkbeamconfigure(TkTop *t, char *arg, int isrow)
+{
+	TkBeamparam p;
+	TkOptab tko[2];
+	TkName *names;
+	Tk *master;
+	int index;
+	TkGrid *grid;
+	TkGridbeam *beam;
+	Point dim;
+	char *e;
+
+	p.equalise = BoolX;
+	p.name = nil;
+	p.weight = -1;
+	p.minsize = -1;
+	p.maxsize = -1;
+	p.pad = -1;
+
+	tko[0].ptr = &p;
+	tko[0].optab = beamopts;
+	tko[1].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil)
+		return e;
+
+	if(names == nil || names->link == nil)
+		return TkBadvl;
+
+	master = tklook(t, names->name, 0);
+	if(master == nil)
+		return TkBadwp;
+
+	grid = master->grid;
+	if(grid == nil){
+		if(master->slave != nil)
+			return TkNotgrid;
+		grid = master->grid = malloc(sizeof(TkGrid));
+		if(grid == nil){
+			tkfreename(names);
+			return TkNomem;
+		}
+	}
+
+	if(isrow){
+		index = parsegridindex(grid->rows, grid->dim.y, names->link->name);
+	} else
+		index = parsegridindex(grid->cols, grid->dim.x, names->link->name);
+	if(index < 0){
+		e = TkBadix;
+		goto Error;
+	}
+	if(isrow)
+		dim = Pt(grid->dim.x, index + 1);
+	else
+		dim = Pt(index + 1, grid->dim.y);
+	e = ensuregridsize(grid, dim);
+	if(e != nil)
+		goto Error;
+
+	if(isrow)
+		beam = &grid->rows[index];
+	else
+		beam = &grid->cols[index];
+
+	if(p.minsize >= 0)
+		beam->minsize = p.minsize;
+	if(p.maxsize >= 0)
+		beam->maxsize = p.maxsize;
+	if(p.weight >= 0)
+		beam->weight = p.weight;
+	if(p.pad >= 0)
+		beam->pad = p.pad;
+	if(p.name != nil){
+		free(beam->name);
+		beam->name = p.name;
+	}
+	if(p.equalise != BoolX)
+		beam->equalise = p.equalise == BoolT;
+
+	tkpackqit(master);
+	tkrunpack(t);
+
+Error:
+	tkfreename(names);
+	return e;
+}
+
+char*
+tkgridsize(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+	Tk *master;
+	TkGrid *grid;
+	char *e;
+
+	e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+	if(e != nil)
+		return e;
+	grid = master->grid;
+	if(grid == nil)
+		return tkvalue(val, "0 0");
+	else
+		return tkvalue(val, "%d %d", grid->dim.x, grid->dim.y);
+}
+
+char*
+tkgridbbox(TkTop *t, char *arg, char **val, char *buf, char *ebuf)
+{
+	Point p0, p1;
+	Tk *master;
+	TkGrid *grid;
+	char *e;
+	int gotarg;
+	Point dim;
+	Rectangle r;
+
+	e = tkgetgridmaster(t, &arg, buf, ebuf, &master);
+	if(e != nil || master->grid == nil)
+		return e;
+
+	grid = master->grid;
+	dim = grid->dim;
+	arg = tkword(t, arg, buf, ebuf, &gotarg);
+	if(!gotarg){
+		p0 = ZP;
+		p1 = dim;
+	} else{
+		p0.x = parsegridindex(grid->cols, dim.x, buf);
+		arg = tkword(t, arg, buf, ebuf, &gotarg);
+		if(!gotarg)
+			return TkFewpt;
+		p0.y = parsegridindex(grid->rows, dim.y, buf);
+		arg = tkword(t, arg, buf, ebuf, &gotarg);
+		if(!gotarg){
+			p1 = p0;
+		} else{
+			p1.x = parsegridindex(grid->cols, dim.x, buf);
+			arg = tkword(t, arg, buf, ebuf, &gotarg);
+			if(!gotarg)
+				return TkFewpt;
+			p1.y = parsegridindex(grid->rows, dim.y, buf);
+		}
+	}
+	if(p0.x < 0 || p0.y < 0 || p1.x < 0 || p1.y < 0)
+		return TkBadix;
+
+	r = cellbbox(grid, p0);
+	if(!eqpt(p0, p1))
+		combinerect(&r, cellbbox(grid, p1));
+	return tkvalue(val, "%d %d %d %d", r.min.x, r.min.y, r.max.x, r.max.y);
+}
+
+char*
+tkgridindex(TkTop *t, char *arg, char **val, char *buf, char *ebuf, int isrow)
+{
+	Tk *master;
+	TkGrid *grid;
+	TkGridbeam *beam;
+	int blen, i;
+
+	arg = tkword(t, arg, buf, ebuf, nil);
+	master = tklook(t, buf, 0);
+	if(master == nil)
+		return TkBadwp;
+	tkword(t, arg, buf, ebuf, nil);
+	grid = master->grid;
+	if(grid == nil){
+		beam = nil;
+		blen = 0;
+	} else if(isrow){
+		beam = grid->rows;
+		blen = grid->dim.y;
+	} else{
+		beam = grid->cols;
+		blen = grid->dim.x;
+	}
+	i = parsegridindex(beam, blen, buf);
+	if(i < 0)
+		return TkBadix;
+	return tkvalue(val, "%d", i);
+}
+
+void
+tkfreegrid(TkGrid *grid)
+{
+	Point dim;
+	int i;
+	dim = grid->dim;
+	for(i = 0; i < dim.x; i++)
+		free(grid->cols[i].name);
+	for(i = 0; i < dim.y; i++)
+		free(grid->rows[i].name);
+	for(i = 0; i < dim.y; i++)
+		free(grid->cells[i]);
+	free(grid->cells);
+	free(grid->rows);
+	free(grid->cols);
+	free(grid);
+}
+
+char*
+tkgrid(TkTop *t, char *arg, char **val)
+{
+	TkGridparam *p;
+	TkOptab tko[2];
+	TkName *names;
+	char *e, *w, *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	w = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	if('a' <= buf[0] && buf[0] <= 'z'){
+		if(strcmp(buf, "debug") == 0){
+			Tk *tk;
+			e = tkgetgridmaster(t, &w, buf, buf+Tkmaxitem, &tk);
+			if(e == nil)
+				printgrid(tk->grid);
+		} else
+		if(strcmp(buf, "forget") == 0)
+			e = tkgridforget(t, w, buf, buf+Tkmaxitem);
+		else if(strcmp(buf, "propagate") == 0)
+			e = tkpropagate(t, w);
+		else if(strcmp(buf, "slaves") == 0)
+			e = tkgridslaves(t, w, val, buf, buf+Tkmaxitem);
+		else if(strcmp(buf, "rowconfigure") == 0)
+			e = tkbeamconfigure(t, w, 1);
+		else if(strcmp(buf, "columnconfigure") == 0)
+			e = tkbeamconfigure(t, w, 0);
+		else if(strcmp(buf, "rowinsert") == 0)
+			e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 1);
+		else if(strcmp(buf, "columninsert") == 0)
+			e = tkgridinsert(t, w, buf, buf+Tkmaxitem, 0);
+		else if(strcmp(buf, "size") == 0)
+			e = tkgridsize(t, w, val, buf, buf+Tkmaxitem);
+		else if(strcmp(buf, "rowdelete") == 0)
+			e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 1);
+		else if(strcmp(buf, "columndelete") == 0)
+			e = tkgriddelete(t, w, buf, buf+Tkmaxitem, 0);
+		else if(strcmp(buf, "rowindex") == 0)
+			e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 1);
+		else if(strcmp(buf, "columnindex") == 0)
+			e = tkgridindex(t, w, val, buf, buf+Tkmaxitem, 0);
+		else if(strcmp(buf, "bbox") == 0)
+			e = tkgridbbox(t, w, val, buf, buf+Tkmaxitem);
+		else if(strcmp(buf, "location") == 0)
+			e = tkgridlocation(t, w, val, buf, buf+Tkmaxitem);
+		else if(strcmp(buf, "cellinfo") == 0)
+			e = tkgridcellinfo(t, w, val, buf, buf+Tkmaxitem);
+		else if(strcmp(buf, "info") == 0)
+			e = tkgridinfo(t, w, val, buf, buf+Tkmaxitem);
+		else{
+			tkerr(t, buf);
+			e = TkBadcm;
+		}
+	} else{
+		p = malloc(sizeof(TkGridparam));
+		if(p == nil)
+			return TkNomem;
+		tko[0].ptr = p;
+		tko[0].optab = opts;
+		tko[1].ptr = nil;
+	
+		p->span.x = 1;
+		p->span.y = 1;
+		p->pad.x = p->pad.y = p->ipad.x = p->ipad.y = -1;
+		p->sticky = -1;
+	
+		names = nil;
+		e = tkparse(t, arg, tko, &names);
+		if(e != nil){
+			free(p);
+			return e;
+		}
+	
+		e = tkgridconfigure(t, p, names);
+		free(p->row);
+		free(p->col);
+		free(p);
+		tkfreename(names);
+	}
+	free(buf);
+	return e;
+}
+
+/*
+ * expand widths of rows/columns according to weight.
+ * return amount of space still left over.
+ */
+static int
+expandwidths(int x0, int x1, int totwidth, TkGridbeam *cols, int expandzero)
+{
+	int share, x, slack, m, w, equal;
+
+	if(x0 >= x1)
+		return 0;
+
+	share = 0;
+	for(x = x0; x < x1; x++)
+		share += cols[x].weight;
+
+	slack = totwidth - beamsize(cols, x0, x1);
+	if(slack <= 0)
+		return 0;
+
+	if(share == 0 && expandzero){
+		share = x1 - x0;
+		equal = 1;
+	} else
+		equal = 0;
+
+	for(x = x0; x < x1 && share > 0 ; x++){
+		w = equal ? 1 : cols[x].weight;
+		m = slack * w / share;
+		cols[x].act += m;
+		slack -= m;
+		share -= w;
+	}
+	return slack;
+}
+
+static void
+gridequalise(TkGridbeam *beam, int blen)
+{
+	int i, max;
+
+	max = 0;
+	for(i = 0; i < blen; i++)
+		if(beam[i].equalise == BoolT && beam[i].act > max)
+			max = beam[i].act;
+
+	if(max > 0)
+		for(i = 0; i < blen; i++)
+			if(beam[i].equalise == BoolT)
+				beam[i].act = max;
+}
+
+/*
+ * take into account min/max beam sizes.
+ * max takes precedence
+ */
+static void
+beamminmax(TkGridbeam *beam, int n)
+{
+	TkGridbeam *e;
+	e = &beam[n];
+	for(; beam < e; beam++){
+		if(beam->act < beam->minsize)
+			beam->act = beam->minsize;
+		if(beam->act > beam->maxsize)
+			beam->act = beam->maxsize;
+	}
+}
+
+int
+tkgridder(Tk *master)
+{
+	TkGrid *grid;
+	TkGridcell **cells, *cell;
+	TkGridbeam *rows, *cols;
+	TkGeom pos;
+	Point org;
+	Tk *slave;
+	int dx, dy, x, y, w, bw2, fpadx, fpady;
+	Point req;
+
+	grid = master->grid;
+	dx = grid->dim.x;
+	dy = grid->dim.y;
+	cells = grid->cells;
+	rows = grid->rows;
+	cols = grid->cols;
+
+	for(x = 0; x < dx; x++)
+		cols[x].act = 0;
+
+	/* calculate column widths and row heights (ignoring multi-column cells) */
+	for(y = 0; y < dy; y++){
+		rows[y].act = 0;
+		for(x = 0; x < dx; x++){
+			cell = &cells[y][x];
+			if((slave = cell->tk) != nil){
+				bw2 = slave->borderwidth * 2;
+				w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x;
+				if(cell->span.x == 1 && w > cols[x].act)
+					cols[x].act = w;
+				w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y;
+				if(cell->span.y == 1 && w > rows[y].act)
+					rows[y].act = w;
+			}
+		}
+	}
+
+	beamminmax(rows, dy);
+	beamminmax(cols, dx);
+
+	/* now check that spanning cells fit in their rows/columns */
+	for(y = 0; y < dy; y++)
+		for(x = 0; x < dx; x++){
+			cell = &cells[y][x];
+			if((slave = cell->tk) != nil){
+				bw2 = slave->borderwidth * 2;
+				if(cell->span.x > 1){
+					w = slave->req.width + bw2 + slave->pad.x + slave->ipad.x;
+					expandwidths(x, x+cell->span.x, w, cols, 1);
+				}
+				if(cell->span.y > 1){
+					w = slave->req.height + bw2 + slave->pad.y + slave->ipad.y;
+					expandwidths(y, y+cell->span.y, w, rows, 1);
+				}
+			}
+		}
+
+	gridequalise(rows, dy);
+	gridequalise(cols, dx);
+
+	if(dx == 0)
+		req.x = 0;
+	else
+		req.x = beamsize(cols, 0, dx) + cols[0].pad + cols[dx-1].pad;
+
+	if(dy == 0)
+		req.y = 0;
+	else
+		req.y = beamsize(rows, 0, dy) + rows[0].pad + rows[dy-1].pad;
+
+	if(req.x != master->req.width || req.y != master->req.height)
+	if((master->flag & Tknoprop) == 0){
+		if(master->geom != nil){
+			master->geom(master, master->act.x, master->act.y, 
+					req.x, req.y);
+		} else{
+			master->req.width = req.x;
+			master->req.height = req.y;
+			tkpackqit(master->master);
+		}
+		return 0;
+    	}
+	org = ZP;
+	if(dx > 0 && master->act.width > req.x)
+		org.x = expandwidths(0, dx,
+				master->act.width - (cols[0].pad + cols[dx-1].pad),
+				cols, 0) / 2;
+	if(dy > 0 && master->act.height > req.y)
+		org.y = expandwidths(0, dy,
+				master->act.height - (rows[0].pad + rows[dy-1].pad),
+				rows, 0) / 2;
+
+	grid->origin = org;
+	pos.y = org.y;
+	fpady = 0;
+	for(y = 0; y < dy; y++){
+		pos.y += maximum(fpady, rows[y].pad);
+		fpady = rows[y].pad;
+
+		pos.x = org.x;
+		fpadx = 0;
+		for(x = 0; x < dx; x++){
+			cell = &cells[y][x];
+			pos.x += maximum(fpadx, cols[x].pad);
+			fpadx = cols[x].pad;
+			if((slave = cell->tk) != nil && cell->span.x > 0){
+				pos.width = beamsize(cols, x, x + cell->span.x);
+				pos.height = beamsize(rows, y, y + cell->span.y);
+				tksetslavereq(slave, pos);
+			}
+			pos.x += cols[x].act;
+		}
+		pos.y += rows[y].act;
+	}
+
+	master->dirty = tkrect(master, 1);
+	tkdirty(master);
+	return 1;
+}
--- /dev/null
+++ b/libtk/image.c
@@ -1,0 +1,380 @@
+#include "lib9.h"
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+char*	tkimgbmcreate(TkTop*, char*, int, char**);
+char*	tkimgbmdel(TkImg*);
+void	tkimgbmfree(TkImg*);
+
+static Rectangle huger = { -1000000, -1000000, 1000000, 1000000 };
+
+typedef struct TkImgtype TkImgtype;
+struct TkImgtype
+{
+	char*	type;
+	char*	(*create)(TkTop*, char*, int, char**);
+	char*	(*delete)(TkImg*);
+	void	(*destroy)(TkImg*);
+} tkimgopts[] = 
+{
+	"bitmap",	tkimgbmcreate,		tkimgbmdel, 	tkimgbmfree,
+	nil,
+};
+
+typedef struct Imgargs Imgargs;
+struct Imgargs {
+	Image*	fgimg;
+	Image*	maskimg;
+};
+
+TkImg*
+tkname2img(TkTop *t, char *name)
+{
+	TkImg *tki;
+
+	for(tki = t->imgs; tki; tki = tki->link)
+		if((tki->name != nil) && strcmp(tki->name->name, name) == 0)
+			return tki;
+
+	return nil;
+}
+
+TkOption
+bitopt[] =
+{
+	"file",		OPTbmap,	O(Imgargs, fgimg),	nil,
+	"maskfile",	OPTbmap,	O(Imgargs, maskimg),	nil,
+	nil
+};
+
+void
+tksizeimage(Tk *tk, TkImg *tki)
+{
+	int dx, dy, repack;
+
+	dx = 0;
+	dy = 0;
+	if(tki->img != nil) {
+		dx = Dx(tki->img->r);
+		dy = Dy(tki->img->r);
+	}
+	repack = 0;
+	if(tki->ref > 1 && (tki->w != dx || tki->h != dy))
+		repack = 1;
+	tki->w = dx;
+	tki->h = dy;
+
+	if(repack) {
+		tkpackqit(tk);
+		tkrunpack(tk->env->top);
+	}
+}
+
+char*
+tkimgbmcreate(TkTop *t, char *arg, int type, char **ret)
+{
+	TkName *names;
+	TkImg *tki, *f;
+	TkOptab tko[2];
+	char buf[32];
+	static int id;
+	char *e = nil;
+	Imgargs iargs;
+	Rectangle r;
+	Display *d;
+	int chan;
+	int locked;
+
+	d = t->display;
+	locked = 0;
+
+	tki = malloc(sizeof(TkImg));
+	if(tki == nil)
+		return TkNomem;
+
+	tki->env = tkdefaultenv(t);
+	if(tki->env == nil)
+		goto err;
+	tki->type = type;
+	tki->ref = 1;
+	tki->top = t;
+
+	iargs.fgimg = nil;
+	iargs.maskimg = nil;
+
+	tko[0].ptr = &iargs;
+	tko[0].optab = bitopt;
+	tko[1].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil)
+		goto err;
+
+	if (iargs.fgimg == nil && iargs.maskimg != nil) {
+		locked = lockdisplay(d);
+		r = Rect(0, 0, Dx(iargs.maskimg->r), Dy(iargs.maskimg->r));
+		tki->img = allocimage(d, r, CHAN2(CAlpha, 8, CGrey, 8), 0, DTransparent);
+		if (tki->img != nil)
+			draw(tki->img, r, nil, iargs.maskimg, iargs.maskimg->r.min);
+		freeimage(iargs.maskimg);
+
+	} else if (iargs.fgimg != nil && iargs.maskimg != nil) {
+		locked = lockdisplay(d);
+		r = Rect(0, 0, Dx(iargs.fgimg->r), Dy(iargs.fgimg->r));
+		if (tkchanhastype(iargs.fgimg->chan, CGrey))
+			chan = CHAN2(CAlpha, 8, CGrey, 8);
+		else
+			chan = RGBA32;
+		tki->img = allocimage(d, r, chan, 0, DTransparent);
+		if (tki->img != nil)
+			draw(tki->img, r, iargs.fgimg, iargs.maskimg, iargs.fgimg->r.min);
+		freeimage(iargs.fgimg);
+		freeimage(iargs.maskimg);
+	} else {
+		tki->img = iargs.fgimg;
+	}
+	if (locked)
+		unlockdisplay(d);
+
+	if(names == nil) {
+		sprint(buf, "image%d", id++);
+		tki->name = tkmkname(buf);
+		if(tki->name == nil)
+			goto err;
+	}
+	else {
+		/* XXX should mark as dirty any widgets using the named
+		 * image - some notification scheme needs putting in place
+		 */
+		tki->name = names;
+		tkfreename(names->link);
+		names->link = nil;
+	}
+
+	tksizeimage(t->root, tki);
+
+	if (tki->name != nil) {
+		f = tkname2img(t, tki->name->name);
+		if(f != nil)
+			tkimgopts[f->type].delete(f);
+	}
+
+	tki->link = t->imgs;
+	t->imgs = tki;
+	
+	if (tki->name != nil) {
+		e = tkvalue(ret, "%s", tki->name->name);
+		if(e == nil)
+			return nil;
+	}
+err:
+	tkputenv(tki->env);
+	if(tki->img != nil) {
+		locked = lockdisplay(d);
+		freeimage(tki->img);
+		if (locked)
+			unlockdisplay(d);
+	}
+	tkfreename(tki->name);
+	free(tki);
+	return e != nil ? e : TkNomem;
+}
+
+char*
+tkimgbmdel(TkImg *tki)
+{
+	TkImg **l, *f;
+
+	l = &tki->top->imgs;
+	for(f = *l; f; f = f->link) {
+		if(f == tki) {
+			*l = tki->link;
+			tkimgput(tki);
+			return nil;
+		}
+		l = &f->link;
+	}
+	return TkBadvl;
+}
+
+void
+tkimgbmfree(TkImg *tki)
+{
+	int locked;
+	Display *d;
+
+	d = tki->top->display;
+	locked = lockdisplay(d);
+	freeimage(tki->img);
+	if(locked)
+		unlockdisplay(d);
+
+	free(tki->cursor);
+	tkfreename(tki->name);
+	tkputenv(tki->env);
+
+	free(tki);
+}
+
+char*
+tkimage(TkTop *t, char *arg, char **ret)
+{
+	int i;
+	TkImg *tkim;
+	char *fmt, *e, *buf, *cmd;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	cmd = mallocz(Tkminitem, 0);
+	if(cmd == nil) {
+		free(buf);
+		return TkNomem;
+	}
+
+	arg = tkword(t, arg, cmd, cmd+Tkminitem, nil);
+	if(strcmp(cmd, "create") == 0) {
+		arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+		for(i = 0; tkimgopts[i].type != nil; i++)
+			if(strcmp(buf, tkimgopts[i].type) == 0) {
+				e = tkimgopts[i].create(t, arg, i, ret);
+				goto ret;
+			}
+		e = TkBadvl;
+		goto ret;
+	}
+	if(strcmp(cmd, "names") == 0) {
+		fmt = "%s";
+		for(tkim = t->imgs; tkim; tkim = tkim->link) {
+		        if (tkim->name != nil) {
+				e = tkvalue(ret, fmt, tkim->name->name);
+				if(e != nil)
+					goto ret;
+			}
+			fmt = " %s";
+		}
+		e = nil;
+		goto ret;
+	}
+
+	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	tkim = tkname2img(t, buf);
+	if(tkim == nil) {
+		e = TkBadvl;
+		goto ret;
+	}
+
+	if(strcmp(cmd, "height") == 0) {
+		e = tkvalue(ret, "%d", tkim->h);
+		goto ret;
+	}
+	if(strcmp(cmd, "width") == 0) {
+		e = tkvalue(ret, "%d", tkim->w);
+		goto ret;
+	}
+	if(strcmp(cmd, "type") == 0) {
+		e = tkvalue(ret, "%s", tkimgopts[tkim->type].type);
+		goto ret;
+	}
+	if(strcmp(cmd, "delete") == 0) {
+		for (;;) {
+			e = tkimgopts[tkim->type].delete(tkim);
+			if (e != nil)
+				break;
+			arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+			if (buf[0] == '\0')
+				 break;
+			tkim = tkname2img(t, buf);
+			if (tkim == nil) {
+				e = TkBadvl;
+				break;
+			}
+		}
+		goto ret;
+	}
+
+	e = TkBadcm;
+ret:
+	free(cmd);
+	free(buf);
+	return e;
+}
+
+void
+tkimgput(TkImg *tki)
+{
+	if(tki == nil)
+		return;
+
+	if(--tki->ref > 0)
+		return;
+
+	tkimgopts[tki->type].destroy(tki);	
+}
+
+TkImg*
+tkauximage(TkTop *t, char* s, TkMemimage *m, int repl)
+{
+	TkName *name;
+	TkCtxt *c;
+	TkImg *tki;
+	Display *d;
+	Image *i;
+	int locked, nbytes;
+
+	tki = tkname2img(t, s);
+	if (tki != nil) {
+		tki->ref++;
+		return tki;
+	}
+
+	name = tkmkname(s);
+	if (name == nil)
+		return nil;
+	tki = mallocz(sizeof(*tki), 1);
+	if (tki == nil)
+		goto err;
+	tki->env = tkdefaultenv(t);
+	if(tki->env == nil)
+		goto err;
+
+	c = t->ctxt;
+	d = c->display;
+
+	nbytes = bytesperline(m->r, chantodepth(m->chans))*Dy(m->r);
+	locked = lockdisplay(d);
+	i = allocimage(d, m->r, m->chans, repl, DTransparent);
+	if (i != nil) {
+		if (loadimage(i, m->r, m->data, nbytes) != nbytes) {
+			freeimage(i);
+			i = nil;
+		}
+		if (repl)
+			replclipr(i, 1, huger);	/* TO DO: doesn't allocimage do this? */
+	}
+	if (locked)
+		unlockdisplay(d);
+	if (i == nil)
+		goto err;
+	tki->top = t;
+	tki->ref = 2;	/* t->imgs ref and the ref we are returning */
+	tki->type = 0;	/* bitmap */
+	tki->w = Dx(m->r);
+	tki->h = Dy(m->r);
+	tki->img = i;
+	tki->name = name;
+	tki->link = t->imgs;
+	t->imgs = tki;
+	return tki;
+err:
+	if (tki != nil) {
+		tkputenv(tki->env);
+		free(tki);
+	}
+	tkfreename(name);
+	return nil;
+}
--- /dev/null
+++ b/libtk/label.c
@@ -1,0 +1,366 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "label.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+TkOption tklabelopts[] =
+{
+	"text",		OPTtext,	O(TkLabel, text),	nil,
+	"label",	OPTtext,	O(TkLabel, text),	nil,
+	"underline",	OPTdist,	O(TkLabel, ul),		nil,
+	"justify",	OPTflag,	O(TkLabel, justify),	tkjustify,
+	"anchor",	OPTflag,	O(TkLabel, anchor),	tkanchor,
+	"bitmap",	OPTbmap,	O(TkLabel, bitmap),	nil,
+	"image",	OPTimag,	O(TkLabel, img),	nil,
+	nil
+};
+
+char*
+tklabel(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkLabel *tkl;
+	TkName *names;
+	TkOptab tko[3];
+
+	tk = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
+	if(tk == nil)
+		return TkNomem;
+
+	tkl = TKobj(TkLabel, tk);
+	tkl->ul = -1;
+	tkl->justify = Tkleft;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = tklabelopts;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	tksizelabel(tk);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tklabelcget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = tklabelopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tklabelconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkOptab tko[3];
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = tklabelopts;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksizelabel(tk);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tkgeomchg(tk, &g, bd);
+
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+void
+tksizelabel(Tk *tk)
+{
+	Point p;
+	int w, h;
+	TkLabel *tkl;
+	
+	tkl = TKobj(TkLabel, tk);
+	if(tkl->anchor == 0)	
+		tkl->anchor = Tkcenter;
+
+	w = 0;
+	h = 0;
+	tkl->textheight = 0;
+	if(tkl->img != nil) {
+		w = tkl->img->w + 2*Bitpadx;
+		h = tkl->img->h + 2*Bitpady;
+	} else if(tkl->bitmap != nil) {
+		w = Dx(tkl->bitmap->r) + 2*Bitpadx;
+		h = Dy(tkl->bitmap->r) + 2*Bitpady;
+	} else if(tkl->text != nil) {
+		p = tkstringsize(tk, tkl->text);
+		w = p.x + 2*Textpadx;
+		h = p.y + 2*Textpady;
+		if(tkl->ul != -1 && tkl->ul > strlen(tkl->text))
+			tkl->ul = strlen(tkl->text);	/* underline all */
+		tkl->textheight = p.y;
+	}
+
+	if(tk->type == TKcascade) {
+		w += CheckButton + 2*CheckButtonBW;
+		if(h < CheckButton)
+			h = CheckButton;
+	}
+	w += 2*tk->highlightwidth;
+	h += 2*tk->highlightwidth;
+	tkl->w = w;
+	tkl->h = h;
+	if((tk->flag & Tksetwidth) == 0)
+		tk->req.width = w;
+	if((tk->flag & Tksetheight) == 0)
+		tk->req.height = h;
+}
+
+int
+tklabelmargin(Tk *tk)
+{
+	TkLabel *tkl;
+	Image *img;
+
+	switch(tk->type){
+	case TKseparator:
+		return 0;
+
+	case TKlabel:
+	case TKcascade:
+		tkl = TKobj(TkLabel, tk);
+		img = nil;
+		if (tkl->img != nil)
+			img = tkl->img->img;
+		else if (tkl->bitmap != nil)
+			img = tkl->bitmap;
+		if (img != nil)
+			return Bitpadx;
+		return Textpadx;
+
+	default:
+		fprint(2, "label margin: type %d\n", tk->type);
+		return 0;
+	}
+}
+
+void
+tkfreelabel(Tk *tk)
+{
+	Image *i;
+	int locked;
+	Display *d;
+	TkLabel *tkl;
+
+	tkl = TKobj(TkLabel, tk);
+
+	if(tkl->text != nil)
+		free(tkl->text);
+	if(tkl->command != nil)
+		free(tkl->command);
+	if(tkl->value != nil)
+		free(tkl->value);
+	if(tkl->variable != nil) {
+		tkfreevar(tk->env->top, tkl->variable, tk->flag & Tkswept);
+		free(tkl->variable);
+	}
+	if(tkl->img != nil)
+		tkimgput(tkl->img);
+	i = tkl->bitmap;
+	if(i != nil) {
+		d = i->display;
+		locked = lockdisplay(d);
+		freeimage(i);
+		if(locked)
+			unlockdisplay(d);
+	}
+	if(tkl->menu != nil)
+		free(tkl->menu);
+}
+
+static void
+tktriangle(Point u, Image *i, TkEnv *e)
+{	
+	Point p[3];
+
+	u.y++;
+	p[0].x = u.x + CheckButton;
+	p[0].y = u.y + CheckButton/2;
+	p[1].x = u.x;
+	p[1].y = u.y + CheckButton;
+	p[2].x = u.x;
+	p[2].y = u.y;
+	fillpoly(i, p, 3, ~0, tkgc(e, TkCforegnd), p[0]);
+}
+
+/*
+ * draw TKlabel, TKseparator, and TKcascade (cascade should really be a button)
+ */
+char*
+tkdrawlabel(Tk *tk, Point orig)
+{
+ 	TkEnv *e;
+	TkLabel *tkl;
+	Rectangle r, s, mainr, focusr;
+	int dx, dy, h;
+	Point p, u, v;
+	Image *i, *dst, *ct, *img;
+	int relief, bgnd, fgnd;
+
+	e = tk->env;
+
+	dst = tkimageof(tk);
+	if(dst == nil)
+		return nil;
+
+	v.x = tk->act.width + 2*tk->borderwidth;
+	v.y = tk->act.height + 2*tk->borderwidth;
+
+	r.min = ZP;
+	r.max = v;
+	focusr = insetrect(r, tk->borderwidth);
+	mainr = insetrect(focusr, tk->highlightwidth);
+	relief = tk->relief;
+
+	tkl = TKobj(TkLabel, tk);
+
+	fgnd = TkCforegnd;
+	bgnd = TkCbackgnd;
+	if (tk->flag & Tkdisabled)
+		fgnd = TkCdisablefgnd;
+	else if (tk->flag & Tkactive) {
+		fgnd = TkCactivefgnd;
+		bgnd = TkCactivebgnd;
+	}
+
+	i = tkitmp(e, r.max, bgnd);
+	if(i == nil)
+		return nil;
+
+	if(tk->flag & Tkactive)
+		draw(i, r, tkgc(e, bgnd), nil, ZP);
+
+	p = mainr.min;
+	h = tkl->h - 2 * tk->highlightwidth;
+
+	dx = tk->act.width - tkl->w - tk->ipad.x;
+	dy = tk->act.height - tkl->h - tk->ipad.y;
+	if((tkl->anchor & (Tknorth|Tksouth)) == 0)
+		p.y += dy/2;
+	else if(tkl->anchor & Tksouth)
+		p.y += dy;
+
+	if((tkl->anchor & (Tkeast|Tkwest)) == 0)
+		p.x += dx/2;
+	else if(tkl->anchor & Tkeast)
+		p.x += dx;
+
+	if(tk->type == TKcascade) {
+		u.x = mainr.max.x - CheckButton - CheckButtonBW;	/* TO DO: CheckButton etc is really the triangle/arrow */
+		u.y = p.y + ButtonBorder + (h-CheckSpace)/2;
+		tktriangle(u, i, e);
+	}
+
+	p.x += tk->ipad.x/2;
+	p.y += tk->ipad.y/2;
+	u = ZP;
+
+	img = nil;
+	if(tkl->img != nil && tkl->img->img != nil)
+		img = tkl->img->img;
+	else if (tkl->bitmap != nil)
+		img = tkl->bitmap;
+	if(img != nil) {
+		s.min.x = p.x + Bitpadx;
+		s.min.y = p.y + Bitpady;
+		s.max.x = s.min.x + Dx(img->r);
+		s.max.y = s.min.y + Dy(img->r);
+		s = rectaddpt(s, u);
+		if(tkchanhastype(img->chan, CGrey))
+			draw(i, s, tkgc(e, fgnd), img, ZP);
+		else
+			draw(i, s, img, nil, ZP);
+	} else if(tkl->text != nil) {
+		u.x += Textpadx;
+		u.y += Textpady;
+		ct = tkgc(e, fgnd);
+		
+		p.y += (h - tkl->textheight) / 2;
+		tkdrawstring(tk, i, addpt(u, p), tkl->text, tkl->ul, ct, tkl->justify);
+	}
+
+	if(tkhaskeyfocus(tk))
+		tkbox(i, focusr, tk->highlightwidth, tkgc(e, TkChighlightfgnd));
+	tkdrawrelief(i, tk, ZP, bgnd, relief);
+
+	p.x = tk->act.x + orig.x;
+	p.y = tk->act.y + orig.y;
+	r = rectaddpt(r, p);
+	draw(dst, r, i, nil, ZP);
+
+	return nil;
+}
+
+void
+tklabelgetimgs(Tk *tk, Image **image, Image **mask)
+{
+	TkLabel *tkl;
+
+	tkl = TKobj(TkLabel, tk);
+	*mask = nil;
+	if (tkl->img != nil)
+		*image = tkl->img->img;
+	else
+		*image = tkl->bitmap;
+}
+
+static
+TkCmdtab tklabelcmd[] =
+{
+	"cget",			tklabelcget,
+	"configure",		tklabelconf,
+	nil
+};
+
+TkMethod labelmethod = {
+	"label",
+	tklabelcmd,
+	tkfreelabel,
+	tkdrawlabel,
+	nil,
+	tklabelgetimgs
+};
--- /dev/null
+++ b/libtk/label.h
@@ -1,0 +1,74 @@
+typedef struct TkLabel TkLabel;
+
+/*
+ * widgets that use the label code:
+ *	label
+ *	checkbutton
+ *	button
+ *	menubutton
+ *	separator
+ *	cascade
+ *	radiobutton
+ */
+
+struct TkLabel
+{
+	char*		text;		/* Label value */
+	Image*		bitmap;		/* Bitmap to display */
+	TkImg*		img;
+	int			justify;
+	int			anchor;
+//	int			flags;		/* justify/anchor */
+	int		w;
+	int		h;
+	int		textheight;
+
+	/* button fields */
+	char*		command;	/* Command to execute at invoke */
+	char*		value;		/* Variable value in radio button */
+	char*		offvalue;		/* Off value for check button */
+	char*		variable;		/* Variable name in radio button */
+	int		ul;
+	int		check;		/* check/radiobutton/choicebutton state */
+	int		indicator;		/* -indicatoron setting */
+	char*		menu;
+
+	char**	values;
+	int nvalues;
+	/* current value of choicebutton is represented by check */
+};
+
+/* Layout constants */
+enum {
+	Textpadx	= 3,
+	Textpady	= 0,
+	Bitpadx	= 0,	/* Bitmap padding in labels */
+	Bitpady	= 0,
+	CheckButton	= 10,
+	CheckButtonBW	= 1,
+	ButtonBorder	= 4,
+	CheckSpace = CheckButton + 2*CheckButtonBW + 2*ButtonBorder,
+};
+
+extern	TkOption	tkbutopts[];
+extern	TkOption	tkradopts[];
+extern	TkOption	tkcbopts[];
+
+/* label.c */
+extern	void		tksizelabel(Tk*);
+extern	char*	tkdrawlabel(Tk*, Point);
+extern	void		tkfreelabel(Tk*);
+extern	void		tklabelgetimgs(Tk*, Image**, Image**);
+extern	char*	tksetvar(TkTop*, char*, char*);
+
+/* buton.c */
+extern	Tk*	tkmkbutton(TkTop*, int);
+extern	void	tksizebutton(Tk*);
+extern	char*	tkdrawbutton(Tk*, Point);
+extern	char*	tkbuttoninvoke(Tk*, char*, char**);
+extern	char*	tkradioinvoke(Tk*, char*, char**);
+extern	void		tkfreebutton(Tk*);
+
+/* support for menus */
+extern	int		tklabelmargin(Tk*);
+extern	int		tkbuttonmargin(Tk*);
--- /dev/null
+++ b/libtk/listb.c
@@ -1,0 +1,1065 @@
+#include "lib9.h"
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+#include "listb.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+	Listpadx	= 2,	/* X padding of text in listboxes */
+};
+
+typedef struct TkLentry TkLentry;
+typedef struct TkListbox TkListbox;
+
+struct TkLentry
+{
+	TkLentry*	link;
+	int		flag;
+	int		width;
+	char		text[TKSTRUCTALIGN];
+};
+
+struct TkListbox
+{
+	TkLentry*	head;
+	TkLentry*	anchor;
+	TkLentry*	active;
+	int		yelem;		/* Y element at top of box */
+	int		xdelta;		/* h-scroll position */
+	int		nitem;
+	int		nwidth;
+	int		selmode;
+	int		sborderwidth;
+	char*		xscroll;
+	char*		yscroll;
+};
+
+TkStab tkselmode[] =
+{
+	"single",	TKsingle,
+	"browse",	TKbrowse,
+	"multiple",	TKmultiple,
+	"extended",	TKextended,
+	nil
+};
+
+static
+TkOption opts[] =
+{
+	"xscrollcommand",	OPTtext,	O(TkListbox, xscroll),	nil,
+	"yscrollcommand",	OPTtext,	O(TkListbox, yscroll),	nil,
+	"selectmode",		OPTstab,	O(TkListbox, selmode),	tkselmode,
+	"selectborderwidth",	OPTnndist,	O(TkListbox, sborderwidth),	nil,
+	nil
+};
+
+static
+TkEbind b[] = 
+{
+	{TkButton1P,		"%W tkListbButton1P %y"},
+	{TkButton1R,	"%W tkListbButton1R"},
+	{TkButton1P|TkMotion,	"%W tkListbButton1MP %y"},
+	{TkMotion,		""},
+	{TkKey,	"%W tkListbKey 0x%K"},
+};
+
+
+static int
+lineheight(Tk *tk)
+{
+	TkListbox *l = TKobj(TkListbox, tk);
+	return tk->env->font->height+2*(l->sborderwidth+tk->highlightwidth);
+}
+
+char*
+tklistbox(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkName *names;
+	TkListbox *tkl;
+	TkOptab tko[3];
+
+	tk = tknewobj(t, TKlistbox, sizeof(Tk)+sizeof(TkListbox));
+	if(tk == nil)
+		return TkNomem;
+
+	tkl = TKobj(TkListbox, tk);
+	tkl->sborderwidth = 1;
+	tk->relief = TKsunken;
+	tk->borderwidth = 1;
+	tk->highlightwidth = 1;
+	tk->flag |= Tktakefocus;
+	tk->req.width = 170;
+	tk->req.height = lineheight(tk)*10;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+	e = tkbindings(t, tk, b, nelem(b));
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+char*
+tklistbcget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkListbox *tkl = TKobj(TkListbox, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreelistb(Tk *tk)
+{
+	TkLentry *e, *next;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	for(e = l->head; e; e = next) {
+		next = e->link;
+		free(e);
+	}
+	if(l->xscroll != nil)
+		free(l->xscroll);
+	if(l->yscroll != nil)
+		free(l->yscroll);
+}
+
+char*
+tkdrawlistb(Tk *tk, Point orig)
+{
+	Point p;
+	TkEnv *env;
+	TkLentry *e;
+	int lh, w, n, ly;
+	Rectangle r, a;
+	Image *i, *fg;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	env = tk->env;
+
+	r.min = ZP;
+	r.max.x = tk->act.width + 2*tk->borderwidth;
+	r.max.y = tk->act.height + 2*tk->borderwidth;
+	i = tkitmp(env, r.max, TkCbackgnd);
+	if(i == nil)
+		return nil;
+
+	w = tk->act.width;
+	if (w < l->nwidth)
+		w = l->nwidth;
+	lh = lineheight(tk);
+	ly = tk->borderwidth;
+	p.x = tk->borderwidth+l->sborderwidth+tk->highlightwidth+Listpadx-l->xdelta;
+	p.y = tk->borderwidth+l->sborderwidth+tk->highlightwidth;
+	n = 0;
+	for(e = l->head; e && ly < r.max.y; e = e->link) {
+		if(n++ < l->yelem)
+			continue;
+
+		a.min.x = tk->borderwidth;
+		a.min.y = ly;
+		a.max.x = a.min.x + tk->act.width;
+		a.max.y = a.min.y + lh;
+		if(e->flag & Tkactivated) {
+			draw(i, a, tkgc(env, TkCselectbgnd), nil, ZP);
+		}
+
+		if(e->flag & Tkactivated)
+			fg = tkgc(env, TkCselectfgnd);
+		else
+			fg = tkgc(env, TkCforegnd);
+		string(i, p, fg, p, env->font, e->text);
+		if((e->flag & Tkactive) && tkhaskeyfocus(tk)) {
+			a.min.x = tk->borderwidth-l->xdelta;
+			a.max.x = a.min.x+w;
+			a = insetrect(a, l->sborderwidth);
+			tkbox(i, a, tk->highlightwidth, fg);
+		}
+		ly += lh;
+		p.y += lh;
+	}
+
+	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+
+	p.x = tk->act.x + orig.x;
+	p.y = tk->act.y + orig.y;
+	r = rectaddpt(r, p);
+	draw(tkimageof(tk), r, i, nil, ZP);
+
+	return nil;
+}
+
+int
+tklindex(Tk *tk, char *buf)
+{
+	int index;
+	TkListbox *l;
+	TkLentry *e, *s;
+
+	l = TKobj(TkListbox, tk);
+
+	if(*buf == '@') {
+		while(*buf && *buf != ',')
+			buf++;
+		index = l->yelem + atoi(buf+1)/lineheight(tk);
+		if (index < 0)
+			return 0;
+		if (index > l->nitem)
+			return l->nitem;
+		return index;
+	}
+	if(*buf >= '0' && *buf <= '9')
+		return atoi(buf);
+
+	if(strcmp(buf, "end") == 0) {
+		if(l->nitem == 0)
+			return 0;
+		return l->nitem-1;
+	}
+
+	index = 0;
+	if(strcmp(buf, "active") == 0)
+		s = l->active;
+	else
+	if(strcmp(buf, "anchor") == 0)
+		s = l->anchor;
+	else
+		return -1;
+
+	for(e = l->head; e; e = e->link) {
+		if(e == s)
+			return index;
+		index++;
+	}
+	return -1;
+}
+
+void
+tklistsv(Tk *tk)
+{
+	TkListbox *l;
+	int nl, lh, top, bot;
+	char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+
+	l = TKobj(TkListbox, tk);
+	if(l->yscroll == nil)
+		return;
+
+	top = 0;
+	bot = TKI2F(1);
+
+	if(l->nitem != 0) {
+		lh = lineheight(tk);
+		nl = tk->act.height/lh;			/* Lines in the box */
+		top = TKI2F(l->yelem)/l->nitem;
+		bot = TKI2F(l->yelem+nl)/l->nitem;
+	}
+
+	v = tkfprint(val, top);
+	*v++ = ' ';
+	tkfprint(v, bot);
+	snprint(cmd, sizeof(cmd), "%s %s", l->yscroll, val);
+	e = tkexec(tk->env->top, cmd, nil);
+	if ((e != nil) && (tk->name != nil))
+		print("tk: yscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+void
+tklistsh(Tk *tk)
+{
+	int nl, top, bot;
+	char val[Tkminitem], cmd[Tkmaxitem], *v, *e;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	if(l->xscroll == nil)
+		return;
+
+	top = 0;
+	bot = TKI2F(1);
+
+	if(l->nwidth != 0) {
+		nl = tk->act.width;
+		top = TKI2F(l->xdelta)/l->nwidth;
+		bot = TKI2F(l->xdelta+nl)/l->nwidth;
+	}
+
+	v = tkfprint(val, top);
+	*v++ = ' ';
+	tkfprint(v, bot);
+	snprint(cmd, sizeof(cmd), "%s %s", l->xscroll, val);
+	e = tkexec(tk->env->top, cmd, nil);
+	if ((e != nil) && (tk->name != nil))
+		print("tk: xscrollcommand \"%s\": %s\n", tk->name->name, e);
+}
+
+void
+tklistbgeom(Tk *tk)
+{
+	tklistsv(tk);
+	tklistsh(tk);
+}
+
+static void
+listbresize(Tk *tk)
+{
+	TkLentry *e;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	l->nwidth = 0;
+	for (e = l->head; e != nil; e = e->link) {
+		e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth);
+		if(e->width > l->nwidth)
+			l->nwidth = e->width;
+	}
+	tklistbgeom(tk);
+}
+
+
+/* Widget Commands (+ means implemented)
+	+activate
+	 bbox
+	+cget
+	+configure
+	+curselection
+	+delete
+	+get
+	+index
+	+insert
+	+nearest
+	+see
+	+selection
+	+size
+	+xview
+	+yview
+*/
+
+char*
+tklistbconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd, sbw, hlw;
+	TkOptab tko[3];
+	Font *f;
+	TkListbox *tkl = TKobj(TkListbox, tk);
+
+	sbw = tkl->sborderwidth;
+	hlw = tk->highlightwidth;
+	f = tk->env->font;
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tkgeomchg(tk, &g, bd);
+
+	if (sbw != tkl->sborderwidth || f != tk->env->font || hlw != tk->highlightwidth)
+		listbresize(tk);
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static void
+entryactivate(Tk *tk, int index)
+{
+	TkListbox *l = TKobj(TkListbox, tk);
+	TkLentry *e;
+	int flag = Tkactive;
+
+	if (l->selmode == TKbrowse)
+		flag |= Tkactivated;
+	for(e = l->head; e; e = e->link) {
+		if(index-- == 0) {
+			e->flag |= flag;
+			l->active = e;
+		} else
+			e->flag &= ~flag;
+	}
+	tk->dirty = tkrect(tk, 1);
+}
+
+char*
+tklistbactivate(Tk *tk, char *arg, char **val)
+{
+	int index;
+	char buf[Tkmaxitem];
+
+	USED(val);
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	index = tklindex(tk, buf);
+	if(index == -1)
+		return TkBadix;
+
+	entryactivate(tk, index);
+	return nil;
+}
+
+char*
+tklistbnearest(Tk *tk, char *arg, char **val)
+{
+	int lh, y, index;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	lh = lineheight(tk);	/* Line height */
+	y = atoi(arg);
+	index = l->yelem + y/lh;
+	if(index > l->nitem)
+		index = l->nitem;
+	return tkvalue(val, "%d", index);
+}
+
+char*
+tklistbindex(Tk *tk, char *arg, char **val)
+{
+	int index;
+	char buf[Tkmaxitem];
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	index = tklindex(tk, buf);
+	if(index == -1)
+		return TkBadix;
+	return tkvalue(val, "%d", index);
+}
+
+char*
+tklistbsize(Tk *tk, char *arg, char **val)
+{
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	USED(arg);
+	return tkvalue(val, "%d", l->nitem);
+}
+
+char*
+tklistbinsert(Tk *tk, char *arg, char **val)
+{
+	int n, index;
+	TkListbox *l;
+	TkLentry *e, **el;
+	char *tbuf, buf[Tkmaxitem];
+
+	USED(val);
+	l = TKobj(TkListbox, tk);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "end") == 0) {
+		el = &l->head;
+		if(*el != nil) {
+			for(e = *el; e->link; e = e->link)
+				;
+			el = &e->link;
+		}
+	}
+	else {
+		index = tklindex(tk, buf);
+		if(index == -1)
+			return TkBadix;
+		el = &l->head;
+		for(e = *el; e && index-- > 0; e = e->link)
+			el = &e->link;
+	}
+
+	n = strlen(arg);
+	if(n > Tkmaxitem) {
+		n = (n*3)/2;
+		tbuf = malloc(n);
+		if(tbuf == nil)
+			return TkNomem;
+	}
+	else {
+		tbuf = buf;
+		n = sizeof(buf);
+	}
+
+	while(*arg) {
+		arg = tkword(tk->env->top, arg, tbuf, &tbuf[n], nil);
+		e = malloc(sizeof(TkLentry)+strlen(tbuf)+1);
+		if(e == nil)
+			return TkNomem;
+
+		e->flag = 0;
+		strcpy(e->text, tbuf);
+		e->link = *el;
+		*el = e;
+		el = &e->link;
+		e->width = stringwidth(tk->env->font, e->text)+2*(Listpadx+l->sborderwidth+tk->highlightwidth);
+		if(e->width > l->nwidth)
+			l->nwidth = e->width;
+		l->nitem++;
+	}
+
+	if(tbuf != buf)
+		free(tbuf);
+
+	tklistbgeom(tk);
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+int
+tklistbrange(Tk *tk, char *arg, int *s, int *e)
+{
+	char buf[Tkmaxitem];
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	*s = tklindex(tk, buf);
+	if(*s == -1)
+		return -1;
+	*e = *s;
+	if(*arg == '\0')
+		return 0;
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	*e = tklindex(tk, buf);
+	if(*e == -1)
+		return -1;
+	return 0;
+}
+
+char*
+tklistbselection(Tk *tk, char *arg, char **val)
+{
+	TkTop *t;
+	TkLentry *f;
+	TkListbox *l;
+	int s, e, indx;
+	char buf[Tkmaxitem];
+
+	l = TKobj(TkListbox, tk);
+
+	t = tk->env->top;
+	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "includes") == 0) {
+		tkword(t, arg, buf, buf+sizeof(buf), nil);
+		indx = tklindex(tk, buf);
+		if(indx == -1)
+			return TkBadix;
+		for(f = l->head; f && indx > 0; f = f->link)
+			indx--;
+		s = 0;
+		if(f && (f->flag&Tkactivated))
+			s = 1;
+		return tkvalue(val, "%d", s);
+	}
+
+	if(strcmp(buf, "anchor") == 0) {
+		tkword(t, arg, buf, buf+sizeof(buf), nil);
+		indx = tklindex(tk, buf);
+		if(indx == -1)
+			return TkBadix;
+		for(f = l->head; f && indx > 0; f = f->link)
+			indx--;
+		if(f != nil)
+			l->anchor = f;
+		return nil;
+	}
+	indx = 0;
+	if(strcmp(buf, "clear") == 0) {
+		if(tklistbrange(tk, arg, &s, &e) != 0)
+			return TkBadix;
+		for(f = l->head; f; f = f->link) {
+			if(indx <= e && indx++ >= s)
+				f->flag &= ~Tkactivated;
+		}
+		tk->dirty = tkrect(tk, 1);
+		return nil;
+	}
+	if(strcmp(buf, "set") == 0) {
+		if(tklistbrange(tk, arg, &s, &e) != 0)
+			return TkBadix;
+		for(f = l->head; f; f = f->link) {
+			if(indx <= e && indx++ >= s)
+				f->flag |= Tkactivated;
+		}
+		tk->dirty = tkrect(tk, 1);
+		return nil;
+	}
+	return TkBadcm;
+}
+
+char*
+tklistbdelete(Tk *tk, char *arg, char **val)
+{
+	TkLentry *e, **el;
+	int start, end, indx, bh;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	USED(val);
+	if(tklistbrange(tk, arg, &start, &end) != 0)
+		return TkBadix;
+
+	indx = 0;
+	el = &l->head;
+	for(e = l->head; e && indx < start; e = e->link) {
+		indx++;
+		el = &e->link;
+	}
+	while(e != nil && indx <= end) {
+		*el = e->link;
+		if(e->width == l->nwidth)
+			l->nwidth = 0;
+		if (e == l->anchor)
+			l->anchor = nil;
+		if (e == l->active)
+			l->active = nil;
+		free(e);
+		e = *el;
+		indx++;
+		l->nitem--;
+	}
+	if(l->nwidth == 0) {
+		for(e = l->head; e; e = e->link)
+			if(e->width > l->nwidth)
+				l->nwidth = e->width;
+	}
+	bh = tk->act.height/lineheight(tk);	/* Box height */
+	if(l->yelem + bh > l->nitem)
+		l->yelem = l->nitem - bh;
+	if(l->yelem < 0)
+		l->yelem = 0;
+
+	tklistbgeom(tk);
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+char*
+tklistbget(Tk *tk, char *arg, char **val)
+{
+	TkLentry *e;
+	char *r, *fmt;
+	int start, end, indx;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	if(tklistbrange(tk, arg, &start, &end) != 0)
+		return TkBadix;
+
+	indx = 0;
+	for(e = l->head; e && indx < start; e = e->link)
+		indx++;
+	fmt = "%s";
+	while(e != nil && indx <= end) {
+		r = tkvalue(val, fmt, e->text);
+		if(r != nil)
+			return r;
+		indx++;
+		fmt = " %s";
+		e = e->link;
+	}
+	return nil;		
+}
+
+char*
+tklistbcursel(Tk *tk, char *arg, char **val)
+{
+	int indx;
+	TkLentry *e;
+	char *r, *fmt;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	USED(arg);
+	indx = 0;
+	fmt = "%d";
+	for(e = l->head; e; e = e->link) {
+		if(e->flag & Tkactivated) {
+			r = tkvalue(val, fmt, indx);
+			if(r != nil)
+				return r;
+			fmt = " %d";
+		}
+		indx++;
+	}
+	return nil;		
+}
+
+static char*
+tklistbview(Tk *tk, char *arg, char **val, int nl, int *posn, int max)
+{
+	int top, bot, amount;
+	char buf[Tkmaxitem];
+	char *v, *e;
+
+	top = 0;
+	if(*arg == '\0') {
+		if ( max <= nl || max == 0 ) {	/* Double test redundant at
+						 * this time, but want to
+						 * protect against future
+						 * calls. -- DBK */
+			top = 0;
+			bot = TKI2F(1);
+		}
+		else {
+			top = TKI2F(*posn)/max;
+			bot = TKI2F(*posn+nl)/max;
+		}
+		v = tkfprint(buf, top);
+		*v++ = ' ';
+		tkfprint(v, bot);
+		return tkvalue(val, "%s", buf);
+	}
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "moveto") == 0) {
+		e = tkfracword(tk->env->top, &arg, &top, nil);
+		if (e != nil)
+			return e;
+		*posn = TKF2I((top+1)*max);
+	}
+	else
+	if(strcmp(buf, "scroll") == 0) {
+		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		amount = atoi(buf);
+		tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		if(buf[0] == 'p')		/* Pages */
+			amount *= nl;
+		*posn += amount;
+	}
+	else {
+		top = tklindex(tk, buf);
+		if(top == -1)
+			return TkBadix;
+		*posn = top;
+	}
+
+	bot = max - nl;
+	if(*posn > bot)
+		*posn = bot;
+	if(*posn < 0)
+		*posn = 0;
+
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static int
+entrysee(Tk *tk, int index)
+{
+	TkListbox *l = TKobj(TkListbox, tk);
+	int bh;
+
+	/* Box height in lines */
+	bh = tk->act.height/lineheight(tk);
+	if (bh > l->nitem)
+		bh = l->nitem;
+	if (index >= l->nitem)
+		index = l->nitem -1;
+	if (index < 0)
+		index = 0;
+
+	/* If the item is already visible, do nothing */
+	if (l->nitem == 0 || index >= l->yelem && index < l->yelem+bh)
+		return index;
+
+	if (index < l->yelem)
+		l->yelem = index;
+	else
+		l->yelem = index - (bh-1);
+
+	tklistsv(tk);
+	tk->dirty = tkrect(tk, 1);
+	return index;
+}
+
+char*
+tklistbsee(Tk *tk, char *arg, char **val)
+{
+	int index;
+	char buf[Tkmaxitem];
+
+	USED(val);
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	index = tklindex(tk, buf);
+	if(index == -1)
+		return TkBadix;
+
+	entrysee(tk, index);
+	return nil;
+}
+
+char*
+tklistbyview(Tk *tk, char *arg, char **val)
+{
+	int bh;
+	char *e;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	bh = tk->act.height/lineheight(tk);	/* Box height */
+	e = tklistbview(tk, arg, val, bh, &l->yelem, l->nitem);
+	tklistsv(tk);
+	return e;
+}
+
+char*
+tklistbxview(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	e = tklistbview(tk, arg, val, tk->act.width, &l->xdelta, l->nwidth);
+	tklistsh(tk);
+	return e;
+}
+
+static TkLentry*
+entryset(TkListbox *l, int indx, int toggle)
+{
+	TkLentry *e, *anchor;
+
+	anchor = nil;
+	for(e = l->head; e; e = e->link) {
+		if (indx-- == 0) {
+			anchor = e;
+			if (toggle) {
+				e->flag ^= Tkactivated;
+				break;
+			} else
+				e->flag |= Tkactivated;
+			continue;
+		}
+		if (!toggle)
+			e->flag &= ~Tkactivated;
+	}
+	return anchor;
+}
+
+static void
+selectto(TkListbox *l, int indx)
+{
+	TkLentry *e;
+	int inrange;
+
+	if (l->anchor == nil)
+		return;
+	inrange = 0;
+	for(e = l->head; e; e = e->link) {
+		if(indx == 0)
+			inrange = !inrange;
+		if(e == l->anchor)
+			inrange = !inrange;
+		if(inrange || e == l->anchor || indx == 0)
+			e->flag |= Tkactivated;
+		else
+			e->flag &= ~Tkactivated;
+		indx--;
+	}
+}
+
+static char*
+dragto(Tk *tk, int y)
+{
+	int indx;
+	TkLentry *e;
+	TkListbox *l = TKobj(TkListbox, tk);
+
+	indx = y/lineheight(tk);
+	if (y < 0)
+		indx--;	/* int division rounds towards 0 */
+	if (y < tk->act.height && indx >= l->nitem)
+		return nil;
+	indx = entrysee(tk, l->yelem+indx);
+	entryactivate(tk, indx);
+
+	if(l->selmode == TKsingle || l->selmode == TKmultiple)
+		return nil;
+
+	if(l->selmode == TKbrowse) {
+		for(e = l->head; e; e = e->link) {
+			if(indx-- == 0) {
+				if (e == l->anchor)
+					return nil;
+				l->anchor = e;
+				e->flag |= Tkactivated;
+			} else
+				e->flag &= ~Tkactivated;
+		}
+		return nil;
+	}
+	/* extended selection mode */
+	selectto(l, indx);
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static void
+autoselect(Tk *tk, void *v, int cancelled)
+{
+	Point pt;
+	int y, eh, ne;
+
+	USED(v);
+	if (cancelled)
+		return;
+
+	pt = tkposn(tk);
+	pt.y += tk->borderwidth;
+	y = tk->env->top->ctxt->mstate.y;
+	y -= pt.y;
+	eh = lineheight(tk);
+	ne = tk->act.height/eh;
+	if (y >= 0 && y < eh*ne)
+		return;
+	dragto(tk, y);
+	tkdirty(tk);
+	tkupdate(tk->env->top);
+}
+
+static char*
+tklistbbutton1p(Tk *tk, char *arg, char **val)
+{
+	TkListbox *l = TKobj(TkListbox, tk);
+	int y, indx;
+
+	USED(val);
+
+	y = atoi(arg);
+	indx = y/lineheight(tk);
+	indx += l->yelem;
+	if (indx < l->nitem) {
+		l->anchor = entryset(l, indx, l->selmode == TKmultiple);
+		entryactivate(tk, indx);
+		entrysee(tk, indx);
+	}
+	tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
+	return nil;
+}
+
+char *
+tklistbbutton1r(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+	tkcancelrepeat(tk);
+	return nil;
+}
+
+char*
+tklistbbutton1m(Tk *tk, char *arg, char **val)
+{
+	int y, eh, ne;
+	USED(val);
+
+	eh = lineheight(tk);
+	ne = tk->act.height/eh;
+	y = atoi(arg);
+	/* If outside the box, let autoselect handle it */
+	if (y < 0 || y >= ne * eh)
+		return nil;
+	return dragto(tk, y);
+}
+
+char*
+tklistbkey(Tk *tk, char *arg, char **val)
+{
+	TkListbox *l = TKobj(TkListbox, tk);
+	TkLentry *e;
+	int key, active;
+	USED(val);
+
+	if(tk->flag & Tkdisabled)
+		return nil;
+
+	key = strtol(arg, nil, 0);
+	active = 0;
+	for (e = l->head; e != nil; e = e->link) {
+		if (e->flag & Tkactive)
+			break;
+		active++;
+	}
+
+	if (key == '\n' || key == ' ') {
+		l->anchor = entryset(l, active, l->selmode == TKmultiple);
+		tk->dirty = tkrect(tk, 0);
+		return nil;
+	}
+	if (key == Up)
+		active--;
+	else if (key == Down)
+		active++;
+	else
+		return nil;
+
+	if (active < 0)
+		active = 0;
+	if (active >= l->nitem)
+		active = l->nitem-1;
+	entryactivate(tk, active);
+	if (l->selmode == TKextended) {
+		selectto(l, active);
+		tk->dirty = tkrect(tk, 0);
+	}
+	entrysee(tk, active);
+	return nil;
+}
+
+static
+TkCmdtab tklistcmd[] =
+{
+	"activate",		tklistbactivate,
+	"cget",			tklistbcget,
+	"configure",		tklistbconf,
+	"curselection",		tklistbcursel,
+	"delete",		tklistbdelete,
+	"get",			tklistbget,
+	"index",		tklistbindex,
+	"insert",		tklistbinsert,
+	"nearest",		tklistbnearest,
+	"selection",		tklistbselection, 
+	"see",			tklistbsee,
+	"size",			tklistbsize,
+	"xview",		tklistbxview,
+	"yview",		tklistbyview,
+	"tkListbButton1P",	tklistbbutton1p,
+	"tkListbButton1R",	tklistbbutton1r,
+	"tkListbButton1MP",	tklistbbutton1m,
+	"tkListbKey",	tklistbkey,
+	nil
+};
+
+TkMethod listboxmethod = {
+	"listbox",
+	tklistcmd,
+	tkfreelistb,
+	tkdrawlistb,
+	tklistbgeom
+};
--- /dev/null
+++ b/libtk/listb.h
@@ -1,0 +1,1 @@
+extern	char*	tklistbselection(Tk*, char*, char**);
--- /dev/null
+++ b/libtk/mail.tk
@@ -1,0 +1,224 @@
+
+# This is the first screen of the Sun mailtool
+
+# Frame .frame1 contains top-row buttons, label and entry
+# Frame .frame2 contains bottom-row buttons
+frame .frame1 -relief flat -bd 2
+frame .frame1.frame11 -relief flat -bd 2
+frame .frame1.frame12 -relief flat -bd 2
+frame .frame2 -relief flat -bd 2
+frame .frame2.frame21 -relief flat -bd 2
+frame .frame2.frame22 -relief flat -bd 2
+#frame .dummy -width 18c 
+pack .frame1 .frame2 -side top -fill x
+pack .frame2.frame21 -side left -fill x
+pack .frame2.frame22 -side left -fill x
+pack .frame1.frame11 -side left -fill x
+pack .frame1.frame12 -side left -fill x
+# Scrolltext frame
+frame .frame3 -relief sunken -bd 2
+frame .frame3.frame
+
+# File View Edit Compose buttons and associated menus
+
+# Build File button
+menubutton .frame1.frame11.file -text {File} -relief raised -width 8 \    	
+        -menu {.frame1.frame11.file.menu}
+
+# Build File-menu 
+menu .frame1.frame11.file.menu 
+.frame1.frame11.file.menu add command \
+    -label {Load In-Box} \
+    -state {active}
+.frame1.frame11.file.menu add command \
+    -label {Print}
+.frame1.frame11.file.menu add command \
+    -label {Save Changes}
+.frame1.frame11.file.menu add command \
+    -label {Done}
+.frame1.frame11.file.menu add command \
+    -label {Mail Files...}
+
+# Build View button
+menubutton .frame1.frame11.view -text {View} -relief raised -width 8 \
+        -menu {.frame1.frame11.view.menu}
+
+# Build View-menu
+menu .frame1.frame11.view.menu 
+
+.frame1.frame11.view.menu add command \
+    -label {Messages}
+.frame1.frame11.view.menu add command \
+    -label {Previous}
+.frame1.frame11.view.menu add command \
+    -label {Next} \
+    -state {active}
+.frame1.frame11.view.menu add command \
+    -label {Sort By}
+.frame1.frame11.view.menu add command \
+    -label {Find...}
+
+# Build Edit button
+menubutton .frame1.frame11.edit -text {Edit} -relief raised -width 8 \
+        -menu {.frame1.frame11.edit.menu}
+
+# Build Edit-menu
+  menu .frame1.frame11.edit.menu 
+  .frame1.frame11.edit.menu add command \
+    -label {Cut}
+  .frame1.frame11.edit.menu add command \
+    -label {Copy}
+  .frame1.frame11.edit.menu add command \
+    -label {Delete}
+  .frame1.frame11.edit.menu add command \
+    -label {Undelete}
+  .frame1.frame11.edit.menu add separator
+  .frame1.frame11.edit.menu add command \
+    -label {Properties....}
+
+
+# Build Compose button
+menubutton .frame1.frame11.compose -text {Compose} -relief raised -width 12 \
+        -menu {.frame1.frame11.compose.menu}
+
+# Build Compose-menu
+  menu .frame1.frame11.compose.menu 
+  .frame1.frame11.compose.menu add command \
+    -label {New}
+  .frame1.frame11.compose.menu add command \
+    -label {Reply}
+  .frame1.frame11.compose.menu add command \
+    -label {Forward}
+  .frame1.frame11.compose.menu add separator
+  .frame1.frame11.compose.menu add command \
+    -label { Vacation}
+
+# Pack the buttons File, View, Edit, Compose
+pack .frame1.frame11.file \
+    .frame1.frame11.view \
+    .frame1.frame11.edit \
+    .frame1.frame11.compose \
+     -side left 
+
+update
+
+# Build Done, Next, Delete, Reply buttons and associated menus
+# Build Done button
+menubutton .frame2.frame21.done -text {Done} -relief raised  -width 8 \
+	-menu {.frame2.frame21.done.menu}
+
+# Build Done-menu (empty)
+menu .frame2.frame21.done.menu
+
+# Build Next button
+menubutton .frame2.frame21.next -text {Next} -relief raised  -width 8 \
+         -menu {.frame2.frame21.next.menu}
+
+# Build Next-menu (empty)
+menu .frame2.frame21.next.menu
+
+# Build Delete button
+menubutton .frame2.frame21.delete -text {Delete} -relief raised -width 8 \
+        -menu {.frame2.frame21.delete.menu}
+
+# Build Delete-menu (empty)
+menu .frame2.frame21.delete.menu
+
+# Build Reply button
+menubutton .frame2.frame21.reply -text {Reply} -relief raised -width 12 \
+        -menu {.frame2.frame21.reply.menu}
+
+# Build Reply-menu
+menu .frame2.frame21.reply.menu 
+  .frame2.frame21.reply.menu add command \
+    -label {To Sender}
+  .frame2.frame21.reply.menu add command \
+    -label {To All}
+  .frame2.frame21.reply.menu add command \
+    -label {To Sender, Include}
+  .frame2.frame21.reply.menu add command \
+    -label {To All, Include}
+
+# Pack buttons Done, Next, Delete, Reply
+pack .frame2.frame21.done \
+    .frame2.frame21.next \
+    .frame2.frame21.delete \
+    .frame2.frame21.reply \
+     -side left 
+
+update
+
+# Build buttons Move, Copy, Load and associated menus
+menubutton .frame2.frame22.move -text {Move} -relief raised -width 8 \
+        -menu {.frame2.frame22.move.menu}
+menu .frame2.frame22.move.menu 
+.frame2.frame22.move.menu add command \
+    -label {Entry}
+
+menubutton .frame2.frame22.copy -text {Copy} -relief raised -width 8 \
+        -menu {.frame2.frame22.copy.menu}
+menu .frame2.frame22.copy.menu
+.frame2.frame22.copy.menu add command \
+    -label {Entry}
+
+menubutton .frame2.frame22.load -text {Load} -relief raised -width 8 \
+        -menu {.frame2.frame22.load.menu}
+menu .frame2.frame22.load.menu
+.frame2.frame22.load.menu add command \
+    -label {Entry}
+
+pack .frame2.frame22.move \
+    .frame2.frame22.copy \
+    .frame2.frame22.load \
+     -side left -fill x
+
+update
+
+# Build Mail-File label and Dir-Path entry widgets 
+label .frame1.frame12.lab_mailfile -relief flat -text {Mail File:   }
+entry .frame1.frame12.entry_mailfile -width 30 -relief sunken -bd 2 
+pack .frame1.frame12.entry_mailfile -side right 
+pack .frame1.frame12.lab_mailfile  -side left 
+
+update
+
+# Build scrolltext w/ scrollbars
+scrollbar .frame3.frame.scrollbar1 \
+	-command {.frame3.frame.listbox1 xview} \
+	-orient {horizontal} \
+    	-relief {raised}
+scrollbar .frame3.frame.scrollbar2 \
+	-command {.frame3.frame.listbox1 yview} \
+	-relief {raised}
+text .frame3.frame.listbox1 \
+	-relief {raised} \
+	-xscrollcommand {.frame3.frame.scrollbar1 set} \
+    	-yscrollcommand {.frame3.frame.scrollbar2 set}
+.frame3.frame.listbox1 insert end {Some Text}
+pack .frame3.frame 
+pack .frame3.frame.scrollbar2 -side left -fill y 
+pack .frame3.frame.listbox1 -side top -expand 1 -fill both
+pack .frame3.frame.scrollbar1 -side bottom -fill x
+
+# Pack frame3 to the rest of container frames
+pack .frame3 .frame3.frame -side top -expand 1 -fill both
+
+update
+
+# Build label(???) at the bottom
+label .lab_msgnum -relief flat
+pack .lab_msgnum -side top -fill x
+
+# Now make everything visible
+update
+
+# Enable keyboard traversal of a menu (Is this needed in inferno Tk?) 
+#tk_menuBar .frame1.frame11 .frame1.frame11.file .frame1.frame11.view \
+        #.frame1.frame11.edit .frame1.frame11.compose
+#tk_menuBar .frame2.frame21 .frame2.frame21.done .frame2.frame21.next \
+        #.frame2.frame21.delete .frame2.frame21.reply \
+        #.frame2.frame22 .frame2.frame22.move .frame2.frame22.copy .frame2.frame22.load
+focus .frame1.frame11
+update
+
+
--- /dev/null
+++ b/libtk/menu.tk
@@ -1,0 +1,49 @@
+frame .spacer -width 10c -height 5c
+
+listbox .spacer.l -yscrollcommand {.spacer.scroll set} -xscrollcommand {.scrollh set}
+scrollbar .spacer.scroll -command {.spacer.l yview}
+scrollbar .scrollh -orient horizontal -command  {.spacer.l xview} -width [.spacer.l cget width]
+.spacer.l insert end This is some text for the
+.spacer.l insert end listboxandthisentryisverymuchlongerthattherest
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+.spacer.l insert end and here is some more stuff to box
+
+canvas .c -width 5c -height 3c
+.c create rectangle 1c 1c 2c 2c -fill red
+.c create line 1c 1c 2c 2c -arrow both
+
+pack .spacer.l .spacer.scroll .c -side left -fill y
+.spacer.l selection set 3
+
+frame .mbar -relief raised -bd 2
+pack .mbar -fill x
+pack .mbar .spacer .scrollh -anchor w
+
+menubutton .mbar.file -text File -menu .mbar.file.m -underline 0
+menubutton .mbar.edit -text Edit -menu .mbar.edit.m -underline 0
+pack .mbar.file .mbar.edit -side left
+
+menu .mbar.file.m
+.mbar.file.m add checkbutton -label Italic
+.mbar.file.m add checkbutton -label Bold
+.mbar.file.m add checkbutton -label Underline
+.mbar.file.m add separator
+.mbar.file.m add command -label Quit
+.mbar.file.m add command -label Dictionary
+.mbar.file.m add cascade -label Search -menu .mbar.file.m.global
+
+menu .mbar.edit.m
+.mbar.edit.m add checkbutton -label Italic
+.mbar.edit.m add checkbutton -label Bold
+.mbar.edit.m add checkbutton -label Underline
+
+menu .mbar.file.m.global
+.mbar.file.m.global add checkbutton -label "\{Case Sensitive\}"
+.mbar.file.m.global add checkbutton -label Forward
+.mbar.file.m.global add checkbutton -label Backward
+.mbar.file.m.global add radiobutton -label "\{Upper case\}" -variable case -value u
+.mbar.file.m.global add radiobutton -label "\{Lower case\}" -variable case -value l
+.mbar.file.m.global add radiobutton -label "\{Case Insensitive\}" -variable case -value i
--- /dev/null
+++ b/libtk/menus.c
@@ -1,0 +1,1840 @@
+#include "lib9.h"
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+#include "frame.h"
+#include "label.h"
+
+/*
+arrow annotation for choicebutton: how do we make sure
+the menu items come up the same size?
+	- set menu items to same req.width & height as button itself.
+
+autorepeat:
+when we get mouse event at the edge of the screen
+and the menu overlaps that edge,
+start autorepeat timer to slide the menu the opposite direction.
+
+variable setting + command invocation:
+is the value of the variable the text or the index?
+same for the value appended to the command, text or index?
+
+if it's reimplemented as a custom widget, how does the custom widget
+get notified of variable changes?
+*/
+
+/* Widget Commands (+ means implemented)
+	+activate
+	+add
+	+cget
+	+configure
+	+delete
+	+entrycget
+	+entryconfigure
+	+index
+	+insert
+	+invoke
+	+post
+	+postcascade
+	+type
+	+unpost
+	+yposition
+*/
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+	Sepheight	= 6,	/* Height of menu separator */
+};
+
+#define NOCHOICE "-----"
+
+enum {
+	Startspeed = TKI2F(1),
+};
+
+static
+TkOption mbopts[] =
+{
+	"text",		OPTtext,	O(TkLabel, text),		nil,
+	"anchor",	OPTflag,	O(TkLabel, anchor),	tkanchor,
+	"underline",	OPTdist,	O(TkLabel, ul),		nil,
+	"justify",	OPTstab,	O(TkLabel, justify),	tkjustify,
+	"menu",		OPTtext,	O(TkLabel, menu),		nil,
+	"bitmap",	OPTbmap,	O(TkLabel, bitmap),		nil,
+	"image",	OPTimag,	O(TkLabel, img),		nil,
+	nil
+};
+
+static
+TkOption choiceopts[] =
+{
+	"variable",	OPTtext,	O(TkLabel, variable),	nil,
+	"values",	OPTlist,	O(TkLabel, values), nil,
+	"command", OPTtext, O(TkLabel, command), nil,
+	nil
+};
+
+static
+TkEbind mbbindings[] = 
+{
+	{TkEnter,		"%W tkMBenter %s"},
+	{TkLeave,		"%W tkMBleave"},
+	{TkButton1P,		"%W tkMBpress 1"},
+	{TkKey,		"%W tkMBkey 0x%K"},
+	{TkButton1P|TkMotion,	"%W tkMBpress 0"},
+};
+
+extern Rectangle bbnil;
+static char* tkmpost(Tk*, int, int, int, int, int);
+static void menuclr(Tk*);
+static void freemenu(Tk*);
+static void appenditem(Tk*, Tk*, int);
+static void layout(Tk*);
+static Tk* tkmenuindex2ptr(Tk*, char**);
+static void activateitem(Tk*);
+
+/*
+ * unmap menu cascade upto (but not including) tk
+ */
+static void
+tkunmapmenus(TkTop *top, Tk *tk)
+{
+	TkTop *t;
+	Tk *menu;
+	TkWin *tkw;
+
+	menu = top->ctxt->tkmenu;
+	if (menu == nil)
+		return;
+	t = menu->env->top;
+
+	/* if something went wrong, clear down all menus */
+	if (tk != nil && tk->env->top != t)
+		tk = nil;
+
+	while (menu != nil && menu != tk) {
+		menuclr(menu);
+		tkunmap(menu);
+		tkcancelrepeat(menu);
+		tkw = TKobj(TkWin, menu);
+		if (tkw->cascade != nil) {
+			menu = tklook(t, tkw->cascade, 0);
+			free(tkw->cascade);
+			tkw->cascade = nil;
+		} else
+			menu = nil;
+	}
+	top->ctxt->tkmenu = menu;
+	tksetmgrab(top, menu);
+}
+
+static void
+tkunmapmenu(Tk *tk)
+{
+	TkTop *t;
+	TkWin *tkw;
+	Tk *parent;
+
+	parent = nil;
+	tkw = TKobj(TkWin, tk);
+	t = tk->env->top;
+	if (tkw->cascade != nil)
+		parent = tklook(t, tkw->cascade, 0);
+	tkunmapmenus(t, parent);
+	if (tkw->freeonunmap)
+		freemenu(tk);
+}
+
+static void
+tksizemenubutton(Tk *tk)
+{
+	int w, h;
+	char **v, *cur;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	tksizelabel(tk);
+	if(tk->type != TKchoicebutton)
+		return;
+	w = tk->req.width;
+	h = tk->req.height;
+	v = tkl->values;
+	if (v == nil || *v == nil)
+		return;
+	cur = tkl->text;
+	for (; *v; v++) {
+		tkl->text = *v;
+		tksizelabel(tk);
+		if (tk->req.width > w)
+			w = tk->req.width;
+		if (tk->req.height > h)
+			h = tk->req.height;
+	}
+	tkl->text = cur;
+	tksizelabel(tk);
+	tk->req.width = w;
+	tk->req.height = h;
+}
+
+static char*
+tkmkmenubutton(TkTop *t, char *arg, char **ret, int type, TkOption *opts)
+{
+	Tk *tk;
+	char *e, **v;
+	TkName *names;
+	TkLabel *tkl;
+	TkOptab tko[3];
+
+/* need to get the label from elsewhere */
+	tk = tknewobj(t, type, sizeof(Tk)+sizeof(TkLabel));
+	if(tk == nil)
+		return TkNomem;
+	tk->borderwidth = 2;
+	tk->flag |= Tknograb;
+
+	tkl = TKobj(TkLabel, tk);
+	tkl->ul = -1;
+	if(type == TKchoicebutton)
+		tkl->anchor = Tknorth|Tkwest;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tkl->nvalues = 0;
+	if (tkl->values != nil) {
+		for (v = tkl->values; *v; v++)
+			;
+		tkl->nvalues = v - tkl->values;
+	}
+	if(type == TKchoicebutton){
+		if(tkl->nvalues > 0)
+			tkl->text = strdup(tkl->values[0]);
+		else
+			tkl->text = strdup(NOCHOICE);
+	}
+	tksettransparent(tk, 
+		tkhasalpha(tk->env, TkCbackgnd) ||
+		tkhasalpha(tk->env, TkCselectbgnd) ||
+		tkhasalpha(tk->env, TkCactivebgnd));
+
+	e = tkbindings(t, tk, mbbindings, nelem(mbbindings));
+
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tksizemenubutton(tk);
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+char*
+tkchoicebutton(TkTop *t, char *arg, char **ret)
+{
+	return tkmkmenubutton(t, arg, ret, TKchoicebutton, choiceopts);
+}
+
+char*
+tkmenubutton(TkTop *t, char *arg, char **ret)
+{
+	return tkmkmenubutton(t, arg, ret, TKmenubutton, mbopts);
+}
+
+static char*
+tkmenubutcget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = (tk->type == TKchoicebutton ? choiceopts : mbopts);
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkmenubutconf(Tk *tk, char *arg, char **val)
+{
+	char *e, **v;
+	TkGeom g;
+	int bd;
+	TkOptab tko[3];
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkl;
+	tko[1].optab = (tk->type == TKchoicebutton ? choiceopts : mbopts);
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+
+	if (tk->type == TKchoicebutton) {
+		tkl->nvalues = 0;
+		if (tkl->values != nil) {
+			for (v = tkl->values; *v; v++)
+				;
+			tkl->nvalues = v - tkl->values;
+		}
+		if (tkl->check >= tkl->nvalues || strcmp(tkl->text, tkl->values[tkl->check])) {
+			/*
+			 * try to keep selected value the same if possible
+			 */
+			for (v = tkl->values; v && *v; v++)
+				if (!strcmp(*v, tkl->text))
+					break;
+			free(tkl->text);
+			if (v == nil || *v == nil) {
+				tkl->text = strdup(tkl->nvalues > 0 ? tkl->values[0] : NOCHOICE);
+				tkl->check = 0;
+			} else {
+				tkl->check = v - tkl->values;
+				tkl->text = strdup(*v);
+			}
+		}
+	}
+	tksettransparent(tk, 
+		tkhasalpha(tk->env, TkCbackgnd) ||
+		tkhasalpha(tk->env, TkCselectbgnd) ||
+		tkhasalpha(tk->env, TkCactivebgnd));
+	tksizemenubutton(tk);
+	tkgeomchg(tk, &g, bd);
+
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static char*
+tkMBleave(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+
+	tk->flag &= ~Tkactive;
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static Tk*
+mkchoicemenu(Tk *tkb)
+{
+	Tk *menu, *tkc;
+	int i;
+	TkLabel *tkl, *tkcl;
+	TkWin *tkw;
+	TkTop *t;
+
+	tkl = TKobj(TkLabel, tkb);
+	t = tkb->env->top;
+
+	menu = tknewobj(t, TKmenu, sizeof(Tk)+sizeof(TkWin));
+	if(menu == nil)
+		return nil;
+
+	menu->relief = TKraised;
+	menu->flag |= Tknograb;
+	menu->borderwidth = 1;
+	tkputenv(menu->env);
+	menu->env = tkb->env;
+	menu->env->ref++;
+
+	menu->flag |= Tkwindow;
+	menu->geom = tkmoveresize;
+	tkw = TKobj(TkWin, menu);
+	tkw->cbname = strdup(tkb->name->name);
+	tkw->di = (void*)-1;			// XXX
+
+	for(i = tkl->nvalues - 1; i >= 0; i--){
+		tkc = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
+		/* XXX recover from malloc failure */
+		tkc->flag = Tkwest|Tkfillx|Tktop;
+		tkc->highlightwidth = 0;
+		tkc->borderwidth = 1;
+		tkc->relief = TKflat;
+		tkputenv(tkc->env);
+		tkc->env = tkb->env;
+		tkc->env->ref++;
+		tkcl = TKobj(TkLabel, tkc);
+		tkcl->anchor = Tkwest;
+		tkcl->ul = -1;
+		tkcl->justify = Tkleft;
+		tkcl->text = strdup(tkl->values[i]);
+		tkcl->command = smprint("%s invoke %d", tkb->name->name, i);
+		/* XXX recover from malloc failure */
+		tksizelabel(tkc);
+		tkc->req.height = tkb->req.height;
+		appenditem(menu, tkc, 0);
+	}
+	layout(menu);
+
+	tkw->next = t->windows;
+	tkw->freeonunmap = 1;
+	t->windows = menu;
+	return menu;
+}
+
+static char*
+tkMBpress(Tk *tk, char *arg, char **val)
+{
+	Tk *menu, *item;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+	Point g;
+	char buf[12], *bufp, *e;
+
+	USED(arg);
+	USED(val);
+
+	g = tkposn(tk);
+	if (tk->type == TKchoicebutton) {
+		menu = mkchoicemenu(tk);
+		if (menu == nil)
+			return TkNomem;
+		sprint(buf, "%d", tkl->check);
+		bufp = buf;
+		item = tkmenuindex2ptr(menu, &bufp);
+		if(item == nil)
+			return nil;
+		g.y -= item->act.y;
+		e = tkmpost(menu, g.x, g.y, 0, 0, 0);
+		activateitem(item);
+		return e;
+	} else {
+		if (tkl->menu == nil)
+			return nil;
+		menu = tklook(tk->env->top, tkl->menu, 0);
+		if(menu == nil || menu->type != TKmenu)
+			return TkBadwp;
+
+		if(menu->flag & Tkmapped) {
+			if(atoi(arg))
+				tkunmapmenu(menu);
+			return nil;
+		}
+		return tkmpost(menu, g.x, g.y, 0, tk->act.height + 2*tk->borderwidth, 1);
+	}
+}
+
+static char*
+tkMBkey(Tk *tk, char *arg, char **val)
+{
+	int key;
+	USED(val);
+
+	if(tk->flag & Tkdisabled)
+		return nil;
+
+	key = strtol(arg, nil, 0);
+	if (key == '\n' || key == ' ')
+		return tkMBpress(tk, "1", nil);
+	return nil;
+}
+
+static char*
+tkMBenter(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+
+	tk->flag |= Tkactive;
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static char*
+tkchoicebutset(Tk *tk, char *arg, char **val)
+{
+	char buf[12], *e;
+	int v;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	USED(val);
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if (*buf == '\0')
+		return TkBadvl;
+	v = atoi(buf);
+	if (v < 0 || v >= tkl->nvalues)
+		return TkBadvl;
+	if (v == tkl->check)
+		return nil;
+	free(tkl->text);
+	tkl->text = strdup(tkl->values[v]);
+	/* XXX recover from malloc error */
+	tkl->check = v;
+
+	sprint(buf, "%d", v);
+	e = tksetvar(tk->env->top, tkl->variable, buf);
+	if(e != nil)
+		return e;
+
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static char*
+tkchoicebutinvoke(Tk *tk, char *arg, char **val)
+{
+	TkLabel *tkl = TKobj(TkLabel, tk);
+	char *e;
+
+	e = tkchoicebutset(tk, arg, val);
+	if(e != nil)
+		return e;
+	if(tkl->command)
+		return tkexec(tk->env->top, tkl->command, val);
+	return nil;
+}
+
+static char*
+tkchoicebutgetvalue(Tk *tk, char *arg, char **val)
+{
+	char buf[12];
+	int gotarg, v;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+	if (tkl->nvalues == 0)
+		return nil;
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg);
+	if (!gotarg)
+		return tkvalue(val, "%s", tkl->values[tkl->check]);
+	v = atoi(buf);
+	if (buf[0] < '0' || buf[0] > '9' || v >= tkl->nvalues)
+		return TkBadvl;
+	return tkvalue(val, "%s", tkl->values[tkl->check]);
+}
+
+static char*
+tkchoicebutsetvalue(Tk *tk, char *arg, char **val)
+{
+	char *buf;
+	char **v;
+	int gotarg;
+	TkLabel *tkl = TKobj(TkLabel, tk);
+
+	USED(val);
+	if (tkl->nvalues == 0)
+		return TkBadvl;
+	buf = mallocz(Tkmaxitem, 0);
+	if (buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, &gotarg);
+	if (!gotarg) {
+		free(buf);
+		return TkBadvl;
+	}
+	for (v = tkl->values; *v; v++)
+		if (strcmp(*v, buf) == 0)
+			break;
+	free(buf);
+	if (*v == nil)
+		return TkBadvl;
+	free(tkl->text);
+	tkl->text = strdup(*v);
+	/* XXX recover from malloc error */
+	tkl->check = v - tkl->values;
+
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static char*
+tkchoicebutget(Tk *tk, char *arg, char **val)
+{
+	TkLabel *tkl = TKobj(TkLabel, tk);
+	char *buf, **v;
+	int gotarg;
+	
+	if (tkl->nvalues == 0)
+		return nil;
+	buf = mallocz(Tkmaxitem, 0);
+	if (buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, &gotarg);
+	if (!gotarg) {
+		free(buf);
+		return tkvalue(val, "%d", tkl->check);
+	}
+
+	for (v = tkl->values; *v; v++)
+		if (strcmp(*v, buf) == 0)
+			break;
+	free(buf);
+	if (*v)
+		return tkvalue(val, "%d", v - tkl->values);
+	return nil;
+}
+
+static char*
+tkchoicebutvaluecount(Tk *tk, char *arg, char **val)
+{
+	TkLabel *tkl = TKobj(TkLabel, tk);
+	USED(arg);
+	return tkvalue(val, "%d", tkl->nvalues);
+}
+
+
+static void
+tkchoicevarchanged(Tk *tk, char *var, char *value)
+{
+	TkLabel *tkl = TKobj(TkLabel, tk);
+	int v;
+
+	if(tkl->variable != nil && strcmp(tkl->variable, var) == 0){
+		if(value[0] < '0' || value[0] > '9')
+			return;
+		v = atoi(value);
+		if(v < 0 || v >= tkl->nvalues)
+			return;		/* what else can we do? */
+		free(tkl->text);
+		tkl->text = strdup(tkl->values[v]);
+		/* XXX recover from malloc error */
+		tkl->check = v;
+		tk->dirty = tkrect(tk, 0);
+		tkdirty(tk);
+	}
+}
+
+Tk *
+tkfindchoicemenu(Tk *tkb)
+{
+	Tk *tk, *next;
+	TkTop *top;
+	TkWin *tkw;
+
+	top = tkb->env->top;
+	for (tk = top->windows; tk != nil; tk = next){
+		tkw = TKobj(TkWin, tk);
+		if(tk->name == nil){
+			assert(strcmp(tkw->cbname, tkb->name->name) == 0);
+			return tk;
+		}
+		next = tkw->next;
+	}
+	return nil;
+}
+
+static
+TkOption menuopt[] =
+{
+	"postcommand",	OPTtext,	O(TkWin, postcmd),		nil,
+	nil,
+};
+
+char*
+tkmenu(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkWin *tkw;
+	TkName *names;
+	TkOptab tko[3];
+
+	tk = tknewobj(t, TKmenu, sizeof(Tk)+sizeof(TkWin));
+	if(tk == nil)
+		return TkNomem;
+
+	tkw = TKobj(TkWin, tk);
+	tkw->di = (void*)-1;		// XXX
+	tk->relief = TKraised;
+	tk->flag |= Tknograb;
+	tk->borderwidth = 1;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkw;
+	tko[1].optab = menuopt;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	tk->flag |= Tkwindow;
+	tk->geom = tkmoveresize;
+
+	tkw->next = t->windows;
+	t->windows = tk;
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+static void
+freemenu(Tk *top)
+{
+	Tk *tk, *f, *nexttk, *nextf;
+	TkWin *tkw;
+
+	tkunmapmenu(top);
+	tkw = TKobj(TkWin, top);
+	for(tk = tkw->slave; tk; tk = nexttk) {
+		nexttk = tk->next;
+		for(f = tk->slave; f; f = nextf) {
+			nextf = f->next;
+			tkfreeobj(f);
+		}
+		tkfreeobj(tk);
+	}
+	top->slave = nil;
+	tkfreeframe(top);
+}
+
+static
+TkOption mopt[] =
+{
+	"menu",		OPTtext,	O(TkLabel, menu),		nil,
+	nil,
+};
+
+static void
+tkbuildmopt(TkOptab *tko, int n, Tk *tk)
+{
+	memset(tko, 0, n*sizeof(TkOptab));
+
+	n = 0;
+	tko[n].ptr = tk;
+	tko[n++].optab = tkgeneric;
+
+	switch(tk->type) {
+	case TKcascade:
+		tko[n].ptr = TKobj(TkLabel, tk);
+		tko[n++].optab = mopt;
+		goto norm;
+	case TKradiobutton:	
+		tko[n].ptr = TKobj(TkLabel, tk);
+		tko[n++].optab = tkradopts;
+		goto norm;
+	case TKcheckbutton:
+		tko[n].ptr = TKobj(TkLabel, tk);
+		tko[n++].optab = tkcbopts;
+		/* fall through */
+	case TKlabel:
+	norm:
+		tko[n].ptr = TKobj(TkLabel, tk);
+		tko[n].optab = tkbutopts;
+		break;	
+	}
+}
+
+static char*
+tkmenuentryconf(Tk *menu, Tk *tk, char *arg)
+{
+	char *e;
+	TkOptab tko[4];
+
+	USED(menu);
+
+	tkbuildmopt(tko, nelem(tko), tk);
+	e = tkparse(tk->env->top, arg, tko, nil);
+	switch (tk->type) {
+	case TKlabel:
+	case TKcascade:
+		tksizelabel(tk);
+		break;
+	case TKradiobutton:
+	case TKcheckbutton:
+		tksizebutton(tk);
+	}
+
+	return e;
+}
+
+static void
+layout(Tk *menu)
+{
+	TkWin *tkw;
+	Tk *tk;
+	int m, w, y, maxmargin, maxw;
+
+	y = 0;
+	maxmargin = 0;
+	maxw = 0;
+
+	tkw = TKobj(TkWin, menu);
+
+	/* determine padding for item text alignment */
+	for (tk = tkw->slave; tk != nil; tk = tk->next) {
+		m = tkbuttonmargin(tk);	/* TO DO: relies on buttonmargin defaulting to labelmargin */
+		tk->act.x = m;		/* temp store */
+		if (m > maxmargin)
+			maxmargin = m;
+	}
+	/* set x pos and determine max width */
+	for (tk = tkw->slave; tk != nil; tk = tk->next) {
+		tk->act.x = tk->borderwidth + maxmargin - tk->act.x;
+		tk->act.y = y + tk->borderwidth;
+		tk->act.height = tk->req.height;
+		tk->act.width = tk->req.width;
+		y += tk->act.height+2*tk->borderwidth;
+		w = tk->act.x + tk->req.width + 2* tk->borderwidth;
+		if (w > maxw)
+			maxw = w;
+	}
+	/* expand separators and cascades and mark all as dirty */
+	for (tk = tkw->slave; tk != nil; tk = tk->next) {
+		switch (tk->type) {
+		case TKseparator:
+			tk->act.x = tk->borderwidth;
+			/*FALLTHRU*/
+		case TKcascade:
+			tk->act.width = (maxw - tk->act.x) - tk->borderwidth;
+		}
+		tk->dirty = tkrect(tk, 1);
+	}
+	menu->dirty = tkrect(menu, 1);
+	tkmoveresize(menu, 0, 0, maxw, y);
+}
+
+static void
+menuitemgeom(Tk *sub, int x, int y, int w, int h)
+{
+	if (sub->parent == nil)
+		return;
+	if(w < 0)
+		w = 0;
+	if(h < 0)
+		h = 0;
+	sub->req.x = x;
+	sub->req.y = y;
+	sub->req.width = w;
+	sub->req.height = h;
+	layout(sub->parent);
+}
+
+static void
+appenditem(Tk *menu, Tk *item, int where)
+{
+	TkWin *tkw;
+	Tk *f, **l;
+
+	tkw = TKobj(TkWin, menu);
+	l = &tkw->slave;
+	for (f = *l; f != nil; f = f->next) {
+		if (where-- == 0)
+			break;
+		l = &f->next;
+	}
+	*l = item;
+	item->next = f;
+	item->parent = menu;
+	item->geom = menuitemgeom;
+}
+
+static char*
+menuadd(Tk *menu, char *arg, int where)
+{
+	Tk *tkc;
+	int configure;
+	char *e;
+	TkTop *t;
+	TkLabel *tkl;
+	char buf[Tkmaxitem];
+	
+	t = menu->env->top;
+	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+	configure = 1;
+	e = nil;
+
+	if(strcmp(buf, "checkbutton") == 0)
+		tkc = tkmkbutton(t, TKcheckbutton);
+	else if(strcmp(buf, "radiobutton") == 0)
+		tkc = tkmkbutton(t, TKradiobutton);
+	else if(strcmp(buf, "command") == 0)
+		tkc = tknewobj(t, TKlabel, sizeof(Tk)+sizeof(TkLabel));
+	else if(strcmp(buf, "cascade") == 0)
+		tkc = tknewobj(t, TKcascade, sizeof(Tk)+sizeof(TkLabel));
+	else if(strcmp(buf, "separator") == 0) {
+		tkc = tknewobj(t, TKseparator, sizeof(Tk));	/* it's really a frame */
+		if (tkc != nil) {
+			tkc->flag = Tkfillx|Tktop;
+			tkc->req.height = Sepheight;
+			configure = 0;
+		}
+	}
+	else
+		return TkBadvl;
+
+	if (tkc == nil)
+		e = TkNomem;
+
+	if (e == nil) {
+		if(tkc->env == t->env && menu->env != t->env) {
+			tkputenv(tkc->env);
+			tkc->env = menu->env;
+			tkc->env->ref++;
+		}
+		if (configure) {
+			tkc->flag = Tkwest|Tkfillx|Tktop;
+			tkc->highlightwidth = 0;
+			tkc->borderwidth = 1;
+			tkc->relief = TKflat;
+			tkl = TKobj(TkLabel, tkc);
+			tkl->anchor = Tkwest;
+			tkl->ul = -1;
+			tkl->justify = Tkleft;
+			e = tkmenuentryconf(menu, tkc, arg);
+		}
+	}
+
+	if(e != nil) {
+		if (tkc != nil)
+			tkfreeobj(tkc);
+		return e;
+	}	
+
+	appenditem(menu, tkc, where);
+	layout(menu);
+	return nil;
+}
+
+static int
+tkmindex(Tk *tk, char *p)
+{
+	TkWin *tkw;
+	int y, n;
+
+	if(*p >= '0' && *p <= '9')
+		return atoi(p);
+
+	tkw = TKobj(TkWin, tk);
+	n = 0;
+	if(*p == '@') {
+		y = atoi(p+1);
+		for(tk = tkw->slave; tk; tk = tk->next) {
+			if(y >= tk->act.y && y < tk->act.y+tk->act.height+2*tk->borderwidth )
+				return n;
+			n++;
+		}
+	}
+	if(strcmp(p, "end") == 0 || strcmp(p, "last") == 0) {
+		for(tk = tkw->slave; tk && tk->next; tk = tk->next)
+			n++;
+		return n;
+	}
+	if(strcmp(p, "active") == 0) {
+		for(tk = tkw->slave; tk; tk = tk->next) {
+			if(tk->flag & Tkactive)
+				return n;
+			n++;
+		}
+		return -2;
+	}
+	if(strcmp(p, "none") == 0)
+		return -2;
+
+	return -1;
+}
+
+static int
+tkmenudel(Tk *tk, int y)
+{
+	TkWin *tkw;
+	Tk *f, **l, *next;
+
+	tkw = TKobj(TkWin, tk);
+	l = &tkw->slave;
+	for(tk = *l; tk; tk = tk->next) {
+		if(y-- == 0) {
+			*l = tk->next;
+			for(f = tk->slave; f; f = next) {
+				next = f->next;
+				tkfreeobj(f);
+			}
+			tkfreeobj(tk);
+			return 1;
+		}
+		l = &tk->next;
+	}
+	return 0;	
+}
+
+static char*
+tkmpost(Tk *tk, int x, int y, int cascade, int bh, int adjust)
+{
+	char *e;
+	TkWin *w;
+	TkTop *t;
+	Rectangle *dr;
+
+	t = tk->env->top;
+	if(adjust){
+		dr = &t->screenr;
+		if(x+tk->act.width > dr->max.x)
+			x = dr->max.x - tk->act.width;
+		if(x < 0)
+			x = 0;
+		if(y+bh+tk->act.height > dr->max.y)
+			y -= tk->act.height + 2* tk->borderwidth;
+		else
+			y += bh;
+		if(y < 0)
+			y = 0;
+	}
+	menuclr(tk);
+	tkmovewin(tk, Pt(x, y));
+
+	/* stop possible postcommand recursion */
+	if (tk->flag & Tkmapped)
+		return nil;
+
+	w = TKobj(TkWin, tk);
+	if(w->postcmd != nil) {
+		e = tkexec(tk->env->top, w->postcmd, nil);
+		if(e != nil) {
+			print("%s: postcommand: %s: %s\n", tkname(tk), w->postcmd, e);
+			return e;
+		}
+	}
+	if (!cascade)
+		tkunmapmenus(t, nil);
+
+	e = tkmap(tk);
+	if(e != nil)
+		return e;
+
+	if (t->ctxt->tkmenu != nil)
+		w->cascade = strdup(t->ctxt->tkmenu->name->name);
+	t->ctxt->tkmenu = tk;
+	tksetmgrab(t, tk);
+
+	/* Make sure slaves are redrawn */
+	return tkupdate(tk->env->top);
+}
+
+static Tk*
+tkmenuindex2ptr(Tk *tk, char **arg)
+{
+	TkWin *tkw;
+	int index;
+	char *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return nil;
+	*arg = tkword(tk->env->top, *arg, buf, buf+Tkmaxitem, nil);
+	index = tkmindex(tk, buf);
+	free(buf);
+	if(index < 0)
+		return nil;
+
+	tkw = TKobj(TkWin, tk);
+	for(tk = tkw->slave; tk && index; tk = tk->next)
+		index--;
+
+	if(tk == nil)
+		return nil;
+
+	return tk;
+}
+
+static char*
+tkmenuentrycget(Tk *tk, char *arg, char **val)
+{
+	Tk *etk;
+	TkOptab tko[4];
+
+	etk = tkmenuindex2ptr(tk, &arg);
+	if(etk == nil)
+		return TkBadix;
+
+	tkbuildmopt(tko, nelem(tko), etk);
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkmenucget(Tk *tk, char *arg, char **val)
+{
+	TkWin *tkw;
+	TkOptab tko[4];
+
+	tkw = TKobj(TkWin, tk);
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkw;
+	tko[1].optab = tktop;
+	tko[2].ptr = tkw;
+	tko[2].optab = menuopt;
+	tko[3].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkmenuconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkWin *tkw;
+	TkOptab tko[3];
+
+	tkw = TKobj(TkWin, tk);
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkw;
+	tko[1].optab = menuopt;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tkgeomchg(tk, &g, bd);
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static char*
+tkmenuadd(Tk *tk, char *arg, char **val)
+{
+	USED(val);
+	return menuadd(tk, arg, -1);	
+}
+
+static char*
+tkmenuinsert(Tk *tk, char *arg, char **val)
+{
+	int index;
+	char *buf;
+
+	USED(val);
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	index = tkmindex(tk, buf);
+	free(buf);
+	if (index < 0)
+		return TkBadix;
+	return menuadd(tk, arg, index);
+}
+
+static void
+menuitemdirty(Tk *item)
+{
+	Tk *menu;
+	Rectangle r;
+
+	menu = item->parent;
+	if (menu == nil)
+		return;
+	item->dirty = tkrect(item, 1);
+	r = rectaddpt(item->dirty, Pt(item->act.x, item->act.y));
+	combinerect(&menu->dirty, r);
+}
+
+static void
+menuclr(Tk *tk)
+{
+	TkWin *tkw;
+	Tk *f;
+	tkw = TKobj(TkWin, tk);
+	for(f = tkw->slave; f; f = f->next) {
+		if(f->flag & Tkactive) {
+			f->flag &= ~Tkactive;
+			menuitemdirty(f);
+		}
+	}
+}
+
+static char*
+tkpostcascade(Tk *parent, Tk *tk, int toggle)
+{
+	Tk *tkm;
+	TkWin *tkw;
+	Point g;
+	TkTop *t;
+	TkLabel *tkl;
+	char *e;
+
+	if(tk->flag & Tkdisabled)
+		return nil;
+
+	tkl = TKobj(TkLabel, tk);
+	t = tk->env->top;
+	tkm = tklook(t, tkl->menu, 0);
+	if(tkm == nil || tkm->type != TKmenu)
+		return TkBadwp;
+
+	if((tkm->flag & Tkmapped)) {
+		if (toggle) {
+			tkunmapmenus(t, parent);
+			return nil;
+		} else {
+			/* check that it is immediate cascade */
+			tkw = TKobj(TkWin, t->ctxt->tkmenu);
+			if (strcmp(tkw->cascade, parent->name->name) == 0)
+				return nil;
+		}
+	}
+
+	tkunmapmenus(t, parent);
+
+	tkl = TKobj(TkLabel, tk);
+	if(tkl->command != nil) {
+		e = tkexec(t, tkl->command, nil);
+		if (e != nil)
+			return e;
+	}
+
+	g = tkposn(tk);
+	g.x += tk->act.width;
+	g.y -= tkm->borderwidth;
+	e = tkmpost(tkm, g.x, g.y, 1, 0, 1);
+	return e;
+}
+
+static void
+activateitem(Tk *item)
+{
+	Tk *menu;
+	if (item == nil || (menu = item->parent) == nil)
+		return;
+	menuclr(menu);
+	if (!(item->flag & Tkdisabled)) {
+		item->flag |= Tkactive;
+		menuitemdirty(item);
+	}
+}
+
+static char*
+tkmenuactivate(Tk *tk, char *arg, char **val)
+{
+	Tk *f;
+	TkWin *tkw;
+	int index;
+	char *buf;
+	
+	USED(val);
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	index = tkmindex(tk, buf);
+	free(buf);
+	if (index == -1)
+		return TkBadix;
+	if (index == -2) {
+		menuclr(tk);
+		return nil;
+	}
+
+	tkw = TKobj(TkWin, tk);
+	for(f = tkw->slave; f; f = f->next)
+		if(index-- == 0)
+			break;
+
+	if(f == nil || f->flag & Tkdisabled) {
+		menuclr(tk);
+		return nil;
+	}
+	if(f->flag & Tkactive)
+		return nil;
+
+	activateitem(f);
+	return nil;
+}
+
+static int
+iteminvoke(Tk *tk, Tk *tki, char *arg)
+{
+	int unmap = 0;
+	menuitemdirty(tki);
+	switch(tki->type) {
+	case TKlabel:
+		unmap = 1;
+	case TKcheckbutton:
+	case TKradiobutton:
+		tkbuttoninvoke(tki, arg, nil);
+		break;
+	case TKcascade:
+		tkpostcascade(tk, tki, 0);
+		break;
+	}
+	return unmap;
+}
+
+static char*
+tkmenuinvoke(Tk *tk, char *arg, char **val)
+{
+	Tk *tki;
+	USED(val);
+	tki = tkmenuindex2ptr(tk, &arg);
+	if(tki == nil)
+		return nil;
+	iteminvoke(tk, tki, arg);
+	return nil;
+}
+
+static char*
+tkmenudelete(Tk *tk, char *arg, char **val)
+{
+	int index1, index2;
+	char *buf;
+
+	USED(val);
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkitem(buf, arg);
+	index1 = tkmindex(tk, buf);
+	if(index1 < 0) {
+		free(buf);
+		return TkBadix;
+	}
+	index2 = index1;
+	if(*arg != '\0') {
+		tkitem(buf, arg);
+		index2 = tkmindex(tk, buf);
+	}
+	free(buf);
+	if(index2 < 0)
+		return TkBadix;
+	while(index2 >= index1 && tkmenudel(tk, index2))
+		index2--;
+
+	layout(tk);
+	return nil;
+}
+
+static char*
+tkmenupost(Tk *tk, char *arg, char **val)
+{
+	int x, y;
+	TkTop *t;
+	char *buf;
+
+	USED(val);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	t = tk->env->top;
+	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	if(buf[0] == '\0') {
+		free(buf);
+		return TkBadvl;
+	}
+	x = atoi(buf);
+	tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	if(buf[0] == '\0') {
+		free(buf);
+		return TkBadvl;
+	}
+	y = atoi(buf);
+	free(buf);
+
+	return tkmpost(tk, x, y, 0, 0, 1);
+}
+
+static char*
+tkmenuunpost(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+	tkunmapmenu(tk);
+	return nil;
+}
+
+static char*
+tkmenuindex(Tk *tk, char *arg, char **val)
+{
+	char *buf;
+	int index;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	index = tkmindex(tk, buf);
+	free(buf);
+	if (index == -1)
+		return TkBadix;
+	if (index == -2)
+		return "none";
+	return tkvalue(val, "%d", index);
+}
+
+static char*
+tkmenuyposn(Tk *tk, char *arg, char **val)
+{
+	tk = tkmenuindex2ptr(tk, &arg);
+	if(tk == nil)
+		return TkBadix;
+	return tkvalue(val, "%d", tk->act.y);
+}
+
+static char*
+tkmenupostcascade(Tk *tk, char *arg, char **val)
+{
+	Tk *tki;
+	USED(val);
+	tki = tkmenuindex2ptr(tk, &arg);
+	if(tki == nil || tki->type != TKcascade)
+		return nil;
+
+	return tkpostcascade(tk, tki, 0);
+}
+
+static char*
+tkmenutype(Tk *tk, char *arg, char **val)
+{
+	tk = tkmenuindex2ptr(tk, &arg);
+	if(tk == nil)
+		return TkBadix;
+
+	return tkvalue(val, tk->type == TKlabel ? "command" : tkmethod[tk->type]->name);
+}
+
+static char*
+tkmenususpend(Tk *tk, char *arg, char **val)
+{
+	USED(arg);
+	USED(val);
+	if(tk->type == TKchoicebutton){
+		tk = tkfindchoicemenu(tk);
+		if(tk == nil)
+			return TkNotwm;
+	}
+	tk->flag |= Tksuspended;
+	return nil;
+}
+
+static char*
+tkmenuentryconfig(Tk *tk, char *arg, char **val)
+{
+	Tk *etk;
+	char *e;
+
+	USED(val);
+	etk = tkmenuindex2ptr(tk, &arg);
+	if(etk == nil)
+		return TkBadix;
+
+	e = tkmenuentryconf(tk, etk, arg);
+	layout(tk);
+	return e;
+}
+
+static Tk*
+xymenuitem(Tk *tk, int x, int y)
+{
+	TkWin *tkw = TKobj(TkWin, tk);
+	x -= tkw->act.x;
+	y -= tkw->act.y;
+
+	x -= tk->borderwidth;
+	y -= tk->act.y + tk->borderwidth;
+	if (x < tk->act.x || x > tk->act.x+tk->act.width)
+		return nil;
+	for(tk = tkw->slave; tk; tk = tk->next) {
+		if(y >= tk->act.y && y < tk->act.y+tk->act.height+2*tk->borderwidth)
+			return tk;
+	}
+	return nil;
+}
+
+static char *
+menukey(Tk *tk, int key)
+{
+	Tk *scan, *active, *first, *last, *prev, *next;
+	TkWin *tkw;
+	TkTop *top;
+
+	top = tk->env->top;
+
+	active = first = last = prev = next = nil;
+	tkw = TKobj(TkWin, tk);
+	for(scan = tkw->slave; scan != nil; scan = scan->next) {
+		if(scan->type == TKseparator)
+			continue;
+		if(first == nil)
+			first = scan;
+		if (active != nil && next == nil)
+			next = scan;
+		if(active == nil && scan->flag & Tkactive)
+			active = scan;
+		if (active == nil)
+			prev = scan;
+		last = scan;
+	}
+	if (next == nil)
+		next = first;
+	if (prev == nil)
+		prev = last;
+
+	switch (key) {
+	case Esc:
+		tkunmapmenus(top, nil);
+		break;
+	case Left:
+		if (tkw->cascade != nil)
+			tkunmapmenu(tk);
+		break;
+	case Right:
+		if (active == nil || active->type != TKcascade)
+			break;
+	case ' ':
+	case '\n':
+		if (active != nil) {
+			if (iteminvoke(tk, active, nil))
+				tkunmapmenus(top, nil);
+		}
+		break;
+	case Up:
+		next = prev;
+	case Down:
+		if (next != nil)
+			activateitem(next);
+	}
+	return nil;
+}
+
+static char*
+drawmenu(Tk *tk, Point orig)
+{
+	Image *dst;
+	TkWin *tkw;
+	Tk *sub;
+	Point p, bd;
+	int bg;
+	Rectangle mainr, clientr, subr;
+
+	tkw = TKobj(TkWin, tk);
+	dst = tkimageof(tk);
+
+	bd = Pt(tk->borderwidth, tk->borderwidth);
+	mainr.min = addpt(orig, Pt(tk->act.x, tk->act.y));
+	clientr.min = addpt(mainr.min, bd);
+	clientr.max = addpt(clientr.min, Pt(tk->act.width, tk->act.height));
+	mainr.max = addpt(clientr.max, bd);
+
+	/*
+	 * note that we draw item background to get full menu width
+	 * active indicator, this means we must dirty the entire
+	 * item rectangle to ensure it is fully redrawn
+	 */
+	p = clientr.min;
+	subr = clientr;
+	for (sub = tkw->slave; sub != nil; sub = sub->next) {
+		if (Dx(sub->dirty) == 0)
+			continue;
+		subr.min.y = p.y + sub->act.y - sub->borderwidth;
+		subr.max.y = p.y + sub->act.y + sub->act.height + sub->borderwidth;
+		bg = TkCbackgnd;
+		if (sub->flag & Tkactive)
+			bg = TkCactivebgnd;
+		draw(dst, subr, tkgc(sub->env, bg), nil, ZP);
+		sub->dirty = tkrect(sub, 1);
+		sub->flag |= Tkrefresh;
+		tkmethod[sub->type]->draw(sub, p);
+		sub->dirty = bbnil;
+		sub->flag &= ~Tkrefresh;
+	}
+	/* todo: dirty check */
+	tkdrawrelief(dst, tk, mainr.min, TkCbackgnd, tk->relief);
+	return nil;
+}
+
+static void
+menudirty(Tk *sub)
+{
+	menuitemdirty(sub);
+}
+
+static Point
+menurelpos(Tk *sub)
+{
+	return Pt(sub->act.x-sub->borderwidth, sub->act.y-sub->borderwidth);
+}
+
+static void
+autoscroll(Tk *tk, void *v, int cancelled)
+{
+	TkWin *tkw;
+	Rectangle r, dr;
+	Point delta, od;
+	TkMouse *m;
+	Tk *item;
+	USED(v);
+
+	tkw = TKobj(TkWin, tk);
+	if (cancelled) {
+		tkw->speed = 0;
+		return;
+	}
+	if(!eqpt(tkw->act, tkw->req)){
+print("not autoscrolling, act: %P, req: %P\n", tkw->act, tkw->req);
+		return;
+}
+	dr = tk->env->top->screenr;
+	delta.x = TKF2I(tkw->delta.x * tkw->speed);
+	delta.y = TKF2I(tkw->delta.y * tkw->speed);
+	r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
+
+	od = delta;
+	/* make sure we don't go too far */
+	if (delta.x > 0 && r.min.x + delta.x > dr.min.x)
+		delta.x = dr.min.x - r.min.x;
+	else if (delta.x < 0 && r.max.x + delta.x < dr.max.x)
+		delta.x = dr.max.x - r.max.x;
+	if (delta.y > 0 && r.min.y + delta.y > dr.min.y)
+		delta.y = dr.min.y - r.min.y;
+	else if (delta.y < 0 && r.max.y + delta.y < dr.max.y)
+		delta.y = dr.max.y - r.max.y;
+
+	m = &tk->env->top->ctxt->mstate;
+	item = xymenuitem(tk, m->x - delta.x, m->y - delta.y);
+	if (item == nil)
+		menuclr(tk);
+	else
+		activateitem(item);
+	tkmovewin(tk, Pt(tkw->req.x + delta.x, tkw->req.y + delta.y));
+	tkupdate(tk->env->top);
+	/* tkenterleave won't do this for us, so we have to do it ourselves */
+
+	tkw->speed += tkw->speed / 3;
+
+	r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
+	if((delta.y > 0 && r.min.x >= dr.min.x) || (delta.x < 0 && r.max.x <= dr.max.x))
+		tkw->delta.x = 0;
+	if((delta.y > 0 && r.min.y >= dr.min.y) || (delta.y < 0 && r.max.y <= dr.max.y))
+		tkw->delta.y = 0;
+	if (eqpt(tkw->delta, ZP)) {
+		tkcancelrepeat(tk);
+		tkw->speed = 0;
+	}
+}
+
+static void
+startautoscroll(Tk *tk, TkMouse *m)
+{
+	Rectangle dr, r;
+	Point d;
+	TkWin *tkw;
+	tkw = TKobj(TkWin, tk);
+	dr = tk->env->top->screenr;
+	r = rectaddpt(tkrect(tk, 1), Pt(tk->borderwidth + tkw->act.x, tk->borderwidth + tkw->act.y));
+	d = Pt(0, 0);
+	if(m->x <= 0 && r.min.x < dr.min.x)
+		d.x = 1;
+	else if (m->x >= dr.max.x - 1 && r.max.x >= dr.max.x)
+		d.x = -1;
+	if(m->y <= 0 && r.min.y < dr.min.y)
+		d.y = 1;
+	else if (m->y >= dr.max.y - 1 && r.max.y >= dr.max.y)
+		d.y = -1;
+//print("startautoscroll, delta %P\n", d);
+	if (d.x == 0 && d.y == 0){
+		if (tkw->speed > 0){
+			tkcancelrepeat(tk);
+			tkw->speed = 0;
+		}
+		return;
+	}
+	if (tkw->speed == 0) {
+		tkw->speed = TKI2F(Dy(r)) / 100;
+		tkrepeat(tk, autoscroll, nil, 0, TkRptinterval/2);
+	}
+	tkw->delta = d;
+}
+
+static void
+menuevent1(Tk *tk, int event, void *a)
+{
+	TkMouse *m;
+	Tk *item;
+
+	if (event & TkKey) {
+		menukey(tk, event & 0xffff);
+		return;
+	}
+
+	if (event & TkLeave) {
+		menuclr(tk);
+		return;
+	}
+
+	if ((!(event & TkEmouse) || (event & TkTakefocus)) && !(event & TkEnter))
+		return;
+
+	m = (TkMouse*)a;
+
+	startautoscroll(tk, m);
+
+	item = xymenuitem(tk, m->x, m->y);
+	if (item == nil)
+		menuclr(tk);
+	else
+		activateitem(item);
+	if ((event & (TkMotion|TkEnter)) && item == nil)
+		return;
+	if (event & TkEpress) {
+		if (item == nil) {
+			tkunmapmenus(tk->env->top, nil);
+			return;
+		}
+		if (item->type == TKcascade)
+			tkpostcascade(tk, item, !(event & TkMotion));
+		else
+			tkunmapmenus(tk->env->top, tk);
+		return;
+	}
+	if ((event & TkErelease) && m->b == 0) {
+		if (item != nil) {
+			if (item->type == TKcascade)
+				return;
+			if (!iteminvoke(tk, item, nil))
+				return;
+		}
+		tkunmapmenus(tk->env->top, nil);
+	}
+}
+
+static Tk*
+menuevent(Tk *tk, int event, void *a)
+{
+	menuevent1(tk, event, a);
+	tksubdeliver(tk, tk->binds, event, a, 0);
+	return nil;
+}
+
+static
+TkCmdtab menucmd[] =
+{
+	"activate",		tkmenuactivate,
+	"add",			tkmenuadd,
+	"cget",			tkmenucget,
+	"configure",		tkmenuconf,
+	"delete",		tkmenudelete,
+	"entryconfigure",	tkmenuentryconfig,
+	"entrycget",		tkmenuentrycget,
+	"index",		tkmenuindex,
+	"insert",		tkmenuinsert,
+	"invoke",		tkmenuinvoke,
+	"post",			tkmenupost,
+	"postcascade",		tkmenupostcascade,
+	"type",			tkmenutype,
+	"unpost",		tkmenuunpost,
+	"yposition",		tkmenuyposn,
+	"suspend",		tkmenususpend,
+	nil
+};
+
+static
+TkCmdtab menubutcmd[] =
+{
+	"cget",			tkmenubutcget,
+	"configure",		tkmenubutconf,
+	"tkMBenter",		tkMBenter,
+	"tkMBleave",		tkMBleave,
+	"tkMBpress",		tkMBpress,
+	"tkMBkey",		tkMBkey,
+	nil
+};
+
+static
+TkCmdtab choicebutcmd[] =
+{
+	"cget",			tkmenubutcget,
+	"configure",		tkmenubutconf,
+	"set",			tkchoicebutset,
+	"get",			tkchoicebutget,
+	"setvalue",		tkchoicebutsetvalue,
+	"getvalue",		tkchoicebutgetvalue,
+	"invoke",			tkchoicebutinvoke,
+	"valuecount",		tkchoicebutvaluecount,
+	"tkMBenter",		tkMBenter,
+	"tkMBleave",		tkMBleave,
+	"tkMBpress",		tkMBpress,
+	"tkMBkey",		tkMBkey,
+	"suspend",		tkmenususpend,
+	nil
+};
+
+TkMethod menumethod = {
+	"menu",
+	menucmd,
+	freemenu,
+	drawmenu,
+	nil,
+	nil,
+	nil,
+	menudirty,
+	menurelpos,
+	menuevent
+};
+
+TkMethod menubuttonmethod = {
+	"menubutton",
+	menubutcmd,
+	tkfreelabel,
+	tkdrawlabel
+};
+
+TkMethod choicebuttonmethod = {
+	"choicebutton",
+	choicebutcmd,
+	tkfreelabel,
+	tkdrawlabel,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	nil,
+	tkchoicevarchanged
+};
+
+TkMethod separatormethod = {
+	"separator",
+	nil,
+	tkfreeframe,
+	tkdrawframe
+};
+
+TkMethod cascademethod = {
+	"cascade",
+	nil,
+	tkfreelabel,
+	tkdrawlabel
+};
--- /dev/null
+++ b/libtk/mkfile
@@ -1,0 +1,27 @@
+<../mkconfig
+
+LIB=libtk.a
+
+OFILES=\
+	ebind.$O\
+	grids.$O\
+	image.$O\
+	packr.$O\
+	panel.$O\
+	parse.$O\
+	utils.$O\
+	varbl.$O\
+	windw.$O\
+	xdata.$O\
+
+HFILES=\
+	$ROOT/include/tk.h\
+	$ROOT/include/draw.h\
+
+default:V:	all
+
+<mkfile-$TKSTYLE
+<$ROOT/mkfiles/mksyslib-$SHELLTYPE
+
+ebind.$O:		$ROOT/include/interp.h
+windw.$O:	canvs.h textw.h
--- /dev/null
+++ b/libtk/mkfile-std
@@ -1,0 +1,44 @@
+CANVSFILES=\
+	canvs.$O\
+	canvu.$O\
+	carcs.$O\
+	cbits.$O\
+	cimag.$O\
+	cline.$O\
+	coval.$O\
+	cpoly.$O\
+	crect.$O\
+	ctext.$O\
+	cwind.$O\
+
+LABELFILES=\
+	buton.$O\
+	label.$O\
+
+TEXTWFILES=\
+	textu.$O\
+	textw.$O\
+	tindx.$O\
+	tmark.$O\
+	ttags.$O\
+	twind.$O\
+
+OFILES=$OFILES\
+	$CANVSFILES\
+	colrs.$O\
+	entry.$O\
+	extns.$O\
+	frame.$O\
+	$LABELFILES\
+	listb.$O\
+	menus.$O\
+	scale.$O\
+	scrol.$O\
+	$TEXTWFILES\
+
+frame.$O:	frame.h
+$CANVSFILES:	canvs.h
+$LABELFILES:	label.h
+listb.$O:	listb.h
+menus.$O:	frame.h label.h
+$TEXTWFILES:	textw.h
--- /dev/null
+++ b/libtk/packr.c
@@ -1,0 +1,696 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+typedef struct Pack Pack;
+struct Pack 
+{
+	Tk*	t;
+	Pack*	next;
+};
+static Pack *packorder;
+
+static int tkpacker(Tk *);
+
+typedef struct TkParam TkParam;
+struct TkParam
+{
+	Point	pad;
+	Point	ipad;
+	int	side;
+	int	anchor;
+	int	fill;
+	Tk*	in;
+	Tk*	before;
+	Tk*	after;
+	int	expand;
+};
+
+TkParam defparam = {
+	{-1, -1},	/* p.pad */
+	{-1, -1},	/* p.ipad */
+	-1,		/* side */
+	-1,		/* anchor */
+	-1,		/* fill */
+	nil,		/* in */
+	nil, 		/* before */
+	nil,		/* after */
+	BoolX	/* expand */
+};
+
+static
+TkStab tkside[] =
+{
+	"top",		Tktop,
+	"bottom",	Tkbottom,
+	"left",		Tkleft,
+	"right",	Tkright,
+	nil
+};
+
+static
+TkStab tkfill[] =
+{
+	"none",		0,
+	"x",		Tkfillx,
+	"y",		Tkfilly,
+	"both",		Tkfillx|Tkfilly,
+	nil
+};
+
+static
+TkOption opts[] =
+{
+	"padx",		OPTnndist,	O(TkParam, pad.x),	nil,
+	"pady",		OPTnndist,	O(TkParam, pad.y),	nil,
+	"ipadx",	OPTnndist,	O(TkParam, ipad.x),	nil,
+	"ipady",	OPTnndist,	O(TkParam, ipad.y),	nil,
+	"side",		OPTstab,	O(TkParam, side),	tkside,
+	"anchor",	OPTstab,	O(TkParam, anchor),	tkanchor,
+	"fill",		OPTstab,	O(TkParam, fill),	tkfill,
+	"in",		OPTwinp,	O(TkParam, in),		nil,
+	"before",	OPTwinp,	O(TkParam, before),	nil,
+	"after",	OPTwinp,	O(TkParam, after),	nil,
+	"expand",	OPTstab,	O(TkParam, expand),	tkbool,
+	nil
+};
+
+void
+tkdelpack(Tk *t)
+{
+	Tk *f, **l, *sub, *p;
+
+	sub = tkfindsub(t);
+	if(sub != nil) {
+		p = sub->parent;
+		if(tkmethod[p->type]->forgetsub != nil)
+			tkmethod[p->type]->forgetsub(sub, t);
+	}
+
+	if(t->master == nil)
+		return;
+
+	if(t->master->grid != nil)
+		tkgriddelslave(t);
+
+	l = &t->master->slave;
+	for(f = *l; f; f = f->next) {
+		if(f == t) {
+			*l = t->next;
+			break;
+		}
+		l = &f->next;
+	}
+	t->master = nil;
+}
+
+void
+tkappendpack(Tk *parent, Tk *tk, int where)
+{
+	Tk *f, **l;
+
+	tk->master = parent;
+	l = &parent->slave;
+	for(f = *l; f; f = f->next) {
+		if(where-- == 0)
+			break;
+		l = &f->next;
+	}
+	*l = tk;
+	tk->next = f;
+
+	for( ; parent != nil; parent = parent->master)
+		if(parent->parent != nil){
+			tk->flag |= Tksubsub;
+			break;
+		}
+}
+
+static void
+tkpackqrm(Tk *t)
+{
+	Pack *f, **l;
+
+	l = &packorder;
+	for(f = *l; f; f = f->next) {
+		if(f->t == t) {
+			*l = f->next;
+			free(f);
+			break;
+		}
+		l = &f->next;
+	}
+}
+
+/* XXX - Tad: leaky... should propagate  */
+void
+tkpackqit(Tk *t)
+{
+	Pack *f;
+
+	if(t == nil || (t->flag & Tkdestroy))
+		return;
+
+	tkpackqrm(t);
+	f = malloc(sizeof(Pack));
+	if(f == nil) {
+		print("tkpackqit: malloc failed\n");
+		return;
+	}
+
+	f->t = t;
+	f->next = packorder;
+	packorder = f;
+}
+
+void
+tkrunpack(TkTop *t)
+{
+	Tk *tk;
+	int done;
+
+	while(packorder != nil) {
+		tk = packorder->t;
+		if (tk->grid != nil)
+			done = tkgridder(tk);
+		else
+			done = tkpacker(tk);
+		if (done)
+			tkpackqrm(tk);
+	}
+	tkenterleave(t);
+	tkdirtyfocusorder(t);
+}
+
+static void
+tksetopt(TkParam *p, Tk *tk)
+{
+	if(p->pad.x != -1)
+		tk->pad.x = p->pad.x*2;
+	if(p->pad.y != -1)
+		tk->pad.y = p->pad.y*2;
+	if(p->ipad.x != -1)
+		tk->ipad.x = p->ipad.x*2;
+	if(p->ipad.y != -1)
+		tk->ipad.y = p->ipad.y*2;
+	if(p->side != -1) {
+		tk->flag &= ~Tkside;
+		tk->flag |= p->side;
+	}
+	if(p->anchor != -1) {
+		tk->flag &= ~Tkanchor;
+		tk->flag |= p->anchor;
+	}
+	if(p->fill != -1) {
+		tk->flag &= ~Tkfill;
+		tk->flag |= p->fill;
+	}
+	if(p->expand != BoolX) {
+		if(p->expand == BoolT) {
+			tk->flag |= Tkexpand;
+		}
+		else
+			tk->flag &= ~Tkexpand;
+	}
+}
+
+static char*
+tkforget(TkTop *t, char *arg)
+{
+	Tk *tk;
+	char *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	for(;;) {
+		arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+		if(buf[0] == '\0')
+			break;
+		tk = tklook(t, buf, 0);
+		if(tk == nil) {
+			tkrunpack(t);
+			tkerr(t, buf);
+			free(buf);
+			return TkBadwp;
+		}
+		tkpackqit(tk->master);
+		tkdelpack(tk);
+	}
+	free(buf);
+	tkrunpack(t);
+	return nil;
+}
+
+char*
+tkpropagate(TkTop *t, char *arg)
+{
+	Tk *tk;
+	TkStab *s;
+	char *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	tk = tklook(t, buf, 0);
+	if(tk == nil) {
+		tkerr(t, buf);
+		free(buf);
+		return TkBadwp;
+	}
+
+	tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	for(s = tkbool; s->val; s++) {
+		if(strcmp(s->val, buf) == 0) {
+			if(s->con == BoolT) {
+				tk->flag &= ~Tknoprop;
+				tkpackqit(tk);
+				tkrunpack(t);
+			} else
+				tk->flag |= Tknoprop;
+			free(buf);
+			return nil;
+		}
+	}
+	free(buf);
+	return TkBadvl;
+}
+
+static char*
+tkslaves(TkTop *t, char *arg, char **val)
+{
+	Tk *tk;
+	char *fmt, *e, *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	tk = tklook(t, buf, 0);
+	if(tk == nil){
+		tkerr(t, buf);
+		free(buf);
+		return TkBadwp;
+	}
+	free(buf);
+
+	fmt = "%s";
+	for(tk = tk->slave; tk; tk = tk->next) {
+		if (tk->name != nil) {
+			e = tkvalue(val, fmt, tk->name->name);
+			if(e != nil)
+				return e;
+			fmt = " %s";
+		}
+	}
+	
+	return nil;
+}
+
+int
+tkisslave(Tk *in, Tk *tk)
+{
+	if(in == nil)
+		return 0;
+	if(in == tk)
+		return 1;
+	for(tk = tk->slave; tk; tk = tk->next)
+		if(tkisslave(in, tk))
+			return 1;
+	return 0;
+}
+
+static char*
+tkcanpack(Tk *tk, Tk *parent)
+{
+	if(tkisslave(parent, tk))
+		return TkRecur;
+	if (parent->grid != nil) {
+		if (parent->slave != nil)
+			return TkIsgrid;
+		tkfreegrid(parent->grid);
+		parent->grid = nil;
+	}
+	return nil;
+}
+
+char*
+tkpack(TkTop *t, char *arg, char **val)
+{
+	TkParam param = defparam;
+	TkParam *p = &param;
+	TkOptab tko[2];
+	Tk *tk, **l, *tkp;
+	TkName *names, *n;
+	char *e, *w, *buf;
+
+	buf = mallocz(Tkminitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	w = tkword(t, arg, buf, buf+Tkminitem, nil);
+	if(strcmp(buf, "forget") == 0) {
+		e = tkforget(t, w);
+		free(buf);
+		return e;
+	}
+	if(strcmp(buf, "propagate") == 0) {
+		e = tkpropagate(t, w);
+		free(buf);
+		return e;
+	}
+	if(strcmp(buf, "slaves") == 0) {
+		e = tkslaves(t, w, val);
+		free(buf);
+		return e;
+	}
+	free(buf);
+
+	tko[0].ptr = p;
+	tko[0].optab = opts;
+	tko[1].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil)
+		return e;
+
+	if((p->before && p->before->master == nil) ||
+	   (p->after && p->after->master == nil)) {
+		tkfreename(names);
+		return TkNotpk;
+	}
+
+	for(n = names; n; n = n->link) {
+		tkp = tklook(t, n->name, 0);
+		if(tkp == nil) {
+			tkerr(t, n->name);
+			tkfreename(names);
+			return TkBadwp;
+		}
+		if(tkp->flag & Tkwindow) {
+			tkfreename(names);
+			return TkIstop;
+		}
+		if(tkp->parent != nil) {
+			tkfreename(names);
+			return TkWpack;
+		}
+		n->obj = tkp;
+	}
+
+	e = nil;
+	for(n = names; n; n = n->link) {
+		tk = n->obj;
+		if(tk->master == nil) {
+			tk->pad = ZP;
+			tk->ipad = ZP;
+			tk->flag &= ~(Tkanchor|Tkside|Tkfill|Tkexpand);
+			tk->flag |= Tktop;
+		}
+		if(tk->master != nil) {
+			tkpackqit(tk->master);
+			tkdelpack(tk);
+		}
+		if(p->before == nil && p->after == nil && p->in == nil) {
+			tkp = tklook(t, n->name, 1);
+			if(tkp == nil) {
+				e = TkBadwp;
+				tkerr(t, n->name);
+				goto Error;
+			}
+			e = tkcanpack(tk, tkp);
+			if (e != nil)
+				goto Error;
+			tkappendpack(tkp, tk, -1);
+		}
+		else {
+			if(p->in != nil) {
+				e = tkcanpack(tk, p->in);
+				if(e != nil)
+					goto Error;
+				tkappendpack(p->in, tk, -1);
+			}
+			else
+			if(p->before != nil) {
+				e = tkcanpack(tk, p->before->master);
+				if (e != nil)
+					goto Error;
+				tk->master = p->before->master;
+				l = &tk->master->slave;
+				for(;;) {
+					if(*l == p->before) {
+						tk->next = *l;
+						*l = tk;
+						break;
+					}
+					l = &(*l)->next;
+				}
+				p->before = tk;
+			}
+			else {
+				e = tkcanpack(tk, p->after->master);
+				if (e != nil)
+					goto Error;
+				tk->master = p->after->master;
+				tk->next = p->after->next;
+				p->after->next = tk;
+				p->after = tk;
+			}
+		}
+		tksetopt(p, tk);
+		if (tk->master->flag&Tksubsub)
+			tksetbits(tk, Tksubsub);
+		tkpackqit(tk->master);
+	}
+
+Error:
+	tkfreename(names);
+	tkrunpack(t);
+
+	return e;
+}
+
+void
+tksetslavereq(Tk *slave, TkGeom frame)
+{
+	Point border;
+	TkGeom pos, old;
+	int slave2BW;
+	void (*geomfn)(Tk*);
+
+	border.x = slave->pad.x;
+	border.y = slave->pad.y;
+
+	slave2BW = slave->borderwidth * 2;
+
+	pos.width = slave->req.width + slave2BW + slave->ipad.x;
+	if((slave->flag&Tkfillx) || (pos.width > (frame.width - border.x)))
+		pos.width = frame.width - border.x;
+
+	pos.height = slave->req.height + slave2BW + slave->ipad.y;
+	if((slave->flag&Tkfilly) || (pos.height > (frame.height - border.y)))
+    		pos.height = frame.height - border.y;
+
+	border.x /= 2;
+	border.y /= 2;
+
+	if(slave->flag & Tknorth)
+		pos.y = frame.y + border.y;
+	else
+	if(slave->flag & Tksouth)
+		pos.y = frame.y + frame.height - pos.height - border.y;
+	else
+		pos.y = frame.y + (frame.height - pos.height)/2;
+
+	if(slave->flag & Tkwest)
+		pos.x = frame.x + border.x;
+	else
+	if(slave->flag & Tkeast)
+		pos.x = frame.x + frame.width - pos.width - border.x;
+	else
+		pos.x = frame.x + (frame.width - pos.width)/2;
+
+	pos.width -= slave2BW;
+	pos.height -= slave2BW;
+
+	if(memcmp(&slave->act, &pos, sizeof(TkGeom)) != 0) {
+		old = slave->act;
+		slave->act = pos;
+		geomfn = tkmethod[slave->type]->geom;
+		if(geomfn != nil)
+			geomfn(slave);
+		if(slave->slave)
+			tkpackqit(slave);
+		tkdeliver(slave, TkConfigure, &old);
+
+		slave->dirty = tkrect(slave, 1);
+		slave->flag |= Tkrefresh;
+	}
+}
+static int
+tkexpandx(Tk* slave, int cavityWidth)
+{
+	int numExpand, minExpand, curExpand, childWidth;
+
+	minExpand = cavityWidth;
+	numExpand = 0;
+	for( ;slave != nil; slave = slave->next) {
+		childWidth = slave->req.width + slave->borderwidth*2 +
+				slave->pad.x + slave->ipad.x;
+		if(slave->flag & (Tktop|Tkbottom)) {
+			curExpand = (cavityWidth - childWidth)/numExpand;
+			if (curExpand < minExpand)
+				minExpand = curExpand;
+		}
+		else {
+	    		cavityWidth -= childWidth;
+	    		if(slave->flag & Tkexpand)
+				numExpand++;
+		}
+	}
+	curExpand = cavityWidth/numExpand;
+	if(curExpand < minExpand)
+		minExpand = curExpand;
+
+	return (minExpand < 0) ? 0 : minExpand;
+}
+
+static int
+tkexpandy(Tk *slave, int cavityHeight)
+{
+	int numExpand, minExpand, curExpand, childHeight;
+
+	minExpand = cavityHeight;
+	numExpand = 0;
+	for ( ;slave != nil; slave = slave->next) {
+		childHeight = slave->req.height + slave->borderwidth*2 +
+			+ slave->pad.y + slave->ipad.y;
+		if(slave->flag & (Tkleft|Tkright)) {
+			curExpand = (cavityHeight - childHeight)/numExpand;
+			if(curExpand < minExpand)
+				minExpand = curExpand;
+		}
+		else {
+			cavityHeight -= childHeight;
+			if(slave->flag & Tkexpand)
+				numExpand++;
+		}
+	}
+	curExpand = cavityHeight/numExpand;
+	if(curExpand < minExpand)
+		minExpand = curExpand;
+
+	return (minExpand < 0) ? 0 : minExpand;
+}
+
+static int
+tkpacker(Tk *master)
+{
+	Tk *slave;
+	TkGeom frame, cavity, pos;
+	int maxwidth, maxheight, tmp, slave2BW;
+
+	pos.width = 0;
+	pos.height = 0;
+	maxwidth = 0;
+	maxheight = 0;
+
+	master->flag |= Tkrefresh;
+
+	for (slave = master->slave; slave != nil; slave = slave->next) {
+		slave2BW = slave->borderwidth*2;
+		if(slave->flag & (Tktop|Tkbottom)) {
+	    		tmp = slave->req.width + slave2BW +
+		    		slave->pad.x + slave->ipad.x + pos.width;
+			if(tmp > maxwidth)
+				maxwidth = tmp;
+	    		pos.height += slave->req.height + slave2BW +
+		    		slave->pad.y + slave->ipad.y;
+		}
+		else {
+	    		tmp = slave->req.height + slave2BW +
+		    		slave->pad.y + slave->ipad.y + pos.height;
+	    		if(tmp > maxheight)
+				maxheight = tmp;
+	    		pos.width += slave->req.width + slave2BW +
+		    		+ slave->pad.x + slave->ipad.x;
+		}
+	}
+	if(pos.width > maxwidth)
+		maxwidth = pos.width;
+	if(pos.height > maxheight)
+		maxheight = pos.height;
+
+	if(maxwidth != master->req.width || maxheight != master->req.height)
+	if((master->flag & Tknoprop) == 0) {
+		if(master->geom != nil) {
+			master->geom(master, master->act.x, master->act.y, 
+					maxwidth, maxheight);
+		} else {
+			master->req.width = maxwidth;
+			master->req.height = maxheight;
+			tkpackqit(master->master);
+		}
+		return 0;
+    	}
+
+    	cavity.x = 0;
+	cavity.y = 0;
+	pos.x = 0;
+	pos.y = 0;
+	cavity.width = master->act.width;
+	cavity.height = master->act.height;
+
+	for(slave = master->slave; slave != nil; slave = slave->next) {
+		slave2BW = slave->borderwidth*2;
+		if(slave->flag & (Tktop|Tkbottom)) {
+	    		frame.width = cavity.width;
+	    		frame.height = slave->req.height + slave2BW +
+		    			slave->pad.y + slave->ipad.y;
+	    		if(slave->flag & Tkexpand)
+				frame.height += tkexpandy(slave, cavity.height);
+	    		cavity.height -= frame.height;
+	    		if(cavity.height < 0) {
+				frame.height += cavity.height;
+				cavity.height = 0;
+	    		}
+	    		frame.x = cavity.x;
+	    		if(slave->flag & Tktop) {
+				frame.y = cavity.y;
+				cavity.y += frame.height;
+	    		}
+			else
+				frame.y = cavity.y + cavity.height;
+		}
+		else {
+	    		frame.height = cavity.height;
+	    		frame.width = slave->req.width + slave2BW + 
+					slave->pad.x + slave->ipad.x;
+	    		if(slave->flag & Tkexpand)
+				frame.width += tkexpandx(slave, cavity.width);
+	    		cavity.width -= frame.width;
+	    		if(cavity.width < 0) {
+				frame.width += cavity.width;
+				cavity.width = 0;
+	    		}
+	    		frame.y = cavity.y;
+	    		if(slave->flag & Tkleft) {
+				frame.x = cavity.x;
+				cavity.x += frame.width;
+	    		}
+			else
+				frame.x = cavity.x + cavity.width;
+		}
+
+		tksetslavereq(slave, frame);
+	}
+
+	master->dirty = tkrect(master, 1);
+	tkdirty(master);
+	return 1;
+}
+
--- /dev/null
+++ b/libtk/panel.c
@@ -1,0 +1,408 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+typedef struct TkPanel TkPanel;
+struct TkPanel
+{
+	Image*	image;
+	Image*	matte;
+	Point		view;	/* vector from image origin to widget origin */
+	Rectangle		r;		/* drawn rectangle (in image coords) */
+	int		anchor;
+	int		hasalpha;	/* does the image include an alpha channel? */
+};
+
+static TkOption tkpanelopts[] =
+{
+	"anchor",	OPTflag,	O(TkPanel, anchor),	tkanchor,
+	nil
+};
+
+static int
+tkdrawnrect(Image *image, Image *matte, Rectangle *r)
+{
+	*r = image->clipr;
+	if (matte != nil) {
+		if (!rectclip(r, matte->clipr))
+			return 0;
+		if (!matte->repl && !rectclip(r, matte->r))
+			return 0;
+	}
+	if (!image->repl && !rectclip(r, image->r))
+		return 0;
+	return 1;
+}
+
+char*
+tkpanel(TkTop *t, char *arg, char **ret)
+{
+	TkOptab tko[3];
+	Tk *tk;
+	TkPanel *tkp;
+	TkName *names;
+	char *e;
+
+	tk = tknewobj(t, TKpanel, sizeof(Tk)+sizeof(TkPanel));
+	if(tk == nil)
+		return TkNomem;
+
+	tkp = TKobj(TkPanel, tk);
+	tkp->anchor = Tkcenter;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkp;
+	tko[1].optab = tkpanelopts;
+	tko[2].ptr = nil;
+	names = nil;
+
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+	e = tkaddchild(t, tk, &names);
+
+	tkfreename(names);
+	if (e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	tk->name->link = nil;
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+void
+tkgetpanelimage(Tk *tk, Image **i, Image **m)
+{
+	TkPanel *tkp = TKobj(TkPanel, tk);
+	*i = tkp->image;
+	*m = tkp->matte;
+}
+
+void
+tksetpanelimage(Tk *tk, Image *image, Image *matte)
+{
+	TkPanel *tkp = TKobj(TkPanel, tk);
+	int ishuge;
+	TkGeom g;
+
+	g = tk->req;
+
+	tkp->image = image;
+	tkp->matte = matte;
+
+	if (!tkdrawnrect(image, matte, &tkp->r)) {
+		tkp->r.min = image->r.min;
+		tkp->r.max = image->r.min;
+	}
+
+	tkp->view = tkp->r.min;		/* XXX do we actually want to keep the old one? */
+	/*
+	 * if both image and matte are replicated, then we've got no idea what
+	 * the rectangle should be, so request zero size, and set origin to (0, 0).
+	 */
+	ishuge = (Dx(tkp->r) >= 10000000);
+	if((tk->flag & Tksetwidth) == 0){
+		if(ishuge)
+			tk->req.width = 0;
+		else
+			tk->req.width = Dx(tkp->r);
+	}
+	if(ishuge)
+		tkp->view.x = 0;
+
+	ishuge = (Dy(tkp->r) >= 10000000);
+	if((tk->flag & Tksetheight) == 0){
+		if(ishuge)
+			tk->req.height = 0;
+		else
+			tk->req.height = Dy(tkp->r);
+	}
+	if(ishuge)
+		tkp->view.y = 0;
+
+	tkp->hasalpha = tkchanhastype(image->chan, CAlpha);
+	tkgeomchg(tk, &g, tk->borderwidth);
+	tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd));
+	tk->dirty = tkrect(tk, 0);
+}
+
+static void
+tkfreepanel(Tk *tk)
+{
+	TkPanel *tkp = TKobj(TkPanel, tk);
+	tkdelpanelimage(tk->env->top, tkp->image);
+	tkdelpanelimage(tk->env->top, tkp->matte);
+}
+
+static Point
+tkpanelview(Tk *tk)
+{
+	int dx, dy;
+	Point view;
+	TkPanel *tkp = TKobj(TkPanel, tk);
+	
+	dx = tk->act.width - Dx(tkp->r);
+	dy = tk->act.height - Dy(tkp->r);
+
+	view = tkp->view;
+
+	if (dx > 0) {
+		if((tkp->anchor & (Tkeast|Tkwest)) == 0)
+			view.x -= dx/2;
+		else
+		if(tkp->anchor & Tkeast)
+			view.x -= dx;
+	}
+	if (dy > 0) {
+		if((tkp->anchor & (Tknorth|Tksouth)) == 0)
+			view.y -= dy/2;
+		else
+		if(tkp->anchor & Tksouth)
+			view.y -= dy;
+	}
+	return view;
+}
+
+static char*
+tkdrawpanel(Tk *tk, Point orig)
+{
+	Rectangle r, pr;
+	TkPanel *tkp = TKobj(TkPanel, tk);
+	Image *i;
+	int any;
+	Point view, p;
+
+	i = tkimageof(tk);
+	if (i == nil)
+		return nil;
+
+	p.x = orig.x + tk->act.x + tk->borderwidth;
+	p.y = orig.y + tk->act.y + tk->borderwidth;
+
+	view = tkpanelview(tk);
+
+	/*
+	 * if the image doesn't fully cover the dirty rectangle, then
+	 * paint some background in there
+	 */
+	r = rectsubpt(tkp->r, view);		/* convert to widget coords */
+	pr = tkrect(tk, 0);
+	any = rectclip(&r, pr);				/* clip to inside widget borders */
+
+	if (!any || tkp->hasalpha || !rectinrect(tk->dirty, r))
+		draw(i, rectaddpt(tk->dirty, p), tkgc(tk->env, TkCbackgnd), nil, ZP);
+
+	if (any && rectclip(&r, tk->dirty))
+		draw(i, rectaddpt(r, p), tkp->image, tkp->matte, addpt(r.min, view));
+
+	if (!rectinrect(tk->dirty, pr)) {
+		p.x -= tk->borderwidth;
+		p.y -= tk->borderwidth;
+		tkdrawrelief(i, tk, p, TkCbackgnd, tk->relief);
+	}
+	return nil;
+}
+
+static char*
+tkpanelcget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkPanel *tkp = TKobj(TkPanel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkp;
+	tko[1].optab = tkpanelopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkpanelcvt(Tk *tk, char *arg, int rel, int *p)
+{
+	char buf[Tkmaxitem];
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+	*p = atoi(buf) + rel;
+	return nil;
+}
+
+/*
+ * screen to image
+ */
+static char*
+tkpanelpanelx(Tk *tk, char *arg, char **val)
+{
+	Point p;
+	char *e;
+
+	USED(val);
+	p = subpt(tkposn(tk), tkpanelview(tk));
+	e = tkpanelcvt(tk, arg, -p.x, &p.x);
+	if (e != nil)
+		return e;
+	return tkvalue(val, "%d", p.x);
+}
+
+static char*
+tkpanelpanely(Tk *tk, char *arg, char **val)
+{
+	Point p;
+	char *e;
+
+	USED(val);
+	p = subpt(tkposn(tk), tkpanelview(tk));
+	e = tkpanelcvt(tk, arg, -p.y, &p.y);
+	if (e != nil)
+		return e;
+	return tkvalue(val, "%d", p.y);
+}
+
+/*
+ * image to screen
+ */
+static char*
+tkpanelscreenx(Tk *tk, char *arg, char **val)
+{
+	Point p;
+	char *e;
+
+	USED(val);
+	p = subpt(tkposn(tk), tkpanelview(tk));
+	e = tkpanelcvt(tk, arg, p.x, &p.x);
+	if (e != nil)
+		return e;
+	return tkvalue(val, "%d", p.x);
+}
+
+static char*
+tkpanelscreeny(Tk *tk, char *arg, char **val)
+{
+	Point p;
+	char *e;
+
+	USED(val);
+	p = subpt(tkposn(tk), tkpanelview(tk));
+	e = tkpanelcvt(tk, arg, p.y, &p.y);
+	if (e != nil)
+		return e;
+	return tkvalue(val, "%d", p.y);
+}
+
+static char*
+tkpanelconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkOptab tko[3];
+	TkPanel *tkp = TKobj(TkPanel, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkp;
+	tko[1].optab = tkpanelopts;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tkgeomchg(tk, &g, bd);
+	tksettransparent(tk, tkp->hasalpha || tkhasalpha(tk->env, TkCbackgnd));
+
+	tk->dirty = tkrect(tk, 1);
+
+	return e;
+}
+
+static char*
+tkpaneldirty(Tk *tk, char *arg, char **val)
+{
+	char buf[Tkmaxitem];
+	int n, coords[4];
+	Rectangle r;
+	char *e, *p;
+	TkPanel *tkp = TKobj(TkPanel, tk);
+
+	USED(val);
+	n = 0;
+	while (n < 4) {
+		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		if (buf[0] == 0)
+			break;
+		p = buf;
+		e = tkfrac(&p, &coords[n++], nil);
+		if (e != nil)
+			return TkBadvl;
+	}
+	if (n == 0)
+		r = tkp->r;
+	else {
+		 if (n != 4)
+			return TkBadvl;
+		r.min.x = TKF2I(coords[0]);
+		r.min.y = TKF2I(coords[1]);
+		r.max.x = TKF2I(coords[2]);
+		r.max.y = TKF2I(coords[3]);
+	}
+	if (rectclip(&r, tkp->r)) {
+		r = rectsubpt(r, tkpanelview(tk));		/* convert to widget coords */
+		if (rectclip(&r, tkrect(tk, 0)))			/* clip to visible area */
+			combinerect(&tk->dirty, r);
+	}
+	return nil;
+}
+
+static char*
+tkpanelorigin(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	Point view;
+	TkPanel *tkp = TKobj(TkPanel, tk);
+
+	e = tkxyparse(tk, &arg, &view);
+	if (e != nil) {
+		if (e == TkOparg)
+			return tkvalue(val, "%d %d", tkp->view.x, tkp->view.y);
+		return e;
+	}
+	tkp->view = view;
+	tk->dirty = tkrect(tk, 0);
+	return nil;
+}
+
+static
+TkCmdtab tkpanelcmd[] =
+{
+	"cget",			tkpanelcget,
+	"configure",		tkpanelconf,
+	"dirty",			tkpaneldirty,
+	"origin",			tkpanelorigin,
+	"panelx",			tkpanelpanelx,
+	"panely",			tkpanelpanely,
+	"screenx",			tkpanelscreenx,
+	"screeny",			tkpanelscreeny,
+	nil
+};
+
+TkMethod panelmethod = {
+	"panel",
+	tkpanelcmd,
+	tkfreepanel,
+	tkdrawpanel
+};
--- /dev/null
+++ b/libtk/parse.c
@@ -1,0 +1,1195 @@
+#include "lib9.h"
+#include "kernel.h"
+#include "draw.h"
+#include "tk.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+static char* pdist(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pstab(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* ptext(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pwinp(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pbmap(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pbool(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pfont(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pfrac(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pnnfrac(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pctag(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* ptabs(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pcolr(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pimag(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* psize(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pnndist(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pact(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* pignore(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* psticky(TkTop*, TkOption*, void*, char**, char*, char*);
+static char* plist(TkTop*, TkOption*, void*, char**, char*, char*);
+
+static char* (*oparse[])(TkTop*, TkOption*, void*, char**, char*, char*) =
+{
+	/* OPTdist */	pdist,
+	/* OPTstab */	pstab,
+	/* OPTtext */	ptext,
+	/* OPTwinp */	pwinp,
+	/* OPTflag */	pstab,
+	/* OPTbmap */	pbmap,
+	/* OPTbool */	pbool,
+	/* OPTfont */	pfont,
+	/* OPTfrac */	pfrac,
+	/* OPTnnfrac */	pnnfrac,
+	/* OPTctag */	pctag,
+	/* OPTtabs */	ptabs,
+	/* OPTcolr */	pcolr,
+	/* OPTimag */	pimag,
+	/* OPTsize */	psize,
+	/* OPTnndist */	pnndist,
+	/* OPTact */	pact,
+	/* OPTignore */	pignore,
+	/* OPTsticky */	psticky,
+	/* OPTlist */ plist,
+	/* OPTflags */	pstab,
+};
+
+char*
+tkskip(char *s, char *bl)
+{
+	char *p;
+
+	while(*s) {
+		for(p = bl; *p; p++)
+			if(*p == *s)
+				break;
+		if(*p == '\0')
+			return s;	
+		s++;
+	}
+	return s;
+}
+
+/* XXX - Tad: error propagation? */
+char*
+tkword(TkTop *t, char *str, char *buf, char *ebuf, int *gotarg)
+{
+	int c, lev, tmp;
+	char *val, *e, *p, *cmd;
+	if (gotarg == nil)
+		gotarg = &tmp;
+
+	/*
+	 * ebuf is one beyond last byte in buf; leave room for nul byte in
+	 * all cases.
+	 */
+	--ebuf;
+
+	str = tkskip(str, " \t");
+	*gotarg = 1;
+	lev = 1;
+	switch(*str) {
+	case '{':
+		/* XXX - DBK: According to Ousterhout (p.37), while back=
+		 * slashed braces don't count toward finding the matching
+		 * closing braces, the backslashes should not be removed.
+		 * Presumably this also applies to other backslashed
+		 * characters: the backslash should not be removed.
+		 */
+		str++;
+		while(*str && buf < ebuf) {
+			c = *str++;
+			if(c == '\\') {
+				if(*str == '}' || *str == '{' || *str == '\\')
+					c = *str++;
+			} else if(c == '}') {
+				lev--;
+				if(lev == 0)
+					break;
+			} else if(c == '{')
+				lev++;
+			*buf++ = c;
+		}
+		break;
+	case '[':
+		/* XXX - DBK: According to Ousterhout (p. 33) command
+		 * substitution may occur anywhere within a word, not
+		 * only (as here) at the beginning.
+		 */
+		cmd = malloc(strlen(str));	/* not strlen+1 because the first character is skipped */
+		if ( cmd == nil ) {
+			buf[0] = '\0';	/* DBK - Why not an error message? */
+			return str;
+		}
+		p = cmd;
+		str++;
+		while(*str) {
+			c = *str++;
+			if(c == '\\') {
+				if(*str == ']' || *str == '[' || *str == '\\')
+					c = *str++;
+			} else if(c == ']') {
+				lev--;
+				if(lev == 0)
+					break;
+			} else if(c == '[')
+				lev++;
+			*p++ = c;
+		}
+		*p = '\0';
+		val = nil;
+		e = tkexec(t, cmd, &val);
+		free(cmd);
+		 /* XXX - Tad: is this appropriate behavior?
+		  *	      Am I sure that the error doesn't need to be
+		  *	      propagated back to the caller?
+		  */
+		if(e == nil && val != nil) {
+			strncpy(buf, val, ebuf-buf);
+			buf = ebuf;
+			free(val);
+		}
+		break;
+	case '\'':
+		str++;
+		while(*str && buf < ebuf)
+			*buf++ = *str++;
+		break;
+	case '\0':
+		*gotarg = 0;
+		break;
+	default:
+		/* XXX - DBK: See comment above about command substitution.
+		 * Also, any backslashed character should be replaced by
+		 * itself (e.g. to put a space, tab, or [ into a word.
+		 * We assume that the C compiler has already done the
+		 * standard ANSI C substitutions.  (But should we?)
+		 */
+		while(*str && *str != ' ' && *str != '\t' && buf < ebuf)
+			*buf++ = *str++;
+	}
+	*buf = '\0';
+	return str;
+}
+
+static TkOption*
+Getopt(TkOption *o, char *buf)
+{
+	while(o->o != nil) {
+		if(strcmp(buf, o->o) == 0)
+			return o;
+		o++;
+	}
+	return nil;
+}
+
+TkName*
+tkmkname(char *name)
+{
+	TkName *n;
+
+	n = malloc(sizeof(struct TkName)+strlen(name));
+	if(n == nil)
+		return nil;
+	strcpy(n->name, name);
+	n->link = nil;
+	n->obj = nil;
+	return n;
+}
+
+char*
+tkparse(TkTop *t, char *str, TkOptab *ot, TkName **nl)
+{
+	int l;
+	TkOptab *ft;
+	TkOption *o;
+	TkName *f, *n;
+	char *e, *buf, *ebuf;
+
+	l = strlen(str);
+	if (l < Tkmaxitem)
+		l = Tkmaxitem;
+	buf = malloc(l + 1);
+	if(buf == 0)
+		return TkNomem;
+	ebuf = buf + l + 1;
+
+	e = nil;
+	while(e == nil) {
+		str = tkword(t, str, buf, ebuf, nil);
+		switch(*buf) {
+		case '\0':
+			goto done;
+		case '-':
+			if (buf[1] != '\0') {
+				for(ft = ot; ft->ptr; ft++) {
+					o = Getopt(ft->optab, buf+1);
+					if(o != nil) {
+						e = oparse[o->type](t, o, ft->ptr, &str, buf, ebuf);
+						break;
+					}
+				}
+				if(ft->ptr == nil){
+					e = TkBadop;
+					tkerr(t, buf);
+				}
+				break;
+			}
+			/* fall through if we've got a singleton '-' */
+		default:
+			if(nl == nil) {
+				e = TkBadop;
+				tkerr(t, buf);
+				break;
+			}
+			n = tkmkname(buf);
+			if(n == nil) {
+				e = TkNomem;
+				break;
+			}
+			if(*nl == nil)
+				*nl = n;
+			else {
+				for(f = *nl; f->link; f = f->link)
+					;
+				f->link = n;
+			}
+		}		
+	}
+
+	if(e != nil && nl != nil)
+		tkfreename(*nl);
+done:
+	free(buf);
+	return e;
+}
+
+char*
+tkconflist(TkOptab *ot, char **val)
+{
+	TkOption *o;
+	char *f, *e;
+
+	f = "-%s";
+	while(ot->ptr != nil) {
+		o = ot->optab;
+		while(o->o != nil) {
+			e = tkvalue(val, f, o->o);
+			if(e != nil)
+				return e;
+			f = " -%s";
+			o++;
+		}
+		ot++;
+	}
+	return nil;
+}
+
+char*
+tkgencget(TkOptab *ft, char *arg, char **val, TkTop *t)
+{
+	Tk *w;
+	char *c;
+	Point g;
+	TkEnv *e;
+	TkStab *s;
+	TkOption *o;
+	int wh, con, i, n, flag, *v;
+	char *r, *buf, *fmt, *out;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	tkitem(buf, arg);
+	r = buf;
+	if(*r == '-')
+		r++;
+	o = nil;
+	while(ft->ptr) {
+		o = Getopt(ft->optab, r);
+		if(o != nil)
+			break;
+		ft++;
+	}
+	if(o == nil) {
+		tkerr(t, r);
+		free(buf);
+		return TkBadop;
+	}
+
+	switch(o->type) {
+	default:
+		tkerr(t, r);
+		free(buf);
+		return TkBadop;
+	case OPTignore:
+		return nil;
+	case OPTact:
+		w = ft->ptr;
+		g = tkposn(w);
+		n = g.y;
+		if(o->aux == 0)
+			n = g.x;
+		free(buf);
+		return tkvalue(val, "%d", n);
+	case OPTdist:
+	case OPTnndist:
+		free(buf);
+		return tkvalue(val, "%d", OPTION(ft->ptr, int, o->offset));
+	case OPTsize:
+		w = ft->ptr;
+		if(strcmp(r, "width") == 0)
+			wh = w->req.width;
+		else
+			wh = w->req.height;
+		free(buf);
+		return tkvalue(val, "%d", wh);
+	case OPTtext:
+		c = OPTION(ft->ptr, char*, o->offset);
+		if(c == nil)
+			c = "";
+		free(buf);
+		return tkvalue(val, "%s", c);
+	case OPTwinp:
+		w = OPTION(ft->ptr, Tk*, o->offset);
+		if(w == nil || w->name == nil)
+			c = "";
+		else
+			c = w->name->name;
+		free(buf);
+		return tkvalue(val, "%s", c);
+	case OPTstab:
+		s = o->aux;
+		c = "";
+		con = OPTION(ft->ptr, int, o->offset);
+		while(s->val) {
+			if(con == s->con) {
+				c = s->val;
+				break;
+			}
+			s++;
+		}
+		free(buf);
+		return tkvalue(val, "%s", c);
+	case OPTflag:
+		con = OPTION(ft->ptr, int, o->offset);
+		flag = 0;
+		for (s = o->aux; s->val != nil; s++)
+			flag |= s->con;
+		c = "";
+		for (s = o->aux; s->val != nil; s++) {
+			if ((con & flag) == s->con) {
+				c = s->val;
+				break;
+			}
+		}
+		free(buf);
+		return tkvalue(val, "%s", c);
+	case OPTflags:
+		con = OPTION(ft->ptr, int, o->offset);
+		out = mallocz(Tkmaxitem, 0);
+		if(out == nil) {
+			free(buf);
+			return TkNomem;
+		}
+		c = out;
+		for (s = o->aux; s->val != nil; s++) {
+			if (s->con == (s->con&-s->con) && (con & s->con) != 0)
+				c = seprint(c, out+Tkmaxitem, " %s", s->val);	/* should this be quoted? */
+		}
+		free(buf);
+		*c = 0;
+		r = tkvalue(val, "%s", out);
+		free(out);
+		return r;
+	case OPTfont:
+		e = OPTION(ft->ptr, TkEnv*, o->offset);
+		free(buf);
+		if (e->font != nil)
+			return tkvalue(val, "%s", e->font->name);
+		return nil;
+	case OPTcolr:
+		e = OPTION(ft->ptr, TkEnv*, o->offset);
+		i = AUXI(o->aux);
+		free(buf);
+		return tkvalue(val, "#%.8lux", e->colors[i]);
+	case OPTfrac:
+	case OPTnnfrac:
+		v = &OPTION(ft->ptr, int, o->offset);
+		n = (int)o->aux;
+		if(n == 0)
+			n = 1;
+		fmt = "%s";
+		for(i = 0; i < n; i++) {
+			tkfprint(buf, *v++);
+			r = tkvalue(val, fmt, buf);
+			if(r != nil) {
+				free(buf);
+				return r;
+			}
+			fmt = " %s";
+		}
+		free(buf);
+		return nil;
+	case OPTbmap:
+		//free(buf);
+		return tkvalue(val, "%d", OPTION(ft->ptr, Image*, o->offset) != nil);
+	case OPTimag:
+		//free(buf);
+		return tkvalue(val, "%d", OPTION(ft->ptr, TkImg*, o->offset) != nil);
+	}
+}
+
+static char*
+pact(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	USED(buf);
+	USED(ebuf);
+	USED(str);
+	USED(place);
+	tkerr(t, o->o);
+	return TkBadop;
+}
+
+static char*
+pignore(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char *p;
+	USED(t);
+	USED(o);
+	USED(place);
+
+	p = tkword(t, *str, buf, ebuf, nil);
+	if(*buf == '\0')
+		return TkOparg;
+	*str = p;
+	return nil;
+}
+
+static char*
+pdist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	int d;
+	char *e;
+	TkEnv *env;
+
+	USED(buf);
+	USED(ebuf);
+
+	/*
+	 * this is a bit of a hack, as 0 is a valid option offset,
+	 * but a nil aux is commonly used when 'w' and 'h' suffixes
+	 * aren't appropriate.
+	 * just make sure that no structure placed in TkOptab->ptr
+	 * with an OPTdist element has a TkEnv as its first member.
+	 */
+
+	if (o->aux == nil)
+		env = nil;
+	else
+		env = OPTION(place, TkEnv*, AUXI(o->aux));
+	e = tkfracword(t, str, &d, env);
+	if(e != nil)
+		return e;
+	OPTION(place, int, o->offset) = TKF2I(d);
+	return nil;
+}
+
+static char*
+pnndist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char* e;
+	int oldv;
+
+	oldv = OPTION(place, int, o->offset);
+	e = pdist(t, o, place, str, buf, ebuf);
+	if(e == nil && OPTION(place, int, o->offset) < 0) {
+		OPTION(place, int, o->offset) = oldv;
+		return TkBadvl;
+	}
+	return e;	
+}
+
+static char*
+psize(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	Tk *tk;
+	char *e;
+	int d, off;
+
+	USED(ebuf);
+	e = tkfracword(t, str, &d, OPTION(place, TkEnv*, AUXI(o->aux)));
+	if (e != nil)
+		return e;
+	if(d < 0)
+		return TkBadvl;
+
+	tk = place;
+	/*
+	 * XXX there's no way of resetting Tksetwidth or Tksetheight.
+	 * could perhaps allow it by setting width/height to {}
+	 */
+	if(strcmp(buf+1, "width") == 0) {
+		tk->flag |= Tksetwidth;
+		off = O(Tk, req.width);
+	}
+	else {
+		tk->flag |= Tksetheight;
+		off = O(Tk, req.height);
+	}
+	OPTION(place, int, off) = TKF2I(d);
+	return nil;
+}
+
+static TkStab*
+lookstab(TkStab *s, char *word)
+{
+	for(; s->val != nil; s++)
+		if(strcmp(s->val, word) == 0)
+			return s;
+	return nil;
+}
+
+static char*
+pstab(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char *p, *fields[8];
+	int mask, val, nf;
+	TkStab *s, *c;
+
+	p = tkword(t, *str, buf, ebuf, nil);
+	if(*buf == '\0')
+		return TkOparg;
+
+	if(o->type == OPTstab) {
+		s = lookstab(o->aux, buf);
+		if(s == nil)
+			return TkBadvl;
+		*str = p;
+		OPTION(place, int, o->offset) = s->con;
+		return nil;
+	}
+
+	nf = getfields(buf, fields, nelem(fields), 1, " \t,");
+	if(nf < 1 || nf > 1 && o->type != OPTflags)
+		return TkBadvl;
+
+	mask = 0;
+	for(c = o->aux; c->val; c++)
+		mask |= c->con;
+
+	val = 0;
+	while(--nf >= 0) {
+		s = lookstab(o->aux, fields[nf]);
+		if(s == nil)
+			return TkBadvl;
+		val |= s->con;
+	}
+	*str = p;
+
+	OPTION(place, int, o->offset) &= ~mask;
+	OPTION(place, int, o->offset) |= val;
+
+	/*
+	 * a hack, but otherwise we have to dirty the focus order
+	 * every time any command is executed on a widget
+	 */
+	if(strcmp(o->o, "takefocus") == 0)
+		tkdirtyfocusorder(t);
+	return nil;
+}
+
+enum {
+	Stickyn = (1<<0),
+	Stickye = (1<<1),
+	Stickys = (1<<2),
+	Stickyw = (1<<3)
+};
+
+static int stickymap[16] =
+{
+	0,
+	Tknorth,
+	Tkeast,
+	Tknorth|Tkeast,
+	Tksouth,
+	Tkfilly,
+	Tksouth|Tkeast,
+	Tkeast|Tkfilly,
+	Tkwest,
+	Tknorth|Tkwest,
+	Tkfillx,
+	Tknorth|Tkfillx,
+	Tksouth|Tkwest,
+	Tkwest|Tkfilly,
+	Tksouth|Tkfillx,
+	Tkfillx|Tkfilly,
+};
+
+static char*
+psticky(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char *p, *s;
+	int flag, sflag;
+
+	p = tkword(t, *str, buf, ebuf, nil);
+	*str = p;
+
+	flag = 0;
+	for (s = buf; *s; s++) {
+		switch (*s) {
+		case 'n':
+			flag |= Stickyn;
+			break;
+		case 's':
+			flag |= Stickys;
+			break;
+		case 'e':
+			flag |= Stickye;
+			break;
+		case 'w':
+			flag |= Stickyw;
+			break;
+		case ' ':
+		case ',':
+			break;
+		default:
+			return TkBadvl;
+		}
+	}
+	sflag =  OPTION(place, int, o->offset) & ~(Tkanchor|Tkfill);
+	OPTION(place, int, o->offset) = sflag | stickymap[flag];
+	return nil;
+}
+
+static char*
+ptext(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char **p;
+
+	*str = tkword(t, *str, buf, ebuf, nil);
+
+	p = &OPTION(place, char*, o->offset);
+	if(*p != nil)
+		free(*p);
+	if(buf[0] == '\0')
+		*p = nil;
+	else {
+		*p = strdup(buf);
+		if(*p == nil)
+			return TkNomem;
+	}
+	return nil;
+}
+
+static char*
+pimag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	int locked;
+	Display *d;
+	TkImg **p, *i;
+
+	i = nil;
+	p = &OPTION(place, TkImg*, o->offset);
+	*str = tkword(t, *str, buf, ebuf, nil);
+	if(*buf != '\0') {
+		i = tkname2img(t, buf);
+		if(i == nil)
+			return TkBadvl;
+		i->ref++;
+	}
+
+	if(*p != nil) {
+		d = t->display;
+		locked = lockdisplay(d);
+		tkimgput(*p);
+		if(locked)
+			unlockdisplay(d);
+	}
+	*p = i;
+	return nil;
+}
+
+static char*
+pbmap(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	Display *d;
+	Image *i, **p;
+	int locked, fd;
+	char *c;
+
+	p = &OPTION(place, Image*, o->offset);
+
+	d = t->display;
+	*str = tkword(t, *str, buf, ebuf, nil);
+	if(*buf == '\0' || *buf == '-') {
+		if(*p != nil) {
+			locked = lockdisplay(d);
+			freeimage(*p);
+			if(locked)
+				unlockdisplay(d);
+			*p = nil;
+		}
+		return nil;
+	}
+
+	if(buf[0] == '@')
+		i = display_open(d, buf+1);
+ else if(buf[0] == '<') {
+		buf++;
+		fd = strtoul(buf, &c, 0);
+		if(c == buf) {
+			return TkBadvl;
+		}
+		i = readimage(d, fd, 1);
+	}
+	else {
+		char *file;
+
+		file = mallocz(Tkmaxitem, 0);
+		if(file == nil)
+			return TkNomem;
+
+		snprint(file, Tkmaxitem, "/icons/tk/%s", buf);
+		i = display_open(d, file);
+		free(file);
+	}
+	if(i == nil)
+		return TkBadbm;
+
+	if(*p != nil) {
+		locked = lockdisplay(d);
+		freeimage(*p);
+		if(locked)
+			unlockdisplay(d);
+	}
+	*p = i;
+	return nil;
+}
+
+static char*
+pfont(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	TkEnv *e;
+	Display *d;
+	int locked;
+	Font *font;
+
+	*str = tkword(t, *str, buf, ebuf, nil);
+	if(*buf == '\0')
+		return TkOparg;
+
+	d = t->display;
+	font = font_open(d, buf);
+	if(font == nil)
+		return TkBadft;
+
+	e = tkdupenv(&OPTION(place, TkEnv*, o->offset));
+	if(e == nil) {
+		freefont(font);		/* XXX lockdisplay around this? */
+		return TkNomem;
+	}
+	if(e->font)
+		font_close(e->font);
+	e->font = font;
+
+	locked = lockdisplay(d);
+	e->wzero = stringwidth(font, "0");
+	if ( e->wzero <= 0 )
+		e->wzero = e->font->height / 2;
+	if(locked)
+		unlockdisplay(d);
+
+	return nil;
+}
+
+static int
+hex(int c)
+{
+	if(c >= 'a')
+		c -= 'a'-'A';
+	if(c >= 'A')
+		c = 10 + (c - 'A');
+	else
+		c -= '0';
+	return c;
+}
+
+static ulong
+changecol(TkEnv *e, int setcol, int col, ulong rgba)
+{
+	if (setcol) {
+		e->set |= (1<<col);
+	} else {
+		rgba = 0;
+		e->set &= ~(1<<col);
+	}
+	e->colors[col] = rgba;
+	return rgba;
+}
+
+char*
+tkparsecolor(char *buf, ulong *rgba)
+{
+	char *p, *q, *e;
+	int R, G, B, A;
+	int i, alpha, len, alen;
+	/*
+	 * look for alpha modifier in *#AA or *0.5 format
+	 */
+	len = strlen(buf);
+	p = strchr(buf, '*');
+	if(p != nil) {
+		alen = len - (p - buf);
+		if(p[1] == '#') {
+			if(alen != 4)
+				return TkBadvl;
+			alpha = (hex(p[2])<<4) | (hex(p[3]));
+		} else {
+			q = p+1;
+			e = tkfrac(&q, &alpha, nil);
+			if (e != nil)
+				return e;
+			alpha = TKF2I(alpha * 0xff);
+		}
+		*p = '\0';
+		len -= alen;
+	} else
+		alpha = 0xff;
+	
+	if (*buf == '#') {
+		switch(len) {
+		case 4:			/* #RGB */
+			R = hex(buf[1]);
+			G = hex(buf[2]);
+			B = hex(buf[3]);
+			*rgba = (R<<28) | (G<<20) | (B<<12) | 0xff;
+			break;
+		case 7:			/* #RRGGBB */
+			R = (hex(buf[1])<<4)|(hex(buf[2]));
+			G = (hex(buf[3])<<4)|(hex(buf[4]));
+			B = (hex(buf[5])<<4)|(hex(buf[6]));
+			*rgba = (R<<24) | (G<<16) | (B<<8) | 0xff;
+			break;
+		case 9:			/* #RRGGBBAA */
+			R = (hex(buf[1])<<4)|(hex(buf[2]));
+			G = (hex(buf[3])<<4)|(hex(buf[4]));
+			B = (hex(buf[5])<<4)|(hex(buf[6]));
+			A = (hex(buf[7])<<4)|(hex(buf[8]));
+			*rgba = (R<<24) | (G<<16) | (B<<8) | A;
+			break;
+		default:
+			return TkBadvl;
+		}
+	} else {
+		for(i = 0; tkcolortab[i].val != nil; i++)
+			if (!strcmp(tkcolortab[i].val, buf))
+				break;
+		if (tkcolortab[i].val == nil)
+			return TkBadvl;
+		*rgba = tkcolortab[i].con;
+	}
+	if (alpha != 0xff) {
+		tkrgbavals(*rgba, &R, &G, &B, &A);
+		A = (A * alpha) / 255;
+		*rgba = tkrgba(R, G, B, A);
+	}
+	return nil;
+}
+
+static char*
+pcolr(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	TkEnv *env;
+	char *e;
+	ulong rgba, dark, light;
+	int color, setcol;
+
+	*str = tkword(t, *str, buf, ebuf, nil);
+	rgba = 0;
+	if(*buf == '\0') {
+		setcol = 0;
+	} else {
+		setcol = 1;
+		e = tkparsecolor(buf, &rgba);
+		if(e != nil)
+			return e;
+	}
+		
+	env = tkdupenv(&OPTION(place, TkEnv*, o->offset));
+	if(env == nil)
+		return TkNomem;
+
+	color = AUXI(o->aux);
+	rgba = changecol(env, setcol, color, rgba);
+	if(color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
+		if (setcol) {
+			light = tkrgbashade(rgba, TkLightshade);
+			dark = tkrgbashade(rgba, TkDarkshade);
+		} else
+			light = dark = 0;
+		changecol(env, setcol, color+1, light);
+		changecol(env, setcol, color+2, dark);
+	}
+	return nil;
+}
+
+static char*
+pbool(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	USED(buf);
+	USED(ebuf);
+	USED(str);
+	USED(t);
+	OPTION(place, int, o->offset) = 1;
+	return nil;
+}
+
+static char*
+pwinp(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	Tk *f;
+	char *p;
+
+	p = tkword(t, *str, buf, ebuf, nil);
+	if(*buf == '\0')
+		return TkOparg;
+	*str = p;
+	
+	f = tklook(t, buf, 0);
+	if(f == nil){
+		tkerr(t, buf);
+		return TkBadwp;
+	}
+
+	OPTION(place, Tk*, o->offset) = f;
+	return nil;
+}
+
+static char*
+pctag(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char *p;
+	TkName *n, *l;
+
+	*str = tkword(t, *str, buf, ebuf, nil);
+
+	l = nil;
+	p = buf;
+	while(*p) {
+		p = tkskip(p, " \t");
+		buf = p;
+		while(*p && *p != ' ' && *p != '\t')
+			p++;
+		if(*p != '\0')
+			*p++ = '\0';
+
+		if(p == buf || buf[0] >= '0' && buf[0] <= '9') {
+			tkfreename(l);
+			return TkBadtg;
+		}
+		n = tkmkname(buf);
+		if(n == nil) {
+			tkfreename(l);
+			return TkNomem;
+		}
+		n->link = l;
+		l = n;
+	}
+	tkfreename(OPTION(place, TkName*, o->offset));
+	OPTION(place, TkName*, o->offset) = l;
+	return nil;
+}
+
+static char*
+pfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char *p, *e;
+	int i, n, d, *v;
+
+	*str = tkword(t, *str, buf, ebuf, nil);
+
+	v = &OPTION(place, int, o->offset);
+	n = (int)o->aux;
+	if(n == 0)
+		n = 1;
+	p = buf;
+	for(i = 0; i < n; i++) {
+		p = tkskip(p, " \t");
+		if(*p == '\0')
+			return TkOparg;
+		e = tkfracword(t, &p, &d, nil);
+		if (e != nil)
+			return e;
+		*v++ = d;
+	}
+	return nil;
+}
+
+/*
+ * N.B. nnfrac only accepts aux==nil (can't deal with several items)
+ */
+static char*
+pnnfrac(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	int oldv;
+	char *e;
+
+	oldv = OPTION(place, int, o->offset);
+
+	e = pfrac(t, o, place, str, buf, ebuf);
+	if(e == nil && OPTION(place, int, o->offset) < 0) {
+		OPTION(place, int, o->offset) = oldv;
+		return TkBadvl;
+	}
+	return e;	
+
+}
+
+typedef struct Tabspec {
+	int	dist;
+	int	just;
+	TkEnv	*env;
+} Tabspec;
+
+static char*
+ptabs(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char *e, *p, *eibuf;
+	TkOption opd, opj;
+	Tabspec tspec;
+	TkTtabstop *tabfirst, *tab, *tabprev;
+	char *ibuf;
+
+	ibuf = mallocz(Tkmaxitem, 0);
+	if(ibuf == nil)
+		return TkNomem;
+	eibuf = ibuf + Tkmaxitem;
+	tspec.env = OPTION(place, TkEnv*, AUXI(o->aux));
+	opd.offset = O(Tabspec, dist);
+	opd.aux = IAUX(O(Tabspec, env));
+	opj.offset = O(Tabspec, dist);
+	opj.aux = tktabjust;
+	tabprev = nil;
+	tabfirst = nil;
+
+	p = tkword(t, *str, buf, ebuf, nil);
+	if(*buf == '\0') {
+		free(ibuf);
+		return TkOparg;
+	}
+	*str = p;
+
+	p = buf;
+	while(*p != '\0') {
+		e = pdist(t, &opd, &tspec, &p, ibuf, eibuf);
+		if(e != nil) {
+			free(ibuf);
+			return e;
+		}
+
+		e = pstab(t, &opj, &tspec, &p, ibuf, eibuf);
+		if(e != nil)
+			tspec.just = Tkleft;
+
+		tab = malloc(sizeof(TkTtabstop));
+		if(tab == nil) {
+			free(ibuf);
+			return TkNomem;
+		}
+
+		tab->pos = tspec.dist;
+		tab->justify = tspec.just;
+		tab->next = nil;
+		if(tabfirst == nil)
+			tabfirst = tab;
+		else
+			tabprev->next = tab;
+		tabprev = tab;
+	}
+	free(ibuf);
+
+	tab = OPTION(place, TkTtabstop*, o->offset);
+	if(tab != nil)
+		free(tab);
+	OPTION(place, TkTtabstop*, o->offset) = tabfirst;
+	return nil;
+}
+
+char*
+tkxyparse(Tk* tk, char **parg, Point *p)
+{
+	char *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	*parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+	if(*buf == '\0') {
+		free(buf);
+		return TkOparg;
+	}
+	p->x = atoi(buf);
+
+	*parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+	if(*buf == '\0') {
+		free(buf);
+		return TkOparg;
+	}
+	p->y = atoi(buf);
+
+	free(buf);
+	return nil;
+}
+
+static char*
+plist(TkTop *t, TkOption *o, void *place, char **str, char *buf, char *ebuf)
+{
+	char *w, ***p, *wbuf, *ewbuf, **v, **nv;
+	int n, m, i, found;
+
+	*str = tkword(t, *str, buf, ebuf, nil);
+	n = strlen(buf) + 1;
+	wbuf = mallocz(n, 0);
+	if (wbuf == nil)
+		return TkNomem;		/* XXX should we free old values too? */
+	ewbuf = &wbuf[n];
+
+	p = &OPTION(place, char**, o->offset);
+	if (*p != nil){
+		for (v = *p; *v; v++)
+			free(*v);
+		free(*p);
+	}
+	n = 0;
+	m = 4;
+	w = buf;
+	v = malloc(m * sizeof(char*));
+	if (v == nil)
+		goto Error;
+	for (;;) {
+		w = tkword(t, w, wbuf, ewbuf, &found);
+		if (!found)
+			break;
+		if (n == m - 1) {
+			m += m/2;
+			nv = realloc(v, m * sizeof(char*));
+			if (nv == nil)
+				goto Error;
+			v = nv;
+		}
+		v[n] = strdup(wbuf);
+		if (v[n] == nil)
+			goto Error;
+		n++;
+	}
+	v[n++] = nil;
+	*p = realloc(v, n * sizeof(char*));
+	free(wbuf);
+	return nil;
+Error:
+	free(buf);
+	for (i = 0; i < n; i++)
+		free(v[i]);
+	free(v);
+	*p = nil;
+	return TkNomem;
+}
--- /dev/null
+++ b/libtk/radio.tk
@@ -1,0 +1,4 @@
+radiobutton .u -text {Upper case} -variable case -value u
+radiobutton .l -text {Lower case} -variable case -value l
+radiobutton .i -text {Ignore case} -variable case -value i
+pack .u .l .i -anchor w -fill x
--- /dev/null
+++ b/libtk/scale.c
@@ -1,0 +1,963 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "keyboard.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+typedef struct TkScale TkScale;
+struct TkScale
+{
+	int	value;
+	int	bigi;
+	int	digits;
+	int	digwidth;
+	int	from;		/* Base of range */
+	int	to;		/* Limit of range */
+	int	len;		/* Length of groove */
+	int	res;		/* Resolution */
+	int	sv;		/* Show value */
+	int	sl;		/* Slider length */
+	int	sw;		/* Slider width div 2 */
+	int	relief;
+	int	tick;
+	int	orient;
+	char*	command;
+	char*	label;
+	int	pixmin;
+	int	pixmax;
+	int	pixpos;
+	int	center;
+	int	pix;
+	int	base;
+	int	flag;
+	int	jump;
+};
+
+enum {
+	Dragging = (1<<0),
+	Autorepeat = (1<<1),
+};
+
+static
+TkOption opts[] =
+{
+	"bigincrement",		OPTnnfrac,	O(TkScale, bigi),	nil,
+	"digits",		OPTdist,	O(TkScale, digits),	nil,
+	"from",			OPTfrac,	O(TkScale, from),	nil,
+	"to",			OPTfrac,	O(TkScale, to),		nil,
+	"length",		OPTdist,	O(TkScale, len),	nil,
+	"resolution",		OPTnnfrac,	O(TkScale, res),	nil,
+	"showrange",	OPTignore,	0,	nil,
+	"showvalue",		OPTstab,	O(TkScale, sv),		tkbool,
+	"jump",		OPTstab, O(TkScale, jump),	tkbool,
+	"sliderlength",		OPTdist,	O(TkScale, sl),		nil,
+	"sliderrelief",		OPTstab,	O(TkScale, relief),	tkrelief,
+	"tickinterval",		OPTfrac,	O(TkScale, tick),	nil,
+	"tick",		OPTfrac,	O(TkScale, tick),	nil,
+	"label",		OPTtext,	O(TkScale, label),	nil,
+	"command",		OPTtext,	O(TkScale, command),	nil,
+	"orient",		OPTstab,	O(TkScale, orient),	tkorient,
+	nil
+};
+
+static char trough1[] = "trough1";
+static char trough2[] = "trough2";
+static char slider[]  = "slider";
+
+static
+TkEbind b[] = 
+{
+	{TkMotion,		"%W tkScaleMotion %x %y"},
+	{TkButton1P|TkMotion,	"%W tkScaleDrag %x %y"},
+	{TkButton1P,		"%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},
+	{TkButton1P|TkDouble,	"%W tkScaleMotion %x %y; %W tkScaleBut1P %x %y"},
+	{TkButton1R,		"%W tkScaleDrag %x %y; %W tkScaleBut1R; %W tkScaleMotion %x %y"},
+	{TkKey,		"%W tkScaleKey 0x%K"},
+};
+
+enum
+{
+	Scalewidth	= 18,
+	ScalePad	= 2,
+	ScaleBW		= 1,
+	ScaleSlider	= 16,
+	ScaleLen	= 80,
+
+};
+
+static int
+maximum(int a, int b)
+{
+	if (a > b)
+		return a;
+	return b;
+}
+
+void
+tksizescale(Tk *tk)
+{
+	Point p;
+	char buf[32];
+	TkScale *tks;
+	int fh, w, h, digits, digits2;
+
+	tks = TKobj(TkScale, tk);
+
+	digits = tks->digits;
+	if(digits <= 0) {
+		digits = tkfprint(buf, tks->from) - buf;
+		digits2 = tkfprint(buf, tks->to) - buf;
+		digits = maximum(digits, digits2);
+		if (tks->res > 0) {
+			digits2 = tkfprint(buf, tks->from + tks->res) - buf;
+			digits = maximum(digits, digits2);
+			digits2 = tkfprint(buf, tks->to - tks->res) - buf;
+			digits = maximum(digits, digits2);
+		}
+	}
+
+	digits *= tk->env->wzero;
+	if(tks->sv != BoolT)
+		digits = 0;
+
+	tks->digwidth = digits;
+
+	p = tkstringsize(tk, tks->label);
+	if(tks->orient == Tkvertical) {
+		h = tks->len + 2*ScaleBW + 2*ScalePad;
+		w = Scalewidth + 2*ScalePad + 2*ScaleBW;
+		if (p.x)
+			w += p.x + ScalePad;
+		if (tks->sv == BoolT)
+			w += digits + ScalePad;
+	} else {
+		w = maximum(p.x, tks->len + ScaleBW + 2*ScalePad);
+		h = Scalewidth + 2*ScalePad + 2*ScaleBW;
+		fh = tk->env->font->height;
+		if(tks->label != nil)
+			h += fh + ScalePad;
+		if(tks->sv == BoolT)
+			h += fh + ScalePad;
+	}
+	w += 2*tk->highlightwidth;
+	h += 2*tk->highlightwidth;
+	if(!(tk->flag & Tksetwidth))
+		tk->req.width = w;
+	if(!(tk->flag & Tksetheight))
+		tk->req.height = h;
+}
+
+static int
+tkscalecheckvalue(Tk *tk)
+{
+	int v;
+	TkScale *tks = TKobj(TkScale, tk);
+	int limit = 1;
+
+	v = tks->value;
+	if (tks->res > 0)
+		v = (v / tks->res) * tks->res;
+	if (tks->to >= tks->from) {
+		if (v < tks->from)
+			v = tks->from;
+		else if (v > tks->to)
+			v = tks->to;
+		else
+			limit = 0;
+	} else {
+		if (v < tks->to)
+			v = tks->to;
+		else if (v > tks->from)
+			v = tks->from;
+		else
+			limit = 0;
+	}
+	/*
+	 *  it's possible for the value to end up as a non-whole
+	 * multiple of resolution here, if the end points aren't
+	 * themselves such a multiple. if so, tough - that's
+	 * what you asked for! (it does mean that the endpoints
+	 * are always accessible however, which could be a good thing).
+	 */
+	tks->value = v;
+	return limit;
+}
+
+char*
+tkscale(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkName *names;
+	TkScale *tks;
+	TkOptab tko[3];
+
+	tk = tknewobj(t, TKscale, sizeof(Tk)+sizeof(TkScale));
+	if(tk == nil)
+		return TkNomem;
+
+	tk->flag |= Tktakefocus;
+	tks = TKobj(TkScale, tk);
+	tks->res = TKI2F(1);
+	tks->to = TKI2F(100);
+	tks->len = ScaleLen;
+	tks->orient = Tkvertical;
+	tks->relief = TKraised;
+	tks->sl = ScaleSlider;
+	tks->sv = BoolT;
+	tks->bigi = 0;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tks;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tkscalecheckvalue(tk);
+	tksizescale(tk);
+	if (tks->bigi == 0)
+		tks->bigi = TKI2F(TKF2I(tks->to - tks->from) / 10);
+	e = tkbindings(t, tk, b, nelem(b));
+
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tkscalecget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkScale *tks = TKobj(TkScale, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tks;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreescale(Tk *tk)
+{
+	TkScale *tks = TKobj(TkScale, tk);
+
+	if(tks->command != nil)
+		free(tks->command);
+	if(tks->label != nil)
+		free(tks->label);
+}
+
+static void
+tkscalehoriz(Tk *tk, Image *i)
+{
+	TkEnv *e;
+	char sv[32];
+	TkScale *tks;
+	Image *d, *l;
+	Rectangle r, r2, sr;
+	Point p, q;
+	int fh, sh, gh, sl, v, w, h, len;
+	int fgnd;
+
+	e = tk->env;
+	tks = TKobj(TkScale, tk);
+
+
+	fh = e->font->height;
+	fgnd = TkCforegnd;
+	if (tk->flag & Tkdisabled)
+		fgnd = TkCdisablefgnd;
+
+	r = Rect(0, 0, tk->act.width, tk->act.height);
+	r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));
+	r = insetrect(r, tk->highlightwidth);
+	r = insetrect(r, ScalePad);
+
+	if(tks->label != nil) {
+		string(i, r.min, tkgc(e, fgnd), ZP, e->font, tks->label);
+		r.min.y += fh + ScalePad;
+	}
+	if(tks->sv == BoolT)
+		r.min.y += fh + ScalePad;
+
+	sr = insetrect(r, ScaleBW);
+	w = Dx(sr);
+	h = Dy(sr);
+	sl = tks->sl + 2*ScaleBW;
+
+	l = tkgc(e, TkCbackgndlght);
+	d = tkgc(e, TkCbackgnddark);
+	tkbevel(i, r.min, w, h, ScaleBW, d, l);
+
+	tks->pixmin = sr.min.x;
+	tks->pixmax = sr.max.x;
+
+	sh = h - 2*ScaleBW;
+	tks->sw = sh/2;
+
+	w -= sl;
+	if (w <= 0)
+		w = 1;
+	p.x = sr.min.x;
+	p.y = sr.max.y;
+	if(tks->tick > 0){
+		int j, t, l;
+		t = tks->tick;
+		l = tks->to-tks->from;
+		if (l < 0)
+			l = -l;
+		if (l == 0)
+			l = 1;
+		r2.min.y = p.y;
+		r2.max.y = p.y + ScaleBW + ScalePad;
+		for(j = 0; j <= l; j += t){
+			r2.min.x = p.x+((vlong)j*w)/l+sl/2;
+			r2.max.x = r2.min.x+1;
+			draw(i, r2, tkgc(e, fgnd), nil, ZP);
+		}
+	}
+	v = tks->value-tks->from;
+	len = tks->to-tks->from;
+	if (len != 0)
+		p.x += ((vlong)v*w)/len;
+	p.y = sr.min.y;
+	q = p;
+	q.x += tks->sl/2 + 1;
+	if(ScaleBW > 1) {
+		gh = sh;
+		q.y++;
+	} else
+		gh = sh-1;
+	if(tk->flag & Tkactivated) {
+		r2.min = p;
+		r2.max.x = p.x+sl;
+		r2.max.y = sr.max.y;
+		draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);
+	}
+	switch(tks->relief) {
+	case TKsunken:
+		tkbevel(i, p, tks->sl, sh, ScaleBW, d, l);
+		tkbevel(i, q, 0, gh, 1, l, d);
+		break;
+	case TKraised:
+		tkbevel(i, p, tks->sl, sh, ScaleBW, l, d);
+		tkbevel(i, q, 0, gh, 1, d, l);
+		break;
+	}
+	tks->pixpos = p.x;
+	tks->center = p.y + sh/2 + ScaleBW;
+
+	if(tks->sv != BoolT)
+		return;
+
+	tkfprint(sv, tks->value);
+	if(tks->digits > 0 && tks->digits < strlen(sv))
+		sv[tks->digits] = '\0';
+
+	w = stringwidth(e->font, sv);
+	p.x = q.x;
+	p.x -= w/2;
+	p.y = r.min.y - fh - ScalePad;
+	if(p.x < tks->pixmin)
+		p.x = tks->pixmin;
+	if(p.x+w > tks->pixmax)
+		p.x = tks->pixmax - w;
+	
+	string(i, p, tkgc(e, fgnd), ZP, e->font, sv);
+}
+
+static void
+tkscalevert(Tk *tk, Image *i)
+{
+	TkEnv *e;
+	TkScale *tks;
+	char sv[32];
+	Image *d, *l;
+	Rectangle r, r2, sr;
+	Point p, q;
+	int fh, v, sw, gw, w, h, len, sl;
+	int fgnd;
+
+	e = tk->env;
+	tks = TKobj(TkScale, tk);
+
+	fh = e->font->height;
+	fgnd = TkCforegnd;
+	if (tk->flag & Tkdisabled)
+		fgnd = TkCdisablefgnd;
+
+	r = Rect(0, 0, tk->act.width, tk->act.height);
+	r = rectaddpt(r, Pt(tk->borderwidth, tk->borderwidth));
+	r = insetrect(r, tk->highlightwidth);
+	r = insetrect(r, ScalePad);
+
+	if (tks->sv)
+		r.min.x += tks->digwidth + ScalePad;
+
+	if(tks->label != nil) {
+		p =  stringsize(e->font, tks->label);
+		r.max.x -= p.x;
+		string(i, Pt(r.max.x, r.min.y), tkgc(e, fgnd), ZP, e->font, tks->label);
+		r.max.x -= ScalePad;
+	}
+
+	sr = insetrect(r, ScaleBW);
+	h = Dy(sr);
+	w = Dx(sr);
+	sl = tks->sl + 2*ScaleBW;
+
+	l = tkgc(e, TkCbackgndlght);
+	d = tkgc(e, TkCbackgnddark);
+	tkbevel(i, r.min, w, h, ScaleBW, d, l);
+
+	tks->pixmin = sr.min.y;
+	tks->pixmax = sr.max.y;
+
+	sw = w - 2*ScaleBW;
+	tks->sw = sw/2;
+
+	h -= sl;
+	if (h <= 0)
+		h = 1;
+	p.x = sr.max.x;
+	p.y = sr.min.y;
+	if(tks->tick > 0){
+		int j, t, l;
+		t = tks->tick;
+		l = tks->to-tks->from;
+		if (l < 0)
+			l = -l;
+		if (l == 0)
+			l = 1;
+		r2.min = p;
+		r2.max.x = p.x + ScaleBW + ScalePad;
+		for(j = 0; j <= l; j += t){
+			r2.min.y = p.y+((vlong)j*h)/l+sl/2;
+			r2.max.y = r2.min.y+1;
+			draw(i, r2, tkgc(e, fgnd), nil, ZP);
+		}
+	}
+
+	v = tks->value-tks->from;
+	len  = tks->to-tks->from;
+	if (len != 0)
+		p.y += ((vlong)v*h)/len;
+	p.x = sr.min.x;
+	q = p;
+	if(ScaleBW > 1) {
+		q.x++;
+		gw = sw;
+	} else
+		gw = sw-1;
+	q.y += tks->sl/2 + 1;
+	if(tk->flag & Tkactivated) {
+		r2.min = p;
+		r2.max.x = sr.max.x;
+		r2.max.y = p.y+sl;
+		draw(i, r2, tkgc(e, TkCactivebgnd), nil, ZP);
+	}
+	switch(tks->relief) {
+	case TKsunken:
+		tkbevel(i, p, sw, tks->sl, ScaleBW, d, l);
+		tkbevel(i, q, gw, 0, 1, l, d);
+		break;
+	case TKraised:
+		tkbevel(i, p, sw, tks->sl, ScaleBW, l, d);
+		tkbevel(i, q, gw, 0, 1, d, l);
+		break;
+	}
+	tks->pixpos = p.y;
+	tks->center = p.x + sw/2 + ScaleBW;
+
+	if(tks->sv != BoolT)
+		return;
+
+	tkfprint(sv, tks->value);
+	if(tks->digits > 0 && tks->digits < strlen(sv))
+		sv[tks->digits] = '\0';
+
+	p.x = r.min.x - ScalePad - stringwidth(e->font, sv);
+	p.y = q.y;
+	p.y -= fh/2;
+	if (p.y < tks->pixmin)
+		p.y = tks->pixmin;
+	if (p.y + fh > tks->pixmax)
+		p.y = tks->pixmax - fh;
+	string(i, p, tkgc(e, fgnd), ZP, e->font, sv);
+}
+
+char*
+tkdrawscale(Tk *tk, Point orig)
+{
+	Point p;
+	TkEnv *env;
+	TkScale *tks;
+	Rectangle r, fr;
+	Image *i;
+
+	tks = TKobj(TkScale, tk);
+	env = tk->env;
+
+	r.min = ZP;
+	r.max.x = tk->act.width + 2*tk->borderwidth;
+	r.max.y = tk->act.height + 2*tk->borderwidth;
+	i = tkitmp(env, r.max, TkCbackgnd);
+	if(i == nil)
+		return nil;
+
+	if(tks->orient == Tkvertical)
+		tkscalevert(tk, i);
+	else
+		tkscalehoriz(tk, i);
+
+	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+	if (tkhaskeyfocus(tk)) {
+		fr = insetrect(r, tk->borderwidth);
+		tkbox(i, fr, tk->highlightwidth, tkgc(env, TkChighlightfgnd));
+	}
+
+	p.x = tk->act.x + orig.x;
+	p.y = tk->act.y + orig.y;
+	r = rectaddpt(r, p);
+	draw(tkimageof(tk), r, i, nil, ZP);
+
+	return nil;
+}
+
+/* Widget Commands (+ means implemented)
+	+cget
+	+configure
+	+coords
+	+get
+	+identify
+	+set
+*/
+
+static char*
+tkscaleconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkOptab tko[3];
+	TkScale *tks = TKobj(TkScale, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tks;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tkscalecheckvalue(tk);
+	tksizescale(tk);
+	tkgeomchg(tk, &g, bd);
+
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+char*
+tkscaleposn(TkEnv *env, Tk *tk, char *arg, int *z)
+{
+	int x, y;
+	TkScale *tks = TKobj(TkScale, tk);
+	char *e;
+
+	e = tkfracword(env->top, &arg, &x, env);
+	if(e != nil)
+		return e;
+	e = tkfracword(env->top, &arg, &y, env);
+	if(e != nil)
+		return e;
+
+	x = TKF2I(x) + tk->borderwidth;
+	y = TKF2I(y) + tk->borderwidth;
+
+	if(tks->orient == Tkvertical) {
+		if(z != nil) {
+			z[0] = x;
+			z[1] = y;
+		}
+		x = y;
+	}
+	else {
+		if(z != nil) {
+			z[0] = y;
+			z[1] = x;
+		}
+	}
+	if(x > tks->pixmin && x < tks->pixpos)
+		return trough1;
+	else if(x >= tks->pixpos && x < tks->pixpos+tks->sl+2*ScaleBW)
+		return slider;
+	else if(x >= tks->pixpos+tks->sl+2*ScaleBW && x < tks->pixmax)
+		return trough2;
+
+	return "";
+}
+
+static char*
+tkscaleident(Tk *tk, char *arg, char **val)
+{
+	char *v;
+
+	v = tkscaleposn(tk->env, tk, arg, nil);
+	if(v == nil)
+		return TkBadvl;
+	return tkvalue(val, "%s", v);
+}
+
+static char*
+tkscalecoords(Tk *tk, char *arg, char **val)
+{
+	int p, x, y, l, value;
+	TkScale *tks = TKobj(TkScale, tk);
+	char *e;
+
+	value = tks->value;
+	if(arg != nil && arg[0] != '\0') {
+		e = tkfracword(tk->env->top, &arg, &value, tk->env);
+		if (e != nil)
+			return e;
+	}
+
+	value -= tks->from;
+	p = tks->pixmax - tks->pixmin;
+	l = TKF2I(tks->to-tks->from);
+	if (l==0)
+		p /= 2;
+	else
+		p = TKF2I(value*p/l);
+	p += tks->pixmin;
+	if(tks->orient == Tkvertical) {
+		x = tks->center;
+		y = p;
+	}
+	else {
+		x = p;
+		y = tks->center;
+	}
+	return tkvalue(val, "%d %d", x, y);
+}
+
+static char*
+tkscaleget(Tk *tk, char *arg, char **val)
+{
+	int x, y, value, v, l;
+	char buf[Tkminitem], *e;
+	TkScale *tks = TKobj(TkScale, tk);
+
+	value = tks->value;
+	if(arg[0] != '\0') {
+		e = tkfracword(tk->env->top, &arg, &x, tk->env);
+		if (e != nil)
+			return e;
+		e = tkfracword(tk->env->top, &arg, &y, tk->env);
+		if (e != nil)
+			return e;
+		if(tks->orient == Tkvertical)
+			v = TKF2I(y) + tk->borderwidth;
+		else
+			v = TKF2I(x) + tk->borderwidth;
+
+		if(v < tks->pixmin)
+			value = tks->from;
+		else
+		if(v > tks->pixmax)
+			value = tks->to;
+		else {
+			l = tks->pixmax-tks->pixmin;
+			value = 0;
+			if (l!=0)
+				value = v * ((tks->to-tks->from)/l);
+			value += tks->from;
+		}
+		if(tks->res > 0)
+			value = (value/tks->res)*tks->res;
+	}
+	tkfprint(buf, value);
+	return tkvalue(val, "%s", buf);
+}
+
+static char*
+tkscaleset(Tk *tk, char *arg, char **val)
+{
+	TkScale *tks = TKobj(TkScale, tk);
+	char *e;
+
+	USED(val);
+
+	e = tkfracword(tk->env->top, &arg, &tks->value, tk->env);
+	if (e != nil)
+		return e;
+	tkscalecheckvalue(tk);
+	tk->dirty = tkrect(tk, 1);
+	return nil;		
+}
+
+/* tkScaleMotion %x %y */
+static char*
+tkscalemotion(Tk *tk, char *arg, char **val)
+{
+	int o, z[2];
+	char *v;
+	TkScale *tks = TKobj(TkScale, tk);
+	extern int tkstylus;
+
+	USED(val);
+	v = tkscaleposn(tk->env, tk, arg, z);
+	if(v == nil)
+		return TkBadvl;
+
+	o = tk->flag;
+	if(v != slider || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw)
+		tk->flag &= ~Tkactivated;
+	else if(tkstylus == 0 || tk->env->top->ctxt->mstate.b != 0)
+		tk->flag |= Tkactivated;
+
+	if((o & Tkactivated) != (tk->flag & Tkactivated))
+		tk->dirty = tkrect(tk, 1);
+
+	return nil;
+}
+
+static char*
+tkscaledrag(Tk *tk, char *arg, char **val)
+{
+	int x, y, v;
+	char *e, buf[Tkmaxitem], f[32];
+	TkScale *tks = TKobj(TkScale, tk);
+
+	USED(val);
+	if((tks->flag & Dragging) == 0)
+		return nil;
+	if(tks->flag & Autorepeat)
+		return nil;
+
+	e = tkfracword(tk->env->top, &arg, &x, tk->env);
+	if(e != nil)
+		return e;
+	e = tkfracword(tk->env->top, &arg, &y, tk->env);
+	if(e != nil)
+		return e;
+
+	if(tks->orient == Tkvertical)
+		v = TKF2I(y) + tk->borderwidth;
+	else
+		v = TKF2I(x) + tk->borderwidth;
+
+	v -= tks->pix;
+	x = tks->pixmax-tks->pixmin;
+	if (x!=tks->sl)
+		v = tks->base + (vlong)v * (tks->to-tks->from)/(x-tks->sl);
+	else
+		v = tks->base;
+	if(tks->res > 0) {
+		int a = tks->res / 2;
+		if (v < 0)
+			a = -a;
+		v = ((v+a)/tks->res)*tks->res;
+	}
+
+	tks->value = v;
+	tkscalecheckvalue(tk);
+
+	if(tks->command != nil && tks->jump != BoolT) {
+		tkfprint(f, tks->value);
+		snprint(buf, sizeof(buf), "%s %s", tks->command, f);
+		e = tkexec(tk->env->top, buf, nil);
+	}
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static int
+sgn(int v)
+{
+	return v >= 0 ? 1 : -1;
+}
+
+static char*
+stepscale(Tk *tk, char *pos, int *end)
+{
+	TkScale *tks = TKobj(TkScale, tk);
+	char *e, buf[Tkmaxitem], f[32];
+	int s;
+
+	s = sgn(tks->to - tks->from);
+	if(pos == trough1) {
+		tks->value -= s * tks->bigi;
+	} else {
+		/* trough2 */
+		tks->value += s * tks->bigi;
+	}
+	s = !tkscalecheckvalue(tk);
+	if (end != nil)
+		*end = s;
+	e = nil;
+	if(tks->command != nil) {
+		/* XXX perhaps should only send command if value has actually changed */
+		tkfprint(f, tks->value);
+		snprint(buf, sizeof(buf), "%s %s", tks->command, f);
+		e = tkexec(tk->env->top, buf, nil);
+	}
+	return e;
+}
+
+static void
+screpeat(Tk *tk, void *v, int cancelled)
+{
+	char *e, *pos;
+	int repeat;
+	TkScale *tks = TKobj(TkScale, tk);
+
+	pos = v;
+	if (cancelled) {
+		tks->flag &= ~Autorepeat;
+		return;
+	}
+	e = stepscale(tk, pos, &repeat);
+	if(e != nil || !repeat) {
+		tks->flag &= ~Autorepeat;
+		tkcancelrepeat(tk);
+	}
+	tk->dirty = tkrect(tk, 1);
+	tkupdate(tk->env->top);
+}
+
+static char*
+tkscalebut1p(Tk *tk, char *arg, char **val)
+{
+	int z[2];
+	char *v, *e;
+	TkScale *tks = TKobj(TkScale, tk);
+	int repeat;
+
+	USED(val);
+	v = tkscaleposn(tk->env, tk, arg, z);
+	if(v == nil)
+		return TkBadvl;
+
+	e = nil;
+	if(v[0] == '\0' || z[0] < tks->center-tks->sw || z[0] > tks->center+tks->sw)
+		return nil;
+	if(v == slider) {
+		tks->flag |= Dragging;
+		tks->relief = TKsunken;
+		tks->pix = z[1];
+		tks->base = tks->value;
+		tkscalecheckvalue(tk);
+	} else  {
+		e = stepscale(tk, v, &repeat);
+		if (e == nil && repeat) {
+			tks->flag |= Autorepeat;
+			tkrepeat(tk, screpeat, v, TkRptpause, TkRptinterval);
+		}
+	}
+
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static char*
+tkscalebut1r(Tk *tk, char *arg, char **val)
+{
+	TkScale *tks = TKobj(TkScale, tk);
+	char *e, buf[Tkmaxitem], f[32];
+	USED(val);
+	USED(arg);
+	if(tks->flag & Autorepeat) {
+		tkcancelrepeat(tk);
+		tks->flag &= ~Autorepeat;
+	}
+	e = nil;
+	if (tks->flag & Dragging) {
+		if (tks->command != nil && tks->jump == BoolT && (tks->flag & Dragging)) {
+			tkfprint(f, tks->value);
+			snprint(buf, sizeof(buf), "%s %s", tks->command, f);
+			e = tkexec(tk->env->top, buf, nil);
+		}
+		tks->relief = TKraised;
+		tks->flag &= ~Dragging;
+		tk->dirty = tkrect(tk, 1);
+	}
+	return e;
+}
+
+static char*
+tkscalekey(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	int key;
+	char *pos = nil;
+	USED(arg);
+	USED(val);
+
+	if(tk->flag & Tkdisabled)
+		return nil;
+
+	key = strtol(arg, nil, 0);
+	if (key == Up || key == Left)
+		pos = trough1;
+	else if (key == Down || key == Right)
+		pos = trough2;
+	if (pos != nil) {
+		e = stepscale(tk, pos, nil);
+		tk->dirty = tkrect(tk, 1);
+		return e;
+	}
+	return nil;
+}
+
+TkCmdtab tkscalecmd[] =
+{
+	"cget",			tkscalecget,
+	"configure",		tkscaleconf,
+	"set",			tkscaleset,
+	"identify",		tkscaleident,
+	"get",			tkscaleget,
+	"coords",		tkscalecoords,
+	"tkScaleMotion",	tkscalemotion,
+	"tkScaleDrag",		tkscaledrag,
+	"tkScaleBut1P",		tkscalebut1p,
+	"tkScaleBut1R",		tkscalebut1r,
+	"tkScaleKey",		tkscalekey,
+	nil
+};
+
+TkMethod scalemethod = {
+	"scale",
+	tkscalecmd,
+	tkfreescale,
+	tkdrawscale
+};
--- /dev/null
+++ b/libtk/scrol.c
@@ -1,0 +1,735 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+	Triangle	= 10,	/* Height of scroll bar triangle */
+	Elembw	= 1,		/* border around elements (triangles etc.) */
+	Scrollbw	= 1,		/* bevel border on scrollbar */
+	Tribw=	1,	/* shadow border on triangle */
+};
+
+typedef struct TkScroll TkScroll;
+struct TkScroll
+{
+	int		activer;
+	int		orient;		/* Horitontal or Vertical */
+	int		dragpix;	/* Scroll delta in button drag */
+	int		dragtop;
+	int		dragbot;
+	int		jump;		/* Jump scroll enable */
+	int		flag;		/* Display flags */
+	int		top;		/* Top fraction */
+	int		bot;		/* Bottom fraction */
+	int		a1;		/* Pixel top/left arrow1 */
+	int		t1;		/* Pixel top/left trough */
+	int		t2;		/* Pixel top/left lower trough */
+	int		a2;		/* Pixel top/left arrow2 */
+	char*		cmd;
+};
+
+enum {
+	ActiveA1	= (1<<0),	/* Scrollbar control */
+	ActiveA2	= (1<<1),
+	ActiveB1	= (1<<2),
+	ButtonA1	= (1<<3),
+	ButtonA2	= (1<<4),
+	ButtonB1	= (1<<5),
+	Autorepeat = (1<<6)
+};
+
+static
+TkOption opts[] =
+{
+	"activerelief",	OPTstab,	O(TkScroll, activer),	tkrelief,
+	"command",	OPTtext,	O(TkScroll, cmd),	nil,
+	"jump",	OPTstab,	O(TkScroll, jump),	tkbool,
+	"orient",	OPTstab,	O(TkScroll, orient),	tkorient,
+	nil
+};
+
+static
+TkEbind b[] = 
+{
+	{TkLeave,		"%W activate {}"},
+	{TkEnter,		"%W activate [%W identify %x %y]"},
+	{TkMotion,		"%W activate [%W identify %x %y]"},
+	{TkButton1P|TkMotion,	"%W tkScrollDrag %x %y"},
+	{TkButton1P,		"%W tkScrolBut1P %x %y"},
+	{TkButton1P|TkDouble,	"%W tkScrolBut1P %x %y"},
+	{TkButton1R,	"%W tkScrolBut1R; %W activate [%W identify %x %y]"},
+	{TkButton2P,		"%W tkScrolBut2P [%W fraction %x %y]"},
+};
+
+static char*
+tkinitscroll(Tk *tk)
+{
+	int gap;
+	TkScroll *tks;
+
+	tks = TKobj(TkScroll, tk);
+	
+	gap = 2*tk->borderwidth;
+	if(tks->orient == Tkvertical) {
+		if(tk->req.width == 0)
+			tk->req.width = Triangle + gap;
+		if(tk->req.height == 0)	
+			tk->req.height = 2*Triangle + gap + 6*Elembw;
+	}
+	else {
+		if(tk->req.width == 0)
+			tk->req.width = 2*Triangle + gap + 6*Elembw;
+		if(tk->req.height == 0)	
+			tk->req.height = Triangle + gap;
+	}
+
+
+	return tkbindings(tk->env->top, tk, b, nelem(b));
+}
+
+char*
+tkscrollbar(TkTop *t, char *arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkName *names;
+	TkScroll *tks;
+	TkOptab tko[3];
+
+	tk = tknewobj(t, TKscrollbar, sizeof(Tk)+sizeof(TkScroll));
+	if(tk == nil)
+		return TkNomem;
+
+	tks = TKobj(TkScroll, tk);
+
+	tk->relief = TKflat;
+	tk->borderwidth = 1;
+	tks->activer = TKraised;
+	tks->orient = Tkvertical;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tks;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+
+	e = tkinitscroll(tk);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil) {
+		tkfreeobj(tk);
+		return e;
+	}
+	tk->name->link = nil;
+
+	return tkvalue(ret, "%s", tk->name->name);
+}
+
+static char*
+tkscrollcget(Tk *tk, char *arg, char **val)
+{
+	TkOptab tko[3];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tks;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+void
+tkfreescrlb(Tk *tk)
+{
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	if(tks->cmd != nil)
+		free(tks->cmd);
+}
+
+static void
+drawarrow(TkScroll *tks, Image *i, Point p[3], TkEnv *e, int activef, int buttonf)
+{
+	Image *l, *d, *t;
+	int bgnd;
+
+	bgnd = TkCbackgnd;
+	if(tks->flag & (activef|buttonf)) {
+		bgnd = TkCactivebgnd;
+		fillpoly(i, p, 3, ~0, tkgc(e, bgnd), p[0]);
+	}
+
+	l = tkgc(e, bgnd+TkLightshade);
+	d = tkgc(e, bgnd+TkDarkshade);
+	if(tks->flag & buttonf) {
+		t = d;
+		d = l;
+		l = t;
+	}
+	line(i, p[1], p[2], 0, 0, Tribw-1, d, p[1]);
+	line(i, p[2], p[0], 0, 0, Tribw-1, d, p[2]);
+	line(i, p[0], p[1], 0, 0, Tribw-1, l, p[0]);
+}
+
+static void
+drawslider(TkScroll *tks, Image *i, Point o, int w, int h, TkEnv *e)
+{
+	Image *l, *d;
+	Rectangle r;
+	int bgnd;
+
+	bgnd = TkCbackgnd;
+	if(tks->flag & (ActiveB1|ButtonB1)) {
+		r.min = o;
+		r.max.x = o.x + w + Elembw*2;
+		r.max.y = o.y + h + Elembw*2;
+		bgnd = TkCactivebgnd;
+		draw(i, r, tkgc(e, bgnd), nil, ZP);
+	}
+
+	l = tkgc(e, bgnd+TkLightshade);
+	d = tkgc(e, bgnd+TkDarkshade);
+	if(tks->flag & ButtonB1)
+		tkbevel(i, o, w, h, Scrollbw, d, l);
+	else
+		tkbevel(i, o, w, h, Scrollbw, l, d);
+}
+
+static void
+tkvscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
+{
+	TkEnv *e;
+	Point p[3], o;
+	int bo, w, h, triangle;
+
+	e = tk->env;
+
+	triangle = tk->act.width - Elembw;
+
+	bo = tk->borderwidth + Elembw;
+	p[0].x = size.x/2;
+	p[0].y = bo;
+	p[1].x = p[0].x - triangle/2;
+	p[1].y = p[0].y + triangle;
+	p[2].x = p[0].x + triangle/2;
+	p[2].y = p[0].y + triangle;
+	drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
+
+	tks->a1 = p[2].y;
+	h = p[2].y + Elembw;
+
+	p[0].y = size.y - bo - 1;
+	p[1].y = p[0].y - triangle;
+	p[2].y = p[0].y - triangle;
+	drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
+
+	tks->a2 = p[2].y;
+
+	o.x = tk->borderwidth ;
+	o.y = bo + triangle + 2*Elembw;
+	w = size.x - 2*bo;
+	h = p[2].y - 2*Elembw - h - 2*tk->borderwidth;
+
+	o.y += TKF2I(tks->top*h);
+	h *= tks->bot - tks->top;
+	h = TKF2I(h);
+
+	tks->t1 = o.y - Elembw;
+	tks->t2 = o.y + h + Elembw;
+
+	drawslider(tks, i, o, w, h, e);
+}
+
+static void
+tkhscroll(Tk *tk, TkScroll *tks, Image *i, Point size)
+{
+	TkEnv *e;
+	Point p[3], o;
+	int bo, w, h, triangle;
+
+	e = tk->env;
+
+	triangle = tk->act.height - Elembw;
+
+	bo = tk->borderwidth + Elembw;
+	p[0].x = bo;
+	p[0].y = size.y/2;
+	p[1].x = p[0].x + triangle;
+	p[1].y = p[0].y - triangle/2 + 1;
+	p[2].x = p[0].x + triangle;
+	p[2].y = p[0].y + triangle/2 - 2;
+	drawarrow(tks, i, p, e, ActiveA1, ButtonA1);
+
+	tks->a1 = p[2].x;
+	w = p[2].x + Elembw;
+
+	p[0].x = size.x - bo - 1;
+	p[1].x = p[0].x - triangle;
+	p[2].x = p[0].x - triangle;
+	drawarrow(tks, i, p, e, ActiveA2, ButtonA2);
+
+	tks->a2 = p[2].x;
+
+	o.x = bo + triangle + 2*Elembw;
+	o.y = tk->borderwidth;
+	w = p[2].x - 2*Elembw - w - 2*tk->borderwidth;
+	h = size.y - 2*bo;
+
+	o.x += TKF2I(tks->top*w);
+	w *= tks->bot - tks->top;
+	w = TKF2I(w);
+
+	tks->t1 = o.x - Elembw;
+	tks->t2 = o.x + w + Elembw;
+
+	drawslider(tks, i, o, w, h, e);
+}
+
+char*
+tkdrawscrlb(Tk *tk, Point orig)
+{
+	Point p;
+	TkEnv *e;
+	Rectangle r;
+	Image *i, *dst;
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	e = tk->env;
+
+	dst = tkimageof(tk);
+	if(dst == nil)
+		return nil;
+
+	r.min = ZP;
+	r.max.x = tk->act.width + 2*tk->borderwidth;
+	r.max.y = tk->act.height + 2*tk->borderwidth;
+
+	i = tkitmp(e, r.max, TkCbackgnd);
+	if(i == nil)
+		return nil;
+
+	if(tks->orient == Tkvertical)
+		tkvscroll(tk, tks, i, r.max);
+	else
+		tkhscroll(tk, tks, i, r.max);
+
+	tkdrawrelief(i, tk, ZP, TkCbackgnd, tk->relief);
+
+	p.x = tk->act.x + orig.x;
+	p.y = tk->act.y + orig.y;
+	r = rectaddpt(r, p);
+	draw(dst, r, i, nil, ZP);
+
+	return nil;
+}
+
+/* Widget Commands (+ means implemented)	
+	+activate
+	+cget
+	+configure
+	+delta
+	+fraction
+	+get
+	+identify
+	+set
+*/
+
+static char*
+tkscrollconf(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkOptab tko[3];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tks;
+	tko[1].optab = opts;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	tkgeomchg(tk, &g, bd);
+
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+static char*
+tkscrollactivate(Tk *tk, char *arg, char **val)
+{
+	int s, gotarg;
+	char buf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	USED(val);
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), &gotarg);
+	s = tks->flag;
+	if (!gotarg) {
+		char *a;
+		if (s & ActiveA1)
+			a = "arrow1";
+		else if (s & ActiveA2)
+			a = "arrow2";
+		else if (s & ActiveB1)
+			a = "slider";
+		else
+			a = "";
+		return tkvalue(val, a);
+	}
+	tks->flag &= ~(ActiveA1 | ActiveA2 | ActiveB1);
+	if(strcmp(buf, "arrow1") == 0)
+		tks->flag |= ActiveA1;
+	else
+	if(strcmp(buf, "arrow2") == 0)
+		tks->flag |= ActiveA2;
+	else
+	if(strcmp(buf, "slider") == 0)
+		tks->flag |= ActiveB1;
+
+	if(s ^ tks->flag)
+		tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static char*
+tkscrollset(Tk *tk, char *arg, char **val)
+{
+	TkTop *t;
+	char *e;
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	USED(val);
+	t = tk->env->top;
+	e = tkfracword(t, &arg, &tks->top, nil);
+	if (e != nil)
+		return e;
+	e = tkfracword(t, &arg, &tks->bot, nil);
+	if (e != nil)
+		return e;
+	if(tks->top < 0)
+		tks->top = 0;
+	if(tks->top > TKI2F(1))
+		tks->top = TKI2F(1);
+	if(tks->bot < 0)
+		tks->bot = 0;
+	if(tks->bot > TKI2F(1))
+		tks->bot = TKI2F(1);
+
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+static char*
+tkscrolldelta(Tk *tk, char *arg, char **val)
+{
+	int l, delta;
+	char buf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	arg = tkitem(buf, arg);
+	if(tks->orient == Tkvertical)
+		tkitem(buf, arg);
+	if(*arg == '\0' || *buf == '\0')
+		return TkBadvl;
+
+	l = tks->a2-tks->a1-4*Elembw;
+	delta = TKI2F(1);
+	if(l != 0)
+		delta = TKI2F(atoi(buf)) / l;
+	tkfprint(buf, delta);
+
+	return tkvalue(val, "%s", buf);	
+}
+
+static char*
+tkscrollget(Tk *tk, char *arg, char **val)
+{
+	char *v, buf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	USED(arg);
+	v = tkfprint(buf, tks->top);
+	*v++ = ' ';
+	tkfprint(v, tks->bot);
+
+	return tkvalue(val, "%s", buf);	
+}
+
+static char*
+tkscrollidentify(Tk *tk, char *arg, char **val)
+{
+	int gotarg;
+	TkTop *t;
+	char *v, buf[Tkmaxitem];
+	Point p;
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	t = tk->env->top;
+	arg = tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
+	if (!gotarg)
+		return TkBadvl;
+	p.x = atoi(buf);
+	tkword(t, arg, buf, buf+sizeof(buf), &gotarg);
+	if (!gotarg)
+		return TkBadvl;
+	p.y = atoi(buf);
+	if (!ptinrect(p, tkrect(tk, 0)))
+		return nil;
+	if (tks->orient == Tkvertical)
+		p.x = p.y;
+	p.x += tk->borderwidth;
+
+	v = "";
+	if(p.x <= tks->a1)
+		v = "arrow1";
+	if(p.x > tks->a1 && p.x <= tks->t1)
+		v = "trough1";
+	if(p.x > tks->t1 && p.x < tks->t2)
+		v = "slider";
+	if(p.x >= tks->t2 && p.x < tks->a2)
+		v = "trough2";
+	if(p.x >= tks->a2)
+		v = "arrow2";
+	return tkvalue(val, "%s", v);
+}
+
+static char*
+tkscrollfraction(Tk *tk, char *arg, char **val)
+{
+	int len, frac, pos;
+	char buf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	arg = tkitem(buf, arg);
+	if(tks->orient == Tkvertical)
+		tkitem(buf, arg);
+	if(*arg == '\0' || *buf == '\0')
+		return TkBadvl;
+
+	pos = atoi(buf);
+	if(pos < tks->a1)
+		pos = tks->a1;
+	if(pos > tks->a2)
+		pos = tks->a2;
+	len = tks->a2 - tks->a1 - 4*Elembw;
+	frac = TKI2F(1);
+	if(len != 0)
+		frac = TKI2F(pos-tks->a1)/len;
+	tkfprint(buf, frac);
+	return tkvalue(val, "%s", buf);
+}
+
+static char*
+tkScrolBut1R(Tk *tk, char *arg, char **val)
+{
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	USED(val);
+	USED(arg);
+	tkcancelrepeat(tk);
+	tks->flag &= ~(ActiveA1|ActiveA2|ActiveB1|ButtonA1|ButtonA2|ButtonB1|Autorepeat);
+	tk->dirty = tkrect(tk, 1);
+	return nil;
+}
+
+/* tkScrolBut2P fraction */
+static char*
+tkScrolBut2P(Tk *tk, char *arg, char **val)
+{
+	TkTop *t;
+	char *e, buf[Tkmaxitem], fracbuf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+	
+
+	USED(val);
+	t = tk->env->top;
+
+	if(arg[0] == '\0')
+		return TkBadvl;
+
+	tkword(t, arg, fracbuf, fracbuf+sizeof(fracbuf), nil);
+
+	e = nil;
+	if(tks->cmd != nil) {
+		snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, fracbuf);
+		e = tkexec(t, buf, nil);
+	}
+	return e;
+}
+
+static void
+sbrepeat(Tk *tk, void *v, int cancelled)
+{
+	char *e, buf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+	char *fmt = (char *)v;
+
+	if (cancelled) {
+		tks->flag &= ~Autorepeat;
+		return;
+	}
+		
+	if(tks->cmd != nil && fmt != nil) {
+		snprint(buf, sizeof(buf), fmt, tks->cmd);
+		e = tkexec(tk->env->top, buf, nil);
+		if (e != nil) {
+			tks->flag &= ~Autorepeat;
+			tkcancelrepeat(tk);
+		} else
+			tkupdate(tk->env->top);
+	}
+}
+
+/* tkScrolBut1P %x %y */
+static char*
+tkScrolBut1P(Tk *tk, char *arg, char **val)
+{
+	int pix;
+	TkTop *t;
+	char *e, *fmt, buf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	USED(val);
+	t = tk->env->top;
+
+	if (tks->flag & Autorepeat)
+		return nil;
+	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+	if(tks->orient == Tkvertical)
+		tkword(t, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+
+	pix = atoi(buf);
+	
+	tks->dragpix = pix;
+	tks->dragtop = tks->top;
+	tks->dragbot = tks->bot;
+
+	pix += tk->borderwidth;
+
+	fmt = nil;
+	e = nil;
+	if(pix <= tks->a1) {
+		fmt = "%s scroll -1 unit";
+		tks->flag |= ButtonA1;
+	}
+	if(pix > tks->a1 && pix <= tks->t1)
+		fmt = "%s scroll -1 page";
+	if(pix > tks->t1 && pix < tks->t2)
+		tks->flag |= ButtonB1;
+	if(pix >= tks->t2 && pix < tks->a2)
+		fmt = "%s scroll 1 page";
+	if(pix >= tks->a2) {
+		fmt = "%s scroll 1 unit";
+		tks->flag |= ButtonA2;
+	}
+	if(tks->cmd != nil && fmt != nil) {
+		snprint(buf, sizeof(buf), fmt, tks->cmd);
+		e = tkexec(t, buf, nil);
+		tks->flag |= Autorepeat;
+		tkrepeat(tk, sbrepeat, fmt, TkRptpause, TkRptinterval);
+	}
+	tk->dirty = tkrect(tk, 1);
+	return e;
+}
+
+/* tkScrolDrag %x %y */
+static char*
+tkScrollDrag(Tk *tk, char *arg, char **val)
+{
+	TkTop *t;
+	int pix, delta;
+	char frac[32], buf[Tkmaxitem];
+	TkScroll *tks = TKobj(TkScroll, tk);
+
+	USED(val);
+	t = tk->env->top;
+
+	if (tks->flag & Autorepeat)
+		return nil;
+	if((tks->flag & ButtonB1) == 0)
+		return nil;
+
+	arg = tkword(t, arg, buf, buf+sizeof(buf), nil);
+	if(tks->orient == Tkvertical)
+		tkword(t, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '\0')
+		return TkBadvl;
+
+	pix = atoi(buf);
+
+	delta = TKI2F(pix-tks->dragpix);
+	if ( tks->a2 == tks->a1 )
+		return TkBadvl;
+	delta = delta/(tks->a2-tks->a1-4*Elembw);
+	if(tks->jump == BoolT) {
+		if(tks->dragtop+delta >= 0 &&
+		   tks->dragbot+delta <= TKI2F(1)) {
+			tks->top = tks->dragtop+delta;
+			tks->bot = tks->dragbot+delta;
+		}
+		return nil;
+	}
+	if(tks->cmd != nil) {
+		delta += tks->dragtop;
+		if(delta < 0)
+			delta = 0;
+		if(delta > TKI2F(1))
+			delta = TKI2F(1);
+		tkfprint(frac, delta);
+		snprint(buf, sizeof(buf), "%s moveto %s", tks->cmd, frac);
+		return tkexec(t, buf, nil);
+	}
+	return nil;
+}
+
+TkCmdtab tkscrlbcmd[] =
+{
+	"activate",		tkscrollactivate,
+	"cget",			tkscrollcget,
+	"configure",		tkscrollconf,
+	"delta",		tkscrolldelta,
+	"fraction",		tkscrollfraction,
+	"get",			tkscrollget,
+	"identify",		tkscrollidentify,
+	"set",			tkscrollset,
+	"tkScrollDrag",		tkScrollDrag,
+	"tkScrolBut1P",		tkScrolBut1P,
+	"tkScrolBut1R",		tkScrolBut1R,
+	"tkScrolBut2P",		tkScrolBut2P,
+	nil
+};
+
+TkMethod scrollbarmethod = {
+	"scrollbar",
+	tkscrlbcmd,
+	tkfreescrlb,
+	tkdrawscrlb
+};
--- /dev/null
+++ b/libtk/textu.c
@@ -1,0 +1,1077 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+/* debugging */
+int tktdbg;
+extern void tktprinttext(TkText*);
+extern void tktprintindex(TkTindex*);
+extern void tktprintitem(TkTitem*);
+extern void tktprintline(TkTline*);
+extern void tktcheck(TkText*, char*);
+int tktutfpos(char*, int);
+
+char*
+tktnewitem(int kind, int tagextra,TkTitem **ret)
+{
+	int n;
+	TkTitem *i;
+
+	n = sizeof(TkTitem) + tagextra * sizeof(ulong);
+	i = malloc(n);
+	if(i == nil)
+		return TkNomem;
+
+	memset(i, 0, n);
+	i->kind = kind;
+	i->tagextra = tagextra;
+	*ret = i;
+	return nil;
+}
+
+char*
+tktnewline(int flags, TkTitem *items, TkTline *prev, TkTline *next, TkTline **ret)
+{
+	TkTline *l;
+	TkTitem *i;
+
+	l = malloc(sizeof(TkTline));
+	if(l == nil)
+		return TkNomem;
+
+	memset(l, 0, sizeof(TkTline));
+	l->flags = flags;
+	l->items = items;
+	l->prev = prev;
+	l->next = next;
+	next->prev = l;
+	prev->next = l;
+
+	for(i = items; i->next != nil;)
+		i = i->next;
+	if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline))
+		print("text:tktnewline botch\n");
+	i->iline = l;
+
+	*ret = l;
+	return nil;
+}
+
+/*
+ * free items; freewins is 0 when the subwindows will be
+ * freed anyway as the main text widget is being destroyed.
+ */
+void
+tktfreeitems(TkText *tkt, TkTitem *i, int freewins)
+{
+	TkTitem *n;
+	Tk *tk;
+
+	while(i != nil) {
+		n = i->next;
+		if(tkt->mouse == i)
+			tkt->mouse = nil;
+		switch(i->kind) {
+		case TkTascii:
+		case TkTrune:
+			if(i->istring != nil)
+				free(i->istring);
+			break;
+		case TkTwin:
+			if (i->iwin != nil) {
+				tk = i->iwin->sub;
+				if (tk != nil) {
+					tk->geom = nil;
+					tk->destroyed = nil;
+					if (i->iwin->owned && freewins) {
+						if (tk->name != nil)
+							tkdestroy(tk->env->top, tk->name->name, nil);
+					} else {
+						tk->parent = nil;
+						tk->geom = nil;
+						tk->destroyed = nil;
+					}
+				}
+				if(i->iwin->create != nil)
+					free(i->iwin->create);
+				free(i->iwin);
+			}
+			break;
+		case TkTmark:
+			break;
+		}
+		free(i);
+		i = n;
+	}
+}
+
+void
+tktfreelines(TkText *tkt, TkTline *l, int freewins)
+{
+	TkTline *n;
+
+	while(l != nil) {
+		n = l->next;
+		tktfreeitems(tkt, l->items, freewins);
+		free(l);
+		l = n;
+	}
+}
+
+void
+tktfreetabs(TkTtabstop *t)
+{
+	TkTtabstop *n;
+
+	while(t != nil) {
+		n = t->next;
+		free(t);
+		t = n;
+	}
+}
+
+void
+tkfreetext(Tk *tk)
+{
+	TkText *tkt = TKobj(TkText, tk);
+
+	if(tkt->start.next != nil && tkt->start.next != &(tkt->end)) {
+		tkt->end.prev->next = nil;
+		tktfreelines(tkt, tkt->start.next, 0);
+	}
+	tktfreeitems(tkt, tkt->start.items, 0);
+	tktfreeitems(tkt, tkt->end.items, 0);
+	tktfreetabs(tkt->tabs);
+	if(tkt->tagshare == nil)
+		tktfreetags(tkt->tags);
+	else
+		tk->binds = nil;
+	tktfreemarks(tkt->marks);
+	if(tkt->xscroll != nil)
+		free(tkt->xscroll);
+	if(tkt->yscroll != nil)
+		free(tkt->yscroll);
+	/* don't free image because it belongs to window */
+}
+
+/*
+ * Remove the item at ix, joining previous and next items.
+ * If item is at end of line, remove next line and join
+ * its items to this one (except at end).
+ * On return, ix is adjusted to point to the next item.
+ */
+void
+tktremitem(TkText *tkt, TkTindex *ix)
+{
+	TkTline *l, *lnext;
+	TkTindex prev, nx;
+	TkTitem *i, *ilast;
+
+	l = ix->line;
+	i = ix->item;
+
+	if(i->next == nil) {
+		if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline)) {
+			print("tktremitem: botch 1\n");
+			return;
+		}
+		lnext = l->next;
+		if(lnext == &tkt->end)
+			/* not supposed to remove final newline */
+			return;
+		if(i->kind == TkTnewline)
+			tkt->nlines--;
+		ilast = tktlastitem(lnext->items);
+		ilast->iline = l;
+		i->next = lnext->items;
+		l->flags = (l->flags & ~TkTlast) | (lnext->flags & TkTlast);
+		l->next = lnext->next;
+		lnext->next->prev = l;
+		free(lnext);
+	}
+	if(l->items == i)
+		l->items = i->next;
+	else {
+		prev = *ix;
+		if(!tktadjustind(tkt, TkTbyitemback, &prev) && tktdbg) {
+			print("tktremitem: botch 2\n");
+			return;
+		}
+		prev.item->next = i->next;
+	}
+	ix->item = i->next;
+	ix->pos = 0;
+	i->next = nil;
+	nx = *ix;
+	tktadjustind(tkt, TkTbycharstart, &nx);
+
+	/* check against cached items */
+	if(tkt->selfirst == i)
+		tkt->selfirst = nx.item;
+	if(tkt->sellast == i)
+		tkt->sellast = nx.item;
+	if(tkt->selfirst == tkt->sellast) {
+		tkt->selfirst = nil;
+		tkt->sellast = nil;
+	}
+
+	tktfreeitems(tkt, i, 1);
+}
+
+int
+tktdispwidth(Tk *tk, TkTtabstop *tb, TkTitem *i, Font *f, int x, int pos, int nchars)
+{
+	int w, del, locked;
+	TkTtabstop *tbprev;
+	Display *d;
+	TkText *tkt;
+	TkEnv env;
+
+	tkt = TKobj(TkText, tk);
+	d = tk->env->top->display;
+	if (tb == nil)
+		tb = tkt->tabs;
+
+	switch(i->kind) {
+	case TkTrune:
+		pos = tktutfpos(i->istring, pos);
+		/* FALLTHRU */
+	case TkTascii:
+		if(f == nil) {
+			if(!tktanytags(i))
+				f = tk->env->font;
+			else {
+				tkttagopts(tk, i, nil, &env, nil, 1);
+				f = env.font;
+			}
+		}
+		locked = 0;
+		if(!(tkt->tflag&TkTdlocked))
+			locked = lockdisplay(d);
+		if(nchars >= 0)
+			w = stringnwidth(f, i->istring+pos, nchars);
+		else
+			w = stringwidth(f, i->istring+pos);
+		if(locked)
+			unlockdisplay(d);
+		break;
+	case TkTtab:
+		if(tb == nil)
+			w = 0;
+		else {
+			tbprev = nil;
+			while(tb->pos <= x && tb->next != nil) {
+					tbprev = tb;
+					tb = tb->next;
+				}
+			w = tb->pos - x;
+			if(w <= 0) {
+				del = tb->pos;
+				if(tbprev != nil)
+					del -= tbprev->pos;
+				while(w <= 0)
+					w += del;
+			}
+			/* todo: other kinds of justification */
+		}
+		break;
+	case TkTwin:
+		if(i->iwin->sub == 0)
+			w = 0;
+		else
+			w = i->iwin->sub->act.width + 2*i->iwin->padx + 2*i->iwin->sub->borderwidth;
+		break;
+	default:
+		w = 0;
+	}
+	return w;
+}
+
+int
+tktindrune(TkTindex *ix)
+{
+	int ans;
+	Rune r;
+
+	switch(ix->item->kind) {
+		case TkTascii:
+			ans = ix->item->istring[ix->pos];
+			break;
+		case TkTrune:
+			chartorune(&r, ix->item->istring + tktutfpos(ix->item->istring, ix->pos));
+			ans = r;
+			break;
+		case TkTtab:
+			ans = '\t';
+			break;
+		case TkTnewline:
+			ans = '\n';
+			break;
+		default:
+			/* only care that it isn't a word char */
+			ans = 0x80;
+	}
+	return ans;
+}
+
+TkTitem*
+tktlastitem(TkTitem *i)
+{
+	while(i->next != nil)
+		i = i->next;
+	if(tktdbg && !(i->kind == TkTnewline || i->kind == TkTcontline))
+		print("text:tktlastitem botch\n");
+
+	return i;
+}
+
+TkTline*
+tktitemline(TkTitem *i)
+{
+	i = tktlastitem(i);
+	return i->iline;
+}
+
+int
+tktlinenum(TkText *tkt, TkTindex *p)
+{
+	int n;
+	TkTline *l;
+
+	if(p->line->orig.y <= tkt->end.orig.y / 2) {
+		/* line seems closer to beginning */
+		n = 1;
+		for(l = tkt->start.next; l != p->line; l = l->next) {
+			if(tktdbg && l->next == nil) {
+				print("text: tktlinenum botch\n");
+				break;
+			}
+			if(l->flags & TkTlast)
+				n++;
+		}
+	}
+	else {
+		n = tkt->nlines;
+		for(l = tkt->end.prev; l != p->line; l = l->prev) {
+			if(tktdbg && l->prev == nil) {
+				print("text: tktlinenum botch\n");
+				break;
+			}
+			if(l->flags & TkTfirst)
+				n--;
+		}
+	}
+	return n;
+}
+
+int
+tktlinepos(TkText *tkt, TkTindex *p)
+{
+	int n;
+	TkTindex ix;
+	TkTitem *i;
+
+	n = 0;
+	ix = *p;
+	i = ix.item;
+	tktadjustind(tkt, TkTbylinestart, &ix);
+	while(ix.item != i) {
+		if(tktdbg && ix.item->next == nil && (ix.line->flags&TkTlast)) {
+			print("text: tktlinepos botch\n");
+			break;
+		}
+		n += tktposcount(ix.item);
+		if(!tktadjustind(tkt, TkTbyitem, &ix)) {
+			if(tktdbg)
+				print("tktlinepos botch\n");
+			break;
+		}
+	}
+	return (n+p->pos);
+}
+
+int
+tktposcount(TkTitem *i)
+{
+	int n;
+
+	if(i->kind == TkTascii)
+		n = strlen(i->istring);
+	else
+	if(i->kind == TkTrune)
+		n = utflen(i->istring);
+	else
+	if(i->kind == TkTmark || i->kind == TkTcontline)
+		n = 0;
+	else
+		n = 1;
+	return n;
+}
+
+/*
+ * Insert item i before position ins.
+ * If i is a newline or a contline, make a new line to contain the items up to
+ * and including the new newline, and make the original line
+ * contain the items from ins on.
+ * Adjust ins so that it points just after inserted item.
+ */
+char*
+tktiteminsert(TkText *tkt, TkTindex *ins, TkTitem *i)
+{
+	int hasprev, flags;
+	char *e;
+	TkTindex prev;
+	TkTline *l;
+	TkTitem *items;
+
+	prev = *ins;
+	hasprev = tktadjustind(tkt, TkTbyitemback, &prev);
+
+	if(i->kind == TkTnewline || i->kind == TkTcontline) {
+		i->next = nil;
+		if(hasprev && prev.line == ins->line) {
+			items = ins->line->items;
+			prev.item->next = i;
+		}
+		else
+			items = i;
+
+		flags = ins->line->flags&TkTfirst;
+		if(i->kind == TkTnewline)
+			flags |= TkTlast;
+		e = tktnewline(flags, items, ins->line->prev, ins->line, &l);
+		if(e != nil) {
+			if(hasprev && prev.line == ins->line)
+				prev.item->next = ins->item;
+			return e;
+		}
+
+		if(i->kind == TkTnewline)
+			ins->line->flags |= TkTfirst;
+
+		if(i->kind == TkTcontline)
+			ins->line->flags &= ~TkTfirst;
+		ins->line->items = ins->item;
+		ins->pos = 0;
+	}
+	else {
+		if(hasprev && prev.line == ins->line)
+			prev.item->next = i;
+		else
+			ins->line->items = i;
+		i->next = ins->item;
+	}
+
+	return nil;
+}
+
+/*
+ * If index p doesn't point at the beginning of an item,
+ * split the item at p.  Adjust p to point to the beginning of
+ * the item after the split (same character it used to point at).
+ * If there is a split, the old item gets the characters before
+ * the split, and a new item gets the characters after it.
+ */
+char*
+tktsplititem(TkTindex *p)
+{
+	int l1, l2;
+	char *s1, *s2, *e;
+	TkTitem *i, *i2;
+
+	i = p->item;
+
+	if(p->pos != 0) {
+		/*
+		 * Must be TkTascii or TkTrune
+		 *
+		 * Make new item i2, to be inserted after i,
+		 * with portion of string from p->pos on
+		 */
+
+		if (i->kind == TkTascii)
+			l1 = p->pos;
+		else
+			l1 = tktutfpos(i->istring, p->pos);
+		l2 = strlen(i->istring) - l1;
+		if (l2 == 0)
+			print("tktsplititem botch\n");
+		s1 = malloc(l1+1);
+		if(s1 == nil)
+			return TkNomem;
+		s2 = malloc(l2+1);
+		if(s2 == nil) {
+			free(s1);
+			return TkNomem;
+		}
+
+		memmove(s1, i->istring, l1);
+		s1[l1] = '\0';
+		memmove(s2, i->istring + l1, l2);
+		s2[l2] = '\0';
+
+		e = tktnewitem(i->kind, i->tagextra, &i2);
+		if(e != nil) {
+			free(s1);
+			free(s2);
+			return e;
+		}
+
+		free(i->istring);
+
+		tkttagcomb(i2, i, 1);
+		i2->next = i->next;
+		i->next = i2;
+		i->istring = s1;
+		i2->istring = s2;
+
+		p->item = i2;
+		p->pos = 0;
+	}
+
+	return nil;
+}
+
+int
+tktmaxwid(TkTline *l)
+{
+	int w, maxw;
+
+	maxw = 0;
+	while(l != nil) {
+		w = l->width;
+		if(w > maxw)
+			maxw = w;
+		l = l->next;
+	}
+	return maxw;
+}
+
+Rectangle
+tktbbox(Tk *tk, TkTindex *ix)
+{
+	Rectangle r;
+	int d, w;
+	TkTitem *i;
+	TkTline *l;
+	TkEnv env;
+	TkTtabstop *tb = nil;
+	Tk *sub;
+	TkText *tkt = TKobj(TkText, tk);
+ 	int opts[TkTnumopts];
+
+	l = ix->line;
+
+	/* r in V space */
+	r.min = subpt(l->orig, tkt->deltatv);
+	r.min.y += l->ascent;
+	r.max = r.min;
+
+	/* tabs dependon tags of first non-mark on display line */
+	for(i = l->items; i->kind == TkTmark; )
+		i = i->next;
+	tkttagopts(tk, i, opts, &env, &tb, 1);
+
+	for(i = l->items; i != nil; i = i->next) {
+		if(i == ix->item) {
+			tkttagopts(tk, i, opts, &env, nil, 1);
+			r.min.y -= opts[TkToffset];
+			switch(i->kind) {
+			case TkTascii:
+			case TkTrune:
+				d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, ix->pos);
+				w = tktdispwidth(tk, tb, i, nil, r.min.x, ix->pos, 1);
+				r.min.x += d;
+				r.min.y -= env.font->ascent;
+				r.max.x = r.min.x + w;
+				r.max.y = r.min.y + env.font->height;
+				break;
+			case TkTwin:
+				sub = i->iwin->sub;
+				if(sub == nil)
+					break;
+				r.min.x += sub->act.x;
+				r.min.y += sub->act.y;
+				r.max.x = r.min.x + sub->act.width + 2*sub->borderwidth;
+				r.max.y = r.min.y + sub->act.height + 2*sub->borderwidth;
+				break;
+			case TkTnewline:
+				r.max.x = r.min.x;
+				r.min.y -= l->ascent;
+				r.max.y = r.min.y + l->height;
+				break;
+			default:
+				d = tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1);
+				r.max.x = r.min.x + d;
+				r.max.y = r.min.y;
+				break;
+			}
+			return r;
+		}
+		r.min.x += tktdispwidth(tk, tb, i, nil, r.min.x, 0, -1);
+	}
+	r.min.x = 0;
+	r.min.y = 0;
+	r.max.x = 0;
+	r.max.y = 0;
+	return r;
+}
+
+/* Return left-at-baseline position of given item, in V coords */
+static Point
+tktitempos(Tk *tk, TkTindex *ix)
+{
+	Point p;
+	TkTitem *i;
+	TkTline *l;
+	TkText *tkt = TKobj(TkText, tk);
+ 
+	l = ix->line;
+
+	/* p in V space */
+	p = subpt(l->orig, tkt->deltatv);
+	p.y += l->ascent;
+
+	for(i = l->items; i != nil && i != ix->item; i = i->next)
+		p.x += i->width;
+	return p;
+}
+
+static Tk*
+tktdeliver(Tk *tk, TkTitem *i, TkTitem *tagit, int event, void *data, Point deltasv)
+{
+	Tk *ftk, *dest;
+	TkTwind *w;
+	TkText *tkt;
+	TkTtaginfo *t;
+	TkTline *l;
+	TkMouse m;
+	Point mp, p;
+	TkTindex ix;
+	int bd;
+
+	dest = nil;
+	if(i != nil) {
+		tkt = TKobj(TkText, tk);
+
+		if(i->kind == TkTwin) {
+			w = i->iwin;
+			if(w->sub != nil) {
+				if(!(event & TkKey) && (event & TkEmouse)) {
+					m = *(TkMouse*)data;
+					mp.x = m.x;
+					mp.y = m.y;
+					ix.item = i;
+					ix.pos = 0;
+					ix.line = tktitemline(i);
+					p = tktitempos(tk, &ix);
+					bd = w->sub->borderwidth;
+					mp.x = m.x - (deltasv.x + p.x + w->sub->act.x + bd);
+					mp.y = m.y - (deltasv.y + p.y + w->sub->act.y + bd);
+					ftk = tkinwindow(w->sub, mp, 0);
+					if(ftk != w->focus) {
+						tkdeliver(w->focus, TkLeave, data);
+						tkdeliver(ftk, TkEnter, data);
+
+						w->focus = ftk;
+					}
+					if(ftk != nil)
+						dest = tkdeliver(ftk, event, &m);
+				}
+				else {
+					if ((event & TkLeave) && (w->focus != w->sub)) {
+						tkdeliver(w->focus, TkLeave, data);
+						w->focus = nil;
+						event &= ~TkLeave;
+					}
+					if (event)
+						tkdeliver(w->sub, event, data);
+				}
+				if(Dx(w->sub->dirty) > 0) {
+					l = tktitemline(i);
+					tktfixgeom(tk, tktprevwrapline(tk, l), l, 0);
+				}
+				if(event & TkKey)
+					return dest;
+			}
+		}
+
+		if(tagit != 0) {
+			for(t = tkt->tags; t != nil; t = t->next) {
+				if(t->binds != nil && tkttagset(tagit, t->id)) {
+					if(tksubdeliver(tk, t->binds, event, data, 0) == TkDbreak) {
+						return dest;
+					}
+				}
+			}
+		}
+	}
+	return dest;
+}
+
+Tk*
+tktinwindow(Tk *tk, Point *p)
+{
+	TkTindex ix;
+	Point q;
+	Tk *sub;
+
+	tktxyind(tk, p->x, p->y, &ix);
+	if (ix.item == nil || ix.item->kind != TkTwin || ix.item->iwin->sub == nil)
+		return tk;
+	sub = ix.item->iwin->sub;
+	q = tktitempos(tk, &ix);
+	p->x -= q.x + sub->borderwidth + sub->act.x;
+	p->y -= q.y + sub->borderwidth + sub->act.y;
+	return sub;
+}
+
+Tk*
+tktextevent(Tk *tk, int event, void *data)
+{
+	char *e;
+	TkMouse m, vm;
+	TkTitem *f, *tagit;
+	TkText *tkt;
+	TkTindex ix;
+	Tk *dest;
+	Point deltasv;
+
+	tkt = TKobj(TkText, tk);
+	deltasv = tkposn(tk);
+	deltasv.x += tk->borderwidth + tk->ipad.x/2;
+	deltasv.y += tk->borderwidth + tk->ipad.y/2;
+
+	dest = nil;
+	if(event == TkLeave && tkt->mouse != nil) {
+		vm.x = 0;
+		vm.y = 0;
+		tktdeliver(tk, tkt->mouse, tkt->mouse, TkLeave, data, deltasv);
+		tkt->mouse = nil;
+	}
+	else if((event & TkKey) == 0 && (event & TkEmouse)) {
+		/* m in S space, tm in V space */
+		m = *(TkMouse*)data;
+		vm = m;
+		vm.x -= deltasv.x;
+		vm.y -= deltasv.y;
+		if((event & TkMotion) == 0 || m.b == 0) {
+			tkt->current.x = vm.x;
+			tkt->current.y = vm.y;
+		}
+		tktxyind(tk, vm.x, vm.y, &ix);
+		f = ix.item;
+		if(tkt->mouse != f) {
+			tagit = nil;
+			if(tkt->mouse != nil) {
+				if(tktanytags(tkt->mouse)) {
+					e = tktnewitem(TkTascii, tkt->mouse->tagextra, &tagit);
+					if(e != nil)
+						return dest;	/* XXX propagate error? */
+					tkttagcomb(tagit, tkt->mouse, 1);
+					tkttagcomb(tagit, f, -1);
+				}
+				tktdeliver(tk, tkt->mouse, tagit, TkLeave, data, deltasv);
+				if(tagit)
+					free(tagit);
+				tagit = nil;
+			}
+			if(tktanytags(f)) {
+				e = tktnewitem(TkTascii, f->tagextra, &tagit);
+				if(e != nil)
+					return dest;		/* XXX propagate error? */
+				tkttagcomb(tagit, f, 1);
+				if(tkt->mouse)
+					tkttagcomb(tagit, tkt->mouse, -1);
+			}
+			tktdeliver(tk, f, tagit, TkEnter, data, deltasv);
+			tkt->mouse = f;
+			if(tagit)
+				free(tagit);
+		}
+		if(tkt->mouse != nil)
+			dest = tktdeliver(tk, tkt->mouse, tkt->mouse, event, &m, deltasv);
+	}
+	else if(event == TkFocusin) 
+		tktextcursor(tk, " insert", (char **) nil);
+	/* pass all "real" events on to parent text widget - DBK */
+	tksubdeliver(tk, tk->binds, event, data, 0);
+	return dest;
+}
+
+/* Debugging */
+void
+tktprintitem(TkTitem *i)
+{
+	int j;
+
+	print("%p:", i);
+	switch(i->kind){
+	case TkTascii:
+		print("\"%s\"", i->istring);
+		break;
+	case TkTrune:
+		print("<rune:%s>", i->istring);
+		break;
+	case TkTnewline:
+		print("<nl:%p>", i->iline);
+		break;
+	case TkTcontline:
+		print("<cont:%p>", i->iline);
+		break;
+	case TkTtab:
+		print("<tab>");
+		break;
+	case TkTmark:
+		print("<mk:%s>", i->imark->name);
+		break;
+	case TkTwin:
+	        if (i->iwin->sub->name != nil)
+		  print("<win:%s>", i->iwin->sub? i->iwin->sub->name->name : "<null>");
+	}
+	print("[%d]", i->width);
+	if(i->tags !=0 || i->tagextra !=0) {
+		print("{%lux", i->tags[0]);
+		for(j=0; j < i->tagextra; j++)
+			print(" %lux", i->tags[j+1]);
+		print("}");
+	}
+	print(" ");
+}
+
+void
+tktprintline(TkTline *l)
+{
+	TkTitem *i;
+
+	print("line %p: orig=(%d,%d), w=%d, h=%d, a=%d, f=%x\n\t",
+		l, l->orig.x, l->orig.y, l->width, l->height, l->ascent, l->flags);
+	for(i = l->items; i != nil; i = i->next)
+		tktprintitem(i);
+	print("\n");
+}
+
+void
+tktprintindex(TkTindex *ix)
+{
+	print("line=%p,item=%p,pos=%d\n", ix->line, ix->item, ix->pos);
+}
+
+void
+tktprinttext(TkText *tkt)
+{
+	TkTline *l;
+	TkTtaginfo *ti;
+	TkTmarkinfo *mi;
+
+	for(ti=tkt->tags; ti != nil; ti=ti->next)
+		print("%s{%d} ", ti->name, ti->id);
+	print("\n");
+	for(mi = tkt->marks; mi != nil; mi=mi->next)
+		print("%s{%p} ", mi->name? mi->name : "nil", mi->cur);
+	print("\n");
+	print("selfirst=%p sellast=%p\n", tkt->selfirst, tkt->sellast);
+
+	for(l = &tkt->start; l != nil; l = l->next)
+		tktprintline(l);
+}
+
+/*
+ * Check that assumed invariants are true.
+ *
+ * - start line and end line have no items
+ * - all other lines have at least one item
+ * - start line leads to end line via next pointers
+ * - prev pointers point to previous lines
+ * - each line ends in either a TkTnewline or a TkTcontline
+ *    whose iline pointer points to the line itself
+ * - TkTcontline and TkTmark items have no tags
+ *    (this is so they don't get realloc'd because of tag combination)
+ * - all cur fields of marks point to nil or a TkTmark
+ * - selfirst and sellast correctly define select region
+ * - nlines counts the number of lines
+ */
+void
+tktcheck(TkText *tkt, char *fun)
+{
+	int nl, insel, selfound;
+	TkTline *l;
+	TkTitem *i;
+	TkTmarkinfo *mi;
+	TkTindex ix;
+	char *prob;
+
+	prob = nil;
+	nl = 0;
+
+	if(tkt->start.items != nil || tkt->end.items != nil)
+		prob = "start/end has items";
+	for(l = tkt->start.next; l != &tkt->end; l = l->next) {
+		if(l->prev->next != l) {
+			prob = "prev mismatch";
+			break;
+		}
+		if(l->next->prev != l) {
+			prob = "next mismatch";
+			break;
+		}
+		i = l->items;
+		if(i == nil) {
+			prob = "empty line";
+			break;
+		}
+		while(i->next != nil) {
+			if(i->kind == TkTnewline || i->kind == TkTcontline) {
+				prob = "premature end of line";
+				break;
+			}
+			if(i->kind == TkTmark && (i->tags[0] != 0 || i->tagextra != 0)) {
+				prob = "mark has tags";
+				break;
+			}
+			i = i->next;
+		}
+		if(i->kind == TkTnewline)
+			nl++;
+		if(!(i->kind == TkTnewline || i->kind == TkTcontline)) {
+			prob = "bad end of line";
+			break;
+		}
+		if(i->kind == TkTcontline && (i->tags[0] != 0 || i->tagextra != 0)) {
+			prob = "contline has tags";
+			break;
+		}
+		if(i->iline != l) {
+			prob = "bad end-of-line pointer";
+			break;
+		}
+	}
+	for(mi = tkt->marks; mi != nil; mi=mi->next) {
+		if(mi->cur != nil) {
+			tktstartind(tkt, &ix);
+			do {
+				if(ix.item->kind == TkTmark && ix.item == mi->cur)
+					goto foundmark;
+			} while(tktadjustind(tkt, TkTbyitem, &ix));
+			prob = "bad mark cur";
+			break;
+		    foundmark: ;
+		}
+	}
+	insel = 0;
+	selfound = 0;
+	tktstartind(tkt, &ix);
+	do {
+		i = ix.item;
+		if(i == tkt->selfirst) {
+			if(i->kind == TkTmark || i->kind == TkTcontline) {
+				prob = "selfirst not on character";
+				break;
+			}
+			if(i == tkt->sellast) {
+				prob = "selfirst==sellast, not nil";
+				break;
+			}
+			insel = 1;
+			selfound = 1;
+		}
+		if(i == tkt->sellast) {
+			if(i->kind == TkTmark || i->kind == TkTcontline) {
+				prob = "sellast not on character";
+				break;
+			}
+			insel = 0;
+		}
+		if(i->kind != TkTmark && i->kind != TkTcontline) {
+			if(i->tags[0] & (1<<TkTselid)) {
+				if(!insel) {
+					prob = "sel set outside selfirst..sellast";
+					break;
+				}
+			}
+			else {
+				if(insel) {
+					prob = "sel not set inside selfirst..sellast";
+					break;
+				}
+			}
+		}
+	} while(tktadjustind(tkt, TkTbyitem, &ix));
+	if(tkt->selfirst != nil && !selfound)
+		prob = "selfirst not found";
+
+	if(prob != nil) {
+		print("tktcheck problem: %s: %s\n", fun, prob);
+		tktprinttext(tkt);
+abort();
+	}
+}
+
+int
+tktutfpos(char *s, int pos)
+{
+	char *s1;
+	int c;
+	Rune r;
+
+	for (s1 = s; pos > 0; pos--) {
+		c = *(uchar *)s1;
+		if (c < Runeself) {
+			if (c == '\0')
+				break;
+			s1++;
+		}
+		else
+			s1 += chartorune(&r, s1);
+	}
+	return s1 - s;
+}
+
+/*
+struct timerec {
+	char *name;
+	ulong ms;
+};
+
+static struct timerec tt[100];
+static int ntt = 1;
+
+int
+tktalloctime(char *name)
+{
+	if(ntt >= 100)
+		abort();
+	tt[ntt].name = strdup(name);
+	tt[ntt].ms = 0;
+	return ntt++;
+}
+
+void
+tktstarttime(int ind)
+{
+return;
+	tt[ind].ms -= osmillisec();
+}
+
+void
+tktendtime(int ind)
+{
+return;
+	tt[ind].ms += osmillisec();
+}
+
+void
+tktdumptime(void)
+{
+	int i;
+
+	for(i = 1; i < ntt; i++)
+		print("%s: %d\n", tt[i].name, tt[i].ms);
+}
+*/
--- /dev/null
+++ b/libtk/textw.c
@@ -1,0 +1,3701 @@
+#include "lib9.h"
+#include "draw.h"
+#include "keyboard.h"
+#include "tk.h"
+#include "textw.h"
+
+/*
+ * useful text widget info to be found at:
+ * :/coordinate.systems		- what coord. systems are in use
+ * textu.c:/assumed.invariants	- some invariants that must be preserved
+ */
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+#define FLUSH() flushimage(tk->env->top->display, 1)
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+/* Layout constants */
+enum {
+	Textpadx	= 2,
+	Textpady	= 0,
+};
+
+typedef struct Interval {
+	int	lo;
+	int	hi;
+} Interval;
+
+typedef struct Mprint Mprint;
+struct Mprint
+{
+	char*	buf;
+	int	ptr;
+	int	len;
+};
+
+typedef struct TkDump TkDump;
+struct TkDump
+{
+	int	sgml;
+	int	metrics;
+};
+
+static
+TkOption dumpopts[] =
+{
+	"sgml",		OPTbool,	O(TkDump, sgml),	nil,
+	"metrics",	OPTbool,	O(TkDump, metrics),	nil,
+	nil
+};
+
+static
+TkStab tkcompare[] =
+{
+	"<",		TkLt,
+	"<=",		TkLte,
+	"==",		TkEq,
+	">=",		TkGte,
+	">",		TkGt,
+	"!=",		TkNeq,
+	nil
+};
+
+static
+TkOption textopts[] =
+{
+	"wrap",			OPTstab, O(TkText, opts[TkTwrap]),	tkwrap,
+	"spacing1",		OPTnndist, O(TkText, opts[TkTspacing1]),	(void *)O(Tk, env),
+	"spacing2",		OPTnndist, O(TkText, opts[TkTspacing2]),	(void *)O(Tk, env),
+	"spacing3",		OPTnndist, O(TkText, opts[TkTspacing3]),	(void *)O(Tk, env),
+	"tabs",			OPTtabs, O(TkText, tabs), 		(void *)O(Tk, env),
+	"xscrollcommand",	OPTtext, O(TkText, xscroll),		nil,
+	"yscrollcommand",	OPTtext, O(TkText, yscroll),		nil,
+	"insertwidth",		OPTnndist, O(TkText, inswidth),		nil,
+	"tagshare",		OPTwinp, O(TkText, tagshare),		nil,
+	"propagate",		OPTstab, O(TkText, propagate),	tkbool,
+	"selectborderwidth",	OPTnndist, O(TkText, sborderwidth), nil,
+	nil
+};
+
+#define CNTL(c) ((c)&0x1f)
+#define DEL 0x7f
+
+static TkEbind tktbinds[] = {
+	{TkButton1P,		"%W tkTextButton1 %X %Y"},
+	{TkButton1P|TkMotion,	"%W tkTextSelectTo %X %Y"},
+	{TkButton1P|TkDouble,	"%W tkTextSelectTo %X %Y double"},
+	{TkButton1R,		"%W tkTextButton1R"},
+	{TkButton2P,		"%W scan mark %x %y"},
+	{TkButton2P|TkMotion,	"%W scan dragto %x %y"},
+	{TkKey,			"%W tkTextInsert {%A}"},
+	{TkKey|CNTL('a'),	"%W tkTextSetCursor {insert linestart}"},
+	{TkKey|Home,		"%W tkTextSetCursor {insert linestart}"},
+	{TkKey|CNTL('<'),	"%W tkTextSetCursor {insert linestart}"},
+	{TkKey|CNTL('b'),	"%W tkTextSetCursor insert-1c"},
+	{TkKey|Left,		"%W tkTextSetCursor insert-1c"},
+	{TkKey|CNTL('d'),	"%W tkTextDelIns"},
+	{TkKey|CNTL('e'),	"%W tkTextSetCursor {insert lineend}"}, 
+	{TkKey|End,		"%W tkTextSetCursor {insert lineend}"}, 
+	{TkKey|CNTL('>'),	"%W tkTextSetCursor {insert lineend}"}, 
+	{TkKey|CNTL('f'),	"%W tkTextSetCursor insert+1c"},
+	{TkKey|Right,		"%W tkTextSetCursor insert+1c"},
+	{TkKey|CNTL('h'),	"%W tkTextDelIns -c"},
+	{TkKey|DEL,		"%W tkTextDelIns"},
+	{TkKey|CNTL('k'),	"%W tkTextDelIns +l"},
+	{TkKey|CNTL('n'),	"%W tkTextSetCursor {insert+1l}"},
+	{TkKey|Down,		"%W tkTextSetCursor {insert+1l}"},
+	{TkKey|CNTL('o'),       "%W tkTextInsert {\n}; %W mark set insert insert-1c"},
+	{TkKey|CNTL('p'),	"%W tkTextSetCursor {insert-1l}"},
+	{TkKey|Up,		"%W tkTextSetCursor {insert-1l}"},
+	{TkKey|CNTL('u'),	"%W tkTextDelIns -l"},
+	{TkKey|CNTL('v'),	"%W yview scroll 0.75 page"},
+	{TkKey|Pgdown,	"%W yview scroll 0.75 page"},
+	{TkKey|CNTL('w'),	"%W tkTextDelIns -w"},
+	{TkKey|Pgup,	"%W yview scroll -0.75 page"},
+	{TkButton4P,	"%W yview scroll -0.2 page"},
+	{TkButton5P,	"%W yview scroll 0.2 page"},
+	{TkFocusout,            "%W tkTextCursor delete"},
+	{TkKey|APP|'\t',	""},
+	{TkKey|BackTab,		""},
+};
+
+static int	tktclickmatch(TkText *, int, int, int, TkTindex *);
+static void	tktdoubleclick(TkText *, TkTindex *, TkTindex *);
+static char* 	tktdrawline(Image*, Tk*, TkTline*, Point);
+static void	tktextcursordraw(Tk *, int);
+static char* 	tktsetscroll(Tk*, int);
+static void	tktsetclip(Tk *);
+static char* 	tktview(Tk*, char*, char**, int, int*, int, int);
+static Interval tkttranslate(Tk*, Interval, int);
+static void 	tktfixscroll(Tk*, Point);
+static void 	tktnotdrawn(Tk*, int, int, int);
+static void	tktdrawbg(Tk*, int, int, int);
+static int	tktwidbetween(Tk*, int, TkTindex*, TkTindex*);
+static int	tktpostspace(Tk*, TkTline*);
+static int	tktprespace(Tk*, TkTline*);
+static void	tktsee(Tk*, TkTindex*, int);
+static Point	tktrelpos(Tk*);
+static void	autoselect(Tk*, void*, int);
+static void	blinkreset(Tk*);
+
+/* debugging */
+extern int tktdbg;
+extern void tktprinttext(TkText*);
+extern void tktprintindex(TkTindex*);
+extern void tktprintitem(TkTitem*);
+extern void tktprintline(TkTline*);
+extern void tktcheck(TkText*, char*);
+extern int tktutfpos(char *, int);
+
+char*
+tktext(TkTop *t, char* arg, char **ret)
+{
+	Tk *tk;
+	char *e;
+	TkEnv *ev;
+	TkTline *l;
+	TkTitem *it = nil;
+	TkName *names = nil;
+	TkTtaginfo *ti = nil;
+	TkOptab tko[3];
+	TkTmarkinfo *mi = nil;
+	TkText *tkt, *tktshare;
+
+	tk = tknewobj(t, TKtext, sizeof(Tk)+sizeof(TkText));
+	if(tk == nil)
+		return TkNomem;
+
+	tkt = TKobj(TkText, tk);
+
+	tk->relief = TKsunken;
+	tk->borderwidth = 1;
+	tk->ipad.x = Textpadx * 2;
+	tk->ipad.y = Textpady * 2;
+	tk->flag |= Tktakefocus;
+	tkt->sborderwidth = 0;
+	tkt->inswidth = 2;
+	tkt->cur_flag = 0;	/* text cursor doesn't show up initially */
+	tkt->opts[TkTwrap] = Tkwrapchar;
+	tkt->opts[TkTrelief] = TKflat;
+	tkt->opts[TkTjustify] = Tkleft;
+	tkt->propagate = BoolX;
+
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkt;
+	tko[1].optab = textopts;
+	tko[2].ptr = nil;
+
+	tk->req.width = tk->env->wzero*Textwidth;
+	tk->req.height = tk->env->font->height*Textheight;
+
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if(e != nil)
+		goto err;
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	if(names == nil) {
+		/* tkerr(t, arg); XXX */
+		e = TkBadwp;
+		goto err;
+	}
+
+	if(tkt->tagshare != nil) {
+		tkputenv(tk->env);
+		tk->env = tkt->tagshare->env;
+		tk->env->ref++;
+	}
+
+	if(tk->flag&Tkdisabled)
+		tkt->inswidth = 0;
+
+	if(tkt->tabs == nil) {
+		tkt->tabs = malloc(sizeof(TkTtabstop));
+		if(tkt->tabs == nil) 
+			goto err;
+		tkt->tabs->pos = 8*tk->env->wzero;
+		tkt->tabs->justify = Tkleft;
+		tkt->tabs->next = nil;
+	}
+
+	if(tkt->tagshare != nil) {
+		tktshare = TKobj(TkText, tkt->tagshare);
+		tkt->tags = tktshare->tags;
+		tkt->nexttag = tktshare->nexttag;
+	}
+	else {
+		/* Note: sel should have id == TkTselid == 0 */
+		e = tktaddtaginfo(tk, "sel", &ti);
+		if(e != nil)
+			goto err;
+
+		tkputenv(ti->env);
+		ti->env = tknewenv(t);
+		if(ti->env == nil)
+			goto err;
+
+		ev = ti->env;
+		ev->colors[TkCbackgnd] = tk->env->colors[TkCselectbgnd];
+		ev->colors[TkCbackgndlght] = tk->env->colors[TkCselectbgndlght];
+		ev->colors[TkCbackgnddark] = tk->env->colors[TkCselectbgnddark];
+		ev->colors[TkCforegnd] = tk->env->colors[TkCselectfgnd];
+		ev->set = (1<<TkCbackgnd)|(1<<TkCbackgndlght)|
+			  (1<<TkCbackgnddark)|(1<<TkCforegnd);
+
+		ti->opts[TkTborderwidth] = tkt->sborderwidth;
+		if(tkt->sborderwidth > 0)
+			ti->opts[TkTrelief] = TKraised;
+	}
+
+	e = tktaddmarkinfo(tkt, "current", &mi);
+	if(e != nil)
+		goto err;
+
+	e = tktaddmarkinfo(tkt, "insert", &mi);
+	if(e != nil)
+		goto err;
+
+	tkt->start.flags = TkTfirst|TkTlast;
+	tkt->end.flags = TkTlast;
+
+	e = tktnewitem(TkTnewline, 0, &it);
+
+	if(e != nil)
+		goto err;
+
+	e = tktnewline(TkTfirst|TkTlast, it, &tkt->start, &tkt->end, &l);
+	if(e != nil)
+		goto err;
+
+	e = tktnewitem(TkTmark, 0, &it);
+	if(e != nil)
+		goto err;
+
+	it->next = l->items;
+	l->items = it;
+	it->imark = mi;
+	mi->cur = it;
+	tkt->nlines = 1;
+	tkt->scrolltop[Tkvertical] = -1;
+	tkt->scrolltop[Tkhorizontal] = -1;
+	tkt->scrollbot[Tkvertical] = -1;
+	tkt->scrollbot[Tkhorizontal] = -1;
+
+	if(tkt->tagshare != nil)
+		tk->binds = tkt->tagshare->binds;
+	else {
+		e = tkbindings(t, tk, tktbinds, nelem(tktbinds));
+
+		if(e != nil)
+			goto err;
+	}
+	if (tkt->propagate == BoolT) {
+		if ((tk->flag & Tksetwidth) == 0)
+			tk->req.width = tktmaxwid(tkt->start.next);
+		if ((tk->flag & Tksetheight) == 0)
+			tk->req.height = tkt->end.orig.y;
+	}
+
+	e = tkaddchild(t, tk, &names);
+	tkfreename(names);
+	if(e != nil)
+		goto err;
+	tk->name->link = nil;
+
+	return tkvalue(ret, "%s", tk->name->name);
+
+err:
+	/* XXX it's possible there's a memory leak here */
+	tkfreeobj(tk);
+	return e;
+}
+
+/*
+ * There are four coordinate systems of interest:
+ *	S - screen coordinate system (i.e. top left corner of
+ *		inferno screen is (0,0) in S space.)
+ *	I - image coordinate system (i.e. top left corner of
+ *		tkimageof(this widget) is (0,0) in I space.)
+ *	T - text coordinate system (i.e., top left of first line
+ *		is at (0,0) in T space.)
+ *	V - view coordinate system (i.e., top left of visible
+ *		portion of widget is at (0,0) in V space.)
+ *
+ *	A point P in the four systems (Ps, Pi, Pt, Pv) satisfies:
+ *		Pt = Ps - deltast
+ *		Pv = Ps - deltasv
+ *		Pv = Pi - deltaiv
+ *	(where deltast is vector from S origin to T origin;
+ *	     deltasv is vector from S origin to V origin;
+ *	     deltaiv is vector from I origin to V origin)
+ *
+ *	We keep deltatv, deltasv, and deltaiv in tkt.
+ *	Deltatv is updated by scrolling.
+ *	Deltasv is updated by geom changes:
+ *		tkposn(tk)+ipad/2
+ *	Deltaiv is affected by geom changes and the call to the draw function:
+ *		tk->act+orig+ipad/2+(bw,bw) (orig is the parameter to tkdrawtext),
+ *
+ *	We can derive
+ *		Ps = Pt + deltast
+ *		   = Pt +  deltasv - deltatv
+ *
+ *		Pv = Pt - deltatv
+ *
+ * Here are various coordinates in the text widget according
+ * to which coordinate system they use:
+ *
+ *	S - Mouse coordinates (coming in to tktextevent);
+ *		the deltasv parameter to tkdrawtext;
+ *		coords in tkt->image, where drawing is done to
+ *		(to get same bit-alignment as screen, for fast transfer)
+ *	T - orig in TkTlines
+ *	V - %x,%y delivered via binds to TkText or its tags
+
+ * Note deltasv changes underneath us, so is calculated on the fly
+ * when it needs to be (in tktextevent).
+ *
+ */
+static void
+tktsetdeltas(Tk *tk, Point orig)
+{
+	TkText *tkt = TKobj(TkText, tk);
+
+	tkt->deltaiv.x = orig.x + tk->act.x + tk->ipad.x/2 + tk->borderwidth;
+	tkt->deltaiv.y = orig.y + tk->act.y + tk->ipad.y/2 + tk->borderwidth;
+}
+
+static Point
+tktrelpos(Tk *sub)
+{
+	Tk *tk;
+	TkTindex ix;
+	Rectangle r;
+	Point ans;
+
+	tk = sub->parent;
+	if(tk == nil)
+		return ZP;
+
+	if(tktfindsubitem(sub, &ix)) {
+		r = tktbbox(tk, &ix);
+		ans.x = r.min.x;
+		ans.y = r.min.y;
+		return r.min;
+	}
+	return ZP;
+}
+
+static void
+tktreplclipr(Image *dst, Rectangle r)
+{
+	int locked;
+
+	locked = lockdisplay(dst->display);
+	replclipr(dst, 0, r);
+	if(locked)
+		unlockdisplay(dst->display);
+}
+
+char*
+tkdrawtext(Tk *tk, Point orig)
+{
+	int vh;
+	Image *dst;
+	TkText *tkt;
+	TkTline *l, *lend;
+	Point p, deltait;
+	Rectangle oclipr;
+	int reldone = 1;
+	char *e;
+	tkt = TKobj(TkText, tk);
+	dst = tkimageof(tk);
+	if (dst == nil)
+		return nil;
+	tkt->image = dst;
+	tktsetdeltas(tk, orig);
+	tkt->tflag |= TkTdrawn|TkTdlocked;
+	oclipr = dst->clipr;
+	tktsetclip(tk);
+
+	if(tk->flag&Tkrefresh) {
+		reldone = 0;
+		tktnotdrawn(tk, 0, tkt->end.orig.y, 1);
+	}
+	tk->flag &= ~Tkrefresh;
+
+	deltait = subpt(tkt->deltaiv, tkt->deltatv);
+	vh = tk->act.height - tk->ipad.y/2;
+	lend = &tkt->end;
+	for(l = tkt->start.next; l != lend; l = l->next) {
+		if(l->orig.y+l->height < tkt->deltatv.y)
+			continue;
+		if(l->orig.y > tkt->deltatv.y + vh)
+			break;
+		if(!(l->flags&TkTdrawn)) {
+			e = tktdrawline(dst, tk, l, deltait);
+			if(e != nil)
+				return e;
+		}
+	}
+
+	tktreplclipr(dst, oclipr);
+	if(!reldone) {
+		p.x = orig.x + tk->act.x;
+		p.y = orig.y + tk->act.y;
+		tkdrawrelief(dst, tk, p, TkCbackgnd, tk->relief);
+	}
+	tkt->tflag &= ~TkTdlocked;
+
+	return nil;
+}
+
+/*
+ * Set the clipping rectangle of the destination image to the
+ * intersection of the current clipping rectangle and the area inside
+ * the text widget that needs to be redrawn.
+ * The caller should save the old one and restore it later.
+ */
+static void
+tktsetclip(Tk *tk)
+{
+	Rectangle r;
+	Image *dst;
+	TkText *tkt = TKobj(TkText, tk);
+
+	dst = tkt->image;
+	r.min = tkt->deltaiv;
+	r.max.x = r.min.x + tk->act.width - tk->ipad.x / 2;
+	r.max.y = r.min.y + tk->act.height - tk->ipad.y / 2;
+
+	if(!rectclip(&r, dst->clipr))
+		r.max = r.min;
+	tktreplclipr(dst, r);
+}
+
+static char*
+tktdrawline(Image *i, Tk *tk, TkTline *l, Point deltait)
+{
+	Tk *sub;
+	Font *f;
+	Image *bg;
+	Point p, q;
+	Rectangle r;
+	TkText *tkt;
+	TkTitem *it, *z;
+	int bevtop, bevbot;
+	TkEnv *e, *et, *env;
+	int *opts;
+	int o, bd, ul, ov, h, w, la, lh, cursorx, join;
+	char *err;
+
+	env = mallocz(sizeof(TkEnv), 0);
+	if(env == nil)
+		return TkNomem;
+	opts = mallocz(TkTnumopts*sizeof(int), 0);
+	if(opts == nil) {
+		free(env);
+		return TkNomem;
+	}
+	tkt = TKobj(TkText, tk);
+	e = tk->env;
+	et = env;
+	et->top = e->top;
+	f = e->font;
+
+	/* l->orig is in T space, p is in I space */
+	la = l->ascent;
+	lh = l->height;
+	p = addpt(l->orig, deltait);
+	p.y += la;
+/* if(tktdbg){print("drawline, p=(%d,%d), f->a=%d, f->h=%d\n", p.x, p.y, f->ascent, f->height); tktprintline(l);} */
+	cursorx = -1000;
+	join = 0;
+	for(it = l->items; it != nil; it = it->next) {
+		bg = tkgc(e, TkCbackgnd);
+		if(tktanytags(it)) {
+			tkttagopts(tk, it, opts, env, nil, 1);
+			if(e->colors[TkCbackgnd] != et->colors[TkCbackgnd]) {
+				bg = tkgc(et, TkCbackgnd);
+				r.min = p;
+				r.min.y -= la;
+				r.max.x = r.min.x + it->width;
+				r.max.y = r.min.y + lh;
+				draw(i, r, bg, nil, ZP);
+			}
+			o = opts[TkTrelief];
+			bd = opts[TkTborderwidth];
+			if((o == TKsunken || o == TKraised) && bd > 0) {
+				/* fit relief inside item bounding box */
+
+				q.x = p.x;
+				q.y = p.y - la;
+				if(it->width < 2*bd)
+					bd = it->width / 2;
+				if(lh < 2*bd)
+					bd = lh / 2;
+				w = it->width - 2*bd;
+				h = lh - 2*bd;
+				if(o == TKraised) {
+					bevtop = TkLightshade;
+					bevbot = TkDarkshade;
+				}
+				else {
+					bevtop = TkDarkshade;
+					bevbot = TkLightshade;
+				}
+
+				tkbevel(i, q, w, h, bd,
+					tkgc(et, TkCbackgnd+bevtop), tkgc(et, TkCbackgnd+bevbot));
+
+				/* join relief between adjacent items if tags match */
+				if(join) {
+					r.min.x = q.x;
+					r.max.x = q.x + bd;
+					r.min.y = q.y + bd;
+					r.max.y = r.min.y + h;
+					draw(i, r, bg, nil, ZP);
+					r.min.y = r.max.y;
+					r.max.y = r.min.y + bd;
+					draw(i, r, tkgc(et, TkCbackgnd+bevbot), nil, ZP);
+				}
+				for(z = it->next; z != nil && z->kind == TkTmark; )
+					z = z->next;
+				if(z != nil && tktsametags(z, it)) {
+					r.min.x = q.x + bd + w;
+					r.max.x = r.min.x + bd;
+					r.min.y = q.y;
+					r.max.y = q.y + bd;
+					draw(i, r, tkgc(et, TkCbackgnd+bevtop), nil, ZP);
+					r.min.y = r.max.y;
+					r.max.y = r.min.y + h;
+					draw(i, r, bg, nil, ZP);
+					join = 1;
+				}
+				else
+					join = 0;
+			}
+			o = opts[TkToffset];
+			ul = opts[TkTunderline];
+			ov = opts[TkToverstrike];
+		}
+		else {
+			et->font = f;
+			et->colors[TkCforegnd] = e->colors[TkCforegnd];
+			o = 0;
+			ul = 0;
+			ov = 0;
+		}
+
+		switch(it->kind) {
+		case TkTascii:
+		case TkTrune:
+			q.x = p.x;
+			q.y = p.y - env->font->ascent - o;
+/*if(tktdbg)print("q=(%d,%d)\n", q.x, q.y);*/
+			string(i, q, tkgc(et, TkCforegnd), q, env->font, it->istring);
+			if(ov == BoolT) {
+				r.min.x = q.x;
+				r.max.x = r.min.x + it->width;
+				r.min.y = q.y + 2*env->font->ascent/3;
+				r.max.y = r.min.y + 2;
+				draw(i, r, tkgc(et, TkCforegnd), nil, ZP);
+			}
+			if(ul == BoolT) {
+				r.min.x = q.x;
+				r.max.x = r.min.x + it->width;
+				r.max.y = p.y - la + lh;
+				r.min.y = r.max.y - 2;
+				draw(i, r, tkgc(et, TkCforegnd), nil, ZP);
+			}
+			break;
+		case TkTmark:
+			if((it->imark != nil) 
+                           && strcmp(it->imark->name, "insert") == 0) {
+				cursorx = p.x - 1;
+			}
+			break;
+		case TkTwin:
+			sub = it->iwin->sub;
+			if(sub != nil) {
+				int dirty;
+				sub->flag |= Tkrefresh;
+				sub->dirty = tkrect(sub, 1);
+				err = tkdrawslaves(sub, p, &dirty);
+				if(err != nil) {
+					free(opts);
+					free(env);
+					return err;
+				}
+			}
+			break;
+		}
+		p.x += it->width;
+	}
+	l->flags |= TkTdrawn;
+
+	/* do cursor last, so not overwritten by later items */
+	if(cursorx != -1000 && tkt->inswidth > 0) {
+		r.min.x = cursorx;
+		r.min.y = p.y - la;
+		r.max.x = r.min.x + tkt->inswidth;
+		r.max.y = r.min.y + lh;
+		r = rectsubpt(r, deltait);
+		if (!eqrect(tkt->cur_rec, r))
+			blinkreset(tk);
+		tkt->cur_rec = r;
+		if(tkt->cur_flag)
+			tktextcursordraw(tk, TkCforegnd);
+	}
+
+	free(opts);
+	free(env);
+	return nil;
+}
+
+static void
+tktextcursordraw(Tk *tk, int color)
+{
+	Rectangle r;
+	TkText *tkt;
+	Image *i;
+
+	tkt = TKobj(TkText, tk);
+	
+	r = rectaddpt(tkt->cur_rec, subpt(tkt->deltaiv, tkt->deltatv));
+
+	/* check the cursor with widget boundary */
+	/* do nothing if entire cursor outside widget boundary */
+	if( ! (	r.max.x < tkt->deltaiv.x ||
+		r.min.x > tkt->deltaiv.x + tk->act.width ||
+		r.max.y < tkt->deltaiv.y ||
+		r.min.y > tkt->deltaiv.y + tk->act.height)) {
+
+		/* clip rectangle if extends beyond widget boundary */
+		if (r.min.x < tkt->deltaiv.x)
+			r.min.x = tkt->deltaiv.x;
+		if (r.max.x > tkt->deltaiv.x + tk->act.width)
+			r.max.x = tkt->deltaiv.x + tk->act.width;
+		if (r.min.y < tkt->deltaiv.y)
+			r.min.y = tkt->deltaiv.y;
+		if (r.max.y > tkt->deltaiv.y + tk->act.height)
+			r.max.y = tkt->deltaiv.y + tk->act.height;
+		i = tkimageof(tk);
+		if (i != nil)
+			draw(i, r, tkgc(tk->env, color), nil, ZP);
+	}
+}
+
+static void
+blinkreset(Tk *tk)
+{
+	TkText *tkt = TKobj(TkText, tk);
+	if (!tkhaskeyfocus(tk) || tk->flag&Tkdisabled)
+		return;
+	tkt->cur_flag = 1;
+	tkblinkreset(tk);
+}
+
+static void
+showcaret(Tk *tk, int on)
+{
+	TkText *tkt = TKobj(TkText, tk);
+	TkTline *l, *lend;
+	TkTitem *it;
+
+	tkt->cur_flag = on;
+	lend = &tkt->end;
+	for(l = tkt->start.next; l != lend; l = l->next) {
+		for (it = l->items; it != nil; it = it->next) {
+			if (it->kind == TkTmark && it->imark != nil &&
+				    strcmp(it->imark->name, "insert") == 0) {
+				if (on) {
+					tktextcursordraw(tk, TkCforegnd);
+					tk->dirty = tkrect(tk, 1);
+				} else
+					tktnotdrawn(tk, l->orig.y, l->orig.y+l->height, 0);
+				tkdirty(tk);
+				return;
+			}
+		}
+	}
+}
+
+char*
+tktextcursor(Tk *tk, char* arg, char **ret)
+{
+	int on = 0;
+	USED(ret);
+
+	if (tk->flag&Tkdisabled)
+		return nil;
+
+	if(strcmp(arg, " insert") == 0) {
+		tkblink(tk, showcaret);
+		on = 1;
+	}
+	else
+		tkblink(nil, nil);
+
+	showcaret(tk, on);
+	return nil;
+}
+
+/*
+ * Insert string s just before ins, but don't worry about geometry values.
+ * Don't worry about doing wrapping correctly, but break long strings
+ * into pieces to avoid bad behavior in the wrapping code of tktfixgeom.
+ * If tagit != 0, use its tags, else use the intersection of tags of 
+ * non cont or mark elements just before and just after insertion point.
+ * (At beginning and end of widget, just use the tags of one adjacent item).
+ * Keep *ins up-to-date.
+ */
+char*
+tktinsert(Tk *tk, TkTindex *ins, char *s, TkTitem *tagit)
+{
+	int c, n, nextra, nmax, atend, atbeg;
+	char *e, *p;
+	Rune r;
+	TkTindex iprev, inext;
+	TkTitem *i, *utagit;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tktsplititem(ins);
+	if(e != nil)
+		return e;
+
+	/* if no tags give, use intersection of previous and next char tags */
+
+	nextra = 0;
+	n = tk->env->wzero;
+	if(n <= 0)
+		n = 8;
+	nmax = tk->act.width - tk->ipad.x;
+	if(nmax <= 0) {
+		if (tkt->propagate != BoolT || (tk->flag & Tksetwidth))
+			nmax = tk->req.width;
+		if(nmax <= 0)
+			nmax = 60*n;
+	}
+	nmax = (nmax + n - 1) / n;
+	utagit = nil;
+	if(tagit == nil) {
+		inext = *ins;
+		tktadjustind(tkt, TkTbycharstart, &inext);
+		atend = (inext.item->next == nil && inext.line->next == &tkt->end);
+		if(atend || tktanytags(inext.item)) {
+			iprev = *ins;
+			tktadjustind(tkt, TkTbycharback, &iprev);
+			atbeg = (iprev.line->prev == &tkt->start && iprev.line->items == iprev.item);
+			if(atbeg || tktanytags(iprev.item)) {
+				nextra = 0;
+				if(!atend)
+					nextra = inext.item->tagextra;
+				if(!atbeg && iprev.item->tagextra > nextra)
+					nextra = iprev.item->tagextra;
+				e = tktnewitem(TkTascii, nextra, &utagit);
+				if(e != nil)
+					return e;
+				if(!atend) {
+					tkttagcomb(utagit, inext.item, 1);
+					if(!atbeg)
+						tkttagcomb(utagit, iprev.item, 0);
+				}
+				else if(!atbeg)
+					tkttagcomb(utagit, iprev.item, 1);
+				tagit = utagit;
+			}
+		}
+	}
+	else
+		nextra = tagit->tagextra;
+
+	while((c = *s) != '\0') {
+		e = tktnewitem(TkTascii, nextra, &i);
+		if(e != nil) {
+			if(utagit != nil)
+				free(utagit);
+			return e;
+		}
+
+		if(tagit != nil)
+			tkttagcomb(i, tagit, 1);
+
+		if(c == '\n') {
+			i->kind = TkTnewline;
+			tkt->nlines++;
+			s++;
+		}
+		else
+		if(c == '\t') {
+			i->kind = TkTtab;
+			s++;
+		}
+		else {
+			p = s;
+			n = 0;
+			i->kind = TkTascii;
+			while(c != '\0' && c != '\n' && c != '\t' && n < nmax){
+				s += chartorune(&r, s);
+				c = *s;
+				n++;
+			}
+			/*
+			 * if more bytes than runes, then it's not all ascii, so create a TkTrune item
+			 */
+			if(s - p > n)
+				i->kind = TkTrune;
+			n = s - p;
+			i->istring = malloc(n+1);
+			if(i->istring == nil) {
+				tktfreeitems(tkt, i, 1);
+				if(utagit != nil)
+					free(utagit);
+				return TkNomem;
+			}
+			memmove(i->istring, p, n);
+			i->istring[n] = '\0';
+		}
+		e = tktiteminsert(tkt, ins, i);
+		if(e != nil) {
+			if(utagit != nil)
+				free(utagit);
+			tktfreeitems(tkt, i, 1);
+			return e;
+		}
+	}
+
+	if(utagit != nil)
+		free(utagit);
+	return nil;
+}
+
+void
+tktextsize(Tk *tk, int dogeom)
+{
+	TkText *tkt;
+	TkGeom g;
+	tkt = TKobj(TkText, tk);
+	if (tkt->propagate == BoolT) {
+		g = tk->req;
+		if ((tk->flag & Tksetwidth) == 0)
+			tk->req.width = tktmaxwid(tkt->start.next);
+		if ((tk->flag & Tksetheight) == 0)
+			tk->req.height = tkt->end.orig.y;
+		if (dogeom)
+			tkgeomchg(tk, &g, tk->borderwidth);
+	}
+}
+
+static int
+maximum(int a, int b)
+{
+	if (a > b)
+		return a;
+	return b;
+}
+
+/*
+ * For lines l1->next, ..., l2, fix up the geometry
+ * elements of constituent TkTlines and TkTitems.
+ * This involves doing proper line wrapping, and calculating item
+ * widths and positions.
+ * Also, merge any adjacent TkTascii/TkTrune items with the same tags.
+ * Finally, bump the y component of lines l2->next, ... end.
+ * l2 should not be tkt->end.
+ *
+ * if finalwidth is 0, we're trying to work out what the
+ * width and height should be. if propagation is off,
+ * it's irrelevant; otherwise it must assume that
+ * its desired width will be fulfilled, as the packer
+ * doesn't iterate...
+ *
+ * N.B. this function rearranges lines, merges and splits items.
+ * this means that in general the item and line pointed to
+ * by any index might have been freed after tktfixgeom
+ * has been called.
+ */
+char*
+tktfixgeom(Tk *tk, TkTline *l1, TkTline *l2, int finalwidth)
+{
+	int x, y, a, wa, h, w, o, n, j, sp3, xleft, xright, winw, oa, oh, lh;
+	int wrapmode, just, needsplit;
+	char *e, *s;
+	TkText *tkt;
+	Tk *sub;
+	TkTitem *i, *it, *ilast, *iprev;
+	TkTindex ix, ixprev, ixw;
+	TkTline *l, *lafter;
+	Interval oldi, hole, rest, newrest;
+	TkEnv *env;
+	Font *f;
+	int *opts;
+	TkTtabstop *tb;
+
+	tkt = TKobj(TkText, tk);
+
+	if(tktdbg)
+		tktcheck(tkt, "tktfixgeom");
+
+	if (!finalwidth && tkt->propagate == BoolT) {
+		if ((tk->flag & Tksetwidth) == 0)
+			winw = 1000000;
+		else
+			winw = tk->req.width;
+	} else {
+		winw = tk->act.width - tk->ipad.x;
+		if(winw <= 0)
+			winw = tk->req.width;
+	}
+	if(winw < 0)
+		return nil;
+
+	/*
+	 * Make lafter be the first line after l2 that comes after a newline
+	 * (so that wrap correction cannot affect it)
+	 */
+	lafter = l2->next;
+	if(tktdbg && lafter == nil) {
+		print("tktfixgeom: botch 1\n");
+		return nil;
+	}
+	while((lafter->flags & TkTfirst) == 0 && lafter != &tkt->end)
+		lafter = lafter->next;
+
+
+	y = l1->orig.y + l1->height + tktpostspace(tk, l1);
+
+	oldi.lo = y;
+	oldi.hi = lafter->orig.y;
+	rest.lo = oldi.hi;
+	rest.hi = rest.lo + 1000; /* get background after end, too */
+
+	opts = mallocz(TkTnumopts*sizeof(int), 0);
+	if(opts == nil)
+		return TkNomem;
+	env = mallocz(sizeof(TkEnv), 0);
+	if(env == nil) {
+		free(opts);
+		return TkNomem;
+	}
+
+	for(l = l1->next; l != lafter; l = l->next) {
+		if(tktdbg && l == nil) {
+			print("tktfixgeom: botch 2\n");
+			free(opts);
+			free(env);
+			return nil;
+		}
+
+		l->flags &= ~TkTdrawn;
+
+		/* some spacing depends on tags of first non-mark on display line */
+		iprev = nil;
+		for(i = l->items; i->kind == TkTmark; ) {
+			iprev = i;
+			i = i->next;
+		}
+		tkttagopts(tk, i, opts, env, &tb, 1);
+
+		if(l->flags&TkTfirst) {
+			xleft = opts[TkTlmargin1];
+			y += opts[TkTspacing1];
+		}
+		else {
+			xleft = opts[TkTlmargin2];
+			y += opts[TkTspacing2];
+		}
+		sp3 = opts[TkTspacing3];
+		just = opts[TkTjustify];
+
+		wrapmode = opts[TkTwrap];
+		f = env->font;
+		h = f->height;
+		lh = opts[TkTlineheight];
+		a = f->ascent;
+		x = xleft;
+		xright = winw - opts[TkTrmargin];
+		if(xright < xleft)
+			xright = xleft;
+
+		/*
+		 * perform line wrapping and calculate h (height) and a (ascent)
+		 * for the current line
+		 */
+		for(; i != nil; iprev = i, i = i->next) {
+		    again:
+			if(i->kind == TkTmark)
+				continue;
+			if(i->kind == TkTnewline)
+				break;
+			if(i->kind == TkTcontline) {
+				/*
+				 * See if some of following line fits on this one.
+				 * First, ensure that following line isn't empty.
+				 */
+				it = l->next->items;
+				while(it->kind == TkTmark)
+					it = it->next;
+				
+				if(it->kind == TkTnewline || it->kind == TkTcontline) {
+					/* next line is empty; join it to this one by removing i */
+					ix.item = i;
+					ix.line = l;
+					ix.pos = 0;
+					tktremitem(tkt, &ix);
+					it = l->next->items;
+					if(iprev == nil)
+						i = l->items;
+					else
+						i = iprev->next;
+					goto again;
+				}
+
+				n = xright - x;
+				if(n <= 0)
+					break;
+				ixprev.line = l;
+				ixprev.item = i;
+				ixprev.pos = 0;
+				ix = ixprev;
+				tktadjustind(tkt, TkTbychar, &ix);
+				if(wrapmode == Tkwrapword)
+					tktadjustind(tkt, TkTbywrapend, &ix);
+				if(wrapmode != Tkwrapnone && tktwidbetween(tk, x, &ixprev, &ix) > n)
+					break;
+				/* move one item up from next line and try again */
+				it = l->next->items;
+				if(tktdbg && (it == nil || it->kind == TkTnewline || it->kind == TkTcontline)) {
+					print("tktfixgeom: botch 3\n");
+					free(opts);
+					free(env);
+					return nil;
+				}
+				if(iprev == nil)
+					l->items = it;
+				else
+					iprev->next = it;
+				l->next->items = it->next;
+				it->next = i;
+				i = it;
+				goto again;
+			}
+
+			oa = a;
+			oh = h;
+			if(!tktanytags(i)) {
+				env->font = tk->env->font;
+				o = 0;
+			}
+			else {
+				tkttagopts(tk, i, opts, env, nil, 1);
+				o = opts[TkToffset];
+			}
+			if((o != 0 || env->font != f) && i->kind != TkTwin) {
+				/* check ascent of current item */
+				n = o+env->font->ascent;
+				if(n > a) {
+					a = n;
+					h += (a - oa);
+				}
+				/* check descent of current item */
+				n = (env->font->height - env->font->ascent) - o;
+				if(n > h-a)
+					h = a + n;
+			}
+			if(i->kind == TkTwin && i->iwin->sub != nil) {
+				sub = i->iwin->sub;
+				n = 2 * i->iwin->pady + sub->act.height +
+					2 * sub->borderwidth;
+				switch(i->iwin->align) {
+				case Tktop:
+				case Tkbottom:
+					if(n > h)
+						h = n;
+					break;
+				case Tkcenter:
+					if(n/2 > a)
+						a = n/2;
+					if(n/2 > h-a)
+						h = a + n/2;
+					break;
+				case Tkbaseline:
+					wa = i->iwin->ascent;
+					if (wa == -1)
+						wa = n;
+					h = maximum(a, wa) + maximum(h - a, n - wa);
+					a = maximum(a, wa);
+					break;
+				}
+			}
+
+			w = tktdispwidth(tk, tb, i, env->font, x, 0, -1);
+			n = x + w - xright;
+			if(n > 0 && wrapmode != Tkwrapnone) {
+				/* find shortest suffix that can be removed to fit item */
+				j = tktposcount(i) - 1;
+				while(j > 0 && tktdispwidth(tk, tb, i, env->font, x, j, -1) < n)
+					j--;
+				/* put at least one item on a line before splitting */
+				if(j == 0 && x == xleft) {
+					if(tktposcount(i) == 1)
+						goto Nosplit;
+					j = 1;
+				}
+				ix.line = l;
+				ix.item = i;
+				ix.pos = j;
+				if(wrapmode == Tkwrapword) {
+					/* trim the item at the first word at or before the shortest suffix */
+					/* TO DO: convert any resulting trailing white space to zero width */
+					ixw = ix;
+					if(tktisbreak(tktindrune(&ixw))) {
+						/* at break character, find end of word preceding it */
+						while(tktisbreak(tktindrune(&ixw))){
+							if(!tktadjustind(tkt, TkTbycharback, &ixw) ||
+							   ixw.line != l || ixw.item == l->items && ixw.pos == 0)
+								goto Wrapchar;		/* no suitable point, degrade to char wrap */
+						}
+						ix = ixw;
+					}
+					/* now find start of word */
+					tktadjustind(tkt, TkTbywrapstart, &ixw);
+					if(ixw.line == l && (ixw.item != l->items || ixw.pos > 0)){
+						/* it will leave something on the line, so reasonable to split here */
+						ix = ixw;
+					}
+					/* otherwise degrade to char wrap */
+				}
+			   Wrapchar:
+				if(ix.pos > 0) {
+					needsplit = 1;
+					e = tktsplititem(&ix);
+					if(e != nil) {
+						free(opts);
+						free(env);
+						return e;
+					}
+				}
+				else
+					needsplit = 0;
+
+				e = tktnewitem(TkTcontline, 0, &it);
+				if(e != nil) {
+					free(opts);
+					free(env);
+					return e;
+				}
+				e = tktiteminsert(tkt, &ix, it);
+				if(e != nil) {
+					tktfreeitems(tkt, it, 1);
+					free(opts);
+					free(env);
+					return e;
+				}
+
+				l = l->prev;	/* work on part of line up to split */
+
+				if(needsplit) {
+					/* have to calculate width of pre-split part */
+					ixprev = ix;
+					if(tktadjustind(tkt, TkTbyitemback, &ixprev) &&
+					   tktadjustind(tkt, TkTbyitemback, &ixprev)) {
+						w = tktdispwidth(tk, tb, ixprev.item, nil, x, 0, -1);
+						ixprev.item->width = w;
+						x += w;
+					}
+				}
+				else {
+					h = oh;
+					a = oa;
+				}
+				break;
+			}
+			else {
+			    Nosplit:
+				i->width =w;
+				x += w;
+			}
+		}
+		if (a > h)
+			h = a;
+		if (lh == 0)
+			lh = f->height;
+		if (lh > h) {
+			a += (lh - h) / 2;
+			h = lh;
+		}
+
+		/*
+		 * Now line l is broken correctly and has correct item widths/line height/ascent.
+		 * Merge adjacent TkTascii/TkTrune items with same tags.
+		 * Also, set act{x,y} of embedded widgets to offset from
+		 * left of item box at baseline.
+		 */
+		for(i = l->items; i->next != nil; i = i->next) {
+			it = i->next;
+			if( (i->kind == TkTascii || i->kind == TkTrune)
+			      &&
+			     i->kind == it->kind
+			      &&
+			     tktsametags(i, it)) {
+				n = strlen(i->istring);
+				j = strlen(it->istring);
+				s = realloc(i->istring, n + j + 1);
+				if(s == nil) {
+					free(opts);
+					free(env);
+					return TkNomem;
+				}
+				i->istring = s;
+				memmove(i->istring+n, it->istring, j+1);
+				i->width += it->width;
+				i->next = it->next;
+				it->next = nil;
+				tktfreeitems(tkt, it, 1);
+			}
+			else if(i->kind == TkTwin && i->iwin->sub != nil) {
+				sub = i->iwin->sub;
+				n = sub->act.height + 2 * sub->borderwidth;
+				o = i->iwin->pady;
+				sub->act.x = i->iwin->padx;
+				/*
+				 * sub->act.y is y-origin of widget relative to baseline.
+				 */
+				switch(i->iwin->align) {
+				case Tktop:
+					sub->act.y = o - a;
+					break;
+				case Tkbottom:
+					sub->act.y = h - (o + n) - a;
+					break;
+				case Tkcenter:
+					sub->act.y = (h - n) / 2 - a;
+					break;
+				case Tkbaseline:
+					wa = i->iwin->ascent;
+					if (wa == -1)
+						wa = n;
+					sub->act.y = -wa;
+					break;
+				}
+			}
+		}
+
+		l->width = x - xleft;
+
+		/* justification bug: wrong if line has tabs */
+		l->orig.x = xleft;
+		n = xright - x;
+		if(n > 0) {
+			if(just == Tkright)
+				l->orig.x += n;
+			else
+			if(just == Tkcenter)
+				l->orig.x += n/2;
+		}
+
+		/* give newline or contline width up to right margin */
+		ilast = tktlastitem(l->items);
+		ilast->width = xright - l->width;
+		if(ilast->width < 0)
+			ilast->width = 0;
+
+		l->orig.y = y;
+		l->height = h;
+		l->ascent = a;
+		y += h;
+		if(l->flags&TkTlast)
+			y += sp3;
+	}
+	free(opts);
+	free(env);
+
+	tktdrawbg(tk, oldi.lo, oldi.hi, 0);
+
+	y += tktprespace(tk, l);
+	newrest.lo = y;
+	newrest.hi = y + rest.hi - rest.lo;
+
+	hole = tkttranslate(tk, newrest, rest.lo);
+
+	tktdrawbg(tk, hole.lo, hole.hi, 0);
+
+	if(l != &tkt->end) {
+		while(l != &tkt->end) {
+			oh = l->next->orig.y - l->orig.y;
+			l->orig.y = y;
+			if(y + oh > hole.lo && y < hole.hi) {
+				l->flags &= ~TkTdrawn;
+			}
+			y += oh;
+			l = l->next;
+		}
+	}
+	tkt->end.orig.y = tkt->end.prev->orig.y + tkt->end.prev->height;
+
+	if(tkt->deltatv.y > tkt->end.orig.y)
+		tkt->deltatv.y = tkt->end.prev->orig.y;
+
+
+	e = tktsetscroll(tk, Tkvertical);
+	if(e != nil)
+		return e;
+	e = tktsetscroll(tk, Tkhorizontal);
+	if(e != nil)
+		return e;
+
+	tk->dirty = tkrect(tk, 1);
+	if(tktdbg)
+		tktcheck(tkt, "tktfixgeom end");
+	return nil;
+}
+
+static int
+tktpostspace(Tk *tk, TkTline *l)
+{
+	int ans;
+	TkTitem *i;
+	TkEnv env;
+	int *opts;
+
+	opts = mallocz(TkTnumopts*sizeof(int), 0);
+	if(opts == nil)
+		return 0;
+	ans = 0;
+	if(l->items != nil && (l->flags&TkTlast)) {
+		for(i = l->items; i->kind == TkTmark; )
+			i = i->next;
+		tkttagopts(tk, i, opts, &env, nil, 1);
+		ans = opts[TkTspacing3];
+	}
+	free(opts);
+	return ans;
+}
+
+static int
+tktprespace(Tk *tk, TkTline *l)
+{
+	int ans;
+	TkTitem *i;
+	TkEnv env;
+	int *opts;
+	
+	opts = mallocz(TkTnumopts*sizeof(int), 0);
+	if(opts == nil)
+		return 0;
+
+	ans = 0;
+	if(l->items != nil) {
+		for(i = l->items; i->kind == TkTmark; )
+			i = i->next;
+		tkttagopts(tk, i, opts, &env, nil, 1);
+		if(l->flags&TkTfirst)
+			ans = opts[TkTspacing1];
+		else
+			ans = opts[TkTspacing2];
+	}
+	free(opts);
+	return ans;
+}
+
+static int
+tktwidbetween(Tk *tk, int x, TkTindex *i1, TkTindex *i2)
+{
+	int d, w, n;
+	TkTindex ix;
+	TkText *tkt = TKobj(TkText, tk);
+
+	w = 0;
+	ix = *i1;
+	while(ix.item != i2->item) {
+		/* probably wrong w.r.t tag tabs */
+		d = tktdispwidth(tk, nil, ix.item, nil, x, ix.pos, -1);
+		w += d;
+		x += d;
+		if(!tktadjustind(tkt, TkTbyitem, &ix)) {
+			if(tktdbg)
+				print("tktwidbetween botch\n");
+			break;
+		}
+	}
+	n = i2->pos - ix.pos;
+	if(n > 0)
+		/* probably wrong w.r.t tag tabs */
+		w += tktdispwidth(tk, nil, ix.item, nil, x, ix.pos, i2->pos-ix.pos);
+	return w;
+}
+
+static Interval
+tktvclip(Interval i, int vh)
+{
+	if(i.lo < 0)
+		i.lo = 0;
+	if(i.hi > vh)
+		i.hi = vh;
+	return i;
+}
+
+/*
+ * Do translation of any part of interval that appears on screen
+ * starting at srcy to its new position, dsti.
+ * Return y-range of the hole left in the image (either because
+ * the src bits were out of the V window, or because the src bits
+ * vacated an area of the V window).
+ * The coordinates passed in and out are in T space.
+ */
+static Interval
+tkttranslate(Tk *tk, Interval dsti, int srcy)
+{
+	int vh, vw, dvty, locked;
+	TkText *tkt;
+	Image *i;
+	Interval hole, vdst, vsrc;
+	Point src;
+	Rectangle dst;
+	Display *d;
+
+	hole.hi = 0;
+	hole.lo = 0;
+
+
+	/*
+	 * If we are embedded in a text widget, we need to come in through
+	 * the tkdrawtext routine, to ensure our clipr is set properly, so we
+	 * just punt in that case.
+	 * XXX is just checking parent good enough. what if we're in
+	 * a frame in a text widget?
+	 * BUG!
+
+	* if(tk->parent != nil && tk->parent->type == TKtext) {
+	*	tk->flag |= Tkrefresh;
+	*	return hole;
+	* }
+	*/
+	tkt = TKobj(TkText, tk);
+	dvty = tkt->deltatv.y;
+	i = tkt->image;
+
+	vw = tk->act.width - tk->ipad.x;
+	vh = tk->act.height - tk->ipad.y;
+
+	/* convert to V space */
+	vdst.lo = dsti.lo - dvty;
+	vdst.hi = dsti.hi - dvty;
+	vsrc.lo = srcy - dvty;
+	vsrc.hi = vsrc.lo + dsti.hi - dsti.lo;
+	if(vsrc.lo == vsrc.hi || vsrc.lo == vdst.lo)
+		return hole;
+	else if(vsrc.hi <= 0 || vsrc.lo >= vh)
+		hole = tktvclip(vdst, vh);
+	else if(vdst.hi <= 0 || vdst.lo >= vh)
+		hole = tktvclip(vsrc, vh);
+	else if(i != nil) {
+		src.x = 0;
+		src.y = vsrc.lo;
+		if(vdst.lo > vsrc.lo) {  /* see earlier text lines */
+			if(vsrc.lo < 0) {
+				src.y = 0;
+				vdst.lo -= vsrc.lo;
+			}
+			if(vdst.hi > vh)
+				vdst.hi = vh;
+			hole.lo = src.y;
+			hole.hi = vdst.lo;
+		}
+		else {  /* see later text lines */
+			if(vsrc.hi > vh)
+				vdst.hi -= (vsrc.hi - vh);
+			if(vdst.lo < 0){
+				src.y -= vdst.lo;
+				vdst.lo = 0;
+			}
+			hole.lo = vdst.hi;
+			hole.hi = src.y + (vdst.hi - vdst.lo);
+		}
+		if(vdst.hi > vdst.lo && (tkt->tflag&TkTdrawn)) {
+			src = addpt(src, tkt->deltaiv);
+			dst = rectaddpt(Rect(0, vdst.lo, vw, vdst.hi), tkt->deltaiv);
+			d = tk->env->top->display;
+			locked = 0;
+			if(!(tkt->tflag&TkTdlocked))
+				locked = lockdisplay(d);
+			i = tkimageof(tk);
+			tkt->image = i;
+			if(i != nil)
+				draw(i, dst, i, nil, src);
+			if(locked)
+				unlockdisplay(d);
+		}
+	}
+	hole.lo += dvty;
+	hole.hi += dvty;
+	return hole;
+}
+
+/*
+ * mark lines from firsty to lasty as not drawn.
+ * firsty and lasty are in T space
+ */
+static void
+tktnotdrawn(Tk *tk, int firsty, int lasty, int all)
+{
+	TkTline *lend, *l;
+	TkText *tkt = TKobj(TkText, tk);
+	if(firsty >= lasty && !all)
+		return;
+	lend = &tkt->end;
+	for(l = tkt->start.next; l != lend; l = l->next) {
+		if(l->orig.y+l->height <= firsty)
+			continue;
+		if(l->orig.y >= lasty)
+			break;
+		l->flags &= ~TkTdrawn;
+		if (firsty > l->orig.y)
+			firsty = l->orig.y;
+		if (lasty < l->orig.y+l->height)
+			lasty = l->orig.y+l->height;
+	}
+	tktdrawbg(tk, firsty, lasty, all);
+	tk->dirty = tkrect(tk, 1);
+}
+
+/*
+ * firsty and lasty are in T space
+ */
+static void
+tktdrawbg(Tk *tk, int firsty, int lasty, int all)
+{
+	int vw, vh, locked;
+	Rectangle r;
+	Image *i;
+	Display *d;
+	TkText *tkt = TKobj(TkText, tk);
+
+	if(tk->env->top->root->flag & Tksuspended){
+		tk->flag |= Tkrefresh;
+		return;
+	}
+	/*
+	 * If we are embedded in a text widget, we need to come in through
+	 * the tkdrawtext routine, to ensure our clipr is set properly, so we
+	 * just punt in that case.
+	 * BUG!
+	 * if(tk->parent != nil && tk->parent->type == TKtext) {
+	 * 	tk->flag |= Tkrefresh;
+	 * 	return;
+	 * }
+	 */
+	vw = tk->act.width - tk->ipad.x;
+	vh = tk->act.height - tk->ipad.y;
+	if(all) {
+		/* whole background is to be drawn, not just until last line */
+		firsty = 0;
+		lasty = 100000;
+	}
+	if(firsty >= lasty)
+		return;
+	firsty -= tkt->deltatv.y;
+	lasty -= tkt->deltatv.y;
+	if(firsty < 0)
+		firsty = 0;
+	if(lasty > vh)
+		lasty = vh;
+	r = rectaddpt(Rect(0, firsty, vw, lasty), tkt->deltaiv);
+	if(r.min.y < r.max.y && (tkt->tflag&TkTdrawn)) {
+		d = tk->env->top->display;
+		locked = 0;
+		if(!(tkt->tflag&TkTdlocked))
+			locked = lockdisplay(d);
+		i = tkimageof(tk);
+		tkt->image = i;
+		if(i != nil)
+			draw(i, r, tkgc(tk->env, TkCbackgnd), nil, ZP);
+		if(locked)
+			unlockdisplay(d);
+	}
+}
+
+static void
+tktfixscroll(Tk *tk, Point odeltatv)
+{
+	int lasty;
+	Interval oi, hole;
+	Rectangle oclipr;
+	Image *dst;
+	Point ndeltatv;
+	TkText *tkt = TKobj(TkText, tk);
+
+	ndeltatv = tkt->deltatv;
+
+	if(eqpt(odeltatv, ndeltatv))
+		return;
+
+	/* set clipr to avoid spilling outside (in case didn't come in through draw) */
+	dst = tkimageof(tk);
+	if(dst != nil) {
+		tkt->image = dst;
+		oclipr = dst->clipr;
+		tktsetclip(tk);
+	}
+
+	lasty = tkt->end.orig.y;
+	if(odeltatv.x != ndeltatv.x)
+		tktnotdrawn(tk, ndeltatv.y, lasty, 0);
+	else {
+		oi.lo = odeltatv.y;
+		oi.hi = lasty;
+		hole = tkttranslate(tk, oi, ndeltatv.y);
+		tktnotdrawn(tk, hole.lo, hole.hi, 0);
+	}
+	if(dst != nil)
+		tktreplclipr(dst, oclipr);
+}
+
+void
+tktextgeom(Tk *tk)
+{
+	TkTindex ix;
+	Rectangle oclipr;
+	Image *dst;
+	TkText *tkt = TKobj(TkText, tk);
+	char buf[20], *p;
+
+	tkt->tflag &= ~TkTdrawn;
+	tktsetdeltas(tk, ZP);
+	/* find index of current top-left, so can see it again */
+	tktxyind(tk, 0, 0, &ix);
+	/* make sure scroll bar is redrawn */
+	tkt->scrolltop[Tkvertical] = -1;
+	tkt->scrolltop[Tkhorizontal] = -1;
+	tkt->scrollbot[Tkvertical] = -1;
+	tkt->scrollbot[Tkhorizontal] = -1;
+
+	/* set clipr to avoid spilling outside (didn't come in through draw) */
+	dst = tkimageof(tk);
+	if(dst != nil) {
+		tkt->image = dst;
+		oclipr = dst->clipr;
+		tktsetclip(tk);
+	}
+
+	/*
+	 * have to save index in a reusable format, as
+	 * tktfixgeom can free everything that ix points to.
+	 */
+	snprint(buf, sizeof(buf), "%d.%d", tktlinenum(tkt, &ix), tktlinepos(tkt, &ix));
+	tktfixgeom(tk, &tkt->start, tkt->end.prev, 1);
+	p = buf;
+	tktindparse(tk, &p, &ix);		/* restore index to something close to original value */
+	tktsee(tk, &ix, 1);
+
+	if(dst != nil)
+		tktreplclipr(dst, oclipr);
+}
+
+static char*
+tktsetscroll(Tk *tk, int orient)
+{
+	TkText *tkt;
+	TkTline *l;
+	int ntot, nmin, nmax, top, bot, vw, vh;
+	char *val, *cmd, *v, *e, *s;
+
+	tkt = TKobj(TkText, tk);
+
+	s = (orient == Tkvertical)? tkt->yscroll : tkt->xscroll;
+	if(s == nil)
+		return nil;
+
+	vw = tk->act.width - tk->ipad.x;
+	vh = tk->act.height - tk->ipad.y;
+
+	if(orient == Tkvertical) {
+		l = tkt->end.prev;
+		ntot = l->orig.y + l->height;
+		nmin = tkt->deltatv.y;
+		if(vh <= 0)
+			nmax = nmin;
+		else
+			nmax = nmin + vh;
+	}
+	else {
+		ntot = tktmaxwid(tkt->start.next);
+		nmin = tkt->deltatv.x;
+		if(vw <= 0)
+			nmax = nmin;
+		else
+			nmax = nmin + vw;
+	}
+
+	if(ntot == 0) {
+		top = 0;
+		bot = TKI2F(1);
+	}
+	else {
+		if(ntot < nmax)
+			ntot = nmax;
+		top = TKI2F(nmin)/ntot;
+		bot = TKI2F(nmax)/ntot;
+	}
+
+	if(tkt->scrolltop[orient] == top && tkt->scrollbot[orient] == bot)
+		return nil;
+
+	tkt->scrolltop[orient] = top;
+	tkt->scrollbot[orient] = bot;
+
+	val = mallocz(Tkminitem, 0);
+	if(val == nil)
+		return TkNomem;
+	cmd = mallocz(Tkmaxitem, 0);
+	if(cmd == nil) {
+		free(val);
+		return TkNomem;
+	}
+
+	v = tkfprint(val, top);
+	*v++ = ' ';
+	tkfprint(v, bot);
+	snprint(cmd, Tkmaxitem, "%s %s", s, val);
+	e = tkexec(tk->env->top, cmd, nil);
+	free(cmd);
+	free(val);
+	return e;
+}
+
+static char*
+tktview(Tk *tk, char *arg, char **val, int nl, int *posn, int max, int orient)
+{
+	int top, bot, amount, n;
+	char buf[Tkminitem], *v, *e;
+
+	if(*arg == '\0') {
+		if ( max == 0 ) {
+			top = 0;
+			bot = TKI2F(1);
+		}
+		else {
+			top = TKI2F(*posn)/max;
+			bot = TKI2F(*posn+nl)/max;
+			if (bot > TKI2F(1))
+				bot = TKI2F(1);
+		}
+		v = tkfprint(buf, top);
+		*v++ = ' ';
+		tkfprint(v, bot);
+		return tkvalue(val, "%s", buf);
+	}
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(strcmp(buf, "moveto") == 0) {
+		e = tkfracword(tk->env->top, &arg, &top, nil);
+		if (e != nil)
+			return e;
+		*posn = TKF2I(top*max);
+	}
+	else
+	if(strcmp(buf, "scroll") == 0) {
+		e = tkfracword(tk->env->top, &arg, &amount, nil);
+		if(e != nil)
+			return e;
+		arg = tkskip(arg, " \t");
+		if(*arg == 'p')		/* Pages */
+			amount *= nl;
+		else				/* Lines or Characters */
+		if(orient == Tkvertical) {
+			/* XXX needs improvement */
+			amount *= tk->env->font->height;
+		}
+		else
+			amount *= tk->env->wzero;
+		amount = TKF2I(amount);
+		n = *posn + amount;
+		if(n < 0)
+			n = 0;
+		if(n > max)
+			n = max;
+		*posn = n;
+	}
+	else	
+		return TkBadcm;
+
+	bot = max - (nl * 3 / 4);
+	if(*posn > bot)
+		*posn = bot;
+	if(*posn < 0)
+		*posn = 0;
+
+	return nil;
+}
+
+static void
+tktclearsel(Tk *tk)
+{
+	TkTindex ibeg, iend;
+	TkText *tkt = TKobj(TkText, tk);
+
+	if(tkt->selfirst == nil)
+		return;
+	tktitemind(tkt->selfirst, &ibeg);
+	tktitemind(tkt->sellast, &iend);
+
+	tkttagchange(tk, TkTselid, &ibeg, &iend, 0);
+}
+
+static int
+tktgetsel(Tk *tk, TkTindex *i1, TkTindex *i2)
+{
+	TkText *tkt =TKobj(TkText, tk);
+
+	if(tkt->selfirst == nil)
+		return 0;
+	tktitemind(tkt->selfirst, i1);
+	tktitemind(tkt->sellast, i2);
+	return 1;
+}
+
+/*
+ * Adjust tkt->deltatv so that indexed character is visible.
+ *	- if seetop is true, make indexed char be at top of window
+ *	- if it is already visible, do nothing.
+ *	- if it is > 1/2 screenful off edge of screen, center it
+ *	   else put it at bottom or top (whichever is nearer)
+ *	- if first line is visible, put it at top
+ *	- if last line is visible, allow one blank line at bottom
+ *
+ * BUG: should handle x visibility too
+ */
+static void
+tktsee(Tk *tk, TkTindex *ixp, int seetop)
+{
+	int ycur, ynext, deltatvy, adjy, h;
+	Point p, odeltatv;
+	Rectangle bbox;
+	TkTline *l, *el;
+	TkText *tkt = TKobj(TkText, tk);
+	TkTindex ix;
+
+	ix = *ixp;
+	deltatvy = tkt->deltatv.y;
+	odeltatv = tkt->deltatv;
+	h = tk->act.height;
+
+	/* find p (in T space): top left of indexed line */
+	l = ix.line;
+	p = l->orig;
+
+	/* ycur, ynext in V space */
+	ycur = p.y - deltatvy;
+	ynext = ycur + l->height;
+	adjy = 0;
+
+	/* quantize h to line boundaries (works if single font) */
+	if ( l->height )
+		h -= h%l->height;
+
+	if(seetop) {
+		deltatvy = p.y;
+		adjy = 1;
+	}
+	else
+	if(ycur < 0 || ynext >= h) {
+		adjy = 1;
+
+		if(ycur < -h/2 || ycur > 3*h/2)
+			deltatvy = p.y - h/2;
+		else if(ycur < 0)
+			deltatvy = p.y;
+		else
+			deltatvy = p.y - h + l->height;
+
+		el = tkt->end.prev;
+		if(el != nil && el->orig.y - deltatvy < h)
+			deltatvy = tkt->end.orig.y - (h * 3 / 4);
+
+		if(p.y - deltatvy < 0)
+			deltatvy = p.y;
+		if(deltatvy < 0)
+			deltatvy = 0;
+	}
+	if(adjy) {
+		tkt->deltatv.y = deltatvy;
+		tktsetscroll(tk, Tkvertical);	/* XXX - Tad: err ignored */
+		tktfixscroll(tk, odeltatv);
+	}
+	while (ix.item->kind == TkTmark)
+		ix.item = ix.item->next;
+	bbox = tktbbox(tk, &ix);
+	/* make sure that cursor at the end gets shown */
+	tksee(tk, bbox, Pt(bbox.min.x, (bbox.min.y + bbox.max.y) / 2));
+}
+
+static int
+tktcmatch(int c1, int c2, int nocase)
+{
+	if(nocase) {
+		if(c1 >= 'a' && c1 <= 'z')
+			c1 -= 'a' - 'A';
+		if(c2 >= 'a' && c2 <= 'z')
+			c2 -= 'a' - 'A';
+	}
+	return (c1 == c2);
+}
+
+/*
+ * Return 1 if tag with id m1 ends before tag with id m2,
+ * starting at the item after that indexed in ix (but don't
+ * modify ix).
+ */
+static int
+tagendsbefore(TkText *tkt, TkTindex *ix, int m1, int m2)
+{
+	int s1, s2;
+	TkTindex ix1;
+	TkTitem *i;
+
+	ix1 = *ix;
+	while(tktadjustind(tkt, TkTbyitem, &ix1)) {
+		i = ix1.item;
+		if(i->kind == TkTwin || i->kind == TkTcontline || i->kind == TkTmark)
+			continue;
+		s1 = tkttagset(i, m1);
+		s2 = tkttagset(i, m2);
+		if(!s1)
+			return s2;
+		else if(!s2)
+			return 0;
+	}
+	return 0;
+}
+
+static int
+tktsgmltags(TkText *tkt, Fmt *fmt, TkTitem *iprev, TkTitem *i, TkTindex *ix, int *stack, int *pnstack, int *tmpstack)
+{
+	int nprev, n, m, r, k, j, ii, onstack, nt;
+
+	nprev = 0;
+	if(iprev != nil && (iprev->tags[0] != 0 || iprev->tagextra > 0))
+		nprev = 32*(iprev->tagextra + 1);
+	n = 0;
+	if(i != nil && (i->tags[0] != 0 || i->tagextra > 0))
+		n = 32*(i->tagextra + 1);
+	nt = 0;
+	if(n > 0) {
+		/* find tags which open here */
+		for(m = 0; m < n; m++)
+			if(tkttagset(i, m) && (iprev == nil || !tkttagset(iprev, m)))
+				tmpstack[nt++] = m;
+	}
+	if(nprev > 0) {
+		/*
+		 * Find lowest tag in stack that ends before any tag beginning here.
+		 * We have to emit end tags all the way down to there, then add
+		 * back the ones that haven't actually ended here, together with ones
+		 * that start here, and sort all of the added ones so that tags that
+		 * end later are lower in the stack.
+		 */
+		ii = *pnstack;
+		for(k = *pnstack - 1; k >=0; k--) {
+			m = stack[k];
+			if(i == nil || !tkttagset(i, m))
+				ii = k;
+			else
+				for(j = 0; j < nt; j++)
+					if(tagendsbefore(tkt, ix, m, tmpstack[j]))
+						ii = k;
+		}
+		for(k = *pnstack - 1; k >= ii; k--) {
+			m = stack[k];
+			r = fmtprint(fmt, "</%s>", tkttagname(tkt, m));
+			if(r < 0)
+				return r;
+			/* add m back to starting tags if m didn't actually end here */
+			if(i != nil && tkttagset(i, m))
+				tmpstack[nt++] = m;
+		}
+		*pnstack = ii;
+	}
+	if(nt > 0) {
+		/* add tags which open  or reopen here */
+		onstack = *pnstack;
+		k = onstack;
+		for(j = 0; j < nt; j++)
+			stack[k++] = tmpstack[j];
+		*pnstack = k;
+		if(k - onstack > 1) {
+			/* sort new stack entries so tags that end later are lower in stack */
+			for(ii = k-2; ii>= onstack; ii--) {
+				m = stack[ii];
+				for(j = ii+1; j < k && tagendsbefore(tkt, ix, m, stack[j]); j++) {
+					stack[j-1] = stack[j];
+				}
+				stack[j-1] = m;
+			}
+		}
+		for(j = onstack; j < k; j++) {
+			r = fmtprint(fmt, "<%s>", tkttagname(tkt, stack[j]));
+			if(r < 0)
+				return r;
+		}
+	}
+	return 0;
+}
+
+/*
+ * In 'sgml' format, just print text (no special treatment of
+ * special characters, except that < turns into &lt;)
+ * interspersed with things like <Bold> and </Bold>
+ * (where Bold is a tag name).
+ * Make sure that the tag pairs nest properly.
+*/
+static char*
+tktget(TkText *tkt, TkTindex *ix1, TkTindex *ix2, int sgml, char **val)
+{
+	int n, m, i, bychar, nstack;
+	int *stack, *tmpstack;
+	char *s;
+	TkTitem *iprev;
+	Tk *sub;
+	Fmt fmt;
+	char *buf;
+
+	if(!tktindbefore(ix1, ix2))
+		return nil;
+
+	stack = nil;
+	tmpstack = nil;
+
+	iprev = nil;
+	fmtstrinit(&fmt);
+	buf = mallocz(100, 0);
+	if(buf == nil)
+		return TkNomem;
+	if(sgml) {
+		stack = malloc((tkt->nexttag+1)*sizeof(int));
+		tmpstack = malloc((tkt->nexttag+1)*sizeof(int));
+		if(stack == nil || tmpstack == nil)
+			goto nomemret;
+		nstack = 0;
+	}
+	for(;;) {
+		if(ix1->item == ix2->item && ix1->pos == ix2->pos)
+			break;
+		s = nil;
+		bychar = 0;
+		m = 1;
+		switch(ix1->item->kind) {
+		case TkTrune:
+			s = ix1->item->istring;
+			s += tktutfpos(s, ix1->pos);
+			if(ix1->item == ix2->item) {
+				m = ix2->pos - ix1->pos;
+				bychar = 1;
+			}
+			break;
+		case TkTascii:
+			s = ix1->item->istring + ix1->pos;
+			if(ix1->item == ix2->item) {
+				m = ix2->pos - ix1->pos;
+				bychar = 1;
+			}
+			else {
+				m = strlen(s);
+				if(sgml && memchr(s, '<', m) != nil)
+					bychar = 1;
+			}
+			break;
+		case TkTtab:
+			s = "\t";
+			break;
+		case TkTnewline:
+			s = "\n";
+			break;
+		case TkTwin:
+			sub = ix1->item->iwin->sub;
+			if(sgml &&  sub != nil && sub->name != nil) {
+				snprint(buf, 100, "<Window %s>", sub->name->name);
+				s = buf;
+			}
+		}
+		if(s != nil) {
+			if(sgml) {
+				n = tktsgmltags(tkt, &fmt, iprev, ix1->item, ix1, stack, &nstack, tmpstack);
+				if(n < 0)
+					goto nomemret;
+			}
+			if(bychar) {
+				if (ix1->item->kind == TkTrune)
+					n = fmtprint(&fmt, "%.*s", m, s);
+				else {
+					n = 0;
+					for(i = 0; i < m && n >= 0; i++) {
+						if(s[i] == '<')
+							n = fmtprint(&fmt, "&lt;");
+						else
+							n = fmtprint(&fmt, "%c", s[i]);
+					}
+				}
+			}
+			else
+				n = fmtprint(&fmt, "%s", s);
+			if(n < 0)
+				goto nomemret;
+			iprev = ix1->item;
+		}
+		if(ix1->item == ix2->item)
+			break;
+		if(!tktadjustind(tkt, TkTbyitem, ix1)) {
+			if(tktdbg)
+				print("tktextget botch\n");
+			break;
+		}
+	}
+	if(sgml) {
+		n = tktsgmltags(tkt, &fmt, iprev, nil, nil, stack, &nstack, tmpstack);
+		if(n < 0)
+			goto nomemret;
+	}
+
+	*val = fmtstrflush(&fmt);
+	free(buf);
+	return nil;
+
+nomemret:
+	free(buf);
+	if(stack != nil)
+		free(stack);
+	if(tmpstack != nil)
+		free(tmpstack);
+	return TkNomem;
+}
+
+/* Widget Commands (+ means implemented)
+	+bbox
+	+cget
+	+compare
+	+configure
+	+debug
+	+delete
+	+dlineinfo
+	+dump
+	+get
+	+index
+	+insert
+	+mark
+	+scan
+	+search
+	+see
+	+tag
+	+window
+	+xview
+	+yview
+*/
+
+static int
+tktviewrectclip(Rectangle *r, Rectangle b);
+
+static char*
+tktextbbox(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	int noclip, w, h;
+	Rectangle r, rview;
+	TkTindex ix;
+	TkText *tkt;
+	char buf[Tkmaxitem];
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+
+	noclip = 0;
+	if(*arg != '\0') {
+		/* extension to tk4.0:
+		 * "noclip" means don't clip to viewable area
+		 * "all" means give unclipped bbox of entire contents
+		 */
+		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		if(strcmp(buf, "noclip") == 0)
+			noclip = 1;
+		else
+		if(strcmp(buf, "all") == 0) {
+			tkt = TKobj(TkText, tk);
+			w = tktmaxwid(tkt->start.next);
+			h = tkt->end.orig.y;
+			return tkvalue(val, "0 0 %d %d", w, h);
+		}
+	}
+
+	/*
+	 * skip marks; bbox applies to characters only.
+	 * it's not defined what happens when bbox is applied to a newline char,
+	 * so we'll just let the default case sort that out.
+	 */
+	while (ix.item->kind == TkTmark)
+		ix.item = ix.item->next;
+	r = tktbbox(tk, &ix);
+
+	rview.min.x = 0;
+	rview.min.y = 0;
+	rview.max.x = tk->act.width - tk->ipad.x;
+	rview.max.y = tk->act.height - tk->ipad.y;
+	if(noclip || tktviewrectclip(&r, rview))
+		return tkvalue(val, "%d %d %d %d", r.min.x, r.min.y,
+			r.max.x-r.min.x, r.max.y-r.min.y);
+	return nil;
+}
+
+/*
+ * a supplemented rectclip, as ((0, 1), (0,1)) does not intersect ((0, 0), (5, 5))
+ * but for our purposes, we want it to. it's a hack.
+ */
+static int
+tktviewrectclip(Rectangle *rp, Rectangle b)
+{
+	Rectangle *bp = &b;
+	if((rp->min.x<bp->max.x &&
+		(bp->min.x<rp->max.x || (rp->max.x  == b.min.x
+				&& rp->min.x == b.min.x)) &&
+			rp->min.y<bp->max.y && bp->min.y<rp->max.y)==0)
+		return 0;
+	/* They must overlap */
+	if(rp->min.x < bp->min.x)
+		rp->min.x = bp->min.x;
+	if(rp->min.y < bp->min.y)
+		rp->min.y = bp->min.y;
+	if(rp->max.x > bp->max.x)
+		rp->max.x = bp->max.x;
+	if(rp->max.y > bp->max.y)
+		rp->max.y = bp->max.y;
+	return 1;
+}
+
+static Point
+scr2local(Tk *tk, Point p)
+{
+	p = subpt(p, tkposn(tk));
+	p.x -= tk->borderwidth;
+	p.y -= tk->borderwidth;
+	return p;
+}
+
+static char*
+tktextbutton1(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	Point p;
+	TkCtxt *c;
+	TkTindex ix;
+	TkTmarkinfo *mi;
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(val);
+
+	e = tkxyparse(tk, &arg, &p);
+	if(e != nil)
+		return e;
+	tkt->track = p;
+	p = scr2local(tk, p);
+
+	tktxyind(tk, p.x, p.y, &ix);
+	tkt->tflag &= ~TkTjustfoc;
+	c = tk->env->top->ctxt;
+	if(!(tk->flag&Tkdisabled) && c->tkkeygrab != tk 
+                      && (tk->name != nil) && ix.item->kind != TkTwin) {
+		tkfocus(tk->env->top, tk->name->name, nil);
+		tkt->tflag |= TkTjustfoc;
+		return nil;
+	}
+
+	mi = tktfindmark(tkt->marks, "insert");
+	if(tktdbg && !mi) {
+		print("tktextbutton1: botch\n");
+		return nil;
+	}
+	tktmarkmove(tk, mi, &ix);
+
+	tktclearsel(tk);
+	tkrepeat(tk, autoselect, nil, TkRptpause, TkRptinterval);
+	return nil;
+}
+
+static char*
+tktextbutton1r(Tk *tk, char *arg, char **val)
+{
+	TkText *tkt;
+
+	USED(arg);
+	USED(val);
+
+	tkt = TKobj(TkText, tk);
+	tkt->tflag &= ~TkTnodrag;
+	tkcancelrepeat(tk);
+	return nil;
+}
+
+static char*
+tktextcget(Tk *tk, char *arg, char **val)
+{
+	TkText *tkt;
+	TkOptab tko[3];
+
+	tkt = TKobj(TkText, tk);
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkt;
+	tko[1].optab = textopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tktextcompare(Tk *tk, char *arg, char **val)
+{
+	int op;
+	char *e;
+	TkTindex i1, i2;
+	TkText *tkt;
+	TkStab *s;
+	char *buf;
+
+	tkt = TKobj(TkText, tk);
+
+	e = tktindparse(tk, &arg, &i1);
+	if(e != nil)
+		return e;
+
+	if(*arg == '\0')
+		return TkBadcm;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+
+	op = -1;
+	for(s = tkcompare; s->val; s++)
+		if(strcmp(s->val, buf) == 0) {
+			op = s->con;
+			break;
+		}
+	if(op == -1) {
+		free(buf);
+		return TkBadcm;
+	}
+
+	e = tktindparse(tk, &arg, &i2);
+	if(e != nil) {
+		free(buf);
+		return e;
+	}
+
+	e = tkvalue(val, tktindcompare(tkt, &i1, op, &i2)? "1" : "0");
+	free(buf);
+	return e;
+}
+
+static char*
+tktextconfigure(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkGeom g;
+	int bd;
+	TkText *tkt;
+	TkOptab tko[3];
+	tkt = TKobj(TkText, tk);
+	tko[0].ptr = tk;
+	tko[0].optab = tkgeneric;
+	tko[1].ptr = tkt;
+	tko[1].optab = textopts;
+	tko[2].ptr = nil;
+
+	if(*arg == '\0')
+		return tkconflist(tko, val);
+
+	g = tk->req;
+	bd = tk->borderwidth;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	tksettransparent(tk, tkhasalpha(tk->env, TkCbackgnd));
+	if (tkt->propagate != BoolT) {
+		if ((tk->flag & Tksetwidth) == 0)
+			tk->req.width = tk->env->wzero*Textwidth;
+		if ((tk->flag & Tksetheight) == 0)
+			tk->req.height = tk->env->font->height*Textheight;
+	}
+	/* note: tkgeomchg() may also call tktfixgeom() via tktextgeom() */
+	tktfixgeom(tk, &tkt->start, tkt->end.prev, 0);
+	tktextsize(tk, 0);
+	tkgeomchg(tk, &g, bd);
+	tktnotdrawn(tk, 0, tkt->end.orig.y, 1);
+
+	return e;
+}
+
+static char*
+tktextdebug(Tk *tk, char *arg, char **val)
+{
+	char buf[Tkmaxitem];
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(*buf == '\0')
+		return tkvalue(val, "%s", tktdbg? "on" : "off");
+	else {
+		tktdbg = (strcmp(buf, "1") == 0 || strcmp(buf, "yes") == 0);
+		if(tktdbg) {
+			tktprinttext(TKobj(TkText, tk));
+		}
+		return nil;
+	}
+}
+
+static char*
+tktextdelete(Tk *tk, char *arg, char **val)
+{
+	int sameit;
+	char *e;
+	TkTindex i1, i2, ip, isee;
+	TkTline *lmin;
+	TkText *tkt = TKobj(TkText, tk);
+	char buf[20], *p;
+
+	USED(val);
+
+	e = tktindparse(tk, &arg, &i1);
+	if(e != nil)
+		return e;
+	tktadjustind(tkt, TkTbycharstart, &i1);
+
+	e = tktsplititem(&i1);
+	if(e != nil)
+		return e;
+
+	if(*arg != '\0') {
+		e = tktindparse(tk, &arg, &i2);
+		if(e != nil)
+			return e;
+	}
+	else {
+		i2 = i1;
+		tktadjustind(tkt, TkTbychar, &i2);
+	}
+	if(tktindcompare(tkt, &i1, TkGte, &i2))
+		return nil;
+
+	sameit = (i1.item == i2.item);
+
+	/* save possible fixup see place */
+	isee.line = nil;
+	if(i2.line->orig.y + i2.line->height < tkt->deltatv.y) {
+		/* delete completely precedes view */
+		tktxyind(tk, 0, 0, &isee);
+	}
+
+	e = tktsplititem(&i2);
+	if(e != nil)
+		return e;
+
+	if(sameit) {
+		/* after split, i1 should be in previous item to i2 */
+		ip = i2;
+		tktadjustind(tkt, TkTbyitemback, &ip);
+		i1.item = ip.item;
+	}
+
+	lmin = tktprevwrapline(tk, i1.line);
+	while(i1.item != i2.item) {
+		if(i1.item->kind != TkTmark)
+			tktremitem(tkt, &i1);
+			/* tktremitem moves i1 to next item */
+		else {
+			if(!tktadjustind(tkt, TkTbyitem, &i1)) {
+				if(tktdbg)
+					print("tktextdelete botch\n");
+				break;
+			}
+		}
+	}
+
+	/*
+	 * guard against invalidation of index by tktfixgeom
+	 */
+	if (isee.line != nil)
+		snprint(buf, sizeof(buf), "%d.%d", tktlinenum(tkt, &isee), tktlinepos(tkt, &isee));
+
+	tktfixgeom(tk, lmin, i1.line, 0);
+	tktextsize(tk, 1);
+	if(isee.line != nil) {
+		p = buf;
+		tktindparse(tk, &p, &isee);
+		tktsee(tk, &isee, 1);
+	}
+	return nil;
+}
+
+static char*
+tktextsee(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+
+	USED(val);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+
+	tktsee(tk, &ix, 0);
+	return nil;
+}
+
+static char*
+tktextdelins(Tk *tk, char *arg, char **val)
+{
+	int m, c, skipping, wordc, n;
+	TkTindex ix, ix2;
+	TkText *tkt = TKobj(TkText, tk);
+	char buf[30];
+
+	USED(val);
+
+	if(tk->flag&Tkdisabled)
+		return nil;
+
+	if(tktgetsel(tk, &ix, &ix2))
+		tktextdelete(tk, "sel.first sel.last", nil);
+	else {
+		while(*arg == ' ')
+			arg++;
+		if(*arg == '-') {
+			m = arg[1];
+			if(m == 'c')
+				n = 1;
+			else {
+				/* delete prev word (m=='w') or prev line (m=='l') */
+				if(!tktmarkind(tk, "insert", &ix))
+					return nil;
+				if(!tktadjustind(tkt, TkTbycharback, &ix))
+					return nil;
+				n = 1;
+				/* ^W skips back over nonwordchars, then takes maximal seq of wordchars */
+				skipping = 1;
+				for(;;) {
+					c = tktindrune(&ix);
+					if(c == '\n') {
+						/* special case: always delete at least one char */
+						if(n > 1)
+							n--;
+						break;
+					}
+					if(m == 'w') {
+						wordc = tkiswordchar(c);
+						if(wordc && skipping)
+							skipping = 0;
+						else if(!wordc && !skipping) {
+							n--;
+							break;
+						}
+					}
+					if(tktadjustind(tkt, TkTbycharback, &ix))
+						n++;
+					else
+						break;
+				}
+			}
+			sprint(buf, "insert-%dc insert", n);
+			tktextdelete(tk, buf, nil);
+		}
+		else if(arg[0] == '+' && arg[1] == 'l')
+			tktextdelete(tk, "insert {insert lineend}", nil);
+		else
+			tktextdelete(tk, "insert", nil);
+		tktextsee(tk, "insert", nil);
+	}
+	return nil;
+}
+
+static char*
+tktextdlineinfo(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+	TkTline *l;
+	Point p;
+	int vh;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+
+	l = ix.line;
+	vh = tk->act.height;
+
+	/* get p in V space */
+	p = subpt(l->orig, tkt->deltatv);
+	if(p.y+l->height < 0 || p.y >= vh)
+		return nil;
+
+	return tkvalue(val, "%d %d %d %d %d",
+		p.x, p.y, l->width, l->height, l->ascent);
+}
+
+static char*
+tktextdump(Tk *tk, char *arg, char **val)
+{
+	TkTline *l;
+	TkTitem *i;
+	Fmt fmt;
+	TkText *tkt;
+	TkDump tkdump;
+	TkOptab tko[2];
+	TkTtaginfo *ti;
+	TkName *names, *n;
+	char *e, *win, *p;
+	TkTindex ix1, ix2;
+	int r, j, numitems;
+	ulong fg, bg;
+
+	tkt = TKobj(TkText, tk);
+
+
+	tkdump.sgml = 0;
+	tkdump.metrics = 0;
+
+	tko[0].ptr = &tkdump;
+	tko[0].optab = dumpopts;
+	tko[1].ptr = nil;
+	names = nil;
+	e = tkparse(tk->env->top, arg, tko, &names);
+	if(e != nil)
+		return e;
+
+	if(names != nil) {			/* supplied indices */
+		p = names->name;
+		e = tktindparse(tk, &p, &ix1);
+		if(e != nil) {
+			tkfreename(names);
+			return e;
+		}
+		n = names->link;
+		if(n != nil) {
+			p = n->name;
+			e = tktindparse(tk, &p, &ix2);
+			if(e != nil) {
+				tkfreename(names);
+				return e;
+			}
+		}
+		else {		
+			ix2 = ix1;
+			tktadjustind(tkt, TkTbychar, &ix2);
+		}
+		tkfreename(names);
+		if(!tktindbefore(&ix1, &ix2))
+			return nil;
+	}
+	else
+		return TkBadix;
+	
+	if(tkdump.metrics != 0) {
+		fmtstrinit(&fmt);
+		if(fmtprint(&fmt, "%%Fonts\n") < 0)
+			return TkNomem;
+		for(ti=tkt->tags; ti != nil; ti=ti->next) {
+			if(ti->env == nil || ti->env->font == nil)
+				continue;
+			if(fmtprint(&fmt, "%d::%s\n", ti->id,ti->env->font->name) < 0)
+				return TkNomem;
+		}
+		if(fmtprint(&fmt, "-1::%s\n%%Colors\n", tk->env->font->name) < 0)
+			return TkNomem;
+		for(ti=tkt->tags; ti != nil; ti=ti->next) {
+			if(ti->env == nil)
+				continue;
+			bg = ti->env->colors[TkCbackgnd];
+			fg = ti->env->colors[TkCforegnd];
+			if(bg == tk->env->colors[TkCbackgnd] &&
+			   fg == ti->env->colors[TkCforegnd])
+				continue;
+			r = fmtprint(&fmt,"%d::#%.8lux\n", ti->id, bg);
+			if(r < 0)
+				return TkNomem;
+			r = fmtprint(&fmt,"%d::#%.8lux\n", ti->id, fg);
+			if(r < 0)
+				return TkNomem;
+		}
+		if(fmtprint(&fmt, "%%Lines\n") < 0)
+			return TkNomem;
+
+		/*
+		 * In 'metrics' format lines are recorded in the following way:
+		 *    xorig yorig wd ht as [data]
+		 * where data is of the form:
+		 *    CodeWidth{tags} data
+		 * For Example;
+		 *    A200{200000} Hello World!
+		 * denotes an A(scii) contiguous string of 200 pixels with
+		 * bit 20 set in its tags which corresponds to some font.
+		 *
+	 	*/
+		if(ix2.line->items != ix2.item)
+			ix2.line = ix2.line->next;
+		for(l = ix1.line; l != ix2.line; l = l->next) {
+			numitems = 0;
+			for(i = l->items; i != nil; i = i->next) {
+				if(i->kind != TkTmark)
+					numitems++;
+			}
+			r = fmtprint(&fmt, "%d %d %d %d %d %d ",
+				l->orig.x, l->orig.y, l->width, l->height, l->ascent,numitems);
+			if(r < 0)
+				return TkNomem;
+			for(i = l->items; i != nil; i = i->next) {
+				switch(i->kind) {
+				case TkTascii:
+				case TkTrune:
+					r = i->kind == TkTascii ? 'A' : 'R';
+					if(fmtprint(&fmt,"[%c%d{", r, i->width) < 0)
+						return TkNomem;
+					if(i->tags !=0 || i->tagextra !=0) {
+						if(fmtprint(&fmt,"%lux", i->tags[0]) < 0)
+							return TkNomem;
+						for(j=0; j < i->tagextra; j++)
+							if(fmtprint(&fmt,"::%lux", i->tags[j+1]) < 0)
+								return TkNomem;
+					}
+					/* XXX string should be quoted to avoid embedded ']'s */
+					if(fmtprint(&fmt,"}%s]", i->istring) < 0)
+						return TkNomem;
+					break;
+				case TkTnewline:
+				case TkTcontline:
+					r = i->kind == TkTnewline ? 'N' : 'C';
+					if(fmtprint(&fmt, "[%c]", r) < 0)
+						return TkNomem;
+					break;
+				case TkTtab:
+					if(fmtprint(&fmt,"[T%d]",i->width) < 0)
+						return TkNomem;
+					break;
+				case TkTwin:
+					win = "<null>";
+					if(i->iwin->sub != nil)
+						win = i->iwin->sub->name->name;
+					if(fmtprint(&fmt,"[W%d %s]",i->width, win) < 0)
+						return TkNomem;
+					break;
+				}
+				if(fmtprint(&fmt, " ") < 0)
+					return TkNomem;
+	
+			}
+			if(fmtprint(&fmt, "\n") < 0)
+				return TkNomem;
+			*val = fmtstrflush(&fmt);
+			if(*val == nil)
+				return TkNomem;
+		}
+	}
+	else
+		return tktget(tkt, &ix1, &ix2, tkdump.sgml, val);
+
+	return nil;
+}
+
+
+static char*
+tktextget(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix1, ix2;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tktindparse(tk, &arg, &ix1);
+	if(e != nil)
+		return e;
+
+	if(*arg != '\0') {
+		e = tktindparse(tk, &arg, &ix2);
+		if(e != nil)
+			return e;
+	}
+	else {
+		ix2 = ix1;
+		tktadjustind(tkt, TkTbychar, &ix2);
+	}
+	return tktget(tkt, &ix1, &ix2, 0, val);
+}
+
+static char*
+tktextindex(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+	return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix), tktlinepos(tkt, &ix));
+}
+
+static char*
+tktextinsert(Tk *tk, char *arg, char **val)
+{
+	int n;
+	char *e, *p, *pe;
+	TkTindex ins, pins;
+	TkTtaginfo *ti;
+	TkText *tkt;
+	TkTline *lmin;
+	TkTop *top;
+	TkTitem *tagit;
+	char *tbuf, *buf;
+
+	USED(val);
+
+	tkt = TKobj(TkText, tk);
+	top = tk->env->top;
+
+	e = tktindparse(tk, &arg, &ins);
+	if(e != nil)
+		return e;
+
+	if(ins.item->kind == TkTmark) {
+		if(ins.item->imark->gravity == Tkleft) {
+			while(ins.item->kind == TkTmark && ins.item->imark->gravity == Tkleft)
+				if(!tktadjustind(tkt, TkTbyitem, &ins)) {
+					if(tktdbg)
+						print("tktextinsert botch\n");
+					break;
+				}
+		}
+		else {
+			for(;;) {
+				pins = ins;
+				if(!tktadjustind(tkt, TkTbyitemback, &pins))
+					break;
+				if(pins.item->kind == TkTmark && pins.item->imark->gravity == Tkright)
+					ins = pins;
+				else
+					break;
+			}
+		}
+	}
+
+	lmin = tktprevwrapline(tk, ins.line);
+
+	n = strlen(arg) + 1;
+	if(n < Tkmaxitem)
+		n = Tkmaxitem;
+	tbuf = malloc(n);
+	if(tbuf == nil)
+		return TkNomem;
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil) {
+		free(tbuf);
+		return TkNomem;
+	}
+
+	tagit = nil;
+
+	while(*arg != '\0') {
+		arg = tkword(top, arg, tbuf, tbuf+n, nil);
+		if(*arg != '\0') {
+			/* tag list spec -- add some slop to tagextra for added tags */
+			e = tktnewitem(TkTascii, (tkt->nexttag-1)/32 + 1, &tagit);
+			if(e != nil) {
+				free(tbuf);
+				free(buf);
+				return e;
+			}
+			arg = tkword(top, arg, buf, buf+Tkmaxitem, nil);
+			p = buf;
+			while(*p) {
+				while(*p == ' ') {
+					p++;
+				}
+				if(*p == '\0')
+					break;
+				pe = strchr(p, ' ');
+				if(pe != nil)
+					*pe = '\0';
+				ti = tktfindtag(tkt->tags, p);
+				if(ti == nil) {
+					e = tktaddtaginfo(tk, p, &ti);
+					if(e != nil) {
+						if(tagit != nil)
+							free(tagit);
+						free(tbuf);
+						free(buf);
+						return e;
+					}
+				}
+				tkttagbit(tagit, ti->id, 1);
+				if(pe == nil)
+					break;
+				else
+					p = pe+1;
+			}
+		}
+		e = tktinsert(tk, &ins, tbuf, tagit);
+		if(tagit != nil) {
+			free(tagit);
+			tagit = nil;
+		}
+		if(e != nil) {
+			free(tbuf);
+			free(buf);
+			return e;
+		}
+	}
+
+	tktfixgeom(tk, lmin, ins.line, 0);
+	tktextsize(tk, 1);
+
+	free(tbuf);
+	free(buf);
+
+	return nil;
+}
+
+static char*
+tktextinserti(Tk *tk, char *arg, char **val)
+{
+	int n;
+	TkTline *lmin;
+	TkTindex ix, is1, is2;
+	TkText *tkt = TKobj(TkText, tk);
+	char *tbuf, *buf;
+
+	USED(val);
+
+	if(tk->flag&Tkdisabled)
+		return nil;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	tbuf = nil;
+	n = strlen(arg) + 1;
+	if(n < Tkmaxitem)
+		tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	else {
+		tbuf = malloc(n);
+		if(tbuf == nil) {
+			free(buf);
+			return TkNomem;
+		}
+		tkword(tk->env->top, arg, tbuf, buf+n, nil);
+	}
+	if(*buf == '\0')
+		goto Ret;
+	if(!tktmarkind(tk, "insert", &ix)) {
+		print("tktextinserti: botch\n");
+		goto Ret;
+	}
+	if(tktgetsel(tk, &is1, &is2)) {
+		if(tktindcompare(tkt, &is1, TkLte, &ix) &&
+		   tktindcompare(tkt, &is2, TkGte, &ix)) {
+			tktextdelete(tk, "sel.first sel.last", nil);
+			/* delete might have changed ix item */
+			tktmarkind(tk, "insert", &ix);
+		}
+	}
+
+	lmin = tktprevwrapline(tk, ix.line);
+	tktinsert(tk, &ix, tbuf==nil ? buf : tbuf, 0);
+	tktfixgeom(tk, lmin, ix.line, 0);
+	if(tktmarkind(tk, "insert", &ix))		/* index doesn't remain valid after fixgeom */
+		tktsee(tk, &ix, 0);
+	tktextsize(tk, 1);
+Ret:
+	if(tbuf != nil)
+		free(tbuf);
+	free(buf);
+	return nil;
+}
+
+static char*
+tktextmark(Tk *tk, char *arg, char **val)
+{
+	char *buf;
+	TkCmdtab *cmd;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	for(cmd = tktmarkcmd; cmd->name != nil; cmd++) {
+		if(strcmp(cmd->name, buf) == 0) {
+			free(buf);
+			return cmd->fn(tk, arg, val);
+		}
+	}
+	free(buf);
+	return TkBadcm;
+}
+
+static char*
+tktextscan(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	int mark, x, y, xmax, ymax, vh, vw;
+	Point p, odeltatv;
+	char buf[Tkmaxitem];
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(val);
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+
+	if(strcmp(buf, "mark") == 0)
+		mark = 1;
+	else
+	if(strcmp(buf, "dragto") == 0)
+		mark = 0;
+	else
+		return TkBadcm;
+
+	e = tkxyparse(tk, &arg, &p);
+	if(e != nil)
+		return e;
+
+	if(mark)
+		tkt->track = p;
+	else {
+		odeltatv = tkt->deltatv;
+		vw = tk->act.width - tk->ipad.x;
+		vh = tk->act.height - tk->ipad.y;
+		ymax = tkt->end.prev->orig.y + tkt->end.prev->height - vh;
+		y = tkt->deltatv.y -10*(p.y - tkt->track.y);
+		if(y > ymax)
+			y = ymax;
+		if(y < 0)
+			y = 0;
+		tkt->deltatv.y = y;
+		e = tktsetscroll(tk, Tkvertical);
+		if(e != nil)
+			return e;
+		if(tkt->opts[TkTwrap] == Tkwrapnone) {
+			xmax = tktmaxwid(tkt->start.next) - vw;
+			x = tkt->deltatv.x - 10*(p.x - tkt->track.x);
+			if(x > xmax)
+				x = xmax;
+			if(x < 0)
+				x = 0;
+			tkt->deltatv.x = x;
+			e = tktsetscroll(tk, Tkhorizontal);
+			if(e != nil)
+				return e;
+		}
+		tktfixscroll(tk, odeltatv);
+		tkt->track = p;
+	}
+
+	return nil;
+}
+
+static char*
+tktextscrollpages(Tk *tk, char *arg, char **val)
+{
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(tkt);
+	USED(arg);
+	USED(val);
+	return nil;
+}
+
+static char*
+tktextsearch(Tk *tk, char *arg, char **val)
+{
+	int i, n;
+	Rune r;
+	char *e, *s;
+	int wrap, fwd, nocase;
+	TkText *tkt;
+	TkTindex ix1, ix2, ixstart, ixend, tx;
+	char buf[Tkmaxitem];
+
+	tkt = TKobj(TkText, tk);
+
+	fwd = 1;
+	nocase = 0;
+
+	while(*arg != '\0') {
+		arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+		if(*buf != '-')
+			break;
+		if(strcmp(buf, "-backwards") == 0)
+			fwd = 0;
+		else if(strcmp(buf, "-nocase") == 0)
+			nocase = 1;
+		else if(strcmp(buf, "--") == 0) {
+			arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+			break;
+		}
+	}
+
+	tktstartind(tkt, &ixstart);
+	tktadjustind(tkt, TkTbycharstart, &ixstart);
+	tktendind(tkt, &ixend);
+
+	if(*arg == '\0')
+		return TkOparg;
+
+	e = tktindparse(tk, &arg, &ix1);
+	if(e != nil)
+ 		return e;
+	tktadjustind(tkt, fwd? TkTbycharstart : TkTbycharback, &ix1);
+
+	if(*arg != '\0') {
+		wrap = 0;
+		e = tktindparse(tk, &arg, &ix2);
+		if(e != nil)
+			return e;
+		if(!fwd)
+			tktadjustind(tkt, TkTbycharback, &ix2);
+	}
+	else {
+		wrap = 1;
+		if(fwd) {
+			if(tktindcompare(tkt, &ix1, TkEq, &ixstart))
+				ix2 = ixend;
+			else {
+				ix2 = ix1;
+				tktadjustind(tkt, TkTbycharback, &ix2);
+			}
+		}
+		else {
+			if(tktindcompare(tkt, &ix1, TkEq, &ixend))
+				ix2 = ixstart;
+			else {
+				ix2 = ix1;
+				tktadjustind(tkt, TkTbychar, &ix2);
+			}
+		}
+	}
+	tktadjustind(tkt, TkTbycharstart, &ix2);
+	if(tktindcompare(tkt, &ix1, TkEq, &ix2))
+		return nil;
+
+	if(*buf == '\0')
+		return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix1), tktlinepos(tkt, &ix1));
+
+	while(!(ix1.item == ix2.item && ix1.pos == ix2.pos)) {
+		tx = ix1;
+		for(i = 0; buf[i] != '\0'; i++) {
+			switch(tx.item->kind) {
+			case TkTascii:
+				if(!tktcmatch(tx.item->istring[tx.pos], buf[i], nocase))
+					goto nomatch;
+				break;
+			case TkTrune:
+				s = tx.item->istring;
+				s += tktutfpos(s, tx.pos);
+				n = chartorune(&r, s);
+				if(strncmp(s, buf+i, n) != 0)
+					goto nomatch;
+				i += n-1;
+				break;
+			case TkTtab:
+				if(buf[i] != '\t')
+					goto nomatch;
+				break;
+			case TkTnewline:
+				if(buf[i] != '\n')
+					goto nomatch;
+				break;
+			default:
+				goto nomatch;
+			}
+			tktadjustind(tkt, TkTbychar, &tx);
+		}
+		return tkvalue(val, "%d.%d", tktlinenum(tkt, &ix1), tktlinepos(tkt, &ix1));
+	nomatch:
+		if(fwd) {
+			if(!tktadjustind(tkt, TkTbychar, &ix1)) {
+				if(!wrap)
+					break;
+				ix1 = ixstart;
+			}
+		}
+		else {
+			if(!tktadjustind(tkt, TkTbycharback, &ix1)) {
+				if(!wrap)
+					break;
+				ix1 = ixend;
+			}
+		}
+	}
+
+	return nil;
+}
+
+char*
+tktextselection(Tk *tk, char *arg, char **val)
+{
+	USED(val);
+	if (strcmp(arg, " clear") == 0) {
+		tktclearsel(tk);
+		return nil;
+	}
+	else
+		return TkBadcm;
+}
+
+static void
+doselectto(Tk *tk, Point p, int dbl)
+{
+	int halfway;
+	TkTindex cur, insert, first, last;
+	TkText *tkt = TKobj(TkText, tk);
+	tktclearsel(tk);
+
+	halfway = tktxyind(tk, p.x, p.y, &cur);
+
+	if(!dbl) {
+		if(!tktmarkind(tk, "insert", &insert))
+			insert = cur;
+
+		if(tktindcompare(tkt, &cur, TkLt, &insert)) {
+			first = cur;
+			last = insert;
+		}
+		else {
+			first = insert;
+			last = cur;
+			if(halfway)
+				tktadjustind(tkt, TkTbychar, &last);
+			if(last.line == &tkt->end)
+				tktadjustind(tkt, TkTbycharback, &last);
+			if(tktindcompare(tkt, &first, TkGte, &last))
+				return;
+			cur = last;
+		}
+		tktsee(tk, &cur, 0);
+	}
+	else {
+		first = cur;
+		last = cur;
+		tktdoubleclick(tkt, &first, &last);
+	}
+
+	tkttagchange(tk, TkTselid, &first, &last, 1);
+}
+
+static void
+autoselect(Tk *tk, void *v, int cancelled)
+{
+	TkText *tkt = TKobj(TkText, tk);
+	Rectangle hitr;
+	Point p;
+	USED(v);
+
+	if (cancelled)
+		return;
+
+	p = scr2local(tk, tkt->track);
+	if (tkvisiblerect(tk, &hitr) && ptinrect(p, hitr))
+		return;
+	doselectto(tk, p, 0);
+	tkdirty(tk);
+	tkupdate(tk->env->top);
+}
+
+static char*
+tktextselectto(Tk *tk, char *arg, char **val)
+{
+	int dbl;
+	char *e;
+	Point p;
+	Rectangle hitr;
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(val);
+
+	if(tkt->tflag & (TkTjustfoc|TkTnodrag))
+		return nil;
+
+	e = tkxyparse(tk, &arg, &p);
+	if(e != nil)
+		return e;
+	tkt->track = p;
+	p = scr2local(tk, p);
+
+	arg = tkskip(arg, " ");
+	if(*arg == 'd') {
+		tkcancelrepeat(tk);
+		dbl = 1;
+		tkt->tflag |= TkTnodrag;
+	} else {
+		dbl = 0;
+		if (!tkvisiblerect(tk, &hitr) || !ptinrect(p, hitr))
+			return nil;
+	}
+	doselectto(tk, p, dbl);
+	return nil;
+}
+
+static char tktleft1[] = "{[(<";
+static char tktright1[] = "}])>";
+static char tktleft2[] = "\n";
+static char tktleft3[] = "\'\"`";
+
+static char *tktleft[] = {tktleft1, tktleft2, tktleft3, nil};
+static char *tktright[] = {tktright1,  tktleft2, tktleft3, nil};
+
+static void
+tktdoubleclick(TkText *tkt, TkTindex *first, TkTindex *last)
+{
+	int c, i;
+	TkTindex ix, ix2;
+	char *r, *l, *p;
+
+	for(i = 0; tktleft[i] != nil; i++) {
+		ix = *first;
+		l = tktleft[i];
+		r = tktright[i];
+		/* try matching character to left, looking right */
+		ix2 = ix;
+		if(!tktadjustind(tkt, TkTbycharback, &ix2))
+			c = '\n';
+		else
+			c = tktindrune(&ix2);
+		p = strchr(l, c);
+		if(p != nil) {
+			if(tktclickmatch(tkt, c, r[p-l], 1, &ix)) {
+				*last = ix;
+				if(c != '\n')
+					tktadjustind(tkt, TkTbycharback, last);
+			}
+			return;
+		}
+		/* try matching character to right, looking left */
+		c = tktindrune(&ix);
+		p = strchr(r, c);
+		if(p != nil) {
+			if(tktclickmatch(tkt, c, l[p-r], -1, &ix)) {
+				*last = *first;
+				if(c == '\n')
+					tktadjustind(tkt, TkTbychar, last);
+				*first = ix;
+				if(!(c=='\n' && ix.line == tkt->start.next && ix.item == ix.line->items))
+					tktadjustind(tkt, TkTbychar, first);
+			}
+			return;
+		}
+	}
+	/* try filling out word to right */
+	while(tkiswordchar(tktindrune(last))) {
+		if(!tktadjustind(tkt, TkTbychar, last))
+			break;
+	}
+	/* try filling out word to left */
+	for(;;) {
+		ix = *first;
+		if(!tktadjustind(tkt, TkTbycharback, &ix))
+			break;
+		if(!tkiswordchar(tktindrune(&ix)))
+			break;
+		*first = ix;
+	}
+}
+
+static int
+tktclickmatch(TkText *tkt, int cl, int cr, int dir, TkTindex *ix)
+{
+	int c, nest, atend;
+
+	nest = 1;
+	atend = 0;
+	for(;;) {
+		if(dir > 0) {
+			if(atend)
+				break;
+			c = tktindrune(ix);
+			atend = !tktadjustind(tkt, TkTbychar, ix);
+		} else {
+			if(!tktadjustind(tkt, TkTbycharback, ix))
+				break;
+			c = tktindrune(ix);
+		}
+		if(c == cr){
+			if(--nest==0)
+				return 1;
+		}else if(c == cl)
+			nest++;
+	}
+	return cl=='\n' && nest==1;
+}
+
+/*
+ * return the line before line l, unless word wrap is on,
+ * (for the first word of line l), in which case return the last non-empty line before that.
+ * tktgeom might then combine the end of that line with the start of the insertion
+ * (unless there is a newline in the way).
+ */
+TkTline*
+tktprevwrapline(Tk *tk, TkTline *l)
+{
+	TkTitem *i;
+	int *opts, wrapmode;
+	TkText *tkt = TKobj(TkText, tk);
+	TkEnv env;
+
+	if(l == nil)
+		return nil;
+	/* some spacing depends on tags of first non-mark on display line */
+	for(i = l->items; i != nil; i = i->next)
+		if(i->kind != TkTmark && i->kind != TkTcontline)
+			break;
+	if(i == nil || i->kind == TkTnewline)	/* can't use !tkanytags(i) because it doesn't check env */
+		return l->prev;
+	opts = mallocz(TkTnumopts*sizeof(int), 0);
+	if(opts == nil)
+		return l->prev;	/* in worst case gets word wrap wrong */
+	tkttagopts(tk, i, opts, &env, nil, 1);
+	wrapmode = opts[TkTwrap];
+	free(opts);
+	if(wrapmode != Tkwrapword)
+		return l->prev;
+	if(l->prev != &tkt->start)
+		l = l->prev;	/* having been processed by tktgeom, shouldn't have extraneous marks etc */
+	return l->prev;
+}
+
+static char*
+tktextsetcursor(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+	TkTmarkinfo *mi;
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(val);
+
+	/* do clearsel here, because it can change indices */
+	tktclearsel(tk);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+
+	mi = tktfindmark(tkt->marks, "insert");
+	if(tktdbg && mi == nil) {
+		print("tktextsetcursor: botch\n");
+		return nil;
+	}
+	tktmarkmove(tk, mi, &ix);
+	tktsee(tk, &ix, 0);
+	return nil;
+}
+
+static char*
+tktexttag(Tk *tk, char *arg, char **val)
+{
+	char *buf;
+	TkCmdtab *cmd;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	arg = tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+	for(cmd = tkttagcmd; cmd->name != nil; cmd++) {
+		if(strcmp(cmd->name, buf) == 0) {
+			free(buf);
+			return cmd->fn(tk, arg, val);
+		}
+	}
+	free(buf);
+	return TkBadcm;
+}
+
+static char*
+tktextwindow(Tk *tk, char *arg, char **val)
+{
+	char buf[Tkmaxitem];
+	TkCmdtab *cmd;
+
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	for(cmd = tktwincmd; cmd->name != nil; cmd++) {
+		if(strcmp(cmd->name, buf) == 0)
+			return cmd->fn(tk, arg, val);
+	}
+	return TkBadcm;
+}
+
+static char*
+tktextxview(Tk *tk, char *arg, char **val)
+{
+	int ntot, vw;
+	char *e;
+	Point odeltatv;
+	TkText *tkt = TKobj(TkText, tk);
+
+	odeltatv = tkt->deltatv;
+	vw = tk->act.width - tk->ipad.x;
+	ntot = tktmaxwid(tkt->start.next);
+	if(ntot < tkt->deltatv.x +vw)
+		ntot = tkt->deltatv.x + vw;
+	e = tktview(tk, arg, val, vw, &tkt->deltatv.x, ntot, Tkhorizontal);
+	if(e == nil) {
+		e = tktsetscroll(tk, Tkhorizontal);
+		if(e == nil)
+			tktfixscroll(tk, odeltatv);
+	}
+	return e;
+}
+
+static int
+istext(TkTline *l)
+{
+	TkTitem *i;
+
+	for(i = l->items; i != nil; i = i->next)
+		if(i->kind == TkTwin || i->kind == TkTmark)
+			return 0;
+	return 1;
+}
+
+static void
+tkadjpage(Tk *tk, int ody, int *dy)
+{
+	int y, a, b, d;
+	TkTindex ix;
+	TkTline *l;
+
+	d = *dy-ody;
+	y = d > 0 ? tk->act.height : 0;
+	tktxyind(tk, 0, y-d, &ix);
+	if((l = ix.line) != nil && istext(l)){
+		a = l->orig.y;
+		b = a+l->height;
+/* print("AP: %d %d %d (%d+%d)\n", a, ody+y, b, ody, y); */
+		if(a+2 < ody+y && ody+y < b-2){	/* partially obscured line */
+			if(d > 0)
+				*dy -= ody+y-a;
+			else
+				*dy += b-ody;
+		}
+	}
+}
+
+static char*
+tktextyview(Tk *tk, char *arg, char **val)
+{
+	int ntot, vh, d;
+	char *e;
+	TkTline *l;
+	Point odeltatv;
+	TkTindex ix;
+	TkText *tkt = TKobj(TkText, tk);
+	char buf[Tkmaxitem], *v;
+
+	if(*arg != '\0') {
+		v = tkitem(buf, arg);
+		if(strcmp(buf, "-pickplace") == 0)
+			return tktextsee(tk,v, val);
+		if(strcmp(buf, "moveto") != 0 && strcmp(buf, "scroll") != 0) {
+			e = tktindparse(tk, &arg, &ix);
+			if(e != nil)
+				return e;
+			tktsee(tk, &ix, 1);
+			return nil;
+		}
+	}
+	odeltatv = tkt->deltatv;
+	vh = tk->act.height;
+	l =  tkt->end.prev;
+	ntot = l->orig.y + l->height;
+//	if(ntot < tkt->deltatv.y + vh)
+//		ntot = tkt->deltatv.y + vh;
+	e = tktview(tk, arg, val, vh, &tkt->deltatv.y, ntot, Tkvertical);
+	d = tkt->deltatv.y-odeltatv.y;
+	if(d == vh || d == -vh)
+		tkadjpage(tk, odeltatv.y, &tkt->deltatv.y);
+	if(e == nil) {
+		e = tktsetscroll(tk, Tkvertical);
+		if(e == nil)
+			tktfixscroll(tk, odeltatv);
+	}
+	return e;
+}
+static void
+tktextfocusorder(Tk *tk)
+{
+	TkTindex ix;
+	TkText *t;
+	Tk *isub;
+
+	t = TKobj(TkText, tk);
+	tktstartind(t, &ix);
+	do {
+		if(ix.item->kind == TkTwin) {
+			isub = ix.item->iwin->sub;
+			if(isub != nil)
+				tkappendfocusorder(isub);
+		}
+	} while(tktadjustind(t, TkTbyitem, &ix));
+}
+
+TkCmdtab tktextcmd[] =
+{
+	"bbox",			tktextbbox,
+	"cget",			tktextcget,
+	"compare",		tktextcompare,
+	"configure",		tktextconfigure,
+	"debug",		tktextdebug,
+	"delete",		tktextdelete,
+	"dlineinfo",		tktextdlineinfo,
+	"dump",			tktextdump,
+	"get",			tktextget,
+	"index",		tktextindex,
+	"insert",		tktextinsert,
+	"mark",			tktextmark,
+	"scan",			tktextscan,
+	"search",		tktextsearch,
+	"see",			tktextsee,
+	"selection",		tktextselection,
+	"tag",			tktexttag,
+	"window",		tktextwindow,
+	"xview",		tktextxview,
+	"yview",		tktextyview,
+	"tkTextButton1",	tktextbutton1,
+	"tkTextButton1R",	tktextbutton1r,
+	"tkTextDelIns",		tktextdelins,
+	"tkTextInsert",		tktextinserti,
+	"tkTextSelectTo",	tktextselectto,
+	"tkTextSetCursor",	tktextsetcursor,
+	"tkTextScrollPages",	tktextscrollpages,
+	"tkTextCursor",		tktextcursor,
+	nil
+};
+
+TkMethod textmethod = {
+	"text",
+	tktextcmd,
+	tkfreetext,
+	tkdrawtext,
+	tktextgeom,
+	nil,
+	tktextfocusorder,
+	tktdirty,
+	tktrelpos,
+	tktextevent,
+	nil,				/* XXX need to implement textsee */
+	tktinwindow,
+	nil,
+	tktxtforgetsub,
+};
--- /dev/null
+++ b/libtk/textw.h
@@ -1,0 +1,230 @@
+typedef struct TkText TkText;
+typedef struct TkTitem TkTitem;
+typedef struct TkTline TkTline;
+typedef struct TkTindex TkTindex;
+typedef struct TkTmarkinfo TkTmarkinfo;
+typedef struct TkTtaginfo TkTtaginfo;
+typedef struct TkTwind TkTwind;
+
+enum
+{
+	/* text item types */
+	TkTascii,	/* contiguous string of ascii chars, all with same tags */
+	TkTrune,	/* printable utf (one printing position) */
+	TkTtab,
+	TkTnewline,	/* line field contains pointer to containing line */
+	TkTcontline,	/* end of non-newline line; line field as with TkTnewline */
+	TkTwin,
+	TkTmark,
+
+	TkTbyitem = 0,	/* adjustment units */
+	TkTbyitemback,
+	TkTbytline,
+	TkTbytlineback,
+	TkTbychar,
+	TkTbycharback,
+	TkTbycharstart,
+	TkTbyline,
+	TkTbylineback,
+	TkTbylinestart,
+	TkTbylineend,
+	TkTbywordstart,
+	TkTbywordend,
+	TkTbywrapstart,
+	TkTbywrapend,
+
+	TkTselid	= 0,		/* id of sel tag */
+	TkTmaxtag	= 32,
+	Textwidth	= 40,		/* default width, in chars */
+	Textheight	= 10,		/* default height, in chars */
+
+	TkTfirst	= (1<<0),	/* first line in buffer, or after a TkTlast */
+	TkTlast		= (1<<1),	/* TkTnewline at end of line */
+	TkTdrawn	= (1<<2),	/* screen cache copy is ok */
+	TkTdlocked	= (1<<3),	/* display already locked */
+	TkTjustfoc	= (1<<4),	/* got focus on last B1 press */
+	TkTnodrag		= (1<<5),	/* ignore B1 drag until B1 up */
+	TkTunset 	= (1<<31),	/* marks int tag options "unspecified" */
+
+	TkTborderwidth	= 0,
+	TkTjustify,
+	TkTlmargin1,
+	TkTlmargin2,
+	TkTlmargin3,
+	TkTrmargin,
+	TkTspacing1,
+	TkTspacing2,
+	TkTspacing3,
+	TkToffset,
+	TkTunderline,
+	TkToverstrike,
+	TkTrelief,
+	TkTwrap,
+	TkTlineheight,
+
+	TkTnumopts
+};
+
+struct TkTline
+{
+	Point		orig;		/* where to put first item of line */
+	int		width;
+	int		height;
+	int		ascent;
+	int		flags;
+	TkTitem*	items;
+	TkTline*	next;
+	TkTline*	prev;
+};
+
+struct TkText
+{
+	TkTline		start;		/* fake before-the-first line */
+	TkTline		end;		/* fake after-the-last line */
+	Tk*			tagshare;
+	TkTtabstop*	tabs;
+	TkTtaginfo*	tags;
+	TkTmarkinfo*	marks;
+	char*		xscroll;
+	char*		yscroll;
+	uchar		selunit;	/* select adjustment unit */
+	uchar		tflag;		/* various text-specific flags */
+	int			nlines;	/* number of nl items in widget */
+	TkTitem*	selfirst;	/* first item marked with sel tag */
+	TkTitem*	sellast;	/* item after last marked with sel tag */
+	Point		deltatv;	/* vector from text-space to view-space */
+	Point		deltaiv;	/* vector from image-space to view-space */
+	Point		current;	/* last known mouse pos */
+	Point		track;	/* for use when B1 or B2 is down */
+	int		nexttag;	/* next usable tag index */
+	TkTitem*	mouse;		/* mouse focus */
+	int		inswidth;	/* width of insertion cursor */
+	int		sborderwidth;
+	int		opts[TkTnumopts];
+	int		propagate;
+	int		scrolltop[2];
+	int		scrollbot[2];
+	Image*		image;
+	uchar		cur_flag;	/* text cursor to be shown up? */
+	Rectangle	cur_rec;	/* last text cursor rectangle */
+};
+
+struct TkTwind
+{
+	Tk*		sub;		/* Subwindow of canvas */
+	Tk*		focus;		/* Current Mouse focus */
+	int		width;		/* current internal width */
+	int		height;		/* current internal height */
+	int		owned;	/* true if window is destroyed on item deletion */
+	int		align;		/* how to align within line */
+	char*		create;		/* creation script */
+	int		padx;		/* extra space on each side */
+	int		pady;		/* extra space on top and bot */
+	int		ascent;		/* distance from top of widget to baseline */
+	int		stretch;	/* true if need to stretch height */
+};
+
+struct TkTitem
+{
+	uchar		kind;		/* e.g. TkTascii, etc */
+	uchar		tagextra;
+	short		width;
+	TkTitem		*next;
+	union	{
+		char*		string;
+		TkTwind*	win;
+		TkTmarkinfo*	mark;
+		TkTline*	line;
+	} u;
+	ulong		tags[1];
+	/* TkTitem length extends tagextra ulongs beyond */
+};
+
+struct TkTmarkinfo
+{
+	char*		name;
+	int		gravity;
+	TkTitem*	cur;
+	TkTmarkinfo*	next;
+};
+
+struct TkTtaginfo
+{
+	int		id;
+	char*		name;
+	TkEnv*		env;
+	TkTtabstop*	tabs;
+	TkTtaginfo*	next;
+	TkAction*	binds;		/* Binding of current events */
+	int		opts[TkTnumopts];
+};
+
+struct TkTindex
+{
+	TkTitem*	item;
+	TkTline*	line;
+	int		pos;		/* index within multichar item */
+};
+
+extern	TkCmdtab	tkttagcmd[];
+extern	TkCmdtab	tktmarkcmd[];
+extern	TkCmdtab	tktwincmd[];
+
+extern	void		tkfreetext(Tk*);
+extern	char*		tktaddmarkinfo(TkText*, char*, TkTmarkinfo**);
+extern	char*		tktaddtaginfo(Tk*, char*, TkTtaginfo**);
+extern	int		tktadjustind(TkText*, int, TkTindex*);
+extern	int		tktanytags(TkTitem*);
+extern	Rectangle	tktbbox(Tk*, TkTindex*);
+extern	void		tktdirty(Tk*);
+extern	int		tktdispwidth(Tk*, TkTtabstop *tabs, TkTitem*, Font*, int, int, int);
+extern	void		tktendind(TkText*, TkTindex*);
+extern	char*	tktextcursor(Tk*, char*, char **);
+extern	Tk*		tktextevent(Tk*, int, void*);
+extern	Tk*		tktinwindow(Tk*, Point*);
+extern	char*		tktextselection(Tk*, char*, char**);
+extern	void		tktextsize(Tk*, int);
+extern	TkTmarkinfo*	tktfindmark(TkTmarkinfo*, char*);
+extern	int		tktfindsubitem(Tk*, TkTindex*);
+extern	TkTtaginfo*	tktfindtag(TkTtaginfo*, char*);
+extern	char*		tktfixgeom(Tk*, TkTline*, TkTline*, int);
+extern	void		tktfreeitems(TkText*, TkTitem*, int);
+extern	void		tktfreelines(TkText*, TkTline*, int);
+extern	void		tktfreemarks(TkTmarkinfo*);
+extern	void		tktfreetabs(TkTtabstop*);
+extern	void		tktfreetags(TkTtaginfo*);
+extern	int		tktindcompare(TkText*, TkTindex*, int, TkTindex*);
+extern	int		tktindbefore(TkTindex*, TkTindex*);
+extern	int		tktindrune(TkTindex*);
+extern	char*		tktinsert(Tk*, TkTindex*, char*, TkTitem*);
+extern	int	tktisbreak(int);
+extern	void		tktitemind(TkTitem*, TkTindex*);
+extern	char*		tktiteminsert(TkText*, TkTindex*, TkTitem*);
+extern	TkTline*	tktitemline(TkTitem*);
+extern	char*		tktindparse(Tk*, char**, TkTindex*);
+extern	TkTitem*	tktlastitem(TkTitem*);
+extern	int		tktlinenum(TkText*, TkTindex*);
+extern	int		tktlinepos(TkText*, TkTindex*);
+extern	int		tktmarkind(Tk*, char*, TkTindex*);
+extern	char*		tktmarkmove(Tk*, TkTmarkinfo*, TkTindex*);
+extern	char*		tktmarkparse(Tk*, char**, TkTmarkinfo**);
+extern	int		tktmaxwid(TkTline*);
+extern	char*		tktnewitem(int, int, TkTitem**);
+extern	char*		tktnewline(int, TkTitem*, TkTline*, TkTline*, TkTline**);
+extern	int		tktposcount(TkTitem*);
+extern	TkTline*	tktprevwrapline(Tk*, TkTline*);
+extern	void		tktremitem(TkText*, TkTindex*);
+extern	int		tktsametags(TkTitem*, TkTitem*);
+extern	char*		tktsplititem(TkTindex*);
+extern	void		tktstartind(TkText*, TkTindex*);
+extern	char*		tkttagchange(Tk*, int, TkTindex*, TkTindex*, int);
+extern	int		tkttagbit(TkTitem*, int, int);
+extern	void		tkttagcomb(TkTitem*, TkTitem*, int);
+extern	int		tkttagind(Tk*, char*, int, TkTindex*);
+extern	char*		tkttagname(TkText*, int);
+extern	int		tkttagnrange(TkText*, int, TkTindex*, TkTindex*, TkTindex*, TkTindex*);
+extern	void		tkttagopts(Tk*, TkTitem*, int*, TkEnv*, TkTtabstop **, int);
+extern	char*		tkttagparse(Tk*, char**, TkTtaginfo**);
+extern	int		tkttagset(TkTitem*, int);
+extern	int		tktxyind(Tk*, int, int, TkTindex*);
+extern	void		tktxtforgetsub(Tk*, Tk*);
--- /dev/null
+++ b/libtk/tindx.c
@@ -1,0 +1,610 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+/* debugging */
+extern int tktdbg;
+extern void tktprinttext(TkText*);
+extern void tktprintindex(TkTindex*);
+extern void tktprintitem(TkTitem*);
+extern void tktprintline(TkTline*);
+
+char*
+tktindparse(Tk *tk, char **pspec, TkTindex *ans)
+{
+	int m, n, done, neg, modstart;
+	char *s, *mod;
+	TkTline *lend;
+	TkText *tkt;
+	char *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	tkt = TKobj(TkText, tk);
+	lend = &tkt->end;
+
+	*pspec = tkword(tk->env->top, *pspec, buf, buf+Tkmaxitem, nil);
+	modstart = 0;
+	for(mod = buf; *mod != '\0'; mod++)
+		if(*mod == ' ' || *mod == '-' || *mod == '+') {
+			modstart = *mod;
+			*mod = '\0';
+			break;
+		}
+
+	/*
+	 * XXX there's a problem here - if either coordinate is negative
+	 * which shouldn't be precluded, then the above scanning code
+	 * will break up the coordinate pair, so @-23,45 for example
+	 * yields a bad index, when it should probably return the index
+	 * of the character at the start of the line containing y=45.
+	 * i've seen this cause wm/sh to crash.
+	 */
+	if(strcmp(buf, "end") == 0)
+		tktendind(tkt, ans);
+	else
+	if(*buf == '@') {
+		/* by coordinates */
+
+		s = strchr(buf, ',');
+		if(s == nil) {
+			free(buf);
+			return TkBadix;
+		}
+		*s = '\0';
+		m = atoi(buf+1);
+		n = atoi(s+1);
+		tktxyind(tk, m, n, ans);
+	}
+	else
+	if(*buf >= '0' && *buf <= '9') {
+		/* line.char */
+
+		s = strchr(buf, '.');
+		if(s == nil) {
+			free(buf);
+			return TkBadix;
+		}
+		*s = '\0';
+		m = atoi(buf);
+		n = atoi(s+1);
+
+		if(m < 1)
+			m = 1;
+
+		tktstartind(tkt, ans);
+
+		while(--m > 0 && ans->line->next != lend)
+			tktadjustind(tkt, TkTbyline, ans);
+
+		while(n-- > 0 && ans->item->kind != TkTnewline)
+			tktadjustind(tkt, TkTbychar, ans);
+	}
+	else
+	if(*buf == '.') {
+		/* window */
+
+		tktstartind(tkt, ans);
+
+		while(ans->line != lend) {
+			if(ans->item->kind == TkTwin &&
+			   ans->item->iwin->sub != nil &&
+			   ans->item->iwin->sub->name != nil &&
+			   strcmp(ans->item->iwin->sub->name->name, buf) == 0)
+				break;
+			if(!tktadjustind(tkt, TkTbyitem, ans))
+				ans->line = lend;
+		}
+		if(ans->line == lend) {
+			free(buf);
+			return TkBadix;
+		}
+	}
+	else {
+		s = strchr(buf, '.');
+		if(s == nil) {
+			if(tktmarkind(tk, buf, ans) == 0) {
+				free(buf);
+				return TkBadix;
+			}
+		}
+		else {
+			/* tag.first or tag.last */
+
+			*s = '\0';
+			if(strcmp(s+1, "first") == 0) {
+				if(tkttagind(tk, buf, 1, ans) == 0) {
+					free(buf);
+					return TkBadix;
+				}
+			}
+			else
+			if(strcmp(s+1, "last") == 0) {
+				if(tkttagind(tk, buf, 0, ans) == 0) {
+					free(buf);
+					return TkBadix;
+				}
+			}
+			else {
+				free(buf);
+				return TkBadix;
+			}
+		}
+	}
+
+	if(modstart == 0) {
+		free(buf);
+		return nil;
+	}
+
+	*mod = modstart;
+	while(*mod == ' ')
+		mod++;
+
+	while(*mod != '\0') {
+		done = 0;
+		switch(*mod) {
+		case '+':
+		case '-':
+			neg = (*mod == '-');
+			mod++;
+			while(*mod == ' ')
+				mod++;
+			n = strtol(mod, &mod, 10);
+			while(*mod == ' ')
+				mod++;
+			while(n-- > 0) {
+				if(*mod == 'c')
+					tktadjustind(tkt, neg? TkTbycharback : TkTbychar, ans);
+				else
+				if(*mod == 'l')
+					tktadjustind(tkt, neg? TkTbylineback : TkTbyline, ans);
+				else
+					done = 1;
+			}
+			break;
+		case 'l':
+			if(strncmp(mod, "lines", 5) == 0)
+				tktadjustind(tkt, TkTbylinestart, ans);
+			else
+			if(strncmp(mod, "linee", 5) == 0)
+				tktadjustind(tkt, TkTbylineend, ans);
+			else
+				done = 1;
+			break;
+		case 'w':
+			if(strncmp(mod, "words", 5) == 0)
+				tktadjustind(tkt, TkTbywordstart, ans);
+			else
+			if(strncmp(mod, "worde", 5) == 0)
+				tktadjustind(tkt, TkTbywordend, ans);
+			else
+				done = 1;
+			break;
+		default:
+				done = 1;
+		}
+
+		if(done)
+			break;
+
+		while(tkiswordchar(*mod))
+			mod++;
+		while(*mod == ' ')
+			mod++;
+	}
+
+	free(buf);
+	return nil;
+}
+
+int
+tktisbreak(int c)
+{
+	/* unicode rules suggest / as well but that would split dates, and URLs might as well char. wrap */
+	return c == ' ' || c == '\t' || c == '\n' || c == '-' || c == ',';
+	/* previously included . but would probably need more then to handle ." */
+}
+
+/*
+ * Adjust the index p by units (one of TkTbyitem, etc.).
+ * The TkTbychar units mean that the final point should rest on a
+ * "character" (in text widget index space; i.e., a newline, a rune,
+ * and an embedded window are each 1 character, but marks and contlines are not).
+ *
+ * Indexes may not point in the tkt->start or tkt->end lines (which have
+ * no items); tktadjustind sticks at the beginning or end of the buffer.
+ *
+ * Return 1 if the index changes at all, 0 otherwise.
+ */
+int
+tktadjustind(TkText *tkt, int units, TkTindex *p)
+{
+	int n, opos, count, c;
+	TkTitem *i, *it, *oit;
+	TkTindex q;
+
+	oit = p->item;
+	opos = p->pos;
+	count = 1;
+
+	switch(units) {
+	case TkTbyitemback:
+		it = p->item;
+		p->item = p->line->items;
+		p->pos = 0;
+		if(it == p->item) {
+			if(p->line->prev != &tkt->start) {
+				p->line = p->line->prev;
+				p->item = tktlastitem(p->line->items);
+			}
+		}
+		else {
+			while(p->item->next != it) {
+				p->item = p->item->next;
+				if(tktdbg && p->item == nil) {
+					print("tktadjustind: botch 1\n");
+					break;
+				}
+			}
+		}
+		break;
+
+	case TkTbyitem:
+		p->pos = 0;
+		i = p->item->next;
+		if(i == nil) {
+			if(p->line->next != &tkt->end) {
+				p->line = p->line->next;
+				p->item = p->line->items;
+			}
+		}
+		else
+			p->item = i;
+		break;
+
+	case TkTbytlineback:
+		if(p->line->prev != &tkt->start)
+			p->line = p->line->prev;
+		p->item = p->line->items;
+		p->pos = 0;
+		break;
+
+	case TkTbytline:
+		if(p->line->next != &tkt->end)
+			p->line = p->line->next;
+		p->item = p->line->items;
+		p->pos = 0;
+		break;
+
+	case TkTbycharstart:
+		count = 0;
+	case TkTbychar:
+		while(count > 0) {
+			i = p->item;
+			n = tktposcount(i) - p->pos;
+			if(count >= n) {
+				if(tktadjustind(tkt, TkTbyitem, p))
+					count -= n;
+				else
+					break;
+			}
+			else {
+				p->pos += count;
+				break;
+			}
+		}
+		while(p->item->kind == TkTmark || p->item->kind == TkTcontline)
+			if(!tktadjustind(tkt, TkTbyitem, p))
+				break;
+		break;
+	case TkTbycharback:
+		count = -1;
+		while(count < 0) {
+			if(p->pos + count >= 0) {
+				p->pos += count;
+				count = 0;
+			}
+			else {
+				count += p->pos;
+				if(!tktadjustind(tkt, TkTbyitemback, p))
+					break;
+				n = tktposcount(p->item);
+				p->pos = n;
+			}
+		}
+		break;
+
+	case TkTbylineback:
+		count = -1;
+		/* fall through */
+	case TkTbyline:
+		n = tktlinepos(tkt, p);
+		while(count > 0) {
+			if(p->line->next == &tkt->end) {
+				count = 0;
+				break;
+			}
+			if(p->line->flags&TkTlast)
+				count--;
+			p->line = p->line->next;
+		}
+		while(count < 0 && p->line->prev != &tkt->start) {
+			if(p->line->flags&TkTfirst)
+				count++;
+			p->line = p->line->prev;
+		}
+		tktadjustind(tkt, TkTbylinestart, p);
+		while(n > 0) {
+			if(p->item->kind == TkTnewline)
+				break;
+			if(!tktadjustind(tkt, TkTbychar, p))
+				break;
+			n--;
+		}
+		break;
+
+	case TkTbylinestart:
+		/* note: can call this with only p->line set correctly  in *p */
+
+		while(!(p->line->flags&TkTfirst))
+			p->line = p->line->prev;
+		p->item = p->line->items;
+		p->pos = 0;
+		break;
+
+	case TkTbylineend:
+		while(p->item->kind != TkTnewline)
+			if(!tktadjustind(tkt, TkTbychar, p))
+				break;
+		break;
+
+	case TkTbywordstart:
+		tktadjustind(tkt, TkTbycharstart, p);
+		q = *p;
+		c = tktindrune(p);
+		while(tkiswordchar(c)) {
+			q = *p;
+			if(!tktadjustind(tkt, TkTbycharback, p))
+				break;
+			c = tktindrune(p);
+		}
+		*p = q;
+		break;
+
+	case TkTbywordend:
+		tktadjustind(tkt, TkTbycharstart, p);
+		if(p->item->kind == TkTascii || p->item->kind == TkTrune) {
+			c = tktindrune(p);
+			if(tkiswordchar(c)) {
+				do {
+					if(!tktadjustind(tkt, TkTbychar, p))
+						break;
+					c = tktindrune(p);
+				} while(tkiswordchar(c));
+			}
+			else
+				tktadjustind(tkt, TkTbychar, p);
+		}
+		else if(!(p->item->kind == TkTnewline && p->line->next == &tkt->end))
+			tktadjustind(tkt, TkTbychar, p);
+
+		break;
+
+	case TkTbywrapstart:
+		tktadjustind(tkt, TkTbycharstart, p);
+		q = *p;
+		c = tktindrune(p);
+		while(!tktisbreak(c)) {
+			q = *p;
+			if(!tktadjustind(tkt, TkTbycharback, p))
+				break;
+			c = tktindrune(p);
+		}
+		*p = q;
+		break;
+
+	case TkTbywrapend:
+		tktadjustind(tkt, TkTbycharstart, p);
+		if(p->item->kind == TkTascii || p->item->kind == TkTrune) {
+			c = tktindrune(p);
+			if(!tktisbreak(c)) {
+				do {
+					if(!tktadjustind(tkt, TkTbychar, p))
+						break;
+					c = tktindrune(p);
+				} while(!tktisbreak(c) && (p->item->kind == TkTascii || p->item->kind == TkTrune));
+				while(tktisbreak(c) && tktadjustind(tkt, TkTbychar, p))
+					c = tktindrune(p);	/* could limit it */
+			}
+			else
+				tktadjustind(tkt, TkTbychar, p);
+		}
+		else if(!(p->item->kind == TkTnewline && p->line->next == &tkt->end))
+			tktadjustind(tkt, TkTbychar, p);
+
+		break;
+	}
+	return (p->item != oit || p->pos != opos);
+}
+
+/* return 1 if advancing i1 by item eventually hits i2 */
+int
+tktindbefore(TkTindex *i1, TkTindex *i2)
+{
+	int ans;
+	TkTitem *i;
+	TkTline *l1, *l2;
+
+	ans = 0;
+	l1 = i1->line;
+	l2 = i2->line;
+
+	if(l1 == l2) {
+		if(i1->item == i2->item)
+			ans = (i1->pos < i2->pos);
+		else {
+			for(i = i1->item; i != nil; i = i->next)
+				if(i->next == i2->item) {
+					ans = 1;
+					break;
+				}
+		}
+	}
+	else {
+		if(l1->orig.y < l2->orig.y)
+			ans = 1;
+		else
+		if(l1->orig.y == l2->orig.y) {
+			for(; l1 != nil; l1 = l1->next) {
+				if(l1->next == l2) {
+					ans = 1;
+					break;
+				}
+				if(l1->orig.y > l2->orig.y)
+					break;
+			}
+		}
+	}
+
+	return ans;
+}
+
+/*
+ * This comparison only cares which characters the indices are before.
+ * So two marks should be called "equal" (and not "less" or "greater")
+ * if they are adjacent.
+ */
+int
+tktindcompare(TkText *tkt, TkTindex *i1, int op, TkTindex *i2)
+{
+	int eq, ans;
+	TkTindex x1, x2;
+
+	x1 = *i1;
+	x2 = *i2;
+
+	/* skip over any marks, contlines, to see if on same character */
+	tktadjustind(tkt, TkTbycharstart, &x1);
+	tktadjustind(tkt, TkTbycharstart, &x2);
+	eq = (x1.item == x2.item && x1.pos == x2.pos);
+
+	switch(op) {
+	case TkEq:
+		ans = eq;
+		break;
+	case TkNeq:
+		ans = !eq;
+		break;
+	case TkLte:
+		ans = eq || tktindbefore(i1, i2);
+		break;
+	case TkLt:
+		ans = !eq && tktindbefore(i1, i2);
+		break;
+	case TkGte:
+		ans = eq || tktindbefore(i2, i1);
+		break;
+	case TkGt:
+		ans = !eq && tktindbefore(i2, i1);
+		break;
+	default:
+		ans = 0;	/* not reached */
+		break;
+	};
+
+	return ans;
+}
+
+void
+tktstartind(TkText *tkt, TkTindex *ans)
+{
+	ans->line = tkt->start.next;
+	ans->item = ans->line->items;
+	ans->pos = 0;
+}
+
+void
+tktendind(TkText *tkt, TkTindex *ans)
+{
+	ans->line = tkt->end.prev;
+	ans->item = tktlastitem(ans->line->items);
+	ans->pos = 0;
+}
+
+void
+tktitemind(TkTitem *it, TkTindex *ans)
+{
+	ans->item = it;
+	ans->line = tktitemline(it);
+	ans->pos = 0;
+}
+
+/*
+ * Fill ans with the item that (x,y) (in V space) is over.
+ * Return 0 if it is over the first half of the width,
+ * and 1 if it is over the second half.
+ */
+int
+tktxyind(Tk *tk, int x, int y, TkTindex *ans)
+{
+	int n, w, secondhalf, k;
+	Point p, q;
+	TkTitem *i;
+	TkText *tkt;
+
+ 	tkt = TKobj(TkText, tk);
+	tktstartind(tkt, ans);
+	secondhalf = 0;
+
+	/* (x,y), p, q in V space */
+	p = subpt(ans->line->orig, tkt->deltatv);
+	q = subpt(ans->line->next->orig, tkt->deltatv);
+	while(ans->line->next != &tkt->end) {
+		if(q.y > y)
+			break;
+		tktadjustind(tkt, TkTbytline, ans);
+		p = q;
+		q = subpt(ans->line->next->orig, tkt->deltatv);
+	}
+	if (ans->line->next == &tkt->end) {
+		Point ep = subpt(tkt->end.orig, tkt->deltatv);
+		if (ep.y < y)
+			x = 1000000;
+	}
+
+	while(ans->item->next != nil) {
+		i = ans->item;
+		w = i->width;
+		if(p.x+w > x) {
+			n = tktposcount(i);
+			if(n > 1) {
+				for(k = 0; k < n; k++) {
+					/* probably wrong w.r.t tag tabs */
+					w = tktdispwidth(tk, nil, i, nil, p.x, k, 1);
+					if(p.x+w > x) {
+						ans->pos = k;
+						break;
+					}
+					p.x += w;
+				}
+			}
+			secondhalf = (p.x + w/2 <= x);
+			break;
+		}
+		p.x += w;
+		if(!tktadjustind(tkt, TkTbyitem, ans))
+			break;
+	}
+	tktadjustind(tkt, TkTbycharstart, ans);
+	return secondhalf;
+}
+
--- /dev/null
+++ b/libtk/tmark.c
@@ -1,0 +1,392 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+static char* tktmarkgravity(Tk*, char*, char**);
+static char* tktmarknames(Tk*, char*, char**);
+static char* tktmarknext(Tk*, char*, char**);
+static char* tktmarkprevious(Tk*, char*, char**);
+static char* tktmarkset(Tk*, char*, char**);
+static char* tktmarkunset(Tk*, char*, char**);
+
+TkCmdtab
+tktmarkcmd[] =
+{
+	"gravity",		tktmarkgravity,
+	"names",		tktmarknames,
+	"next",		tktmarknext,
+	"previous",	tktmarkprevious,
+	"set",		tktmarkset,
+	"unset",		tktmarkunset,
+	nil
+};
+
+char*
+tktaddmarkinfo(TkText *tkt, char *name, TkTmarkinfo **ret)
+{
+	TkTmarkinfo *mi;
+
+	mi = malloc(sizeof(TkTmarkinfo));
+	if(mi == nil)
+		return TkNomem;
+
+	mi->name = strdup(name);
+	if(mi->name == nil) {
+		free(mi);
+		return TkNomem;
+	}
+	mi->gravity = Tkright;
+	mi->cur = nil;
+	mi->next = tkt->marks;
+	tkt->marks = mi;
+	*ret = mi;
+	return nil;
+}
+
+void
+tktfreemarks(TkTmarkinfo *m)
+{
+	TkTmarkinfo *n;
+
+	while(m != nil) {
+		n = m->next;
+		free(m->name);
+		free(m);
+		m = n;
+	}
+}
+
+TkTmarkinfo *
+tktfindmark(TkTmarkinfo *m, char *name)
+{
+	while(m != nil) {
+		if(strcmp(m->name, name) == 0)
+			return m;
+		m = m->next;
+	}
+	return nil;
+}
+
+int
+tktmarkind(Tk *tk, char *name, TkTindex *ans)
+{
+	TkTmarkinfo *mk;
+	TkText *tkt = TKobj(TkText, tk);
+
+	if(strcmp(name, "current") == 0) {
+		tktxyind(tk, tkt->current.x, tkt->current.y, ans);
+		return 1;
+	}
+
+	mk = tktfindmark(tkt->marks, name);
+	if(mk == nil || mk->cur == nil)
+		return 0;
+
+	ans->item = mk->cur;
+	ans->line = tktitemline(ans->item);
+	ans->pos = 0;
+	return 1;
+}
+
+char*
+tktmarkparse(Tk *tk, char **parg, TkTmarkinfo **ret)
+{
+	char *e, *buf;
+	TkText *tkt = TKobj(TkText, tk);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	*parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+	if(*buf == '\0') {
+		free(buf);
+		return TkOparg;
+	}
+
+	*ret = tktfindmark(tkt->marks, buf);
+	if(*ret == nil) {
+		e = tktaddmarkinfo(tkt, buf, ret);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+	}
+	free(buf);
+
+	return nil;
+}
+
+/*
+ * Insert mark before ixnew, first removing it from old place, if any.
+ * Make sure ixnew continues to point after mark.
+ */
+char*
+tktmarkmove(Tk *tk, TkTmarkinfo *m, TkTindex *ixnew)
+{
+	char *e;
+	int deleted, split;
+	TkTitem *i;
+	TkTindex ix, pix;
+	TkText *tkt = TKobj(TkText, tk);
+
+	deleted = 0;
+	if(m->cur != nil) {
+		if(m->cur == ixnew->item)
+			return nil;
+		ix.item = m->cur;
+		ix.line = tktitemline(m->cur);
+		ix.pos = 0;
+		tktremitem(tkt, &ix);
+		deleted = 1;
+	}
+
+	/* XXX - Tad: memory leak on 'i' if something fails later? */
+	e = tktnewitem(TkTmark, 0, &i);
+	if(e != nil)
+		return e;
+
+	i->imark = m;
+	m->cur = i;
+
+	/* keep adjacent marks sorted: all rights, then all lefts */
+	if(m->gravity == Tkright) {
+		while(ixnew->item->kind == TkTmark && ixnew->item->imark->gravity == Tkleft)
+			if(!tktadjustind(tkt, TkTbyitem, ixnew))
+				break;
+	}
+	else {
+		for(;;) {
+			pix = *ixnew;
+			if(!tktadjustind(tkt, TkTbyitemback, &pix))
+				break;
+			if(pix.item->kind == TkTmark && pix.item->imark->gravity == Tkright)
+				*ixnew = pix;
+			else
+				break;
+		}
+	}
+
+	split = (ixnew->pos > 0);
+	e = tktsplititem(ixnew);
+	if(e != nil)
+		return e;
+
+	e = tktiteminsert(tkt, ixnew, i);
+	if(e != nil)
+		return nil;
+
+	if(strcmp(m->name, "insert") == 0 || split) {
+		if(deleted && ix.line != ixnew->line) {
+			tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);
+			/*
+			 * this is ok only because tktfixgeom cannot
+			 * free mark items, and we know that i is a mark item.
+			 */
+			ixnew->item = i;
+			ixnew->line = tktitemline(i);
+			ixnew->pos = 0;
+		}
+		tktfixgeom(tk, tktprevwrapline(tk, ixnew->line), ixnew->line, 0);
+		tktextsize(tk, 1);
+	}
+	
+	ixnew->item = i;
+	ixnew->line = tktitemline(i);
+	ixnew->pos = 0;
+	return nil;
+}
+
+/* Text Mark Commands (+ means implemented)
+	+gravity
+	+names
+	+next
+	+previous
+	+set
+	+unset
+*/
+
+static char*
+tktmarkgravity(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTmarkinfo *m;
+	char *buf;
+
+	e = tktmarkparse(tk, &arg, &m);
+	if(e != nil)
+		return e;
+
+	if(*arg == '\0')
+		return tkvalue(val, (m->gravity & Tkleft)? "left" : "right");
+	else {
+		buf = mallocz(Tkmaxitem, 0);
+		if(buf == nil)
+			return TkNomem;
+		tkword(tk->env->top, arg, buf, buf+Tkmaxitem, nil);
+		if(strcmp(buf, "left") == 0)
+			m->gravity = Tkleft;
+		else
+		if(strcmp(buf, "right") == 0)
+			m->gravity = Tkright;
+		else {
+			free(buf);
+			return TkBadcm;
+		}
+		free(buf);
+	}
+	return nil;
+}
+
+static char*
+tktmarknames(Tk *tk, char *arg, char **val)
+{
+	char *r, *fmt;
+	TkTmarkinfo *m;
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(arg);
+
+	fmt = "%s";
+	for(m = tkt->marks; m != nil; m = m->next) {
+		r = tkvalue(val, fmt, m->name);
+		if(r != nil)
+			return r;
+		fmt = " %s";
+	}
+	return nil;
+}
+
+static char*
+tktmarknext(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTmarkinfo *mix;
+	TkTindex ix, ixend;
+	TkText *tkt = TKobj(TkText, tk);
+
+	/* special behavior if specified index is a mark name */
+	mix = tktfindmark(tkt->marks, arg);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+
+	if(mix != nil)
+		tktadjustind(tkt, TkTbyitem, &ix);
+
+	/* special behavior if index is 'end' */
+	tktendind(tkt, &ixend);
+	if(tktindcompare(tkt, &ix, TkEq, &ixend)) {
+		do {
+			tktadjustind(tkt, TkTbyitemback, &ix);
+		} while(ix.item->kind == TkTmark);
+	}
+
+	do {
+		if(ix.item->kind == TkTmark)
+			return tkvalue(val, "%s", ix.item->imark->name);
+		
+	} while(tktadjustind(tkt, TkTbyitem, &ix));
+	
+	return nil;
+}
+
+static char*
+tktmarkprevious(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+
+	while(tktadjustind(tkt, TkTbyitemback, &ix)) {
+		if(ix.item->kind == TkTmark)
+			return tkvalue(val, "%s", ix.item->imark->name);
+	}
+	
+	return nil;
+}
+
+/* XXX - Tad: possible memory leak here */
+static char*
+tktmarkset(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTmarkinfo *m;
+	TkTindex ixnew;
+
+	USED(val);
+
+	e = tktmarkparse(tk, &arg, &m);
+	if(e != nil)
+		return e;
+	e = tktindparse(tk, &arg, &ixnew);
+	if(e != nil)
+		return e;
+
+	return tktmarkmove(tk, m, &ixnew);
+}
+
+static char*
+tktmarkunset(Tk *tk, char *arg, char **val)
+{
+	TkText *tkt;
+	TkTmarkinfo *m, **p;
+	TkTindex ix;
+	char *e;
+	int resize;
+
+	USED(val);
+
+	tkt = TKobj(TkText, tk);
+
+	e = tktmarkparse(tk, &arg, &m);
+	if(e != nil)
+		return e;
+
+	resize = 0;
+	while(m != nil) {
+		if(strcmp(m->name, "insert") == 0 || strcmp(m->name, "current") == 0)
+			return TkBadvl;
+
+		if(m->cur != nil) {
+			ix.item = m->cur;
+			ix.line = tktitemline(m->cur);
+			ix.pos = 0;
+			tktremitem(tkt, &ix);
+			tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);
+			resize = 1;
+		}
+
+		for(p = &tkt->marks; *p != nil; p = &(*p)->next) {
+			if(*p == m) {
+				*p = m->next;
+				break;
+			}
+		}
+		m->next = nil;
+		tktfreemarks(m);
+
+		if(*arg != '\0') {
+			e = tktmarkparse(tk, &arg, &m);
+			if(e != nil)
+				return e;
+		}
+		else
+			m = nil;
+	}
+	if (resize)
+		tktextsize(tk, 1);
+	return nil;
+}
+
--- /dev/null
+++ b/libtk/ttags.c
@@ -1,0 +1,1029 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+static char* tkttagadd(Tk*, char*, char**);
+static char* tkttagbind(Tk*, char*, char**);
+static char* tkttagcget(Tk*, char*, char**);
+static char* tkttagconfigure(Tk*, char*, char**);
+static char* tkttagdelete(Tk*, char*, char**);
+static char* tkttaglower(Tk*, char*, char**);
+static char* tkttagnames(Tk*, char*, char**);
+static char* tkttagnextrange(Tk*, char*, char**);
+static char* tkttagprevrange(Tk*, char*, char**);
+static char* tkttagraise(Tk*, char*, char**);
+static char* tkttagranges(Tk*, char*, char**);
+static char* tkttagremove(Tk*, char*, char**);
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+#define TKTEO		(O(TkTtaginfo, env))
+static 
+TkOption tagopts[] =
+{
+	"borderwidth",
+		OPTnndist, O(TkTtaginfo, opts[TkTborderwidth]),	nil,
+	"justify",
+		OPTstab, O(TkTtaginfo, opts[TkTjustify]),	tkjustify,
+	"lineheight",
+		OPTnndist, O(TkTtaginfo, opts[TkTlineheight]),	IAUX(TKTEO),
+	"lmargin1",
+		OPTdist, O(TkTtaginfo, opts[TkTlmargin1]),	IAUX(TKTEO),
+	"lmargin2",
+		OPTdist, O(TkTtaginfo, opts[TkTlmargin2]),	IAUX(TKTEO),
+	"lmargin3",
+		OPTdist, O(TkTtaginfo, opts[TkTlmargin3]),	IAUX(TKTEO),
+	"rmargin",
+		OPTdist, O(TkTtaginfo, opts[TkTrmargin]),	IAUX(TKTEO),
+	"spacing1",
+		OPTnndist, O(TkTtaginfo, opts[TkTspacing1]),	IAUX(TKTEO),
+	"spacing2",
+		OPTnndist, O(TkTtaginfo, opts[TkTspacing2]),	IAUX(TKTEO),
+	"spacing3",
+		OPTnndist, O(TkTtaginfo, opts[TkTspacing3]),	IAUX(TKTEO),
+	"offset",	
+		OPTdist, O(TkTtaginfo, opts[TkToffset]),	IAUX(TKTEO),
+	"underline",
+		OPTstab, O(TkTtaginfo, opts[TkTunderline]),	tkbool,
+	"overstrike",
+		OPTstab, O(TkTtaginfo, opts[TkToverstrike]),	tkbool,
+	"relief",
+		OPTstab, O(TkTtaginfo, opts[TkTrelief]),	tkrelief,
+	"tabs",	
+		OPTtabs, O(TkTtaginfo, tabs),			IAUX(TKTEO),
+	"wrap",
+		OPTstab, O(TkTtaginfo, opts[TkTwrap]),		tkwrap,
+	nil,
+};
+
+static 
+TkOption tagenvopts[] =
+{
+	"foreground",	OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCforegnd),
+	"background",	OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCbackgnd),
+	"fg",		OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCforegnd),
+	"bg",		OPTcolr,	O(TkTtaginfo, env),	IAUX(TkCbackgnd),
+	"font",		OPTfont,	O(TkTtaginfo, env),	nil,
+	nil
+};
+
+TkCmdtab
+tkttagcmd[] =
+{
+	"add",		tkttagadd,
+	"bind",		tkttagbind,
+	"cget",		tkttagcget,
+	"configure",	tkttagconfigure,
+	"delete",	tkttagdelete,
+	"lower",	tkttaglower,
+	"names",	tkttagnames,
+	"nextrange",	tkttagnextrange,
+	"prevrange",	tkttagprevrange,
+	"raise",	tkttagraise,
+	"ranges",	tkttagranges,
+	"remove",	tkttagremove,
+	nil
+};
+
+int
+tktanytags(TkTitem *it)
+{
+	int i;
+
+	if(it->tagextra == 0)
+		return (it->tags[0] != 0);
+	for(i = 0; i <= it->tagextra; i++)
+		if(it->tags[i] != 0)
+			return 1;
+	return 0;
+}
+
+int
+tktsametags(TkTitem *i1, TkTitem *i2)
+{
+	int i, j;
+
+	for(i = 0; i <= i1->tagextra && i <= i2->tagextra; i++)
+		if(i1->tags[i] != i2->tags[i])
+			return 0;
+	for(j = i; j <= i1->tagextra; j++)
+		if(i1->tags[j] != 0)
+			return 0;
+	for(j = i; j <= i2->tagextra; j++)
+		if(i2->tags[j] != 0)
+			return 0;
+	return 1;
+}
+
+int
+tkttagset(TkTitem *it, int id)
+{
+	int i;
+
+	if(it->tagextra == 0 && it->tags[0] == 0)
+		return 0;
+	for(i = 0; i <= it->tagextra; i++) {
+		if(id < 32)
+			return ((it->tags[i] & (1<<id)) != 0);
+		id -= 32;
+	}
+	return 0;
+}
+
+char *
+tkttagname(TkText *tkt, int id)
+{
+	TkTtaginfo *t;
+
+	for(t = tkt->tags; t != nil; t = t->next) {
+		if(t->id == id)
+			return t->name;
+	}
+	return "";
+}
+
+/* return 1 if this actually changes the value */
+int
+tkttagbit(TkTitem *it, int id, int val)
+{
+	int i, changed;
+	ulong z, b;
+
+	changed = 0;
+	for(i = 0; i <= it->tagextra; i++) {
+		if(id < 32) {
+			b = (1<<id);
+			z = it->tags[i];
+			if(val == 0) {
+				if(z & b) {
+					changed = 1;
+					it->tags[i] = z & (~b);
+				}
+			}
+			else {
+				if((z & b) == 0) {
+					changed = 1;
+					it->tags[i] = z | b;
+				}
+			}
+			break;
+		}
+		id -= 32;
+	}
+	return changed;
+}
+
+void
+tkttagcomb(TkTitem *i1, TkTitem *i2, int add)
+{
+	int i;
+
+	for(i = 0; i <= i1->tagextra && i <= i2->tagextra; i++) {
+		if(add == 1)
+			i1->tags[i] |= i2->tags[i];
+		else if(add == 0)
+			/* intersect */
+			i1->tags[i] &= i2->tags[i];
+		else
+			/* subtract */
+			i1->tags[i] &= ~i2->tags[i];
+	}
+}
+
+char*
+tktaddtaginfo(Tk *tk, char *name, TkTtaginfo **ret)
+{
+	int i, *ntagp;
+	TkTtaginfo *ti;
+	TkText *tkt, *tktshare;
+
+	tkt = TKobj(TkText, tk);
+	ti = malloc(sizeof(TkTtaginfo));
+	if(ti == nil)
+		return TkNomem;
+
+	ntagp = &tkt->nexttag;
+	if(tkt->tagshare != nil) {
+		tktshare = TKobj(TkText, tkt->tagshare);
+		ntagp = &tktshare->nexttag;
+	}
+	ti->id = *ntagp;
+	ti->name = strdup(name);
+	if(ti->name == nil) {
+		free(ti);
+		return TkNomem;
+	}
+	ti->env = tknewenv(tk->env->top);
+	if(ti->env == nil) {
+		free(ti->name);
+		free(ti);
+		return TkNomem;
+	}
+
+	ti->tabs = nil;
+	for(i = 0; i < TkTnumopts; i++)
+		ti->opts[i] = TkTunset;
+	ti->next = tkt->tags;
+	tkt->tags = ti;
+
+	(*ntagp)++;
+	if(tkt->tagshare)
+		tkt->nexttag = *ntagp;
+
+	*ret = ti;
+	return nil;
+}
+
+TkTtaginfo *
+tktfindtag(TkTtaginfo *t, char *name)
+{
+	while(t != nil) {
+		if(strcmp(t->name, name) == 0)
+			return t;
+		t = t->next;
+	}
+	return nil;
+}
+
+void
+tktfreetags(TkTtaginfo *t)
+{
+	TkTtaginfo *n;
+
+	while(t != nil) {
+		n = t->next;
+		free(t->name);
+		tktfreetabs(t->tabs);
+		tkputenv(t->env);
+		tkfreebind(t->binds);
+		free(t);
+		t = n;
+	}
+}
+
+int
+tkttagind(Tk *tk, char *name, int first, TkTindex *ans)
+{
+	int id;
+	TkTtaginfo *t;
+	TkText *tkt;
+
+	tkt = TKobj(TkText, tk);
+
+	if(strcmp(name, "sel") == 0) {
+		if(tkt->selfirst == nil)
+			return 0;
+		if(first)
+			tktitemind(tkt->selfirst, ans);
+		else
+			tktitemind(tkt->sellast, ans);
+		return 1;
+	}
+
+	t = tktfindtag(tkt->tags, name);
+	if(t == nil)
+		return 0;
+	id = t->id;
+
+	if(first) {
+		tktstartind(tkt, ans);
+		while(!tkttagset(ans->item, id))
+			if(!tktadjustind(tkt, TkTbyitem, ans))
+				return 0;
+	}
+	else {
+		tktendind(tkt, ans);
+		while(!tkttagset(ans->item, id))
+			if(!tktadjustind(tkt, TkTbyitemback, ans))
+				return 0;
+		tktadjustind(tkt, TkTbyitem, ans);
+	}
+
+	return 1;
+}
+
+/*
+ * Fill in opts and e, based on info from tags set in it,
+ * using tags order for priority.
+ * If dflt != 0, options not set are filled from tk,
+ * otherwise iInteger options not set by any tag are left 'TkTunset'
+ * and environment values not set are left nil.
+ */
+void
+tkttagopts(Tk *tk, TkTitem *it, int *opts, TkEnv *e, TkTtabstop **tb, int dflt)
+{
+	int i;
+	int colset;
+	TkEnv *te;
+	TkTtaginfo *tags;
+	TkText *tkt = TKobj(TkText, tk);
+
+	if (tb != nil)
+		*tb = tkt->tabs;
+
+	tags = tkt->tags;
+
+	if(opts != nil)
+		for(i = 0; i < TkTnumopts; i++)
+			opts[i] = TkTunset;
+
+	memset(e, 0, sizeof(TkEnv));
+	e->top = tk->env->top;
+	colset = 0;
+	while(tags != nil) {
+		if(tkttagset(it, tags->id)) {
+			if(opts != nil) {
+				for(i = 0; i < TkTnumopts; i++) {
+					if(opts[i] == TkTunset && tags->opts[i] != TkTunset)
+						opts[i] = tags->opts[i];
+				}
+			}
+
+			te = tags->env;
+			for(i = 0; i < TkNcolor; i++)
+				if(!(colset & (1<<i)) && te->set & (1<<i)) {
+					e->colors[i] = te->colors[i];
+					colset |= 1<<i;
+				}
+
+			if(e->font == nil && te->font != nil)
+				e->font = te->font;
+
+			if (tb != nil && tags->tabs != nil)
+				*tb = tags->tabs;
+		}
+		tags = tags->next;
+	}
+	e->set |= colset;
+	if(dflt) {
+		if(opts != nil) {
+			for(i = 0; i < TkTnumopts; i++)
+				if(opts[i] == TkTunset)
+					opts[i] = tkt->opts[i];
+		}
+		te = tk->env;
+		for(i = 0; i < TkNcolor; i++)
+			if(!(e->set & (1<<i))) {
+				e->colors[i] = te->colors[i];
+				e->set |= 1<<i;
+			}
+		if(e->font == nil)
+			e->font = te->font;
+	}
+}
+
+char*
+tkttagparse(Tk *tk, char **parg, TkTtaginfo **ret)
+{
+	char *e, *buf;
+	TkText *tkt = TKobj(TkText, tk);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+	*parg = tkword(tk->env->top, *parg, buf, buf+Tkmaxitem, nil);
+	if(*buf == '\0') {
+		free(buf);
+		return TkOparg;
+	}
+	if(buf[0] >= '0' && buf[0] <= '9'){
+		free(buf);
+		return TkBadtg;
+	}
+
+	*ret = tktfindtag(tkt->tags, buf);
+	if(*ret == nil) {
+		e = tktaddtaginfo(tk, buf, ret);
+		if(e != nil) {
+			free(buf);
+			return e;
+		}
+	}
+	free(buf);
+
+	return nil;
+}
+
+int
+tkttagnrange(TkText *tkt, int tid, TkTindex *i1, TkTindex *i2,
+			TkTindex *istart, TkTindex *iend)
+{
+	int found;
+
+	found = 0;
+	while(i1->line != &tkt->end) {
+		if(i1->item == i2->item && i2->pos == 0)
+			break;
+		if(tkttagset(i1->item, tid)) {
+			if(!found) {
+				found = 1;
+				*istart = *i1;
+			}
+			if(i1->item == i2->item) {
+				/* i2->pos > 0 */
+				*iend = *i2;
+				return 1;
+			}
+		}
+		else
+		if(i1->item == i2->item || (found && i1->item->kind != TkTmark && i1->item->kind != TkTcontline))
+			break;
+		tktadjustind(tkt, TkTbyitem, i1);
+	}
+	if(found)
+		*iend = *i1;
+
+	return found;
+}
+
+static int
+tkttagprange(TkText *tkt, int tid, TkTindex *i1, TkTindex *i2,
+			TkTindex *istart, TkTindex *iend)
+{
+	int found;
+
+	found = 0;
+	while(i1->line != &tkt->start && i1->item != i2->item) {
+		tktadjustind(tkt, TkTbyitemback, i1);
+		if(tkttagset(i1->item, tid)) {
+			if(!found) {
+				found = 1;
+				*iend = *i1;
+			}
+		}
+		else
+		if(found && i1->item->kind != TkTmark && i1->item->kind != TkTcontline)
+			break;
+	}
+	if(found) {
+		tktadjustind(tkt, TkTbyitem, i1);
+		*istart = *i1;
+		if(i1->item == i2->item)
+			istart->pos = i2->pos;
+	}
+
+	return found;
+}
+
+/* XXX - Tad: potential memory leak on memory allocation failure */
+char *
+tkttagchange(Tk *tk, int tid, TkTindex *i1, TkTindex *i2, int add)
+{
+	char *e;
+	int samei, nextra, j, changed;
+	TkTline *lmin, *lmax;
+	TkTindex ixprev;
+	TkTitem *nit;
+	TkText *tkt = TKobj(TkText, tk);
+
+	if(!tktindbefore(i1, i2))
+		return nil;
+
+	nextra = tid/32;
+	lmin = nil;
+	lmax = nil;
+	tktadjustind(tkt, TkTbycharstart, i1);
+	tktadjustind(tkt, TkTbycharstart, i2);
+	samei = (i1->item == i2->item);
+	if(i2->pos != 0) {
+		e = tktsplititem(i2);
+		if(e != nil)
+			return e;
+		if(samei) {
+			/* split means i1 should now point to previous item */
+			ixprev = *i2;
+			tktadjustind(tkt, TkTbyitemback, &ixprev);
+			i1->item = ixprev.item;
+		}
+	}
+	if(i1->pos != 0) {
+		e = tktsplititem(i1);
+		if(e != nil)
+			return e;
+	}
+	/* now i1 and i2 both point to beginning of non-mark/contline items */
+	if(tid == TkTselid) {
+		/*
+		 * Cache location of selection.
+		 * Note: there can be only one selection range in widget
+		 */
+		if(add) {
+			if(tkt->selfirst != nil)
+				return TkBadsl;
+			tkt->selfirst = i1->item;
+			tkt->sellast = i2->item;
+		}
+		else {
+			tkt->selfirst = nil;
+			tkt->sellast = nil;
+		}
+	}
+	while(i1->item != i2->item) {
+		if(i1->item->kind != TkTmark && i1->item->kind != TkTcontline) {
+			if(tid >= 32 && i1->item->tagextra < nextra) {
+				nit = realloc(i1->item, sizeof(TkTitem) + nextra * sizeof(long));
+				if(nit == nil)
+					return TkNomem;
+				for(j = nit->tagextra+1; j <= nextra; j++)
+					nit->tags[j] = 0;
+				nit->tagextra = nextra;
+				if(i1->line->items == i1->item)
+					i1->line->items = nit;
+				else {
+					ixprev = *i1;
+					tktadjustind(tkt, TkTbyitemback, &ixprev);
+					ixprev.item->next = nit;
+				}
+				/* check nit against cached items */
+				if(tkt->selfirst == i1->item)
+					tkt->selfirst = nit;
+				if(tkt->sellast == i1->item)
+					tkt->sellast = nit;
+				i1->item = nit;
+			}
+			changed = tkttagbit(i1->item, tid, add);
+			if(lmin == nil) {
+				if(changed) {
+					lmin = i1->line;
+					lmax = lmin;
+				}
+			}
+			else {
+				if(changed)
+					lmax = i1->line;
+			}
+		}
+		if(!tktadjustind(tkt, TkTbyitem, i1))
+			break;
+	}
+	if(lmin != nil) {
+		tktfixgeom(tk, tktprevwrapline(tk, lmin), lmax, 0);
+		tktextsize(tk, 1);
+	}
+	return nil;
+}
+
+static char*
+tkttagaddrem(Tk *tk, char *arg, int add)
+{
+	char *e;
+	TkText *tkt;
+	TkTtaginfo *ti;
+	TkTindex ix1, ix2;
+
+	tkt = TKobj(TkText, tk);
+
+	e = tkttagparse(tk, &arg, &ti);
+	if(e != nil)
+		return e;
+
+	while(*arg != '\0') {
+		e = tktindparse(tk, &arg, &ix1);
+		if(e != nil)
+			return e;
+		if(*arg != '\0') {
+			e = tktindparse(tk, &arg, &ix2);
+			if(e != nil)
+				return e;
+		}
+		else {
+			ix2 = ix1;
+			tktadjustind(tkt, TkTbychar, &ix2);
+		}
+		if(!tktindbefore(&ix1, &ix2))
+			continue;
+
+		e = tkttagchange(tk, ti->id, &ix1, &ix2, add);
+		if(e != nil)
+			return e;
+	}
+
+	return nil;
+}
+
+
+/* Text Tag Command (+ means implemented)
+	+add
+	+bind
+	+cget
+	+configure
+	+delete
+	+lower
+	+names
+	+nextrange
+	+prevrange
+	+raise
+	+ranges
+	+remove
+*/
+
+static char*
+tkttagadd(Tk *tk, char *arg, char **val)
+{
+	USED(val);
+
+	return tkttagaddrem(tk, arg, 1);
+}
+
+static char*
+tkttagbind(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	Rune r;
+	TkTtaginfo *ti;
+	TkAction *a;
+	int event, mode;
+	char *cmd, buf[Tkmaxitem];
+
+
+	e = tkttagparse(tk, &arg, &ti);
+	if(e != nil)
+		return e;
+
+	arg = tkskip(arg, " \t");
+	if (arg[0] == '\0')
+		return TkBadsq;
+	arg = tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	if(buf[0] == '<') {
+		event = tkseqparse(buf+1);
+		if(event == -1)
+			return TkBadsq;
+	}
+	else {
+		chartorune(&r, buf);
+		event = TkKey | r;
+	}
+	if(event == 0)
+		return TkBadsq;
+
+	arg = tkskip(arg, " \t");
+	if(*arg == '\0') {
+		for(a = ti->binds; a; a = a->link)
+				if(event == a->event)
+					return tkvalue(val, "%s", a->arg);
+		return nil;		
+	}
+
+	mode = TkArepl;
+	if(*arg == '+') {
+		mode = TkAadd;
+		arg++;
+	}
+	else if(*arg == '-'){
+		mode = TkAsub;
+		arg++;
+	}
+
+	tkword(tk->env->top, arg, buf, buf+sizeof(buf), nil);
+	cmd = strdup(buf);
+	if(cmd == nil)
+		return TkNomem;
+	return tkaction(&ti->binds, event, TkDynamic, cmd, mode);
+}
+
+static char*
+tkttagcget(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTtaginfo *ti;
+	TkOptab tko[3];
+
+	e = tkttagparse(tk, &arg, &ti);
+	if(e != nil)
+		return e;
+
+	tko[0].ptr = ti;
+	tko[0].optab = tagopts;
+	tko[1].ptr = ti;
+	tko[1].optab = tagenvopts;
+	tko[2].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tkttagconfigure(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkOptab tko[3];
+	TkTtaginfo *ti;
+	TkTindex ix;
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(val);
+
+	e = tkttagparse(tk, &arg, &ti);
+	if(e != nil)
+		return e;
+
+	tko[0].ptr = ti;
+	tko[0].optab = tagopts;
+	tko[1].ptr = ti;
+	tko[1].optab = tagenvopts;
+	tko[2].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil)
+		return e;
+
+	if(tkttagind(tk, ti->name, 1, &ix)) {
+		tktfixgeom(tk, tktprevwrapline(tk, ix.line), tkt->end.prev, 0);
+		tktextsize(tk, 1);
+	}
+
+	return nil;
+}
+
+static void
+tktunlinktag(TkText *tkt, TkTtaginfo *t)
+{
+	TkTtaginfo *f, **l;
+
+	l = &tkt->tags;
+	for(f = *l; f != nil; f = f->next) {
+		if(f == t) {
+			*l = t->next;
+			return;
+		}
+		l = &f->next;
+	}
+}
+
+static char*
+tkttagdelete(Tk *tk, char *arg, char **val)
+{
+	TkText *tkt;
+	TkTtaginfo *t;
+	TkTindex ix;
+	char *e;
+	int found;
+
+	USED(val);
+
+	tkt = TKobj(TkText, tk);
+
+	e = tkttagparse(tk, &arg, &t);
+	if(e != nil)
+		return e;
+
+	found = 0;
+	while(t != nil) {
+		if(t->id == TkTselid)
+			return TkBadvl;
+
+		while(tkttagind(tk, t->name, 1, &ix)) {
+			found = 1;
+			tkttagbit(ix.item, t->id, 0);
+		}
+
+		tktunlinktag(tkt, t);
+		t->next = nil;
+		tktfreetags(t);
+
+		if(*arg != '\0') {
+			e = tkttagparse(tk, &arg, &t);
+			if(e != nil)
+				return e;
+		}
+		else
+			t = nil;
+	}
+	if (found) {
+		tktfixgeom(tk, &tkt->start, tkt->end.prev, 0);
+		tktextsize(tk, 1);
+	}
+
+	return nil;
+}
+
+static char*
+tkttaglower(Tk *tk, char *arg, char **val)
+{
+	TkText *tkt;
+	TkTindex ix;
+	TkTtaginfo *t, *tbelow, *f, **l;
+	char *e;
+
+	USED(val);
+
+	tkt = TKobj(TkText, tk);
+
+	e = tkttagparse(tk, &arg, &t);
+	if(e != nil)
+		return e;
+
+	if(*arg != '\0') {
+		e = tkttagparse(tk, &arg, &tbelow);
+		if(e != nil)
+			return e;
+	}
+	else
+		tbelow = nil;
+
+	tktunlinktag(tkt, t);
+
+	if(tbelow != nil) {
+		t->next = tbelow->next;
+		tbelow->next = t;
+	}
+	else {
+		l = &tkt->tags;
+		for(f = *l; f != nil; f = f->next)
+			l = &f->next;
+		*l = t;
+		t->next = nil;
+	}
+	if(tkttagind(tk, t->name, 1, &ix)) {
+		tktfixgeom(tk, tktprevwrapline(tk, ix.line), tkt->end.prev, 0);
+		tktextsize(tk, 1);
+	}
+
+	return nil;
+}
+
+
+static char*
+tkttagnames(Tk *tk, char *arg, char **val)
+{
+	char *e, *r, *fmt;
+	TkTtaginfo *t;
+	TkTindex i;
+	TkText *tkt = TKobj(TkText, tk);
+	TkTitem *tagit;
+
+	if(*arg != '\0') {
+		e = tktindparse(tk, &arg, &i);
+		if(e != nil)
+			return e;
+		/* make sure we're actually on a character */
+		tktadjustind(tkt, TkTbycharstart, &i);
+		tagit = i.item;
+	}
+	else
+		tagit = nil;
+
+	/* generate in order highest-to-lowest priority (contrary to spec) */
+	fmt = "%s";
+	for(t = tkt->tags; t != nil; t = t->next) {
+		if(tagit == nil || tkttagset(tagit, t->id)) {
+			r = tkvalue(val, fmt, t->name);
+			if(r != nil)
+				return r;
+			fmt = " %s";
+		}
+	}
+	return nil;
+}
+
+static char*
+tkttagnextrange(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTtaginfo *t;
+	TkTindex i1, i2, istart, iend;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tkttagparse(tk, &arg, &t);
+	if(e != nil)
+		return e;
+	e = tktindparse(tk, &arg, &i1);
+	if(e != nil)
+		return e;
+	if(*arg != '\0') {
+		e = tktindparse(tk, &arg, &i2);
+		if(e != nil)
+			return e;
+	}
+	else
+		tktendind(tkt, &i2);
+
+	if(tkttagnrange(tkt, t->id, &i1, &i2, &istart, &iend))
+		return tkvalue(val, "%d.%d %d.%d",
+			tktlinenum(tkt, &istart), tktlinepos(tkt, &istart),
+			tktlinenum(tkt, &iend), tktlinepos(tkt, &iend));
+
+	return nil;
+}
+
+static char*
+tkttagprevrange(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTtaginfo *t;
+	TkTindex i1, i2, istart, iend;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tkttagparse(tk, &arg, &t);
+	if(e != nil)
+		return e;
+	e = tktindparse(tk, &arg, &i1);
+	if(e != nil)
+		return e;
+	if(*arg != '\0') {
+		e = tktindparse(tk, &arg, &i2);
+		if(e != nil)
+			return e;
+	}
+	else
+		tktstartind(tkt, &i2);
+
+	if(tkttagprange(tkt, t->id, &i1, &i2, &istart, &iend))
+		return tkvalue(val, "%d.%d %d.%d",
+			tktlinenum(tkt, &istart), tktlinepos(tkt, &istart),
+			tktlinenum(tkt, &iend), tktlinepos(tkt, &iend));
+
+	return nil;
+}
+
+static char*
+tkttagraise(Tk *tk, char *arg, char **val)
+{
+	TkText *tkt;
+	TkTindex ix;
+	TkTtaginfo *t, *tabove, *f, **l;
+	char *e;
+
+	USED(val);
+
+	tkt = TKobj(TkText, tk);
+
+	e = tkttagparse(tk, &arg, &t);
+	if(e != nil)
+		return e;
+
+	if(*arg != '\0') {
+		e = tkttagparse(tk, &arg, &tabove);
+		if(e != nil)
+			return e;
+	}
+	else
+		tabove = nil;
+
+	tktunlinktag(tkt, t);
+
+	if(tabove != nil) {
+		l = &tkt->tags;
+		for(f = *l; f != nil; f = f->next) {
+			if(f == tabove) {
+				*l = t;
+				t->next = tabove;
+				break;
+			}
+			l = &f->next;
+		}
+	}
+	else {
+		t->next = tkt->tags;
+		tkt->tags = t;
+	}
+
+	if(tkttagind(tk, t->name, 1, &ix)) {
+		tktfixgeom(tk, tktprevwrapline(tk, ix.line), tkt->end.prev, 0);
+		tktextsize(tk, 1);
+	}
+	return nil;
+}
+
+static char*
+tkttagranges(Tk *tk, char *arg, char **val)
+{
+	char *e, *fmt;
+	TkTtaginfo *t;
+	TkTindex i1, i2, istart, iend;
+	TkText *tkt = TKobj(TkText, tk);
+
+	e = tkttagparse(tk, &arg, &t);
+	if(e != nil)
+		return e;
+
+	tktstartind(tkt, &i1);
+	tktendind(tkt, &i2);
+
+	fmt = "%d.%d %d.%d";
+	while(tkttagnrange(tkt, t->id, &i1, &i2, &istart, &iend)) {
+		e = tkvalue(val, fmt,
+			tktlinenum(tkt, &istart), tktlinepos(tkt, &istart),
+			tktlinenum(tkt, &iend), tktlinepos(tkt, &iend));
+		if(e != nil)
+			return e;
+
+		fmt = " %d.%d %d.%d";
+		i1 = iend;
+	}
+
+	return nil;
+}
+
+static char*
+tkttagremove(Tk *tk, char *arg, char **val)
+{
+	USED(val);
+
+	return tkttagaddrem(tk, arg, 0);
+}
--- /dev/null
+++ b/libtk/twind.c
@@ -1,0 +1,389 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "textw.h"
+
+#define istring u.string
+#define iwin u.win
+#define imark u.mark
+#define iline u.line
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+static char* tktwincget(Tk*, char*, char**);
+static char* tktwinconfigure(Tk*, char*, char**);
+static char* tktwincreate(Tk*, char*, char**);
+static char* tktwinnames(Tk*, char*, char**);
+static int winowned(Tk *tk, Tk *sub);
+
+static
+TkStab tkalign[] =
+{
+	"top",		Tktop,
+	"bottom",	Tkbottom,
+	"center",	Tkcenter,
+	"baseline",	Tkbaseline,
+	nil
+};
+
+static
+TkOption twinopts[] =
+{
+	"align",	OPTstab,	O(TkTwind, align),	tkalign,
+	"create",	OPTtext,	O(TkTwind, create),	nil,
+	"padx",		OPTnndist,	O(TkTwind, padx),	nil,
+	"pady",		OPTnndist,	O(TkTwind, pady),	nil,
+	"stretch",	OPTstab,	O(TkTwind, stretch),	tkbool,
+	"window",	OPTwinp,	O(TkTwind, sub),	nil,
+	"ascent",	OPTdist,	O(TkTwind, ascent), nil,
+	nil
+};
+
+TkCmdtab
+tktwincmd[] =
+{
+	"cget",		tktwincget,
+	"configure",	tktwinconfigure,
+	"create",	tktwincreate,
+	"names",	tktwinnames,
+	nil
+};
+
+int
+tktfindsubitem(Tk *sub, TkTindex *ix)
+{
+	Tk *tk, *isub;
+	TkText *tkt;
+
+	tk = sub->parent;
+	if(tk != nil) {
+		tkt = TKobj(TkText, tk);
+		tktstartind(tkt, ix);
+		do {
+			if(ix->item->kind == TkTwin) {
+				isub = ix->item->iwin->sub;
+				if(isub != nil && 
+				   isub->name != nil && 
+				   strcmp(isub->name->name, sub->name->name) == 0)
+				return 1;
+			}
+		} while(tktadjustind(tkt, TkTbyitem, ix));
+	}
+	return 0;
+}
+
+static void
+tktwindsize(Tk *tk, TkTindex *ix)
+{
+	Tk *s;
+	TkTitem *i;
+	TkTwind *w;
+
+
+	i = ix->item;
+	/* assert(i->kind == TkTwin); */
+
+	w = i->iwin;
+	s = w->sub;
+	if(s == nil)
+		return;
+
+	if(w->width != s->act.width || w->height != s->act.height) {
+		s->act.width = w->width;
+		s->act.height = w->height;
+		if(s->slave) {
+			tkpackqit(s);
+			tkrunpack(tk->env->top);
+		}
+	}
+
+	tktfixgeom(tk, tktprevwrapline(tk, ix->line), ix->line, 0);
+	tktextsize(tk, 1);
+}
+
+void
+tktxtforgetsub(Tk *sub, Tk *tk)
+{
+	TkTwind *w;
+	TkTindex ix;
+
+	if(!tktfindsubitem(sub, &ix))
+		return;
+	w = ix.item->iwin;
+	if(w->focus == tk) {
+if(0)print("tktxtforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk));
+		w->focus = nil;
+	}
+}
+
+static void
+tktwingeom(Tk *sub, int x, int y, int w, int h)
+{
+	TkTindex ix;
+	Tk *tk;
+	TkTwind *win;
+
+	USED(x);
+	USED(y);
+
+	tk = sub->parent;
+	if(!tktfindsubitem(sub, &ix)) {
+		print("tktwingeom: %s not found\n", sub->name->name);
+		return;
+	}
+
+	win = ix.item->iwin;
+
+	win->width = w;
+	win->height = h;
+
+	sub->req.width = w;
+	sub->req.height = h;
+	tktwindsize(tk, &ix);
+}
+
+static void
+tktdestroyed(Tk *sub)
+{
+	TkTindex ix;
+	Tk *tk;
+
+	if(tktfindsubitem(sub, &ix)) {
+		ix.item->iwin->sub = nil;
+		ix.item->iwin->focus = nil;
+		if((tk = sub->parent) != nil) {
+			tktfixgeom(tk, tktprevwrapline(tk, ix.line), ix.line, 0);
+			tktextsize(tk, 1);
+			sub->parent = nil;
+		}
+	}
+}
+
+void
+tktdirty(Tk *sub)
+{
+	Tk *tk, *parent, *isub;
+	TkText *tkt;
+	TkTindex ix;
+
+	parent = nil;
+	for(tk = sub; tk && parent == nil; tk = tk->master)
+		parent = tk->parent;
+	if(tk == nil)
+		return;
+
+	tkt = TKobj(TkText, parent);
+	tktstartind(tkt, &ix);
+	do {
+		if(ix.item->kind == TkTwin) {
+			isub = ix.item->iwin->sub;
+			if(isub != nil) {
+				tktfixgeom(parent, tktprevwrapline(parent, ix.line), ix.line, 0);
+				if (sub->flag & Tktransparent)
+					parent->flag |= Tkrefresh;	/* XXX could be more efficient, by drawing the background locally? */
+				return;
+			}
+		}
+	} while(tktadjustind(tkt, TkTbyitem, &ix));
+	tktextsize(parent, 1);
+}
+
+static char*
+tktwinchk(Tk *tk, TkTwind *w, Tk *oldsub)
+{
+	Tk *sub;
+
+	sub = w->sub;
+	if (sub != oldsub) {
+		w->sub = oldsub;
+		if(sub == nil)
+			return nil;
+
+		if(sub->flag & Tkwindow)
+			return TkIstop;
+	
+		if(sub->master != nil || sub->parent != nil)
+			return TkWpack;
+
+		if (oldsub != nil) {
+			oldsub->parent = nil;
+			oldsub->geom = nil;
+			oldsub->destroyed = nil;
+		}
+		w->sub = sub;
+		w->focus = nil;
+
+		sub->parent = tk;
+		tksetbits(sub, Tksubsub);
+		sub->geom = tktwingeom;
+		sub->destroyed = tktdestroyed;
+
+		w->width = sub->req.width;
+		w->height = sub->req.height;
+		w->owned = winowned(tk, sub);
+	}
+
+	return nil;
+}
+
+
+/* Text Window Command (+ means implemented)
+	+cget
+	+configure
+	+create
+	+names
+*/
+
+static char*
+tktwincget(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+	TkOptab tko[2];
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+	if(ix.item->kind != TkTwin)
+		return TkBadwp;
+
+	tko[0].ptr = ix.item->iwin;
+	tko[0].optab = twinopts;
+	tko[1].ptr = nil;
+
+	return tkgencget(tko, arg, val, tk->env->top);
+}
+
+static char*
+tktwinconfigure(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+	TkOptab tko[2];
+	Tk *oldsub;
+
+	USED(val);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+	if(ix.item->kind != TkTwin)
+		return TkBadwp;
+
+	oldsub = ix.item->iwin->sub;
+
+	tko[0].ptr = ix.item->iwin;
+	tko[0].optab = twinopts;
+	tko[1].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil)
+		return e;
+
+	e = tktwinchk(tk, ix.item->iwin, oldsub);
+	if(e != nil)
+		return e;
+
+	tktwindsize(tk, &ix);
+	return nil;
+}
+
+/*
+ * return true if tk is an ancestor of sub
+ */
+static int
+winowned(Tk *tk, Tk *sub)
+{
+	int len;
+	if (tk->name == nil || sub->name == nil)
+		return 0;
+	len = strlen(tk->name->name);
+	if (strncmp(tk->name->name, sub->name->name, len) == 0 &&
+			sub->name->name[len] == '.')
+		return 1;
+	return 0;
+}
+
+static char*
+tktwincreate(Tk *tk, char *arg, char **val)
+{
+	char *e;
+	TkTindex ix;
+	TkTitem *i;
+	TkText *tkt;
+	TkOptab tko[2];
+
+	USED(val);
+
+	tkt = TKobj(TkText, tk);
+
+	e = tktindparse(tk, &arg, &ix);
+	if(e != nil)
+		return e;
+
+	e = tktnewitem(TkTwin, 0, &i);
+	if(e != nil)
+		return e;
+
+	i->iwin = malloc(sizeof(TkTwind));
+	if(i->iwin == nil) {
+		tktfreeitems(tkt, i, 1);
+		return TkNomem;
+	}
+
+	memset(i->iwin, 0, sizeof(TkTwind));
+	i->iwin->align = Tkcenter;
+	i->iwin->ascent = -1;
+
+	tko[0].ptr = i->iwin;
+	tko[0].optab = twinopts;
+	tko[1].ptr = nil;
+
+	e = tkparse(tk->env->top, arg, tko, nil);
+	if(e != nil) {
+    err1:
+		tktfreeitems(tkt, i, 1);
+		return e;
+	}
+
+	e = tktwinchk(tk, i->iwin, nil);
+	if(e != nil)
+		goto err1;
+
+	e = tktsplititem(&ix);
+	if(e != nil)
+		goto err1;
+
+	tktiteminsert(tkt, &ix, i);
+	if(e != nil)
+		goto err1;
+
+	tktadjustind(tkt, TkTbyitemback, &ix);
+	tktwindsize(tk, &ix);
+
+	return nil;
+}
+
+static char*
+tktwinnames(Tk *tk, char *arg, char **val)
+{
+	char *e, *fmt;
+	TkTindex ix;
+	TkText *tkt = TKobj(TkText, tk);
+
+	USED(arg);
+
+	tktstartind(tkt, &ix);
+	fmt = "%s";
+	do {
+		if(ix.item->kind == TkTwin &&
+		   ix.item->iwin->sub != nil &&
+                     ix.item->iwin->sub->name != nil) {
+			e = tkvalue(val, fmt, ix.item->iwin->sub->name->name);
+			if(e != nil)
+				return e;
+			fmt = " %s";
+		}
+	} while(tktadjustind(tkt, TkTbyitem, &ix));
+	return nil;
+}
--- /dev/null
+++ b/libtk/utils.c
@@ -1,0 +1,2124 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+struct TkCol
+{
+	ulong	rgba1;
+	ulong	rgba3;	/* if mixed, otherwise DNotacolor */
+	Image*	i;
+	TkCol*	forw;
+};
+
+extern void	rptwakeup(void*, void*);
+extern void*	rptproc(char*, int, void*, int (*)(void*), int (*)(void*,int), void (*)(void*));
+
+typedef struct Cmd Cmd;
+struct Cmd
+{
+	char*	name;
+	char*	(*fn)(TkTop*, char*, char**);
+};
+static struct Cmd cmdmain[] =
+{
+	"bind",		tkbind,
+	"button",	tkbutton,
+	"canvas",	tkcanvas,
+	"checkbutton",	tkcheckbutton,
+	"choicebutton", tkchoicebutton,
+	"cursor",	tkcursorcmd,
+	"destroy",	tkdestroy,
+	"entry",	tkentry,
+	"focus",	tkfocus,
+	"frame",	tkframe,
+	"grab",		tkgrab,
+	"grid",	tkgrid,
+	"image",	tkimage,
+	"label",	tklabel,
+	"listbox",	tklistbox,
+	"lower",	tklower,
+	"menu",		tkmenu,
+	"menubutton",	tkmenubutton,
+	"pack",		tkpack,
+	"panel",		tkpanel,
+	"puts",		tkputs,
+	"radiobutton",	tkradiobutton,
+	"raise",	tkraise,
+	"scale",	tkscale,
+	"scrollbar",	tkscrollbar,
+	"see",	tkseecmd,
+	"send",		tksend,
+	"text",		tktext,
+	"update",	tkupdatecmd,
+	"variable",	tkvariable,
+	"winfo",	tkwinfo,
+};
+
+char*	tkfont;
+
+/*
+ * auto-repeating support
+ * should perhaps be one rptproc per TkCtxt
+ * This is not done for the moment as there isn't
+ * a mechanism for terminating the rptproc
+ */
+static void *autorpt;
+static int rptid;
+static Tk *rptw;
+static void *rptnote;
+static void (*rptcb)(Tk*, void*, int);
+static long rptto;
+static int rptint;
+
+/* blinking carets - should be per TkCtxt */
+static void *blinkrpt;
+static Tk *blinkw;
+static void (*blinkcb)(Tk*, int);
+static int blinkignore;
+static int blinkon;
+
+
+ulong
+tkrgba(int r, int g, int b, int a)
+{
+	ulong p;
+
+	if(r < 0)
+		r = 0;
+	else if(r > 255)
+		r = 255;
+	if(g < 0)
+		g = 0;
+	else if(g > 255)
+		g = 255;
+	if(b < 0)
+		b = 0;
+	else if(b > 255)
+		b = 255;
+	p = (r<<24)|(g<<16)|(b<<8)|0xFF;
+	if(a == 255)
+		return p;
+	return setalpha(p, a);
+}
+
+/* to be replaced */
+static int
+revalpha(int c, int a)
+{
+	if (a == 0)
+		return 0;
+	return (c & 0xff) * 255 / a;
+}
+
+void
+tkrgbavals(ulong rgba, int *R, int *G, int *B, int *A)
+{
+	int a;
+
+	a = rgba & 0xff;
+	*A = a;
+	if (a != 0xff) {
+		*R = revalpha(rgba>>24, a);
+		*G = revalpha((rgba>>16) & 0xFF, a);
+		*B = revalpha((rgba >> 8) & 0xFF, a);
+	} else {
+		*R = (rgba>>24);
+		*G = ((rgba>>16) & 0xFF);
+		*B = ((rgba >> 8) & 0xFF);
+	}
+}
+
+static int
+tkcachecol(TkCtxt *c, Image *i, ulong one, ulong three)
+{
+	TkCol *cc;
+
+	cc = malloc(sizeof(*cc));
+	if(cc == nil)
+		return 0;
+	cc->rgba1 = one;
+	cc->rgba3 = three;
+	cc->i = i;
+	cc->forw = c->chead;
+	c->chead = cc;
+	c->ncol++;
+	/* we'll do LRU management at some point */
+	if(c->ncol > TkColcachesize){
+		static int warn;
+		if(warn == 0){
+			warn = 1;
+			print("tk: %d colours cached\n", TkColcachesize);
+		}
+	}
+	return 1;
+}
+
+static Image*
+tkfindcol(TkCtxt *c, ulong one, ulong three)
+{
+	TkCol *cc, **l;
+
+	for(l = &c->chead; (cc = *l) != nil; l = &cc->forw)
+		if(cc->rgba1 == one && cc->rgba3 == three){
+			/* move it up in the list */
+			*l = cc->forw;
+			cc->forw = c->chead;
+			c->chead = cc;
+			/* we assume it will be used right away and not stored */
+			return cc->i;
+		}
+	return nil;
+}
+
+void
+tkfreecolcache(TkCtxt *c)
+{
+	TkCol *cc;
+
+	if(c == nil)
+		return;
+	while((cc = c->chead) != nil){
+		c->chead = cc->forw;
+		freeimage(cc->i);
+		free(cc);
+	}
+	c->ctail = nil;
+	c->ncol = 0;
+}
+
+Image*
+tkcolormix(TkCtxt *c, ulong one, ulong three)
+{
+	Image *i;
+	Display *d;
+
+	i = tkfindcol(c, one, three);
+	if(i != nil)
+		return i;
+	d = c->display;
+	i = allocimagemix(d, one, three);
+	if(i == nil)
+		return d->black;
+	if(!tkcachecol(c, i, one, three)){
+		freeimage(i);
+		return d->black;
+	}
+	return i;
+}
+
+Image*
+tkcolor(TkCtxt *c, ulong pix)
+{
+	Image *i;
+	Display *d;
+	Rectangle r;
+
+	d = c->display;
+	if(pix == DWhite)
+		return d->white;
+	if(pix == DBlack)
+		return d->black;
+	i = tkfindcol(c, pix, DNotacolor);
+	if(i != nil)
+		return i;
+	r.min = ZP;
+	r.max.x = 1;
+	r.max.y = 1;
+	if ((pix & 0xff) == 0xff)
+		i = allocimage(d, r, RGB24, 1, pix);
+	else
+		i = allocimage(d, r, RGBA32, 1, pix);
+	if(i == nil)
+		return d->black;
+	if(!tkcachecol(c, i, pix, DNotacolor)) {
+		freeimage(i);
+		return d->black;
+	}
+	return i;
+}
+
+Image*
+tkgradient(TkCtxt *c, Rectangle r, int dir, ulong pix0, ulong pix1)
+{
+	Display *d;
+	Image *i;
+	uchar *b, *p, *e;
+	int c0[3], c1[3], delta[3], a, j, x, y, n, locked;
+	Rectangle s;
+
+	d = c->display;
+	y = Dy(r);
+	x = Dx(r);
+	if(x <= 0 || y <= 0) {
+		r = Rect(0, 0, 1, 1);
+		x = y = 1;
+	}
+	/* TO DO: diagonal */
+	s = r;
+	if(dir == Tkhorizontal){
+		n = x;
+		r.max.y = r.min.y+1;
+	}else{
+		n = y;
+		r.max.x = r.min.x+1;
+	}
+	b = mallocz(3*n, 0);
+	if(b == nil)
+		return nil;
+	locked = lockdisplay(d);
+	i = allocimage(d, r, RGB24, 1, DNofill);
+	if(i == nil)
+		goto Ret;
+	tkrgbavals(pix0, &c0[2], &c0[1], &c0[0], &a);
+	tkrgbavals(pix1, &c1[2], &c1[1], &c1[0], &a);
+	for(j = 0; j < 3; j++){
+		c0[j] <<= 12;
+		c1[j] <<= 12;
+		delta[j] = ((c1[j]-c0[j])+(1<<11))/n;
+	}
+	e = b+3*n;
+	for(p = b; p < e; p += 3) {
+		p[0] = c0[0]>>12;
+		p[1] = c0[1]>>12;
+		p[2] = c0[2]>>12;
+		c0[0] += delta[0];
+		c0[1] += delta[1];
+		c0[2] += delta[2];
+	}
+	loadimage(i, r, b, 3*n);
+	replclipr(i, 1, s);
+Ret:
+	if(locked)
+		unlockdisplay(d);
+	free(b);
+	return i;
+}
+
+/*
+ * XXX should be in libdraw?
+ */
+int
+tkchanhastype(ulong c, int t)
+{
+	for(; c; c>>=8)
+		if(TYPE(c) == t)
+			return 1;
+	return 0;
+}
+
+void
+tksettransparent(Tk *tk, int transparent)
+{
+	if (transparent)
+		tk->flag |= Tktransparent;
+	else
+		tk->flag &= ~Tktransparent;
+}
+
+int
+tkhasalpha(TkEnv *e, int col)
+{
+	return (e->colors[col] & 0xff) != 0xff;
+}
+
+Image*
+tkgc(TkEnv *e, int col)
+{
+	return tkcolor(e->top->ctxt, e->colors[col]);
+}
+
+
+/*
+ * Todo: improve the fixed-point code
+ * the 255 scale factor is used because RGB ranges 0-255
+ */
+static void
+rgb2hsv(int r, int g, int b, int *h, int *s, int *v)
+{
+	int min, max, delta;
+
+	max = r;
+	if(g > max)
+		max = g;
+	if(b > max)
+		max = b;
+	min = r;
+	if(g < min)
+		min = g;
+	if(b < min)
+		min = b;
+	*v = max;
+	if (max != 0)
+		*s = ((max - min)*255) / max;
+	else
+		*s = 0;
+
+	if (*s == 0) {
+		*h = 0;	/* undefined */
+	} else {
+		delta = max - min;
+		if (r == max) 
+			*h = (g - b)*255 / delta;
+		else if (g == max)
+			*h = (2*255) + ((b - r)*255) / delta;
+		else if (b == max)
+			*h = (4*255) + ((r - g)*255)/ delta;
+		*h *= 60;
+		if (*h < 0)
+			*h += 360*255;
+		*h /= 255;
+	}
+}
+
+static void
+hsv2rgb(int h, int s, int v, int *r, int *g, int *b)
+{
+	int	i;
+	int	f,p,q,t;
+
+	if (s == 0 && h == 0) {
+		*r = *g = *b = v;	/* achromatic case */
+	} else {
+		if (h >= 360)
+			h = 0;
+		i = h / 60;
+		h *= 255;
+		h /= 60;
+
+		f = h % 255;
+		p = v * (255 - s);
+		q = v * (255 - ((s * f)/255));
+		t = v * (255- ((s * (255 - f))/255));
+		p /= 255;
+		q /= 255;
+		t /= 255;
+		switch (i) {
+		case 0: *r = v; *g = t; *b = p; break;
+		case 1: *r = q; *g = v; *b = p; break;
+		case 2: *r = p; *g = v; *b = t; break;
+		case 3: *r = p; *g = q; *b = v; break;
+		case 4: *r = t; *g = p; *b = v; break;
+		case 5: *r = v; *g = p; *b = q; break;
+		}
+	}
+}
+
+enum {
+	MINDELTA	= 0x10,
+	DELTA	= 0x30,
+};
+
+ulong
+tkrgbashade(ulong rgba, int shade)
+{
+	int R, G, B, A, h, s, v, vl, vd;
+
+	if (shade == TkSameshade)
+		return rgba;
+
+	tkrgbavals(rgba, &R, &G, &B, &A);
+	h = s = v = 0;
+	rgb2hsv(R, G, B, &h, &s, &v);
+
+	if (v < MINDELTA) {
+		vd = v+DELTA;
+		vl = vd+DELTA;
+	} else if (v > 255-MINDELTA) {
+		vl = v-DELTA;
+		vd = vl-DELTA;
+	} else {
+		vl = v+DELTA;
+		vd = v-DELTA;
+	}
+
+	v = (shade == TkLightshade)?vl:vd;
+	if (v < 0)
+		v = 0;
+	if (v > 255)
+		v = 255;
+	hsv2rgb(h, s, v, &R, &G, &B);
+
+	return tkrgba(R, G, B, A);
+}
+
+Image*
+tkgshade(TkEnv *e, int col, int shade)
+{
+	ulong rgba;
+
+	if (col == TkCbackgnd || col == TkCselectbgnd || col == TkCactivebgnd)
+		return tkgc(e, col+shade);
+	rgba = tkrgbashade(e->colors[col], shade);
+	return tkcolor(e->top->ctxt, rgba);
+}
+
+TkEnv*
+tknewenv(TkTop *t)
+{
+	TkEnv *e;
+
+	e = malloc(sizeof(TkEnv));
+	if(e == nil)
+		return nil;
+
+	e->ref = 1;
+	e->top = t;
+	return e;
+}
+
+TkEnv*
+tkdefaultenv(TkTop *t)
+{
+	int locked;
+	TkEnv *env;
+	Display *d;
+
+	if(t->env != nil) {
+		t->env->ref++;
+		return t->env;
+	}
+	t->env = malloc(sizeof(TkEnv));
+	if(t->env == nil)
+		return nil;
+
+	env = t->env;
+	env->ref = 1;
+	env->top = t;
+
+	if(tkfont == nil)
+		tkfont = "/fonts/pelm/unicode.8.font";
+
+	d = t->display;
+	env->font = font_open(d, tkfont);
+	if(env->font == nil) {
+		static int warn;
+		if(warn == 0) {
+			warn = 1;
+			print("tk: font not found: %s\n", tkfont);
+		}
+		env->font = font_open(d, "*default*");
+		if(env->font == nil) {
+			free(t->env);
+			t->env = nil;
+			return nil;
+		}
+	}
+
+	locked = lockdisplay(d);
+	env->wzero = stringwidth(env->font, "0");
+	if ( env->wzero <= 0 )
+		env->wzero = env->font->height / 2;
+	if(locked)
+		unlockdisplay(d);
+
+	tksetenvcolours(env);
+	return env;
+}
+
+void
+tkputenv(TkEnv *env)
+{
+	Display *d;
+	int locked;
+
+	if(env == nil)
+		return;
+
+	env->ref--;
+	if(env->ref != 0)
+		return;
+
+	d = env->top->display;
+	locked = lockdisplay(d);
+
+	if(env->font != nil)
+		font_close(env->font);
+
+	if(locked)
+		unlockdisplay(d);
+
+	free(env);
+}
+
+TkEnv*
+tkdupenv(TkEnv **env)
+{
+	Display *d;
+	TkEnv *e, *ne;
+
+	e = *env;
+	if(e->ref == 1)
+		return e;
+
+	ne = malloc(sizeof(TkEnv));
+	if(ne == nil)
+		return nil;
+
+	ne->ref = 1;
+	ne->top = e->top;
+
+	d = e->top->display;
+	memmove(ne->colors, e->colors, sizeof(e->colors));
+	ne->set = e->set;
+	ne->font = font_open(d, e->font->name);
+	ne->wzero = e->wzero;
+
+	e->ref--;
+	*env = ne;
+	return ne;
+}
+
+Tk*
+tknewobj(TkTop *t, int type, int n)
+{
+	Tk *tk;
+
+	tk = malloc(n);
+	if(tk == 0)
+		return 0;
+
+	tk->type = type;		/* Defaults */
+	tk->flag = Tktop;
+	tk->relief = TKflat;
+	tk->env = tkdefaultenv(t);
+	if(tk->env == nil) {
+		free(tk);
+		return nil;
+	}
+
+	return tk;
+}
+
+void
+tkfreebind(TkAction *a)
+{
+	TkAction *next;
+
+	while(a != nil) {
+		next = a->link;
+		if((a->type & 0xff) == TkDynamic)
+			free(a->arg);
+		free(a);
+		a = next;
+	}
+}
+
+void
+tkfreename(TkName *f)
+{
+	TkName *n;
+
+	while(f != nil) {
+		n = f->link;
+		free(f);
+		f = n;
+	}
+}
+
+void
+tkfreeobj(Tk *tk)
+{
+	TkCtxt *c;
+
+	c = tk->env->top->ctxt;
+	if(c != nil) {
+		if(c->tkkeygrab == tk)
+			c->tkkeygrab = nil;
+		if(c->mgrab == tk)
+			tksetmgrab(tk->env->top, nil);
+		if(c->mfocus == tk)
+			c->mfocus = nil;
+		if(c->entered == tk)
+			c->entered = nil;
+	}
+
+	if (tk == rptw) {
+		/* cancel the autorepeat without notifying the widget */
+		rptid++;
+		rptw = nil;
+	}
+	if (tk == blinkw)
+		blinkw = nil;
+	tkextnfreeobj(tk);
+	tkmethod[tk->type]->free(tk);
+	tkputenv(tk->env);
+	tkfreebind(tk->binds);
+	if(tk->name != nil)
+		free(tk->name);
+	free(tk);
+}
+
+char*
+tkaddchild(TkTop *t, Tk *tk, TkName **names)
+{
+	TkName *n;
+	Tk *f, **l;
+	int found, len;
+	char *s, *ep;
+
+	n = *names;
+	if(n == nil || n->name[0] != '.'){
+		if(n != nil)
+			tkerr(t, n->name);
+		return TkBadwp;
+	}
+
+	if (n->name[1] == '\0')
+		return TkDupli;
+
+	/*
+	 * check that the name is well-formed.
+	 * ep will point to end of parent component of the name.
+	 */
+	ep = nil;
+	for (s = n->name + 1; *s; s++) {
+		if (*s == '.'){
+			tkerr(t, n->name);
+			return TkBadwp;
+		}
+		for (; *s && *s != '.'; s++)
+			;
+		if (*s == '\0')
+			break;
+		ep = s;
+	}
+	if (ep == s - 1){
+		tkerr(t, n->name);
+		return TkBadwp;
+	}
+	if (ep == nil)
+		ep = n->name + 1;
+	len = ep - n->name;
+
+	found = 0;
+	l = &t->root;
+	for(f = *l; f; f = f->siblings) {
+		if (f->name != nil) {
+			if (strcmp(n->name, f->name->name) == 0)
+				return TkDupli;
+			if (!found &&
+					strncmp(n->name, f->name->name, len) == 0 &&
+					f->name->name[len] == '\0')
+				found = 1;
+		}
+		l = &f->siblings;
+	}
+	if (0) {		/* don't enable this until a reasonably major release... if ever */
+		/*
+		 * parent widget must already exist
+		 */
+		if (!found){
+			tkerr(t, n->name);
+			return TkBadwp;
+		}
+	}
+	*l = tk;
+	tk->name = n;
+	*names = n->link;
+
+	return nil;
+}
+
+Tk*
+tklook(TkTop *t, char *wp, int parent)
+{
+	Tk *f;
+	char *p, *q;
+
+	if(wp == nil)
+		return nil;
+
+	if(parent) {
+		p = strdup(wp);
+		if(p == nil)
+			return nil;
+		q = strrchr(p, '.');
+		if(q == nil)
+			abort();
+		if(q == p) {
+			free(p);
+			return t->root;
+		}
+		*q = '\0';	
+	} else
+		p = wp;
+
+	for(f = t->root; f; f = f->siblings)
+		if ((f->name != nil) && (strcmp(f->name->name, p) == 0))
+			break;
+
+	if(f != nil && (f->flag & Tkdestroy))
+		f = nil;
+
+	if (parent)
+		free(p);
+	return f;
+}
+
+void
+tktextsdraw(Image *img, Rectangle r, TkEnv *e, int sbw)
+{
+	Image *l, *d;
+	Rectangle s;
+
+	draw(img, r, tkgc(e, TkCselectbgnd), nil, ZP);
+	s.min = r.min;
+	s.min.x -= sbw;
+	s.min.y -= sbw;
+	s.max.x = r.max.x;
+	s.max.y = r.min.y;
+	l = tkgc(e, TkCselectbgndlght);
+	draw(img, s, l, nil, ZP);
+	s.max.x = s.min.x + sbw;
+	s.max.y = r.max.y + sbw;
+	draw(img, s, l, nil, ZP);
+	s.max = r.max;
+	s.max.x += sbw;
+	s.max.y += sbw;
+	s.min.x = r.min.x;
+	s.min.y = r.max.y;
+	d = tkgc(e, TkCselectbgnddark);
+	draw(img, s, d, nil, ZP);
+	s.min.x = r.max.x;
+	s.min.y = r.min.y - sbw;
+	draw(img, s, d, nil, ZP);
+}
+
+void
+tkbox(Image *i, Rectangle r, int bd, Image *fill)
+{
+	if (bd > 0) {
+		draw(i, Rect(r.min.x, r.min.y, r.max.x, r.min.y+bd), fill, nil, ZP);
+		draw(i, Rect(r.min.x, r.min.y+bd, r.min.x+bd, r.max.y-bd), fill, nil, ZP);
+		draw(i, Rect(r.min.x, r.max.y-bd, r.max.x, r.max.y), fill, nil, ZP);
+		draw(i, Rect(r.max.x-bd, r.min.y+bd, r.max.x, r.max.y), fill, nil, ZP);
+	}
+}
+
+void
+tkbevel(Image *i, Point o, int w, int h, int bw, Image *top, Image *bottom)
+{
+	Rectangle r;
+	int x, border;
+
+	border = 2 * bw;
+
+	r.min = o;
+	r.max.x = r.min.x + w + border;
+	r.max.y = r.min.y + bw;
+	draw(i, r, top, nil, ZP);
+
+	r.max.x = r.min.x + bw;
+	r.max.y = r.min.y + h + border;
+	draw(i, r, top, nil, ZP);
+
+	r.max.x = o.x + w + border;
+	r.max.y = o.y + h + border;
+	r.min.x = o.x + bw;
+	r.min.y = r.max.y - bw;
+	for(x = 0; x < bw; x++) {
+		draw(i, r, bottom, nil, ZP);
+		r.min.x--;
+		r.min.y++;
+	}
+	r.min.x = o.x + bw + w;
+	r.min.y = o.y + bw;
+	for(x = bw; x >= 0; x--) {
+		draw(i, r, bottom, nil, ZP);
+		r.min.x++;
+		r.min.y--;
+	}
+}
+
+/*
+ * draw a relief border.
+ * color is an index into tk->env->colors and assumes
+ * light and dark versions following immediately after
+ * that index
+ */
+void
+tkdrawrelief(Image *i, Tk *tk, Point o, int color, int rlf)
+{
+	TkEnv *e;
+	Image *l, *d, *t;
+	int h, w, bd, bd1, bd2;
+
+	if(tk->borderwidth == 0)
+		return;
+
+	h = tk->act.height;
+	w = tk->act.width;
+
+	e = tk->env;
+	if (color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
+		l = tkgc(e, color+TkLightshade);
+		d = tkgc(e, color+TkDarkshade);
+	} else {
+		l = tkgshade(e, color, TkLightshade);
+		d = tkgshade(e, color, TkDarkshade);
+	}
+	bd = tk->borderwidth;
+	if(rlf < 0)
+		rlf = TKraised;
+	switch(rlf) {
+	case TKflat:
+		break;
+	case TKsunken:
+		tkbevel(i, o, w, h, bd, d, l);
+		break;	
+	case TKraised:
+		tkbevel(i, o, w, h, bd, l, d);
+		break;	
+	case TKgroove:
+		t = d;
+		d = l;
+		l = t;
+		/* fall through */
+	case TKridge:
+		bd1 = bd/2;
+		bd2 = bd - bd1;
+		if(bd1 > 0)
+			tkbevel(i, o, w + 2*bd2, h + 2*bd2, bd1, l, d);
+		o.x += bd1;
+		o.y += bd1;
+		tkbevel(i, o, w, h, bd2, d, l);
+		break;
+	}
+}
+
+Point
+tkstringsize(Tk *tk, char *text)
+{
+	char *q;
+	int locked;
+	Display *d;
+	Point p, t;
+
+	if(text == nil) {
+		p.x = 0;
+		p.y = tk->env->font->height;
+		return p;
+	}
+
+	d = tk->env->top->display;
+	locked = lockdisplay(d);
+
+	p = ZP;
+	while(*text) {
+		q = strchr(text, '\n');
+		if(q != nil)
+			*q = '\0';
+		t = stringsize(tk->env->font, text);
+		p.y += t.y;
+		if(p.x < t.x)
+			p.x = t.x;
+		if(q == nil)
+			break;
+		text = q+1;
+		*q = '\n';
+	}
+	if(locked)
+		unlockdisplay(d);
+
+	return p;	
+}
+
+static void
+tkulall(Image *i, Point o, Image *col, Font *f, char *text)
+{
+	Rectangle r;
+
+	r.max = stringsize(f, text);
+	r.max = addpt(r.max, o);
+	r.min.x = o.x;
+	r.min.y = r.max.y - 1;
+	draw(i, r, col, nil, ZP);	
+}
+
+static void
+tkul(Image *i, Point o, Image *col, int ul, Font *f, char *text)
+{
+	char c, *v;
+	Rectangle r;
+
+	v = text+ul+1;
+	c = *v;
+	*v = '\0';
+	r.max = stringsize(f, text);
+	r.max = addpt(r.max, o);
+	r.min = stringsize(f, v-1);
+	*v = c;
+	r.min.x = r.max.x - r.min.x;
+	r.min.y = r.max.y - 1;
+	r.max.y++;
+	draw(i, r, col, nil, ZP);	
+}
+
+void
+tkdrawstring(Tk *tk, Image *i, Point o, char *text, int ul, Image *col, int j)
+{
+	int n, l, maxl, sox;
+	char *q, *txt;
+	Point p;
+	TkEnv *e;
+
+	e = tk->env;
+	sox = maxl = 0;
+	if(j != Tkleft){
+		maxl = 0;
+		txt = text;
+		while(*txt){
+			q = strchr(txt, '\n');
+			if(q != nil)
+				*q = '\0';
+			l = stringwidth(e->font, txt);
+			if(l > maxl)
+				maxl = l;
+			if(q == nil)
+				break;
+			txt = q+1;
+			*q = '\n';
+		}
+		sox = o.x;
+	}
+	while(*text) {
+		q = strchr(text, '\n');
+		if(q != nil)
+			*q = '\0';
+		if(j != Tkleft){
+			o.x = sox;
+			l = stringwidth(e->font, text);
+			if(j == Tkcenter)
+				o.x += (maxl-l)/2;
+			else
+				o.x += maxl-l;
+		}
+		p = string(i, o, col, o, e->font, text);
+		if(ul >= 0) {
+			n = strlen(text);
+			if(ul < n) {
+				tkul(i, o, col, ul, e->font, text);
+				ul = -1;
+			} else if(ul == n) {
+				tkulall(i, o, col, e->font, text);
+				ul = -1;
+			} else
+				ul -= n;
+		}
+		o.y += e->font->height;
+		if(q == nil)
+			break;
+		text = q+1;
+		*q = '\n';
+	}
+}
+
+/* for debugging */
+char*
+tkname(Tk *tk)
+{
+	if(tk == nil)
+		return "(nil)";
+	if(tk->name == nil)
+		return "(noname)";
+	return tk->name->name;
+}
+
+Tk*
+tkdeliver(Tk *tk, int event, void *data)
+{
+	Tk *dest;
+
+	if(tk != nil && ((ulong)tk->type >= TKwidgets || (ulong)tk->name < 4096 && tk->name != nil)){
+		print("invalid Tk: type %d name %p\n", tk->type, tk->name);
+		abort();
+	}
+//print("tkdeliver %v to %s\n", event, tkname(tk));
+	if(tk == nil || ((tk->flag&Tkdestroy) && event != TkDestroy))
+		return tk;
+	if(event&(TkFocusin|TkFocusout) && (tk->flag&Tktakefocus))
+		tk->dirty = tkrect(tk, 1);
+
+	if (tkmethod[tk->type]->deliver != nil) {
+		dest = tkmethod[tk->type]->deliver(tk, event, data);
+		if (dest == nil)
+			return tk;
+		tkdirty(tk);
+		return dest;
+	}
+
+	if((tk->flag & Tkdisabled) == 0)
+		tksubdeliver(tk, tk->binds, event, data, 0);
+	tkdirty(tk);
+	return tk;
+}
+
+static int
+nullop(char *fmt, ...)
+{
+	USED(fmt);
+	return 0;
+}
+
+int
+tksubdeliver(Tk *tk, TkAction *binds, int event, void *data, int extn)
+{
+
+	TkAction *a;
+	int delivered, genkey, delivered2, iskey;
+//int (*debug)(char *fmt, ...);
+
+	if (!extn)
+		return tkextndeliver(tk, binds, event, data);
+
+//debug = (tk->name && !strcmp(tk->name->name, ".cd")) ? print : nullop;
+//debug("subdeliver %v\n", event);
+
+	if (event & TkTakefocus) {
+		if (tk->flag & Tktakefocus)
+			tksetkeyfocus(tk->env->top, tk, 0);
+		return TkDdelivered;
+	}
+
+	delivered = TkDnone;
+	genkey = 0;
+	for(a = binds; a != nil; a = a->link) {
+		if(event == a->event) {
+//debug("  exact match on %v\n", a->event);
+			tkcmdbind(tk, event, a->arg, data);
+			delivered = TkDdelivered;
+		} else if (a->event == TkKey && (a->type>>8)==TkAadd)
+			genkey = 1;
+	}
+	if(delivered != TkDnone && !((event & TkKey) && genkey))
+		return delivered;
+
+	delivered2 = delivered;
+	for(a = binds; a != nil; a = a->link) {
+		/*
+		 * only bind to non-specific key events; if a specific
+		 * key event has already been delivered, only deliver event if
+		 * the non-specific binding was added. (TkAadd)
+		 */
+		if (a->event & TkExtns)
+			continue;
+		iskey = (a->event & TkKey);
+		if (iskey ^ (event & TkKey))
+			continue;
+		if(iskey && (TKKEY(a->event) != 0
+					|| ((a->type>>8) != TkAadd && delivered != TkDnone)))
+			continue;
+		if(!iskey && (a->event & TkMotion) && (a->event&TkEpress) != 0)
+			continue;
+		if(!(event & TkDouble) && (a->event & TkDouble))
+			continue;
+		if((event & ~TkDouble) & a->event) {
+//debug("  partial match on %v\n", a->event);
+			tkcmdbind(tk, event, a->arg, data);
+			delivered2 = TkDdelivered;
+		}
+	}
+	return delivered2;
+}
+
+void
+tkcancel(TkAction **l, int event)
+{
+	TkAction *a;
+
+	for(a = *l; a; a = *l) {
+		if(a->event == event) {
+			*l = a->link;
+			a->link = nil;
+			tkfreebind(a);
+			continue;
+		}
+		l = &a->link;
+	}
+}
+
+static void
+tkcancela(TkAction **l, int event, int type, char *arg)
+{
+	TkAction *a;
+
+	for(a = *l; a; a = *l) {
+		if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
+			*l = a->link;
+			a->link = nil;
+			tkfreebind(a);
+			continue;
+		}
+		l = &a->link;
+	}
+}
+
+char*
+tkaction(TkAction **l, int event, int type, char *arg, int how)
+{
+	TkAction *a;
+
+	if(arg == nil)
+		return nil;
+	if(how == TkArepl)
+		tkcancel(l, event);
+	else if(how == TkAadd){
+		for(a = *l; a; a = a->link)
+			if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
+				a->type = type + (how << 8);
+				return nil;
+			}
+	}
+	else if(how == TkAsub){
+		tkcancela(l, event, type, arg);
+		if(type == TkDynamic)	/* should always be the case */
+			free(arg);
+		return nil;
+	}
+
+	a = malloc(sizeof(TkAction));
+	if(a == nil) {
+		if(type == TkDynamic)
+			free(arg);
+		return TkNomem;
+	}
+
+	a->event = event;
+	a->arg = arg;
+	a->type = type + (how << 8);
+
+	a->link = *l;
+	*l = a;
+
+	return nil;
+}
+
+char*
+tkitem(char *buf, char *a)
+{
+	char *e;
+
+	while(*a && (*a == ' ' || *a == '\t'))
+		a++;
+
+	e = buf + Tkmaxitem - 1;
+	while(*a && *a != ' ' && *a != '\t' && buf < e)
+		*buf++ = *a++;
+
+	*buf = '\0';
+	while(*a && (*a == ' ' || *a == '\t'))
+		a++;
+	return a;
+}
+
+/*
+ * if tk is a subwindow or a descendent, return the subwindow;
+ * return nil otherwise
+ */
+Tk*
+tkfindsub(Tk *tk)
+{
+	for(; tk != nil; tk = tk->master){
+		if(tk->parent != nil)
+			return tk;	/* tk->parent is canvas or text */
+	}
+	return nil;
+}
+
+/*
+ * Return absolute screen position of tk (just outside its top-left border).
+ * When a widget is embedded in a text or canvas widget, we need to
+ * use the text or canvas's relpos() function instead of act{x,y}, and we
+ * need to folow up the parent pointer rather than the master one.
+ */
+Point
+tkposn(Tk *tk)
+{
+	Tk *f, *last;
+	Point g;
+
+	last = tk;
+	if(tk->parent != nil) {
+		g = tkmethod[tk->parent->type]->relpos(tk);
+		f = tk->parent;
+	} else {
+		g.x = tk->act.x;
+		g.y = tk->act.y;
+		f = tk->master;
+	}
+	while(f != nil) {
+		g.x += f->borderwidth;
+		g.y += f->borderwidth;
+		last = f;
+		if(f->parent != nil) {
+			g = addpt(g, tkmethod[f->parent->type]->relpos(f));
+			f = f->parent;
+		} else {
+			g.x += f->act.x;
+			g.y += f->act.y;
+			f = f->master;
+		}
+	}
+	if (last->flag & Tkwindow)
+		g = addpt(g, TKobj(TkWin, last)->req);
+	return g;
+}
+
+/*
+ * convert screen coords to local widget coords
+ */
+Point
+tkscrn2local(Tk *tk, Point p)
+{
+	p = subpt(p, tkposn(tk));
+	p.x -= tk->borderwidth;
+	p.y -= tk->borderwidth;
+	return p;
+}
+
+int
+tkvisiblerect(Tk *tk, Rectangle *rr)
+{
+	Rectangle r;
+	Point g;
+	Tk *f, *last;
+	g = Pt(tk->borderwidth, tk->borderwidth);
+	last = tk;
+	if(tk->parent != nil) {
+		g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
+		f = tk->parent;
+	} else {
+		g.x += tk->act.x;
+		g.y += tk->act.y;
+		f = tk->master;
+	}
+	if (f == nil) {
+		*rr = tkrect(tk, 1);
+		return 1;
+	}
+	r = rectaddpt(tkrect(tk, 1), g);
+	while (f) {
+		if (!rectclip(&r, tkrect(f, 0)))
+			return 0;
+		g.x = f->borderwidth;
+		g.y = f->borderwidth;
+		last = f;
+		if (f->parent != nil) {
+			g = addpt(g, tkmethod[f->parent->type]->relpos(f));
+			f = f->parent;
+		} else {
+			g.x += f->act.x;
+			g.y += f->act.y;
+			f = f->master;
+		}
+		r = rectaddpt(r, g);
+	}
+	if (last->flag & Tkwindow)
+		r = rectaddpt(r, TKobj(TkWin, last)->act);
+	/*
+	 * now we have the visible rectangle in screen coords;
+	 * subtract actx+borderwidth and we've got it back in
+	 * widget-local coords again
+	 */
+	r = rectsubpt(r, tkposn(tk));
+	*rr = rectsubpt(r, Pt(tk->borderwidth, tk->borderwidth));
+	return 1;
+}
+
+Point
+tkanchorpoint(Rectangle r, Point size, int anchor)
+{
+	int dx, dy;
+	Point p;
+
+	p = r.min;
+	dx = Dx(r) - size.x;
+	dy = Dy(r) - size.y;
+	if((anchor & (Tknorth|Tksouth)) == 0)
+		p.y += dy/2;
+	else if(anchor & Tksouth)
+		p.y += dy;
+
+	if((anchor & (Tkeast|Tkwest)) == 0)
+		p.x += dx/2;
+	else if(anchor & Tkeast)
+		p.x += dx;
+	return p;
+}
+	
+static char*
+tkunits(char c, int *d, TkEnv *e)
+{
+	switch(c) {
+	default:
+		if(c >= '0' || c <= '9' || c == '.')
+			break;
+		return TkBadvl;
+	case '\0':
+		break;
+	case 'c':		/* Centimeters */
+		*d *= (Tkdpi*100)/254;
+		break;
+	case 'm':		/* Millimeters */
+		*d *= (Tkdpi*10)/254;
+		break;
+	case 'i':		/* Inches */
+		*d *= Tkdpi;
+		break;
+	case 'p':		/* Points */
+		*d = (*d*Tkdpi)/72;
+		break;
+	case 'w':		/* Character width */
+		if(e == nil)
+			return TkBadvl;
+		*d = *d * e->wzero;
+		break;
+	case 'h':		/* Character height */
+		if(e == nil)
+			return TkBadvl;
+		*d = *d * e->font->height;
+		break;
+	}
+	return nil;
+}
+
+int
+TKF2I(int f)
+{
+	if (f >= 0)
+		return (f + Tkfpscalar/2) / Tkfpscalar;
+	return (f - Tkfpscalar/2) / Tkfpscalar;
+}
+
+/*
+ * Parse a floating point number into a decimal fixed point representation
+ */
+char*
+tkfrac(char **arg, int *f, TkEnv *env)
+{
+	int c, minus, i, fscale, seendigit;
+	char *p, *e;
+
+	seendigit = 0;
+
+	p = *arg;
+	p = tkskip(p, " \t");
+
+	minus = 0;
+	if(*p == '-') {
+		minus = 1;
+		p++;
+	}
+	i = 0;
+	while(*p) {
+		c = *p;
+		if(c == '.')
+			break;
+		if(c < '0' || c > '9')
+			break;
+		i = i*10 + (c - '0');
+		seendigit = 1;
+		p++;
+	}
+	i *= Tkfpscalar;
+	if(*p == '.')
+		p++;
+	fscale = Tkfpscalar;
+	while(*p && *p >= '0' && *p <= '9') {
+		fscale /= 10;
+		i += fscale * (*p++ - '0');
+		seendigit = 1;
+	}
+
+	if(minus)
+		i = -i;
+
+	if(!seendigit)
+		return TkBadvl;
+	e = tkunits(*p, &i, env);
+	if (e != nil)
+		return e;
+	while (*p && *p != ' ' && *p != '\t')
+		p++;
+	*arg = p;
+	*f = i;
+	return nil;
+}
+
+char*
+tkfracword(TkTop *t, char **arg, int *f, TkEnv *env)
+{
+	char *p;
+	char buf[Tkminitem];
+
+	*arg = tkword(t, *arg, buf, buf+sizeof(buf), nil);
+	p = buf;
+	return tkfrac(&p, f, env);
+}
+
+char*
+tkfprint(char *v, int frac)
+{
+	int fscale;
+
+	if(frac < 0) {
+		*v++ = '-';
+		frac = -frac;
+	}
+	v += sprint(v, "%d", frac/Tkfpscalar);
+	frac = frac%Tkfpscalar;
+	if(frac != 0)
+		*v++ = '.';
+	fscale = Tkfpscalar/10;
+	while(frac) {
+		*v++ = '0' + frac/fscale;
+		frac %= fscale;
+		fscale /= 10;
+	}
+	*v = '\0';
+	return v;	
+}
+
+char*
+tkvalue(char **val, char *fmt, ...)
+{
+	va_list arg;
+	Fmt fmtx;
+
+	if(val == nil)
+		return nil;
+
+	fmtstrinit(&fmtx);
+	if(*val != nil)
+		if(fmtprint(&fmtx, "%s", *val) < 0)
+			return TkNomem;
+	va_start(arg, fmt);
+	fmtvprint(&fmtx, fmt, arg);
+	va_end(arg);
+	free(*val);
+	*val = fmtstrflush(&fmtx);
+	if(*val == nil)
+		return TkNomem;
+	return nil;
+}
+
+static char*
+tkwidgetcmd(TkTop *t, Tk *tk, char *arg, char **val)
+{
+	TkMethod *cm;
+	TkCmdtab *ct;
+	int bot, top, new, r;
+	char *e, *buf;
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	if(val != nil)
+		*val = nil;
+
+	cm = tkmethod[tk->type];
+
+	e = TkBadcm;
+	bot = 0;
+	top = cm->ncmd - 1;
+
+	while(bot <= top) {
+		new = (bot + top)/2;
+		ct = &cm->cmd[new];
+		r = strcmp(ct->name, buf);
+		if(r == 0) {
+			e = ct->fn(tk, arg, val);
+			break;
+		}
+		if(r < 0)
+			bot = new + 1;
+		else
+			top = new - 1;
+	}
+	free(buf);
+	tkdirty(tk);
+	return e;
+}
+
+Rectangle
+tkrect(Tk *tk, int withborder)
+{
+	Rectangle r;
+	int bd;
+
+	bd = withborder? tk->borderwidth: 0;
+	r.min.x = -bd;
+	r.min.y = -bd;
+	r.max.x = tk->act.width + bd;
+	r.max.y = tk->act.height + bd;
+	return r;
+}
+
+void
+tkdirty(Tk *tk)
+{
+	Tk *sub;
+	Point rel;
+	Rectangle dirty;
+	int isdirty, transparent;
+
+	/*
+	 * mark as dirty all views underneath a dirty transparent widget
+	 *	down to the first opaque widget.
+	 * inform parents about any dirtiness.
+
+	 * XXX as Tksubsub never gets reset, testing against Tksubsub doesn't *exactly* test
+	 * whether we're in a canvas/text widget, but merely
+	 * whether it has ever been. Tksubsub should probably be reset on unpack.
+	 */
+	isdirty = Dx(tk->dirty) > 0;
+	transparent = tk->flag & Tktransparent;
+	sub = tk;
+	while (isdirty && ((tk->flag&Tksubsub) || transparent)) {
+		if (tk->master != nil) {
+			if (transparent) {
+				rel.x = tk->act.x + tk->borderwidth;
+				rel.y = tk->act.y + tk->borderwidth;
+				dirty = rectaddpt(sub->dirty, rel);
+				sub = tk->master;
+				combinerect(&sub->dirty, dirty);
+				transparent = sub->flag & Tktransparent;
+			}
+			tk = tk->master;
+		} else if (tk->parent != nil) {
+			tkmethod[tk->parent->type]->dirtychild(sub);
+			tk = sub = tk->parent;
+			isdirty = Dx(sub->dirty) > 0;
+			transparent = sub->flag & Tktransparent;
+		} else
+			break;
+	}
+}
+
+static int
+qcmdcmp(const void *a, const void *b)
+{
+	return strcmp(((TkCmdtab*)a)->name, ((TkCmdtab*)b)->name);
+}
+
+void
+tksorttable(void)
+{
+	int i;
+	TkMethod *c;
+	TkCmdtab *cmd;
+
+	for(i = 0; i < TKwidgets; i++) {
+		c = tkmethod[i];
+		if(c->cmd == nil)
+			continue;
+
+		for(cmd = c->cmd; cmd->name != nil; cmd++)
+			;
+		c->ncmd = cmd - c->cmd;
+
+		qsort(c->cmd, c->ncmd, sizeof(TkCmdtab), qcmdcmp);
+	}
+}
+
+static char*
+tksinglecmd(TkTop *t, char *arg, char **val)
+{
+	Tk *tk;
+	int bot, top, new;
+	char *e, *buf;
+
+	if(t->debug)
+		print("tk: '%s'\n", arg);
+
+	buf = mallocz(Tkmaxitem, 0);
+	if(buf == nil)
+		return TkNomem;
+
+	arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
+	switch(buf[0]) {
+	case '\0':
+		free(buf);
+		return nil;
+	case '.':
+		tk = tklook(t, buf, 0);
+		if(tk == nil){
+			tkerr(t, buf);
+			free(buf);
+			return TkBadwp;
+		}
+		e = tkwidgetcmd(t, tk, arg, val);
+		free(buf);
+		return e;
+	}
+
+	bot = 0;
+	top = nelem(cmdmain) - 1;
+	e = TkBadcm;
+	while(bot <= top) {
+		int rc;
+		new = (bot + top)/2;
+		rc = strcmp(cmdmain[new].name, buf); 
+		if(!rc) {
+			e = cmdmain[new].fn(t, arg, val);
+			break;
+		}
+
+		if(rc < 0) 
+			bot = new + 1;
+		else
+			top = new - 1;
+	}
+	free(buf);
+	return e;
+}
+
+static char*
+tkmatch(int inc, int dec, char *p)
+{
+	int depth, esc, c;
+
+	esc = 0;
+	depth = 1;
+	while(*p) {
+		c = *p;
+		if(esc == 0) {
+			if(c == inc)
+				depth++;
+			if(c == dec)
+				depth--;
+			if(depth == 0)
+				return p;
+		}
+		if(c == '\\' && esc == 0)
+			esc = 1;
+		else
+			esc = 0;
+		p++;
+	}
+	return nil;
+}
+
+char*
+tkexec(TkTop *t, char *arg, char **val)
+{
+	int cmdsz, n;
+	char *p, *cmd, *e, *c;
+
+	if(t->execdepth >= 0 && ++t->execdepth > 128)
+		return TkDepth;
+
+	cmd = nil;
+	cmdsz = 0;
+
+	p = arg;
+	for(;;) {
+		switch(*p++) {
+		case '[':
+			p = tkmatch('[', ']', p);
+			if(p == nil){
+				free(cmd);
+				return TkSyntx;
+			}
+			break;
+		case '{':
+			p = tkmatch('{', '}', p);
+			if(p == nil){
+				free(cmd);
+				return TkSyntx;
+			}
+			break;
+		case ';':
+			n = p - arg - 1;
+			if(cmdsz < n)
+				cmdsz = n;
+			c = realloc(cmd, cmdsz+1);
+			if(c == nil){
+				free(cmd);
+				return TkNomem;
+			}
+			cmd = c;
+			memmove(cmd, arg, n);
+			cmd[n] = '\0';
+			e = tksinglecmd(t, cmd, nil);
+			if(e != nil) {
+				t->err = e;
+				strncpy(t->errcmd, cmd, sizeof(t->errcmd));
+				t->errcmd[sizeof(t->errcmd)-1] = '\0';
+				free(cmd);
+				return e;
+			}
+			arg = p;
+			break;
+		case '\0':
+		case '\'':
+			free(cmd);
+			e = tksinglecmd(t, arg, val);
+			if(e != nil) {
+				t->err = e;
+				strncpy(t->errcmd, arg, sizeof(t->errcmd));
+				t->errcmd[sizeof(t->errcmd)-1] = '\0';
+			}
+			return e;
+		}
+	}
+}
+
+static struct {
+	char *name;
+	int mask;
+} events[] = {
+	"Button1P",	TkButton1P,
+	"Button1R",	TkButton1R,
+	"Button2P",	TkButton2P,
+	"Button2R",	TkButton2R,
+	"Button3P",	TkButton3P,
+	"Button3R",	TkButton3R,
+	"Button4P",	TkButton4P,
+	"Button4R",	TkButton4R,
+	"Button5P",	TkButton5P,
+	"Button5R",	TkButton5R,
+	"Button6P",	TkButton6P,
+	"Button6R",	TkButton6R,
+	"Extn1",		TkExtn1,
+	"Extn2",		TkExtn2,
+	"Takefocus",	TkTakefocus,
+	"Destroy",		TkDestroy,
+	"Enter",		TkEnter,
+	"Leave",		TkLeave,
+	"Motion",		TkMotion,
+	"Map",		TkMap,
+	"Unmap",		TkUnmap,
+	"Key",		TkKey,
+	"Focusin",		TkFocusin,
+	"Focusout",	TkFocusout,
+	"Configure",	TkConfigure,
+	"Double",		TkDouble,
+	0
+};
+
+int
+tkeventfmt(Fmt *f)
+{
+	int k, i, d;
+	int e;
+
+	e = va_arg(f->args, int);
+
+	if ((f->flags & FmtSharp) && e == TkMotion)
+		return 0;
+	fmtprint(f, "<");
+	k = -1;
+	if (e & TkKey) {
+		k = e & 0xffff;
+		e &= ~0xffff;
+	}
+	d = 0;
+	for (i = 0; events[i].name; i++) {
+		if (e & events[i].mask) {
+			if (d++)
+				fmtprint(f, "|");
+			fmtprint(f, "%s", events[i].name);
+		}
+	}
+	if (k != -1) {
+		fmtprint(f, "[%c]", k);
+	} else if (e == 0)
+		fmtprint(f, "Noevent");
+	fmtprint(f, ">");
+	return 0;
+}
+
+void
+tkerr(TkTop *t, char *e)
+{
+	if(t != nil && e != nil){
+		strncpy(t->errx, e, sizeof(t->errx));
+		t->errx[sizeof(t->errx)-1] = '\0';
+	}
+}
+
+char*
+tkerrstr(TkTop *t, char *e)
+{
+	char *s = malloc(strlen(e)+1+strlen(t->errx)+1);
+
+	if(s == nil)
+		return nil;
+	strcpy(s, e);
+	if(*e == '!'){
+		strcat(s, " ");
+		strcat(s, t->errx);
+	}
+	t->errx[0] = '\0';
+	return s;
+}
+
+char*
+tksetmgrab(TkTop *t, Tk *tk)
+{
+	Tk *omgrab;
+	TkCtxt *c;
+	c = t->ctxt;
+	if (tk == nil) {
+		omgrab = c->mgrab;
+		c->mgrab = nil;
+		/*
+		 * don't enterleave if grab reset would cause no leave event
+		 */
+		if (!(omgrab != nil && (omgrab->flag & Tknograb) &&
+				c->entered != nil && (c->entered->flag & Tknograb)))
+			tkenterleave(t);
+	} else {
+		if (c->focused && c->mfocus != nil && c->mfocus->env->top != tk->env->top)
+			return "!grab already taken on another toplevel";
+		c->mgrab = tk;
+		if (tk->flag & Tknograb) {
+			if (c->focused) {
+				c->focused = 0;
+				c->mfocus = nil;
+			}
+		} else if (c->focused || c->mstate.b != 0) {
+			c->focused = 1;
+			c->mfocus = tk;
+		}
+//print("setmgrab(%s) focus now %s\n", tkname(tk), tkname(c->mfocus));
+		tkenterleave(t);
+	}
+	return nil;
+}
+
+int
+tkinsidepoly(Point *poly, int np, int winding, Point p)
+{
+	Point pi, pj;
+	int i, j, hit;
+
+	hit = 0;
+	j = np - 1;
+	for(i = 0; i < np; j = i++) {
+		pi = poly[i];
+		pj = poly[j];
+		if((pi.y <= p.y && p.y < pj.y || pj.y <= p.y && p.y < pi.y) &&
+				p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) {
+			if(winding == 1 || pi.y > p.y)
+				hit++;
+			else
+				hit--;
+		}
+	}
+	return (hit & winding) != 0;
+}
+
+int
+tklinehit(Point *a, int np, int w, Point p)
+{
+	Point *b;
+	int z, nx, ny, nrm;
+
+	while(np-- > 1) {
+		b = a+1;
+		nx = a->y - b->y;
+		ny = b->x - a->x;
+		nrm = (nx < 0? -nx : nx) + (ny < 0? -ny : ny);
+		if(nrm)
+			z = (p.x-b->x)*nx/nrm + (p.y-b->y)*ny/nrm;
+		else
+			z = (p.x-b->x) + (p.y-b->y);
+		if(z < 0)
+			z = -z;
+		if(z < w)
+			return 1;
+		a++;
+	}
+	return 0;
+}
+
+int
+tkiswordchar(int c)
+{
+	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c >= 0xA0;
+}
+
+int
+tkhaskeyfocus(Tk *tk)
+{
+	if (tk == nil || tk->env->top->focused == 0)
+		return 0;
+	return tk == tk->env->top->ctxt->tkkeygrab;
+}
+
+static int
+rptactive(void *v)
+{
+	int id = (int)v;
+	if (id == rptid)
+		return 1;
+	return 0;
+}
+
+static int
+ckrpt(void *v, int interval)
+{
+	int id = (int)v;
+	if (id != rptid)
+		return -1;
+	if (interval < rptto)
+		return 0;
+	return 1;
+}
+
+static void
+dorpt(void *v)
+{
+	int id = (int)v;
+
+	if (id == rptid) {
+		rptto = rptint;
+		(*rptcb)(rptw, rptnote, 0);
+		if (rptint <= 0) {
+			rptid++;
+			rptw = nil;
+		}
+	}
+}
+
+void
+tkcancelrepeat(Tk *tk)
+{
+	if (tk == rptw) {
+		rptid++;
+		rptw = nil;
+	}
+}
+
+void
+tkrepeat(Tk *tk, void (*callback)(Tk*, void*, int), void *note, int pause, int interval)
+{
+	rptid++;
+	if (tk != rptw && rptw != nil)
+		/* existing callback being replaced- report to owner */
+		(*rptcb)(rptw, rptnote, 1);
+	rptw = tk;
+	if (tk == nil || callback == nil)
+		return;
+	rptnote = note;
+	rptcb = callback;
+	rptto = pause;
+	rptint = interval;
+	if (!autorpt)
+		autorpt = rptproc("autorepeat", TkRptclick, (void*)rptid, rptactive, ckrpt, dorpt);
+	else
+		rptwakeup((void*)rptid, autorpt);
+}
+
+static int
+blinkactive(void *v)
+{
+	USED(v);
+	return blinkw != nil;
+}
+
+static int
+ckblink(void *v, int interval)
+{
+	USED(v);
+	USED(interval);
+
+	if (blinkw == nil)
+		return -1;
+	if (blinkignore) {
+		blinkignore = 0;
+		return 0;
+	}
+	return 1;
+}
+
+static void
+doblink(void *v)
+{
+	USED(v);
+
+	if (blinkw == nil)
+		return;
+	blinkcb(blinkw, blinkon++ & 1);
+	tkupdate(blinkw->env->top);
+}
+
+void
+tkblinkreset(Tk *tk)
+{
+	if (blinkw == tk) {
+		blinkignore = 1;
+		blinkon = 0;
+	}
+}
+
+void
+tkblink(Tk *tk, void (*callback)(Tk*, int))
+{
+	if (tk == nil || callback == nil) {
+		blinkw = nil;
+		return;
+	}
+	blinkw = tk;
+	blinkcb = callback;
+	if (!blinkrpt)
+		blinkrpt = rptproc("blinker", TkBlinkinterval, nil, blinkactive, ckblink, doblink);
+	else
+		rptwakeup(nil, blinkrpt);
+}
+
+/*
+ * debugging
+ */
+void
+tkdump(Tk *tk)
+{
+	Tk *sl;
+
+	if(tk == nil)
+		return;
+	if((uint)tk->type < TKwidgets)
+		print("%s", tkmethod[tk->type]->name);
+	else
+		print("TYPE#%#ux", tk->type);
+	if(tk->name == nil || (ulong)tk->name < 512)
+		print(" NAME %p", tk->name);
+	else
+		print(" %s", tkname(tk));
+	print(" # tk %#p flag %#ux grid %#p", tk, tk->flag, tk->grid);
+	if(tk->parent != nil)
+		print(" parent [%#p %q]", tk->parent, tkname(tk->parent));
+	if(tk->master != nil)
+		print(" master [%#p %q]", tk->master, tkname(tk->master));
+	if(tk->slave != nil){
+		print(" slaves");
+		for(sl = tk->slave; sl != nil; sl = sl->next)
+			print(" [%#p %q]", sl, tkname(sl));
+	}
+	print("\n");
+	if(tk->type != TKcanvas)
+		return;
+	tkcvsdump(tk);
+}
+
+void
+tktopdump(Tk *tk)
+{
+	TkTop *top;
+	Tk *sub;
+
+	if(tk == nil || tk->env == nil){
+		print("# %#p no top\n", tk);
+		return;
+	}
+	top = tk->env->top;
+	print("# env %#p top %#p\n", tk->env, top);
+	if(top != nil){
+		for(sub = top->root; sub != nil; sub = sub->siblings)
+			tkdump(sub);
+	}
+}
--- /dev/null
+++ b/libtk/varbl.c
@@ -1,0 +1,91 @@
+#include <lib9.h>
+#include <kernel.h>
+#include "draw.h"
+#include "tk.h"
+#include "label.h"
+
+char*
+tksetvar(TkTop *top, char *c, char *newval)
+{
+	TkVar *v;
+	TkWin *tkw;
+	Tk *f, *m;
+	void (*vc)(Tk*, char*, char*);
+
+	if (c == nil || c[0] == '\0')
+		return nil;
+
+	v = tkmkvar(top, c, TkVstring);
+	if(v == nil)
+		return TkNomem;
+	if(v->type != TkVstring)
+		return TkNotvt;
+
+	if(newval == nil)
+		newval = "";
+
+	if(v->value != nil) {
+		if (strcmp(v->value, newval) == 0)
+			return nil;
+		free(v->value);
+	}
+
+	v->value = strdup(newval);
+	if(v->value == nil)
+		return TkNomem;
+
+	for(f = top->root; f; f = f->siblings) {
+		if(f->type == TKmenu) {
+			tkw = TKobj(TkWin, f);
+			for(m = tkw->slave; m; m = m->next)
+				if ((vc = tkmethod[m->type]->varchanged) != nil)
+					(*vc)(m, c, newval);
+		} else
+			if ((vc = tkmethod[f->type]->varchanged) != nil)
+				(*vc)(f, c, newval);
+	}
+
+	return nil;
+}
+
+char*
+tkvariable(TkTop *t, char *arg, char **ret)
+{
+	TkVar *v;
+	char *fmt, *e, *buf, *ebuf, *val;
+	int l;
+
+	l = strlen(arg) + 2;
+	buf = malloc(l);
+	if(buf == nil)
+		return TkNomem;
+	ebuf = buf+l;
+
+	arg = tkword(t, arg, buf, ebuf, nil);
+	arg = tkskip(arg, " \t");
+	if (*arg == '\0') {
+		if(strcmp(buf, "lasterror") == 0) {
+			free(buf);
+			if(t->err == nil)
+				return nil;
+			fmt = "%s: %s";
+			if(strlen(t->errcmd) == sizeof(t->errcmd)-1)
+				fmt = "%s...: %s";
+			e = tkvalue(ret, fmt, t->errcmd, t->err);
+			t->err = nil;
+			return e;
+		}
+		v = tkmkvar(t, buf, 0);
+		free(buf);
+		if(v == nil || v->value == nil)
+			return nil;
+		if(v->type != TkVstring)
+			return TkNotvt;
+		return tkvalue(ret, "%s", v->value);
+	}
+	val = buf+strlen(buf)+1;
+	tkword(t, arg, val, ebuf, nil);
+	e = tksetvar(t, buf, val);
+	free(buf);
+	return e;
+}
--- /dev/null
+++ b/libtk/windw.c
@@ -1,0 +1,693 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+#include "canvs.h"
+#include "textw.h"
+#include "kernel.h"
+
+TkCtxt*
+tknewctxt(Display *d)
+{
+	TkCtxt *c;
+	c = malloc(sizeof(TkCtxt));
+	if(c == nil)
+		return nil;
+	c->lock = libqlalloc();
+	if(c->lock == nil){
+		free(c);
+		return nil;
+	}
+	if (tkextnnewctxt(c) != 0) {
+		free(c->lock);
+		free(c);
+		return nil;
+	}
+	c->display = d;
+	return c;
+}
+
+void
+tkfreectxt(TkCtxt *c)
+{
+	int locked;
+	Display *d;
+
+	if(c == nil)
+		return;
+
+	tkextnfreectxt(c);
+
+	d = c->display;
+	locked = lockdisplay(d);
+	tkfreecolcache(c);
+	freeimage(c->i);
+	freeimage(c->ia);
+	if(locked)
+		unlockdisplay(d);
+	libqlfree(c->lock);
+	free(c);
+}
+
+Image*
+tkitmp(TkEnv *e, Point p, int fillcol)
+{
+	Image *i, **ip;
+	TkTop *t;
+	TkCtxt *ti;
+	Display *d;
+	Rectangle r;
+	ulong pix;
+	int alpha;
+	
+	t = e->top;
+	ti = t->ctxt;
+	d = t->display;
+
+	pix = e->colors[fillcol];
+	alpha = (pix & 0xff) != 0xff;
+	ip = alpha ? &ti->ia : &ti->i;
+
+	if(*ip != nil) {
+		i = *ip;
+		if(p.x <= i->r.max.x && p.y <= i->r.max.y) {
+			r.min = ZP;
+			r.max = p;
+			if (alpha)
+				drawop(i, r, nil, nil, ZP, Clear);
+			draw(i, r, tkgc(e, fillcol), nil, ZP);
+			return i;
+		}
+		r = i->r;
+		freeimage(i);
+		if(p.x < r.max.x)
+			p.x = r.max.x;
+		if(p.y < r.max.y)
+			p.y = r.max.y;
+	}
+
+	r.min = ZP;
+	r.max = p;
+	*ip = allocimage(d, r, alpha?RGBA32:d->image->chan, 0, pix);
+
+	return *ip;
+}
+
+void
+tkgeomchg(Tk *tk, TkGeom *g, int bd)
+{
+	int w, h;
+	void (*geomfn)(Tk*);
+	if(memcmp(&tk->req, g, sizeof(TkGeom)) == 0 && bd == tk->borderwidth)
+		return;
+
+	geomfn = tkmethod[tk->type]->geom;
+	if(geomfn != nil)
+		geomfn(tk);
+
+	if(tk->master != nil) {
+		tkpackqit(tk->master);
+		tkrunpack(tk->env->top);
+	}
+	else
+	if(tk->geom != nil) {
+		w = tk->req.width;
+		h = tk->req.height;
+		tk->req.width = 0;
+		tk->req.height = 0;
+		tk->geom(tk, tk->act.x, tk->act.y, w, h);
+		if (tk->slave) {
+			tkpackqit(tk);
+			tkrunpack(tk->env->top);
+		}
+	}
+	tkdeliver(tk, TkConfigure, g);
+}
+
+/*
+ * return the widget within tk with by point p (in widget coords)
+ */
+Tk*
+tkinwindow(Tk *tk, Point p, int descend)
+{
+	Tk *f;
+	Point q;
+	if (ptinrect(p, tkrect(tk, 1)) == 0)
+		return nil;
+	for (;;) {
+		if (descend && tkmethod[tk->type]->inwindow != nil)
+			f = tkmethod[tk->type]->inwindow(tk, &p);
+		else {
+			q = p;
+			for (f = tk->slave; f; f = f->next) {
+				q.x = p.x - (f->act.x + f->borderwidth);
+				q.y = p.y - (f->act.y + f->borderwidth);
+				if (ptinrect(q, tkrect(f, 1)))
+					break;
+			}
+			p = q;
+		}
+		if (f == nil || f == tk)
+			return tk;
+		tk = f;
+	}
+}
+
+Tk*
+tkfindfocus(TkTop *t, int x, int y, int descend)
+{
+	Point p, q;
+	Tk *tk, *f;
+	TkWin *tkw;
+	p.x = x;
+	p.y = y;
+	for(f = t->windows; f != nil; f = TKobj(TkWin, f)->next) {
+		assert(f->flag&Tkwindow);
+		if(f->flag & Tkmapped) {
+			tkw = TKobj(TkWin, f);
+			q.x = p.x - (tkw->act.x+f->borderwidth);
+			q.y = p.y - (tkw->act.y+f->borderwidth);
+			tk = tkinwindow(f, q, descend);
+			if(tk != nil)
+				return tk;
+		}
+	}
+	return nil;
+}
+
+void
+tkmovewin(Tk *tk, Point p)
+{
+	TkWin *tkw;
+	if((tk->flag & Tkwindow) == 0)
+		return;
+	tkw = TKobj(TkWin, tk);
+	if(! eqpt(p, tkw->req)){
+		tkw->req = p;
+		tkw->changed = 1;
+	}
+}
+
+void
+tkmoveresize(Tk *tk, int x, int y, int w, int h)
+{
+	TkWin *tkw;
+	USED(x);
+	USED(y);
+	assert(tk->flag&Tkwindow);
+	tkw = TKobj(TkWin, tk);
+	if(w < 0)
+		w = 0;
+	if(h < 0)
+		h = 0;
+//print("moveresize %s %d %d +[%d %d], callerpc %lux\n", tk->name->name, x, y, w, h, getcallerpc(&tk));
+	tk->req.width = w;
+	tk->req.height = h;
+	tk->act = tk->req;
+	/* XXX perhaps should actually suspend the window here? */
+	tkw->changed = 1;
+}
+
+static void
+tkexterncreatewin(Tk *tk, Rectangle r)
+{
+	TkWin *tkw;
+	TkTop *top;
+	char *name;
+
+	top = tk->env->top;
+	tkw = TKobj(TkWin, tk);
+
+	/*
+	 * for a choicebutton menu, use the name of the choicebutton which created it
+	 */
+	if(tk->name == nil){
+		name = tkw->cbname;
+		assert(name != nil);
+	} else
+		name = tk->name->name;
+
+	tkw->reqid++;
+	tkwreq(top, "!reshape %s %d %d %d %d %d", name, tkw->reqid, r.min.x, r.min.y, r.max.x, r.max.y);
+	tkw->changed = 0;
+	tk->flag |= Tksuspended;
+}
+
+/*
+ * return non-zero if the window size has changed (XXX choose better return value/function name!)
+ */
+int
+tkupdatewinsize(Tk *tk)
+{
+	TkWin *tkw;
+	Image *previ;
+	Rectangle r, or;
+	int bw2;
+
+	tkw = TKobj(TkWin, tk);
+	bw2 = 2*tk->borderwidth;
+	r.min.x = tkw->req.x;
+	r.min.y = tkw->req.y;
+	r.max.x = r.min.x + tk->act.width + bw2;
+	r.max.y = r.min.y + tk->act.height + bw2;
+	previ = tkw->image;
+	if(previ != nil){
+		or.min.x = tkw->act.x;
+		or.min.y = tkw->act.y;
+		or.max.x = tkw->act.x + Dx(previ->r);
+		or.max.y = tkw->act.y + Dy(previ->r);
+		if(eqrect(or, r))
+			return 0;
+	}
+	tkexterncreatewin(tk, r);
+	return 1;
+}
+
+static char*
+tkdrawslaves1(Tk *tk, Point orig, Image *dst, int *dirty)
+{
+	Tk *f;
+	char *e = nil;
+	Point worig;
+	Rectangle r, oclip;
+
+	worig.x = orig.x + tk->act.x + tk->borderwidth;
+	worig.y = orig.y + tk->act.y + tk->borderwidth;
+
+	r = rectaddpt(tk->dirty, worig);
+	if (Dx(r) > 0 && rectXrect(r, dst->clipr)) {
+		e = tkmethod[tk->type]->draw(tk, orig);
+		tk->dirty = bbnil;
+		*dirty = 1;
+	}
+	if(e != nil)
+		return e;
+
+	/*
+	 * grids need clipping
+	 * XXX BUG: they can't, 'cos text widgets don't clip appropriately.
+	 */
+	if (tk->grid != nil) {
+		r = rectaddpt(tkrect(tk, 0), worig);
+		if (rectclip(&r, dst->clipr) == 0)
+			return nil;
+		oclip = dst->clipr;
+		replclipr(dst, 0, r);
+	}
+	for(f = tk->slave; e == nil && f; f = f->next)
+		e = tkdrawslaves1(f, worig, dst, dirty);
+	if (tk->grid != nil)
+		replclipr(dst, 0, oclip);
+	return e;
+}
+	
+char*
+tkdrawslaves(Tk *tk, Point orig, int *dirty)
+{
+	Image *i;
+	char *e;
+	i = tkimageof(tk);
+	if (i == nil)
+		return nil;
+	e =  tkdrawslaves1(tk, orig, i, dirty);
+	return e;
+}
+
+char*
+tkupdate(TkTop *t)
+{
+	Tk* tk;
+	int locked;
+	TkWin *tkw;
+	Display *d;
+	char *e;
+	int dirty = 0;
+	if(t->noupdate)
+		return nil;
+
+	d = t->display;
+	locked = lockdisplay(d);
+	tk = t->windows;
+	while(tk) {
+		tkw = TKobj(TkWin, tk);
+		if((tk->flag & (Tkmapped|Tksuspended)) == Tkmapped) {
+			if (tkupdatewinsize(tk) == 0){
+				e = tkdrawslaves(tk, ZP, &dirty);
+				if(e != nil)
+					return e;
+			}
+		}
+		tk = tkw->next;
+	}
+	if (dirty || t->dirty) {
+		flushimage(d, 1);
+		t->dirty = 0;
+	}
+	if(locked)
+		unlockdisplay(d);
+	return nil;
+}
+
+int
+tkischild(Tk *tk, Tk *child)
+{
+	while(child != nil && child != tk){
+		if(child->master)
+			child = child->master;
+		else
+			child = child->parent;
+	}
+	return child == tk;
+}
+
+void
+tksetbits(Tk *tk, int mask)
+{
+	tk->flag |= mask;
+	for(tk = tk->slave; tk; tk = tk->next)
+		tksetbits(tk, mask);
+}
+
+char*
+tkmap(Tk *tk)
+{
+/*
+	is this necessary?
+	tkw = TKobj(TkWin, tk);
+	if(tkw->image != nil)
+		tkwreq(tk->env->top, "raise %s", tk->name->name);
+*/
+
+	if(tk->flag & Tkmapped)
+		return nil;
+
+	tk->flag |= Tkmapped;
+	tkmoveresize(tk, 0, 0, tk->act.width, tk->act.height);
+	tkdeliver(tk, TkMap, nil);
+	return nil;
+//tkupdate(tk->env->top);
+}
+
+void
+tkunmap(Tk *tk)
+{
+	TkTop *t;
+	TkCtxt *c;
+
+	while(tk->master)
+		tk = tk->master;
+
+	if((tk->flag & Tkmapped) == 0)
+		return;
+
+	t = tk->env->top;
+	c = t->ctxt;
+
+	if(tkischild(tk, c->mgrab))
+		tksetmgrab(t, nil);
+	if(tkischild(tk, c->entered)){
+		tkdeliver(c->entered, TkLeave, nil);
+		c->entered = nil;
+	}
+	if(tk == t->root)
+		tksetglobalfocus(t, 0);
+
+	tk->flag &= ~(Tkmapped|Tksuspended);
+
+	tkdestroywinimage(tk);
+	tkdeliver(tk, TkUnmap, nil);
+	tkenterleave(t);
+	/* XXX should unmap menus too */
+}
+
+Image*
+tkimageof(Tk *tk)
+{
+	while(tk) {
+		if(tk->flag & Tkwindow)
+			return TKobj(TkWin, tk)->image;
+		if(tk->parent != nil) {
+			tk = tk->parent;
+			switch(tk->type) {
+			case TKmenu:
+				return TKobj(TkWin, tk)->image;
+			case TKcanvas:
+				return TKobj(TkCanvas, tk)->image;
+			case TKtext:
+				return TKobj(TkText, tk)->image;
+			}
+			abort();
+		}
+		tk = tk->master;
+	}
+	return nil;
+}
+
+void
+tktopopt(Tk *tk, char *opt)
+{
+	TkTop *t;
+	TkWin *tkw;
+	TkOptab tko[4];
+
+	tkw = TKobj(TkWin, tk);
+
+	t = tk->env->top;
+
+	tko[0].ptr = tkw;
+	tko[0].optab = tktop;
+	tko[1].ptr = tk;
+	tko[1].optab = tkgeneric;
+	tko[2].ptr = t;
+	tko[2].optab = tktopdbg;
+	tko[3].ptr = nil;
+
+	tkparse(t, opt, tko, nil);
+}
+
+/* general compare - compare top-left corners, y takes priority */
+static int
+tkfcmpgen(void *ap, void *bp)
+{
+	TkWinfo *a = ap, *b = bp;
+
+	if (a->r.min.y > b->r.min.y)
+		return 1;
+	if (a->r.min.y < b->r.min.y)
+		return -1;
+	if (a->r.min.x > b->r.min.x)
+		return 1;
+	if (a->r.min.x < b->r.min.x)
+		return -1;
+	return 0;
+}
+
+/* compare x-coords only */
+static int
+tkfcmpx(void *ap, void *bp)
+{
+	TkWinfo *a = ap, *b = bp;
+	return a->r.min.x - b->r.min.x;
+}
+
+/* compare y-coords only */
+static int
+tkfcmpy(void *ap, void *bp)
+{
+	TkWinfo *a = ap, *b = bp;
+	return a->r.min.y - b->r.min.y;
+}
+
+static void
+tkfintervalintersect(int min1, int max1, int min2, int max2, int *min, int *max)
+{
+	if (min1 < min2)
+		min1 = min2;
+	if (max1 > max2)
+		max1 = max2;
+	if (max1 > min1) {
+		*min = min1;
+		*max = max1;
+	} else
+		*max = *min;		/* no intersection */
+}
+
+void
+tksortfocusorder(TkWinfo *inf, int n)
+{
+	int i;
+	Rectangle overlap, r;
+	int (*cmpfn)(void*, void*);
+
+	overlap = inf[0].r;
+	for (i = 0; i < n; i++) {
+		r = inf[i].r;
+		tkfintervalintersect(overlap.min.x, overlap.max.x,
+				r.min.x, r.max.x, &overlap.min.x, &overlap.max.x);
+		tkfintervalintersect(overlap.min.y, overlap.max.y,
+				r.min.y, r.max.y, &overlap.min.y, &overlap.max.y);
+	}
+
+	if (Dx(overlap) > 0)
+		cmpfn = tkfcmpy;
+	else if (Dy(overlap) > 0)
+		cmpfn = tkfcmpx;
+	else
+		cmpfn = tkfcmpgen;
+
+	qsort(inf, n, sizeof(*inf), cmpfn);
+}
+
+void
+tkappendfocusorder(Tk *tk)
+{
+	TkTop *tkt;
+	tkt = tk->env->top;
+	if (tk->flag & Tktakefocus)
+		tkt->focusorder[tkt->nfocus++] = tk;
+	if (tkmethod[tk->type]->focusorder != nil)
+		tkmethod[tk->type]->focusorder(tk);
+}
+
+void
+tkbuildfocusorder(TkTop *tkt)
+{
+	Tk *tk;
+	int n;
+
+	if (tkt->focusorder != nil)
+		free(tkt->focusorder);
+	n = 0;
+	for (tk = tkt->root; tk != nil; tk = tk->siblings)
+		if (tk->flag & Tktakefocus)
+			n++;
+	if (n == 0) {
+		tkt->focusorder = nil;
+		return;
+	}
+
+	tkt->focusorder = malloc(sizeof(*tkt->focusorder) * n);
+	tkt->nfocus = 0;
+	if (tkt->focusorder == nil)
+		return;
+
+	tkappendfocusorder(tkt->root);
+}
+
+void
+tkdirtyfocusorder(TkTop *tkt)
+{
+	free(tkt->focusorder);
+	tkt->focusorder = nil;
+	tkt->nfocus = 0;
+}
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+#define OA(t, e)	((long)(((t*)0)->e))
+
+typedef struct TkSee TkSee;
+struct TkSee {
+	int r[4];
+	int p[2];
+	int query;
+};
+
+static
+TkOption seeopts[] = {
+	"rectangle",		OPTfrac,	OA(TkSee, r),	IAUX(4),
+	"point",			OPTfrac,	OA(TkSee, p),	IAUX(2),
+	"where",			OPTbool,	O(TkSee, query),	nil,
+	nil
+};
+
+char*
+tkseecmd(TkTop *t, char *arg, char **ret)
+{
+	TkOptab tko[2];
+	TkSee opts;
+	TkName *names;
+	Tk *tk;
+	char *e;
+	Rectangle vr;
+	Point vp;
+
+	opts.r[0] = bbnil.min.x;
+	opts.r[1] = bbnil.min.y;
+	opts.r[2] = bbnil.max.x;
+	opts.r[3] = bbnil.max.y;
+	opts.p[0] = bbnil.max.x;
+	opts.p[1] = bbnil.max.y;
+	opts.query = 0;
+
+	tko[0].ptr = &opts;
+	tko[0].optab = seeopts;
+	tko[1].ptr = nil;
+	names = nil;
+	e = tkparse(t, arg, tko, &names);
+	if (e != nil)
+		return e;
+	if (names == nil)
+		return TkBadwp;
+	tk = tklook(t, names->name, 0);
+	tkfreename(names);
+	if (tk == nil)
+		return TkBadwp;
+	if (opts.query) {
+		if (!tkvisiblerect(tk, &vr))
+			return nil;
+		/* XXX should this be converted into screen coords? */
+		return tkvalue(ret, "%d %d %d %d", vr.min.x, vr.min.y, vr.max.x, vr.max.y);
+	}
+	vr.min.x = opts.r[0];
+	vr.min.y = opts.r[1];
+	vr.max.x = opts.r[2];
+	vr.max.y = opts.r[3];
+	vp.x = opts.p[0];
+	vp.y = opts.p[1];
+
+	if (eqrect(vr, bbnil))
+		vr = tkrect(tk, 1);
+	if (eqpt(vp, bbnil.max))
+		vp = vr.min;
+	tksee(tk, vr, vp);
+	return nil;
+}
+
+/*
+ * make rectangle r in widget tk visible if possible;
+ * if not possible, at least make point p visible.
+ */
+void
+tksee(Tk *tk, Rectangle r, Point p)
+{
+	Point g;
+//print("tksee %R, %P in %s\n", r, p, tk->name->name);
+	g = Pt(tk->borderwidth, tk->borderwidth);
+	if(tk->parent != nil) {
+		g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
+		tk = tk->parent;
+	} else {
+		g.x += tk->act.x;
+		g.y += tk->act.y;
+		tk = tk->master;
+	}
+	r = rectaddpt(r, g);
+	p = addpt(p, g);
+	while (tk != nil) {
+		if (tkmethod[tk->type]->see != nil){
+//print("see r %R, p %P in %s\n", r, p, tk->name->name);
+			tkmethod[tk->type]->see(tk, &r, &p);
+//print("now r %R, p %P\n", r, p);
+		}
+		g = Pt(tk->borderwidth, tk->borderwidth);
+		if (tk->parent != nil) {
+			g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
+			tk = tk->parent;
+		} else {
+			g.x += tk->act.x;
+			g.y += tk->act.y;
+			tk = tk->master;
+		}
+		r = rectaddpt(r, g);
+		p = addpt(p, g);
+	}
+}
--- /dev/null
+++ b/libtk/xdata.c
@@ -1,0 +1,217 @@
+#include "lib9.h"
+#include "draw.h"
+#include "tk.h"
+
+#define	O(t, e)		((long)(&((t*)0)->e))
+
+TkStab tkorient[] =
+{
+	"vertical",	Tkvertical,
+	"horizontal",	Tkhorizontal,
+	nil
+};
+
+#define RGB(r,g,b) ((r<<24)|(g<<16)|(b<<8)|0xff)
+
+TkStab tkcolortab[] =
+{
+	"black",	RGB(0,0,0),
+	"blue",		RGB(0,0,204),
+	"darkblue",	RGB(93,0,187),
+	"red",		RGB(255,0,0),
+	"yellow",	RGB(255,255,0),
+	"green",	RGB(0,128,0),
+	"white",	RGB(255,255,255),
+	"orange",	RGB(255,170,0),
+	"aqua",		RGB(0,255,255),
+	"fuchsia",	RGB(255,0,255),
+	"gray",		RGB(128,128,128),
+	"grey",		RGB(128,128,128),
+	"lime",		RGB(0,255,0),
+	"maroon",	RGB(128,0,0),
+	"navy",		RGB(0,0,128),
+	"olive",	RGB(128,128,0),
+	"purple",	RGB(128,0,128),
+	"silver",	RGB(192,192,192),
+	"teal",		RGB(0,128,128),
+	"transparent",	DTransparent,
+	nil
+};
+
+TkStab tkrelief[] =
+{
+	"raised",	TKraised,
+	"sunken",	TKsunken,
+	"flat",		TKflat,
+	"groove",	TKgroove,
+	"ridge",	TKridge,
+	nil
+};
+
+TkStab tkbool[] =
+{
+	"0",		BoolF,
+	"no",		BoolF,
+	"off",		BoolF,
+	"false",	BoolF,
+	"1",		BoolT,
+	"yes",		BoolT,
+	"on",		BoolT,
+	"true",		BoolT,
+	nil
+};
+
+TkStab tkanchor[] =
+{
+	"center",	Tkcenter,
+	"c",		Tkcenter,
+	"n",		Tknorth,
+	"ne",		Tknorth|Tkeast,
+	"e",		Tkeast,
+	"se",		Tksouth|Tkeast,
+	"s",		Tksouth,
+	"sw",		Tksouth|Tkwest,
+	"w",		Tkwest,
+	"nw",		Tknorth|Tkwest,
+	nil
+};
+
+static
+TkStab tkstate[] =
+{
+	"normal",	0,
+	"active",	Tkactive,
+	"disabled",	Tkdisabled,
+	nil
+};
+
+static
+TkStab tktakefocus[] =
+{
+	"0",	0,
+	"1",	Tktakefocus,
+	nil
+};
+
+TkStab tktabjust[] =
+{
+	"left",		Tkleft,
+	"right",	Tkright,
+	"center",	Tkcenter,
+	"numeric",	Tknumeric,	
+	nil
+};
+
+TkStab tkwrap[] =
+{
+	"none",		Tkwrapnone,
+	"word",		Tkwrapword,
+	"char",		Tkwrapchar,
+	nil
+};
+
+TkStab tkjustify[] =
+{
+	"left",		Tkleft,
+	"right",	Tkright,
+	"center",	Tkcenter,
+	nil
+};
+
+TkOption tkgeneric[] =
+{
+ "actx",		OPTact,	0,	IAUX(0),
+ "acty",		OPTact,	0,	IAUX(1),
+ "actwidth",		OPTdist, O(Tk, act.width),	IAUX(O(Tk, env)),
+ "actheight",		OPTdist, O(Tk, act.height),	IAUX(O(Tk, env)),
+ "bd",			OPTnndist, O(Tk, borderwidth),	nil,
+ "borderwidth",		OPTnndist, O(Tk, borderwidth),	nil,
+ "highlightthickness",	OPTnndist, O(Tk, highlightwidth), nil,
+ "height",		OPTsize, 0,			IAUX(O(Tk, env)),
+ "width",		OPTsize, 0,			IAUX(O(Tk, env)),
+ "relief",		OPTstab, O(Tk, relief),		tkrelief,
+ "state",		OPTflag, O(Tk, flag),		tkstate,
+ "font",		OPTfont, O(Tk, env),		nil,
+ "foreground",		OPTcolr, O(Tk, env),		IAUX(TkCforegnd),
+ "background",		OPTcolr, O(Tk, env),		IAUX(TkCbackgnd),
+ "fg",			OPTcolr, O(Tk, env),		IAUX(TkCforegnd),
+ "bg",			OPTcolr, O(Tk, env),		IAUX(TkCbackgnd),
+ "selectcolor",		OPTcolr, O(Tk, env),		IAUX(TkCselect),
+ "selectforeground",	OPTcolr, O(Tk, env),		IAUX(TkCselectfgnd),
+ "selectbackground",	OPTcolr, O(Tk, env),		IAUX(TkCselectbgnd),
+ "activeforeground",	OPTcolr, O(Tk, env),		IAUX(TkCactivefgnd),
+ "activebackground",	OPTcolr, O(Tk, env),		IAUX(TkCactivebgnd),
+ "highlightcolor",	OPTcolr, O(Tk, env),		IAUX(TkChighlightfgnd),
+ "disabledcolor",	OPTcolr, O(Tk, env),		IAUX(TkCdisablefgnd),
+ "padx",		OPTnndist, O(Tk, pad.x),		nil,
+ "pady",		OPTnndist, O(Tk, pad.y),		nil,
+ "takefocus",	OPTflag, O(Tk, flag),		tktakefocus,
+ nil
+};
+
+TkOption tktop[] =
+{
+	"x",		OPTdist,	O(TkWin, req.x),		nil,
+	"y",		OPTdist,	O(TkWin, req.y),		nil,
+	nil
+};
+
+TkOption tktopdbg[] =
+{
+	"debug",	OPTbool,	O(TkTop, debug),	nil,
+	nil
+};
+
+TkMethod *tkmethod[] =
+{
+	&framemethod,	/* TKframe */
+	&labelmethod,		/* TKlabel */
+	&checkbuttonmethod,	/* TKcheckbutton */
+	&buttonmethod,	/* TKbutton */
+	&menubuttonmethod,	/* TKmenubutton */
+	&menumethod,	/* TKmenu */
+	&separatormethod,	/* TKseparator */
+	&cascademethod,	/* TKcascade */	
+	&listboxmethod,	/* TKlistbox */
+	&scrollbarmethod,	/* TKscrollbar */
+	&textmethod,	/* TKtext */
+	&canvasmethod,	/* TKcanvas */
+	&entrymethod,	/* TKentry */
+	&radiobuttonmethod,	/* TKradiobutton */
+	&scalemethod,	/* TKscale */
+	&panelmethod,	/* TKpanel */
+	&choicebuttonmethod,	/*TKchoicebutton */
+};
+
+char TkNomem[]	= "!out of memory";
+char TkBadop[]	= "!bad option";
+char TkOparg[]	= "!arg requires option";
+char TkBadvl[]	= "!bad value";
+char TkBadwp[]	= "!bad window path";
+char TkWpack[]	= "!window is already packed";
+char TkNotop[]	= "!no toplevel";
+char TkDupli[]  = "!window path already exists";
+char TkNotpk[]	= "!window not packed";
+char TkBadcm[]	= "!bad command";
+char TkIstop[]	= "!can't pack top level";
+char TkBadbm[]	= "!failed to load bitmap";
+char TkBadft[]	= "!failed to open font";
+char TkBadit[]	= "!bad item type";
+char TkBadtg[]	= "!bad/no matching tag";
+char TkFewpt[]	= "!wrong number of points";
+char TkBadsq[]	= "!bad event sequence";
+char TkBadix[]	= "!bad index";
+char TkNotwm[]	= "!not a window";
+char TkBadvr[]	= "!variable does not exist";
+char TkNotvt[]	= "!variable is wrong type";
+char TkMovfw[]	= "!too many events buffered";
+char TkBadsl[]	= "!selection already exists";
+char TkSyntx[]	= "!bad [] or {} syntax";
+char TkRecur[] = "!cannot pack recursively";
+char TkDepth[] = "!execution stack too big";
+char TkNomaster[] = "!no master given";
+char TkNotgrid[] = "!not a grid";
+char TkIsgrid[] = "!cannot use pack inside a grid";
+char TkBadgridcell[] = "!grid cell in use";
+char TkBadspan[] = "!bad grid span";
+char TkBadcursor[] = "!bad cursor image";